Writing to sd card on XAIO expansion board

I have tried without success to write to the sd card on the xaio expansion board. Code used for many other Arduino boards does not work. Other than knowing that the sd chip select pin is 2, is there something else unique to Xiao? I am writing in C++.

1 Like

I just used Examples from the SD library.

For the CardInfo example: After changing chipSelect to 2 for the XIAO expansion board, I plugged in a 16 Gig SD card that has, among other things, a FAT32 partition that has a bunch of files.

Here’s what it told me:

XIAO Expansion board SD Card Test Compiled on Mar 31 2022 at 18:38:15

Initializing SD card...Wiring is correct and a card is present.

Card type:         SDHC
Clusters:          516190
Blocks x Cluster:  1
Total Blocks:      516190

Volume type is:    FAT32
Volume size (Kb):  258095
Volume size (Mb):  252
Volume size (Gb):  0.25

Files found on the card (name, date and size in bytes): 
OVERLAYS/     2020-07-31 22:00:14
  ACT-LE~1.DTB  2020-07-31 21:58:38 569
  README        2020-07-31 21:58:38 121565
  AKKORD~1.DTB  2020-07-31 21:58:42 1387
  ADAU19~1.DTB  2020-07-31 21:58:38 1027
  ADAU70~1.DTB  2020-07-31 21:58:40 1587
  ADS101~1.DTB  2020-07-31 21:58:40 2509
  ADS111~1.DTB  2020-07-31 21:58:40 2509
.
. // And all of the other files on the root of the FAT32 partition...
.

Bottom line: If this doesn’t work for you then either
Your card doesn’t have a FAT32 partition.

or

Your hardware is defective

Note that large SD cards these days come formatted as XFAT, which did not work the last time I tested the Arduino SD library. There are third-party tools for Windows that allow you to format them as FAT32 if necessary. (For Linux, just use fdisk/sfdisk followed by mkfs, as usual.)

Anyhow…

If CardInfo works but other stuff doesn’t, (creating, writng, reading files, etc…) then maybe you could post one of your projects, and maybe someone can help you get to the bottom of things.

My setup:
Arduino1.8.16, Seeeduidno samd board software 1.8.2. Seeeduino XAIO

Regards,

Dave

Footnote: The SD library ReadWrite example also worked, and with an additional output line from me, and after changing the SD.Begin statement to use pin 2 as the Chip select, output was (as expected)

SD Card ReadWrite Example compiled on Mar 31 2022 at 18:51:16
Initializing SD card...initialization done.
Writing to test.txt...done.
test.txt:
testing 1, 2, 3.

XIAO_SD_CardInfo.zip (1.9 KB)

davekw7x

Thank you for the quick reply. Initially, my sketch wasn’t doing the self-check, by adding “Sd2Card card” it at least performs the self-check and finds the sd card. Still not writing to sd card though. I have used multiple XIAO, XIAO expansion boards, and sd cards to no avail. I’ve attached my code for your review; I’m still fairly new to this so hopefully I have made an obvious (to you) mistake. BTW: I should mention that in spite of my love for this little controller, I find it somewhat flukey and very different than Nano and a couple other controllers, especially when it isn’t mounted on an expansion board. My original sketch was working fine on the Stroud Water Research Mayfly and the Seeeduino Stalker. The project is an ultrasonic-based Water Level Indicator for a stream flooding project my not-for-profit is undertaking.

type or paste code here

#define sensorPin 0
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include <Adafruit_SSD1306.h>
#include <Time.h>
#include "RTClib.h"

Sd2Card card;
//SdVolume volume;
//SdFile root;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define ds3231_I2C_ADDRESS 0x68
#define TIME_MSG_LEN 11
#define TIME_HEADER 'T'
#define sensorPin 0
#define PCF8563address 0x51

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

long distance = 0;

File myFile;
char fileName[] = "WLI_001.txt";
const int chipSelect = 2;
char charRead;

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
String days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

byte bcdToDec(byte value)
{
  return ((value / 16) * 10 + value % 16);
}

byte decToBcd(byte value) {
  return (value / 10 * 16 + value % 10);
}

void setPCF8563()
// this sets the time and date to the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void readPCF8563()
// this gets the time and date from the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(PCF8563address, 7);
  second     = bcdToDec(Wire.read() & B01111111); // remove VL error bit
  minute     = bcdToDec(Wire.read() & B01111111); // remove unwanted bits from MSB
  hour       = bcdToDec(Wire.read() & B00111111);
  dayOfMonth = bcdToDec(Wire.read() & B00111111);
  dayOfWeek  = bcdToDec(Wire.read() & B00000111);
  month      = bcdToDec(Wire.read() & B00011111);  // remove century bit, 1999 is over
  year       = bcdToDec(Wire.read());
}

void setup() {
  pinMode(sensorPin, INPUT);
  Serial.begin(9600);
  Wire.begin();
  pinMode (2, OUTPUT);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("\nInitializing SD card...");
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    Serial.println("* is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    while (1);
  } else {
    Serial.println("Wiring is correct and a card is present.");
  }
}

void read_sensor() {
  distance = analogRead(sensorPin) * 5;
}

void print_data() {
}

void loop()
{
  Serial.print(distance);
  Serial.print("mm");
  Serial.print('\t');

  readPCF8563();
  Serial.print(" ");

  { if (month < 10)
      Serial.print("0");
  }
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/20");
  Serial.print(year, DEC);
  Serial.print('\t');
  { if (hour < 10)
      Serial.print("0");
  }
  Serial.print(hour, DEC);
  Serial.print(":");
  if (minute < 10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second < 10)
  {
    Serial.print("0");
  }
  Serial.println(second, DEC);
  Serial.print('\t');

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  { if (month < 10)
      display.print("0");
  }
  display.print(month, DEC);
  display.print("/");
  { if (dayOfMonth < 10)
      display.print("0");
  }
  display.print(dayOfMonth, DEC);
  display.print("/20");
  display.print(year, DEC);
  display.setTextColor(WHITE);
  display.setCursor(0, 18);
  { if (hour < 10)
      display.print("0");
  }
  display.print(hour, DEC);
  display.print(":");
  { if (minute < 10)
      display.print("0");
  }
  display.print(minute, DEC);
  display.print(":");
  { if (second < 10)
      display.print("0");
  }
  display.print(second, DEC);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 38);
  display.print(distance);
  display.print("mm");
  display.display();

  myFile = SD.open("WLI_001.txt", FILE_WRITE);
  { if (month < 10)
      myFile.print("0");
  }
  myFile.print(month, DEC);
  myFile.print('/');
  { if (dayOfMonth < 10)
      myFile.print("0");
  }
  myFile.print(dayOfMonth, DEC);
  myFile.print('/');
  myFile.print(year, DEC);
  myFile.print('\t');
  { if (hour < 10)
      myFile.print("0");
  }
  myFile.print(hour, DEC);
  myFile.print(':');
  { if (minute < 10)
      myFile.print("0");
  }
  myFile.print(minute, DEC);
  myFile.print(':');
  { if (second < 10)
      myFile.print("0");
  }
  myFile.print(second, DEC);
  myFile.print('\t');
  myFile.print(distance);
  myFile.print("mm");
  myFile.close();

  read_sensor();
  print_data();
  delay(2000);
}

Since you are experiencing problems with the SD card, I respectfully suggest that you make a test program that does nothing but manipulate a file on the SD card. I previously showed output from the SD library example program.

I’m not going to try to figure out what your problem is, but…

Here’s something a little more elaborate than the library example that works for me with an XIAO plugged into the Seeed XIAO expansion board: I attached a screen capture of the output.

If this doesn’t work for you, let us know. If it does, then maybe you can reconcile whatever differences exist between my example and your application.

/*
  SD Read/Write example for Seeeduino XIAO plugged into the
  Seeed XIAO expansion board

  Create a file named example.txt and put some stuff in it.
  Then
    Show the contents and write some new stuff in a loop repeated
    every five seconds

  If the user presses a key, the program stops executing,
  and the SD card can be removed from the expansion board
  to be read on your workstation.

  davekw7x
  April, 2022


*/

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

File exampleFile;
const char *fileName = "example.txt";

// XIAO Expansion board has SD Chip Select on pin 2 of the XIAO
const int SD_ChipSelect = 2;

void setup()
{
  // Wait for serial communications port to open:
  Serial.begin(115200);
  while (!Serial) ;

  Serial.println("Daves SD Test example compiled on " __DATE__ " at " __TIME__ "\n");
  Serial.print("Initializing SD card with Chip select on pin ");
  Serial.println(SD_ChipSelect);

  if (!SD.begin(SD_ChipSelect)) {
    Serial.println("Initialization failed! ");
    Serial.println("Make sure an SD card formatted as FAT or FAT32 is plugged in!");
    while (1);
  }
  Serial.println("Initialization done.");
  
  // When you open a file for writing, it is actually in an "append" mode
  // and new stuff will be written at the end.
  // So, I'll erase the old file if it exists so that every time
  // I run this program it starts with a new, fresh file.
  if (SD.exists(fileName)) {
    Serial.printf("Old file %s is being deleted.\n", fileName);
    SD.remove(fileName);
  }

  // OK.  Now ready for business
  Serial.printf("Opening file %s for writing.\n", fileName);
  exampleFile = SD.open(fileName, FILE_WRITE);
  if (!exampleFile) {
    Serial.println("Error: Couldn't open the file");
    while (1) ;
  }
  exampleFile.print("  File initialized at time ");exampleFile.println(millis());
  // Close the file so that we can re-open it for reading
  exampleFile.close();
  
  exampleFile = SD.open(fileName, FILE_READ);
  if (!exampleFile) {
    Serial.println("Hmmm...Opened for writing OK, but couldn't open for reading!");
    Serial.println("Needs some detective work: Are connections secure?");
    while (1) ;
  }
  Serial.println("Here are the file contents in setup():");
  while (exampleFile.available()) {
    Serial.print((char)exampleFile.read());
  }
  // Now, close the file so that it can be reopened, examined, and modified in loop()
  exampleFile.close();
} // End of setup()

void loop()
{
  unsigned long now_ms = millis();
  static int count = 0;

  // Append new stuff
  char buffer[80];
  snprintf(buffer, sizeof(buffer), "  Loop %d at %lu ms", ++count, now_ms);
  exampleFile = SD.open(fileName, FILE_WRITE);
  exampleFile.println(buffer);
  exampleFile.close();

  // Now read it back
  Serial.print("\nFile contents after writing in loop ");Serial.println(count);
  exampleFile = SD.open(fileName, FILE_READ);
  while (exampleFile.available()) {
    Serial.print((char)exampleFile.read());
  }
  exampleFile.close();

  // If the user presses a key, the program effectively halts here.
  // Since the file has been closed at this point, the SD card can
  // removed from the test board and its contents can be read on your
  // workstation.
  while ((int)(millis() - now_ms) < 5000) {// time test
    if (Serial.available()) {
      Serial.read();
      Serial.println("\nUser input: OK to remove SD Card.");
      while (1);
    }
  }// End of time test
} // End of loop()

[/Begin Editorial Comment]
I will close with a note that I don’t think there is much flakey about the XIAO. It uses a samd21 processor that is vastly different from the traditional avr cpus in classical Arduino boards, and there are some hardware differences that affect functionality and software usage. I think it is phenomenal that the Arduino community and vendors are able to get things to run at all with the same IDE interface and with lots of similar, if not identical, library functions.
[/End Editorial Comment]

Regards,

Dave

I thank you for the input, will try all suggestions and reply back.

Your sketch failed on three different XAIO expansion boards, each with their own XIOA microcontrollers, plus with four different sd micro cards. Failed to initiate sd card on all attempts.

Tried your sketch on two Unos, and a Mega 2560 with a sd card shield and different full-size sd cards to no avail. I received a " ‘class hardware serial’ has no member named ‘printf’, did you mean ‘print’?" fault. Of course I don’t know of the minor differences between these processors to know if it should have only run on the XIAO. Will try other micro sd cards tomorrow.

Find it incredulous that I have multiple defective XIOA/sd shields since they were purchased months apart. Programming is via USB port.

I’m sorry that did not work for you. I just now copied the source code from my previous post into a new Arduino project and verified that it works as I reported. (I never post code that I haven’t tested, but sometimes stuff happens…)

Anyhow…
One thing that comes to mind is that the SD card must be formatted as FAT32 (or FAT, but I haven’t tested FAT recently).
Some SD cards (especially large-capacity cards) come formatted as exFAT. This did not work with the SD library the last time I tested

Some SD cards (especialy older ones) came formatted as NTFS, which used to be the default for Windows. These definitely do not work with the SD library (I just now tested this.)

I show screen shots from Windows Disk Manager. Make sure yours is formatted FAT32. This is from my Windows 10 workstation. It looks exactly the same on Windows 11.

I also show a screenshot from the Arduino Serial Monitor and a screenshot from the Windows machine showing the file in File manager and showing the contents in an editor window after the run I just made.

My setup
Arduino version 1.8.16 with Seeed SAMD Board version 1.8.2

The SPI library is in the Board software, and the SD library is in the basic Arduino library. No external libraries have been loaded.

Note that Serial.printf() is defined in the Seeed SAMD Board software, which is the subject of your post and my response. I did not and do not claim anything for other stuff that I have not tested with this specific setup.

Seeed XIAO Serial.printf() is used like the standard C library printf(). You can always use the traditional Arduino Serial.print();Serial.println(); for other boards that do not support printf().

Regards,

Dave

Sorry, no go. Just tried three new sd micros, 32GB. Failure to initialize. All are formatted FAT32 via Windows 10.Preformatted text

I attempted using other pins for the chip select in the event the manufacturer had made a change, nada.

Dave, your help is greatly appreciated, I’m pulling my hair out trying to get this project ready to measure stream levels in time for spring flooding and the help is welcome.

Attached is a bare-bones of my sketch in the event you want to check for mistakes.

Thank you again!

[code]
#include <SD.h>
#include <SPI.h>

Sd2Card card;
#define sensorPin 0

long distance = 0;

File myFile;
char fileName[] = "WLI_001.txt";
const int chipSelect = 2;

void setup() {
  pinMode(sensorPin, INPUT);
  Serial.begin(9600);
  pinMode (2, OUTPUT);
  SD.begin ();

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("\nInitializing SD card...");
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    Serial.println("* is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    while (1);
  } else {
    Serial.println("Wiring is correct and a card is present.");
  }
}

void read_sensor() {
  distance = analogRead(sensorPin) * 5;
}

void loop()
{
  Serial.print(distance);
  Serial.println("mm");

  myFile = SD.open("WLI_001.txt", FILE_WRITE);
  myFile.print(distance);
  myFile.print("mm");
  myFile.close();

  read_sensor();
  delay(2000);
}
[/code]```

Well, if you can’t get my sketch to run, I can’t think of anything else I can do for you.

However, looking at your sketch I see

  SD.begin ();

With no arguments, SD.begin uses something #defined as SD_CHIP_SELECT_PIN somewhere in an Arduino libary. (It turns out this value is 4)

I changed that to

  SD.begin(chipSelect);

And, with no other changes in your sketch, it worked for me on my Seeeduino XIAO Expansion Board v1.0

I attached screenshots of the serial monitor output and showing the contents of the file. (I pulled the plug after four times through the loop.)

This is using the same Sandisk Ultra 16 GB uSD card that I used for testing my sketch.

Bottom line: That pretty much does it for me. I’m running out of gas on this one

Regards,

Dave

SD_SerialMonitor.

SD_FileContents

That did the trick! Weeks of toil due to a missing word, “chipSelect”. What is weird is that it worked on other boards as I had previously mentioned. Dave, you have done a great service to me and my not-for-profit, Greenbelt Overhaul Alliance of Levittown (G.O.A.L.), located in Levittown, Bucks County, Pa. Trust me, I know how much work goes into troubleshooting.

I have always been reluctant to use forums where some of the participants get nasty with us newbies, thank you for being so courteous.

There is a default chip select that is used if you invoke SD.begin() with no arguments. For the XIAO, it happens to be pin 4 (Shown as A4 on XIAO pinout drawings).
To make it use something else, you call SD.begin() with the chip select pin that you are connecting. That’s pin 2 for the XIAO Expansion board.

The other boards you used apparently had the correct default SS assignment so they worked as expected without your having to do anything else.

I note that the XIAO pinout drawings (at least the ones that I have seen) do not have a SPI SS pin shown, so users aren’t aware that there is a default.

By the way:
I suggested ways of running the XIAO Chipinfo and XIAO ReadWrite examples on the XIAO expansion board, and my test sketch also used SD.begin() with Pin 2 chip select. Didn’t those work on your setup? I really don’t understand.

Anyhow, I’m glad you finally got things to work.

Bottom line:
Onward and upward!

Regards,

Dave

Footnote to all of those unhelpful, unkind “helpers” who are nasty to newbies (or anyone else asking for help):
No one was born knowing this stuff!

2 Likes