STM32F107的USBHOST问题

filmwind   2010-11-29 19:50 楼主
本人最近做stm32f107芯片读U盘的一个程序. 目前已经成功实现了: u盘插入检测, usb总线复位, 启动SOF, 枚举U盘, 和发送并执行若干条UFI命令.

现在的问题是在发送若干条UFI命令后, stm32f107的usb host就不再接受用户代码的任何usb transaction请求.

经过几天的排查,我最为怀疑的是以下这个问题:
当做完第一个IN transaction的时候, OTG_FS_HCINTx寄存器中的XFRC位没有置一. 而此时, OTG_FS_HCTSIZx中的PKTCNT已经从1变为0,表明期望收到的data packet已经收到. 实际用示波器观察,也的确正确完成了这次IN transaction.且读回来收到的数据(device descriptor)都是正确的.
为什么OTG_FS_HCINTx寄存器中的XFRC位在实际transaction成功完成后没有置一?

有没有哪位高手发扬一下风格,共享一个transaction级别的函数原代码?
先抛砖引玉,贴上我的transaction函数. (思路不一定是最好的,而且还是有故障的)

//return 0: success
//return 1: NAKed, need to retry this function again
//return 0xff: need to reset all --- fatal error
U8 UsbSetupPktTransfer(void)
{
    U32 i,d;
    VU32 *p;
    U8 TmpU8[8],r;
    //for hc_char register
    d=0;
    d|=((UsbXferInfo.bUsbDevAddr)<<22);                 //dev address
    d|=(UsbXferInfo.EPType<<18);                        //EP type, 0: control or 2: bulk, it has to be 2 (bulk) here
    d|=(0<<15);                                         //EP direction: 1 is in, 0 is out, NOTE, this is for one TRANSACTION
                                //for endpoint type control: EP direction in is IN packet
                                //for endpoint type control: EP direction out is SETUP packet
                                //for endpoint type bulk: EP direction in is IN packet
                                //for endpoint type bulk: EP direction out is OUT packet       ZZZZZZZZZZZZZZZZZZZZ??????????????????
    d|=(0<<11);                                         //EP address, for setup transfer, it has to be 0 here, only EP0 supports setup transfer
    d|=(8<<0);                                          //max packet size, fixed to 8 while doing SETUP packet and the following DATA0 packet
    UsbReg.HCReg[0]->hc_char=d;
   
    //for hc_txfer_siz register
    d=0;
    d=8;                                                //total transfer size
    d|=(1<<19);                                         //total packets
    d|=(UsbXferInfo.PIDType<<29);                       //PID type=3, which is Setup(when EP is control type), here it has to be 3 (setup)
    UsbReg.HCReg[0]->hc_txfer_siz=d;
   
    //prepare the 8 byte data to be transferred.
    TmpU8[0]=UsbXferInfo.SetupPackage.bmRequest;
    TmpU8[1]=UsbXferInfo.SetupPackage.bRequest;
    TmpU8[2]=(UsbXferInfo.SetupPackage.wValue)&0xff;
    TmpU8[3]=(UsbXferInfo.SetupPackage.wValue)>>8;
    TmpU8[4]=(UsbXferInfo.SetupPackage.wIndex)&0xff;
    TmpU8[5]=(UsbXferInfo.SetupPackage.wIndex)>>8;
    TmpU8[6]=(UsbXferInfo.SetupPackage.wLength)&0xff;
    TmpU8[7]=(UsbXferInfo.SetupPackage.wLength)>>8;
    p=(VU32 *)TmpU8;
    //enable the channel
    UsbReg.HCReg[0]->hc_char|=0x80000000;
    //write 8 bytes data of the setup transfer
    //usb transfer starts immediately after data is written into the data_fifo
    *(UsbReg.data_fifo[0])=  *p++;
    *(UsbReg.data_fifo[0])=  *p;
    //the following 2 lines test shows; hc_char bit 32 is 1 while USB sending is on going, it is back to 0 when sending is finished
    //i=0;
    //while((UsbReg.HCReg[0]->hc_char)&0x80000000) i++;

    //wait until there is a intr response from Host channel 0
    i=0;
    while(1)
    {
        d=UsbReg.HCReg[0]->hc_int;
        if(d&0x00000708)
            UsDelay(1);
        if((d==0x00000001)||(d==0x00000021))            //transfer completed, transfer success
                                                        //ack, transfer success bit, or transfer completed, transfer success
        {
            r=0;
            break;
        }else
        {
            i++;
            if(d&0x00000010) {r=1; break;};             //NAK --> retry
            if(i>50000)
            {
                //if(d&0x00000002) {r=1; break;};       //host chanel halted --> reset all
                //if(d&0x00000008) {r=2; break;};       //stall --> reset all
                //if(d) {r=3; break;};                  //other error --> reset all
                //r=4; break;                           //no response --> reset all
                r=0xff; break;                          //it seems directly return 0xff to reset all is OK here
            };
        };
    };
    UsbReg.HCReg[0]->hc_int|=0x000007ff;   //write 1 to clear all intr status

    //flush the fifo
    UsbReg.CommonReg->rst_ctl=0x00000020;               //bit 10:6: flush number --> 10000 menas flush all fifos, bit 5: do tx fifo flush,
    UsDelay(1);                                         //wait for flush tx data
    UsbReg.CommonReg->rst_ctl=0x00000010;               //bit 4: do rx fifo flush,
    UsDelay(1);                                         //wait for flush tx data
    UsbReg.CommonReg->int_sts|=0x00000010;
    return(r);

}


//return 0: success
//return 1: NAKed, need to retry this function again
//return 0xff: need to reset all --- fatal error
U8 UsbInPktTransfer(void)
{
    U32 i,d,num_packets,InByteCnt;
    VU32 *p;
    //U8 TmpU8[8];
    U8 r;
    if(!NakRetry)
{
    if (UsbXferInfo.wTotalXferDataLen>512) return(0xff);
    if(DataTgl[UsbXferInfo.EPAddrForXfer])
    {   //to be data1
        UsbXferInfo.PIDType=Stm32F107UsbHostPidTypeData1;
    }else
    {   //to be data0
        UsbXferInfo.PIDType=Stm32F107UsbHostPidTypeData0;
    };
    // Compute the expected number of packets associated to the transfer
    if (UsbXferInfo.wTotalXferDataLen==0)
    {
        num_packets = 1;        //even there is 0 data to transfer, the packet number needs to be 1, so that an transfer
                                //complete intr can be generated.
    }
    else
    {
        num_packets = (UsbXferInfo.wTotalXferDataLen + UsbXferInfo.wPktPayloadMax - 1) / UsbXferInfo.wPktPayloadMax;
    }
    //for hc_char register
    d=0;
    d|=((UsbXferInfo.bUsbDevAddr)<<22);                 //dev address
    d|=(UsbXferInfo.EPType<<18);                        //EP type, 0: control or 2: bulk, it could be control(setup) or bulk here
    d|=(1<<15);                                         //EP direction: 1 is in, 0 is out, NOTE, this is for one TRANSACTION
                                //for endpoint type control: EP direction in is IN packet
                                //for endpoint type control: EP direction out is SETUP packet   ???????????????
                                //for endpoint type bulk: EP direction in is IN packet
                                //for endpoint type bulk: EP direction out is OUT packet       ZZZZZZZZZZZZZZZZZZZZ??????????????????
    d|=((UsbXferInfo.EPAddrForXfer)<<11);               //EP address
    d|=((UsbXferInfo.wPktPayloadMax)<<0);               //max packet size
    UsbReg.HCReg[1]->hc_char=d;
    //for hc_txfer_siz register
    d=0;
    if(UsbXferInfo.wTotalXferDataLen)
    {
        d=num_packets*(UsbXferInfo.wPktPayloadMax);
                                                        //for IN transfer, the transfer size should be an integer multiple of the MAX packet size
    };
    d|=(num_packets<<19);                               //total packets
    d|=(UsbXferInfo.PIDType<<29);                       //PID type
    UsbReg.HCReg[1]->hc_txfer_siz=d;
};
    //enable the channel
    UsbReg.HCReg[1]->hc_char|=0x80000000;
    //wait for the transfer result
    i=0;
    while(1)
    {
        d=UsbReg.HCReg[1]->hc_int;
        if(d&0x00000708)
            UsDelay(1);
        if((d==0x00000001)||(d==0x00000021))
        {   //transaction completed successfully
            r=0;
            DataTgl[UsbXferInfo.EPAddrForXfer]=1-DataTgl[UsbXferInfo.EPAddrForXfer];
            break;
        }else
        {
            i++;
            if(d==0x00000020)
            {   //ACK received   
                if(!((UsbReg.HCReg[1]->hc_txfer_siz)&0x1ff80000))
                {   //packet count is 0 --> means transaction completed
                    DataTgl[UsbXferInfo.EPAddrForXfer]=1-DataTgl[UsbXferInfo.EPAddrForXfer];
                    r=0; break;
                }else
                {   //packet count is not 0 --> means transaction not completed
                    UsbReg.HCReg[1]->hc_int|=0x000007ff;                //write 1 to clear all intr status
                    i=0;
                };
            };
            if(d==0x00000010)
            {
                //disable the channel
                //UsbReg.HCReg[1]->hc_char=0xc0000000;
                //UsDelay(5);
                NakRetry=1;
                r=1; break;
            };             //NAK --> retry
            if(i>50000)
            {
                //if(d&0x00000002) {r=1; break;};       //host chanel halted --> reset all
                //if(d&0x00000008) {r=2; break;};       //stall --> reset all
                //if(d) {r=3; break;};                  //other error --> reset all
                //r=4; break;                           //no response --> reset all
                r=0xff; break;                          //it seems directly return 0xff to reset all is OK here
            };
        };
    };
    UsbReg.HCReg[1]->hc_int|=0x000007ff;                //write 1 to clear all intr status
    //read the data from fifo, only if the transaction is successful
    if(!r)
    {
        //InByteCnt=UsbReg.CommonReg->rx_stsr;
        InByteCnt=(UsbReg.CommonReg->rx_stsr&0x00007fff)>>4;
                                                        //read out the received IN data byte count
        p=(VU32 *)(UsbXferInfo.PktDataBufPtr);
        d=(InByteCnt+3)>>2;
        if(d) *p=*(UsbReg.data_fifo[1]);                //if it is not an empty IN packet, read out the first 32 bit word, which is the transfer complete status
                                                        //how to check this 32 bit? where is the definition for this 32 bit???????
                                                        //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZ??????????????????????????
        for (i = 0; i < d; i++)
        {
            *p++=*(UsbReg.data_fifo[1]);
        };
        NakRetry=0;
    };
    //flush the fifo
    UsbReg.CommonReg->rst_ctl=0x00000020;               //bit 10:6: flush number --> 10000 menas flush all fifos, bit 5: do tx fifo flush,
    UsDelay(1);                                         //wait for flush tx data
    UsbReg.CommonReg->rst_ctl=0x00000010;               //bit 4: do rx fifo flush,
    UsDelay(1);                                         //wait for flush tx data
    UsbReg.CommonReg->int_sts|=0x00000010;
    return(r);
};

//return 0: success
//return 1: NAKed, need to retry this function again
//return 0xff: need to reset all --- fatal error
U8 UsbOutPktTransfer(void)
{
    U32 i,d,num_packets;
    VU32 *p;
    //U8 TmpU8[8];
    U8 r;
    if (UsbXferInfo.wTotalXferDataLen>512) return(0xff);
    if(DataTgl[UsbXferInfo.EPAddrForXfer])
    {   //to be data1
        UsbXferInfo.PIDType=Stm32F107UsbHostPidTypeData1;
    }else
    {   //to be data0
        UsbXferInfo.PIDType=Stm32F107UsbHostPidTypeData0;
    };
    // Compute the expected number of packets associated to the transfer
    if (UsbXferInfo.wTotalXferDataLen==0)
    {
        num_packets = 1;        //even there is 0 data to transfer, the packet number needs to be 1, so that an transfer
                                //complete intr can be generated.
    }
    else
    {
        num_packets = (UsbXferInfo.wTotalXferDataLen + UsbXferInfo.wPktPayloadMax - 1) / UsbXferInfo.wPktPayloadMax;
    }
    //for hc_char register
    d=0;
    d|=((UsbXferInfo.bUsbDevAddr)<<22);                 //dev address
    d|=(UsbXferInfo.EPType<<18);                        //EP type, 0: control or 2: bulk, it could be control(setup) or bulk here
    d|=(0<<15);                                         //EP direction: 1 is in, 0 is out, NOTE, this is for one TRANSACTION
                                //for endpoint type control: EP direction in is IN packet
                                //for endpoint type control: EP direction out is SETUP packet
                                //for endpoint type bulk: EP direction in is IN packet
                                //for endpoint type bulk: EP direction out is OUT packet       ZZZZZZZZZZZZZZZZZZZZ??????????????????
    d|=((UsbXferInfo.EPAddrForXfer)<<11);               //EP address
    d|=((UsbXferInfo.wPktPayloadMax)<<0);               //max packet size
    UsbReg.HCReg[2]->hc_char=d;
    //for hc_txfer_siz register
    d=0;
    d=UsbXferInfo.wTotalXferDataLen;                    //tx size in bytes
    d|=(num_packets<<19);                               //total packets
    d|=(UsbXferInfo.PIDType<<29);                       //PID type=3, which is non data (IN or OUT)(when EP is bulk type), here it has to be 3 (IN)
    UsbReg.HCReg[2]->hc_txfer_siz=d;
    //enable the channel
    UsbReg.HCReg[2]->hc_char|=0x80000000;
    //write data to the tx buffer
    p=(VU32 *)(UsbXferInfo.PktDataBufPtr);
    d=(UsbXferInfo.wTotalXferDataLen+3)>>2;
    for (i = 0; i < d; i++)
    {
        *(UsbReg.data_fifo[2])=*p++;
    };
    //wait for the transfer result
    i=0;
    while(1)
    {
        d=UsbReg.HCReg[2]->hc_int;
        if(d&0x00000708)
            UsDelay(1);

        if((d==0x00000001)||(d==0x00000021))
        {   //transaction completed successfully
            r=0;
            DataTgl[UsbXferInfo.EPAddrForXfer]=1-DataTgl[UsbXferInfo.EPAddrForXfer];
            break;
        }else
        {
            i++;
            if(d==0x00000020)
            {   //ACK received   
                if(!((UsbReg.HCReg[2]->hc_txfer_siz)&0x1ff80000))
                {   //packet count is 0 --> means transaction completed
                    DataTgl[UsbXferInfo.EPAddrForXfer]=1-DataTgl[UsbXferInfo.EPAddrForXfer];
                    r=0; break;
                }else
                {   //packet count is not 0 --> means transaction not completed
                    UsbReg.HCReg[2]->hc_int|=0x000007ff;                //write 1 to clear all intr status
                    i=0;
                };
            };
            if(d==0x00000010) {r=1; break;};             //NAK --> retry
            if(i>50000)
            {
                //if(d&0x00000002) {r=1; break;};       //host chanel halted --> reset all
                //if(d&0x00000008) {r=2; break;};       //stall --> reset all
                //if(d) {r=3; break;};                  //other error --> reset all
                //r=4; break;                           //no response --> reset all
                r=0xff; break;                          //it seems directly return 0xff to reset all is OK here
            };
        };
    };
    UsbReg.HCReg[2]->hc_int|=0x000007ff;                //write 1 to clear all intr status
    //flush the fifo
    UsbReg.CommonReg->rst_ctl=0x00000020;               //bit 10:6: flush number --> 10000 menas flush all fifos, bit 5: do tx fifo flush,
    UsDelay(1);                                         //wait for flush tx data
    UsbReg.CommonReg->rst_ctl=0x00000010;               //bit 4: do rx fifo flush,
    UsDelay(1);                                         //wait for flush tx data
    UsbReg.CommonReg->int_sts|=0x00000010;
    return(r);
};

回复评论 (5)

                                 观望,做了很久都没有做出来的说,只实现了device,另请问:为啥不用SCSI而用UFI?
点赞  2010-11-29 21:06
                                 SCSI和UFI好像是一回事吧,这个概念我没有太去研究。
点赞  2010-11-29 21:27
                                 刚刚查了一下, Interface Descriptor中 Byte6指定了 device sub class code. 的确如2楼所说, 绝大部分U盘用的是scsi命令接口. 我的程序用的是scsi,而不是UFI,之前是我表述错了.
点赞  2010-11-30 09:05
有没有人来谈谈STM32F107的USB HOST寄存器阿?

为什么OTG_FS_HCINTx寄存器中的XFRC位在实际IN transaction成功完成后没有置一?
点赞  2010-11-30 09:07
                                 顶下,以后看。
点赞  2010-12-1 14:04
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复