2)Control/Bulk/Interrupt传输(CBI)
Mass Storage类规范定义了两个类规定的请求:Get_Max_LUN和Mass Storage Reset,所有的Mass Storage类设备都必须支持这两个请求。
Get_Max_LUN(bmRequestType= 10100001b and bRequest= 11111110b)用来确认设备支持的逻辑单元数。Max LUN的值必须是0~15。注意:LUN是从0开始的。主机不能向不存在的LUN发送CBW,本章我们定义Max LUN的值为1,即代表2个逻辑单元。
Mass Storage Reset(bmRequestType=00100001b and bRequest= 11111111b)用来复位Mass Storage设备及其相关接口。
支持BOT传输的Mass Storage设备接口描述符要求如下:
接口类代码bInterfaceClass=08h,表示为Mass Storage设备;
接口类子代码bInterfaceSubClass=06h,表示设备支持SCSI Primary Command-2(SPC-2);
协议代码bInterfaceProtocol有3种:0x00、0x01、0x50,前两种需要使用中断传输,最后一种仅使用批量传输(BOT)。
支持BOT的设备必须支持最少3个endpoint:Control, Bulk-In和Bulk-Out。USB2.0的规范定义了控制端点0。Bulk-In端点用来从设备向主机传送数据(本章用端点1实现)。Bulk-Out端点用来从主机向设备传送数据(本章用端点2实现)。
ST官方的例程是通过USB来读写SD卡(SDIO方式)和NAND FALSH,支持2个逻辑单元,我们在官方例程的基础上,只需要修改SD驱动部分代码(改为SPI),并将对NAND FLASH的操作修改为对SPI FLASH的操作。只要这两步完成了,剩下的就比较简单了,对底层磁盘的读写,都是在mass_mal.c文件实现的,所以我们只需要修改该函数的MAL_Init、MAL_Write、MAL_Read和MAL_GetStatus等4个函数,使之与我们的SD卡和SPI FLASH对应起来即可。
USB时钟频率一定要48Mhz
void Set_USBClock(void)
{
if (SystemCoreClock == 72000000)
{
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);//USBclk=PLLclk/1.5=48Mhz
}
else if (SystemCoreClock == 48000000)
{
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div1);
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
}
初始化时配置好内存大小等参数
Mass_Memory_Size[0]=1024*1024*8;
Mass_Block_Size[0] =512;
Mass_Block_Count[0]=Mass_Memory_Size[0]/Mass_Block_Size[0];
USB_Interrupts_Config();
Set_USBClock();
USB_Init();
通过电脑端就可以向spi flash写入数据了,设备想要读取U盘中的文件数据需要移植fatfs文件系统。FATFS文件系统的移植,主要是diskio.c文件。
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
u8 res=0;
switch(drv)
{
case SD_CARD:
break;
case EX_FLASH:
SPI_Flash_Init();
break;
default:
res=1;
}
if(res)return STA_NOINIT;
else return 0;
}
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to read (1..255) */
)
{
u8 res=0;
if (!count)return RES_PARERR;//count²»ÄܵÈÓÚ0£¬·ñÔò·µ»Ø²ÎÊý´íÎó
switch(drv)
{
case SD_CARD:
break;
case EX_FLASH:
for(;count>0;count--)
{
SPI_Flash_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
res=0;
break;
default:
res=1;
}
if(res==0x00)return RES_OK;
else return RES_ERROR;
}
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..255) */
)
{
u8 res=0;
if (!count)return RES_PARERR;//count²»ÄܵÈÓÚ0£¬·ñÔò·µ»Ø²ÎÊý´íÎó
switch(drv)
{
case SD_CARD:
break;
case EX_FLASH:
for(;count>0;count--)
{
//SPI_Flash_Erase_Sector(sector);
SPI_Flash_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
res=0;
break;
default:
res=1;
}
if(res == 0x00)return RES_OK;
else return RES_ERROR;
}
#endif /* _READONLY */
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
if(drv==SD_CARD)
{
}
else if(drv==EX_FLASH)
{
switch(ctrl)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = FLASH_SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = FLASH_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FLASH_SECTOR_COUNT;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
}
else res=RES_ERROR;
return res;
}
通过fatfs读取U盘中的数据
FRESULT fresult;
fresult = f_mount(0, fs);
if (fresult == FR_NO_FILESYSTEM)
{
res = f_mkfs(0, 1, 4096);
}
if (fresult == FR_OK)
{
FIL fil;
fresult = f_open (&fil, "1.txt", FA_OPEN_EXISTING | FA_READ);
if (fresult == FR_OK)
{
uint8_t buff[8];
UINT readlen;
f_read (&fil, buff, 6, &readlen);
}
}