Go Down

Topic: [Risolto] Gestire errore di scrittura su micro SD. (Read 495 times) previous topic - next topic

r69ts

Ciao a tutti

ho "creato" il solito datalogger con arduino nano, per rilevare temperatura e umidità uso un sensore DHT22, rtc DS1307 per data e ora e una fotoresistenza per la luminosità, i dati vengono presi e scritti su SD ogni 30 minuti senza nessun problema

mi è capitato di leggere i dati e questi si erano fermati da un paio di giorni (purtroppo il progetto non è sempre visibile)

per il momento ho installato un led rosso nel caso in cui la scrittura non vada a buon fine, nel caso in cui questo si accende devo resettare il micro, ma non mi sembra una soluzione valida

la mia domanda è:

è possibile reinizializzare la scheda SD in automatico senza dover resettare il tutto??

grazie per qualsiasi consiglio

Silente

Io mi domando un altra cosa: come mai una scrittura può non andare a buon fine? E come lo si vede?
Domando questo perché, da quel poco che uso le SD per qualche progettino, so che la scheda si inizializza una volta, in setup() e se va bene allora va bene sempre. Di conseguenza credo che se qualcosa non va bene vuol dire che c'é qualche problema hardware (la scheda che non tocca, fili staccati ecc), quibdi dubito che si possa operare da software.
Comunque credo che un modo di reinizializzare una SD esista, e che se c'é é scritto nel reference della libreria SD

r69ts

grazie per una risposta rapida.

ho riletto il reference come consigliato, ma non ho trovato nulla di utile (per quanto possa valere ho anche sbirciato all'interno dei vari file .h e .c ma non sono in grado di capirli al 100% (forse arrivo al 3%))

comunque se ti mettono a disposizione un diciamo "allarme" di mancata apertura/scrittura del file forse un modo dovrebbe esserci per riprovare, a dire il vero non ho riprovato a riscrivere dopo l'errore

ci provo e aspetto che succeda qualcosa

grazie

docdoc

Se c'è un errore hardware (dell'interfaccia e/o della scheda SD) c'è poco da cercare di inizializzare.

Se l'errore è software, allora dipende dal tipo di errore.

Può darsi che la SD abbia il filesystem danneggiato, ma anche in questo caso non puoi fare nulla se non estrarla, formattarla, e rimetterla dentro.

Oppure, la cosa più probabile forse, hai riempito lo spazio disponibile oppure hai creato un file troppo grande per il file system (es. un file da 4Gbyte). In entrambi i casi è necessario pensare a dividere i dati in più file ed una procedura di pulziia che cancelli i file più vecchi di un certo tempo quando lo spazio disponibile scende al di sotto di un minimo (es. 5%).
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

r69ts

come faccio a sapere il tipo di errore nel caso sia sw?? posso solo intercettarlo come mancata apertura o mancata scrittura del file, devo mettere altri led?? perchè altre soluzioni non mi vengono in mente

non credo sia un problema hw, in quanto una volta riavviato il tutto a distanza di giorni funziona perfettamente ovvero continua a scrivere accodando i dati sullo stesso file come da programma, il "peso" del file è di circa 50 Kb quindi nulla di che e lo spazio disponibile è di circa 1 Gb

Standardoil

Metti sorgente e schema, che ci si da un occhio
Prima legge di Nelson (che sono io):
A parità di risultato maggiore è il pensiero, minore il lavoro.
Quindi prima di fare pensa!

SukkoPera

Concordo con gli altri: se una scrittura fallisce, è per un problema "grave", che non si risolverà semplicemente con un nuovo tentativo, altrimenti avrebbe funzionato in prima istanza.

Non c'è un OS con altri processi che girano (come su un PC) e che possono lockare il file o altri problemi del genere. Ogni errore è hardware (fili staccati o SD passata a miglior vita) o "logico" (del filesystem).

Ad esempio, il mio logger GPS in condizioni normali non dà mai errori, se li dà è colpa del filesystem, di solito. Purtroppo la FAT si corrompe con una facilità estrema.

Make your Sega MegaDrive/Genesis region-free with Arduino! https://goo.gl/X7zBcq

Guida rapida a ESP8266: https://goo.gl/kzh62E

docdoc

#7
Jul 12, 2018, 11:00 am Last Edit: Jul 12, 2018, 11:02 am by docdoc
come faccio a sapere il tipo di errore nel caso sia sw?? posso solo intercettarlo come mancata apertura o mancata scrittura del file, devo mettere altri led?? perchè altre soluzioni non mi vengono in mente
Come ha detto anche Standardoil, posta il tuo codice (non uso il termine "sketch", che non esiste in nessun altro ambito di programmazione, scusami.. ;) ), una descrizione di cosa succede quando capita l'errore, lo schema dei collegamenti, altrimenti non è semplice poterti aiutare o almeno consigliare.
Ad esempio sei riuscito a capire se dà errore nella open? O nel write? O nella close? Se possibile, puoi lasciare collegato un PC con monitor seriale e scrivere info di debug con Serial.print() per capire dove e quando esattamente accade il problema?
Se invece non puoi perché magari è installato in un posto non accessibile, perché in questo caso non scrivi nella EEPROM di Arduino (così resta memorizzato anche al reset) la condizione dell'ultimo errore ad es. data ed ora ed un qualche codice per indicare dove è avvenuto?

Per iniziare però potresti intanto provare a cambiare microSD (magari è la scheda difettosa?)? E comunque facendo resettare Arduino da programma quando avviene questo evento, per capire se in questo modo si possa recuperare il blocco (seppure siano comunque da investigare le cause).
Per farlo puoi provare così, collega un pin, es. il 12, al pin RESET di Arduino e fai una cosa del genere:

Code: [Select]
#define RESETPIN 12
void setup() {  
  digitalWrite(RESETPIN, HIGH);
  pinMode(RESETPIN, OUTPUT);    
  Serial.begin(9600);
  ... qui tutto il resto
}

void loop() {
  ..
  if (condizione errore) {
    digitalWrite(RESETPIN, LOW);
  }



Penso che possa funzionare.

Ad esempio, il mio logger GPS in condizioni normali non dà mai errori, se li dà è colpa del filesystem, di solito. Purtroppo la FAT si corrompe con una facilità estrema.
Si, oppure è la microSD che è difettosa (es. magari quando si scalda?).
Ma sempre fermo restando che se vediamo il codice possiamo cercare di dare altri consigli.
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

r69ts

intanto ringrazio per tutti i consigli avuti

purtroppo lo schema non esiste (ovviamente) fatto in "ambiente" di prova e quindi definitivo, casomai allego una foto se ci riesco

non mandatemi al quel paese per come è stato scritto (non è il mio lavoro principale e sono un principiante)

di seguito il codice funzionante:

Code: [Select]

#include <Wire.h>    // libreria per lettura su seriale Wire
#include "RTClib.h"  // libreria per lettura orologio
#include <SD.h>      // libreria per uso SD
#include <DHT22.h>    // libreria per sensore temperatura e umidità

#define DHT22_PIN 9    // pin ingresso dati sensore temperatura e umidità
/*
 ** MOSI - pin 11      // pin usati per SD
 ** MISO - pin 12      // pin usati per SD
 ** CLK - pin 13      // pin usati per SD
 ** CS - pin 10        // pin usati per SD
 */

RTC_DS1307 rtc;     //inizializzazione orologio
DHT22 myDHT22(DHT22_PIN);  //inizializzazione sensore temperatura/umidità

int scrittura_ko=8;  //led per avvertire mancata scrittura su file
int luce=A0;    // pin analogico per lettura luminosità A0
int chipSelect = 10;  // cs per scrittura SD
bool scritto=false;  // flag per scrittura eseguita
bool inizio=false;  // faccio iniziare periodo in qualsiasi momento
int periodo=0;      // inizio lettura dati e scrittura su SD
char nomefile[15];  // array nome file
File myFile;        // dichiarazione file

void setup () {
  Serial.begin(9600);    // inizializzo seriale
  delay(2000);     

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  Serial.print("Initializing SD card...");
  pinMode(10, OUTPUT);      // pin cs per SD
  pinMode(8,OUTPUT);      // pin x led mancata scrittura su sd
 
  if (!SD.begin(chipSelect))
  {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");


}

void loop () {

  DateTime now = rtc.now();    //aggiorno orologio

  sprintf(nomefile,"%02d%02d.txt",now.year(),now.month());   // creo nome file da anno e mese forniti da orologio

  if (inizio==false && now.minute() <30 ){       // aggiorno periodo a qualsiasi ora metto in funzione il programma
    periodo=30;
    inizio=true;
  }
  if (inizio==false && now.minute() >30 ){       // aggiorno periodo a qualsiasi ora metto in funzione il programma
    periodo=0;
    inizio=true;
  }


  if (scritto==false && now.minute() == periodo ){      //verifico condizione per scrivere su file
    File dataFile = SD.open(nomefile , FILE_WRITE);    // apro in scrittura il file nome file creato con sprintf
    // if the file is available, write to it:              // se non esiste lo crea in automatico
    if (dataFile) {                                      // se tutto a posto

      dataFile.println(dati());                        // aggiungo al file i dati richiamati dalla funzione dati()
      dataFile.close();                            // chiudo il file
      //  Serial.println(nomefile);                    //scrivo su seriale il nome file
      Serial.println(dati());                      // scrivo su seriale i dati aggiunti
      scritto=true;                                //porto a vero la condizione scritto
      //Serial.println(scritto);
    } 

    else {
      Serial.print("errore apertura file: " );
      Serial.print(nomefile);                       
      Serial.println("  mancata scrittura dati" );
      digitalWrite(scrittura_ko, HIGH);
     

    }
  }
  if (periodo == 0 && scritto==true ){        //condizione per aumentare il periodo di 30 minuti
    periodo=30;
    scritto=false;
  }
  if (periodo==30 && scritto==true){          //condizione per aumentare il periodo di 30 minuti
    periodo=0;
    scritto=false;
  }


  if (Serial.read()=='a'){          // comando letto su seriale per aprire in lettura il file creato
    myFile = SD.open(nomefile);   
    if (myFile) {
      Serial.println();

      // read from the file until there's nothing else in it:
      while (myFile.available()) {    //condizione per leggere tutto il contenuto del file
        Serial.write(myFile.read());  // scrivo su monitor seriale il contenuto del file
      }
      myFile.close();        // chiudo il file
    }
    else {
      Serial.print("errore apertura file: " );
      Serial.println(nomefile);
    }
  }
}

String dati() {              // funzione per raccogliere dati da scrivere su file

  myDHT22.readData();         //aggiorno dati temperatura e umidità
  DateTime now = rtc.now();  // aggiorno orologio

  int x = map(analogRead(luce),0,1024,100,0);  //aggiorno e scalo valore luminosità
  char buf[60];              // inizializzo array dati da scrivere

  sprintf(buf,"%02d/%02d/%02d; %02d:%02d ; %d; %hi.%01hi; %i.%01i",now.year(),now.month(),now.day(),
  now.hour(),now.minute(),x,myDHT22.getTemperatureCInt()/10, abs(myDHT22.getTemperatureCInt()%10),
  myDHT22.getHumidityInt()/10, myDHT22.getHumidityInt()%10);           // formatto i dati da scrivere e li inserisco in buf

  /* Serial.println("scritto da funzione");
   Serial.println(buf);   
   */
  return buf; 
}


fabpolli

Per farlo puoi provare così, collega un pin, es. il 12, al pin RESET di Arduino e fai una cosa del genere:
...omissis...
Penso che possa funzionare.

Non è una buona pratica secondo Atmel
Quote
You should not try to use another pin of the AVR to pull the external RESET line. The pins of the AVR are tristated halfway through the minimum reset time, this releases the RESET line and hence nothing happens.
Mi pare di ricordare che sul sito di Atmel consigliavano l'uso del watchdog per resettare, prima però sarebbe meglio tentare di capire se l'errore è software e porvi rimedio, il softreset deve essere l'ultima spiaggia, lo dico soprattutto per l'OP che è inesperto (a detta sua) che potrebbe essere tentato dal lato oscuro della programmazione :)
Comunque in un mio progetto ho inserito il reset via watchdog per resettare da remoto casomai mi servisse reinizializzare il tutto e il metodo funziona, anche se in fase operativa non mi è mai servito  :)

Standardoil

Complimenti, ben indentato, ha la sua importanza
Unico vero bacherozzo che vedo è l'uso degli oggetti stringa, io farei lo sforzo di sostituirli con stringhe di C
Quindi a te rimane acceso il led, che significa mancata apertura file...
Una formattata alla sd, possibilmente cambiarla, ma magari trovare la maniera di vedere la variabile nomefile non sarebbe male
Hai visto mai che ci rimane dentro un bacherozzo...
Prima legge di Nelson (che sono io):
A parità di risultato maggiore è il pensiero, minore il lavoro.
Quindi prima di fare pensa!

gpb01

#11
Jul 12, 2018, 11:50 am Last Edit: Jul 12, 2018, 11:50 am by gpb01
... Per farlo puoi provare così, collega un pin, es. il 12, al pin RESET di Arduino e fai una cosa del genere:
Come ha già detto "fabpolli" è assolutamnete da NON fare e contrario a tutte le specifiche di Atmel.

Basta fare un po' di ricerche su questo forum per trovare discussioni in cui, con Astrobeed, se ne è ampiamente parlato e sono state date tutte le spiegazioni (... che coinvolgono i "tempi" del reset).

In ogni caso ... come detto mille volte ... a voi v'ha rovinato Windows ed il suo CTRL-ALT-DEL  :smiley-twist:  !!!   I problemi si risolvono, NON si fanno certe schifezze !!!

Guglielmo
Search is Your friend ... or I am Your enemy !

Standardoil

Però c'è un problema:
Tu non spegni mai il led, quindi non sappiamo se dopo una prima scrittura cliccata ne sono invece avvenute di buone oppure se il programma si è impiantato o cosa...
Hai il Pc sempre connesso?
Prima legge di Nelson (che sono io):
A parità di risultato maggiore è il pensiero, minore il lavoro.
Quindi prima di fare pensa!

r69ts

grazie a tutti

per quanto riguarda il reset automaizzato andrò in cerca di informazioni al riguardo anche se la soluzione di docdoc non mi dispiaceva affatto.

il bacherozzo non riesco a capirlo, mi sembra di passare tutto su array "riempiti" tramite sprintf (uso di oggetti stringa?? perdona la mia ignoranza)
stringhe di C?? lavorare con array di char?? ogni consiglio è benvenuto al riguardo (forse ho un po di casino in mente)

purtroppo come docdoc ipotizzava il progetto vive lontano dal pc, quindi quando il led è acceso vuol dire che si è piantata la scrittura e quindi devo premere il reset di arduino

Standardoil

E quindi Debug difficile
Usi una Uno?
Prima legge di Nelson (che sono io):
A parità di risultato maggiore è il pensiero, minore il lavoro.
Quindi prima di fare pensa!

Go Up