Solved: The card's format was bad - reformatting it fixed it
Hello,
I'm using a clone of a NodeMCU ESP32 dev board and a HiLetgo Micro SD card reader.
This same hardware configuration successfully writes files using a proprietary ino i am developing for a client.
However, the example code I am providing writes a 0 byte file called test.txt when what is expected is a 12 byte file called test.txt containing "Hello World!"
As you can see I have tried delaying. I have tried removing the call to SD.end(). I've tried everything I can think of. It always writes a zero byte file.
The only weirdity is I'm using the SD reader on the second ESP32 SPI bus which I've remapped the pins for (shown in the constants).
The wiring for the ENTIRE device is as follows:
RA8875 (Primary SPI)
In particular note the advice to Auto format code in the IDE and to use code tags when posting code here as it prevents some combinations of characters in code being interpreted as HTML commands such as italics, bold or a smiley character, all of which render the code useless
The delays() are probably totally useless - if you suspect a timing issue, it would be better to slow down the SPI bus.
EDIT - NOT THE CASE, IGNORE
Just a guess / something to investigate: You declare
SPIClass _sdSPI(HSPI);
so in the _sdSPI instance spi_num will be ** **HSPI** ** (BTW not a good practice to have global variable starting with _ as All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.).
Then it's curious it's working at all. The example code I've used is actually pulled originally from the Espressif forums for using a second SPI bus
What's really curious is that like I said, I have another ino where all this works, no problem - same hardware configuration. Same equipment. Literally all i do is flash another ino to it and the code in there works.
This code is copied from that.
What I think might be happening is since SPI begin() was already called maybe it's failing the second time? I'll remove the line in SD.cpp and try it.
Edit: I tried removing the call to begin() in SPI.cpp and nothing changed. It mounts the filesystem and creates test.txt but it's zero bytes, like before
I'm loath to change the hardware because we're getting it on a pcb and it has been tested.
If the software needs to be changed, I'd love to know an alternative. This was the only way I could figure on passing the necessary SPI pin parameters. the only other thing I could think of is initializing the SPI and then remuxing the pins myself by calling into espressif's core apis. not something i want to do.
best,
honey the codewitch
PS: regarding globals: I know it's bad practice, but so are globals, and honestly i'd rather not get my locals and globals colliding. I guess if i went to something like g_ that would do it, but then everything starts with g_ and that aesthetically doesn't work for me. I figure if i collide with something I can rename it, and from the library code adafruit releases it seams they use a lot of things like "y0" in their global variable names. I'd rather not conflict with those either. In other words, I've thought about it and this is in my opinion, the best of an array of bad choices.
I don't have a second SD reader. Sorry I probably could have been clearer. I have a second SPI bus. The first SPI bus is wired to a display controller called an RA8875. The second bus is wired to the SD Reader. ESP32s have two buses but the second is by default mapped to the flash controller pins. You have to remap them in order to use them. Two buses are necessary in this setup because the RA8875 uses SPI mode 3 which cannot be shared with an SD reader.
yes I agree that what I describe is "weird" but following the source code it seems that's what really happens... I have also seen @me-no-devrecommending doing it like you do but with different PINS
What's really curious is that like I said, I have another ino where all this works, no problem - same hardware configuration. Same equipment. Literally all i do is flash another ino to it and the code in there works.
exactly the same pins? would be interesting to see the other code and double check what might differ
JML yes. I'm not even touching the hardware between flashing the different inos.
It's hard to tell how exactly it's different because the overall flow of the proprietary ino is more complicated and the SD access code is buried.
The main difference is it calls SD.end() first before reinitializing everything. That way it only ends after the next call, which seems to work well with that setup.
I also reinitialize on every write - which is why my writeToFile() routine is also written that way. This is because there is no line change detection for my SD reader and the SD card itself is the SPI device, which is why I'm just reinitializing all the time in case it was removed and reinserted. I've tested that code extensively.
I pasted this code largely from that. I wish I could post my proprietary ino but I can't disclose it.
correction on what I said before and why the pins are NOT changed. I missed the test that will return immediately if SPI has already been initialized right at the start of begin()
if(_spi) {
return;
}
have you tried disconnecting the other peripherals that are connected but not handled in that code?
Not yet. I'm saving that as a last resort as this is on a solderless board still and there are enough wires that the odds of a bad connection are very high. I've had to jiggle what was there when i first got it working, now I don't touch it and if i need to make sure the hardware connections are good i run my proprietary ino on it through a diagnostic. If it can't init any critical hardware, it dumps to the serial and refuses to boot. Non critical hardware like the SD which it can operate without it STILL initializes them and dumps the result to the serial so I know the connections are good.
ETA: I built a new circuit with a different ESP32 chip and a different reader, and only those two pieces of hardware. It does the same thing - writes a zero byte "/test.txt"
I was curious of possible issues with pins not configured whilst expected by the target device or bus to be set as OUTPUT (may be you've seen in the past that using the SD library on an Ethernet Shield would still require to have pin 10 as OUTPUT)
so may be before tweaking the wires, try adding in your code the pin definitions and begin() functions for the RA8875 and DS1307 ?
actually i do that already - in my proprietary ino, and see my edit - I've built a new circuit with a new SD reader and new ESP32, wired up on the second SPI bus w/ remapped pins. Whole different circuit, same result. =(
Edit: I've now also tried it on the first SPI bus (using the default pins for that bus and modified code) and same result, writes the file, but no contents
What's the preferred way of closing this thread? I found the issue. My device wasn't formatted properly somehow. It was working in some directories but not others. When I took the SD over to my windows machine, formatted it, then returned here to write the file, it worked great.
Sorry folks, and thanks for all your help in any case.
oh, don't be sorry! We all learned a lot and future readers will do the same.
The byte count information does not come from your file, it comes only from the header information in the FAT. Your "file" will always be made up of 512 byte segments. A 0 byte file likely has just one 512 byte segment with no new data written to it by your program.