TinyUSB 基本使用

由于早期时候我们产品基于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的工作流,这样才能很好的移植.由于这个不具备通用性,我就不再展开讨论了.(或者后续会写)

《TinyUSB 基本使用》有4个想法

  1. 你好,我用你的方法尝试了一下stm32f070f6p6的移植,发现一个优化的问题,打开“one ELF section per function”选项时,系统识别不出usb设备,去掉可以,好像是被优化掉了;但是,由于芯片的存储很小,去掉这个选择之后空间不够了,我看你的项目中的这个选项也是打开的,百度了一下问题,这类资料很少,望不吝赐教,万分感激!

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注