2016-12-28 12:45 PM
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.
2016-12-28 01:40 PM
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 */
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2016-12-30 04:49 AM
,
,
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 == 1DRESULT
SD_write
(
BYTElun
,
const
BYTE*
buff
,
DWORDsector
,
UINTcount
)
{
,
DRESULTres
=
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
)
,
,
}
,
returnres
,
}
♯ endif
/* _USE_WRITE == 1 */