I need another shower. Inspiration is failing me.
I took a couple of days to come back to this. I just couldn’t see a way through. In the end I sat down to graph what was going on and a plan presented itself. I don’t know if it’s going to lead to success, but it’s at least an approach. Anything’s better than being stalled.
I’ve been playing with init() in SD.cpp. When card.init() is called, I can apply any of 7 speed options (0-6) acceptable to Sd2Card::init() and get nearly identical results for copy speed of “large” files.
As you can see above, the different bus speeds have a marked effect in the mid-range of file sizes I tested, files around 4kB. As files get very small, or larger than 100kB there’s less and less distinction. This can only be due to the overwhelming effect of some other factors. More than “bus speed isn’t everything” I’d say “speed is almost nothing”. This is a major confounding of my premise for this project. I thought ramping up the bus speed would get me into the megabytes per second realm. Ok.
Let’s imagine for a second that there was no FAT file system, that there’s no need to initialise the SD card. Pretend we can say “write 1024 bytes to the card” and all that mattered was serialising the data and getting it across the SPI bus.
If the SPI bus at its fastest speed is at half the core clock rate, then it’s at 4MHz. I’m still using my EtherTen; it’s effectively an Arduino Uno. So 4,000,000 clock cycles occur every second. If 8 cycles are required to transfer a byte, then we can push through 500,000 bytes in a second. So, accounting for nothing but SPI’s serialisation of data and the clock speed, writing a 1GB file would take about 36 minutes. That might be bearable, if we could achieve this theoretical speed which, so far, we can’t. If we pushed an SPI bus at 10MHz, we could write a 1GB file in about 14 minutes. 20MHz, 7 minutes.
Meanwhile, back in reality …
The trip into the theoretical has told me two things. First, the SPI bus is not the bottleneck. At 4MHz we can (theoretically, at least) push data way faster. And second, we don’t need insane SPI speeds to achieve useful throughput. A 10MHz bus speed isn’t much of an increase over the current, reliable, speed. Obviously we’ll need another microcontroller to go faster, as the ATmega328P is flat out already. But for now, I think we need to find the bottleneck.
I went off to do what, perhaps, I should have done first. Read!
The first article I ran into was this one. The English is difficult to read, but the content is worth the effort. Having read that and moved on I found many other people referring back to the same article. It’s the definitive article, or so it seems.
Three main things came out of it for me.
- SD (and MMC cards) support SPI natively, and define a protocol of sorts for communication with the card.
- Data is read and written to the cards in blocks, it seems 512 bytes is a common block size.
- The default read/write operations are supported by the READ_SINGLE_BLOCK and WRITE_BLOCK commands. Much higher throughput is achieved using READ_MULTIPLE_BLOCK and WRITE_MULTIPLE_BLOCK instead.
There are also other challenges, like
- Writing blocks that require an erase cycle, which uses lot so RAM (which Arduino’s don’t have much of)
So the challenge now is to understand the SPI specification for SD cards and to see if the fastest read/write methods are available in the existing SD class for Arduino. I’m betting they’re not. So it will be down to either extending the SD library or blazing a new trail. If I blaze a new trail, the Arduino Playground has a good starting point.
This is no longer a simple project. The question remains: is the benefit worth the effort?
[That is all]