移植STM32F1系列代码至GD32F1系列驱动WS2812B/SM16703全彩灯-PWM+DMA模式
本文通过类比STM32F1开发流程,主要介绍了如何使用CubeMX和keil将已经开发的STM32F1系列代码高效快速的移植到GD32F1系列单片机中。本文将以PWM+DMA模式下,驱动WS2812B/SM16703全彩灯为例逐步介绍。
STM32F103rct6与GD32F1103rct6比较
芯片简介
STM32是意法半导体(ST)推出一款32位的单片机。STM32具有超低的价格、超多的外设、丰富的型号、优异的实时性、极低的开发成本等优势。STM32凭借其产品线的多样化、极高的性价比、简单易用的库开发方式,迅速在众多32位单片机中脱颖而出。 STM32芯片内部可以粗略划分两部分:内核+片上外设。如果与电脑类比,内核与片上外设就如同电脑的CPU与主板、内存、显卡、硬盘的关系。 ARM公司只设计内核不生产芯片,他会将有关内核的技术授权给各半导体厂商例如ST、TI、Atme1、NXP等厂商。这些厂商都是基于这个内核自己设计片上外设如SRAM、ROM、FLASH、USART、GPIO等,然后集成到一个硅片上,这就是我们现在用的芯片。
但是进入2022年,芯片大厂的涨价函仍在更新,涨价仍在继续。 近期突发事件频发,日本地震工厂停工、闪存芯片大厂材料污染,香港疫情、苏州疫情联电、京元电染疫冲击半导体产业链,加重了市场紧张神经。 对于“晶圆产能是否紧缺”及“芯片缺货涨价何时休”等问题,目前行业内也未有定论:一边是产能过剩预警、需求疲软,另一边是止不住的涨价、交期继续延长,产能(订单)被抢售一空。国内芯片需求持续增长,发展空间大,所以国内芯片公司开始尝试提供自产芯片以替代国外芯片,争夺市场。
GD32单片机是指由国内芯片公司兆易创新GigaDevice研发设计的一系列单片机。GD32是有和ST产品线P2P的产品系列,抢占一部分市场是一方面原因,另外更大一部分原因也是所有国产厂家进入单片机行业的必经之路;
开发环境对比
不同之处:
开发调试环境:支持主流的Keil MDK4/5、IAR、Eclipse等IDE环境;
开发编程/烧写工具:因为采用标准的Cortex-M内核,所有支持标准的JlinkV8/V9、Ulink2和自己的GD-link工具;
开发特色:同样是基于标准库的形式进行开发,每一个外设都有相对应的API封装库,不必要去熟悉每个外设的底层寄存器,可以快速上手。
简单点说基本上就是你怎么使用stm32f1系列开发,GD32基本一致。当然,毕竟是两个厂家的芯片,
WS2812B/SM16703全彩灯介绍
WS2812/SM16703介绍
WS2812B是一款全彩LED控制IC,单总线控制。就是数据线在一根线上传输的控制方式就是单总线。其实要把灯点亮仅有一根线是不行的,还需要电源线和地线给其供电。
SM16703是明微电子生产的LED全彩驱动IC,采用800kb归零码串行数据信号,内置5V稳压管,信号高电平电压为4.5~5.5V。
本文章使用过5V的WS2812B和24V的SM16703两款全彩灯,都是一个集控制电路与发光电路于一体的智能外控 LED 光源。 其外型与一个 SMD5050 侧发光 LED 灯珠相同, 每个元件即为一个像素点。 像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路, 电源稳压电路, 内置恒流电路, 高精度 RC 振荡器, 输出驱动采用 PWM 技术, 有效保证了像素点内光的颜色高一致性。
WS2812B全彩灯(SM16703基本一样)图:
PWM+DMA模式原理
PWM输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装载寄存器ARR的值决定,占空比由比较寄存器CCR的值决定。根据下面两篇博文,可以较为清楚的理解WS2812的单总线通讯协议是如何通过PWM+DMA模式实现的
WS2812灯珠(三)-- STM32 PWM+DMA方式驱动 https://blog.csdn.net/xiaoyuanwuhui/article/details/99639068
STM32L051驱动WS2812B全彩灯-PWM+DMA模式https://blog.csdn.net/cheng_nnan/article/details/105490778
使用DMA输出PWM可以精确控制脉冲数量,且可以精确控制脉冲周期与占空比,更重要的是使用DMA传输不消耗CPU资源。根据上网搜索资源与教程,秉承自己动手丰衣足食的古训,于是去翻阅参考手册,从DMA章节看到定时器章节,结合代码实战,总算搞清些端倪,也分享一下在此过程中遇到的问题。我将我自己的代码整理如下,这段程序来自实际项目,功能是实现压力传感器采集到液位数据信息后灯带分段显示。
可参考HARDWARE文件夹中的bsp_ws281x.c/.h文件
基于液位控制灯带显示
https://github.com/MWLiuChuanfeng/Liquid-Level-Controled-LED
#include "bsp_ws281x.h"
#include <string.h>
uint16_t pixelBuffer[PIXEL_NUM][GRB];
void WS281x_Init(void)
{
//MX_TIM2_Init();
/*关闭所有灯珠*/
WS281x_CloseAll();
HAL_Delay(100);
}
void WS281x_CloseAll(void)
{
uint16_t i;
uint8_t j;
for(i = 0; i < PIXEL_NUM; ++i)
{
for(j = 0; j < 24; ++j)
{
pixelBuffer[i][j] = WS_LOW;
}
}
ws281x_show();
}
/**
* @brief 将RGB颜色组合到一个32位数据中存储
* @param red: 0-255
* green:0-255
* blue: 0-255
* @retval None
*/
uint32_t ws281x_color(uint8_t red, uint8_t green, uint8_t blue)
{
return (uint32_t)(green << 16 | red << 8 | blue);
}
/**
* @brief 给特定LED灯设定颜色
* @param n:LED灯号
* GRBClor: 32位的颜色值
* @retval None
*/
void ws281x_setPixelColor(uint16_t n, uint32_t GRBColor)
{
uint8_t i;
if(n < PIXEL_NUM)
{
for(i = 0; i < GRB; i++)
{
pixelBuffer[n][i] = ((GRBColor