1、新增一个class里面没有参考示例的设备
如果用户想增加一个device设备但是在TinyUSB class里面又没有参考示例,本次我们一起来移植一个CDC+printer复合设备。操作步骤还是和上篇一样,先将TinyUSB 从GitHub上克隆下来,将src 整个文件夹copy替换到例程components目录下的src。
图1 TinyUSB源码
将tinyusb 目录下example下的对应文件,将tinyusb\examples\device\cdc_dual_ports\src 三个文件copy到例程user文件夹里面,其他增加时钟配置函数和添加tud_dcd_port.c 接口函数文件和上一篇一致(tud_dcd_port.c 文件可以参考现有例程或者联系灵动技术支持)。
图2 工程的USER文件
在tinyusb\src\class里面新增一个printer文件夹,可以参考其他设备比如从hid里面copy两个hid_device.c和hid_device.h 文件做为模板,将文件名修改成printer_device.c和printer_device.h,在这个文件里面修改对应的函数接口。
图3 新增printer文件
工程文件树如下:
1. TinyUSB_CDC_Printer
2. │
3. ├─USER
4. │ main.c
5. │ usb_descriptors.c
6. │ usb_dcd_port.c
7. │
8. └─TinyUSB
9.
10. tusb.c
11. cdc_device.c
12. tud_fifo.c
13. usbd.c
14. usb_control.c
15. printer_device.c
2、修改printer接口函数
1、在printer接口文件里面需要修改实现以下几个函数:
printer_init, //接口变量初始化 printer_reset, //接口变量重置 printer_open, printer_control_xfer_cb, //控制接口回调 printer_xfer_cb //数据接口回调 tud_printer_task //while(1)循环打印机数据处理
图4 需要实现的接口函数
2、在tusb_config.h 文件里面增加宏定义#define CFG_TUD_PRINTER 1 ,同时将对应的设备define改成2 ( #define CFG_TUD_CDC 2 ) ,使能两个CDC设备。
//------------- CLASS -------------// #define CFG_TUD_CDC 2 #define CFG_TUD_MSC 0 #define CFG_TUD_PRINTER 1 #define CFG_TUD_HID 0 #define CFG_TUD_MIDI 0 #define CFG_TUD_VENDOR 0
3、在usbd.c 里面增加printer回调函数接口处理。
#if CFG_TUD_PRINTER { DRIVER_NAME("PRINTER") .init = printer_init, .reset = printer_reset, .open = printer_open, .control_xfer_cb = printer_control_xfer_cb, .xfer_cb = printer_xfer_cb, .sof = NULL }, #endif
4、在tusb.h增加printer对应的头文件。
#if CFG_TUD_PRINTER #include "class/printer/printer_device.h" #endif
5、在tusb.h增加printer描述符。
//--------------------------------------------------------------------+ // PRINTER Descriptor Templates //--------------------------------------------------------------------+ // Length of template descriptor: 23 bytes #define TUD_PRINTER_DESC_LEN (9 + 7 + 7) // Interface number, string index, EP Out & EP In address, EP size #define TUD_PRINTER_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \ /* Interface */\ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_PRINTER, 0x01, 0x02, 0,\ /* Endpoint Out */\ 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0x00,\ /* Endpoint In */\ 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0x00
6、修改usb_descriptors.c 的描述符,增加一个printer的描述符和对应的端点。
//--------------------------------------------------------------------+ // Configuration Descriptor //--------------------------------------------------------------------+ enum { ITF_NUM_PRINTER= 0, ITF_NUM_CDC_0, ITF_NUM_CDC_0_DATA, ITF_NUM_CDC_1, ITF_NUM_CDC_1_DATA, ITF_NUM_TOTAL }; #define EPNUM_CDC_0_NOTIF 0x81 #define EPNUM_CDC_0_OUT 0x02 #define EPNUM_CDC_0_IN 0x82 #define EPNUM_CDC_1_NOTIF 0x83 #define EPNUM_CDC_1_OUT 0x04 #define EPNUM_CDC_1_IN 0x84 #define EPNUM_PRINTER_OUT 0x05 #define EPNUM_PRINTER_IN 0x86 uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), TUD_PRINTER_DESCRIPTOR(ITF_NUM_PRINTER, 5, EPNUM_PRINTER_OUT, EPNUM_PRINTER_IN, 64), // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64), };
7、增加device id描述符和string字符串。
//--------------------------------------------------------------------+ // String Descriptors //--------------------------------------------------------------------+ // array of pointer to string descriptors char const* string_desc_arr [] = { (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) "TinyUSB", // 1: Manufacturer "TinyUSB Device", // 2: Product "123456", // 3: Serials, should use chip ID "TinyUSB CDC", // 4: CDC Interface "MM32 Printer", // 5: printer Interface }; uint8_t const desc_printer_device_id[] = { 0x00,0x08, 'p', 'r', 'i', 'n', 't', '0', '0', '0', }; uint8_t * tud_printer_device_id_cb(void) { //(void) itf; return desc_printer_device_id; }
8、对应的需要在printer_device.c的printer_control_xfer_cb实现 device id的数据回复。
bool printer_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* p_request) { uint8_t * devicedesc; // nothing to do with DATA & ACK stage if (stage != CONTROL_STAGE_SETUP) return true; // Handle class request only TU_VERIFY(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); switch ( p_request->bRequest ) { case 0x00: devicedesc = tud_printer_device_id_cb(); tud_control_xfer(rhport, p_request, (void*) devicedesc, 10); break; case 0x01: devicedesc = tud_printer_device_id_cb(); tud_control_xfer(rhport, p_request, (void*) devicedesc, 10); break; default: return false; // stall unsupported request } return true; }
9、在tusb_config.h文件里面添加#define CFG_TUSB_MCU OPT_MCU_MM32F016X
Tusb_option.h 文件里面增加:
#define OPT_MCU_MM32F016X 1501 ///< MindMotion MM32F0160
否则TUP_DCD_ENDPOINT_MAX 没有定义。
图5 增加MM32F0160 宏定义
10、在main.c 里面主循环增加三个处理函数:
tud_task(); cdc_task(); tud_printer_task();
main函数:
/*------------- MAIN -------------*/ int main(void) { USB_DeviceClockInit(); // board_init(); CONSOLE_Init(460800); //Config uart2 // init device stack on configured roothub port tud_init(BOARD_TUD_RHPORT); TU_LOG1("TinyUSB Printer & CDC\r\n"); while (1) { tud_task(); // tinyusb device task cdc_task(); tud_printer_task(); //user printer task } }
3、功能验证测试
完成上述移植修改解决基本的编译问题后烧录测试能枚举打印机和CDC两个设备。
图6 枚举过程
图7 枚举成功
选择打印机设备,直接打印word的内容,能抓到通过枚举的打印机28号设备端点4下发的数据。
图8 枚举成功
图9 printer EP4 OUT包数据
相关链接:基于MM32F0163D7P的USB接口TinyUSB应用:移植和新增设备(一)
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。