Skip to main content
ChrisH
Associate III
December 28, 2016
Question

[BUG] FatFS + SDIO(DMA) L4

  • December 28, 2016
  • 2 replies
  • 603 views
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.

    This topic has been closed for replies.

    2 replies

    Tesla DeLorean
    Guru
    December 28, 2016
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    ChrisH
    ChrisHAuthor
    Associate III
    December 30, 2016
    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 */