cancel
Showing results for 
Search instead for 
Did you mean: 

Problems controlling SK6812RGBW/Neopixel with STM32H7

gcoard
Associate II

I'm trying to control a strip of 9 SK6812RGBW LED's with an STM32H757XIH6 microcontroller. I've been through a couple of tutorials on how to use DMA to control the PWM, and I've gone with this tutorial as a base.

I've read a few threads on the forum but haven't managed to find any solutions from them.

I'm fairly new to this level of microcontroller programming with timers, DMA, etc.

These are the timings for SK6812RBGW:

D0NY9Y4E.png

The clock is configured as so:

DdYGKqA4.png

The APB1 Timer clock is at 240mhz

I'm using TIM3 configured as shown:

ezGxRbvI.pngJrMbHt2C.png9nyWWzmK.png

Now I've tried a few different configs of the DMA stream, currently I'm trying with half word as TIM3 is a 16 bit timer.

The LED strip is connected to PC7 via a 1.3kohm pullup resistor to 5V.

Here's the code I'm using, mostly following the digikey tutorial code:

 

/*
 * led.h
 *
 *  Created on: Jan 27, 2025
 *      Author: Graeme
 */

#ifndef APPLICATION_USER_CORE_DASH_APP_LED_LED_H_
#define APPLICATION_USER_CORE_DASH_APP_LED_LED_H_

#include "header.h"
#include "tim.h"

#define NEOPIXEL_ZERO 72
#define NEOPIXEL_ONE 144

#define NUM_PIXELS 9
#define DMA_BUFF_SIZE (NUM_PIXELS * 32) + 64

typedef union
{
  struct
  {
    uint8_t w;
    uint8_t b; //switch coz some reason
    uint8_t g;
    uint8_t r;
  } color;
  uint32_t data;
} PixelRGBW_t;

extern void led_test();

#endif /* APPLICATION_USER_CORE_DASH_APP_LED_LED_H_ */
/*
 * led.c
 *
 *  Created on: Jan 27, 2025
 *      Author: Graeme
 */

#include "led.h"

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
    //HAL_TIM_PWM_Stop_DMA(htim, TIM_CHANNEL_2);
}

void led_test() {

    PixelRGBW_t pixel[NUM_PIXELS] = { 0 };
    uint32_t dmaBuffer[DMA_BUFF_SIZE]__attribute__((aligned(4))) = { 0 };
    uint32_t *pBuff;



    for (int i = 0; i < NUM_PIXELS; i++) {
        pixel[i].color.r = 3;
        pixel[i].color.g = 7;
        pixel[i].color.b = 15;
        pixel[i].color.w = 31;
    }

    pBuff = dmaBuffer;
    for (int i = 0; i < NUM_PIXELS; i++) {
        for (int j = 31; j >= 0; j--) {
            if ((pixel[i].data >> j) & 0x01) {
                *pBuff = NEOPIXEL_ONE;
            } else {
                *pBuff = NEOPIXEL_ZERO;
            }
            pBuff++;
        }
    }


    for (int i = 0; i < 64; i++) {
        dmaBuffer[DMA_BUFF_SIZE - 65 + i] = 0;
    }

//      dmaBuffer[DMA_BUFF_SIZE - 1] = 0; // last element must be 0!

        HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_2, dmaBuffer, DMA_BUFF_SIZE);
        //HAL_Delay(10);
        //HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_2);


}

 

(I have commented out the DMA_Stop as I was trying to use circular mode (??))

When ran, the LED's illuminate, but randomly, and random colors.

Inspecting the dmaBuffer shows the bits in the correct positions for the SK6812RGBW encoding:

FxjhyAVo.png19SKQ6A3.png

I have some confusion around the ARR setting and the CCR values, as they don't seem to line up with what should and shouldn't work. With ARR set to 299, CCR for high of 144 and CCR for low of 72, my output data seems to run at 400Khz with a period of 2.5us (should be 800mhz, 1.25us). But, the bit timings are correct at around 0.6us and 0.3us respectively. When ARR set at 149, CCR high 72 and low 36, the data runs at 800Khz and 1.25 period, but the bit timings are looking like half of what they should be.

Keeping in mind I'm using a cheap handheld scope.

Either way, the LED's seem to light up randomly, which seems odd. Shouldn't they only work on one set of timings? They don't flicker or anything. They change on reset.

The other confusion is setting of of DMA, FIFO, Normal/Circular, memory length etc.

Any ideas? Let me know if I can provide any more info

Thanks

1 ACCEPTED SOLUTION

Accepted Solutions
gbm
Lead III

Actually few ideas:

1. Why don't you use UART or SPI instead of a timer?

2. You are sending 16 bit PWM duty values (correct) but your PWM data table is 32-bit -> clearly an error.

3. Your data table occupies over 1200 bytes of stack space - not really a good idea.

4. Once you start the DMA transfer, you data table disapears/gets destroyed while the DMA continues. Declare the table as static!!!

5. Check the timer clock frequency shown by CubeMX in clock config tab; look at the for TIMER CLOCK boxes, not primary ABP clock.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

View solution in original post

3 REPLIES 3
gbm
Lead III

Actually few ideas:

1. Why don't you use UART or SPI instead of a timer?

2. You are sending 16 bit PWM duty values (correct) but your PWM data table is 32-bit -> clearly an error.

3. Your data table occupies over 1200 bytes of stack space - not really a good idea.

4. Once you start the DMA transfer, you data table disapears/gets destroyed while the DMA continues. Declare the table as static!!!

5. Check the timer clock frequency shown by CubeMX in clock config tab; look at the for TIMER CLOCK boxes, not primary ABP clock.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

@gbm wrote:

1. Why don't you use UART or SPI instead of a timer?


+1

 

PS:

Rather than think of it as PWM, I think you should be able to use DMA direct to the GPIO to generate the required output pattern.

But I've not tried this myself.

 

Also, note that there are versions of these "smart" LEDs which work on proper SPI - so no need to mess about with bit-banging the critical timing:

https://community.st.com/t5/others-hardware-and-software/background-function/m-p/761089/highlight/true#M30453

 

PPS:

Interesting article on what's really critical in the timing - and what isn't:

https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/

 

#NeoPixel #DotStar #W2812B #W2812 #SK6812 #SK9822 #APA102C

gcoard
Associate II

Yeah, it was both the 32-bit buffer and the buffer not being static that was my problem (I think), so thanks for pointing those out. 

I also had to increase the PWM timings a little bit, not sure if this is due to the pullup resistor or some other factor.

I would be interested in using SPI as it does seem like a viable option, especially if I had more led's for mempry saving. This is just a hobby thing though.

 

Thanks for your help!