hi there, im just trying start simple but i cant figure how add and sd card logger, i use sd,mmc and somtimes writes some times not, i using ttgo lora esp32 paxcuounter i use standar librarys but i not find how start thanks for advice
Why would you want a SD card loger? If the purposes of LoRaWAN is to send your data to your backend / database and then to your applications?
Not clear to us, which ‘standard’ libraries you are using however.
So can you say exactly which libraries you are using ?
Assuming that you are using the board for LoRaWAN, it is not clear if you are using the LMIC-node software or something else (e.g. Paxcounter).
Anything else than LMIC-node (e.g. Paxcounter) is off-topic here (LMIC-node topic).
The LMIC-node topic is for discussions about the bare LMIC-node example program in general. Your question is about SD card support for a specific board. I will therefore move your post to a separate topic [done].
‘TTGO ESP32-Paxcounter LoRa32’ is a confusing marketing name used by LilyGO for the normal ‘TTGO LoRa32’ board (but comes preloaded with Paxcounter firmware).
From your post it is not clear which exact version of the board you have. The version is essential because different versions of those boards use (very) different hardware configurations. See Big ESP32 + SX127x topic part 3
Hi there, i finnally make working SD logger with ttn, i want save data be cause we are goin install the sensors and the loragateway in my country Chile near Atacama desert we are not sure about gsm conectivity gona work we dont have lan conection. be cause of this we beed backup data.
the default SD and test sd_mmc library too are the arduino ones for esp32, i use arduno ide and mcci lorawan otta demo file, i ask here be cause it supouse the started point
the working SD library GitHub - nhatuan84/esp32-micro-sdcard and the pinuout are for lora esp32 V2 1.6 paxcunter and lora esp32 v2 standard
pinout especial del paxcounter tiene monitoreo de bateria y usa otros pines para conectarse
TTGO LoRa32 V2.1.6:
ESP32 LoRa (SPI) SDCARD(SPI) Display (I2C) LED BAT
----------- ---------- ----------- ------------- ------------------
GPIO5 SCK SCK
GPIO27 MOSI MOSI
GPIO19 MISO MISO
GPIO18 SS NSS
GPIO23 RST
GPIO26 DIO0
GPIO33 DIO1
GPIO32 DIO2
GPIO21 SDA SDA
GPIO22 SCL SCL
GPIO25 LED
GPIO35 LECTURA 100K BAT
GPIO14 SD_CLK
GPIO2 SD_MISO
GPIO15 SD_MOSI
GPIO13 SD_CS
GPIO12 DAT2
GPIO4 DAT1
i can share the whole code, but are very crude and is still WIP
Well in one part of your post you mention the SD_MMC library and then point to a library that uses the SPI SD library, and the pinout diagram also suggests the SPI SD library.
In general I have not found the SPI SD library on ESP32 very reliable, especially when sharing the same SPI bus as the LoRa module. The reliability can vary between different cards too. Why that is the case is really down to Expressif who produce the libraries.
The MMC library seems to be a lot more stable, uses one less IO pin too. For the unused pins on MMC, CS, DAT1 and DAT2 use pullup resistors.
The same issues with SD cards arrises on other microcontroller platforms too, SDs can be a bit un-reliable.
IIRC on some TTGO LoRa32 version(s) only SPI is supported on the onboard SD card slot.
It’s been a few years back that I observed this though, I don’t remember the exact version but I think it was in one of the v2.x versions, or possibly even the T-Beam board.
Depends how the wired the SD card, the MMC pins are fixed and cannot be re-directed.
However the SPI pins can be re-directed, so if the SD card was connected to the fixed MMC pins, 2, 14,15, then you would have the choice of MMC or SPI.
Exactly, “only SPI” means MMC interface was not wired on the SD card slot.
@arebolledo posted a pinout that I thought was for the "
TTGO LoRa32 V2.1.6:", it has that title.
On that list of pins the SPI pinouts for the SD appear to support MMC.
Yes, the examples work alone but the ota and sd mmc together didnt work anyway i can make work but im sure its not the most efficient its works anyway Code
// SPI port #2: SD Card Adapter
#define SD_CLK 14
#define SD_MISO 02
#define SD_MOSI 15
#define SD_CS 13
#define LoRa_CS 18
#define Select LOW // Low CS means that SPI device Selected
#define DeSelect HIGH // High CS means that SPI device Deselected
//#include "FS.h"
#include <mySD.h>
#include <SPI.h>
#include <lmic.h>
#include <hal/hal.h>
//#include <SPI.h>
#include <U8x8lib.h>
#define DISABLE_PING 0
#define DISABLE_BEACONS 0
#include <Wire.h>
#include <Adafruit_INA219.h>
Adafruit_INA219 ina219;
const int numReadings = 20;
int indexD = 0; // El indice de la lectura actual
float readings[numReadings]; // Lecturas de la entrada analogica
float total = 0.0; // Total
float average = 0.0; // Promedio
float voltageLevel;
float current_mA = 0;
String mensaje ;
static const u1_t PROGMEM APPEUI[8] = {0x79, 0x88, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x79}; // este se invierte
void os_getArtEui(u1_t * buf) {
memcpy_P(buf, APPEUI, 8);
}
static const u1_t PROGMEM DEVEUI[8] = {0x79, 0xFE, 0x04, 0xD0, 0x7E, 0xD5, 0xB3, 0x70}; // 0x70,0xB3,0xD5,0x7E,0xD0,0x04,0xFE,0x79 //
void os_getDevEui(u1_t * buf) {
memcpy_P(buf, DEVEUI, 8);
} //2F27DF318F19674A6EF7C81ACF435A88
//2F 27 DF 31 8F 19 67 4A 6E F7 C8 1A CF 43 5A 88
static const u1_t PROGMEM APPKEY[16] = {0x2F, 0x27, 0xDF, 0x31, 0x8F, 0x19, 0x67, 0x4A, 0x6E, 0xF7, 0xC8, 0x1A, 0xCF, 0x43, 0x5A, 0x88}; //0x67,0xA3,0x60,0x70,0x93,0x65,0xC7,0xE8,0x84,0x7C,0x50,0x3D,0xD8,0xE3,0xC8,0xFF
void os_getDevKey(u1_t * buf) {
memcpy_P(buf, APPKEY, 16);
}
RTC_DATA_ATTR char filenameCSV[25]=""; //para construir el archivo csv base cada vez que se prenda y guarde
File root;
File myFile;
int led = 25;
//For TTGO LoRa32 V2.x use:
U8X8_SSD1306_128X64_NONAME_HW_I2C display_(/*rst*/ U8X8_PIN_NONE);
//static uint8_t mydata[] = "Hello, from ESP32";
//uint8_t mydata[20]="esp32Test";
// char mydata[20]="esp32Test";
static uint8_t mydata[51];
static int counter;
static osjob_t sendjob;
int runs = 0;
const unsigned TX_INTERVAL = 30;
// For TTGO LoRa32 V2.1.6
const lmic_pinmap lmic_pins = {
.nss = LoRa_CS,
.rxtx = LMIC_UNUSED_PIN,
.rst = 23,
.dio = {/*dio0*/ 26, /*dio1*/ 33, /*dio2*/ 32}
};
void printHex2(unsigned v) {
v &= 0xff;
if (v < 16)
Serial.print('0');
Serial.print(v, HEX);
}
void onEvent(ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch (ev) {
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED")); {
u4_t netid = 0;
devaddr_t devaddr = 0;
u1_t nwkKey[16];
u1_t artKey[16];
LMIC_getSessionKeys( & netid, & devaddr, nwkKey, artKey);
Serial.print("netid: ");
Serial.println(netid, DEC);
Serial.print("devaddr: ");
Serial.println(devaddr, HEX);
Serial.print("AppSKey: ");
for (size_t i = 0; i < sizeof(artKey); ++i) {
if (i != 0)
Serial.print(" ");
printHex2(artKey[i]);
}
Serial.println("");
Serial.print("NwkSKey: ");
for (size_t i = 0; i < sizeof(nwkKey); ++i) {
if (i != 0)
Serial.print(" ");
printHex2(nwkKey[i]);
}
Serial.println();
display_.drawString(0, 5, "Network Joined");
}
initSD();
// Disable link check validation (automatically enabled
// during join, but because slow data rates change max TX
// size, we don't use it in this example.
LMIC_setLinkCheckMode(0);
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
display_.drawString(0, 3, "Data Sent");
WriteReadSD();
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.print(F("Received "));
Serial.print(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
display_.drawString(0, 4, "Data received");
Serial.println(F("Data is "));
// Change the following codes to process incoming data !!
for (int counter = 0; counter < LMIC.dataLen; counter++) {
Serial.print(LMIC.frame[LMIC.dataBeg + counter], HEX);
}
Serial.println(F(" "));
}
else
display_.drawString(0, 4, " ");
// Schedule next transmission
os_setTimedCallback( & sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
case EV_TXCANCELED:
Serial.println(F("EV_TXCANCELED"));
break;
case EV_JOIN_TXCOMPLETE:
Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));
break;
default:
Serial.print(F("Unknown event: "));
Serial.println((unsigned) ev);
break;
}
}
void do_send(osjob_t * j) {
display_.clear();
display_.drawString(0, 0, "TTGO ESP32 LoRa Test");
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
++counter;
mydata[0] = 0; //este es el mensaje completo
mensaje = "2V";
mensaje = mensaje + String(voltageLevel) + " numero envio: " + String(counter) + " corriente: " + String(average) + "mA '\0'";
Serial.println(mensaje);
int str_lenM = mensaje.length() + 1; // esta funcion es para asignarle el valor de casillas al array
char menC[str_lenM]; //este es el char array
mensaje.toCharArray(menC, str_lenM);
Serial.println(menC);
strcat ((char*)mydata, menC); //copio el mensaje ‘\0’ average
// Prepare upstream data transmission at the next possible time.
//LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
LMIC_setTxData2(1, mydata, sizeof(mydata) + 1, 0);
Serial.println(F("Packet queued"));
display_.drawString(0, 2, "Packet Queued");
digitalWrite(led, HIGH);
delay(1000);
}
// Next TX is scheduled after TX_COMPLETE event.
digitalWrite(led, LOW);
delay(500);
}
int uno = 1;
void setup() {
Serial.begin(115200);
pinMode(led, OUTPUT);
uint32_t currentFrequency;
Serial.println("Test esp32 RM95");
// Initialize the INA219.
// By default the initialization will use the largest range (32V, 2A). However
// you can call a setCalibration function to change this range (see comments).
if (! ina219.begin()) {
Serial.println("Failed to find INA219 chip");
while (1) {
delay(10);
}
}
// lower 16V, 400mA range (higher precision on volts and amps):
ina219.setCalibration_16V_400mA();
Serial.println("Measuring voltage and current with INA219 ...");
Serial.println(F("Starting"));
display_.begin();
display_.setFont(u8x8_font_pxplusibmcgathin_r);
display_.drawString(0, 0, "TTGO ESP32 LoRa Test");
Serial.println(F("Module Configured for CHILE BAND (AU915 MHz)"));
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
LMIC_setClockError(MAX_CLOCK_ERROR * 5 / 100);
//LMIC_setClockError(MAX_CLOCK_ERROR * 10 / 100);
// Reset the MAC state. Session and pending data transfers will be discarded.
// LMIC_reset();
LMIC_setLinkCheckMode(0);
LMIC_setAdrMode(false);
LMIC_setDrTxpow(DR_SF7, 14);
LMIC_enableSubBand(1);
LMIC_selectSubBand(1);
do_send( & sendjob);
// set output pins
pinMode(SD_CS, OUTPUT);
pinMode(LoRa_CS, OUTPUT);
}
void loop() {
// os_runloop_once();
float shuntvoltage = 0;
float busvoltage = 0;
float loadvoltage = 0;
float power_mW = 0;
int batR = analogRead(35);
voltageLevel = (batR / 4095.0) * 2 * 1.1 * 3.3; // calculate voltage level
shuntvoltage = ina219.getShuntVoltage_mV();
busvoltage = ina219.getBusVoltage_V();
current_mA = ina219.getCurrent_mA();
power_mW = ina219.getPower_mW();
loadvoltage = busvoltage + (shuntvoltage / 1000);
// Restamos la ultima lectura:
total = total - readings[indexD];
// Leemos del sensor:
readings[indexD] = current_mA;
// Añadimos la lectura al total:
total = total + readings[indexD];
// Avanzamos a la proxima posicion del array
indexD = indexD + 1;
// Si estamos en el final del array...
if (indexD >= numReadings)
indexD = 0; // ...volvemos al inicio:
// Calculamos el promedio:
average = total / numReadings;
// Lo mandamos a la PC como un valor ASCII
//
// Serial.print("Bus Voltage: "); Serial.print(busvoltage); Serial.println(" V");
// Serial.print("Shunt Voltage: "); Serial.print(shuntvoltage); Serial.println(" mV");
// Serial.print("Load Voltage: "); Serial.print(loadvoltage); Serial.println(" V");
// Serial.print("Current: "); Serial.print(current_mA); Serial.println(" mA");
// Serial.print("Power: "); Serial.print(power_mW); Serial.println(" mW");
// Serial.println("");
// display_.drawString(0, 4, "Current:");
display_.setCursor(0, 4);
display_.print(String(average) + " mA " + String(loadvoltage) + " V");
display_.setCursor(0, 6);
display_.print("Bat: " + String(voltageLevel) + " V");
os_runloop_once();
}
void WriteReadSD(){
static uint32_t debs;
if (millis() - debs >= 3000){
debs = millis();
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
digitalWrite(LoRa_CS, DeSelect);
digitalWrite(SD_CS, Select); // SELECT (Low) SD Card SPI
myFile = SD.open(filenameCSV, FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to "+String(filenameCSV));
myFile.println(mensaje);
// close the file:
myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening "+String(filenameCSV));
}
// re-open the file for reading:
myFile = SD.open(filenameCSV);
if (myFile) {
Serial.println(filenameCSV);
// read from the file until there's nothing else in it:
while (myFile.available()) {
Serial.write(myFile.read());
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening "+String(filenameCSV));
}
digitalWrite(SD_CS, DeSelect);
delay( 1000 );
digitalWrite(LoRa_CS, Select); // SELECT (low) LoRa SPI
}
}
void initSD(){
Serial.print("Initializing SD card...");
digitalWrite(LoRa_CS, DeSelect);
digitalWrite(SD_CS, Select); // SELECT (Low) SD Card SPI
delay(100);
/**/
Serial.print("Initializing SD card...");
pinMode(SD_CS, OUTPUT); // SELECT (Low) SD Card SPI
/**/
if (!SD.begin( SD_CS, SD_MOSI, SD_MISO, SD_CLK )) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
int n = 0;
snprintf(filenameCSV, sizeof(filenameCSV), "data%03d.csv", n); // includes a three-digit sequence number in the file name
while(SD.exists(filenameCSV)) {
n++;
snprintf(filenameCSV, sizeof(filenameCSV), "data%03d.csv", n);
}
File dataFile = SD.open(filenameCSV,FILE_READ);
Serial.println(n);
Serial.println(filenameCSV);
dataFile.close();
root = SD.open("/");
printDirectory(root, 0);
Serial.println(" done!");
digitalWrite(SD_CS, DeSelect);
delay( 1000 );
digitalWrite(LoRa_CS, Select); // SELECT (low) LoRa SPI
}
void printDirectory(File dir, int numTabs) {
// Begin at the start of the directory
dir.rewindDirectory();
while(true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
//Serial.println("**nomorefiles**");
break;
}
for (uint8_t i=0; i<numTabs; i++) {
Serial.print('\t'); // we'll have a nice indentation
}
// Print the 8.3 name
Serial.print(entry.name());
// Recurse for directories, otherwise print the file size
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
If anyone think can be more officient i´m glad to hear coments
This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.