drv_usbh.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-02-16 Tuber first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include "board.h"
  13. #include "drv_usbh.h"
  14. #ifdef BSP_USING_USBH
  15. static struct rt_completion urb_completion;
  16. //USB接收缓存区
  17. __align(4) UINT8 usb_rx_buf[MAX_PACKET_SIZE]; // IN, must even address
  18. __align(4) UINT8 usb_tx_buf[MAX_PACKET_SIZE]; // OUT, must even address
  19. static struct uhcd uhcd;
  20. static rt_err_t drv_reset_port(rt_uint8_t port)
  21. {
  22. //关闭中断
  23. R8_USB_INT_EN = 0x00;
  24. R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | (0x00 & MASK_USB_ADDR); //设置地址
  25. R8_UHOST_CTRL &= ~RB_UH_PORT_EN; // 关掉端口
  26. //判断设备速度
  27. if (R8_USB_MIS_ST & RB_UMS_DM_LEVEL)
  28. {
  29. //低速
  30. R8_USB_CTRL |= RB_UC_LOW_SPEED; // 默认为低速
  31. R8_UHOST_CTRL = (R8_UHOST_CTRL | RB_UH_LOW_SPEED) | RB_UH_BUS_RESET; // 默认为低速,开始复位
  32. }
  33. else
  34. {
  35. //全速
  36. R8_USB_CTRL &= ~ RB_UC_LOW_SPEED; // 默认为全速
  37. R8_UHOST_CTRL = (R8_UHOST_CTRL & ~RB_UH_LOW_SPEED) | RB_UH_BUS_RESET; // 默认为全速,开始复位
  38. }
  39. rt_thread_mdelay(15); // 复位时间10mS到20mS
  40. R8_UHOST_CTRL = R8_UHOST_CTRL & ~ RB_UH_BUS_RESET; // 结束复位
  41. rt_thread_mdelay(1);
  42. R8_UHOST_CTRL |= RB_UH_PORT_EN; //打开端口
  43. R8_USB_INT_FG = RB_UIF_DETECT; // 清中断标志
  44. //打开中断
  45. R8_USB_INT_EN = RB_UIF_TRANSFER | RB_UIE_DETECT;
  46. return RT_EOK;
  47. }
  48. static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
  49. {
  50. rt_err_t res;
  51. UINT16 i;
  52. UINT16 retry_count = 3;
  53. rt_uint8_t usb_pid, res_pid;
  54. UINT8 *tog = (UINT8 *)pipe->user_data;
  55. //设置目标usb地址
  56. R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | (pipe->inst->address & MASK_USB_ADDR);
  57. //判断是in还是out操作
  58. if (pipe->ep.bEndpointAddress & USB_DIR_IN)
  59. {
  60. usb_pid = USB_PID_IN; //in
  61. R8_UH_TX_LEN = 0x00;
  62. }
  63. else
  64. {
  65. usb_pid = (token == USBH_PID_SETUP) ? USB_PID_SETUP : USB_PID_OUT; //setup/out
  66. rt_memcpy(usb_tx_buf, buffer, nbytes);
  67. R8_UH_TX_LEN = nbytes;
  68. }
  69. //设置数据TOG
  70. switch (usb_pid)
  71. {
  72. case USB_PID_IN:
  73. if (nbytes == 0) *tog = USB_PID_DATA1; //状态反馈
  74. R8_UH_RX_CTRL = (*tog == USB_PID_DATA1) ? RB_UH_R_TOG : 0x00;
  75. break;
  76. case USB_PID_OUT:
  77. if (nbytes == 0) *tog = USB_PID_DATA1; //状态反馈
  78. R8_UH_TX_CTRL = (*tog == USB_PID_DATA1) ? RB_UH_T_TOG : 0x00;
  79. break;
  80. case USB_PID_SETUP:
  81. *(UINT8 *)pipe->inst->pipe_ep0_out->user_data = USB_PID_DATA0;
  82. *(UINT8 *)pipe->inst->pipe_ep0_in->user_data = USB_PID_DATA1;
  83. R8_UH_TX_CTRL = (*tog == USB_PID_DATA1) ? RB_UH_T_TOG : 0x00;
  84. break;
  85. }
  86. //usb枚举的时候加大重试次数,提高usb设备枚举成功率
  87. if ((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_CONTROL)
  88. {
  89. retry_count = 1000;
  90. }
  91. for (i = 0; i < retry_count; i++)
  92. {
  93. //传输
  94. R8_UH_EP_PID = (usb_pid << 4) | (pipe->ep.bEndpointAddress & 0x0F);
  95. res = rt_completion_wait(&urb_completion, timeouts);
  96. if (res != RT_EOK)
  97. {
  98. return res;
  99. }
  100. //判断是否需要反转数据
  101. if (R8_USB_INT_ST & RB_UIS_TOG_OK)
  102. {
  103. *tog = (*tog == USB_PID_DATA0) ? USB_PID_DATA1 : USB_PID_DATA0;//翻转
  104. }
  105. res_pid = R8_USB_INT_ST & MASK_UIS_H_RES;
  106. switch (res_pid)
  107. {
  108. case USB_PID_ACK://发送成功
  109. pipe->status = UPIPE_STATUS_OK;
  110. if (pipe->callback != RT_NULL) pipe->callback(pipe);
  111. return nbytes;
  112. case USB_PID_DATA0: //收到数据
  113. case USB_PID_DATA1: //收到数据
  114. pipe->status = UPIPE_STATUS_OK;
  115. if (pipe->callback != RT_NULL) pipe->callback(pipe);
  116. //拷贝数据到buffer
  117. if (usb_pid == USB_PID_IN)
  118. {
  119. rt_memcpy(buffer, usb_rx_buf, R8_USB_RX_LEN);
  120. return R8_USB_RX_LEN;
  121. }
  122. return nbytes;
  123. case USB_PID_NAK: //数据未就绪
  124. if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
  125. {
  126. rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
  127. }
  128. rt_thread_mdelay(1);
  129. continue;//重试
  130. case USB_PID_STALL: //传输停止
  131. pipe->status = UPIPE_STATUS_STALL;
  132. if (pipe->callback != RT_NULL) pipe->callback(pipe);
  133. return 0;
  134. default:
  135. break;
  136. }
  137. }
  138. pipe->status = UPIPE_STATUS_ERROR;
  139. if (pipe->callback != RT_NULL) pipe->callback(pipe);
  140. return -RT_ERROR;
  141. }
  142. static rt_err_t drv_open_pipe(upipe_t pipe)
  143. {
  144. pipe->pipe_index = pipe->inst->address & MASK_USB_ADDR;
  145. pipe->user_data = rt_malloc(sizeof(UINT8));
  146. //默认发送DATA0
  147. if (pipe->ep.bEndpointAddress & USB_DIR_IN)
  148. {
  149. *(UINT8 *)pipe->user_data = USB_PID_DATA0;
  150. }
  151. else
  152. {
  153. *(UINT8 *)pipe->user_data = USB_PID_DATA0;
  154. }
  155. return RT_EOK;
  156. }
  157. static rt_err_t drv_close_pipe(upipe_t pipe)
  158. {
  159. rt_free(pipe->user_data);
  160. return RT_EOK;
  161. }
  162. static struct uhcd_ops uhcd_ops =
  163. {
  164. drv_reset_port,
  165. drv_pipe_xfer,
  166. drv_open_pipe,
  167. drv_close_pipe,
  168. };
  169. static rt_err_t hcd_init(rt_device_t dev)
  170. {
  171. R16_PIN_ANALOG_IE |= RB_PIN_USB_IE;
  172. R8_USB_CTRL = RB_UC_HOST_MODE;
  173. R8_UHOST_CTRL = 0;
  174. R8_USB_DEV_AD = 0x00;
  175. R8_UH_EP_MOD = RB_UH_EP_TX_EN | RB_UH_EP_RX_EN;
  176. R16_UH_RX_DMA = (UINT16)(UINT32)usb_rx_buf;
  177. R16_UH_TX_DMA = (UINT16)(UINT32)usb_tx_buf;
  178. R8_USB_CTRL = RB_UC_HOST_MODE | RB_UC_INT_BUSY | RB_UC_DMA_EN;
  179. R8_UH_SETUP = RB_UH_SOF_EN;
  180. R8_USB_INT_FG = 0xFF;
  181. R8_USB_INT_EN = RB_UIF_TRANSFER | RB_UIE_DETECT;
  182. //开启中断
  183. NVIC_EnableIRQ(USB_IRQn);
  184. rt_completion_init(&urb_completion);
  185. return RT_EOK;
  186. }
  187. void USB_IRQHandler()
  188. {
  189. rt_interrupt_enter();
  190. //USB连接断开中断
  191. if (R8_USB_INT_FG & RB_UIF_DETECT)
  192. {
  193. R8_USB_INT_FG = RB_UIF_DETECT;//清除中断
  194. //检查USB设备连接状态
  195. if ((R8_USB_MIS_ST & RB_UMS_DEV_ATTACH) != 0)
  196. {
  197. rt_usbh_root_hub_connect_handler(&uhcd, 1, RT_FALSE);
  198. rt_kprintf("usb: up\n");
  199. }
  200. else
  201. {
  202. rt_usbh_root_hub_disconnect_handler(&uhcd, 1);
  203. rt_kprintf("usb: down\n");
  204. }
  205. }
  206. if (R8_USB_INT_FG & RB_UIF_TRANSFER)
  207. {
  208. R8_UH_EP_PID = 0x00; //停止发送
  209. R8_USB_INT_FG = RB_UIF_TRANSFER;//清除中断
  210. rt_completion_done(&urb_completion);
  211. }
  212. if (R8_USB_INT_FG & RB_UIF_SUSPEND)
  213. {
  214. R8_USB_INT_FG = RB_UIF_SUSPEND;//清除中断
  215. }
  216. if (R8_USB_INT_FG & RB_UIF_HST_SOF)
  217. {
  218. R8_USB_INT_FG = RB_UIF_HST_SOF;//清除中断
  219. }
  220. if (R8_USB_INT_FG & RB_UIF_FIFO_OV)
  221. {
  222. R8_USB_INT_FG = RB_UIF_FIFO_OV;//清除中断
  223. }
  224. rt_interrupt_leave();
  225. }
  226. int rt_hw_usbh_init(void)
  227. {
  228. rt_err_t res = -RT_ERROR;
  229. rt_memset((void *)&uhcd, 0, sizeof(struct uhcd));
  230. uhcd.parent.type = RT_Device_Class_USBHost;
  231. uhcd.parent.init = hcd_init;
  232. uhcd.ops = &uhcd_ops;
  233. uhcd.num_ports = 1;
  234. res = rt_device_register(&uhcd.parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
  235. if (res != RT_EOK)
  236. {
  237. rt_kprintf("register usb host failed res = %d\r\n", res);
  238. return -RT_ERROR;
  239. }
  240. rt_usb_host_init("usbh");
  241. return RT_EOK;
  242. }
  243. INIT_DEVICE_EXPORT(rt_hw_usbh_init);
  244. #endif /* BSP_USING_USBH */