0
\$\begingroup\$

I am trying to control WS2812b digital LEDs with stm32f103. I have a buffer of color values for the LED strip and to transfer them I need to write the next value to the timer's CCR every time the timer updates. As the result I should see this buffer as a PWM signal on the pin of the MC. The guy, who helped me with the PCB wired LED's data pin to PB5 of the MC. PB5 is connected to TIM3_CH2. According to the manual there is no DMA request for TIM3_CH2. enter image description here Does this mean it is impossible to use DMA to change TIM3 CCR2 every time the timer updates? I know about the DMA burst mode which can write to any CCR of a timer, but looks like it is impossible to send a big buffer to one CCR. What am I missing?

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Haven't dug into the details of this lately, but any chance you could run another TIM3 OC channel in parallel and use that as a trigger unconnected to any pin, and have DMA load both? Are you sure the appropriate trigger to use actually is the channel specific one. \$\endgroup\$ Dec 10 '19 at 16:59
  • \$\begingroup\$ Hmm, do you mean that I can use any timer channel as an update event for the DMA? \$\endgroup\$
    – George
    Dec 10 '19 at 17:04
  • \$\begingroup\$ Another channel of the same timer would presumably need to be updated at the same time so a "fake" output on that (unrouted to any pin) might work as a substitute timing source \$\endgroup\$ Dec 10 '19 at 17:13
  • \$\begingroup\$ I thought TIM3 was more general purpose. micromouseonline.com/2016/02/04/… \$\endgroup\$ Dec 10 '19 at 17:16
  • \$\begingroup\$ Does this answer your question? stm32 which timer and DMA channel should I use? \$\endgroup\$
    – Tagli
    Dec 13 '19 at 7:19
1
\$\begingroup\$

Turned out I just needed to use TIM_CHANNEL_UPDATE as update source for the DMA and set TIM3 CCR2 as an output. It just works. I used HAL library and I had to create my own HAL_TIM_PWM_Start_DMA and HAL_TIM_PWM_Stop_DMA functions.

Here is the code, it contains hardcoded values for CCR2 and TIM_DMA_ID_UPDATE channel

HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA_HACK(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length)
{
    /* Set the DMA Period elapsed callback */
    htim->hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = TIM_DMADelayPulseCplt;

    /* Set the DMA error callback */
    htim->hdma[TIM_DMA_ID_UPDATE]->XferErrorCallback = TIM_DMAError;

    /* Enable the DMA channel */
    HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_UPDATE], (uint32_t)pData, (uint32_t)&htim->Instance->CCR2, Length);

    /* Enable the TIM Capture/Compare 1 DMA request */
    __HAL_TIM_ENABLE_DMA(htim, TIM_DMA_UPDATE);

    /* Enable the Capture compare channel */
    TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE);

    if (IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)
    {
        /* Enable the main output */
        __HAL_TIM_MOE_ENABLE(htim);
    }

    /* Enable the Peripheral */
    __HAL_TIM_ENABLE(htim);

    /* Return function status */
    return HAL_OK;
}

HAL_StatusTypeDef HAL_TIM_PWM_Stop_DMA_HACK(TIM_HandleTypeDef *htim, uint32_t Channel)
{
    __HAL_TIM_DISABLE_DMA(htim, TIM_DMA_UPDATE);
    /* Disable the Capture compare channel */
    TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_DISABLE);

    if (IS_TIM_BREAK_INSTANCE(htim->Instance) != RESET)
    {
        /* Disable the Main Ouput */
        __HAL_TIM_MOE_DISABLE(htim);
    }

    /* Disable the Peripheral */
    __HAL_TIM_DISABLE(htim);

    /* Change the htim state */
    htim->State = HAL_TIM_STATE_READY;

    /* Return function status */
    return HAL_OK;
}
```
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.