sdc_lld.c bug fixes

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
exuvo
Posts: 2
Joined: Thu Aug 07, 2014 11:30 am

sdc_lld.c bug fixes

Post by exuvo »

I have found some bugs in the STM32 sdc_lld.c file while running on a STM32F437ZGT6. The first is with regards to old SD cards and had already been solved on the forums but is still not included in release 2.6.5 nor github repository/master.

The other is a rare error(every 5 minutes for me while playing .wav from SD) occuring when reading a block (sdc_lld_read_aligned) and an interrupt happens while in sdc_lld_send_cmd_short (and its variants).

Code: Select all

SDIO->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN;
while (((sta = SDIO->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
                               SDIO_STA_CCRCFAIL)) == 0)
    ;
  SDIO->ICR = sta;


If a interrupt happens between CMD=SDIO_CMD_CPSMEN and the reading of SDIO->STA the whole transfer might already be complete and ICR=sta will clear the SDIO_STA_DATAEND bit which is needed by sdc_lld_wait_transaction_end.
The fix is to not clear everything, only clear the bits we were waiting for:

Code: Select all

SDIO->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL);

Affected code paths are sdc_lld_send_cmd_short_crc, sdc_lld_send_cmd_short_crc and sdc_lld_send_cmd_long_crc.


While I'm at it, the behaviour of chThdSleepUntil seems very error prone. If used like I did "chThdSleepUntil(lastSleepTime+=MS2ST(1));" it might attempt to sleep until slightly in the past. At first glance the code already checks this:

Code: Select all

void chThdSleepUntil(systime_t time) {

  chSysLock();
  if ((time -= chTimeNow()) > 0)
    chThdSleepS(time);
  chSysUnlock();
}


But time is unsigned so the check is almost never false and schedules a extremely long sleep duration instead. My local fix is to check if the given sleep duration is more than a day and if so assume that it has overflowed and treat it as no sleep.

Code: Select all

void chThdSleepUntil(systime_t time) {

  chSysLock();
  time -= chTimeNow();
  if (time > 0 && time < S2ST(24UL*60UL*60UL))
    chThdSleepS(time);
  chSysUnlock();
}

The duration might need to be tweaked if the size of systime_t varies.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: sdc_lld.c bug fixes

Post by Giovanni »

Hi,

I committed your fix as bug #522. Could you submit a patch for the old problem? I have no way to test it right now.

About chThdSleepUntil(), it is designed to operate with future times only. It would be a different API if there is the need to consider also the "recent past". The definition of "recent past" could be ambiguous.

Giovanni
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: sdc_lld.c bug fixes

Post by Giovanni »

Moved the comments about chThdSleepUntil() here: viewtopic.php?f=3&t=1947

Giovanni
Post Reply