Level Converters on microSD cards

I have two microSD breakout boards, one from SFE and one from Adafruit. The one from SFE is this:

and the Adafruit one is this:

For the SFE one, I have it paired with a TXB0108 where the Adafruit one uses an HC4050M.

My question is whether anyone can tell why one is faster than the other. And the reason is because with the TXB0108 setup, I can pull data slightly faster from a card than I can with Adafruit's breakout. On a 144 byte read, SFE's breakout with the TXB0108 returns the data in 108 usecs, consistently, except for every 4th read when it needs to seek again. With Adafruit's breakout with the HC4050M, it takes upwards of 120 to 125 usecs doing the same exact thing.

I'm not sure what specifically I'm looking for in their data sheets to compare. Am I looking for the switching characteristics (if so, the TXB0108 is faster) or is something else at play here?

108 usec is the time to copy 144 byte of data from the cache. An entire 512 byte block is read from the SD card into the cache which takes much longer.

I don't understand why there should be a difference in time since the SD card is not accessed. The level shifters should not matter except when a 512 byte block is read. When you cross a cluster boundary two blocks will be read, one FAT block and one data block.

Yeah, there is definitely a difference between these two. Writing is also slower with the HC4050 than with the TXB0108. Granted, I don't know if it's the way Adafruit wires the 4050 to the SD card reader versus how I wire the TXB0108. Or if it's something inherently different between the two.

The copy time from cache does not depend on the SD hardware setup. Try changing the SPI bus speed from 8 MHz to 4 MHz and you will get the same time for reading 144 bytes from cache.

Use sd.begin(chipSelect, SPI_HALF_SPEED) instead of sd.begin(chipSelect, SPI_FULL_SPEED). I get 108 usec for a 144 byte read from cache in both cases. The time to read a 512 byte block changes.

Actually, level converters should not change the timing for read/write to an SD. Level converters either work fast enough or not, there is no middle ground. If a level converter is too slow, errors will occur because the SPI signal will be distorted.

The SPI bus is clocked at 8 Mhz for full speed on a 16 MHz AVR board. This determines transfer times.

Timing will vary for a given SD card since the controller is very complex. You can run the same program with the same access pattern and get different times.

The flash controller maps a given logical block into different physical blocks. The controller may move a block, even if you do not write the block, to make sure all physical blocks have equal wear.

Note that micros() ticks in units of 4 usec and there is some jitter due to timer interrupts.

Yeah, but 108 usecs versus 120 usecs? That's an additional 3 ticks. The other thing too is that it's not consistent. With the TXB0108 I get a consistent 108 usecs and 1256 usecs every 4th read. With the HC4050M it varies between 120 - 125 usecs and 1272 - 1288 usecs every 4th read. (I'm not concerned about writing since I'm not doing that, only reading.)

That, as far as I can tell, is the only difference between the two. The physical card reader itself is the same on both breakouts, same part number.

SD read timing varies each time you run a test.

It's not the level converters. There is no access to the SPI bus for the read from cache.

The level converters don't change the SPI clock so the SD sees the same signal timing.

Interrupts from Serial and timer 0 will cause far more than 12 usec variation.

Post your results from each setup. Run the test three time on the first setup, three on the second, three on the first, and finally three on the second.

You must not change the program or SD content and must use the same pin for chip select.

That's exactly what I did. I'm not one to instantly cry wolf. I test and retest before I say anything, it's unfortunately ingrained in me as a scientist. And that's exactly what I did simply because I wanted to make sure it was repeatable, and it is. Consistently. It's the same exact code run on both setups, the same exact sd card and the same exact file being read as well. I did not reformat and rewrote the file between tests, in case it changed something with the file structure.

There is a wiring difference between the two, but I don't know if it will make a difference. With the TXB0108 I send all four signals through it, MOSI, MISO, CLK, as well as the SS pin. With the Adafruit breakout, they have it wired where only MOSI, CLK, and SS pins go through the HC4050M, MISO is not, it travels unobstructed from the card reader to the MISO pin on the controller. I don't know that that would actually make a difference.

You didn't rewrite the SD I hope.

and rewrote the file between tests

Did the two tests print exactly the same number of characters?

Did you truly alternate test case one and two several times. Just powering an SD on and off changes it's performance since it rebuilds system tables and may remap some blocks during initialization.

SPI is a synchronous bus so correctly functioning level converters can't change timing.

MISO is not, it travels unobstructed from the card reader to the MISO pin on the controller.

This is common and the level is in spec for the AVR SPI controller.

MISO is not, it travels unobstructed from the card reader to the MISO pin on the controller.

Also leaves the SD card unprotected from 5V levels when a programmer is connected, or another device outputs MISO at 5V levels.

Also leaves the SD card unprotected from 5V levels when a programmer is connected, or another device outputs MISO at 5V levels.

Guess it depends on how the SD MISO goes high-Z. Lots of systems have 5V devices connected like this and seem to get away with it. I can't find a definite statement about high-Z MISO.

How does the TXB0108 know to go high-Z?

I don't think high-Z MISO on the SD card matters - I'd be concerned with MISO being above the SD card's 3.3V Vcc.

OE goes low on the A side to make the 3.3V TXB010x pins go Hi-Z.

High-Z MISO is very important. The SD must go high-Z to share the bus.

SD cards are strange, to go high-Z you set chip select high and then clock the bus. If you only set CS high, the SD keeps driving the bus. You must clock SCK.

I have never seen a shared SD card damaged by a shared 5V device as long as the SD is left high-Z.

I did an experiment with an Adafruit micro SD breakout and an old Kingston 2 GB micro SD. I attached a high quality Tek scope to MISO.

When the SD is idle in high-Z mode MISO floats near zero volts.

If I put a 1 M ohm pullup to 5 V on MISO, it floats at about 3.6 V. A 10 K pullup results in about 3.8 V.

I get the same result with a new 8 GB micros SD.

Looks like sharing the bus with a 5 V device could be a problem for the Adafruit breakout.

The most common share is the W5100 and it is a 3.3V device so all is well for the Ethernet shield with no level converter on MISO.

Anyone sharing a 5 V SPI device with the Adafruit micro SD breakout?

Looks like the TXB010x does its trick by edge detection http://www.adafruit.com/datasheets/txb0108appnote.pdf. Cute!

Here are histograms of read times for a Kingston 2 GB micro SD in an Adafruit breakout.

I read a 5 MB file in chunks of 144 bytes. buf is a 144 byte array.

    uint32_t m = micros();
    if (file.read(buf, sizeof(buf)) != sizeof(buf)) {
      error("read failed");
    }
    m = micros() - m;

I saved a histogram of the times in an array. Here is the result for four microsecond bins, the resolution of micros().

Bins with zero counts are suppressed.

The first value is the bin time and the second is the count of events in the bin.

under,0
108,21021
112,2391
116,1544
1184,25
1188,24
1192,217
1196,107
1200,54
1204,116
1208,563
1212,787
1216,1393
1220,687
1224,396
1228,1504
1232,855
1236,291
1240,36
1248,1
1260,1
1272,3
1276,7
1280,19
1284,24
1288,7
1292,13
1296,87
1300,78
1304,231
1308,130
1312,120
1316,185
1320,176
1324,103
1328,87
1332,113
1336,41
1340,31
1344,28
1348,38
1352,18
1356,8
1360,2
1592,18
1596,32
1600,5
1604,4
over,1101

The first three bins contain cases where the read is from cache. The timer 0 interrupt which occurs every 1028 microseconds spreads the time a bit and there is the 4 microsecond resolution of the timer.

The remainder require one or more accesses to the SD. 1101 cases took more than 1604 microseconds.

These results vary depending on whether you rerun the test after a power off and or reinit of the SD.

Here is another histogram with 12 usec bins. The first number is the start of the bin. In this case all cache reads fall into the first bin with 108, 112, and 116 usec.

Note few cases are over 1600 usec, I ran the test without powering the SD off after the above test and this changes the distribution.

under,0
108,24956
1176,31
1188,345
1200,907
1212,2848
1224,2649
1236,276
1284,3
1296,19
1308,91
1320,93
1332,83
1476,6
1488,111
1500,256
1512,912
1524,823
1536,159
1548,2
2568,4
2580,16
2592,23
2604,69
2688,2
2700,3
2772,3
2784,2
2796,11
2868,1
2880,2
2892,4
2904,11
2916,1
over,0

Access to the FAT causes the long times and the SD is quirky when reads are not sequential.

Here is a result for a 8 GB SDHC micro SD.

under,0
108,24955
120,1
1140,2
1152,13
1164,41
1176,75
1188,54
1200,263
1212,222
1224,656
1236,46
1248,40
1260,119
1272,89
1284,37
1296,20
1308,29
1320,84
1332,159
1344,1078
1356,446
1368,55
1380,251
1392,331
1404,1311
1416,1793
1428,39
1440,508
1452,96
1464,1294
1476,228
1488,51
1500,177
1512,5
1836,1
2856,1
2868,5
2880,1
2892,15
2904,1
2928,1
2940,4
2952,1
2988,2
3000,4
3012,21
3024,34
3108,4
3120,3
3132,20
3144,36
over,0

Ashley, try re-reading the same 144 bytes (non-block crossing, 108-120 us), alternating between the hardware.

From what you are saying, you are getting consistent but different speeds when reading (copying) from RAM cache to your RAM buffer, depending on the electrical connection between the SD card and Arduino - which should not matter at all since the SPI bus is not used (and which actually shouldn't matter even if it was given the synchronous SPI bus, but that's another matter).

Does that happen even re-reading the same bytes?