For the LoRa library, if your changing the SPI bus from default you would normally se this command, as detailed in the library API;
LoRa.setSPI(spi);
For the LoRa library, if your changing the SPI bus from default you would normally se this command, as detailed in the library API;
LoRa.setSPI(spi);
I have mixed LoRa devices and SD and TFT displays on the same SPI bus extensively, mainly on ESP32S3.
Whilst the combination works well with no crashes etc, I have noticed that the SD card can go offline under heavy use.
So my preferred setup is to leave the LoRa device and TFT display on the default SPI bus and put the SD card on the HSPI bus. This is more reliable.
Or use the SD card in MMC mode which eliminates the potential SPI conflict completely.
I also have not gone beyond version 2.0.14 of the ESP32 core for Arduino, too many issues with some well established libraries.
could you share me a code example that works for you? so I can adapt mine and tell you if it works
Having the SD on its own SPI could be helpful as some SD cards don't play nice on the bus. They don't tri-state MISO when they're unselected.
Not really, I dont use the same LoRa library your using.
I would suggest you just setup a basic code that has both the LoRa device and SD card run on the default SPI bus.
Check that such a basic code initializes both the LoRa device and SD card without crashing.
Do post a picture or link for the SD card module\holder, as @gfvalvo has said some such module\holders dont work properly.
try the following with SD card on VSPI and RFM95 on HSPI
file ESP32_RFM95_HSPI.ino
// ESP32 using HSPI connected to a RFM95W LoRa module
#include <SPI.h>
#include <LoRa.h>
// default HSPI pins used by RFM95 LoRa module
#define HSPI_SCK 14
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_CS 15
#define HSPI_RESET 4
#define HSPI_D0 2
SPIClass *hspi = new SPIClass(HSPI); // HSPI object used by MFRC522
void SDsetup();
void SDloop();
void setup() {
Serial.begin(115200);
delay(2000);
SDsetup();
Serial.println("\n\nESP32 LoRa RFM95W Receiver");
// void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN);
//LoRa.setPins(8, 4, 7); // for Lora 32u4
LoRa.setSPI(*hspi);
LoRa.setPins(HSPI_CS, HSPI_RESET, HSPI_D0); //4, 2); // for ESP32
if (!LoRa.begin(866E6)) {
Serial.println("Starting LoRa failed!");
while (1)
;
}
Serial.println("Starting LoRa OK!");
}
void loop() {
// try to parse packet
int packetSize = LoRa.parsePacket();
if (packetSize) {
// received a packet
Serial.print("Received packet '");
// read packet
while (LoRa.available()) {
Serial.print((char)LoRa.read());
}
// print RSSI of packet
Serial.print("' with RSSI ");
Serial.println(LoRa.packetRssi());
}
static unsigned int timer1 = millis();
if (millis() - timer1 > 1000) {
timer1 = millis();
SDloop(); // call SD functions
}
}
file ESP32_SD_VSPI.cpp (in same directory as above .ino file)
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-microsd-card-arduino/
This sketch can be found at: Examples > SD(esp32) > SD_Test
*/
// ESP32 connections
// ESP32 SCK pin GPIO18 to SD card SCK
// ESP32 MISO pin GPIO19 to SD card MISO
// ESP32 MOSI pin GPIO23 to SD card MOSI
// ESP32 SS pin GPIO 5 to SD card SS
// ESP32 5V to SD VCC and GND to GND
#include "FS.h"
#include "SD.h"
#include "SPI.h"
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
void renameFile(fs::FS &fs, const char * path1, const char * path2){
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
void testFileIO(fs::FS &fs, const char * path){
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if(file){
len = file.size();
size_t flen = len;
start = millis();
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for(i=0; i<2048; i++){
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
void SDsetup(){
Serial.begin(115200);
if(!SD.begin(5)){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
listDir(SD, "/", 0);
createDir(SD, "/mydir");
listDir(SD, "/", 0);
removeDir(SD, "/mydir");
listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}
void SDloop(){
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}
serial monitor output
SD Card Type: SDSC
SD Card Size: 121MB
Listing directory: /
DIR : System Volume Information
FILE: data.txt SIZE: 486
FILE: test.txt SIZE: 77824
FILE: foo.txt SIZE: 13
FILE: TestNumber.txt SIZE: 2
FILE: test1.dat SIZE: 7
FILE: test2.dat SIZE: 12
FILE: test3.dat SIZE: 68
FILE: test5.dat SIZE: 7
FILE: test6.dat SIZE: 7
FILE: test7.dat SIZE: 7
FILE: test8.dat SIZE: 7
FILE: test9.dat SIZE: 7
FILE: test10.dat SIZE: 14
FILE: test11.dat SIZE: 7
FILE: test12.dat SIZE: 7
FILE: test13.dat SIZE: 5
FILE: test14.dat SIZE: 354
FILE: test15.dat SIZE: 35
FILE: test16.dat SIZE: 10682
FILE: test17.dat SIZE: 259
FILE: test18.dat SIZE: 343
FILE: test19.dat SIZE: 42
FILE: test20.dat SIZE: 300
FILE: test21.dat SIZE: 55
Creating Dir: /mydir
Dir created
Listing directory: /
DIR : System Volume Information
FILE: data.txt SIZE: 486
FILE: test.txt SIZE: 77824
FILE: foo.txt SIZE: 13
FILE: TestNumber.txt SIZE: 2
FILE: test1.dat SIZE: 7
FILE: test2.dat SIZE: 12
FILE: test3.dat SIZE: 68
FILE: test5.dat SIZE: 7
FILE: test6.dat SIZE: 7
FILE: test7.dat SIZE: 7
FILE: test8.dat SIZE: 7
FILE: test9.dat SIZE: 7
FILE: test10.dat SIZE: 14
FILE: test11.dat SIZE: 7
FILE: test12.dat SIZE: 7
FILE: test13.dat SIZE: 5
FILE: test14.dat SIZE: 354
FILE: test15.dat SIZE: 35
FILE: test16.dat SIZE: 10682
FILE: test17.dat SIZE: 259
FILE: test18.dat SIZE: 343
FILE: test19.dat SIZE: 42
FILE: test20.dat SIZE: 300
FILE: test21.dat SIZE: 55
DIR : mydir
Removing Dir: /mydir
Dir removed
Listing directory: /
DIR : System Volume Information
Listing directory: System Volume Information
Failed to open directory
FILE: data.txt SIZE: 486
FILE: test.txt SIZE: 77824
FILE: foo.txt SIZE: 13
FILE: TestNumber.txt SIZE: 2
FILE: test1.dat SIZE: 7
FILE: test2.dat SIZE: 12
FILE: test3.dat SIZE: 68
FILE: test5.dat SIZE: 7
FILE: test6.dat SIZE: 7
FILE: test7.dat SIZE: 7
FILE: test8.dat SIZE: 7
FILE: test9.dat SIZE: 7
FILE: test10.dat SIZE: 14
FILE: test11.dat SIZE: 7
FILE: test12.dat SIZE: 7
FILE: test13.dat SIZE: 5
FILE: test14.dat SIZE: 354
FILE: test15.dat SIZE: 35
FILE: test16.dat SIZE: 10682
FILE: test17.dat SIZE: 259
FILE: test18.dat SIZE: 343
FILE: test19.dat SIZE: 42
FILE: test20.dat SIZE: 300
FILE: test21.dat SIZE: 55
Writing file: /hello.txt
File written
Appending to file: /hello.txt
Message appended
Reading file: /hello.txt
Read from file: Hello World!
Deleting file: /foo.txt
File deleted
Renaming file /hello.txt to /foo.txt
File renamed
Reading file: /foo.txt
Read from file: Hello World!
77824 bytes read for 188 ms
1048576 bytes written for 256 ms
Total space: 120MB
Used space: 0MB
ESP32 LoRa RFM95W Receiver
Starting LoRa OK!
Received packet 'hello 2282' with RSSI -51
Received packet 'hello 2283' with RSSI -50
Total space: 120MB
Used space: 0MB
Received packet 'hello 2284' with RSSI -48
Received packet 'hello 2285' with RSSI -51
Total space: 120MB
Used space: 0MB
Received packet 'hello 2286' with RSSI -51
Received packet 'hello 2287' with RSSI -51
Total space: 120MB
Used space: 0MB
Received packet 'hello 2288' with RSSI -51
Received packet 'hello 2289' with RSSI -51
Total space: 120MB
Used space: 0MB
Received packet 'hello 2290' with RSSI -51
Total space: 120MB
Used space: 0MB
Received packet 'hello 2291' with RSSI -51
Received packet 'hello 2292' with RSSI -51
Total space: 120MB
Used space: 0MB
Received packet 'hello 2293' with RSSI -49
Received packet 'hello 2294' with RSSI -50
Total space: 120MB
Used space: 0MB
Received packet 'hello 2295' with RSSI -51
Received packet 'hello 2296' with RSSI -51
Total space: 120MB
Used space: 0MB
Received packet 'hello 2297' with RSSI -51
photo
I finally solved it, it works now
#include <SPI.h>
#include <SD.h>
#include <LoRa.h>
// Definizione dei pin SPI per SD (HSPI) e LoRa (VSPI)
#define SD_MISO 12
#define SD_MOSI 13
#define SD_SCLK 14
#define SD_SS 15
#define LORA_MISO 19
#define LORA_MOSI 23
#define LORA_SCLK 18
#define LORA_SS 5
#define LORA_RST 26 // Reset LoRa
#define LORA_DIO0 27 // Interrupt LoRa
// Frequenza LoRa (da adattare al tuo paese)
#define LORA_FREQUENCY 868E6
byte destination_address = 0x3E;
// Inizializzazione dei bus SPI
SPIClass *hspi = NULL; // HSPI per la SD
SPIClass *vspi = NULL; // VSPI per LoRa
void setup() {
Serial.begin(115200);
delay(1000); // Piccola pausa per stabilizzazione
// Creazione delle istanze SPI
hspi = new SPIClass(HSPI);
vspi = new SPIClass(VSPI);
// Inizializzazione HSPI per la scheda SD
hspi->begin(SD_SCLK, SD_MISO, SD_MOSI, SD_SS);
pinMode(SD_SS, OUTPUT);
if (!SD.begin(SD_SS, *hspi)) {
Serial.println("⚠️ Errore nell'inizializzazione della SD!");
return;
}
Serial.println("✅ SD inizializzata con successo!");
// Inizializzazione VSPI per LoRa
vspi->begin(LORA_SCLK, LORA_MISO, LORA_MOSI, LORA_SS);
LoRa.setSPI(*vspi);
LoRa.setPins(LORA_SS, LORA_RST, LORA_DIO0);
if (!LoRa.begin(LORA_FREQUENCY)) {
Serial.println("⚠️ Errore nell'inizializzazione di LoRa!");
return;
}
LoRa.setTxPower(17); //17 dB (defoult)(max power)
LoRa.setSpreadingFactor(7); //7 defoult (can be set from 6 to 12)
LoRa.setSignalBandwidth(62.5E3); //125E3 defoult (7.8 10.4 15.6 20.8 31.25 41.7 62.5 125 250 500)
LoRa.setCodingRate4(8); //5 defoult (can be from 5 to 8 that correspond to 4/5 and 4/8)
Serial.println("✅ LoRa inizializzato con successo!");
}
void loop() {
unsigned long timestamp = millis();
salvaSuSD(timestamp);
inviaLoRa(timestamp);
delay(5000); // Aspetta 5 secondi prima del prossimo ciclo
}
// Funzione per salvare il timestamp sulla scheda SD
void salvaSuSD(unsigned long timestamp) {
File file = SD.open("/log.txt", FILE_APPEND);
if (file) {
file.println(timestamp);
file.close();
Serial.print("📂 Salvato su SD: ");
Serial.println(timestamp);
} else {
Serial.println("❌ Errore nell'apertura del file sulla SD!");
}
}
// Funzione per inviare il timestamp via LoRa
void inviaLoRa(unsigned long timestamp) {
LoRa.beginPacket();
LoRa.write(destination_address);
LoRa.print(timestamp);
LoRa.endPacket();
Serial.print("📡 Inviato via LoRa: ");
Serial.println(timestamp);
}
Serial:
✅ SD inizializzata con successo!
✅ LoRa inizializzato con successo!
📂 Salvato su SD: 1055
📡 Inviato via LoRa: 1055
📂 Salvato su SD: 6160
📡 Inviato via LoRa: 6160
📂 Salvato su SD: 11243
📡 Inviato via LoRa: 11243
📂 Salvato su SD: 16325
📡 Inviato via LoRa: 16325
And the problem with your original code was ?
Initialization and instances were bad. Now everything works fine without any hitches
A post was split to a new topic: Heltec ESP32 Lora Project