K60 SDHC hanging problem

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

K60 SDHC hanging problem

2,521 Views
mjbcswitzerland
Specialist V

Hi All

Has anyone had a problem that the SDHC gets blocked?
When doing  tests I sometimes get the following while loop waiting forever:

while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {}

This is performed in the read of a sector (not using DMA) of 512 bytes (actually 128 long words at the SDHC interface). The BREN flag indicates that there are bytes to be read and the problem always occurs when 127 long word reads have been made and there is never a flag to say that the final one is ready.

When this happens there are no data error bits set in the SDHC_IRQSTAT register.

The value of SDHC_PRSSTAT is 0xff88020a

This is the routine:

// Read a sector from SD card into the specified data buffer//extern int fnGetSector(unsigned char *ptrBuf){    unsigned long *ptrData = (unsigned long *)ptrBuf;                    // the Kinetis driver ensures that the buffer is long word aligned    int i = (512/sizeof(unsigned long));    while (i--) {        if (SDHC_IRQSTAT & (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE)) { // check for read errors            SDHC_IRQSTAT = (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE | SDHC_IRQSTAT_BRR);            return UTFAT_DISK_READ_ERROR;                                // return error        }        while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {             <---------- gets stuck here        }        *ptrData++ = SDHC_DATPORT;    }    while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) {                          // wait for transfer to complete    }    SDHC_IRQSTAT = (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_BRR | SDHC_IRQSTAT_AC12E); // reset flags    return UTFAT_SUCCESS;                                                // read successfully terminated}

 



This seems quite a standard/typical realisation. The following subtle effects have also been noticed:
1) When built with GCC it hangs very often when the SDHC_IRQSTAT check before it is removed. With the check in position it seems to be stable.
2) When built with CW10.1 it gets stuck quite often, even with the SDHC_IRQSTAT check before the line.

Therefore the stability is compiler/timing dependent (all registers are declared as volatile).

Has anyone else encountered such a behaviour?

Regards

Mark


P.S. During the test the SD card is used by various sources (to display images to the TFT display (file system reads), for USB-MSD (PC reads) and for serving pages at web server (web server file reads). It is easier to reproduce when all are working together but still happens when only one read source is actually active (although less frequently). Accesses are however protected so only one source actually physically reads at a time.

 

0 Kudos
Reply
11 Replies

1,398 Views
mjbcswitzerland
Specialist V

Hi All

 

I may have been able to solve this by adding the following before starting the read:

 

while (SDHC_PRSSTAT & SDHC_PRSSTAT_DLA) {}

 

This ensures that the previous command has completely terminated before checking for the read data. There is obviously a short time where the command hasn't completely terminated but the FIFO can flag that there is something there (or something similar). This would explain why the compiler (with slightly different optimisation and delays) could be more or less affected. In fact, using IAR (faster code) it was even worst before and then stable afterward.

 

Regards

 

Mark

 

0 Kudos
Reply

1,398 Views
mdomingo
Contributor I

Hi Mark,

 

I'm having the same issue.

 

Are you sure that line solves your problem?

 

I mean, I think you are checking the wrong value. From the datasheet:

"In the case of read transactions:
This bit will be set in either of the following cases:
• After the end bit of the read command.

..."

 

Therefore, I think you should check:

    while ((SDHC_PRSSTAT & SDHC_PRSSTAT_DLA_MASK)==0){};

 

But anyway, sometimes I still have the same problem.

Someone has any idea where should be the problem?

 

 

Thanks,

 

Marc Domingo

0 Kudos
Reply

1,398 Views
mjbcswitzerland
Specialist V

Hi Marc

 

I have understood that the DLA indicates that the data line(s) is/are active. It is set when a read or write is in operation and cleared when the operation has been completed.

 

By adding

while (SDHC_PRSSTAT & SDHC_PRSSTAT_DLA) {}

'before' starting the read it is verifying that any 'previous' operation has completely terminated. If the tail end of any previous activity happens to still not be completely termianted the start of the new read will be delayed until it is (the DLA returns back to '0').

 

Since adding this I haven't had a hang take place so it looks to be doing something positive but I never did any measurements with an analyser connected to the bus and some indication of where the code was; whether the wait took place and how long, etc. (which I would do in case of any further difficulties).

 

My feeling is that the difficulty occurs when a read quickly follows another operation, whereby the bus has not fully completed what it was doing before the new read is started. I also expect that by simply adding a short delay (say a couple fo us) at the start of the read function would also give the bus time to complete and so would stop the hanging situation arise, which is presumably because new commands are issued a bit too soon.

 

I could however be completely wrong, so if you can confirm something else it would also be useful :smileywink:

 

Regards

 

Mark

 

0 Kudos
Reply

1,398 Views
mdomingo
Contributor I

Hi,

 

I think you are right. Seems that now my driver is working better. Thanks!!

 

Do you also check DLA before starting writing to the sd?

 

 

Thanks,

 

Marc Domingo

0 Kudos
Reply

1,398 Views
mjbcswitzerland
Specialist V

Hi Marc

 

I didn't need to change anything when writing (yet...)

 

Regards

 

Mark

 

0 Kudos
Reply

1,398 Views
JOliverasC
Contributor I

Hi Mark (and others)

I know that this tread is old and solved, but I have a concern about the code

 

I just copy the inner loop

{        if (SDHC_IRQSTAT & (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE)) {             SDHC_IRQSTAT = (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | 
 SDHC_IRQSTAT_DTOE | SDHC_IRQSTAT_BRR   );            return UTFAT_DISK_READ_ERROR;                                // return error        }       while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) { }        *ptrData++ = SDHC_DATPORT;  }    while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) {  }                       // wait for transfer to complete   

I do not  underestand why you did not check errors inside while loop as follows

 

{
   while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {
        if (SDHC_IRQSTAT & (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE)) {
            SDHC_IRQSTAT = (SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE |
                            SDHC_IRQSTAT_DTOE | SDHC_IRQSTAT_BRR   );
            return UTFAT_DISK_READ_ERROR;                                // return error
        }
   }
   *ptrData++ = SDHC_DATPORT;  
}
while (!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC)) {  }                       // wait for transfer to complete

 

 

 

 

0 Kudos
Reply

1,398 Views
mjbcswitzerland
Specialist V

Hi JOliverasC

 

The reason why the check for errors is not performed in the while loop is because the while loop is entered very rarely - normally the BREN flag is set and so the error check would not be made at all.

 

The question as to whether the error check should be before AND in the while loop is another one. This may be the best but the wait loop by itself hasn't represented a problem in any cases to date.

 

In fact a do {error_check} while (BREN not set) may be the best solution. In practice I never actually had an error and there may be other waits which could potentially be improved by checking for errors while waiting. The exact internal workings of the SDHC is not documented in such detail that one can see in what order things take place and what can happen while other things are in progress and so there is a certain amount of trial and error involved - sometimes with a code hang during initial testing (which does however help to get some insights into what can take place).

 

Regards

 

Mark

0 Kudos
Reply

1,398 Views
T_M_F
Contributor I

Where can I get this SDHC driver code?

 

Thanks!

 

Richard.

 

0 Kudos
Reply

1,398 Views
mjbcswitzerland
Specialist V

Hi Richard

 

The particular code referenced here is from the uTasker project for Kinetis: http://www.utasker.com/forum/index.php?topic=1252.0

 

Regards

 

Mark

 

0 Kudos
Reply

1,398 Views
SDK
Contributor I

Hi Mark!

Have you used the multiple_block read?

When I use it ,I fond it often could 't stop,and BCEN unnormal.It often read wrong

0 Kudos
Reply

1,398 Views
mjbcswitzerland
Specialist V

Hi

 

I am sorry but I never used the multi-block command; just the single block command.

 

Regards

 

Mark

 

0 Kudos
Reply