cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 memory areas for DMA. Different?

chuck guzis
Associate III
Posted on September 28, 2017 at 00:51

I'm probably missing something obvious, but I'd appreciate any clarification.

Basically, I'm using a peripheral device that transmits data in 16K word blocks using DMA.   That works fine.  I'm taking the data and writing it to an SD card, using the SPL and Chan's FATFS code.

Up until yesterday, things worked fine also, but I ran into errors because of FATFS occasionally using buffers that aren't aligned to a 32-bit boundary.  So I added code to check for a misaligned buffer and move data to an aligned one before writing to SD.   My code passes his compatibility checker (app4.c) test.

Confident in the outcome, I started running my regular code with the compatibility modification.   All of the sudden, some SD writes now hang up and timeout with a DMA failure.  If I perform single-sector writes using the buffer that I use for resolving misalignment issues, things are fine, albeit slower.  But if I attempt to write (aligned data) right from the device buffer, it will go for a bit and then hang.

My thought is that perhaps some areas of memory are less suited to DMA than others, but if that's true, I don't know how to resolve the issue.

3 REPLIES 3
Posted on September 28, 2017 at 02:10

CCM RAM won't work with DMA on the F4

I built some code in diskio.c to decompose unaligned reads/writes into single-up read/write through an aligned scratch buffer. That did require an adequate stack.

/*-----------------------------------------------------------------------*/

/* Write Sector(s) */

#if _READONLY == 0

DRESULT disk_write (

BYTE drv, /* Physical drive nmuber (0..) */

const BYTE *buff, /* Data to be written */

DWORD sector, /* Sector address (LBA) */

BYTE count /* Number of sectors to write (1..255) */

)

{

SD_Error Status;

// printf('disk_write %d %p %10d %d\n',drv,buff,sector,count);

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(drv, (void *)scratch, sector++, 1);

if (res != RES_OK)

break;

buff += BLOCK_SIZE;

}

return(res);

}

Status = SD_WriteMultiBlocksFIXED(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 /* _READONLY */
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
chuck guzis
Associate III
Posted on September 28, 2017 at 02:40

That's what mine essentially looks like, mutatis mutandis.   I use a buffer shared between the read and write code as scratch.   However, I don't get your comment about needing more stack space.  It would seem to be unchanged from the 'let's assume that everything is aligned' case.  After all, the buffer address, count and sector address are already resident as part of the calling sequence.  There aren't any additional onstack variables--and the scratch buffer is statically allocated; i.e.

uint8_t  __attribute__ ((aligned(4))) ScratchBuffer[ SECTOR_SIZE];

I guess that I'm not following you.  It doesn't explain why, if I treat all writes as single-sector unaligned writes, everything works.

chuck guzis
Associate III
Posted on September 30, 2017 at 03:16

Nevermind--I found the typo--a missing semicolon.

Thanks for your help.

Chuck