|
|
|
@ -2,42 +2,22 @@
|
|
|
|
|
#include "sd_mmc_intf.h"
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
static bool sd_mmc_check_cd(void)
|
|
|
|
|
{
|
|
|
|
|
switch(SD_MMC_CD_MODE)
|
|
|
|
|
{
|
|
|
|
|
case SD_MMC_CD_MODE_UNUSED:
|
|
|
|
|
{
|
|
|
|
|
// Always assume the card is detected since we aren't using this function
|
|
|
|
|
return true;
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_CD_MODE_SYNC:
|
|
|
|
|
{
|
|
|
|
|
return SD_MMC_INTF_CHECK_CD();
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_CD_MODE_ASYNC:
|
|
|
|
|
{
|
|
|
|
|
// Unimplemented
|
|
|
|
|
return false;
|
|
|
|
|
}break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// send 80 clock cycles
|
|
|
|
|
static void sd_mmc_send_clock()
|
|
|
|
|
{
|
|
|
|
|
uint8_t i;
|
|
|
|
|
uint8_t dummy = 0xFF;
|
|
|
|
|
for(i = 0; i < 10; i++)
|
|
|
|
|
{
|
|
|
|
|
SD_MMC_INTF_WRITE(&dummy, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Functions used to interact with the SD card
|
|
|
|
|
static sd_mmc_err_t sd_mmc_power_up_sequence();
|
|
|
|
|
static sd_mmc_err_t sd_mmc_idle_sequence();
|
|
|
|
|
static sd_mmc_err_t sd_mmc_if_sequence();
|
|
|
|
|
static sd_mmc_err_t sd_mmc_read_ocr(uint8_t* res);
|
|
|
|
|
static sd_mmc_err_t sd_mmc_read_res1(uint8_t* res1);
|
|
|
|
|
static sd_mmc_err_t sd_mmc_read_res7(uint8_t* res7);
|
|
|
|
|
static sd_mmc_err_t sd_mmc_read_res3(uint8_t* res3);
|
|
|
|
|
static bool sd_mmc_check_cd(void);
|
|
|
|
|
static void sd_mmc_send_clock(void);
|
|
|
|
|
|
|
|
|
|
// Functions used for debugging
|
|
|
|
|
static void sd_mmc_print_err(sd_mmc_err_t err);
|
|
|
|
|
static void sd_mmc_print_res1(uint8_t res);
|
|
|
|
|
static void sd_mmc_print_res7(const uint8_t* const res);
|
|
|
|
|
|
|
|
|
|
sd_mmc_err_t sd_mmc_init(void)
|
|
|
|
|
{
|
|
|
|
@ -45,34 +25,39 @@ sd_mmc_err_t sd_mmc_init(void)
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
// Hardware initialize
|
|
|
|
|
if(0 != SD_MMC_INTF_INIT())
|
|
|
|
|
{
|
|
|
|
|
ret = SD_MMC_INIT_FAILURE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// power up sequence
|
|
|
|
|
delay_ms(1);
|
|
|
|
|
sd_mmc_send_clock();
|
|
|
|
|
|
|
|
|
|
// Power up sd card sequence
|
|
|
|
|
if((ret != sd_mmc_power_up_sequence()) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// go idle
|
|
|
|
|
sd_mmc_select(0, 0, 0, true);
|
|
|
|
|
if(0 != sd_mmc_send_command(CMD0, CMD0_ARG, CMD0_CRC))
|
|
|
|
|
if((ret != sd_mmc_idle_sequence()) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
ret = SD_MMC_ERR_COMM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t res1_ret = 0xFF;
|
|
|
|
|
if(0 != sd_mmc_read_res1(&res1_ret))
|
|
|
|
|
// interface sequence
|
|
|
|
|
if((ret != sd_mmc_if_sequence()) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
ret = SD_MMC_ERR_COMM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sd_mmc_deselect(0);
|
|
|
|
|
|
|
|
|
|
}while(0);
|
|
|
|
|
|
|
|
|
|
if(ret != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
printf("Error initializing SD Card: ");
|
|
|
|
|
sd_mmc_print_err(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("res1: 0x%02x\n", res1_ret);
|
|
|
|
|
}while(0);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -92,7 +77,6 @@ sd_mmc_err_t sd_mmc_select(uint8_t slot, uint32_t clock, uint8_t bus_width, bool
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
SD_MMC_INTF_SELECT_DEVICE();
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sd_mmc_err_t sd_mmc_send_command(uint8_t cmd, uint32_t arg, uint8_t crc)
|
|
|
|
@ -113,7 +97,7 @@ sd_mmc_err_t sd_mmc_send_command(uint8_t cmd, uint32_t arg, uint8_t crc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sd_mmc_err_t sd_mmc_read_res1(uint8_t* ret_byte)
|
|
|
|
|
sd_mmc_err_t sd_mmc_read_res1(uint8_t* byte)
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
|
|
|
|
@ -121,11 +105,263 @@ sd_mmc_err_t sd_mmc_read_res1(uint8_t* ret_byte)
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
i++;
|
|
|
|
|
SD_MMC_INTF_READ(ret_byte, 1);
|
|
|
|
|
}while(i <= 8 && *ret_byte == 0xFF);
|
|
|
|
|
if(*ret_byte == 0xFF)
|
|
|
|
|
SD_MMC_INTF_READ(byte, 1);
|
|
|
|
|
}while(i <= 8 && *byte == 0xFF);
|
|
|
|
|
if(*byte == 0xFF)
|
|
|
|
|
{
|
|
|
|
|
return SD_MMC_TIMEOUT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sd_mmc_err_t sd_mmc_read_res7(uint8_t* res7)
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if(5 != SD_MMC_INTF_READ(res7, 5))
|
|
|
|
|
{
|
|
|
|
|
ret = SD_MMC_ERR_COMM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(res7[0] > 1)
|
|
|
|
|
{
|
|
|
|
|
// handle this error better later
|
|
|
|
|
ret = SD_MMC_ERR_COMM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}while(0);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sd_mmc_err_t sd_mmc_read_res3(uint8_t* res3)
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if(5 != SD_MMC_INTF_READ(res3, 5))
|
|
|
|
|
{
|
|
|
|
|
ret = SD_MMC_ERR_COMM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(res3[0] > 1)
|
|
|
|
|
{
|
|
|
|
|
// handle this error better later
|
|
|
|
|
ret = SD_MMC_ERR_COMM;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}while(0);
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
sd_mmc_err_t sd_mmc_power_up_sequence()
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
// power up sequence
|
|
|
|
|
delay_ms(1);
|
|
|
|
|
sd_mmc_send_clock();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sd_mmc_err_t sd_mmc_idle_sequence()
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
uint8_t res1 = 0xFF;
|
|
|
|
|
|
|
|
|
|
sd_mmc_select(0, 0, 0, false);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_select(0, 0, 0, true);
|
|
|
|
|
if((ret != sd_mmc_send_command(CMD0, CMD0_ARG, CMD0_CRC)) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((ret != sd_mmc_read_res1(&res1)) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sd_mmc_print_res1(res1);
|
|
|
|
|
}while(0);
|
|
|
|
|
sd_mmc_deselect(0);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
sd_mmc_err_t sd_mmc_if_sequence()
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
uint8_t res7[5];
|
|
|
|
|
|
|
|
|
|
sd_mmc_select(0, 0, 0, false);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if((ret = sd_mmc_send_command(CMD8, CMD8_ARG, CMD8_CRC)) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((ret = sd_mmc_read_res7(res7)) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sd_mmc_print_res7(res7);
|
|
|
|
|
}while(0);
|
|
|
|
|
sd_mmc_deselect(0);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sd_mmc_print_err(sd_mmc_err_t err)
|
|
|
|
|
{
|
|
|
|
|
switch(err)
|
|
|
|
|
{
|
|
|
|
|
case SD_MMC_SUCCESS:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_SUCCESS\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_FAILURE:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_FAILURE\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_INIT_ONGOING:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_INIT_ONGOING\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_ERR_NO_CARD:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_ERR_NO_CARD\n");
|
|
|
|
|
}
|
|
|
|
|
case SD_MMC_ERR_UNUSABLE:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_UNUSABLE\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_ERR_SLOT:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_ERR_SLOT\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_ERR_COMM:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_ERR_COMM\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_ERR_PARAM:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_ERR_PARAM\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_ERR_WP:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_ERR_WP\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_INIT_FAILURE:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_INIT_FAILURE\n");
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_TIMEOUT:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "SD_MMC_TIMEOUT\n");
|
|
|
|
|
}break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
printf("%s", "UNKNOWN ERROR");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sd_mmc_print_res1(uint8_t res)
|
|
|
|
|
{
|
|
|
|
|
if(res & 0b10000000)
|
|
|
|
|
{ printf("\tError: MSB = 1\r\n"); return; }
|
|
|
|
|
if(res == 0)
|
|
|
|
|
{ printf("\tCard Ready\r\n"); return; }
|
|
|
|
|
if(PARAM_ERROR(res))
|
|
|
|
|
printf("\tParameter Error\r\n");
|
|
|
|
|
if(ADDR_ERROR(res))
|
|
|
|
|
printf("\tAddress Error\r\n");
|
|
|
|
|
if(ERASE_SEQ_ERROR(res))
|
|
|
|
|
printf("\tErase Sequence Error\r\n");
|
|
|
|
|
if(CRC_ERROR(res))
|
|
|
|
|
printf("\tCRC Error\r\n");
|
|
|
|
|
if(ILLEGAL_CMD(res))
|
|
|
|
|
printf("\tIllegal Command\r\n");
|
|
|
|
|
if(ERASE_RESET(res))
|
|
|
|
|
printf("\tErase Reset Error\r\n");
|
|
|
|
|
if(IN_IDLE(res))
|
|
|
|
|
printf("\tIn Idle State\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sd_mmc_print_res7(const uint8_t* const res)
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_print_res1(res[0]);
|
|
|
|
|
if(res[0] > 1) return;
|
|
|
|
|
|
|
|
|
|
printf("\tCommand Version: 0x%02x\n", CMD_VER(res[1]));
|
|
|
|
|
|
|
|
|
|
printf("\tVoltage Accepted: %s\n",
|
|
|
|
|
(res[3] == VOLTAGE_ACC_27_33) ? "2.7-3.6V"
|
|
|
|
|
: (res[3] == VOLTAGE_ACC_LOW) ? "LOW VOLTAGE"
|
|
|
|
|
: (res[3] == VOLTAGE_ACC_RES1 || res[3] == VOLTAGE_ACC_RES2) ? "RESERVED"
|
|
|
|
|
: "NOT DEFINED");
|
|
|
|
|
printf("\tEcho: 0x%02x\n", res[4]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool sd_mmc_check_cd(void)
|
|
|
|
|
{
|
|
|
|
|
switch(SD_MMC_CD_MODE)
|
|
|
|
|
{
|
|
|
|
|
case SD_MMC_CD_MODE_UNUSED:
|
|
|
|
|
{
|
|
|
|
|
// Always assume the card is detected since we aren't using this function
|
|
|
|
|
return true;
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_CD_MODE_SYNC:
|
|
|
|
|
{
|
|
|
|
|
return SD_MMC_INTF_CHECK_CD();
|
|
|
|
|
}break;
|
|
|
|
|
case SD_MMC_CD_MODE_ASYNC:
|
|
|
|
|
{
|
|
|
|
|
// Unimplemented
|
|
|
|
|
return false;
|
|
|
|
|
}break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sd_mmc_send_clock()
|
|
|
|
|
{
|
|
|
|
|
uint8_t i;
|
|
|
|
|
uint8_t dummy = 0xFF;
|
|
|
|
|
for(i = 0; i < 10; i++)
|
|
|
|
|
{
|
|
|
|
|
SD_MMC_INTF_WRITE(&dummy, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sd_mmc_err_t sd_mmc_read_ocr(uint8_t* res)
|
|
|
|
|
{
|
|
|
|
|
sd_mmc_err_t ret = SD_MMC_SUCCESS;
|
|
|
|
|
uint8_t res3[5];
|
|
|
|
|
|
|
|
|
|
sd_mmc_select(0, 0, 0, false);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if((ret = sd_mmc_send_command(CMD58, CMD58_ARG, CMD58_CRC)) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((ret = sd_mmc_read_res3(res3)) != SD_MMC_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}while(0);
|
|
|
|
|
sd_mmc_deselect(0);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|