Figure it out. The SD library forced SPI speed to SPI_HALF_SPEED which, for some reason, isn't working. If I change it to the value '2' instead, the above sketch works fine. From SD.cpp:
boolean SDClass::begin(uint8_t csPin) {
/*
Performs the initialisation required by the sdfatlib library.
Return true if initialization succeeds, false otherwise.
*/
return card.init(SPI_HALF_SPEED, csPin) &&
volume.init(card) &&
root.openRoot(volume);
}
If I change that single line to:
return card.init(2, csPin) &&
... everything works.
So the question now is, why won't SPI_HALF_SPEED work? Is it because of the hardware being used? I'm passing signals through a logic level converter and then to the breakout.
And if it IS the hardware, what are my options? A different breakout? I don't want to have to be editing the library files every time I need to install/upgrade the Arduino IDE. Seems stupid.