cancel
Showing results for 
Search instead for 
Did you mean: 

Interfacing STM32F103ZE to SD Card

mohamed2
Associate II
Posted on December 23, 2015 at 18:06

The original post was too long to process during our migration. Please click on the attachment to read the original post.
5 REPLIES 5
Posted on December 23, 2015 at 19:04

Seems like a bit of a mish-mash of code there from different sources. Do the SDIO routine your calling into use block or byte addressing.  The latter will have issues with cards >2GB. Why are there two sets of read/write implementations?

You should start by validating your SD read/write level code before using it in the FatFs abstraction layer. Once you understand those routines, remove all the irrelevant clutter from the diskio.c

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mohamed2
Associate II
Posted on December 23, 2015 at 23:34

Hello clive, thanks for your fast reply. I am testing on 8GB SD Card and according to your reply (correct me if I am wrong), I should use byte addressing because my card is greater than 2GB. so that what i am doing as you see in those lines

Status = SD_ReadMultiBlocks(buff, sector, BLOCK_SIZE, count);

Status = SD_WriteMultiBlocks((uint8_t *)buff, sector, BLOCK_SIZE, count);

you are right I am using codes from different sources, for the low level code I am using files provided from std peripheral libraries examples stm32_eval_sdio_sd.c & stm32_eval_sdio_sd.h. I even tested the test functions in this application (Erase, Read Block & Write block) and they work fine, and after I connect my SD Card to my PC, the windows ask me to format the card as FAT32 as expected because I already wrote data on it which wasn't in FAT format. Next step for me was to get the Chan library but as I said up there it writes into a file (please check the application code up) but when i take the card back to my PC i can't find the text file i created, i think i am missing something or a step I am not sure.

Posted on December 24, 2015 at 00:44

Actually that's block addressing, but that's what you want.

What's critical here however is the SDIO code below this has been coded for block addressing, because most of ST's code fails in this regard, and that the code supports SD and SDHC cards, which behave differently than MMC ones. Also not sure if the F1 implementation uses DMA or not. May be the best approach here would be to ZIP up all the components you are bringing together, rather than a few selective files. I don't have any F1 parts/boards with SDIO support, but may be we can get an example worked out. diskio.c should look something like

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include ''diskio.h'' /* FatFs lower layer API */
#include ''stm32_eval_sdio_sd.h'' /* Example: Header file of existing MMC/SDC control module */
#include <
string.h
> // memcpy
#define BLOCK_SIZE 512 /* Block Size in Bytes */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
DSTATUS stat = RES_OK;
if (SD_Detect() != SD_PRESENT)
{
stat |= STA_NODISK;
} 
else if (SD_GetState() == SD_CARD_ERROR)
{
stat |= STA_NOINIT;
}
else
{
stat = RES_OK;
}
return stat;
}
/*-----------------------------------------------------------------------*/
/* Initialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
DSTATUS stat = RES_OK;
if (SD_Init() != SD_OK)
{
stat |= (STA_NOINIT); 
}
else
{
stat = RES_OK;
}
// translate the result code here
return stat;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive number to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
SD_Error Status;
if (SD_Detect() != SD_PRESENT)
return(RES_NOTRDY);
if ((DWORD)buff & 3) // DMA Alignment failure, do single up to aligned buffer
{
DRESULT res = RES_OK;
DWORD scratch[BLOCK_SIZE / 4]; // Alignment assured, you'll need a sufficiently big stack
while(count--)
{
res = disk_read(pdrv, (void *)scratch, sector++, 1);
if (res != RES_OK)
break;
memcpy(buff, scratch, BLOCK_SIZE);
buff += BLOCK_SIZE;
}
return(res);
}
Status = SD_ReadMultiBlocks(buff, sector, BLOCK_SIZE, count); // 4GB Compliant
if (Status == SD_OK)
{
SDTransferState State;
Status = SD_WaitReadOperation(); // Check if the Transfer is finished
while((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
if ((State == SD_TRANSFER_ERROR) || (Status != SD_OK))
return(RES_ERROR);
else
return(RES_OK);
}
else
return(RES_ERROR);
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (
BYTE pdrv, /* Physical drive number to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
SD_Error Status;
if (SD_Detect() != SD_PRESENT)
return(RES_NOTRDY);
if ((DWORD)buff & 3) // DMA Alignment failure, do single up to aligned buffer
{
DRESULT res = RES_OK;
DWORD scratch[BLOCK_SIZE / 4]; // Alignment assured, you'll need a sufficiently big stack
while(count--)
{
memcpy(scratch, buff, BLOCK_SIZE);
res = disk_write(pdrv, (void *)scratch, sector++, 1);
if (res != RES_OK)
break;
buff += BLOCK_SIZE;
}
return(res);
}
Status = SD_WriteMultiBlocks((uint8_t *)buff, sector, BLOCK_SIZE, count); // 4GB Compliant
if (Status == SD_OK)
{
SDTransferState State;
Status = SD_WaitWriteOperation(); // Check if the Transfer is finished
while((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
if ((State == SD_TRANSFER_ERROR) || (Status != SD_OK))
return(RES_ERROR);
else
return(RES_OK);
}
else
return(RES_ERROR);
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive number (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
// Process of the command for the MMC/SD card
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _FS_NORTC == 0
DWORD get_fattime (void)
{
/* 
This function is not needed when _FS_READONLY == 1 or _FS_NORTC == 1.
If there is RTC (real time clock) this function should return the 
Current local time is returned with packed into a DWORD value. The bit field is as follows:
bit31:25
Year origin from the 1980 (0..127)
bit24:21
Month (1..12)
bit20:16
Day of the month(1..31)
bit15:11
Hour (0..23)
bit10:5
Minute (0..59)
bit4:0
Second / 2 (0..29)
*/
//// for now a fixed current local time will be returned (22-12-2015 4:06:50)
SHORT year = 2015;
BYTE month = 12;
BYTE day = 22;
BYTE hour = 4;
BYTE minute = 20;
BYTE second = 0;
return (((year-1980) << 
25
) // 
Year
= 
2011
| (month << 21) // 
Month
= 
Mar
| (day << 16) // 
Day
= 
26
| (hour << 11) // 
Hour
= 
22
| (minute << 5) // 
Min
= 
30
| (second >> 1) // Sec = 0
);
}
#endif

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mohamed2
Associate II
Posted on December 26, 2015 at 05:41

Thanks so much I used your code, but I just changed 2 lines

Status = SD_ReadMultiBlocks(buff, sector, BLOCK_SIZE, count); // 4GB Compliant

replaced with

Status = SD_ReadMultiBlocks(buff, sector << 9, BLOCK_SIZE, count);

&

Status = SD_WriteMultiBlocks((uint8_t *)buff, sector , BLOCK_SIZE, count); 
// 4GB Compliant

with

Status = SD_WriteMultiBlocks((uint8_t *)buff, sector << 9, BLOCK_SIZE, count); 
// 4GB Compliant

hope that would be helpful for someone, can you please help me figure out how just changing those lines made the code works?thanks in advance
Posted on December 26, 2015 at 16:37

Ok, but that's byte addressing. You need to be very careful about the math and parameters here, and they are 64-bit, otherwise anything above 4GB is going to wrap.

The DISKIO code and the SDIO code need to have a common interface. ST's original code uses byte addressing, and later versions used 64-bit parameters to contain that. I've provided a number of libraries that use block addressing which can use 32-bit parameters and support 2TB. The media is accessed via blocks, so multiplying a sector/block by the block size, and then subsequently dividing it, is an inefficient method. It becomes more inefficient when the divide is not done in hardware, and I'm sure none of the Cortex parts support a rapid 64-bit divide.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..