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