/*------------------------- 硬件配置 -------------------------*/
#include <xc.h>
#include <stdint.h>
#pragma config FNOSC = FRCPLL // 使用FRC振荡器+PLL
// SPI引脚配置(使用RP引脚重映射)
#define SD_CS _LATB9 // CS: RB9
#define SD_CS_TRIS _TRISB9
#define SPI_MOSI _RP10R = 0b0011 // SDO1映射到RP10
#define SPI_MISO 11 // SDI1使用RP11
#define SPI_SCK _RP9R = 0b0011 // SCK1映射到RP9
/*------------------------- SD驱动层 -------------------------*/
#define CMD0 0x40
#define CMD8 0x48
#define ACMD41 0x69
#define CMD16 0x50
#define CMD17 0x51
#define CMD24 0x58
uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg) {
SPI1_Transfer(cmd);
SPI1_Transfer(arg >> 24);
SPI1_Transfer(arg >> 16);
SPI1_Transfer(arg >> 8);
SPI1_Transfer(arg);
SPI1_Transfer((cmd == CMD0) ? 0x95 : (cmd == CMD8) ? 0x87 : 0x01);
for(uint8_t retry=0; retry<10; retry++) {
uint8_t res = SPI1_Transfer(0xFF);
if((res & 0x80) == 0) return res;
}
return 0xFF;
}
uint8_t SD_Init(void) {
SD_CS_TRIS = 0; // 配置CS为输出
SD_CS = 1; // CS置高
// SPI初始化(主模式,8MHz)
SPI1CON1 = 0;
SPI1CON1bits.MSTEN = 1; // 主模式
SPI1CON1bits.MODE16 = 0; // 8位模式
SPI1CON1bits.PPRE = 3; // 预分频 1:1
SPI1CON1bits.SPRE = 6; // 主分频 1:2
SPI1STATbits.SPIEN = 1; // 使能SPI
// 发送至少74个时钟脉冲
for(uint8_t i=0; i<10; i++) SPI1_Transfer(0xFF);
// CMD0复位
if(SD_SendCmd(CMD0, 0) != 0x01) return 1;
// 初始化流程(支持SDv2)
uint8_t resp = SD_SendCmd(CMD8, 0x1AA);
if(resp == 0x01) {
for(uint8_t i=0; i<4; i++) SPI1_Transfer(0xFF); // 丢弃响应
do {
resp = SD_SendCmd(ACMD41, 0x40000000);
} while(resp != 0x00);
} else return 2;
// 设置块长度(512字节)
if(SD_SendCmd(CMD16, 512) != 0x00) return 3;
return 0;
}
/*------------------------- FatFs集成 ------------------------*/
#include "ff.h" // FatFs R0.15
DSTATUS disk_initialize (BYTE pdrv) {
return (SD_Init() == 0) ? 0 : STA_NOINIT;
}
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count) {
SD_CS = 0;
for(UINT i=0; i<count; i++) {
if(SD_SendCmd(CMD17, sector+i) != 0x00) {
SD_CS = 1;
return RES_ERROR;
}
while(SPI1_Transfer(0xFF) != 0xFE); // 等待数据令牌
for(uint16_t j=0; j<512; j++) buff[j] = SPI1_Transfer(0xFF);
SPI1_Transfer(0xFF); // 丢弃CRC
SPI1_Transfer(0xFF);
}
SD_CS = 1;
return RES_OK;
}
/*------------------------- 使用示例 ------------------------*/
void main(void) {
FATFS fs;
FIL fil;
if(f_mount(&fs, "", 1) == FR_OK) {
f_open(&fil, "test.txt", FA_WRITE | FA_CREATE_ALWAYS);
f_printf(&fil, "PIC24 SD Card Test @2025");
f_close(&fil);
}
while(1);
}
// SPI数据传输函数(必须内联优化)
static inline uint8_t SPI1_Transfer(uint8_t data) {
SPI1BUF = data;
while(!SPI1STATbits.SPIRBF);
return SPI1BUF;
}
|