README_zh.md
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