OpenHarmony 2.0 Canary 的 IoT硬件子系统 原创 精华
OpenHarmony 2.0 Canary 的 IoT硬件子系统
liangkz 2021.07.22
前文《Hi3861_WiFi IoT工程:理解IoT外设控制模块》是基于DevEco IDE的HPM工具下载和安装的“@ohos/wifi_iot”工程(下文的D_Hi3861项目)所做出的一些分析,但这个工程,看上去是在非常久远以前的鸿蒙系统裁剪出来的,鸿蒙系统在不停地优化和调整,但这个工程并没有同步更新,所以最新的鸿蒙系统master分支(Canary)或者LTS分支(下文的A_Master/B_LTS项目),很多子系统/组件的结构和API等,都与“@ohos/wifi_iot”工程的代码有很大差异,最明显的例子之一,是这个IoT硬件子系统部分的差异。
先看一下IoT硬件子系统在D_Hi3861项目和A_Master/B_LTS项目的相关目录结构的差异,如下表:
通过两个表格的对比(以及更细致的具体的代码对比),可以明显看出,A_Master/B_LTS项目的API实现和调用层次比D_Hi3861项目的少了一层,相对简洁了不少。
A_Master/B_LTS项目中,在framework层只提供接口的声明,而对接口的实现则直接由芯片/平台的适配层调用硬件驱动的相关接口来操作硬件来完成,当需要适配别的芯片时,只需要在芯片的适配层完成实现即可,不需要改动framework的任何东西。
而在framework声明的API,相关文件/API的命名,也从D_Hi3861项目的wifiiot_xxx改为A_Master/B_LTS项目的iot_xxx,基本上是重新写了一遍,需要注意的是,有部分在D_Hi3861项目中存在的API,不清楚什么原因,在A_Master/B_LTS项目上没有实现,下面的例子会提到,需要我们开发者根据需要来自己实现。
我们看一下B_LTS项目的官方的示例程序://applications/sample/wifi-iot/app/iothardware/led_example.c
增加一点简单的代码,通过开发板上的USER按键来实现切换LED1灯的亮灯模式。
通过查看原理图,可以知道Hi3861开发板上的USER按键是连接在主芯片的GPIO5上,这个GPIO5是一个可复用的IO口。系统在上电时会根据CONFIG_UART1_SUPPORT的配置,默认将其配置为uart1 串口的一个信号引脚,见B_LTS/device/hisilicon/hispark_pegasus/sdk_liteos/app/wifiiot_app/init/app_io_init.c 的:
hi_void app_io_init(hi_void)
{
......
#ifdef CONFIG_UART1_SUPPORT
/* uart1 AT命令串口 */
hi_io_set_func(HI_IO_NAME_GPIO_5, HI_IO_FUNC_GPIO_5_UART1_RXD); /* uart1 rx */
hi_io_set_func(HI_IO_NAME_GPIO_6, HI_IO_FUNC_GPIO_6_UART1_TXD); /* uart1 tx */
#endif
......
}
“CONFIG_UART1_SUPPORT”定义在B_LTS/device/hisilicon/hispark_pegasus/sdk_liteos/build/config/usr_config.mk 文件内。
备份该文件后打开它,找到“CONFIG_UART1_SUPPORT=y”,行首加“#”将其注释掉,不编译uart1功能即可。
如果是D_Hi3861项目,则上述文件分别位于:
D_Hi3861/vendor/hisi/hi3861/hi3861/app/wifiiot_app/init/app_io_init.c
D_Hi3861/vendor/hisi/hi3861/hi3861/build/config/usr_config.mk
打开//applications/sample/wifi-iot/app/ 目录下的BUILD.gn,在features列表中增加"iothardware:led_example"让led_example参与编译,这里需要注意格式,只能用空格键,不能用Tab键:
lite_component("app") {
features = [
"startup",
"iothardware:led_example",
]
}
打开led_example.c文件,在LedExampleEntry()函数前增加GPIO5的宏定义以及响应USER按键中断的回调函数的定义:
#define IOT_IO_NAME_GPIO_5 (5) //USR buttom
static void UsrBtnDetect(char *arg)
{
(void)arg;
g_ledState = (g_ledState+1)%LED_MAX; //LED_MAX define to 3
return;
}
在LedExampleEntry()函数内,GPIO9初始化的下面,增加:
/////////////////////////////////////
IoTGpioInit(IOT_IO_NAME_GPIO_5);
IoTGpioSetFunc(IOT_IO_NAME_GPIO_5, 0); //0-HI_IO_FUNC_GPIO_5_GPIO
IoTGpioSetDir(IOT_IO_NAME_GPIO_5, IOT_GPIO_DIR_IN);
IoTGpioSetPull(IOT_IO_NAME_GPIO_5, HI_IO_PULL_UP); //1
IoTGpioRegisterIsrFunc( IOT_IO_NAME_GPIO_5,
IOT_INT_TYPE_EDGE, //边沿触发
IOT_GPIO_EDGE_FALL_LEVEL_LOW, //下降沿触发
UsrBtnDetect, //下降沿触发中断调用回调函数处理
NULL);
/////////////////////////////////////
因为IoTGpioSetFunc()和IoTGpioSetPull()两个函数在A_Master/B_LTS项目中并没有定义和实现,需要我们自己参考D_Hi3861的代码,添加定义和实现,如下:
打开B_LTS/base/iot_hardware/peripheral/interfaces/kits/iot_gpio.h 头文件,在文件末尾添加这两个函数的声明(其它的函数可以按此套路自行添加和实现):
typedef enum {
IOT_IO_PULL_NONE, /**< Disabled.CNcomment:无拉CNend */
IOT_IO_PULL_UP, /**< Pull-up enabled.CNcomment:上拉CNend */
IOT_IO_PULL_DOWN, /**< Pull-down enabled.CNcomment:下拉CNend */
IOT_IO_PULL_MAX, /**< Invalid.CNcomment:无效值CNend */
} iot_io_pull;
unsigned int IoTGpioSetPull(unsigned int id, iot_io_pull val);
//unsigned int IoTGpioGetPull(unsigned int id, iot_io_pull *val);
unsigned int IoTGpioSetFunc(unsigned int id, unsigned char val);
//unsigned int IoTGpioGetFunc(unsigned int id, unsigned char *val);
#if 0
typedef enum {
IOT_IO_DRIVER_STRENGTH_0 = 0, /**< Drive strength level 0 (highest).CNcomment:驱动能力0级,驱动能力最高CNend */
IOT_IO_DRIVER_STRENGTH_1, /**< Drive strength level 1.CNcomment:驱动能力1级CNend */
IOT_IO_DRIVER_STRENGTH_2, /**< Drive strength level 2.CNcomment:驱动能力2级CNend */
IOT_IO_DRIVER_STRENGTH_3, /**< Drive strength level 3.CNcomment:驱动能力3级CNend */
IOT_IO_DRIVER_STRENGTH_4, /**< Drive strength level 4.CNcomment:驱动能力4级CNend */
IOT_IO_DRIVER_STRENGTH_5, /**< Drive strength level 5.CNcomment:驱动能力5级CNend */
IOT_IO_DRIVER_STRENGTH_6, /**< Drive strength level 6.CNcomment:驱动能力6级CNend */
IOT_IO_DRIVER_STRENGTH_7, /**< Drive strength level 7 (lowest).CNcomment:驱动能力7级,驱动能力最低CNend */
IOT_IO_DRIVER_STRENGTH_MAX,
} iot_io_driver_strength;
unsigned int IoTGpioGetDriverStrength(unsigned int id, iot_io_driver_strength *val);
unsigned int IoTGpioSetDriverStrength(unsigned int id, iot_io_driver_strength val);
#endif
打开B_LTS/device/hisilicon/hispark_pegasus/hi3861_adapter/hals/iot_hardware/wifiiot_lite/hal_iot_gpio.c文件,在文件头部增加 #include "hi_io.h",在文件尾部增加两个函数的定义(其它函数可以按此套路增加定义):
/////////////////////////////////////
unsigned int IoTGpioSetPull(unsigned int id, iot_io_pull val)
{
if (id >= HI_GPIO_IDX_MAX) {
return IOT_FAILURE;
}
return hi_io_set_pull((hi_gpio_idx)id, (hi_io_pull)val);
}
unsigned int IoTGpioSetFunc(unsigned int id, unsigned char val)
{
if (id >= HI_GPIO_IDX_MAX) {
return IOT_FAILURE;
}
return hi_io_set_func((hi_gpio_idx)id, val);
}
/////////////////////////////////////
编译工程后烧录bin到开发板上,重启,查看LED1灯的状态,按下USER按键就可以切换LED1的亮灯状态了。
每次通过楼主的表格都能看的挺明了。
还是一句话,文不如表,表不如图。
“IoTGpioSetFunc()和IoTGpioSetPull()两个函数在A_Master/B_LTS项目中并没有定义和实现“,我也发现这个问题,正常是鸿蒙系统写好吧?
如果需要用户自己添加,这些函数接口无法保持一致的。
我测试一下呢。感谢分享