专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

SDNAND的SDIO在STM32上的应用详解(下篇)

  七。SDIO外设结构体
  其实前面关于SDIO寄存器的讲解已经比较详细了,这里再借助于关于SDIO结构体再进行总结一遍。
  标准库函数对SDIO外设建立了三个初始化结构体,分别为SDIO初始化结构体SDIOInitTypeDef、SDIO命令初始化结构体SDIOCmdInitTypeDef和SDIO数据初始化结
  构体SDIODataInitTypeDef。这些结构体成员用于设置SDIO工作环境参数,并由SDIO相应初始化配置函数或功能函数调用,这些参数将会被写入到SDIO相应的寄存器,达到配置SDIO工作环境的目的。
  至于为什么需要一个命令结构体与数据结构体,就是为了方便我们配置SDIO关于寄存器位,因为发送命令或者数据需要很多参数配置。1。SDIO初始化结构体
  SDIO初始化结构体用于配置SDIO基本工作环境,比如时钟分频、时钟沿、数据宽度等等。它被SDIOInit函数使用。
  1)SDIOClockEdge:主时钟SDIOCLK产生CLK引脚时钟有效沿选择,可选上升沿或下降沿。
  2)SDIOClockBypass:时钟分频旁路使用,可选使能或禁用,如果使能旁路,SDIOCLK(72MHZ)直接驱动CLK线输出时钟(不满足最高25HZ的要求),如果禁用,使用SDIOCLKCR寄存器的CLKDIV位值分频SDIOCLK,然后输出到CLK线。一般选择禁用时钟分频旁路。
  3)SDIOClockPowerSave:节能模式选择,可选使能或禁用,它设定SDIOCLKCR寄存器的PWRSAV位的值。如果使能节能模式,CLK线只有在总线激活时才有时钟输出;如果禁用节能模式,始终使能CLK线输出时钟。
  4)SDIOBusWide:数据线宽度选择,可选1位数据总线、4位数据总线或8为数据总线,系统默认使用1位数据总线,操作SD卡时在数据传输模式下一般选择4位数据总线。它设定SDIOCLKCR寄存器的WIDBUS位的值。
  5)SDIOHardwareFlowControl:硬件流控制选择,可选使能或禁用,它设定SDIOCLKCR寄存器的HWFCEN位的值。硬件流控制功能可以避免FIFO发送上溢和下溢错误。
  6)SDIOClockDiv:时钟分频系数,它设定SDIOCLKCR寄存器的CLKDIV位的值,设置SDIOCLK与CLK线输出时钟分频系数:
  CLK线时钟频率SDIOCLK(〔CLKDIV2〕)。
  2。SDIO命令初始化结构体
  1)SDIOArgument:作为命令的一部分发送到卡的命令参数,它设定SDIO参数寄存器(SDIOARG)的值。
  (2)SDIOCmdIndex:命令号选择,它设定SDIO命令寄存器(SDIOCMD)的CMDINDEX位的值。
  (3)SDIOResponse:响应类型,SDIO定义两个响应类型:长响应和短响应。根据命令号选择对应的响应类型。SDIO定义了四个32位的SDIO响应寄存器(SDIORESPx,x14),短响应只用SDIORESP1,长响应使用4个(SDIORESPx,x14)。
  1)命令响应寄存器
  2)SDIO响应寄存器14
  4)SDIOWait:等待类型选择,有三种状态可选,一种是无等待状态,超时检测功能启动,一种是等待中断,另外一种是等待传输完成。
  5)SDIOCPSM:命令路径状态机控制,可选使能或禁用CPSM。它设定SDIOCMD寄存器的CPSMEN位的值
  只要我们使能的了命令状态机,则下面发送命令和接收响应的过程中的状态转换就不用我们管了
  当我们要发送命令,我们只需要配置这个命令初始化结构体的成员,然后调用下图这个函数,则我们配置的参数写入对应的寄存器位中。
  3。SDIO数据初始化结构体
  1)SDIODataTimeOut:设置数据传输以卡总线时钟周期表示的超时周期,它设定SDIO数据定时器寄存器(SDIODTIMER)的值。在DPSM进入WaitR或繁忙状态后开始递减,直到0还处于以上两种状态则将超时状态标志置1(详情前面的数据通道小节)。
  2)SDIODataLength:设置传输数据长度。
  3)SDIODataBlockSize:设置数据块大小,有多种尺寸可选,不同命令要求的数据块可能不同。
  4)SDIOTransferDir:数据传输方向,可选从主机到卡的写操作,或从卡到主机的读操作。
  5)SDIOTransferMode:数据传输模式,可选数据块或数据流模式。对于SD卡操作使用数据块类型。
  6)SDIODPSM:数据路径状态机控制,可选使能或禁用DPSM。它设定SDIODCTRL寄存器的DTEN位的值。要实现数据传输都必须使能SDIODPSM。
  与命令一样使能了数据路径状态机,就不用高那么多麻烦的状态转换了八。SD卡读写测试实验
  我们平时使用的SD卡都是已经包含有文件系统的,一般不会使用本实验的操作方式读写SD卡,但是对学习SD卡的驱动原理非常重要!!!
  本实验是进行SD卡最底层的数据读写操作,直接使用SDIO对SD卡进行读写,会损坏SD卡的文件系统,导致数据丢失,所以做这个实验之前需要备份SD卡数据。
  主要是学习SD卡的卡识别过程,以及数据传输工过程,其实就是完全依照前面的两个流程图来实现代码的。
  卡识别模式流程图
  数据传输流程图
  1。硬件设计
  原理图:
  实物图:
  我这里用的是CS创世的贴片式SD卡,也称之为SDNAND,内部存储单元架构为SLC,适合存代码。直接上板时相比于拔插式SD卡在抗震和抗PIN氧化方面更有优势,对于缩小整板体积也有一定帮助。
  详情请参考:雷龙官网
  2。代码讲解
  先看主函数:
  SDTerst函数:
  我们主要讲解的就是SD卡的初始化
  SDInit()函数:函数名:SDInit描述:初始化SD卡,使卡处于就绪状态(准备传输数据)输入:无输出:SDErrorSD卡错误代码成功时则为SDOK调用:外部调用SDErrorSDInit(void){重置SDError状态SDErrorerrorstatusSDOK;NVICConfiguration();SDIO外设底层引脚初始化GPIOConfiguration();对SDIO的所有寄存器进行复位SDIODeInit();上电并进行卡识别流程,确认卡的操作电压errorstatusSDPowerON();如果上电,识别不成功,返回响应超时错误if(errorstatus!SDOK){!CMDResponseTimeOut(waitforCMDSENTflag)return(errorstatus);}卡识别成功,进行卡初始化errorstatusSDInitializeCards();if(errorstatus!SDOK)失败返回{!CMDResponseTimeOut(waitforCMDSENTflag)return(errorstatus);}配置SDIO外设上电识别,卡初始化都完成后,进入数据传输模式,提高读写速度SDIOCLKHCLK,SDIOCKHCLK(2SDIOTRANSFERCLKDIV)SDIOInitStructure。SDIOClockDivSDIOTRANSFERCLKDIV;上升沿采集数据SDIOInitStructure。SDIOClockEdgeSDIOClockEdgeRising;Bypass模式使能的话,SDIOCK不经过SDIOClockDiv分频SDIOInitStructure。SDIOClockBypassSDIOClockBypassDisable;若开启此功能,在总线空闲时关闭sdclk时钟SDIOInitStructure。SDIOClockPowerSaveSDIOClockPowerSaveDisable;暂时配置成1bit模式SDIOInitStructure。SDIOBusWideSDIOBusWide1b;硬件流,若开启,在FIFO不能进行发送和接收数据时,数据传输暂停SDIOInitStructure。SDIOHardwareFlowControlSDIOHardwareFlowControlDisable;SDIOInit(SDIOInitStructure);if(errorstatusSDOK){用来读取csdcid寄存器errorstatusSDGetCardInfo(SDCardInfo);}if(errorstatusSDOK){通过cmd7,rca选择要操作的卡errorstatusSDSelectDeselect((uint32t)(SDCardInfo。RCA16));}if(errorstatusSDOK){最后为了提高读写,开启4bits模式errorstatusSDEnableWideBusOperation(SDIOBusWide4b);}return(errorstatus);}
  接下来逐段代码来分析一下:
  errorstatus其实是一个SDError类型的枚举变量,SDError是
  列举了控制器可能出现的错误、比如CRC校验错误、CRC校验错误、通信等待超时、FIFO上溢或下溢、擦除命令错误等等。这些错误类型部分是控制器系统寄存器的标志位,部分是通过命令的响应内容得到的,如果是SDOK则代表没有发送错误,
  配置SDIO中断:
  SDIO外设底层引脚初始化
  复位所有SDIO寄存器
  重点来了:调用SDPowerON()进入卡识别模式
  函数名:SDPowerON描述:确保SD卡的工作电压和配置控制时钟输入:无输出:SDErrorSD卡错误代码成功时则为SDOK调用:在SDInit()调用SDErrorSDPowerON(void){SDErrorerrorstatusSDOK;uint32tresponse0,count0,validvoltage0;uint32tSDTypeSDSTDCAPACITY;上电初始化配置SDIO的外设SDIOCLKHCLK,SDIOCKHCLK(2SDIOINITCLKDIV)初始化时的时钟不能大于400KHzHCLK72MHz,SDIOCLK72MHz,SDIOCKHCLK(1782)400KHzSDIOInitStructure。SDIOClockDivSDIOINITCLKDIV;SDIOInitStructure。SDIOClockEdgeSDIOClockEdgeRising;不使用bypass模式,直接用HCLK进行分频得到SDIOCKSDIOInitStructure。SDIOClockBypassSDIOClockBypassDisable;空闲时不关闭时钟电源SDIOInitStructure。SDIOClockPowerSaveSDIOClockPowerSaveDisable;初始化的时候暂时先把数据线配置成1根SDIOInitStructure。SDIOBusWideSDIOBusWide1b;失能硬件流控制SDIOInitStructure。SDIOHardwareFlowControlSDIOHardwareFlowControlDisable;SDIOInit(SDIOInitStructure);开启SDIO外设的电源SDIOSetPowerState(SDIOPowerStateON);使能SDIO时钟SDIOClockCmd(ENABLE);下面发送一系列命令,开始卡识别流程CMD0:GOIDLESTATE(复位所以SD卡进入空闲状态)没有响应SDIOCmdInitStructure。SDIOArgument0x0;SDIOCmdInitStructure。SDIOCmdIndexSDCMDGOIDLESTATE;没有响应SDIOCmdInitStructure。SDIOResponseSDIOResponseNo;关闭等待中断SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;CPSM在开始发送命令之前等待数据传输结束SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);检测是否正确接收到cmd0errorstatusCmdError();命令发送出错,返回if(errorstatus!SDOK){CMDResponseTimeOut(waitforCMDSENTflag)return(errorstatus);}CMD8:SENDIFCOND发送CMD8检查SD卡的电压操作条件参数:〔31:12〕:保留(要被设置为0)〔11:8〕:支持的电压(VHS)0x1(范围:2。73。6V)〔7:0〕:校验模式(推荐0xAA)响应类型:R7接收到命令sd会返回这个参数SDIOCmdInitStructure。SDIOArgumentSDCHECKPATTERN;SDIOCmdInitStructure。SDIOCmdIndexSDIOSENDIFCOND;SDIOCmdInitStructure。SDIOResponseSDIOResponseShort;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);检查是否接收到命令errorstatusCmdResp7Error();有响应则card遵循sd协议2。0版本if(errorstatusSDOK){SDCard2。0,先把它定义会sdsc类型的卡CardTypeSDIOSTDCAPACITYSDCARDV20;这个变量用作ACMD41的参数,用来询问是sdsc卡还是sdhc卡SDTypeSDHIGHCAPACITY;}else无响应,说明是1。x的或mmc的卡{发命令CMD55SDIOCmdInitStructure。SDIOArgument0x00;SDIOCmdInitStructure。SDIOCmdIndexSDCMDAPPCMD;SDIOCmdInitStructure。SDIOResponseSDIOResponseShort;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);errorstatusCmdResp1Error(SDCMDAPPCMD);}CMD55发送cmd55,用于检测是sd卡还是mmc卡,或是不支持的卡CMD响应:R1SDIOCmdInitStructure。SDIOArgument0x00;SDIOCmdInitStructure。SDIOCmdIndexSDCMDAPPCMD;SDIOCmdInitStructure。SDIOResponseSDIOResponseShort;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);是否响应,没响应的是mmc或不支持的卡errorstatusCmdResp1Error(SDCMDAPPCMD);若errorstatus为CommandTimeOut,说明是MMC卡若errorstatus为SDOK,说明是SDcard:SD卡2。0(电压范围不匹配)或SD卡1。xif(errorstatusSDOK)响应了cmd55,是sd卡,可能为1。x,可能为2。0{下面开始循环地发送sdio支持的电压范围,循环一定次数SDCARD发送ACMD41SDAPPOPCOND,带参数0x80100000while((!validvoltage)(countSDMAXVOLTTRIAL)){在发送ACMD命令前都要先向卡发送CMD55发送CMD55APPCMD,RCA为0SDIOCmdInitStructure。SDIOArgument0x00;SDIOCmdInitStructure。SDIOCmdIndexSDCMDAPPCMD;SDIOCmdInitStructure。SDIOResponseSDIOResponseShort;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);errorstatusCmdResp1Error(SDCMDAPPCMD);if(errorstatus!SDOK){return(errorstatus);}ACMD41命令参数由支持的电压范围及HCS位组成,HCS位置一来区分卡是SDSC还是SDHC0:SDSC1:SDHC响应:R3,对应的是OCR寄存器SDIOCmdInitStructure。SDIOArgumentSDVOLTAGEWINDOWSDSDType;SDIOCmdInitStructure。SDIOCmdIndexSDCMDSDAPPOPCOND;SDIOCmdInitStructure。SDIOResponseSDIOResponseShort;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);errorstatusCmdResp3Error();if(errorstatus!SDOK){return(errorstatus);}若卡需求电压在SDIO的供电电压范围内,会自动上电并标志pwrup位读取卡寄存器,卡状态responseSDIOGetResponse(SDIORESP1);读取卡的ocr寄存器的pwrup位,看是否已工作在正常电压validvoltage(((response31)1)?1:0);count;计算循环次数}if(countSDMAXVOLTTRIAL)循环检测超过一定次数还没上电{errorstatusSDINVALIDVOLTRANGE;SDIO不支持card的供电电压return(errorstatus);}检查卡返回信息中的HCS位判断ocr中的ccs位,如果是sdsc卡则不执行下面的语句if(responseSDHIGHCAPACITY){CardTypeSDIOHIGHCAPACITYSDCARD;把卡类型从初始化的sdsc型改为sdhc型}}elseMMCCardreturn(errorstatus);}
  1。配置SDIO初始化结构体
  配置SDIOInitStructure结构体变量成员并调用SDIOInit库函数完成SDIO外设的基本配置,注意此处的SDIO时钟分频,由于处于卡识别阶段,其时钟不能超过400KHz。
  2。发送CMD0命令:要SD卡回到空闲状态
  那些检测标志全是来源与下图:
  3。发送CMD8:用来识别不同版本的卡和检测卡是否能在主机提供的电压下工作。如果发送CMD8无响应:
  1。电压不匹配的2。0以上SD卡
  2。1。0的SD卡
  3。不是SD卡如果发送CMD8有响应:
  电压匹配的2。0以上SD卡(就是我们即将要使用的SD卡)
  4。使用ACMD41命令判断卡的具体类型。因为是A类命令,所以在发送ACMD41之前必须先发送CMD55,CMD55命令的响应类型的R1。如果CMD55命令都没有响应说明是MMC卡或不可用卡。在正确发送CMD55之后就可以送ACMD41,并根据响应判断卡类型,ACMD41的响应号为R3,CmdResp3Error函数用于检测命令正确发送并带有超时检测功能,但并不具备响应内容接收功能,需要在判定命令正确发送之后调用SDIOGetResponse函数才能获取响应的内容。
  实际上,在有响应时,SDIO外设会自动把响应存放在SDIORESPx寄存器中,SDIOGetResponse函数只是根据形参返回对应响应寄存器的值。通过判定响应内容值即可确定SD卡类型。
  总结:执行SDPowerON函数无错误后就已经确定了SD卡类型,并说明卡和主机电压是匹配的,SD卡处于卡识别模式下的准备状态。退出SDPowerON函数返回SDInit函数,执行接下来代码。
  执行SDPowerON函数没有错误后:SD卡处于卡识别模式下的准备状态
  SDInitializeCards()函数:函数名:SDInitializeCards描述:初始化所有的卡或者单个卡进入就绪状态输入:无输出:SDErrorSD卡错误代码成功时则为SDOK调用:在SDInit()调用,在调用poweron()上电卡识别完毕后,调用此函数进行卡初始化SDErrorSDInitializeCards(void){SDErrorerrorstatusSDOK;uint16trca0x01;if(SDIOGetPowerState()SDIOPowerStateOFF){errorstatusSDREQUESTNOTAPPLICABLE;return(errorstatus);}判断卡的类型if(SDIOSECUREDIGITALIOCARD!CardType){SendCMD2ALLSENDCID响应:R2,对应CID寄存器SDIOCmdInitStructure。SDIOArgument0x0;SDIOCmdInitStructure。SDIOCmdIndexSDCMDALLSENDCID;SDIOCmdInitStructure。SDIOResponseSDIOResponseLong;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);errorstatusCmdResp2Error();if(SDOK!errorstatus){return(errorstatus);}将返回的CID信息存储起来CIDTab〔0〕SDIOGetResponse(SDIORESP1);CIDTab〔1〕SDIOGetResponse(SDIORESP2);CIDTab〔2〕SDIOGetResponse(SDIORESP3);CIDTab〔3〕SDIOGetResponse(SDIORESP4);}if((SDIOSTDCAPACITYSDCARDV11CardType)(SDIOSTDCAPACITYSDCARDV20CardType)(SDIOSECUREDIGITALIOCOMBOCARDCardType)(SDIOHIGHCAPACITYSDCARDCardType))使用的是2。0的卡{SendCMD3SETRELADDRwithargument0SDCardpublishesitsRCA。响应:R6,对应RCA寄存器SDIOCmdInitStructure。SDIOArgument0x00;SDIOCmdInitStructure。SDIOCmdIndexSDCMDSETRELADDR;SDIOCmdInitStructure。SDIOResponseSDIOResponseShort;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);把接收到的卡相对地址存起来errorstatusCmdResp6Error(SDCMDSETRELADDR,rca);if(SDOK!errorstatus){return(errorstatus);}}if(SDIOSECUREDIGITALIOCARD!CardType){RCArca;SendCMD9SENDCSDwithargumentascardsRCA响应:R2对应寄存器CSD(CardSpecificData)SDIOCmdInitStructure。SDIOArgument(uint32t)(rca16);SDIOCmdInitStructure。SDIOCmdIndexSDCMDSENDCSD;SDIOCmdInitStructure。SDIOResponseSDIOResponseLong;SDIOCmdInitStructure。SDIOWaitSDIOWaitNo;SDIOCmdInitStructure。SDIOCPSMSDIOCPSMEnable;SDIOSendCommand(SDIOCmdInitStructure);errorstatusCmdResp2Error();if(SDOK!errorstatus){return(errorstatus);}CSDTab〔0〕SDIOGetResponse(SDIORESP1);CSDTab〔1〕SDIOGetResponse(SDIORESP2);CSDTab〔2〕SDIOGetResponse(SDIORESP3);CSDTab〔3〕SDIOGetResponse(SDIORESP4);}全部卡初始化成功errorstatusSDOK;return(errorstatus);}
  1。判断SDIO电源是否启动,如果没有启动电源返回错误。
  2。发送CMD2命令:是用于通知所有卡通过CMD线返回CID值,执行CMD2发送之后就可以使用CmdResp2Error函数获取CMD2命令发送情况,发送无错误后即可以使用SDIOGetResponse函数获取响应内容,它是个长响应,我们把CMD2响应内容存放在CIDTab数组内。
  3。发送CMD3命令,用于指示SD卡自行推荐RCA地址,CMD3的响应为R6类型,CmdResp6Error函数用于检查R6响应错误,它有两个形参,一个是命令号,这里为CMD3,另外一个是RCA数据指针,这里使用rca变量的地址赋值给它,使得在CMD3正确响应之后rca变量即存放SD卡的RCA。
  CmdResp6Error函数通用会对每个错误位进行必要的检测,如果发现有错误存在则直接返回对应错误类型。
  执行完CmdResp6Error函数之后返回到SDInitializeCards函数中,如果判断无错误说明此刻SD卡已经处于数据传输模式。
  4。发送CMD9给指定RCA的SD卡使其发送返回其CSD寄存器内容,这里的RCA就是在CmdResp6Error函数获取得到的rca。最后把响应内容存放在CSDTab数组中。
  执行SDInitializeCards函数无错误后SD卡就已经处于数据传输模式下的待机状态,退出SDInitializeCards后会返回前面的SDInit函数,执行接下来代码,以下是SDInit函数的后续执行过程:
  1)重新配置SDIO外设,提高时钟频率,之前的卡识别模式都设定CMD线时钟为小于400KHz,进入数据传输模式可以把时钟设置为小于25MHz,以便提高数据传输速率。
  (2)调用SDGetCardInfo函数获取SD卡信息,它需要一个指向SDCardInfo类型变量地址的指针形参,这里赋值为SDCardInfo变量的地址。SD卡信息主要是CID和CSD寄存器内容,这两个寄存器内容在SDInitializeCards函数中都完成读取过程并将其分别存放在CIDTab数组和CSDTab数组中,SDGetCardInfo函数只是简单的把这两个数组内容整合复制到SDCardInfo变量对应成员内。正确执行SDGetCardInfo函数后,SDCardInfo变量就存放了SD卡的很多状态信息,这在之后应用中使用频率是很高的。
  结构体类型定义:有SDCSD、SDCID、SDCardStatus以及SDCardInfo。SDCSD定义了SD卡的特定数据(CSD)寄存器位,一般提供R2类型的响应可以获取得到CSD寄存器内容。SDCID结构体类似SDCSD结构体,它定义SD卡CID寄存器内容,也是通过R2响应类型获取得到。SDCardStatus结构体定义了SD卡状态,有数据宽度、卡类型、速度等级、擦除宽度、传输偏移地址等等SD卡状态。SDCardInfo结构体定义了SD卡信息,包括了SDCSD类型和SDCID类型成员,还有定义了卡容量、卡块大小、卡相对地址RCA和卡类型成员。
  主要是存储卡的容量,卡的大小,RCA地址,卡的类型(这些是关键信息,由命令响应返回然后存入这个结构体中)
  3)调用SDSelectDeselect函数用于选择特定RCA的SD卡,它实际是向SD卡发送CMD7。执行之后,卡就从待机状态转变为传输模式,可以说数据传输已经是万事俱备了
  4)扩展数据线宽度,之前的所有操作都是使用一根数据线传输完成的,使用4根数据线可以提高传输性能,调用可以设置数据线宽度,函数只有一个形参,用于指定数据线宽度。
  至此,SDInit函数已经全部执行完成。如果程序可以正确执行,接下来就可以进行SD卡读写以及擦除等操作。
  SDEraseTest()函数
  SDErase()函数:
  1)检查SD卡是否支持擦除功能,如果不支持则直接返回错误。为保证擦除指令正常进行,要求主机一个遵循下面的命令序列发送指令:CMD32CMD33CMD38。如果发送顺序不对,SD卡会设置ERASESEQERROR位到状态寄存器
  2)SDErase函数发送CMD32指令用于设定擦除块开始地址,在执行无错误后发送CMD33设置擦除块的结束地址。
  3)发送擦除命令CMD38,使得SD卡进行擦除操作。SD卡擦除操作由SD卡内部控制完成,不同卡擦除后是0xff还是0x00由厂家决定。擦除操作需要花费一定时间,这段时间不能对SD卡进行其他操作。
  4)通过IsCardProgramming函数可以检测SD卡是否处于编程状态(即卡内部的擦写状态),需要确保SD卡擦除完成才退出SDErase函数。IsCardProgramming函数先通过发送CMD13命令SD卡发送它的状态寄存器内容,并对响应内容进行分析得出当前SD卡的状态以及可能发送的错误。
  数据写入操作
  SDWriteBlock函数用于向指定的目标地址写入一个块的数据,它有三个形参,分别为指向待写入数据的首地址的指针变量、目标写入地址和块大小。块大小一般都设置为512字节。SDWriteBlock写入函数的执行流程如下:
  1)SDWriteBlock函数开始时将SDIO数据控制寄存器(SDIODCTRL)清零,复位之前的传输设置。
  2)对SD卡进行数据读写之前,都必须发送CMD16指定块的大小,对于标准卡,要写入BlockSize长度字节的块;对于SDHC卡,写入固定为512字节的块。接下来就可以发送块写入命令CMD24通知SD卡要进行数据写入操作,并指定待写入数据的目标地址。
  3)利用SDIODataInitTypeDef结构体类型变量配置数据传输的超时、块数量、数据块大小、数据传输方向等参数并使用SDIODataConfig函数完成数据传输环境配置。
  4)调用SDIOITConfig函数使能SDIO数据结束传输结束中断,传输结束时,会跳转到SDIO的中断服务函数运行。
  5)SDDMATxConfig函数,配置使能SDIO数据向SD卡的数据传输的DMA请求,为使SDIO发送DMA请求,需要调用
  SDIODMACmd函数使能。对于高容量的SD卡要求块大小必须为512字节,SDIO外设会自动生成DMA发送请求,将指定数据使用DMA传输写入到SD卡内。
  普通模式需要自己去处理那些溢出什么的太麻烦了,用DMA传输数据就好了
  DMA外设配置(不清楚的参考:DMA外设详解):
  写入操作等待函数
  SDWaitWriteOperation函数用于检测和等待数据写入完成,在调用数据写入函数之后一般都需要调用,SDWaitWriteOperation函数适用于单块及多块写入函数。
  SDIO中断服务函数
  在进行数据传输操作时都会使能相关标志中断,用于跟踪传输进程和错误检测。
  SDProcessIRQSrc函数首先判断全局变量StopCondition变量是否为1,该全局变量在SDIO的多块读写函数中被置1(前面分析的单块读写函数中StopCondition均为0),因为根据SD卡的要求,多块读写命令由CMD12结束,SD卡在接收到该命令时才停止多块的传输,此处正是根据StopCondition的情况控制是否发送CMD12命令,它发送命令时直接采用往寄存器写入命令和参数的方式。
  调用库函数SDDMAEndOfTransferStatus一直检测DMA的传输完成标志,当DMA传输结束时,该函数会返回SET值。另外,while循环中的判断条件使用的TransferEnd和TransferError是全局变量,它们会在SDIO的中断服务函数根据传输情况被设置,传输结束后,根据TransferError的值来确认是否正确传输,若不正确则直接返回错
  误代码。SDWaitWriteOperation函数最后是清除相关标志位并返回错误。
  数据读取操作
  同向SD卡写入数据类似,从SD卡读取数据可分为单块读取和多块读取。这里仅介绍单块读操作函数,多块读操作类似。
  这一部分自己看代码吧,操作差不多,已经人麻了太多了。
  还有多块读取与多块写入,其实是一样的,只不过传输结束需要发送CMD12来结束传输。
  总结:代码太多了,但是核心的东西已经讲完了,自己去看代码悟一下,其实前面的理论部分懂了,代码部分是完全按照理论来走的,只不过多了一点点细节,就这样咯,那些边边角角留给你们。3。实验结果
  【本文转载自CSDN,作者:rivencode】
  全文目录内容分为三篇【上中下】原文链接跳转如下:
  SDNAND的SDIO在STM32上的应用详解(上篇):http:www。longsto。comnews58。html
  SDNAND的SDIO在STM32上的应用详解(中篇):http:www。longsto。comnews59。html
  SDNAND的SDIO在STM32上的应用详解(下篇):http:www。longsto。comnews60。html

任脉督脉,阴阳互生天地人存,谓曰三才,天圆地方,地方天圆,万物有形。山之南麓,谓之曰阳,山之北坡,名之曰阴,阴阳有别。藤生山南,茎叶阳绿,草长山北,茎叶柔绿,各呈其美。河流北岸,谓之曰阳,河流南侧,甲状腺结节牢记7种食物多吃3类食物少吃,对结节清零有益一7多吃芋头效果消肿止痛增益补气清淤散结李子效果清毒活血利水消肿雪里红效果活血化瘀解毒消肿马齿苑效果消炎灭菌解毒消肿丝瓜效果活血化瘀通经消结无花果效果健脾养胃利水消肿油菜效果润肠通秋冬季气候干燥,容易上火生气?每天早晨几个小动作就可以改善老陈生活在北方城市,一到秋冬季节天气就很干燥,总是会皮肤瘙痒,买了很多外用药膏也是治标不治本,仅仅是缓解了皮肤的干燥。其实在秋冬季除了肤发干燥以外,我们的脏腑同样缺少津液,容易上火1年264万,望底薪回归勇士!不甘就此退役,库里需要你再战1赛季休赛期已经过了一大半,各支球队都陆陆续续开启了备战模式,一些NBA球星也进入了训练场,还有一些NBA球星正在酣战欧锦赛,遗憾的是,本届欧锦赛最大牌的三名选手,约基奇东契奇还有字母哥2换2交易方案,湖人拿到杰伦布朗斯玛特,浓眉哥加盟凯尔特人爵士记者TonyJones报道,博扬博格达诺维奇行情不错,在交易市场上获得了极大关注度,其中爵士和湖人一直有在进行对话,但距离达成交易还相差甚远。博扬是一名身高2米03的锋线,不需37分28分!火箭眼光果然很犀利,捡漏得到低配伦纳德简直大赚在詹姆斯哈登离开火箭队之后,休斯顿火箭队这两年一直都在重建,上赛季,火箭队开始培养杰伦格林申京和克里斯托弗等年轻球员。但是,不少球迷质疑和批评火箭管理层的选人眼光首先是有人认为榜眼CBA新赛季各支球队队长名单一览!广东山东青岛正式换人队长不一定是球队中能力最强的球员,但一定是球队的精神领袖。CBA新赛季10月份就拉开大幕,我们来看看各支球队的队长都是谁。辽宁队韩德君。如果周琦能够回来,我会把顶薪让给他!只要辽宁偏爱丰满型女孩,哈登为何还拒绝300斤模特玛丽安娜的主动示爱?说到哈登,除了篮球,很多球迷能够想到的第一件事情就是哈登和灯红酒绿,毕竟夜店小王子的名号不是白叫的,除了夜店,哈登对于女友的选择也是一直被球迷津津乐道,相比杜兰特的审美还属于球迷认正式官宣!火箭迎回强力中锋,欧锦赛大杀四方,斯通布局很合理北京时间9月16日,根据休斯顿火箭官方发布的消息,代表土耳其男篮参加欧洲锦标赛的申京回来了,这则消息无疑让诸多球迷陈奋人心毕竟,申京在欧洲锦标赛的表现非常出色,虽然遗憾无缘击败法国辽宁男篮众神归位!争冠最后一块拼图紧急抵达,他们不需要郭艾伦北京时间9月16日,辽宁男篮众神归位,争冠的最后一块拼图已经紧急抵达,他们已经不需要郭艾伦了。就在9月16号的13点30分,权威辽宁媒体人导演我躺哪重磅爆料,辽宁外援弗格已经正式抵女人不管多少岁,秋天穿裤子选这4种颜色,高级又大气在众多颜色中,我为大家选出了最高级最大气的四种颜色,无论年龄是多少,选裤装时只要认准这四种颜色准不会出错,保证上身效果高级又大气。随着天气的渐渐转凉,不少女性朋友也开始从裙装换成了
石墨烯是什么?它究竟有多神奇石墨烯,一个熟悉又陌生的名词石墨烯又被称为黑金新材料之王,被誉为改变21世纪的神奇材料。不仅在航空航天太阳能利用纳米电子学生物医疗复合型材料等领域有广泛运用,而且在我们服饰日用品等富豪榜的启示2022年胡润财富榜发布,农夫山泉创始人钟睒睒的财富比去年增长650亿,以4550亿再次成为中国首富。排名第二的张一鸣和排名第三的曾毓群加起来是4750亿。值得注意的是随着全球各大饮酒不过多就没事?医生建议这4类人尽可能做到滴酒不沾我国的酒文化自古以来传承至今,酒逢知己千杯少。更是有人把酒称为精神粮食,适当饮用对身体有好处。就连平时请客吃饭,喜事聚会等等都少不了酒的存在。很多老年人觉得要在抽烟和喝酒里选一个,李莲英葬母比皇帝葬礼都豪气,乡亲白吃35天,往家拿多少一概不问历史总是不缺乏贪财的宦官,清朝末年一人之下,万人之上,最受慈禧太后宠爱的宦官李莲英就是其中一个,而且他的贪是摊在明面上,是贪的明目张胆。据说他的母亲去世时所花的丧葬费将近五十万两白叶利钦为何要让苏联解体,当苏联总统不好吗?久加诺夫道出实情历史在大多数情况下都是复杂的,那些历史人物也是如此。俗话说,时势造英雄,我们不能用今天的眼光或者是视角去审视那个年代的人物,而是要客观全面考察和分析历史人物。对于叶利钦来说就是如此中国有一座灵山,日本人一来就会消失,难道真的有魔法存在?中国自古地大物博,近960万平方公里的土地上,有着广袤的自然资源和丰富的地形地貌,在这片中华大地上,孕育出了世界上最伟大的文明,华夏文明,而我们作为这个文明的子孙后代,更是在这片土日元暴跌,日本人开始青睐二手苹果手机环球时报综合报道很多日本购物者追求最新款电子产品,但由于日元暴跌将新款苹果手机的价格不断推高,导致越来越多的日本人青睐二手苹果手机。二手苹果手机图源视觉中国据路透社8日报道,日元兑医生警惕3种食物,易诱发癌症,致癌率非常高,别不当回事3种食物中都含有这种添加剂,3g就能够导致人死亡,并且致癌率非常高,家里有赶紧丢掉随着生活水平不断提高,现在市面上的食物越来越多,并且很多食物中都具有大量添加剂,食物中使用添加剂能1946年,通化河中鱼又大又肥无人愿吃,老百姓吃日本人长大的前言你们这里的鱼看着还挺肥美的,怎么不见村民打捞呢?没人会吃这些鱼,饿死都不会吃。青年走到村民身边,放下包裹,探着头询问原因。老人瞥了他一眼,直接越过青年离开。青年尴尬地挠挠头,嘿重庆中心城区KTV舞厅等密闭聚集性娱乐场所暂停营业11月7日,重庆市举行新冠肺炎疫情防控工作新闻发布会(第135场)。重庆市文化旅游委副主任新闻发言人秦定波介绍了重庆对于文化娱乐场所的相关疫情防控措施。秦定波介绍,对涉疫区县的KT像保护眼睛一样保护湿地国际湿地城市新华社哈尔滨11月7日电题像保护眼睛一样保护湿地国际湿地城市一线直击新华社记者杨思琪戴锦镕立冬时节,登上哈尔滨松浦大桥,在下桥口顺台阶而下,映入眼帘的是大片金黄色的芦苇荡,白色芦花
友情链接:快好知快生活快百科快传网中准网文好找聚热点快软网