基于TMS320F28335的SPI接口读取SD卡文件数据
一、硬件连接配置
TMS320F28335 SD卡模块
-------------------------
SPISTE (GPIO34) → CS
SPISIMO (GPIO32) → SCLK
SPICLKO (GPIO33) → MOSI
SPISOMI (GPIO31) → MISO
GND → GND
3.3V → VDD
关键配置说明:
- 使用SPI-A模块,配置为4线主模式
- SPI时钟初始频率设置为1MHz(初始化阶段)
- 数据格式:MSB优先,时钟极性CPOL=0,相位CPHA=0
- 启用硬件CRC校验(需根据SD卡版本选择)
二、SPI驱动初始化
#include "DSP28x_Project.h"
#define SPI_BASE_ADDR 0x00007000 // SPI-A基地址
#define SD_CS_ASSERT() GpioDataRegs.GPACLEAR.bit.GPIO34 = 1
#define SD_CS_DEASSERT() GpioDataRegs.GPASET.bit.GPIO34 = 1
void SPI_Init() {
// 1. 使能SPI时钟
EALLOW;
SysCtrlRegs.PCLKCR3.bit.SPIAENCLK = 1;
EDIS;
// 2. 配置SPI模式
SpiaRegs.SPICCR.all = 0x0007; // 16位字符长度,时钟停止时保持高电平
SpiaRegs.SPICTL.all = 0x0006; // 主模式,使能时钟,中断禁用
SpiaRegs.SPIBRR = 0x000F; // 分频系数=16 (100MHz/16=6.25MHz)
SpiaRegs.SPICR2.bit.CLK_PHASE = 0; // CPOL=0, CPHA=0
SpiaRegs.SPICR1.bit.SPI_INT_ENA = 0;
// 3. 引脚配置
EALLOW;
GpioCtrlRegs.GPADIR.bit.GPIO34 = 1; // CS设为输出
GpioCtrlRegs.GPADIR.bit.GPIO32 = 1; // SCLK设为输出
GpioCtrlRegs.GPADIR.bit.GPIO33 = 1; // MOSI设为输出
GpioCtrlRegs.GPAINPUTEN.bit.GPIO31 = 0; // MISO设为输入
EDIS;
}
三、SD卡初始化流程
#define CMD0 0x40 // GO_IDLE_STATE
#define CMD8 0x48 // SEND_IF_COND
#define ACMD41 0x60 // SEND_OP_COND (with CMD55 prefix)
#define CMD16 0x50 // SET_BLOCKLEN
Uint16 SD_Init() {
Uint16 r1;
// 1. 硬件复位
SD_CS_ASSERT();
SPI_WriteCmd(CMD0, 0, 0x95); // 发送CMD0,CRC=0x95
while(SpiaRegs.SPISTS.bit.RXFULL == 0); // 等待接收完成
r1 = SpiaRegs.SPIRXBUF >> 8; // 读取R1响应
// 2. 发送ACMD41(带CMD55前缀)
SD_CS_DEASSERT();
DELAY_US(1000); // 等待卡上电
for(int i=0; i<1000; i++) {
SD_CS_ASSERT();
SPI_WriteCmd(CMD55, 0, 0x65); // CMD55前缀
r1 = SpiaRegs.SPIRXBUF >> 8;
if(r1 == 0x01) { // 支持应用命令
SPI_WriteCmd(ACMD41, 0x40000000, 0xE5); // HCS=1
r1 = SpiaRegs.SPIRXBUF >> 8;
if(r1 == 0x00) break; // 初始化完成
}
SD_CS_DEASSERT();
DELAY_MS(1);
}
// 3. 设置块大小为512字节
SD_CS_ASSERT();
SPI_WriteCmd(CMD16, 512, 0x15); // CRC=0x15
r1 = SpiaRegs.SPIRXBUF >> 8;
SD_CS_DEASSERT();
return (r1 == 0x00) ? 1 : 0;
}
四、文件系统解析与数据读取
#include "fatfs.h" // 需集成FatFs文件系统库
FATFS fs; // 文件系统对象
FIL fil; // 文件对象
UINT bytesRead; // 实际读取字节数
void Read_SD_File(char *filename) {
FRESULT fr;
// 1. 挂载文件系统
fr = f_mount(&fs, "", 1);
if(fr != FR_OK) {
printf("文件系统挂载失败: 0x%02X\n", fr);
return;
}
// 2. 打开文件
fr = f_open(&fil, filename, FA_READ);
if(fr != FR_OK) {
printf("文件打开失败: 0x%02X\n", fr);
f_mount(NULL, "", 0);
return;
}
// 3. 读取数据
char buffer[512];
while(1) {
fr = f_read(&fil, buffer, sizeof(buffer), &bytesRead);
if(fr != FR_OK || bytesRead == 0) break;
// 处理数据(示例:通过UART输出)
UART_WriteBuffer(buffer, bytesRead);
}
// 4. 关闭文件并卸载
f_close(&fil);
f_mount(NULL, "", 0);
}
五、SPI数据传输实现
void SPI_WriteCmd(Uint16 cmd, Uint32 arg, Uint8 crc) {
SD_CS_ASSERT();
// 发送命令头
SpiaRegs.SPITXBUF = 0x40 | (cmd & 0x3F); // 起始位+命令索引
while(SpiaRegs.SPISTS.bit.TXEMPTY == 0); // 等待发送完成
// 发送参数(4字节)
SpiaRegs.SPITXBUF = (arg >> 24) & 0xFF;
SpiaRegs.SPITXBUF = (arg >> 16) & 0xFF;
SpiaRegs.SPITXBUF = (arg >> 8) & 0xFF;
SpiaRegs.SPITXBUF = arg & 0xFF;
// 发送CRC
SpiaRegs.SPITXBUF = crc;
while(SpiaRegs.SPISTS.bit.TXEMPTY == 0);
// 等待响应(最大8次重试)
for(int i=0; i<10; i++) {
if(SpiaRegs.SPISTS.bit.RXFULL) {
r1 = SpiaRegs.SPIRXBUF >> 8;
if((r1 & 0x80) == 0) break; // 响应有效
}
}
SD_CS_DEASSERT();
}
参考代码 利用TMS320F28335的SPI口读取SD卡中的文件数据 www.youwenfan.com/contentcsr/56772.html
六、参考资料与工具
-
必备文档:
- TMS320F28335数据手册(SPRS667)
- SD卡物理层规范(SD 3.01)
- FatFs文件系统源码(FatFs_0.14c)
-
调试工具:
- 逻辑分析仪:Saleae Logic Pro 8
- 协议分析仪:Total Phase Aardvark
- 性能分析:CCS Profiler