【SoC】【W800】基于W800的PWM实现
一、简介
联盛德的 W800 是一款优势显著的安全 IoT Wi-Fi / 蓝牙双模 SoC 芯片。它采用 40 纳米工艺,QFN32 封装,尺寸仅 4mm x 4mm ,十分小巧。
在性能方面,集成 32 位 XT804 处理器,最高工作频率达 240MHz,内置 DSP、浮点运算单元,可满足高算例音视频算法等应用需求。其 Wi-Fi / 蓝牙射频性能在行业中颇具优势,支持 2.4G IEEE802.11b/g/n Wi-Fi 通讯协议,涵盖 Wi-Fi WMM/WMM-PS/WPA/WPA2/WPS 等,支持 20/40M 带宽工作模式,传输速率最高到 150Mbps ,还支持 STA、AP、APSTA 功能;蓝牙方面,支持 BT/BLE 双模工作模式及 BT/BLE4.2 协议 ,集成蓝牙基带处理器 / 协议处理器,支持蓝牙配网。
W800 的安全特性突出,内置 TEE 安全引擎,代码可区分安全世界与非安全世界,集成 SASC/TIPC,能对内存及内部模块 / 接口配置安全属性,防止非安全代码访问;启用固件签名机制,实现安全 Boot / 升级,具备固件加密功能,且固件加密密钥使用非对称算法分发,增强密钥安全性,还集成了 RC4 256、AES 128 等硬件加解密模块。
芯片内部资源丰富,内置 2MB Flash 与 288KB RAM ,支持大容量 PSRAM 扩展,集成 5 路高速 UART 接口(最高支持 2Mbps)、2 路 16 比特 ADC(最高采样率 1KHz)、1 个 I2C 控制器、GPIO 控制器、5 路 PWM 接口、1 路 Duplex I2S 控制器、7816(SIM 卡)接口等多种数字接口。
由于这些特性,W800 适用于智能家电、智能家居、智能玩具、无线音视频、工业控制、医疗监护等广泛的物联网领域,能够为相关产品提供可靠的无线连接、高性能运算以及安全保障 。
二、开发环境准备
系统:win11
开发板:W800_Arduino 开发板
SDK版本:wm_iot_sdk_v2.4-rc
IDE:VSCode
三、W800的PWM资源
技术资料
3.1 文档资料
3.2 SDK代码部分
/*** @brief PWM work mode supported by W800*/
enum wm_pwm_mode {WM_PWM_OUT_INDPT, /**< independent output mode */WM_PWM_OUT_2SYNC, /**< two channel sync output mode */WM_PWM_OUT_ALLSYNC, /**< all channel sync output mode */WM_PWM_OUT_MC, /**< complement output mode */WM_PWM_OUT_BRAKE, /**< brake output mode */WM_PWM_IN_CAP, /**< capture for input mode */WM_PWM_MODE_MAX
};
这段代码定义了联盛德 W800 芯片支持的 PWM(脉冲宽度调制)工作模式枚举类型enum wm_pwm_mode
,每种模式对应不同的功能场景:
-
WM_PWM_OUT_INDPT
:独立输出模式,各 PWM 通道独立工作,输出波形参数(频率、占空比等)可单独设置,适用于需要独立控制的场景(如 RGB LED 调色)。 -
WM_PWM_OUT_2SYNC
:双通道同步输出模式,两组 PWM 通道同步工作,保持相同的频率和相位,适用于需要对称控制的设备(如电机正反转驱动)。 -
WM_PWM_OUT_ALLSYNC
:全通道同步模式,所有 PWM 通道同步输出,波形完全一致,适合需要协同动作的多设备控制(如多路 LED 同步调光)。 -
WM_PWM_OUT_MC
:互补输出模式,通道输出互为反相的 PWM 波形(一通道高电平时另一通道低电平),常用于 H 桥电路驱动(如直流电机调速)。 -
WM_PWM_OUT_BRAKE
:制动输出模式,可快速将输出置于特定电平(如低电平),用于紧急停止场景(如电机刹车)。 -
WM_PWM_IN_CAP
:输入捕获模式,此时 PWM 模块作为输入设备,用于测量外部信号的频率、占空比等参数(如脉冲计数、传感器信号检测)。 -
WM_PWM_MODE_MAX
:枚举边界值,用于模式合法性校验(如判断输入模式是否超出范围)。
这些模式覆盖了输出控制、同步协同、输入检测等场景,体现了 W800 芯片 PWM 模块的灵活性,可满足物联网设备中电机控制、灯光调节、信号测量等多种需求。
四、PWM的API接口
PWM API 参考 — WinnerMicro 在线文档
wm_device_t *wm_drv_pwm_init(const char *name)
函数声明:wm_device_t *wm_drv_pwm_init(const char *name)
功能翻译
初始化具有指定名称的 PWM 驱动及其相关参数。
备注说明
该函数通过提供的名称和参数初始化 PWM 驱动,同时为驱动上下文分配内存并初始化必要的数据结构。函数返回一个指向已初始化的 PWM 驱动设备的指针,可用于后续操作。
参数说明
name
– [输入参数] PWM 驱动设备的名称(字符串类型)
返回值说明
- 成功时:返回指向已初始化的 PWM 驱动设备的指针(
wm_device_t *
类型) - 失败时:返回
NULL
补充解析
这是 W800 芯片 PWM 驱动的初始化函数,作用是:
- 根据设备名称(如 "pwm0")找到对应的硬件 PWM 模块
- 完成底层硬件配置和内存资源分配
- 返回可用于后续操作的设备句柄(类似 "设备 ID")
后续调用wm_drv_pwm_channel_start
等函数时,需要将此返回的指针作为第一个参数传入,以指定操作哪个 PWM 设备。例如:
// 初始化名为"pwm0"的PWM设备
wm_device_t *pwm_dev = wm_drv_pwm_init("pwm0");
if (pwm_dev == NULL) {// 初始化失败处理
}
PWM API 参考 — WinnerMicro 在线文档
API可以在写代码时编写边了解,这里就不用过多文字的描述了,直接上示例代码。
五、正式代码环节
前情提要:
WM的插件以及配置,看官网
5.1 初始化
void pwm_init(void)
{// 配置GPIOB_1为PWM功能int ret = wm_drv_gpio_iomux_func_sel(GPIOB_1_NUM, PWM_FUNC_SEL);if (ret != WM_ERR_SUCCESS) {wm_log_error("GPIOB_1 set PWM func failed!");return;}pwm_device = wm_drv_pwm_init("pwm");// 配置PWM通道(假设GPIOB_1对应PWM通道0)wm_drv_pwm_channel_cfg_t pwm_cfg = {.channel = WM_PWM_CHANNEL_0, // 对应GPIOB_1的PWM通道.mode = WM_PWM_OUT_INDPT, // 独立输出模式.clkdiv = WM_PWM_CLKDIV_DEFAULT, // 时钟分频.period_cycle = 255-1, // 周期(根据需求调整).duty_cycle = 0, // 占空比(根据需求调整).autoload = true // 自动加载参数};// 初始化PWM通道ret = wm_drv_pwm_channel_init(pwm_device, &pwm_cfg);if (ret != WM_ERR_SUCCESS) {wm_log_error("PWM channel init failed!");return;}// 启动PWM输出ret = wm_drv_pwm_channels_start(pwm_device);if (ret != WM_ERR_SUCCESS) {wm_log_error("PWM start failed!");return;}
}
5.2 创建任务test
void test_task(void *parameters)
{int duty=0;pwm_init();while (1) {if(duty > 255) {duty = 0; // 重置占空比}wm_drv_pwm_set_channel_duty(pwm_device, WM_PWM_CHANNEL_0, duty++);vTaskDelay(pdMS_TO_TICKS(100)); // 每秒输出一次日志}vTaskDelete(NULL);
}
5.3 全代码
#define LOG_TAG "test"
#include "wm_log.h"#include "freertos/FreeRTOS.h"
#include "freertos/task.h"#include "wm_drv_gpio.h"
#include "wm_drv_pwm.h"#define GPIOB_1_NUM WM_GPIO_NUM_17 /*PB1*/
#define PWM_FUNC_SEL WM_GPIO_IOMUX_FUN2 // 替换为PWM对应的复用功能序号wm_device_t *pwm_device = NULL;void pwm_init(void)
{// 配置GPIOB_1为PWM功能int ret = wm_drv_gpio_iomux_func_sel(GPIOB_1_NUM, PWM_FUNC_SEL);if (ret != WM_ERR_SUCCESS) {wm_log_error("GPIOB_1 set PWM func failed!");return;}// uint8_t ret;// wm_drv_pwm_channel_cfg_t cfg = { 0 };pwm_device = wm_drv_pwm_init("pwm");// 配置PWM通道(假设GPIOB_1对应PWM通道0)wm_drv_pwm_channel_cfg_t pwm_cfg = {.channel = WM_PWM_CHANNEL_0, // 对应GPIOB_1的PWM通道.mode = WM_PWM_OUT_INDPT, // 独立输出模式.clkdiv = WM_PWM_CLKDIV_DEFAULT, // 时钟分频.period_cycle = 255-1, // 周期(根据需求调整).duty_cycle = 0, // 占空比(根据需求调整).autoload = true // 自动加载参数};// 初始化PWM通道ret = wm_drv_pwm_channel_init(pwm_device, &pwm_cfg);if (ret != WM_ERR_SUCCESS) {wm_log_error("PWM channel init failed!");return;}// 启动PWM输出ret = wm_drv_pwm_channels_start(pwm_device);if (ret != WM_ERR_SUCCESS) {wm_log_error("PWM start failed!");return;}
}void test_task(void *parameters)
{int duty=0;pwm_init();while (1) {if(duty > 255) {duty = 0; // 重置占空比}wm_drv_pwm_set_channel_duty(pwm_device, WM_PWM_CHANNEL_0, duty++);vTaskDelay(pdMS_TO_TICKS(100)); // 每秒输出一次日志}vTaskDelete(NULL);
}int main(void)
{xTaskCreate(test_task, "test", 512, NULL, 5, NULL);return 0;
}