5.29 USBFSD 使用说明
本章说明 N32H49x 全速 USB 设备(USBFSD)驱动的文件组成、接口来源与 12 个示例。USBFSD 使用随 SDK 发布的独立驱动 firmware/n32h49x_usbfsd_driver,不属于标准外设库,示例覆盖 HID、CDC、MSC、Printer 等设备类与组合设备。USB 时钟、数据包缓冲区与端点配置请配合用户手册的“通用串行总线全速设备接口(USB_FS_Device)”章节阅读。
5.29.1 相关文件
| 相对路径 | 作用 |
|---|---|
firmware/n32h49x_usbfsd_driver/inc/ |
驱动头文件目录:usbfsd_core.h 声明控制传输状态机与标准请求处理函数,usbfsd_init.h、usbfsd_sil.h、usbfsd_mem.h、usbfsd_int.h 声明设备初始化、底层收发、缓冲区拷贝与中断处理函数,usbfsd_type.h、usbfsd_regs.h、usbfsd_def.h 定义类型、寄存器与描述符结构,usbfsd_lib.h 汇总全部头文件 |
firmware/n32h49x_usbfsd_driver/src/ |
驱动源文件目录:usbfsd_core.c、usbfsd_init.c、usbfsd_sil.c、usbfsd_mem.c、usbfsd_int.c、usbfsd_regs.c 实现上述接口 |
projects/n32h49x_EVAL/examples/USBFSD/ |
USBFSD 示例根目录,含 12 个示例:HID_CDC_Composite、HID_Customer、HID_Keyboard、HID_Keyboard_Xtal_Less、HID_MSC_Composite、JoyStickMouse、Mass_Storage、MSC_CDC_Composite、Printer、Virtual_COM_Port、Virtual_COM_Port_LoopBack、Virtual_COM_Port_LoopBack_Composite |
projects/n32h49x_EVAL/examples/USBFSD/HID_Keyboard/ |
该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt |
projects/n32h49x_EVAL/bsp/ |
HID 键盘、HID 自定义设备、HID 与 CDC 组合、HID 与 MSC 组合等示例引用的板级支持文件:inc/bsp_eval.h 定义板卡选择与 LED、按键引脚宏,src/bsp_eval.c 提供 LED 与按键初始化函数 |
5.29.2 API 参考
USBFSD 的接口来自独立驱动 firmware/n32h49x_usbfsd_driver,不属于标准外设库,因此不按标准外设库的 API 条目形式列出。示例通过 usbfsd_lib.h 一次性引入该驱动全部头文件,其中 usbfsd_core.h、usbfsd_init.h、usbfsd_sil.h、usbfsd_mem.h、usbfsd_int.h 共声明 23 个公开函数。
按头文件划分:usbfsd_core.h 声明控制传输状态机与标准请求处理函数(USB_ProcessSetup0、USB_ProcessPost0、USB_ProcessIn0、USB_ProcessOut0、Standard_GetConfiguration、Standard_SetConfiguration、Standard_GetInterface、Standard_SetInterface、Standard_GetDescriptorData、Standard_GetStatus、Standard_ClearFeature、Standard_SetEndPointFeature、Standard_SetDeviceFeature、USB_SetDeviceAddress、USB_ProcessNop);usbfsd_init.h 声明 USB_Init;usbfsd_sil.h 声明底层收发 USB_SilInit、USB_SilWrite、USB_SilRead;usbfsd_mem.h 声明数据包缓冲区拷贝 USB_CopyUserToPMABuf、USB_CopyPMAToUserBuf;usbfsd_int.h 声明中断处理 USB_CorrectTransferLp、USB_CorrectTransferHp。
类型、寄存器与描述符基础结构由 usbfsd_type.h、usbfsd_regs.h、usbfsd_def.h 定义;各示例的设备类实现(描述符、端点、属性与唤醒回调)位于各自示例工程的 inc/、src/ 下,不属于驱动本身。
5.29.3 Demo 示例说明
本节说明 USBFSD 的 12 个示例,覆盖 HID 键盘、HID 自定义设备、HID 与 CDC 组合、HID 与 MSC 组合、虚拟串口及其回环等用法。
5.29.3.1 HID_CDC_Composite HID 与 CDC 组合设备
工程目录: projects/n32h49x_EVAL/examples/USBFSD/HID_CDC_Composite/
配置 USBFS 引脚为复用功能→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→按键通过 IN 端点上报 HID 报告→主机 OUT 端点数据控制三路 LED→虚拟串口与 USART1 双向转发数据
| 项目 | 源码解读 |
|---|---|
| 功能 | 同一 USB 设备同时提供 HID 与 CDC 两个接口:HID 上报按键并接收主机控制 LED 的命令,CDC 与 USART1 双向转发数据。 |
| 源码组成 | src/main.c 主循环与 HID 报告;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO、中断与 USART 配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c 组合设备描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; KEY2 为 PA15,LED1 为 PA3、LED2 为 PB3、LED3 为 PA8; USART1 为 PA9(TX)与 PA10(RX),波特率 115200。 |
| 程序与数据路径 | main 初始化板级 LED 与按键、USBFS 引脚和中断后,用 240MHz 系统时钟配置并启动 USB 设备,等待主机进入已配置状态;主循环在 PrevXferComplete 为真时读取 KEY2 状态,把两字节 HID 报告写入端点 1 的 IN 缓冲区并置为有效;主机下发的 OUT 数据经端点回调控制 LED1~LED3 亮灭,USART1 与虚拟串口之间双向转发数据。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config、USB_SilWrite、SetEPTxStatus、CDC_Receive_DATA、CDC_Send_DATA |
| 验证方法 | 下载复位后经 J4 口连接主机,主机识别出串口与 HID 设备; 点击 KEY2 时通过 IN 端点上报按键; 主机经 OUT 端点发送 0x01、0x02、0x03 加 0x00 或 0x01 可分别熄灭或点亮 LED1~LED3; 虚拟串口与 USART1 之间可双向收发数据。 |
| 使用提示 | 不使用开发板上的串口工具时,需要断开与 NSLINK 连接的 TX 与 RX; HID 报告长度为 2 字节,第 0 字节固定为 0x05; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例先把 HID 与 CDC 组合为一个设备,再在 HID 通道上报按键、在 CDC 通道转发串口数据。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/HID_CDC_Composite/src/main.c
1. 初始化板级与 USB 资源。 先初始化板载 LED 与按键,再配置 USBFS 引脚复用和 USB 中断。
Hardware_Board_Led_Init();
Hardware_Board_Key_Init();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
3. 在主循环上报按键。 上一次传输完成后读取 KEY2 状态,把两字节 HID 报告写入 IN 端点并置为有效。
if(PrevXferComplete)
{
Sendbuffer[0] = 0x05;
if (KEY_Press_Status_Read(LEFT_BUTTON_AND_2) == SET)
{
Sendbuffer[1] = 0x01;
}
else
{
Sendbuffer[1] = 0x00;
}
USB_SilWrite(EP1_IN, Sendbuffer, 2);
SetEPTxStatus(ENDP1, EP_TX_VALID);
PrevXferComplete = 0;
}
对应源码: src/main.c
5.29.3.2 HID_Customer 自定义 HID 设备
工程目录: projects/n32h49x_EVAL/examples/USBFSD/HID_Customer/
配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→按键通过 IN 端点发送两字节报告→主机 OUT 端点数据控制三路 LED
| 项目 | 源码解读 |
|---|---|
| 功能 | 自定义 HID 设备:KEY2 触发时向主机上报按键,同时接收主机通过 OUT 端点下发的 LED 控制命令。 |
| 源码组成 | src/main.c 主循环与 HID 报告;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c 自定义 HID 描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; KEY2 为 PA15,LED1 为 PA3、LED2 为 PB3、LED3 为 PA8。 |
| 程序与数据路径 | main 初始化板级 LED 与按键、USBFS 引脚和中断后,用 240MHz 系统时钟配置并启动 USB 设备,等待主机进入已配置状态;主循环在 PrevXferComplete 为真时把报告首字节置为 0x05,再按 KEY2 电平把第二字节置为 0x01 或 0x00,写入端点 1 的 IN 缓冲区并置为有效;主机下发的 OUT 数据在端点回调中解析为 LED1~LED3 的亮灭命令。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config、USB_SilWrite、SetEPTxStatus |
| 验证方法 | 下载复位后经 J4 口连接主机,主机识别出 HID 设备; 点击 KEY2 时通过 IN 端点上报按键; 主机经 OUT 端点发送 0x01、0x02、0x03 加 0x00 或 0x01 可分别熄灭或点亮 LED1~LED3。 |
| 使用提示 | HID 报告长度为 2 字节,第 0 字节固定为 0x05; 修改报告格式时需同步修改示例中的报告描述符; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例实现一个自定义 HID 设备:主循环上报按键状态,端点回调接收主机下发的 LED 控制命令。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/HID_Customer/src/main.c
1. 初始化板级与 USB 资源。 先初始化板载 LED 与按键,再配置 USBFS 引脚复用和 USB 中断。
Hardware_Board_Led_Init();
Hardware_Board_Key_Init();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
3. 在主循环上报按键。 上一次传输完成后按 KEY2 电平组装两字节报告,写入 IN 端点并置为有效。
if(PrevXferComplete)
{
Sendbuffer[0] = 0x05;
if (KEY_Press_Status_Read(LEFT_BUTTON_AND_2) == SET)
{
Sendbuffer[1] = 0x01;
}
else
{
Sendbuffer[1] = 0x00;
}
USB_SilWrite(EP1_IN, Sendbuffer, 2);
SetEPTxStatus(ENDP1, EP_TX_VALID);
PrevXferComplete = 0;
}
对应源码: src/main.c
5.29.3.3 HID_Keyboard USB 键盘
工程目录: projects/n32h49x_EVAL/examples/USBFSD/HID_Keyboard/
配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→轮询按键生成键码写入端点缓冲→通过 IN 端点发送 8 字节按键报告→用 LED 指示 CapsLock 与 NumLock 状态
| 项目 | 源码解读 |
|---|---|
| 功能 | 把评估板做成 USB HID 键盘:KEY1、KEY2、KEY3 分别输入 a、b、c,主机切换 CapsLock 与 NumLock 时对应指示灯亮灭。 |
| 源码组成 | src/main.c 主循环、按键键码与键盘灯;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置,含键盘指示灯宏;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c HID 键盘描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; KEY1 为 PC13、KEY2 为 PA15、KEY3 为 PB4,均为键盘输入; 键盘指示灯 D1 为 PA3、D2 为 PB3。 |
| 程序与数据路径 | main 初始化板级 LED 与按键、USBFS 引脚和中断后,用 240MHz 系统时钟配置并启动 USB 设备,等待主机进入已配置状态;主循环在 PrevXferComplete 为真时按 KEY1、KEY2、KEY3 的按下状态决定 key_buffer[2] 的键码,把 8 字节报告写入端点 1 的 IN 缓冲区并置为有效,随后清零再次上报;主机下发的键盘灯命令控制 D1、D2 指示灯亮灭。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config、USB_SilWrite、SetEPTxStatus |
| 验证方法 | 下载复位后经 J4 口连接主机,主机识别出键盘设备; 按下 KEY1、KEY2、KEY3 时主机输入 a、b、c; 用另一个键盘切换 CapsLock 与 NumLock 时 D1、D2 对应亮灭。 |
| 使用提示 | 按键键码 0x04、0x05、0x06 分别对应 a、b、c; 键盘指示灯由示例的键盘灯回调控制,引脚定义在板级头文件中; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例把评估板做成 USB HID 键盘:主循环轮询按键生成键码,端点回调处理主机的键盘灯命令。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/HID_Keyboard/src/main.c
1. 初始化板级与 USB 资源。 先初始化板载 LED 与按键,再配置 USBFS 引脚复用和 USB 中断。
Hardware_Board_Led_Init();
Hardware_Board_Key_Init();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
3. 写入按键报告并置端点有效。 键码组装完成后,把 8 字节报告写入 IN 端点、置为有效,并清零键码准备下一次上报。
USB_SilWrite(EP1_IN, key_buffer, 8);
SetEPTxStatus(ENDP1, EP_TX_VALID);
key_buffer[2] = 0;
PrevXferComplete = 0;
}
对应源码: src/main.c
5.29.3.4 HID_Keyboard_Xtal_Less 无晶体 USB 键盘
工程目录: projects/n32h49x_EVAL/examples/USBFSD/HID_Keyboard_Xtal_Less/
配置 USBFS 引脚与中断→以内部时钟源启动 USB 设备→等待主机枚举并进入已配置状态→检测挂起状态并支持远程唤醒→轮询按键通过 IN 端点发送按键报告→用 LED 指示 CapsLock 与 NumLock 状态
| 项目 | 源码解读 |
|---|---|
| 功能 | 无晶体模式下的 USB HID 键盘:不使用外部晶振时由内部时钟为 USB 提供时钟,按键与指示灯行为与 HID_Keyboard 一致。 |
| 源码组成 | src/main.c 主循环、挂起唤醒与按键处理;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c HID 键盘描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 未定义 USE_USBFSD_XTALLESS 时系统时钟取 240MHz,定义时取 SystemCoreClock;HSE 16MHz,USB 时钟 48MHz; KEY1 为 PC13、KEY2 为 PA15、KEY3 为 PB4,键盘指示灯 D1 为 PA3、D2 为 PB3。 |
| 程序与数据路径 | main 初始化板级 LED、按键和按键中断后,再配置 USBFS 引脚与中断,并按键选择系统时钟后配置并启动 USB 设备;主循环在挂起状态下比较连续两次 SOF 计数判断是否被唤醒,唤醒后恢复为已配置状态; 已配置且无远程唤醒时按 KEY1、KEY2、KEY3 生成键码,写入端点 1 的 IN 缓冲区并置为有效。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config、USB_SilWrite、SetEPTxStatus、Set_System、Cfg_KeyInterrupt |
| 验证方法 | 下载复位后经 J4 口连接主机,主机识别出键盘设备; 按下 KEY1、KEY2、KEY3 时主机输入 a、b、c; 用另一个键盘切换 CapsLock 与 NumLock 时 D1、D2 对应亮灭。 |
| 使用提示 | 该示例在挂起状态下通过比较 SOF 计数判断唤醒,比 HID_Keyboard 增加了远程唤醒处理; 按键键码 0x04、0x05、0x06 分别对应 a、b、c; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例在 HID 键盘的基础上支持无晶体模式与远程唤醒:主机挂起后通过 SOF 计数判断是否被唤醒。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/HID_Keyboard_Xtal_Less/src/main.c
1. 初始化板级、按键中断与 USB 资源。 先初始化 LED、按键与按键中断,再配置 USBFS 引脚复用和 USB 中断。
Hardware_Board_Led_Init();
Hardware_Board_Key_Init();
Cfg_KeyInterrupt();
Set_System();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 选择系统时钟并启动设备。 未定义无晶体宏时取 240MHz,定义时取内核时钟,随后配置并启动 USB 设备。
#ifndef USE_USBFSD_XTALLESS
#if defined (N32H49X)
system_clock = SYSCLK_VALUE_240MHz;
#endif
#else
system_clock = SystemCoreClock;
#endif /* USE_USBFSD_XTALLESS */
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
3. 挂起后判断是否被唤醒。 记录当前 SOF 计数并等待一段时间,若计数变化说明总线仍有活动,恢复为已配置状态。
if (bDeviceState == SUSPENDED)
{
LastIntPackSOF = bIntPackSOF;
for (i = 0; i < 0xffff; i++);
if (LastIntPackSOF != bIntPackSOF)
{
bDeviceState = CONFIGURED;
}
}
对应源码: src/main.c
5.29.3.5 HID_MSC_Composite HID 与 MSC 组合设备
工程目录: projects/n32h49x_EVAL/examples/USBFSD/HID_MSC_Composite/
初始化 SPI FLASH 并挂载存储介质→配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→按主机 OUT 数据控制三路 LED→通过 U 盘接口读写 SPI FLASH
| 项目 | 源码解读 |
|---|---|
| 功能 | HID 与 MSC 组合设备:设备同时呈现为 HID 设备与 U 盘,U 盘由板上 SPI FLASH 模拟,HID 上报按键并接收 LED 控制命令。 |
| 源码组成 | src/main.c 存储介质初始化与主循环;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c 组合设备描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; SPI 的 NSS 为 PA15、SCK 为 PB3、MISO 为 PD11、MOSI 为 PD12,连接 W25Q128; KEY2 为 PA15,LED1 为 PA3、LED2 为 PB3、LED3 为 PA8。 |
| 程序与数据路径 | main 先初始化 SPI FLASH 存储介质,再初始化 USBFS 引脚与中断,用 240MHz 系统时钟配置并启动 USB 设备;等待主机进入已配置状态后,主循环按 KEY2 状态把 HID 报告写入端点 1 的 IN 缓冲区并置为有效; 主机经 OUT 端点控制 LED1~LED3,U 盘的读写请求由 MSC 回调经 SPI FLASH 完成。 |
| 主要 API | USB_Config、USB_Init、MAL_Config、USBFS_IO_Configure、USB_Interrupts_Config、USB_SilWrite、SetEPTxStatus |
| 验证方法 | 下载复位后经 J4 口连接主机,主机同时识别出 U 盘与 HID 设备; 点击 KEY2 时通过 IN 端点上报按键; 主机经 OUT 端点发送 0x01、0x02、0x03 加 0x00 或 0x01 可分别熄灭或点亮 LED1~LED3。 |
| 使用提示 | 首次挂载 U 盘需要格式化,之后即可作为 U 盘使用; 在 N32H49XZEL7_EVB V1.1 开发板上需用跳线帽连接 J20; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例把 HID 与 MSC 组合为一个设备:HID 通道上报按键并接收 LED 控制,MSC 通道用 SPI FLASH 模拟 U 盘。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/HID_MSC_Composite/src/main.c
1. 初始化存储介质、板级与 USB 资源。 先初始化板载 LED 与按键,再初始化 SPI FLASH 存储介质、USBFS 引脚和中断。
Hardware_Board_Led_Init();
Hardware_Board_Key_Init();
MAL_Config();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
3. 在主循环上报按键。 上一次传输完成后读取 KEY2 状态,把两字节 HID 报告写入 IN 端点并置为有效。
if(PrevXferComplete)
{
Sendbuffer[0] = 0x05;
if (KEY_Press_Status_Read(LEFT_BUTTON_AND_2) == SET)
{
Sendbuffer[1] = 0x01;
}
else
{
Sendbuffer[1] = 0x00;
}
USB_SilWrite(EP1_IN, Sendbuffer, 2);
SetEPTxStatus(ENDP1, EP_TX_VALID);
PrevXferComplete = 0;
}
对应源码: src/main.c
5.29.3.6 JoyStickMouse USB 摇杆鼠标
工程目录: projects/n32h49x_EVAL/examples/USBFSD/JoyStickMouse/
配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→轮询上、下、左、右按键方向→通过 IN 端点发送鼠标位移报告
| 项目 | 源码解读 |
|---|---|
| 功能 | 把评估板按键当作鼠标:WKUP、KEY1、KEY2、KEY3 分别让鼠标上、下、左、右移动。 |
| 源码组成 | src/main.c 主循环与鼠标报告;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c HID 鼠标描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; 上为 WKUP(PA0)、下为 KEY1(PC13)、左为 KEY2(PA15)、右为 KEY3(PB4)。 |
| 程序与数据路径 | main 初始化板级 LED 与按键、USBFS 引脚和中断后,用 240MHz 系统时钟配置并启动 USB 设备;主循环在已配置状态下,只要方向状态非零且上一次传输已完成,就把鼠标位移报告写入端点发送缓冲区。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config、JoyState、Joystick_Send |
| 验证方法 | 下载复位后经 J4 口连接主机,主机识别出鼠标设备; 按下 WKUP、KEY1、KEY2、KEY3 时鼠标分别上、下、左、右移动。 |
| 使用提示 | 鼠标位移报告由示例按按键方向生成; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例把评估板按键当作鼠标:主循环轮询方向状态,把位移报告写入端点后由中断发送。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/JoyStickMouse/src/main.c
1. 初始化板级与 USB 资源。 先初始化板载 LED 与按键,再配置 USBFS 引脚复用和 USB 中断。
Hardware_Board_Led_Init();
Hardware_Board_Key_Init();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
}
3. 在主循环按方向发送位移。 已配置状态下,只要方向状态非零且上一次传输已完成,就发送鼠标报告。
while (1)
{
if (bDeviceState == CONFIGURED)
{
if ((JoyState() != 0) && (PrevXferComplete))
{
Joystick_Send(JoyState());
}
}
}
对应源码: src/main.c
5.29.3.7 Mass_Storage U 盘设备
工程目录: projects/n32h49x_EVAL/examples/USBFSD/Mass_Storage/
初始化 SPI FLASH 并挂载存储介质→配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→通过 U 盘接口读写 SPI FLASH
| 项目 | 源码解读 |
|---|---|
| 功能 | 用板上 SPI FLASH 模拟 U 盘:主机把设备识别为大容量存储设备,可在其中读写文件。 |
| 源码组成 | src/main.c 存储介质初始化与主循环;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c MSC 描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; SPI 的 NSS 为 PA15、SCK 为 PB3、MISO 为 PD11、MOSI 为 PD12,连接 W25Q128。 |
| 程序与数据路径 | main 先初始化 SPI FLASH 存储介质,再初始化 USBFS 引脚、中断,用 240MHz 系统时钟配置并启动 USB 设备,等待主机进入已配置状态;挂载后 U 盘的读写请求由 MSC 回调经 SPI FLASH 完成。 |
| 主要 API | USB_Config、USB_Init、MAL_Config、USBFS_IO_Configure、USB_Interrupts_Config |
| 验证方法 | 下载复位后经 J4 口连接主机,挂载完成后设备被识别为 U 盘,可正常读写。 |
| 使用提示 | 首次挂载 U 盘需要格式化,之后即可作为 U 盘使用; 在 N32H49XZEL7_EVB V1.1 开发板上需用跳线帽连接 J20; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例用板上 SPI FLASH 模拟 U 盘:主程序先把 FLASH 挂载为存储介质,再启动设备等待主机访问。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/Mass_Storage/src/main.c
1. 初始化存储介质与 USB 资源。 先初始化 SPI FLASH 存储介质,再配置 USBFS 引脚复用和 USB 中断。
MAL_Config();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
}
3. 空循环等待 U 盘读写。 进入已配置状态后主循环为空,读写请求全部由 MSC 回调处理。
while(1)
{
}
对应源码: src/main.c
5.29.3.8 MSC_CDC_Composite 存储与串口组合设备
工程目录: projects/n32h49x_EVAL/examples/USBFSD/MSC_CDC_Composite/
初始化 SPI FLASH 并挂载存储介质→配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→通过 U 盘接口读写 SPI FLASH→虚拟串口与 USART1 双向转发数据
| 项目 | 源码解读 |
|---|---|
| 功能 | MSC 与 CDC 组合设备:设备同时呈现为 U 盘与串口,U 盘由板上 SPI FLASH 模拟,串口与 USART1 双向转发数据。 |
| 源码组成 | src/main.c 存储介质初始化与主循环;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO、中断与 USART 配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c 组合设备描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; SPI 的 NSS 为 PA15、SCK 为 PB3、MISO 为 PD11、MOSI 为 PD12,连接 W25Q128; USART1 为 PA9(TX)与 PA10(RX),波特率 115200。 |
| 程序与数据路径 | main 先初始化 SPI FLASH 存储介质,再初始化 USBFS 引脚与中断,用 240MHz 系统时钟配置并启动 USB 设备,等待主机进入已配置状态;USART1 与虚拟串口之间双向转发数据,U 盘的读写请求由 MSC 回调经 SPI FLASH 完成。 |
| 主要 API | USB_Config、USB_Init、MAL_Config、USBFS_IO_Configure、USB_Interrupts_Config |
| 验证方法 | 下载复位后经 J4 口连接主机,主机同时识别出串口与 U 盘设备; 虚拟串口与 USART1 之间可双向收发数据。 |
| 使用提示 | 首次挂载 U 盘需要格式化,之后即可作为 U 盘使用; 在 N32H49XZEL7_EVB V1.1 开发板上需用跳线帽连接 J20; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例把 MSC 与 CDC 组合为一个设备:MSC 通道用 SPI FLASH 模拟 U 盘,CDC 通道与 USART1 互转数据。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/MSC_CDC_Composite/src/main.c
1. 初始化存储介质与 USB 资源。 先初始化 SPI FLASH 存储介质,再配置 USBFS 引脚复用和 USB 中断。
MAL_Config();
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
}
3. 空循环等待数据转发。 进入已配置状态后主循环为空,U 盘读写与串口转发分别由 MSC 与 CDC 回调处理。
while(1)
{
}
对应源码: src/main.c
5.29.3.9 Printer USB 打印机
工程目录: projects/n32h49x_EVAL/examples/USBFSD/Printer/
配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→通过批量端点接收主机打印数据→在端点回调中转发收到的数据
| 项目 | 源码解读 |
|---|---|
| 功能 | USB 打印机设备:主机把设备识别为 USB 打印支持,设备通过批量端点接收主机下发的打印数据。 |
| 源码组成 | src/main.c 发送流程与主循环;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c 打印机描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz。 |
| 程序与数据路径 | main 初始化 USBFS 引脚与中断后,用 240MHz 系统时钟配置并启动 USB 设备,等待主机进入已配置状态;主循环检测到接收标志后清零,并把最近一次收到的批量数据交回发送流程; 主机下发的打印数据由批量端点的回调接收。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config |
| 验证方法 | 下载复位后经 J4 口连接主机,主机识别出 USB 打印支持; 在批量端点回调中设置断点,可看到正常接收主机下发的数据。 |
| 使用提示 | 打印数据由批量端点接收,可在端点回调中断点观察; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例把评估板做成 USB 打印机:批量端点接收主机下发的打印数据,主循环把收到的数据交回发送流程。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/Printer/src/main.c
1. 初始化 USB 资源。 配置 USBFS 引脚复用与 USB 中断。
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
}
3. 主循环转发收到的数据。 检测到接收标志后清零,并调用发送流程把最近一次收到的数据送出。
while (1)
{
if (m_rx_flag)
{
m_rx_flag = 0;
m_BulkData_send(m_rx_buf, m_rx_len);
}
}
对应源码: src/main.c
5.29.3.10 Virtual_COM_Port 虚拟串口
工程目录: projects/n32h49x_EVAL/examples/USBFSD/Virtual_COM_Port/
配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→虚拟串口与 USART1 双向转发数据
| 项目 | 源码解读 |
|---|---|
| 功能 | USB 虚拟串口设备:主机把设备识别为串口,虚拟串口与板上 USART1 之间双向转发数据。 |
| 源码组成 | src/main.c 主循环;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO、中断与 USART 配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c CDC 描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; USART1 为 PA9(TX)与 PA10(RX),波特率 115200。 |
| 程序与数据路径 | main 初始化 USBFS 引脚与中断后,用 240MHz 系统时钟配置并启动 USB 设备,等待主机进入已配置状态;USART1 收到的数据经端点 1 的 IN 缓冲区转发到虚拟串口,虚拟串口下发的数据经 USART1 发出。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config |
| 验证方法 | 下载复位后经 J4 口连接主机,挂载完成后设备管理中出现新增串口; 把 USART1 接到串口工具,虚拟串口发送的数据由串口工具接收,串口工具发送的数据由虚拟串口接收。 |
| 使用提示 | 串口收发长度受示例缓冲区大小限制; 不使用开发板上的串口工具时,需要断开与 NSLINK 连接的 TX 与 RX; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例把评估板做成 USB 虚拟串口:设备初始化后,虚拟串口与板上 USART1 之间双向转发数据。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/Virtual_COM_Port/src/main.c
1. 初始化 USB 资源。 配置 USBFS 引脚复用与 USB 中断。
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
while (bDeviceState != CONFIGURED)
{
}
}
3. 空循环等待串口转发。 进入已配置状态后主循环为空,转发全部由收发的端点回调处理。
while(1)
{
}
对应源码: src/main.c
5.29.3.11 Virtual_COM_Port_LoopBack 虚拟串口回环
工程目录: projects/n32h49x_EVAL/examples/USBFSD/Virtual_COM_Port_LoopBack/
配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→读取虚拟串口收到的数据→通过 IN 端点原样回发
| 项目 | 源码解读 |
|---|---|
| 功能 | USB 虚拟串口回环:设备把从虚拟串口收到的数据原样发回主机。 |
| 源码组成 | src/main.c 主循环与回环逻辑;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c CDC 描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; 虚拟串口为 115200、8 数据位、1 停止位、无校验。 |
| 程序与数据路径 | main 初始化 USBFS 引脚与中断后,用 240MHz 系统时钟配置并启动 USB 设备;进入已配置状态后循环读取虚拟串口数据,只要收到非零长度数据且上一次发送已完成,就把同一份数据原样发回。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config、CDC_Receive_DATA、CDC_Send_DATA |
| 验证方法 | 下载复位后经 J4 口连接主机,挂载完成后设备管理中出现新增串口; 用串口工具打开该虚拟串口发送数据,立即收到相同数据。 |
| 使用提示 | 回环不经过 USART1,只经虚拟串口自身; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例把评估板做成虚拟串口回环:主循环不断读取虚拟串口数据,收到后原样发回主机。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/Virtual_COM_Port_LoopBack/src/main.c
1. 初始化 USB 资源。 配置 USBFS 引脚复用与 USB 中断。
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
3. 主循环读取并原样回发。 已配置状态下读取虚拟串口数据,收到非零长度数据且上一次发送完成后原样发回。
while(1)
{
if (bDeviceState == CONFIGURED)
{
CDC_Receive_DATA();
/*Check to see if we have data yet */
if (Receive_length != 0)
{
if (packet_sent == 1)
{
CDC_Send_DATA ((unsigned char*)Receive_Buffer,Receive_length);
}
Receive_length = 0;
}
}
}
对应源码: src/main.c
5.29.3.12 Virtual_COM_Port_LoopBack_Composite 多路虚拟串口回环
工程目录: projects/n32h49x_EVAL/examples/USBFSD/Virtual_COM_Port_LoopBack_Composite/
配置 USBFS 引脚与中断→启动 USB 设备时钟并初始化设备→等待主机枚举并进入已配置状态→读取两路虚拟串口收到的数据→分别通过对应 IN 端点原样回发
| 项目 | 源码解读 |
|---|---|
| 功能 | 多路虚拟串口回环:设备提供多路虚拟串口,各路把收到的数据原样发回主机。 |
| 源码组成 | src/main.c 主循环与多路回环逻辑;src/hw_config.c、inc/hw_config.h USB 时钟、GPIO 与中断配置;src/usbfsd_desc.c、src/usbfsd_endp.c、src/usbfsd_prop.c、src/usbfsd_istr.c、src/usbfsd_pwr.c 多路 CDC 描述符、端点、属性、中断与唤醒实现;readme.txt 功能与使用说明;MDK-ARM/、EWARM/ Keil 与 IAR 工程。 |
| 关键配置 | 系统时钟 240MHz,HSE 16MHz,USB 时钟 48MHz; 虚拟串口路数由示例宏决定,各路各自维护接收缓冲; 虚拟串口为 115200、8 数据位、1 停止位、无校验。 |
| 程序与数据路径 | main 先按串口路数初始化各路的发送与接收标志,再初始化 USBFS 引脚与中断,用 240MHz 系统时钟配置并启动 USB 设备;进入已配置状态后循环读取各虚拟串口数据,对每一路收到非零长度数据的串口把数据原样发回。 |
| 主要 API | USB_Config、USB_Init、USBFS_IO_Configure、USB_Interrupts_Config、CDC_Receive_DATA、CDC_Send_DATA |
| 验证方法 | 下载复位后经 J4 口连接主机,挂载完成后设备管理中出现新增串口; 用串口工具打开虚拟串口发送数据,立即收到相同数据。 |
| 使用提示 | 回环不经过 USART1,只经虚拟串口自身; 每路串口使用独立的接收缓冲与端点,路数由示例宏决定; 开发环境为 KEIL MDK-ARM V5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
该示例提供多路虚拟串口并分别回环:主程序按路数初始化标志,主循环逐路读取并原样发回。
数据路径: projects/n32h49x_EVAL/examples/USBFSD/Virtual_COM_Port_LoopBack_Composite/src/main.c
1. 初始化 USB 资源。 配置 USBFS 引脚复用与 USB 中断。
USBFS_IO_Configure();
USB_Interrupts_Config();
2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备。
if(USB_Config(system_clock) == SUCCESS)
{
USB_Init();
3. 主循环逐路读取并回发。 已配置状态下读取各路虚拟串口数据,随后逐路把收到的数据原样发回。
while(1)
{
if (bDeviceState == CONFIGURED)
{
CDC_Receive_DATA();
/*Check to see if we have data yet */
对应源码: src/main.c
5.29.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| USB 时钟配置 | 使用 USB_FS_Device 时需保证 PLLCLK 为 48MHz、96MHz、144MHz、192MHz 或 240MHz,否则模块无法正常工作; APB1 总线时钟频率必须大于 8MHz,否则可能导致数据缓冲区上溢或下溢; 只有在 USB 模块时钟打开后,才能操作 USB 寄存器与模块 SRAM。 |
用户手册 |
| 应用访问 Packet Buffer Memory | 用户程序从 APB1 总线访问数据包缓冲区须按 32 位对齐、16 位读写,不能按 8 位或 32 位访问; 缓冲区描述表起始地址必须在数据包缓冲区内,并按 8 字节对齐。 |
用户手册 |
| 复位后使能 USB | 每次系统复位或上电复位后使能 USB 模块,都需要配置 DP 信号线上拉电阻; USB 复位中断产生后,软件必须在 10ms 内使能端点 0 的传输,并设置 USB_ADDR.EFUC 位、初始化端点 0 寄存器及其数据包缓冲区。 |
用户手册 |
| 挂起与唤醒 | USB 设备进入挂起状态后仍必须具备检测 RESET 信号的功能; 只有在 USB_CTRL.FSUSPD 置 1 时才可设置 USB_CTRL.RESUM 位; 进入低功耗模式需先置位 FSUSPD,再置位 USB_CTRL.LP_MODE。 |
用户手册 |
| 控制端点的 SETUP 事务 | USB 设备收到 SETUP 令牌包后不能用 NAK 或 STALL 握手包回复,只能用 ACK 回复; 端点 0 的接收状态即使是 STALL 或 NAK,USB 模块仍可接收 SETUP 令牌包; 当 USB_EP0.CTRS_RX 为 1 时再次收到 SETUP 令牌包,模块会丢弃该包且不回复任何握手包。 |
用户手册 |
| 端点接收溢出与双缓冲 | 接收到的数据超过接收端点的数据包缓冲区大小时,硬件自动停止写入并回复 STALL、置位缓冲区溢出错误,但不产生中断; 双缓冲批量端点只在缓冲区访问冲突时才置 NAK 状态; 同步端点状态只能设置为 VALID 或 DISABLED,设置成 STALL 或 NAK 是非法的。 |
用户手册 |