Tengo una tarjeta sd de 4 GB conectada a través de SPI a mi XMega MCU y quiero leer esta tarjeta con la interfaz USART-SPI en el modo SPI de la MCU. Así que tengo este código
SD.c
SD_Error_t SD_Init(SPI_Config_t* Config)
{
SD_Error_t Status = SD_InitInterface(Config);
SD_ReadSingleBlock(0x00);
return Status;
}
SD.h
#ifndef SD_H_
#define SD_H_
/*
SD card settings
*/
#define SD_INTERFACE_TYPE INTERFACE_USART_SPI
#define SD_SS_PORT &PORTE
#define SD_SS_PIN 0
#define SD_BLOCK_SIZE 512
typedef enum
{
SD_SUCCESSFULL = 0,
SD_NO_RESPONSE = -1,
SD_TIMEOUT = -2,
SD_UNSUPPORTED_CARD = -3,
} SD_Error_t;
#include "Peripheral/SD/Interface/SD_Interface.h"
SD_Error_t SD_Init(SPI_Config_t* Config);
#endif /* SD_H_ */
Y mi controlador de tarjeta SD de bajo nivel
SD_Interface.h
#ifndef SD_INTERFACE_H_
#define SD_INTERFACE_H_
/*
Driver include
*/
#include "Board.h"
#include "Common/types.h"
#include "Peripheral/SD/SD.h"
#if MCU_ARCH == MCU_ARCH_XMEGA
#include "XMega/GPIO/GPIO.h"
#include "XMega/ClockManagment/SysClock.h"
#if SD_INTERFACE_TYPE == INTERFACE_USART_SPI
#include "XMega/USART/USART.h"
#define SD_SPI_INIT(Config) USART_SPI_Init(Config)
#define SD_SPI_TRANSMIT(Command) USART_SPI_Transmit(SPI_INTERFACE, Command)
#define SD_SPI_CHIP_SELECT(Port, Pin) USART_SPI_SelectDevice(Port, Pin)
#define SD_SPI_CHIP_UNSELECT(Port, Pin) USART_SPI_DeselectDevice(Port, Pin)
#elif SD_INTERFACE_TYPE == INTERFACE_SPI
#include "XMega/SPI/SPI.h"
#define SD_SPI_INIT(Config) SPI_Init(Config)
#define SD_SPI_TRANSMIT(Command) SPI_Transmit(SPI_INTERFACE, Command)
#define SD_SPI_CHIP_SELECT(Port, Pin) SPI_SelectDevice(Port, Pin)
#define SD_SPI_CHIP_UNSELECT(Port, Pin) SPI_DeselectDevice(Port, Pin)
#else
#error "No SPI interface specified"
#endif
#elif MCU_ARCH == MCU_ARCH_AVR8
#include "AVR8/GPIO/GPIO.h"
#include "AVR8/SPI/SPI.h"
#define SD_SPI_INIT(Config) SPI_Init(Config)
#define SD_SPI_TRANSMIT(Command) SPI_Transmit(Command)
#define SD_SPI_CHIP_SELECT(Port, Pin) SPI_SelectDevice(Port, Pin)
#define SD_SPI_CHIP_UNSELECT(Port, Pin) SPI_DeselectDevice(Port, Pin)
#else
#error "MCU architecture not supported"
#endif
typedef enum
{
SD_VER_UNKNOWN = 0x00,
SD_VER_1_STD = 0x01,
SD_VER_2_STD = 0x02,
SD_VER_2_HI = 0x03,
SD_MMC = 0x04,
} SD_CardType_t;
typedef struct
{
uint8_t MID;
uint16_t OID;
uint8_t PNM[5];
uint8_t PRV;
uint32_t PSN;
uint8_t Reserved0:3;
uint16_t MDT0:11;
uint8_t CRC0:6;
uint8_t Reserved1:1;
} __attribute__((packed)) SD_CID_t;
#define SD_ID_TO_CMD(ID) (0x40 + ID)
#define SD_STATE_SUCCESSFULL 0x00
#define SD_STATE_IDLE 0x01
#define SD_STATE_ERASE_RESEIT 0x02
#define SD_STATE_ILLEGAL_COMMAND 0x04
#define SD_STATE_CRC_ERROR 0x08
#define SD_STATE_ERASE_ERROR 0x10
#define SD_STATE_ADDRESS_ERROR 0x20
#define SD_STATE_PARAMETER_ERROR 0x40
#define SD_STATE_BEGIN_TRANSMISSION 0xFE
SD_Error_t SD_InitInterface(SPI_Config_t* Config);
void SD_ReadCSD(void);
void SD_ReadCID(void);
uint8_t SD_Command(uint8_t Command, uint32_t Arg, uint8_t Checksum, uint32_t Count, uint8_t* Buffer);
SD_Error_t SD_SoftwareReset(void);
SD_Error_t SD_InitializeCard(void);
SD_CardType_t SD_GetCardType(void);
uint8_t SD_SetBlockLength(uint32_t BlockLength);
uint8_t SD_ReadSingleBlock(uint32_t Address);
#endif /* SD_INTERFACE_H_ */
SD_Interface.c
#include "Peripheral/SD/SD.h"
#include "Peripheral/SD/Interface/SD_Interface.h"
static SD_CardType_t CardType = SD_VER_UNKNOWN;
SD_Error_t SD_InitInterface(SPI_Config_t* Config)
{
SD_Error_t ErrorCode = SD_SUCCESSFULL;
// Set SD card CS as output in high state
GPIO_SetDirection(SD_SS_PORT, SD_SS_PIN, GPIO_DIRECTION_OUT);
GPIO_Set(SD_SS_PORT, SD_SS_PIN);
if(Config != NULL)
{
SD_SPI_INIT(Config);
}
// Reset the SD card
ErrorCode = SD_SoftwareReset();
if(ErrorCode != SD_SUCCESSFULL)
{
return ErrorCode;
}
// Initialize the SD card
ErrorCode = SD_InitializeCard();
if(ErrorCode != SD_SUCCESSFULL)
{
return ErrorCode;
}
// Set the block length to 512 (only necessary if the card is not a SDXC or SDHX card)
if((CardType != SD_VER_2_HI) & (CardType != SD_VER_2_STD))
{
ErrorCode = SD_SetBlockLength(SD_BLOCK_SIZE);
if(ErrorCode != SD_SUCCESSFULL)
{
return ErrorCode;
}
}
return ErrorCode;
}
/*
void SD_ReadCSD(void)
{
uint8_t Buffer[16];
uint8_t R1 = SD_Command(SD_ID_TO_CMD(9), 0x00000000, 0x00000000, 16, Buffer);
}
void SD_ReadCID(void)
{
uint8_t Buffer[16];
uint8_t R1 = SD_Command(SD_ID_TO_CMD(10), 0x00000000, 0x00000000, 16, Buffer);
SD_CID_t* T = (SD_CID_t*)Buffer;
}*/
uint8_t SD_Command(uint8_t Command, uint32_t Arg, uint8_t Checksum, uint32_t Count, uint8_t* Buffer)
{
// Create 8 clock pulse before activating the card
SD_SPI_TRANSMIT(0xFF);
SD_SPI_CHIP_SELECT(SD_SS_PORT, SD_SS_PIN);
SD_SPI_TRANSMIT(Command);
SD_SPI_TRANSMIT(Arg >> 0x18);
SD_SPI_TRANSMIT(Arg >> 0x10);
SD_SPI_TRANSMIT(Arg >> 0x08);
SD_SPI_TRANSMIT(Arg);
SD_SPI_TRANSMIT(Checksum);
/*
Wait for the response (0 - 8 bytes for SD cards and 1 - 8 bytes for MMC)
The spec also say that you have to wait 8 clock cycles after the last bus
transaction.
*/
for(uint8_t i = 0; i < 0x08; i++)
{
uint8_t DataIn = SD_SPI_TRANSMIT(0xFF);
if(DataIn != 0xFF)
{
// Read all additional data
if(Count > 0)
{
for(uint32_t j = 0x01; j < Count; j++)
{
*Buffer++ = SD_SPI_TRANSMIT(0xFF);
}
}
// Send a dummy byte and deselect the card after it
SD_SPI_TRANSMIT(0xFF);
SD_SPI_CHIP_UNSELECT(SD_SS_PORT, SD_SS_PIN);
return DataIn;
}
}
SD_SPI_CHIP_UNSELECT(SD_SS_PORT, SD_SS_PIN);
return SD_NO_RESPONSE;
}
SD_Error_t SD_SoftwareReset(void)
{
uint8_t Repeat = 0x00;
//SD_SPI_CHIP_SELECT(SD_SS_PORT, SD_SS_PIN);
for(uint8_t i = 0x00; i < 0x0A; i++)
{
SD_SPI_TRANSMIT(0xFF);
}
SD_SPI_CHIP_UNSELECT(SD_SS_PORT, SD_SS_PIN);
while(SD_Command(SD_ID_TO_CMD(0), 0x00000000, 0x95, 0, 0) != SD_STATE_IDLE)
{
// Initialization failed
if(Repeat++ == 10)
{
return SD_NO_RESPONSE;
}
}
return SD_SUCCESSFULL;
}
SD_Error_t SD_InitializeCard(void)
{
uint16_t Wait = 0x00;
uint32_t R3 = 0x00;
uint8_t R1 = 0xFF;
uint8_t Buffer[4];
R1 = SD_Command(SD_ID_TO_CMD(8), 0x000001AA, 0x87, 4, Buffer);
if(R1 == SD_STATE_IDLE)
{
/*
Version 2 SD card
*/
R3 = ((uint32_t)Buffer[3]) << 0x18;
R3 |= ((uint32_t)Buffer[2]) << 0x10;
R3 |= ((uint32_t)Buffer[1]) << 0x08;
R3 |= ((uint32_t)Buffer[0]);
/*
if(R3 != 0x000001AA)
{
return SD_UNSUPPORTED_CARD;
}*/
// Send ACMD41 and check for ready
R1 = 0xFF;
while((++Wait < 0x2710) & (R1 != SD_STATE_SUCCESSFULL))
{
SD_Command(SD_ID_TO_CMD(55), 0x00000000, 0x00, 0, 0);
R1 = SD_Command(SD_ID_TO_CMD(41), 0x40000000, 0x00, 0, 0);
}
if((Wait >= 0x2710) | (R1 != SD_STATE_SUCCESSFULL))
{
return SD_TIMEOUT;
}
// Send CMD58 to read OCR
R1 = SD_Command(SD_ID_TO_CMD(58), 0x00000000, 0x00, 4, Buffer);
if(R1 == SD_STATE_SUCCESSFULL)
{
R3 = ((uint32_t)Buffer[3]) << 0x18;
R3 |= ((uint32_t)Buffer[2]) << 0x10;
R3 |= ((uint32_t)Buffer[1]) << 0x08;
R3 |= ((uint32_t)Buffer[0]);
}
else
{
CardType = SD_VER_UNKNOWN;
}
// Check if the CCS bit is set
if(R3 & 0x40000000)
{
CardType = SD_VER_2_HI;
}
else
{
CardType = SD_VER_2_STD;
}
}
else
{
/*
Version 1 SD card or MMC
*/
// Check for version 1 SD card
Wait = 0x00;
while(++Wait < 0xFF)
{
SD_Command(SD_ID_TO_CMD(55), 0x00000000, 0, 0, 0);
R1 = SD_Command(SD_ID_TO_CMD(41), 0x00000000, 0, 0, 0);
if(R1 == SD_STATE_SUCCESSFULL)
{
CardType = SD_VER_1_STD;
break;
}
}
// Check for multimedia card
Wait = 0x00;
if(R1 & SD_STATE_ILLEGAL_COMMAND)
{
while(++Wait < 0xFF)
{
R1 = SD_Command(SD_ID_TO_CMD(1), 0x00000000, 0, 0, 0);
if(R1 == SD_STATE_SUCCESSFULL)
{
CardType = SD_MMC;
break;
}
}
}
}
return SD_SUCCESSFULL;
}
SD_CardType_t SD_GetCardType(void)
{
return CardType;
}
uint8_t SD_SetBlockLength(uint32_t BlockLength)
{
return SD_Command(SD_ID_TO_CMD(16), 0x00000200, 0xFF, 0, 0);
}
uint8_t SD_ReadSingleBlock(uint32_t Address)
{
uint8_t R1 = 0x00;
uint16_t Wait = 0x00;
uint32_t Offset = 0x00;
uint32_t Len = 10;
uint8_t Buffer[512];
uint32_t Sector = 0x00;
SD_SPI_TRANSMIT(0xFF);
SD_SPI_CHIP_SELECT(SD_SS_PORT, SD_SS_PIN);
SD_SPI_TRANSMIT(SD_ID_TO_CMD(17));
SD_SPI_TRANSMIT(0);
SD_SPI_TRANSMIT(0);
SD_SPI_TRANSMIT(0);
SD_SPI_TRANSMIT(0x00);
SD_SPI_TRANSMIT(0xFF);
// Wait for 0x00
R1 = 0xFF;
while((++Wait < 0x2710) & (R1 != SD_STATE_SUCCESSFULL))
{
R1 = SD_SPI_TRANSMIT(0xFF);
}
if((Wait >= 0x2710) | (R1 != SD_STATE_SUCCESSFULL))
{
return SD_TIMEOUT;
}
// Wait for 0xFE
Wait = 0x00;
R1 = 0xFF;
while((++Wait < 0x2710) & (R1 != SD_STATE_BEGIN_TRANSMISSION))
{
R1 = SD_SPI_TRANSMIT(0xFF);
}
if((Wait >= 0x2710) | (R1 != SD_STATE_BEGIN_TRANSMISSION))
{
return SD_TIMEOUT;
}
for(uint32_t i = 0x00; i < Offset; i++)
{
SD_SPI_TRANSMIT(0xFF);
}
for(uint32_t i = 0x00; i < Len; i++)
{
Buffer[i] = SD_SPI_TRANSMIT(0xFF);
}
for(uint32_t i = 0x00; i < 512 - Offset; i++)
{
SD_SPI_TRANSMIT(0xFF);
}
// skip checksum
SD_SPI_TRANSMIT(0xFF);
SD_SPI_TRANSMIT(0xFF);
SD_SPI_CHIP_UNSELECT(SD_SS_PORT, SD_SS_PIN);
return;
}
Puedo inicializar la tarjeta sd. La llamada
SD_Error_t Status = SD_InitInterface(Config);
devuelve SD_SUCCESSFULL
y la tarjeta se detecta como SD_VER_2_STD
(4 GB micro sdhc).
Pero si trato de leer 512 bytes del primer sector de la tarjeta, me convierto en un búfer que se llena con 0x00 (verificado por el depurador). Pero la tarjeta no está vacía. He comprobado el contenido con HxD (ver captura de pantalla).
Entonces, ¿cuál es el problema? No tengo idea de lo que está pasando aquí.
Gracias.