打印
[其他]

基于 MM32F0163D7P 的 USB 接口 TinyUSB 应用:移植和新增设备(二)

[复制链接]
1028|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 MindMotion 于 2023-9-6 11:01 编辑

上文链接:基于MM32F0163D7P的USB接口TinyUSB应用:移植和新增设备(一)


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包数据

272864f6f964618b0.png (83.42 KB )

272864f6f964618b0.png

使用特权

评论回复
沙发
chenjun89| | 2023-9-6 21:35 | 只看该作者
这个屏幕底色看起来不刺眼嘛?

使用特权

评论回复
评论
forgot 2023-9-15 09:34 回复TA
这底色看5分钟眼药花 
板凳
chenqianqian| | 2023-9-7 08:24 | 只看该作者
灵动微这几年的新产品推出有点慢了啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司
简介:上海灵动微电子股份有限公司成立于 2011 年,是中国本土通用 32 位 MCU 产品及解决方案供应商。 灵动股份的 MCU 产品以 MM32 为标识,基于 Arm Cortex-M 系列内核,自主研发软硬件和生态系统。目前已量产近 300 多款型号,累计交付超 4 亿颗,在本土通用 32 位 MCU 公司中位居前列。

83

主题

101

帖子

5

粉丝