可以使用标准库进行移植,但使用cubemx移植更加方便,我这里就使用stm32cubemx进行移植了,首先新建工程,配置RCC,


配置定时器产生1ms中断个tinyusb使用,

开启更新中断

配置USB为设备模式,但是不要选择类,后续由tinyusb接管

开启中断

修改USB中断优先级

配置系统时钟



点击右上角生成代码

打开工程编译后0报错即可开始下一步

从官网下载tinyusb源码放入工程中,
打开魔法笔勾选GNU extensions

然后新建分组添加源码


然后配置文件路径,再次打开魔法棒选择tinyusb的src路径,根据自己路径来

然后需要移植config文件作为配置文件,我们从官方示例中移植修改,先导航到一个基础示例

我们把这个配置文件放到inc,

然后添加到工程中


打开文件,添加这两行代码,这里是配置哪个板子,配置为设备模式和全速模式

把这个配置从2改为1

修改这个配置

并在结尾之前添加

修改buff大小

删除这三行因为上面已经判断了

然后开始解决编译器问题,要排除armgcc选项,打开这个文件

找到#if defined(GNUC) || defined(ICCARM) || defined(TI_COMPILER_VERSION)改为
#if (defined(__GNUC__) && !defined(__CC_ARM)) || defined(__ICCARM__) || defined(__TI_COMPILER_VERSION__)
在#elif defined(CCRX)分支之后,#else之前新增分支,
#elif defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION < 6000000)
// Keil armcc (AC5): supports GNU-style attributes subset, no __has_attribute/__builtin_bswap*
#define TU_ATTR_ALIGNED(Bytes) __attribute__((aligned(Bytes)))
#define TU_ATTR_SECTION(sec_name) __attribute__((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__((packed))
#define TU_ATTR_WEAK __attribute__((weak))
#ifndef TU_ATTR_ALWAYS_INLINE
#define TU_ATTR_ALWAYS_INLINE
#endif
#define TU_ATTR_DEPRECATED(mess) __attribute__((deprecated))
#define TU_ATTR_UNUSED __attribute__((unused))
#define TU_ATTR_USED __attribute__((used))
#define TU_ATTR_FALLTHROUGH do {} while (0)
#define TU_ATTR_PACKED_BEGIN
#define TU_ATTR_PACKED_END
#define TU_ATTR_BIT_FIELD_ORDER_BEGIN
#define TU_ATTR_BIT_FIELD_ORDER_END
// ARM Cortex-M is little-endian
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
#define TU_BITFIELD_ORDER TU_BITFIELD_LE
// Portable C implementation (compiler optimizes to REV/REV16 instructions)
#define TU_BSWAP16(u16) (uint16_t)(((uint16_t)(u16) >> 8) | ((uint16_t)(u16) << 8))
#define TU_BSWAP32(u32) ((((uint32_t)(u32) & 0xFF000000u) >> 24) | \
(((uint32_t)(u32) & 0x00FF0000u) >> 8) | \
(((uint32_t)(u32) & 0x0000FF00u) << 8) | \
(((uint32_t)(u32) & 0x000000FFu) << 24))
然后需要新建一个usb_descriptors.c文件,位置可以放在之前config的位置,内容如下
#include "tusb.h"
#define USB_VID 0xCafe
#define USB_PID 0x4001
#define USB_BCD 0x0200
//--------------------------------------------------------------------+
// Device Descriptor
//--------------------------------------------------------------------+
static tusb_desc_device_t const desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
uint8_t const *tud_descriptor_device_cb(void) {
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum {
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_TOTAL
};
#define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
static uint8_t const desc_fs_configuration[] = {
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
};
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void) index;
return desc_fs_configuration;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
static char const *string_desc_arr[] = {
(const char[]) { 0x09, 0x04 }, // 0: English (0x0409)
"TinyUSB", // 1: Manufacturer
"STM32F407 CDC", // 2: Product
"1234567890ABCDEF", // 3: Serial
"TinyUSB CDC", // 4: CDC Interface
};
static uint16_t _desc_str[32 + 1];
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
size_t chr_count;
switch (index) {
case 0:
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
break;
default:
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) {
return NULL;
}
const char *str = string_desc_arr[index];
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1;
if (chr_count > max_count) chr_count = max_count;
for (size_t i = 0; i < chr_count; i++) {
_desc_str[1 + i] = str[i];
}
break;
}
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
然后开始修改main.c,首先添加头文件
#include "tusb.h"
#include <stdio.h>
#include <stdarg.h>
添加全局变量volatile uint32_t g_usb_millis = 0;
然后启动定时器并对tinyusb进行初始化
HAL_TIM_Base_Start_IT(&htim1); // start TIM1 1ms time base before tusb_init
tusb_rhport_init_t dev_init = { .role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_FULL };
tusb_init(BOARD_TUD_RHPORT, &dev_init);
然后在底部实现
uint32_t tusb_time_millis_api(void) {
return g_usb_millis;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM1) {
g_usb_millis++;
}
}
main的while调用
tud_task();
uint8_t b; while (tud_cdc_available()) { tud_cdc_read(&b, 1); tud_cdc_write_char(b); } tud_cdc_write_flush();
