README_zh.md
1# Niobe407开发板OpenHarmony基于HDF驱动框架编程开发——PWM
2本示例将演示如何在Niobe407开发板上通过HDF驱动框架,使用TIM2和TIM3定时器模拟pwm进行输出。
3
4
5## 编译调试
6- 进入//kernel/liteos_m目录, 在menuconfig配置中进入如下选项:
7
8 `(Top) → Platform → Board Selection → select board niobe407 → use talkweb niobe407 application → niobe407 application choose`
9
10- 选择 `206_hdf_pwm`
11
12- 在menuconfig的`(Top) → Driver`选项中使能如下配置:
13
14```
15 [*] Enable Driver
16 [*] HDF driver framework support
17 [*] Enable HDF platform driver
18 [*] Enable HDF platform pwm driver
19```
20- 回到sdk根目录,执行`hb build -f`脚本进行编译。
21
22### 运行结果
23
24示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志
25```
26[HDF:I/HDF_LOG_TAG]open pwm 2 success!
27
28[HDF:I/HDF_LOG_TAG]PwmSetConfig success ! duty is 10000000
29
30[HDF:I/HDF_LOG_TAG]open pwm 3 success!
31
32[HDF:I/HDF_LOG_TAG]PwmSetConfig success ! duty is 10000000
33```
34使用示波器接对应的管脚可以观察到对应的PWM输出波形如下图所示
35
36此图为PWM2的输出波形,频率为20hz, 占空比为20%,对应PA3 引脚
37
38此图为PWM3的输出波形,频率为10hz, 占空比为10% 对应PA6引脚
39# OpenHarmony驱动子系统开发—PWM
40
41## 概述
42 PWM(Pulse Width Modulator)即脉冲宽度调节器,在HDF框架中,PWM的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
43
44## 接口说明
45 1. pwm open初始化函数:DevHandle PwmOpen(uint32_t num);
46 参数说明:
47 num: PWM设备编号
48 return: 获取成功返回PWM设备句柄,失败返回NULL
49 2. pwm close去初始化函数:void PwmClose(DevHandle handle);
50 参数说明:
51 handle: pwm设备句柄,
52 return: 无
53 3. 设置PWM设备参数:int32_t PwmSetConfig(DevHandle handle, struct PwmConfig *config);
54 参数说明:
55 handle: pwm设备句柄,
56 *config 参数指针
57 return: 返回0表示设置成功,返回负数表示失败
58## PWM HDF HCS配置文件解析
59- device_uart_info.hcs文件位于/device/board/talkweb/niobe407/sdk/hdf_config/device_pwm_info.hcs,本例子使用的是TIM2和TIM3定时器模拟的PWM信号
60```
61
62root {
63 module = "talkweb,stm32f407";
64 device_info {
65 match_attr = "hdf_manager";
66 template host {
67 hostName = "";
68 priority = 100;
69 template device {
70 template deviceNode {
71 policy = 0;
72 priority = 100;
73 preload = 0;
74 permission = 0664;
75 moduleName = "";
76 serviceName = "";
77 deviceMatchAttr = "";
78 }
79 }
80 }
81 platform :: host {
82 hostName = "platform_host";
83 priority = 50;
84 device_pwm1 :: device {
85 pwm1 :: deviceNode { //pwm config
86 policy = 2;
87 priority = 100;
88 moduleName = "NIOBE_HDF_PLATFORM_PWM";
89 serviceName = "HDF_PLATFORM_PWM_1"; // 编号要与PwmOpen入参一致,否则找不到service
90 deviceMatchAttr = "config_pwm1";
91 }
92 }
93 device_pwm2 :: device {
94 pwm2 :: deviceNode { //pwm config
95 policy = 2;
96 priority = 100;
97 moduleName = "NIOBE_HDF_PLATFORM_PWM";
98 serviceName = "HDF_PLATFORM_PWM_2"; // 编号要与PwmOpen入参一致,否则找不到service
99 deviceMatchAttr = "config_pwm2";
100 }
101 }
102 }
103 }
104}
105```
106
107- hdf_uart.hcs文件位于/device/board/talkweb/niobe407/sdk/hdf_config/hdf_pwm.hcs,在此文件中配置串口对应的GPIO引脚信息,串口配置信息
108```
109#include "device_pwm_info.hcs"
110root {
111 platform {
112 pwm1_config {
113 gpio_pwm1{ // PWM2 配置的gpio信息
114 // 要配置的引脚个数,接下来的引脚名必须定义成gpio_num_1, gpio_num_2, gpio_num_3...
115 gpio_num_max = 1;
116 // port, pin, mode, speed, outputType, pull, alternate
117 gpio_num_1 = [0, 3, 2, 3, 0, 2, 1]; // tim2 ch4 pa3
118 }
119
120 pwmconfig : gpio_pwm1 {
121 match_attr = "config_pwm1"; // 本驱动默认使用pwm1模式 和上升计数模式
122 pwmTim = 1; // 定时器ID tim2 0 :tim1, 1:tim2 ..... tim6 和 tim7不可用
123 pwmCh = 3; // 对应chanel 4 0:ch1 1:ch2 2:ch3 3:ch4
124 prescaler = 4199; // 预分频器 例如tim2 时钟为84M, (84M/(4199+1)) = 20khz, 然后以20khz 为基准 ,tim2-tim7, tim12-tim14为84M,TIM1、TIM8~TIM11 为168M,tim6和tim7不能输出pwm
125 // tim1~tim5 tim8 有4个channel tim9,tim12有ch1, ch2, tim10, tim11,tim13,tim14只有ch1
126 }
127 }
128 pwm2_config {
129 gpio_pwm2{ // pwm3配置的GPIO信息
130 // 要配置的引脚个数,接下来的引脚名必须定义成gpio_num_1, gpio_num_2, gpio_num_3...
131 gpio_num_max = 1;
132 // port, pin, mode, speed, outputType, pull, alternate
133 gpio_num_1 = [0, 6, 2, 3, 0, 2, 2]; // tim3 ch1 pa6
134 }
135
136 pwmconfig2 : gpio_pwm2 {
137 match_attr = "config_pwm2"; // 本驱动默认使用pwm1模式 和上升计数模式
138 pwmTim = 2; // 定时器ID tim2 0 :tim1, 1:tim2 ..... tim6 和 tim7不可用
139 pwmCh = 0; // 对应chanel 4 0:ch1 1:ch2 2:ch3 3:ch4
140 prescaler = 8399; // 预分频器 例如tim2 时钟为84M, (84M/(4199+1)) = 20khz, 然后以20khz 为基准,根据在pwmSetconfig 设置的period和duty,来计算频率 ,tim2-tim7, tim12-tim14为84M,TIM1、TIM8~TIM11 为168M,tim6和tim7不能输出pwm
141 // tim1~tim5 tim8 有4个channel tim9,tim12有ch1, ch2, tim10, tim11,tim13,tim14只有ch1 这个值如果16位最大分频数位65535
142 }
143 }
144 }
145}
146
147```
148
149## 例程原理简介
150 NIOBE407开发板有可以使用TIM定时器来产生PWM波形,系统有TIM1和TIM8两个高级定时器,TIM2-TIM5,TIM9-TIM14为通用定时器,TIM6和TIM7是基本定时器,这两个定时器不用做PWM输出,Tim2-Tim7, Tim12-Tim14为84M,TIM1、TIM8~TIM11 为168M,Tim1~Tim5 Tim8 有4个channel Tim9,Tim12有ch1, ch2, Tim10, Tim11,Tim13,Tim14只有ch1, 本例程使用TIM2的ch4 和 TIM3 的ch1来做示例,具体可前往device\board\talkweb\niobe407\sdk\hdf_config\hdf_pwm.hcs中根据您的开发板原理图进行修改
151
152## 示例代码解析
153```c
154static void* HdfPwmTestEntry(void* arg)
155{
156 int32_t ret;
157
158 uint32_t num;
159 DevHandle handle = NULL;
160
161 struct PwmConfig pcfg;
162 pcfg.duty = 10000000; /*占空时间为10000000纳秒, 占空比为20%*/
163 pcfg.period = 50000000; /*周期为50000000纳秒,计算出1s/50ms = 20hz为频率*/
164 pcfg.number = 0; /*生成无限个方波*/
165 pcfg.polarity = PWM_NORMAL_POLARITY; /*极性为正*/
166 pcfg.status = PWM_ENABLE_STATUS; /*运行状态为启用*/
167
168 /* PWM设备编号,要填写实际平台上的编号 */
169 num = 1; //tim2
170
171 /* 获取PWM设备句柄 */
172 handle = PwmOpen(num);
173 if (handle == NULL) {
174 HDF_LOGE("PwmOpen: failed!\n");
175 return;
176 } else {
177 HDF_LOGI("open pwm %u success!\n", num + 1);
178 }
179
180 /*设置PWM设备参数*/
181 ret = PwmSetConfig(handle, &pcfg);
182 if (ret != 0) {
183 HDF_LOGE("PwmSetConfig: failed, ret %d\n", ret);
184 goto _ERR2;
185 } else {
186 HDF_LOGI("PwmSetConfig success ! duty is %u\n", pcfg.duty);
187 }
188
189 DevHandle handle1 = NULL;
190
191 struct PwmConfig pcfg1;
192 pcfg1.duty = 10000000; /*占空时间为10000000纳秒, 占空比为10%*/
193 pcfg1.period = 100000000; /*周期为100000000纳秒 1s/100ms = 10HZ 频率*/
194 pcfg1.number = 0; /*生成无限个方波*/
195 pcfg1.polarity = PWM_NORMAL_POLARITY; /*极性为正*/
196 pcfg1.status = PWM_ENABLE_STATUS; /*运行状态为启用*/
197
198 /* PWM设备编号,要填写实际平台上的编号 */
199 uint32_t num2 = 2; //tim2
200
201 handle1 = PwmOpen(num2);
202 if (handle1 == NULL) {
203 HDF_LOGE("PwmOpen: failed!\n");
204 return;
205 } else {
206 HDF_LOGI("open pwm %u success!\n", num2 + 1);
207 }
208
209 /*设置PWM设备参数*/
210 ret = PwmSetConfig(handle1, &pcfg1);
211 if (ret != 0) {
212 HDF_LOGE("PwmSetConfig: failed, ret %d\n", ret);
213 goto _ERR1;
214 } else {
215 HDF_LOGI("PwmSetConfig success ! duty is %u\n", pcfg1.duty);
216 }
217
218 while (1) {
219 LOS_TaskDelay(1000);
220 }
221_ERR1:
222 /* 销毁PWM设备句柄 */
223 PwmClose(handle);
224_ERR2:
225 PwmClose(handle1);
226}
227```