Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper October 2015 Document Number: 332918–001US You may not use or facilitate the use of this document in connection with any infringement or other legal analysis concerning Intel products described herein. You agree to grant Intel a non-exclusive, royalty-free license to any patent claim thereafter drafted which includes subject matter disclosed herein. No license (express or implied, by estoppel or otherwise) to any intellectual property rights is granted by this document. All information provided here is subject to change without notice. Contact your Intel representative to obtain the latest Intel product specifications and roadmaps. The products described may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request. Copies of documents which have an order number and are referenced in this document may be obtained by calling 1-800-5484725 or by visiting: http://www.intel.com/design/literature.htm Intel, Intel® Quark™ and the Intel logo are trademarks of Intel Corporation in the U.S. and/or other countries. *Other names and brands may be claimed as the property of others. Copyright © 2015, Intel Corporation. All rights reserved. Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 2 Document Number: 332918–001US Contents 1 Abstract ........................................................................................................... 5 2 Introduction ...................................................................................................... 6 3 Methods ........................................................................................................... 9 4 Results ............................................................................................................ 15 5 Discussion ....................................................................................................... 22 6 Conclusion ....................................................................................................... 23 7 References ....................................................................................................... 24 Figures Figure 1. Typical Servo Consists of Electric Motor, Gear Reduction, Closed Loop Controller, and 3wire Connector [2] ............................................................................................. 7 Figure 2. Typical Servo Control Input PWM Timing ..................................................................... 8 Figure 3. PWM Outputs in Cyan and Core Current in Red When Silicon Oscillator and General Purpose Timer Utilities Were Used................................................................................... 15 Figure 4. PWM Pulse Width Accuracy and Jitter When Silicon Oscillator and General Purpose Timer Utlities Were Used ............................................................................................ 16 Figure 5. PWM Outputs in Cyan and Core Current in Red With Silicon Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler .................................................... 18 Figure 6. PWM Pulse Width Accuracy and Jitter With Silicon Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler .................................................................. 19 Figure 7. PWM Outputs in Cyan and Core Current in Red With 33 MHz Crystal Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler ........................................... 20 Figure 8. PWM Pulse Width Accuracy and Jitter with 33 MHz Crystal Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler .................................................... 21 Tables Table 1. Maximum Cycle Frequency at Measured Interrupt Service Latencies and Various Resolutions22 Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 3 Revision History Date Revision October 2015 001 Description Initial release. § Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 4 Document Number: 332918–001US 1 Abstract A common use of microcontrollers is to control servos. Servos are actuators typically used in radio control and robotics. A pulse width modulated (PWM) signal commands rotation of the actuator. The Intel® Quark™ microcontroller D1000 does not have integrated PWM hardware, so a software solution is necessary. This paper presents a software solution for a multiple PWM controller. The methods used can implement PWMs to control up to 22 servos simultaneously with better than 3 µs resolution. This paper defines the requirements for controlling servos, develops a scalable solution, presents test results, and discussed the limitations of this implementation. § Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 5 2 Introduction A typical servo is shown in Figure 1. It consists of a lever (on top) attached to an electric motor through a gear reduction, a closed loop controller, and a 3-wire connector. The 3-wire connector supplies power, ground and a single-ended PWM control signal. The angle of the actuator is controlled by the pulse width of the PWM signal as shown in Figure 2. The period of the PWM signal is generally fixed, but varies from servo to servo and can be as little as 6 ms to as much as 25 ms [1]. A PWM signal can be generated by software bit banging a digital GPIO. However, precisely controlling period and duty cycle requires the use of timers. The Intel® Quark™ microcontroller D1000 has three timers. One uses the system clock frequency. The other two use a programmable division of the oscillator frequency and are independent of system clock frequency. Using the lower frequency timers reduces power consumption. The resolution of the PWM (for example, the size of the discrete time increments by which the pulse width is varied) is limited by the time required to process a change in timer value. One can imagine a software implementation that would process every change in timer value. When the new timer value corresponds to a time that the PWM output should change, software toggles the GPIO. However, this implementation results in software processing every discrete time change even though there only two times of interest: (1) start of cycle and (2) width of pulse. For the finest time resolution, software will be constantly processing and never sleeping. A better implementation uses two timers: (1) a periodic cycle timer and (2) a one shot pulse width timer. When the cycle timer expires, the PWM output is driven high and the pulse width timer is started. When the pulse width timer expires, the PWM output is driven low. Between these times, the processor sleeps or performs background tasks. Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 6 Document Number: 332918–001US Figure 1. Typical Servo Consists of Electric Motor, Gear Reduction, Closed Loop Controller, and 3-wire Connector [2] Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 7 Figure 2. Typical Servo Control Input PWM Timing 20.0 ms 1.5 ms 2.0 ms 1.0 ms § Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 8 Document Number: 332918–001US 3 Methods The implementation in this paper is based on the two-timer solution, but the solutionis extended to a more general case of multiple PWM outputs. The number of PWMs is limited by the number of GPIO pins available. Reserving at least two pins for communication, up to 22 PWM signals can be generated using this implementation with no detriment to performance. In order to simplify things, this paper discusses an eight PWM implementation. However, it should be obvious to the reader how to scale the implementation for fewer or more PWMs. Precise timing requires precise frequency. The Intel® Quark™ microcontroller D1000 supports crystal oscillators from 20-33 MHz for the system clock and 32.768 kHz for the real time clock. Optionally, a silicon oscillator can be used for the system clock to save power. However, the accuracy of the silicon oscillator can be affected by temperature. The silicon oscillator should be calibrated before use. Fortunately, the Intel® Quark™ microcontroller D1000 has an oscillator calibration utility in ROM that will calibrate the silicon oscillator to the real time clock oscillator with 10-bit precision (for example, <0.1% error). The software implementation in this paper supports either use case. //////////////////////////////////////////////////////////////////////////////// // this is the main program //////////////////////////////////////////////////////////////////////////////// void main(void) { #ifdef USE_XTAL //switch to xtal oscillator PM_O33M_CFG1.f.O33M_EXO = 1; for (uint32_t k = 0; k < 64000; k++) if (PM_O33M_CFG1.f.O33M_XOL) break; if (PM_O33M_CFG1.f.O33M_XOL) { PM_O33M_CFG1.f.O33M_MS = 1; PM_O33M_CFG1.f.O33M_ESO = 0; // power up xtal oscillator // wait up to 2 ms for oscillator to lock // if locked... // select xtal oscillator // power down silicon oscillator #else // calibrate silicon oscillator if (r_calibrate_osc_freq(O33M_FREQUENCY) > 0) { #endif The O33M_FREQUENCY symbol is defined in the Quark_D1000_CfgDefs.h header file. For best resolution, it is defined as 32 MHz. The next step is to initialize the hardware environment. The code snippet shown in the following selects clock dividers for the timers, enables APB and timer clocks, powers down the real time clock oscillator, and selects the GPIO pins to use for PWM outputs. Symbols T0_RATIO and T1_RATIO are defined in the Quark_D1000_CfgDefs.h header file. As shown later, the best achievable timing resolution is >1 µs, so the lowest timer clock frequency that will provide 1 µs resolution (for example, the divide by 32 clock) was chosen. Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 9 // initialize hardware PM_CLK_SEL.f = (PM_CLK_SEL_bits_s) { .T0_CLKRATIO = T0_RATIO, // timer 0 clock ratio .T1_CLKRATIO = T1_RATIO}; // timer 1 clock ratio PM_CLK_EN.f = (PM_CLK_EN_bits_s) { .APB_CLKEN = 1, // APB clock enabled .T0_CLKEN = 1, // timer 0 clock enabled .T1_CLKEN = 1, // timer 1 clock enabled .RTC_OPD = 1}; // RTC oscillator powered down GI_SWPORTA_DDR = 0xF0F; // GPIO[11:8,3:0] are outputs PM_IOP_FUNC_CTL0.f = (PM_IOP_FUNC_CTL0_bits_s) { .PF0 = 1, // pin function 0 is GPIO .PF1 = 1, // pin function 1 is GPIO .PF2 = 1, // pin function 2 is GPIO .PF3 = 1, // pin function 3 is GPIO .PF4 = 3, // pin function 4 is analog .PF5 = 3, // pin function 5 is analog .PF6 = 3, // pin function 6 is analog .PF7 = 3}; // pin function 7 is analog PM_IOP_FUNC_CTL1.f = (PM_IOP_FUNC_CTL1_bits_s) { .PF8 = 1, // pin function 8 is GPIO .PF9 = 1, // pin function 9 is GPIO .PF10 = 1, // pin function 10 is GPIO .PF11 = 1, // pin function 11 is GPIO .PF12 = 3, // pin function 12 is analog .PF13 = 3, // pin function 13 is analog .PF14 = 3, // pin function 14 is analog .PF15 = 3}; // pin function 15 is analog The next step is to start a periodic timer and register a callback function for it. The code snippet that follows sets the timer period in timer clock units to the timer frequency divided by the desired PWM frequency (for example, 500 Hz). The interrupt from this timer marks the start of a PWM cycle. // register timer callbacks timer_0_callback(timer_0_callback_function); // PWM period timer start_periodic_timer_0(T0_FREQUENCY/PWM_FREQUENCY); The last stage is to enable interrupts and enter the main loop. The code needed to update PWM settings is application-specific. The control inputs could come from a sensor, a controller or a radio; a discussion of the particular algorithm needed is outside the scope of this paper. The focus here is the software implementation of the PWM. Suffice it to say that whatever the algorithm is, it must be executed as a background task so that it does not introduce any latency in the timer interrupt service. If other interrupts need to be serviced (such as UART, SPI, or I²C), the trap (TR) bit in the IDT entry for that interrupt should be set. This will allow the lower priority interrupt to be preempted by a timer interrupt. Once PWM updates have been processed, there is nothing left to do but wait. Here the code executes a halt instruction to put the processor, AMBA fabric and memory into a clock gated state for power reduction. Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 10 Document Number: 332918–001US // enable interrupts __asm__("sti"); // loop forever while (1) { /************************************************************************* This is where you would process changes to the PWM duty cycle. Do this in the background so that it can be interrupted. Use a ping-pong approach to manage updates to the pwm_state, pwm_duty_cycle and pwm_last_update tables or wait until all PWM outputs are low and update the tables before the next PWM cycle begins. *************************************************************************/ // halt and wait for interrupt __asm__("hlt"); } } } Information on PWM state and duty cycles must be passed from the PWM update algorithm to the timer callback functions. This application does this with global arrays. The PWM state array shown in the following example defines the state of the PWM outputs at each of the pulse width timer events. It must be sorted by shortest to longest pulse width. It could be from one to eight entries long depending on how many PWM outputs share the same pulse width. Each time a pulse width timer expires one or more PWM outputs are driven low. In the initial state of this array PWM 0 has the shortest pulse with and PWMs 1-7 have successively longer pulse widths. //////////////////////////////////////////////////////////////////////////////// // This is the PWM output state table. Each array entry contains the // output state for the eight PWM outputs. There can be up to nine // unique output states. //////////////////////////////////////////////////////////////////////////////// uint32_t pwm_state[] = { 0x00F0E, // GPIO[0] = PWM[0] = 0 0x00F0C, // GPIO[1] = PWM[1] = 0 0x00F08, // GPIO[2] = PWM[2] = 0 0x00F00, // GPIO[3] = PWM[3] = 0 0x00E00, // GPIO[8] = PWM[4] = 0 0x00C00, // GPIO[9] = PWM[5] = 0 0x00800, // GPIO[10] = PWM[6] = 0 0x00000};// GPIO[11] = PWM[7] = 0; This application uses a Boolean array to indicate the final PWM state entry. The code could eliminate this array entirely and rely on a particular GPIO state (for example, all zeroes), but this application uses this array in order to keep the solution general and allow other non-PWM GPIOs to take arbitrary values. Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 11 //////////////////////////////////////////////////////////////////////////////// // This is the last update flag table. Each array entry corresponds to // an entry in the PWM output state array. A non-zero value indicates // which array entry contains the final output state. //////////////////////////////////////////////////////////////////////////////// uint32_t pwm_last_update[] = { 0, 0, 0, 0, 0, 0, 0, 1}; The application needs an array of pulse widths (or duty cycles) for each unique PWM pulse. The values in this array are actually the amount of time the PWMs remain low after having generated their high pulse. At each PWM state update, this value is subtracted from the amount of time remaining in the PWM cycle. The difference is the time until the next PWM update (for example, the next PWM falling edge). Like the PWM state array, there could be from one to eight entries depending on how many PWM outputs share the same pulse width. Also, this array must be sorted from shortest to longest pulse width. //////////////////////////////////////////////////////////////////////////////// // This is the PWM duty cycle table. Each array entry contains a duty // cycle expressed as duration of low state in timer clock // units. There can be up to eight duty cycles (one for each PWM // output). Entries are sorted from highest to lowest. //////////////////////////////////////////////////////////////////////////////// uint32_t pwm_duty_cycle[] = { T0_FREQUENCY/PWM_FREQUENCY - 1500, // 1500 us pulse T0_FREQUENCY/PWM_FREQUENCY - 1505, // 1505 us pulse T0_FREQUENCY/PWM_FREQUENCY - 1510, // 1510 us pulse T0_FREQUENCY/PWM_FREQUENCY - 1515, // 1515 us pulse T0_FREQUENCY/PWM_FREQUENCY - 1520, // 1520 us pulse T0_FREQUENCY/PWM_FREQUENCY - 1525, // 1525 us pulse T0_FREQUENCY/PWM_FREQUENCY - 1530, // 1530 us pulse T0_FREQUENCY/PWM_FREQUENCY - 1535};// 1535 us pulse Finally, the application needs a global variable to index the PWM state and duty cycle arrays. This variable is cleared at the start of each PWM cycle and increments with each PWM state update. //////////////////////////////////////////////////////////////////////////////// // This is the index into the PWM state array. It points to the next PWM state. //////////////////////////////////////////////////////////////////////////////// uint32_t state_index = 0; Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 12 Document Number: 332918–001US The cycle timer initiates the start of each PWM cycle. The code snippet shown in the following example shows the tasks that must be completed at start of each PWM cycle. All PWM outputs must be driven high. The pulse width timer must be started with the relative time to the shortest PWM pulse. The PWM state index must be reset to the top of the PWM state table. Finally, the pulse width timer callback must be registered and the cycle timer callback must be re-registered. //////////////////////////////////////////////////////////////////////////////// // this is the timer0 callback function //////////////////////////////////////////////////////////////////////////////// void timer_0_callback_function(void) { // update PWM outputs GI_SWPORTA_DR = 0xF0F; // enable pulse width timer clock PM_CLK_EN.f.T1_CLKEN = 1; // load count relative to start of cycle T1_LOAD_CNT = T0_CRNT_VAL - pwm_duty_cycle[0]; // enable pulse width timer T1_CTL_REG.all = ((0 << Tx_INT_MASK_fo) | // unmask interrupt (0 << Tx_MODE_fo) | // free running (1 << Tx_ENABLE_fo)); // enable timer // reset state index pointer state_index = 0; // re-register timer 0 callback function timer_0_callback(timer_0_callback_function); // register timer 1 callback timer_1_callback(timer_1_callback_function); } The code snippet shown in the following example shows the PWM pulse width timer interrupt service. The PWM pulse width timer signals a PWM state update. Each time the timer expires, one or more PWM outputs are driven low. If more state updates are required, the pulse width timer is restarted with the relative time to the next PWM state update. Lastly, the PWM pulse width timer callback is re-registered. It is clear that the time between discrete PWM output states cannot be less than the time required to service timer interrupts including the callbacks. This places a lower bound on PWM resolution. The algorithm used to update the PWM state arrays must police this lower bound. Any discrete state updates that are separated by less than the timer interrupt service latency must be collapsed into a single state update. Finally, too low a timer clock frequency could also limit PWM resolution. However, as shown in the results section, timer interrupt service latency is greater than the 1 µs timer clock period. Therefore, timer clock frequency does not limit PWM resolution. Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 13 //////////////////////////////////////////////////////////////////////////////// // this is the timer1 callback function //////////////////////////////////////////////////////////////////////////////// void timer_1_callback_function(void) { // update PWM outputs GI_SWPORTA_DR = pwm_state[state_index]; // if not last update, set timer for next update if (!pwm_last_update[state_index]) { // enable timer clock PM_CLK_EN.f.T1_CLKEN = 1; // load count relative to current time T1_LOAD_CNT = T0_CRNT_VAL - pwm_duty_cycle[++state_index]; // enable timer T1_CTL_REG.all = ((0 << Tx_INT_MASK_fo) | // unmask interrupt (0 << Tx_MODE_fo) | // free running (1 << Tx_ENABLE_fo)); // enable timer // re-register callback timer_1_callback(timer_1_callback_function); } } § Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 14 Document Number: 332918–001US 4 Results The PWM software was tested on an Intel® Quark™ microcontroller D1000 with the eight PWM outputs instrumented on digital channels of an Agilent* MSO-X 4034A mixed signal oscilloscope and the core current instrumented using an Agilent N2820A current probe. Figure 3 shows the results at the best possible resolution of 5 µs. The core current waveform in red shows eight 14.8 mA pulses that coincide with the falling edges of the PWM outputs in cyan. These pulses envelop the pulse width timer interrupt service routines. It is clear from the waveforms that the interrupt service routines nearly run together at 5 µs resolution. Decreasing resolution to 4 µs resulted in error since the interrupt service routine latency is greater than 4 µs in this application. Figure 3. PWM Outputs in Cyan and Core Current in Red When Silicon Oscillator and General Purpose Timer Utilities Were Used Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 15 Figure 4 shows the accuracy and jitter of the PWM pulse width when the silicon oscillator was used. The mean pulse widths are within 2 µs of the ideal value. This error is primarily due to the difference between the silicon oscillator clock frequency and the oscilloscope’s internal time base. The silicon oscillator is calibrated against the 32 kHz crystal oscillator on entry to the main function. However, calibration error includes up to ±0.1% for 10-bit quantization of the trim code and ±60 PPM for 32.768 kHz crystal oscillator frequency. Standard deviation in PWM pulse width was little over 650 ns. Assuming a normal distribution, about 68% of pulses will be within 650 ns of the mean, and 95% of pulses will be within 1.3 µs of the mean. Figure 4. PWM Pulse Width Accuracy and Jitter When Silicon Oscillator and General Purpose Timer Utlities Were Used In order to improve precision, the application needs to reduce the interrupt service latency. Interrupt service using the general-purpose timer utilities includes an interrupt service stub that pushes and pops all core registers, a call and return from the general-purpose timer utilities interrupt service routine, and a call and return from the registered callback. Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 16 Document Number: 332918–001US While the general-purpose timer utilities are very flexible and easy to use, the application can substantially reduce interrupt service latency by coding the entire handler in the interrupt service stub. The code snippet shown in the following example shows the coding of the entire PWM cycle timer interrupt service routine in its interrupt service stub. Notice that only one register needs to be saved and restored. Also note that the PWM outputs are set high at the end of the service routine. This equalizes the delay from timer event to output change with the pulse width timer interrupt service. timer0_interrupt_handler_stub: push %eax // save EAX movl $0x0,0xfee000b0 // APIC EOI mov 0x9300000c,%eax // timer 0 EOI mov 0x93000004,%eax // get timer 0 current value sub pwm_duty_cycle,%eax // subtract first entry in duty cycle array mov %eax,0x93000014 // write result in timer 1 load count movl $0x1,0x9300001c // enable timer 1 in one shot mode movl $0x0,state_index // clear the PWM state index movl $0xf0f,0x90000000 // set all PWM outputs high pop %eax // restore EAX iret The code snippet shown in the following example shows the coding the entire PWM pulse width timer interrupt service routine in its interrupt service stub. Notice that only two registers need to be saved and restored. Also note that value read from the timer EOI register is used to clear the timer control register. This shortcut is possible because the timer EOI register always returns zero. timer1_interrupt_handler_stub: push %eax // save EAX push %ecx // save ECX movl $0x0,0xfee000b0 // APIC EOI mov 0x93000020,%ecx // timer 1 EOI mov state_index,%eax // get state index mov %ecx,0x9300001c // disable timer 1 in one shot mode mov pwm_state(,%eax,4),%ecx // get desired PWM state mov %ecx,0x90000000 // update PWM outputs cmpl $0x0,pwm_last_update(,%eax,4) // get last update flag jne timer1_interrupt_handler_stub_1 // exit if last update addl $0x1,%eax // increment state index mov 0x93000004,%ecx // get timer 0 current value sub pwm_duty_cycle(,%eax,4),%ecx // subtract next duty cycle from current time mov %ecx,0x93000014 // write result in timer 1 load count movl $0x1,0x9300001c // enable timer 1 in one shot mode mov %eax,state_index // store incremented state index timer1_interrupt_handler_stub_1: pop %ecx // restore ECX pop %eax // restore EAX iret Figure 5 shows the resolution after coding custom interrupt service routines in assembler. The best resolution improved from 5 to 3 µs. Figure 6 shows the accuracy Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 17 and jitter of the PWM pulse widths after coding custom interrupt service routines in assembler. Mean pulse widths are almost 4 µs too short, but the standard deviation has dropped to about 280 ns. The pulse width error can easily be compensated in the PWM duty cycle array. Figure 5. PWM Outputs in Cyan and Core Current in Red With Silicon Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 18 Document Number: 332918–001US Figure 6. PWM Pulse Width Accuracy and Jitter With Silicon Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler In order to reduce jitter in the PWM pulse widths, switch to the crystal oscillator. Figure 7 shows the resolution after switching to the 33 MHz crystal oscillator. The best resolution improved from 3 to 2.9 µs. Figure 8 shows the accuracy and jitter of the PWM pulse widths after switching to the crystal oscillator. Mean pulse widths are within 1 µs of ideal, and standard deviation has dropped to less than 15 ns. The price paid for these improvements is ~0.2 mA increase in current consumption. Regarding current consumption, this implementation has the Intel® Quark™ microcontroller D1000 actively processing for only 27 µs out of the total 20 ms cycle time. This puts overall current consumption at only marginally above the base current consumption of 3.5 mA for the silicon oscillator or 3.7 mA for the crystal oscillator. Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 19 Figure 7. PWM Outputs in Cyan and Core Current in Red With 33 MHz Crystal Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 20 Document Number: 332918–001US Figure 8. PWM Pulse Width Accuracy and Jitter with 33 MHz Crystal Oscillator and Custom Timer Interrupt Service Routines Coded in Assembler § Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 21 5 Discussion This paper has demonstrated that the Intel® Quark™ microcontroller D1000 is capable of controlling up to 22 servos simultaneously using only two timers. The PWM cycle time resolution is set by the timer clock frequency which is some division of the system clock oscillator (for example, 1, 2, 8 or 32 MHz). The PWM pulse width resolution is limited by timer interrupt service latencies. By coding custom interrupt service routines in assembly language, this application achieved a pulse width resolution of less than 3 µs (which is 0.2% of the nominal 1.5 ms pulse width). The silicon oscillator has much higher jitter than the crystal oscillator. Testing the application with the silicon oscillator revealed a standard deviation of slightly more than 280 ns. Assuming a normal distribution, 95% of pulses will be within ±560 ns of the mean when the silicon oscillator is used. For applications requiring lower jitter, the crystal oscillator measured less than 15 ns standard deviation. Besides servos, there are many other uses for PWM signals, from motors to audio to switching power supplies [3]. Assuming a full 0 to 100% duty cycle range, maximum cycle frequency, interrupt service latency and pulse width resolution are related by: ๐≤ ๐ผ ๐ …where ๐ is the cycle frequency, ๐ is the interrupt service latency, and ๐ผ is the pulse width resolution as a fraction of the cycle period. Table 1 shows the maximum cycle frequency achievable at 3 and 5 µs interrupt service latencies for various pulse width resolutions. This software PWM implementation is clearly limited to low cycle frequency or coarse pulse width resolutions. Table 1. Maximum Cycle Frequency at Measured Interrupt Service Latencies and Various Resolutions Frequency ๐ (Hz) Pulse Width Resolution ๐ถ (%) Interrupt Service Latency ๐ (µs) 400 0.2 5 2000 1.0 5 10000 5.0 5 667 0.2 3 3333 1.0 3 16667 5.0 3 § Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 22 Document Number: 332918–001US 6 Conclusion This paper has demonstrated that the Intel® Quark™ microcontroller D1000 is capable of controlling the types of servos typically used in radio control or robotics using its two general purpose timers. Furthermore, multiple servos can be controlled simultaneously with no impact on performance. By coding the timer interrupt service routines in assembly language, this application was able to achieve a pulse width resolution of 3 µs on a pulse that is nominally 1,500 µs. By using a crystal oscillator, this application was able to achieve pulse widths with less than 15 ns of standard deviation. While the Intel® Quark™ microcontroller D1000 does not have specialpurpose PWM hardware, it is more than capable of generating the types of low frequency PWM signals used in many control applications. § Multiple Pulse Width Modulation on the Intel® Quark™ microcontroller D1000 White Paper Document Number: 332918–001US October 2015 23 7 References [1] Wikipedia contributors. "Servo control." Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 27 Apr. 2014. Web. 22 Aug. 2014. [2] Oomlout. "Micro servo" - SERV-03-MI (Micro Servo). Licensed under Creative Commons Attribution-Share Alike 2.0 via Wikimedia Commons http://commons.wikimedia.org/wiki/File:Micro_servo.jpg#mediaviewer/File:Mi cro_servo.jpg. [3] Wikipedia contributors. "Pulse-width modulation." Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 21 Aug. 2014. Web. 25 Aug. 2014. § Multiple Pulse Width Modulation on Intel® Quark™ microcontroller D1000 White Paper October 2015 24 Document Number: 332918–001US