在嵌入式系统开发中,外扩存储设备是常见需求。SPI(Serial Peripheral Interface)因其接口简单、速率适中且支持全双工通信,成为连接存储设备的理想选择。本文将基于ARM Cortex-M Prototyping System (MPS2+)开发平台,详细解析如何通过SPI接口实现uSD卡的读写控制。
MPS2+开发板搭载的PL022 PrimeCell SPI控制器是ARM提供的标准IP核,支持以下关键特性:
uSD卡适配板作为转接模块,主要完成三项功能:
注意:虽然uSD卡支持SPI模式,但并非所有操作命令都与原生SD模式相同。SPI模式下仅支持部分基础命令集,且初始化流程存在差异。
拆除原有支架:
安装金属支架:
连接适配板:
插入uSD卡:
安装完成后建议进行以下信号检测:
常见问题:若出现通信失败,首先检查nSS信号是否正常拉低。SPI模式下uSD卡需要保持nSS持续有效,这与常规SPI外设操作不同。
uSD卡在SPI模式下工作时有以下特殊要求:
命令格式:
响应类型:
数据令牌:
通过ARM MBED API配置SPI接口时需注意:
cpp复制SPI spi(J22_2, J22_3, J22_6); // mosi, miso, sclk
DigitalOut cs(J22_4); // nSS
void spi_init() {
spi.format(8, 1); // 8位数据,模式1(CPOL=0, CPHA=1)
spi.frequency(25000000); // 25MHz时钟(需确认uSD卡支持)
cs = 1; // 初始时保持片选无效
}
关键参数说明:
实测中发现以下时序优化可提升稳定性:
典型写操作时序示例:
code复制[命令] -> [等待响应] -> [发送0xFF] -> [发送数据令牌0xFE]
-> [发送512字节数据] -> [发送2字节CRC] -> [等待忙状态结束]
完整的uSD卡SPI模式初始化包含以下步骤:
硬件复位:
发送CMD0:
c复制uint8_t cmd0[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95};
spi_write(cmd0, 6);
uint8_t resp = wait_response();
电压检查(CMD8):
初始化流程(ACMD41):
c复制do {
send_cmd(55, 0); // APP_CMD前缀
send_cmd(41, 0x400000); // HCS=1表示支持高容量卡
resp = wait_response();
} while(resp == 0x01); // 等待退出空闲状态
cpp复制int read_block(uint32_t addr, uint8_t *buf) {
uint8_t cmd[] = {0x51, (addr>>24)&0xFF, (addr>>16)&0xFF,
(addr>>8)&0xFF, addr&0xFF, 0xFF};
cs = 0;
spi_write(cmd, 6);
if(wait_response() != 0x00) {
cs = 1;
return -1;
}
while(spi_read() != 0xFE); // 等待数据令牌
spi_read(buf, 512); // 读取数据
spi_read(); spi_read(); // 丢弃CRC
cs = 1;
return 0;
}
多块写入需特别注意:
常见故障现象及解决方法:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无响应 | 电源异常 | 测量3.3V电源纹波(<50mV) |
| 响应超时 | 时钟频率过高 | 初始化阶段降至100kHz |
| CRC错误 | 信号干扰 | 缩短走线长度,增加上拉电阻 |
| 数据错位 | 模式不匹配 | 确认CPHA与卡规格一致 |
| 写保护 | 写锁开关 | 检查适配板WP引脚电平 |
经验分享:使用逻辑分析仪抓取SPI信号时,建议同时监测nSS、SCK、MOSI、MISO四路信号。异常情况下首先检查nSS信号是否符合"命令阶段拉低,数据阶段保持低"的特性。
对于Cortex-M3/M4内核,可通过DMA提升吞吐量:
配置PL022的DMA接口:
c复制PL022->DMACR = 0x3; // 启用TX/RX DMA
设置DMA控制器:
c复制DMA_Config(SPI_TX_CH, &PL022->DR, buffer, length, DMA_MEM_TO_PERIPH);
DMA_Config(SPI_RX_CH, &PL022->DR, buffer, length, DMA_PERIPH_TO_MEM);
传输完成中断处理:
c复制void DMA_IRQHandler() {
if(DMA_GetFlag(SPI_TX_CH)) {
// 处理发送完成
}
if(DMA_GetFlag(SPI_RX_CH)) {
// 处理接收完成
}
}
实测表明,DMA方式可使连续读写速度提升40%以上。
在MBED OS中集成FAT文件系统的关键步骤:
实现底层磁盘接口:
cpp复制DSTATUS disk_initialize() {
return sd_init() ? 0 : STA_NOINIT;
}
DRESULT disk_read(BYTE *buff, LBA_t sector, UINT count) {
for(int i=0; i<count; i++) {
if(read_block(sector+i, buff+i*512) != 0)
return RES_ERROR;
}
return RES_OK;
}
挂载文件系统:
cpp复制FATFS fs;
f_mount(&fs, "", 0);
性能优化建议:
针对低功耗应用的优化方案:
动态时钟调整:
智能轮询机制:
c复制while(sd_check_status() == BUSY) {
enter_low_power();
delay_ms(10);
}
掉电保护设计:
通过上述优化,待机功耗可降至50μA以下,同时保证数据完整性。