0
votes

I am trying to get to know stm32 boards and am currently trying to control a strip of ws2812b leds. My code already works with timer1 in pwm mode and dma enabled, but now I want to use half transfer complete and transfer complete interrupts. Unfortunately, the interrupt functions won't be called.

My assumption is, that the interrupts are not enabled for HT and TC, so I searched the code for the initalization of the dma to check if these interrupts are enabled. I am using stm32cubemx and I couldn't find code where the dma is initialized, but without interrupts the code is working. So somewhere has to be an initialization of dma.

So my Questions: Where should be the generated code for the dma initialization? And how do I enabled the dma interrupts for HT and TC?

The generated code for timer 1:

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 19;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 6;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.BreakFilter = 0;
  sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
  sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
  sBreakDeadTimeConfig.Break2Filter = 0;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);

}

Generated code for dma:

/** 
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void) 
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

}

I registered the callback functions for HT and TC:

HAL_DMA_RegisterCallback(hdma, HAL_DMA_XFER_HALFCPLT_CB_ID, _ws2812b_halfTrf_int);
HAL_DMA_RegisterCallback(hdma, HAL_DMA_XFER_CPLT_CB_ID, _ws2812b_fullTrf_int);

And I start the timer pwm with:

HAL_TIM_PWM_Start_DMA(tim, timChn, pwmData, 48);
1
to be honest - what those HAL magic functions do no one knows, You need to debug them see what is in the hardware registers and then try to modify "magic" HAL structures. After a month or two you have a 25% success chance . or you can just write it using registers in one day without any problems. Your choice0___________
If you feel unsure about which HAL function to use for one or a few HW operations (and you wouldn't like to throw away the HAL libs to work with registers as P__J__ suggested), you can look up in the reference manual which hardware register must be written in order to achieve what you are missing (starting the DMA controller, activating interrupt generation, whatever). Then, you can use the project generated by cube to search for the HAL function that accesses that register, and find out how the API of the corresponding driver module is meant to be used.HelpingHand
I'm trying to do the exact same thing, driving WS2812 LEDs. I understand that the call backs need to be called void HAL_TIM_PWM_PulseFinishedHalfCpltCallback(TIM_HandleTypeDef *htim) {} and void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {}Andy Baker

1 Answers

2
votes

So stm32xxxx_hal_dma.c will hold the answer to your question. This is how these HT and TC interrupts are called. As far as configuration goes, they are bits set in the register for event flags. You can check the DMA interrupt status register to see if those interrupts are set. The location of these bits in the register depend on which micro you have. Also check the DMA channel x configuration register, which has each interrupt enable sitting in it. It's important to understand your micro's capabilities in hardware before you start programming. I'm not particularly sure which STM32 micro you have, but I am going to give you the control bit and event flag prefixes you can search for from a STM32L0. You will have to look through the datasheet and reference manual to understand what you need to do for this and make sure those two bits to enable those IRQs are set. This would be a sure-fire method of getting these set correctly. For faster searching through the reference manual, the control bits are "HTIE" (Half-transfer) and "TCIE" (transfer complete) and event flags are "HTIF" and "TCIF" respectively.

Answer to your second question, is set these register bits at the spots of the above prefixes to '1' to enable each of them, and maybe then check the status of the register afterwards to see if the bit is set. If the interrupt is still not working, you can then look for other sources of error.

Make sure you also have a HAL_OK return from the register callback as well, there is a chance that could be failing if the DMA is not in the ready state. This could be due to the fact it isn't initialized, or you started the DMA before registering the callback.