本人最近做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);
};
观望,做了很久都没有做出来的说,只实现了device,另请问:为啥不用SCSI而用UFI?
SCSI和UFI好像是一回事吧,这个概念我没有太去研究。
刚刚查了一下, Interface Descriptor中 Byte6指定了 device sub class code. 的确如2楼所说, 绝大部分U盘用的是scsi命令接口. 我的程序用的是scsi,而不是UFI,之前是我表述错了.
有没有人来谈谈STM32F107的USB HOST寄存器阿?
为什么OTG_FS_HCINTx寄存器中的XFRC位在实际IN transaction成功完成后没有置一?