#2020征文-开发板#【 AI Camera连载】第一个驱动程序

蓝初柳
发布于 2021-1-7 17:38
浏览
0收藏

一、前言
本文主要介绍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驱动和串口测试应用的系统:

#2020征文-开发板#【 AI Camera连载】第一个驱动程序-鸿蒙开发者社区

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!

 本文结束,感谢您的阅读!

分类
已于2021-1-7 17:38:27修改
收藏
回复
举报
回复
    相关推荐