Skip to content

Unable to write more than one block at a time with any GCC optimization #5

Description

@jmaff

When using -O0 (no optimization), file writes perform as expected. However, when any level of optimization is used (-O1, -O2, or -O3) file writes of size 512 bytes or less are successful, but any larger size fails with FR_DISK_ERROR.

The issue seems to lie in fatfs_sd.c:

/* transmit data block */
#if _USE_WRITE == 1
static bool SD_TxDataBlock(const uint8_t *buff, BYTE token)
{
	uint8_t resp;
	uint8_t i = 0;

/* REST OF FUNCTION */

        /* transmit 0x05 accepted */
	if ((resp & 0x1F) == 0x05) return TRUE;

	return FALSE;
}

resp is only updated in this function if the token to send isn't the stop token, which is sent once the write is complete. Stepping through with a debugger shows that everything works as normal in a block write up until this point. However, once the stop token is sent, the function relies on an external mechanism to set the value of resp/its memory address (I'm a bit unclear on where exactly this is done, but it must be occurring as otherwise the function would always return FALSE (a failure) when sending a stop token). GCC optimization recognizes this and so always returns FALSE when a stop token is sent.

I was able to successfully fix this by declaring resp as volatile:

/* transmit data block */
#if _USE_WRITE == 1
static bool SD_TxDataBlock(const uint8_t *buff, BYTE token)
{
	volatile uint8_t resp;
	uint8_t i = 0;

/* REST OF FUNCTION */

Hopefully this will help anyone else who happens to run into this issue. I can open a PR with the change as well, and perhaps someone might have some insight as to how the memory address of resp has the correct value for stop token transmission despite not being set in the function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions