MMC

该示例演示了如何使用SD library实现芯片与 MMC 读、写的应用。

示例中初始化了存储卡,并执行了基本操作,如向存储卡写入数据,然后读取数据并检查数据是否一致。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL87x2G HDK

RTL87x2G EVB

更多信息请参考快速入门

硬件连线

MMC子板及接线,参考Model B评估板WiFi和SD Nand Flash复用接口

MMC接口引脚如下表:

MMC接口引脚

引脚名称

PIN

含义

DAT3 / CS

P9_5

数据线3

CMD / DI

P9_3

命令响应线

VSS1

GND

GND

VDD

VCC(3.3V)

3.3V供电

CLK

P9_4

时钟

VSS2

GND

GND

DAT0 / DO

P10_0

数据线0

DAT1

P9_7

数据线1

DAT2

P9_6

数据线2

编译和下载

该示例的工程路径如下:

Project file: samples\sd\mmc\proj\mdk

Project file: samples\sd\mmc\proj\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MPTool 给出的步骤将app bin烧录至EVB内。

  5. 按下复位按键,开始运行。

测试验证

  1. 当EVB启动后,在DebugAnalyzer工具内观察MMC初始化的状态,认卡成功则打印状态: Init: 0

    Init: 0
    
  2. 将准备好的数据(前30 block数据为0xff,后30 block数据为0x00)写到MMC中,写成功则打印状态: Write: 0

    Write: 0
    
  3. 读MMC数据,读成功则打印状态: Read: 0,同时打印读到的数据。

    Read: 0
    
    Block 0: 0x0000 -> 0xFF - 0xFF - 0xFF - 0xFF --- 0xFF - 0xFF - 0xFF - 0xFF
    ...
    Block 30: 0x0000 -> 0x00 - 0x00 - 0x00 - 0x00 --- 0x00 - 0x00 - 0x00 - 0x00
    ...
    
  4. 检查读写数据是否一致,如果不一致会打印错误数据,例如:第1 block第 100 个数据错误数据为0x33打印如下:

    Block 0: 0xA0 -> 0x33 data error
    

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\samples\sd\mmc\proj

  • 源码路径: sdk\samples\sd\mmc\src

该工程的工程文件代码结构如下:

└── Project: mmc
    └── secure_only_app
        └── Device                   includes startup code
            ├── startup_rtl.c
            └── system_rtl.c
        ├── CMSIS                    includes CMSIS header files
        ├── CMSE Library             Non-secure callable lib
        ├── lib                      includes all binary symbol files that user application is built on
            ├── sd.lib
            └── rtl87x2g_io.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl_rcc.c
            ├── rtl_pinmux.c
            ├── io_dlps.c
            └── rtl_nvic.c
        └── APP                      includes the ble_peripheral user application implementation
            ├── main_ns.c
            ├── app_task.c
            └── sd_test.c

初始化

  1. 设置初始化参数。

    1. 设置Card类型为EMMC。

    2. 设置数据宽度为4BIT。

    3. 设置时钟输出频率为52MHz。

static const SdEmmcInitParm_t Parm =
{
  .CardType = CARDTYPE_EMMC,
  .DataWidth = DATAWIDTH_4BIT,
  .ClkOutFreq_kHz = 52 * 1000,
};
...

功能实现

  1. 执行 Emmc_Init ,对MMC初始化。

  2. 执行 os_mem_alloc 申请内存pBuf。

  3. 准备好数据(前30 block数据为0xff,后30 block数据为0x00),执行 Emmc_Write 函数,将pBuf数据写入MMC中。

  4. 将pBuf数据预填为0x77,执行 Emmc_Read 函数,读取数据到pBuf内。

  5. 打印读取的数据,同时检查读写数据是否一致,如果不一致会打印错误数据。

  6. 执行 os_mem_free 释放内存pBuf。

SdEmmcRes_t Res = Init(SD_Demo, &Parm);

uint8_t *pBuf = os_mem_alloc(RAM_TYPE_EXT_DATA_SRAM, BUF_BYTES);
memset(pBuf, 0xff, BUF_BYTES / 2);
memset(pBuf + BUF_BYTES / 2, 0, BUF_BYTES / 2);
Res = Write(SD_Demo, START_BLOCK, BLOCK_CNT, pBuf);

memset(pBuf, 0x77, BUF_BYTES);
Res = Read(SD_Demo, START_BLOCK, BLOCK_CNT, pBuf);

/* Print all read data */
for (size_t i = 0; i < BUF_BYTES; i += 8)
{
    DBG_DIRECT("Block %d: 0x%04x -> 0x%02x - 0x%02x - 0x%02x - 0x%02x --- 0x%02x - 0x%02x - 0x%02x - 0x%02x",
               i / 512, i % 512,
               pBuf[i], pBuf[i + 1], pBuf[i + 2], pBuf[i + 3],
               pBuf[i + 4], pBuf[i + 5], pBuf[i + 6], pBuf[i + 7]);
}

/* Compare whether the read data is correct from write data */
for (uint32_t j = 0; j < BUF_BYTES; j++)
{
    if (((j < BUF_BYTES / 2) && ((pBuf[j] != 0xff))) ||
        ((j >= BUF_BYTES / 2) && (j < BUF_BYTES) && (pBuf[j] != 0x00)))
    {
        DBG_DIRECT("Block %d: 0x%04x -> 0x%02x data error", j / 512, j % 512, pBuf[j]);
        if (pBuf[j] == 0x77) { break; }
    }
}

os_mem_free(pBuf);