Skip to content

Contributed by 爱笑, organized by Ai-Thinker

[Ai-WB2 Getting Started] PWM

Pulse width modulation (PWM) is an analog control method. It modulates the bias of the transistor base or the MOS transistor gate according to changes in the corresponding load, so as to change the conduction time of the transistor or MOS transistor, thereby changing the output of the switching regulated power supply. This method keeps the output voltage of the power supply constant when operating conditions change. It is a very effective technique for controlling analog circuits with the digital signals of a microprocessor, and is widely used in many fields from measurement and communication to power control and conversion. This article describes in detail how to use the PWM module of the Ai-WB2: 1. PWM Introduction of the Ai-WB2 The PWM of the Ai-WB2 has the following features:

Click to expand full code
c
**·** 支持5通道PWM信号生成
**·** 三种时钟源可选择(总线时钟、晶振时钟<xtalck>、慢速时钟<32k>),搭配16-bit时钟分频器
**·** 双门限值设定,增加脉冲弹性
**·** 最高工作频率为40MHZ
**时钟与分频**

Each PWM counter has three choices of clock source, as follows:

Click to expand full code
c
**·** bclk-芯片的总线时钟
**·** XTAL-外部晶振时钟
**·** f32k-系统RTC时钟

Each counter has its own 16-bit divider. The selected clock can be divided through the APB, and the PWM counter uses the divided clock as the counting cycle unit, incrementing by 1 every counting cycle. Pulse Generation Principle The PWM has an internal counter. When the counter is between the two settable threshold ranges, the PWM output is 1; conversely, when the counter is outside the two configured thresholds, the PWM output is 0, as shown in the figure below:

The PWM period is determined by two parts: one is the clock division factor, and the other is the clock duration period. The clock division factor is set by the register PWMn_CLK_DIV[15:0], which is used to divide the source clock of the PWM. The clock duration period is set by the register PWMn_PERIOD[15:0], which is used to set how many divided clock cycles make up one PWM period. That is, the PWM period = PWM source clock / PWMn_CLK_DIV[15:0] / PWMn_PERIOD[15:0]. The PWM duty cycle is determined by the clock duration period and two thresholds. The first threshold is set by the register PWMn_THRE1[15:0], and the second threshold is set by the register PWMn_THRE2[15:0]. The PWM waveform is pulled high at the first threshold and pulled low at the second threshold. That is, the PWM duty cycle = (PWMn_THRE2[15:0] - PWMn_THRE1[15:0]) / PWMn_PERIOD[15:0]. For example, if the PWM source clock is 80MHz and a PWM wave of 1kHz with a 20% duty cycle is required, the settings are as follows: PWMn_CLK_DIVI15:0]=2 PWMn_PERIOD[15:01=80000000/2/1000=40000 PWMn_THRE1[15:0]=0 PWMn_THRE2[15:0]=0+40000*20%=8000 PWM Interrupt For each PWM channel, a period count value can be set. When the number of PWM output periods reaches this count value, a PWM interrupt is generated. The duty cycle parameters are as follows:

2. PWM Driver API Introduction The HOSAL layer high-level driver API related to the PWM driver is defined in the file components/platform/hosal/include/hosal_pwm.h. The commonly used APIs are as follows: · int hosal_pwm_init(hosal_pwm_dev_t*pwm): PWM initialization. Its parameters are described as follows: · pwm: the PWM device object, defined as follows:

Click to expand full code
c
typedef struct {
uint8_t       port;         /**< pwm 端口 */
hosal_pwm_config_t  config; /**< pwm 配置 */
void         *priv;         /**< 用户自定义数据 */
} hosal_pwm_dev_t;

Here, hosal_pwm_config_t is the PWM configuration definition, whose content is as follows:

Click to expand full code
c
typedef struct {
uint8_t    pin;        /**< pwm 引脚  */
uint32_t   duty_cycle; /**< pwm占空比 0 ~ 10000(0 ~ 100%)*/
uint32_t   freq;       /**< pwm频率 0 ~ 40M */
} hosal_pwm_config_t;
Click to expand full code
c
**·** 返回值:成功时,返回0;否则返回其他非零值。
**·** int hosal_pwm_start(hosal_pwm_dev_t *pwm):启动PWM。参数说明如下:
**·** pwm:PWM设备对象
**·** 返回值:成功时,返回0;否则返回其他非零值。
**·** int hosal_pwm_stop(hosal_pwm_dev_t*pwm):停止PWM。参数说明如下:
**·** opwm:PWM设备对象
**·** 返回值:成功时,返回0;否则返回其他非零值。
**·** int hosal_pum_para_chg(hosal_pum_dev_t *pwm, hosal_pwm_config_t para):PWM配置更新。参数说明如下:
**·** pwm:PWM设备设备对象
**·** para:新的PWM配置
**·** 返回值:成功时,返回0;否则返回其他非零值。
**·** int hosal_pwm_freq_set(hosal_pwm_dev_t*pwm,uint32_t freg):设置PWM频率。参数说明如下:
**·** pwm:PWM设备设备对象
**·** freq:新的PWM频率
**·** 返回值:成功时,返回0;否则返回其他非零值。
**·** int hosal_pwm_freg_get(hosal_pwm_dev_t*pwm, uint32 t*p_freg):查询当前PWM频率。参数说明如下:
**·** pwm:PWM设备设备对象
**·** pfreq:用于返回当前PWM频率
**·** 返回值:成功时,返回0;否则返回其他非零值。
**·** int hosal_pwm_duty_set(hosal_pwm_dev_t*pwm, uint32 t_duty):设置PWM的占空比。参数说明如下:
      **·** pwm:PWM设备设备对象
      **·** duty:新的占空比
      **·** 返回值:成功时,返回0;否则返回其他非零值。
**·** int hosal_pwm_duty_get(hosal_pwm_dev_t*pwm, uint32_t*p_duty):查询当前PWM的占空比。参数说明如下:
**·** pwm:PWM设备对象
**·** p_duty:用于返回当前PWM占空比
**·** 返回值:成功时,返回0;否则返回其他非零值,
**·** int hosal_pwm_finalize(hosal_pwm_dev_t *pwm):销毁PWM设备对象并释放相关资源。参数说明如下:

· pwm: the PWM device object       · Return value: 0 on success; a non-zero value otherwise 3. PWM Usage Example

Click to expand full code
c
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdbool.h>
#include <hosal_pwm.h>
#include <blog.h>
#define TAG "pwm_demo"
hosal_pwm_dev_t pwm;
void demo_hosal_pwm_init(void)
{
uint32_t p_freq;
uint32_t duty;
/* pwm 端口及引脚设置 注意:端口与引脚有对应关系,对于 bl602,映射为端口=引脚%5 */
pwm.port = 3;
/* pwm config */
pwm.config.pin = 3;
pwm.config.duty_cycle = 5000; //占空比范围为:0~10000相当于0~100%
pwm.config.freq = 1000;       //频率范围为 0~40MHZ
/* 初始化PWM */
hosal_pwm_init(&pwm);
}
void demo_hosal_pwm_change_param(uint8_t duty)
{
/* 更改PWM配置 */
hosal_pwm_config_t para;
para.duty_cycle = duty * 1000; //ex.8000/10000=80%
para.freq = 500;
// 更新PWM配置
hosal_pwm_para_chg(&pwm, para);
}
void pwm_task(void* params) {
printf("pwm task start...\r\n");
demo_hosal_pwm_init();
hosal_pwm_start(&pwm);
while (true) {
for(uint8_t duty = 0;duty <= 10;duty++){
demo_hosal_pwm_change_param(duty);
vTaskDelay(100);
}
vTaskDelay(500);
for(uint8_t duty = 9;duty >= 0;duty--){
demo_hosal_pwm_change_param(duty);
vTaskDelay(100);
}
}
hosal_pwm_stop(&pwm);
vTaskDelete(NULL);
}
void main(void) {
printf("pwm demo inited\r\n");
xTaskCreate(pwm_task, "pwm_task", 1024, NULL, 15, NULL);
}

Released under the MIT License. Build Time 2026-09-11 14:52:23