[应用相关] 零死角玩转stm32-高级篇之SDIO

[复制链接]
4323|59
 楼主| 雨果喝水 发表于 2021-6-30 16:45 | 显示全部楼层
本实验中使用的Micro SD卡属于SDSC(标准容量,最大两G)卡。介绍卡的种类是因为SD协议中的命令也支持这三种类型的卡,因此对STM32中的SDIO接口进行初始化后,上电后就要对接入的卡进行检测、分类,这个过程是通过向卡发送一系列不同的命令,根据卡不同的响应来进行分类。
 楼主| 雨果喝水 发表于 2021-6-30 16:46 | 显示全部楼层
下面进入代码展开具体讲解。

1.4 代码分析

首先要添加用的库文件,在工程文件夹下Fwlib下我们需添加以下库文件:
 楼主| 雨果喝水 发表于 2021-6-30 16:47 | 显示全部楼层
  1. FWlib/stm32f10x_gpio.c

  2. FWlib/stm32f10x_rcc.c

  3. FWlib/stm32f10x_usart.c

  4. FWlib/stm32f10x_sdio.c

  5. FWlib/stm32f10x_dma.c

  6. FWlib/misc.c
 楼主| 雨果喝水 发表于 2021-6-30 16:47 | 显示全部楼层
还要在 stm32f10x_conf.h中把相应的头文件添加进来:
 楼主| 雨果喝水 发表于 2021-6-30 16:48 | 显示全部楼层
#include "stm32f10x_dma.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_rcc.h"

#include "stm32f10x_sdio.h"

#include "stm32f10x_usart.h"

#include "misc.h"
 楼主| 雨果喝水 发表于 2021-6-30 16:49 | 显示全部楼层
保持良好的习惯,从main函数开始分析:
 楼主| 雨果喝水 发表于 2021-6-30 16:49 | 显示全部楼层
int main(void)

{

/*进入到main函数前,启动文件startup(startup_stm32f10x_xx.s)已经调用了在

system_stm32f10x.c中的SystemInit(),配置好了系统时钟,在外部晶振8M的条件下,

设置HCLK = 72M  */

/* Interrupt Config */

NVIC_Configuration();

/* USART1 config */

USART1_Config();

/*------------------------------ SD Init ---------------------------------- */

Status = SD_Init();

printf( "\r\n 这是一个MicroSD卡实验(没有跑文件系统).........\r\n " );

if(Status == SD_OK) //检测初始化是否成功

{

printf( " \r\n SD_Init 初始化成功 \r\n " );

}

else

{

printf("\r\n SD_Init 初始化失败 \r\n" );

printf("\r\n 返回的Status的值为: %d \r\n",Status );

}

printf( " \r\n CardType is :%d ", SDCardInfo.CardType );

printf( " \r\n CardCapacity is :%d ", SDCardInfo.CardCapacity );

printf( " \r\n CardBlockSize is :%d ", SDCardInfo.CardBlockSize );

printf( " \r\n RCA is :%d ", SDCardInfo.RCA);

printf( " \r\n ManufacturerID is :%d \r\n", SDCardInfo.SD_cid.ManufacturerID );

SD_EraseTest();    //擦除测试

SD_SingleBlockTest();  //单块读写测试

SD_MultiBlockTest();  //多块读写测试

while (1)

{}

}
 楼主| 雨果喝水 发表于 2021-6-30 16:51 | 显示全部楼层
main函数的流程简单明了:
 楼主| 雨果喝水 发表于 2021-6-30 16:52 | 显示全部楼层
1、用NVIC_Configuration()初始化好SDIO的中断;
 楼主| 雨果喝水 发表于 2021-6-30 16:52 | 显示全部楼层
2、用USART1_Config()配置好用于返回调试信息的串口,SD_Init()开始进行SDIO的初始化;
 楼主| 雨果喝水 发表于 2021-6-30 16:53 | 显示全部楼层
3、最后分别用SD_EraseTest()、SD_SingleBlockTest()、SD_MultiBlockTest()进行擦除,单数据块读写,多数据块读写测试。
 楼主| 雨果喝水 发表于 2021-6-30 16:55 | 显示全部楼层
下面我们先进入SDIO驱动函数的大头——SD_Init()进行分析:
 楼主| 雨果喝水 发表于 2021-6-30 16:56 | 显示全部楼层
  1. /*

  2. * 函数名:SD_Init

  3. * 描述  :初始化SD卡,使卡处于就绪状态(准备传输数据)

  4. * 输入  :无

  5. * 输出  :-SD_Error SD卡错误代码

  6. *         成功时则为 SD_OK

  7. * 调用  :外部调用

  8. */

  9. SD_Error SD_Init(void)

  10. {

  11. /*重置SD_Error状态*/

  12. SD_Error errorstatus = SD_OK;

  13. /* SDIO 外设底层引脚初始化 */

  14. GPIO_Configuration();

  15. /*对SDIO的所有寄存器进行复位*/

  16. SDIO_DeInit();

  17. /*上电并进**识别流程,确认卡的操作电压  */

  18. errorstatus = SD_PowerON();

  19. /*如果上电,识别不成功,返回“响应超时”错误 */

  20. if (errorstatus != SD_OK)

  21. {

  22. /*!< CMD Response TimeOut (wait for CMDSENT flag) */

  23. return(errorstatus);

  24. }

  25. /*卡识别成功,进**初始化    */

  26. errorstatus = SD_InitializeCards();

  27. if (errorstatus != SD_OK)   //失败返回

  28. {

  29. /*!< CMD Response TimeOut (wait for CMDSENT flag) */

  30. return(errorstatus);

  31. }

  32. /*!< Configure the SDIO peripheral
 楼主| 雨果喝水 发表于 2021-6-30 16:57 | 显示全部楼层
上电识别,卡初始化都完成后,进入数据传输模式,提高读写速度

速度若超过24M要进入bypass模式

!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz

!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */

SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
 楼主| 雨果喝水 发表于 2021-6-30 16:58 | 显示全部楼层
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;         //上升沿采集数据

SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;  //时钟频率若超过24M,要开启此模式

SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;    //若开启此功能,在总线空闲时关闭sd_clk时钟
 楼主| 雨果喝水 发表于 2021-6-30 16:59 | 显示全部楼层
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;                        //1位模式

SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable; //硬件流,若开启,在FIFO不能进行发送和接收数据时,数据传输暂停
 楼主| 雨果喝水 发表于 2021-6-30 17:01 | 显示全部楼层
  1. SDIO_Init(&SDIO_InitStructure);

  2. if (errorstatus == SD_OK)

  3. {

  4. /*----------------- Read CSD/CID MSD registers ------------------*/

  5. errorstatus = SD_GetCardInfo(&SDCardInfo);   //用来读取csd/cid寄存器

  6. }

  7. if (errorstatus == SD_OK)

  8. {

  9. /*----------------- Select Card --------------------------------*/

  10. errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));   //通过cmd7  ,rca选择要操作的卡

  11. }

  12. if (errorstatus == SD_OK)

  13. {

  14. errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);   //开启4bits模式

  15. }

  16. return(errorstatus);

  17. }
 楼主| 雨果喝水 发表于 2021-6-30 17:03 | 显示全部楼层
先从整体上了解这个SD_Init()函数:

1.用 GPIO_Configuration()进行SDIO的端口底层配置

2.分别调用了SD_PowerON()和SD_InitializeCards()函数,这两个函数共同实现了上面提到的卡检测、识别流程。

3.调用SDIO_Init(&SDIO_InitStructure)库函数配置SDIO的时钟,数据线宽度,硬件流(在读写数据的时候,开启硬件流是和很必要的,可以减少出错)

4. 调用SD_GetCardInfo(&SDCardInfo)获取sd卡的CSD寄存器
 楼主| 雨果喝水 发表于 2021-6-30 17:04 | 显示全部楼层
中的内容,在main函数里输出到串口的数据就是这个时候从卡读取得到的。
 楼主| 雨果喝水 发表于 2021-6-30 17:05 | 显示全部楼层
5. 调用SD_SelectDeselect()选定后面即将要操作的卡。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部