<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
二、追踪USB大容量设备的实现流程
5、主机发命令READ FORMAT CATPACITIES
再次分析一次命令执行的流程
(1)首先在批量输出端点2产生RX中断
在中断中调用Mass_Storage_Out ()。
在处理过程中先将接收缓冲区的数据、长度保存。
由于此时,命令处理状态机处于BOT_IDLE状态,所以调用命令解码函数CBW_Decode()。
(2)解码函数所做的工作
把接收到的数据先赋值给命令封包结构CBW。同时开始准备填充命令状态封包结构CSW。
switch (CBW.CB[0]),根据命令操作码进行命令处理散转。
(3)操作码0x23,进入相应处理函数SCSI_ReadFormatCapacity_Cmd()
这个命令处理主要是填充用户返回的容量数据结构体,然后调用另外一个函数Transfer_Data_Request()来完成数据的传输。
这个函数接收发送数据缓冲区的起始地址、长度,首先把数据复制到数据输出批量端点1:
UserToPMABufferCopy(Data_Pointer, ENDP1_TXADDR, Data_Len);
SetEPTxCount(ENDP1, Data_Len);
SetEPTxStatus(ENDP1, EP_TX_VALID);
Bot_State = BOT_DATA_IN_LAST; //设置命令处理的新状态
CSW.dDataResidue -= Data_Len;
CSW.bStatus = CSW_CMD_PASSED; //填充命令状态封包。
接下来主机会连发两个“IN”,第一次将容量数据结构体返回。
然后在端点1输入中断中,又将命令状态封包结构复制到批量端点1输出缓冲区。主机的第二个“IN“将取走这个数据。
在第二次输入中断处理程序中,命令状态重新回到“BOT_IDLE”,于是又可以接收新的命令。
6、读容量命令
这个跟上个命令返回的数据差不多,具体什么区别,等到移植调试的时候再看。
7、READ(10)命令
这是一个非常重要的命令,我们获取U盘的文件主要就靠它了。
(1)前面的过程忽略,直接进入读命令解码SCSI_Read10_Cmd()
处理中,主要存在两种情况:
在BOT_IDLE时:
if ((CBW.bmFlags & 0x80) != 0)
{
Bot_State = BOT_DATA_IN;
Read_Memory();
}
在BOT_DATA_IN时:
直接 Read_Memory();
(2)进入Read_Memory()处理函数。
void Read_Memory(void)
{
if (!Block_Read_count)
{ //读入一个扇区512字节,但是一次只能发送64个字节。
MSD_ReadBlock(Data_Buffer, Memory_Offset, 512);
UserToPMABufferCopy(Data_Buffer, ENDP1_TXADDR, BULK_MAX_PACKET_SIZE);
Block_Read_count = 512 - BULK_MAX_PACKET_SIZE;
Block_offset = BULK_MAX_PACKET_SIZE;
}
else
{
UserToPMABufferCopy(Data_Buffer + Block_offset, ENDP1_TXADDR, BULK_MAX_PACKET_SIZE);
Block_Read_count -= BULK_MAX_PACKET_SIZE;
Block_offset += BULK_MAX_PACKET_SIZE;
}
SetEPTxCount(ENDP1, BULK_MAX_PACKET_SIZE);
SetEPTxStatus(ENDP1, EP_TX_VALID);
Memory_Offset += BULK_MAX_PACKET_SIZE;
Transfer_Length -= BULK_MAX_PACKET_SIZE; //剩下的需要传输的字节数。
CSW.dDataResidue -= BULK_MAX_PACKET_SIZE;
Led_RW_ON();
}
这里不清楚的是主机是一次把512字节读完,还是每次发一个命令读取64字节。我觉得应该是发一次读命令,8次“IN”读取一个扇区,再发一个“IN”读取命令状态封包。
8、写命令WRITE(10)
这个命令的处理过程跟读命令的处理差不多,只是最后它会调用Write_Memory()进行处理。
i = 0;
for (; Counter < temp; Counter++)
{
Data_Buffer[Counter] = Bulk_Data_Buff;
i++;
}
从接受缓冲区得到的数据总是先放到用户缓冲区,这个缓冲区有512个字节。
if (!(Transfer_Length % 512))
{
Counter = 0;
MSD_WriteBlock(Data_Buffer, Memory_Offset - 512, 512);
}
每次收到512字节的时候,写入SD卡。
9、u盘文件系统的实现
从这个U盘的实现过程来看,设备端只需完成 SD卡扇区的读写工作,所以与文件系统相关的工作都是由主机方完成的。
至于文件系统的详细实现,前面在FatFs的分析过程中已经涉及,这里就不再叙述了。
文章评论(0条评论)
登录后参与讨论