HAL_TIM_PWM_PulseFinishedCallback not being triggered.
I've seen this around and I was hoping to get additional information on how to track down why this is the case.
I'm writing a Neopixel driver for an STM32F411RE based on this example.
The example works good, and I've been working on getting a struct-based version of the code going so that I can have multiple Neopixel strips of variable lengths attached to one microcontroller.
I've run into a problem where HAL_TIM_PWM_PulseFinishedCallback isn't being called, which (according to this post) means CC1 isn't being reached. I've been trying to diagnose why that isn't happening, but I've been coming up short.
This is the code in the driver:
#define NUM_PIXELS 40
#define RGBW_DMA_BUFF_SIZE (NUM_PIXELS * 32) + 1
typedef union
{
struct
{
uint8_t w;
uint8_t b;
uint8_t r;
uint8_t g;
} color;
uint32_t data;
} PixelRGBW_t;
/*
* Note, must use a 32bit timer channel to work.
*/
typedef struct
{
TIM_HandleTypeDef* timer;
uint32_t timer_channel;
uint32_t pixel_length;
uint32_t buf_length;
}PixelDRV_t;
uint8_t pixelRGBW_init(PixelDRV_t *strip, PixelRGBW_t *color, TIM_HandleTypeDef* setTIMER, uint32_t setCHANNEL, uint32_t setLENGTH, uint32_t *Pbuff)
{
strip->timer = setTIMER;
strip->timer_channel = setCHANNEL;
strip->pixel_length = setLENGTH;
strip->buf_length = (setLENGTH * 32) + 1;
for(int x = 0; x < setLENGTH; x++)
{
for (int b = 31; b >= 0; b--)
{
if ((color->data >> b) & 0x01)
{
*Pbuff = NEOPIXEL_RGBW_ONE;
}
else
{
*Pbuff = NEOPIXEL_RGBW_ZERO;
}
Pbuff++;
}
color++;
}
return HAL_OK;
}
uint8_t setPixelColorMonoRGBW(PixelDRV_t *strip, PixelRGBW_t *color, uint32_t pixel, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
{
color[pixel].color.r = red;
color[pixel].color.g = green;
color[pixel].color.b = blue;
color[pixel].color.w = white;
return HAL_OK;
}
uint8_t setPixelLengthColorMonoRGBW(PixelDRV_t *strip, PixelRGBW_t *color, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
{
for(int a = 0; a < strip->pixel_length; a++)
{
color[a].color.r = red;
color[a].color.g = green;
color[a].color.b = blue;
color[a].color.w = white;
}
return HAL_OK;
}
/*
Sets the relevant "1" and "0" bits into the buffer to be written to the Neopixels via PWM. Must set whole strip's values, even if you are only updating one LED in one pixel, since all pixels need to know their RGB values, even if they are zero.
*/
uint8_t setPixelBufRGBW(PixelDRV_t *strip, PixelRGBW_t *color, uint32_t *Pbuff)
{
for(int x = 0; x < strip->pixel_length; x++)
{
for (int b = 31; b >= 0; b--)
{
if ((color[x].data >> b) & 0x01)
{
*Pbuff = NEOPIXEL_RGBW_ONE;
}
else
{
*Pbuff = NEOPIXEL_RGBW_ZERO;
}
Pbuff++;
}
}
return HAL_OK;
}
uint8_t transmitPixelBufRGBW(PixelDRV_t *strip, PixelRGBW_t *color, uint32_t *Pbuff)
{
HAL_TIM_PWM_Start_DMA(&strip->timer, strip->timer_channel, Pbuff, strip->buf_length);
return HAL_OK;
}
And this is the relevant code in the project file I'm testing with:
PixelRGBW_t STRIP1;
PixelRGBW_t* strip1 = &STRIP1;
PixelDRV_t PIXEL_DRV1;
PixelDRV_t* pixel_drv1 = &PIXEL_DRV1;
uint32_t dmaBuffer[RGBW_DMA_BUFF_SIZE] = {0};
uint32_t *pBuff = &dmaBuffer;
void Init_NeoPixels();
void ascendingRed();
void descendingRed();
void ascendingGreen();
void descendingGreen();
void ascendingBlue();
void descendingBlue();
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_3);
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
MX_I2S3_Init();
MX_DMA_Init();
MX_TIM2_Init(); //timer being used for neopixels.
MX_SPI2_Init();
/* USER CODE BEGIN 2 */
Init_NeoPixels();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
ascendingRed();
HAL_Delay(1000);
descendingRed();
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 100;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2);
}
void Init_NeoPixels()
{
pixelRGBW_init(pixel_drv1, strip1, htim2, TIM_CHANNEL_3, 40, pBuff);
}
void ascendingRed()
{
for(int x = 0; x < pixel_drv1->pixel_length; x++)
{
setPixelColorMonoRGBW(pixel_drv1, strip1, x, 255, 0, 0, 0);
setPixelBufRGBW(pixel_drv1, strip1, pBuff);
transmitPixelBufRGBW(pixel_drv1, strip1, pBuff);
HAL_Delay(125);
}
}
void descendingRed()
{
for(int x = pixel_drv1->pixel_length; x >= 0; x--)
{
setPixelColorMonoRGBW(pixel_drv1, strip1, x, 0, 0, 0, 0);
setPixelBufRGBW(pixel_drv1, strip1, pBuff);
transmitPixelBufRGBW(pixel_drv1, strip1, pBuff);
HAL_Delay(125);
}
}
I'm still trying to figure out what I lost in translation, but my best guess is that it has something to do with the pointers/structs I'm using to try and store all the information about what neopixel strip is connected to which timer. Does anyone see anything I'm missing?
edit: Okay, I made some progress thanks to TDK's suggestion of changing the pixel_drv struct to user a pointer for the timer struct! ascendingRed and descendingRed are both doing exactly what I want them to do. However, there is a problem at the start where that same random assortment of LEDs light up. They get overwritten by the desired LEDs and stay that way when they're turned off, but I'd rather have them not lighting up in the first place
