请问CH552如果不使用DMA方式的话,如何读取FIFO数据

我在翻阅手册和学习Demo程序的时候,有以下几点问题。


  1. 当我设置UEP0_DMA=Ep0Buffer之后,是否就代表了当UIF_TRANSFER成功且进入UIS_TOKEN_SETUP,则其默认把FIFO中的8字节Setup包填入了Ep0Buffer中了?如果是的话,请问在不设置DMA的情况下,我是否可以通过什么方法自己读取FIFO中的数据?如果不是的话是哪里我理解错了。

  2. 当发送hid请求SetReport的时候,HID描述符我设置数据包大小是256,处理流程是否是这样,处理SETUP(识别指令)->循环处理OUT(在DMA地址或者FIFO中不断拿数据)->结束。

  3. 当发送hid请求GetReport的时候,HID描述符设置包大小256,则处理流程是否是,处理SETUP(识别指令)->循环处理IN(在DMA地址或者FIFO中把需要写的数据写入) ->结束。

  4. 我现在碰到的这个问题比较奇怪,我抄的官方HID的demo,但是始终无法走通第一条报文,系统总是下发Get_Descriptor,问我要设备描述符,可是我走串口调试,确实已经发过去了,可是系统依然不停向我发请求设备描述符,不知道问题在哪里。

另外,本例只使用低速模式和端点0,其他端点一律禁用。


start

host: 80 6 0 1 0 0 40 0 

is dev scr,18,64

12 1 10 1 0 0 0 8 

send..

11 11 22 22 3 1 0 0 

send..

0 1 

send..


host: 0 5 22 0 0 0 0 0 

host: 80 6 0 1 0 0 40 0 

is dev scr,18,64

12 1 10 1 0 0 0 8 

send..

11 11 22 22 3 1 0 0 

send..

0 1 

send..


host: 0 5 23 0 0 0 0 0 


根据log来看,第二次主机下发的数据怎么变成乱码了,不知道哪里出问题了


#include "CH552.H"

#include 

#include 

#include "usb_func.h"

#include "Debug.H"


UINT8X Ep0Buffer[THIS_ENDP0_SIZE + 2] _at_ 0x0000; //端点0 OUT&IN缓冲区,必须是偶地址

//UINT8X g_transbuf[256];

UINT8X SetupReq; //setup指令

UINT8X Ready, UsbConfig;

PUINT8 data_ptr;   //要发送的数据指针

UINT16X data_len;  //要接收或者发送的数据长度

UINT16X setup_len; //主机下发指令需要的长度

//USB_SETUP_REQ SetupReqBuf; //暂存Setup包

#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)


/*设备描述符*/

UINT8C DevDesc[] = {0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, THIS_ENDP0_SIZE,

                    0x11, 0x11,

                    0x22, 0x22,

                    0x03, 0x01, //BCD 发行版本号

                    0x00,       //厂商信息索引

                    0x00,       //产品信息索引

                    0x00,       //序列号索引

                    0x01};      //配置文件数

UINT8C CfgDesc[] =

    {

        0x09, 0x02, 27, 0x00, 0x01, 0x01, 0x04, 0x80, 0x19,   //配置描述符

        0x09, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x05, //接口描述符

        0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, 60, 0x00,   //HID类描述符

};

/*字符串描述符 略*/

/*HID类报表描述符*/

UINT8C HIDRepDesc[] =

    {

        0x06, 0x00, 0xFF,

        0x09, 0x01,

        0xA1, 0x01,

        0x06, 0x00, 0xFF,

        0x09, 0x01,

        0xA1, 0x01,

        0x85, 0x01,

        0x06, 0x01, 0xFF,

        0x09, 0x02,

        0x15, 0x00,

        0x25, 0xFF,

        0x96, 0x00, 0x01, //256

        0x75, 0x08,

        0xB1, 0x02,

        0xC0,

        0x06, 0x00, 0xFF,

        0x09, 0x01,

        0xA1, 0x01,

        0x85, 0x02,

        0x06, 0x02, 0xFF,

        0x09, 0x02,

        0x15, 0x00,

        0x25, 0xFF,

        0x96, 0x00, 0x01, //256

        0x75, 0x08,

        0xB1, 0x02,

        0xC0,

        0xC0};


/*******************************************************************************

* Function Name  : usb_init()

* Description    : USB设备模式配置,设备模式启动,收发端点配置,中断开启

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void usb_init()

{

    IE_USB = 0;

    USB_CTRL = 0x00;            // 先设定USB设备模式

    UDEV_CTRL = bUD_PD_DIS;     // 禁止DP/DM下拉电阻

    UDEV_CTRL |= bUD_LOW_SPEED; //选择低速12M模式

    USB_CTRL |= bUC_LOW_SPEED;

    UEP0_DMA = Ep0Buffer; //端点0数据传输地址

    //UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN); //端点0单64字节收发缓冲区

    UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //OUT事务返回ACK,IN事务返回NAK


    USB_DEV_AD = 0x00;

    USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA,在中断期间中断标志未清除前自动返回NAK

    UDEV_CTRL |= bUD_PORT_EN;                              // 允许USB端口

    USB_INT_FG = 0xFF;                                     // 清中断标志

    USB_INT_EN = bUIE_TRANSFER | bUIE_BUS_RST;

    IE_USB = 1;

}


//处理usb standard setup请求

void usb_setup_standard_process()

{

    UINT8X process_len;

    process_len = 0;

    printf("host: ");

    outputdebug(Ep0Buffer , 8);

    switch (UsbSetupBuf->bRequest)

    {

    case USB_GET_DESCRIPTOR:

        switch (UsbSetupBuf->wValueH)

        {

        case USB_DESCR_TYP_DEVICE: //设备描述符

            data_ptr = DevDesc;

            data_len = sizeof(DevDesc);

            printf("is dev scr,%d,%d\n", data_len, setup_len);

            break;

        case USB_DESCR_TYP_CONFIG: //配置描述符

            printf("conf scr\n");

            data_ptr = CfgDesc;

            data_len = sizeof(CfgDesc);

            break;

        case USB_DESCR_TYP_REPORT: //报表描述符(HID)

            printf("hid scr\n");

            data_ptr = HIDRepDesc;

            data_len = sizeof(HIDRepDesc);

            break;

        default:

            printf("err scr\n");

            data_len = 0;

            data_ptr = DevDesc;

            break;

        }


        process_len = (data_len >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : data_len);

        if (process_len > 0)

        {

            memcpy(Ep0Buffer, data_ptr, process_len);

            outputdebug(Ep0Buffer, process_len);

            data_len -= process_len;

            data_ptr += process_len;

        }


        UEP0_T_LEN = process_len;

        UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; //返回应答ACK

        break;

    default:

        break;

    }

    return;

}


//处理usb setup请求

void usb_setup_process()

{

    if (8 != USB_RX_LEN) //接收到的setup长度不对,则返回STALL不支持

    {

        UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; //STALL

        return;

    }

    //开始处理setup请求

    setup_len = UsbSetupBuf->wLengthH << 8;

    setup_len += UsbSetupBuf->wLengthL;


    if ((UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK) == USB_REQ_TYP_STANDARD) //处理标准USB请求

    {

        usb_setup_standard_process();

    }


    return;

}

//主机要拿数据

void usb_inbuf_process()

{

    UINT8X process_len;


    process_len = (data_len >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : data_len);

    memcpy(Ep0Buffer, data_ptr, process_len);

    data_len -= process_len;

    data_ptr += process_len;

    UEP0_T_LEN = process_len;

    UEP0_CTRL ^= bUEP_T_TOG; //同步标记位翻转


    printf("send..\n");

    outputdebug(Ep0Buffer, process_len);

    return;

}

//主机发来数据

void usb_outbuf_process()

{

}


/*******************************************************************************

* Function Name  : usb_interrupt()

* Description    : CH559USB中断处理函数

*******************************************************************************/

void usb_interrupt(void) interrupt INT_NO_USB //USB中断服务程序,使用寄存器组1

{

    if (UIF_TRANSFER) //USB传输完成标记

    {

        switch (USB_INT_ST & MASK_UIS_TOKEN)

        {

        case UIS_TOKEN_SETUP:

            usb_setup_process();

            break;

        case UIS_TOKEN_IN:

            usb_inbuf_process();

            break;

        case UIS_TOKEN_OUT:

            usb_outbuf_process();

            break;

        default:

            break;

        }

        UIF_TRANSFER = 0; //写0清空中断

    }

    else if (UIF_BUS_RST)

    {

        UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;

        USB_DEV_AD = 0x00;

        UIF_SUSPEND = 0;

        UIF_TRANSFER = 0;

        UIF_BUS_RST = 0; //清中断标志

    }


    return;

}


1、当我设置UEP0_DMA=Ep0Buffer之后,是否就代表了当UIF_TRANSFER成功且进入UIS_TOKEN_SETUP,则其默认把FIFO中的8字节Setup包填入了Ep0Buffer中了?A:是

1、如果是的话,请问在不设置DMA的情况下,我是否可以通过什么方法自己读取FIFO中的数据?如果不是的话是哪里我理解错了。A:必须使用DMA

2&3、SET REPORT 和 GET REPORT都是USB的”批量事务“,包括令牌包阶段、数据包阶段、握手包阶段,你描述的两个都缺少了握手包阶段

4、学习研究阶段建议备上硬件层面的抓包分析仪,观察总线上双方行为,对应代码运行状况。


谢谢,问题已经解决,是我没有设置主机下发的地址导致的。


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