开发Hi3516第一个驱动程序示例

    参考“开发Hi3516第一个应用程序示例”获取源码。

    下面基于HDF框架,提供一个简单的UART(Universal Asynchronous Receiver/Transmitter)平台驱动开发样例,包含配置文件的添加,驱动代码的实现以及用户态程序和驱动交互的流程。驱动程序源码位于vendor/huawei/hdf/sample目录。

    1. 添加配置。

      在HDF框架的驱动配置文件(例如vendor/hisi/hi35xx/hi3516dv300/config/uart/uart_config.hcs)中添加该驱动的配置信息,如下所示:

      在HDF框架的设备配置文件(例如vendor/hisi/hi35xx/hi3516dv300/config/device_info/device_info.hcs)中添加该驱动的设备节点信息,如下所示:

      1. device_info {
      2. platform :: host {
      3. hostName = "platform_host";
      4. priority = 50;
      5. device_uart :: device {
      6. device5 :: deviceNode {
      7. policy = 2;
      8. priority = 10;
      9. permission = 0660;
      10. moduleName = "UART_SAMPLE";
      11. serviceName = "HDF_PLATFORM_UART_5";
      12. deviceMatchAttr = "sample_uart_5";
      13. }
      14. }
      15. }
      16. }
      17. }
    2. 注册UART驱动入口。

      基于HDF框架注册UART驱动的入口HdfDriverEntry,代码如下:

      1. // 绑定UART驱动接口到HDF框架
      2. static int32_t HdfUartSampleBind(struct HdfDeviceObject *device)
      3. {
      4. if (device == NULL) {
      5. return HDF_ERR_INVALID_OBJECT;
      6. }
      7. HDF_LOGI("Enter %s:", __func__);
      8. return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
      9. }
      10. // 从UART驱动的HCS中获取配置信息
      11. static uint32_t UartDeviceGetResource(
      12. struct UartDevice *device, const struct DeviceResourceNode *resourceNode)
      13. {
      14. struct UartResource *resource = &device->resource;
      15. struct DeviceResourceIface *dri = NULL;
      16. dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
      17. if (dri == NULL || dri->GetUint32 == NULL) {
      18. HDF_LOGE("DeviceResourceIface is invalid");
      19. return HDF_FAILURE;
      20. }
      21. if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) {
      22. HDF_LOGE("uart config read num fail");
      23. return HDF_FAILURE;
      24. }
      25. if (dri->GetUint32(resourceNode, "base", &resource->base, 0) != HDF_SUCCESS) {
      26. HDF_LOGE("uart config read base fail");
      27. return HDF_FAILURE;
      28. }
      29. resource->physBase = (unsigned long) OsalIoRemap(resource->base, 0x48);
      30. if (resource->physBase == 0) {
      31. HDF_LOGE("uart config fail to remap physBase");
      32. return HDF_FAILURE;
      33. }
      34. if (dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0) != HDF_SUCCESS) {
      35. HDF_LOGE("uart config read irqNum fail");
      36. return HDF_FAILURE;
      37. }
      38. if (dri->GetUint32(resourceNode, "baudrate", &resource->baudrate, 0) != HDF_SUCCESS) {
      39. HDF_LOGE("uart config read baudrate fail");
      40. return HDF_FAILURE;
      41. }
      42. if (dri->GetUint32(resourceNode, "wlen", &resource->wlen, 0) != HDF_SUCCESS) {
      43. HDF_LOGE("uart config read wlen fail");
      44. return HDF_FAILURE;
      45. }
      46. if (dri->GetUint32(resourceNode, "parity", &resource->parity, 0) != HDF_SUCCESS) {
      47. HDF_LOGE("uart config read parity fail");
      48. return HDF_FAILURE;
      49. }
      50. if (dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0) != HDF_SUCCESS) {
      51. HDF_LOGE("uart config read stopBit fail");
      52. }
      53. if (dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0) != HDF_SUCCESS) {
      54. return HDF_FAILURE;
      55. }
      56. return HDF_SUCCESS;
      57. }
      58. // 将UART驱动的配置和接口附加到HDF驱动框架
      59. static int32_t SampleAttach(struct UartHost *host, struct HdfDeviceObject *device)
      60. {
      61. int32_t ret;
      62. struct UartDevice *uartDevice = NULL;
      63. if (device->property == NULL) {
      64. HDF_LOGE("%s: property is NULL", __func__);
      65. return HDF_FAILURE;
      66. }
      67. uartDevice = (struct UartDevice *) OsalMemCalloc(sizeof(struct UartDevice));
      68. if (uartDevice == NULL) {
      69. HDF_LOGE("%s: OsalMemCalloc uartDevice error", __func__);
      70. return HDF_ERR_MALLOC_FAIL;
      71. }
      72. ret = UartDeviceGetResource(uartDevice, device->property);
      73. if (ret != HDF_SUCCESS) {
      74. (void) OsalMemFree(uartDevice);
      75. return HDF_FAILURE;
      76. }
      77. host->num = uartDevice->resource.num;
      78. host->priv = uartDevice;
      79. UartSampleAddDev(host); // 添加用户态UART设备节点,具体实现见源码uart_dev_sample
      80. return UartDeviceInit(uartDevice); // 初始化UART PL011,具体实现见源码uart_pl011_sample
      81. }
      82. // 初始化UART驱动
      83. static int32_t HdfUartSampleInit(struct HdfDeviceObject *device)
      84. {
      85. int32_t ret;
      86. struct UartHost *host = NULL;
      87. if (device == NULL) {
      88. HDF_LOGE("%s: device is NULL", __func__);
      89. return HDF_ERR_INVALID_OBJECT;
      90. }
      91. HDF_LOGI("Enter %s:", __func__);
      92. host = UartHostFromDevice(device);
      93. if (host == NULL) {
      94. HDF_LOGE("%s: host is NULL", __func__);
      95. return HDF_FAILURE;
      96. }
      97. ret = SampleAttach(host, device);
      98. if (ret != HDF_SUCCESS) {
      99. HDF_LOGE("%s: attach error", __func__);
      100. return HDF_FAILURE;
      101. }
      102. host->method = &g_uartSampleHostMethod;
      103. return ret;
      104. }
      105. static void UartDeviceDeinit(struct UartDevice *device)
      106. {
      107. struct UartRegisterMap *regMap = (struct UartRegisterMap *) device->resource.physBase;
      108. /* wait for uart enter idle. */
      109. while (UartPl011IsBusy(regMap));
      110. UartPl011ResetRegisters(regMap);
      111. uart_clk_cfg(0, false);
      112. OsalIoUnmap((void *) device->resource.physBase);
      113. device->state = UART_DEVICE_UNINITIALIZED;
      114. }
      115. // 解绑并释放UART驱动
      116. static void SampleDetach(struct UartHost *host)
      117. {
      118. struct UartDevice *uartDevice = NULL;
      119. if (host->priv == NULL) {
      120. HDF_LOGE("%s: invalid parameter", __func__);
      121. }
      122. UartDeviceDeinit(uartDevice);
      123. (void) OsalMemFree(uartDevice);
      124. host->priv = NULL;
      125. }
      126. // 释放UART驱动
      127. static void HdfUartSampleRelease(struct HdfDeviceObject *device)
      128. {
      129. struct UartHost *host = NULL;
      130. HDF_LOGI("Enter %s:", __func__);
      131. if (device == NULL) {
      132. HDF_LOGE("%s: device is null", __func__);
      133. return;
      134. }
      135. host = UartHostFromDevice(device);
      136. if (host == NULL) {
      137. HDF_LOGE("%s: host is null", __func__);
      138. return;
      139. }
      140. if (host->priv != NULL) {
      141. SampleDetach(host);
      142. }
      143. UartHostDestroy(host);
      144. }
      145. struct HdfDriverEntry g_hdfUartSample = {
      146. .moduleVersion = 1,
      147. .moduleName = "UART_SAMPLE",
      148. .Bind = HdfUartSampleBind,
      149. .Init = HdfUartSampleInit,
      150. .Release = HdfUartSampleRelease,
      151. };
      152. HDF_INIT(g_hdfUartSample);
    3. 注册UART驱动接口。

      HDF框架提供了UART驱动接口的模板方法UartHostMethod,实现UART驱动接口的代码如下:

      在vendor/huawei/hdf/hdf_vendor.mk编译脚本中增加示例UART驱动模块,代码如下:

      1. LITEOS_BASELIB += -lhdf_uart_sample
      2. LIB_SUBDIRS += $(VENDOR_HDF_DRIVERS_ROOT)/sample/platform/uart
    4. 用户程序和驱动交互代码。

      1. #include <stdlib.h>
      2. #include <unistd.h>
      3. #include <fcntl.h>
      4. #include "hdf_log.h"
      5. #define HDF_LOG_TAG "hello_uart"
      6. #define INFO_SIZE 16
      7. int main(void)
      8. {
      9. int ret;
      10. int fd;
      11. const char info[INFO_SIZE] = {" HELLO UART! "};
      12. fd = open("/dev/uartdev-5", O_RDWR);
      13. if (fd < 0) {
      14. HDF_LOGE("hello_uart uartdev-5 open failed %d", fd);
      15. return -1;
      16. }
      17. ret = write(fd, info, INFO_SIZE);
      18. if (ret != 0) {
      19. HDF_LOGE("hello_uart write uartdev-5 ret is %d", ret);
      20. }
      21. ret = close(fd);
      22. if (ret != 0) {
      23. HDF_LOGE("hello_uart uartdev-5 close failed %d", fd);
      24. return -1;
      25. }
      26. return ret;
      27. }

      在build/lite/product/ipcamera_hi3516dv300.json产品配置的hdf子系统下增加hello_uart_sample组件,代码如下:

    参考示例1进行编译和烧写:、烧写

    1. 连接串口。

      图 1 连接串口图

    1. ![](/projects/openharmony-1.0-zh-cn/quick-start/figures/chuankou1.png)
    2. 1. 单击**Serial port**打开串口。
    3. 2. 输入"com11"串口编号并连续输入回车直到串口显示"hisillicon"
    1. (单板初次启动必选)修改U-boot的bootcmd及bootargs内容:该步骤为固化操作,若不修改参数只需执行一次。每次复位单板均会自动进入系统。

      表 1 U-boot启动参数

    2. 输入“reset”指令并回车,重启单板,启动成功如下图,输入回车串口显示OHOS字样。

      图 2 系统启动图

    1. ![](/projects/openharmony-1.0-zh-cn/quick-start/figures/qi1.png)

    恭喜,您已完成Hi3516 快速上手!建议您下一步进入带屏摄像头产品开发的学习 。