File non viene rimosso da sd

Ciao a tutti, sono tornato dopo aver accantonato arduino per un po causa sessione estiva. Mi sono rimesso all'opera nella speranza di poter progettare un dispositivo che mi permettesse di raccogliere dati utilizzando un mpu6050 e di salvarli in una sd. E' una specie di datalogger che non sfutta un modulo rtx bensì salva il tempo millis().
Ovviamente realizzare ciò mi ha portato tanti problemi tutti risolti in un modo o nell'altro. Oggi credevo di avercela finalmente fatta, tutto funzionava ma dovevo modificare lo sketch poichè avevo dimenticato di far printare uno " " sul file .txt, tuttavia quando ho aggiunto ciò e ricaricato lo sketch mi si è ripresentato un nuovo problema che non c'era mai stato:

// check esistenza file, in caso lo elimino
 if (SD.exists("datalog.txt")) {
   SD.remove("datalog.txt");
   digitalWrite(7, HIGH);
   delay(2000);
 }

l'if viene aperto ma la funzione .remove non fa il suo compito.
il risultato è che non viene eliminato il file che vi era in precedenza per poi ricrearne un altro vuoto ma semplicemente aggiunge i nuovi dati al file contenente ii dati di un altra "sessione".

vi allego il codice anche se come già detto, mi sembra essere uno di quei casi di "prima funzionava e ora no e non ho cambiato nulla", ovviamente mi piace pensare che la magia nera non esista :wink:

// include librerie per i2c e gestione mpu
#include <Wire.h>
#include <MPU6050_tockn.h>

// librerie gestione interfaccia SPI e SD
#include <SPI.h>
#include <SD.h>
//##########################################################################

// creo oggetto per mpu
MPU6050 mpu6050(Wire);

// creazione oggetto file
File file;


void setup() {
  //pinmode
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  //  check connessione SD
  if (!SD.begin(10)) {
    digitalWrite(9, HIGH);
    while(1);
  }
  
  // check esistenza file, in caso lo elimino
  if (SD.exists("datalog.txt")) {
    SD.remove("datalog.txt");
    digitalWrite(7, HIGH);
    delay(2000);
  }
  digitalWrite(7, LOW);
  
  digitalWrite(8, HIGH);
  //  creo file in modalità WRITE
  file = SD.open("datalog.txt", FILE_WRITE);
  file.println("coordinate inclinazione x y z");
  delay(2000);
  digitalWrite(8, LOW);
  delay(1000);

  // inizializzo i2c ed mpu
  digitalWrite(8, HIGH);
  Wire.begin();
  mpu6050.begin();
  // taro mpu
  mpu6050.calcGyroOffsets(true);
  delay(1000);
  digitalWrite(8, LOW);
  file.close();
}

//##########################################################################
// definizione di altre varibili
unsigned long dt, t1=0;
float x, y, z;

void loop() {
  // update del mpu6050
  mpu6050.update();
  digitalWrite(9, HIGH);
  // prendo dati ogni 0.2 sec
  dt = millis() - t1;
  if (dt >= 300) {
    t1 = millis();
    digitalWrite(9, LOW);
    
    // estraggo dati angoli lungo le coordinate
    x = mpu6050.getAngleX();
    y = mpu6050.getAngleY();
    z = mpu6050.getAngleZ();

    // converto dati numerici in stringa
    String coord = String(x,1) + " " + String(y,1) + " " + String(z,1) +" ";

    // stampo i numeri nel file
    file = SD.open("datalog.txt", FILE_WRITE);
    file.print(coord.c_str());
    file.println(t1, DEC);
    file.close();
  }
      
}

i led mi aiutano per il debugging del codice poichè non posso utilizzare la serial. Infatti un'altra informazione importante è che sto realizzando questo progetto utilizzando un Atmega328 standalone (anche questo mi ha dato molti problemi per programmarlo per via della sua signature che si discosta da quella del fratello P).

se volete vi allego lo schema elettrico, ma è molto standard:
i2c per mpu6050
spi (maledetta) per il lettore di microsd
quarzo da 16000hz
due condensatori da 22pico
resistenza da 10kohm connessa al pin di reset dell'atmega
e tre led connessi ai pin 9 8 7

grazie mille!
Riccardo

Salve, dopo aver lasciato tutto come prima (tutto intendo tutto, cablaggio e codice) sono ritornato nel dopocena a fare un tentativo ed adesso...va. Il file viene cancellato e riscritto come dovrebbe essere.
Allora la mia domanda cambia, quali potrebbero essere le cause di questi malfunzionamenti strani ed immotivati? aggiungo che il led che doveva segnalarmi che il file si fosse eliminato si accendeva sia prima che adesso.
Sono un pò preoccupato perchè vorrei aumentare l'affidabilità di questo dispositivo ma non saprei da dove iniziare e come procedere poichè non mi sono chiare le cause del perchè un certo malfunzionamento accada. Soprattutto non capisco se ciò derivi da un mio errore a livello di script/hardware o del controllore che "impazzisce" in alcuni momenti.

Siamo sicuri che non andava prima e ora va?
Io me lo chiedo perché è normale che il led si accenda e poi dopo 2 secondi circa si spegne.
Prova così: spegni arduino, estrai la sd e la inserisci sul PC, cancelli o rinomini il file. A questo punto inserendo la sd in arduino, il programma non trova il file (non si accende il led) e lo crea e questa cosa si ripete ad ogni spegnimento/riaccensione di arduino.

Questo comportamento ovviamente si verifica anche dopo avere fatto un upload, poiché arduino viene resettato e riavviato e questo accade anche solo aprendo il serial monitor.

Ciao.

sicuro al 99.9%.
ho fatto la prova da te indicatomi e tutto funziona come dovrebbe: il led pin7 non si accende e si passa direttamente a quello pin8.
Se il file non c'è lo crea, se c'era in precedenza lo elimina e ne crea uno nuovo, tutto funziona ora.

quello che accadeva prima che tutto si aggiustasse da sé era che il file non venisse eliminato (nonostante si attivasse il led pin7), venisse aperto e si continuava a scrivere sul file precedente.

ESEMPIO:

coordinate inclinazione x y z
2.9 -1.3 0.7 13740
1.5 1.1 0.7 14042
1.4 1.4 0.7 14344
1.4 1.4 0.7 14646
1.4 1.4 0.7 14947
1.4 1.4 0.7 15247
1.4 1.4 0.7 15548
1.4 1.4 0.7 15848
1.3 1.4 0.7 16149
1.4 1.4 0.7 16449
1.4 1.4 0.7 16750
1.4 1.4 0.7 17050
1.4 1.4 0.7 17351
1.4 1.4 0.7 17651
1.4 1.4 0.7 17951
1.4 1.4 0.7 18252

mettiamo caso che io abbia zero file nella SD, la inserisco nel dispositivo, viene creato il file datalog.txt (di cui sopra ho riportato il risultato), tutto ciò senza che il led pin7 si accenda.

Ora ripeto l'operazione, questa volta esiste già il file datalog.txt quindi come giusto che sia si accende il led pin7 e come ci aspettiamo, il file precedente dovrebbe essere eliminato...il risultato però era questo:

coordinate inclinazione x y z
2.9 -1.3 0.7 13740
1.5 1.1 0.7 14042
1.4 1.4 0.7 14344
1.4 1.4 0.7 14646
1.4 1.4 0.7 14947
1.4 1.4 0.7 15247
1.4 1.4 0.7 15548
1.4 1.4 0.7 15848
1.3 1.4 0.7 16149
1.4 1.4 0.7 16449
1.4 1.4 0.7 16750
1.4 1.4 0.7 17050
1.4 1.4 0.7 17351
1.4 1.4 0.7 17651
1.4 1.4 0.7 17951
1.4 1.4 0.7 18252
coordinate inclinazione x y z
2.9 -1.3 0.7 13740
1.5 1.1 0.7 14042
1.4 1.4 0.7 14344
1.4 1.4 0.7 14646
1.4 1.4 0.7 14947
1.4 1.4 0.7 15247
1.4 1.4 0.7 15548
1.4 1.4 0.7 15848
1.3 1.4 0.7 16149
1.4 1.4 0.7 16449
1.4 1.4 0.7 16750

spero di essere stato chiaro.
ribadisco che ormai il problema è stato risolto...ma non da me, sembra piuttosto essere stato un miracolo :joy: e perciò mi piacerebbe acquisire più consapevolezza dello strumento con la quale mi ritrovo a che fare.

grazie mille e buona giornata
RIccardo

... spero bene ciascuno con la dovuta resistenza per limitare la corrente vero?

Guglielmo

Io per sicurezza proverei con altra sd. Sia mai qualche problema di "file system"

Non mi sento di puntare il dito verso qualcosa di specifico, però per quello che scrivi c'è da pensare che il metodo exist() ha lavorato correttamente e ha invece fallito il metodo remove().

#define FILE_READ O_READ
#define FILE_WRITE (O_READ | O_WRITE | O_CREAT | O_APPEND)

Queste due righe si trovano nel file SD.h, penso si possa aprire il file in scrittura con O_WRITE e se il file esiste inizia a scrivere dall'inizio.
Non ho provato di recente.

Non sapendo dove puntare il dito mi limito a consigliare modifiche di codice che male non possono fare.
Ad esempio usi un solo nome di file e perciò è meglio fare così:

constexpr char logFileName[] = "datalog.txt";

void setup() {
    file = SD.open(logFileName, FILE_WRITE);
}

Se per un errore di digitazione avessi scritto:

if (SD.exists("datalog.txt")) {
    SD.remove("datalo.txt");

Sarebbe entrato nella if (si accende il led) non avrebbe cancellato il file ma avrebbe dovuto restituire qualche errore perché sto tentando di cancellare un file name che non esiste.

Non resta che fare dei test ripetuti sperando che si verifichi nuovamente il comportamento anomalo.

Già, speriamo che abbia seguito il tutorial corretto. La rete è piena di guide fuorvianti, quindi non gli darei neanche la colpa. :wink:

Ciao.

Innanziutto grazie per le risposte!
spero di aver citato nella maniera corretta ma ho i miei dubbi...

Citazione
... spero bene ciascuno con la dovuta resistenza per limitare la corrente vero?
Guglielmo
sisi, mi sono scordato di specificarlo!

Citazione
Io per sicurezza proverei con altra sd. Sia mai qualche problema di "file system"

proverò con un'altra SD quando ne avrò un'altra sotto mano

Citazione
Non sapendo dove puntare il dito mi limito a consigliare modifiche di codice che male non possono fare.
Ad esempio usi un solo nome di file e perciò è meglio fare così:

constexpr char logFileName[] = "datalog.txt";

void setup() {
    file = SD.open(logFileName, FILE_WRITE);
}

Citazione
Se per un errore di digitazione avessi scritto:

if (SD.exists("datalog.txt")) {
    SD.remove("datalo.txt");

Citazione
Sarebbe entrato nella if (si accende il led) non avrebbe cancellato il file ma avrebbe dovuto restituire qualche errore perché sto tentando di cancellare un file name che non esiste.
Non resta che fare dei test ripetuti sperando che si verifichi nuovamente il comportamento anomalo.

effettivamente potrei rendere più chiaro e sicuro il codice con questa modifica.
Comunque ho fatto qualche decina di test e per ora sembra fuznionare tutto alla perfezione, vedremo in futuro se mi ricapiterà questo scherzetto...

grazie mille
RIccardo

Rieccomi, non so cosa dire. Mi si sta di nuovo presentando il problema sopra descritto. Non riesco a capire il perché. A volte si e a volte no...circuito lasciato così com'è eppure ha, a tratti, questi comportamenti anomali.
Stavolta ho cambiato sensore i2c, si tratta di un bmp280.

ecco qui l'output di tre prove: (ricordo che ad ogni prova il file dovrebbe essere eliminato)

DATI ALTITUDINE
altitude:  126.21  2118
altitude:  126.40  2439
altitude:  126.47  2758
altitude:  126.45  3078
altitude:  126.53  3397
altitude:  126.45  3718
altitude:  126.49  4037
altitude:  126.42  4357
altitude:  126.49  4676
altitude:  126.58  4997
altitude:  126.65  5316
altitude:  126.51  5644
altitude:  126.36  5963
altitude:  126.68  6283
altitude:  126.40  6602
altitude:  126.48  6922
altitude:  126.39  7242
altitude:  126.59  7562
altitude:  126.19  7881
altitude:  126.33  8201
altitude:  126.04  8524
altitude:  126.09  8844
altitude:  126.43  9163
altitude:  126.37  9483
altitude:  126.26  9803
altitude:  126.51  10123
altitude:  126.33  10442

DATI ALTITUDINE
altitude:  126.38  1657
altitude:  126.32  1978
altitude:  126.27  2297
altitude:  126.32  2621
altitude:  126.14  2940
altitude:  126.21  3260
altitude:  126.44  3579
altitude:  126.12  3899
altitude:  126.27  4227
DATI ALTITUDINE
altitude:  126.40  1657
altitude:  126.33  1978
altitude:  126.28  2297
altitude:  126.34  2618
altitude:  126.35  2938
altitude:  126.36  3258
altitude:  126.03  3577
altitude:  126.21  3897
altitude:  126.11  4217
altitude:  126.28  4537
altitude:  126.18  4856
altitude:  126.21  5177
altitude:  126.33  5496
altitude:  126.22  5816
altitude:  126.03  6139
altitude:  126.48  6459
altitude:  126.62  6778
altitude:  126.22  7099
altitude:  126.31  7418

ogni "dati altitudine" rappresenta un'accensione del datalogger, difatti vi è un println("dati altitudine") nel SETUP.

Dimenticavo, vi si è aggiunta una problematica rispetto a quanto accaduto l'altra volta: se elimino il file manualmente dalla SD, la stessa non viene addirittura letta.

Grazie mille!

Questo è il circuito utilizzato (specifico che ho dovuto abbassare la tensione di ingresso nel bmp280 poichè la mia schedina non dovrebbe disporre di adattatore di livello).

lo sketch invece è questo (mantiene la struttura principale identica quella precedente)

// librerie gestione interfaccia SPI e SD
#include <SPI.h>
#include <SD.h>
// connessione i2c
#include <Wire.h>
// libreria sensore bpm280
#include <Adafruit_BMP280.h>

// creazione oggetto file
File file;
// creo oggetto sensore
Adafruit_BMP280 bmx;
// datalog file
constexpr char logFileName[] = "datalog.txt";

void setup() {
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  // inizial conn i2c
  Wire.begin();
  // verifico conn a bmp280
  if (!bmx.begin(0x76)) {
    digitalWrite(8, HIGH);
    while(1);
  }
  // verifico conn a SD
  if (!SD.begin(10)) {
    digitalWrite(9, HIGH);
    while(1);
  }
  // check esistenza file, in caso lo elimino
  if (SD.exists(logFileName)) {
    SD.remove(logFileName);
    delay(500);
  }
  
  //Default settings from datasheet. 
  bmx.setSampling(Adafruit_BMP280::MODE_NORMAL, Adafruit_BMP280::SAMPLING_X16);
  delay(500);
  // creo file datalog.txt
  file = SD.open(logFileName, FILE_WRITE);
  file.println("DATI ALTITUDINE");
  digitalWrite(9, HIGH);
  delay(500);
  digitalWrite(9, LOW);
  file.close();
}

// var stringa
char h[6];

void loop() {
  // converto il float altitude in *char
  dtostrf(bmx.readAltitude(1013.25), 4,2, h);
  // stampo i numeri nel file
  file = SD.open(logFileName, FILE_WRITE);
  file.print("altitude:  ");
  file.print(h);
  file.print("  ");
  file.println(millis(), DEC);
  delay(300);
  file.close();
}

Prova a stampare h con questo codice:

for (byte i=0; i<6; i++) {
        Serial.print(h[i], HEX);
        Serial.print(" ");
    }

Questo è ciò che stampa:

31 32 36 2E 32 31

Dov'è il terminatore di C string?
Non c'è, grave, noi diciamo che l'hai fatta fuori dal vaso. :smiley:

Dimensiona l'array di caratteri h in modo generoso, 126.03 conta 6 caratteri incluso il punto e manca un elemento che per essere una C string valida deve avere valore 0.

Vedi qui per gli array.

Ho dimenticato dtostrf

Da modificare in 6, 2 anziché 4,2. Ovviamente h[6+1]

Ciao.

Ti consiglierei di mettere una stampa prima della cancellazione del file

E siccome anche la remove() restituisce 1 se andata a buon fine, testala e stampa una conferma

Sospetto file system "sporco" sulla SD

Problema certamente grave, ma siccome la print termina (ci sono righe successive) non sembra influire, potrebbe essere che la variabile stringa sia allocata per ultima e non sporca nulla,
Comunque da risolvere

O forse da eliminare:

Basta evitare la ditodellastrega ... scherzo
La dtostrf()
La si può eliminare, basta passare alla print direttamente il valore numerico e il formato di stampa, per i double la print accetta il numero di cifre dopo la virgola...

Io propendo sempre per un volume "sciancato"

Riformattare la SD o farne un checkdisk sul pc forse aiuta

Comunque il problema della stringa non terminata va risolto prima di proseguire le prove,inutile cercarsi casini, hai visto mai che la stringa troppo lunga va a scrivere nel descrittore di file...

Credo poco probabile ma possibile...

Ma infatti dice:

se elimino il file manualmente dalla SD, la stessa non viene addirittura letta.

E quindi quello che dici è altamente probabile.

Se ci allega il file in questione lo possiamo aprire con un editor binario
ma tanto per passatempo. Quelle modifiche suggerite non risolveranno di certo un filesystem "scincato". Viene da chiedersi; chi lo ha sciancato?
la print(h)?? booo, tutto è possibile quando la fai fuori dal vaso.

Certo la print prima o poi uno 0 lo trova

Ciao.

Non è che la print() prima o poi uno zero lo trova

È che lo trova nel posto giusto, altrimenti vedremmo sporcizia

È nel posto giusto perché nel posto giusto lo mette subito prima la dtostrf()

È la dtostrf() che forse altera (mettendo lo zero fuori dal vaso) il descrittore di file

Ma non credo
Perché il descrittore di file è allocato staticamente, mentre la stringa è allocata dinamicamente

Comunque il pensiero ce lo caviamo in fretta
Allungando la stringa, come dici tu
Oppure eliminando la dtostrf(), come dico io

Invece un file system sciancato potrebbe avere qualunque origine

Le schede SD sono piuttosto sensibili

La libreria SD è pure piuttosto approssimata nella gestione del file system

E anche le utility di formattazione delle SD alcune combinano porcherie

Ma anche da quel lato basta poco: si cambia SD con una differente ed appena formattata...

Edit

Sono tutti e due statici, sbagliavo...

Ma la stringa è allocata "dopo" il descrittore

Quindi continuo a peansare che non possa sporcarlo

Occhio che ho appena "scoperto"

Io abito al polo sud ricordatevi, in casa non ho finestre

Dicevo che ho appena scoperto che l'attributo ReadOnly delle cartelle di windows si comporta in modo strano...
(Ovvero ne cambia la sola veste grafica in esplora risorse)

Non vorrei che la libreria SD lo interpreti invece in maniera "letterale"
Ovvero impedisce di creare o cancellare file nella directory, non impedisce di modificarli (sarebbe readonly la directory, non il file)

Anche questo da verificare su un pc con il sapiente uso di "attrib"

Buongiorno e grazie a tutti delle risposte.
Mi rendo conto che il mio errore è stato fin troppo grave: il terminatore ammetto di non averlo considerato e me ne vergogno :sweat_smile:
Non ho aggiornato il mio codice ieri sera ma ho fatto un'altra semplice prova: cambiare atmega328 (ne ho a disposizione 2), carico lo sketch e tutto funziona.
Due atmega, medesimo sketch, medesimo circuito, uno funziona l altro no (Questo trascurando il problema del terminatore che fixeró appena avrò Arduino di nuovo tra le mani).
Inoltre come posso inviarvi il binario all interno della SD?

PS: opero da linux

Edit:
Inizio a pensare che il problema possa essere un banale malfunzionamento dei pin coinvolti nella spi? Oppure vi è un qualche problema di contatto legato agli stessi? Può essere un'idea?

Grazie mille
Riccardo

Se con una MCU funziona e con l'altra no, come dici tu potrebbe esserci un problema elettrico, fai allora i dovuti controlli e facci sapere.

Con Linux puoi installare un editor esadecimale e guardarlo da solo cosa contiene. Mentre per allegarlo clicca sulla icona "upload" e scegli il file, non serve fare altro.

Ciao.

dubito prblemi elettrici
ci sono solo 4 fili di collegamento, e sono tutti dati (si, OK, 5: + gnd, clk MOSI e MISO)
se scrive significa che + GND CLK MISO e MOSI sono connessi
non avanza nulla che possa essere sconnesso....

ripeto: un chkdsk sul volume della SD
una bella formattata
mettere a posto la stringa (per prima cosa)

magari fare una cosa per volta, per vedere quale sarebbe il problema

e non mi viene in mente altro

fatto questo ci si riaggiorna

E questo succedeva col programma vecchio e senza usare stringhe corte

Siccome il led si accendeva la exist() restituiva vero

Seccome il file non spariva la remove() falliva

Senza stringhe strane

Ergo:
File system sciancato