1# PWM 2 3## 概述 4 5### 功能简介 6 7PWM即脉冲宽度调制(Pulse Width Modulation)的缩写,是一种对模拟信号电平进行数字编码并将其转换为脉冲的技术。 8 9PWM接口定义了操作PWM设备的通用方法集合,包括: 10 11- PWM设备句柄获取和释放 12 13- PWM周期、占空比、极性的设置 14 15- PWM使能和关闭 16 17- PWM配置信息的获取和设置 18 19### 基本概念 20 21脉冲是“电脉冲”的简称,指电路中电流或电压短暂起伏的现象,其特点是突变和不连续性。脉冲的种类很多,常见的脉冲波形有:三角脉冲、尖脉冲、矩形脉冲、方形脉冲、梯形脉冲及阶梯脉冲等。脉冲的主要参数包括重复周期T(T=1/F,F为重复频率)、脉冲幅度U、脉冲前沿上升时间ts、后沿下降时间t、脉冲宽度tk等。 22 23### 运作机制 24 25在HDF框架中,PWM接口适配模式采用独立服务模式(如图1所示)。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDF设备管理器的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 26 27独立服务模式下,核心层不会统一发布一个服务供上层使用,因此这种模式下驱动要为每个控制器发布一个服务,具体表现为: 28 29- 驱动适配者需要实现HdfDriverEntry的Bind钩子函数以绑定服务。 30 31- device_info.hcs文件中deviceNode的policy字段为1或2,不能为0。 32 33PWM模块各分层作用: 34 35- 接口层提供打开PWM设备、设置PWM设备周期、设置PWM设备占空时间、设置PWM设备极性、设置PWM设备参数、获取PWM设备参数、使能PWM设备、禁止PWM设备、关闭PWM设备的接口。 36 37- 核心层主要提供PWM控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互。 38 39- 适配层主要是将钩子函数的功能实例化,实现具体的功能。 40 41**图 1** PWM独立服务模式结构图 42 43 44 45## 使用指导 46 47### 场景介绍 48 49通常情况下,在使用马达控制、背光亮度调节时会用到PWM模块。 50 51### 接口说明 52 53PWM模块设备属性如表1所示,PWM模块提供的主要接口如表2所示,具体API详见//drivers/hdf_core/framework/include/platform/pwm_if.h。 54 55**表 1** PwmConfig结构体介绍 56 57| 名称 | 描述 | 58| -------- | -------- | 59| duty | uint32_t类型,占空时间,以纳秒为单位。 | 60| period | uint32_t类型,PWM周期,以纳秒为单位。 | 61| number | uint32_t类型,要生成的方波数:<br/>- 正值:表示将生成指定数量的方波<br/>- 0:表示方波将不断产生 | 62| polarity | uint8_t类型,极性:正极性/反极性。 | 63| status | uint8_t类型,状态:启用状态/禁用状态。 | 64 65**表 2** PWM驱动API接口功能介绍 66 67| 接口名 | 接口描述| 68| ------------------------------------------------------------ | ------------------- | 69| DevHandle PwmOpen(uint32_t num) | 打开PWM设备 | 70| void PwmClose(DevHandle handle)| 关闭PWM设备 | 71| int32_t PwmSetPeriod(DevHandle handle, uint32_t period) | 设置PWM设备周期 | 72| int32_t PwmSetDuty(DevHandle handle, uint32_t duty) | 设置PWM设备占空时间 | 73| int32_t PwmSetPolarity(DevHandle handle, uint8_t polarity) | 设置PWM设备极性 | 74| int32_t PwmEnable(DevHandle handle) | 使能PWM设备 | 75| int32_t PwmDisable(DevHandle handle) | 禁用PWM设备 | 76| int32_t PwmSetConfig(DevHandle handle, struct PwmConfig \*config) | 设置PWM设备参数 | 77| int32_t PwmGetConfig(DevHandle handle, struct PwmConfig \*config) | 获取PWM设备参数 | 78 79>  **说明:**<br> 80> 本文涉及PWM的所有接口,支持内核态及用户态使用。 81 82### 开发步骤 83 84使用PWM的一般流程如下图所示。 85 86**图 2** PWM使用流程图 87 88 89 90#### 获取PWM设备句柄 91 92在操作PWM设备时,首先要调用PwmOpen获取PWM设备句柄,该函数会返回指定设备号的PWM设备句柄。 93 94```c 95DevHandle PwmOpen(uint32_t num); 96``` 97 98**表 3** PwmOpen参数和返回值描述 99 100| **参数** | **参数描述** | 101| -------- | -------- | 102| num | uint32_t类型,PWM设备号 | 103| **返回值** | **返回值描述** | 104| handle | 打开PWM设备成功,返回PWM设备句柄 | 105| NULL | 打开PWM设备失败 | 106 107假设系统中的PWM设备号为0,获取该PWM设备句柄的示例如下: 108 109```c 110uint32_t num = 0; // PWM设备号 111DevHandle handle = NULL; 112 113handle = PwmOpen(num); // 打开PWM 0设备并获取PWM设备句柄 114if (handle == NULL) { 115 HDF_LOGE("PwmOpen: open pwm_%u failed.\n", num); 116 return HDF_FAILURE; 117} 118``` 119 120#### 销毁PWM设备句柄 121 122关闭PWM设备,系统释放对应的资源。 123 124```c 125void PwmClose(DevHandle handle); 126``` 127 128**表 4** PwmClose参数描述 129 130| **参数** | **参数描述** | 131| -------- | -------- | 132| handle | DevHandle类型,PWM设备句柄 | 133 134```c 135PwmClose(handle); // 关闭PWM设备销毁PWM设备句柄 136``` 137 138#### 使能PWM设备 139 140```c 141int32_t PwmEnable(DevHandle handle); 142``` 143 144**表 5** PwmEnable参数和返回值描述 145 146| **参数** | **参数描述** | 147| -------- | -------- | 148| handle | DevHandle类型,PWM设备句柄 | 149| **返回值** | **返回值描述** | 150| HDF_SUCCESS | 使能PWM设备成功 | 151| 负数 | 使能PWM设备失败 | 152 153```c 154int32_t ret; 155 156ret = PwmEnable(handle); // 启用PWM设备 157if (ret != HDF_SUCCESS) { 158 HDF_LOGE("PwmEnable: enable pwm failed, ret:%d\n", ret); 159 return ret; 160} 161``` 162 163#### 禁用PWM设备 164 165```c 166int32_t PwmDisable(DevHandle handle); 167``` 168 169**表 6** PwmDisable参数和返回值描述 170 171| **参数** | **参数描述** | 172| -------- | -------- | 173| handle | DevHandle类型,PWM设备句柄 | 174| **返回值** | **返回值描述** | 175| HDF_SUCCESS | 禁用PWM设备成功 | 176| 负数 | 禁用PWM设备失败 | 177 178```c 179int32_t ret; 180 181ret = PwmDisable(handle); // 禁用PWM设备 182if (ret != HDF_SUCCESS) { 183 HDF_LOGE("PwmDisable: disable pwm failed, ret:%d\n", ret); 184 return ret; 185} 186``` 187 188#### 设置PWM设备周期 189 190```c 191int32_t PwmSetPeriod(DevHandle handle, uint32_t period); 192``` 193 194**表 7** PwmSetPeriod参数和返回值描述 195 196| **参数** | **参数描述** | 197| -------- | -------- | 198| handle | DevHandle类型,PWM设备句柄 | 199| period | uint32_t类型,要设置的周期,单位为纳秒 | 200| **返回值** | **返回值描述** | 201| HDF_SUCCESS | 设置PWM设备周期成功 | 202| 负数 | 设置PWM设备周期失败 | 203 204```c 205int32_t ret; 206 207ret = PwmSetPeriod(handle, 50000000); // 设置周期为50000000纳秒 208if (ret != HDF_SUCCESS) { 209 HDF_LOGE("PwmSetPeriod: pwm set period failed, ret:%d\n", ret); 210 return ret; 211} 212``` 213 214#### 设置PWM设备占空时间 215 216```c 217int32_t PwmSetDuty(DevHandle handle, uint32_t duty); 218``` 219 220**表 8** PwmSetDuty参数和返回值描述 221 222| **参数** | **参数描述** | 223| -------- | -------- | 224| handle | DevHandle类型,PWM设备句柄 | 225| duty | uint32_t类型,要设置的占空时间,单位为纳秒 | 226| **返回值** | **返回值描述** | 227| HDF_SUCCESS | 设置PWM设备占空时间成功 | 228| 负数 | 设置PWM设备占空时间失败 | 229 230 231```c 232int32_t ret; 233 234ret = PwmSetDuty(handle, 25000000); // 设置占空时间为25000000纳秒 235if (ret != HDF_SUCCESS) { 236 HDF_LOGE("PwmSetDuty: pwm set duty failed, ret:%d\n", ret); 237 return ret; 238} 239``` 240 241#### 设置PWM设备极性 242 243```c 244int32_t PwmSetPolarity(DevHandle handle, uint8_t polarity); 245``` 246 247**表 9** PwmSetPolarity参数和返回值描述 248 249| **参数** | **参数描述** | 250| -------- | -------- | 251| handle | DevHandle类型,PWM设备句柄 | 252| polarity | uint8_t类型,要设置的极性,正/反 | 253| **返回值** | **返回值描述** | 254| HDF_SUCCESS | 设置PWM设备极性成功 | 255| 负数 | 设置PWM设备极性失败 | 256 257 258```c 259int32_t ret; 260 261ret = PwmSetPolarity(handle, PWM_INVERTED_POLARITY); // 设置极性为反 262if (ret != HDF_SUCCESS) { 263 HDF_LOGE("PwmSetPolarity: pwm set polarity failed, ret:%d\n", ret); 264 return ret; 265} 266``` 267 268#### 设置PWM设备参数 269 270```c 271int32_t PwmSetConfig(DevHandle handle, struct PwmConfig *config); 272``` 273 274**表 10** PwmSetConfig参数和返回值描述 275 276| **参数** | **参数描述** | 277| -------- | -------- | 278| handle | DevHandle类型,PWM设备句柄 | 279| config | 结构体指针类型,配置参数 | 280| **返回值** | **返回值描述** | 281| HDF_SUCCESS | 设置PWM设备参数成功 | 282| 负数 | 设置PWM设备参数失败 | 283 284```c 285int32_t ret; 286struct PwmConfig pcfg; 287 288pcfg.duty = 25000000; // 占空时间为25000000纳秒 289pcfg.period = 50000000; // 周期为50000000纳秒 290pcfg.number = 0; // 不断产生方波 291pcfg.polarity = PWM_INVERTED_POLARITY; // 极性为反 292pcfg.status = PWM_ENABLE_STATUS; // 运行状态为启用 293 294ret = PwmSetConfig(handle, &pcfg); // 设置PWM设备参数 295if (ret != HDF_SUCCESS) { 296 HDF_LOGE("PwmSetConfig: pwm set config failed, ret:%d\n", ret); 297 return ret; 298} 299``` 300 301#### 获取PWM设备参数 302 303```c 304int32_t PwmGetConfig(DevHandle handle, struct PwmConfig *config); 305``` 306 307**表 11** PwmGetConfig参数和返回值描述 308 309| **参数** | **参数描述** | 310| -------- | -------- | 311| handle | DevHandle类型,PWM设备句柄 | 312| config | 结构体指针类型,配置参数 | 313| **返回值** | **返回值描述** | 314| HDF_SUCCESS | 获取PWM设备参数成功 | 315| 负数 | 获取PWM设备参数失败 | 316 317```c 318int32_t ret; 319struct PwmConfig pcfg; 320 321ret = PwmGetConfig(handle, &pcfg); // 获取PWM设备参数 322if (ret != HDF_SUCCESS) { 323 HDF_LOGE("PwmGetConfig: pwm get config failed, ret:%d\n", ret); 324 return ret; 325} 326``` 327 328## 使用实例 329 330下面将基于Hi3516DV300开发板展示使用PWM完整操作,步骤主要如下: 331 3321. 传入PWM设备号,打开PWM设备并获得PWM设备句柄。 333 3342. 通过PWM设备句柄及待设置的周期,设置PWM设备周期。 335 3363. 通过PWM设备句柄及待设置的占空时间,设置PWM设备占空时间。 337 3384. 通过PWM设备句柄及待设置的极性,设置PWM设备极性。 339 3405. 通过PWM设备句柄及待获取的设备参数,获取PWM设备参数。 341 3426. 通过PWM设备句柄,使能PWM设备。 343 3447. 通过PWM设备句柄及待设置的设备参数,设置PWM设备参数。 345 3468. 通过PWM设备句柄,禁用PWM设备。 347 3489. 通过PWM设备句柄,关闭PWM设备。 349 350```c 351#include "pwm_if.h" // pwm标准接口头文件 352#include "hdf_log.h" // 标准日志打印头文件 353 354static int32_t PwmTestSample(void) 355{ 356 int32_t ret; 357 uint32_t num; 358 uint32_t period; 359 uint32_t duty; 360 DevHandle handle = NULL; 361 362 struct PwmConfig pcfg; 363 pcfg.duty = 20000000; // 占空时间为20000000纳秒 364 pcfg.period = 40000000; // 周期为40000000纳秒 365 pcfg.number = 100; // 生成100个方波 366 pcfg.polarity = PWM_NORMAL_POLARITY; // 极性为正 367 pcfg.status = PWM_ENABLE_STATUS; // 运行状态为启用 368 369 num = 1; // PWM设备编号,要填写实际平台上的编号 370 371 handle = PwmOpen(num); // 获取PWM设备句柄 372 if (handle == NULL) { 373 HDF_LOGE("PwmTestSample: open pwm_%u fail!\n", num); 374 return HDF_FAILURE; 375 } 376 377 period = 50000000; // 设置周期为50000000纳秒 378 ret = PwmSetPeriod(handle, period); 379 if (ret != HDF_SUCCESS) { 380 HDF_LOGE("PwmTestSample: pwm set period fail, ret:%d\n", ret); 381 goto ERR; 382 } 383 384 duty = 25000000; // 设置占空时间为25000000纳秒 385 ret = PwmSetDuty(handle, duty); 386 if (ret != HDF_SUCCESS) { 387 HDF_LOGE("PwmTestSample: pwm set duty fail, ret:%d\n", ret); 388 goto ERR; 389 } 390 391 ret = PwmSetPolarity(handle, PWM_INVERTED_POLARITY); // 设置极性为反 392 if (ret != HDF_SUCCESS) { 393 HDF_LOGE("PwmTestSample: pwm set polarity fail, ret:%d\n", ret); 394 goto ERR; 395 } 396 397 ret = PwmGetConfig(handle, &pcfg); // 获取PWM设备参数 398 if (ret != HDF_SUCCESS) { 399 HDF_LOGE("PwmTestSample: get pwm config fail, ret:%d\n", ret); 400 goto ERR; 401 } 402 403 ret = PwmEnable(handle); // 启用PWM设备 404 if (ret != HDF_SUCCESS) { 405 HDF_LOGE("PwmEnable: enable pwm fail, ret:%d\n", ret); 406 goto ERR; 407 } 408 409 ret = PwmSetConfig(handle, &pcfg); // 设置PWM设备参数 410 if (ret != HDF_SUCCESS) { 411 HDF_LOGE("PwmTestSample: set pwm config fail, ret:%d\n", ret); 412 goto ERR; 413 } 414 415 ret = PwmDisable(handle); // 禁用PWM设备 416 if (ret != HDF_SUCCESS) { 417 HDF_LOGE("PwmTestSample: disable pwm fail, ret:%d\n", ret); 418 goto ERR; 419 } 420 421 HDF_LOGD("PwmTestSample: all tests end."); 422ERR: 423 PwmClose(handle); // 销毁PWM设备句柄 424 return ret; 425} 426``` 427