[ell-i-developers] Re: ELL-i-Arduino Delay functions and interrupt disable

  • From: Pekka Nikander <pekka.nikander@xxxxxx>
  • To: ell-i-developers@xxxxxxxxxxxxx
  • Date: Sat, 22 Feb 2014 19:00:04 +0200

Good work!

> I tested the delays with the oscilloscope, and the ASM section on
> function delayMicroseconds that performs the delays below 20
> microseconds works perfectly in wiring_time.h:

Good to know.

> The next section, for delays equal or over 20 microsecond that
> compares the current micros() with the micros() the function started
> works well for delays over 1000 microseconds, so the delay and
> delayMilisecond functions work fine.

Based on your notes below I suspect it may not be that accurate there, either, 
but that we just don't see the jitter as it is so small (tens of us) compared 
to the 1 ms...

> The problem is with delay times between 20 and 1000 microseconds, and
> then strange things happen on the oscilloscope, with what appear to be
> random delays appearing, sometimes too small and sometimes too big.

Even the comments say that sometimes the current implementation fails if the 
millisecond counter rolls over.  I don't remember how often that happens, but 
apparently only once every few days.  Anyway, at some point that needs to be 
fixed too.

In addition to changing the cutoff value of the asm loop, we could also 
explicitly compute timo - micros() (as the compiler needs to do that anyway), 
and compare that to the cutoff value.  If the difference is less than the 
cutoff value, run only the assembler loop for the rest of the time.  Something 
like the following:

    remaining = us;
    if (remaining > cutoff)
       timo = micros() + us;

    do {
       if (remaining < cutoff) { do the asm loop); return; }
       yield();
       remaining = timo - micros();
    while (remaining > 0);

You need to be careful with signed and unsigned values.  But that should give 
you more accuracy.

> I would like to know if there are problems of extending the ASM loop
> that currently works with less than 20 microseconds into more than 20
> microseconds, and how much more is reasonable? Currently it does 240
> iterations of the code above for 20 microseconds.

I think the cutoff could well be 2000 or even 3000 CPU clocks.

> After several tests, I noticed that if I call twice the delayMicroseconds 
> function with the same argument in consecutive lines, the second calls gets 
> ignored.

Hard to say more without seeing the generated assemble.  You can generate that 
with -S.

> The sensor is still not working, but at least the delays are working
> now. The library for the sensor first sets the pin as output, takes it
> to LOW to signal the sensor to start sending data and sets the pin as
> input to listen. I don't know how long this change takes, but if it is
> more than a few microseconds, the problem with the reading might be
> there. I will test it, but if someone has done it before, I am glad to
> know.

Have you tried to connect the sensor to the +5V, 3.3V may be too low?  If you 
connect it to +5V, please make sure you use an 5V tolerant I/O pin at the MCU.

I still think the right way is to use a counter/timer instead of a delay.  
Please note also that on STM32F it is possible to set the weak pulldown and 
pullup on an I/O even if it is an input.  See Figure 15 on page 126 of RM0091.  
In that way you should be able to set the pin low and high without setting it 
as an output, and start receiving data as soon as it first transitions.  

I would use a timer to read the high-pulse length (26-28 us vs 70 us) and 
trigger an interrupt at each high-to-low edge.  Then, at the interrupt routine 
I could easily determine from the counter value whether the previous bit was 
one or zero.

The timer could even be set up before pulling the line high after the long low. 
 The first interrupt would then be triggered by the first high-to-low 
transition, at the beginning of the transmission, and you could then see the 
that the 20-40 ms waiting time.

It will take some time to figure out how to initialise the timer/counter 
correctly, but then you'll learn how to program bare metal in the first place. 
:-)

--Pekka


Other related posts: