I am using STM32F4-development board with a STM32F407 chip. To communicate with the SD card I use SPI1, and are using the FatFs library created by Chan.
So the gist of the problem is that I have successfully managed to create a file on the SD card, I am able to read from it. But when I try to write to the file it either corrupts the file or prints garbage data like this "{46040EDD-C". If I look at the memmory I can see the stuff I wrote, but somehow it is being written to the wrong memmory address.
Another problem that I have is that the first time I create a file and try to write to it with f_write I get the reply FR_DISK_ERR. The error comes form trying to create a cluster chain, when I step trough the code it works fine. So It might be some delay missing. The next time I run the programm it works, and f_write returns FR_OK.
I am not sure if these problems are related or not. I have been trying to get this to work for about two weeks now and would love any help I can get. Thank you.
The code:
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 file that I have edited.
#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
}