In the Sd2Card.cpp file, used within the SD library, there is a #ifndef macro:
#ifndef SDCARD_SPI
#define SDCARD_SPI SPI
#endif
that sets the SPI bus to be used. In my case, I would like to use the second SPI bus, SPI1, but I cannot work out how to define the entity SDCARD_SPI in my sketch in a way that is recognised by this macro. I can change the definition in Sd2Card.cpp to
#define SDCARD_SPI SPI1
and everything works as I would like, but how do I include a definition somewhere else so that the macro behaves as intended, assigns the value SPI, by default—when there is no existing definition of SDCARD_SPI—but picks up my desired definition, SPI1, when I want to use the SPI1 bus?
I have tried the obvious option of simply including the above definition in my sketch, but it does not appear to be recognised within Sd2Card.cpp, and I don't have a good enough understanding of the use of extern or any other construct that might be used to achieve the desired outcome.
#define SDCARD_SPI SPI1 actually defines how the library is going to be compiled. You can not have it compiled twice in the same sketch with different #definition. So, if you #define SDCARD_SPI prior to #including the library this is how the library is going to be compiled in your sketch.
If you need two different values for SDCARD_SPI in the same sketch you should reprogram the whole library so that SDCARD_SPI would be a parameter rather than compile-time directive.
I'm using a Heltec CubeCell Plus Dev-Board, but the question was really meant more generally: if there's a [#ifndef] macro checking whether or not something has been defined before a library file is 'processed', how do I get that entity defined in such a way that the linker/loader or whatever knows that it has indeed been defined?
No, I only need it defined once, I just need to know how to define it in such a way that the [#ifndef] macro in the library knows that it has already been defined [elsewhere].
That suggestion was sounding promising but alas, no, that didn't seem to make any difference. My local definition is recognised within my sketch, but not, it would seem, by the library when it is loaded.
If it helps, the following is the code, including the recommendation of @gcjr, to the point of 'failure':
#define SDCARD_SPI SPI1
#include <SPI.h>
#include <SD.h>
#define CS1 GPIO4
File myFile;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
delay(1000);
SPI1.begin(SCK1,MISO1,MOSI1,CS1);// sck, miso, mosi, nss
#ifndef SDCARD_SPI
Serial.println("[setup] No definition...");
#else
Serial.println("[setup] Definition recognised...");
#endif
Serial.print("Initializing SD card...");
if (!SD.begin(CS1)) {
Serial.println("failed!");
while (1);
}
Serial.println("done");
As it stands, my definition is recognised locally, but I never get past the SD.begin(CS1) check, unless I go in and modify the library to assign SPI1 as described in my original post.
guessing your output was [setup] Definition recognised.... which would also be the output without your local definition because SDCARD_SPI will be defined in the library
can you print the values of SPI, SPI1 and SDCARD_SPI instead?
That depend on how the library is structured. In some cases you can't, you must change the definition in the library's source files themselves. In other cases you can put the #define statement before the #include statement for the library's .h file. The FastLED library, for example, has several optional features that are implemented this way.
That's correct, but without my local definition I get
08:30:40.302 -> [setup] No definition...
08:30:40.302 -> Initializing SD card...failed!
So there's no 'link' between my local definition and that used in the SD library. The fact that the #ifndef macro is present in the Sd2Card.cpp file suggests that the author believes that the relevant definitions could have been made elsewhere. I think what I am trying to work out how this would be possible—how would a situation arise where that #ifndef macro would not assign a value to SDCARD_SPI.
I tried just putting the #define before the #include statement in the SD.h file and that didn't work either. Not surprisingly, if I put the #define in the Sd2Card.h file, before the #ifndef macro, or in either of the .h files that are #included therein, it is recognised but, in a practical sense, that's not really any different to changing the definition in the Sd2Card.cpp file—it would apply every time the definition was used, and the #ifndef macro would then appear to be superfluous (i.e. if it can only ever give one result, why would it be there in the first place?)
I'd like to specify the option of using the SPI1 bus—signalling to the #ifndef macro that it should not include the definition that specifies the SPI[0] bus—in some file that a user would normally be responsible for preparing, ideally the 'parent' sketch itself, and not to have to modify any of the library files, which the average user would not be expected to be doing.
So how is this done? Does the user set the optional features by declaring or defining something in their sketch or a 'local' .h file?
explains the situation... What I want can't be done through the IDE, maybe unless I'm willing to get under the covers and use the CLI, which I didn't even know existed.
If I've misinterpreted the essence of the explanations provided in this thread, I'd still love to hear how I can solve my particular problem, or if @pert is out there and can confirm my [unwelcome] suspicion, I'd be [not so] happy to have my conclusion confirmed.
It all comes down to the library's .cpp files being compiled separately from your .ino file. So any #define's you make in the .ino file have no effect on the library's .cpp files.
Some light reading:
I've added extra choices to existing options with the techniques outlined above. It's quite likely that you could add an extra option to give you a choice of the default SPI bus in the same manner. It would be a bit of a learning experience though.
@horace, I just realised a detail in what you were suggesting there:
The SD library for the ESP32 provides a form of the begin method that includes the specification of the SPI bus to use. There is no such form of the begin method in the 'standard' version of the library.
The fact probably is that the Heltec CubeCell support software also needs to include a version of the SD library that includes this functionality, particularly given that in this case there is an expectation that the second SPI bus, SPI1, will generally be used to support external SPI connectivity.
By putting the macro's #define in the user code before the #include for the library. It works because that library is structured to support that method.
I've just had a quick look at that library, but there's a lot of stuff in there. Is there any particular area there you could point me to that illustrates the required structure?
it looks like this is more complicated. Don't understand why the code was written this way or how these defines are intended to be used
if you look inside Sd2Card.cpp, the bodies of functions often contain code defined within an #ifndef USE_SPI_LIB and an alternative that uses SDCARD_SPI as a prefix for methods, e.g. SDCARD_SPI.transfer(). There is also SOFTWARE_SPI
USE_SPI_LIB is defined within both Sd2Card.h and Sd2Card.cpp. SOFTWARE_SPI and SDCARD_SPI are undefined.
i don't see any point in defining SDCARD_SPI with providing the associated methods.
So am I understanding correctly if I read this to mean that the definition is not really intended to be user-controlled as such, but rather controlled universally for a particular board definition—i.e. the intention [of the macro] is not for a user to be able to specify which SPI bus to use but rather for a particular SPI bus to be identified for use with a specific board?