Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STM32L452 SPI2 port assignation not working #447

Open
NezhaZahri opened this issue Nov 2, 2023 · 17 comments
Open

STM32L452 SPI2 port assignation not working #447

NezhaZahri opened this issue Nov 2, 2023 · 17 comments

Comments

@NezhaZahri
Copy link

Hello,

I'm trying to connect my STM32L452 chip to an SD Card for logging purpose but it doesn't seem to work using port assignation delivered by STM32duino.
I tried using STM32Cube libraries and it's working, so the problem is not on my PCB but really the SdFat and/or STM32duino and the way I'm initializing things.

I tried to use the code example in here which is shown bellow.

Another thing is I went to find STM32Test.ino and it is mentioned that there is a V2 of the example but I can't find it.
image

I wonder if I missed something.

/*
  SD card test for stm32 and SdFat library
 
  This example shows how use the utility libraries
 
    SD card attached to the secondary SPI as follows:
        SS    = PB2;
        MOSI  = PC3;
        MISO  = PC2;
        SCK   = PB10;
 
   by Mischianti Renzo <https://mischianti.org>
  
   https://www.mischianti.org
*/
#include <SPI.h>
#include "SdFat.h"
 
SdFat SD;

// Define your pin configuration for SPI2
const int spi2ClockPin = PB10;    // SCK (Serial Clock)
const int spi2MisoPin = PC2;     // MISO (Master In Slave Out)
const int spi2MosiPin = PC3;     // MOSI (Master Out Slave In)
const int spi2chipSelectPin = PB2;  // CS (Chip Select)
 
#define SD2_CONFIG SdSpiConfig(spi2chipSelectPin, USER_SPI_BEGIN,SD_SCK_MHZ (10))

void printDirectory(File dir, int numTabs);
 
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  SPIClass SPI_2(spi2MosiPin, spi2MisoPin, spi2ClockPin);
  SPI_2.begin(spi2chipSelectPin);

 // SPI_2.setFrequency(1000000);
  Serial.print("\nInitializing SD card...");
 
  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!SD.begin(SD2_CONFIG)) {
  // if (!SD.begin(SD_CS_PIN)) {
    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.");
  }
 
  uint32_t cardSize = SD.card()->sectorCount();
 
  // print the type of card
  Serial.println();
  Serial.print("Card type:         ");
  switch (SD.card()->type()) {
  case SD_CARD_TYPE_SD1:
    Serial.println(F("SD1"));
    break;
  case SD_CARD_TYPE_SD2:
    Serial.println(F("SD2"));
    break;
 
  case SD_CARD_TYPE_SDHC:
    if (cardSize < 70000000) {
      Serial.println(F("SDHC"));
    } else {
      Serial.println(F("SDXC"));
    }
    break;
 
  default:
    Serial.println(F("Unknown"));
  }
 
 
//  print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("Volume type is:    FAT");
  Serial.println(int(SD.vol()->fatType()), DEC);
 
  Serial.print("Card size:  ");
  Serial.println((float) 0.000512*cardSize);
 
  Serial.print("Total bytes: ");
  Serial.println(0.000512*SD.vol()->clusterCount()*SD.sectorsPerCluster());
 
  Serial.print("Free bytes: ");
  Serial.println(0.000512*SD.vol()->freeClusterCount()*SD.sectorsPerCluster());
 
  File dir =  SD.open("/");
  printDirectory(dir, 0);
 
}
 
void loop(void) {
}
 
void printDirectory(File dir, int numTabs) {
  while (true) {
 
    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    entry.printName(&Serial);
 
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.print(entry.size(), DEC);
      uint16_t pdate;
      uint16_t ptime;
      entry.getModifyDateTime(&pdate, &ptime);
 
      Serial.printf("\tLAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", FS_YEAR(pdate), FS_MONTH(pdate), FS_DAY(pdate), FS_HOUR(ptime), FS_MINUTE(ptime), FS_SECOND(ptime));
    }
    entry.close();
  }
}

#ifdef __cplusplus
extern "C" {
#endif
  /**
  * @brief System Clock Configuration
  * @retval None
  */
  void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

    /** Configure the main internal regulator output voltage
  */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
      Error_Handler();
    }

    /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
    RCC_OscInitStruct.OscillatorType      = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState            = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState        = RCC_PLL_NONE;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
      Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
  */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
      Error_Handler();
    }
  }

#ifdef __cplusplus
}
#endif
@greiman
Copy link
Owner

greiman commented Nov 2, 2023

I can't help. Contact the author of this program:

by Mischianti Renzo https://mischianti.org

https://www.mischianti.org

The old example in SdFat was for a old board support package and there is no longer a working example for SdFat V2.

@greiman
Copy link
Owner

greiman commented Nov 2, 2023

I don't have your board but I tried a Nucleo L476RG using the "Arduino" SPI pins SS, MOSI, MOSI, SCK. (10, 11, 12, 13)

I uses the standard STMicroelectronics Arduino board support package which has super slow SPI.

Here is the standard bench example speed:

write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
361.19,1433,1414,1415
361.17,1433,1414,1416

Starting read test, please wait.

read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
358.89,1439,1424,1425
358.86,1437,1424,1425

I edited SdFatConfig.h like this

#define SPI_DRIVER_SELECT 1
#define USE_SPI_ARRAY_TRANSFER 4

A bit faster:

write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
1250.31,425,406,407
1250.31,424,406,407

Starting read test, please wait.

read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
1134.04,460,448,449
1134.30,461,448,449

Still almost Uno performance.

Try using the QuickStart example to get your connections working.

See this for performance with RP2040 fast SPI. About 6 - 7 times faster.

@NezhaZahri
Copy link
Author

NezhaZahri commented Nov 2, 2023

Hi Bill,

Thanks for the help, I managed to make it work with what you suggested with some changes that you can see below!

I did change

#define SPI_DRIVER_SELECT 1
#define USE_SPI_ARRAY_TRANSFER 4

And then I kind of also forced the default SPI pins to be SPI2 ports: (CS = PB2, MOSI = PC3, MISO = PC2, SCK = PB10)
Where in the code could I hard code the pins it's taking without compromising SPI1 port? Because I cannot just do it this way since I'm also using SPI1 for other purposes.

image

For references here's the output of the quickstart test which shows that the lib was able to connect with the SD CARD on SPI2:

image

@greiman
Copy link
Owner

greiman commented Nov 3, 2023

You can use any pins that can be configured for any SPI port.

If SPIn is the port configure it for the pins you require. then use:

#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK, &SPIn)

If a begin call is needed to set the pins do this:
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI | USER_SPI_BEGIN, SPI_CLOCK, &SPIn)

Then you must call begin with your custom pins like this.

SPIn.begin(mypin1, myPin2, myPin3, anyOtherOption);

Then call sd.begin(SD_CONFIG)

@NezhaZahri
Copy link
Author

NezhaZahri commented Nov 3, 2023

I did it this way but no luck:
Not sure what that error code reffers to.

  #define SPI_SPEED SD_SCK_MHZ(50)
  #define SD_CS_PIN PB2
  SPIClass SPI_2(PC3, PC2, PB10);
  SPI_2.begin(SD_CS_PIN);
  #define SD2_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI | USER_SPI_BEGIN, SPI_SPEED, &SPI_2)

I'm getting this output:

image

Could the error code help us? I'm not sure what it refers to.

image

If you check in the beginning in my first post this is how I chose my SPI2 pins. And I actually already tested this way for SPI1 (see bellow) for a radio that's connected to it and it works, it seems that sd.begin() might be the issue somehow when using SdSpiConfig?

image

Did you manage to make SPI2 work on your board?

@greiman
Copy link
Owner

greiman commented Nov 3, 2023

The error code refers to this call. Error codes are defined here.

This is a common place for a failure when there is a bad SPI configuration or wiring error.

SdFat has no knowledge of what pins are used for MISO, MOSI, or SCK. It only cares about the CS pin and that the SPI instance in the SdSpiConfig() definition works with the standard SPI member functions.

Can you test SPI2 to make sure signals are on the correct pins.

Here is a loop-back test. It won't test SCK so it would be good if you had a way to do a better test but this is a first step.

// connect MISO to MOSI for your setup and modify code below.
#include <SPI.h>
#define SPIX SPI
void setup() {
  Serial.begin(9600);
  delay(1000);
  SPIX.begin();
  // try 1 MHz
  SPIX.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  uint8_t rAA = SPIX.transfer(0XAA);
  uint8_t r55 = SPIX.transfer(0X55);
  Serial.print("rAA: 0X");
  Serial.println(rAA, HEX);
  Serial.print("r55: 0X");
  Serial.println(r55, HEX);
  SPIX.endTransaction();
  SPIX.end();
}
void loop() {
} 

Here is the expected output:

rAA: 0XAA
r55: 0X55

SdFat must control CS, not auto control by the SPI driver.

@greiman
Copy link
Owner

greiman commented Nov 3, 2023

One possibility is your call:
SPI_2.begin(SD_CS_PIN);

I think this means the SPI library controls CS, not SdFat.

Try this call:
SPI_2.begin();

I looked at the STM32 library and found this:

/**
  * @brief  Initialize the SPI instance.
  * @param  _pin: chip select pin (optional). If this parameter is filled,
  *         it gives the management of the CS pin to the SPI class. In this case
  *         do not manage the CS pin outside of the SPI class.
  */
void SPIClass::begin(uint8_t _pin)

The default in SPI.h is:
virtual void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER);

Actually you could remove the | USER_SPI_BEGIN from SdSpiConfig and let SdFat do the default begin() call.

@NezhaZahri
Copy link
Author

No luck for the last suggestion. :/
I'm still surprised that it worked when I hardcoded the default values but wouldn't work when using the SPI class assignation..

I wrote this :

  #define SD_CS_PIN PB2

  SPIClass SPI_2(PC3, PC2, PB10);
  //SPI_2.begin();

  #define SD2_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_SPEED, &SPI_2)

  if (!sd.begin(SD2_CONFIG)) {

I also tried this:

#define SD_CS_PIN PB2

 //SPIClass SPI_2(PC3, PC2, PB10);
 //SPI_2.begin();
 SPI.setMISO(PC2);
 SPI.setMOSI(PC3);
 SPI.setSCLK(PB10);

 #define SD2_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_SPEED, &SPI)

I could do the loop back test to make sure the right pins are getting configured good idea, the PCB got pins I can solder header to and do a loop back with a jumper. I'll do that on Monday.

If that doesn't work I'm probably going to move to STM32Cube as this was working with their libraries using this tutorial. That would be a bummer tho.

@greiman
Copy link
Owner

greiman commented Nov 4, 2023

I got loop back to work with this program on my Nucleo L476RG.

// connect MISO to MOSI for your setup and modify code below.
#include <SPI.h>
//#define SPIX SPI
//#define CS_PIN 10
#define CS_PIN PB2
SPIClass SPIX(PC3, PC2, PB10);
void setup() {
  pinMode(CS_PIN, OUTPUT);
  digitalWrite(CS_PIN, HIGH);
  Serial.begin(9600);
  delay(1000);
  SPIX.begin();
  Serial.println("Start LA");
  while(!Serial.available()) {}
  // try 1 MHz
  SPIX.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  digitalWrite(CS_PIN, LOW);
  uint8_t rAA = SPIX.transfer(0XAA);
  uint8_t r55 = SPIX.transfer(0X55);
  digitalWrite(CS_PIN, HIGH);
  Serial.print("rAA: 0X");
  Serial.println(rAA, HEX);
  Serial.print("r55: 0X");
  Serial.println(r55, HEX);
  SPIX.endTransaction();
  SPIX.end();
}
void loop() {
}

Here is a logic analyzer trace:

SPI2

Now I will try to get SdFat to work.

@greiman
Copy link
Owner

greiman commented Nov 4, 2023

I attached a SD socket to the SPI2 pins and made these changes to the bench example:

Added:
SPIClass SPIX(PC3, PC2, PB10);

Changed SD_CONFIG

//#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#define SD_CONFIG SdSpiConfig(PB2, DEDICATED_SPI, SPI_CLOCK, &SPIX)
Still using:
#define SPI_DRIVER_SELECT 1
#define USE_SPI_ARRAY_TRANSFER 4

Result:

FreeStack: 94736
Type is FAT32
Card size: 32.01 GB (GB = 1E9 bytes)

Manufacturer ID: 0X1B
OEM ID: SM
Product: 00000
Revision: 1.0
Serial number: 0X6C90572C
Manufacturing date: 7/2016

FILE_SIZE_MB = 5
BUF_SIZE = 512 bytes
Starting write test, please wait.

write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
1250.31,425,406,407
1250.63,425,406,407

Starting read test, please wait.

read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
1135.07,461,448,449
1134.82,461,448,449

@NezhaZahri
Copy link
Author

Hello Bill,

So it is working! For some reason I had to unmount/remount the card when I power cycle the board or reset it.

Here's the final config code I used in the end:

SPIClass SPI_2(PC3, PC2, PB10);

SdSpiConfig SD2_CONFIG(PB2, DEDICATED_SPI, SPI_SPEED, &SPI_2);

while(!sd.begin(SD2_CONFIG)) {
    if (sd.card()->errorCode()) {
      Serial.println("\nSD initialization failed.\n");
    }else{
      Serial.println("\nCard successfully initialized.\n");
    }
}

With the modification you suggested:

#define SPI_DRIVER_SELECT 1
#define USE_SPI_ARRAY_TRANSFER 4

I added the loop on the begin() function because it doesn't always work right away. I suspect either bad sd card or bad soldering.

@greiman
Copy link
Owner

greiman commented Nov 7, 2023

For some reason I had to unmount/remount the card when I power cycle the board or reset it.

If the card is powered on and gets noise on clock with CS high, A card can go into SDIO mode. After that the only way to get it to SPI mode is power cycle.

The Arduino Due can even corrupt a card when you upload a program.

7.2.1 Mode Selection and Initialization
The SD Card is powered up in the SD mode. It will enter SPI mode if the CS signal is asserted (negative)
during the reception of the reset command (CMD0). If the card recognizes that the SD mode is required
it will not respond to the command and remain in the SD mode.

@NezhaZahri
Copy link
Author

Hello Bill,

So I have an additional question, let me know if I should create a separate issue for it.

I started writing code using ReadCsvFile as an example.
It seems that everything works in the setup() but when I try to open, write and close in the loop() the program crashes.
When I check the SD card in the computer I find that only the setup part has been written.

Here are the parts of the code:

In setup :

 if (sd.exists("ReadCsvDemo.csv")) {
    sd.remove("ReadCsvDemo.csv");
  }
  // Create the file.
  if (!file.open("ReadCsvDemo.csv", FILE_WRITE)) {
    Serial.println("open failed");
  }
  // Write test data.
  file.print(
      F("abc,123,456,7.89\r\n"
        "def,-321,654,-9.87\r\n"
        "ghi,333,0xff,5.55"));

  // Rewind file for read.
  file.rewind();

  while (file.available()) {
    int n = file.fgets(line, sizeof(line));
    if (n <= 0) {
      Serial.println("fgets failed");
    }
    if (line[n - 1] != '\n' && n == (sizeof(line) - 1)) {
      Serial.println("line too long");
    }
  }
  file.close();
  Serial.println(F("Done"));

In the loop:

if (sd.exists("ReadCsvDemo.csv")) {
    sd.remove("ReadCsvDemo.csv");
  }
  if (!file.open("ReadCsvDemo.csv", FILE_WRITE)) {
    Serial.println("open failed");
  }
  // Write test data.
  file.print(
      F("b,b,b,b\r\n"
        "b,b,b,b\r\n"
        "a,a,a,a"));

  // Rewind file for read.
  file.rewind();

  while (file.available()) {
    int n = file.fgets(line, sizeof(line));
    if (n <= 0) {
      Serial.println("fgets failed");
    }
    if (line[n - 1] != '\n' && n == (sizeof(line) - 1)) {
      Serial.println("line too long");
    }
  }
  file.close();
  Serial.println(F("Done"));

@greiman
Copy link
Owner

greiman commented Nov 17, 2023

I tried to run the code in loop but it never stops. It just prints "Done" forever.

When I did a reset the SD was corrupt since the file was not properly closed.

I ran it several times and often the file is OK with the correct content.

I added a loop counter and the following at the end of loop like this:

int nLoop = 0;  // << ADDED
void loop() {
if (sd.exists("ReadCsvDemo.csv")) {
    sd.remove("ReadCsvDemo.csv");
  }
  if (!file.open("ReadCsvDemo.csv", FILE_WRITE)) {
    Serial.println("open failed");
  }
  // Write test data.
  file.print(
      F("b,b,b,b\r\n"
        "b,b,b,b\r\n"
        "a,a,a,a"));

  // Rewind file for read.
  file.rewind();

  while (file.available()) {
    int n = file.fgets(line, sizeof(line));
    if (n <= 0) {
      Serial.println("fgets failed");
    }
    if (line[n - 1] != '\n' && n == (sizeof(line) - 1)) {
      Serial.println("line too long");
    }
  }
  file.close();
  Serial.println(F("Done"));
  if (nLoop++ > 10) {   // << ADDED
    Serial.println("stop"); // << ADDED
    while (true) {}           // << ADDED
  }                                // << ADDED
}

It ran until nLoop was greater than 10. It printed "done" each time and then "stop"

The content of the SD was as expected:

b,b,b,b
b,b,b,b
a,a,a,a

I am not sure what you expected.

@NezhaZahri
Copy link
Author

For some reason whenever I do file.print() in the loop it crashes or hangs I'm not sure.
I put the same loop in setup and it writes no problem.

image

I'm gonna probe this on the logic analyzer to see what's up and send you the screenshot for it.

So it's not hardware, not the SD card. I'm not sure why the main loop causes problems..

@NezhaZahri
Copy link
Author

Hello,

So I've been able to fix the problem, after some thorough debugging. Somehow when I put the following code for sd.begin() initialization purpose outside of setup() it worked. Didn't think those class needed to be global.

  SPIClass SPI_2(PC3, PC2, PB10);

  SdSpiConfig SD2_CONFIG(PB2, DEDICATED_SPI, SPI_SPEED, &SPI_2);

Here's the full working test code:


//                      RX    TX
HardwareSerial Serial1(PA3, PA2);

char line[40];
const char* filename = "ReadCsvDemo.csv";
///////////////////////////////////////////
//        SD CARD INITIALIZATION
///////////////////////////////////////////
#include "SPI.h"
#include "SdFat.h"
#include "sdios.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
uint8_t const SD_FAT_TYPE = 3;

// Test with reduced SPI speed for breadboards.  SD_SCK_MHZ(4) will select
// the highest speed supported by the board that is not over 4 MHz.
// Change SPI_SPEED to SD_SCK_MHZ(50) for best performance.
unsigned long const SPI_SPEED = SD_SCK_MHZ(16);

SdFs sd;
FsFile file;

void reformatMsg() {
  Serial1.println(F("Try reformatting the card.  For best results use\n"));
  Serial1.println(F("the SdFormatter program in SdFat/examples or download\n"));
  Serial1.println(F("and use SDFormatter from www.sdcard.org/downloads.\n"));
}

void cardOrSpeed() {
  Serial1.println(F("Try another SD card or reduce the SPI bus speed.\n"));
  Serial1.println(F("Edit SPI_SPEED in this program to change it.\n"));
}

SPIClass SPI_2(PC3, PC2, PB10);

SdSpiConfig SD2_CONFIG(PB2, DEDICATED_SPI, SPI_SPEED, &SPI_2);

void setup() {
  // put your setup code here, to run once:

  Serial1.begin(9600);
  pinMode(PA5, OUTPUT);
  digitalWrite(PA5, LOW);

  ///////////////////////////////////////////////
  //        SD Card SETUP
  ///////////////////////////////////////////////

  while (!sd.begin(SD2_CONFIG)) {
    if (sd.card()->errorCode()) {
      Serial1.println("\nSD initialization failed.\n");
    } else {
      Serial1.println("\nCard successfully initialized.\n");
    }

    if (sd.vol()->fatType() == 0) {
      Serial1.println("Can't find a valid FAT16/FAT32 partition.\n");
      reformatMsg();
    }
    Serial1.println("Can't determine error type\n");

    uint32_t size = sd.card()->sectorCount();
    if (size == 0) {
      Serial1.println(F("Can't determine the card size.\n"));
      cardOrSpeed();
    }

    uint32_t sizeMB = 0.000512 * size + 0.5;
    Serial1.print("Card size: ");
    Serial1.println(sizeMB);
    Serial1.println(" MB (MB = 1,000,000 bytes)\n");
    Serial1.print("Volume is FAT");
    Serial1.println(int(sd.vol()->fatType()));
    Serial1.print(", Cluster size (bytes): ");
    Serial1.println(sd.vol()->bytesPerCluster());

    Serial1.println("Files found (date time size name):\n");
    sd.ls(LS_R | LS_DATE | LS_SIZE);

    if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64) || (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
      Serial1.println("\nThis card should be reformatted for best performance.\n");
      Serial1.println("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
      Serial1.println("Only cards larger than 2 GB should be formatted FAT32.\n");
      reformatMsg();
      return;
    }
  }

  if (sd.exists(filename)) {
    sd.remove(filename);
  }
  // Create the file.
  if (!file.open(filename, O_CREAT | O_WRONLY)) {
    Serial1.println("open failed");
  }
  // Write test data.
  file.print(
    F("abc,123,456,7.89\r\n"
      "def,-321,654,-9.87\r\n"
      "ghi,333,0xff,5.55"));

  if (file.close()) {
    Serial1.println("closed");
  } else {
    Serial1.println("not close");
  }

  Serial1.println(F("Done"));
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(1000);
  digitalWrite(PA5, HIGH);
  Serial1.println("hello");

  delay(1000);

  if (!file.open(filename, FILE_WRITE)) {
    Serial1.println("open failed");
  } else {
    Serial1.println("open worked");
  }

  // Write test data.
  file.print(
    F("abc,123,456,7.89\r\n"
      "def,-321,654,-9.87\r\n"
      "ghi,333,0xff,5.55"));


  file.close();
  Serial1.println(F("Done"));

  delay(1000);
  digitalWrite(PA5, LOW);
}

#ifdef __cplusplus
extern "C" {
#endif
  /**
  * @brief System Clock Configuration
  * @retval None
  */
  void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

    /** Configure the main internal regulator output voltage
  */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
      Error_Handler();
    }

    /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
      Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
  */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
      Error_Handler();
    }
  }

#ifdef __cplusplus
}
#endif

@greiman
Copy link
Owner

greiman commented Nov 18, 2023

Yes the instance of the SPI class must be global or in memory that is not destroyed when it goes out of scope. SdFat only gets a pointer to the SPI instance.

When SPI_2 went out of scope it's destructor was called and SdFat had a pointer to a section of recycled stack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants