cancel
Showing results for 
Search instead for 
Did you mean: 

PWM + DMA not changing the color of WS2812B LED strip

Beartama
Associate II

I have the following code trying to turn 5 pixels of the LED strip to red. The setup I have is the LED strip is connected to PC6.

#include <stdint.h>
// STM32F103C8 is a medium density device, hence we use the xB header
#include <stm32f103xb.h>

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning                                                                       \
    "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

void enable_clock() {
  RCC->CR |= RCC_CR_HSION;
  while ((RCC->CR & RCC_CR_HSIRDY) == 0);
}

// @formatter:off
#define HI 6
#define LO 3
uint32_t buffer[] = {
  LO, LO, LO, LO, LO, LO, LO, LO,
  HI, HI, HI, HI, HI, HI, HI, HI,
  LO, LO, LO, LO, LO, LO, LO, LO,
  LO, LO, LO, LO, LO, LO, LO, LO,
  HI, HI, HI, HI, HI, HI, HI, HI,
  LO, LO, LO, LO, LO, LO, LO, LO,
  LO, LO, LO, LO, LO, LO, LO, LO,
  HI, HI, HI, HI, HI, HI, HI, HI,
  LO, LO, LO, LO, LO, LO, LO, LO,
  LO, LO, LO, LO, LO, LO, LO, LO,
  HI, HI, HI, HI, HI, HI, HI, HI,
  LO, LO, LO, LO, LO, LO, LO, LO,
  LO, LO, LO, LO, LO, LO, LO, LO,
  HI, HI, HI, HI, HI, HI, HI, HI,
  LO, LO, LO, LO, LO, LO, LO, LO,
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,
};
// @formatter:on

void blink_dma_to_gpio() {
  enable_clock();

  // GPIO C configuration
  RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Enable IO port C

  GPIOC->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_MODE6); // GPIO C: Clear pin 6 configuration
  GPIOC->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_MODE6; // GPIO C: Set pin 6 to alternate function push-pull 50MHz output

  // TIM3 configuration
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // Enable TIM3
  RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // Enable alternate function
  AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP; // Full remap TIM3

  TIM3->PSC = 1 - 1;
  TIM3->ARR = 10 - 1;

  TIM3->BDTR |= TIM_BDTR_MOE;

  TIM3->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // PWM mode 1
  TIM3->CCER |= TIM_CCER_CC1E; // Enable capture compare 1

  TIM3->CCMR2 |= TIM_CCMR2_OC3M_0; // Active on match
  TIM3->CCER |= TIM_CCER_CC3E; // Enable capture compare 3
  TIM3->DIER |= TIM_DIER_CC3DE; // Enable DMA1 request

  // DMA1 configuration
  RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Enable DMA1

  DMA1_Channel2->CPAR = (uint32_t) &TIM3->CCR1;
  DMA1_Channel2->CMAR = (uint32_t) &buffer;
  DMA1_Channel2->CNDTR = 168;

  DMA1_Channel2->CCR = DMA_CCR_MSIZE_1 // 32 bit memory
  | DMA_CCR_PSIZE_1 // 32 bit peripheral
      | DMA_CCR_MINC // Increment memory
      | DMA_CCR_CIRC // Circular memory
      | DMA_CCR_DIR  // Memory to peripheral
      | DMA_CCR_HTIE // Half transfer interrupt
      | DMA_CCR_TCIE // Transfer complete interrupt
  ;

  // Enable peripherals
  DMA1_Channel2->CCR |= DMA_CCR_EN;
  TIM3->CR1 |= TIM_CR1_CEN;
}

int main() {
  blink_dma_to_gpio();
  for (;;);
}

I already had the output hooked up to an oscilloscope and the output waves look correct. However, when I run this code, nothing changes on the LED strip. I just want to ask if there is something wrong with my code here, or could there be any potential hardware issues I did not think of.

1 ACCEPTED SOLUTION

Accepted Solutions

Thank you for the comments, I checked again and I had the configuration for the GPIO wrong. I configured it to be open-drain while it should be push-pull instead. Changing to push-pull makes the edges cleaner and the LEDs now have the expected colors.

View solution in original post

4 REPLIES 4
Andrew Neil
Super User

Please show your schematic.

 


@Beartama wrote:

I already had the output hooked up to an oscilloscope and the output waves look correct.


Please share scope screenshots - someone may be able to spot something...

If your scope has a screenshot facility, please use it - this will be far better than trying to photograph the screen!

 


@Beartama wrote:

when I run this code, nothing changes on the LED strip.


Do you see changes on the scope?

 

Do you have a known-good, working implementation to compare against; eg, Arduino?

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

Please show your schematic.


Screenshot from 2025-09-03 12-52-06.png

RM STATUS LIGHT CTRL LV is the LED strip.

 


Please share scope screenshots - someone may be able to spot something...


3f111fbc-a605-429d-b2cc-a1566c35f3bc.jpeg

The high spike is for bit 1 to be sent to the LED, and the low spike is for bit 0. The high spike is high for 0.75us and the low spike is high for 0.375us, these are according to the spec of WS2812B.


Do you have a known-good, working implementation to compare against; eg, Arduino?


No

 

That doesn't show how the STM32 is actually connected to the LED strip, nor the LED power supply.

 


@Beartama wrote:


Please share scope screenshots - someone may be able to spot something...



you missed:


@Andrew Neil wrote:
If your scope has a screenshot facility, please use it - this will be far better than trying to photograph the screen!

Your scope does have that facility:

AndrewNeil_0-1756893878101.png

 

Anyhow, that waveform looks terrible: there should be clear pulses with clean edges, and consistent height; eg,

 

AndrewNeil_2-1756894069004.png

from: https://www.pjrc.com/2017/10/

 

PS:

From the LED datasheet:

AndrewNeil_3-1756894444768.png

You haven't shown what your VDD is for the LEDs but, if it's 3.3V, that would mean that the minimum 'High' voltage is 2.3V.

In your scope trace, the short spikes aren't even reaching 2V, and even the tall ones are marginal.

 

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

Thank you for the comments, I checked again and I had the configuration for the GPIO wrong. I configured it to be open-drain while it should be push-pull instead. Changing to push-pull makes the edges cleaner and the LEDs now have the expected colors.