Inconsistant wait period for digital out

23 Aug 2012

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);
                                                                                             
    }
}
23 Aug 2012

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.

23 Aug 2012

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.

24 Aug 2012

For such demands I would either try using the FastIO library

Import programFastIO

Fast GPIO using C++ templates. Now with port I/O.

or probably even better for single output manipulation

Import librarySimpleIOMacros

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.

24 Aug 2012

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

24 Aug 2012

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.

24 Aug 2012

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.

/media/uploads/wim/_scaled_screenshot_60_1.jpg Highres is here

/media/uploads/wim/_scaled_screenshot_100_1.jpg 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.

24 Aug 2012

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.

24 Aug 2012

Nathan Biggs wrote:

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).

/media/uploads/wim/_scaled_screenshot_excel_.jpg 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.

25 Aug 2012

The problem issue has been resolved with a new mbed. Thanks for all your help!