I'm trying to use the ESP32's SPI peripheral to drive a chain of LED matrices dynamically.
The LED matrices have a shift register for the vertical and horizontal control lines, so the cycle is basically:
1. Shift out (row length/2) bits on QIO0 and QIO1 with the bitmap data, while also in QIO2 setting the bits at positions (bit_num % row_number) to 1 to enable the correct row.
2. Stop the clock and momentarily change the LATCH pin state from 1 to 0 then back.
3. Continue with the next row
What I currently do on every frame (at roughly 60 Hz) is queue 17 transactions by DMA (one for each row + one dummy so that the bottom row isn't brighter than the rest due to waiting for the next frame to come). Then in the `post_cb` ISR I do the LATCH change.
The final code is here inside the project: https://github.com/vladkorotnev/plasma- ... i_k875.cpp
However, because of the many other tasks running on the ESP, the timing of this process drifts significantly. Eventually some rows start blinking brighter than the others at random because there is some task that has to be taken care of between the post_cb happens and the next transaction starts.
So I thought to use low-level SPI and circular linked lists similar to that one VGA output project, to never have to bother with the callback and enqueueing the transactions again. For that I would wire the LATCH pin to the currently unused QIO3, and clear that bit in the data array between frames when I need to latch the row.
However even before implementing the circular linked list solution, just trying this approach with the normal SPI and the whole screen in a single transaction, resulted in "noise" next to the active pixels. You can see those are not perfect diagonal lines but have some "jitter".
This seems to be because of the clock signal being still active while the LATCH change is happening with this approach — because the shift register continues to shift even though there is no data being fed and latch is active.
So my question is, can I pause the clock of the SPI easily for just one bus cycle?
P.S. Now that I think of it, maybe a good solution would be to use the clock-on-CS configuration, and send that one single bus cycle to a different dummy device, so that the shift register doesn't see the clock signal. But I'm not sure if it's possible to do multiple devices in a single transaction, neither whether that is doable with the clock-on-CS flag set.
Pause SPI clock momentarily while using DMA
-
- Posts: 15
- Joined: Tue Oct 08, 2024 9:11 am
- Location: Sapporo, Japan
-
- Posts: 1734
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: Pause SPI clock momentarily while using DMA
Can you use QIO3 for the latch signal?
Or the CS signal?
Or the CS signal?
-
- Posts: 200
- Joined: Sun Jun 23, 2024 6:18 pm
Re: Pause SPI clock momentarily while using DMA
You can add a dummy DMA descriptor at the end of each frame with no output data to allow a pause in the cycle.
-
- Posts: 15
- Joined: Tue Oct 08, 2024 9:11 am
- Location: Sapporo, Japan
Re: Pause SPI clock momentarily while using DMA
MicroController
The picture above with the offset and noise is actually from when using QIO3 for the latch signal.
As for the CS... good catch, I don't know why I didn't do that — judging by the `SPI_DEVICE_POSITIVE_CS` flag already in the configuration I tried it at some point and then for some reason removed it. I've put it back and now I don't need the `post_cb` anymore it seems, everything works as it was before — the flicker is still there, but less noticeable.
aliarifat794
Given the above changes now I wonder, would adding a dummy DMA descriptor cause the CS line to disengage while the pause is ongoing?
Also is there some easier example about how to set up low level circular DMA for SPI? The VGA code is somewhat hard to follow for someone with zero experience in programming on such a low level for the ESP.
The picture above with the offset and noise is actually from when using QIO3 for the latch signal.
As for the CS... good catch, I don't know why I didn't do that — judging by the `SPI_DEVICE_POSITIVE_CS` flag already in the configuration I tried it at some point and then for some reason removed it. I've put it back and now I don't need the `post_cb` anymore it seems, everything works as it was before — the flicker is still there, but less noticeable.
aliarifat794
Given the above changes now I wonder, would adding a dummy DMA descriptor cause the CS line to disengage while the pause is ongoing?
Also is there some easier example about how to set up low level circular DMA for SPI? The VGA code is somewhat hard to follow for someone with zero experience in programming on such a low level for the ESP.
-
- Posts: 15
- Joined: Tue Oct 08, 2024 9:11 am
- Location: Sapporo, Japan
Re: Pause SPI clock momentarily while using DMA
OK, so I have tried to copy the VGA example and adapt it for QIO like this:
https://github.com/vladkorotnev/plasma- ... #L149-L342
However, I don't see any activity on the display bus now whatsoever.
Is there something that has changed in the register assignment since the VGA example was posted?
https://github.com/vladkorotnev/plasma- ... #L149-L342
However, I don't see any activity on the display bus now whatsoever.
Is there something that has changed in the register assignment since the VGA example was posted?
-
- Posts: 15
- Joined: Tue Oct 08, 2024 9:11 am
- Location: Sapporo, Japan
Re: Pause SPI clock momentarily while using DMA
After changing it to this, it can finally do the DMA without taking up CPU:
https://github.com/vladkorotnev/plasma- ... i_k875.cpp
However, the CS line stays idle, so I have to generate my own latch signal (not very successfully, the picture slides across like an old broken TV).
Is there some way to mark the virtual end of transaction in the lldesc_s so that it bumps the CS line for a bit?
https://github.com/vladkorotnev/plasma- ... i_k875.cpp
However, the CS line stays idle, so I have to generate my own latch signal (not very successfully, the picture slides across like an old broken TV).
Is there some way to mark the virtual end of transaction in the lldesc_s so that it bumps the CS line for a bit?
-
- Posts: 15
- Joined: Tue Oct 08, 2024 9:11 am
- Location: Sapporo, Japan
[SOLVED] Pause SPI clock momentarily while using DMA
I have managed to solve it by cleverly using the already-sacrificed GPIO pin, putting the LATCH signal in the data as suggested above, and the MCPWM peripheral.
Basically I can set the MCPWM module to produce a 100% duty cycle, thus a constant logic HIGH.
Then it has emergency stop inputs, which I can configure to send the output LOW when any of those go LOW.
So I use the pin mux to connect the MCPWM inputs to the SPI outputs, and then connect the MCPWM output to where I need my clock signal.
And presto, aside from some flicker due to concurrent writing while DMA is reading, this is fully working dynamic refresh of a shift-register based display without making the CPU busy. I think I've read someone on this forum saying the original ESP32 is too slow for being a display driver without an external controller and with letting the CPU do something useful aside from driving the display. Guess I've proved them wrong!
The absolutely deranged source code with extensive comments is here: https://github.com/vladkorotnev/plasma- ... #L233-L320
Hope you find this exercise amusing or interesting. On my side, I'll go get a beer and question what am I doing with my life...
Basically I can set the MCPWM module to produce a 100% duty cycle, thus a constant logic HIGH.
Then it has emergency stop inputs, which I can configure to send the output LOW when any of those go LOW.
So I use the pin mux to connect the MCPWM inputs to the SPI outputs, and then connect the MCPWM output to where I need my clock signal.
And presto, aside from some flicker due to concurrent writing while DMA is reading, this is fully working dynamic refresh of a shift-register based display without making the CPU busy. I think I've read someone on this forum saying the original ESP32 is too slow for being a display driver without an external controller and with letting the CPU do something useful aside from driving the display. Guess I've proved them wrong!
The absolutely deranged source code with extensive comments is here: https://github.com/vladkorotnev/plasma- ... #L233-L320
Hope you find this exercise amusing or interesting. On my side, I'll go get a beer and question what am I doing with my life...
-
- Posts: 1734
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: Pause SPI clock momentarily while using DMA
Code: Select all
// ... I'm too lazy and cheap to use a whole package for just 2 transistors worth of stuff.
// And I'm even lazier to use just 2 transistors, because ...
// Thus we have just created an AND gate out of the MCPWM unit!
Who is online
Users browsing this forum: No registered users and 32 guests