XIAO nrf52840 SD-card and SPI-display

Hi

I have a project running on a XIAO nrf52840 with a Sharp MIP-display on SPI (needed for performance) and need to log a bit of data to the sd-card coming from sensors… basically timestamp, GPS lat/lng and 4 float values, with at least 2Hz, better 10.
So this would be:

it would be something like:

  • timestamp (The time stamp consists of the number of weeks since that zero point and the number of seconds since the last week number change (0 to 604,799).) - so f.e. 2200 (weeks) and 604000 (seconds) making it 220060400 - 9 digits long
  • GPS latitude and longitude (20.1234567, 10.1234567) so 20 digits
  • 4 floats with 2 decimal places, so 5 digits each, 20 digits in sum

with crlf, separators etc. around 60 characters per update, 480 bytes, 10/s would then be 4800bytes/s

So can I use some SPI-adapter for an SD-card and just use a soft-SPI? Should be plenty fast enough, right?

Thanks for any suggestion, hint or tipp.

Cheers

@msfujino I imagine that the file open/close take a lot of the 30ms, so I could of course also “cache” them in RAM for a few seconds and then purge them into the SD every now and then, if that makes more sense?

this board could be a solution but I don’t understand yet if the XIAO supports SDIO… Adafruit Micro SD SPI or SDIO Card Breakout Board - 3V ONLY! : ID 4682 : $3.50 : Adafruit Industries, Unique & fun DIY electronics and kits

Hi raffiniert,
For example, with 32MHz SPI, “file_open → write 60 digit numbers → file_close” takes about 24~27mS.

Here is the sketch I used for this test.

//----------------------------------------------------------------------------------------------
// Boards Library : Seeed nRF52 Borads 1.0.0
// Boards Select  : Seeed nRF52 Borads / Seeed XIAO nRF52840 (Sense)

// Using SSD1306(8MHz) and SD(32MHz) via SPI interface
// 2023/02/27

#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

//**************************************************************************************** 
#define SPI_MOSI   D10      // MOSI/D1
#define OLED_DC     D6      // DC 
#define SPI_MISO    D9      // MISO 
#define SPI_CLK     D8      // CLK/D0
#define OLED_CS     D7      // OLED CS
#define SD_CS       D2      // SD CS 
#define OLED_RESET  D3      // OLED RES
//***************************************************************************************** 

Adafruit_SSD1306 display(1228, 64, &SPI, OLED_DC, OLED_RESET, OLED_CS, 8000000UL);
File myFile;

void setup()
{
  Serial.begin(115200); 
  while(!Serial);

  pinMode(LED_RED, OUTPUT);
  digitalWrite(LED_RED, HIGH);
  
  // Initialization of SSD1306 (8MHz)
  if(!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println("Initialization failure of SSD1306");
//    while (1);
  }
  Serial.println("SSD1306 initialization completed");
  
  // Initialization of SD card (32MHz)
  if (!SD.begin(32000000UL, SD_CS)) {    
    Serial.println("Initialization failure of SD card");
//    while (1);
  }
  Serial.println("SD card initialization completed"); 
  display.clearDisplay();
}

void loop()
{
  unsigned long looptimestamp = millis();   // loop time start
  
  // sample display
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.setTextSize(2);
  display.print(millis()); display.println("mS");
  display.print(micros()); display.println("uS");  
  display.display();

  // *************************************************************
  digitalWrite(LED_RED, LOW);
  unsigned long timestamp = micros();   // start
  // file open
  myFile = SD.open("TEST.txt", FILE_WRITE);
  if (!myFile) {
    Serial.print("error opening TEST.txt");
  }  

  // sample data write 60 digit number
  for(int i = 0; i < 5; i++) {
    myFile.print("123456789"); myFile.print(",");
  }
  myFile.println("123456789");
        
  // file close
  myFile.close();
  digitalWrite(LED_RED, HIGH);

  Serial.print("save time : ");
  Serial.println(micros() - timestamp);           // 60 digit number : 24~27mS
  
  while(millis() - looptimestamp < 100);          // loop time 100mS
}
1 Like

Thank you!
And if you write 10 or 100 times the charactwrs?
Just to see what part is file open/close and what‘s actually the data.

I measured open, save, and close individually. Increasing the number of data was not proportional, perhaps due to the buffer.
If it can be closed properly before turning off the power, there is no need to open/close every time.
I think the Adafruit breakout board will work fine.

open              : 13~14mS
save 60 digit     : 3~7mS
close             : 9~10mS
1 Like

thank you so much, again.

So I could basically get away with opening the file once on setup and close it on before shutdown. Or I could do it every minute to be on the safe side.
What would happen if the last “close” would be missing? Would just the data since the last open not be saved?

Another option is to “open” the file once with setup() and then “flush” it each time it is “save” with loop(). However, “flush” requires the same amount of time as “close”.

If the power is turned off while manipulating the file, in the worst case, the file will be destroyed and all data will not be readable.
The following methods can be considered.

  1. Using record/not-record switch and turning off the power only when the data is not being recorded.
  2. Monitor the power supply and close the file with a voltage drop interrupt.
1 Like

If I would understand how to power-down the XIAO including all connected peripherals (display, GPS, SD-card-adapter) with a button I would go this route. At the moment, I’m switching it with a hardware switch, which is unelegant but at least not using power when down :wink:

Btw @msfujino you are a great inspiration and I want to thank you again for all your generous help

in this code, isn’t MISO = D0? Or do I misunderstand your comment?

See Hardware overview on the Wiki page. MOSI=D10.
The definitions of SPI_MOSI, SPI_MISO, and SPI_CLK are determined by hardware and may not be necessary.
Why did you think D0?

1 Like

would this really work? Like attaching an interrupt to EN and save before it drops too low?

Explained in the case of connecting a 3.7V battery to the pad and turning it on/off with the power switch. (This has been proven with XIAO_SAMD21, but not tried with XIAO_nRF52840.)

  1. Monitor the battery voltage PIN_VBAT by AD conversion, and “close” and stop the sketch when the voltage drops below 3V, for example.
  2. Monitor the battery voltage with COMP (datasheet 6.5 COMP–Comparator) and generate an interrupt to “close” and stop the sketch when the voltage drops below 3V, for example.

To ensure that “close” is executed, the operating voltage of XIAO and SD must be 3 V or higher for 10 mS, for example. You will need to connect a capacitor of about 1000uF (value not calculated) to the battery pad in case of a sudden battery disconnection or power switch off.

[EDIT]
You will need to connect a capacitor of about 1000uF (value not calculated) to 3.3V pin in case of a sudden battery disconnection or power switch off.

Hi there,
I don’t know if it applicable to you op, but fyi ,that Grove Expansion base with the extra flash chip installed works with the existing Qspi onboard flash.
Perhaps, sd card replacement ,faster too.
HtH
GL :smiley: PJ :v:

Very nice of you, thanks @PJ_Glasso
I changed my code to only write the buffered info once per minute, and it’s plenty fast enough like this

1 Like