1# Niobe407开发板OpenHarmony基于HDF驱动框架编程开发——GPIO 2本示例将演示如何在Niobe407开发板上通过HDF驱动框架,使用GPIO按键中断。 3 4 5## 编译调试 6- 进入//kernel/liteos_m目录, 在menuconfig配置中进入如下选项: 7 8 `(Top) → Platform → Board Selection → select board niobe407 → use talkweb niobe407 application → niobe407 application choose` 9 10- 选择 `201_hdf_gpio_key` 11 12- 在menuconfig的`(Top) → Driver`选项中使能如下配置: 13 14``` 15 [*] Enable Driver 16 [*] HDF driver framework support 17 [*] Enable HDF platform driver 18 [*] Enable HDF platform gpio driver 19``` 20- 回到sdk根目录,执行`hb build -f`脚本进行编译。 21 22### 运行结果 23 24示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志 25``` 26Entering scheduler 27[HDF:E/HDF_LOG_TAG]DeviceManagerStart in 28[HDF:I/devmgr_service]start svcmgr result 0 29[HDF:I/hcs_blob_if]CheckHcsBlobLength: the blobLength: 1884, byteAlign: 1 30[HDF:I/device_node]launch devnode HDF_PLATFORM_GPIO 31GpioDriverBind 32[HDF:I/gpio_manager]GpioManagerAdd: start:0 count:8 added success 33[HDF:D/HDF_LOG_TAG]PlatformManagerAddDevice: add dev:(null)(0) to PLATFORM_MODULE_GPIO success 34[HDF:D/HDF_LOG_TAG]PlatformDeviceAdd: add dev:(null)(0) success 35[HDF:E/HDF_LOG_TAG]HdfDriverManagerGetDriver:driver STM_TW_SPI_MODULE_HDF not found 36[HDF:E/devhost_service_clnt]failed to install driver HDF_PLATFORM_SPI_0, ret = -207 37hiview init success. 38[HDF:E/HDF_LOG_TAG]HdfGpioTestEntry: mode:2 39``` 40 41当按下开发板上的按钮sw2时,点亮或者点灭, 按下开发板上按钮sw3时, 绿灯点亮或者点灭 ,可通过串口助手查看到如下日志: 42``` 43[HDF:E/HDF_LOG_TAG]TestCaseGpioIrqHandler1: irq triggered! on gpio:2, data=(nil) 44[HDF:E/gpio_stm32_c]GpioDevWrite 433 ,write pin num 5 45[HDF:E/HDF_LOG_TAG]TestCaseGpioIrqHandler1: irq triggered! on gpio:2, data=(nil) 46[HDF:E/gpio_stm32_c]GpioDevWrite 433 ,write pin num 5 47[HDF:E/HDF_LOG_TAG]TestCaseGpioIrqHandler2: irq triggered! on gpio:3, data=(nil) 48[HDF:E/gpio_stm32_c]GpioDevWrite 433 ,write pin num 6 49``` 50## GPIO HDF hcs配置文件解析 51- device_gpio_info 在/device/board/talkweb/niobe407/sdk/hdf_config/device_gpio_info.hcs 52``` 53root { 54 module = "talkweb,stm32f407"; 55 device_info { 56 match_attr = "hdf_manager"; 57 template host { 58 hostName = ""; 59 priority = 100; 60 template device { 61 template deviceNode { //gpio信息的模板,集成模板可以缺省 62 policy = 0; 63 priority = 100; 64 preload = 0; 65 permission = 0664; 66 moduleName = ""; 67 serviceName = ""; 68 deviceMatchAttr = ""; 69 } 70 } 71 } 72 platform :: host { 73 hostName = "platform_host"; 74 priority = 50; 75 device_gpio :: device { 76 gpio0 :: deviceNode { 77 policy = 2; 78 priority = 60; //权限决定加载的顺序 79 moduleName = "STM_TW_GPIO_MODULE_HDF"; 80 serviceName = "HDF_PLATFORM_GPIO";//驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 81 deviceMatchAttr = "gpio_config"; // 与hdf_gpio_.hcs中的config匹配 82 } 83 } 84 } 85 } 86} 87``` 88- hdf_gpio.hcs解析 在/device/board/talkweb/niobe407/sdk/hdf_config/目录下,配置具体gpio引脚的信息 89``` 90#include "device_gpio_info.hcs" // 包含具体的device_info文件 91root { 92 platform { 93 gpio_config { 94 match_attr = "gpio_config"; // 与device_gpio_info.hcs中的deviceMatchAttr对应 95 pin = [0, 1, 2, 3]; // 框架注册pin号,在使用接口时用作GPIO号来使用 96 realPin = [5, 6, 0, 1]; // 与pin对应的真实的在stm32中真实的引脚编号(0-15)开发板,此示例为 led2 pe5, led3 pe6, key1按键终端 pe0,sw2, key2按键终端pe1,sw3 97 group = [4, 4, 4, 4]; // gpio引脚所属的group 0到8 分别对应GPIOA~GPIOI,此例4个gpio属于GPIOE 98 mode = [1, 1, 0, 0]; // 0: input 1: output 2:alternate 3:analog 99 speed = [0, 0, 0, 0]; // 0: low 1: middle 2:high 3:very_high 100 pull = [0, 0, 0, 0]; // 0: nopull 1:up 2:down 101 pinNum = 4; //总注册gpio个数 如果发现因为加载的gpio个数过多导致无法申请到锁资源,可修改target_config.h中的LOSCFG_BASE_IPC_MUX_LIMIT 增大锁的数量限制 102 output = [0, 0, 0, 0]; // 0:pushpull 1:opendrain 103 alternate = [0, 0, 0, 0]; // 对应的stm32的管脚复用功能gpio作为每种外设都对应一种复用功能(0-15,具体参考编程手册) 104 } 105 } 106} 107``` 108## 接口说明 109 110``` 111 1.读写GPIO管脚, 如果要读取一个GPIO管脚电平,通过以下函数完成: 112 int32_t GpioRead(uint16_t gpio, uint16_t *val); 113 参数说明: 114 gpio: 对应hcs文件中的pin号 115 val: 存储读取的值 116 返回值: 117 0: 读取成功 118 负数:读取失败 119 1202.如果要向GPIO管脚写入电平值,通过以下函数完成: 121int32_t GpioWrite(uint16_t gpio, uint16_t val); 122参数说明: 123 gpio: 对应hcs文件中的pin号 124 val: 需要设置的电平值 125返回值: 126 0: 设置成功 127 负数:设置失败 1283.如果要为一个GPIO管脚设置中断响应程序,使用如下函数: 129int32_t GpioSetIrq(uint16_t gpio, uint16_t mode, GpioIrqFunc func, void *arg); 130参数说明: 131 gpio: 对应hcs文件中的pin号 132 mode: 中断触发模式 133 func: 中断回调函数 134 arg: 回调函数参数 135返回值: 136 0: 设置成功 137 负数:设置失败 1384.当不再需要响应中断服务函数时,使用如下函数取消中断设置: 139int32_t GpioUnSetIrq(uint16_t gpio); 140参数说明: 141 gpio: 对应hcs文件中的pin号 142返回值: 143 0: 设置成功 144 负数:设置失败 1455.在中断服务程序设置完成后,还需要先通过如下函数使能GPIO管脚的中断: 146int32_t GpioEnableIrq(uint16_t gpio); 147参数说明: 148 gpio: 对应hcs文件中的pin号 149返回值: 150 0: 使能成功 151 负数: 使能失败 1526.如果要临时屏蔽此中断,可以通过如下函数禁止GPIO管脚中断 153int32_t GpioDisableIrq(uint16_t gpio); 154参数说明: 155 gpio: 对应hcs文件中的pin号 156返回值: 157 0: 禁止成功 158 负数: 禁止失败 159``` 160## 示例代码 161``` c 162/* 中断服务函数*/ 163static int32_t TestCaseGpioIrqHandler1(uint16_t gpio, void *data) // pin2 回调函数 164{ 165 HDF_LOGE("%s: irq triggered! on gpio:%u, data=%p", __func__, gpio, data); 166 uint16_t val = 0; 167 GpioRead(0, &val); // 读取pin0 的电平值,中断产生则设置相反的电平 168 if (val) { 169 GpioWrite(0, 0); 170 } else { 171 GpioWrite(0, 1); 172 } 173} 174 175static int32_t TestCaseGpioIrqHandler2(uint16_t gpio, void *data) // pin3 回调函数 176{ 177 HDF_LOGE("%s: irq triggered! on gpio:%u, data=%p", __func__, gpio, data); 178 uint16_t val = 0; 179 GpioRead(1, &val); // 读取pin1 的电平值,中断产生则设置相反的电平 180 if (val) { 181 GpioWrite(1, 0); 182 } else { 183 GpioWrite(1, 1); 184 } 185} 186 187 188static void* HdfGpioTestEntry(void* arg) 189{ 190 int32_t ret; 191 uint16_t valRead; 192 uint16_t mode; 193 uint16_t gpio0 = 0; // hcs 中对应的pin值 194 uint16_t gpio1 = 1; 195 uint16_t gpio2 = 2; 196 uint16_t gpio3 = 3; 197 uint32_t timeout; 198 mode = OSAL_IRQF_TRIGGER_FALLING; 199 HDF_LOGE("%s: mode:%0x\n", __func__, mode); 200 ret = GpioSetIrq(gpio2, mode, TestCaseGpioIrqHandler1, NULL); // 设置中断函数 201 if (ret != HDF_SUCCESS) { 202 HDF_LOGE("%s: set irq fail! ret:%d\n", __func__, ret); 203 return ret; 204 } 205 206 ret = GpioSetIrq(gpio3, mode, TestCaseGpioIrqHandler2, NULL); // 设置中断函数 207 if (ret != HDF_SUCCESS) { 208 HDF_LOGE("%s: set irq fail! ret:%d\n", __func__, ret); 209 return ret; 210 } 211 212 ret = GpioEnableIrq(gpio2); // 使能中断 213 if (ret != HDF_SUCCESS) { 214 HDF_LOGE("%s: enable irq fail! ret:%d\n", __func__, ret); 215 return ret; 216 } 217 218 ret = GpioEnableIrq(gpio3); // 使能中断 219 if (ret != HDF_SUCCESS) { 220 HDF_LOGE("%s: enable irq fail! ret:%d\n", __func__, ret); 221 return ret; 222 } 223} 224``` 225