2019-08-31 12:53 AM
I've been working on making my SD SDIO card access non blocking. My implementation is a derivative from the standard ST SDIO SD driver (stm324xg_eval_sdio_sd).
I'm using Protothreads (basically a state machine) to make the SD SDIO calls non-blocking and allow the program execution to continue while I'm waiting for the operations to complete. For some unknown reason, and I've not been able to identify the cause, when I continue with the program execution, I get a timeout error from the SDIO interface. But when I block and wait for the result all is fine. This is what I currently have:
static PT_THREAD(sd_CMDResponse1Error_V(struct pt* Thread_PS, uint8_t CMD_U8, SD_Error* SDResult_PE))
{
static uint32_t Status_U32;
uint32_t Response_U32;
static uint32_t Timeout_U32;
// Begin the thread
PT_BEGIN(Thread_PS);
// Initialise the result
*SDResult_PE = SD_OK;
// Initialise the timeout
Timeout_U32 = SDIO_CMD0TIMEOUT;
while (1)
{
// Get the status
Status_U32 = SDIO->STA;
// If we received the status or timeout
if ((Status_U32 & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT))||(Timeout_U32 == 0))
{
break;
}
// Decrease the timeout
Timeout_U32--;
// Yield the thread
PT_YIELD(Thread_PS);
}
// If there was a timeout
if (Status_U32 & SDIO_FLAG_CTIMEOUT)
{
// Set the result
*SDResult_PE = SD_CMD_RSP_TIMEOUT;
// Clear the flags
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
// Exit the thread
PT_EXIT(Thread_PS);
}
else
// If the CRC failed
if (Status_U32 & SDIO_FLAG_CCRCFAIL)
{
// Set the result
*SDResult_PE = SD_CMD_CRC_FAIL;
// Clear the flags
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
// Exit the thread
PT_EXIT(Thread_PS);
}
.....
// End the thread
PT_END(Thread_PS);
}
When I cal PT_YIELD to allow the program execution to continu, I get a timeout error. But when I remove the PT_YIELD statement, the IO completes without any errors.
It does not make sense. Because whether I exit and return to check the SDIO status (SDIO->STA) or sit and wait for the SDIO status (SDIO->STA) it should not make any difference.
Nothing else is accessing the SDIO when I do exit and return.
Maybe someone else can shed some light on this?
Addendum
For those who are not familiar with Protothreads, I've quickly re-written this function with a basic state machine (sort of what the Protothreads implementation would have looked liked when expanded).
static char sd_CMDResponse1Error_C(int State_S, uint8_t CMD_U8, SD_Error* SDResult_PE)
{
static uint32_t Status_U32;
uint32_t Response_U32;
static uint32_t Timeout_U32;
switch (State_S)
{
case 0:
// Initialise the result
*SDResult_PE = SD_OK;
// Initialise the timeout
Timeout_U32 = SDIO_CMD0TIMEOUT;
// Go to the next state
State_S = 1;
// Fall through to next state
case 1:
// Get the status
Status_U32 = SDIO->STA;
// If we received the status or timeout
if ((Status_U32 & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT))||(Timeout_U32 == 0))
{
// Go to the next state
State_S = 2;
// Fall through to the next state
}
else
{
// Decrease the timeout
Timeout_U32--;
return PT_YIELDED;
}
case 2:
// If there was a timeout
if (Status_U32 & SDIO_FLAG_CTIMEOUT)
{
// Set the SD result
*SDResult_PE = SD_CMD_RSP_TIMEOUT;
// Clear the flags
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
return PT_EXITED;
}
else
// If the CRC failed
if (Status_U32 & SDIO_FLAG_CCRCFAIL)
{
// Set the SD result
*SDResult_PE = SD_CMD_CRC_FAIL;
// Clear the flags
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
return PT_EXITED;
}
....
// Fall through to PT_ENDED (No default needed)
}
return PT_ENDED;
}
Solved! Go to Solution.
2019-09-02 08:18 AM
Ok, found the issue. There was another disk access when the thread yielded.
2019-09-02 08:18 AM
Ok, found the issue. There was another disk access when the thread yielded.