Amount of jitter on LEVEL3 interrupt?
Posted: Fri Sep 04, 2020 9:48 am
Hi,
I'm doing a fairly standard thing of using the RMT interface to control LEDs. You have a simple test program that does the same, there are multiple libraries.
However, I've also got a very simple web server, and accepting TCP requests. That code is also part of your standard distribution, and not being hit very hard. Like, having a few browser windows. The REST requests coming in are not serving flash objects, they are simply returning time values using a REST interface.
The timing required to control 800Khz WS8211 with a single RMT buffer is about 35us. That's the amount of time using the double-buffer technique - the interrupt handler has to be called every 35us, and can tolerate about 10 to 20us of jitter. This is running at the highest priority that will accept C code ( even though the function itself is not doing anything other than math from pointers ).
I am finding with this simple use case that there is often (a few times a minute) 40 to 50us of jitter in this interrupt, on either core. I can only imagine it's the wifi interrupt, because that's all that's happening in the system. This is enough to cause the RMT driver to run dry, which creates visual artifcats.
In this case, I would prefer to drop the IP packet. Having glitchy LEDs is bad, and TCP is a protocol that accepts retransmits ( and wifi is lossy anyway ).
The test case is very simple, because it uses three different documented ESP-IDF interfaces ( HTTP server, Wifi module, RMT test code ). It can even be observed without LEDs, because one can measure the jitter.
The questions:
* Do you expect jitter amounts in the 40 to 50us range on an IRAM_ADDR LEVEL3 interrupt, just for a two-line response to a HTTP rest request ( like 404 not found )? Or should this be considered a bug? The test case is not hard to reproduce.
* Is there a way to decrease the priority of WIFI interrupts? I have crawled through the code for a few hours and couldn't find anything obvious. I found a very old forum post where someone said they needed to do that in a similar case, but reading everywhere I haven't found where the priority levels for the different Wifi interrupts are held. A great feature would be a CONFIG for higher and lower priority wifi.
I have two other paths.
One is to use more RMT buffer space, reducing the number of channels to 4, which given the measurements I have, might solve the problem with little code. However, I will never be sure of a larger delay coming and creating a glitch, because any number of people could put a web browser at the control interface. There is a limit on the number of TCP connections, so perhaps the problem won't be bad. In this particular application I am only controlling 500-ish LEDs thus can still run good frame rates with 4 pins.
The second is to write an assembly language shim and raise the priority level of the interrupt code which translates the RGB values to RMT's format. Since the code literally does nothing other than pointers and copies it is very safe. I wish there was an easy way to notate that a particular bit of code is safe, instead of having to actually write in assembly language, but I think you have an example of calling C from assembly (which carefully states in the comments that particular C call is safe) so I can make a shim without having to literally code the logic in assembly.
In the case of raising the priority, the documentation implies I must not use the usual routine of using a xSemaphoreGiveFromISR to wake the task. Is there a safe way of signaling a task from a high priority interrupt (say, 5). I have some other ways to check completion, like using combination of a timer and a shared memory address, but if there is a better way using the scheduling system it would be nice to know.
I wonder if you could also give an opinion on which of these is more likely to succeed.
Thank you.
I'm doing a fairly standard thing of using the RMT interface to control LEDs. You have a simple test program that does the same, there are multiple libraries.
However, I've also got a very simple web server, and accepting TCP requests. That code is also part of your standard distribution, and not being hit very hard. Like, having a few browser windows. The REST requests coming in are not serving flash objects, they are simply returning time values using a REST interface.
The timing required to control 800Khz WS8211 with a single RMT buffer is about 35us. That's the amount of time using the double-buffer technique - the interrupt handler has to be called every 35us, and can tolerate about 10 to 20us of jitter. This is running at the highest priority that will accept C code ( even though the function itself is not doing anything other than math from pointers ).
I am finding with this simple use case that there is often (a few times a minute) 40 to 50us of jitter in this interrupt, on either core. I can only imagine it's the wifi interrupt, because that's all that's happening in the system. This is enough to cause the RMT driver to run dry, which creates visual artifcats.
In this case, I would prefer to drop the IP packet. Having glitchy LEDs is bad, and TCP is a protocol that accepts retransmits ( and wifi is lossy anyway ).
The test case is very simple, because it uses three different documented ESP-IDF interfaces ( HTTP server, Wifi module, RMT test code ). It can even be observed without LEDs, because one can measure the jitter.
The questions:
* Do you expect jitter amounts in the 40 to 50us range on an IRAM_ADDR LEVEL3 interrupt, just for a two-line response to a HTTP rest request ( like 404 not found )? Or should this be considered a bug? The test case is not hard to reproduce.
* Is there a way to decrease the priority of WIFI interrupts? I have crawled through the code for a few hours and couldn't find anything obvious. I found a very old forum post where someone said they needed to do that in a similar case, but reading everywhere I haven't found where the priority levels for the different Wifi interrupts are held. A great feature would be a CONFIG for higher and lower priority wifi.
I have two other paths.
One is to use more RMT buffer space, reducing the number of channels to 4, which given the measurements I have, might solve the problem with little code. However, I will never be sure of a larger delay coming and creating a glitch, because any number of people could put a web browser at the control interface. There is a limit on the number of TCP connections, so perhaps the problem won't be bad. In this particular application I am only controlling 500-ish LEDs thus can still run good frame rates with 4 pins.
The second is to write an assembly language shim and raise the priority level of the interrupt code which translates the RGB values to RMT's format. Since the code literally does nothing other than pointers and copies it is very safe. I wish there was an easy way to notate that a particular bit of code is safe, instead of having to actually write in assembly language, but I think you have an example of calling C from assembly (which carefully states in the comments that particular C call is safe) so I can make a shim without having to literally code the logic in assembly.
In the case of raising the priority, the documentation implies I must not use the usual routine of using a xSemaphoreGiveFromISR to wake the task. Is there a safe way of signaling a task from a high priority interrupt (say, 5). I have some other ways to check completion, like using combination of a timer and a shared memory address, but if there is a better way using the scheduling system it would be nice to know.
I wonder if you could also give an opinion on which of these is more likely to succeed.
Thank you.