📄 drvsdcard.c
字号:
/****************************************************************
* *
* Copyright (c) Nuvoton Technology Corp. All rights reserved. *
* *
****************************************************************/
/*---------------------------------------------------------------------------------------------------------*/
/* Includes of system headers */
/*---------------------------------------------------------------------------------------------------------*/
#include <stdio.h>
/*---------------------------------------------------------------------------------------------------------*/
/* Includes of local headers */
/*---------------------------------------------------------------------------------------------------------*/
#include "DrvSDCARD.h"
#include "DrvGPIO.h"
#include "DrvSYS.h"
#include "DrvSPI.h"
/*---------------------------------------------------------------------------------------------------------*/
/* Macro, type and constant definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define DBG_PRINTF(...)
//#define DBG_PRINTF printf
// Erase group size = 16 MMC FLASH sectors
#define PHYSICAL_BLOCK_SIZE 512
// Command table value definitions
// Used in the MMC_Command_Exec function to
// decode and execute MMC command requests
#define EMPTY 0
#define YES 1
#define NO 0
#define CMD 0
#define RD 1
#define WR 2
#define RDB 3
#define WDB 4
#define R1 0
#define R1b 1
#define R2 2
#define R3 3
#define R7 4
// Start and stop data tokens for single and multiple
// block MMC data operations
#define START_SBR 0xFE
#define START_MBR 0xFE
#define START_SBW 0xFE
#define START_MBW 0xFC
#define STOP_MBW 0xFD
// Mask for data response Token after an MMC write
#define DATA_RESP_MASK 0x11
// Mask for busy Token in R1b response
#define BUSY_BIT 0x80
#define BACK_FROM_ERROR { SingleWrite(0xFF);DrvSPI_ClrSS(eDRVSPI_PORT1, eDRVSPI_SS0); return FALSE;}
typedef union { // byte-addressable unsigned long
uint32_t l;
uint8_t b[4];
} UINT32;
typedef union { // byte-addressable unsigned int
uint16_t i;
uint8_t b[2];
} UINT16;
// This structure defines entries into the command table;
typedef struct {
uint8_t command_byte; // OpCode;
uint8_t arg_required; // Indicates argument requirement;
uint8_t CRC; // Holds CRC for command if necessary;
uint8_t trans_type; // Indicates command transfer type;
uint8_t response; // Indicates expected response;
uint8_t var_length; // Indicates varialble length transfer;
} COMMAND;
// Command table for MMC. This table contains all commands available in SPI
// mode; Format of command entries is described above in command structure
// definition;
COMMAND __I command_list[] = {
{ 0,NO ,0x95,CMD,R1 ,NO }, // CMD0; GO_IDLE_STATE: reset card;
{ 1,NO ,0xFF,CMD,R1 ,NO }, // CMD1; SEND_OP_COND: initialize card;
{ 8,YES,0xFF,CMD,R7 ,NO }, // CMD8; SEND_IF_COND
{ 9,NO ,0xFF,RD ,R1 ,NO }, // CMD9; SEND_CSD: get card specific data;
{10,NO ,0xFF,RD ,R1 ,NO }, // CMD10; SEND_CID: get card identifier;
{12,NO ,0xFF,CMD,R1b,NO }, // CMD12; STOP_TRANSMISSION: end read;
{13,NO ,0xFF,CMD,R2 ,NO }, // CMD13; SEND_STATUS: read card status;
{16,YES,0xFF,CMD,R1 ,NO }, // CMD16; SET_BLOCKLEN: set block size;
{17,YES,0xFF,RDB ,R1 ,NO }, // CMD17; READ_SINGLE_BLOCK: read 1 block;
{18,YES,0xFF,RD ,R1 ,YES}, // CMD18; READ_MULTIPLE_BLOCK: read > 1;
{23,NO ,0xFF,CMD,R1 ,NO }, // CMD23; SET_BLOCK_COUNT
{24,YES,0xFF,WR ,R1 ,NO }, // CMD24; WRITE_BLOCK: write 1 block;
{25,YES,0xFF,WR ,R1 ,YES}, // CMD25; WRITE_MULTIPLE_BLOCK: write > 1;
{27,NO ,0xFF,CMD,R1 ,NO }, // CMD27; PROGRAM_CSD: program CSD;
{28,YES,0xFF,CMD,R1b,NO }, // CMD28; SET_WRITE_PROT: set wp for group;
{29,YES,0xFF,CMD,R1b,NO }, // CMD29; CLR_WRITE_PROT: clear group wp;
{30,YES,0xFF,CMD,R1 ,NO }, // CMD30; SEND_WRITE_PROT: check wp status;
{32,YES,0xFF,CMD,R1 ,NO }, // CMD32; TAG_SECTOR_START: tag 1st erase;
{33,YES,0xFF,CMD,R1 ,NO }, // CMD33; TAG_SECTOR_END: tag end(single);
{34,YES,0xFF,CMD,R1 ,NO }, // CMD34; UNTAG_SECTOR: deselect for erase;
{35,YES,0xFF,CMD,R1 ,NO }, // CMD35; TAG_ERASE_GROUP_START;
{36,YES,0xFF,CMD,R1 ,NO }, // CMD36; TAG_ERASE_GROUP_END;
{37,YES,0xFF,CMD,R1 ,NO }, // CMD37; UNTAG_ERASE_GROUP;
{38,YES,0xFF,CMD,R1b,NO }, // CMD38; ERASE: erase all tagged sectors;
{42,YES,0xFF,CMD,R1 ,NO }, // CMD42; LOCK_UNLOCK;
{55,NO ,0xFF,CMD,R1 ,NO }, // CMD55; APP_CMD
{58,NO ,0xFF,CMD,R3 ,NO }, // CMD58; READ_OCR: read OCR register;
{59,YES,0xFF,CMD,R1 ,NO }, // CMD59; CRC_ON_OFF: toggles CRC checking;
{0x80+13,NO ,0xFF,CMD,R2 ,NO },// ACMD13; SD_SEND_STATUS: read card status;
{0x80+23,YES,0xFF,CMD,R1 ,NO },// ACMD23;SD_SET_WR_BLK_ERASE_COUNT
{0x80+41,YES,0xFF,CMD,R1 ,NO } // ACMD41; SD_SEND_OP_COND: initialize card;
};
/*---------------------------------------------------------------------------------------------------------*/
/* Parameter checking definitions */
/*---------------------------------------------------------------------------------------------------------*/
int8_t Is_Initialized=0,SDtype=0;
uint32_t LogicSector=0;
/*---------------------------------------------------------------------------------------------------------*/
/* SD CARD Protocol */
/*---------------------------------------------------------------------------------------------------------*/
/*
Transfer Length:48bit
BIT POSITION WIDTH(BITS) VAULE
[47] 1 0:Start bit
[46] 1 1:Transmit 0:Receive
[45:40] 6 CMD8:001000
[39:8] 32 Reserved
[7:1] 7 Reserved
[0] 1 1:End bit
*/
/*---------------------------------------------------------------------------------------------------------*/
/* Function: GenerateCRC */
/* */
/* Parameters: */
/* uint32_t u32Data Input Data */
/* uint32_t u32GenPoly CRC7:0x1200 CRC16:0x1021 */
/* uint32_t u32Accum CRC value */
/* */
/* */
/* Returns: */
/* uint32_t u32Accum CRC value */
/* */
/* */
/* Side effects: */
/* Description: */
/* This function is used to generate CRC value */
/*---------------------------------------------------------------------------------------------------------*/
static uint32_t GenerateCRC(uint32_t u32Data, uint32_t u32GenPoly, uint32_t u32Accum)
{
volatile uint8_t i;
u32Data <<= 8;
for (i=8; i>0; i--)
{
if ((u32Data ^ u32Accum) & 0x8000)
u32Accum = (u32Accum << 1) ^ u32GenPoly;
else
u32Accum <<= 1;
u32Data <<= 1;
}
return u32Accum;
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: SingleWrite */
/* */
/* Parameters: */
/* UINT32 u32Data Data to send */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to send data though SPI to general clock for SDCARD operation */
/*---------------------------------------------------------------------------------------------------------*/
static uint32_t SingleWrite(uint32_t u32Data)
{
uint32_t SPIdata=u32Data;
DrvSPI_BurstTransfer(eDRVSPI_PORT1,1,2);
DrvSPI_SingleWrite(eDRVSPI_PORT1,&SPIdata);
while (DrvSPI_IsBusy(eDRVSPI_PORT1));
DrvSPI_DumpRxRegister(eDRVSPI_PORT1,&SPIdata,1);
return SPIdata;
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: MMC_Command_Exec */
/* */
/* Parameters: */
/* uint8_t nCmd Set command register */
/* uint32_t nArg Set command argument */
/* uint8_t *pchar Get register and data */
/* uint32_t *response Get response */
/* */
/* Returns: */
/* TRUE get response */
/* FALSE 1.SD Card busy, 2.Card moved, 3.Timeout */
/* */
/* */
/* Side effects: */
/* Description: */
/* This function is used to Send SDCARD CMD and Receive Response */
/*---------------------------------------------------------------------------------------------------------*/
uint32_t MMC_Command_Exec (uint8_t nCmd, uint32_t nArg,uint8_t *pchar, uint32_t *response)
{
uint8_t loopguard;
COMMAND current_command; // Local space for the command table
UINT32 long_arg; // Local space for argument
static uint32_t current_blklen = 512;
uint32_t old_blklen = 512;
int32_t counter = 0; // Byte counter for multi-byte fields;
UINT16 card_response; // Variable for storing card response;
uint8_t data_resp; // Variable for storing data response;
UINT16 dummy_CRC; // Dummy variable for storing CRC field;
card_response.i = 0;
current_command = command_list[nCmd];// Retrieve desired command table entry
// from code space;
if(current_command.command_byte & 0x80) // Detect ACMD
{
if(MMC_Command_Exec(APP_CMD,EMPTY,EMPTY,response)==FALSE)//Send APP_CMD
return FALSE;
}
DrvSPI_SetSS(eDRVSPI_PORT1, eDRVSPI_SS0); // CS = 0
SingleWrite(0xFF);
SingleWrite((current_command.command_byte | 0x40)&0x7f);
DBG_PRINTF("CMD:%d,",current_command.command_byte&0x7f);
long_arg.l = nArg; // Make argument byte addressable;
// If current command changes block
// length, update block length variable
// to keep track;
// Command byte = 16 means that a set
// block length command is taking place
// and block length variable must be
// set;
if(current_command.command_byte == 16)
{current_blklen = nArg;}
// Command byte = 9 or 10 means that a
// 16-byte register value is being read
// from the card, block length must be
// set to 16 bytes, and restored at the
// end of the transfer;
if((current_command.command_byte == 9)||(current_command.command_byte == 10))
{
old_blklen = current_blklen; // Command is a GET_CSD or GET_CID,
current_blklen = 16; // set block length to 16-bytes;
}
// If an argument is required, transmit
// one, otherwise transmit 4 bytes of
// 0x00;
if(current_command.arg_required == YES)
{
dummy_CRC.i = GenerateCRC((current_command.command_byte | 0x40), 0x1200, 0);
for(counter=3;counter>=0;counter--)
{
SingleWrite(long_arg.b[counter]);
dummy_CRC.i = GenerateCRC(long_arg.b[counter], 0x1200, dummy_CRC.i);
}
dummy_CRC.i = (dummy_CRC.i >> 8)| 0x01;
SingleWrite(dummy_CRC.b[0]);
} else
{
counter = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -