GrumpyOldPizza / ArduinoCore-stm32l0

Arduino Core for STM32L0
125 stars 67 forks source link

delayMicroseconds() timing is not good #25

Closed battosai30 closed 6 years ago

battosai30 commented 6 years ago

Hi,

This time I think I've found a real bug xD

Trying to connect a DS18B20 (so OneWire protocol) I failed. I took my logic analyzer and surprise, timings are not good !

I used a simple code like this :

    digitalWrite(2, LOW);
    delayMicroseconds(10);
    digitalWrite(2, HIGH);
    delay(20);

    digitalWrite(2, LOW);
    delayMicroseconds(50);
    digitalWrite(2, HIGH);
    delay(20);

    digitalWrite(2, LOW);
    delayMicroseconds(100);
    digitalWrite(2, HIGH);
    delay(20);

    digitalWrite(2, LOW);
    delayMicroseconds(480);
    digitalWrite(2, HIGH);
    delay(20);

    digitalWrite(2, LOW);
    delayMicroseconds(800);
    digitalWrite(2, HIGH);
    delay(20);

    digitalWrite(2, LOW);
    delayMicroseconds(1000);
    digitalWrite(2, HIGH);
    delay(20);

    digitalWrite(2, LOW);
    delayMicroseconds(1200);
    digitalWrite(2, HIGH);
    delay(20);

And with an excel sheet I calculated a correction that I applied to all timings in OneWire library and magic I got my DS18B20.

So for example if you want a delay of 200µs you have to use delayMicroseconds(200*1.32-5) to get a real 200µs pause.

GrumpyOldPizza commented 6 years ago

What CPU clock are you using ?

On Wed, Jul 18, 2018 at 9:43 AM, battosai30 notifications@github.com wrote:

Hi,

This time I think I've found a real bug xD

Trying to connect a DS18B20 (so OneWire protocol) I failed. I took my logic analyzer and surprise, timings are not good !

I used a simple code like this :

digitalWrite(2, LOW);
delayMicroseconds(10);
digitalWrite(2, HIGH);
delay(20);

digitalWrite(2, LOW);
delayMicroseconds(50);
digitalWrite(2, HIGH);
delay(20);

digitalWrite(2, LOW);
delayMicroseconds(100);
digitalWrite(2, HIGH);
delay(20);

digitalWrite(2, LOW);
delayMicroseconds(480);
digitalWrite(2, HIGH);
delay(20);

digitalWrite(2, LOW);
delayMicroseconds(800);
digitalWrite(2, HIGH);
delay(20);

digitalWrite(2, LOW);
delayMicroseconds(1000);
digitalWrite(2, HIGH);
delay(20);

digitalWrite(2, LOW);
delayMicroseconds(1200);
digitalWrite(2, HIGH);
delay(20);

And with an excel sheet I calculated a correction that I applied to all timings in OneWire library and magic I got my DS18B20.

So for example if you want a delay of 200µs you have to use delayMicroseconds(200*1.32-5) to get a real 200µs pause.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/GrumpyOldPizza/ArduinoCore-stm32l0/issues/25, or mute the thread https://github.com/notifications/unsubscribe-auth/AG4QfJcxfGzVNVdMFhwcorZjnGkSfZkeks5uH1ebgaJpZM4VU2Mw .

battosai30 commented 6 years ago

32 MHz I did not try with the others but as I need USB for debug I do not really have the choice :s

GrumpyOldPizza commented 6 years ago

I'll take a peek. Will take a bit. The loop is a software loop, which is bad ... Should be replaced by a Systick based one to compensate for prefetch deltas ...

On Wed, Jul 18, 2018 at 10:49 AM, battosai30 notifications@github.com wrote:

32 MHz did not try with the others but as I need USB for debug I do not really have the choice :s

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/GrumpyOldPizza/ArduinoCore-stm32l0/issues/25#issuecomment-405999700, or mute the thread https://github.com/notifications/unsubscribe-auth/AG4QfBT1qGyO7z1O3aTewpKz1u582d6fks5uH2cNgaJpZM4VU2Mw .

battosai30 commented 6 years ago

Is there a particular reason to don't use the same approach as standard Arduino like Uno with a simple loop with a while comparing the target time with micros() ? I see in your armv6m_systick.h that a armv6m_systick_micros() exists and as I understand it it's based on systick interruption so it should a good timing reference no ?

GrumpyOldPizza commented 6 years ago

The main reason (besides that all other cores than Arduino AVR) use the same technique) is that the code is reused in the system layer, where SysTick (which drivers micos()) is not available yet, or precise enough.

On Thu, Jul 19, 2018 at 1:36 AM, battosai30 notifications@github.com wrote:

Is there a particular reason to don't use the same approach as standard Arduino like Uno with a simple loop with a while comparing the target time with micros() ? I see in your armv6m_systick.h that a armv6m_systick_micros() exists and as I understand it it's based on systick interruption so it should a good timing reference no ?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/GrumpyOldPizza/ArduinoCore-stm32l0/issues/25#issuecomment-406183825, or mute the thread https://github.com/notifications/unsubscribe-auth/AG4QfCJh90O97iQoSGewLCFe6uvAJ-_5ks5uIDb6gaJpZM4VU2Mw .

GrumpyOldPizza commented 6 years ago

Fixed as of 08/30