基于nrf51822 SDK10的蓝牙串口工程 ,增加SPI的资源文件到工程,定义SPI0使能,以及定义IO口,和CS引脚电平,新建drv_sd_api.c文件如下即可在主函数调用接口函数对SD卡进行操作,此接口函数是官方提供的一个我只是修改一下,使用前对SD卡的指令以及一些注意事项说明如下:
SD卡的命令格式如下,6字节共48位,传输时最高位(MSB)先传输:
SD卡的command(命令)占6 bit,一般叫CMDx或ACMDx,比如CMD1就是1,CMD13就是13,ACMD41就是41,依此类推。Command Argument(命令参数)占4 byte,并不是所有命令都有参数,没有参数的话该位一般就用置0。最后一个字节由7 bit CRC校验位和1 bit停止位组成。在SPI模式下,CRC是被忽略的,可以都置1或置0.但是发送CMD0时要记得加上CRC,即最后1字节为0x95,因为发送CMD0时还未进入SPI模式。
关于SD卡SPI和command的发送要注意以下几点:
1.SD卡的SPI总线,在读入数据时SD卡的SPI是CLK的上升沿输入锁存,输出数据也是在上升沿。
2.向SD卡写入一个CMD或者ACMD指令的过程是这样的: 首先使CS为低电平,SD卡使能;其次在SD卡的Din写入指令;写入指令后还要附加8个填充时钟,是SD卡完成内部操作;之后在SD卡的Dout上接受回应;回应接受完毕使CS为低电平,再附加8个填充时钟。
#include "nrf_gpio.h"
#include "nrf_drv_spi.h"
#include "nrf_drv_common.h"
#include "nrf_assert.h"
#include "app_util_platform.h"
#include "bsp.h"
#include "app_trace.h"
#include "string.h"
#define TX_RX_MSG_LENGTH 100
#define GO_IDLE_STATE 0
#define SEND_OP_COND 1
#define SEND_CSD 9
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define SET_BLOCK_LEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCKS 18
#define WRITE_SINGLE_BLOCK 24
#define WRITE_MULTIPLE_BLOCKS 25
#define ERASE_BLOCK_START_ADDR 32
#define ERASE_BLOCK_END_ADDR 33
#define ERASE_SELECTED_BLOCKS 38
#define CRC_ON_OFF 59
#define MMCSD_PIN_SELECT 30
#define ON 1
#define OFF 0
uint8_t sd_cmd1[9] = {0xFF,0x40,0x00,0x00,0x00,0x00,0x95,0xFF,0xFF};
uint8_t sd_cmd2[13] = {0xFF,0x48,0x00,0x00,0x01,0xAA,0x87,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
uint8_t sd_cmd3[8] = {0xFF,0x77,0x00,0x00,0x00,0x00,0xFF,0xFF};
uint8_t sd_cmd4[9] = {0xFF,0x69,0x40,0x00,0x00,0x00,0xFF,0xFF,0xFF};
uint8_t sd_cmd5[10] = {0xFF,0x7A,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF};
uint32_t *SDCard_spi;
uint32_t startBlock;
uint32_t totalBlocks;
#if (SPI0_ENABLED == 1)
static const nrf_drv_spi_t m_spi_master_0 = NRF_DRV_SPI_INSTANCE(0);
#endif
static void spi_master_init(nrf_drv_spi_t const * p_instance, bool lsb)
{
uint32_t err_code = NRF_SUCCESS;
nrf_drv_spi_config_t config =
{
.ss_pin = NRF_DRV_SPI_PIN_NOT_USED,
.irq_priority = APP_IRQ_PRIORITY_LOW,
.orc = 0xCC,
.frequency = NRF_DRV_SPI_FREQ_500K,
.mode = NRF_DRV_SPI_MODE_0,
.bit_order = (lsb ?
NRF_DRV_SPI_BIT_ORDER_LSB_FIRST : NRF_DRV_SPI_BIT_ORDER_MSB_FIRST),
};
#if (SPI0_ENABLED == 1)
if (p_instance == &m_spi_master_0)
{
config.sck_pin = SPIM0_SCK_PIN;
config.mosi_pin = SPIM0_MOSI_PIN;
config.miso_pin = SPIM0_MISO_PIN;
err_code = nrf_drv_spi_init(p_instance, &config,
NULL);
}
else
#endif // (SPI0_ENABLED == 1)
APP_ERROR_CHECK(err_code);
}
static void spi_send_recv(nrf_drv_spi_t const * p_instance,
uint8_t * p_tx_data,
uint8_t * p_rx_data,
uint16_t len)
{
// // Initalize buffers.
// init_buf(p_tx_data, p_rx_data, len);
uint32_t err_code = nrf_drv_spi_transfer(p_instance,
p_tx_data, len, p_rx_data, len);
APP_ERROR_CHECK(err_code);
}
uint8_t spi_xfer(uint8_t data)
{
uint8_t spi_txbuf[1];
uint8_t spi_rxbuf[1];
spi_txbuf[0]=data;
spi_send_recv(&m_spi_master_0 , spi_txbuf, spi_rxbuf,1);
return spi_rxbuf[0];
}
void mmcsd_select()
{
nrf_gpio_pin_clear(MMCSD_PIN_SELECT);
}
void mmcsd_deselect()
{
nrf_gpio_pin_set(MMCSD_PIN_SELECT);
spi_xfer( 0xFF);
}
uint8_t send_spi(uint8_t spi_msg)
{
static uint8_t spi_rcv;
spi_rcv=spi_xfer( spi_msg);
return spi_rcv;
}
uint8_t Send_Command(uint8_t cmd[], uint8_t size)
{
static uint8_t p;
static uint8_t resp;
//mmcsd_select();
for(p=0;p>24);
spi_xfer(arg>>16);
spi_xfer(arg>>8);
spi_xfer(arg);
spi_xfer(0x95);
while((response = spi_xfer(0xFF)) == 0xff) //wait response
if(retry++ > 0xfe) break; //time out error
return response; //return state
}
uint8_t SD_init(void)
{
uint8_t i, response, retry=0 ;
mmcsd_deselect();
for(i=0;i<16;i++)
{
//SPI_transmit(0xff);
spi_xfer(0xFF);
}
mmcsd_select();
do
{
response = SD_sendCommand(GO_IDLE_STATE, 0);//send 'reset & go idle' command
retry++;
if(retry>0xfe)
{
mmcsd_deselect();
printf("\rSD init fail..");
return 1;
}//time out
} while(response != 0x01);
mmcsd_deselect();
mmcsd_select();
retry = 0;
do
{
response = SD_sendCommand(SEND_OP_COND, 0); //activate card's initialization process
response = SD_sendCommand(SEND_OP_COND, 0); //resend command (for compatibility with some cards)
retry++;
if(retry>0xFE) return 1; //time out
}while(response);
SD_sendCommand(CRC_ON_OFF, OFF); //disable CRC; deafault - CRC disabled in SPI mode
SD_sendCommand(SET_BLOCK_LEN, 512); //set block size to 512
return 0; //normal return
}
bool Initialize_SDHC(void)
{
bool done=0;
static uint8_t rcv;
static uint16_t count=0;
//Send Dummys
nrf_gpio_pin_set(MMCSD_PIN_SELECT);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
spi_xfer( 0xFF);
nrf_gpio_pin_clear(MMCSD_PIN_SELECT);
mmcsd_deselect();
mmcsd_select();
Send_Command(sd_cmd1,9);
mmcsd_deselect();
mmcsd_select();
Send_Command(sd_cmd2,13);
mmcsd_deselect();
while(!done)
{
mmcsd_select();
rcv=Send_Command(sd_cmd3,8);
if (rcv == 0x00 ){done=1;}
else{ mmcsd_deselect();}
mmcsd_select();
rcv=Send_Command(sd_cmd4,9);
if (rcv == 0x00 ){done=1;}
else{ mmcsd_deselect();}
count++;
if(count==5000){return 1;}
}
mmcsd_select();
if(Send_Command(sd_cmd5,10) == 0xC0)
{
send_spi(0xFF);
send_spi(0xFF);
send_spi(0xFF);
send_spi(0xFF);
return 0;
}
else {mmcsd_deselect(); return 1;}
}
uint8_t SD_Card_Initialize(void)
{
spi_master_init(&m_spi_master_0,false);
nrf_gpio_cfg_output(MMCSD_PIN_SELECT);
nrf_gpio_pin_set(MMCSD_PIN_SELECT);
if(SD_init())
{
if(Initialize_SDHC())
return 0;
else
return 2; //SDHC card
}
else
return 1; // SD card
}
uint8_t SD_writeSingleBlock(uint32_t startBlock,const uint8_t *data)
{
uint8_t response;
uint16_t i, retry=0;
response = SD_sendCommand(WRITE_SINGLE_BLOCK, startBlock<<9); //write a Block command
if(response != 0x00) //check for SD status: 0x00 - OK (No flags set)
return response;
mmcsd_select();
//spi_xfer( 0xFF)
spi_xfer(0xfe); //Send start block token 0xfe (0x11111110)
for(i=0; i<512; i++) //send 512 bytes data
{
printf("%c",*(data+i));
spi_xfer(*(data+i));
}
spi_xfer(0xff); //transmit dummy CRC (16-bit), CRC is ignored here
spi_xfer(0xff);
response = spi_xfer( 0xFF);
if( (response & 0x1f) != 0x05) //response= 0xXXX0AAA1 ; AAA='010' - data accepted
{ //AAA='101'-data rejected due to CRC error
mmcsd_deselect(); //AAA='110'-data rejected due to write error
return response;
}
while(!spi_xfer( 0xFF)) //wait for SD card to complete writing and get idle
if(retry++ > 0xfffe){mmcsd_deselect(); return 1;}
mmcsd_deselect();
spi_xfer(0xFF); //just spend 8 clock cycle delay before reasserting the CS line
mmcsd_select(); //re-asserting the CS line to verify if card is still busy
while(!spi_xfer( 0xFF)) //wait for SD card to complete writing and get idle
if(retry++ > 0xfffe){mmcsd_deselect(); return 1;}
mmcsd_deselect();
return 0;
}
uint8_t SD_readSingleBlock(uint32_t startBlock,uint8_t *data)
{
uint8_t response;
uint16_t i, retry=0;
response = SD_sendCommand(READ_SINGLE_BLOCK, startBlock<<9); //read a Block command
//block address converted to starting address of 512 byte Block
if(response != 0x00) //check for SD status: 0x00 - OK (No flags set)
return response;
mmcsd_select();
while(spi_xfer( 0xFF) != 0xFE) //wait for start block token 0xfe (0x11111110)
if(retry++ > 0xfffe){mmcsd_deselect(); return 1;} //return if time-out
for(i=0; i<512; i++) //read 512 bytes
{
*data = spi_xfer( 0xFF);
printf("%c",*data);
data++;
}
spi_xfer( 0xFF); //receive incoming CRC (16-bit), CRC is ignored here
spi_xfer( 0xFF);
spi_xfer( 0xFF); //extra 8 clock pulses
mmcsd_deselect();
return 0;
}
uint8_t SD_WriteMultiBlock(uint32_t startBlock,const uint8_t *data ,uint32_t count)
{
uint8_t response;
uint16_t i, retry=0;
response = SD_sendCommand(WRITE_SINGLE_BLOCK, startBlock<<9); //write a Block command
if(response != 0x00) //check for SD status: 0x00 - OK (No flags set)
return response;
do{
mmcsd_select();
//spi_xfer( 0xFF)
spi_xfer(0xfc); //Send start block token 0xfc
for(i=0; i<512; i++) //send 512 bytes data
spi_xfer(*(data+i));
spi_xfer(0xff); //transmit dummy CRC (16-bit), CRC is ignored here
spi_xfer(0xff);
response = spi_xfer( 0xFF);
if( (response & 0x1f) != 0x05) //response= 0xXXX0AAA1 ; AAA='010' - data accepted
{ //AAA='101'-data rejected due to CRC error
mmcsd_deselect(); //AAA='110'-data rejected due to write error
return response;
}
while(!spi_xfer( 0xFF)) //wait for SD card to complete writing and get idle
if(retry++ > 0xfffe){mmcsd_deselect(); return 1;}
}while(--count);
mmcsd_deselect();
spi_xfer(0xFd); //just spend 8 clock cycle delay before reasserting the CS line
mmcsd_select(); //re-asserting the CS line to verify if card is still busy
while(!spi_xfer( 0xFF)) //wait for SD card to complete writing and get idle
if(retry++ > 0xfffe){mmcsd_deselect(); return 1;}
mmcsd_deselect();
return 0;
}
uint8_t SD_ReadMultiBlock(uint32_t startBlock, uint8_t* data, uint32_t count)
{
uint8_t response;
uint16_t i, retry=0;
response = SD_sendCommand(READ_MULTIPLE_BLOCKS, startBlock<<9);
//block address converted to starting address of 512 byte Block
if(response != 0x00) //check for SD status: 0x00 - OK (No flags set)
return response;
do{
mmcsd_select();
while(spi_xfer( 0xFF) != 0xFE) //wait for start block token 0xfe (0x11111110)
if(retry++ > 0xfffe){mmcsd_deselect(); return 1;} //return if time-out
retry=0;
for(i=0; i<512; i++) //read 512 bytes
{
*data = spi_xfer( 0xFF);
printf("%c",*data);
data++;
}
spi_xfer( 0xFF); //receive incoming CRC (16-bit), CRC is ignored here
spi_xfer( 0xFF);
}while( --count );
retry=0;
response = SD_sendCommand(STOP_TRANSMISSION, 0);
if(response!=0x00)
{
printf("SD_ReadMultiBlock fail....");
}
// spi_xfer( 0xFF); //extra 8 clock pulses
mmcsd_deselect();
return 0;
}
uint8_t SD_GetCSD(uint8_t *csd_data)
{
uint8_t r1;
uint16_t i, retry=0;
r1=SD_sendCommand(SEND_CSD,0);//·¢CMD9ÃüÁ¶ÁCSD
if(r1)return r1; //û·µ»ØÕýÈ·Ó¦´ð£¬ÔòÍ˳ö£¬±¨´í
mmcsd_select();
while(spi_xfer( 0xFF) != 0xFE) //wait for start block token 0xfe (0x11111110)
if(retry++ > 0xfffe){mmcsd_deselect(); return 1;} //return if time-out
for(i=0; i<16; i++) //read 16 bytes
{
*(csd_data+i) = spi_xfer( 0xFF);
}
spi_xfer( 0xFF); //receive incoming CRC (16-bit), CRC is ignored here
spi_xfer( 0xFF);
spi_xfer( 0xFF); //extra 8 clock pulses
mmcsd_deselect();
return 0;
}
uint32_t SD_GET_SD_SIZE(void)
{
uint8_t csd[16];
uint32_t Capacity;
uint8_t r1;
uint16_t i;
uint16_t temp;
//È¡CSDÐÅÏ¢£¬Èç¹ûÆÚ¼ä³ö´í£¬·µ»Ø0
if(SD_GetCSD(csd)!=0) return 0;
//Èç¹ûΪSDHC¿¨£¬°´ÕÕÏÂÃ淽ʽ¼ÆËã
if((csd[0]&0xC0)==0x40)
{
Capacity=((uint32_t)csd[8])<<8;
Capacity+=(uint32_t)csd[9]+1;
Capacity = (Capacity)*1024;//µÃµ½ÉÈÇøÊý
Capacity*=512;//µÃµ½×Ö½ÚÊý
}
else
{
i = csd[6]&0x03;
i<<=8;
i += csd[7];
i<<=2;
i += ((csd[8]&0xc0)>>6);
//C_SIZE_MULT
r1 = csd[9]&0x03;
r1<<=1;
r1 += ((csd[10]&0x80)>>7);
r1+=2;//BLOCKNR
temp = 1;
while(r1)
{
temp*=2;
r1--;
}
Capacity = ((uint32_t)(i+1))*((uint32_t)temp);
// READ_BL_LEN
i = csd[5]&0x0f;
//BLOCK_LEN
temp = 1;
while(i)
{
temp*=2;
i--;
}
//The final result
Capacity *= (uint32_t)temp;//×Ö½ÚΪµ¥Î»
}
return (uint32_t)Capacity;
}