1 /*
2  * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-12-30     CDT          first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #ifdef RT_USB_DEVICE_CDC
15 /* menuconfig:
16   1.Hardware Drivers Config--->On-Chip Peripheral Driver--->Enable USB--->
17                                                             [*]Use USBFS Core
18                                                                 Select USB Mode(USB Device Mode)
19                                                             [*]Enable VBUS Sensing for Device
20   2.RT-Thread Components--->
21         Using USB legacy version--->
22             Using USB device--->Device type--->
23                 [*]Enable to use device as CDC device
24 */
25 /*
26  * 程序清单:这是一个 usb device 设备使用例程
27  * 例程导出了 cdc_sample 命令到控制终端
28  * PC上需要使用串口助手以DTR[√]方式打开USB的虚拟串口(比如 SSCOM 有这个功能)
29  * 命令调用格式:cdc_sample
30  * 程序功能:首先会打印三次str_write字符串内容,同时虚拟串口可输入发送任意小于255个字符的字符串,
31  * 发送内容可在Finsh串口显示。
32  */
33 
34 #define USBD_DEV_NAME   "vcom"     /* 名称 */
35 rt_uint8_t str_read[255];
36 
cdc_rx_handle(rt_device_t dev,rt_size_t size)37 static rt_err_t cdc_rx_handle(rt_device_t dev, rt_size_t size)
38 {
39     /* 读取虚拟串口接收内容 */
40     rt_device_read(dev, 0, str_read, size);
41     rt_kprintf("Read message:  %s\n", str_read);
42 
43     return RT_EOK;
44 }
45 
cdc_sample(void)46 static int cdc_sample(void)
47 {
48     rt_uint8_t i;
49     rt_err_t ret = RT_EOK;
50     rt_device_t cdc_dev = RT_NULL;                           /* usb device设备句柄 */
51     rt_uint8_t str_write[] = "This is a usb cdc device test!\r\n";
52 
53 
54     /* 查找USB虚拟串口设备 */
55     cdc_dev = rt_device_find(USBD_DEV_NAME);
56     if (cdc_dev == RT_NULL)
57     {
58         rt_kprintf("cdc sample run failed! can't find %s device!\n", USBD_DEV_NAME);
59         return -RT_ERROR;
60     }
61 
62     /* 以读写方式打开设备 */
63     ret = rt_device_open(cdc_dev, RT_DEVICE_FLAG_INT_RX);
64     if (ret != RT_EOK)
65     {
66         rt_kprintf("open %s device failed!\n", USBD_DEV_NAME);
67         return ret;
68     }
69     rt_device_set_rx_indicate(cdc_dev, cdc_rx_handle);
70 
71     for (i = 1; i < 4; i++)
72     {
73         rt_kprintf("Start to send test message 3 timers :%d.\n", i);
74         if (rt_device_write(cdc_dev, 0, str_write, sizeof(str_write)) != sizeof(str_write))
75         {
76             rt_kprintf("send test message failed\n");
77             return -RT_ERROR;
78         }
79         /* 延时1000ms */
80         rt_thread_mdelay(1000);
81     }
82 
83     // for (;;);
84     return ret;
85 }
86 /* 导出到 msh 命令列表中 */
87 MSH_CMD_EXPORT(cdc_sample, usbd cdc sample);
88 #endif
89 
90 
91 #if defined(RT_USB_DEVICE_MSTORAGE)
92 
93 /* F4A0 only FS can used with spi flash */
94 #if (defined(HC32F4A0) && defined(BSP_USING_USBFS)) || \
95      defined(HC32F460)  || defined(HC32F472)
96 
97 /* Enable spibus1, SFUD, usb msc */
98 /* menuconfig:
99 1. Hardware Drivers Config--->On-Chip Peripheral Driver--->Enable SPI BUS--->Enable SPI1 BUS
100 2. Hardware Drivers Config--->On-Chip Peripheral Driver--->Enable USB--->
101                                                             [*]Use USBFS Core
102                                                                 Select USB Mode(USB Device Mode)
103                                                             [*]Enable VBUS Sensing for Device
104 3. RT-Thread Components--->Device Drivers--->Using SPI Bus/Device device drivers
105                                                 [*]Using Serial Flash Universal Driver
106                                                     [*]Using auto probe flash JEDEC SFDP parameters
107                                                     [*]Using defined supported flash chip information table
108                                                     (50000000)Default spi maximum speed(HZ)
109 4. RT-Thread Components--->Using USB legacy version
110                                                 [*]Using USB device--->
111                                                     Device type--->...Mass Storage device
112                                                     (spiflash)msc class disk name
113 
114 */
115 #include "drv_gpio.h"
116 #include "drv_spi.h"
117 #include "dev_spi_flash_sfud.h"
118 
119 #define SPI_FLASH_CHIP                  RT_USB_MSTORAGE_DISK_NAME /* msc class disk name */
120 #if defined(HC32F4A0)
121     #define SPI_FLASH_SS_PORT               GPIO_PORT_C
122     #define SPI_FLASH_SS_PIN                GPIO_PIN_07
123     #define SPI_BUS_NAME                    "spi1"
124     #define SPI_FLASH_DEVICE_NAME           "spi10"
125 #elif defined(HC32F460)
126     #define SPI_FLASH_SS_PORT               GPIO_PORT_C
127     #define SPI_FLASH_SS_PIN                GPIO_PIN_07
128     #define SPI_BUS_NAME                    "spi3"
129     #define SPI_FLASH_DEVICE_NAME           "spi30"
130 #elif defined(HC32F472)
131     #define SPI_FLASH_SS_PORT               GPIO_PORT_B
132     #define SPI_FLASH_SS_PIN                GPIO_PIN_12
133     #define SPI_BUS_NAME                    "spi1"
134     #define SPI_FLASH_DEVICE_NAME           "spi10"
135 #endif
136 
rt_hw_spi_flash_reset(char * spi_dev_name)137 static void rt_hw_spi_flash_reset(char *spi_dev_name)
138 {
139     struct rt_spi_device *spi_dev_w25;
140     rt_uint8_t w25_en_reset = 0x66;
141     rt_uint8_t w25_reset_dev = 0x99;
142 
143     spi_dev_w25 = (struct rt_spi_device *)rt_device_find(spi_dev_name);
144     if (!spi_dev_w25)
145     {
146         rt_kprintf("Can't find %s device!\n", spi_dev_name);
147     }
148     else
149     {
150         rt_spi_send(spi_dev_w25, &w25_en_reset, 1U);
151         rt_spi_send(spi_dev_w25, &w25_reset_dev, 1U);
152         DDL_DelayMS(1U);
153         rt_kprintf("Reset ext flash!\n");
154     }
155 }
156 
157 
rt_hw_spi_flash_with_sfud_init(void)158 static int rt_hw_spi_flash_with_sfud_init(void)
159 {
160 #if defined(HC32F4A0) || defined(HC32F460)
161     rt_hw_spi_device_attach(SPI_BUS_NAME, SPI_FLASH_DEVICE_NAME, GET_PIN(C, 7));
162 #elif defined(HC32F472)
163     rt_hw_spi_device_attach(SPI_BUS_NAME, SPI_FLASH_DEVICE_NAME, GET_PIN(B, 12));
164 #endif
165     if (RT_NULL == rt_sfud_flash_probe(SPI_FLASH_CHIP, SPI_FLASH_DEVICE_NAME))
166     {
167         rt_hw_spi_flash_reset(SPI_FLASH_DEVICE_NAME);
168         if (RT_NULL == rt_sfud_flash_probe(SPI_FLASH_CHIP, SPI_FLASH_DEVICE_NAME))
169         {
170             return -RT_ERROR;
171         }
172     }
173 
174     return RT_EOK;
175 }
176 INIT_COMPONENT_EXPORT(rt_hw_spi_flash_with_sfud_init);
177 #endif
178 
179 #endif
180 
181 #ifdef RT_USB_DEVICE_HID
182 #include "drv_gpio.h"
183 
184 /* menuconfig:
185 1. Hardware Drivers Config--->On-Chip Peripheral Driver--->Enable USB--->
186                                                             [*]Use USBFS Core
187                                                                 Select USB Mode(USB Device Mode)
188                                                             [*]Enable VBUS Sensing for Device
189 2. RT-Thread Components--->
190     Using USB legacy version--->
191         Using USB device--->Device type--->
192             [*]Enable to use device as HID device
193 */
194 /*
195  * 程序清单:这是一个 usb hid device 设备使用例程
196  * 例程导出了 hid_sample 命令到控制终端
197  * 命令调用格式:hid_sample
198  * 程序功能:首先会打印str_write[0]字符串内容,然后按下按键WKUP,hid设备将发送按键keyn,n是按下次数,可
199  * 通过bus hound查看数据。
200  * 发送内容可在Finsh串口显示。
201 */
202 
203 #define USBD_DEV_NAME   "hidd"     /* 名称 */
204 #if defined(HC32F4A0)
205     #define KEY_PIN_NUM     GET_PIN(A,0)          /* PA0 */
206 #elif defined(HC32F460)
207     #define KEY_PIN_NUM     GET_PIN(B,1)          /* PB1 */
208 #elif defined(HC32F472)
209     #define KEY_PIN_NUM     GET_PIN(B,5)          /* PB5 */
210 #endif
211 
hid_sample(void)212 static int hid_sample(void)
213 {
214     rt_err_t ret = RT_EOK;
215     rt_device_t hid_dev = RT_NULL;                           /* usb device设备句柄 */
216     char str_write[2][5] = {"test", "Key0"};
217 
218 
219     /* 查找设备 */
220     hid_dev = rt_device_find(USBD_DEV_NAME);
221     if (hid_dev == RT_NULL)
222     {
223         rt_kprintf("hid sample run failed! can't find %s device!\n", USBD_DEV_NAME);
224         return -RT_ERROR;
225     }
226 
227     /* 以收中断方式打开设备 */
228     ret = rt_device_open(hid_dev, RT_DEVICE_OFLAG_RDWR);
229     if (ret != RT_EOK)
230     {
231         rt_kprintf("open %s device failed!\n", USBD_DEV_NAME);
232         return ret;
233     }
234 
235     rt_kprintf("This is a usb hid device test!\r\n");
236     rt_device_write(hid_dev, 0, str_write[0], sizeof(str_write[0]));
237     rt_pin_mode(KEY_PIN_NUM, PIN_MODE_INPUT);
238 
239     for (;;)
240     {
241         rt_thread_mdelay(200);
242         if (PIN_LOW == rt_pin_read(KEY_PIN_NUM))
243         {
244             rt_device_write(hid_dev, 0, str_write[1], sizeof(str_write[1]));
245             str_write[1][3] += 0x01;
246         }
247     }
248 
249     //return ret;
250 }
251 /* 导出到 msh 命令列表中 */
252 MSH_CMD_EXPORT(hid_sample, usbd hid sample);
253 #endif
254 
255 #ifdef RT_USB_DEVICE_WINUSB
256 /* menuconfig:
257 1. Hardware Drivers Config--->On-Chip Peripheral Driver--->Enable USB--->
258                                                             [*]Use USBFS Core
259                                                                 Select USB Mode(USB Device Mode)
260                                                             [*]Enable VBUS Sensing for Device
261 2. RT-Thread Components--->
262     Using USB legacy version--->
263         Using USB device--->Device type--->
264             [*]Enable to use device as winusb device
265 */
266 /*
267  * 程序清单:这是一个 usb WINUSB device 设备使用例程
268  * RTT 的WINUSB Windows无法免驱,需要使用zadig安装winusb驱动程序(如设备管理器-通用串行总线设备-RTT Win USB已识别则不需要安装)。
269  * 例程导出了 winusb_sample 命令到控制终端
270  * 命令调用格式:winusb_sample
271  * 软件:llcom.exe
272  * 程序功能:MSH命令发送winusb_sample,运行测试程序。
273  * 打开llcom.exe软件,选择小工具-WinUSB设备-选择对应RTT Win USB设备-打开-勾选Hex发送-发送数据。
274  * 通过llcom.exe可发送bulk数据(100字符以内)到设备,设备收到后会回发给主机(llcom.exe),同时通过MSH终端显示收到的HEX数据。
275  * 注意:1、llcom.exe中的GUID与驱动程序中设定保持一致(通过设备管理器选择RTT Win USB设备的属性来查看);
276  *      2、win_usb_read()函数中的UIO_REQUEST_READ_FULL改为UIO_REQUEST_READ_BEST,实现数据即读即取;
277  *         否则需要接满传入的size数量,才会回调接收函数。
278  *
279  */
280 #define WINUSB_DEV_NAME   "winusb"     /* 名称 */
281 uint8_t str_read[100];
282 
winusb_rx_handle(rt_device_t dev,rt_size_t size)283 static rt_err_t winusb_rx_handle(rt_device_t dev, rt_size_t size)
284 {
285     uint8_t i;
286     /* 读取定时器当前值 */
287     rt_kprintf("Rx:");
288     for (i = 0; i < size; i++)
289     {
290         rt_kprintf("%x", str_read[i]);
291     }
292     rt_kprintf("\r\n");
293     rt_device_write(dev, 0, str_read, size);
294     /* prepare read config */
295     rt_device_read(dev, 0, str_read, sizeof(str_read));
296     return RT_EOK;
297 }
298 
winusb_sample(void)299 static int winusb_sample(void)
300 {
301     rt_err_t ret = RT_EOK;
302     rt_device_t winusb_dev = RT_NULL;                       /* usb device设备句柄 */
303 
304     /* 查找设备 */
305     winusb_dev = rt_device_find(WINUSB_DEV_NAME);
306     if (winusb_dev == RT_NULL)
307     {
308         rt_kprintf("winusb sample run failed! can't find %s device!\n", WINUSB_DEV_NAME);
309         return -RT_ERROR;
310     }
311 
312     /* 以读写方式打开设备 */
313     ret = rt_device_open(winusb_dev, RT_DEVICE_OFLAG_RDWR);
314     if (ret != RT_EOK)
315     {
316         rt_kprintf("open %s device failed!\n", WINUSB_DEV_NAME);
317         return ret;
318     }
319     rt_kprintf("Found and open success %s device!\n", WINUSB_DEV_NAME);
320 
321     ret = rt_device_set_rx_indicate(winusb_dev, winusb_rx_handle);
322     if (ret == RT_EOK)
323     {
324         /* prepare read config,set once,read once, */
325         rt_device_read(winusb_dev, 0, str_read, sizeof(str_read));
326     }
327     return ret;
328 }
329 
330 /* 导出到 msh 命令列表中 */
331 MSH_CMD_EXPORT(winusb_sample, usbd winusb sample);
332 #endif
333