drv_usbh.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-4-30 IceBear003 the first version adapted from CherryUSB
  9. */
  10. #include "board.h"
  11. #include "drv_usbh.h"
  12. #ifdef BSP_USING_USBH
  13. #define LOG_TAG "drv.usbh"
  14. #include "drv_log.h"
  15. static struct uhcd uhcd;
  16. static struct rt_completion urb_completion;
  17. __attribute__((aligned(4))) int8_t usb_rx_buf[ MAX_PACKET_SIZE ];
  18. __attribute__((aligned(4))) int8_t usb_tx_buf[ MAX_PACKET_SIZE ];
  19. USBOTGH_FS_TypeDef *USBFSH = USBOTG_H_FS;
  20. rt_err_t usbh_reset_port(rt_uint8_t port)
  21. {
  22. //Disable interrupt
  23. USBFSH->INT_EN &= (~USBFS_UIE_DETECT);
  24. USBFSH->HOST_CTRL &= ~USBFS_UH_SOF_EN;
  25. //Set address
  26. USBFSH->DEV_ADDR = (USBFS_UDA_GP_BIT & USBFSH->DEV_ADDR) | (0x00 & USBFS_USB_ADDR_MASK);
  27. //Close port
  28. USBFSH->HOST_CTRL &= ~USBFS_UH_PORT_EN;
  29. //Reset
  30. USBFSH->HOST_CTRL |= USBFS_UH_BUS_RESET;
  31. rt_thread_mdelay(30);
  32. USBFSH->HOST_CTRL &= ~USBFS_UH_BUS_RESET;
  33. rt_thread_mdelay(20);
  34. //Set speed
  35. if ((USBFSH->HOST_CTRL & USBFS_UH_PORT_EN) == 0) { //Set speed only when port is closed
  36. if(USBFSH->MIS_ST & USBFS_UMS_DM_LEVEL) //RB_UMS_DM_LEVEL: 1/Low 0/Full
  37. { //Low speed
  38. USBFSH->BASE_CTRL |= USBFS_UC_LOW_SPEED;
  39. USBFSH->HOST_CTRL |= USBFS_UH_LOW_SPEED;
  40. USBFSH->HOST_SETUP |= USBFS_UH_PRE_PID_EN;
  41. }
  42. else
  43. { //Full speed
  44. USBFSH->BASE_CTRL &= ~USBFS_UC_LOW_SPEED;
  45. USBFSH->HOST_CTRL &= ~USBFS_UH_LOW_SPEED;
  46. USBFSH->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN;
  47. }
  48. }
  49. //Enable port
  50. USBFSH->HOST_CTRL |= USBFS_UH_PORT_EN;
  51. USBFSH->HOST_SETUP |= USBFS_UH_SOF_EN;
  52. //Enable interrupt
  53. USBFSH->INT_EN |= USBFS_UIE_DETECT;
  54. if(USBFSH->INT_FG & USBFS_UIF_DETECT)
  55. if(USBFSH->MIS_ST & USBFS_UMS_DEV_ATTACH)
  56. USBFSH->INT_FG = USBFS_UIF_DETECT;
  57. return RT_EOK;
  58. }
  59. int usbh_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
  60. {
  61. rt_uint8_t usb_pid;
  62. rt_uint8_t *tog = (rt_uint8_t *)pipe->user_data;
  63. USBFSH->DEV_ADDR = (USBFS_UDA_GP_BIT & USBFSH->DEV_ADDR) | (pipe->pipe_index & USBFS_USB_ADDR_MASK);
  64. if(pipe->ep.bEndpointAddress & USB_DIR_IN)
  65. {
  66. usb_pid = USB_PID_IN;
  67. USBFSH->HOST_TX_LEN = 0x00;
  68. }
  69. else
  70. {
  71. usb_pid = (token == USBH_PID_SETUP) ? USB_PID_SETUP : USB_PID_OUT;
  72. rt_memcpy(usb_tx_buf, buffer, nbytes);
  73. USBFSH->HOST_TX_LEN = nbytes;
  74. }
  75. switch(usb_pid)
  76. {
  77. case USB_PID_IN:
  78. if (nbytes == 0) *tog = USB_PID_DATA1;
  79. USBFSH->HOST_RX_CTRL = (*tog == USB_PID_DATA1) ? USBFS_UH_R_TOG : 0x00;
  80. break;
  81. case USB_PID_OUT:
  82. if (nbytes == 0) *tog = USB_PID_DATA1;
  83. USBFSH->HOST_TX_CTRL = (*tog == USB_PID_DATA1) ? USBFS_UH_T_TOG : 0x00;
  84. break;
  85. case USB_PID_SETUP:
  86. *(rt_uint8_t *)pipe->inst->pipe_ep0_out->user_data = USB_PID_DATA0;
  87. *(rt_uint8_t *)pipe->inst->pipe_ep0_in->user_data = USB_PID_DATA1;
  88. USBFSH->HOST_TX_CTRL = (*tog == USB_PID_DATA1) ? USBFS_UH_T_TOG : 0x00;
  89. break;
  90. }
  91. rt_uint16_t try = 3;
  92. if ((pipe->ep.bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_CONTROL)
  93. try = 1000;
  94. while(try--)
  95. {
  96. USBFSH->HOST_EP_PID = (usb_pid << 4) | (pipe->ep.bEndpointAddress & 0x0F);
  97. if (rt_completion_wait(&urb_completion, timeouts) != RT_EOK)
  98. continue;
  99. if (USBFSH->INT_ST & USBHS_UIS_TOG_OK)
  100. *tog = (*tog == USB_PID_DATA0) ? USB_PID_DATA1 : USB_PID_DATA0;
  101. switch(USBFSH->INT_ST & USBHS_UIS_H_RES_MASK)
  102. {
  103. case USB_PID_DATA0:
  104. case USB_PID_DATA1:
  105. pipe->status = UPIPE_STATUS_OK;
  106. if (pipe->callback != RT_NULL)
  107. pipe->callback(pipe);
  108. if (usb_pid == USB_PID_IN)
  109. {
  110. rt_memcpy(buffer, usb_rx_buf, USBFSH->RX_LEN);
  111. return USBFSH->RX_LEN;
  112. }
  113. return nbytes;
  114. case USB_PID_ACK:
  115. pipe->status = UPIPE_STATUS_OK;
  116. if (pipe->callback != RT_NULL)
  117. pipe->callback(pipe);
  118. return nbytes;
  119. case USB_PID_NAK:
  120. if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
  121. rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
  122. rt_thread_mdelay(1);
  123. continue;
  124. case USB_PID_STALL:
  125. pipe->status = UPIPE_STATUS_STALL;
  126. if (pipe->callback != RT_NULL)
  127. pipe->callback(pipe);
  128. return 0;
  129. default:
  130. break;
  131. }
  132. }
  133. pipe->status = UPIPE_STATUS_ERROR;
  134. if (pipe->callback != RT_NULL)
  135. pipe->callback(pipe);
  136. return -RT_ERROR;
  137. }
  138. rt_err_t usbh_open_pipe(upipe_t pipe)
  139. {
  140. pipe->pipe_index = pipe->inst->address & USBFS_USB_ADDR_MASK;
  141. pipe->user_data = rt_malloc(sizeof(rt_uint8_t));
  142. *(rt_uint8_t *)pipe->user_data = (pipe->ep.bEndpointAddress & USB_DIR_IN) ? USB_PID_DATA0 : USB_PID_DATA0;
  143. return RT_EOK;
  144. }
  145. rt_err_t usbh_close_pipe(upipe_t pipe)
  146. {
  147. rt_free(pipe->user_data);
  148. return RT_EOK;
  149. }
  150. rt_err_t hcd_init(rt_device_t dev)
  151. {
  152. //Force reset handler clear FIFO & interrupt flags
  153. USBFSH->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
  154. rt_thread_mdelay(20);
  155. USBFSH->BASE_CTRL = 0; //Set SIE to 0 manually
  156. USBFSH->BASE_CTRL = USBFS_UC_HOST_MODE;
  157. USBFSH->HOST_CTRL = 0;
  158. USBFSH->DEV_ADDR = 0;
  159. USBFSH->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; //SETUP/OUT/IN
  160. USBFSH->HOST_RX_DMA = (uint32_t)usb_rx_buf;
  161. USBFSH->HOST_TX_DMA = (uint32_t)usb_tx_buf;
  162. USBFSH->HOST_RX_CTRL = 0;
  163. USBFSH->HOST_TX_CTRL = 0;
  164. USBFSH->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
  165. USBFSH->INT_FG = 0xFF;
  166. USBFSH->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT;
  167. if( SystemCoreClock == 144000000 )
  168. RCC_OTGFSCLKConfig( RCC_OTGFSCLKSource_PLLCLK_Div3 );
  169. else if( SystemCoreClock == 96000000 )
  170. RCC_OTGFSCLKConfig( RCC_OTGFSCLKSource_PLLCLK_Div2 );
  171. else if( SystemCoreClock == 48000000 )
  172. RCC_OTGFSCLKConfig( RCC_OTGFSCLKSource_PLLCLK_Div1 );
  173. RCC_AHBPeriphClockCmd( RCC_AHBPeriph_OTG_FS, ENABLE );
  174. NVIC_EnableIRQ(OTG_FS_IRQn);
  175. rt_completion_init(&urb_completion);
  176. return RT_EOK;
  177. }
  178. static struct uhcd_ops uhcd_ops =
  179. {
  180. .reset_port = usbh_reset_port,
  181. .pipe_xfer = usbh_pipe_xfer,
  182. .open_pipe = usbh_open_pipe,
  183. .close_pipe = usbh_close_pipe,
  184. };
  185. void OTG_HS_IRQHandler() __attribute__((interrupt("WCH-Interrupt-fast")));
  186. void OTG_HS_IRQHandler()
  187. {
  188. rt_interrupt_enter();
  189. if (USBFSH->INT_FG & USBFS_UIF_TRANSFER)
  190. {
  191. USBFSH->HOST_EP_PID = 0x00;
  192. USBFSH->INT_FG = USBFS_UIF_TRANSFER;
  193. rt_completion_done(&urb_completion); //本应在此处理的中断在传输函数里进行枚举
  194. rt_kprintf("USB: Transfer finished\n");
  195. }
  196. else if (USBFSH->INT_FG & USBFS_UIF_DETECT)
  197. {
  198. if (USBFSH->MIS_ST & USBFS_UMS_DEV_ATTACH)
  199. {
  200. rt_usbh_root_hub_connect_handler(&uhcd, 1, RT_FALSE);
  201. rt_kprintf("USB: Connect\n");
  202. }
  203. else
  204. {
  205. USBFSH->HOST_SETUP &= ~USBFS_UH_SOF_EN;
  206. USBFSH->HOST_CTRL &= ~USBFS_UH_PORT_EN;
  207. rt_usbh_root_hub_disconnect_handler(&uhcd, 1);
  208. rt_kprintf("USB: Disconnect\n");
  209. }
  210. USBFSH->INT_FG = USBFS_UIF_DETECT;
  211. }
  212. else
  213. {
  214. rt_kprintf("USB: Unknown\n");
  215. }
  216. rt_interrupt_leave();
  217. }
  218. int rt_hw_usbh_init()
  219. {
  220. rt_err_t res = -RT_ERROR;
  221. rt_memset((void *)&uhcd, 0, sizeof(struct uhcd));
  222. uhcd.parent.type = RT_Device_Class_USBHost;
  223. uhcd.parent.init = hcd_init;
  224. uhcd.ops = &uhcd_ops;
  225. uhcd.num_ports = 1;
  226. res = rt_device_register(&uhcd.parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
  227. if (res != RT_EOK)
  228. {
  229. rt_kprintf("register usb host failed res = %d\r\n", res);
  230. return -RT_ERROR;
  231. }
  232. rt_usb_host_init();
  233. return RT_EOK;
  234. }
  235. #endif //BSP_USING_USBH