前言
本項目(mu)是(shi)以SPI Flash(如W25Q128等)存儲元件(jian)作(zuo)為存儲單元,MCU主控完成USB接口通信并根據SCSI協議實現U盤功(gong)能。其(qi)結構(gou)如下圖所(suo)示:
SPI Flash部(bu)分移植(zhi)
SPI功(gong)能部分相對(dui)簡單,ACM32F403的(de)接(jie)口引腳和STM32F103的(de)相同(tong),可(ke)直接(jie)對(dui)接(jie),按照ACM32F403的(de)說明對(dui)SPI接(jie)口進(jin)(jin)行初始化,并對(dui)底層讀(du)寫函數進(jin)(jin)行更改即(ji)可(ke)。
USB部分移植
1. STM32F103代碼結(jie)構(gou)
在ST的芯(xin)片上,USB的數據是由兩個中(zhong)斷(duan),USB_LP_CAN1_RX0_IRQHandler和(he)USB_HP_CAN1_TX_IRQHandler來(lai)進(jin)行(xing),其中(zhong)高優先級中(zhong)斷(duan)(USB_HP_CAN1_TX_IRQHandler)用于(yu)(yu)處(chu)理(li)同步(Isochronous)模式傳輸或雙緩沖塊(Bulk)傳輸模式下的正(zheng)確傳輸事件(jian),而低優先級中(zhong)斷(duan)(USB_LP_CAN1_RX0_IRQHandler)用于(yu)(yu)處(chu)理(li)其他傳輸時間。ST的USB數據處(chu)理(li)如下圖所示:
由于USBFS協議的限制(zhi),一包數(shu)(shu)據(ju)中最多可攜帶(dai)64字(zi)節數(shu)(shu)據(ju),因此(ci),當存在大(da)量(liang)數(shu)(shu)據(ju)需(xu)要進行傳(chuan)輸(IN或OUT包)時(shi),需(xu)要分批次(ci)進行傳(chuan)輸。在ST的代碼中,通過變量(liang)“Bot_State”來進行控制(zhi),以Read10指(zhi)令為例,其讀數(shu)(shu)據(ju)流程可如下圖所示:
需要注(zhu)意的是(shi)(shi),Read10指令解析完(wan)成之后(即(ji)上圖(tu)(tu)左(zuo)側流程圖(tu)(tu))則進入數據傳輸(shu)階段,此階段是(shi)(shi)通(tong)過多(duo)次(ci)進入USB高優先級中(zhong)斷中(zhong),調用Read_Memory();來實現的。Read_Memory();函數內每次(ci)傳輸(shu)64字節數據。
2. ACM32F403代碼移植(zhi)要點
本文基于(yu)上海航(hang)芯官方(fang)USB例程進行(xing)移植,移植后(hou)的程序結構如下圖(tu)所(suo)示(shi):
ACM32F403的USB是(shi)采(cai)用一個中斷來(lai)(lai)進(jin)(jin)行(xing)(xing)數(shu)(shu)(shu)(shu)據處理。在官方例程中,USB的中斷函(han)數(shu)(shu)(shu)(shu)內判(pan)定(ding)接收數(shu)(shu)(shu)(shu)據類型,包括suspend,resume,reset,EP0_pack以(yi)及其(qi)他(ta)端點的接收數(shu)(shu)(shu)(shu)據。判(pan)定(ding)結束(shu)后,會(hui)調用USB_Monitor();函(han)數(shu)(shu)(shu)(shu)來(lai)(lai)處理suspend,resume,reset以(yi)及EP0_pack數(shu)(shu)(shu)(shu)據。而其(qi)他(ta)端點數(shu)(shu)(shu)(shu)據會(hui)在usb_transfer_monitor();函(han)數(shu)(shu)(shu)(shu)中進(jin)(jin)行(xing)(xing)解析,該函(han)數(shu)(shu)(shu)(shu)由客戶調用,一般在主函(han)數(shu)(shu)(shu)(shu)的死循環中進(jin)(jin)行(xing)(xing)處理。在本文的移植中,主要需對USB的端點數(shu)(shu)(shu)(shu)據進(jin)(jin)行(xing)(xing)處理。
A. EP0_Pack
EP0接收(shou)的setup數據(ju)會被存(cun)放在(zai)SETIP_0_3_DATA和SETIP_4_7_DATA寄存(cun)器中 ,數據(ju)結構如下所示:
dev_req.bmRequestType=USBCTRL->SETIP_0_3_DATA &0xff;
dev_req.bRequest=(USBCTRL->SETIP_0_3_DATA>>8)&0xff;
dev_req.wValue=(USBCTRL->SETIP_0_3_DATA>>16)&0xffff;
dev_req.wIndex = USBCTRL->SETIP_4_7_DATA&0xffff;
dev_req.wLength=(USBCTRL->SETIP_4_7_DATA>>16)&0xffff;
該(gai)部分解析,可(ke)由用戶在函(han)數(shu)void usb_control_transfer(void)中添加(jia)需(xu)要的處(chu)理函(han)數(shu)。該(gai)函(han)數(shu)由航(hang)芯官方(fang)例(li)程(cheng)里提供。在做U Disk程(cheng)序移植時(shi),需(xu)添加(jia)GetMaxLun和Storage_Reset處(chu)理函(han)數(shu),如下圖(tu)所示:
B. EP1_Pack
在本(ben)文所述的(de)(de)(de)代碼中,ACM32F403采用(yong)EP1完成數(shu)(shu)(shu)據的(de)(de)(de)收發工作。主(zhu)要(yao)是完成對SCSI協議的(de)(de)(de)解析工作。移(yi)植過(guo)程中,需要(yao)文件mass_mal.c、memory.c、scsi_data.c、usb_scsi.c、usb_bot.c及(ji)其頭文件。本(ben)段主(zhu)要(yao)就上述文件中代碼需要(yao)改(gai)動(dong)的(de)(de)(de)地方進行說明(ming),部分參(can)數(shu)(shu)(shu)需要(yao)重新定義,讀者可(ke)自行解決。下表列出了(le)ST和Aisino的(de)(de)(de)USB收發功能函數(shu)(shu)(shu),該(gai)部分移(yi)植時需要(yao)修改(gai)的(de)(de)(de)主(zhu)要(yao)部分:
a. void Mass_Storage_In (void)
在(zai)ST的(de)工程代碼中該部(bu)分主(zhu)要(yao)用于處理(li)(li)SCSI的(de)讀指令。由于全速USB一包(bao)數(shu)(shu)據最(zui)大支持64字節,因此,當需要(yao)傳輸(shu)的(de)數(shu)(shu)據個數(shu)(shu)大于該數(shu)(shu)值時(shi),則需要(yao)分包(bao)傳輸(shu)。在(zai)使用ACM32F403時(shi),可直(zhi)接傳送(song)需要(yao)的(de)數(shu)(shu)據長度(du),內部(bu)會進(jin)行分包(bao)處理(li)(li),因此,該函數(shu)(shu)可省(sheng)略。
b. void Mass_Storage_Out (void)
該函數(shu)用(yong)(yong)于處(chu)理SCSI指令解(jie)析以及發送指令,需在(zai)usb_transfer_monitor()中調用(yong)(yong),并(bing)將函數(shu)內部(bu)的接收數(shu)據部(bu)分更改為:
“Data_Len = HAL_FSUSB_Receive_Data(Bulk_Data_Buff, 64, out_ep_index, 1);”
c.void Transfer_Data_Request(uint8_t* Data_Pointer, uint16_t Data_Len)
將USB發送(song)函(han)(han)數(shu)(shu)更改為ACM32F403對應的(de)(de)發送(song)函(han)(han)數(shu)(shu)。在(zai)(zai)ST的(de)(de)工程中(zhong),該(gai)(gai)函(han)(han)數(shu)(shu)用于傳輸完數(shu)(shu)據后,進入BOT_DATA_IN_LAST狀態,并在(zai)(zai)下一次的(de)(de)Mass_Storage_In()函(han)(han)數(shu)(shu)調用時(shi),回復CSW指令。而本文的(de)(de)移(yi)植(zhi)代(dai)碼中(zhong),省略了Mass_Storage_In()函(han)(han)數(shu)(shu),因此,可在(zai)(zai)該(gai)(gai)函(han)(han)數(shu)(shu)的(de)(de)尾(wei)部增加CSW發送(song)指令:
Set_CSW (CSW_CMD_PASSED, SEND_CSW_ENABLE);
d.void Set_CSW (uint8_t CSW_Status, uint8_t Send_Permission)
將(jiang)USB發(fa)送(song)函數更改為ACM32F403對(dui)應的發(fa)送(song)函數。
e.void Bot_Abort(uint8_t Direction)
該函數主要對收發端點的STALL狀態進行處理,在ACM32F403的收發庫函數中,對端點的STALL已做出相應控制,因此,該函數可省略。
f.void Read_Memory(uint8_t lun, uint32_t Memory_Offset, uint32_t Transfer_Length)
Read_Memory函(han)數(shu)用于收到PC端的IN包(bao)請求后將存儲器中的數(shu)據讀取(qu)并(bing)發送至PC端。而ACM32F403的USB發送庫函(han)數(shu)中,自行進行分包(bao)操作(一包(bao)最大數(shu)據為64字(zi)節),因此(ci)在數(shu)據緩沖區容量允(yun)許條件下,可直接發送完(wan)畢(bi),該函(han)數(shu)修(xiu)改(gai)如下:
{
uint32_t Offset, Length;
Offset = Memory_Offset * Mass_Block_Size[lun];
Length = Transfer_Length * Mass_Block_Size[lun];
CSW.dDataResidue = CBW.dDataLength;
while(Transfer_Length --)
{
MAL_Read(lun ,
Offset ,
Data_Buffer,
Mass_Block_Size[lun]);
Length = min(Mass_Block_Size[lun], CSW.dDataResidue);
Offset += Mass_Block_Size[lun];
HAL_FSUSB_Send_Data((uint8_t *)(Data_Buffer), Length, in_ep_index);
CSW.dDataResidue -= Length;
}
Set_CSW (CSW_CMD_PASSED, SEND_CSW_ENABLE);
}
g.void Write_Memory (uint8_t lun, uint32_t Memory_Offset, uint32_t Transfer_Length)
寫(xie)數據指令完成(cheng)后,將Bot_State 值更改為 BOT_IDLE。ST的(de)工(gong)程代碼中,變量“Bot_State”收發狀態機的(de)狀態值,其(qi)值如(ru)下(xia)表所示:
而基于ACM32F403的U Disk工(gong)程,IN包可由(you)函數HAL_FSUSB_Send_Data()在其內部進行分包處(chu)理(li),不(bu)需(xu)(xu)要(yao)額外(wai)邏輯(ji),因此,移植后Bot_State僅需(xu)(xu)要(yao)在BOT_IDLE、BOT_DATA_OUT、BOT_ERROR之間轉(zhuan)換(huan),其他對Bot_State的控制可省略。
掃碼在線答(da)疑(yi)
如需銷售(shou)咨(zi)詢,請聯系: