由于早期时候我们产品基于STM32开发,自然而然的用了STM32的USB库,这个本身没什么问题,库也很完善,而且有官方在完善,这本来是个不错的东西,但是随着ST的缺货,问题就越来越多,比如别人的芯片可不会兼容ST的库,如果是标准设备那还好,如果像我们还做HOTP Key这样的,移植起来就相当的麻烦.一开始他们推荐我使用RL-USB,但是RL-USB始终是挂载RTX上的,至于哪一天RTX也出毛病,这就太惨了,为了避免被各种平台捆绑,我选择了TinyUSB,这个库目前对Host模式支持还不是很好,但是Deivce模式基本上没毛病,如果要兼容适配其他平台,只需要适配一些函数即可,当然Host模式暂时还不完善,先用STM32来测试.
移植好的工程从这里下载:https://github.com/nickfox-taterli/tinyusb_stm32f769disco (请不要在线下载ZIP,因为这样并不完整.)
移植只需要几步,第一步添加用到的文件,如下:
- 属于工程专用文件:usb_descriptors.c tusb_config.h usb_descriptors.h
- 属于库内文件:tusb.c *_device.c tusb_fifo.c dcd_*.c usbd.c usbd_control.c
只有属于工程专属文件,才是我们需要开发的,我这里是从hid_composite例子中挪过来的,然后修改tusb_config.h文件来指定设备属性.查看完整文件:https://github.com/nickfox-taterli/tinyusb_stm32f769disco/blob/main/Core/Inc/tusb_config.h#L37
#define CFG_TUSB_MCU OPT_MCU_STM32F7
#define BOARD_DEVICE_RHPORT_NUM 1
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
之后还要给出端口的配置,这个根据实际PCB来修改,这里修改的是main.c,具体文件:https://github.com/nickfox-taterli/tinyusb_stm32f769disco/blob/main/Core/Src/main.c#L105
void board_init(void)
{
LL_GPIO_InitTypeDef GPIO_InitStruct;
// Enable All GPIOs clocks
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOD);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOG);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOH);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOI);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOJ);
/* ULPI CLK */
GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_10;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ULPI D0 */
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_10;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ULPI D1 D2 D3 D4 D5 D6 D7 */
GPIO_InitStruct.Pin = LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_10 | LL_GPIO_PIN_11 | LL_GPIO_PIN_12 | LL_GPIO_PIN_13 | LL_GPIO_PIN_5;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* ULPI STP */
GPIO_InitStruct.Pin = LL_GPIO_PIN_0 | LL_GPIO_PIN_2;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* NXT */
GPIO_InitStruct.Pin = LL_GPIO_PIN_4;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOH, &GPIO_InitStruct);
/* ULPI DIR */
GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOI, &GPIO_InitStruct);
// Enable USB HS & ULPI Clocks
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_OTGHSULPI);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_OTGHS);
// No VBUS sense
USB_OTG_HS->GCCFG &= ~USB_OTG_GCCFG_VBDEN;
// B-peripheral session valid override enable
USB_OTG_HS->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
USB_OTG_HS->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
// Force device mode
USB_OTG_HS->GUSBCFG &= ~USB_OTG_GUSBCFG_FHMOD;
USB_OTG_HS->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;
}
现在USB就正常工作了~
如何移植,这个问题就相当的复杂了,我们需要分离仓库,针对每个平台分离单独的仓库,然后对齐进行推送,具体移植内容在这里 => https://github.com/hathach/tinyusb/tree/master/src/portable,如果你的芯片不是大家所熟知的,那么大概率过不了PR,你需要非常熟悉USB的工作流,这样才能很好的移植.由于这个不具备通用性,我就不再展开讨论了.(或者后续会写)
你好,我用你的方法尝试了一下stm32f070f6p6的移植,发现一个优化的问题,打开“one ELF section per function”选项时,系统识别不出usb设备,去掉可以,好像是被优化掉了;但是,由于芯片的存储很小,去掉这个选择之后空间不够了,我看你的项目中的这个选项也是打开的,百度了一下问题,这类资料很少,望不吝赐教,万分感激!
@青衣楼主 你先用大size的先调功能,优化掉概率不大,编译器可以试试V6的.
对了,我移植的是web-serial这个sample,keil5环境。QQ:51245426
请问文章可以转载吗?