1# UART 2 3## Overview 4 5### Function 6 7The Universal Asynchronous Receiver/Transmitter (UART) is a universal serial data bus used for asynchronous communication. It enables bi-directional communication between devices in full-duplex mode. 8 9A UART is connected to other modules through two wires (as shown in Figure 1) or four wires (as shown in Figure 2). 10 11 - TX: UART transmitter. It is connected to the RX of the peer UART. 12 - RX: UART receiver. It is connected to the TX of the peer UART. 13 - RTS: Request to Send signal, indicating whether the local UART is ready to receive data. It is connected to the CTS of the peer UART. 14 - CTS: Clear to Send signal, indicating whether the local UART is allowed to send data to the peer end. It is connected to the RTS of the peer UART. 15 16**Figure 1** Two-wire UART communication 17 18![image1](figures/2-wire-uart-communication.png "2-wire-uart-communication") 19 20**Figure 2** Four-wire UART communication 21 22 ![image2](figures/4-wire-uart-communication.png "4-wire-uart-communication") 23 24The UART transmitter and receiver must have the same settings on particular attributes, such as the baud rate and data format (start bit, data bits, parity bit, and stop bit) before they start to communicate. A UART sends data to the peer end over the TX and receives data from the peer end over the RX. When the size of the buffer used by a UART for storing received data reaches the preset threshold, the RTS signal of the UART changes to **1** (data cannot be received), and the peer UART stops sending data to it because its CTS signal does not allow it to send data. 25 26### Basic Concepts 27 28- Asynchronous communication 29 30 In asynchronous communication, data is transmitted in frames of characters or bytes. Frames are sent and received one by one through the transmission line. The transmitter and receiver have their own clocks to control data sending and receiving. The two clock sources are independent and not synchronized with each other. 31 32 When data is sent one character at a time, the time interval between two characters is not fixed, but the time interval between two adjacent bits in a character frame is fixed. 33 34- Full-duplex transmission 35 36 A duplex communication mode allows data to be transmitted in both directions at the same time. A duplex communication channel is equivalent to two simplex communication channels operating in opposite directions at the same time. In full-duplex mode, signals can be transmitted bidirectionally at the same time. 37 38### Working Principles 39 40In the Hardware Driver Foundation (HDF), the UART uses the independent service mode (see Figure 3) 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. 41 42In 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: 43 44- You need to implement the **Bind()** function in **HdfDriverEntry** to bind services. 45- The **policy** field of **deviceNode** in the **device_info.hcs** file can be **1** or **2**, but not **0**. 46 47The UART module is divided into the following layers: 48 49- Interface layer: provides APIs for opening or closing a UART device, reading or writing data of the specified length, setting or obtaining the baud rate or attributes of a UART device, and setting the transmission mode. 50- Core layer: provides the capabilities of adding or removing a UART controller, and managing UART devices. The core layer interacts with the adaptation layer through hook functions. 51- Adaptation layer: instantiates the hook functions to implement specific features. 52 53**Figure 3** Independent service mode 54 55![image3](figures/independent-service-mode.png) 56 57## Development Guidelines 58 59### When to Use 60 61The UART module is widely used to implement low-speed serial communication between devices, for example, output the printing information. It can also connect to a variety of external GPS and Bluetooth devices. Before using your UART devices with OpenHarmony, you need to perform UART driver adaptation. 62 63### Available APIs 64 65To enable the upper layer to successfully operate the PWM controller by calling the UART APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/uart/uart_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. 66 67**UartHostMethod**: 68 69```c 70struct UartHostMethod { 71 int32_t (*Init)(struct UartHost *host); 72 int32_t (*Deinit)(struct UartHost *host); 73 int32_t (*Read)(struct UartHost *host, uint8_t *data, uint32_t size); 74 int32_t (*Write)(struct UartHost *host, uint8_t *data, uint32_t size); 75 int32_t (*GetBaud)(struct UartHost *host, uint32_t *baudRate); 76 int32_t (*SetBaud)(struct UartHost *host, uint32_t baudRate); 77 int32_t (*GetAttribute)(struct UartHost *host, struct UartAttribute *attribute); 78 int32_t (*SetAttribute)(struct UartHost *host, struct UartAttribute *attribute); 79 int32_t (*SetTransMode)(struct UartHost *host, enum UartTransMode mode); 80 int32_t (*pollEvent)(struct UartHost *host, void *filep, void *table); 81}; 82``` 83 84**Table 1** Hook functions in UartHostMethod 85 86| Function| Input Parameter| Output Parameter| Return Value| Description| 87| -------- | -------- | -------- | -------- | -------- | 88| Init | **host**: structure pointer to the UART controller at the core layer.| –| HDF_STATUS| Initializes a UART device.| 89| Deinit | **host**: structure pointer to the UART controller at the core layer.| –| HDF_STATUS| Deinitializes a UART device.| 90| Read | **host**: structure pointer to the UART controller at the core layer.<br>**size**: size of the data to read, which is of the uint32_t type.| **data**: pointer to the data read, which is of the uint8_t type. | HDF_STATUS| Reads data.| 91| Write | **host**: structure pointer to the UART controller at the core layer.<br>**data**: pointer to the data to write, which is of the uint8_t type.<br>**size**: size of the data to write, which is of the uint32_t type.| –| HDF_STATUS| Writes data.| 92| SetBaud | **host**: structure pointer to the UART controller at the core layer.<br>**baudRate**: baud rate to set, which is of the uint32_t type.| –| HDF_STATUS| Sets the baud rate.| 93| GetBaud | **host**: structure pointer to the UART controller at the core layer.| **baudRate**: pointer to the baud rate obtained, which is of the uint32_t type.| HDF_STATUS| Obtains the baud rate.| 94| GetAttribute | **host**: structure pointer to the UART controller at the core layer.| **attribute**: structure pointer to the attributes obtained. For details, see **UartAttribute** in **uart_if.h**.| HDF_STATUS| Obtains UART attributes.| 95| SetAttribute | **host**: structure pointer to the UART controller at the core layer.<br>**attribute**: structure pointer to the attributes to set.| –| HDF_STATUS| Sets UART attributes.| 96| SetTransMode | **host**: structure pointer to the UART controller at the core layer.<br>**mode**: transmission mode to set. For details, see **UartTransMode** in **uart_if.h**.| –| HDF_STATUS| Sets the UART transmission mode.| 97| PollEvent | **host**: structure pointer to the UART controller at the core layer.<br>**filep**: void pointer to a file.<br>**table**: void pointer to the poll_table.| –| HDF_STATUS| Polls for the pending events.| 98 99### How to Develop 100 101The UART module adaptation procedure is as follows: 102 1031. Instantiate the driver entry. 1042. Configure attribute files. 1053. Instantiate the UART controller object. 1064. Debug the driver. 107 108### Example 109 110The following uses the **//device_soc_hisilicon/common/platform/uart/uart_hi35xx.c** driver of the Hi3516D V300 development board as an example to describe the UART driver adaptation. 111 1121. Instantiate the driver entry. 113 114 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. 115 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. 116 117 UART driver entry example: 118 119 ```c 120 struct HdfDriverEntry g_hdfUartDevice = { 121 .moduleVersion = 1, 122 .moduleName = "HDF_PLATFORM_UART", // (Mandatory) The value must be the same as that of moduleName in the .hcs file. 123 .Bind = HdfUartDeviceBind, // See the Bind function. 124 .Init = HdfUartDeviceInit, // See the Init function. 125 .Release = HdfUartDeviceRelease, // See the Release function. 126 }; 127 HDF_INIT(g_hdfUartDevice); // Call HDF_INIT to register the driver entry with the HDF. 128 ``` 129 1302. Configure attribute files. 131 132 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 UART controllers as an example. If there are more UART controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values configured in **uart_config.hcs** are closely related to default values or value ranges of the **UartHost** members at the core layer. 133 134 - **device_info.hcs** example: 135 136 Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file. 137 138 ```c 139 root { 140 device_info { 141 match_attr = "hdf_manager"; 142 platform :: host { 143 hostName = "platform_host"; 144 priority = 50; 145 device_uart :: device { 146 device0 :: deviceNode { 147 policy = 1; // The value 1 means to publish services only to the kernel-mode processes. 148 priority = 40; // Driver startup priority. 149 permission = 0644; // Permission for the device node created. 150 moduleName = "HDF_PLATFORM_UART"; // Driver name, which must be the same as moduleName in the HdfDriverEntry structure. 151 serviceName = "HDF_PLATFORM_UART_0"; // Unique name of the service published by the driver. The name is in the HDF_PLATFORM_UART_X format. X indicates the UART controller number. 152 deviceMatchAttr = "hisilicon_hi35xx_uart_0";// Keyword for matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver. 153 } 154 device1 :: deviceNode { 155 policy = 2; // The value 2 means to publish services for both kernel- and user-mode processes. 156 permission = 0644; 157 priority = 40; 158 moduleName = "HDF_PLATFORM_UART"; 159 serviceName = "HDF_PLATFORM_UART_1"; 160 deviceMatchAttr = "hisilicon_hi35xx_uart_1"; 161 } 162 ... 163 } 164 } 165 } 166 } 167 ``` 168 169 - **uart_config.hcs** example 170 171 Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/uart/uart_config.hcs** file. The parameters are as follows: 172 173 ```c 174 root { 175 platform { 176 template uart_controller { // 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. 177 match_attr = ""; 178 num = 0; // (Mandatory) Port number. 179 baudrate = 115200; // (Mandatory) Baud rate. 180 fifoRxEn = 1; // (Mandatory) Enable RX FIFO. 181 fifoTxEn = 1; // (Mandatory) Enable TX FIFO. 182 flags = 4; // (Mandatory) flag signal. 183 regPbase = 0x120a0000; // (Mandatory) Register physical base address used for address mapping. 184 interrupt = 38; // (Mandatory) Interrupt number. 185 iomemCount = 0x48; // (Mandatory) Used for address mapping. 186 } 187 controller_0x120a0000 :: uart_controller { 188 match_attr = "hisilicon_hi35xx_uart_0"; // (Mandatory) The value must be the same as that of deviceMatchAttr of the device in device_info.hcs. 189 } 190 controller_0x120a1000 :: uart_controller { 191 num = 1; 192 baudrate = 9600; 193 regPbase = 0x120a1000; 194 interrupt = 39; 195 match_attr = "hisilicon_hi35xx_uart_1"; 196 } 197 ... // Add node information for more UART devices. 198 } 199 } 200 ``` 201 202 After the **uart_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect. 203 204 ```c 205 #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/uart/uart_config.hcs" // Relative path of the file. 206 ``` 207 2083. Instantiate the UART controller object. 209 210 Initialize the **UartHost** 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 **UartHostMethod** in **UartHost** (so that the underlying driver functions can be called). 211 212 - Define a custom structure. 213 214 To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **uart_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the UART port number, to the object at the core layer. 215 216 ```c 217 struct UartPl011Port { // Pin description structure customized. 218 int32_t enable; 219 unsigned long physBase; // Physical base address. 220 uint32_t irqNum; // IRQ number. 221 uint32_t defaultBaudrate; // Default baud rate. 222 uint32_t flags; // Flag signals related to the following three macros. 223 #define PL011_FLG_IRQ_REQUESTED (1 << 0) 224 #define PL011_FLG_DMA_RX_REQUESTED (1 << 1) 225 #define PL011_FLG_DMA_TX_REQUESTED (1 << 2) 226 struct UartDmaTransfer *rxUdt; // DMA transfer. 227 struct UartDriverData *udd; 228 }; 229 struct UartDriverData { // Structure related to data transfer 230 uint32_t num; // Port number. 231 uint32_t baudrate; // Baud rate (configurable). 232 struct UartAttribute attr; // Attributes, such as the data bits and stop bit of the data to transfer. 233 struct UartTransfer *rxTransfer; // Buffer structure (FIFO structure) 234 wait_queue_head_t wait; // Queuing signal related to conditional variables 235 int32_t count; // Data count. 236 int32_t state; // UART controller state. 237 #define UART_STATE_NOT_OPENED 0 238 #define UART_STATE_OPENING 1 239 #define UART_STATE_USEABLE 2 240 #define UART_STATE_SUSPENDED 3 241 uint32_t flags; // Status flags. 242 #define UART_FLG_DMA_RX (1 << 0) 243 #define UART_FLG_DMA_TX (1 << 1) 244 #define UART_FLG_RD_BLOCK (1 << 2) 245 RecvNotify recv; // Pointer to the function that receives serial port data. 246 struct UartOps *ops; // Custom function pointer structure. 247 void *private; // Private data. 248 }; 249 250 // UartHost is the controller structure at the core layer. The Init function assigns values to the members of UartHost. 251 struct UartHost { 252 struct IDeviceIoService service; // Driver service. 253 struct HdfDeviceObject *device; // Driver device object. 254 uint32_t num; // Port number. 255 OsalAtomic atom; // Atomic quantity. 256 void *priv; // Private data. 257 struct UartHostMethod *method; // Callback functions. 258 }; 259 ``` 260 261 - Instantiate **UartHostMethod** in **UartHost**. 262 263 ```c 264 // Instantiate the hook functions in uart_hi35xx.c. 265 struct UartHostMethod g_uartHostMethod = { 266 .Init = Hi35xxInit, // Initialize the device. 267 .Deinit = Hi35xxDeinit, // Deinitialize the device. 268 .Read = Hi35xxRead, // Receive data. 269 .Write = Hi35xxWrite, // Write data. 270 .SetBaud = Hi35xxSetBaud, // Set the baud rate. 271 .GetBaud = Hi35xxGetBaud, // Obtain the baud rate. 272 .SetAttribute = Hi35xxSetAttribute, // Set device attributes. 273 .GetAttribute = Hi35xxGetAttribute, //Obtain device attributes. 274 .SetTransMode = Hi35xxSetTransMode, // Set the transmission mode. 275 .pollEvent = Hi35xxPollEvent, // Polling for pending events. 276 }; 277 ``` 278 279 - Implement the **Bind** function. 280 281 Input parameter: 282 283 **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 284 285 Return value: 286 287 **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. 288 289 **Table 2** HDF_STATUS 290 291 | Status| Description| 292 | -------- | -------- | 293 | HDF_ERR_INVALID_OBJECT | Invalid controller object.| 294 | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.| 295 | HDF_ERR_INVALID_PARAM | Invalid parameter.| 296 | HDF_ERR_IO | I/O error.| 297 | HDF_SUCCESS | Initialization successful.| 298 | HDF_FAILURE | Initialization failed.| 299 300 Function description: 301 302 Initializes the custom structure object and **UartHost**. 303 304 ```c 305 //uart_hi35xx.c 306 static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device) 307 { 308 ... 309 return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS; // (Mandatory) Call UartHostCreate. 310 } 311 312 // Description of UartHostCreate() in uart_core.c 313 struct UartHost *UartHostCreate(struct HdfDeviceObject *device) 314 { 315 struct UartHost *host = NULL // Create UartHost. 316 ... 317 host = (struct UartHost *)OsalMemCalloc(sizeof(*host)); // Allocate memory. 318 ... 319 host->device = device; // (Mandatory) Prerequisites for conversion between HdfDeviceObject and UartHost. 320 device->service = &(host->service); // (Mandatory) Prerequisites for conversion between HdfDeviceObject and UartHost. 321 host->device->service->Dispatch = UartIoDispatch; // Assign values to Dispatch() of service. 322 OsalAtomicSet(&host->atom, 0); // Initialize or set the atomic service. 323 host->priv = NULL; 324 host->method = NULL; 325 return host; 326 } 327 ``` 328 329 - Implement the **Init** function. 330 331 Input parameter: 332 333 **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 334 335 Return value: 336 337 HDF_STATUS 338 339 Function description: 340 341 Initialize the custom structure and **UartHost**, calls **UartAddDev()** at the core layer to add the UART controller, and accesses the VFS. 342 343 ```c 344 int32_t HdfUartDeviceInit(struct HdfDeviceObject *device) 345 { 346 int32_t ret; 347 struct UartHost *host = NULL; 348 HDF_LOGI("%s: entry", __func__); 349 ... 350 host = UartHostFromDevice(device); // Forcibly convert to UartHost by using service. The values are assigned by Bind(). 351 ... 352 ret = Hi35xxAttach(host, device); // Initialize the UartHost object. 353 ... 354 host->method = &g_uartHostMethod; // Attach the UartHostMethod instance. 355 return ret; 356 } 357 // Initialize UartHost. 358 static int32_t Hi35xxAttach(struct UartHost *host, struct HdfDeviceObject *device) 359 { 360 int32_t ret; 361 struct UartDriverData *udd = NULL; // udd and port are custom structure objects. You can implement features as required. 362 struct UartPl011Port *port = NULL; 363 ... 364 // Steps 1 to 7 assign values to the udd object and then UartHost. 365 udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd)); // Step 1 366 ... 367 port = (struct UartPl011Port *)OsalMemCalloc(sizeof(struct UartPl011Port)); // Step 2 368 ... 369 udd->ops = Pl011GetOps(); // Step 3 Hook the functions for opening or closing a device, setting device attributes, and sending data. 370 udd->recv = PL011UartRecvNotify; // Step 4 Hook the data receiving notification function (conditional lock mechanism). 371 udd->count = 0; // Step 5. 372 port->udd = udd; // Step 6 Prerequisites for conversion between UartPl011Port and UartDriverData. 373 ret = UartGetConfigFromHcs(port, device->property); // Pass the attributes of HdfDeviceObject to the custom structure to perform related operations. The sample code is as follows: 374 ... 375 udd->private = port; // Step 7 376 host->priv = udd; // (Mandatory) Prerequisites for conversion between UartHost and UartDriverData. 377 host->num = udd->num; // (Mandatory) UART device number. 378 UartAddDev(host); // (Mandatory) Function in uart_dev.c at the core layer used to register a character device node to the VFS so that the UART can be accessed through the virtual file node in user mode. 379 return HDF_SUCCESS; 380 } 381 382 static int32_t UartGetConfigFromHcs(struct UartPl011Port *port, const struct DeviceResourceNode *node) 383 { 384 uint32_t tmp, regPbase, iomemCount; 385 struct UartDriverData *udd = port->udd; 386 struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 387 ... 388 // Extract the values based on the request and assign the values to the custom structures. 389 if (iface->GetUint32(node, "num", &udd->num, 0) != HDF_SUCCESS) { 390 HDF_LOGE("%s: read busNum fail", __func__); 391 return HDF_FAILURE; 392 } 393 ... 394 return 0; 395 } 396 ``` 397 398 - Implement the **Release** function. 399 400 Input parameter: 401 402 **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs. 403 404 Return value: 405 406 No value is returned. 407 408 Function description: 409 410 Releases the memory and deletes the controller. This function assigns values to **Release()** in the driver entry structure. When the HDF fails to call **Init()** to initialize the driver, **Release()** is called to release driver resources. 411 412 > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE** 413 > All forced conversion operations for obtaining the corresponding object can be successful only when **Init()** has the corresponding value assignment operations. 414 415 ```c 416 void HdfUartDeviceRelease(struct HdfDeviceObject *device) 417 { 418 struct UartHost *host = NULL; 419 ... 420 host = UartHostFromDevice(device); // Forcible conversion from HdfDeviceObject to UartHost through the service member. For details about the value assignment, see the Bind function. 421 ... 422 if (host->priv != NULL) { 423 Hi35xxDetach(host); // Customized memory release function. For details, see the following. 424 } 425 UartHostDestroy(host); // Call the core layer function to release the host. 426 } 427 428 static void Hi35xxDetach(struct UartHost *host) 429 { 430 struct UartDriverData *udd = NULL; 431 struct UartPl011Port *port = NULL; 432 ... 433 udd = host->priv; // The conversion from UartHost to UartDriverData is involved. 434 ... 435 UartRemoveDev (host); // Remove the VFS. 436 port = udd->private; // The conversion from UartDriverData to UartPl011Port is involved. 437 if (port != NULL) { 438 if (port->physBase != 0) { 439 OsalIoUnmap((void *)port->physBase); // Unmap addresses. 440 } 441 OsalMemFree(port); 442 udd->private = NULL; 443 } 444 OsalMemFree (udd); // Release UartDriverData. 445 host->priv = NULL; 446 } 447 ``` 448 4494. Debug the driver. 450 451 (Optional) For new drivers, verify basic functions, for example, check the information returned after the driver is attached and whether data is successfully transmitted. 452