查看: 580  |  回复: 0
SD NAND 的 SDIO在STM32上的应用详解(下篇)

主题

回复
发表于2022-12-08 17:30:47 | 只看该作者
1# 电梯直达

  七.SDIO外设结构体其实前面关于SDIO寄存器的讲解已经比较详细了,这里再借助于关于SDIO结构体再进行总结一遍。

  标准库函数对 SDIO 外设建立了三个初始化结构体,分别为 SDIO 初始化结构体SDIO_InitTypeDef、SDIO 命令初始化结构体 SDIO_CmdInitTypeDef 和 SDIO 数据初始化结

  构体 SDIO_DataInitTypeDef。这些结构体成员用于设置 SDIO 工作环境参数,并由 SDIO 相应初始化配置函数或功能函数调用,这些参数将会被写入到 SDIO 相应的寄存器,达到配置 SDIO 工作环境的目的。

  至于为什么需要一个命令结构体与数据结构体,就是为了方便我们配置SDIO关于寄存器位,因为发送命令或者数据需要很多参数配置。1.SDIO初始化结构体SDIO 初始化结构体用于配置 SDIO 基本工作环境,比如时钟分频、时钟沿、数据宽度等等。它被 SDIO_Init 函数使用。

  1) SDIO_ClockEdge:主时钟 SDIOCLK 产生 CLK 引脚时钟有效沿选择,可选上升沿或下降沿。

  2) SDIO_ClockBypass:时钟分频旁路使用,可选使能或禁用,如果使能旁路,SDIOCLK (72MHZ )直接驱动 CLK 线输出时钟(不满足最高25HZ的要求),如果禁用,使用 SDIO_CLKCR 寄存器的 CLKDIV 位值分频 SDIOCLK,然后输出到 CLK 线。一般选择禁用时钟分频旁路。

  3) SDIO_ClockPowerSave:节能模式选择,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 PWRSAV 位的值。如果使能节能模式,CLK 线只有在总线激活时才有时钟输出;如果禁用节能模式,始终使能 CLK 线输出时钟。

  4) SDIO_BusWide:数据线宽度选择,可选 1 位数据总线、4 位数据总线或 8 为数据总线,系统默认使用 1 位数据总线,操作 SD 卡时在数据传输模式下一般选择 4 位数据总线。它设定 SDIO_CLKCR 寄存器的 WIDBUS 位的值。

  5) SDIO_HardwareFlowControl:硬件流控制选择,可选使能或禁用,它设定SDIO_CLKCR 寄存器的 HWFC_EN 位的值。硬件流控制功能可以避免 FIFO 发送上溢和下溢错误。

  6) SDIO_ClockDiv:时钟分频系数,它设定 SDIO_CLKCR 寄存器的 CLKDIV 位的值,设置 SDIOCLK 与 CLK 线输出时钟分频系数:

  CLK 线时钟频率=SDIOCLK/([CLKDIV+2])。

  2.SDIO命令初始化结构体

  1) SDIO_Argument:作为命令的一部分发送到卡的命令参数,它设定 SDIO 参数寄存器(SDIO_ARG)的值。

  (2) SDIO_CmdIndex:命令号选择,它设定 SDIO 命令寄存器(SDIO_CMD)的 CMDINDEX位的值。

  (3) SDIO_Response:响应类型,SDIO 定义两个响应类型:长响应和短响应。根据命令号选择对应的响应类型。SDIO 定义了四个 32 位的 SDIO 响应寄存器(SDIO_RESPx,x=1…4),短响应只用SDIO_RESP1,长响应使用4个(SDIO_RESPx,x=1…4)。

  1)命令响应寄存器

  2)SDIO响应寄存器1~4

  4) SDIO_Wait:等待类型选择,有三种状态可选,一种是无等待状态,超时检测功能启动,一种是等待中断,另外一种是等待传输完成。

  5) SDIO_CPSM:命令路径状态机控制,可选使能或禁用 CPSM。它设定 SDIO_CMD 寄存器的 CPSMEN 位的值

  只要我们使能的了命令状态机,则下面发送命令和接收响应的过程中的状态转换就不用我们管了

  当我们要发送命令,我们只需要配置这个命令初始化结构体的成员,然后调用下图这个函数,则我们配置的参数写入对应的寄存器位中。

  3.SDIO数据初始化结构体

  1) SDIO_DataTimeOut:设置数据传输以卡总线时钟周期表示的超时周期,它设定 SDIO数据定时器寄存器(SDIO_DTIMER)的值。在 DPSM 进入 Wait_R 或繁忙状态后开始递减,直到 0 还处于以上两种状态则将超时状态标志置 1(详情前面的数据通道小节)。

  2) SDIO_DataLength:设置传输数据长度。

  3) SDIO_DataBlockSize:设置数据块大小,有多种尺寸可选,不同命令要求的数据块可能不同。

  4) SDIO_TransferDir:数据传输方向,可选从主机到卡的写操作,或从卡到主机的读操作。

  5) SDIO_TransferMode:数据传输模式,可选数据块或数据流模式。对于 SD 卡操作使用数据块类型。

  6) SDIO_DPSM:数据路径状态机控制,可选使能或禁用 DPSM。它设定 SDIO_DCTRL寄存器的 DTEN 位的值。要实现数据传输都必须使能 SDIO_DPSM。

  与命令一样使能了数据路径状态机,就不用高那么多麻烦的状态转换了八.SD卡读写测试实验我们平时使用的SD 卡都是已经包含有文件系统的,一般不会使用本实验的操作方式读写 SD 卡,但是对学习SD卡的驱动原理非常重要!!!

  本实验是进行 SD卡最底层的数据读写操作,直接使用 SDIO 对 SD 卡进行读写,会损坏 SD 卡的文件系统,导致数据丢失,所以做这个实验之前需要备份SD卡数据。

  主要是学习SD卡的卡识别过程,以及数据传输工过程,其实就是完全依照前面的两个流程图来实现代码的。

  卡识别模式流程图

  数据传输流程图

  1.硬件设计原理图:

  实物图:

  我这里用的是CS创世的贴片式SD卡,也称之为SD NAND , 内部存储单元架构为SLC,适合存代码。直接上板时相比于拔插式SD卡在抗震和抗PIN氧化方面更有优势,对于缩小整板体积也有一定帮助。

  详情请参考:雷龙官网

  2.代码讲解先看主函数:

  SD_Terst函数:

  我们主要讲解的就是SD卡的初始化

  SD_Init()函数:

  /**

  * 函数名:SD_Init

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

  * 输入:无

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

  * 成功时则为 SD_OK

  * 调用:外部调用

  */SD_Error SD_Init(void){

  /*重置SD_Error状态*/

  SD_Error errorstatus = SD_OK;

  NVIC_Configuration();

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

  GPIO_Configuration();

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

  SDIO_DeInit();

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

  errorstatus = SD_PowerON();

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

  if (errorstatus != SD_OK)

  {

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

  return(errorstatus);

  }

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

  errorstatus = SD_InitializeCards();

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

  {

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

  return(errorstatus);

  }

  /* 配置SDIO外设

  * 上电识别,卡初始化都完成后,进入数据传输模式,提高读写速度

  */

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

  SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;

  /*上升沿采集数据 */

  SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;

  /* Bypass模式使能的话,SDIO_CK不经过SDIO_ClockDiv分频 */

  SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;

  /* 若开启此功能,在总线空闲时关闭sd_clk时钟 */

  SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;

  /* 暂时配置成1bit模式 */

  SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;

  /* 硬件流,若开启,在FIFO不能进行发送和接收数据时,数据传输暂停 */

  SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;

  SDIO_Init(&SDIO_InitStructure);

  if (errorstatus == SD_OK)

  {

  /* 用来读取csd/cid寄存器 */

  errorstatus = SD_GetCardInfo(&SDCardInfo);

  }

  if (errorstatus == SD_OK)

  {

  /* 通过cmd7,rca选择要操作的卡 */

  errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));

  }

  if (errorstatus == SD_OK)

  {

  /* 最后为了提高读写,开启4bits模式 */

  errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);

  }

  return(errorstatus);}

  接下来逐段代码来分析一下:

  errorstatus其实是一个SD_Error类型的枚举变量,SD_Error 是




主题

回复
  • 温馨提示: 标题不合格、重复发帖、发布广告贴,将会被删除帖子或禁止发言。 详情请参考: 社区发帖规则
  • 您当前输入了 0 个文字。还可以输入 8000 个文字。 已添加复制上传图片功能,该功能目前仅支持chrome和火狐

禁言/删除

X
请选择禁言时长:
是否清除头像:
禁言/删除备注:
昵 称:
 
温馨提示:昵称只能设置一次,设置后无法修改。
只支持中文、英文和数字。

举报

X
请选择举报类型:
请输入详细内容:

顶部