energia / Energia

Fork of Arduino for the Texas Instruments LaunchPad's
http://energia.nu
Other
794 stars 672 forks source link

MSP430: delayMicroseconds() limited to 65536 μs #695

Closed rei-vilo closed 9 years ago

rei-vilo commented 9 years ago

I'm comparing three methods for a 1 s = 1000 ms = 1000000 μs delay:

void wait_ms(uint32_t ms)
{
    uint32_t chrono = millis() + ms;
    while (chrono > millis());
}

delayMicroseconds() seems to be bugged for the MSP430. For the MSP430F5529, I've experienced issues as I've detailed at #693.

Why the void delayMicroseconds(unsigned int us) is limited to 65536 μs?


Sketch

#include "Energia.h"

#define MAX_RESULTS 32

void wait_ms(uint32_t ms)
{
    uint32_t chrono = millis() + ms;
    while (chrono > millis());
}

uint32_t chrono, chrono1, chrono2;
uint32_t minimum, maximum;
uint64_t average;

void setup()
{
    // put your setup code here, to run once:
    Serial.begin(9600);
    delay(500);

#if defined(__LM4F120H5QR__)
    Serial.println("*** Chrono LM4F120");
#elif defined(__MSP430F5529__)
    Serial.println("*** Chrono MSP430F5529");
#elif defined(__MSP432P401R__)
    Serial.println("*** Chrono MSP432");
#elif defined(__CC3200R1M1RGC__)
    Serial.println("*** Chrono CC3200");
#elif defined(__MSP430G2553__)
    Serial.println("*** Chrono MSP430G2553");
#else
    Serial.println("*** Chrono");
#endif
    Serial.println("Results in us = \tminimum\taverage\tmaximum");
    Serial.println();

    Serial.print("* delayMicroseconds(1000000L);");
    average = 0;
    minimum = -1;
    maximum = 0;
    for (uint16_t i=0; i<MAX_RESULTS; i++)
    {
    chrono1 = micros();
    delayMicroseconds(1000000L); // delay(500);
    chrono2 = micros();
        Serial.print(".");
        chrono = chrono2 - chrono1;
        average += chrono;
        if (chrono > maximum) maximum = chrono;
        if (chrono < minimum) minimum = chrono;
    }

    Serial.println();
    Serial.print("delayMicroseconds(1000000L) = \t");
    Serial.print(minimum, DEC);
    Serial.print("\t");
    Serial.print((uint32_t)(average / MAX_RESULTS), DEC);
    Serial.print("\t");
    Serial.println(maximum, DEC);

    Serial.print("* wait_ms(1000);");
    average = 0;
    minimum = -1;
    maximum = 0;
    for (uint16_t i=0; i<MAX_RESULTS; i++)
    {
        chrono1 = micros();
        wait_ms(1000);
        chrono2 = micros();
        Serial.print(".");
        chrono = chrono2 - chrono1;
        average += chrono;
        if (chrono > maximum) maximum = chrono;
        if (chrono < minimum) minimum = chrono;
    }

    Serial.println();
    Serial.print("wait_ms(1000) =\t");
    Serial.print(minimum, DEC);
    Serial.print("\t");
    Serial.print((uint32_t)(average / MAX_RESULTS), DEC);
    Serial.print("\t");
    Serial.println(maximum, DEC);

    Serial.print("* delay(1000);");
    average = 0;
    minimum = -1;
    maximum = 0;
    for (uint16_t i=0; i<MAX_RESULTS; i++)
    {
        chrono1 = micros();
        delay(1000);
        chrono2 = micros();
        Serial.print(".");
        chrono = chrono2 - chrono1;
        average += chrono;
        if (chrono > maximum) maximum = chrono;
        if (chrono < minimum) minimum = chrono;
    }

    Serial.println();
    Serial.print("delay(1000) =\t");
    Serial.print(minimum, DEC);
    Serial.print("\t");
    Serial.print((uint32_t)(average / MAX_RESULTS), DEC);
    Serial.print("\t");
    Serial.println(maximum, DEC);

    Serial.println("===");
}

void loop()
{
    // put your main code here, to run repeatedly:

}
rei-vilo commented 9 years ago
capture 2015-08-07 a 11 48 25
StefanSch commented 9 years ago

Interesting result - never thought about that in this detail. Having a quick look into the code i can see to issues:

  1. The delayMicroseconds only decode settings for 1 / 8 / 16 MHZ - so this needs to be extended to the other settings as well or better scaled
  2. the parameter for the function call is void delayMicroseconds(unsigned int us) which results in 16 bits on the MSP430 ( max value 65536) 32 bits on the ARM cores (=> unsigned int scales with the bus width of the target processor) So you should be able to enter values up to 65536 with getting the right delay.
rei-vilo commented 9 years ago

Thank for the update on the 65536 limit, not 256.

On Energia MT, the delay() function yields but not the delayMicroseconds() one, hence the importance of the later.

spirilis commented 9 years ago

It is probably nearly impossible to have an "accurate" delayMicroseconds implementation that can delay at sub-1ms resolution while simultaneously letting it "yield". So having delayMicroseconds lock up the processor is a highly appropriate behavior IMO. I personally don't find delayMicroseconds all that useful.

rei-vilo commented 9 years ago

1000 ppm is good enough. The importance is to avoid yielding, hence my interest on delayMicroseconds() over delay().

spirilis commented 9 years ago

Ah, gotcha.

robertinant commented 9 years ago

delayMicroseconds() takes an unsigned int as argument and is 2 bytes hence the limit of 65,535.