开发板:
原理图:
开发工具:S32 Design Studio for Power Architecture
调试内容:MPC5748G通过SDHC模块读写eMMC
eMMC:
嵌入式多媒体卡 (Embedded Multi Media Card)是MMC协会订立、主要针对手机或平板电脑等产品的内嵌式存储器标准规格。eMMC在封装中集成了一个控制器,提供标准接口并管理闪存。eMMC的应用是对存储容量有较高要求的消费电子产品。
带有MMC(多媒体卡)接口、快闪存储器设备及主控制器。所有都在一个小型的BGA 封装。接口速度高达每秒52MBytes,eMMC具有快速、可升级的性能。同时其接口电压可以是1.8v 或者是3.3v。
SDHC:
MPC5748G支持一个超安全数字主机控制器(uSDHC:ultra Secure Digital Host Controller)模块,uSDHC提供主系统与SD/SDIO/ MMC卡通信的接口。uSDHC充当桥梁的作用,以发送命令的方式,通过主机总线传输到SD/SDIO/ MMC卡中,执行数据访问(读写操作),它遵循SD/SDIO/MMC卡的传输协议。
注意:为了 uSDHC 外部接口的正常运行,uSDHC_VEND_SPEC [ CMD_OE_PRE_EN ] 【Vendor Specific Register :此寄存器包含供应商特定的控制/状态寄存器位应该被编程为 1 。
设备寄存器的特定复位值如下表所示:
uSDHC_BLK_ATT:Block Attributes (uSDHC_BLK_ATT),这个寄存器用于配置数据块的数量和每一块的字节数。
uSDHC_PRES_STATE:Present State (uSDHC_PRES_STATE),该只读寄存器获得uSDHC的状态。当一个数据发送期间,DAT lines 处于忙状态,主驱动可以发送 CMD0, CMD12, CMD13 (for memory) 和 CMD52 (for SDIO)。这些命令能够被发送,当 Command Inhibit (DAT)【命令抑制位,uSDHC_PRES_STATE[CIHB]:如果此状态位为0,则表示CMD线未使用,uSDHC可以使用CMD线发出SD/MMC命令。在写入传输类型寄存器Command Transfer Type (uSDHC_CMD_XFR_TYP)后立即设置此位。当接收到命令响应时,此位被清除。即使这个Command Inhibit (DAT) 【CDIHB】被设置为 1,仅仅 CMD 线能用于发送命令(如果该位为0)。
打开调试工程:
安装完成开发工具:S32DS_Power_Win32_v2017.R1_b171019.exe
1、双击打开开发工具:
2、打开File --> New --> S32DS Project from Example,选择如下工程。
3、打开SDHC调试工程如下:
一、配置SDHC工程:
1、配置SDHC的引脚
2、配置SDHC时钟
3、配置uSDHC参数信息
二、SDHC Pads 初始化:
1、设置 Pins Output Buffer:
(1) 调用接口描述
(2) 寄存器描述
MSCR(Multiplexed Signal Configuration Register):多路信号配置寄存器,选择哪一个信号源连接到寄存器相关联的目的地,即这是一个芯片引脚,是或可以配置为一个输出。对于相关联的芯片引脚目的地,该寄存器也可以指定这个引脚的电气属性。
MSCR 寄存器中的字段根据其关联的目的地(芯片引脚)变化而变化。 对于 芯片引脚 的 MSCR 寄存器分配,引脚类型,APC (Analog Pad Control)支持,SSS(Source Signal Select)等等。这个寄存器只支持32位访问。字节和半字写访问不支持。
注:参见I/O信号描述和输入多路复用附属于 MPC5748GRM 手册的表格(excel文件)。
2、设置 Pins Input Buffer:
(1) 调用接口描述
(2) 寄存器描述
IMCR(Input Multiplexed Signal Configuration Register):输入多路复用信号配置寄存器,选择哪一个信号源连接到寄存器相关联的目的地,即这是一个内部模块端口(internal module port),是或可以配置为一个输入。
IMCR 寄存器中的字段根据其关联的目的地(module port)变化而变化,对于 IMCR 的分配和SSS (Source Signal Select)的值参见I/O信号描述和输入多路复用表。
3、设置 Pins Pull 选择:
(1) 调用接口描述
(2) 寄存器描述见以上描述
三、SDHC 初始化:
1、uSDHC 初始化代码解析:
(1)去初始化:调用接口 uSDHC_DRV_Deinit();
(2)uSDHC驱动初始化:调用接口 uSDHC_DRV_Init();
/* Reset uSDHC. */
/* Configures the usdhc protocol */
/* Disable all clock auto gated off feature because of DAT0 line logic(card buffer full status) can't be updated correctly when clock auto gated off is enabled. */
四、eMMC 初始化:
1、判断 eMMC卡是否插入:
读取 uSDHC_PRES_STATE 寄存器中的 CINST 位,判断卡是否插入。
2、如果 eMMC卡插入,则初始化eMMC卡:
(1)设置 uSDHC 的总线时钟为 400KHZ
1)首先得到系统时钟:srcClock ( 例如设置的系统时钟为 40MHZ = 40 000 000 HZ )
2)禁用 uSDHC时钟。在更改 eMMC 时钟频率之前,应该禁用它。
uSDHC_VEND_SPEC[ FRC_SDCLK_ON ] = 0;
3)求 prescaler 和 divisor 的大小。
Clock Frequency = (srcClock ) / (prescaler x divisor)
例如:Clock Frequency = 400 000 hz;srcClock = 40 000 000 HZ
即:prescaler x divisor = 100
参照 MPC5748G数据手册,可知:prescaler <=256;divisor <=16
并且,在单数据速率模式下,prescaler 只允许以下设置:
• 80h) Base clock divided by 256
• 40h) Base clock divided by 128
• 20h) Base clock divided by 64
• 10h) Base clock divided by 32
• 08h) Base clock divided by 16
• 04h) Base clock divided by 8
• 02h) Base clock divided by 4
• 01h) Base clock divided by 2
• 00h) Base clock divided by 1
所以,设置 divisor =16 时,求出 prescaler =100/16=6.25,按照上面分析,prescaler =8;当 prescaler =8 时,divisor = 100/8=12.5,约等于13。
即:uSDHC_SYS_CTRL[SDCLKFS]=prescaler >>1;
uSDHC_SYS_CTRL[DVS]=divisor-1;
同时,设置 Data Timeout Counter Value: uSDHC_SYS_CTRL[DTOCV]=0x0E;
注:详细 uSDHC_SYS_CTR L描述请见手册。
4)等待 eMMC 卡的时钟稳定。
while ( uSDHC_PRES_STATE [ SDSTB ] == 0 ){ };
5)使能 uSDHC 时钟。
uSDHC_VEND_SPEC[ FRC_SDCLK_ON ] = 1;
(2)发送80时钟周期到卡,以至于激活卡。
1)写1清除 uSDHC_SYS_CTRL 寄存器中的 INITA 位
即: uSDHC_SYS_CTRL [ INITA ] = 1;
2)等待卡激活。
while ( uSDHC_SYS_CTRL [ INITA ] == 0 ) { };
(3)参考芯片手册以及 emmc 协议发送 CMD 命令 初始化 eMMC卡。
1)发送 CMD0 命令,设置卡 空闲状态。
command . index = CMD0 /*!< Go Idle State */
command . argument = 0;
2)host发送CMD1后,会从device收到R3,如果R3中busy bit为0,表示device还没准备好。host重复发送CMD1,接收R3这个过程。
command . index = CMD1 /*!< Send Operation Condition */
command . argument = 0xFF8000
command . responseType = uSDHC_RESPONSE_TYPE_R3
3)host 发送CMD2后,会从device收到获取CID,R2用来用来返回 device's CID。
command . index = CMD2 /*!< All Send CID */
command . argument = 0U;
command . responseType = uSDHC_RESPONSE_TYPE_R2;
4)host 发送 CMD3 用来给设置设备的 relative device address(RCA)
command . index = CMD3 /*!< Set Relative Address */
command . argument = 0 /* Relative Address */
command . responseType = uSDHC_RESPONSE_TYPE_R1;
5)host 发送 CMD9 用来请求设备发送它的 Device-specific data (CSD) 到 CMD line 上。参数指定设备的RCA [31:16] RCA
command . index = CMD9 /*!< Send CSD */
command . argument = (card->relativeAddress << 16U) /* 参数 */
command . responseType = uSDHC_RESPONSE_TYPE_R2
6)host 发送 CMD7 用来选择或取消卡
当设备处在Stand-by状态,CMD7把设备从Stand-by State切换到Transfer State;也可以把设备从Transfer State切换回Stand-by State。
当设备处在Disconnect状态,CMD7把设备从Disconnect State切换到Programming State。
在以上两种情况下,使用当前的RCA会选择设备,任何其他RCA 地址都会取消选择。使用RCA 0x0000表示取消选择。
command . index = CMD7 /*!< Select Card */
command . argument = card->relativeAddress << 16U //选择卡
command . argument = 0x0000 //取消选择
command . responseType = uSDHC_RESPONSE_TYPE_R1
7)host 发送 CMD23 用来设置卡的读写块数目
参数:
[30] '0' non-packed '1' packed
[24] forced programming, 设置为1,强迫数据直接写入存储介质,而不是仅写入cache
[15:0] number of blocks, 定义读写块数目
command . index = CMD23 /*!< Set Block Count */
command . argument = blockCount
command . responseType = uSDHC_RESPONSE_TYPE_R1
8)host 发送 CMD16 设置接下来所有block命令(读和写)的block尺寸。缺省的块长度在CSD中指定。
参数[31:0] : block长度
command . index = CMD16 ; /*!< Set Block Length */
command . argument = blockSize
command . responseType = uSDHC_RESPONSE_TYPE_R1
9)host 发送 CMD6 切换设备的操作模式或者修改EXT_CSD寄存器,SWITCH命令可以用来写EXT_CSD或者改变命令集。如果SWITCH命令用来改变命令集,那么Index和Value被忽略不会修改EXT_CSD; 如果SWITCH用来写EXT_CSD寄存器,Cmd Set被忽略。
参数
[31:26] Set to 0
[25:24] Access, 00 切换command set; 01 设置Value中指定的位; 10 清除Value中指定的位; 11 写入Value指定的值。
[23:16] Index, EXT_CSD的索引值,index值为0~255,但是仅仅0~191为有效索引值。
[15:8] Value,
[7:3] Set to 0
[2:0] Cmd Set ,要切换的command set
command . index = CMD6 /*!< Switch */
command . argument = 0x3b70100U //参数
command . responseType = uSDHC_RESPONSE_TYPE_R1b
(4)在非高速模式下设置设置 uSDHC最大频率为 52MHZ。参见(1)的设置方法。
(5)设置uSDHC的数据总线模式为4位。
uSDHC_PROT_CTRL [DTW] = 0x01