STM32通过SPI读写SD卡,初始化失败
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32通过SPI读写SD卡,初始化失败相关的知识,希望对你有一定的参考价值。
主程序如下
int main(void)
char c[100] = "";
char *string = c;
SD_Error II;
sprintf(string, "number = %d", number);
UseSysClkInit();
UseGpioInit();
Init_TFT();
LCDAPI_Clear(Green);
LCDAPI_PutStrAtLine(LINE15, string, Red, Green, CHARSIZE_8x16);
TIM5_Init();
TIM4_Init();
NVIC_Configuration();
II = SD_Init();
if (II == SD_RESPONSE_NO_ERROR )
LCDAPI_PutStrAtLine(LINE10, " OK!", Red, Green, CHARSIZE_8x16);
else
LCDAPI_PutStrAtLine(LINE10, " ERROR!", Red, Green, CHARSIZE_8x16);
while(1)
原理图如图
SD代码如链接
http://pan.baidu.com/s/1kTr9IIj
使用芯片STM32F107VCT
SD卡为8G卡
现问题。SD始终初始化失败。请大神帮忙解决!
做生意,要钱的勿扰
那SDHC卡咋初始化呢?
追答初始化发的命令不同,翻SD2.0的规范手册上有,或者直接百度搜索支持SDHC的源代码就行了,这个是参照手册写的应该是初始化命令还需要发一个0x3A还是0x58来着,SDHC是向下兼容SD的,所以再原来基础上多发个别的命令应该就能初始化了,不过具体太久了,忘记具体是什么命令了
参考技术A 需要帮你完成吗追问最好能帮忙指出问题。
帮完成也可以。
可以丘上说
我id
你们还是算了吧。做生意的
追答好的
参考技术B 有SDIO干嘛还要用SPI追问没有啊
嵌入式用STM32F103完成对SD卡的数据读取
用STM32F103完成对SD卡的数据读取
一、SD卡协议原理
1.SDIO协议
SD卡(Secure Digital Memory Card)在我们的生活中已经非常普遍了,控制器对SD卡进行读写通信操作一般有两种通信接口可选,一种是 SPI接口,另外一种就是 SDIO接口。SDIO 全称是 安全数字输入/输出接口,多媒体卡(MMC)、SD卡、SD I/O卡 都有 SDIO接口。STM32F103系列控制器有一个 SDIO主机接口,它可以与 MMC卡、SD卡、SD I/O卡 以及 CE-ATA 设备进行数据传输。
2.SD卡物理结构
一般SD卡包括有存储单元、存储单元接口、电源检测、卡及接口控制器和接口驱动器 5个部分。
存储单元是存储数据部件,存储单元通过存储单元接口与卡控制单元进行数据传输;
电源检测单元保证SD卡工作在合适的电压下,如出现掉电或上状态时,它会使控制单元和存储单元接口复位;
卡及接口控制单元控制SD卡的运行状态,它包括有8个寄存器;
接口驱动器控制SD卡引脚的输入输出。
SD卡总共有8个寄存器,用于设定或表示SD卡信息。
这些寄存器只能通过对应的命令访问,SDIO定义64个命令,每个命令都有特殊意义,可以实现某一特定功能,SD卡接收到命令后,根据命令要求对SD卡内部寄存器进行修改,程序控制中只需要发送组合命令就可以实现SD卡的控制以及读写操作。
3.SD卡寄存器列表
4.SD卡初始化(SPI模式)
SPI操作模式下:在SD卡收到复位命令时,CS为有效电平(低电平),则SPI模式被启用,在发送CMD之前要先发送74个时钟,64个为内部供电上升时间,10个用于SD卡同步;之后才能开始CMD操作,在初始化时CLK时钟不能超过400KHz。
1、初始化与SD卡连接的硬件条件(MCU的SPI配置,IO口配置);
2、上电延时(>74个CLK);
3、复位卡(CMD0),进入IDLE状态;
4、发送CMD8,检查是否支持2.0协议;
5、根据不同协议检查SD卡(命令包括:CMD55、CMD41、CMD58和CMD1等);
6、取消片选,发多8个CLK,结束初始化
这样我们就完成了对SD卡的初始化,注意末尾发送的8个CLK是提供SD卡额外的时钟,完成某些操作。通过SD卡初始化,我们可以知道SD卡的类型(V1、V2、V2HC或者MMC),在完成了初始化之后,就可以开始读写数据了。
5.SD卡读写(SPI模式)
1、发送CMD17;
2、接收卡响应R1;
3、接收数据起始令牌0XFE;
4、接收数据;
5、接收2个字节的CRC,如果不使用CRC,这两个字节在读取后可以丢掉。
6、禁止片选之后,发多8个CLK;
以上就是一个典型的读取SD卡数据过程,SD卡的写于读数据差不多,写数据通过CMD24来实现,具体过程如下:
1、发送CMD24;
2、接收卡响应R1;
3、发送写数据起始令牌0XFE;
4、发送数据;
5、发送2字节的伪CRC;
6、禁止片选之后,发多8个CLK;
以上就是一个典型的写SD卡过程。
6.采用SPI方式,连线
我们在用USB转TTL为STM32供电的时候一定需要接到5V上面去,并且在用32给SD卡模块供电的时候一定一定要接到5V电源上,否则我们无法驱动该SD模块
二、CubeMX创建工程
完整工程链接在最后
1.配置SYS
2.配置PA4如图所示
3.配置USART1
4.配置SPI1为全双工主模式
5.配置FATFS
6.管脚配置
7.配置时钟树
8.工程配置
这里一定要修改堆栈的大小,太小了会使我们无法读取SD卡的数据,直接导致我们的程序跑飞
三、代码
1.主函数
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "SDdriver.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
HAL_UART_Transmit(&huart1, (unsigned char *)&ch, 1, 0xFFFF);
return ch;
uint16_t uart_value[3];
uint8_t aRxBuffer1; //uart rx buff
void WritetoSD(BYTE write_buff[],uint8_t bufSize);
char SD_FileName[] = "123.txt";
uint8_t WriteBuffer[] = "01 631907030429 石头\\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");
else
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);
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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(" main \\r\\n");
Get_SDCard_Capacity(); //得到使用内存并选择格式化
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
WritetoSD(WriteBuffer,sizeof(WriteBuffer));
// HAL_Delay(500);
WriteBuffer[0] = WriteBuffer[0] +0;
WriteBuffer[1] = WriteBuffer[1] +1;
write_cnt ++;
while(write_cnt > 5)
printf(" while \\r\\n");
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
RCC_OscInitTypeDef RCC_OscInitStruct = 0;
RCC_ClkInitTypeDef RCC_ClkInitStruct = 0;
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
Error_Handler();
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
Error_Handler();
/**
* @brief SPI1 Initialization Function
* @param None
* @retval None
*/
static void MX_SPI1_Init(void)
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
Error_Handler();
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
Error_Handler();
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
GPIO_InitTypeDef GPIO_InitStruct = 0;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : SD_CS_Pin */
GPIO_InitStruct.Pin = SD_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\\r\\n", file, line) */
/* USER CODE END 6 */
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
2.编译
编译无错,接下来烧录即可。
四、结果
参考
工程下载:
https://pan.baidu.com/s/12EJQf1qGzPf1M7w4I9alrg
提取码:1111
以上是关于STM32通过SPI读写SD卡,初始化失败的主要内容,如果未能解决你的问题,请参考以下文章
STM32开发_利用SPI协议读写SD卡介绍SD卡SPI时序
STM32开发_利用SPI协议读写SD卡介绍SD卡SPI时序
无法使用 STM32F407 上的 Chan FatFs 库通过 SPI 写入 SD 卡文件