完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
文末附主要代码,完整测试程序到参考资料[7]下载。
1- SD卡的初始化
2- 基本的可靠性修正 1、由于SD卡的读写速率较高,当电路板老化或SD卡线太长时,都会大大增加SD的读写错误的发生。 原子哥虽然提供了不错的SD卡代码,但是为了降低错误,把读写速率讲得很低,这样并不是很合理,速率低了依然可能发生错误。因此处理方法是在读写错误发生后,重新读写该区域的数据,知道正确读取数据后才跳出循环。 2、另外,STM32H7 HAL库中的DMA方式写SD卡的程序中出现了笔误,导致不能正常些SD卡,故做了如下修正。当然,最好的解决办法是使用最新的1.90版本的库(目前,OpenedvSD卡HAL库版本还是1.30版本)。 3、即使上面两步已经做到位了,但依然可能收到错误数据,因此使用FATFS时,数据尽量有个校验和,当检验和出错时,通过fseek调整文件指针,实现数据重读。这也就要求校验和设计要严谨,不然会出现数据错了,但校验和凑巧还是正确的问题。 4、数据层面的再次检验,如一个变量A>100,如何A读出小于100的值,那也可以考虑数据回溯或丢弃本次数据了。 3- 参考资料 [1] physical layer simplified specification Vision 7.10 [2]STM32之SD卡 [3]向SD卡某块写数据时,是否要先擦除该块,还是直接写啊? [4] RM0433 STM32H742, STM32H743/753 and STM32H750 Value line advanced Arm®-based 32-bit MCUs [5] AN5200 Getting started with STM32H7 Series SDMMC host controller [6]STM32-HAL库(固件库)升级 [7] NoDistanceY-SD卡测试.zip 4- 主要代码 /* Includes ------------------------------------------------------------------*/#include "sdmmc_sdcard.h"#include "string.h"#include "delay.h"//#include "debug.h"#include#define Debug_Printf(format, ...) printf(format, ##__VA_ARGS__)#define Debug_IT_Printf(format, ...) printf(format, ##__VA_ARGS__)#define Debug_Fflush() /* imported part--------------------------------------------------------------*//* variables -----------------------------------------------------------------*/SD_HandleTypeDef SDCARD_Handler; //SD卡句柄 HAL_SD_CardInfoTypeDef SDCardInfo; //SD卡信息结构体//SD_ReadDisk/SD_WriteDisk函数专用buf,当这两个函数的数据缓存区地址不是4字节对齐的时候,//需要用到该数组,确保数据缓存区地址是4字节对齐的.__align(4) uint8_t SDIO_DATA_BUFFER[512];static bool isInReadProcess = false;static int SDerrCnt = 0;/* SD initialization --------------------------------------------------------*///SD卡初始化,SDMMC频率为200MHz,SD卡最大频率25MHz//返回值:0 初始化正确;其他值,初始化错误uint8_t SD_Init(void){ uint8_t SD_Error; //初始化时的时钟不能大于400KHZ SDCARD_Handler.Instance=SDMMC1; SDCARD_Handler.Init.ClockEdge=SDMMC_CLOCK_EDGE_RISING; //上升沿 SDCARD_Handler.Init.ClockPowerSave=SDMMC_CLOCK_POWER_SAVE_DISABLE; //空闲时不关闭时钟电源 SDCARD_Handler.Init.BusWide=SDMMC_BUS_WIDE_4B; //4位数据线 SDCARD_Handler.Init.HardwareFlowControl=SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;//关闭硬件流控 SDCARD_Handler.Init.ClockDiv=SDMMC_NSpeed_CLK_DIV;//SDMMC_INIT_CLK_DIV; SD_Error=HAL_SD_Init(&SDCARD_Handler); if(SD_Error!=HAL_OK) return 1; //获取SD卡信息 HAL_SD_GetCardInfo(&SDCARD_Handler,&SDCardInfo); return 0;}//SDMMC底层驱动,时钟使能,引脚配置,DMA配置//此函数会被HAL_SD_Init()调用//hsd:SD卡句柄void HAL_SD_MspInit(SD_HandleTypeDef *hsd){ GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_SDMMC1_CLK_ENABLE(); //使能SDMMC1时钟 __HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC时钟 __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟 //PC8,9,10,11,12 GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12; GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽复用 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //高速 GPIO_Initure.Alternate=GPIO_AF12_SDIO1; //复用为SDIO HAL_GPIO_Init(GPIOC,&GPIO_Initure); //初始化 //PD2 GPIO_Initure.Pin=GPIO_PIN_2; HAL_GPIO_Init(GPIOD,&GPIO_Initure); //初始化}/* Interrupt service function and Handlers ----------------------------------*/#if SD_DMA_MODE == 1 || SD_IT_MODE == 1 volatile uint8_t SDCardWriteStatus=0,SDCardReadStatus=0,SDCardErrorStatus=0; void SdmmcSetPriority(uint8_t groupid, uint8_t subid){ HAL_NVIC_SetPriority(SDMMC1_IRQn,groupid,subid); //配置SDMMC1中断,抢占优先级2,子优先级0 HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断}//SDMMC1中断服务函数 ,放置在 stm327xx_it.cvoid SDMMC1_IRQHandler(void){ HAL_SD_IRQHandler(&SDCARD_Handler);}//SDMMC1写完成回调函数void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd){ SDCardWriteStatus=1; //标记写完成}//SDMMC1读完成回调函数void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd){ SDCardReadStatus=1; //标记读完成}//SDMMC1 错误回调函数void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd){ //ErrorCode 解析于:hal_sd.h line271,II_sdmmc.h line138 Debug_IT_Printf("#errorCode:%#x, isInRead?=%drn",hsd->ErrorCode,(int)isInReadProcess);//test SDCardErrorStatus = hsd->ErrorCode; SDerrCnt++; if(isInReadProcess) SDCardReadStatus = 1; else SDCardWriteStatus = 1;}#endif/* funtions -----------------------------------------------------------------*///得到卡信息//cardinfo:卡信息存储区//返回值:错误状态uint8_t SD_GetCardInfo(HAL_SD_CardInfoTypeDef *cardinfo){ uint8_t sta; sta=HAL_SD_GetCardInfo(&SDCARD_Handler,cardinfo); return sta;}//判断SD卡是否可以传输(读写)数据//返回值:SD_TRANSFER_OK 传输完成,可以继续下一次传输// SD_TRANSFER_BUSY SD卡正忙,不可以进行下一次传输uint8_t SD_GetCardState(void){ return((HAL_SD_GetCardState(&SDCARD_Handler)==HAL_SD_CARD_TRANSFER )?SD_TRANSFER_OK:SD_TRANSFER_BUSY);}#if SD_DMA_MODE == 1//如果使用DMA的话下面两个变量用来标记SD卡读写是否完成//读SD卡//buf:读数据缓存区//sector:扇区地址//cnt:扇区个数 //返回值:错误状态;0,正常;其他,错误代码;uint8_t SD_ReadDisk(uint8_t* buf,uint32_t sector,uint32_t cnt){ uint8_t sta=HAL_ERROR; SDCardReadStatus=0; isInReadProcess = true; while(1) { Debug_Fflush(); while(HAL_SD_ReadBlocks_DMA(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt) != HAL_OK) { SDerrCnt++; if(SDerrCnt>10) break; Debug_Printf("##errorCode:%#x, isInRead?=%drn",SDCARD_Handler.Instance->STA,(int)isInReadProcess); Debug_Fflush(); delay_ms(10);//猜测的时间 } if(SDerrCnt > 10) { Debug_Printf("###errorCode:%#x, isInRead?=%drn",SDCardErrorStatus,(int)isInReadProcess); break; } while(SDCardReadStatus==0){}; //等待读完成 SDCardReadStatus=0; if(SDCardErrorStatus) { Debug_Fflush(); SDCardErrorStatus = 0; continue; } while(SD_GetCardState()){}; //等待SD卡空闲 sta=HAL_OK; break; } SDerrCnt = 0; isInReadProcess = false; return sta;}//写SD卡//buf:写数据缓存区//sector:扇区地址//cnt:扇区个数 //返回值:错误状态;0,正常;其他,错误代码; uint8_t SD_WriteDisk(uint8_t *buf,uint32_t sector,uint32_t cnt){ uint8_t sta=HAL_ERROR; SDCardWriteStatus=0; while(1) { while(HAL_SD_WriteBlocks_DMA(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt) != HAL_OK) { SDerrCnt++; if(SDerrCnt>10) break; Debug_Printf("##errorCode:%#x, isInRead?=%drn",SDCARD_Handler.Instance->STA,(int)isInReadProcess); delay_ms(10);//猜测的时间 } if(SDerrCnt > 10) { Debug_Printf("###errorCode:%#x, isInRead?=%drn",SDCardErrorStatus,isInReadProcess); break; } while(SDCardWriteStatus==0){}; //等待读完成 SDCardWriteStatus=0; if(SDCardErrorStatus) { Debug_Fflush(); SDCardErrorStatus = 0; continue; } while(SD_GetCardState()){}; //等待SD卡空闲 sta=HAL_OK; break; } SDerrCnt = 0; return sta;}#endif#if (SD_IT_MODE==1) //IT模式//读SD卡//buf:读数据缓存区//sector:扇区地址//cnt:扇区个数 //返回值:错误状态;0,正常;其他,错误代码;uint8_t SD_ReadDisk(uint8_t* buf,uint32_t sector,uint32_t cnt){ uint8_t sta=HAL_ERROR; SDCardReadStatus=0; if(HAL_SD_ReadBlocks_IT(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt)==HAL_OK) { while(SDCardReadStatus==0) { if(SDCardErrorStatus != 0) { SDCardErrorStatus = 0; sta = HAL_SD_WriteBlocks_IT(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt); } }; //等待写完成 //SDCardReadStatus=0;//不能用 2019/5/24 while(SD_GetCardState()){}; //等待SD卡空闲 sta=HAL_OK; } return sta;} //写SD卡//buf:写数据缓存区//sector:扇区地址//cnt:扇区个数 //返回值:错误状态;0,正常;其他,错误代码; uint8_t SD_WriteDisk(uint8_t *buf,uint32_t sector,uint32_t cnt){ uint8_t sta=HAL_ERROR; SDCardWriteStatus=0; if(HAL_SD_WriteBlocks_IT(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt)==HAL_OK) { while(SDCardWriteStatus==0) { if(SDCardErrorStatus != 0) { SDCardErrorStatus = 0; HAL_SD_WriteBlocks_IT(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt); } }; //等待写完成 //SDCardWriteStatus=0; //不能用 2019/5/24 while(SD_GetCardState()){}; //等待SD卡空闲 sta=HAL_OK; } return sta;} #endif#if SD_POLLING_MODE == 1 //轮询模式//如果使用DMA的话下面两个变量用来标记SD卡读写是否完成volatile uint8_t SDCardWriteStatus=0,SDCardReadStatus=0,SDCardErrorStatus=0; //读SD卡//buf:读数据缓存区//sector:扇区地址//cnt:扇区个数 //返回值:错误状态;0,正常;其他,错误代码;uint8_t SD_ReadDisk(uint8_t* buf,uint32_t sector,uint32_t cnt){ uint8_t sta=HAL_OK; uint32_t timeout=SD_TIMEOUT; long long lsector=sector; //INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) sta=HAL_SD_ReadBlocks(&SDCARD_Handler, (uint8_t*)buf,lsector,cnt,SD_TIMEOUT);//多个sector的读操作 //等待SD卡读完 while(SD_GetCardState()!=SD_TRANSFER_OK) { if(timeout-- == 0) { sta=SD_TRANSFER_BUSY; } } //INTX_ENABLE();//开启总中断 return sta;} //写SD卡//buf:写数据缓存区//sector:扇区地址//cnt:扇区个数 //返回值:错误状态;0,正常;其他,错误代码; uint8_t SD_WriteDisk(uint8_t *buf,uint32_t sector,uint32_t cnt){ uint8_t sta=HAL_OK; uint32_t timeout=SD_TIMEOUT; long long lsector=sector; //INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) sta=HAL_SD_WriteBlocks(&SDCARD_Handler,(uint8_t*)buf,lsector,cnt,SD_TIMEOUT);//多个sector的写操作 //等待SD卡写完 while(SD_GetCardState()!=SD_TRANSFER_OK) { if(timeout-- == 0) { sta=SD_TRANSFER_BUSY; } } //INTX_ENABLE();//开启总中断 return sta;}#endif/* Private variables ---------------------------------------------------------*/static void show_sdcard_info(void){ uint64_t CardCap; //SD卡容量 HAL_SD_CardCIDTypedef SDCard_CID; HAL_SD_GetCardCID(&SDCARD_Handler,&SDCard_CID); //获取CID SD_GetCardInfo(&SDCardInfo); //获取SD卡信息 switch(SDCardInfo.CardType) { case CARD_SDSC: { if(SDCardInfo.CardVersion == CARD_V1_X) Debug_Printf("Card Type:SDSC V1rn"); else if(SDCardInfo.CardVersion == CARD_V2_X) Debug_Printf("Card Type:SDSC V2rn"); } break; case CARD_SDHC_SDXC:Debug_Printf("Card Type:SDHCrn");break; } CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize); //计算SD卡容量 Debug_Printf("Card ManufacturerID:%drn",SDCard_CID.ManufacturerID); //制造商ID Debug_Printf("Card RCA:%drn",SDCardInfo.RelCardAdd); //卡相对地址 Debug_Printf("LogBlockNbr:%d rn",(uint32_t)(SDCardInfo.LogBlockNbr)); //显示逻辑块数量 Debug_Printf("LogBlockSize:%d rn",(uint32_t)(SDCardInfo.LogBlockSize)); //显示逻辑块大小 Debug_Printf("Card Capacity:%d MBrn",(uint32_t)(CardCap>>20)); //显示容量 Debug_Printf("Card BlockSize:%drnrn",SDCardInfo.BlockSize); //显示块大小}void TDD_SD_Test(void){ while(SD_Init())//检测不到SD卡 { Debug_Printf("##SD Card Error!,is SD inserted?rn"); delay_ms(2000); } SDCARD_Handler.Instance->ICR = 0; show_sdcard_info(); Debug_Printf("@SD Card OK!rn"); Debug_Fflush(); __align(4) uint8_t buf[512] ="hello SD card yyyrn "; SD_WriteDisk(buf,2,1); while(1) { delay_ms(1000); memset(buf,0,1024); SD_ReadDisk(buf,2,1); //Debug_TxFixedLen((char*)buf,sizeof("hello SD card xxxrn")-1); Debug_Printf("%s",buf); Debug_Fflush(); };}/************************ (C) COPYRIGHT NODISTANCEY****************END OF FILE****/ |
|
|
|
只有小组成员才能发言,加入小组>>
3320 浏览 9 评论
2998 浏览 16 评论
3496 浏览 1 评论
9066 浏览 16 评论
4089 浏览 18 评论
1186浏览 3评论
612浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
602浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2339浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1899浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 11:01 , Processed in 1.708590 second(s), Total 80, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号