TinyUSB 是一个用于嵌入式系统的开源跨平台 USB 主机/设备堆栈, 设计为内存安全,没有动态分配,线程安全,所有中断事件都被延迟,然后在非 ISR 任务函数中处理。但是看tinyUSB的官方介绍里不能使用DMA进行数据传输,这也是个遗憾的地方。
在AG32官方提供的SDK中,已经集成了tinyUSB,可自行关联使用。值得注意的是AG32中usb 使用到的PIN 脚是固定的管脚,不能在ve 中进行改变。目前AG32支持:单纯device 端、单纯host 端、OTG 自动切换主从端。三种情况要支持的枚举类型,可以在配置头文件中自行配置。目前针对三种情况,在platforms\AgRV\examples\usb
文件夹中也有官方提供的示例工程。
这里我们仅需要将AG32做为设备端,将采集到的数据发送给电脑上位机,因此这里我们以示例工程中的cdc_msc
工程为例进行介绍。
首先使用VS code打开cdc_msc
文件夹,并对其中的platformio.ini
文件进行如下修改:
board = agrv2k_407
protocol = cmsis-dap-openocd
之后查看main.c
文件,首先是将头文件包含了进去
#include "tusb.h"
然后是main函数
int main(void)
{
board_init();
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
while (1)
{
tud_task(); // tinyusb device task
cdc_task();
}
return 0;
}
其中首先对板子进行了初始化,并且调用了tud_init
函数对tud进行了初始化。因为我们这里没有使用RTOS,所以则需要持续和/或定期调用tud_task()
函数(在 tinyUSB 库中,tud_task()
和 tuh_task()
分别是设备模式(Device Mode)和主机模式(Host Mode)的任务处理函数。)。所有回调和功能都在该任务运行程序的调用中处理和调用。
在cdc_task
函数中,我们定义了对于插入设备和接收到数据的操作,当检测到设备插入或接受到数据时,将会调用tud_cdc_read
函数读取数据并使用tud_cdc_write
函数发送”message received!“
,最后调用函数tud_cdc_write_flush
清空缓存区。
void cdc_task(void)
{
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_connected() )
{
// connected and there are data available
if ( tud_cdc_available() )
{
// read data
char buf[64];
uint32_t count = tud_cdc_read(buf, sizeof(buf));
(void) count;
// Echo back
// Note: Skip echo by commenting out write() and write_flush()
// for throughput test e.g
// $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
tud_cdc_write("message received!", 17);
tud_cdc_write_flush();
}
}
}
实验效果如下:
实测这里的波特率选择任意时,设备都是可以正常接收并发送数据的。