delayMicroseconds() works strangely in a timer timeout

Hi, guys, I’ve got my Photon recently and am tring to make a high resolution PWM to control a servo.

But then I found someting strange when using delayMicroseconds(n) in a timer timeout.

When n = 1 ~ 983, it seems all right. But when it comes to 984 ~ 1029, the actual delay time is always 1033 micorsecons.
When n goes above 1029, it seems all righ again.

And it happens rapidly. Follow is the regularity I got:

n = 984 ~ 1029, actual delay time is 1033
n = 1983 ~ 2030, actual delay time is 2033
n = 2983 ~ 3030, actual delay time is 3033
n = 3983 ~ 4030, actual delay time is 4033

Here is my test code:

int delay_value, delay_time;

void time_out() {
    int temp;
    
    temp = micros();
    delayMicroseconds(delay_value);
    delay_time = micros() - temp;
}

Timer timer(20,  time_out);

void setup() {
    Particle.variable("delay_value", &delay_value, INT);
    Particle.variable("delay_time", &delay_time, INT);

    Particle.function("set_value", set_delay_value);
}

void loop() {
}

int set_delay_value(String command) {
    int temp;
    
    timer.stop();
    delay_value = command.toInt();
    
    time_out();
    temp = delay_time;
    
    timer.start();
    
    return temp;
}

In the Console, delay_value could be set by calling the function "set_value ", and it will return the delay time of delayMicroseconds(delay_value) called by the function directly. This delay time seems always be right.

Then the function will start the timer. When the timer times out, the time_out() function will be called, and the delay time of delayMicroseconds(delay_value) in the time_out() function will be saved in delay_time, witch can be get from the Console page.

For example:


When I set the delay_value = 983, the set_value function returns 985, the delayMicroseconds() called by time out delays 985.

When I set the delay_value = 984, the set_value function returns 986, but the delayMicroseconds() called by time out delays 1033.

This confused me for a few days. Hope someone could help.

One thing to consider is that software timers are run in a dedicated FreeRTOS thread which gets a 1ms time slice just as all the other threads.
So my gut feeling tells me that your timer call back gets pushed out the way as it takes more than ~1ms to let the other thread(s) get their share of the controller too.

To test this properly try delayMicroseconds() inside loop() without any other thread running (so no timers).

1 Like

Thanks for helping.
I think you are right. When I run delayMicroseconds() in loop() or the function called from Particle Console, it always works correctly.

So this is probably a bummer in the FreeRTOS: You can’t make an accurate delay in a thread when the delay time is around “n” ms.
Though maybe that is rarely used, in certain situations it still could cause some trouble.

Back to the high resolution PWM, now I‘ve’ found the analogWriteResolution() in the particle online docs. So the delayMicroseconds() and timer are no longer needed.

However, as the online doc describes, the pwm resolution value can range from 2 to 31 bits. But when I tried to set the D0 pin, the value above 15bit would not be applied.
I’m wondering is there any infomation about the supported resolution value of each pin?

You may want to read the docs about the other PWM functions too :wink:
e.g. https://docs.particle.io/reference/firmware/photon/#analogwritemaxfrequency-pwm-

I have read those already, but did not find the describe about the supported resolution values of the pins.
Now i’m just a little queries about why D0’s resolution can only be set up to 15 bits, while the docs saying it could be up to 31 bits.

As a matter of fact, setting to 15 bits is enough for me. But… just queries…:confused:

The function can take 2..31 as resolution, but the timers connected to the pin may not be set up to support the full range, hence this comment

So it would be best to check analogWriteResolution() after setting it.

The individual max resolution could be documented, but I think if each and every such detail would need to be documented it would clutter up docs and if system firmware changes for some reason this kind of detail may well be forgotten to be updated too :sunglasses:

Yeah, that maks sence. But it would always maks users confused.
Anyway, it shoud not be big problem.

Thanks for helping~