Hello there,
I'm struggling to port a PWM-based WS2812 LED driver (viewtopic.php?f=8&t=2601&start=10, https://github.com/joewa/WS2812-LED-Driver_ChibiOS) to STM32H750.
Data line is on Port D12 with AF2, I use timer 4, channel 0 (1 in data sheet. DMA stream is set to DMA_ID_ANY, the channel is not set, instead I call dmaSetRequestSource(STM32_DMAMUX1_TIM4_UP). PWM frequency is set to STM32_TIMCLK1.
I'm able to set a color to the WS2812 led once, when there's no sleep between ws2812_init() and ws2812_write_led(). Multiple calls to ws2812_write_led do not change the color; it seems that new color values are not correctly DMA'd to TIM4->CCR[0], but the DMA transmission complete callback (TCIE) is triggered regularly. The transmission error interrupt (TEIE, DMEIE) is not called.
ChibiOS checks and assertions are enabled.
The modified driver code is attached.
Thanks for your help.
WS2812 driver with STM32H7, DMA and PWM
Moderators: RoccoMarco, barthess
- stertingen
- Posts: 21
- Joined: Mon Jan 13, 2020 10:55 pm
- Has thanked: 7 times
- Been thanked: 7 times
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: WS2812 driver with STM32H7, DMA and PWM
Hi,
I cannot go into details of your code but you should consider that TIM4 has a 16 bits counter, it cannot count up to 800000 (am I reading it right?).
Giovanni
I cannot go into details of your code but you should consider that TIM4 has a 16 bits counter, it cannot count up to 800000 (am I reading it right?).
Giovanni
- stertingen
- Posts: 21
- Joined: Mon Jan 13, 2020 10:55 pm
- Has thanked: 7 times
- Been thanked: 7 times
Re: WS2812 driver with STM32H7, DMA and PWM
Giovanni wrote:Hi,
I cannot go into details of your code but you should consider that TIM4 has a 16 bits counter, it cannot count up to 800000 (am I reading it right?).
Giovanni
It does not need to. The period currently is 250 timer ticks. (STM32_TIMCLK1 / 800000). Also the PWM signal itself seems to work correctly; the PWM signals for the first frame buffer run are emitted correctly.
New signals written into the frame buffer later do not have an effect on the WS2812 LED. (Due to the lack of an oscilloscope in quarantaine, I'm unable to verify the PWM signal.)
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: WS2812 driver with STM32H7, DMA and PWM
I am prisoner as well... no instrumentation at home.
Giovanni
Giovanni
Re: WS2812 driver with STM32H7, DMA and PWM
I have written code for WS2812 driving.....
I start a timer to go around at 3*800kHz. Then at wraparound/reset, I trigger a DMA to the output port from a memory location where I've stored: "a one" (all ones binary). The DMA controller is configured to not increment the memory address. So max 32bits required. Then at 1/3 of the max value, I trigger a second DMA channel. This one holds the data. And then at 2/3rd another non-incrementing DMA happens that finishes the WS2812 bit with a zero.
You can do 8 WS2812 strings at once. this way with an 8-bit DMA to 8 bits of an IO port. Or you can do 16 strings.
If you need only one, the memory area where you store the data becomes a bit sparse. Anyway, then the "one" DMA needs to have only the data-bit that is involved set. And you DMA to the port-set-register. The zero does something similar but with the reset register. For the data, I think you'll have to invert the data and use the port-reset register. (the output will always be high when the data is supposed to come... )
read-modifiy-write of the port data register becomes "forbidden". That will give odd effects.
If you have just a few leds that you need to give new data a few times per second... It pays to just write it yourself.
Add a ws_delay, maybe better use a macro. for (j=0;j<15;j++) __asm__ ("nop"); will probably be about right (for a 216MHz clock).
I start a timer to go around at 3*800kHz. Then at wraparound/reset, I trigger a DMA to the output port from a memory location where I've stored: "a one" (all ones binary). The DMA controller is configured to not increment the memory address. So max 32bits required. Then at 1/3 of the max value, I trigger a second DMA channel. This one holds the data. And then at 2/3rd another non-incrementing DMA happens that finishes the WS2812 bit with a zero.
You can do 8 WS2812 strings at once. this way with an 8-bit DMA to 8 bits of an IO port. Or you can do 16 strings.
If you need only one, the memory area where you store the data becomes a bit sparse. Anyway, then the "one" DMA needs to have only the data-bit that is involved set. And you DMA to the port-set-register. The zero does something similar but with the reset register. For the data, I think you'll have to invert the data and use the port-reset register. (the output will always be high when the data is supposed to come... )
read-modifiy-write of the port data register becomes "forbidden". That will give odd effects.
If you have just a few leds that you need to give new data a few times per second... It pays to just write it yourself.
Code: Select all
for (i=0;i<24;i++) {
palSetPad (MYPORT, MYBIT);
ws_delay();
palWritePad (MYPORT, MYBIT, data&0x1);
data >>= 1;
ws_delay ();
palClearPad (MYPORT, MYBIT);
ws_delay ();
}
Add a ws_delay, maybe better use a macro. for (j=0;j<15;j++) __asm__ ("nop"); will probably be about right (for a 216MHz clock).
- stertingen
- Posts: 21
- Joined: Mon Jan 13, 2020 10:55 pm
- Has thanked: 7 times
- Been thanked: 7 times
Re: WS2812 driver with STM32H7, DMA and PWM
rew wrote:I have written code for WS2812 driving.....
I start a timer to go around at 3*800kHz. Then at wraparound/reset, I trigger a DMA to the output port from a memory location where I've stored: "a one" (all ones binary). The DMA controller is configured to not increment the memory address. So max 32bits required. Then at 1/3 of the max value, I trigger a second DMA channel. This one holds the data. And then at 2/3rd another non-incrementing DMA happens that finishes the WS2812 bit with a zero.
You can do 8 WS2812 strings at once. this way with an 8-bit DMA to 8 bits of an IO port. Or you can do 16 strings.
If you need only one, the memory area where you store the data becomes a bit sparse. Anyway, then the "one" DMA needs to have only the data-bit that is involved set. And you DMA to the port-set-register. The zero does something similar but with the reset register. For the data, I think you'll have to invert the data and use the port-reset register. (the output will always be high when the data is supposed to come... )
read-modifiy-write of the port data register becomes "forbidden". That will give odd effects.
If you have just a few leds that you need to give new data a few times per second... It pays to just write it yourself.Code: Select all
for (i=0;i<24;i++) {
palSetPad (MYPORT, MYBIT);
ws_delay();
palWritePad (MYPORT, MYBIT, data&0x1);
data >>= 1;
ws_delay ();
palClearPad (MYPORT, MYBIT);
ws_delay ();
}
Add a ws_delay, maybe better use a macro. for (j=0;j<15;j++) __asm__ ("nop"); will probably be about right (for a 216MHz clock).
I'll try that, thanks. Do you have a code example?
- stertingen
- Posts: 21
- Joined: Mon Jan 13, 2020 10:55 pm
- Has thanked: 7 times
- Been thanked: 7 times
Re: WS2812 driver with STM32H7, DMA and PWM
I managed to get it working by adding a ws2812_flush() function.
In this function all DMA interrupts are cleared using dmaStreamClearInterrupt() and a new DMA transaction is startet using dmaStreamEnable().
The STM32_DMA_CR_CIRC flag was removed from dmaStreamSetMode().
In this function all DMA interrupts are cleared using dmaStreamClearInterrupt() and a new DMA transaction is startet using dmaStreamEnable().
The STM32_DMA_CR_CIRC flag was removed from dmaStreamSetMode().
- Attachments
-
- ws2812.zip
- (6.58 KiB) Downloaded 244 times
- stertingen
- Posts: 21
- Joined: Mon Jan 13, 2020 10:55 pm
- Has thanked: 7 times
- Been thanked: 7 times
Re: WS2812 driver with STM32H7, DMA and PWM
Looks like the fault was at the WS2812B LED. The driver I used was suitable for revision v3 and prior; the manufacturer changed in revision v4 and later the needed reset time between two frames from 50us to 280us.
Adding the flush function worked because I called it every 1ms; now I've added a few reset frames.
Adding the flush function worked because I called it every 1ms; now I've added a few reset frames.
Re: WS2812 driver with STM32H7, DMA and PWM
stertingen wrote:Looks like the fault was at the WS2812B LED. The driver I used was suitable for revision v3 and prior; the manufacturer changed in revision v4 and later the needed reset time between two frames from 50us to 280us.
Adding the flush function worked because I called it every 1ms; now I've added a few reset frames.
Hi,
with the code on my STM32H750 cpu i only see 8 bits transmitted.
Did you experimented similar problem?
Thanks
Who is online
Users browsing this forum: No registered users and 55 guests