Hi all. I recently made a pcb with an esp32 chip, an sd connected in vspi and a lora RFM95 in hspi. How can I make the two modules work without interfering with each other? Do you have any demo codes?
if you run individual tests do the SD and RFM95 work OK?
not done this particular combination - I have used
- a SD module on VSPI or HSPI with a MFRC522 RFID reader on other SPI
- a RFM95 on VSPI - don't remember ever trying it on HSPI
assume you are talking about a ESP32 - not S3, C3, etc
The LoRa library and SD library should work OK for basic stuff on the same SPI bus without any magic. SPI is a bus and the LoRa module and SD module will have separate select lines.
So perhaps tell us how you connected it all, provide links to the modules used and maybe describe what 'interfering' you are seeing.
Also useful for the forum to be told what you are trying to do with the LoRa module and SD card.
Do they? If so, post the details.
Did you bread board the design using available an ESP32 board, SD, and Lora Eval Board? Did you write sufficient software to confirm they all worked together? Or, did you just jump in and cut metal on a custom PCB?
I'll go into more detail: I use two separate codes which are:
1 on the sd as a test I used):
#include "FS.h"
#include "SD.h"
#include "SPI.h"
// Definizione dei pin per HSPI
#define HSPI_SCK 14
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_CS 15
// Creazione di un'istanza SPI personalizzata (HSPI)
SPIClass hspi(HSPI);
// Funzione per scrivere il valore di millis() su file
void writeMillisToFile(fs::FS &fs, const char *path) {
uint32_t currentMillis = millis();
// Apri il file in modalitĂ append
File file = fs.open(path, FILE_APPEND);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
// Scrivi millis nel file
if (file.printf("%lu\n", currentMillis)) {
Serial.printf("Millis written to file: %lu\n", currentMillis);
} else {
Serial.println("Failed to write to file");
}
file.close();
}
void setup() {
Serial.begin(115200);
// Configura HSPI
hspi.begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, HSPI_CS);
// Inizializza la scheda SD su HSPI
if (!SD.begin(HSPI_CS, hspi)) {
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println("No SD card attached");
return;
}
Serial.println("SD Card initialized successfully");
// Controllo e creazione file log
const char *filePath = "/millis_log.txt";
if (!SD.exists(filePath)) {
File file = SD.open(filePath, FILE_WRITE);
if (file) {
file.println("Millis Log Start");
file.close();
Serial.println("Created file: millis_log.txt");
} else {
Serial.println("Failed to create file");
}
}
}
void loop() {
writeMillisToFile(SD, "/millis_log.txt");
delay(1000); // Log ogni secondo
}
2 for the Lora I use this:
#include <BluetoothSerial.h>
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
BluetoothSerial SerialBT; // Oggetto per la gestione del Bluetooth
#include <SPI.h>
#include <LoRa.h>
#define SR 5 // [ms] : delta_tempo per aggiornare comandi al motore
#define RST 26 // [ms] : delta_tempo per aggiornare comandi al motore
#define DIO0 27 // [ms] : delta_tempo per aggiornare comandi al motore
SPIClass LoRaSPI(HSPI);
byte localAddress = 0x3D; // IRENE
// byte localAddress = 0x2D; // ANDREA
void setup() {
Serial.begin(115200);
SerialBT.begin("ESP_PATCH2");
LoRaSPI.begin();
LoRa.setPins(SR, RST, DIO0);
if (!LoRa.begin(868E6)) {
Serial.println("Starting LoRa failed!");
SerialBT.println("Starting LoRa failed!");
while (1);
}
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)
}
void loop() {
// try to parse packet
int packetSize = LoRa.parsePacket();
int password = LoRa.read();
if (packetSize) {
if (password != localAddress) {
return;
}
// received a packet
// read packet and print
while (LoRa.available()) {
SerialBT.print((char)LoRa.read());
}
SerialBT.print(" , ");
SerialBT.print(LoRa.packetSnr());
SerialBT.print(" , ");
SerialBT.print(LoRa.packetRssi());
SerialBT.print(" , ");
SerialBT.print(packetSize);
SerialBT.print(" , %");
SerialBT.println("");
}
}
now I had done more tests but the code crashes, the test code for example was this:
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include <TinyGPS++.h>
#include "FS.h"
#include "SD.h"
#include <LoRa.h>
#define SR 5 // [ms] : delta_tempo per aggiornare comandi al motore
#define RST 26 // [ms] : delta_tempo per aggiornare comandi al motore
#define DIO0 27 // [ms] : delta_tempo per aggiornare comandi al motore
SPIClass LoRaSPI(HSPI);
//-----------------------------------------------LORA:
byte destination_address = 0x3E;
byte local_address = 0x5E;
String ID = "LOGGER";
int listening_window = 500; // ms
int spam_times = 30;
int last_packet = -1;
int last_packet_sent = -1;
// Definizione dei pin per HSPI
#define HSPI_SCK 14
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_CS 15
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME680 bme(&Wire); // I2C
TinyGPSPlus gps;
#define RX2 16 // Pin RX2 su ESP32
#define TX2 17 // Pin TX2 su ESP32
/* Variabili per i dati GPS */
float lat, lng, alt, speed;
int year, month, day, hour, minute, second, centisecond;
int pin_buzzer = 4;
void setup() {
Serial.begin(115200);
pinMode(pin_buzzer, OUTPUT);
while (!bme.begin()) {
Serial.println("Could not find a valid BME680 sensor, check wiring!");
delay(500);
}
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
Serial.println("BME OK");
// Configura HSPI
//pinMode(HSPI_CS, LOW);
// hspi.begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, HSPI_CS);
// // Inizializza la scheda SD su HSPI
// while (!SD.begin(HSPI_CS, hspi)) {
// Serial.println("Card Mount Failed");
// delay(500);
// }
// uint8_t cardType = SD.cardType();
// while (cardType == CARD_NONE) {
// Serial.println("No SD card attached");
// delay(500);
// }
// Serial.println("SD OK");
Serial2.begin(9600, SERIAL_8N1, RX2, TX2);
delay(1000);
Serial.println("GPS OK");
LoRaSPI.begin();
LoRa.setPins(SR, RST, DIO0);
while(!LoRa.begin(868E6)) {
Serial.println("Starting LoRa failed!");
delay(500);
}
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 OK");
beep();
delay(200);
beep();
}
void loop() {
core();
//save_sd(status);
}
void core(){
listen();
float pressure = read_pressure();
Serial.println(pressure);
get_GPS_data();
/* Stampa i dati GPS */
Serial.println("---------------------------------------------------");
Serial.print("Data: "); Serial.print(day); Serial.print("/"); Serial.print(month); Serial.print("/"); Serial.println(year);
Serial.print("Ora: "); Serial.print(hour); Serial.print(":"); Serial.print(minute); Serial.print(":"); Serial.print(second); Serial.print("."); Serial.println(centisecond);
Serial.print("Latitudine: "); Serial.println(lat, 8);
Serial.print("Longitudine: "); Serial.println(lng, 8);
Serial.print("Altitudine: "); Serial.print(alt); Serial.println(" m");
Serial.print("Velocità: "); Serial.print(speed); Serial.println(" km/h");
Serial.println("---------------------------------------------------\n");
String status = "DATA: " +
String(lat, 8) + "," +
String(lng, 8) + "," +
String(alt) + "," +
String(speed) + "," +
String(pressure);
//spam_text(status);
last_packet_sent += 1;
send_packet(String(last_packet_sent) + "|" + status);
}
void get_GPS_data() {
unsigned long startWait = millis();
bool gpsDataReceived = false;
while (millis() - startWait < 1200) {
while (Serial2.available() > 0) {
gps.encode(Serial2.read());
}
/* Se i dati sono validi, stampali */
if (gps.location.isValid()) {
lat = gps.location.lat();
lng = gps.location.lng();
} else {
lat = lng = 0;
}
if (gps.altitude.isValid()) {
alt = gps.altitude.meters();
} else {
alt = 0;
}
if (gps.speed.isValid()) {
speed = gps.speed.kmph();
} else {
speed = 0;
}
if (gps.date.isValid() && gps.time.isValid()) {
year = gps.date.year();
month = gps.date.month();
day = gps.date.day();
hour = gps.time.hour();
minute = gps.time.minute();
second = gps.time.second();
centisecond = gps.time.centisecond();
} else {
year = month = day = hour = minute = second = centisecond = 0;
}
}
}
void split_string(const String& inputString, char delimiter, String* outputArray, int arraySize, int& itemCount) {
int startIndex = 0;
int endIndex = inputString.indexOf(delimiter);
itemCount = 0;
while (endIndex >= 0 && itemCount < arraySize - 1) {
outputArray[itemCount] = inputString.substring(startIndex, endIndex);
startIndex = endIndex + 1;
endIndex = inputString.indexOf(delimiter, startIndex);
itemCount++;
}
if (startIndex < inputString.length() && itemCount < arraySize) {
outputArray[itemCount] = inputString.substring(startIndex);
itemCount++;
}
}
void send_packet(String text) {
LoRa.beginPacket();
LoRa.write(destination_address);
LoRa.print(ID + "|" + text);
LoRa.endPacket();
}
void spam_text(String text) {
last_packet_sent += 1;
for (int i = 0; i < spam_times; i++) {
send_packet(String(last_packet_sent) + "|" + text);
delay(10);
}
}
String get_packet() {
unsigned long t1 = millis();
while (millis() - t1 <= listening_window) {
int packetSize = LoRa.parsePacket();
int passwordflight = LoRa.read();
if (packetSize) {
if (passwordflight == local_address) {
String received_message = "";
while (LoRa.available()) {
char c = (char)LoRa.read();
received_message += c;
}
return received_message;
}
}
}
return "";
}
void listen() {
String data = get_packet();
if (data != "") {
data.trim();
if (data.indexOf("|") > 0) {
const int numFields = 2; // Numero di dati attesi
String fields[numFields];
int itemCount = 0;
split_string(data, '|', fields, numFields, itemCount);
int packet_number = fields[0].toInt();
if (packet_number != last_packet) {
data = fields[1];
last_packet = packet_number;
log(data);
if (data == "YOLO") {
delay(1000);
beep();
spam_text("BUY GME!");
}
}
}
}
}
void log(String text) {
Serial.println(text);
save_sd(text);
}
void save_sd(String text) {
File file = SD.open("logs.txt", FILE_WRITE);
file.println(text);
file.close();
}
void beep() {
digitalWrite(pin_buzzer, HIGH);
delay(100);
digitalWrite(pin_buzzer, LOW);
}
float read_pressure() {
bme.performReading();
float pressure = bme.pressure;
return pressure;
}
if i remove the comments for sd this error appears:
:
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:4688
load:0x40078000,len:15460
ho 0 tail 12 room 4
load:0x40080400,len:4
load:0x40080404,len:3196
entry 0x400805a4
E (175) esp_image: Checksum failed. Calculated 0xa1 read 0xaf
E (175) boot: OTA app partition slot 0 is not bootable
E (175) esp_image: image at 0x150000 has invalid magic byte (nothing flashed here?)
E (182) boot: OTA app partition slot 1 is not bootable
E (187) boot: No bootable app partitions in the partition table
ets Jul 29 2019 12:21:46
and in download mode i see this:
Wrote 386496 bytes (217422 compressed) at 0x00010000 in 4.5 seconds (effective 688.1 kbit/s)...
File md5: 106b79b45cd8bfc5c54cd6499796dc94
Flash md5: d14bded0f6bed1bbc74235ba3cc91cee
MD5 of 0xFF is ed07f41eb84e99a432e1f76a6d7b0e10
A fatal error occurred: MD5 of file does not match data in flash!
Caricamento non riuscito: errore durante il caricamento: exit status 2
obviously code 1 and code 2 used individually on the same board work correctly.
on the pcb i have an sd slot directly connected to the esp32 chip (all at 3v as logic so without level shifter modules). the lora instead the rfm95 chip direct to the esp32 chip with a 100nf capacitor on the input power supply of the lora chip. individually the codes work but if i join the two systems everything collapses ...
So ignoring the code with all the extra sensor stuff ................
What happens when you have a basic code that sets up the LoRa device and initializes the SD card, does that crash as well ?
same error that I post before
see post #6
In post #6 I response
could you show me an example? see Post 6#
On post 6, I cant see the vspi init.
You are using boths devices with the same pin connection?
SPIClass LoRaSPI(HSPI);
And then:
hspi.begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, HSPI_CS);
// Inizializza la scheda SD su HSPI
while (!SD.begin(HSPI_CS, hspi)) {
Also, it would be good practice to add some serial prints to know where the code crashes.
if I set vspi it doesn't change, in fact the lora doesn't work at all. furthermore the problem is that the crash occurs when loading the code and therefore it doesn't even initialize the code
So the answer is "no". You didn't first bread board the design and test it with software that would demonstrate your final use case (simultaneous SD and LORA access).
Ok, then I would try to use one device or the other.
Something like:
SD.begin();
/do what you need with the SD
SD.end();
And:
LoRaSPI.begin();
/do what you need with this module
LoRaSPI.end();
You can try toying with the SD card slave select to enable/disable.
Never worked with rf modules, but the pinout shows a slave select to enable disable that module.
As someonne stated before, you need to test this onn a breadboard (since the code is not running, not even the breadboard is needed).
SD cards are super tricky. Are you using a module for this device? If its the one with a level shifter and a power regulator it should be powered with 5V.
no, I have always used the lora in this mode alone. I wanted to add the sd to a pcb already tested several times and nothing comes back. moreover sd has no modules it is directly connected and this thing does not make sense to me that on the individually assembled card everything works. so I think it is only code the problem and for this I asked for example codes to understand how to manage its components
the chip select selection must be done as specified? both setup and loop right? could you give me an example? anyway I wrote in the last post why I didn't do a breadboard test. the sd is directly connected without modules
I think you either use the rf or the sd.
Your code should look like this:
// Read data from device
Init_device(); // Init and enable the device, read data andn save it to ram/buffer etc.
de_init_device(); // device.end(); or similar.
// Save data to SD Card.
Init_SD_Card(); // Init SD card in SPI Mode, save buffer to SD.
de_init_SD_Card(); // De-init SD Card. SD.end();
The chip selection is defined before. Check for lines similar to :
pinMode(HSPI_CS, LOW);
Can't see that line works for the RF module. It seems to be for the SD Card.
so for example both in the setup and in the loop I write:
\\ when I start :
pinMode(SR, HIGH);
pinMode(HSPI_CS, HIGH);
pinMode(HSPI_CS, LOW);
\\..... setup sd
pinMode(HSPI_CS, HIGH);
pinMode(SR, LOW);
\\..... setup lora
pinMode(SR, HIGH);
each component in the loop similar to this?