Serial1.available() dopo un po' satura. problema.

salve a tutti, come ho detto in un altro post sto lavorando con Arduino su cui è connessa una IMU da cui vengono prelevati i dati che poi vengono inviati tramite xbee ad un PC.
Funziona tutto alla perfezione ma dopo un po’ di tempo che lo xBee invia i frame l’Arduino non riesce più a lavorare i dati che riceve dalla porta seriale Serial1. Premetto che i dati in input arrivano ad un baudrate di 57600 mentre lo xbee invia a 9600. Quale può essere il problema?? Potrei postarvi il codice così magari qualcuno mi può dare una mano. Il tempo di blocco della comunicazione è randomico e se riavvio l’Arduino riprende normalmente.
Grazieee

Parlare di saturazione farebbe capire che si satura uno dei buffer. Per caso uno dei led RX/TX sull'Arduino resta fisso acceso?

Ho supposto io che saturi. Devo inviare i dati il più velocemente possibile quindi i delay() sono praticamente nulli, Resta Acceso TX quando trasmetto, dopo si spegne. Quando la comunicazione si blocca (lo vedo dal pc perchè non riceve le trame) se accendo il Serial-Monitor riprende per un po' e il led 'L' lampeggia due volte (si resetta). Può essere la differenza di velocità RX/TX?? Non posso modificarla.

Hai provato a debuggare il codice (infilando un po' di print di controllo) per vedere dove si blocca?

Cmq una considerazione, quando apri una comunicazione seriale, apri sia il canale di ricezione che quello di trasmissione, quindi sia RX che TX lavorano con la stessa chiamata ed alla stessa velocità. Se devi aprire 2 canali diversi, apri il secondo usando la libreria NewSoftSerial, usando 2 pin differenti da D0 e D1.

Ho arduino Mega 2560 con 4 serial ... ricevo i dati della IMU su Serial1 e li invio tramite xBee connesso a Serial con lo shield ... Sembra sia tutto OK ho provato pure con il Serial1.flush() ma niente. Io ricevo le trame dalla IMU ma dopo un po' i valori che stampo sono tutti uguali cioè sempre il preamble della trama e anche il secondo valore BID.

leo72:
Hai provato a debuggare il codice (infilando un po’ di print di controllo) per vedere dove si blocca?

No, l'unica cosa che ho fatto è stampare i dati che vengono memorizzati nel buffer. Come posso fare?

Ogni tot righe metti un serial.println stampando un dato a caso, tipo un numero progressivo. così quando il programma si ferma guardi l'ultimo n° arrivato e risali al punto del codice ;)

Grazie gli aiuti cmq ... il problema è che il codice continua a girare ma la trama che viene lavorata non è effettivamente quella che la IMU invia quindi non invia niente (faccio inviare la trama solo se è giusta dopo i check dei campi). in pratica la trama è del tipo fa ff 32 12 ... ... ... ma dopo un po' che viene inviata correttamente quello che l'Arduino lavora sono dei byte del tipo fa ff fa fa quindi non invia niente. i byte della trama li memorizzo in un buffer e qualora la trama è sbagliata l'indice riparte da zero, riparte da zero anche dopo l'invio corretto.

Non è che forse saturi il buffer?

Puoi postare il codice, magari è un errore di logica?

Ho pensato lo stesso…
Ecco il codice

#include <avr/wdt.h>
#include <XBee.h>


//////////XBEE DECLARATION/////////
XBee xbee = XBee(); //create the xbee object
uint8_t payloadTest[24];// = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //this is the payload that xbee will send, after rewritten. This will contain all the IMU'S frame
XBeeAddress64 addr64 = XBeeAddress64(0x00000000,    0x00000000);// SH + SL Address of receiving XBee. All zeros means broadcast message
ZBTxRequest zbTx = ZBTxRequest(addr64, payloadTest, sizeof(payloadTest)); //this is the method to send data through xBee
ZBTxStatusResponse txStatus = ZBTxStatusResponse(); //this return the response of the receive
//////////////////////////////////

//////////IMU DECLARATION/////////
//frame values
#define PREAMBLE 0xFA //this is the frame's start byte
#define BID 0xFF //bus identifier. follows PREAMBLE and is always 0xFF
#define DATAMSG 0x32 //this byte indicates the kind of the frame, if it's 0x32 (50 in DEC) means DATA MESSAGE



char buff[128]; //this array will contain the bytes read from serial port of the IMU
int buffpos; //buffer index
int pktlen; //data packet length
//////////////////////////////////


int sent;


void setup() {
  
  xbee.begin(9600);
  Serial1.begin(57600);//Hardware serial on Arduino, here will be connected the IMU (pin 18, 19) the baudrate of the IMU is set at 57600
 }



void loop()
{   
   
    readValueOnSerial();
   if(!sent){
    xbee.send(zbTx);
   }
    sent = 1;
   
    
}

/////////IMU /////////



//this method reads the bytes that arrive at the Serial1 port, from the Imu, and if detects the frame will elaborate it calling the setXbeeFrame() function 
void readValueOnSerial(){
  
  if(Serial1.available()){
  
  unsigned char letto = Serial1.read();
    
      buff[buffpos]=letto;
    
        
			 if(buffpos==0) {
				 if(letto==0xFA) buffpos++;           
			 } else if(buffpos==1) {
				 if(letto==0xFF) buffpos++; else buffpos=0;
			 } else if(buffpos==2) {
                             if (letto==50) buffpos++; else buffpos=0;
			 } else if(buffpos==3) {
				 pktlen=(int)letto; buffpos++;
			 } else if(buffpos<pktlen+4) {
				 buffpos++;
			 } else {
  
				 buffpos++;
				 setXbeeFrame(buff, pktlen);
				 buffpos=0;
                          }

    
    }
    
    //delay(10);
    

}

//setXbeeFrame puts the all the IMU's array into the payload of the xbee
void setXbeeFrame(char *buff,int len){
  
  int i;
  
  for (i=0; i<len+4; i++){
  
    payloadTest[i] = buff[i];
   
     
  }
  
  sent = 0;
   
  delay(5);
  
}

Non ho analizzato tutto però ho capito una cosa, correggimi se sbaglio. I dati arrivano all'Arduino dall'IMU a 57600 e vengono salvati in un buffer di 128 byte. Da qui li prelevi e li spedisci tramite Xbee a 9600.

A logica non ci siamo. Ricevi più velocemente di quanto spedisci, secondo me si riempie il buffer.

Quello è il minimo a cui posso ricevere e il massimo a cui posso inviare... se si perdono dei dati non importa l'importante è che non si blocchi tutto...

Allora vai di debug. Io non posso aiutarti perché non possiedo né l'uno né l'altro accessorio. Serial1.println("1"); (...) Serial1.println("2"); (...) ecc... ;)

OK, appena posso ci provo e poi posto pure la soluzione. Quello che avevo pensato, se possibile, era inserire una parte di codice che fa il reboot automatico dopo un tot di tempo in cui non viene inviata alcuna trama tramite xbee dato che facendolo si risolve tutto... ho cercato in giro e ho trovato un comando del tipo asm volatile (" jmp 0"); potrebbe andare bene??

Non è un vero reset, fai solo ripartire l'esecuzione dalla prima locazione di memoria. Non azzeri registri, variabili, puntatori ecc...

Il discorso dell'autoreset è stato affrontato diverse volte e con il solo Arduino la conclusione a cui si è giunti è che non si può fare: ci vuole qualche circuito esterno che tenga il pin di reset dell'Arduino a LOW per un numero sufficiente di cicli di sistema.

sckah: Premetto che i dati in input arrivano ad un baudrate di 57600 mentre lo xbee invia a 9600. Quale può essere il problema??

Mi pare abbastanza ovvio che se ricevi dei dati sei volte più velocemente di come li trasmetti puoi pure avere un buffer di 1 megabyte, ma alla lunga si riempie sempre e vai in buffer overun. Le soluzioni possibili sono due, la prima è settare gli Xbee a 57600, e non capisco perché dici di non poterlo fare, la seconda è azzerare forzatamente il buffer di ricezione non appena è pieno, cioè nella funzione di acquisizione dati dalla seriale devi controllare se il puntatore arriva oltre 128 e in questo azzeri sia il puntatore che il buffer stesso scrivendoci dentro 0x00, o altro valore a tua scelta, tramite un for.

leo72: Non è un vero reset, fai solo ripartire l'esecuzione dalla prima locazione di memoria. Non azzeri registri, variabili, puntatori ecc...

Se fai un jump alla locazione 0 è un soft reset a tutti gli effetti, ovvero tutte le variabili vengono rilasciate e ricreate reinizializzandole ai valori di default previsti dal programma, tutti i puntatori vengono distrutti, lo stack e l'heap vengono azzerati e reinizializzati etc. L'unica cosa che non torna ai valori di default come con un reset hardware sono i valori dei registri macchina per le periferiche, ma in tutti i casi vengono reinizializzati come serve dal tuo programma quindi non fa alcuna differenza. Il jump alla locazione 0 è una tecnica universalmente utilizzata su tutti i micro per ottenere il reset da software, p.e. per attivare il bootloader quando si riceve uno specifico comando.

astrobeed:

sckah: Premetto che i dati in input arrivano ad un baudrate di 57600 mentre lo xbee invia a 9600. Quale può essere il problema??

Mi pare abbastanza ovvio che se ricevi dei dati sei volte più velocemente di come li trasmetti puoi pure avere un buffer di 1 megabyte, ma alla lunga si riempie sempre e vai in buffer overun. Le soluzioni possibili sono due, la prima è settare gli Xbee a 57600, e non capisco perché dici di non poterlo fare, la seconda è azzerare forzatamente il buffer di ricezione non appena è pieno, cioè nella funzione di acquisizione dati dalla seriale devi controllare se il puntatore arriva oltre 128 e in questo azzeri sia il puntatore che il buffer stesso scrivendoci dentro 0x00, o altro valore a tua scelta, tramite un for.

Si in effetti basta X-CTU e non è nemmeno difficile da fare...

astrobeed: Se fai un jump alla locazione 0 è un soft reset a tutti gli effetti, ovvero tutte le variabili vengono rilasciate e ricreate reinizializzandole ai valori di default previsti dal programma, tutti i puntatori vengono distrutti, lo stack e l'heap vengono azzerati e reinizializzati etc. L'unica cosa che non torna ai valori di default come con un reset hardware sono i valori dei registri macchina per le periferiche, ma in tutti i casi vengono reinizializzati come serve dal tuo programma quindi non fa alcuna differenza. Il jump alla locazione 0 è una tecnica universalmente utilizzata su tutti i micro per ottenere il reset da software, p.e. per attivare il bootloader quando si riceve uno specifico comando.

Prof, immagino che questo sia un 4 in tecnologia dei micro :fearful: