我正在根据here提供的示例为STM32编写Neopixel驱动程序。
总而言之,像素没有正确点亮。我最近的尝试是让第一行 8 个像素在停止之前亮起绿色。这种情况不会每次都会发生,但无论如何,这些 LED 灯最终都会亮起,始终保持相同的颜色。.
这些是我正在开发的驱动程序中的相关功能:
#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;
}
这是我用来测试/排除故障的主文件中的相关代码。
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 */
}
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);
}
}
目标是以一种纯色依次点亮 LED,然后以相反的方向将其关闭。相反,我得到了上面显示的图像中发生的任何废话。
我最初的假设是我没有在函数中正确使用联合指针(这仍然在我的脑海中),但是当我进行更多故障排除时,我注意到 HAL_TIM_PWM_PulseFinishedCallback 仅被调用一次,即第一次时间在 ascendingRed 的 for 循环中,再也不会了。通常这意味着脉冲值 (CC1) 尚未达到。
我将第一个成功周期中 htim3 的内容与所有后续周期中的内容进行了比较,并在调试器中看到了这一点:
这两张图分别是成功调用HAL_TIM_PWM_PulseFinishedCallback之前和期间: 第一次进入HAL_TIM_PWM_PulseFinishedCallback之前
HAL_TIM_PWM_PulseFinishedCallback 被调用
然后:
我很确定问题出在我用来将所有信息分组在一起的指针结构中。有人看到我错过的东西吗?
编辑:由于其他地方的人建议我将 PixelDRV_t 的计时器参数切换为使用指针,我已经取得了一些进展。
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)
{
/*
if(strip->pixel_length != sizeof(color))
{
return HAL_ERROR;
}
*/
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;
}
现在中断正在应有的时间被调用,并且 LED 正在双向更新!然而,一开始我仍然遇到这个问题,LED 在被所需的 LED 值覆盖之前以奇怪的模式点亮。
因此,回想起来,问题的“大多数”的答案相当明显,并在我的编辑中列出在上面。 我将计时器结构复制到 PixelDRV_t 结构中,而不是使用原始结构,这导致发生各种混乱。我将 PixelDRV_t 切换为指向原始结构,现在一切运行正常!我仍然不能 100% 确定为什么 LED 在开始时会以相同的模式点亮,但我猜测这是因为没有设置值。我调整了代码,在开始时将所有 LED 值设置为零,这似乎已经解决了问题。