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 中断。

src/main.csrc/main.c · main
    Hardware_Board_Led_Init();
    Hardware_Board_Key_Init();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }

3. 在主循环上报按键。 上一次传输完成后读取 KEY2 状态,把两字节 HID 报告写入 IN 端点并置为有效。

src/main.csrc/main.c · main
            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 中断。

src/main.csrc/main.c · main
    Hardware_Board_Led_Init();
    Hardware_Board_Key_Init();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }

3. 在主循环上报按键。 上一次传输完成后按 KEY2 电平组装两字节报告,写入 IN 端点并置为有效。

src/main.csrc/main.c · main
            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 中断。

src/main.csrc/main.c · main
    Hardware_Board_Led_Init();
    Hardware_Board_Key_Init();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }

3. 写入按键报告并置端点有效。 键码组装完成后,把 8 字节报告写入 IN 端点、置为有效,并清零键码准备下一次上报。

src/main.csrc/main.c · main
                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 中断。

src/main.csrc/main.c · main
    Hardware_Board_Led_Init();
    Hardware_Board_Key_Init();
    Cfg_KeyInterrupt();
    Set_System();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 选择系统时钟并启动设备。 未定义无晶体宏时取 240MHz,定义时取内核时钟,随后配置并启动 USB 设备。

src/main.csrc/main.c · main
#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 计数并等待一段时间,若计数变化说明总线仍有活动,恢复为已配置状态。

src/main.csrc/main.c · main
            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 引脚和中断。

src/main.csrc/main.c · main
    Hardware_Board_Led_Init();
    Hardware_Board_Key_Init();
    MAL_Config();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }

3. 在主循环上报按键。 上一次传输完成后读取 KEY2 状态,把两字节 HID 报告写入 IN 端点并置为有效。

src/main.csrc/main.c · main
            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 中断。

src/main.csrc/main.c · main
    Hardware_Board_Led_Init();
    Hardware_Board_Key_Init();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();
    }

3. 在主循环按方向发送位移。 已配置状态下,只要方向状态非零且上一次传输已完成,就发送鼠标报告。

src/main.csrc/main.c · main
    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 中断。

src/main.csrc/main.c · main
    MAL_Config();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }
    }

3. 空循环等待 U 盘读写。 进入已配置状态后主循环为空,读写请求全部由 MSC 回调处理。

src/main.csrc/main.c · main
    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 中断。

src/main.csrc/main.c · main
    MAL_Config();
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }
    }

3. 空循环等待数据转发。 进入已配置状态后主循环为空,U 盘读写与串口转发分别由 MSC 与 CDC 回调处理。

src/main.csrc/main.c · main
    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 中断。

src/main.csrc/main.c · main
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }
    }

3. 主循环转发收到的数据。 检测到接收标志后清零,并调用发送流程把最近一次收到的数据送出。

src/main.csrc/main.c · main
    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 中断。

src/main.csrc/main.c · main
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备并等待主机完成枚举。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

        while (bDeviceState != CONFIGURED)
        {
        }
    }

3. 空循环等待串口转发。 进入已配置状态后主循环为空,转发全部由收发的端点回调处理。

src/main.csrc/main.c · main
    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 中断。

src/main.csrc/main.c · main
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

3. 主循环读取并原样回发。 已配置状态下读取虚拟串口数据,收到非零长度数据且上一次发送完成后原样发回。

src/main.csrc/main.c · main
        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 中断。

src/main.csrc/main.c · main
    USBFS_IO_Configure();
    USB_Interrupts_Config();

2. 配置并启动 USB 设备。 用 240MHz 系统时钟配置 USB,成功后初始化设备。

src/main.csrc/main.c · main
    if(USB_Config(system_clock) == SUCCESS)
    {
        USB_Init();

3. 主循环逐路读取并回发。 已配置状态下读取各路虚拟串口数据,随后逐路把收到的数据原样发回。

src/main.csrc/main.c · main
        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 是非法的。
用户手册
国民技术开发套件文档中心

按芯片系列在线查阅国民技术 MCU 开发套件的芯片资料、SDK、驱动 API 与 Demo 示例说明。

© 2026 国民技术股份有限公司 版权所有粤ICP备11069485号本站使用不含 Cookie 的匿名访问统计