SD Card Using SPI2
SD Card Using SPI2
Hi all I have been bouncing around Google trying to work out how to get SD cards working with SPI and specifically with SPI2. I have managed it with Atmel and ESP but just can't get it going with STM anyone managed it?
What I have tried so far:
The standard Arduino SD library https://www.arduino.cc/en/Reference/SD
This uses SPI but you can not change the default SPI, I looked for some time without luck in changing this,
The Ported STM32 version here https://www.arduino.cc/reference/en/lib ... o-stm32sd/ but the library is specifically designed to work with SDIO/SDMMC-hardware not SPI.
I also found reference to an old Adafruit https://github.com/adafruit/SD version that was SPI and you could specify all the SPI pins in the constructor but they stopped supporting it two years ago and it no longer compiles, after lots of trying I could not get this to work either.
Can anyone please help me to get SPI SD working with STM32?
Thanks in advance for your help...
What I have tried so far:
The standard Arduino SD library https://www.arduino.cc/en/Reference/SD
This uses SPI but you can not change the default SPI, I looked for some time without luck in changing this,
The Ported STM32 version here https://www.arduino.cc/reference/en/lib ... o-stm32sd/ but the library is specifically designed to work with SDIO/SDMMC-hardware not SPI.
I also found reference to an old Adafruit https://github.com/adafruit/SD version that was SPI and you could specify all the SPI pins in the constructor but they stopped supporting it two years ago and it no longer compiles, after lots of trying I could not get this to work either.
Can anyone please help me to get SPI SD working with STM32?
Thanks in advance for your help...
Have you tried using the SdFat library? The latest version can be used with STM32 boards. You just have to configure the correct pinout and the appropriate call for the type of microSD on the SPI bus that you want to use. For example, for exFat cards, on a F411CE board connecting the reader on the SPI2 bus, with the STM32 core 1.9.0:
For a Nucleo F767, with SD reader on the SPI3 bus:
microSD size: 128 Gb
Go to full postCode: Select all
#define SD_PIN PB12
#define SetSDSpeed 48
static SPIClass SPI_2 (PB15, PB14, PB13);
#define SD_CONFIG SdSpiConfig (SD_PIN, DEDICATED_SPI, SD_SCK_MHZ (SetSDSpeed), &SPI_2)
SdFs SD; // exFat
Code: Select all
#define SD_PIN PB11
#define SetSDSpeed 48
static SPIClass SPI_3(PB2, PB4, PB3);
#define SD_CONFIG SdSpiConfig(SD_PIN, DEDICATED_SPI, SD_SCK_MHZ(SetSDSpeed), &SPI_3)
SdFs SD; //exFat
Code: Select all
/*
* This program attempts to initialize an SD card and analyze its structure.
*/
#include "SdFat.h"
#include "sdios.h"
/*
Set DISABLE_CS_PIN to disable a second SPI device.
For example, with the Ethernet shield, set DISABLE_CS_PIN
to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
Change the value of SD_CS_PIN if you are using SPI
and your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = PB11; //Nucleo F767 SPI3
#else // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN
// SPI3 on Nucleo F767 Setup for SdFat beta
static SPIClass mySPI3(PB2, PB4, PB3);
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(48), &mySPI3)
// SPI2 on F103C8
//static SPIClass mySPI2(PB15, PB14, PB13);
//#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
//------------------------------------------------------------------------------
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
bool cidDmp() {
cout << F("\nManufacturer ID: ");
cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
cout << F("Product: ");
for (uint8_t i = 0; i < 5; i++) {
cout << m_cid.pnm[i];
}
cout << F("\nVersion: ");
cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
cout << F("Manufacturing date: ");
cout << int(m_cid.mdt_month) << '/';
cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
cout << endl;
return true;
}
//------------------------------------------------------------------------------
bool csdDmp() {
bool eraseSingleBlock;
if (m_csd.v1.csd_ver == 0) {
eraseSingleBlock = m_csd.v1.erase_blk_en;
m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
} else if (m_csd.v2.csd_ver == 1) {
eraseSingleBlock = m_csd.v2.erase_blk_en;
m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
} else {
cout << F("m_csd version error\n");
return false;
}
m_eraseSize++;
cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
cout << F(" MB (MB = 1,000,000 bytes)\n");
cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
cout << F("eraseSingleBlock: ");
if (eraseSingleBlock) {
cout << F("true\n");
} else {
cout << F("false\n");
}
return true;
}
//------------------------------------------------------------------------------
void errorPrint() {
if (sd.sdErrorCode()) {
cout << F("SD errorCode: ") << hex << showbase;
printSdErrorSymbol(&Serial, sd.sdErrorCode());
cout << F(" = ") << int(sd.sdErrorCode()) << endl;
cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
}
}
//------------------------------------------------------------------------------
bool mbrDmp() {
MbrSector_t mbr;
bool valid = true;
if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
cout << F("\nread MBR failed.\n");
errorPrint();
return false;
}
cout << F("\nSD Partition Table\n");
cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
for (uint8_t ip = 1; ip < 5; ip++) {
MbrPart_t *pt = &mbr.part[ip - 1];
if ((pt->boot != 0 && pt->boot != 0X80) ||
getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
valid = false;
}
cout << int(ip) << ',' << uppercase << showbase << hex;
cout << int(pt->boot) << ',';
for (int i = 0; i < 3; i++ ) {
cout << int(pt->beginCHS[i]) << ',';
}
cout << int(pt->type) << ',';
for (int i = 0; i < 3; i++ ) {
cout << int(pt->endCHS[i]) << ',';
}
cout << dec << getLe32(pt->relativeSectors) << ',';
cout << getLe32(pt->totalSectors) << endl;
}
if (!valid) {
cout << F("\nMBR not valid, assuming Super Floppy format.\n");
}
return true;
}
//------------------------------------------------------------------------------
void dmpVol() {
cout << F("\nScanning FAT, please wait.\n");
uint32_t freeClusterCount = sd.freeClusterCount();
if (sd.fatType() <= 32) {
cout << F("\nVolume is FAT") << int(sd.fatType()) << endl;
} else {
cout << F("\nVolume is exFAT\n");
}
cout << F("sectorsPerCluster: ") << sd.sectorsPerCluster() << endl;
cout << F("clusterCount: ") << sd.clusterCount() << endl;
cout << F("freeClusterCount: ") << freeClusterCount << endl;
cout << F("fatStartSector: ") << sd.fatStartSector() << endl;
cout << F("dataStartSector: ") << sd.dataStartSector() << endl;
if (sd.dataStartSector() % m_eraseSize) {
cout << F("Data area is not aligned on flash erase boundary!\n");
cout << F("Download and use formatter from www.sdcard.org!\n");
}
}
//------------------------------------------------------------------------------
void printCardType() {
cout << F("\nCard type: ");
switch (sd.card()->type()) {
case SD_CARD_TYPE_SD1:
cout << F("SD1\n");
break;
case SD_CARD_TYPE_SD2:
cout << F("SD2\n");
break;
case SD_CARD_TYPE_SDHC:
if (sdCardCapacity(&m_csd) < 70000000) {
cout << F("SDHC\n");
} else {
cout << F("SDXC\n");
}
break;
default:
cout << F("Unknown\n");
}
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
if (DISABLE_CS_PIN < 0) {
cout << F(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
} else {
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CS_PIN) << endl;
pinMode(DISABLE_CS_PIN, OUTPUT);
digitalWrite(DISABLE_CS_PIN, HIGH);
}
cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
(void)config;
cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
printConfig(SD_CONFIG);
}
//------------------------------------------------------------------------------
void loop() {
// Read any existing Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);
// F stores strings in flash to save RAM
cout << F("\ntype any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}
uint32_t t = millis();
if (!sd.cardBegin(SD_CONFIG)) {
cout << F(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is there a wiring/soldering problem?\n");
if (isSpi(SD_CONFIG)) {
cout << F(
"Is SD_CS_PIN set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
);
}
errorPrint();
return;
}
t = millis() - t;
cout << F("init time: ") << t << " ms" << endl;
if (!sd.card()->readCID(&m_cid) ||
!sd.card()->readCSD(&m_csd) ||
!sd.card()->readOCR(&m_ocr)) {
cout << F("readInfo failed\n");
errorPrint();
return;
}
printCardType();
cidDmp();
csdDmp();
cout << F("\nOCR: ") << uppercase << showbase;
cout << hex << m_ocr << dec << endl;
if (!mbrDmp()) {
return;
}
if (!sd.volumeBegin()) {
cout << F("\nvolumeBegin failed. Is the card formatted?\n");
errorPrint();
return;
}
dmpVol();
}
Re: SD Card Using SPI2
Hi,
Refers to the wiki: https://github.com/stm32duino/wiki/wiki ... tance-pins
Simply change default SPI instance pins to the SPI2 peripherals before the SPI.Begin().
Refers to the wiki: https://github.com/stm32duino/wiki/wiki ... tance-pins
Simply change default SPI instance pins to the SPI2 peripherals before the SPI.Begin().
Re: SD Card Using SPI2
Have you tried using the SdFat library? The latest version can be used with STM32 boards. You just have to configure the correct pinout and the appropriate call for the type of microSD on the SPI bus that you want to use. For example, for exFat cards, on a F411CE board connecting the reader on the SPI2 bus, with the STM32 core 1.9.0:
For a Nucleo F767, with SD reader on the SPI3 bus:
microSD size: 128 Gb
Code: Select all
#define SD_PIN PB12
#define SetSDSpeed 48
static SPIClass SPI_2 (PB15, PB14, PB13);
#define SD_CONFIG SdSpiConfig (SD_PIN, DEDICATED_SPI, SD_SCK_MHZ (SetSDSpeed), &SPI_2)
SdFs SD; // exFat
Code: Select all
#define SD_PIN PB11
#define SetSDSpeed 48
static SPIClass SPI_3(PB2, PB4, PB3);
#define SD_CONFIG SdSpiConfig(SD_PIN, DEDICATED_SPI, SD_SCK_MHZ(SetSDSpeed), &SPI_3)
SdFs SD; //exFat
Code: Select all
/*
* This program attempts to initialize an SD card and analyze its structure.
*/
#include "SdFat.h"
#include "sdios.h"
/*
Set DISABLE_CS_PIN to disable a second SPI device.
For example, with the Ethernet shield, set DISABLE_CS_PIN
to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CS_PIN = -1;
/*
Change the value of SD_CS_PIN if you are using SPI
and your hardware does not use the default value, SS.
Common values are:
Arduino Ethernet shield: pin 4
Sparkfun SD shield: pin 8
Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const uint8_t SD_CS_PIN = PB11; //Nucleo F767 SPI3
#else // SDCARD_SS_PIN
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#endif // SDCARD_SS_PIN
// SPI3 on Nucleo F767 Setup for SdFat beta
static SPIClass mySPI3(PB2, PB4, PB3);
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(48), &mySPI3)
// SPI2 on F103C8
//static SPIClass mySPI2(PB15, PB14, PB13);
//#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
//------------------------------------------------------------------------------
SdFs sd;
cid_t m_cid;
csd_t m_csd;
uint32_t m_eraseSize;
uint32_t m_ocr;
static ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
bool cidDmp() {
cout << F("\nManufacturer ID: ");
cout << uppercase << showbase << hex << int(m_cid.mid) << dec << endl;
cout << F("OEM ID: ") << m_cid.oid[0] << m_cid.oid[1] << endl;
cout << F("Product: ");
for (uint8_t i = 0; i < 5; i++) {
cout << m_cid.pnm[i];
}
cout << F("\nVersion: ");
cout << int(m_cid.prv_n) << '.' << int(m_cid.prv_m) << endl;
cout << F("Serial number: ") << hex << m_cid.psn << dec << endl;
cout << F("Manufacturing date: ");
cout << int(m_cid.mdt_month) << '/';
cout << (2000 + m_cid.mdt_year_low + 10 * m_cid.mdt_year_high) << endl;
cout << endl;
return true;
}
//------------------------------------------------------------------------------
bool csdDmp() {
bool eraseSingleBlock;
if (m_csd.v1.csd_ver == 0) {
eraseSingleBlock = m_csd.v1.erase_blk_en;
m_eraseSize = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
} else if (m_csd.v2.csd_ver == 1) {
eraseSingleBlock = m_csd.v2.erase_blk_en;
m_eraseSize = (m_csd.v2.sector_size_high << 1) | m_csd.v2.sector_size_low;
} else {
cout << F("m_csd version error\n");
return false;
}
m_eraseSize++;
cout << F("cardSize: ") << 0.000512 * sdCardCapacity(&m_csd);
cout << F(" MB (MB = 1,000,000 bytes)\n");
cout << F("flashEraseSize: ") << int(m_eraseSize) << F(" blocks\n");
cout << F("eraseSingleBlock: ");
if (eraseSingleBlock) {
cout << F("true\n");
} else {
cout << F("false\n");
}
return true;
}
//------------------------------------------------------------------------------
void errorPrint() {
if (sd.sdErrorCode()) {
cout << F("SD errorCode: ") << hex << showbase;
printSdErrorSymbol(&Serial, sd.sdErrorCode());
cout << F(" = ") << int(sd.sdErrorCode()) << endl;
cout << F("SD errorData = ") << int(sd.sdErrorData()) << endl;
}
}
//------------------------------------------------------------------------------
bool mbrDmp() {
MbrSector_t mbr;
bool valid = true;
if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
cout << F("\nread MBR failed.\n");
errorPrint();
return false;
}
cout << F("\nSD Partition Table\n");
cout << F("part,boot,bgnCHS[3],type,endCHS[3],start,length\n");
for (uint8_t ip = 1; ip < 5; ip++) {
MbrPart_t *pt = &mbr.part[ip - 1];
if ((pt->boot != 0 && pt->boot != 0X80) ||
getLe32(pt->relativeSectors) > sdCardCapacity(&m_csd)) {
valid = false;
}
cout << int(ip) << ',' << uppercase << showbase << hex;
cout << int(pt->boot) << ',';
for (int i = 0; i < 3; i++ ) {
cout << int(pt->beginCHS[i]) << ',';
}
cout << int(pt->type) << ',';
for (int i = 0; i < 3; i++ ) {
cout << int(pt->endCHS[i]) << ',';
}
cout << dec << getLe32(pt->relativeSectors) << ',';
cout << getLe32(pt->totalSectors) << endl;
}
if (!valid) {
cout << F("\nMBR not valid, assuming Super Floppy format.\n");
}
return true;
}
//------------------------------------------------------------------------------
void dmpVol() {
cout << F("\nScanning FAT, please wait.\n");
uint32_t freeClusterCount = sd.freeClusterCount();
if (sd.fatType() <= 32) {
cout << F("\nVolume is FAT") << int(sd.fatType()) << endl;
} else {
cout << F("\nVolume is exFAT\n");
}
cout << F("sectorsPerCluster: ") << sd.sectorsPerCluster() << endl;
cout << F("clusterCount: ") << sd.clusterCount() << endl;
cout << F("freeClusterCount: ") << freeClusterCount << endl;
cout << F("fatStartSector: ") << sd.fatStartSector() << endl;
cout << F("dataStartSector: ") << sd.dataStartSector() << endl;
if (sd.dataStartSector() % m_eraseSize) {
cout << F("Data area is not aligned on flash erase boundary!\n");
cout << F("Download and use formatter from www.sdcard.org!\n");
}
}
//------------------------------------------------------------------------------
void printCardType() {
cout << F("\nCard type: ");
switch (sd.card()->type()) {
case SD_CARD_TYPE_SD1:
cout << F("SD1\n");
break;
case SD_CARD_TYPE_SD2:
cout << F("SD2\n");
break;
case SD_CARD_TYPE_SDHC:
if (sdCardCapacity(&m_csd) < 70000000) {
cout << F("SDHC\n");
} else {
cout << F("SDXC\n");
}
break;
default:
cout << F("Unknown\n");
}
}
//------------------------------------------------------------------------------
void printConfig(SdSpiConfig config) {
if (DISABLE_CS_PIN < 0) {
cout << F(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
} else {
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CS_PIN) << endl;
pinMode(DISABLE_CS_PIN, OUTPUT);
digitalWrite(DISABLE_CS_PIN, HIGH);
}
cout << F("\nAssuming the SD chip select pin is: ") << int(config.csPin);
cout << F("\nEdit SD_CS_PIN to change the SD chip select pin.\n");
}
//------------------------------------------------------------------------------
void printConfig(SdioConfig config) {
(void)config;
cout << F("Assuming an SDIO interface.\n");
}
//-----------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
printConfig(SD_CONFIG);
}
//------------------------------------------------------------------------------
void loop() {
// Read any existing Serial data.
do {
delay(10);
} while (Serial.available() && Serial.read() >= 0);
// F stores strings in flash to save RAM
cout << F("\ntype any character to start\n");
while (!Serial.available()) {
SysCall::yield();
}
uint32_t t = millis();
if (!sd.cardBegin(SD_CONFIG)) {
cout << F(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is there a wiring/soldering problem?\n");
if (isSpi(SD_CONFIG)) {
cout << F(
"Is SD_CS_PIN set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
);
}
errorPrint();
return;
}
t = millis() - t;
cout << F("init time: ") << t << " ms" << endl;
if (!sd.card()->readCID(&m_cid) ||
!sd.card()->readCSD(&m_csd) ||
!sd.card()->readOCR(&m_ocr)) {
cout << F("readInfo failed\n");
errorPrint();
return;
}
printCardType();
cidDmp();
csdDmp();
cout << F("\nOCR: ") << uppercase << showbase;
cout << hex << m_ocr << dec << endl;
if (!mbrDmp()) {
return;
}
if (!sd.volumeBegin()) {
cout << F("\nvolumeBegin failed. Is the card formatted?\n");
errorPrint();
return;
}
dmpVol();
}
Re: SD Card Using SPI2
Thanks your version is working well on a F103RET6 however the STM32_Test example for that library does not compile as the have used:
Instead of how you have done it:
The example compile error shows that there is no constructor where you can pass just the SPI number.
Should I log this with the library to get fixed?
Thanks again for your help
Code: Select all
static SPIClass mySPI2(2);
Code: Select all
static SPIClass SPI_2 (PB15, PB14, PB13);
Should I log this with the library to get fixed?
Thanks again for your help
Re: SD Card Using SPI2
Thank you this was also useful for for other libraries with fixed SPIsfpiSTM wrote: ↑Wed Aug 11, 2021 10:13 am Hi,
Refers to the wiki: https://github.com/stm32duino/wiki/wiki ... tance-pins
Simply change default SPI instance pins to the SPI2 peripherals before the SPI.Begin().
Re: SD Card Using SPI2
It is not as simple as replacing one line with another, you must create another constructor but with the pins of the second port, so that the STM32Test example points to the correct pinout of the other SPI bus (2, 3, etc).
In this example coded for a Nucleo F767, the first port is the SPI1 bus, the second port points to the SPI3 bus. It should be noted, the index 2 in file2 or in sd2 or in SD2_CONFIG, points to the second port that we want to use, this port can be the SPI2 bus or the SPI3 bus.
I should note that the example is not up to date with the latest modifications implemented within the SdFat library; just follow the breadcrumb trail.
I have not verified the operation of the above code since I am working with a teensy 4.1 board and a 3.5 "FT813 TFT, but I must say that it compiles without errors
In this example coded for a Nucleo F767, the first port is the SPI1 bus, the second port points to the SPI3 bus. It should be noted, the index 2 in file2 or in sd2 or in SD2_CONFIG, points to the second port that we want to use, this port can be the SPI2 bus or the SPI3 bus.
Code: Select all
/* This example is for https://github.com/rogerclarkmelbourne/Arduino_STM32
*
* Example use of two SPI ports on an STM32 board.
* Note SPI speed is limited to 18 MHz.
*/
#include <SPI.h>
#include "SdFat.h"
#include "FreeStack.h"
// Chip select PA4, shared SPI, 18 MHz, port 1 --> bus SPI1
#define SD1_CONFIG SdSpiConfig(PA4, SHARED_SPI, SD_SCK_MHZ(18), &SPI)
SdFs sd1;
FsFile file1;
// Use mySPI2 since SPI2 is used in SPI.h as a different type.
//static SPIClass mySPI2(2);
// Chip select PB12, dedicated SPI, 18 MHz, port 2.
//#if ENABLE_DEDICATED_SPI
//#define SD2_CONFIG SdSpiConfig(PB12, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
//#else // ENABLE_DEDICATED_SPI
//#define SD2_CONFIG SdSpiConfig(PB12, SHARED_SPI, SD_SCK_MHZ(18), &mySPI2)
//#endif // ENABLE_DEDICATED_SPI
//port 2 --> bus SPI3
static SPIClass mySPI2(PB2, PB4, PB3);
#define SD2_CONFIG SdSpiConfig(PB11, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
SdFs sd2;
FsFile file2;
const uint8_t BUF_DIM = 100;
uint8_t buf[BUF_DIM];
const uint32_t FILE_SIZE = 1000000;
const uint32_t NWRITE = FILE_SIZE/BUF_DIM;
//------------------------------------------------------------------------------
// print error msg, any SD error codes, and halt.
// store messages in flash
#define error(msg) {Serial.println(msg); errorHalt();}
void errorHalt() {
if (sd1.sdErrorCode()) {
sd1.errorHalt();
}
sd2.errorHalt();
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
Serial.print(F("FreeStack: "));
Serial.println(FreeStack());
// fill buffer with known data
for (size_t i = 0; i < sizeof(buf); i++) {
buf[i] = i;
}
Serial.println(F("type any character to start"));
while (!Serial.available()) {
SysCall::yield();
}
// initialize the first card
if (!sd1.begin(SD1_CONFIG)) {
error("sd1.begin");
}
// create Dir1 on sd1 if it does not exist
if (!sd1.exists("/Dir1")) {
if (!sd1.mkdir("/Dir1")) {
error("sd1.mkdir");
}
}
// Make Dir1 the working directory on sd1.
if (!sd1.chdir("Dir1")) {
error("dsd1.chdir");
}
// initialize the second card
if (!sd2.begin(SD2_CONFIG)) {
error("sd2.begin");
}
// create Dir2 on sd2 if it does not exist
if (!sd2.exists("/Dir2")) {
if (!sd2.mkdir("/Dir2")) {
error("sd2.mkdir");
}
}
// Make Dir2 the working directory on sd2.
if (!sd2.chdir("Dir2")) {
error("sd2.chdir");
}
// remove test.bin from /Dir1 directory of sd1
if (sd1.exists("test.bin")) {
if (!sd1.remove("test.bin")) {
error("remove test.bin");
}
}
// remove rename.bin from /Dir2 directory of sd2
if (sd2.exists("rename.bin")) {
if (!sd2.remove("rename.bin")) {
error("remove rename.bin");
}
}
// list directories.
Serial.println(F("------sd1 Dir1-------"));
sd1.ls("/", LS_R | LS_SIZE);
Serial.println(F("------sd2 Dir2-------"));
sd2.ls("/", LS_R | LS_SIZE);
Serial.println(F("---------------------"));
// create or open /Dir1/test.bin and truncate it to zero length
if (!file1.open(&sd1, "test.bin", O_RDWR | O_CREAT | O_TRUNC)) {
error("file1.open");
}
Serial.println(F("Writing test.bin to sd1"));
// write data to /Dir1/test.bin on sd1
for (uint32_t i = 0; i < NWRITE; i++) {
if (file1.write(buf, sizeof(buf)) != sizeof(buf)) {
error("file1.write");
}
}
// create or open /Dir2/copy.bin and truncate it to zero length
if (!file2.open(&sd2, "copy.bin", O_WRONLY | O_CREAT | O_TRUNC)) {
error("file2.open");
}
Serial.println(F("Copying test.bin to copy.bin"));
// copy file1 to file2
file1.rewind();
uint32_t t = millis();
while (1) {
int n = file1.read(buf, sizeof(buf));
if (n < 0) {
error("file1.read");
}
if (n == 0) {
break;
}
if ((int)file2.write(buf, n) != n) {
error("file2.write");
}
}
t = millis() - t;
Serial.print(F("File size: "));
Serial.println(file2.fileSize());
Serial.print(F("Copy time: "));
Serial.print(t);
Serial.println(F(" millis"));
// close test.bin
file1.close();
// sync copy.bin so ls works.
file2.close();
// list directories.
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Renaming copy.bin"));
// Rename copy.bin. The renamed file will be in Dir2.
if (!sd2.rename("copy.bin", "rename.bin")) {
error("rename copy.bin");
}
file2.close();
// list directories.
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void loop() {}
I have not verified the operation of the above code since I am working with a teensy 4.1 board and a 3.5 "FT813 TFT, but I must say that it compiles without errors
Re: SD Card Using SPI2
Problem below solved by using SDFat library rather than Adafruit SDFat fork, using stm core library. Have a problem with line 26 :
#define SD2_CONFIG SdSpiConfig(PB11, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
as PB11 not recognised. I am not using chip select so setting it to zero gets it to compile ok.
Hi
Thanks for the example and the insight.
I've tried to compile the above code but the following errors occur. Any help fixing them would be very much appreciated. I've tried the STM core, and Richard's maple core to no avail,(Generic stm32f series + Generic F401ccux, and Blackpill stm32f401ccu6 selected).
sketch_aug14a:12:1: error: 'SdFs' does not name a type
12 | SdFs sd1;
| ^~~~
sketch_aug14a:13:1: error: 'FsFile' does not name a type; did you mean 'SdFile'?
13 | FsFile file1;
Any help or pointers much appreciated.
Best Regards
picclock
#define SD2_CONFIG SdSpiConfig(PB11, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
as PB11 not recognised. I am not using chip select so setting it to zero gets it to compile ok.
Hi
Thanks for the example and the insight.
I've tried to compile the above code but the following errors occur. Any help fixing them would be very much appreciated. I've tried the STM core, and Richard's maple core to no avail,(Generic stm32f series + Generic F401ccux, and Blackpill stm32f401ccu6 selected).
sketch_aug14a:12:1: error: 'SdFs' does not name a type
12 | SdFs sd1;
| ^~~~
sketch_aug14a:13:1: error: 'FsFile' does not name a type; did you mean 'SdFile'?
13 | FsFile file1;
Any help or pointers much appreciated.
Best Regards
picclock
Re: SD Card Using SPI2
For the F401 Board, the SPI2 bus pins are different from those of the Nucleo F767. I think you can use these lines for F401CC:
Remember that you must have the latest version of the SdFat library installed
Code: Select all
//port 2 --> bus SPI2 on F411CE or F401CC
static SPIClass mySPI2(PB15, PB14, PB13);
#define SD2_CONFIG SdSpiConfig(PB12, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
Re: SD Card Using SPI2
Thankyou for that post. It saved the day , and possibly my sanity.
for the first time I have a fully functioning SDFat on SPI2.
Definitely worth a virtual Beer !!!
Best Regards
picclock
for the first time I have a fully functioning SDFat on SPI2.
Definitely worth a virtual Beer !!!
Best Regards
picclock
Re: SD Card Using SPI2
I finally got the sdfat library to work on my Nucleo F767zi using a micro SD card module and the SPI pins and wanted to document it.
I used the following pins
PE12 - clk
PE13 - miso
PE14 - mosi
PE11 - ss
3.3 V - power
Gnd - gnd
I selected this SPI port because its pins do not look to conflict with other devices on the card (ie. ethernet signals)
I modified the "pins_arduino.h" file located in folder
..\Arduino15\packages\STMicroelectronics\hardware\stm32\2.8.1\cores\arduino
as follows:
The code which I used is the CardInfo example. The only thing which I changed was to define chipSelect = PIN_SPI_SS
I used the following pins
PE12 - clk
PE13 - miso
PE14 - mosi
PE11 - ss
3.3 V - power
Gnd - gnd
I selected this SPI port because its pins do not look to conflict with other devices on the card (ie. ethernet signals)
I modified the "pins_arduino.h" file located in folder
..\Arduino15\packages\STMicroelectronics\hardware\stm32\2.8.1\cores\arduino
as follows:
Code: Select all
//I added these lines
#define PIN_SPI_SS PE11
#define PIN_SPI_MOSI PE14
#define PIN_SPI_MISO PE13
#define PIN_SPI_SCK PE12
/* Default for Arduino connector compatibility */
/* SPI Definitions */
#ifndef PIN_SPI_SS
#define PIN_SPI_SS 10
#endif
#ifndef PIN_SPI_SS1
#define PIN_SPI_SS1 4
#endif
#ifndef PIN_SPI_SS2
#define PIN_SPI_SS2 7
#endif
#ifndef PIN_SPI_SS3
#define PIN_SPI_SS3 8
#endif
#ifndef PIN_SPI_MOSI
#define PIN_SPI_MOSI 11
#endif
#ifndef PIN_SPI_MISO
#define PIN_SPI_MISO 12
#endif
#ifndef PIN_SPI_SCK
#define PIN_SPI_SCK 13
#endif
static const uint32_t SS = PIN_SPI_SS;
static const uint32_t SS1 = PIN_SPI_SS1;
static const uint32_t SS2 = PIN_SPI_SS2;
static const uint32_t SS3 = PIN_SPI_SS3;
static const uint32_t MOSI = PIN_SPI_MOSI;
static const uint32_t MISO = PIN_SPI_MISO;
static const uint32_t SCK = PIN_SPI_SCK;
/* I2C Definitions */
#ifndef PIN_WIRE_SDA
#define PIN_WIRE_SDA 14
#endif
#ifndef PIN_WIRE_SCL
#define PIN_WIRE_SCL 15
#endif
static const uint32_t SDA = PIN_WIRE_SDA;
static const uint32_t SCL = PIN_WIRE_SCL;
The code which I used is the CardInfo example. The only thing which I changed was to define chipSelect = PIN_SPI_SS
Code: Select all
/*
SD card test
This example shows how use the utility libraries on which the'
SD library is based in order to get info about your SD card.
Very useful for testing a card when you're not sure whether its working or not.
The circuit:
SD card attached to SPI bus as follows:
** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
** CS - depends on your SD card shield or module.
Pin 4 used here for consistency with other Arduino examples
created 28 Mar 2011
by Limor Fried
modified 9 Apr 2012
by Tom Igoe
*/
// include the SD library:
#include <SPI.h>
#include <SD.h>
// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;
// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
// MKRZero SD: SDCARD_SS_PIN
const int chipSelect = PIN_SPI_SS;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.print("\nInitializing SD card...");
delay(50); //dbg
// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
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.");
}
// print the type of card
Serial.println();
Serial.print("Card type: ");
switch (card.type()) {
case SD_CARD_TYPE_SD1:
Serial.println("SD1");
break;
case SD_CARD_TYPE_SD2:
Serial.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
Serial.println("SDHC");
break;
default:
Serial.println("Unknown");
}
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
while (1);
}
Serial.print("Clusters: ");
Serial.println(volume.clusterCount());
Serial.print("Blocks x Cluster: ");
Serial.println(volume.blocksPerCluster());
Serial.print("Total Blocks: ");
Serial.println(volume.blocksPerCluster() * volume.clusterCount());
Serial.println();
// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print("Volume type is: FAT");
Serial.println(volume.fatType(), DEC);
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB)
Serial.print("Volume size (Kb): ");
Serial.println(volumesize);
Serial.print("Volume size (Mb): ");
volumesize /= 1024;
Serial.println(volumesize);
Serial.print("Volume size (Gb): ");
Serial.println((float)volumesize / 1024.0);
Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
}
void loop(void) {
}