1e41f4b71Sopenharmony_ci# PWM 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## Overview 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci### Function 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciPulse 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. 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci### Basic Concepts 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ciA 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**. 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci### Working Principles 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ciIn 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. 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ciIn 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: 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ci- You need to implement the **Bind()** function in **HdfDriverEntry** to bind services. 20e41f4b71Sopenharmony_ci- The **policy** field of **deviceNode** in the **device_info.hcs** file can be **1** or **2**, but not **0**. 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ciThe PWM module is divided into the following layers: 23e41f4b71Sopenharmony_ci 24e41f4b71Sopenharmony_ci- 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 25e41f4b71Sopenharmony_ci- 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. 26e41f4b71Sopenharmony_ci- Adaptation layer: instantiates the hook functions to implement specific features. 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci**Figure 1** Independent service mode 29e41f4b71Sopenharmony_ci 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci## Development Guidelines 33e41f4b71Sopenharmony_ci 34e41f4b71Sopenharmony_ci### When to Use 35e41f4b71Sopenharmony_ci 36e41f4b71Sopenharmony_ciBefore using your PWM device with OpenHarmony, you need to perform PWM driver adaptation. 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci### Available APIs 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ciTo 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. 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci**PwmMethod**: 43e41f4b71Sopenharmony_ci 44e41f4b71Sopenharmony_ci```c 45e41f4b71Sopenharmony_cistruct PwmMethod { 46e41f4b71Sopenharmony_ci int32_t (*setConfig)(struct PwmDev *pwm, struct PwmConfig *config); 47e41f4b71Sopenharmony_ci int32_t (*open)(struct PwmDev *pwm); 48e41f4b71Sopenharmony_ci int32_t (*close)(struct PwmDev *pwm); 49e41f4b71Sopenharmony_ci}; 50e41f4b71Sopenharmony_ci``` 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci**Table 1** Hook functions in **PwmMethod** 53e41f4b71Sopenharmony_ci 54e41f4b71Sopenharmony_ci| Function| Input Parameter| Return Value| Description| 55e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- | 56e41f4b71Sopenharmony_ci| 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.| 57e41f4b71Sopenharmony_ci| open | **pwm**: structure pointer to the PWM controller at the core layer.| HDF_STATUS| Opens a PWM device.| 58e41f4b71Sopenharmony_ci| close | **pwm**: structure pointer to the PWM controller at the core layer.| HDF_STATUS| Closes a PWM device.| 59e41f4b71Sopenharmony_ci 60e41f4b71Sopenharmony_ci### How to Develop 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ciThe PWM module adaptation procedure is as follows: 63e41f4b71Sopenharmony_ci 64e41f4b71Sopenharmony_ci1. Instantiate the driver entry. 65e41f4b71Sopenharmony_ci2. Configure attribute files. 66e41f4b71Sopenharmony_ci3. Instantiate the PWM controller object. 67e41f4b71Sopenharmony_ci4. Debug the driver. 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_ci### Example 70e41f4b71Sopenharmony_ci 71e41f4b71Sopenharmony_ciThe 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. 72e41f4b71Sopenharmony_ci 73e41f4b71Sopenharmony_ci1. Instantiate the driver entry. 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci 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. 76e41f4b71Sopenharmony_ci 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. 77e41f4b71Sopenharmony_ci 78e41f4b71Sopenharmony_ci PWM driver entry example: 79e41f4b71Sopenharmony_ci 80e41f4b71Sopenharmony_ci ```c 81e41f4b71Sopenharmony_ci struct HdfDriverEntry g_hdfPwm = { 82e41f4b71Sopenharmony_ci .moduleVersion = 1, 83e41f4b71Sopenharmony_ci .moduleName = "HDF_PLATFORM_PWM", // (Mandatory) The value must be the same as that of moduleName in the .hcs file. 84e41f4b71Sopenharmony_ci .Bind = HdfPwmBind, // See the Bind function. 85e41f4b71Sopenharmony_ci .Init = HdfPwmInit, // See the Init function. 86e41f4b71Sopenharmony_ci .Release = HdfPwmRelease, // See the Release function. 87e41f4b71Sopenharmony_ci }; 88e41f4b71Sopenharmony_ci HDF_INIT(g_hdfPwm); // Call HDF_INIT to register the driver entry with the HDF. 89e41f4b71Sopenharmony_ci ``` 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci2. Configure attribute files. 92e41f4b71Sopenharmony_ci 93e41f4b71Sopenharmony_ci 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. 94e41f4b71Sopenharmony_ci 95e41f4b71Sopenharmony_ci - **device_info.hcs** example 96e41f4b71Sopenharmony_ci 97e41f4b71Sopenharmony_ci Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file. 98e41f4b71Sopenharmony_ci 99e41f4b71Sopenharmony_ci ```c 100e41f4b71Sopenharmony_ci root { 101e41f4b71Sopenharmony_ci device_info { 102e41f4b71Sopenharmony_ci platform :: host { 103e41f4b71Sopenharmony_ci hostName = "platform_host"; 104e41f4b71Sopenharmony_ci priority = 50; 105e41f4b71Sopenharmony_ci device_pwm ::device { // Configure an HDF device node for each PWM controller. 106e41f4b71Sopenharmony_ci device0 :: deviceNode { 107e41f4b71Sopenharmony_ci policy = 1; // The value 1 means to publish services only to the kernel-mode processes. 108e41f4b71Sopenharmony_ci priority = 80; // Driver startup priority. 109e41f4b71Sopenharmony_ci permission = 0644; // Permission for the device node created. 110e41f4b71Sopenharmony_ci moduleName = "HDF_PLATFORM_PWM"; // (Mandatory) Driver name, which must be the same as moduleName in the driver entry. 111e41f4b71Sopenharmony_ci serviceName = "HDF_PLATFORM_PWM_0"; // (Mandatory) Unique name of the service published by the driver. 112e41f4b71Sopenharmony_ci deviceMatchAttr = "hisilicon_hi35xx_pwm_0"; // Controller private data, which must be the same as that of the controller in pwm_config.hcs. 113e41f4b71Sopenharmony_ci } 114e41f4b71Sopenharmony_ci device1 :: deviceNode { 115e41f4b71Sopenharmony_ci policy = 1; 116e41f4b71Sopenharmony_ci priority = 80; 117e41f4b71Sopenharmony_ci permission = 0644; 118e41f4b71Sopenharmony_ci moduleName = "HDF_PLATFORM_PWM"; 119e41f4b71Sopenharmony_ci serviceName = "HDF_PLATFORM_PWM_1"; 120e41f4b71Sopenharmony_ci deviceMatchAttr = "hisilicon_hi35xx_pwm_1"; 121e41f4b71Sopenharmony_ci } 122e41f4b71Sopenharmony_ci ... 123e41f4b71Sopenharmony_ci } 124e41f4b71Sopenharmony_ci } 125e41f4b71Sopenharmony_ci } 126e41f4b71Sopenharmony_ci } 127e41f4b71Sopenharmony_ci ``` 128e41f4b71Sopenharmony_ci 129e41f4b71Sopenharmony_ci - **pwm_config.hcs** example 130e41f4b71Sopenharmony_ci 131e41f4b71Sopenharmony_ci Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs** file. The parameters are as follows: 132e41f4b71Sopenharmony_ci 133e41f4b71Sopenharmony_ci ```c 134e41f4b71Sopenharmony_ci root { 135e41f4b71Sopenharmony_ci platform { 136e41f4b71Sopenharmony_ci pwm_config { 137e41f4b71Sopenharmony_ci 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. 138e41f4b71Sopenharmony_ci serviceName = ""; 139e41f4b71Sopenharmony_ci match_attr = ""; 140e41f4b71Sopenharmony_ci num = 0; // (Mandatory) Device number. 141e41f4b71Sopenharmony_ci base = 0x12070000; // (Mandatory) Base address used for address mapping. 142e41f4b71Sopenharmony_ci } 143e41f4b71Sopenharmony_ci device_0x12070000 :: pwm_device { // Add the HDF node and device node information for each device. 144e41f4b71Sopenharmony_ci match_attr = "hisilicon_hi35xx_pwm_0"; // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs. 145e41f4b71Sopenharmony_ci } 146e41f4b71Sopenharmony_ci device_0x12070020 :: pwm_device { 147e41f4b71Sopenharmony_ci match_attr = "hisilicon_hi35xx_pwm_1"; 148e41f4b71Sopenharmony_ci num = 1; 149e41f4b71Sopenharmony_ci base = 0x12070020; // (Mandatory) Base address used for address mapping. 150e41f4b71Sopenharmony_ci } 151e41f4b71Sopenharmony_ci } 152e41f4b71Sopenharmony_ci } 153e41f4b71Sopenharmony_ci } 154e41f4b71Sopenharmony_ci ``` 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci After the **pwm_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect. 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci ```c 159e41f4b71Sopenharmony_ci #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pwm/pwm_config.hcs" // Relative path of the file. 160e41f4b71Sopenharmony_ci ``` 161e41f4b71Sopenharmony_ci 162e41f4b71Sopenharmony_ci3. Instantiate the PWM controller object. 163e41f4b71Sopenharmony_ci 164e41f4b71Sopenharmony_ci 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). 165e41f4b71Sopenharmony_ci 166e41f4b71Sopenharmony_ci - Define a custom structure. 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci 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. 169e41f4b71Sopenharmony_ci 170e41f4b71Sopenharmony_ci ```c 171e41f4b71Sopenharmony_ci struct HiPwm { 172e41f4b71Sopenharmony_ci struct PwmDev dev; // (Mandatory) Control object at the core layer. 173e41f4b71Sopenharmony_ci volatile unsigned char *base; // (Mandatory) Register base address used for address mapping. 174e41f4b71Sopenharmony_ci struct HiPwmRegs *reg; // Device attribute structure, which can be customized. 175e41f4b71Sopenharmony_ci bool supportPolarity; // Whether polarity is supported. 176e41f4b71Sopenharmony_ci }; 177e41f4b71Sopenharmony_ci 178e41f4b71Sopenharmony_ci struct PwmDev { // PwmDev is the core layer controller structure. The Bind function assigns values to the members of PwmDev. 179e41f4b71Sopenharmony_ci struct IDeviceIoService service; // Driver service. 180e41f4b71Sopenharmony_ci struct HdfDeviceObject *device; // Driver device object. 181e41f4b71Sopenharmony_ci struct PwmConfig cfg; // Device attribute structure. For details, see the following definition. 182e41f4b71Sopenharmony_ci struct PwmMethod *method; // Hook functions. 183e41f4b71Sopenharmony_ci bool busy; // Whether the device is busy. 184e41f4b71Sopenharmony_ci uint32_t num; // Device number. 185e41f4b71Sopenharmony_ci OsalSpinlock lock; // Spinlock. 186e41f4b71Sopenharmony_ci void *priv; // Private data. 187e41f4b71Sopenharmony_ci }; 188e41f4b71Sopenharmony_ci 189e41f4b71Sopenharmony_ci struct PwmConfig { // PWM device attributes. 190e41f4b71Sopenharmony_ci uint32_t duty; // Time that a signal is in the ON state, in ns. 191e41f4b71Sopenharmony_ci uint32_t period; // Time for a signal to complete an on-and-off cycle, in ns. 192e41f4b71Sopenharmony_ci uint32_t number; // Number of square waves to generate. 193e41f4b71Sopenharmony_ci uint8_t polarity; // Polarity 194e41f4b71Sopenharmony_ci // ------------------- | -------------- 195e41f4b71Sopenharmony_ci // PWM_NORMAL_POLARITY | Normal polarity 196e41f4b71Sopenharmony_ci // PWM_INVERTED_POLARITY | Inverted polarity 197e41f4b71Sopenharmony_ci // 198e41f4b71Sopenharmony_ci uint8_t status; // Running status. 199e41f4b71Sopenharmony_ci // ------------------ | ----------------- 200e41f4b71Sopenharmony_ci // PWM_DISABLE_STATUS | Disabled 201e41f4b71Sopenharmony_ci // PWM_ENABLE_STATUS | Enabled 202e41f4b71Sopenharmony_ci }; 203e41f4b71Sopenharmony_ci ``` 204e41f4b71Sopenharmony_ci 205e41f4b71Sopenharmony_ci - Instantiate the **PwmMethod** structure in **PwmDev**. 206e41f4b71Sopenharmony_ci 207e41f4b71Sopenharmony_ci ```c 208e41f4b71Sopenharmony_ci struct PwmMethod g_pwmOps = { // Instantiate the hook functions in pwm_hi35xx.c. 209e41f4b71Sopenharmony_ci .setConfig = HiPwmSetConfig, // Set device attributes. 210e41f4b71Sopenharmony_ci }; 211e41f4b71Sopenharmony_ci ``` 212e41f4b71Sopenharmony_ci 213e41f4b71Sopenharmony_ci - Implement the **Init** function. 214e41f4b71Sopenharmony_ci 215e41f4b71Sopenharmony_ci **Input parameter**: 216e41f4b71Sopenharmony_ci 217e41f4b71Sopenharmony_ci **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 218e41f4b71Sopenharmony_ci 219e41f4b71Sopenharmony_ci **Return value**: 220e41f4b71Sopenharmony_ci 221e41f4b71Sopenharmony_ci **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. 222e41f4b71Sopenharmony_ci 223e41f4b71Sopenharmony_ci | Status| Description| 224e41f4b71Sopenharmony_ci | -------- | -------- | 225e41f4b71Sopenharmony_ci | HDF_ERR_INVALID_OBJECT | Invalid controller object.| 226e41f4b71Sopenharmony_ci | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.| 227e41f4b71Sopenharmony_ci | HDF_ERR_INVALID_PARAM | Invalid parameter.| 228e41f4b71Sopenharmony_ci | HDF_ERR_IO | I/O error.| 229e41f4b71Sopenharmony_ci | HDF_SUCCESS | Initialization successful.| 230e41f4b71Sopenharmony_ci | HDF_FAILURE | Initialization failed.| 231e41f4b71Sopenharmony_ci 232e41f4b71Sopenharmony_ci **Function description**: 233e41f4b71Sopenharmony_ci 234e41f4b71Sopenharmony_ci Initializes the custom structure object and **PwmDev** members, and calls **PwmDeviceAdd()** to add the PWM controller to the core layer. 235e41f4b71Sopenharmony_ci 236e41f4b71Sopenharmony_ci ```c 237e41f4b71Sopenharmony_ci // In this example, Bind() is an empty function. You can add operations as required or implement related features in Init(). 238e41f4b71Sopenharmony_ci static int32_t HdfPwmBind(struct HdfDeviceObject *obj) 239e41f4b71Sopenharmony_ci { 240e41f4b71Sopenharmony_ci (void)obj; 241e41f4b71Sopenharmony_ci return HDF_SUCCESS; 242e41f4b71Sopenharmony_ci } 243e41f4b71Sopenharmony_ci 244e41f4b71Sopenharmony_ci static int32_t HdfPwmInit(struct HdfDeviceObject *obj) 245e41f4b71Sopenharmony_ci { 246e41f4b71Sopenharmony_ci int ret; 247e41f4b71Sopenharmony_ci struct HiPwm *hp = NULL; 248e41f4b71Sopenharmony_ci ... 249e41f4b71Sopenharmony_ci hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp)); 250e41f4b71Sopenharmony_ci ... 251e41f4b71Sopenharmony_ci ret = HiPwmProbe(hp, obj); // (Mandatory) The implementation is as follows. 252e41f4b71Sopenharmony_ci ... 253e41f4b71Sopenharmony_ci return ret; 254e41f4b71Sopenharmony_ci } 255e41f4b71Sopenharmony_ci 256e41f4b71Sopenharmony_ci static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj) 257e41f4b71Sopenharmony_ci { 258e41f4b71Sopenharmony_ci uint32_t tmp; 259e41f4b71Sopenharmony_ci struct DeviceResourceIface *iface = NULL; 260e41f4b71Sopenharmony_ci 261e41f4b71Sopenharmony_ci iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); // Initialize the custom structure HiPwm. 262e41f4b71Sopenharmony_ci ... 263e41f4b71Sopenharmony_ci 264e41f4b71Sopenharmony_ci hp->reg = (struct HiPwmRegs *)hp->base; // Initialize the custom structure HiPwm. 265e41f4b71Sopenharmony_ci hp->supportPolarity = false; // Initialize the custom structure HiPwm. 266e41f4b71Sopenharmony_ci hp->dev.method = &g_pwmOps; // Attach the PwmMethod instance. 267e41f4b71Sopenharmony_ci hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE; // Initialize PwmDev. 268e41f4b71Sopenharmony_ci hp->dev.cfg.period = PWM_DEFAULT_PERIOD; // Initialize PwmDev. 269e41f4b71Sopenharmony_ci hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY; // Initialize PwmDev. 270e41f4b71Sopenharmony_ci hp->dev.cfg.status = PWM_DISABLE_STATUS; // Initialize PwmDev. 271e41f4b71Sopenharmony_ci hp->dev.cfg.number = 0; // Initialize PwmDev. 272e41f4b71Sopenharmony_ci hp->dev.busy = false; // Initialize PwmDev. 273e41f4b71Sopenharmony_ci if (PwmDeviceAdd(obj, &(hp->dev)) ) != HDF_SUCCESS) { // Call the core layer function to initialize devices and services. 274e41f4b71Sopenharmony_ci OsalIoUnmap((void *)hp->base); 275e41f4b71Sopenharmony_ci return HDF_FAILURE; 276e41f4b71Sopenharmony_ci } 277e41f4b71Sopenharmony_ci return HDF_SUCCESS; 278e41f4b71Sopenharmony_ci } 279e41f4b71Sopenharmony_ci ``` 280e41f4b71Sopenharmony_ci 281e41f4b71Sopenharmony_ci - Implement the **Release** function. 282e41f4b71Sopenharmony_ci 283e41f4b71Sopenharmony_ci **Input parameter**: 284e41f4b71Sopenharmony_ci 285e41f4b71Sopenharmony_ci **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ci **Return value**: 288e41f4b71Sopenharmony_ci 289e41f4b71Sopenharmony_ci No value is returned. 290e41f4b71Sopenharmony_ci 291e41f4b71Sopenharmony_ci **Function description**: 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci 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. 294e41f4b71Sopenharmony_ci 295e41f4b71Sopenharmony_ci ```c 296e41f4b71Sopenharmony_ci static void HdfPwmRelease(struct HdfDeviceObject *obj) 297e41f4b71Sopenharmony_ci { 298e41f4b71Sopenharmony_ci struct HiPwm *hp = NULL; 299e41f4b71Sopenharmony_ci ... 300e41f4b71Sopenharmony_ci hp = (struct HiPwm *)obj->service; // A forced conversion from HdfDeviceObject to HiPwm is involved. 301e41f4b71Sopenharmony_ci ... 302e41f4b71Sopenharmony_ci 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. 303e41f4b71Sopenharmony_ci HiPwmRemove(hp); // Release HiPwm. 304e41f4b71Sopenharmony_ci } 305e41f4b71Sopenharmony_ci ``` 306e41f4b71Sopenharmony_ci 307e41f4b71Sopenharmony_ci4. Debug the driver. 308e41f4b71Sopenharmony_ci 309e41f4b71Sopenharmony_ci (Optional) For new drivers, verify the basic functions, such as the PWM status control and response to interrupts. 310