1# PWM 2 3## Overview 4 5### Function 6 7Pulse Width Modulation (PWM) is a technology that performs digital coding on analog signal levels and converts them into pulses. It is widely used in fields, such as measurement, communication, and power control and conversion. The PWM module is used for controlling vibrators and adjusting backlight brightness in smart devices. 8 9### Basic Concepts 10 11A pulse (electrical pulse) is a burst of current or voltage, characterized by sudden change and discontinuity. There are many types of pulses. Common pulses include triangular, sharp, rectangular, square, trapezoidal, and zigzag pulses. Main pulse parameters include the repetition period **T** (**T** = 1/**F**, where **F** is the pulse repetition frequency), pulse amplitude **U**, rise time **ts** at the leading edge, fall time **t** at the trailing edge, and pulse width **tk**. 12 13### Working Principles 14 15In the Hardware Driver Foundation (HDF), the PWM uses the independent service mode (see Figure 1) for API adaptation. In this mode, each device independently publishes a service to process external access requests. When receiving an access request, the HDF DeviceManager extracts parameters from the request to call the internal APIs of the target device. In the independent service mode, the HDF DeviceManager provides service management capabilities. However, you need to configure a node for each device, which increases memory usage. 16 17In the independent service mode, the core layer does not publish a service for the upper layer. Therefore, a service must be published for each controller. To achieve this purpose: 18 19- You need to implement the **Bind()** function in **HdfDriverEntry** to bind services. 20- The **policy** field of **deviceNode** in the **device_info.hcs** file can be **1** or **2**, but not **0**. 21 22The PWM module is divided into the following layers: 23 24- Interface layer: provides APIs for opening or closing a PWM device, setting the PWM period, signal ON-state time, PWM device polarity, or PWM device parameters, obtaining PWM device parameters, and enabling or disabling a PWM device 25- Core layer: provides the capabilities of adding or removing a PWM controller and managing PWM devices. The core layer interacts with the adaptation layer through hook functions. 26- Adaptation layer: instantiates the hook functions to implement specific features. 27 28**Figure 1** Independent service mode 29 30![image](figures/independent-service-mode.png "PWM independent service mode") 31 32## Development Guidelines 33 34### When to Use 35 36Before using your PWM device with OpenHarmony, you need to perform PWM driver adaptation. 37 38### Available APIs 39 40To enable the upper layer to successfully operate the PWM controller by calling the PWM APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/pwm/pwm_core.h** for the core layer. You need to implement these hook functions at the adaptation layer and hook them to implement the interaction between the interface layer and the core layer. 41 42**PwmMethod**: 43 44```c 45struct PwmMethod { 46 int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config); 47 int32_t (*open)(struct PwmDev *pwm); 48 int32_t (*close)(struct PwmDev *pwm); 49}; 50``` 51 52**Table 1** Hook functions in **PwmMethod** 53 54| Function| Input Parameter| Return Value| Description| 55| -------- | -------- | -------- | -------- | 56| setConfig | **pwm**: structure pointer to the PWM controller at the core layer.<br>**config**: structure pointer to the device attributes to set.| HDF_STATUS| Sets device attributes.| 57| open | **pwm**: structure pointer to the PWM controller at the core layer.| HDF_STATUS| Opens a PWM device.| 58| close | **pwm**: structure pointer to the PWM controller at the core layer.| HDF_STATUS| Closes a PWM device.| 59 60### How to Develop 61 62The PWM module adaptation procedure is as follows: 63 641. Instantiate the driver entry. 652. Configure attribute files. 663. Instantiate the PWM controller object. 674. Debug the driver. 68 69### Example 70 71The following uses the **//device_soc_hisilicon/common/platform/pwm/pwm_hi35xx.c** driver of the Hi3516D V300 development board as an example to describe the PWM driver adaptation. 72 731. Instantiate the driver entry. 74 75 The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **hdf_device_desc.h**), and the value of **moduleName** must be the same as that in **device_info.hcs**. In the HDF, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke. 76 Generally, the HDF calls **Bind()** and then **Init()** to load a driver. If **Init()** fails to be called, the HDF calls **Release()** to release driver resources and exit. 77 78 PWM driver entry example: 79 80 ```c 81 struct HdfDriverEntry g_hdfPwm = { 82 .moduleVersion = 1, 83 .moduleName = "HDF_PLATFORM_PWM", // (Mandatory) The value must be the same as that of moduleName in the .hcs file. 84 .Bind = HdfPwmBind, // See the Bind function. 85 .Init = HdfPwmInit, // See the Init function. 86 .Release = HdfPwmRelease, // See the Release function. 87 }; 88 HDF_INIT(g_hdfPwm); // Call HDF_INIT to register the driver entry with the HDF. 89 ``` 90 912. Configure attribute files. 92 93 Add the deviceNode information to the **device_info.hcs** file. The deviceNode information is related to the driver entry registration. The following example uses two PWM controllers as an example. If there are more PWM controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values configured in **pwm_config.hcs** are closely related to default values or value ranges of the **PwmDev** members at the core layer. 94 95 - **device_info.hcs** example 96 97 Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file. 98 99 ```c 100 root { 101 device_info { 102 platform :: host { 103 hostName = "platform_host"; 104 priority = 50; 105 device_pwm ::device { // Configure an HDF device node for each PWM controller. 106 device0 :: deviceNode { 107 policy = 1; // The value 1 means to publish services only to the kernel-mode processes. 108 priority = 80; // Driver startup priority. 109 permission = 0644; // Permission for the device node created. 110 moduleName = "HDF_PLATFORM_PWM"; // (Mandatory) Driver name, which must be the same as moduleName in the driver entry. 111 serviceName = "HDF_PLATFORM_PWM_0"; // (Mandatory) Unique name of the service published by the driver. 112 deviceMatchAttr = "hisilicon_hi35xx_pwm_0"; // Controller private data, which must be the same as that of the controller in pwm_config.hcs. 113 } 114 device1 :: deviceNode { 115 policy = 1; 116 priority = 80; 117 permission = 0644; 118 moduleName = "HDF_PLATFORM_PWM"; 119 serviceName = "HDF_PLATFORM_PWM_1"; 120 deviceMatchAttr = "hisilicon_hi35xx_pwm_1"; 121 } 122 ... 123 } 124 } 125 } 126 } 127 ``` 128 129 - **pwm_config.hcs** example 130 131 Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs** file. The parameters are as follows: 132 133 ```c 134 root { 135 platform { 136 pwm_config { 137 template pwm_device { // (Mandatory) Template configuration. If the template is used to configure device node information, the default values in the template will be used for the fields that are not declared for the node. 138 serviceName = ""; 139 match_attr = ""; 140 num = 0; // (Mandatory) Device number. 141 base = 0x12070000; // (Mandatory) Base address used for address mapping. 142 } 143 device_0x12070000 :: pwm_device { // Add the HDF node and device node information for each device. 144 match_attr = "hisilicon_hi35xx_pwm_0"; // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs. 145 } 146 device_0x12070020 :: pwm_device { 147 match_attr = "hisilicon_hi35xx_pwm_1"; 148 num = 1; 149 base = 0x12070020; // (Mandatory) Base address used for address mapping. 150 } 151 } 152 } 153 } 154 ``` 155 156 After the **pwm_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect. 157 158 ```c 159 #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs" // Relative path of the file. 160 ``` 161 1623. Instantiate the PWM controller object. 163 164 Initialize the **PwmDev** object at the core layer, including defining a custom structure (to pass parameters and data) and implementing the **HdfDriverEntry** member functions (**Bind**, **Init** and **Release**) to instantiate **PwmMethod** in **PwmDev** (so that the underlying driver functions can be called). 165 166 - Define a custom structure. 167 168 To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **pwm_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the PWM device number, to the object at the core layer. 169 170 ```c 171 struct HiPwm { 172 struct PwmDev dev; // (Mandatory) Control object at the core layer. 173 volatile unsigned char *base; // (Mandatory) Register base address used for address mapping. 174 struct HiPwmRegs *reg; // Device attribute structure, which can be customized. 175 bool supportPolarity; // Whether polarity is supported. 176 }; 177 178 struct PwmDev { // PwmDev is the core layer controller structure. The Bind function assigns values to the members of PwmDev. 179 struct IDeviceIoService service; // Driver service. 180 struct HdfDeviceObject *device; // Driver device object. 181 struct PwmConfig cfg; // Device attribute structure. For details, see the following definition. 182 struct PwmMethod *method; // Hook functions. 183 bool busy; // Whether the device is busy. 184 uint32_t num; // Device number. 185 OsalSpinlock lock; // Spinlock. 186 void *priv; // Private data. 187 }; 188 189 struct PwmConfig { // PWM device attributes. 190 uint32_t duty; // Time that a signal is in the ON state, in ns. 191 uint32_t period; // Time for a signal to complete an on-and-off cycle, in ns. 192 uint32_t number; // Number of square waves to generate. 193 uint8_t polarity; // Polarity 194 // ------------------- | -------------- 195 // PWM_NORMAL_POLARITY | Normal polarity 196 // PWM_INVERTED_POLARITY | Inverted polarity 197 // 198 uint8_t status; // Running status. 199 // ------------------ | ----------------- 200 // PWM_DISABLE_STATUS | Disabled 201 // PWM_ENABLE_STATUS | Enabled 202 }; 203 ``` 204 205 - Instantiate the **PwmMethod** structure in **PwmDev**. 206 207 ```c 208 struct PwmMethod g_pwmOps = { // Instantiate the hook functions in pwm_hi35xx.c. 209 .setConfig = HiPwmSetConfig, // Set device attributes. 210 }; 211 ``` 212 213 - Implement the **Init** function. 214 215 **Input parameter**: 216 217 **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 218 219 **Return value**: 220 221 **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **//drivers/hdf_core/framework/include/utils/hdf_base.h** file. 222 223 | Status| Description| 224 | -------- | -------- | 225 | HDF_ERR_INVALID_OBJECT | Invalid controller object.| 226 | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.| 227 | HDF_ERR_INVALID_PARAM | Invalid parameter.| 228 | HDF_ERR_IO | I/O error.| 229 | HDF_SUCCESS | Initialization successful.| 230 | HDF_FAILURE | Initialization failed.| 231 232 **Function description**: 233 234 Initializes the custom structure object and **PwmDev** members, and calls **PwmDeviceAdd()** to add the PWM controller to the core layer. 235 236 ```c 237 // In this example, Bind() is an empty function. You can add operations as required or implement related features in Init(). 238 static int32_t HdfPwmBind(struct HdfDeviceObject *obj) 239 { 240 (void)obj; 241 return HDF_SUCCESS; 242 } 243 244 static int32_t HdfPwmInit(struct HdfDeviceObject *obj) 245 { 246 int ret; 247 struct HiPwm *hp = NULL; 248 ... 249 hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp)); 250 ... 251 ret = HiPwmProbe(hp, obj); // (Mandatory) The implementation is as follows. 252 ... 253 return ret; 254 } 255 256 static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj) 257 { 258 uint32_t tmp; 259 struct DeviceResourceIface *iface = NULL; 260 261 iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); // Initialize the custom structure HiPwm. 262 ... 263 264 hp->reg = (struct HiPwmRegs *)hp->base; // Initialize the custom structure HiPwm. 265 hp->supportPolarity = false; // Initialize the custom structure HiPwm. 266 hp->dev.method = &g_pwmOps; // Attach the PwmMethod instance. 267 hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE; // Initialize PwmDev. 268 hp->dev.cfg.period = PWM_DEFAULT_PERIOD; // Initialize PwmDev. 269 hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY; // Initialize PwmDev. 270 hp->dev.cfg.status = PWM_DISABLE_STATUS; // Initialize PwmDev. 271 hp->dev.cfg.number = 0; // Initialize PwmDev. 272 hp->dev.busy = false; // Initialize PwmDev. 273 if (PwmDeviceAdd(obj, &(hp->dev)) ) != HDF_SUCCESS) { // Call the core layer function to initialize devices and services. 274 OsalIoUnmap((void *)hp->base); 275 return HDF_FAILURE; 276 } 277 return HDF_SUCCESS; 278 } 279 ``` 280 281 - Implement the **Release** function. 282 283 **Input parameter**: 284 285 **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 286 287 **Return value**: 288 289 No value is returned. 290 291 **Function description**: 292 293 Releases the memory and deletes the controller. This function assigns values to **Release()** in the driver entry structure. If the HDF fails to call **Init()** to initialize the driver, **Release()** is called to release driver resources. 294 295 ```c 296 static void HdfPwmRelease(struct HdfDeviceObject *obj) 297 { 298 struct HiPwm *hp = NULL; 299 ... 300 hp = (struct HiPwm *)obj->service; // A forced conversion from HdfDeviceObject to HiPwm is involved. 301 ... 302 PwmDeviceRemove(obj, &(hp->dev)); // (Mandatory) Call the core layer functions to release PwmDev devices and services. A forced conversion from HiPwm to PwmDev is involved in the process. 303 HiPwmRemove(hp); // Release HiPwm. 304 } 305 ``` 306 3074. Debug the driver. 308 309 (Optional) For new drivers, verify the basic functions, such as the PWM status control and response to interrupts. 310