Multiple Pulse Width Modulation on the Intel® Quark

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