2017-09-27 03:51 PM
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.
2017-09-27 05:10 PM
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 stackwhile(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 */2017-09-27 05:40 PM
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.
2017-09-29 06:16 PM
Nevermind--I found the typo--a missing semicolon.
Thanks for your help.
Chuck