Has anyone successfully integrated an SD card to the CubeCells?

Hi all.

I need to get an SD card working with HTCC-AB02 but I’m looking around and finding that there is no clear solution out there. Has anyone got this to work?

I want to use the SPI1 so as not to interfere with the LoRa (on the SPI) and it’s right there for the taking!

From what I’ve been seeing, the way to go is with the SdFat Library but I just can’t get any of their examples to compile for the CubeCell.

Any working code for this would be MUCH appreciated.

Specifically: when trying to compile the SoftwareSpi.ino example from the SdFat Library on the HTCC-AB02 CubeCell, I get a lot of errors, the most obvious being that:

" C++11 ‘constexpr’ only available with -std=c++11 or -std=gnu++11"

Why isn’t gnu++11 defaulted? I changed the platform.txt file, from the following location:

C:\Users<user>\Documents\Arduino\hardware\CubeCell\ASR650x-Arduino\platform.txt

and turned on the gnu++11 flag on line 90:

compiler.cpp.extra_flags= -std=gnu++11

I compile again and this time I get many less errors, but I still get:

In file included from C:\Users\ngensadmin\AppData\Local\Temp\arduino\sketches\B73DE0AAA31688389119CE82A29A7859\sketch\SoftwareSpi.ino.cpp:1:0:
c:\users\ngensadmin\documents\arduino\libraries\sdfat\src\digitalio\DigitalPin.h: In function 'void fastPinMode(uint8_t, uint8_t)':
C:\Users\ngensadmin\Documents\Arduino\hardware\CubeCell\ASR650x-Arduino\cores\asr650x/Arduino.h:86:47: error: 'PINMODE_mode' was not declared in this scope
 #define pinMode(pin,mode) PINMODE_ ## mode(pin)
                                               ^
c:\users\ngensadmin\documents\arduino\libraries\sdfat\src\digitalio\DigitalPin.h:279:3: note: in expansion of macro 'pinMode'
   pinMode(pin, mode);
   ^

Using library SdFat at version 2.2.3 in folder: C:\Users\ngensadmin\Documents\Arduino\libraries\SdFat 
exit status 1

Compilation error: exit status 1

At this point I don’t know where to go.

Heltec Supporters can you assist? The library is Bill Greiman’s original at https://github.com/greiman/SdFat

More specifically: What would it take to modify the Arduino SD library (wrapper of the SdFat) to be able to use SPI1 and not the default SPI? Arduino-pico has done this. The following screenshot is from
https://arduino-pico.readthedocs.io/en/latest/fs.html#using-second-spi-port-for-sd

BTW the standard SD.h library compiles fine on CubeCell after back and forth between Heltec and BillP .

I can’t comment on most of the things said here - I don’t use CubeCell nor SD cards, but one thing that struck me when reading your post is this: the SdFat library has 205 open issues. That number is unhealthy and points to some serious issues with the library. I’d honestly look around and see if there’s another popular library out there that appears less problematic.

I did look at this a little while back and I can’t remember exactly why I put it aside, although I clearly didn’t get things working as I wanted. But I did get the following:

  1. I could define the second SPI (SPI1) bus OK (#define CS1 GPIO4, the other pins are predefined in the CubeCell pins_arduino.h file))
  SPI1.begin(SCK1,MISO1,MOSI1,CS1);
  1. I then found the following (lines 77–88) in the Sd2Card.h file (one of the SD library utilities—~/Library/Arduino15/libraries/SD/src/utility/Sd2Card.h):
  #ifndef SDCARD_MOSI_PIN
    /** SPI Master Out Slave In pin */
    uint8_t const  SPI_MOSI_PIN = MOSI;
    /** SPI Master In Slave Out pin */
    uint8_t const  SPI_MISO_PIN = MISO;
    /** SPI Clock pin */
    uint8_t const  SPI_SCK_PIN = SCK;
  #else
    uint8_t const  SPI_MOSI_PIN = SDCARD_MOSI_PIN;
    uint8_t const  SPI_MISO_PIN = SDCARD_MISO_PIN;
    uint8_t const  SPI_SCK_PIN = SDCARD_SCK_PIN;
  #endif

I seem to have tried to define the relevant variables:

#define SDCARD_MOSI_PIN MOSI1
#define SDCARD_MISO_PIN MISO1
#define SDCARD_SCK_PIN SCK1

in my sketch, but this did not seem to trigger the #else part of the above conditional macro. I did, however, succeed in using the second SPI bus (SPI1) to access the SD card reader by explicitly changing the assignments in the first part of the above macro:

    /** SPI Master Out Slave In pin */
    uint8_t const  SPI_MOSI_PIN = MOSI1;
    /** SPI Master In Slave Out pin */
    uint8_t const  SPI_MISO_PIN = MISO1;
    /** SPI Clock pin */
    uint8_t const  SPI_SCK_PIN = SCK1;

I would need to go back through my notes more carefully to work out why I didn’t get any further than this. My application required the SD card while also using LoRa [on the first SPI bus] so I likely hit a problem there that I thought was a lower priority than something else I had queued at the time (and since…). But maybe this will help get you closer to a solution to your problem…

EDIT: Sorry, just running through this again, it doesn’t look like this [everything under 2. above] uses the second SPI bus, SPI1, for the SD library at all, it looks like it just defines different parameters for the first SPI bus, which will be at least one reason why I didn’t get any further with this…

EDIT 2: It looks like I can get the SD library to use SPI1 if, as well as the changes described above, I replace the text at lines 27–29 in the file ~/Library/Arduino15/libraries/SD/src/utility/Sd2Card.cpp:

  #ifndef SDCARD_SPI
    #define SDCARD_SPI SPI
  #endif

with

  #ifndef SDCARD_SPI
    #define SDCARD_SPI SPI1
  #endif

(Please note that I have also corrected a typo in my specification of the corresponding .h file in 2. above.)

I seem to be able to create files and delete them OK, but reading and writing data to them still seems pretty flakey.

If you’re still interested, I have an update…

As noted above, writing data to the SD card on the CubeCell platform, using the current SPI & SD libraries, was very hit and miss—it would work sometimes, but most often not. Reading was actually OK, it was the writing before reading in the ReadWrite example that was ultimately causing the failures I observed. This had all the hallmarks of a [processor] timing problem—I saw something similar back when the CubeCells first came out.

Working my way through the relevant code, I have discovered that inserting a very small delay in the [CubeCell] SPI library transfer function (on my Mac, under the Arduino IDE, that’s ~Documents/Arduino/hardware/CubeCell/CubeCell/cores/asr650x/SPI/SPI.cpp, around line 183) solves this problem in my operating environment. If I insert a delay of 2 ms (1 ms gets you there more often than not, but not always) inside the if block at line 193 everything then seems to work reliably.

uint8_t SPIClass::transfer(uint8_t data)
{
	uint32 rxdata;
	uint32 timeout = 0;

	if(_spi_num == 0)
	{
		while (SPI_1_SpiUartGetRxBufferSize() == 0) {
			timeout++;
			if (timeout > spi_TIMEOUT) {
				delay(2);
				break;
			}
		}
	.
	.
	.

Note that there is a separate block of code, that follows the above, to handle SPI_2. Presumably, if you’re using the second SPI bus [on the CubeCell Plus] you would need to add a similar delay there, but I haven’t actually run any of these more recent tests on the CubeCell Plus (the CubeCell V2—same processor but restricted configuration capability—doesn’t identify pins for the second SPI bus and I haven’t done anything to see whether or not a second SPI bus might be ‘available’ regardless).

The delay doesn’t seem to cause any problems in my current environment but I will raise a report on GitHub in the hope that someone with a deeper understanding of ASR6502 behaviour, or the relevant lower-level code, will be able fix the underlying problem.

I have been running tests on a CubeCell V2, so only using the one SPI bus for both SD card writing and LoRa, and the two are working well together. I’m only [LoRa] transmitting, and not trying to write to the SD card at the same time, so blocking is not an issue in this environment.

EDIT: Sometimes it pays to sleep on a problem… I was troubled by the fact that just increasing the value of spi_TIMEOUT in the above code snippet didn’t have the same effect as the delay but I realised that I had incorrectly equated the timeout setting (which was 500) to milliseconds, when it is actually simply the number of cycles through the relevant loop. Looking through the various implementations of the SPI library, even this looks like a bit of a hack but if the CubeCell version was originally developed for the ASR6501 processor, and the ASR6502 is faster, it is logical that this timeout might need to be tuned to a given processor. I still reckon that there must be a more elegant solution here, but given the code we’re working with it seems that the solution to our current problem would simply be to increase the value of spi_TIMEOUT sufficiently—3500 seems to be the lower limit with the CubeCell V2 module that I’m using, so maybe using a value of 4000 would provide a bit of headroom without having an unacceptable hit on performance.

spi_TIMEOUT is set right near the top of the SPI.cpp file, at line 26:

#define spi_TIMEOUT	4000

So, ignore my suggestion to insert any delays and just increase the value of spi_TIMEOUT—this will apply no mater which SPI bus is being used.

1 Like

Thanks UP for this info. Do you know if this fix/hack affects the LoRa radio in any way? I’m currently distracted on something else (movig to the nrf9160 and cellular. My gateways are too much trouble) but I’ll revisit this shortly.

My testing has been pretty focused. My ultimate use was for error logging so all I’ve done is write some data to the SD card and then send the same data in one of my LoRa application packets to my gateway. My test rig ran for several days, writing to the SD card and sending LoRa packets every 60 sec, before I needed it for something else. So the CubeCell can definitely accommodate the SD card reader and LoRa together on the same SPI bus for an extended period. Whether or not that would still apply in a more complex environment, I couldn’t say…

The necessary change to the value of spi_TIMEOUT has been incorporated into the version of the CubeCell support library that is now available from GitHub at https://github.com/HelTecAutomation/CubeCell-Arduino.

1 Like