Inconsistant wait period for digital out
Topic last updated
25 Aug 2012, by
Nathan Biggs.
9 replies
digitalOut,
wait
I need to create a program that outputs varing pulse lengths. The pulse lengths need to be either 58us or 100us. The low pulse length and high pulse length must be withing 3us of each other. For example set output low for 58us then set output high for 58us. Next set output low for 100us then set output hight for 100us. What I'm seeing using a logic probe is that an extra 10us is being added randomly to either a low signal or a high signal. Is there something running in the background that could be causing the extra 10us? Below is my code:
#include "mbed.h"
DigitalOut dcc1(p13);
int main() {
while(1) {
//small
dcc1 = true;
wait(0.000058);
dcc1 = false;
wait(0.000058);
//large
dcc1 = true;
wait(0.0001);
dcc1 = false;
wait(0.0001);
}
}
Replies
You may want to use the wait_us() method instead to make it easier setting us waits.
Are you sure that your logic probe is sampling at a high enough rate. A logic analyser sampling at 10us would seem to add random extra 10us low or high pulsetimes because of its limited resolution.
I have tried using wait_us(58), wait_ms(.058), and wait(.000058). They all behave the same. The logic analyser is sampling at 25Mhz. Plenty fast enough to see the correct signal width.
For such demands I would either try using the FastIO library
Fast GPIO using C++ templates. Now with port I/O.
or probably even better for single output manipulation
Simple to use macros to manipulate GPIOs quickly.
You can also try directly accessing registers, but that should be exactly same speed as the macro library for changing single bits.
I run FastIO and the results were almost from 150nanosec to 50nanosec per iteration
DigitalOut: 11.458334 seconds (114 ns per iteration).
FastOut: 8.333335 seconds (83 ns per iteration).
PortOut: 15.625001 seconds (156 ns per iteration).
FastPortOut: 9.375001 seconds (93 ns per iteration).
MaskedPortOut: 5.208334 seconds (52 ns per iteration).
Nathan's problem seems to be an extra 10 uicrosec which is 10 000 nsec !
@ Nathan . Are you sure ,you are sampling in the 24Mhz sampling rate ? ( 40 nsec resolution ? )
I have not tested wait_us to see if the actual accuracy of the function is 1 , 2,3 or 10 μιcroseconds
( but if this happened , this would happen all the time and not once every some iterations )
So , I suspect that either your usb logic analyser has some data traffic error or
you are sampling with 10 μicrosec resolution ( not the maximum 40nsec ) in which case as Wim says , you could expect an error of one sample
Could you verify the results with another logic analyser ?
I had an error some time ago , I could not see a fast transition but that was a <40 nsec transition , too fast for a 24Mhz analyser to be captured
http://mbed.org/forum/mbed/topic/2478/?page=1#comment-12814
Regards
Christos
Nathan,
One small disadvantage of using the mbed libraries is that they are mostly 'black boxes' (header information, but no source code). As a result, we don't konw the details of how timer functions (like wait()) handle wrap-around of the 32 bit hardware register or linking and garbage collection on a series of 'wait()' requests. So, it is possible that current timer functions themselves do create infrequent, re-occuring delay hiccups.
A possible alternative or work-around is to use one of the other hardware timers with their associated output bit to generate your timing pattern 'in-the-background'. Set-up the timer mode, interrupt condition, interrupt routine, output bit, etc. 'by hand'. The timer should re-set to zero, re-start, toggle the output bit, and launch the interrupt routine upon match. The interrupt routine should update the associated comparison register 'on-the-fly' from a (local static or global) flag something like the following (psuedo-code) -
void my_update(void) { // maybe direct __interrupt routine, instead?
static local_flag /* = 0 */;
COMPARISON_REGISTER = (local_flag ^= (OUTPUT_BIT == 1)) ? DELAY_100US : DELAY_58US);
/* return; */
}
I am assuming that the interrupt-based update of the comparison value can be done on-the-fly without disturbing the hardware timer increments and comparisons, and that the update will complete before any possible comparison trigger of the time-out.
I tested the original software posted by Nathan and measured the results with a USB logic analyser. (samplerate 25 MHz, 50M samples).
#include "mbed.h"
DigitalOut dcc1(p13);
int main() {
while(1) {
//small
dcc1 = true;
wait(0.000058);
dcc1 = false;
wait(0.000058);
//large
dcc1 = true;
wait(0.0001);
dcc1 = false;
wait(0.0001);
}
}
The screenshots below show 2 examples, one for the short pulse and one for the long pulse. I checked a bunch of pulse durations from the collected dataset and the measured variations are always below 1us. However, the short pulse is slightly longer than the preset value of 58us. Its duration is consistently slightly above 60us.
Highres is here
Highres is here
I tried out the wait_us(58) version also, this resulted in minor differences (pulsewidth around 58.9us). This is probably due to rounding errors.
My conclusion is that the wait() and DigitalOut are not causing random 10us pulse jitter. It must be a problem of the measurement method or possibly interference on your mbed clock.
The jitter does not always happen. Did you check through all the samples? It was happening on my about every 10 to 20 pulses.
I also use the Salae. I will try running the test again this afternoon. I will also try use a brand new mbed. Maybe something is damaged on mine.
The jitter does not always happen. Did you check through all the samples? It was happening on my about every 10 to 20 pulses.
I first did some random checks and found no jitter. Then checked a sequence of about 50 or 60 and found no issues. By that time I remembered the export function of the Saleae and produced a CSV file. That file was imported in Excel, I added a formula to compute the samplecount diffs between signalchanges and plotted those. The figure shows a perfect score: all samplecount diffs are either around 1475 samples (59us at 40ns sampletime) or 2520 samples (100 us).
Highres is here
This is measured for some 25000 transitions during a 2 sec interval. It should be easy to measure and analyse longer periods.
The problem issue has been resolved with a new mbed. Thanks for all your help!
Please log in to post a reply.
I need to create a program that outputs varing pulse lengths. The pulse lengths need to be either 58us or 100us. The low pulse length and high pulse length must be withing 3us of each other. For example set output low for 58us then set output high for 58us. Next set output low for 100us then set output hight for 100us. What I'm seeing using a logic probe is that an extra 10us is being added randomly to either a low signal or a high signal. Is there something running in the background that could be causing the extra 10us? Below is my code:
#include "mbed.h" DigitalOut dcc1(p13); int main() { while(1) { //small dcc1 = true; wait(0.000058); dcc1 = false; wait(0.000058); //large dcc1 = true; wait(0.0001); dcc1 = false; wait(0.0001); } }