如何从devicetree中获取GPIO并将其映射到软件中
可参考文章:https://www.cnblogs.com/jayant97/articles/18141263https://github.com/aiminhua/ncs_samples/blob/master/ble_comprehensive/src/io_int_thread.c 我们从两个简单的参考例子开始: ncs/zephyr/samples/basic/blinky/sr
可参考文章:
https://www.cnblogs.com/jayant97/articles/18141263
https://github.com/aiminhua/ncs_samples/blob/master/ble_comprehensive/src/io_int_thread.c
我们从两个简单的参考例子开始:
ncs/zephyr/samples/basic/blinky/src/main.c
ncs/zephyr/samples/basic/button/src/main.c
2.1 devicetree 中的GPIO描述
gpio0: gpio@10a000 {
compatible = "nordic,nrf-gpio";
gpio-controller;
reg = < 0x10a000 0x300 >;
#gpio-cells = < 0x2 >;
ngpios = < 0x5 >;
status = "okay";
port = < 0x0 >;
gpiote-instance = < &gpiote30 >;
};
gpio1: gpio@d8200 {
compatible = "nordic,nrf-gpio";
gpio-controller;
reg = < 0xd8200 0x300 >;
#gpio-cells = < 0x2 >;
ngpios = < 0x10 >;
status = "okay";
port = < 0x1 >;
gpiote-instance = < &gpiote20 >;
phandle = < 0xd >;
};
gpio2: gpio@50400 {
...
};
参考文件:
ncs/zephyr/dts/bindings/gpio/nordic,nrf-gpio.yaml
ncs/zephyr/include/zephyr/dt-bindings/gpio/gpio.h
ncs/zephyr/include/zephyr/drivers/gpio.h
a.节点名:gpio@10a000;gpio@d8200;gpio@d8200
b.标签:gpio0;gpio1;gpio2
c.gpio-controller: 声明具有域控制器功能
d.reg: 外设在总线上的地址分布,需跟节点名对应
e.phandle:一个节点node1可以通过phandle被另一节点node2引用作为属性值
f.gpiote-instance:指向外部gpiote节点的phandle属性,表明可使用该GPIO port的gpiote实体
g.ngpios:所在GPIO Port(槽位)中最大可用GPIO口的数目。如对于nrf54L15:
gpio0(port0): ngpios = < 0xb >; => P0.00~P0.10
gpio1(port1): ngpios = < 0x10 >; =>P1.00~P1.15
gpio2(port2): ngpios = < 0x5 >; =>P2.00~P2.04
h.gpio-reserved-ranges:为系统保留的gpio口,用户不可以直接使用.比如:
"gpio-reserved-ranges = [5,3]": 表明GPIO pin脚偏移为5,6,7的IO口为系统保留
"gpio-reserved-ranges = <0 2>,<10 1>": 表明GPIO pin脚偏移为0, 1,10的IO口为系统保留, 即使定义了ngpios = <0xb>
i.#gpio-cells:gpio节点作为controller时的specifier参数数量。比如#gpio-cells = < 0x2 >; 意味着在其他节点中引用gpio0控制器时,specifier参数数量为2,如:
led0: led_0 {
gpios = < &gpio2 0x9 0x0 >;
label = "Green LED 0";
};
&gpio2:指gpio2控制器, 对应物理上的gpio port2
0x9: 指pin脚编号是0x9,即P2.09
0x0: devicetree中定义的GPIO口配置参数,在软件中有时被描述为flag(s),0x0等价于GPIO_ACTIVE_HIGH |GPIO_PUSH_PULL |GPIO_LINE_OPEN_SOURCE
补充说明:
GPIO_ACTIVE_HIGH: GPIO口高有效(有效指逻辑1)
GPIO_PUSH_PULL: 配置GPIO输出为推挽模式
PIO_LINE_OPEN_SOURCE:单端开源模式(线或)
2.2 代码中如何让获取&配置GPIO?
gpio及其配置更多时候是作为某个节点的属性出现,如button节点的GPIO属性,led节点的gpio属性;spi的cs-gpio属性等等
spi@abcd0001 {
cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
spidev: spi-device@0 { ... };
};
buttons {
compatible = "gpio-keys";
button0: button_0 {
gpios = < &gpio1 0xd 0x11 >;
label = "Push button 0";
zephyr,code = < 0xb >;
};
button1: button_1 { ...};
nrf52840_reset: gpio-reset {
compatible = "nordic,nrf9160dk-nrf52840-reset";
status = "disabled";
gpios = < &interface_to_nrf52840 0x9 0x1 >;
};
aliases {
led00 = &led0;
pwm-led0 = &pwm_led1;
sw0 = &button0;
};
spi@abcd0001, buttons, button_0, button_1, gpio-reset为devicetree中的节点名(node name)
button0,button1,nrf52840_reset,为节点的标签(LABEL)
led00, pwm-led0,sw0为节点的别名(ALIAS)
对于GPIO的应用,也可以系统预留给用户自定义的节点(zephyr,user)中将其定义为属性:
/{
zephyr,user{
my-gpios = <&gpio0 12 (GPIO_ACTIVE_HIGH|GPIO_PUSH_PULL|GPIO_PULL_DOWN)>;
};
};
2.2.1.获取节点描述符node specifier,即node_id
参考文件:ncs/zephyr/doc/build/dts/api-usage.rst
通过标签获取:DT_NODELABEL()
通过别名获取: DT_ALIAS(sw0);DT_ALIAS(led00) //sw0,led00分别为button0,led0的别名
通过绝对路径获取:DT_PATH(zephyr_user);DT_PATH(leds);DT_PATH(soc,gpio_50400)
通过实体编号获取:DT_INST()
通过被选取的节点chosen node获取:DT_CHOSEN()
通过父节点/子节点获取:DT_PARENT(); DT_CHILD() ;
通过node2及其phandle属性获取node1的节点描述符: node1=DT_PHANDLE(node2, prop)
\- DT_PATH(zephyr_user, i2c_40002000)
\- DT_NODELABEL(i2c1)
\- DT_ALIAS(sensor_controller)
\- DT_INST(x, vnd_soc_i2c)
2.2.2通过节点将gpio配置(属性)读取至特定结构体中
gpio_dt_sepc my_gpio=GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), my_gpios)
gpio_dt_spec myled = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); //节点id,属性名
gpio_dt_spec mybutton = GPIO_DT_SPEC_GET_OR(DT_ALIAS(sw0), gpios,{0}); // 节点id,属性名,默认值
以上是gpio-button作为特殊设备的直接获取方式,对于一般的外设如uart/spi等,可以用DEVICE_DT_GET()获取设备。
2.2.3.重新配置gpio参数
GPIO的默认配置来源于devicetree,我们可以用以下方式覆盖默认配置:
参考文档:2.8.0/zephyr/include/zephyr/drivers/gpio.h
a.配置输入输出:
gpio_pin_configure_dt(&mybutton, GPIO_INPUT);
gpio_pin_configure_dt(&myled, GPIO_OUTPUT);
b.设置/获取IO口状态
gpio_pin_toggle_dt(&myled);
gpio_pin_get_dt(&mybutton);
gpio_pin_set_dt(&myled, 1);
c.配置中断
gpio_pin_interrupt_configure_dt()
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
gpio_add_callback_dt() => gpio_add_callback(spec->port, callback);
gpio_add_callback(button.port, &button_cb_data);
d.其他配置
gpio_remove_callback_dt()
gpio_get_pending_int()
更多推荐
所有评论(0)