📄 spi_sd.c
字号:
#include <p33FJ64GP306.h>
#include "delay.h"
#include "SPI_SD.h"
// This source handles SPI, and SD Card Command level.
// File structure is managed by upper layer.
BYTE temp;
void init_SPI(void)
{
PORTGbits.RG9 = 1;
TRISGbits.TRISG9 = 0;
// setup the SPI peripheral
SPI2STAT = 0x0; // disable the SPI module (just in case)
SPI2CON1 = 0x013E;
// bit 12 DISSCK = 0. SCK enabled.
// bit 11 DISSDO = 0. SDO enabled.
// bit 10 MODE16 = 0. Byte(8bit) Mode.
// bit 9 SMP = 0. input sampled at middle of data output time.
// bit 8 CKE = 1. SPI Clock Edge is active to idle.
// bit 7 SSEN = 0. slave select is disabled.(master mode)
// bit 6 CKP = 0. Clock Polarity is, High/Active, Low/Idle.
// bit 5 MSTEN = 1. Master Mode.
// bit 4-2 SPRE=111. Second Prescale bit = 1:1.
// bit 1-0 PPRE=10. Primary Prescale = 4:1.
// SCK = Fcy 33.864MHz / 4 / 1 = 8.47MHz
SPI2STAT = 0x8000; // enable the SPI module
//Wait SD Card
Delay_Us(10);
SD_CLK();
Delay_Us(10);
}
//send CLOCK for SD card, let it sample clock
void SD_CLK(void)
{
int i;
BYTE ret;
PORTGbits.RG9 = 1;
Delay8Tcy();
for (i = 0; i < 100; i++)
{
ret = SPI_read(0);
}
PORTGbits.RG9 = 1;
}
BYTE SD_InitializeCard(void)
{
BYTE stat;
DWORD Count;
Count = 0;
PORTGbits.RG9 = 0;
Delay8Tcy();
// index 0: GO_IDLE_STATE command
stat = SD_CardCommand(0, 0);
// repeat until get 0x01 (In Idle State) answer.
while( (stat != 1) && (stat != 0xFF) )
{
stat = SD_CardCommand(0, 0);
Count++;
if ( Count > 8000)
{
return 1; //failed
}
}
// index 1: SEND_OP_COMMAND, card initializing
// repeat until get 0x00 (In Idle State bit cleared).
while ( stat == 1 )
{
Delay_Us(1);
stat = SD_CardCommand(1, 0);
}
PORTGbits.RG9 = 1;
return 0;
}
BYTE SD_Read_Single_Block(LONG Address, BYTE * Buffer)
{
BYTE stat;
BYTE ret;
int i;
stat = 0;
ret = 0;
PORTGbits.RG9 = 0;
//Send command (single read) and wait response
stat = SD_Read_Single_Block_Phase1(Address);
if (stat == 0)
{
//store return value to buffer
for(i = 0; i < 512; i++)
{
*Buffer = SPI_read(0);
Buffer++;
}
ret = 0;
stat = SPI_read(0);
stat = SPI_read(0);
//Check transaction finished
for (i = 0; i < 800; i++)
{
stat = SPI_read(0);
if (stat == 0xFF) break;
}
}
else
{ ret = 1; }
return ret;
}
BYTE SD_Read_Single_Block_Phase1(LONG Address)
{
int RetryCount;
BYTE ret;
int i;
ret = 0;
for (RetryCount = 0; RetryCount < 100; RetryCount++)
{
ret = SD_CardCommand(17,Address);
if (ret == 0)
{
//Not ready. wait for Data token.
for (i = 0; i < 5000; i++)
{
ret = SPI_read(0);
if (ret == 0xFE) return 0; //got token
}
}
else if (ret == 0xFE)
{
//Got Token.
return 0;
}
}
return 1; // can not opened.
}
// Initialize SD Card to SPI Mode
BYTE SD_CardCommand(BYTE cmd, LONG Argument)
{
BYTE ret;
int i;
//Confirm card nop, before send command
// if no command sent, should return 0xFF.
for (i = 0; i < 800; i++)
{
ret = SPI_read(0);
if (ret == 0xFF)
{
break;
}
}
// failed. upper layer will handle.
if (ret != 0xFF) return 1;
// SD Card Command
SPI_write(0x40 | cmd,0); //command, 0x40 + index
SPI_write((Argument >> 24) & 0xFF,0); //Argument 0
SPI_write((Argument >> 16) & 0xFF,0); //Argument 1
SPI_write((Argument >> 8) & 0xFF,0); //Argument 2
SPI_write((Argument ) & 0xFF,0); //Argument 3
SPI_write(0x95,0); //CRC for GO_STATE_IDLE only. others, don't care
// Some command take long time to answer.
for (i = 0; i < 512; i++)
{
ret = SPI_read(0);
if (ret == 0xFE)
{
break; //data token
}
if ( (ret & 0x80) == 0x00 )
{
break; //got response
}
}
return ret;
}
void SPI_write(BYTE data, BYTE flag)
// data: to send. flag(SS): not used.
{
temp = SPI2BUF; // dummy read of the SPI1BUF register
// to clear the SPIRBF flag
SPI2BUF = data; // write the data out to the SPI peripheral
while(!SPI2STATbits.SPIRBF)
{
Nop();
}
}
BYTE SPI_read(BYTE flag)
// retrun: read value. flag(SS): not used.
{
temp = SPI2BUF; // dummy read of the SPI1BUF register
// to clear the SPIRBF flag
SPI2BUF = 0xFF; // write the data out to the SPI peripheral
while(!SPI2STATbits.SPIRBF)
{
Nop();
}
temp = 0xFF & SPI2BUF; // read result
return temp;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -