小言_互联网的博客

AliOS Things基于USB通道外接4G模组的方案

458人阅读  评论(0)

1、概述

本文介绍AliOS Things关于USB外接广域网芯片连接入云的方案。物联网设备联网方案,可分为OpenCPU的方式与外接通信芯片的方式。OpenCPU的应用层与网络层运行在同一芯片上,该方式具有较高的集成度,但使得应用、协议在接口、配置、性能等方面产生了耦合,不利于方案的移植与推广。

 

而采用外接的方式,可以分离应用层与网络层,较好地降低耦合度,提高联网方案的灵活性。例如,MCU运行MQTT应用层协议,而由外接通信芯片(如Wi-Fi、LTE)完成网络层的TCP/IP连接与传输。当然,外接通信芯片的代价,是MCU与通信芯片之间增加了交互成本,需要开发者选择适合应用场景的外接方式。

 

AliOS Things支持MCU与通信芯片间的多种连接方式,如UART、SPI、SDIO、USB。这些连接方式不仅拓展了基于AliOS Things开发的可选联网方案,还满足了不同应用场景对传输速率需求,如表1所示。其中,HAAS100通过USB外接LTE,可以实现相同厂商不同模组间无缝替换,例如EC20、EC200S。

 

  接口 最高速率 (Mbps) 应用场景举例 MCU + 通信芯片
1 UART 1.5 Developerkit,WiFi STM32L496 + BK7231
2 SPI 20 HAAS100,Ethernet HAAS1000 + CH395
4 USB 12 HAAS100,LTE HAAS1000 + EC20

表1 AliOS Things所支持外接方式以及应用场景

 

2、USB外接通信芯片的优点

USB本身具有使用方便、数据传输可靠、成本低、省电等优点。而使用USB做为外接通信芯片的通道,将保留这些优点,具体表现为:

2.1、使用方便

  • 一个接口可以用于多种设备的连接,用户可以方便地替换所要连接的通信芯片,无需针对不同通信芯片采用不同的连接器和线缆。
  • 自动配置,通信芯片接入后,MCU侧可以自动对通信芯片进行识别,并加载对应的驱动程序。
  • 支持热插拔,用户可以随时接入或拔出通信芯片,而不会损害硬件设备,也无需重启设备。
  • 无需额外供电,USB接口提供了+5V电压,500mA以下电流,一般情况下通信芯片无需额外电源。

2.2、数据传输可靠

  • 接收端和线缆硬件规范,保证数据传输在一个平静的接口电器环境中,避免了导致数据错误的大部分噪声干扰。
  • 差分传输模式,USB 1.1/2.0采用四线模式,其中D+/D-为数据传输通道,采用差分信号的传输方式,D+/D-需要同时满足电平条件才能判定为0或1,降低了因干扰产生比特跳变的可能性。
  • CRC校验,USB硬件自带CRC校验,可检测传输过程中发生的错误。
  • 协议确认重传,USB在协议层面提供了确认(ACK/NACK)与重传机制,可从传输错误中恢复。

2.3、成本低、省电

  • USB部件成本较低,无论是使用独立的controller,还是使用集成IP的方案,成本都可以控制在合理范围内。并且从可扩展性来看,USB可以支持更多种类的设备连接,而无需硬件上的改动。
  • USB使用了省电电路与协议,配合通信芯片的休眠与唤醒功能,可实现整体上的低功耗。

 

3、实现基于USB通道外接通信芯片

为了实现基于USB通道外接通信芯片,除了要保证MCU具备USB连接硬件能力以外,MCU侧还需要实现USB host协议栈,以完成

  • 设备识别
  • 驱动加载
  • 数据传输

图 1 MCU侧USB Host协议栈结构,包括了Host controller层、Host Core层、Host Class层、USB Device Driver层

MCU侧的USB host协议栈大致分为四层:Host Controller层、Host Core层、Host Class层、USB Device Driver层。其中,Host Controlle是USB host协议栈最底层,负责直接与硬件交互,读写寄存器、中断处理;Host Core是协议栈的核心层,对下负责管理Host controller、设备、接口、端点,并负责设备枚举,对上负责host class的注册、设备的配置以及传输请求处理;Host Class层为各USB host类的实现层,例如HID、CDC、UVC等类。 最后,设备驱动层用于实现与USB设备应用交互逻辑,例如通过AT指令与EC20进行交互。各层的设计细节将在另一篇文章中详细介绍,此处将不再展开。本节将围绕设备识别、驱动加载、数据传输介绍USB外接通信芯片的实现方式。

3.1、设备识别

当通信芯片通过USB连接上MCU后,两者会发生以下对话。


  
  1. Host:你是什么设备?
  2. Device: 12 01 0100... /* Device Descriptor */
  3. Host:你有几种功能?
  4. Device:09 02 09... /* Configuration Descriptor */
  5. Host:每个功能有几个接口?
  6. Device: 09 04 00... /* Interface Descriptor */
  7. Host:每个接口使用哪几个端点?
  8. Device: 06 05 82... /* Endpoint Descriptor */
  9. Host: 我知道你是谁了,开始传输
  10. Device: OK
  11. ....

这些问答的目的是为了帮助USB Host准确地对接入的设备进行识别。交互的信息主要包括设备描述符、配置描述符、接口描述符、端点描述符。

 

3.2、类加载

在枚举过程的最后会根据设备所属类加载驱动。这里有两种加载方式,一种是按设备加载,另一种是按接口加载。以EC20为例,其接口都为vendor类,无法根据接口类进行加载。因此,需要根据设备的Vendor ID(VID)、Product ID(PID)加载对应类。

事实上,针对这一类由vendor定制广域网USB设备,Linux USB驱动的解决方案,是使用专门有文件(usb/serial/option.c)用于存储厂商的VID和PID列表;在枚举时,如果USB设备的VID与PID相匹配,则加载相应驱动(usb/serial/wwan.c)进行处理。如上文所述,EC20有5个接口,其中接口0为DM口、接口1为GPS接口、接口2为AT口、接口3为PPP口、接口4为NDIS口,如图5所示。由于PC端资源是充足的,Linux USB Host在枚举EC20时可以为每个接口创建相应的端点,并允许用户同时操作这些接口(open/read/write)。

图 4  EC20各USB接口功能

然而,在运行RTOS的MCU芯片上USB控制器的资源是有限的,无法同时创建这么多个接口所需要的端点。以HAAS1000为例,除了控制端点0,其USB控制器只有4个端点可供使用。因此,在MCU上枚举过程中需要考虑底层硬件资源限制,否则会导致驱动加载失败。这里采用的策略是复用端点的方式。在加载驱动时,有针对性地选择接口:首先为接口2分配端点资源,用于AT指令交互,保证4G模块联网并获取IP;然后,在其它接口需要使用时,释放端点2的端点资源。

3.3、数据交互

完成类加载后,上层可通过USB通道收发送数据。以EC20的AT接口为例,AliOS Things的AT驱动框架(SAL + AT Utility)可以无缝运行在USB协议栈上。

图 5  基于USB协议栈的AT通道

需要做的工作是使用USB Class API实现AT Utility所需HAL(at_dev_ops_t)即可,如下所示。


  
  1. /*
  2. * AT dev operation type
  3. */
  4. typedef struct {
  5. at_dev_type_t type;
  6. /**
  7. * AT device init
  8. *
  9. * @return 0 - success, -1 - failure
  10. */
  11. int (*init)( void *dev);
  12. /**
  13. * Receive data from AT device
  14. *
  15. * @return 0 - success, -1 - failure
  16. */
  17. int (*recv)( void *dev,
  18. void *data,
  19. uint32_t expect_size,
  20. uint32_t *recv_size,
  21. uint32_t timeout);
  22. /**
  23. * Send data to AT device.
  24. *
  25. * @return 0 - success, -1 - failure
  26. */
  27. int (*send)( void *dev,
  28. void *data,
  29. uint32_t size,
  30. uint32_t timeout);
  31. /**
  32. * AT deviec deinit
  33. *
  34. * @return 0 - success, -1 - failure
  35. */
  36. int (*deinit)( void *dev);
  37. } at_dev_ops_t;

在此基础上,使用AT Utility API实现SAL所需HAL(sal_op_t)即可,如下所示。


  
  1. typedef struct sal_op_s {
  2. struct sal_op_s * next; //<! Next sal_op_t structure
  3. char *version; //<! Reserved for furture use.
  4. char *name; //<! Drvier name
  5. /* Add sal device */
  6. int (*add_dev)( void*);
  7. /**
  8. * Module low level init so that it's ready to setup socket connection.
  9. *
  10. * @return 0 - success, -1 - failure
  11. */
  12. int (*init)( void);
  13. /**
  14. * Start a socket connection via module.
  15. *
  16. * @param[in] c - connect parameters which are used to setup
  17. * the socket connection.
  18. *
  19. * @return 0 - success, -1 - failure
  20. */
  21. int (*start)( sal_conn_t *c);
  22. /**
  23. * Send data via module.
  24. * This function does not return until all data sent.
  25. *
  26. */
  27. int (*send_data)( int fd, uint8_t *data, uint32_t len,
  28. char remote_ip[ 16], int32_t remote_port, int32_t timeout);
  29. /**
  30. * Get IP information of the corresponding domain.
  31. * Currently only one IP string is returned (even when the domain
  32. * coresponses to mutliple IPs). Note: only IPv4 is supported.
  33. *
  34. *
  35. * @return 0 - success, -1 - failure
  36. */
  37. int (*domain_to_ip)( char *domain, char ip[ 16]);
  38. /**
  39. * Close the socket connection.
  40. *
  41. * @return 0 - success, -1 - failure
  42. */
  43. int (*finish)( int fd, int32_t remote_port);
  44. /**
  45. * Destroy SAL or exit low level state if necessary.
  46. *
  47. * @return 0 - success, -1 - failure
  48. */
  49. int (*deinit)( void);
  50. /**
  51. * Register network connection data input function
  52. * Input data from module.
  53. * This callback should be called when the data is received from the module
  54. * It should tell the sal where the data comes from.
  55. *
  56. * @return 0 - success, -1 - failure
  57. */
  58. int (*register_netconn_data_input_cb)( netconn_data_input_cb_t cb);
  59. } sal_op_t;

完成以上对接后,上层应用即可以基于标准的套接字API编程,降低了应用层移植成本。相关AT驱动组件介绍请参考AliOS Things帮助文档 SAL组件AT组件

 

4、HaaS100外接4G模组示例

图6 HaaS100通过USB外接EC20

图 7 USB所用排针接线

HaaS100板上排针提供了USB引脚,可以用接USB母口扩展线,与通信模组连接,如图6、7所示。

 

步骤一:配置

 aos make linkkit_demo@haas100 -c config

 

步骤二:配置选择

aos make menuconfig

配置

 

 

 

步骤三:编译

aos make

 

步骤四:烧录

请参考HaaS快速开始

 

步骤五:启动

该应用运行Linkkit demo,USB枚举成功后,通过AT通道,可以连接入阿里云IoT平台。

 

5、总结

广域网通信模组通常都提供USB通道,支持AT、PPP、RNDIS、ECM等通信方式。因此,在MCU侧支持USB协议栈,可自动识别枚举各类通信设备,并加载所需的驱动,方便用户上层的开发。本文简要介绍了AliOS Things的USB Host协议栈,并以EC20为例描述了枚举识别过程,同时给出了在USB通道上对接AliOS Things传统AT通道的方式。在后续相关系列文章中,我们将介绍基于USB通道的PPP、RNDIS、ECM方式,并给出相应对比数据。敬请期待。

 

如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号

更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/


转载:https://blog.csdn.net/HaaSTech/article/details/112046835
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场