关于CH376作HOST的问题请教

最近几天正在学习CH376T模块,因任务需要,要实现作为HOST需要和CDC类设备进行通信;作为Device能和电脑进行数据往来。使用硬件SPI与CH376进行控制。首先,在进行验证CH376作为HOST时,设置的为主机模式6,已经能够正常通过EP0端点收到并成功分析和保存了各种描述符信息,也将CDC设备的数据收/发接口的端点进行保存。然后是尝试进行往CDC设备发送数据,发送函数摘自打印机例程,代码如下

void send_data( uint8_t len, uint8_t *buf )
{  
    uint8_t l, s;
    while( len )          /* 连续输出数据块给USB打印机 */

    {
        toggle_send( tog_send );            /* 数据同步 */
        l = len>endp_out_size?endp_out_size:len;      /* 单次发送不能超过端点尺寸 */
        WR_USB_DATA( l, buf );              /* 将数据先复制到CH375芯片中 */
        issue_token( 0X40, ( endp_out_addr << 4 ) | DEF_USB_PID_OUT );   //endp_out_addr = 0x03    
        s = wait_interrupt();                    /* 请求CH375输出数据 */
        if ( s == USB_INT_SUCCESS )      /* CH375成功发出数据 */
        {  
            tog_send = ~ tog_send;         /* 切换DATA0和DATA1进行数据同步 */
            len-=l;                                     /* 计数 */
            buf+=l;                                    /* 操作成功 */
        }
        else if ( s== 0x2A)
        {  /* USB打印机正忙,如果未执行SET_RETRY命令则CH375自动重试,所以不会返回USB_INT_RET_NAK状态 */
            /* USB打印机正忙,正常情况下应该稍后重试 */
            /* s=get_port_status( );  如果有必要,可以检查是什么原因导致打印机忙 */
            printf("USB is Busy\r\n");
        }
        else                 /* 操作失败,正常情况下不会失败 */
        { 
            clr_stall( endp_out_addr );          /* 清除打印机的数据接收端点,或者 soft_reset_print() */
/*            soft_reset_print();  打印机出现意外错误,软复位 */

            tog_send = 0;                              /* 操作失败 */


            CH376_WriteCmd(CMD_UNLOCK_USB);        //此行为我自行添加,猜测当前端点的缓存区未被释放?

           
        //    printf("USB never Back data, and over time\r\n");
        }
/* 如果数据量较大,可以定期调用get_port_status()检查打印机状态 */
    }
}

遇到的问题:

1、往发送端点发送数据,中断查询返回一直为0x28的数据,请问通常遇到此类通信错误的问题,解决的点在哪?

2、另外的疑惑,在命令列表中,有看到端点0、端点1和端点2的相关设置命令,对于其他端点的操作该如何进行?

3、对于端点的发送数据,都提到了端点数据同步的命令操作,但对于命令,也仅设计涉及到端点0、端点1、端点2,对设备其他的端点,如端点3,该怎么进行数据同步?

发送的数据通过BUS HOUND抓取自CDC的设备,为上位机与设备的握手数据。



你好:

  1.  一般返回“0x28”,表示设备没有应答响应,那么有以下几种原因:

    -> 你发的命令有问题,不在可接受范围(一般应该返回 0x2e STALL)

    -> 发送数据的端点号写错了,不是设备的端点

    -> 你 发送的端点已关闭或异常,需要恢复,要发响应命令。

    自己先找下原因,分清处于什么情况。

  2. 你看到的命令列表如果有写端点0/1/2,那么肯定是USB设备模式的命令,主机模式下只有一组端点(上传和下传),发送数据要填写发送给设备的端点号,自己填入的。你描述中的"endp_out_addr"

  3. 不知道你说是数据同步指的什么?如果是DATA0和DATA1这种的话,和端点号是没有关系的。


你好:


另外“CH376_WriteCmd(CMD_UNLOCK_USB);  ”这是设备模式的命令,不要和主机命令混用。

命令参考CH376DS1、CH376DS2 数据手册,没有的命令不要用。



逻辑分析仪抓的发送数据如下图

图片.png

图片.png

图一发送的数据能对应上,发送端点能对应上 0x03  OUT。图二bmRequestType = 0x02,到端点;Data direction = NO data; Type = Standard, Recipient = Endpoint。


非常谢谢您的解答。



解决了查询中断回复0x28的问题,原因是在分析各描述符过程中给CH376配置了一个错误的地址,重新设置地址为0后,主机查询中断返回0x14,应该能够正常发送。

感谢技术大佬的解疑。

此外,我使用的是硬件SPI作主机控制CH376,CDC设备使用的是串口转USB的控制方式,请问是否也需要将CH376设置波特率?


 你好:


你这操作不对吧,一把上电后,

  1. 总线复位;

  2. 主机以地址0,端点0,要设备描述符,得到端点0的最大包大小;

  3. 分配设备地址X;

  4. 之后主机都以地址X和设备通讯

所以,你到现在还再以地址0通讯,那么前面肯定步骤有问题。

建议参考例程 http://wch.cn/public/uploads/file/20170407/1491551116488367.rar CH376操作CH341设备看看流程是怎么做的。



此外,我使用的是硬件SPI作主机控制CH376,CDC设备使用的是串口转USB的控制方式,请问是否也需要将CH376设置波特率?” 

这个问题,CH376和你的CDC不是USB通讯吗?哪里涉及到波特率了(串口)?如果你要控制CDC设备的另外一端串口收发波特率改变,肯定是需要CH376通过USB口配置CDC的。



是的,之前的步骤确实有误,在设置USB地址时只进行了主机地址的设置,从机地址并未设置,导致后面出现0x28。现在将主机和从机的地址都设置后,再进行发送,并未出现中断异常的状况,但设备仍未进行响应。已经在串口调试助手验证过发送的命令能够得到设备响应。逻辑分析仪抓包有OUT事务,但从抓的包上看,发送的端点和数据都能匹配上,但地址仍是0x00。

我的程序步骤:

    ->连接设备,获得设备描述符

    ->设置地址 0x05,复位

    ->获取配置描述符,取得配置描述符的长度,再次获取设备描述符,分析保存 端点号

    ->开始发送数据


图片.png

上图逻辑分析仪抓的发送包,发现Address仍是0x00,这是地址没被修改成功吗?

程序的步骤中有将得到的配置描述符中的bConfigurationValue值进行配置。


图片.png

上图是设置地址抓取的数据,设置地址0x05


另外,写了一个接收函数,在CDC设备设置重复发送数据。遇到的现象是写入接收同步控制能够返回0x00,ACK就绪,但再往下发出同步令牌的OUT事务后,得不到CH376的INT中断的响应,引脚一直是高电平状态。

uint8_t receive_data(uint8_t *buf)
{
    uint8_t s, len;
    uint8_t tog = 0;
    uint8_t recv_flag = 1;
    
    while(recv_flag)
    {
        toggle_recev(tog);
        issue_token(0x80, (endp_in_addr << 4)| DEF_USB_PID_IN);    //endp_in_addr 0x81
        s = wait_interrupt();
        printf("status is 0x%02x\r\n",s);
        if(s == USB_INT_SUCCESS)
        {
            len = RD_USB_DATA(buf);
            clr_stall( endp_in_addr );
            recv_flag = 0;
        }
        else
        {
            tog = ~tog;
        //    soft_reset_cdc( );
            clr_stall( endp_in_addr );
            recv_flag = 0;
        }
    }
    return len;
}
CDC设备中的中断端点为0x82,这会对接收产生冲突?下面是CDC设备的部分描述符

    /*Union Functional Descriptor*/
    0x05,   /* bFunctionLength */
    0x24,   /* bDescriptorType: CS_INTERFACE */
    0x06,   /* bDescriptorSubtype: Union func desc */
    0x00,   /* bMasterInterface: Communication class interface */
    0x01,   /* bSlaveInterface0: Data Class Interface */

    /*Endpoint 2 Descriptor*/
    0x07,   /* bLength: Endpoint Descriptor size */
    USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    0x82,   /* bEndpointAddress: (IN2) */
    0x03,   /* bmAttributes: Interrupt */
    VIRTUAL_COM_PORT_INT_SIZE,      /* wMaxPacketSize: */
    0x00,
    0xFF,   /* bInterval: */

/*Data class interface descriptor*/
    0x09,   /* bLength: Endpoint Descriptor size */
    USB_INTERFACE_DESCRIPTOR_TYPE,  /* bDescriptorType: */
    0x01,   /* bInterfaceNumber: Number of Interface */
    0x00,   /* bAlternateSetting: Alternate setting */
    0x02,   /* bNumEndpoints: Two endpoints used */
    0x0A,   /* bInterfaceClass: CDC */
    0x00,   /* bInterfaceSubClass: */
    0x00,   /* bInterfaceProtocol: */
    0x00,   /* iInterface: */
    /*Endpoint 3 Descriptor*/
    0x07,   /* bLength: Endpoint Descriptor size */
    USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    0x03,   /* bEndpointAddress: (OUT3) */
    0x02,   /* bmAttributes: Bulk */
    VIRTUAL_COM_PORT_DATA_SIZE,             /* wMaxPacketSize: */
    0x00,
    0x00,   /* bInterval: ignore for Bulk transfer */
    /*Endpoint 1 Descriptor*/
    0x07,   /* bLength: Endpoint Descriptor size */
    USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
    0x81,   /* bEndpointAddress: (IN1) */
    0x02,   /* bmAttributes: Bulk */
    VIRTUAL_COM_PORT_DATA_SIZE,             /* wMaxPacketSize: */
    0x00,
    0x00    /* bInterval */


真的很奇怪,早上过来刚打开电脑进行调试,串口突然能打印收到的一些数据,程序复位之后又收不到了。能够接收前的中断标志是0x23,在清除掉端点缓存后中断标志0x14能接收到一些USB线上的某些数据。程序复位后INT中断引脚又是持续的高电平,并不被拉低返回中断标志。【白开心了】

附上一张串口打印出来的图,因草率的将程序复位了,并未能使用逻辑分析仪抓数据分析,错过了

图片.png

端点0x82设备的中断端点


在设置地址后,将复位总线命令去除后,这次地址应该设置成功了,在逻辑分析仪抓取的包中,地址不再是0x00,而是自行设置的地址。

图片.png


现在知道了为什么时而接收时而不能接收数据,因设置的CDC设备为一直发送,应该是造成了USB总线繁忙了,在将设备断电后重新开机初始化后,CH376主机能够接收到数据,能一直进行接收CDC设备发送的数据。数据无误,证明接收端点配置是正确的。


只有登录才能回复,可以选择微信账号登录