nrf51822蓝牙SPI对microSD卡读写

          基于nrf51822 SDK10的蓝牙串口工程 ,增加SPI的资源文件到工程,定义SPI0使能,以及定义IO口,和CS引脚电平,新建drv_sd_api.c文件如下即可在主函数调用接口函数对SD卡进行操作,此接口函数是官方提供的一个我只是修改一下,使用前对SD卡的指令以及一些注意事项说明如下:

SD卡的命令格式如下,6字节共48位,传输时最高位(MSB)先传输:

nrf51822蓝牙SPI对microSD卡读写_第1张图片

    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模式。


常用的指令解释如下:

nrf51822蓝牙SPI对microSD卡读写_第2张图片

关于SD卡SPI和command的发送要注意以下几点:
    1.SD卡的SPI总线,在读入数据时SD卡的SPI是CLK的上升沿输入锁存,输出数据也是在上升沿。 
    2.向SD卡写入一个CMD或者ACMD指令的过程是这样的: 首先使CS为低电平,SD卡使能;其次在SD卡的Din写入指令;写入指令后还要附加8个填充时钟,是SD卡完成内部操作;之后在SD卡的Dout上接受回应;回应接受完毕使CS为低电平,再附加8个填充时钟。 

    3.在SD卡的Din没有数据写入时,应使Din保持高电平。




#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;
}




你可能感兴趣的:(nrf51822蓝牙开发)