cancel
Showing results for 
Search instead for 
Did you mean: 

[BUG] FatFS + SDIO(DMA) L4

ChrisH
Associate III
Posted on December 28, 2016 at 21:45

Drivers supplied with CubeMX don't check if data that fatfs tries to write is properly aligned (32bit) this results in misaligned address send to DMA controller which is forced to be realigned and results in wrong data being written to the card.

2 REPLIES 2
Posted on December 28, 2016 at 22:40

Did it pass through a user buffer that was unaligned?

I'd added this code back in the day, ST has used without attribution subsequently

/**
 * @brief Writes Sector(s)
 * @param pdrv: Physical drive number (0..)
 * @param *buff: Data to be written
 * @param sector: Sector address (LBA)
 * @param count: Number of sectors to write (1..128)
 * @retval DRESULT: Operation result
 */
#if _USE_WRITE == 1
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;
#ifdef DBG_IO
 printf('disk_write %d %p %10d %d
',pdrv,buff,sector,count);
#endif
 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_WriteMultiBlocksFIXED((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 /* _USE_WRITE == 1 */
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on December 30, 2016 at 12:49

 ,

 ,

Clive, I ended up with simmilar approach however I take adavatage ,of multiple block write to get better performance (maybe?). Anyway my code is modification of SD Driver supplied by ST with Cube.

/**

 , * @brief , Writes Sector(s)

 , * @param , lun : not used

 , * @param , *buff: Data to be written

 , * @param , sector: Sector address (LBA)

 , * @param , count: Number of sectors to write (1..128)

 , * @retval DRESULT: Operation result

 , */

♯ if

_USE_WRITE == 1

DRESULT

SD_write

(

BYTE

lun

,

const

BYTE

*

buff

,

DWORD

sector

,

UINT

count

)

{

 ,

DRESULT

res

=

RES_OK

,

 ,

uint8_t

*

aligned

=

buff

,

 ,

uint8_t

*

temp

,

 ,

if

((

size_t

)

buff

&,

3

)

{

 ,

//Align data

 ,

aligned

=

temp

=

pvPortMalloc

((

BLOCK_SIZE

*

count

)

+

4

)

,

 ,

aligned

+=

4

-

((

size_t

)

aligned

&,

3

)

,

 ,

memcpy

(

aligned

,

buff

,

BLOCK_SIZE

*

count

)

,

 ,

}

 ,

if

(

BSP_SD_WriteBlocks_DMA

((

uint32_t

*

)

aligned

,

 ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,

(

uint64_t

)(

sector

*

BLOCK_SIZE

)

,

 ,

 ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  , BLOCK_SIZE

,

count

)

!=

MSD_OK

)

 ,

{

 ,  ,

res

=

RES_ERROR

,

 ,

}

 , ,

 ,

if

((

size_t

)

buff

&,

3

)

{

 ,

vPortFree

(

temp

)

,

 ,

}

 ,

return

res

,

}

♯ endif

/* _USE_WRITE == 1 */