ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

利用SPI协议读写SD卡

2021-12-23 21:02:17  阅读:183  来源: 互联网

标签:OK res 读写 SPI USER printf RES SD


利用SPI协议模拟SDIO读写SD卡


一、HAL库配置

配置USART1

在这里插入图片描述
配置SPI1

在这里插入图片描述
配置FATFS

在这里插入图片描述
GPIO配置

在这里插入图片描述
时钟配置

在这里插入图片描述

Serial Wire配置

在这里插入图片描述
生成工程

在这里插入图片描述

二、移植并添加工程

(一)移植驱动文件

在这里插入图片描述
SDdriver.cSDdriver.h文件添加到工程中
在这里插入图片描述
复制到与工程同一路径后后,在工程里面添加SDdriver.c文件,并添加包含该文件的路径。

(二)修改user_diskio.c文件

①添加包含的头文件

#include "diskio.h"		/* Declarations of disk functions */
#include "SDdriver.h"

在这里插入图片描述
接下来分别对USER_initialize、USER_status、USER_read、USE_WRITE、USE_IOCTL函数进行修改,将其内容替换为下面对应函数相关内容

②修改USER_initialize函数

	uint8_t res;
	res = SD_init();//SD_Initialize() 
		 	if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
			{
				SPI_setspeed(SPI_BAUDRATEPRESCALER_256);
				spi_readwrite(0xff);//提供额外的8个时钟
				SPI_setspeed(SPI_BAUDRATEPRESCALER_2);
			}
	if(res)
		return  STA_NOINIT;
	else 
		return RES_OK; //初始化成功

在这里插入图片描述
③修改USER_status函数

 switch (pdrv)
	{
		case 0 :
			return RES_OK;
		case 1 :
			return RES_OK;
		case 2 :
			return RES_OK;
		default:
			return STA_NOINIT;
	}

④修改USER_read函数

uint8_t res;
	if( !count )
	{    
		return RES_PARERR;  /* count不能等于0,否则返回参数错误 */
	}
	switch (pdrv)
	{
		case 0:
		    res=SD_ReadDisk(buff,sector,count);	 
				if(res == 0){
					return RES_OK;
				}else{
					return RES_ERROR;
				}                                               
		default:
			return RES_ERROR;
	}

⑤修改USE_WRITE函数

uint8_t  res;
	if( !count )
	{    
		return RES_PARERR;  /* count不能等于0,否则返回参数错误 */
	}
	switch (pdrv)
	{
		case 0:
		    res=SD_WriteDisk((uint8_t *)buff,sector,count);
				if(res == 0){
					return RES_OK;
				}else{
					return RES_ERROR;
				}                                                
		default:return RES_ERROR;
	}

⑥修改USE_IOCTL函数

  DRESULT res;
	 switch(cmd)
	    {
		    case CTRL_SYNC:
						SD_CS(1);
						do{
							HAL_Delay(20);
						}while(spi_readwrite(0xFF)!=0xFF);
						res=RES_OK;
						SD_CS(0);
		        break;	 
		    case GET_SECTOR_SIZE:
		        *(WORD*)buff = 512;
		        res = RES_OK;
		        break;	 
		    case GET_BLOCK_SIZE:
		        *(WORD*)buff = 8;
		        res = RES_OK;
		        break;	 
		    case GET_SECTOR_COUNT:
		        *(DWORD*)buff = SD_GetSectorCount();
		        res = RES_OK;
		        break;
		    default:
		        res = RES_PARERR;
		        break;
	    }
		return res;

(三)main文件配置

包含头文件

#include "SDdriver.h"

在main函数前添加变量与函数定义

uint16_t uart_value[3];
uint8_t aRxBuffer1;	//uart rx buff 

void WritetoSD(BYTE write_buff[],uint8_t bufSize);
char SD_FileName[] = "test.txt";
uint8_t WriteBuffer[] = "山有木兮\r\n";

//uint8_t test_sd =0;	//用于测试格式化
uint8_t write_cnt =0;	//写SD卡次数

void WritetoSD(BYTE write_buff[],uint8_t bufSize)
{
	FATFS fs;
	FIL file;
	uint8_t res=0;
	UINT Bw;	
	
	res = SD_init();		//SD卡初始化
	
	if(res == 1)
	{
		printf("SD卡初始化失败! \r\n");		
	}
	
	res=f_mount(&fs,"0:",1);		//挂载
	
//	if(test_sd == 0)		//用于测试格式化
	if(res == FR_NO_FILESYSTEM)		//没有文件系统,格式化
	{
//		test_sd =1;				//用于测试格式化
		printf("没有文件系统! \r\n");		
		res = f_mkfs("", 0, 0);		//格式化sd卡
		if(res == FR_OK)
		{
			//printf("格式化成功! \r\n");		
			res = f_mount(NULL,"0:",1); 		//格式化后先取消挂载
			res = f_mount(&fs,"0:",1);			//重新挂载	
			if(res == FR_OK)
			{
				//printf("SD卡已经成功挂载,可以进进行文件写入测试!\r\n");
			}	
		}
		else
		{
			printf("格式化失败! \r\n");		
		}
	}
	else if(res == FR_OK)
	{
		//printf("挂载成功! \r\n");		
	}
	else
	{
		printf("挂载失败! \r\n");
	}	
	
	res = f_open(&file,SD_FileName,FA_OPEN_ALWAYS |FA_WRITE);
	if((res & FR_DENIED) == FR_DENIED)
	{
		printf("卡存储已满,写入失败!\r\n");		
	}
	
	f_lseek(&file, f_size(&file));//确保写词写入不会覆盖之前的数据
	if(res == FR_OK)
	{
		//printf("打开成功/创建文件成功! \r\n");		
		res = f_write(&file,write_buff,bufSize,&Bw);		//写数据到SD卡
		if(res == FR_OK)
		{
			printf("文件写入成功! \r\n");			
		}
		else
		{
			printf("文件写入失败! \r\n");
		}		
	}
	else
	{
		printf("打开文件失败!\r\n");
	}	
	
	f_close(&file);						//关闭文件		
	f_mount(NULL,"0:",1);		 //取消挂载
	
}


void Get_SDCard_Capacity(void)
{
	FRESULT result;
	FATFS FS;
	FATFS *fs;
	DWORD fre_clust,AvailableSize,UsedSize;  
	uint16_t TotalSpace;
	uint8_t res;
	
	res = SD_init();		//SD卡初始化
	if(res == 1)
	{
		printf("SD卡初始化失败! \r\n");		
	}
	else
	{
		printf("SD卡初始化成功! \r\n");		
	}
	
	/* 挂载 */
	res=f_mount(&FS,"0:",1);		//挂载
	if (res != FR_OK)
	{
		printf("FileSystem Mounted Failed (%d)\r\n", result);
	}

	res = f_getfree("0:", &fre_clust, &fs);  /* 根目录 */
	if ( res == FR_OK ) 
	{
		TotalSpace=(uint16_t)(((fs->n_fatent - 2) * fs->csize ) / 2 /1024);
		AvailableSize=(uint16_t)((fre_clust * fs->csize) / 2 /1024);
		UsedSize=TotalSpace-AvailableSize;              
		/* Print free space in unit of MB (assuming 512 bytes/sector) */
		printf("\r\n%d MB total drive space.\r\n""%d MB available.\r\n""%d MB  used.\r\n",TotalSpace, AvailableSize,UsedSize);
	}
	else 
	{
		printf("Get SDCard Capacity Failed (%d)\r\n", result);
	}		
} 

将main函数替代为以下内容

int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_FATFS_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1,&aRxBuffer1,1); 	//enable uart	

	printf(" mian \r\n");
	Get_SDCard_Capacity();	//得到使用内存并选择格式化
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		WritetoSD(WriteBuffer,sizeof(WriteBuffer));		

		printf("writing\r\n");
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(四)其他配置及接线

在usart.c中重定向printf()函数

int fputc(int ch, FILE *f)    
{
    HAL_UART_Transmit(&huart1, (unsigned char *)&ch, 1, 0xFFFF);    //修改【4】,串口重定向
    return ch;
}

在usart.h声明并包含头文件stdio.h
打开Micro LIB
编译完成即可
本实验是基于源码自己重新新建了一个工程,如果怕麻烦,可直接下载源码

源码: 提取码27r2

三、实例演示

接线方式

SD卡stm32系统板
CSPA4
SCKPA5
MISOPA6
MOSIPA7
VCC5V
GNDGND

上位机显示

初始化成功,正在写入数据

在这里插入图片描述

写数据成功,查看已写好的数据

在这里插入图片描述


总结

驱动SD卡的时候,最好将供电电压提高到5V,提高更强的驱动能力。我之前默认使用3.3v由于驱动能力不够,所以一直初始化失败,卡顿了好久。所以基于硬件,稍微有一点有错就会导致整体失败,要特别注意细节。

STM32用cube配置FATFS模式下SPI读写SD卡

标签:OK,res,读写,SPI,USER,printf,RES,SD
来源: https://blog.csdn.net/weixin_52288941/article/details/121959752

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有