尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32F4调试USB-SLAVE读卡经历

STM32F4调试USB-SLAVE读卡经历 最近实现了stm32f4中按键控制usb-slave读卡功能。现记录说明如下硬件采用了stm32f4系列正点原子-阿波罗开发板。连接时注意SD卡槽插入SD大卡跳线帽连接PA11PA12D-D接口通过USB_SLAVE接口连接USB线到电脑端口用于读写SD卡和供电。软件上采用SDIODMAUSB_OTG实现SD卡数据记录和USB_SLAVE读写SD卡。其中代码中需要注意的点如下可见USB相关驱动代码中主要修改usb_bsp.c和usbd_storage_msd.c这两个c文件。usb_bsp.c文件主要包含usb端口初始化用到PA11,PA12端口、安装中断服务函数USBD_OTG_ISR_Handler(USB_OTG_dev)两个功能函数。usbd_storage_msd.c中包含访问存储设备的相关函数读写、是否就绪、即STORAGE_Read、STORAGE_Write、STORAGE_GetCapacity。需要根据SD卡的底层驱动代码编写这三个函数体内的具体内容主要编写SD_ReadDisk和SD_WriteDisk这两个函数。而在main函数中调用时主要调用USBD_Init函数即可。核心代码列举如下usb_bsp.c和usbd_storage_msd.c和部分sdio相关代码//usb_bsp.c代码#includeusb_bsp.h#includehal.h//#include sys.h//#include delay.h//#include usart.h//////////////////////////////////////////////////////////////////////////*******************************************************************************//////////////////////////////////////////////////////////////////////////////////voidOTG_FS_IRQHandler(void);//USB主机电源控制口#defineUSB_HOST_PWRCTRLPAout(15)//PA15//USB OTG 底层IO初始化//pdev:USB OTG内核结构体指针voidUSB_OTG_BSP_Init(USB_OTG_CORE_HANDLE*pdev){GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA时钟RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS,ENABLE);//使能USB OTG时钟 钟//GPIOA11,A12设置GPIO_InitStructure.GPIO_PinGPIO_Pin_11|GPIO_Pin_12;//PA11/12复用功能输出GPIO_InitStructure.GPIO_ModeGPIO_Mode_AF;//复用功能GPIO_InitStructure.GPIO_OTypeGPIO_OType_PP;//推挽输出GPIO_InitStructure.GPIO_SpeedGPIO_Speed_100MHz;//100MHzGPIO_InitStructure.GPIO_PuPdGPIO_PuPd_NOPULL;GPIO_Init(GPIOA,GPIO_InitStructure);//初始化GPIO_InitStructure.GPIO_PinGPIO_Pin_15;//PA15推挽输出GPIO_InitStructure.GPIO_ModeGPIO_Mode_OUT;//输出功能GPIO_InitStructure.GPIO_PuPdGPIO_PuPd_NOPULL;GPIO_Init(GPIOA,GPIO_InitStructure);//初始化USB_HOST_PWRCTRL1;//开启USB HOST电源供电GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_OTG_FS);//PA11,AF10(USB)GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG_FS);//PA12,AF10(USB)}//USB OTG 中断设置,开启USB FS中断//pdev:USB OTG内核结构体指针voidUSB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE*pdev){// NVIC_InitTypeDef NVIC_InitStructure;// NVIC_InitStructure.NVIC_IRQChannel OTG_FS_IRQn;// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0x00;//抢占优先级0// NVIC_InitStructure.NVIC_IRQChannelSubPriority 0x03;//子优先级3// NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;//使能通道// NVIC_Init(NVIC_InitStructure);//配置// BSP_IntEn(BSP_INT_ID_OTG_FS);BSP_IntVectSet(BSP_INT_ID_OTG_FS,OTG_FS_IRQHandler);BSP_IntPrioSet(BSP_INT_ID_OTG_FS,17);BSP_IntEn(BSP_INT_ID_OTG_FS);}//USB OTG 中断设置,开启USB FS中断//pdev:USB OTG内核结构体指针voidUSB_OTG_BSP_DisableInterrupt(void){}//USB OTG 端口供电设置(本例程未用到)//pdev:USB OTG内核结构体指针//state:0,断电;1,上电voidUSB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE*pdev,uint8_tstate){}//USB_OTG 端口供电IO配置(本例程未用到)//pdev:USB OTG内核结构体指针voidUSB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE*pdev){}//USB_OTG us级延时函数//本例程采用SYSTEM文件夹的delay.c里面的mDelayuS函数实现//官方例程采用的是定时器2来实现的.//usec:要延时的us数.voidUSB_OTG_BSP_uDelay(constuint32_tusec){// mDelayuS(usec);BSP_Terminus_Delayus(usec);}//USB_OTG ms级延时函数//本例程采用SYSTEM文件夹的delay.c里面的mDelaymS函数实现//官方例程采用的是定时器2来实现的.//msec:要延时的ms数.voidUSB_OTG_BSP_mDelay(constuint32_tmsec){OS_ERR err;mDelaymS(msec);// //用于延时等待485设备信息// OSTimeDlyHMSM(0u, 0u, 0u, msec,// OS_OPT_TIME_HMSM_STRICT,// err);}//////////usbd_storage_msd.c#includeusbd_msc_mem.h#includeusb_conf.h#includebsp_sdio_sd.h#includeff.h//#include sdio_sdcard.h////////////////////////////////////////////////////////////////////////////////////*******************************************************************************//////////////////////////////////////////////////////////////////////////////////externSD_CardInfo SDCardInfo;//最大支持的设备数,2个#defineSTORAGE_LUN_NBR1////////////////////////////自己定义的一个标记USB状态的寄存器/////////////////////bit0:表示电脑正在向SD卡写入数据//bit1:表示电脑正从SD卡读出数据//bit2:SD卡写数据错误标志位//bit3:SD卡读数据错误标志位//bit4:1,表示电脑有轮询操作(表明连接还保持着)vu8 USB_STATUS_REG0;//////////////////////////////////////////////////////////////////////////////////USB Mass storage 标准查询数据(每个lun占36字节)constint8_tSTORAGE_Inquirydata[]{/* LUN 0 */0x00,0x80,0x02,0x02,(USBD_STD_INQUIRY_LENGTH-4),0x00,0x00,0x00,/* Vendor Identification */A,L,I,E,N,T,E,K, ,//9字节/* Product Identification */S,P,I, ,F,l,a,s,h,//15字节 ,D,i,s,k, ,/* Product Revision Level */1,.,0, ,//4字节/* LUN 1 */0x00,0x80,0x02,0x02,(USBD_STD_INQUIRY_LENGTH-4),0x00,0x00,0x00,/* Vendor Identification */A,L,I,E,N,T,E,K, ,//9字节/* Product Identification */S,D, ,F,l,a,s,h, ,//15字节D,i,s,k, , ,/* Product Revision Level */1,.,0, ,//4字节};int8_tSTORAGE_Init(uint8_tlun);int8_tSTORAGE_GetCapacity(uint8_tlun,uint32_t*block_num,uint32_t*block_size);int8_tSTORAGE_IsReady(uint8_tlun);int8_tSTORAGE_IsWriteProtected(uint8_tlun);int8_tSTORAGE_Read(uint8_tlun,uint8_t*buf,uint32_tblk_addr,uint16_tblk_len);int8_tSTORAGE_Write(uint8_tlun,uint8_t*buf,uint32_tblk_addr,uint16_tblk_len);int8_tSTORAGE_GetMaxLun(void);//USB Device 用户回调函数接口USBD_STORAGE_cb_TypeDef USBD_MICRO_SDIO_fops{STORAGE_Init,STORAGE_GetCapacity,STORAGE_IsReady,STORAGE_IsWriteProtected,STORAGE_Read,STORAGE_Write,STORAGE_GetMaxLun,(int8_t*)STORAGE_Inquirydata,};USBD_STORAGE_cb_TypeDef*USBD_STORAGE_fopsUSBD_MICRO_SDIO_fops;//指向USBD_MICRO_SDIO_fops结构体.//初始化存储设备//lun:逻辑单元编号,0,SD卡;1,SPI FLASH//返回值:0,成功;// 其他,错误代码int8_tSTORAGE_Init(uint8_tlun){SD_Init();//W25QXX_Init();return0;}//获取存储设备的容量和块大小//lun:逻辑单元编号,0,SD卡;1,SPI FLASH//block_num:块数量(扇区数)//block_size:块大小(扇区大小)//返回值:0,成功;// 其他,错误代码int8_tSTORAGE_GetCapacity(uint8_tlun,uint32_t*block_num,uint32_t*block_size){*block_size512;*block_numSDCardInfo.CardCapacity/512;return0;}//查看存储设备是否就绪//lun:逻辑单元编号,0,SD卡;1,SPI FLASH//返回值:0,就绪;// 其他,未就绪int8_tSTORAGE_IsReady(uint8_tlun){USB_STATUS_REG|0X10;//标记轮询return0;}//查看存储设备是否写保护//lun:逻辑单元编号,0,SD卡;1,SPI FLASH//返回值:0,没有写保护;// 其他,写保护(只读)int8_tSTORAGE_IsWriteProtected(uint8_tlun){return0;}//从存储设备读取数据//lun:逻辑单元编号,0,SD卡;1,SPI FLASH//buf:数据存储区首地址指针//blk_addr:要读取的地址(扇区地址)//blk_len:要读取的块数(扇区数)//返回值:0,成功;// 其他,错误代码int8_tSTORAGE_Read(uint8_tlun,uint8_t*buf,uint32_tblk_addr,uint16_tblk_len){int8_tres0;USB_STATUS_REG|0X02;//标记正在读数据#if1resSD_ReadDisk(buf,blk_addr,blk_len);if(res1){USB_STATUS_REG|0X08;//SD卡读错误!}#endifreturnres;}//向存储设备写数据//lun:逻辑单元编号,0,SD卡;1,SPI FLASH//buf:数据存储区首地址指针//blk_addr:要写入的地址(扇区地址)//blk_len:要写入的块数(扇区数)//返回值:0,成功;// 其他,错误代码int8_tSTORAGE_Write(uint8_tlun,uint8_t*buf,uint32_tblk_addr,uint16_tblk_len){int8_tres0;USB_STATUS_REG|0X01;//标记正在写数据#if1resSD_WriteDisk(buf,blk_addr,blk_len);if(res1){USB_STATUS_REG|0X04;//SD卡写错误!}#endifreturnres;}//获取支持的最大逻辑单元个数//返回值:支持的逻辑单元个数-1int8_tSTORAGE_GetMaxLun(void){return(STORAGE_LUN_NBR-1);}//sdio相关代码//其中sdio代码用到了DMASDIO主要参考了野火SDIO例程////需要用到该数组,确保数据缓存区地址是4字节对齐的.__align(4)u8 SDIO_DATA_BUFFER[512];#if1//读SD卡//buf:读数据缓存区//sector:扇区地址//cnt:扇区个数//返回值:错误状态;0,正常;其他,错误代码;u8SD_ReadDisk(u8*buf,u32 sector,u8 cnt){u8 staSD_OK;SD_Error StatusSD_OK;longlonglsectorsector;u8 n;lsector9;if((u32)buf%4!0){for(n0;ncnt;n){staSD_ReadBlock(SDIO_DATA_BUFFER,lsector512*n,512);//单个sector的读操作StatusSD_WaitReadOperation();buf512;while(SD_GetStatus()!SD_TRANSFER_OK);memcpy(buf,SDIO_DATA_BUFFER,512);}}else{if(cnt1){staSD_ReadBlock(buf,lsector,512);//单个sector的读操作StatusSD_WaitReadOperation();while(SD_GetStatus()!SD_TRANSFER_OK);}else{staSD_ReadMultiBlocks(buf,lsector,512,cnt);//多个sectorStatusSD_WaitReadOperation();while(SD_GetStatus()!SD_TRANSFER_OK);}}returnsta;}//写SD卡//buf:写数据缓存区//sector:扇区地址//cnt:扇区个数//返回值:错误状态;0,正常;其他,错误代码;u8SD_WriteDisk(u8*buf,u32 sector,u8 cnt){u8 staSD_OK;SD_Error StatusSD_OK;u8 n;longlonglsectorsector;lsector9;if((u32)buf%4!0){for(n0;ncnt;n){memcpy(SDIO_DATA_BUFFER,buf,512);staSD_WriteBlock(SDIO_DATA_BUFFER,lsector512*n,512);//单个sector的写操作buf512;StatusSD_WaitWriteOperation();while(SD_GetStatus()!SD_TRANSFER_OK);}}else{if(cnt1){staSD_WriteBlock(buf,lsector,512);//单个sector的写操作StatusSD_WaitWriteOperation();while(SD_GetStatus()!SD_TRANSFER_OK);}else{staSD_WriteMultiBlocks(buf,lsector,512,cnt);//多个sectorStatusSD_WaitWriteOperation();while(SD_GetStatus()!SD_TRANSFER_OK);}}returnsta;}#endif//main函数调用//USB-slave读卡功能#ifdefUSE_USB_SLAVEif(usb_flag1){//USB-slave初始化USBD_Init(USB_OTG_dev,USB_OTG_FS_CORE_ID,USR_desc,USBD_MSC_cb,USR_cb);//用于延时等待OSTimeDlyHMSM(0u,0u,0u,1800u,OS_OPT_TIME_HMSM_STRICT,err);//#if0res_sdset_timestamp(filename,2025,10,5,14,30,45);if(res_sd!0){}#endifusb_flag2;}//用以判断usb-slave各个状态if(USB_STA!USB_STATUS_REG)//状态改变了{if(USB_STATUS_REG0x01)//正在写{}if(USB_STATUS_REG0x02)//正在读{}if(USB_STATUS_REG0x04){//提示写入错误}else{//清除显示}if(USB_STATUS_REG0x08){//提示读出错误}else{//清除显示}USB_STAUSB_STATUS_REG;//记录最后的状态}if(Divece_STA!bDeviceState){if(bDeviceState1){//提示USB连接已经建立}else{//提示USB被拔出了}Divece_STAbDeviceState;}tct;if(tct200){tct0;//LED11;//LED0!LED0;//提示系统在运行if(USB_STATUS_REG0x10){offline_cnt0;//USB连接了,则清除offline计数器bDeviceState1;}else//没有得到轮询{offline_cnt;if(offline_cnt10)bDeviceState0;//2s内没收到在线标记,代表USB被拔出了}USB_STATUS_REG0;}#else/////#endif
返回列表