STM32 G431RB 利用PWM+DMA+Circular Mode 少量内存 实现对WS2812 灯带的控制
在上一篇文章中DMA的设置使用的是"Normal" Mode,这种实现方法的问题是费内存,要控制168颗灯带的颜色,需要准备168*24 +2*TRST 约4K Byte的内存,
在MCU的世界里就麻烦了,这次这个项目中需要控制4个灯带,两个168,一个21, 一个23.内存严重告急。采用DMA Circular模式能大大的减少内存的使用。
DMA Cirular模式就是DMA发送完成后,在调用HAL_TIM_PWM_Stop_DMA,DMA会自动的循环一直发送数据。
代码工作原理如下:
- 用两颗LED灯的长度(24x2)作为DMA Buffer
- DMA发送数据的时候会产生两个中断,一个是数据发送一半的时候产生一次中断,在中断里将下一个灯的数据填入Buffer的前半段
- DMA一次发送完成产生第二个中断,我们再将下一个灯的数据填入下半Buffer
- 循环往复直到所有的灯的数据都发送完成
当然前后都需要发送TRST数据。
我在例子代码中可以同时配置4个PWM+DMA通道,进行数据发送。感兴趣的可以直接用我的实现函数。
代码放到Github上了。https://github.com/magicduan/demo_pwm_dma
/** * @brief Initilaize the pwm_dma data(Global array pwm_dma_data) according to dma_id. * * @param dma_id: the PWM_DMA item (0 - PWM_LED_CHANNEL_MAX_COUNT-1) * @param htim: pwm Timer * @param channel: pwm DMA channel * @param p_colors: the color buffer of LEDs, every LED color use 24bit (RGB) = 3 Byte * @param leds_count: the numbers of LEDs * @retval 0: success */ void pwm_dma_init(uint32_t dma_id, TIM_HandleTypeDef *htim, uint32_t channel, uint8_t* p_colors, uint32_t leds_count ) { if (dma_id >= PWM_LED_CHANNEL_MAX_COUNT){ return; } pwm_dma_data[dma_id].htim = htim; pwm_dma_data[dma_id].dma_channel = channel; pwm_dma_data[dma_id].p_dma_colors = p_colors; pwm_dma_data[dma_id].total_leds = leds_count; } /** * @brief Send colors to LEDs by PWM + DMA + Circular mode * * @param dma_id: the PWM_DMA item (0 - PWM_LED_CHANNEL_MAX_COUNT-1) * @param channel: pwm DMA channel * @param p_colors: the color buffer of LEDs, every LED color use 24bit (RGB) = 3 Byte * @param leds_count: the numbers of LEDs * @param b_block: flag whether waiting complete for DMA send. b_block = 1, waiting block mode , = 0 noblock mode * @retval 0: success */ int pwm_dma_send(uint32_t dma_id,uint8_t b_block) { int res = 0; if (dma_id >= PWM_LED_CHANNEL_MAX_COUNT){ return -1; } if(pwm_dma_data[dma_id].htim == NULL){ return -1; } pwm_dma_data[dma_id].inter_dma_data.status = PWM_DMA_HEAD_RST; pwm_dma_data[dma_id].inter_dma_data.cur_led = 0; pwm_dma_data[dma_id].inter_dma_data.b_completed = 0; led_data_fill(pwm_dma_data+dma_id,0); res = HAL_TIM_PWM_Start_DMA(pwm_dma_data[dma_id].htim, pwm_dma_data[dma_id].dma_channel, (uint32_t*)(pwm_dma_data[dma_id].inter_dma_data.pwm_buffer), DMA_BUFFER_LEN); if ( res != HAL_OK){ return res; } if (b_block){ // Block Mode while(pwm_dma_data[dma_id].inter_dma_data.b_completed == 0){ osDelay(1); } } return res; }
标签:
嵌入式设备开发
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)