What happens once every milisecond (1000 Hz) and halts loop task

Hi!

I'm actually coming off an ESP32 module yet wrtiting here too because I almost exhausted all my options in FreeRTOS and core config (sdkconfig) AND because I can reproduce the issue on a genuine UNO board which makes me believe it's an Arduino thing.

My code is super simple:

void setup() {
  Serial.begin(115200);
  pinMode(5, OUTPUT);
}
    

void loop() {
  digitalWrite(5, 1);
  digitalWrite(5, 0);
  }

Bitbanging on pin 5 to achieve approximately 50% duty cycle PWM. So looking at it on the oscilloscope it's really odd that every millisecond there is a halt in state-changing that lasts about 7 us. At 4 MHz this is very noticable and hinders my project.

The code I'm going to be using in my project is more complicated but it doesn't affect the issue, I tried by taking chunks off - no difference. Also tried direct write and many other things. Keep in mind that the issue comes up on both genuine Arduino boards and ESP32 ones (tested on two new)..
FOn ESP32 it goes away when using ledc HW PWM and on UNO noInterrupts() solves the issue. So I'm guessing the ledc HW PWM (ESP32) is not affected by the software on top and on UNO noInterrupts() does something that results in no disturbances in code execution.
vTaskEnterCritical() (disables interrupts and scheduler on ESP32) does reduce the number of halts in created tasks but it doesn't eliminate them. Has almost no effect in loopTask. noInterrupts() is defined as vTaskEnterCritical() on ESP32.
Core pinning has no effect either.

What I haven't tried (on it as I'm wriring this) is unicore on ESP32 and making my code an ISR. Oh and ditching the Arduino environtment altogether.

So any idea what it might be? What happens every millisecond and is not processor specific?

Someone else also observed this.

I understand this is solvable on Arduino but for the sake of research, what is it?
Sorry if I was unclear anywhere, thank you for your time in advance :slight_smile:

"Every millisecond" is coherent with Timer0 overflow, so try to disable all interrupts (not recommended) or just the overflow one:

TIMSK0 &= ~_BV(TOIE0);

Please note that this will break "millis()" and "delay()".

It may be part of the case on the UNO, will check tomorrow when I have access to oscilloscope.

However ESP32 has 4 generic 64 bit timers ticking at 80 MHz with 16 bit prescalers. Overflow nowhere near a millisecond.

Is the ESP32 taking a break to check on the WiFi situation?

...R

Everything runs on core 0 and loopTask is thus pinned to core 1. So on core 1 it's bassically loopTask with preemptive scheduler and interrupts able to interfere.
Tried disabling them by putting my code in a new highest priority task and using vTaskEnterCritical() (critical section implementation - scroll to critical sections) which is ESP32 equivalent to cli() and functions as link describes. Moved loopTask to core 0 so core 1 was idle all the time and created the new task there. Nope. Still no.

Also no WiFi situation on UNO.

nkukenberger:
Also no WiFi situation on UNO.

Apologies - I misread and thought the problem was on your ESP32.

If 7 µsecs matters then you might be better with the digitalWriteFast library or port manipulation

...R

Thank you for your input!

Yes, in project code I'm doing port manipulation. Every cycle counts as I'm trying to determine maximum
state switching frequency and implement it into software PDM signal generation (mainly sine and cosine).

If you want a waveform generator, use the timer hardware. At least on the Arduino UNO you can generate pulse trains with three different frequencies (up to 8 MHz for square waves) on six different pins, each with a different duty cycle. The frequency and duty cycle will not be effected by interrupts.

Sigma - Delta PWM / PDM

https://hackaday.io/project/6356-delta-sigma-versus-pwm (not mine)

Thanks for the tip, but I already looked into that and it doesn't suffice my needs.
PDM, also called sigma-delta PWM, requires seamless frequency/pulse leght modulation for virtually every state change eg.:
HIGH state lasts 60 ns,
following LOW state lasts 60 ns,
then HIGH 120 ns,
LOW 60 ns,
HIGH 180 ns,
LOW 60,
HIGH 240,
LOW 60 and so on..
This is an approximate example of ramping up the duty cycle from say 50% to 80% by increasing the number of consecutive HIGH states. Notice that it's different from PWM in period lenght/frequency which is variable (PDM) vs fixed (PWM).

I don't think changing fixed frequency duty cycles on a HW PWM is faster. Also PDM is more accurate in the sense that it can reproduce every duty cycle and every period length, though that is usually not the case since it only uses the minimum number of states needed to achieve the desired duty cycle.

PDM basically tries to match the area under a curve by accounting for accumulated (integrated) error every state change (summation of deltas).

With this form of modulation I can achieve state changes at approximately 5 MHz and possibly more when I optimise my code, with seamlessly variable duty cycles. (on an ESP32, 240 MHz chip)
I feed one period of discrete sine values (or any other periodic function) into PCM to Sigma Delta conversion algorithm, store the resulting bitstream in an array and then with it control state switching.

Anyhow I solved my problem. It was indeed the Arduino on top of the FreeRTOS that was problematic.
Still don't know what exactly it could be. Regrettably I can't afford to look deeper into it since I'm very time pressed right now. Hopefully this can help anyone with similar problems.