1
\$\begingroup\$

I am trying to port the octoWS2811 for STM32F103c8T6.

This guy hubmartin has already done the heavy lifting and created a library using STM32 HAL. But the problem is that i am unable to get it to work. I am using Eclipse IDE.

this is the github page : github

This is his website where he explains whole concept : website

Below is an image which explain how the whole Timers and DMA's are configured to drive the WS2812B WS2812B timer and DMA config

I tried debugging to see if the DMA's were being triggered by putting a breakpoint in the halftransfer-callback and found that it wasn't triggered. Then i tried putting a Breakpoint in Timer-elapsed-callback and found that it wasn't triggered either.

I tried serching online and found a few similar examples and i feel that the DMA's and the timers are not configured properly.

Here is the portion of the code which as per me could be wrong:

TIM_HandleTypeDef    Tim2Handle;
TIM_OC_InitTypeDef tim2OC1;
TIM_OC_InitTypeDef tim2OC2;

uint32_t tim_period;

static void TIM2_init(void)
{
    // TIM2 Periph clock enable
    __HAL_RCC_TIM2_CLK_ENABLE();
// This computation of pulse length should work ok,
// at some slower core speeds it needs some tuning.
tim_period =  SystemCoreClock / 800000; // 0,125us period (10 times lower the 1,25us period to have fixed math below)
uint32_t cc1 = (10 * tim_period) / 36;
uint32_t cc2 = (10 * tim_period) / 15;

Tim2Handle.Instance = TIM2;

Tim2Handle.Init.Period            = tim_period;
Tim2Handle.Init.RepetitionCounter = 0;
Tim2Handle.Init.Prescaler         = 0;
Tim2Handle.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
Tim2Handle.Init.CounterMode       = TIM_COUNTERMODE_UP;
//HAL_TIM_PWM_Init(&Tim2Handle);
if(HAL_TIM_PWM_Init(&Tim2Handle) != HAL_OK)
{
    Error_Handler();
  }

HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);

tim2OC1.OCMode       = TIM_OCMODE_PWM1;
tim2OC1.OCPolarity   = TIM_OCPOLARITY_HIGH;
tim2OC1.Pulse        = cc1;
tim2OC1.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
tim2OC1.OCFastMode   = TIM_OCFAST_DISABLE;
//HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC1, TIM_CHANNEL_1);
if(HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC1, TIM_CHANNEL_1) != HAL_OK)
    {
        Error_Handler();
      }
tim2OC2.OCMode       = TIM_OCMODE_PWM1;
tim2OC2.OCPolarity   = TIM_OCPOLARITY_HIGH;
tim2OC2.Pulse        = cc2;
tim2OC2.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
tim2OC2.OCFastMode   = TIM_OCFAST_DISABLE;
tim2OC2.OCIdleState  = TIM_OCIDLESTATE_RESET;
tim2OC2.OCNIdleState = TIM_OCNIDLESTATE_RESET;
//HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC2, TIM_CHANNEL_2);
if(HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC2, TIM_CHANNEL_2) != HAL_OK)
        {
            Error_Handler();
          }

HAL_TIM_Base_Start(&Tim2Handle);
HAL_TIM_PWM_Start(&Tim2Handle, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&Tim2Handle, TIM_CHANNEL_2);}
DMA_HandleTypeDef     dmaUpdate;
DMA_HandleTypeDef     dmaCC1;
DMA_HandleTypeDef     dmaCC2;

static void DMA_init(void)
{
// TIM2 Update event
__HAL_RCC_DMA1_CLK_ENABLE();
dmaUpdate.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaUpdate.Init.PeriphInc = DMA_PINC_DISABLE;
dmaUpdate.Init.MemInc = DMA_MINC_DISABLE;
dmaUpdate.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaUpdate.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dmaUpdate.Init.Mode = DMA_CIRCULAR;
dmaUpdate.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaUpdate.Instance = DMA1_Channel2;
//dmaUpdate.XferCpltCallback  = TransferComplete;
//dmaUpdate.XferErrorCallback = TransferError;
HAL_DMA_DeInit(&dmaUpdate);
//HAL_DMA_Init(&dmaUpdate);
if(HAL_DMA_Init(&dmaUpdate) != HAL_OK)
            {
                Error_Handler();
              }
//HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
//HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
HAL_DMA_Start(&dmaUpdate, (uint32_t)WS2812_IO_High, (uint32_t)&WS2812B_PORT->BSRR, BUFFER_SIZE);


// TIM2 CC1 event
dmaCC1.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaCC1.Init.PeriphInc = DMA_PINC_DISABLE;
dmaCC1.Init.MemInc = DMA_MINC_ENABLE;
dmaCC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaCC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
dmaCC1.Init.Mode = DMA_CIRCULAR;
dmaCC1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaCC1.Instance = DMA1_Channel5;
//dmaUpdate.XferCpltCallback  = TransferComplete;
//dmaUpdate.XferErrorCallback = TransferError;
//dmaUpdate.XferHalfCpltCallback = TransferHalf;
//HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
//HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
HAL_DMA_DeInit(&dmaCC1);
//HAL_DMA_Init(&dmaCC1);
if(HAL_DMA_Init(&dmaCC1) != HAL_OK)
                {
                    Error_Handler();
                  }
HAL_DMA_Start(&dmaCC1, (uint32_t)ws2812bDmaBitBuffer, (uint32_t)&WS2812B_PORT->BRR, BUFFER_SIZE);


// TIM2 CC2 event
dmaCC2.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaCC2.Init.PeriphInc = DMA_PINC_DISABLE;
dmaCC2.Init.MemInc = DMA_MINC_DISABLE;
dmaCC2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaCC2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dmaCC2.Init.Mode = DMA_CIRCULAR;
dmaCC2.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaCC2.Instance = DMA1_Channel7;
dmaCC2.XferCpltCallback  = DMA_TransferCompleteHandler;
dmaCC2.XferHalfCpltCallback = DMA_TransferHalfHandler;
//dmaUpdate.XferErrorCallback = TransferError;
HAL_DMA_DeInit(&dmaCC2);
if(HAL_DMA_Init(&dmaCC2) != HAL_OK)
                    {
                        Error_Handler();
                      }

//  __HAL_LINKDMA(htim, hdma[TIM_DMA_ID_CC2], dmaCC2);
//  HAL_DMA_Init(htim->hdma[TIM_DMA_ID_CC2]);

HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
//HAL_DMA_Start(&dmaCC2, (uint32_t)WS2812_IO_Low, (uint32_t)&WS2812B_PORT->BSRR, BUFFER_SIZE);

if(HAL_DMA_Start(&dmaCC2, (uint32_t)WS2812_IO_Low, (uint32_t)&WS2812B_PORT->BSRR, BUFFER_SIZE) != HAL_OK)
                        {
                            Error_Handler();
                          }
}


void DMA1_Channel2_IRQHandler(void)
{
  // Check the interrupt and clear flag
  HAL_DMA_IRQHandler(&dmaUpdate);
}

void DMA1_Channel5_IRQHandler(void)
{
  // Check the interrupt and clear flag
  HAL_DMA_IRQHandler(&dmaCC1);
}

void DMA1_Channel7_IRQHandler(void)
{
  // Check the interrupt and clear flag
  HAL_DMA_IRQHandler(&dmaCC2);
}

I checked the relevant datasheets to see if the DMA requests and Timers are available and found that the timer used is supported.

\$\endgroup\$
  • \$\begingroup\$ Driving a DS2812 is a lot easier when you kwow that the low duration is NOT critical, as long as you keep it much shorter than the reset pulse. \$\endgroup\$ – Wouter van Ooijen Aug 20 '18 at 16:17
  • \$\begingroup\$ Hmm that is explained in the website. \$\endgroup\$ – Rejin Jacob Aug 21 '18 at 6:00
  • \$\begingroup\$ But i am unable to make the timers and the DMA work . It will be really helpful if someone could verify the DMA request for STM32F103c8T6 \$\endgroup\$ – Rejin Jacob Aug 21 '18 at 6:01
  • \$\begingroup\$ Sorry, can't help you with that, but I had no problem driving a chain of DS2812's with bit-banged I/O. \$\endgroup\$ – Wouter van Ooijen Aug 21 '18 at 15:37

Your Answer

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

Browse other questions tagged or ask your own question.