1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-07-11     QT-one       first version
9  */
10 
11 #include "ht32_usbd_int.h"
12 
13 #ifdef RT_USING_USB_DEVICE
14 //#include "ht32_usbd_core.h"
15 
16 
17 
18 static void USBPLL_Configuration(void);
19 static void USBVRG_Configuration(void);
20 static void Suspend(u32 uPara);
21 
22 
23 static USBDCore_TypeDef *int_p_usbd_code;
24 static USBD_Driver_TypeDef gUSBDriver;
25 static u32 gIsLowPowerAllowed = TRUE;
26 
27 /*
28     为了不破坏原本的usb_code文件中的USB中断回调函数
29     此处重构USB中断回调函数
30     除了重构USB的中断回调函数以外,还需要重写一些中断回调功能函数
31 */
32 /*
33     RTT的USB中断回调过程如下
34     USB中断函数 -> USB中断回调函数 -> USB相关功能回调函数
35     -> RTT的USB相关功能回调函数 -> 结束USB中断
36 
37     RTT的USB程序运行流程(RTT的USB线程运行流程)
38     USB线程阻塞等待USB获取到消息队列中的消息
39     -> USB中断通过回调函数将接收到的消息传给USB的消息队列
40     -> RTT的USB相关功能回调函数获取到USB中断的消息,并设置USB消息队列的状态
41     -> USB退出中断,USB获取到消息后,线程阻塞被解除
42     -> USB线程根据获取的状态执行对应的功能
43     -> USB线程通过USB操作接口实现对应的功能
44 
45 */
46 /*
47     根据RTT的USB中断回调过程和RTT的USB线程执行过程
48     得出完成USB驱动需要实现的两个重要部分
49     1、USB线程实现功能所需要的调用到的USB操作接口函数
50     2、USB中断回调过程使用到的RTT的USB驱动的函数的相关衔接部分
51 
52     除了以上两个比较重要的功能外,还需要完成以下的一些必要部分
53     1、USB初始化函数
54     2、USB设备注册函数
55 
56     完成以上功能主要涉及到两个文件为:
57     1、drv_usbd.c
58     2、ht32_usbd_int.c
59 
60     对两个文件的内容分配以及文件依赖如下:
61     drv_usbd.c
62         主要负责实现USB的操作接口的实现
63         以及初始化函数和USB设备注册函数
64         由于自定义的USB内核挂载点在该文件中
65         所以USB的中断函数也会写在该文件中
66         依赖:
67             ht32_usbd_core.c
68             ht32_usbd_int.c
69             以及RTT的相关文件
70 
71     ht32_usbd_int.c
72         主要负责实现USB中断回调以及回调函数
73         中和RTT的USB驱动函数相关衔接部分
74         该文件还会包含USB的初始配置函数以及
75         USB的休眠与唤醒的相关函数
76         依赖:
77             ht32_usbd_core.c
78             以及RTT的相关文件
79 */
80 
81 /* 帧起始(SOF)中断回调 */
usbd_sof_callback(USBDCore_TypeDef * pCore)82 void usbd_sof_callback(USBDCore_TypeDef *pCore)
83 {
84     udcd_t udcd = (udcd_t)pCore->pdata;
85     rt_usbd_sof_handler(udcd);
86 }
87 /* USB复位中断 */
usbd_reset_callback(USBDCore_TypeDef * pCore)88 void usbd_reset_callback(USBDCore_TypeDef *pCore)
89 {
90     udcd_t udcd = (udcd_t)pCore->pdata;
91     rt_usbd_reset_handler(udcd);
92 }
93 
94 /* USB暂停(断开连接)中断 */
usbd_suspend_callback(USBDCore_TypeDef * pCore)95 void usbd_suspend_callback(USBDCore_TypeDef *pCore)
96 {
97     udcd_t udcd = (udcd_t)pCore->pdata;
98     rt_usbd_disconnect_handler(udcd);
99 }
100 
101 /* USB恢复(重新连接)中断 */
usbd_resume_callback(USBDCore_TypeDef * pCore)102 void usbd_resume_callback(USBDCore_TypeDef *pCore)
103 {
104     udcd_t udcd = (udcd_t)pCore->pdata;
105     rt_usbd_connect_handler(udcd);
106 }
107 
108 /* USB端点0中断 */
109 /* 端点0控制中断 */
usbd_setup_callback(USBDCore_TypeDef * pCore)110 void usbd_setup_callback(USBDCore_TypeDef *pCore)
111 {
112     udcd_t udcd = (udcd_t)pCore->pdata;
113     rt_usbd_ep0_setup_handler(udcd, (struct urequest *)&pCore->Device.Request);
114 }
115 
116 /* 端点0输入中断(可以归入其他端点输入中断) */
usbd_ep0_in_callback(USBDCore_TypeDef * pCore)117 void usbd_ep0_in_callback(USBDCore_TypeDef *pCore)
118 {
119     udcd_t udcd = (udcd_t)pCore->pdata;
120     rt_usbd_ep0_in_handler(udcd);
121 }
122 
123 /* 端点0输出中断(可以归入其他端点输出中断) */
usbd_ep0_out_callback(USBDCore_TypeDef * pCore)124 void usbd_ep0_out_callback(USBDCore_TypeDef *pCore)
125 {
126     udcd_t udcd = (udcd_t)pCore->pdata;
127     rt_usbd_ep0_out_handler(udcd, pCore->Device.Transfer.sByteLength);
128 }
129 
130 /* USB其他端点中断 */
131 /* 其他端点输入中断 */
usbd_ep_in_callback(USBDCore_TypeDef * pCore,USBD_EPTn_Enum EPTn)132 void usbd_ep_in_callback(USBDCore_TypeDef *pCore, USBD_EPTn_Enum EPTn)
133 {
134     udcd_t udcd = (udcd_t)pCore->pdata;
135     rt_usbd_ep_in_handler(udcd, EPTn | 0x80, pCore->Device.Transfer.sByteLength);
136 }
137 
138 /* 其他端点输出中断 */
usbd_ep_out_callback(USBDCore_TypeDef * pCore,USBD_EPTn_Enum EPTn)139 void usbd_ep_out_callback(USBDCore_TypeDef *pCore, USBD_EPTn_Enum EPTn)
140 {
141     udcd_t udcd = (udcd_t)pCore->pdata;
142     rt_usbd_ep_out_handler(udcd, EPTn, pCore->Device.Transfer.sByteLength);
143 }
144 
145 
146 
147 
148 //rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
149 //rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
150 //rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep);
151 //rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep);
152 //rt_err_t rt_usbd_ep0_set_stall(udevice_t device);
153 //rt_err_t rt_usbd_ep0_clear_stall(udevice_t device);
154 
155 
156 /*********************************************************************************************************//**
157   * @brief  Configure USB.
158   * @retval None
159   ***********************************************************************************************************/
USB_Configuration(USBDCore_TypeDef * pCore)160 static void USB_Configuration(USBDCore_TypeDef *pCore)
161 {
162     CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
163     CKCUClock.Bit.USBD       = 1;
164     CKCUClock.Bit.EXTI       = 1;
165     CKCU_PeripClockConfig(CKCUClock, ENABLE);
166 
167     int_p_usbd_code = pCore;
168 
169 #if (LIBCFG_CKCU_USB_PLL)
170     USBPLL_Configuration();
171 #endif
172 
173 #if (LIBCFG_PWRCU_VREG)
174     USBVRG_Configuration();                               /* Voltage of USB setting                           */
175 #endif
176 
177     pCore->pDriver = (u32 *)&gUSBDriver;                /* Initiate memory pointer of USB driver            */
178     pCore->Power.CallBack_Suspend.func  = Suspend;      /* Install suspend call back function into USB core */
179 
180 //    gUSBCore.pDriver = (u32 *)&gUSBDriver;                /* Initiate memory pointer of USB driver            */
181 //    gUSBCore.Power.CallBack_Suspend.func  = Suspend;      /* Install suspend call back function into USB core */
182     //gUSBCore.Power.CallBack_Suspend.uPara = (u32)NULL;
183 
184     /* 描述符初始化 */
185 //    USBDDesc_Init(&pCore->Device.Desc);                 /* Initiate memory pointer of descriptor            */
186     /* USB类初始化 */
187 //    USBDClass_Init(&(pCore->Class));                      /* Initiate USB Class layer                         */
188     /* USB内核初始化 */
189     USBDCore_Init(pCore);                             /* Initiate USB Core layer                          */
190 
191     /* !!! NOTICE !!!
192        Must turn on if the USB clock source is from HSI (PLL clock Source)
193     */
194 #if 0
195     {
196         /* Turn on HSI auto trim function                                                                       */
197         CKCU_HSIAutoTrimClkConfig(CKCU_ATC_USB);
198         CKCU_HSIAutoTrimCmd(ENABLE);
199     }
200 #endif
201 
202     NVIC_EnableIRQ(USB_IRQn);                             /* Enable USB device interrupt                      */
203 }
204 
205 #if (LIBCFG_CKCU_USB_PLL)
206 /*********************************************************************************************************//**
207  * @brief  Configure USB PLL
208  * @retval None
209  ************************************************************************************************************/
USBPLL_Configuration(void)210 static void USBPLL_Configuration(void)
211 {
212     {
213         /* USB PLL configuration                                                                                */
214 
215         /* !!! NOTICE !!!
216            Notice that the local variable (structure) did not have an initial value.
217            Please confirm that there are no missing members in the parameter settings below in this function.
218         */
219         CKCU_PLLInitTypeDef PLLInit;
220 
221         PLLInit.ClockSource = CKCU_PLLSRC_HSE;  // CKCU_PLLSRC_HSE or CKCU_PLLSRC_HSI
222 #if (LIBCFG_CKCU_USB_PLL_96M)
223         PLLInit.CFG = CKCU_USBPLL_8M_96M;
224 #else
225         PLLInit.CFG = CKCU_USBPLL_8M_48M;
226 #endif
227         PLLInit.BYPASSCmd = DISABLE;
228         CKCU_USBPLLInit(&PLLInit);
229     }
230 
231     CKCU_USBPLLCmd(ENABLE);
232 
233     while (CKCU_GetClockReadyStatus(CKCU_FLAG_USBPLLRDY) == RESET);
234     CKCU_USBClockConfig(CKCU_CKUSBPLL);
235 }
236 #endif
237 
238 #if (LIBCFG_PWRCU_VREG)
239 /*********************************************************************************************************//**
240  * @brief  Configure USB Voltage
241  * @retval None
242  ************************************************************************************************************/
USBVRG_Configuration(void)243 static void USBVRG_Configuration(void)
244 {
245     CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
246     CKCUClock.Bit.BKP                   = 1;
247     CKCU_PeripClockConfig(CKCUClock, ENABLE);
248 
249     PWRCU_SetVREG(PWRCU_VREG_3V3);
250 
251     /* !!! NOTICE !!!
252        USB LDO should be enabled (PWRCU_VREG_ENABLE) if the MCU VDD > 3.6 V.
253     */
254     PWRCU_VREGConfig(PWRCU_VREG_BYPASS);
255 }
256 #endif
257 
258 #define REMOTE_WAKEUP      (0)
259 /*********************************************************************************************************//**
260   * @brief  Suspend call back function which enter DeepSleep1
261   * @param  uPara: Parameter for Call back function
262   * @retval None
263   ***********************************************************************************************************/
Suspend(u32 uPara)264 static void Suspend(u32 uPara)
265 {
266 #if (REMOTE_WAKEUP == 1)
267     u32 IsRemoteWakeupAllowed;
268 #endif
269 
270     if (gIsLowPowerAllowed)
271     {
272 
273 #if (REMOTE_WAKEUP == 1)
274         /* Disable EXTI interrupt to prevent interrupt occurred after wakeup                                    */
275         EXTI_IntConfig(KEY1_BUTTON_EXTI_CHANNEL, DISABLE);
276         IsRemoteWakeupAllowed = USBDCore_GetRemoteWakeUpFeature(&gUSBCore);
277 
278         if (IsRemoteWakeupAllowed == TRUE)
279         {
280             /* Enable EXTI wake event and clear wakeup flag                                                       */
281             EXTI_WakeupEventConfig(KEY1_BUTTON_EXTI_CHANNEL, EXTI_WAKEUP_LOW_LEVEL, ENABLE);
282             EXTI_ClearWakeupFlag(KEY1_BUTTON_EXTI_CHANNEL);
283         }
284 #endif
285 
286         __DBG_USBPrintf("%06ld >DEEPSLEEP\r\n", ++__DBG_USBCount);
287 
288         // Add your procedure here which disable related IO to reduce power consumption
289         // ..................
290         //
291 
292         if ((int_p_usbd_code->Info.CurrentStatus == USB_STATE_SUSPENDED) && ((HT_USB->CSR & 0xC0) == 0x40))   // D+ = 1, D- = 0
293         {
294             /* For Bus powered device, you must enter DeepSleep1 when device has been suspended. For self-powered */
295             /* device, you may decide to enter DeepSleep1 or not depended on your application.                    */
296 
297             /* For the convenient during debugging and evaluation stage, the USBDCore_LowPower() is map to a null */
298             /* function by default. In the real product, you must map this function to the low power function of  */
299             /* firmware library by setting USBDCORE_ENABLE_LOW_POWER as 1 (in the ht32fxxxx_usbdconf.h file).     */
300             USBDCore_LowPower();
301         }
302 
303         // Add your procedure here which recovery related IO for application
304         // ..................
305         //
306 
307         __DBG_USBPrintf("%06ld <DEEPSLEEP\r\n", ++__DBG_USBCount);
308 
309 #if (REMOTE_WAKEUP == 1)
310         if (EXTI_GetWakeupFlagStatus(KEY1_BUTTON_EXTI_CHANNEL) == SET)
311         {
312             __DBG_USBPrintf("%06ld WAKEUP\r\n", ++__DBG_USBCount);
313             if (IsRemoteWakeupAllowed == TRUE && USBDCore_IsSuspend(&gUSBCore) == TRUE)
314             {
315                 USBDCore_TriggerRemoteWakeup();
316             }
317         }
318 
319         if (IsRemoteWakeupAllowed == TRUE)
320         {
321             /* Disable EXTI wake event and clear wakeup flag                                                      */
322             EXTI_WakeupEventConfig(KEY1_BUTTON_EXTI_CHANNEL, EXTI_WAKEUP_LOW_LEVEL, DISABLE);
323             EXTI_ClearWakeupFlag(KEY1_BUTTON_EXTI_CHANNEL);
324         }
325 
326         /* Clear EXTI edge flag and enable EXTI interrupt                                                       */
327         EXTI_ClearEdgeFlag(KEY1_BUTTON_EXTI_CHANNEL);
328         EXTI_IntConfig(KEY1_BUTTON_EXTI_CHANNEL, ENABLE);
329 #endif
330     }
331 
332     return;
333 }
334 
335 
336 
337 
338 
339 
340 
341 
342 
343 
344 
345 
346 
347 
348 
349 
350 
351 
352 
353 #endif /* RT_USING_USB_DEVICE */
354