以下是针对 NUC505DL13Y(Nuvoton Cortex-M4 微控制器)驱动 SD NAND(SPI 模式) 的硬件接线指南与软件代码框架。请根据实际需求调整。
SD NAND 通常支持 SPI 接口,以下是 NUC505DL13Y 与 SD NAND 的典型连接方式:
SD NAND 引脚 | NUC505DL13Y 引脚 | 说明 |
---|---|---|
CS (片选) | GPIO (如 P2.0) | 自定义片选引脚 |
SCK (时钟) | SPI0_CLK (如 P3.0) | SPI 时钟线 |
MOSI (主机输出) | SPI0_MOSI (如 P3.1) | 主设备输出,从设备输入 |
MISO (主机输入) | SPI0_MISO (如 P3.2) | 主设备输入,从设备输出 |
VCC | 3.3V | 电源(注意电平匹配!) |
GND | GND | 地线 |
注意事项:
电平匹配:NUC505DL13Y 是 3.3V 供电,可直接连接 SD NAND(无需电平转换)。
上拉电阻:建议在 MISO
、MOSI
、SCK
线上加 10kΩ 上拉电阻。
电源滤波:在 SD NAND 的 VCC 和 GND 之间添加 0.1μF 电容。
使用 Nuvoton 标准外设库 (BSP),需提前安装:
SPI 驱动库
GPIO 配置库
#include "NUC505Series.h"#include "spi.h"#include "gpio.h"// 定义 SPI 和 GPIO#define SD_CS_PIN P2_0 // 片选引脚// SD 命令定义#define CMD0 0x40+0 // GO_IDLE_STATE#define CMD8 0x40+8 // SEND_IF_COND#define CMD55 0x40+55 // APP_CMD#define ACMD41 0x40+41 // SD_SEND_OP_COND#define CMD17 0x40+17 // READ_SINGLE_BLOCK#define CMD24 0x40+24 // WRITE_BLOCK// 函数声明void SPI_Init(void);void SD_CS(uint8_t state);uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc);uint8_t SD_Init(void);uint8_t SD_ReadBlock(uint32_t blockAddr, uint8_t *buffer);uint8_t SD_WriteBlock(uint32_t blockAddr, uint8_t *buffer);// 初始化 SPIvoid SPI_Init(void) {
SPI_Open(SPI0, SPI_MASTER, SPI_MODE_0, 8, 100000); // 低速初始化(100kHz)
GPIO_SetMode(P2, BIT0, GPIO_MODE_OUTPUT); // 配置 CS 为输出
SD_CS(1); // 初始时取消片选}// 片选控制void SD_CS(uint8_t state) {
P20 = (state) ? 1 : 0;}// SPI 传输单字节uint8_t SPI_Transfer(uint8_t data) {
SPI_WRITE_TX0(SPI0, data);
SPI_TRIGGER(SPI0);
while(SPI_IS_BUSY(SPI0)); // 等待传输完成
return SPI_READ_RX0(SPI0);}// 发送 SD 命令uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc) {
uint8_t res, retry = 0;
SD_CS(0); // 使能片选
SPI_Transfer(0xFF); // 发送 8 个时钟
// 发送命令头
SPI_Transfer(cmd);
SPI_Transfer((arg >> 24) & 0xFF);
SPI_Transfer((arg >> 16) & 0xFF);
SPI_Transfer((arg >> 8) & 0xFF);
SPI_Transfer(arg & 0xFF);
SPI_Transfer(crc);
// 等待响应(超时重试)
for (retry = 0; retry < 10; retry++) {
res = SPI_Transfer(0xFF);
if ((res & 0x80) == 0) break;
}
return res;}// SD 卡初始化uint8_t SD_Init(void) {
uint8_t res, retry = 0;
// 发送至少 74 个时钟脉冲
SD_CS(1);
for (int i = 0; i < 10; i++) SPI_Transfer(0xFF);
// 发送 CMD0 复位
do {
res = SD_SendCmd(CMD0, 0, 0x95);
if (retry++ > 10) return 0xFF; // 超时失败
} while (res != 0x01);
// 发送 CMD8 检查电压
res = SD_SendCmd(CMD8, 0x1AA, 0x87);
if (res == 0x01) {
// 处理 SD V2.0+ 初始化流程
// ...
}
// 发送 ACMD41 初始化
do {
SD_SendCmd(CMD55, 0, 0x01);
res = SD_SendCmd(ACMD41, 0x40000000, 0x01); // HCS=1
if (retry++ > 100) return 0xFF;
} while (res != 0x00);
// 设置块长度为 512 字节
SD_SendCmd(16, 512, 0x01);
// 切换 SPI 到高速模式(例如 10MHz)
SPI_Close(SPI0);
SPI_Open(SPI0, SPI_MASTER, SPI_MODE_0, 8, 10000000);
return 0; // 初始化成功}// 读取单个块(512 字节)uint8_t SD_ReadBlock(uint32_t blockAddr, uint8_t *buffer) {
uint8_t res;
res = SD_SendCmd(CMD17, blockAddr, 0x01); // SDSC 卡使用字节地址,SDHC 卡用块地址
if (res != 0x00) return res;
// 等待数据令牌 0xFE
uint16_t retry = 0;
while (SPI_Transfer(0xFF) != 0xFE) {
if (retry++ > 0xFFF) return 0xFF;
}
// 读取 512 字节
for (uint16_t i = 0; i < 512; i++) {
buffer[i] = SPI_Transfer(0xFF);
}
// 丢弃 CRC
SPI_Transfer(0xFF);
SPI_Transfer(0xFF);
SD_CS(1);
return 0;}// 主函数示例int main(void) {
SYS_Init(); // NUC505 系统初始化
SPI_Init();
uint8_t status = SD_Init();
uint8_t buffer[512];
if (status == 0) {
SD_ReadBlock(0, buffer); // 读取第 0 块
}
while(1);}
时序调整:
初始化阶段使用 低速 SPI(如 100kHz),初始化完成后可切换到更高频率(如 10MHz)。
部分 SD NAND 需要更严格的时序,需根据数据手册调整延时。
SD 卡类型处理:
SDSC(标准容量卡):使用 字节地址。
SDHC/SDXC(高容量卡):使用 块地址(直接传递参数)。
错误处理:
所有读写操作需添加重试机制。
检查 SD_SendCmd
的返回值,确保命令执行成功。
文件系统集成:
可结合 FatFS 等文件系统库实现 FAT32/exFAT 读写。
使用逻辑分析仪抓取 SPI 波形,验证命令和数据传输。
通过 LED 或串口打印调试信息(如初始化状态、错误码)。
参考 SD 卡物理层规范文档 (SD Association)。