航芯国产MCU | 基于SPI Flash的U盘程序,从STM32F103到ACM32F403

前言

本项目是以SPI Flash(如W25Q128等)存储元件作为存储单元,MCU主控完成USB接口通信并根据SCSI协议实现U盘功能。其结构如下图所示:

图片

SPI Flash部分移植

SPI功能部分相对简单,ACM32F403的接口引脚和STM32F103的相同,可直接对接,按照ACM32F403的说明对SPI接口进行初始化,并对底层读写函数进行更改即可。

USB部分移植

1. 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字节数据。

2. 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处理函数,如下图所示:

图片

B. EP1_Pack

在本文所述的代码中,ACM32F403采用EP1完成数据的收发工作。主要是完成对SCSI协议的解析工作。移植过程中,需要文件mass_mal.c、memory.c、scsi_data.c、usb_scsi.c、usb_bot.c及其头文件。本段主要就上述文件中代码需要改动的地方进行说明,部分参数需要重新定义,读者可自行解决。下表列出了ST和Aisino的USB收发功能函数,该部分移植时需要修改的主要部分:

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”收发状态机的状态值,其值如下表所示:

图片

而基于ACM32F403的U Disk工程,IN包可由函数HAL_FSUSB_Send_Data()在其内部进行分包处理,不需要额外逻辑,因此,移植后Bot_State仅需要在BOT_IDLE、BOT_DATA_OUT、BOT_ERROR之间转换,其他对Bot_State的控制可省略。

图片

图片

扫码在线答疑

文章来源:上海航芯

原厂直连:marketing@aisinochip.com

<think>好的,我现在需要帮助用户了解U的BOT技术资料。首先,我要回忆一下BOT是什么。BOT全称是Bulk-Only Transfer,是USB大容量存储设备的一种传输协议。用户可能是在开发U相关功能或者遇到问题需要这方面的信息。 用户提供的引用中有提到上海的技术分享,里面提到了Bot_State变量和状态机。这说明BOT协议涉及到状态机的管理,比如在写数据指令完成后改变状态到BOT_IDLE。我需要结合这些信息来回答。 首先,我应该解释BOT的基本概念,包括它在USB协议中的作用,以及和CBI传输的区别。然后,根据引用中的内容,说明BOT协议的工作流程,比如三个阶段:命令传输、数据传输、状态传输。可能还需要提到CBW和CSW的结构,这在引用中没有直接提到,但这是BOT协议的重要部分。 接下来,状态机部分,引用3提到Bot_State变量及其状态值,如BOT_IDLE。需要详细说明这些状态的变化过程,以及在实际操作中的表现,比如如何通过STM32ACM32F403的代码实现状态管理。 然后,技术实现方面,用户可能想知道如何具体在微控制器上实现BOT协议,比如使用SPI Flash模拟U。引用3提到从STM32F103ACM32F403的移植,这可能涉及固件开发和状态机处理,需要结合代码示例来说明。 另外,用户提供的引用中有提到Active@ Disk Editor验证U扇区数据,这可能涉及到BOT协议中的数据读写验证。需要指出BOT协议在数据传输中的应用,如何通过块传输确保数据正确性。 最后,生成相关问题的时候,要覆盖用户可能进一步询问的方向,比如BOT协议的具体结构、状态机实现细节、与其他协议的区别,以及实际开发中的调试方法。 需要确保回答结构清晰,分点说明,并且正确引用提供的资料。同时,注意使用中文,数学公式和代码块按照要求处理,但当前问题可能不涉及数学公式,所以主要关注技术细节和引用整合。</think>### UBOT协议技术解析 BOT(Bulk-Only Transfer)是USB大容量存储设备(如U)的核心传输协议,其设计目标是简化数据传输流程并提升可靠性。以下是关键分析: #### 1. BOT协议核心机制 - **传输三阶段** BOT协议通过三个阶段完成操作: 1. **命令传输**:主机发送CBW(Command Block Wrapper)包,包含操作指令(如读/写)和逻辑块地址 2. **数据阶段**:通过批量传输端点(Bulk Endpoint)传输数据块 3. **状态反馈**:设备返回CSW(Command Status Wrapper)包,包含操作结果状态码 - **状态机实现** 如引用[3]所述,`Bot_State`变量控制协议状态流转,典型状态包括: - `BOT_IDLE`:空闲等待指令 - `BOT_DATA_IN`:准备向主机发送数据 - `BOT_DATA_OUT`:准备接收主机数据 状态转换触发条件与USB中断事件紧密关联[^3]。 #### 2. 技术实现要点 - **固件开发框架** 在STM32F103/ACM32F403MCU中实现时,需完成以下关键函数: ```c void Mass_Storage_Out_EP_Handler() { if(Bot_State == BOT_DATA_OUT) { // 处理主机下发数据 ProcessDataOutPacket(); } } ``` - **安全增强设计** 如引用[2]提到的加密U方案,BOT协议层需与硬件加密模块(如SM4/AES引擎)协同工作,确保传输数据在端点缓冲区内即完成加密[^2]。 #### 3. 调试与验证 - **物理层验证** 使用Active@ Disk Editor等工具可直接观测U扇区数据(如10号扇区起始于5120字节),验证BOT协议数据读写正确性[^1] - 读操作验证:比较MCU返回数据与磁编辑器显示内容 - 写操作验证:写入特定数据模式后回读校验 $$CSW\_结构 = \begin{cases} dCSWSignature : 4字节标识符(0x53425355) \\ dCSWTag : 与CBW匹配的事务标签 \\ dCSWDataResidue : 未完成数据量 \\ bCSWStatus : 操作状态码(0=成功) \end{cases}$$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值