#2020征文-开发板#【 AI Camera连载】第一个驱动程序
一、前言
本文主要介绍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!
本文结束,感谢您的阅读!