Estoy utilizando la placa de desarrollo STM32F4 con un chip STM32F407. Para comunicarme con la tarjeta SD, uso SPI1, y estoy usando la biblioteca FatFs creada por Chan.
Por lo tanto, lo esencial del problema es que logré crear un archivo en la tarjeta SD, puedo leerlo. Pero cuando intento escribir en el archivo, se corrompe el archivo o se imprimen datos basura como este "{46040EDD-C". Si miro el memmory puedo ver lo que escribí, pero de alguna manera se está escribiendo en la dirección de memmory incorrecta.
Otro problema que tengo es que la primera vez que creo un archivo y trato de escribirlo con f_write obtengo la respuesta FR_DISK_ERR. El error se produce cuando se trata de crear una cadena de clústeres, cuando paso por el código funciona bien. Por lo que podría ser algún retraso que falta. La próxima vez que ejecute el programa, funcionará, y f_write devuelve FR_OK.
No estoy seguro de si estos problemas están relacionados o no. He estado tratando de hacer que esto funcione durante aproximadamente dos semanas y me encantaría cualquier ayuda que pueda obtener. Gracias.
El código:
main.c
int main(void)
{
int i;
//SD CARD INIT
//Fatfs object
FATFS FatFs;
//File object
FIL fil;
UINT fa;
FRESULT res_mount, res_open, res_seek, res_write;
delay(10ms);
res_mount = f_mount(&FatFs, "", 1);
if (res_mount == FR_OK) {
GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
delay(10ms);
res_open = f_open(&fil, "test.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
if (res_open == FR_OK) {
GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
delay(10ms);
res_seek = f_lseek(&fil, f_size(&fil));
if(res_seek == FR_OK)
{
delay(10ms);
GPIO_ToggleBits(GPIOD, GPIO_Pin_14);
res_write = f_write(&fil, "Alpha Beta\n", 11, &fa);
if (fa > 0 && res_write == FR_OK) {
GPIO_ToggleBits(GPIOD, GPIO_Pin_15);
f_sync(&fil);
}
}
f_close(&fil);
}
f_mount(0, "", 1);
}
while(1);
//SD CARD INIT END
}
Chans diskio.c archivo que he editado.
#include "diskio.h" /* FatFs lower layer API */
/* Definitions of physical drive number for each drive */
#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */
static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */
static BYTE CardType; /* Card type flags (b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing) */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
if(pdrv)
return STA_NOINIT; // Supports only drive 0
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
if (Stat & STA_NODISK)
return Stat; /* No card in the socket? */
//SLOW
uint8_t ty = 0;
ty = SD_CARD_InitialiseCard();
CardType = ty;
if(ty)
Stat &= ~STA_NOINIT;
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
//DRESULT res;
//int result;
if(pdrv || !count)
return RES_PARERR;
if (Stat & STA_NOINIT)
return RES_NOTRDY;
if(!(CardType & SDCARD_BLOCK))
sector *= 512;
if(count == 1)
{
if((SD_CARD_Cmd(READ_SINGLE_BLOCK, sector) == 0x00) && SD_CARD_Read(buff, 512))
count = 0;
}
else
{
if(SD_CARD_Cmd(READ_MULTIPLE_BLOCKS, sector) == 0)
{
do
{
if(!SD_CARD_Read(buff, 512))
break;
buff += 512;
}
while(--count);
SD_CARD_Cmd(STOP_TRANSMISSION, 0);
}
}
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
//DRESULT res;
//int result;
if (pdrv || !count)
return RES_PARERR;
if (Stat & STA_NOINIT)
return RES_NOTRDY;
if (Stat & STA_PROTECT)
return RES_WRPRT;
if(!(CardType & SDCARD_BLOCK))
sector *= 512;
if(count == 1)
{
if((SD_CARD_Cmd(WRITE_SINGLE_BLOCK, sector) == 0x00) && SD_CARD_Write(buff, 0xFE))
count = 0;
}
else
{
if (CardType & SDCARD_SDC)
SD_CARD_Cmd(SET_WR_BLOCK_ERASE_COUNT, count);
if(SD_CARD_Cmd(WRITE_MULTIPLE_BLOCKS, sector) == 0)
{
do
{
if(!SD_CARD_Write(buff, 0xFC))
break;
buff += 512;
}
while(--count);
if (!SD_CARD_Write(0, 0xFD)) /* STOP_TRAN token */
count = 1;
}
}
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
//DRESULT res;
//int result;
//NOT NEEDED AT THE MOMENT
return RES_PARERR;
}
DWORD get_fattime (void)
{
/* Pack date and time into a DWORD variable */
return ((DWORD)(2017 - 1980) << 25)
| ((DWORD)1 << 21)
| ((DWORD)1 << 16)
| ((DWORD)0 << 11)
| ((DWORD)0 << 5)
| ((DWORD)0 >> 1);
}
SD_CARD.c:
#include "SD_CARD.h"
/*
SPI1(GPIOA): - Type: - SD CARD:
Pin4 - CS - Pin2
Pin5 - SCLK - Pin5
Pin6 - MISO - Pin7
Pin7 - MOSI - Pin3
*/
uint8_t SD_CARD_InitialiseCard()
{
INT i = 0;
SPI1ENABLE();
ChipSelect(SPI1, HIGH);
for(i = 0;i < 16;i++)
SPI_Send(SPI1, 0xFF);
for(i = 0;i < 0xFFFF;i++);
while(SD_CARD_Cmd(GO_IDLE_STATE, 0) != R1_IDLE_STATE); //CMD0
uint32_t r = SD_CARD_Cmd(SEND_IF_COND, 0x1AA); //CMD8
if(r == 0x1AA)
return SD_CARD_InitialiseCardV2();
else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND))
return SD_CARD_InitialiseCardV1();
else
return SDCARD_FAIL;
}
uint8_t SD_CARD_WriteRead(INT arg)
{
SPI_Send(SPI1, arg);
uint8_t test = SPI_Read(SPI1);
return test;
}
uint8_t SD_CARD_InitialiseCardV1()
{
uint8_t cmd;
INT i = 0;
if(SD_CARD_Cmd(SD_SEND_OP_COND, 0x40040000) <= 1) //ACMD41 - set to 3V, use 0x40200000 for 3V3
cmd = SD_SEND_OP_COND;
else
cmd = SEND_OP_COND;
for(i = 0; i < SD_COMMAND_TIMEOUT;i++)
{
if(SD_CARD_Cmd(cmd, 0) == 0) //CMD1 or ACMD41
{
// Set block length to 512 (CMD16)
if(SD_CARD_Cmd(SET_BLOCKLEN, 512) != 0) //CMD16
return SDCARD_FAIL;
//Init: SEDCARD_V1
if(cmd == SD_SEND_OP_COND)
return SDCARD_V1;
else
return SDCARD_MMCV3;
}
}
//Timeout waiting for v1.x card
return SDCARD_FAIL;
}
uint8_t SD_CARD_InitialiseCardV2()
{
INT i = 0;
INT j = 0;
for(i = 0;i < SD_COMMAND_TIMEOUT;i++)
{
for(j = 0;j < 0xFF;j++);
if(SD_CARD_Cmd(SD_SEND_OP_COND, 0x40040000) == 0) //ACMD41 - set to 3V, use 0x40200000 for 3V3
{
uint32_t ocr = SD_CARD_Cmd(READ_OCR, 0); //CMD58
return (ocr & 0x40000000) ? SDCARD_V2 | SDCARD_BLOCK : SDCARD_V2;
}
}
//Timed out waiting for v2.x card
return SDCARD_FAIL;
}
uint32_t SD_CARD_Cmd(INT cmd, INT arg)
{
struct command_fields com;
com.start_bit = 0;
com.transmitter_bit = 1;
com.index = cmd;
com.argument = arg;
if(cmd == GO_IDLE_STATE)
com.crc = 0x4A;
else if(cmd == SEND_IF_COND)
com.crc = 0x43;
else
com.crc = 0x7F;
com.end_bit = 1;
if(cmd == SD_STATUS | cmd == SET_WR_BLOCK_ERASE_COUNT | cmd == SD_SEND_OP_COND) //ACMDx
SD_CARD_Cmd(APP_CMD, 0); //CMD55
SD_CARD_WriteCom(&com);
if(cmd == SEND_IF_COND)
return SD_CARD_RecieveR7();
else if(cmd == READ_OCR)
return SD_CARD_RecieveR3();
else
return SD_CARD_RecieveR1();
}
void SD_CARD_WriteCom(struct command_fields *com)
{
ChipSelect(SPI1, LOW);
SPI_Send(SPI1, 0xFF);
SPI_Send(SPI1, (0xFF & ((com->start_bit << 7) | (com->transmitter_bit << 6) | com->index)));
SPI_Send(SPI1, (0xFF & (com->argument >> 24)));
SPI_Send(SPI1, (0xFF & (com->argument >> 16)));
SPI_Send(SPI1, (0xFF & (com->argument >> 8)));
SPI_Send(SPI1, (0xFF & com->argument));
SPI_Send(SPI1, (0xFF & ((com->crc << 1) | com->end_bit)));
}
INT SD_CARD_Write(const BYTE *buffer, BYTE token)
{
INT i = 0;
ChipSelect(SPI1, LOW);
while(SD_CARD_WriteRead(0xFF) != 0xFF);
// indicate start of block
SPI_Send(SPI1, token);
if(token != 0xFD)
{
// write the data
for(i = 0;i < 512;i++)
{
SPI_Send(SPI1, *buffer);
buffer++;
}
// write the checksum
SPI_Send(SPI1, 0xFF);
SPI_Send(SPI1, 0xFF);
// check the repsonse token
if(((SD_CARD_WriteRead(0xFF)) & 0x1F) != 0x05)
{
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return SUCCESS;
}
}
// wait for write to finish
while(SD_CARD_WriteRead(0xFF) != 0xFF);
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return ERROR;
}
INT SD_CARD_Read(BYTE *buffer, INT length)
{
INT i = 0;
ChipSelect(SPI1, LOW);
for(i = 0; i < SD_COMMAND_TIMEOUT;i++)
{
// read until start byte (0xFF)
if(SD_CARD_WriteRead(0xFF) == 0xFE)
{
// read data
for(i = 0;i < length;i++)
buffer[i] = SD_CARD_WriteRead(0xFF);
SPI_Send(SPI1, 0xFF); // checksum
SPI_Send(SPI1, 0xFF);
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return SUCCESS;
}
}
return ERROR;
}
uint8_t SD_CARD_RecieveR1()
{
INT i;
uint8_t response = 0xFF;
for(i = 0;i < SD_COMMAND_TIMEOUT;i++)
{
response = SD_CARD_WriteRead(0xFF);
if((response == 0x00) || (response == 0x01))
{
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return response;
}
}
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return 0xFF;
}
uint32_t SD_CARD_RecieveR7()
{
INT i = 0, j = 0;
for(i = 0;i < (SD_COMMAND_TIMEOUT * 1000);i++)
{
uint8_t response[5];
response[0] = SD_CARD_WriteRead(0xFF);
if(!(response[0] & 0x80))
{
for(j = 1;j < 5;j++)
{
response[j] = SD_CARD_WriteRead(0xFF);
}
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return ((response[1] << 24) | (response[2] << 16) | (response[3] << 8) | response[4]);
}
}
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return 0xFFFFFFFF; // timeout
}
uint32_t SD_CARD_RecieveR3()
{
uint32_t ocr = 0;
INT response;
for(int i=0; i < SD_COMMAND_TIMEOUT; i++)
{
response = SD_CARD_WriteRead(0xFF);
if(!(response & 0x80))
{
ocr = SD_CARD_WriteRead(0xFF) << 24;
ocr |= SD_CARD_WriteRead(0xFF) << 16;
ocr |= SD_CARD_WriteRead(0xFF) << 8;
ocr |= SD_CARD_WriteRead(0xFF);
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return ocr;
}
}
ChipSelect(SPI1, HIGH);
SPI_Send(SPI1, 0xFF);
return 0xFFFFFFFF; // timeout
}
INT SD_CARD_InitialiseDisk()
{
if(SD_CARD_InitialiseCard() == SDCARD_FAIL)
return SDCARD_FAIL;
SPI_SetSpeed(SPI1, SPI_SPEED_1300KHz);
return SUCCESS;
}
SPI.c:
#include "SPI.h"
void SPI1ENABLE()
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
static uint8_t SPI1_ENABLED = 0;
if(SPI1_ENABLED)
return;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
GPIO_InitStruct.GPIO_Pin = SPI1_SCLK | SPI1_MISO | SPI1_MOSI;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = SPI1_CS;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA, &GPIO_InitStruct);
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE);
SPI1_ENABLED = 1;
}
uint8_t SPI_Read(SPI_TypeDef* SPIx)
{
while(SPI1->SR & SPI_I2S_FLAG_BSY); // wait until SPI is not busy anymore
while(!(SPI1->SR & SPI_I2S_FLAG_RXNE)); // wait until receive complete
return SPI_ReceiveData(SPIx);
}
void SPI_Send(SPI_TypeDef* SPIx, unsigned char Data)
{
while(SPI1->SR & SPI_I2S_FLAG_BSY); // wait until SPI is not busy anymore
while(!(SPI1->SR & SPI_I2S_FLAG_TXE)); // wait until transmit complete
SPI_SendData(SPIx, Data);
while(!(SPI1->SR & SPI_I2S_FLAG_RXNE)); // wait until receive complete
}