开发Hi3516第一个驱动程序示例
参考“开发Hi3516第一个应用程序示例”获取源码。
下面基于HDF框架,提供一个简单的UART(Universal Asynchronous Receiver/Transmitter)平台驱动开发样例,包含配置文件的添加,驱动代码的实现以及用户态程序和驱动交互的流程。驱动程序源码位于vendor/huawei/hdf/sample目录。
添加配置。
在HDF框架的驱动配置文件(例如vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs)中添加该驱动的配置信息,如下所示:
在HDF框架的设备配置文件(例如vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs)中添加该驱动的设备节点信息,如下所示:
device_info {
platform :: host {
hostName = "platform_host";
priority = 50;
device_uart :: device {
device5 :: deviceNode {
policy = 2;
priority = 10;
permission = 0660;
moduleName = "UART_SAMPLE";
serviceName = "HDF_PLATFORM_UART_5";
deviceMatchAttr = "sample_uart_5";
}
}
}
}
}
注册UART驱动入口。
基于HDF框架注册UART驱动的入口HdfDriverEntry,代码如下:
// 绑定UART驱动接口到HDF框架
static int32_t HdfUartSampleBind(struct HdfDeviceObject *device)
{
if (device == NULL) {
return HDF_ERR_INVALID_OBJECT;
}
HDF_LOGI("Enter %s:", __func__);
return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
}
// 从UART驱动的HCS中获取配置信息
static uint32_t UartDeviceGetResource(
struct UartDevice *device, const struct DeviceResourceNode *resourceNode)
{
struct UartResource *resource = &device->resource;
struct DeviceResourceIface *dri = NULL;
dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
if (dri == NULL || dri->GetUint32 == NULL) {
HDF_LOGE("DeviceResourceIface is invalid");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read num fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "base", &resource->base, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read base fail");
return HDF_FAILURE;
}
resource->physBase = (unsigned long) OsalIoRemap(resource->base, 0x48);
if (resource->physBase == 0) {
HDF_LOGE("uart config fail to remap physBase");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read irqNum fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "baudrate", &resource->baudrate, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read baudrate fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "wlen", &resource->wlen, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read wlen fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "parity", &resource->parity, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read parity fail");
return HDF_FAILURE;
}
if (dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0) != HDF_SUCCESS) {
HDF_LOGE("uart config read stopBit fail");
}
if (dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0) != HDF_SUCCESS) {
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
// 将UART驱动的配置和接口附加到HDF驱动框架
static int32_t SampleAttach(struct UartHost *host, struct HdfDeviceObject *device)
{
int32_t ret;
struct UartDevice *uartDevice = NULL;
if (device->property == NULL) {
HDF_LOGE("%s: property is NULL", __func__);
return HDF_FAILURE;
}
uartDevice = (struct UartDevice *) OsalMemCalloc(sizeof(struct UartDevice));
if (uartDevice == NULL) {
HDF_LOGE("%s: OsalMemCalloc uartDevice error", __func__);
return HDF_ERR_MALLOC_FAIL;
}
ret = UartDeviceGetResource(uartDevice, device->property);
if (ret != HDF_SUCCESS) {
(void) OsalMemFree(uartDevice);
return HDF_FAILURE;
}
host->num = uartDevice->resource.num;
host->priv = uartDevice;
UartSampleAddDev(host); // 添加用户态UART设备节点,具体实现见源码uart_dev_sample
return UartDeviceInit(uartDevice); // 初始化UART PL011,具体实现见源码uart_pl011_sample
}
// 初始化UART驱动
static int32_t HdfUartSampleInit(struct HdfDeviceObject *device)
{
int32_t ret;
struct UartHost *host = NULL;
if (device == NULL) {
HDF_LOGE("%s: device is NULL", __func__);
return HDF_ERR_INVALID_OBJECT;
}
HDF_LOGI("Enter %s:", __func__);
host = UartHostFromDevice(device);
if (host == NULL) {
HDF_LOGE("%s: host is NULL", __func__);
return HDF_FAILURE;
}
ret = SampleAttach(host, device);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: attach error", __func__);
return HDF_FAILURE;
}
host->method = &g_uartSampleHostMethod;
return ret;
}
static void UartDeviceDeinit(struct UartDevice *device)
{
struct UartRegisterMap *regMap = (struct UartRegisterMap *) device->resource.physBase;
/* wait for uart enter idle. */
while (UartPl011IsBusy(regMap));
UartPl011ResetRegisters(regMap);
uart_clk_cfg(0, false);
OsalIoUnmap((void *) device->resource.physBase);
device->state = UART_DEVICE_UNINITIALIZED;
}
// 解绑并释放UART驱动
static void SampleDetach(struct UartHost *host)
{
struct UartDevice *uartDevice = NULL;
if (host->priv == NULL) {
HDF_LOGE("%s: invalid parameter", __func__);
}
UartDeviceDeinit(uartDevice);
(void) OsalMemFree(uartDevice);
host->priv = NULL;
}
// 释放UART驱动
static void HdfUartSampleRelease(struct HdfDeviceObject *device)
{
struct UartHost *host = NULL;
HDF_LOGI("Enter %s:", __func__);
if (device == NULL) {
HDF_LOGE("%s: device is null", __func__);
return;
}
host = UartHostFromDevice(device);
if (host == NULL) {
HDF_LOGE("%s: host is null", __func__);
return;
}
if (host->priv != NULL) {
SampleDetach(host);
}
UartHostDestroy(host);
}
struct HdfDriverEntry g_hdfUartSample = {
.moduleVersion = 1,
.moduleName = "UART_SAMPLE",
.Bind = HdfUartSampleBind,
.Init = HdfUartSampleInit,
.Release = HdfUartSampleRelease,
};
HDF_INIT(g_hdfUartSample);
注册UART驱动接口。
HDF框架提供了UART驱动接口的模板方法UartHostMethod,实现UART驱动接口的代码如下:
在vendor/huawei/hdf/hdf_vendor.mk编译脚本中增加示例UART驱动模块,代码如下:
LITEOS_BASELIB += -lhdf_uart_sample
LIB_SUBDIRS += $(VENDOR_HDF_DRIVERS_ROOT)/sample/platform/uart
用户程序和驱动交互代码。
#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;
}
在build/lite/product/ipcamera_hi3516dv300.json产品配置的hdf子系统下增加hello_uart_sample组件,代码如下:
参考示例1进行编译和烧写:、烧写。
连接串口。
图 1 连接串口图
![](/projects/openharmony-1.0-zh-cn/quick-start/figures/chuankou1.png)
1. 单击**Serial port**打开串口。
2. 输入"com11"串口编号并连续输入回车直到串口显示"hisillicon"。
(单板初次启动必选)修改U-boot的bootcmd及bootargs内容:该步骤为固化操作,若不修改参数只需执行一次。每次复位单板均会自动进入系统。
表 1 U-boot启动参数
输入“reset”指令并回车,重启单板,启动成功如下图,输入回车串口显示OHOS字样。
图 2 系统启动图
![](/projects/openharmony-1.0-zh-cn/quick-start/figures/qi1.png)
恭喜,您已完成Hi3516 快速上手!建议您下一步进入带屏摄像头产品开发的学习 。