一、前言
本文主要介绍hi3516上串口的驱动配置和测试,以及主体驱动代码的跟踪。所涉及的驱动程序源码位于vendor/huawei/hdf/sample目录。
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
二、参考文档:
$ vi ~/harmony/sdk/docs/docs-en/quick-start/developing-the-first-driver-running-on-hi3516.md
$ vi ~/harmony/sdk/docs/docs-en/guide/developing-the-first-driver-program-running-on-the-hi3516-development-board.md
三、驱动修改和跟踪
修改HDF框架的驱动配置文件:
$ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs
- root {
- platform {
- ...
- controller_0x120a3000 :: uart_controller {
- num = 3;
- baudrate = 9600;
- regPbase = 0x120a3000;
- interrupt = 41;
- match_attr = "hisilicon_hi35xx_uart_3";
- }
- +++
- // 平台配置:串口控制器参数配置
- uart_sample {
- num = 5;
- base = 0x120a0000; // UART base register address
- irqNum = 38;
- baudrate = 115200;
- uartClk = 24000000; // 24 M
- wlen = 0x60; // 8 bit width
- parity = 0;
- stopBit = 0;
- match_attr = "sample_uart_5";
- }
- +++
- }
- }
复制代码修改HDF框架的设备配置文件
$ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
- root {
- device_info {
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_uart :: device {
- ...
- device3 :: deviceNode {
- policy = 1;
- priority = 40;
- permission = 0644;
- moduleName = "HDF_PLATFORM_UART";
- serviceName = "HDF_PLATFORM_UART_3";
- deviceMatchAttr = "hisilicon_hi35xx_uart_3";
- }
- +++
- // 描述设备节点信息
- device5 :: deviceNode {
- policy = 2;
- priority = 10;
- permission = 0660;
- moduleName = "UART_SAMPLE";
- serviceName = "HDF_PLATFORM_UART_5";
- deviceMatchAttr = "sample_uart_5";
- }
- +++
- }
- }
- }
- }
复制代码基于HDF框架注册UART驱动的入口HdfDriverEntry,代码如下:
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
- // 修改HDF框架的驱动配置文件
- $ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs
- root {
- platform {
- +++
- // 平台配置:串口控制器参数配置
- uart_sample {
- num = 5;
- base = 0x120a0000; // UART base register address
- irqNum = 38;
- baudrate = 115200;
- uartClk = 24000000; // 24 M
- wlen = 0x60; // 8 bit width
- parity = 0;
- stopBit = 0;
- match_attr = "sample_uart_5"; // uart_config.hcs和device_info.hcs通过deviceMatchAttr匹配
- }
- +++
- }
- }
- // 修改HDF框架的设备配置文件
- $ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
- root {
- device_info {
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- device_uart :: device {
- +++
- // 描述设备节点信息
- device5 :: deviceNode {
- policy = 2;
- priority = 10;
- permission = 0660;
- moduleName = "UART_SAMPLE"; // 设备和驱动源码uart_sample.c通过moduleName匹配
- serviceName = "HDF_PLATFORM_UART_5";
- deviceMatchAttr = "sample_uart_5"; // uart_config.hcs和device_info.hcs通过deviceMatchAttr匹配
- }
- +++
- }
- }
- }
- }
- // 系统启动过程中设备和驱动的加载(绑定)
- $ vi ~/harmony/sdk/drivers/hdf/frameworks/core/host/src/hdf_driver_loader.c
- static struct HdfDeviceNode *HdfDriverLoaderLoadNode(struct IDriverLoader *loader, const struct HdfDeviceInfo *deviceInfo)
- struct HdfDriverEntry *driverEntry = NULL;
- struct HdfDeviceNode *devNode = NULL;
- driverEntry = loader->GetDriverEntry(deviceInfo);
- devNode = HdfDeviceNodeNewInstance();
- devNode->deviceObject.property = HcsGetNodeByMatchAttr(HcsGetRootNode(), deviceInfo->deviceMatchAttr);
- if (driverEntry->Bind(&devNode->deviceObject) != 0) { // 调用uart_sample.c中的Bind = HdfUartSampleBind函数
- HDF_LOGE("bind driver failed");
- HdfDeviceNodeFreeInstance(devNode);
- }
- // 串口驱动源码主入口!!!
- $ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
- /* HdfDriverEntry definitions */
- struct HdfDriverEntry g_hdfUartSample = {
- .moduleVersion = 1,
- .moduleName = "UART_SAMPLE",
- // $ vi ~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
- // 与描述设备节点信息的device5 :: deviceNode 中的 moduleName = "UART_SAMPLE"一致。
- .Bind = HdfUartSampleBind, // 驱动的绑定
- .Init = HdfUartSampleInit, // 驱动的初始化
- .Release = HdfUartSampleRelease, // 驱动的释放
- };
- //
- // Initialize HdfDriverEntry
- HDF_INIT(g_hdfUartSample); // .Init对应的函数可能是在这里面做了统一处理,
- // 这是一段带有特殊属性HDF_SECTION的代码段,
- // 编译器应该会将驱动操作函数放到特定的代码段,
- // 以便启动的时候依次初始化所有设备的驱动。
- // Registers the driver with the HDF
- // $ vi ~/harmony/sdk/drivers/hdf/frameworks/include/core/hdf_device_desc.h
- #define HDF_INIT(module) HDF_DRIVER_INIT(module)
- // $ vi ~/harmony/sdk/drivers/hdf/lite/include/host/hdf_device_section.h
- #define HDF_DRIVER_INIT(module) const size_t USED_ATTR module##HdfEntry HDF_SECTION = (size_t)(&(module))
- // 绑定UART驱动接口到HDF框架
- static int32_t HdfUartSampleBind(struct HdfDeviceObject *device)
- UartHostCreate(device)
- // 初始化UART
- static int32_t HdfUartSampleInit(struct HdfDeviceObject *device)
- host = UartHostFromDevice(device);
- ret = SampleAttach(host, device); // 将UART驱动的配置和接口附加到HDF驱动框架
- uartDevice = (struct UartDevice *)OsalMemCalloc(sizeof(struct UartDevice)); // 为串口设备创建新的资源空间
- SampleDispatchConstruct(uartDevice);
- // 从UART驱动的HCS中获取平台配置信息:串口控制器参数配置
- ret = UartDeviceGetResource(uartDevice, device->property);
- dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
- dri->GetUint32(resourceNode, "num", &resource->num, 0)
- dri->GetUint32(resourceNode, "base", &resource->base, 0)
- dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0)
- dri->GetUint32(resourceNode, "baudrate", &resource->baudrate, 0)
- dri->GetUint32(resourceNode, "wlen", &resource->wlen, 0)
- dri->GetUint32(resourceNode, "parity", &resource->parity, 0)
- dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0)
- dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0)
- UartSampleAddDev(host);
- UartDeviceInit(uartDevice);
- struct UartResource *resource = &device->resource;
- struct UartRegisterMap *regMap = (struct UartRegisterMap *)resource->physBase; // 获取物理寄存器地址,以便后续读写和设置
- /* Updating the system clock */
- device->uartClk = resource->uartClk;
- /* clear and reset registers. */
- UartPl011ResetRegisters(regMap); // 复位寄存器
- /* set baud rate as device config */
- err = UartPl011SetBaudrate(regMap, resource->uartClk, resource->baudrate); // 设置寄存器
- /* set the data format as device config */
- UartPl011SetDataFormat(regMap, resource->wlen, resource->parity, resource->stopBit);
- /* Enabling the FIFOs */
- BufferFifoInit(&device->rxFifo, g_fifoBuffer, UART_RX_FIFO_SIZE);
- device->state = UART_DEVICE_INITIALIZED; // 设置初始化完成标志位
- host->method = &g_uartSampleHostMethod; // 注册串口驱动接口,给用户层提供操作接口
- .Init = SampleInit,
- .Deinit = SampleDeinit,
- .Read = NULL,
- .Write = SampleWrite,
- device = (struct UartDevice *)host->priv; // 通过私有数据获得设备接口,和linux很像
- regMap = (struct UartRegisterMap *)device->resource.physBase; // 获取串口的物理寄存器基地址
- UartPl011Write(regMap, data[idx]); // 操作串口的底层接口
- .SetBaud = SampleSetBaud,
- device = (struct UartDevice *)host->priv;
- regMap = (struct UartRegisterMap *)device->resource.physBase;
- err = UartPl011SetBaudrate(regMap, device->uartClk, baudRate);
- device->baudrate = baudRate;
- .GetBaud = SampleGetBaud,
- device = (struct UartDevice *)host->priv;
- *baudRate = device->baudrate;
- .SetAttribute = NULL,
- .GetAttribute = NULL,
- .SetTransMode = NULL,
- // 释放UART
- static void HdfUartSampleRelease(struct HdfDeviceObject *device)
- host = UartHostFromDevice(device);
- SampleDetach(host);
- UartDeviceDeinit(uartDevice); // 解绑并释放UART驱动
- while (UartPl011IsBusy(regMap));
- UartPl011ResetRegisters(regMap);
- uart_clk_cfg(0, false);
- OsalIoUnmap((void *)device->resource.physBase);
- device->state = UART_DEVICE_UNINITIALIZED; // 设置设备释放完成标志位
- (void)OsalMemFree(uartDevice);
- UartHostDestroy(host);
复制代码目前SDK代码已经和官方文档里的代码不太一样了,主要是函数名称变了,大部分底层接口的函数名没有变化。通过跟踪串口驱动源码,可以发现harmony系统的很多框架和方法(驱动和设备树匹配,数据的传递等)都是参考Linux来设计的,不过具体的细节是不一样的。
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/include/uart_pl011_sample.h
- // 核心的串口寄存器
- struct UartRegisterMap {
- volatile uint32_t dr; /* Offset: 0x000 TYPE: (RW) Data register */
- union {
- volatile uint32_t rsr; /* Offset: 0x004 TYPE: (RO) Receive status register */
- volatile uint32_t ecr; /* Offset: 0x004 TYPE: (WO) Error clear register */
- };
- volatile uint32_t reserved0[4]; /* Offset: 0x008-0x014 Reserved */
- volatile uint32_t fr; /* Offset: 0x018 TYPE: (RO) Flag register */
- volatile uint32_t reserved1; /* Offset: 0x01C Reserved */
- volatile uint32_t ilpr; /* Offset: 0x020 TYPE: (RW) IrDA low-power counter register */
- volatile uint32_t ibrd; /* Offset: 0x024 TYPE: (RW) Integer baud rate register */
- volatile uint32_t fbrd; /* Offset: 0x028 TYPE: (RW) Fractional baud rate register */
- volatile uint32_t lcr; /* Offset: 0x02C TYPE: (RW) Line control register */
- volatile uint32_t cr; /* Offset: 0x030 TYPE: (RW) Control register */
- volatile uint32_t ifls; /* Offset: 0x034 TYPE: (RW) Interrupt FIFO level select register */
- volatile uint32_t imsc; /* Offset: 0x038 TYPE: (RW) Interrupt mask set/clear register */
- volatile uint32_t ris; /* Offset: 0x03C TYPE: (RO) Raw interrupt status register */
- volatile uint32_t mis; /* Offset: 0x040 TYPE: (RO) Masked interrupt status register */
- volatile uint32_t icr; /* Offset: 0x044 TYPE: (WO) Interrupt clear register */
- volatile uint32_t dmacr; /* Offset: 0x048 TYPE: (RW) DMA control register */
- };
- // 串口设置的一些基本参数
- struct UartResource {
- uint32_t num; /* UART port num */
- uint32_t base; /* UART PL011 base address */
- uint32_t irqNum; /* UART PL011 IRQ num */
- uint32_t baudrate; /* Default baudrate */
- uint32_t wlen; /* Default word length */
- uint32_t parity; /* Default parity */
- uint32_t stopBit; /* Default stop bits */
- uint32_t uartClk; /* UART clock */
- unsigned long physBase;
- };
- // 串口的busy寄存器
- static inline bool UartPl011IsBusy(struct UartRegisterMap *regMap)
- {
- return (bool)(regMap->fr & UART_PL011_FR_BUSY_MASK);
- }
- // 串口的写寄存器
- static inline void UartPl011Write(struct UartRegisterMap *regMap, uint8_t byte)
- {
- while (UartPl011IsBusy(regMap));
- regMap->dr = byte;
- }
复制代码$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_pl011_sample.c
- // 通过操作寄存器设置波特率
- UartPl011Error UartPl011SetBaudrate(struct UartRegisterMap *regMap, uint32_t clk, uint32_t baudrate)
- {
- uint32_t value = SAMPLING_FACTOR * baudrate;
- uint32_t divider = clk / value;
- uint32_t remainder = clk % value;
- uint32_t fraction;
- value = (SAMPLING_FACTOR * remainder) / baudrate;
- fraction = (value >> 1) + (value & 1);
- regMap->ibrd = divider;
- regMap->fbrd = fraction;
- // to internally update the contents of UARTIBRD or UARTFBRD, a UARTLCR_H write must always be performed at the end.
- UartPl011UpdateLcr(regMap);
- bool uartEnabled = UartPl011IsEnabled(regMap);
- UartPl011Disable(regMap);
- regMap->lcr = regMap->lcr;
- if (uartEnabled) {
- UartPl011Enable(regMap);
- }
- }
- // 复位寄存器
- void UartPl011ResetRegisters(struct UartRegisterMap *regMap)
- {
- regMap->cr = UART_PL011_DEFAULT_CTRL_REG_VALUE;
- regMap->dr = UART_PL011_DEFAULT_DATA_REG_VALUE;
- /* Clear all the errors */
- regMap->ecr = UART_PL011_DEFAULT_ECR_VALUE;
- regMap->ilpr = UART_PL011_DEFAULT_ILPR_VALUE;
- regMap->ibrd = UART_PL011_DEFAULT_IBRD_REG_VALUE;
- regMap->fbrd = UART_PL011_DEFAULT_FBRD_REG_VALUE;
- regMap->lcr = UART_PL011_DEFAULT_LCR_H_VALUE;
- regMap->ifls = UART_PL011_DEFAULT_IFLS_REG_VALUE;
- /* Clear all interrupt mask */
- regMap->imsc = UART_PL011_DEFAULT_IMSC_REG_VALUE;
- /* Clear all interrupts */
- regMap->icr = UART_PL011_DEFAULT_ICR_VALUE;
- regMap->dmacr = UART_PL011_DEFAULT_DMACR_VALUE;
- }
复制代码$ vi ~/harmony/sdk/drivers/hdf/frameworks/support/platform/src/uart_core.c
- void UartHostDestroy(struct UartHost *host)
- OsalMemFree(host);
- // 创建串口主机控制器驱动
- struct UartHost *UartHostCreate(struct HdfDeviceObject *device)
- struct UartHost *host = NULL;
- host = (struct UartHost *)OsalMemCalloc(sizeof(*host)); // 创建串口主机控制器新的资源空间
- host->device = device; // 主机驱动和设备驱动关联在一起?
- device->service = &(host->service); // 设备获取主机提供的服务接口?
- host->priv = NULL;
- host->method = NULL;
复制代码$ vi ~/harmony/sdk/drivers/hdf/frameworks/support/platform/include/uart_core.h
- static inline struct UartHost *UartHostFromDevice(struct HdfDeviceObject *device)
- return (device == NULL) ? NULL : (struct UartHost *)device->service;
复制代码$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_dev_sample.c
- // 添加串口设备驱动
- void UartSampleAddDev(struct UartHost *host)
- UartSampleAddRemoveDev(host, true); // (struct UartHost *host, bool add)
- devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
- ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/uartdev-%d", host->num);
- if (add) {
- register_driver(devName, &g_uartSampleDevFops, HDF_UART_FS_MODE, host)
- } else {
- unregister_driver(devName)
- }
- OsalMemFree(devName);
- // 提供给用户空间的统一系统调用接口
- const struct file_operations_vfs g_uartSampleDevFops = {
- .open = UartSampleDevOpen,
- .close = UartSampleRelease,
- .read = UartSampleRead,
- .write = UartSampleWrite,
- .ioctl = UartSampleDevIoctl,
- };
- static int32_t UartSampleDevOpen(FAR struct file *filep)
- inode = (struct inode *)filep->f_inode;
- host = (struct UartHost *)inode->i_private;
- static int32_t UartSampleRelease(FAR struct file *filep)
- inode = (struct inode *)filep->f_inode;
- host = (struct UartHost *)inode->i_private;
- static ssize_t UartSampleRead(FAR struct file *filep, FAR char *buf, size_t count)
- inode = (struct inode *)filep->f_inode;
- host = (struct UartHost *)inode->i_private;
- if (LOS_IsUserAddressRange((vaddr_t)buf, count)) {
- tmpBuf = (uint8_t *)OsalMemCalloc(count);
- ret = UartHostRead(host, tmpBuf, count);
- ret = LOS_ArchCopyToUser(buf, tmpBuf, count);
- } else {
- return UartHostRead(host, (uint8_t *)buf, count);
- }
- }
- static ssize_t UartSampleWrite(struct file *filep, const char *buf, size_t count)
- inode = (struct inode *)filep->f_inode;
- host = (struct UartHost *)inode->i_private;
- if (LOS_IsUserAddressRange((vaddr_t)buf, count)) {
- tmpBuf = (uint8_t *)OsalMemCalloc(count);
- ret = LOS_ArchCopyFromUser(tmpBuf, buf, count);
- ret = UartHostWrite(host, tmpBuf, count);
- } else {
- return UartHostWrite(host, (uint8_t *)buf, count);
- }
- static int32_t UartSampleDevIoctl(FAR struct file *filep, int32_t cmd, unsigned long arg)
- inode = (struct inode *)filep->f_inode;
- host = (struct UartHost *)inode->i_private;
- switch (cmd) {
- case UART_CFG_BAUDRATE:
- ret = UartHostSetBaud(host, arg);
- default:
- ret = HDF_ERR_NOT_SUPPORT;
- }
- // 下面三个函数就是之前在uart_sample.c中注册的g_uartSampleHostMethod提供的具体的函数
- // $ vi ~/harmony/sdk/drivers/hdf/frameworks/support/platform/include/uart_core.h
- static inline int32_t UartHostRead(struct UartHost *host, uint8_t *data, uint32_t size)
- return host->method->Read(host, data, size);
- static inline int32_t UartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size)
- return host->method->Write(host, data, size);
- static inline int32_t UartHostSetBaud(struct UartHost *host, uint32_t baudRate)
- return host->method->SetBaud(host, baudRate);
复制代码$ vi ~/harmony/sdk/third_party/NuttX/fs/driver/fs_registerdriver.c
- // NuttX,参考了这个开源系统的源码?
- // 注册新设备
- int register_driver(FAR const char *path, FAR const struct file_operations_vfs *fops,
- mode_t mode, FAR void *priv)
- {
- inode_semtake();
- ret = inode_reserve(path, &node);
- if (ret >= 0)
- {
- INODE_SET_DRIVER(node);
- node->u.i_ops = fops;
- node->i_private = priv;
- ret = OK;
- }
- inode_semgive();
- }
复制代码$ vi ~/harmony/sdk/third_party/NuttX/fs/inode/fs_inode.c
- // NuttX,参考了这个开源系统的源码?
- // 信号量获取
- void inode_semtake(void)
- {
- /* Do we already hold the semaphore? */
- me = getpid();
- if (me == g_inode_sem.holder)
- {
- /* Yes... just increment the count */
- g_inode_sem.count++;
- DEBUGASSERT(g_inode_sem.count > 0);
- }
- /* Take the semaphore (perhaps waiting) */
- else
- {
- while (sem_wait(&g_inode_sem.sem) != 0)
- {
- /* The only case that an error should occur here is if the wait was awakened by a signal.*/
- LOS_ASSERT(get_errno() == EINTR);
- }
-
- /* No we hold the semaphore */
- g_inode_sem.holder = me;
- g_inode_sem.count = 1;
- }
- }
- // 信号量释放
- void inode_semgive(void)
- {
- /* Is this our last count on the semaphore? */
- if (g_inode_sem.count > 1)
- {
- /* No.. just decrement the count */
- g_inode_sem.count--;
- }
- /* Yes.. then we can really release the semaphore */
- else
- {
- g_inode_sem.holder = NO_HOLDER;
- g_inode_sem.count = 0;
- (void)sem_post(&g_inode_sem.sem);
- }
- }
复制代码$ vi ~/harmony/sdk/third_party/NuttX/fs/inode/fs_inodereserve.c
- // 插入新的设备节点
- static void inode_insert(FAR struct inode *node,
- FAR struct inode *peer,
- FAR struct inode *parent)
- {
- /* If peer is non-null, then new node simply goes to the right
- * of that peer node.
- */
- if (peer)
- {
- node->i_peer = peer->i_peer;
- peer->i_peer = node;
- }
- /* If parent is non-null, then it must go at the head of its
- * list of children.
- */
- else if (parent)
- {
- node->i_peer = parent->i_child;
- parent->i_child = node;
- }
- /* Otherwise, this must be the new root_inode */
- else
- {
- node->i_peer = g_root_inode;
- g_root_inode = node;
- }
- }
- // 注册设备时添加设备节点
- int inode_reserve(FAR const char *path, FAR struct inode **inode_ptr)
- {
- /* Find the location to insert the new subtree */
- pathnode = inode_search(&name, &left, &parent, &relpath);
- /* Now we now where to insert the subtree */
- for (; ; ) {
- /* Create a new node -- we need to know if this is the
- * the leaf node or some intermediary. We can find this
- * by looking at the next name.
- */
- FAR const char *next_name = inode_nextname(name);
- if (*next_name) {
- /* Insert an operationless node */
- node = inode_alloc(name);
- if (node) {
- inode_insert(node, left, parent);
- /* Set up for the next time through the loop */
- name = next_name;
- left = NULL;
- parent = node;
- continue;
- }
- } else {
- node = inode_alloc(name);
- if (node) {
- inode_insert(node, left, parent);
- *inode_ptr = node;
- return OK;
- }
- }
- }
- }
复制代码在编译脚本中增加示例UART驱动模块
$ vi ~/harmony/sdk/vendor/huawei/hdf/hdf_vendor.mk
- # lib path
- LITEOS_LD_PATH += -L$(VENDOR_HDF_DRIVERS_PLATFORM_ROOT)/libs/$(LITEOS_PLATFORM)
- LITEOS_LD_PATH += -L$(VENDOR_HDF_DRIVERS_ROOT)/libs/$(LITEOS_PLATFORM)
- +LITEOS_BASELIB += -lhdf_uart_sample
- +LIB_SUBDIRS += $(VENDOR_HDF_DRIVERS_ROOT)/sample/platform/uart
- // 匹配~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
复制代码
四、用户程序和驱动交互代码
UART驱动成功初始化后,会创建/dev/uartdev-5设备节点,通过设备节点与UART驱动交互的代码如下:
$ vi ~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/dev/hello_uart_dev.c
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "hdf_log.h"
- #define HDF_LOG_TAG "hello_uart"
- #define INFO_SIZE 16
- int main(void)
- {
- int ret;
- int fd;
- const char info[INFO_SIZE] = {" HELLO UART! "};
- fd = open("/dev/uartdev-5", O_RDWR);
- if (fd < 0) {
- HDF_LOGE("hello_uart uartdev-5 open failed %d", fd);
- return -1;
- }
- ret = write(fd, info, INFO_SIZE);
- if (ret != 0) {
- HDF_LOGE("hello_uart write uartdev-5 ret is %d", ret);
- }
- ret = close(fd);
- if (ret != 0) {
- HDF_LOGE("hello_uart uartdev-5 close failed %d", fd);
- return -1;
- }
- return ret;
- }
复制代码用户空间的应用开发和Linux基本一样。
在产品配置的hdf子系统下增加hello_uart_sample组件:
$ vi ~/harmony/sdk/build/lite/product/ipcamera_hi3516dv300.json
- {
- "subsystem": [
- {
- "name": "hdf",
- "component": [
- { "name": "posix", "dir": "//drivers/hdf/lite/posix:hdf_posix", "features":[] },
- { "name": "manager", "dir": "//drivers/hdf/lite/manager:hdf_manager", "features":[] },
- { "name": "wifi", "dir": "//vendor/huawei/hdf/wifi:wifi_firmware", "features":[] },
- { "name": "display", "dir": "//vendor/huawei/hdf/display/hdi:hdi_display", "features":[] },
- { "name": "input", "dir": "//vendor/huawei/hdf/input/hdi:hdi_input", "features":[] },
- + { "name": "hdf_sample", "dir": "//vendor/huawei/hdf/sample/platform/uart:hello_uart_sample", "features":[] }
- ]
- },
- ]
- }
复制代码如上代码均为示例代码,完整代码可以在vendor/huawei/hdf/sample查看。示例代码默认不参与编译,需要手动添加到编译脚本中。
五、小结
总共修改六个部分代码(驱动和应用示例由官方写好了,主要添加四项配置):
驱动源码:~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c
HDF框架驱动配置:~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs
HDF框架设备配置:~/harmony/sdk/vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs
驱动模块编译配置:~/harmony/sdk/vendor/huawei/hdf/hdf_vendor.mk
应用源码:~/harmony/sdk/vendor/huawei/hdf/sample/platform/uart/dev/hello_uart_dev.c
应用配置:~/harmony/sdk/build/lite/product/ipcamera_hi3516dv300.json
六 、编译
$ ./build.sh
拷贝到Windows共享目录中:
$ rm /mnt/hgfs/proj-harmony/images/out/ -rf
$ cp -rf out/ /mnt/hgfs/proj-harmony/images/
七 、烧录
下面烧写新增了uart5驱动和串口测试应用的系统:
hisilicon # setenv bootcmd "mmc read 0x0 0x80000000 0x800 0x3000; go 0x80000000";
hisilicon # setenv bootargs "console=ttyAMA0,115200n8 root=emmc fstype=vfat rootaddr=7M rootsize=15M rw";
hisilicon # saveenv
hisilicon # reset
重启后进入系统。
八、测试
在根目录下,在命令行输入指令“./bin/hello_uart”执行写入的demo程序,显示成功结果如下所示:
- OHOS # ./bin/hello_uart
- OHOS # HELLO UART!
复制代码
本文结束,感谢您的阅读!