usbh_net.rst 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. usbh_net
  2. ===============
  3. 本节主要介绍 USB 网卡的使用,当前已经支持和测试以下 USB 网卡:
  4. - 4G 网卡:EC20(ECM/RNDIS)、手机(RNDIS)、SIMCOM7600(RNDIS)、ML307R(RNDIS)、AIR780(RNDIS)
  5. .. caution:: 请注意,部分 4G 网卡默认不带自动拨号功能,请更换固件或者使用 AT 配置成自动拨号,否则无法获取 IP。
  6. - USB 以太网卡:ASIX AX88772,REALTEK RTL8152
  7. - USB WIFI 网卡: 博流 BL616(RNDIS/ECM)
  8. USB 网卡相关的宏和文件
  9. ------------------------
  10. 网卡相关的宏如下,主要用于根据不同的网络组件注册网卡驱动:
  11. .. code-block:: C
  12. // #define CONFIG_USBHOST_PLATFORM_CDC_ECM
  13. // #define CONFIG_USBHOST_PLATFORM_CDC_RNDIS
  14. // #define CONFIG_USBHOST_PLATFORM_CDC_NCM
  15. // #define CONFIG_USBHOST_PLATFORM_ASIX
  16. // #define CONFIG_USBHOST_PLATFORM_RTL8152
  17. .. note:: 如果使用了 Kconfig 系统,上述宏自定生成,其他平台请手动定义。
  18. USB 网卡传输层面已经对接好了相关网络组件,列举如下:
  19. - 自定义 OS + LWIP 请使用 **platform/lwip/usbh_lwip.c**,需要自行包含该文件,并使能上述相关的宏。并在初始化 USB 之前调用 `tcpip_init(NULL, NULL)`
  20. - RT-THREAD + LWIP 请使用 **platform/rtthread/usbh_lwip.c**,在 Kconfig 中使能对应的网卡驱动后自动勾选该文件,勾选 rt-thread lwip以后自动调用 `tcpip_init(NULL, NULL)`
  21. - ESP-IDF + LWIP 请使用 **platform/freertos/usbh_net.c**,在 Kconfig 中使能对应的网卡驱动后自动勾选该文件,并且在初始化 USB 之前调用 `esp_netif_init()` + `esp_event_loop_create_default()`
  22. - NUTTX + NUTTX 网络组件 请使用 **platform/nuttx/usbh_net.c**,在 Kconfig 中使能对应的网卡驱动后自动勾选该文件,勾选网络组件以后自动调用
  23. .. note:: 如果是自行添加代码,别忘了添加 USB 网卡驱动相关的源文件,例如 **class/usbh_cdc_ecm.c**。所以我们推荐搭配对应平台使用哦,省去自己添加文件的麻烦
  24. USB 网卡对接过程
  25. -------------------
  26. 下面举例对接 LWIP 的对接过程。
  27. - 在 USB 网卡枚举完成以后,会 **自动** 调用 `usbh_xxx_run` 函数,此时注册 netif 驱动,并且开启 DHCP 客户端和获取 IP 的定时器。
  28. .. code-block:: C
  29. void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
  30. {
  31. struct netif *netif = &g_cdc_ecm_netif;
  32. netif->hwaddr_len = 6;
  33. memcpy(netif->hwaddr, cdc_ecm_class->mac, 6);
  34. IP4_ADDR(&g_ipaddr, 0, 0, 0, 0);
  35. IP4_ADDR(&g_netmask, 0, 0, 0, 0);
  36. IP4_ADDR(&g_gateway, 0, 0, 0, 0);
  37. netif = netif_add(netif, &g_ipaddr, &g_netmask, &g_gateway, NULL, usbh_cdc_ecm_if_init, tcpip_input);
  38. netif_set_default(netif);
  39. while (!netif_is_up(netif)) {
  40. }
  41. dhcp_handle = usb_osal_timer_create("dhcp", 200, dhcp_timeout, netif, true);
  42. if (dhcp_handle == NULL) {
  43. USB_LOG_ERR("timer creation failed! \r\n");
  44. while (1) {
  45. }
  46. }
  47. usb_osal_thread_create("usbh_cdc_ecm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ecm_rx_thread, NULL);
  48. #if LWIP_DHCP
  49. dhcp_start(netif);
  50. usb_osal_timer_start(dhcp_handle);
  51. #endif
  52. }
  53. - `usbh_lwip_eth_output_common` 用于将发送 pbuf 组装成 USB 网卡数据包
  54. - `usbh_lwip_eth_input_common` 用于将 USB 网卡数据组装成 pbuf
  55. - 实际网卡发送和接收处理
  56. .. code-block:: C
  57. static err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
  58. {
  59. int ret;
  60. (void)netif;
  61. usbh_lwip_eth_output_common(p, usbh_cdc_ecm_get_eth_txbuf());
  62. ret = usbh_cdc_ecm_eth_output(p->tot_len);
  63. if (ret < 0) {
  64. return ERR_BUF;
  65. } else {
  66. return ERR_OK;
  67. }
  68. }
  69. void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen)
  70. {
  71. usbh_lwip_eth_input_common(&g_cdc_ecm_netif, buf, buflen);
  72. }
  73. - USB 网卡 拔出以后会 **自动** 调用 `usbh_xxx_stop` 函数,此时需要停止 DHCP 客户端,删除定时器,并且移除 netif。
  74. .. code-block:: C
  75. void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
  76. {
  77. struct netif *netif = &g_cdc_ecm_netif;
  78. (void)cdc_ecm_class;
  79. #if LWIP_DHCP
  80. dhcp_stop(netif);
  81. dhcp_cleanup(netif);
  82. usb_osal_timer_delete(dhcp_handle);
  83. #endif
  84. netif_set_down(netif);
  85. netif_remove(netif);
  86. }
  87. - 因为 USB 网卡内部已经对接了LWIP,因此用户可以直接使用 LWIP 的 API,无需关心 USB 的实现。
  88. USB 网卡 LWIP 配置宏相关注意事项
  89. ------------------------------------
  90. **LWIP_TCPIP_CORE_LOCKING_INPUT** 用于不使用 lwip 内置的 tcpip 线程,而使用 USB 自己的接收处理线程。
  91. **LWIP_TCPIP_CORE_LOCKING** 在现在 lwip 版本中默认是打开的,也推荐必须打开。
  92. **PBUF_POOL_BUFSIZE** 推荐大于1600,搭配 LWIP_TCPIP_CORE_LOCKING_INPUT 使用,因为我们提供了使用 zero mempy 的方式,使用静态 pbuf,而不是把数据 copy 到 pbuf 中。
  93. **TCPIP_THREAD_STACKSIZE** 推荐大于 1K,防止栈溢出。
  94. .. code-block:: C
  95. #if LWIP_TCPIP_CORE_LOCKING_INPUT != 1
  96. #warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1, usb handles eth input with own thread
  97. #endif
  98. #if LWIP_TCPIP_CORE_LOCKING != 1
  99. #error must set LWIP_TCPIP_CORE_LOCKING to 1
  100. #endif
  101. #if PBUF_POOL_BUFSIZE < 1600
  102. #error PBUF_POOL_BUFSIZE must be larger than 1600
  103. #endif
  104. #if TCPIP_THREAD_STACKSIZE < 1024
  105. #error TCPIP_THREAD_STACKSIZE must be >= 1024
  106. #endif
  107. 总结
  108. --------------
  109. .. note:: 通过以上内容,我们可以看到 CherryUSB 对 USB 网卡的支持是非常完善的,用户只需要使能对应的宏或者勾选,就可以实现 USB 网卡的自动识别和驱动注册,无需手动初始化网卡相关配置,用户只需关注应用层,极大地方便了用户的使用。
  110. 具体移植文章可以参考开发者的一些笔记 https://club.rt-thread.org/ask/article/5cf3e9e0b2d95800.html