B6DB6E37 188C46A3 52291788 44A2512B 168B46A3 52291708 84C2E173 BADDED75 391F0C86 C3E271BB DEEF743A 1D8D4521 934A2511 8BC663B2 59AFD4EA F579BF5C AED768B4 5A2D9549 27904824 12090780 C0E0F078 BC5E2F14 0A058143 A2D1EBF6 FBFE7F3C 1E8FC4E2 F1FBFE7F BCDE6F34 1A8DC5E1 733A9D4D A5D1EBF6 7BBEDF6C B65B2E97 C8E4F279 BFDCEE77 B85C2E97 48A452A9 57A8D46A 35190F04 8241A352 A9D7E8F4 FA7D3D9D 4DA5512B 160B0683 C2E1F3FA FDFD7D3D 9D4D2511 8B462392 49279048 249249A7 50A8542A 15098740 2090C8E4 F279BFDC 6EB7D8EC F6FB7EBF DC6E3718 8C46A3D2 E977381C 8E472090 48A4D269 3798CCE6 733A1D8D C561339A 4DA551AB 562B96CB 66B3DAED 75391F8C C663B2D9 6FB45AAD D5E97738 1C8EC760 30180C86 C3E2713B 9ECFE472 B95F2C16 8BC6E372 399FCCE6 F37A3D9D CDE5713B 9ECFE4F2 F9FFFCFE 7F3C9E4F A4522917 88C46231 1B8EC760 B0582C16 0B060302 0183C2E1 F3FA7DBD DD6D3599 CF643219 8F44A2D1 6B369B4E A7502894 CAE5F17B BEDF6C36 9B4E2790 C8E47239 1F0C86C3 E2F17BBE 5FACD6EB F67B3E9F 4CA6D3EA F5F97FBC DEEFF47A 3D1D0D85 41231289 47A0D068 341A0D05 81432211 8B462392 49A7D0E8 F47A3D9D 4DA5D1EB 76BB5E2F 148AC561 B35AAD55 A9572814 8A45A1D3 EA75391F 8CC663B2 592F148A 452193CA 65311B0E 0780C060 30188C46 23924927 |
6FB4B6DB 6E37188C 46A35229 178844A2 512B168B 46A35229 170884C2 E173BADD ED75391F 0C86C3E2 71BBDEEF 743A1D8D 4521934A 25118BC6 63B259AF D4EAF579 BF5CAED7 68B45A2D 95492790 48241209 0780C0E0 F078BC5E 2F140A05 8143A2D1 EBF6FBFE 7F3C1E8F C4E2F1FB FE7FBCDE 6F341A8D C5E1733A 9D4DA5D1 EBF67BBE DF6CB65B 2E97C8E4 F279BFDC EE77B85C 2E9748A4 52A957A8 D46A3519 0F048241 A352A9D7 E8F4FA7D 3D9D4DA5 512B160B 0683C2E1 F3FAFDFD 7D3D9D4D 25118B46 23924927 90482492 49A750A8 542A1509 87402090 C8E4F279 BFDC6EB7 D8ECF6FB 7EBFDC6E 37188C46 A3D2E977 381C8E47 209048A4 D2693798 CCE6733A 1D8DC561 339A4DA5 51AB562B 96CB66B3 DAED7539 1F8CC663 B2D96FB4 5AADD5E9 77381C8E C7603018 0C86C3E2 713B9ECF E472B95F 2C168BC6 E372399F CCE6F37A 3D9DCDE5 713B9ECF E4F2F9FF FCFE7F3C 9E4FA452 291788C4 62311B8E C760B058 2C160B06 03020183 C2E1F3FA 7DBDDD6D 3599CF64 32198F44 A2D16B36 9B4EA750 2894CAE5 F17BBEDF 6C369B4E 2790C8E4 72391F0C 86C3E2F1 7BBE5FAC D6EBF67B 3E9F4CA6 D3EAF5F9 7FBCDEEF F47A3D1D 0D854123 128947A0 D068341A 0D058143 22118B46 239249A7 D0E8F47A 3D9D4DA5 D1EB76BB 5E2F148A C561B35A AD55A957 28148A45 A1D3EA75 391F8CC6 63B2592F 148A4521 93CA6531 1B0E0780 C0603018 8C462300 |
Hi,
There is no easy solution to this. I have found a walk-around which is slower but eats less RAM and user only when the read/write buffer is misaligned. On other case the standard multiblock read is used.
/**
* @brief Read Sector(s)
* @param drv : driver index
* @param buff : Pointer to the data buffer to store read data
* @param sector : Start sector number
* param count : Sector count (1..255)
* @retval DSTATUS : operation status
*/
DRESULT disk_read (
BYTE drv, /* Physical drive number (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Sector count (1..255) */
)
{
uint32_t timeout = 100000;
SD_Error sdstatus = SD_OK;
DWORD scratch [BLOCK_SIZE / 4] ; // Alignment ensured, need enough stackportENTER_CRITICAL();
if (SD_Detect() != SD_PRESENT)
{
portEXIT_CRITICAL();
return(RES_NOTRDY);
}if ((DWORD)buff & 3) // DMA Alignment issue, do single up to aligned buffer
{
while (count--)
{
SD_ReadBlock((BYTE *)scratch, (uint32_t )((sector + count) * BLOCK_SIZE) ,BLOCK_SIZE);
/* Check if the Transfer is finished */
sdstatus = SD_WaitReadOperation();while(SD_GetStatus() != SD_TRANSFER_OK)
{if (timeout-- == 0)
{
portEXIT_CRITICAL();
return RES_ERROR;
}
}
memcpy (&buff[count * BLOCK_SIZE] ,scratch, BLOCK_SIZE);
}
}
else
{
SD_ReadMultiBlocks((BYTE *)buff, (uint32_t )(sector * BLOCK_SIZE), BLOCK_SIZE, count);/* Check if the Transfer is finished */
sdstatus = SD_WaitReadOperation();while(SD_GetStatus() != SD_TRANSFER_OK)
{if (timeout-- == 0)
{
portEXIT_CRITICAL();
return RES_ERROR;
}
}
}
if (sdstatus == SD_OK)
{
portEXIT_CRITICAL();
return RES_OK;
}
portEXIT_CRITICAL();return RES_NOTRDY;
}
/**
* @brief write Sector(s)
* @param drv : driver index
* @param buff : Pointer to the data to be written
* @param sector : Start sector number
* @param count : Sector count (1..255)
* @retval DSTATUS : operation status
*/#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive number (0) */
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Sector count (1..255) */
)
{
SD_Error sdstatus = SD_OK;
uint32_t timeout = 1000000;
DWORD scratch [BLOCK_SIZE / 4] ; // Alignment ensured, need enough stackportENTER_CRITICAL();
if (SD_Detect() != SD_PRESENT)
{
portEXIT_CRITICAL();
return(RES_NOTRDY);
}if ((DWORD)buff & 3) // DMA Alignment issue, do single up to aligned buffer
{
while (count--)
{
memcpy (scratch, &buff[count * BLOCK_SIZE], BLOCK_SIZE);SD_WriteBlock((BYTE *)scratch, (uint32_t )((sector + count) * BLOCK_SIZE), BLOCK_SIZE);
/* Check if the Transfer is finished */
sdstatus = SD_WaitWriteOperation();while(SD_GetStatus() != SD_TRANSFER_OK)
{
if (timeout-- == 0)
{
portEXIT_CRITICAL();
return RES_ERROR;
}
}
}
}
else
{
SD_WriteMultiBlocks((BYTE *)buff, (uint32_t )(sector * BLOCK_SIZE), BLOCK_SIZE, count);
/* Check if the Transfer is finished */
sdstatus = SD_WaitWriteOperation();
while(SD_GetStatus() != SD_TRANSFER_OK)
{
if (timeout-- == 0)
{
portEXIT_CRITICAL();
return RES_ERROR;
}
}
}
if (sdstatus == SD_OK)
{
portEXIT_CRITICAL();
return RES_OK;
}
portEXIT_CRITICAL();return RES_NOTRDY;
}
#endif /* _READONLY == 0 */
Hello,
I'm wondering if NXP support ever got back to you on this?
It had been 10+ months with 1 or 2 new releases of LPCopen and FatFS too...
I ran in the same issue and timing IS critical (pretty much maxing out the SD Card write throughput), so memcpy to align buffers won't work.
Thank you!
OK, looks like there was no LPCopen release in the meantime, but two FatFs updates (which I have applied).
I'm still curious if NXP has an SDMMC driver update in the pipeline... are any new LPCopen releases planned that may address this issue?
Would be great to get an official NXP answer here...
Thanks!
bx_TDriveResult bx_FS_SdmmcDisk_ReadSectors(bx_TDriveData *pxDriveData, byte *pbBuffer, uint32 uiSector, uint32 uiNumSectors) { bx_TDriveResult result = bx_drInvalidParameter; if(pxDriveData && pbBuffer && (uiSector < bx_Sdmmc_CardGetSectorCount()) && uiNumSectors) { result = bx_drNotReady; if(pxDriveData->xDriveStatus == bx_dsbNoError) { uint32 num_bytes = uiNumSectors * bx_Sdmmc_CardGetSectorSize(); uint32* aligned_buffer = (uint32*)malloc(num_bytes); result = bx_drReadWriteError; if(bx_Sdmmc_CardReadSectors(aligned_buffer, uiSector, uiNumSectors)) { memcpy(pbBuffer, aligned_buffer, num_bytes); result = bx_drOkay; } free(aligned_buffer); } } return result; } bx_TDriveResult bx_FS_SdmmcDisk_WriteSectors(bx_TDriveData *pxDriveData, const byte *pbBuffer, uint32 uiSector, uint32 uiNumSectors) { bx_TDriveResult result = bx_drInvalidParameter; if(pxDriveData && pbBuffer && (uiSector < bx_Sdmmc_CardGetSectorCount()) && uiNumSectors) { result = bx_drNotReady; if(pxDriveData->xDriveStatus == bx_dsbNoError) { uint32 num_bytes = uiNumSectors * bx_Sdmmc_CardGetSectorSize(); uint32* aligned_buffer = (uint32*)malloc(num_bytes); memcpy(aligned_buffer, pbBuffer, num_bytes); result = bx_Sdmmc_CardWriteSectors(aligned_buffer, uiSector, uiNumSectors) ? bx_drOkay : bx_drReadWriteError; free(aligned_buffer); } } return result; } |