Page 1 of 2

WS2812 LEDs - Driver

Posted: Wed Apr 29, 2015 3:34 pm
by Noname
Hello

I need to drive some WS2812 LEDs. They use a NZR communication mode without clock signal, therefore the timing of the 800khz signal generation is critical.
I was happy to find a ChibiOS driver for those LEDs, but unfortunately I can't get it to work :/, and I really don't know how to debug it, I need some help please.

I don't have any oscilloscope to check the signal, but when I use my volt meter, it stays at 0V during the test routine where random color signals are generated, so I have the feeling that no signal at all comes out of the pin, and I have absolutely no idea why. :/

Has someone already successfully used that driver?

Thanks

Re: WS2812 LEDs - Driver

Posted: Sat May 02, 2015 11:40 am
by Noname
The dmaStreamAllocate seems to work as it sends a FALSE value back which indicate that there was no error and that the stream was taken. The rest of the DMA setup seems equal to that seen for the ADC peripheral (adc_lld.c), only the parameters differs of course.

I can't imagine that the logic used to generate the signal with the help of DMA and PWM is wrong, he wouldn't have published it then. :?
Really strange. It was developed on STM32F3 Discovery. Is there an difference with my STM32F4 Discovery which may possibly explain the problem?
(I don't know which version of ChibiOS he used)

Re: WS2812 LEDs - Driver

Posted: Sat May 02, 2015 1:29 pm
by Giovanni
Hi,

F3 and F4 have very different DMAs, it is possible the difference is all here.

Giovanni

Re: WS2812 LEDs - Driver

Posted: Sat May 02, 2015 5:42 pm
by Noname
Hi,

Thanks for your answer :)
If the the problem is related to the different DMA implementation between F3 and F4, it may be a question of a wrong streamer and timer number?

(I'm a beginner, I do it as a hobby only :D )

Re: WS2812 LEDs - Driver

Posted: Sat May 02, 2015 9:17 pm
by Giovanni
It is possible, F3 and F4 are very different.

Giovanni

Re: WS2812 LEDs - Driver

Posted: Sun May 03, 2015 5:14 pm
by Noname
I found another driver, which seems simpler (well that one was coded for a F1 :D ). It uses only 1 DMA stream and 1 PWM/Timer, but it doesn't use ChibiOS.
So I need your help to convert some instructions.
https://github.com/devthrash/STM32F1-wo ... 812/main.c

How do I convert that thing in ChibiOS instructions???

Code: Select all

   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM3_CCR1_Address;   // physical address of Timer 3 CCR1
   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LED_BYTE_Buffer;      // this is the buffer memory
   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                  // data shifted from memory to peripheral
   DMA_InitStructure.DMA_BufferSize = 42;

DMA_PeripheralBaseAddr >>> dmaStreamSetPeripheral ???
DMA_MemoryBaseAddr >>> dmaStreamSetMemory0 ??? No idea, I still haven't understood the meaning of LED_BYTE_Buffer :?
DMA_DIR >>> STM32_DMA_CR_DIR_M2P, I suppose :?
DMA_BufferSize >>> dmaStreamSetTransactionSize ???

Code: Select all

   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;               // automatically increase buffer index
   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                     // stop DMA feed after buffer size is reached
   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_PeripheralInc >>> STM32_DMA_CR_PINC ???
DMA_MemoryInc >>> STM32_DMA_CR_MINC ???
DMA_PeripheralDataSize >>> STM32_DMA_CR_PSIZE_HWORD ???
DMA_MemoryDataSize >>> STM32_DMA_CR_MSIZE_HWORD ???
DMA_Mode >>> :?
DMA_Priority >>> Parameter in the dmaStreamAllocate function, not? :?
DMA_M2M >>> :?

Code: Select all

   DMA_Init(DMA1_Channel6, &DMA_InitStructure);
   
   /* TIM3 CC1 DMA Request enable */
   TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);

dmaStreamEnable(STM32_DMA1_STREAM6); ???

TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE); >>> PWMD4.tim->DIER |= TIM_DMA_CC1; ???



I feel a little bit lost :?

(I'm using PWMD4 [TIM4], not PWMD3)



EDIT:

Code: Select all

void WS2812DriverInit(BaseSequentialStream *chp) {

  bool_t dmaAllocError = TRUE;

  /* PWM configuration */
  palSetPadMode(GPIOD, GPIOD_LED4, PAL_MODE_ALTERNATE(2));
  pwmStart(&PWMD4, &pwm4cfg);

  /* DMA configuration  */
  dmaAllocError = dmaStreamAllocate(STM32_DMA1_STREAM2, 10, NULL, NULL);
  dmaStreamSetPeripheral(STM32_DMA1_STREAM2, (uint32_t)TIM3_CCR1_Address);
  dmaStreamSetMemory0(STM32_DMA1_STREAM6, (uint32_t)LED_BYTE_Buffer);
  dmaStreamSetTransactionSize(STM32_DMA1_STREAM6, 42);
  dmaStreamSetMode(STM32_DMA1_STREAM6,
                   STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_MINC | STM32_DMA_CR_PSIZE_HWORD |
                   STM32_DMA_CR_MSIZE_HWORD);



  PWMD4.tim->DIER |= TIM_DMA_CC1;

}

Re: WS2812 LEDs - Driver

Posted: Sun May 03, 2015 7:47 pm
by Noname

Code: Select all

   DMA_SetCurrDataCounter(DMA1_Channel6, buffersize);    // load number of bytes to be transferred
   DMA_Cmd(DMA1_Channel6, ENABLE);          // enable DMA channel 6
   TIM_Cmd(TIM3, ENABLE);                   // enable Timer 3
   while(!DMA_GetFlagStatus(DMA1_FLAG_TC6));    // wait until transfer complete
   TIM_Cmd(TIM3, DISABLE);                // disable Timer 3
   DMA_Cmd(DMA1_Channel6, DISABLE);          // disable DMA channel 6
   DMA_ClearFlag(DMA1_FLAG_TC6);             // clear DMA1 Channel 6 transfer complete flag

And that bloc in the WS2812_send function is equivalent to:

Code: Select all

  dmaStreamSetTransactionSize(STM32_DMA1_STREAM2, buffersize); // WRONG TYPE!!! load number of bytes to be transferred
  dmaStreamEnable(STM32_DMA1_STREAM2);                                // enable DMA1 channel 2
  pwmEnableChannel(&PWMD4, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD4, 5000)); // WRONG PULSE WIDTH!!! enable Timer 4
  dmaWaitCompletion(STM32_DMA1_STREAM2);                            // wait until transfer complete
  pwmDisableChannel(&PWMD4, 0);


Right?

Re: WS2812 LEDs - Driver

Posted: Sun May 03, 2015 8:00 pm
by Giovanni
It looks OK, you have to test and see if the DMA registers are set as you expect and, after enabling the channel, decrements/increments as you expect.

Edit: it looks you have not specified the channel in the "mode" (STM32_DMA_CR_CHSEL() macro), please refer to the Reference Manual for details.

Giovanni

Re: WS2812 LEDs - Driver

Posted: Sun May 03, 2015 8:48 pm
by Noname
Thank you for your help! :)

Yeah I definitively need to take a look at the manual, but it looks so much complicated for me who have only a few knowledge about all that low level stuff in general. I'm sure it will be funny :D.

More next week.

Re: WS2812 LEDs - Driver

Posted: Sun May 03, 2015 8:57 pm
by Giovanni
The DMA driver is not even a real driver, it is an helper used by the other drivers, the details of the inner DMA unit are not really hidden. On the F4 the DMA it is *particularly* complex, you need to understand, the STM32 RM is your best friend for this.

That STM32_DMA_CR_CHSEL() is the main difference with the F3, so focus on that and its meaning.

Giovanni