首页 > 其他分享 >基于stm32H730的解决方案开发之SD卡的读写调试

基于stm32H730的解决方案开发之SD卡的读写调试

时间:2023-11-18 12:22:54浏览次数:39  
标签:HAL 读写 Init stm32H730 OK hsd1 sd SD

一 概述 在嵌入式小系统领域,SD卡存储是一个非常重要的功能。可从难度上,它又是非常难的。因为它涉及到两个大的功能点,一个是文件系统,这个难度非一般。另外一个是sd卡的底层驱动。涉及到的接口多,所以也是一个难度高的地方。两个混合在一起,非常容易出问题。笔者在这块花费了很多时间。也遇到了很多问题。这里需要做一个总结了。 二 源码解析 通过使用Cube来生成的sd卡读写源码,大概率是不成功的,这就要逐步的定位了,到底是哪儿出了问题呢? 面对纷繁复杂的局势,第一步就是要学会拆解,逐步击破。接下来,就让我们来逐步的分析一下。 步骤一,首先排查硬件十分ok? 这个很简单,写一个GPIO拉高拉低的源码,来逐个验证一下这些IO口是否都是通的。代码如下所示:  

  while (1)
  {
    /* code */
    check_state_on();
    HAL_Delay(1000);
    check_state_off();
    HAL_Delay(1000);
    mprintf("check pc12a loopback cnt is:%d \n\r",g_leds_cnt++);

  }

 

通过万用表来测量这些IO,假如是不通的,那就要检查一下IO硬件了。 步骤二,接下来,就要抛开文件系统,来查看一下sd卡是否能识别了。 这部分源码比较复杂,需要自己整理的,这里给出笔者整理出来的源码。
#define SD_TIMEOUT             ((uint32_t)0x00100000U) //等待时间
#define BLOCK_SIZE            512  //块的数目
#define NUMBER_OF_BLOCKS      50 //块的数据大小
#define MULTI_BUFFER_SIZE    (BLOCK_SIZE * NUMBER_OF_BLOCKS)


/**
  * @brief  数组匹配检测函数
  * @param  pBuffer1:发送数组;pBuffer2:接受数组;BufferLength:数组长度
  * @retval HAL_OK:匹配;HAL_ERROR:不匹配
  */
static HAL_StatusTypeDef Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength)
{
    while (BufferLength--)
    {
      if (*pBuffer1 != *pBuffer2)
      {      
        return HAL_ERROR;      
      }
      else{

        pBuffer1++;
        pBuffer2++;
      }
    }
    return HAL_OK;
} 


uint8_t Buffer_Block_Tx[512]={0};//写入数组
uint8_t Buffer_Block_Rx[512];//读取数组
uint8_t SD_save_ok=0;

uint32_t sd_status_one = 0;
uint32_t time_sd_1=0;
uint32_t time_sd_2=0;
uint16_t sd_test_ii=0;

void SD_SingleBlockTest_easy(void)
{
        
    for(sd_test_ii=0;sd_test_ii<512;sd_test_ii++)
    {    //对写入数组进行赋值
       Buffer_Block_Tx[sd_test_ii]=sd_test_ii%216;
    }
    
    sd_status_one =HAL_SD_WriteBlocks(&hsd1,(uint8_t *)Buffer_Block_Tx,0,1,0xfff);       //将写入数组写入SD卡中,0表示写入地址为0,1表示为写入1个扇区的数据

    if(sd_status_one == HAL_OK)
    {
        mprintf("write success \r\n");
    }
    else
    {
        mprintf("write failed status is:%d \r\n",sd_status_one);
    }
        
    for(sd_test_ii=0;sd_test_ii<512;sd_test_ii++)
    {   //对读取数组赋值
        Buffer_Block_Rx[sd_test_ii]=0;
    }
        
     sd_status_one =HAL_SD_ReadBlocks(&hsd1,(uint8_t *)Buffer_Block_Rx,0,1,0xfff);;   //读取SD卡数据,将数据存在读取数组中
        
     sd_status_one=Buffercmp(Buffer_Block_Tx,Buffer_Block_Rx,512); //写入数组和读取数组进行对比
            
     if(sd_status_one == HAL_OK)
     {
          mprintf("SD test ok!!\r\n");
     }
     else
     {
          mprintf("SD_test fail!\r\n " );
     }
}


/**
  * @brief  SD卡等待擦除完成函数
  * @param  无
  * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败
  */
static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
{
    uint32_t loop = SD_TIMEOUT;
    
    while(loop > 0)
    {
      loop--;
      if(HAL_SD_GetCardState(&hsd1) == HAL_SD_CARD_TRANSFER)
      {
          return HAL_OK;
      }
    }
    return HAL_ERROR;
}


/* USER CODE BEGIN 1 */
/**
  * @brief  SD卡擦除测试
  * @param  无
  * @retval 无
  */
static void SD_EraseTest(void)
{
    HAL_StatusTypeDef Status = HAL_OK;
    HAL_StatusTypeDef EraseStatus = HAL_OK;
    if (Status == HAL_OK)
    {
        Status = HAL_SD_Erase(&hsd1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));// SD卡外设句柄、擦除的起始地址、擦除的结束地址
        //等待擦除完成
        if(Wait_SDCARD_Ready() != HAL_OK)
        {
            EraseStatus = HAL_ERROR;
        }
    }     
    if(EraseStatus == HAL_OK)
    {    
      mprintf("SD card efuse success \r\n");
    }
    else
    {
      mprintf("SD card efuse failed \n");
    }    
}


/**
  * @brief SDMMC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SDMMC1_SD_Init(void)
{

  /* USER CODE BEGIN SDMMC1_Init 0 */

  /* USER CODE END SDMMC1_Init 0 */

  /* USER CODE BEGIN SDMMC1_Init 1 */

  /* USER CODE END SDMMC1_Init 1 */
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 4;
  /* USER CODE BEGIN SDMMC1_Init 2 */

  if (HAL_SD_Init(&hsd1) != HAL_OK)
  {
    Error_Handler();
  }


  if(HAL_SD_GetCardState(&hsd1) == HAL_SD_CARD_TRANSFER)
  {
     mprintf("SD card init ok!\r\n\r\n");
            
     SD_EraseTest();  //SD卡擦除测试

     SD_SingleBlockTest_easy();//SD卡读写测试

  }
  else
  { 
      mprintf("SD card init fail!\r\n" );
  }

  /* USER CODE END SDMMC1_Init 2 */

}

 

这部分是来检查sd卡能否读写的,绕过文件系统的。 通过测试,笔者发现是可以正常读写的,如下所示:   步骤三,接下来就要剑指文件系统了。肯定是这哪儿出了问题,具体怎么定位呢?由于文件系统比较复杂,接下来一章节继续分析吧。 三 总结 做bug定位,能做到化繁为简,这就成功了一半了。接下来,就是对知识点的掌握和对问题的深究能力了。

标签:HAL,读写,Init,stm32H730,OK,hsd1,sd,SD
From: https://www.cnblogs.com/dylancao/p/17840305.html

相关文章

  • 35文本文件的读写
    一、最后效果   二、代码:1procedureTForm1.Button1Click(Sender:TObject);2begin3ifOpenDialog1.Executethen4Edit1.Text:=OpenDialog1.FileName;5end;678procedureTForm1.Button2Click(Sender:TObject);9var10SFileName,DFile......
  • Java文件处理(二):文件读写
    读/写文件前请保证文件存在。InputStreamInputStream是基本的输入流,它是一个抽象类(不是接口)最基本的方法是intread(),作用是读取输入流的下一个字节,并返回字节的int值,返回-1代表已读到结尾。按字节读取一个文件流:publicvoidreadFile()throwsIOException{try(Input......
  • 在线CAD SDK前端库绘制规则多边形图形
    前言在CAD(计算机辅助设计)领域,绘制多边形是常见的任务之一。MxCAD是一款专注在线CAD的前端库,提供了丰富的绘图和设计功能,使得绘制多边形变得轻松而灵活。本文将带领您通过使用MxCAD实现绘制多边形的过程,深入了解其基本概念和功能。mxcad 是一个基于TypeScript的前端库,专为......
  • 基于stm32H730的解决方案开发之freertos系统解析
    一概述在嵌入式小系统领域,freertos是一个非常厉害的角色。它和小芯片结合,能迸发出非常大的威力。这里在H730上使用了这个freertos,是应该做一个总结和备忘。二实例解析1线程初始化:freertos最大的优势就是多任务,所以,多线程非常重要,怎么定义一个线程呢?下面给出一......
  • esp32笔记[10]-rust驱动ssd1306显示屏
    摘要使用rust(no-std)环境和esp-hal库实现SSD1306显示屏(128x64)显示bmp图片.平台信息esp32(模组:ESP32-WROOM-32D)(xtensalx6)(xtensa-esp32-none-elf)rust超链接esp32笔记[7]-使用rust+zig开发入门原理简介rust的include_bytes!宏Rust的include_bytes!宏可以用......
  • 如何利用淘宝 SDK 获取商品详情?
    注册淘宝开放平台账号并创建应用,获取APP_ID和APP_SECRET。下载并导入淘宝开放平台提供的SDK,以便在代码中使用相关接口和功能。使用 TaobaoSDK.init_app 方法初始化SDK,将APP_ID和APP_SECRET传递给该方法。创建一个 TaobaoSDK.Request 对象,设置请求的方法为 taobao.ite......
  • 基于stm32H730的解决方案开发之点亮第一个LED灯
    一概述STM32H730超值系列内含Arm®Cortex®-M7内核(具有双精度浮点单元),工作频率可达550MHz。内嵌的128KB闪存使意法半导体能够为开发人员提供一种经济划算的解决方案。凭借着高主频,高性能以及低成本。这颗料注定会成为一个网红产品。笔者最近有几款产品用到了该芯片,借此机会......
  • @WebServiceClient wsdlLocation 动态给注解内容参数赋值
    动态给注解内容参数赋值@WebServiceClient(name="IXxxService",targetNamespace="http://xxx.xxx.xxx.com",wsdlLocation="${WSDL_URL}")publicclassIXxxServiceextendsService{ //静态变量在静态代码块加载后加载,且注解也在之后加载,完成动态注入修改注解里的参......
  • 《文件篇》读写txt
    stdio.hfopen(),打开文件fopen(constchar*filename,constchar*mode)其中mode:"r",read:为输入操作打开文件,文件必须存在。"w",write:为输出操作创建一个空文件,如果文件已存在,则将已有文件内容舍弃,按照空文件对待。"a",append:为输出打开文件,输出操作总是再文件末尾追......
  • SDL2+FFmpeg5.0播放视频文件
    一、概述上一节使用SDL2播放了YUV视频文件,本节使用SDL2+FFmpeg5.0播放一个视频文件(只播放视频,不播放声音)播放效果图: 二、代码示例#include"sdl_ffmpeg_play.h"//sdl刷新事件#defineSFM_REFRESH_EVENT(SDL_USEREVENT+1)//sdl退出事件#defineSFM_BREAK......