我们在上一篇已经基于Zephyr 的demo 工程添加了shell(【Zephyr】MCXN947 Zephyr 开发入门适配shell),我们基于此基础上田间shell 命令来控制板子(MCXN947-FRDM)的LED功能。查看MCXN947-FRDM原理图,板子上的RGB LED 通过P0_10/P0_27/P1_2来控制。
Zephyr 的驱动使用设备树来描述硬件信息,驱动程序和硬件信息相隔离的方式管理驱动程序,以下是mcxn947(\zephyrproject\zephyr\dts\arm\nxp\nxp_mcxn94x_common.dtsi) 共通设备树文件中对GPIO节点的描述。
gpio0: gpio@96000 { compatible = "nxp,kinetis-gpio"; status = "disabled"; reg = <0x96000 0x1000>; interrupts = <17 0>,<18 0>; gpio-controller; #gpio-cells = <2>; nxp,kinetis-port = <&porta>; }; gpio1: gpio@98000 { compatible = "nxp,kinetis-gpio"; status = "disabled"; reg = <0x98000 0x1000>; interrupts = <19 0>,<20 0>; gpio-controller; #gpio-cells = <2>; nxp,kinetis-port = <&portb>; }; gpio2: gpio@9a000 { compatible = "nxp,kinetis-gpio"; status = "disabled"; reg = <0x9a000 0x1000>; interrupts = <21 0>,<22 0>; gpio-controller; #gpio-cells = <2>; nxp,kinetis-port = <&portc>; }; gpio3: gpio@9c000 { compatible = "nxp,kinetis-gpio"; status = "disabled"; reg = <0x9c000 0x1000>; interrupts = <23 0>,<24 0>; gpio-controller; #gpio-cells = <2>; nxp,kinetis-port = <&portd>; }; gpio4: gpio@9e000 { compatible = "nxp,kinetis-gpio"; status = "disabled"; reg = <0x9e000 0x1000>; interrupts = <25 0>,<26 0>; gpio-controller; #gpio-cells = <2>; nxp,kinetis-port = <&porte>; }; gpio5: gpio@40000 { compatible = "nxp,kinetis-gpio"; status = "disabled"; reg = <0x40000 0x1000>; interrupts = <27 0>,<28 0>; gpio-controller; #gpio-cells = <2>; nxp,kinetis-port = <&portf>; };
gpio 节点采用了"ip@地址" 的描述形式,默认为开启的状态,这时针对CPU级别的DTS文件,在我们使用的MCXN947 板级的DTSI文件中已经将这部分配置更新为“okay”,对应\zephyr\boards\nxp\frdm_mcxn947\frdm_mcxn947_mcxn947_cpu0.dtsi 文件中更新status 配置如下。
&gpio4 { status = "okay"; }; &gpio1 { status = "okay"; }; &gpio0 { status = "okay"; }; &gpio2 { status = "okay"; };
相当于 默认frdm_mcxn947 已经开启了GPIO,添加如下代码通过gpio 驱动控制LED状态。
以下链接为官方的gpio 接口说明文档(https://docs.zephyrproject.org/apidoc/latest/group__gpio__interface.html#gabfab69282fb99be119760436f2d18a9b)
unsigned int led(char argc,char ** argv) { const struct device * dev; dev = device_get_binding("gpio@96000"); if(dev) { printf("get device ok %p.\r\n",dev); if(0 == strcmp(argv[1],"init")) { gpio_pin_configure(dev,27,GPIO_OUTPUT); } if(0 == strcmp(argv[1],"on")) { gpio_pin_set(dev,27,0); } if(0 == strcmp(argv[1],"off")) { gpio_pin_set(dev,27,1); } } else { printf("get device failed.\r\n"); } return 1; } LTSH_FUNCTION_EXPORT(led,"test shell");
输入 “led init" 配置P0_27为输出引脚。
输入 led on 板子的LED 被点亮,led off LED灯熄灭。
验证完了GPIO的输出功能,我们继续验证GPIO输入功能,原理图上P0_23 连接了外部按键。
参考Zephyr 的GPIO 接口说明我们添加如下的代码配置P0_23为中断输入,触发方式为双边沿并在中断函数中添加状态打印处理。
void gpio_key_cb(const struct device *port,struct gpio_callback *cb,gpio_port_pins_t pins) { /* printf key status */ printf("pin status %d\r\n",gpio_pin_get(port,23)); } /* config p023 as input */ const struct device * dev; dev = device_get_binding("gpio@96000"); if(dev) { static struct gpio_callback callback; gpio_pin_configure(dev,23,GPIO_INPUT); /* gpio interrupt init */ callback.pin_mask = 0xffffffff; callback.handler = gpio_key_cb; gpio_add_callback(dev,&callback); gpio_pin_interrupt_configure(dev,23,GPIO_INT_EDGE_BOTH); }
运行效果如下按键按下抬起会有打印输出,至此我们已经完成了Zephyr 系统下的GPIO的输入输出功能验证。