共计 3379 个字符,预计需要花费 9 分钟才能阅读完成。
本我的项目是以 SPI Flash(如 W25Q128 等)存储元件作为存储单元,MCU 主控实现 USB 接口通信并依据 SCSI 协定实现 U 盘性能。其构造如下图所示:
SPI Flash 局部移植
SPI 性能局部绝对简略,ACM32F403 的接口引脚和 STM32F103 的雷同,可间接对接,依照 ACM32F403 的阐明对 SPI 接口进行初始化,并对底层读写函数进行更改即可。
USB 局部移植
- STM32F103 代码构造
在 ST 的芯片上,USB 的数据是由两个中断,USB_LP_CAN1_RX0_IRQHandler 和 USB_HP_CAN1_TX_IRQHandler 来进行,其中高优先级中断(USB_HP_CAN1_TX_IRQHandler)用于解决同步 (Isochronous) 模式传输或双缓冲块 (Bulk) 传输模式下的正确传输事件,而低优先级中断(USB_LP_CAN1_RX0_IRQHandler)用于解决其余传输工夫。ST 的 USB 数据处理如下图所示:
因为 USBFS 协定的限度,一包数据中最多可携带 64 字节数据,因而,当存在大量数据须要进行传输(IN 或 OUT 包)时,须要分批次进行传输。在 ST 的代码中,通过变量“Bot_State”来进行管制,以 Read10 指令为例,其读数据流程可如下图所示:
须要留神的是,Read10 指令解析实现之后(即上图左侧流程图)则进入数据传输阶段,此阶段是通过屡次进入 USB 高优先级中断中,调用 Read_Memory();来实现的。Read_Memory();函数内每次传输 64 字节数据。
- ACM32F403 代码移植要点
本文基于上海航芯官网 USB 例程进行移植,移植后的程序结构如下图所示:
ACM32F403 的 USB 是采纳一个中断来进行数据处理。在官网例程中,USB 的中断函数内断定接收数据类型,包含 suspend,resume,reset,EP0_pack 以及其余端点的接收数据。断定完结后,会调用 USB_Monitor(); 函数来解决 suspend,resume,reset 以及 EP0_pack 数据。而其余端点数据会在 usb_transfer_monitor(); 函数中进行解析,该函数由客户调用,个别在主函数的死循环中进行解决。在本文的移植中,次要需对 USB 的端点数据进行解决。
A. EP0_Pack
EP0 接管的 setup 数据会被寄存在 SETIP_0_3_DATA 和 SETIP_4_7_DATA 寄存器中,数据结构如下所示:
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;
该局部解析,可由用户在函数 void usb_control_transfer(void)中增加须要的处理函数。该函数由航芯官网例程里提供。在做 U Disk 程序移植时,需增加 GetMaxLun 和 Storage_Reset 处理函数,如下图所示:
pYYBAGHEFEmAeQ_4AAAXy3Fvpe4520.png
B. EP1_Pack
在本文所述的代码中,ACM32F403 采纳 EP1 实现数据的收发工作。次要是实现对 SCSI 协定的解析工作。移植过程中,须要文件 mass_mal.c、memory.c、scsi_data.c、usb_scsi.c、usb_bot.c 及其头文件。本段次要就上述文件中代码须要改变的中央进行阐明,局部参数须要从新定义,读者可自行解决。下表列出了 ST 和 Aisino 的 USB 收发性能函数,该局部移植时须要批改的次要局部:
pYYBAGHEFFaAZ_OdAAGrUNCnfJM199.png
a. void Mass_Storage_In (void)
在 ST 的工程代码中该局部次要用于解决 SCSI 的读指令。因为全速 USB 一包数据最大反对 64 字节,因而,当须要传输的数据个数大于该数值时,则须要分包传输。在应用 ACM32F403 时,可间接传送须要的数据长度,外部会进行分包解决,因而,该函数可省略。
b. void Mass_Storage_Out (void)
该函数用于解决 SCSI 指令解析以及发送指令,需在 usb_transfer_monitor()中调用,并将函数外部的接收数据局部更改为:
“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 发送函数更改为 ACM32F403 对应的发送函数。在 ST 的工程中,该函数用于传输完数据后,进入 BOT_DATA_IN_LAST 状态,并在下一次的 Mass_Storage_In()函数调用时,回复 CSW 指令。而本文的移植代码中,省略了 Mass_Storage_In()函数,因而,可在该函数的尾部减少 CSW 发送指令:
Set_CSW (CSW_CMD_PASSED, SEND_CSW_ENABLE);
d.void Set_CSW (uint8_t CSW_Status, uint8_t Send_Permission)
将 USB 发送函数更改为 ACM32F403 对应的发送函数。
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 函数用于收到 PC 端的 IN 包申请后将存储器中的数据读取并发送至 PC 端。而 ACM32F403 的 USB 发送库函数中,自行进行分包操作(一包最大数据为 64 字节),因而在数据缓冲区容量容许条件下,可间接发送结束,该函数批改如下:
{
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)
写数据指令实现后,将 Bot_State 值更改为 BOT_IDLE。ST 的工程代码中,变量“Bot_State”收发状态机的状态值,其值如下表所示:
poYBAGHEFHCARKM7AAInEow6Qbw876.png
而基于 ACM32F403 的 U Disk 工程,IN 包可由函数 HAL_FSUSB_Send_Data()在其外部进行分包解决,不须要额定逻辑,因而,移植后 Bot_State 仅须要在 BOT_IDLE、BOT_DATA_OUT、BOT_ERROR 之间转换,其余对 Bot_State 的管制可省略