极海APM32F427移植CherryUSB实现自定义USB HID设备
《极海芯得》系列的内容是用户使用集海系列产品的体验总结。均转载自21ic论坛集海半导体专区。全文未经过任何形式的修改,未经原作者授权禁止转载。
最近需要使用APM32F427枚举成Custom HID设备进行用户自定义通信,但是我不想使用官方的USB中间件来制作USB Custom HID设备。我了解了Cherry USB,一种开源的USB代码,它的最强点是不需要使用芯片上的任何USB代码就可以使用。因此,我打算使用CherryUSB来实现Custom HID设备。
1.Cherry USB简介
CherryUSB是一个小巧、美观、高度便携、高性能的用于嵌入式系统的USB主从协议栈(带有USB IP)。
关于CherryUSB的介绍,可以去其开源仓库和官方介绍文档进行学习。官方提供了非常详细的介绍和使用说明。
官方使用教程:https://cherryusb.readthedocs.io/zh-cn/latest/
CherryUSB代码存储库:https://github.com/cherry-embedded/CherryUSB
CherryUSB的伟大之处在于它不需要在芯片SDK中使用任何USB相关的代码,并且它完全独立于芯片。 CherryUSB是基于USB IP底层编写的,与芯片无关,所以移植和使用CherryUSB比较简单。支持常见的USB IP。如下:
APM32F427使用的USB IP是DWC2 USB IP。
2. APM32F427移植CherryUSB实现Custom HID设备
2.1 准备工作
1.从官网下载APM32F427 SDK。
下载路径:
https://www.geehy.com/product/fifth/APM32F427_425_423#design
2.下载CherryUSB源代码。
CherryUSB代码存储库:
https://github.com/cherry-embedded/CherryUSB
下载的源码暂时放在SDK的middleware目录下,以供后续使用。
3、复制SDK的一个可以正常使用的例程,然后基于这个例程移植CherryUSB。
2.2 提供CherryUSB
usb_dc_low_level_init/usb_dc_low_level_deinit函数的实现
为了移植和实现CherryUSB,我们只需要提供usb_dc_low_level_init/usb_dc_low_level_deinit函数的实现即可。这两个函数仅初始化最底层的GPIO引脚,并启用芯片的USB时钟和中断等芯片相关代码。
1、复制usb_glue_st.c文件,修改为usb_glue_apm32f27.c文件。
2、在原有usb_dc_low_level_init函数的基础上,修改为适配APM32F427芯片的函数。
无效usb_dc_low_level_init(uint8_t总线ID)
{
if (g_usbdev_bus[busid].reg_base==0x40040000UL) { //USB_OTG_HS_PERIPH_BASE
g_usb_dwc2_busid[1]=总线ID;
g_usb_dwc2_irq[1]=USBD_IRQHandler;
} 否则{
g_usb_dwc2_busid[0]=总线ID;
g_usb_dwc2_irq[0]=USBD_IRQHandler;
}
//g_dwc2_instance.Instance=(USB_OTG_GlobalTypeDef *)g_usbdev_bus[busid].reg_base;
//HAL_PCD_MspInit((PCD_HandleTypeDef *)g_dwc2_instance);
GPIO_InitTypeDef GPIO_InitStruct={0};
/* 配置USB OTG GPIO */
__DAL_RCM_GPIOA_CLK_ENABLE();
/* USB DM、DP引脚配置*/
GPIO_InitStruct.Pin=GPIO_PIN_11 | GPIO_PIN_12;
GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull=GPIO_NOPULL;
GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate=GPIO_AF10_OTG_FS;
DAL_GPIO_Init(GPIOA, GPIO_InitStruct);
/* 配置USB OTG */
__DAL_RCM_USB_OTG_FS_CLK_ENABLE();
/* 配置中断*/
DAL_NVIC_SetPriority(OTG_FS_IRQn, 1U, 0U);
DAL_NVIC_EnableIRQ(OTG_FS_IRQn);
}
该函数主要实现所使用的USB GPIO的初始化,以及打开USB外设时钟、使能USB中断等硬件的初始化。
3.提供usb_dc_low_level_deinit函数实现
无效usb_dc_low_level_deinit(uint8_t总线ID)
{
if (g_usbdev_bus[busid].reg_base==0x40040000UL) { //USB_OTG_HS_PERIPH_BASE
g_usb_dwc2_busid[1]=0;
g_usb_dwc2_irq[1]=NULL;
} 否则{
g_usb_dwc2_busid[0]=0;
g_usb_dwc2_irq[0]=NULL;
}
//g_dwc2_instance.Instance=(USB_OTG_GlobalTypeDef *)g_usbdev_bus[busid].reg_base;
//HAL_PCD_MspDeInit((PCD_HandleTypeDef *)g_dwc2_instance);
/* 禁用外设时钟*/
__DAL_RCM_USB_OTG_FS_CLK_DISABLE();
/* USB DM、DP引脚配置*/
DAL_GPIO_DeInit(GPIOA, GPIO_PIN_11 | GPIO_PIN_12);
/* 禁止外设中断*/
DAL_NVIC_DisableIRQ(OTG_FS_IRQn);
}
该函数是usb_dc_low_level_init函数的逆操作,取消GPIO初始化、禁用时钟等。
2.3 提供CherryUSB中断函数的实现
调用USB中断函数时,不能再调用SDK提供的中断处理函数。需要调用Cherry提供的中断处理函数。如下:
无效OTG_FS_IRQHandler(无效)
{
g_usb_dwc2_irq[0](g_usb_dwc2_busid[0]);
}
//无效OTG_HS_IRQHandler(无效)
无效OTG_FS2_IRQHandler(无效)
{
g_usb_dwc2_irq[1](g_usb_dwc2_busid[1]);
}
至此修改已经完成,需要将CHerryUSB的底层实现移植到APM32F427上。修改实现代码,保存到文件usb_glue_apm32f427.c中。
2.4 修改Keil工程配置
需要准备的代码之前已经实现了。现在我们将从SDK 中复制一个例程并对其进行修改以实现CherryUSB。
1.在Keil工程中添加CherryUSB源码
2.添加CherryUSB的编译路径
3、CherryUSB仓库代码,将cherryusb_config_template.h文件复制到我们的项目目录下,并改名为usb_config.h
2.5 实现CherryUSB Custom HID收发器测试功能
前面的步骤相当于完全移植CherryUSB。现在实现CherryUSB Custom HID应用层的发送和接收测试功能。
无效custom_hid_test(uint8_t总线ID)
{
uint8_t 报告[64]={0};
if(usb_device_is_configured(busid)==false) {
返回;
}
自定义状态=HID_STATE_BUSY;
usbd_ep_start_write(busid, HIDRAW_IN_EP, (uint8_t *)report, sizeof(report));
while (custom_state==HID_STATE_BUSY) {
}
}
该函数是将接收到的数据返回给PC端上位机。
2.6 实现main函数的调用
在主函数中,我们首先需要调用hid_custom_init函数来初始化CherryUSB,然后当主循环检测到接收USB数据时,我们调用2.5节中实现的CherryUSB收发器测试函数。如下:
int 主函数(无效)
{
//uint8_t mouse_cfg[4]={};
/* 设备配置*/
DAL_DeviceConfig();
///* 使用printf 函数在超级终端上输出一条消息*/
//LOG_Print(' UART Printf Example: 将C 库printf 函数重定向到UART ');
//LOG_Print(' ** 测试成功完成。** ');
hid_custom_init(0, USB_OTG_FS_PERIPH_BASE);
/* 无限循环*/
而(1)
{
如果(usb_receive_flag==1)
{
自定义_hid_测试(0);
}
}
}
3. USB Custom HID设备通信的测试验证
关于测试验证,和我之前写的一篇文章很相似,因为代码实现是与上位机进行收发测试。
3.1 在电脑的设备管理器中查看
修改第2节中的代码后,编译并下载到APM32F427芯片中。运行后我们可以在Windows系统的设备管理器的人体输入设备中查看到我们自己实现的USB Custom HID。如下:
或者可以通过控制面板的设备和打印机选项查看我们实现的USB HID设备,如下:
可以看到我们实现的Cherry HID DEMO设备,说明修改后的代码运行正常。
3.2 通过PC端上位机工具进行数据收发测试
我们需要使用USB HID调试工具来进行数据发送和接收测试。互联网上有很多类似的PC工具。我在这里使用PortHelper 工具。您可以在网上搜索并下载该工具。
1、打开PortHelper上位机,然后选择USB调试,然后找到
APM32自定义HID设备,然后打开USB
2、PortHelper用APM32F427测试USB数据发送和接收
打开USB后,我们检查十六进制发送并显示十六进制。然后点击发送,如下图:
然后PC端上位机发送的数据就可以发送到APM32F427,芯片将数据原样返回给上位机。
至此,我们已经实现了定制的USB Custom HID 设备。该装置主要接收PC端上位机发来的数据,然后由APM32F427接收并处理。在实际项目中,我需要基于这种沟通来开发更复杂的项目。
注:文章作者在原帖中提供了代码文件,有需要请至原文21ic论坛原文地址:https://bbs.21ic.com/icview-3501154-1-1.html?_dsign=67f2f385
或点击下方阅读原文跳转