I'm seeing some performance differences between micro sd cards and have found a behavior I don't understand.
K64 running with 120mhz clock.
SDHC used in SD 4bit mode - clock 40mhz
Block read acquires 1 sector of 512 bytes - polling to complete. I have included the code below. I added an LED to the read code so that I could acquire the trace below using a logic probe.
Every 25msec my application acquires around 18 sectors for the sd card (sector is 512 bytes) - I turn on the LED during this acquisition period and the trace shows LOW during the read operation. After the 18 sectors are acquired, the sd card is not accessed until the next 25msec tic occurs.
Behavior:
The first sector read following a non-use of the SDHC - that read takes over 3msec to acquire the data. All other reads following the first only take 400usec - a factor of 10 difference.
I thought it might be due to the SDHC clocks gating off when no sd activity so I turned gating OFF - verified by scoping the SDHC clock line. Disabling the clock gating operation makes no change in behavior.
Can someone please explain this?
Is this the SD card internally delaying?
Is there a SDHC parameter that I can look into to address this?
Thanks in advance for any and all comments.
Joe
[CODE] NOTE ... 95% of the delay is in the code loopwhile(0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN_MASK)) { __asm__ __volatile__ ("nop"); }; // wait until reset is done Which is waiting for the SDHC to fill it's internal 512 buffer with data from the sd card READ_Routine:byte SDHC_ReadBlock(dword *pData, word Count) { dword r = 0;word i;
dword DD, DD1;
RED_LED = 1;
while ((SDHC_PRSSTAT & SDHC_PRSSTAT_DLA_MASK) == 1)
{
__asm__ __volatile__ ("nop");
}; // wait until reset is done
SDHC_IRQSTAT |= SDHC_IRQSTAT_BRR_MASK;
if (SDHC_IRQSTAT & (SDHC_IRQSTAT_DEBE_MASK | SDHC_IRQSTAT_DCE_MASK | SDHC_IRQSTAT_DTOE_MASK))
{
SDHC_IRQSTAT |= SDHC_IRQSTAT_DEBE_MASK | SDHC_IRQSTAT_DCE_MASK | SDHC_IRQSTAT_DTOE_MASK | SDHC_IRQSTAT_BRR_MASK;
SDHC_CMD12_StopTransferWaitForBusy();
SDHC_Error_Displayed = SDHC_Error_Read_Block;
RED_LED = 0;
return RES_ERROR;
}
while(0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN_MASK))
{
__asm__ __volatile__ ("nop");
}; // wait until reset is done
for(i = 0; i < Count; i++)
{
*pData++ = SDHC_DATPORT;
}
while(!(SDHC_IRQSTAT & SDHC_IRQSTAT_TC_MASK)) // wait for transfer to complete
{
__asm__ __volatile__ ("nop");
}; // wait until reset is done
SDHC_IRQSTAT = (SDHC_IRQSTAT_TC_MASK | SDHC_IRQSTAT_BRR_MASK | SDHC_IRQSTAT_AC12E_MASK);
RED_LED = 0;
return 0;
}
[/CODE]
Solved! Go to Solution.
I've moved to multi-block reads and timing is fine -- I just can't get the CMD12 to properly terminate CMD18.
I started another thread on that subject.
Joe
I've moved to multi-block reads and timing is fine -- I just can't get the CMD12 to properly terminate CMD18.
I started another thread on that subject.
Joe
Mark -- sanity check for me.
The initial delay is getting the sd card's internal up to speed - makes sense.
The remaining read times should be as fast as the card can do.
I know CMD18 would provide a short read time over many reads but I tested my app which uses a FAT32 file system and my read requests are never on sector boundaries - so there was little advantage to CMD18.
Now the sanity check - It seems my actual reads (after the first are still too slow.
I'm guessing the following math is close -- if not please correct me.
I currently see a read of 1 sector in 350usec
So that is 512 * 8 bits/byte = 4096 bits in the read package.
I'm using the 4-bit interface mode so that make 1024 bus events.
350 E-6 (usec) / 1024 = 3.42 E-7 bit timing == which equates to an bus event clock of 2.93 mhz. My SDHC clock is 40 mhz.
THAT does not make sense!!!
Any ideas on why my reads are slow?
Just a note - my timing is AFTER issuing the CMD17 - so timing associated with is not included.
Thanks.
Joe
Joe
With 50MHz SD card clock a read can be performed in about 20us.
With 25MHz it is about 40us.
With a little SW overhead maybe 60us.
I use DMA for the read, which isn't that much faster since a tight loop gives about the same, but it helps if there are other interrupts that can disturb the loop.
Check that your read buffer is long word aligned - if it isn't it slow the process down since the Cortex has to split the write into multiple bus accesses and the overall operation may be > 4x slower.
Regards
Mark
Mark:
Last time we communicated on the SDHC - you were only using the SPI interface.
Have you switched your code to using the SDHC controller in 4-bit mode?
Thanks.
Joe
Joe
I have used SDHC since 2011 and also SPI (a configuration, or by default if the Kinetis device has no SDHC interface).
There is a problem with multi-block operations and the Kinetis SDHC since it can't be paused, making it impractical in environments with multiple file users that need to interrupt each other. But when this is not an issue (eg. pure USB-MSD to SD card) it is OK.
Regards
Mark
Hi Joe
If you are reading linear sector from a card you need to use CMD18 (multiple block read) in order to get best performance. The single sector read CMD17 is slower. The first read of multiple sectors is however always slower (whichever command used) since the SD cards internal logic needs to get ready - subsequent linear sector reads are then faster.
The uTasker SDHC card interface reads an initial sector in about 450us and subsequent ones in about 50us (using CMD18). This allows HS USB-MSD operation (eg. on K66) to achieve around 20MByte/sec transfer from the SD card to the PC.
Regards
Mark
uTasker - for more performance and faster, cheaper product development