-
Notifications
You must be signed in to change notification settings - Fork 13.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PWM is blocked during SPIFFS write operations #5568
Comments
This looks like it is caused by PWM going from NMI to a regular IRQ, and SPIFFS having interrupts disabled for a very long time. @Gei0r, could you replace the following function in cores/esp8266/core_esp8266_timer.c and capture your waveform again? I don't have my logic analyzer hooked up presently so can't try it myself. It simply replaces the maskable IRQ with a non-maskable one.
|
@devyte LittleFS shows the behavior on every write: |
@earlephilhower Your code snippet works: Although I'm worried that using the NMI for timer interrupts might cause problems with other functions/libraries. It would probably be better to investigate whether the long interrupt locks can't be removed or at least split up in the FS libraries. |
I think you're seeing the IRQs disabled for an erase. 8 writes = 1 4K sector on SPIFFS, and on LittleFS a sector itself is 4K so every write you need to erase and write. Erases on flash are slow (esp. on the cheapest of cheap flash found on these devices). PWM used to be done in an NMI, but I went back to a regular IRQ when I redid it to be tickless and shared w/tone/servo/etc. Let me do a PR for this and some testing. It shouldn't affect anything, but it's better safe than sorry. |
OK, but what's the reason that (maskable) interrupts need to be disabled during a flash erase? |
That's a very good question, @Gei0r! I don't have a good answer, but the @igrr, @devyte, @d-a-v, any ideas? The least intrusive change is to make PWM NMI, but the best logical change would be to remove the IRQ disabling around spi_* operations in |
IIRC this was done because ISRs were not placed into IRAM, initially. Seems like ISRs are in IRAM now, so we can try removing those locks. The other consideration about keeping timer at NMI level is that other interrupts (e.g. Wi-Fi) may be running for significant enough time to prevent timer ISR from running (if both are level 1 interrupts). |
Thanks, @igrr! I was thinking the same thing. I'll split this into two PRs, one removing the IRQ disabling from the ESP.flash* wrappers and another for the tickless waveform generator->NMI. |
All interrupt service routines are supposed to be in IRAM now, so there is no need to keep interrupts disabled while doing flash operations. Remove the IRQ disable/enable from the ESP.flash* methods. Related to esp8266#5568
Make the waveform generator an NMI using the same code as in 2.4.0. Making it NMI will ensure it runs even when interrupts are disabled. Fixes esp8266#5568
@Gei0r, can you try PR #5578 ? The NMI change I mentioned above in this thread is actually not safe (but may work if only one PWM is in use and it's not updated frequently). The PR is a new one with a safe-by-design configuration and should actually give you somewhat better accuracy at low periods and few active PWM pins. |
Amazing work @earlephilhower ! And the example works as well: Thanks a lot! |
All interrupt service routines are supposed to be in IRAM now, so there is no need to keep interrupts disabled while doing flash operations. Remove the IRQ disable/enable from the ESP.flash* methods. Related to #5568
* Make waveform generator a NMI to run always Make the waveform generator an NMI using the same code as in 2.4.0. Making it NMI will ensure it runs even when interrupts are disabled. Fixes #5568 * Move to a lockless waveform generator Make the waveform generator lockless by doing all dangerous structure updates in the interrupt handler. start/stopWaveform set a flag and cause an interrupt. They wait for the interrupt to complete and clear those flags before returning. Also rework the Waveform[] array to be lockless. * Optimize IRAM and CPU usage in IRQ Try and minimize the IRAM needed to run the IRQ while keeping performance at or better than before. * Avoid WDT errors, optimize pin scans Calculate first and last pins to scan for PWM, significantly increasing accuracy for pulses under 10us at 80MHz. Now if you are using a single PWM channel at 80MHz you can generate a 1.125us pulse (down from ~4us). Rework the IRQ logic to avoid potential WDT errors. When at 80MHz it appears that interrupts occuring faster than 10us apart on the timer cause WDT errors. Avoid it by increasing the minimum delay between IRQs on the timer accordingly. * Clean up format/comment, remove delay() in stop stopWaveform may be called from an interrupt (it's called by digitalWrite) so we can't call delay(). Make it a busy wait for the IRQ to clear the waveform. Only set a new timeout of 10us when starting a new waveform when there is no other event coming sooner than that. Update formatting and comments per @devyte's requests. Replace MicrosecondsToCycles() with standard Arduino call.
The same thing happens with the ESP32. Is there any solution? |
Basic Infos
Platform
Settings in IDE
(removed rest because it's not a flashing problem)
Problem Description
The ESP8266 does not have hardware support for PWM, so the Arduino Core implements PWM in software with timer interrupts.
However, these PWM interrupts seem to be blocked by some SPIFFS write operations. In the picture below, every yellow spike shows the start of a small write operation. The green channel shows a PWM at 500 Hz.
As you can see, every 16th or so write operation takes a lot longer than the other ones (about 110 ms), and disturbs the PWM output.
I understand that SPIFFS is not realtime capable and it is unavoidable that some write operations take longer than others. But maybe the SPIFFS code can be changed so that the PWM is not affected by that?
MCVE Sketch
Debug Messages
(see image)
The text was updated successfully, but these errors were encountered: