cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_TIM_PWM_PulseFinishedCallback not being triggered.

Anonymaton
Associate II

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

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru
for(int x = pixel_drv1->pixel_length; x >= 0; x--)

The first call to this will have x = 40 which writes to a pixel that doesn't exist (out of bounds write), probably clobbering pixel_drv1, which would cause even more issues. Could be causing your issue.

Also pixelRGBW_init should use a pointer to TIM_HandleTypeDef as a parameter, not the entire structure. You're making a copy which is against how HAL handles should be used. PixelDRV_t should use a TIM_HandleTypeDef pointer, not the entire structure.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

4 REPLIES 4
TDK
Guru
for(int x = pixel_drv1->pixel_length; x >= 0; x--)

The first call to this will have x = 40 which writes to a pixel that doesn't exist (out of bounds write), probably clobbering pixel_drv1, which would cause even more issues. Could be causing your issue.

Also pixelRGBW_init should use a pointer to TIM_HandleTypeDef as a parameter, not the entire structure. You're making a copy which is against how HAL handles should be used. PixelDRV_t should use a TIM_HandleTypeDef pointer, not the entire structure.

If you feel a post has answered your question, please click "Accept as Solution".

This was pulled from descendingRed, right? This is the last function related to changing the pixel colors. Would it break it for everything?

 

edit: Follow-up, I went back to the example code and quickly threw together this together. It's basically what I'm trying to do with the struct setup. Check out the deignition function (starts at line 454):

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef union
{
  struct
  {
    uint8_t b;
    uint8_t r;
    uint8_t g;
  } color;
  uint32_t data;
} PixelRGB_t;

typedef union
{
  struct
  {
    uint8_t w;
    uint8_t b;
    uint8_t r;
    uint8_t g;
  } color;
  uint32_t data;
} PixelRGBW_t;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//#define NEOPIXEL_ZERO 34
//#define NEOPIXEL_ONE 67

#define NEOPIXEL_ZERO 25
#define NEOPIXEL_ONE 51

#define NUM_PIXELS 40
//#define DMA_BUFF_SIZE (NUM_PIXELS * 24) + 1
#define DMA_BUFF_SIZE (NUM_PIXELS * 32) + 1
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
DMA_HandleTypeDef hdma_tim2_ch3_up;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP */
void ignition();
void deignition();
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

PixelRGBW_t pixel[NUM_PIXELS] = {0};
uint32_t dmaBuffer[DMA_BUFF_SIZE] = {0};
uint32_t *pBuff;

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
  HAL_TIM_PWM_Stop_DMA(&htim2, TIM_CHANNEL_3);
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

	//uint32_t dmaBuffer[DMA_BUFF_SIZE] = {0};
	//uint32_t *pBuff;
	//int i, j, k;
	//uint16_t stepSize;

  /* 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_DMA_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
  //k = 0;
  //stepSize = 4;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

	  ignition();
	  HAL_Delay(500);
	  deignition();
	  HAL_Delay(500);

    /* USER CODE END WHILE */
	  /*
	  for (i = (NUM_PIXELS - 1); i > 0; i--)
	  {
		pixel[i].data = pixel[i-1].data;
	  }

	  if (k < 255)
	  {
		pixel[0].color.g = 254 - k; //[254, 0]
		pixel[0].color.r =  k + 1;  //[1, 255]
		pixel[0].color.b = 0;
		pixel[0].color.w = 0;
	  }
	  else if (k < 510)
	  {
		pixel[0].color.g = 0;
		pixel[0].color.r = 509 - k; //[254, 0]
		pixel[0].color.b = k - 254; //[1, 255]
		pixel[0].color.w = 0;
		j++;
	  }
	  else if (k < 765)
	  {
		pixel[0].color.g = 0;
		pixel[0].color.r = 0;
		pixel[0].color.b = 764 - k; //[254, 0]
		pixel[0].color.w = k - 509; //[1, 255]
	  }
	  else if (k < 1020)
	  {
		pixel[0].color.g = k - 764; //[1, 255]
		pixel[0].color.r = 0;
		pixel[0].color.b = 0;
		pixel[0].color.w = 1019 - k; //[254, 0]
	  }
	  k = (k + stepSize) % 1020;

	  // 50% brightness
	  pixel[0].color.g >>= 2;
	  pixel[0].color.r >>= 2;
	  pixel[0].color.b >>= 2;
	  pixel[0].color.w >>= 2;

	  pBuff = dmaBuffer;
	  for (i = 0; i < NUM_PIXELS; i++)
	  {
		 for (j = 31; j >= 0; j--)
		 {
		   if ((pixel[i].data >> j) & 0x01)
		   {
			 *pBuff = NEOPIXEL_ONE;
		   }
		   else
		   {
			 *pBuff = NEOPIXEL_ZERO;
		   }
		   pBuff++;
	   }
	  }
	  dmaBuffer[DMA_BUFF_SIZE - 1] = 0; // last element must be 0!

	  HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_3, dmaBuffer, DMA_BUFF_SIZE);

	  HAL_Delay(10);
	*/
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief TIM2 Initialization Function
  * @PAram None
  * @retval None
  */
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);

}

/**
  * @brief USART2 Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

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

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

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

}

/**
  * @brief GPIO Initialization Function
  * @PAram None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : B1_Pin */
  GPIO_InitStruct.Pin = B1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : LD2_Pin */
  GPIO_InitStruct.Pin = LD2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

void ignition()
{
	uint32_t dmaBuffer[DMA_BUFF_SIZE] = {0};
	uint32_t *pBuff;
	for(int a = 0; a < (NUM_PIXELS); a++)
	{
		pixel[a].color.b = 128;
		pixel[a].color.g = 0;
		pixel[a].color.r = 0;
		pixel[a].color.w = 32;

		pixel[a].color.g >>= 2;
		pixel[a].color.r >>= 2;
		pixel[a].color.b >>= 2;
		pixel[a].color.w >>= 2;

		pBuff = dmaBuffer;
		for(int x = 0; x < NUM_PIXELS; x++)
		{
			for (int b = 31; b >= 0; b--)
			{
				if ((pixel[x].data >> b) & 0x01)
				{
					*pBuff = NEOPIXEL_ONE;
				}
				else
				{
					*pBuff = NEOPIXEL_ZERO;
				}
				pBuff++;
			}
		}
		HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_3, dmaBuffer, DMA_BUFF_SIZE);

		HAL_Delay(25);
	}
}

void deignition()
{

	for(int a = (NUM_PIXELS); a >= 0; a--)
	{
		pixel[a].color.b = 0;
		pixel[a].color.g = 0;
		pixel[a].color.r = 0;
		pixel[a].color.w = 0;

		pixel[a].color.g >>= 2;
		pixel[a].color.r >>= 2;
		pixel[a].color.b >>= 2;
		pixel[a].color.w >>= 2;

		pBuff = dmaBuffer;
		for(int x = 0; x < NUM_PIXELS; x++)
		{
			for (int b = 31; b >= 0; b--)
			{
				if ((pixel[x].data >> b) & 0x01)
				{
					*pBuff = NEOPIXEL_ONE;
				}
				else
				{
					*pBuff = NEOPIXEL_ZERO;
				}
				pBuff++;
			}
		}
		dmaBuffer[DMA_BUFF_SIZE - 1] = 0; // last element must be 0!
		HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_3, dmaBuffer, DMA_BUFF_SIZE);

		HAL_Delay(25);
	}
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @PAram  file: pointer to the source file name
  * @PAram  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

All that having been said, I was using a #define there, rather than something pulled from a struct pointer. I did test it and CR1 was always set to 1 when I entered the pulse callback, and zero outside of it. 

> Would it break it for everything?

Possibly. An out of bounds write leads to undefined behavior and should not be ignored. Fix it rather than worrying about what bad behavior it causes.

If you feel a post has answered your question, please click "Accept as Solution".

Looks like it wasn't the problem! It was the timer suggestion you gave me that fixed most of it. I mentioned this in the updated question, but now the LEDs are responding as they should, though there is still one issue, in that those random LEDs still light up before being overwritten by the desired LED values. I'm still working out what's happening there, but I found a temporary solution of just writing a zero to all the pixels in the Init_NeoPixels function.