Si può aggirare il limte di 32 byte del buffer I2C ?

Salve atutti,
sto cercando di scrivere una struct con piu di 32 byte(40 = 10 float) su una eeprom esterna

#define disk 0x57     //24xx32 eeprom
#include <Wire.h>

 struct Val{
  float val1 = 25;
  float val2 = 25 ;
  float val3= 25;
  float val4= 25;
  float val5= 25 ;
  float val6= 25;
  float val7 =8.30;
  float val8 =12.30;
  float val9  =123.235;
  float val10 = 60; 
  } valori;


   union Scomp{        // scompongo  byte
  struct Val;
  byte *valb = ((byte*)&valori) ;
               } Diviso;

void setup() {

Serial.begin(115200);
Wire.begin();

}

void loop() {

int address = 0;

Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    for (int i =0; i< sizeof(valori); i++){
        Wire.write(Diviso.valb[i]) ;
      }
    Wire.endTransmission ();
      
    delay (600);

    Serial.println(sizeof valori);
    Serial.println(valori.val1);
    Serial.println(valori.val2);
    Serial.println(valori.val3);
    Serial.println(valori.val4);
    Serial.println(valori.val5);
    Serial.println(valori.val6);
    Serial.println(valori.val7);
    Serial.println(valori.val8);
    Serial.println(valori.val9);
    Serial.println(valori.val10);
  



 delay(10000);

}

la scrittura (sembra) che vada a buon fine ma quando leggo con :

#define disk 0x57     //24xx32 eeprom
#include <Wire.h>

 struct Val{
  float val1;
  float val2;
  float val3;
  float val4;
  float val5;
  float val6;
  float val7;
  float val8;
  float val9;
  float val10; 
  } valori;


   union Scomp{        // scompongo  byte
  struct Val;
  byte *valb = ((byte*)&valori) ;
               } Diviso;

void setup() {

Serial.begin(115200);
Wire.begin();

}

void loop() {

Serial.println("____VALORI INIZIALI");
    Serial.println(sizeof valori);
    Serial.println(valori.val1);
    Serial.println(valori.val2);
    Serial.println(valori.val3);
    Serial.println(valori.val4);
    Serial.println(valori.val5);
    Serial.println(valori.val6);
    Serial.println(valori.val7);
    Serial.println(valori.val8);
    Serial.println(valori.val9);
    Serial.println(valori.val10);
  



 delay(10000);
int address = 0;
Serial.println("LEGGO EEPROM");
Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    Wire.requestFrom(disk, sizeof(valori));
    for (int i =0; i< sizeof(valori); i++){
       Diviso.valb[i] = Wire.read();        }
    Wire.endTransmission ();
      
    

    Serial.println(sizeof valori);
    Serial.println(valori.val1);
    Serial.println(valori.val2);
    Serial.println(valori.val3);
    Serial.println(valori.val4);
    Serial.println(valori.val5);
    Serial.println(valori.val6);
    Serial.println(valori.val7);
    Serial.println(valori.val8);
    Serial.println(valori.val9);
    Serial.println(valori.val10);
  

Serial.println("FATTO");


 delay(10000);

}

dalla seriale nn vedo gli ultimi 3 valori(val8-10)… presumibilmente x via del buffer interno del bus i2c che è settato a 32 byte di default…
posso aggirare tale limite ?

Devi mandargli i dati per quello che riesce a digerire, se il buffer è di X devi mandargli blocchi di X e aspettare che li digerisca prima di procedere con il successivo blocco.
Guarda il metodo flush()
"flush() clears the buffer once all outgoing characters have been sent."

maubarzi:
Devi mandargli i dati per quello che riesce a digerire, se il buffer è di X devi mandargli blocchi di X e aspettare che li digerisca prima di procedere con il successivo blocco.
Guarda il metodo flush()
“flush() clears the buffer once all outgoing characters have been sent.”

temo di nn capirne l’uso… dovrebbe essere tipo…

Serial.println("LEGGO EEPROM");
Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    Wire.requestFrom(disk, 30);
    for (int i =0; i< 30; i++){
       Diviso.valb[i] = Wire.read();
       Wire.flush();
       }
    Wire.requestFrom(disk, 10); 
      for (int i=30; i< 40; i++){
       Diviso.valb[i] = Wire.read();
       }
    Wire.endTransmission ();

ho provato ancora… ma stesso risultato ( output da seriale in allegato)

 uint16_t address;
  uint16_t address2 = address +(byte)28;
Serial.println("LEGGO EEPROM");

  

          Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    Wire.requestFrom(disk, 40,0 );
    for (int i =0; i< 28; i++){
       Diviso.valb[i] = Wire.read();  
      }
      
      Wire.flush();
     for (int i =28; i< 40; i++){
       Diviso.valb[i] = Wire.read();  
      }
    Wire.endTransmission ();  
      
 /* Wire.beginTransmission ( disk);                     //questa è un'altra prova; due singole 'chiamate' 
    Wire.write((byte)(address2 >> 8));        //        con risultati disastrosi.. scriveva sulla eprom
    Wire.write((byte)(address2  & 0xFF));       
    Wire.requestFrom(disk, 12 );
    for (int i =28; i< 40; i++){
       Diviso.valb[i] = Wire.read();  
      }
      delay(2000);
      Wire.flush();
    Wire.endTransmission ();  */
   
    
      
    delay (2000);

     Serial.print ("dimensione struct ");
    Serial.println(sizeof valori);
    Serial.println(valori.val1);
    Serial.println(valori.val2);
    Serial.println(valori.val3);
    Serial.println(valori.val4);
    Serial.println(valori.val5);
    Serial.println(valori.val6);
    Serial.println(valori.val7);
    Serial.println(valori.val8);
    Serial.println(valori.val9);
    Serial.println(valori.val10);
  

Serial.println("FATTO");


 delay(10000);

di fatto solo gli ultimi tre float non vengono letti/scritti
dove sbaglio?

Cattura.JPG

Io intendevo in scrittura, se il buffer è limitato devi evitare di mandarlo in overflow e quindi dare tempo al buffer di svuotarsi prima di scrivere tutti i dati.
Scivi il primo pezzo, aspetti, scrivi il secondo pezzo, ecc. fino alla fine dell'intero dato.

Sei sicuro che la scrittura sia andata veramente a buon fine?
Cioè che abbia scritto tutto giusto e non che non sia semplicemente andata in errore?

:confused: sicuro ? tutt’altro…

codice in scrittura :

void loop() {

 uint16_t  address = 0;

Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    for (int i =0; i< 28; i++){
        Wire.write(Diviso.valb[i]) ;
      }
      Wire.flush();
      delay(500);
      for (int i =28; i< 40; i++){
       Wire.write(Diviso.valb[i])  ;
      }
    Wire.endTransmission ();
      
    delay (600);

Premetto che io non sono un esperto di C, per cui sto andando puramente a buon senso.
Se ci sono esperti in ascolto sicuramente correggeranno i miei strafalcioni come spesso accade.

Detto questo, la prima ipotesi è che il for con la Wire.write scriva senza dare il tempo al dispositivo di digerire il tutto, quindi, primo tentativo giusto per vedere se la mia intuizione è quella buona, sbatti il Wire.flush() dentro il for dopo ogni write.

Così dovremmo scrivere un byte alla volta aspettando che sia digerito prima di proseguire con il successivo.
Se così funziona poi possiamo passare ad ottimizzare meglio le cose scrivendo a blocchi da 32 byte sfruttando la capienza del buffer.

In attesa di suggerimenti da più esperti possiamo provare così.

Ovviamente questo funziona se la parte che legge è corretta e il problema è in scrittura altrimenti non lo riesci a verificare.

L'alternativa è partire ancora da più indietro, fare cioè un codice che scriva pochi byte (diciamo 32) e poi li legga con successo, senza quindi sforare il buffer.
Poi, fatto questo, fare due scritture contigue (quindi 32+32) con lo stesso metodo per raddoppiare i byte scritti correttamente e provare a leggerli con un'unica operazione dando il tempo giusto a gestire correttamente il buffer in lettura.
Ultimo passo provare a scrivere 32+32 in botta unica dando anche qui il tempo al buffer di essere usato correttamente.
3 Step incrementali per testare un pezzo per volta tutto il giro.

Il linguaggio C non mi pare c'entri nulla.

Non sono esperto di I2C, ma
Qui: Arduino - Wire
In grassetto dice che la libreria è implementata con 32 byte di buffer.

Qui: Arduino - WireEndTransmission
Viene detto che la write accoda nel buffer e solo la endTransmission() spedisce.

Qui una vecchia discussione in inglese, dice come modificare la lib

occhio che è del 2011, spero sia attuale.

Si, certo, io normalmente lavoro in java e non si usano molti buffer perchè si lavora ad un più alto livello, il C si usa tipicamente per comunicare a più basso livello con le periferiche e li i buffer sono il pane quotidiano. Era inteso in questo senso.

Dal link che hai postato dice che non si deve eccedere il buffer in una unica trasmissione, quindi dati di lunghezza maggiore vanno spezzati in comunicazioni separate mi sa.
Pensavo avesse implementato un sistema di svuotamento del buffer durante la trasmissione.
Fino ad ora non ho mai approfondito questo argomento.
Se è così allora bisogna dividere le info in blocchi da 32 byte e fare per ogni blocco beginTransmission() ed endTransmission()?
Appena ho un attimo mi studio bene la libreria.

Edit:
Mi sa di si perchè dice che è la endTransmission che fa la trasmissione del buffer riempito dalla write:
"Ends a transmission to a slave device that was begun by beginTransmission() and transmits the bytes that were queued by write()."

Quindi dividere i dati in blocchi da 32 byte e per ognuno fare

beginTransmission
loop che scrive con write i 32 byte
entTransmission

e poi si ricomincia per il successivo blocco da 32 o meno se il residuo è inferiore.

nid69ita:
Il linguaggio C non mi pare c'entri nulla.

Non sono esperto di I2C, ma
Qui: Arduino - Wire
In grassetto dice che la libreria è implementata con 32 byte di buffer.

Qui: Arduino - WireEndTransmission
Viene detto che la write accoda nel buffer e solo la endTransmission() spedisce.

Qui una vecchia discussione in inglese, dice come modificare la lib
Increase 32 byte I2C buffer size in Wire library - Networking, Protocols, and Devices - Arduino Forum
occhio che è del 2011, spero sia attuale.

si avevo letto di come portare il buffer a 64 byte, ma preferisco evitare perche quel metodo succhia parecchia ram che su questi micro e preziosissima..

@maubarzi:

nemmeno io sono esperto di C: ma "two is megl' che one" xD( anzi in questo caso in tre...)

altro dato... è vero che il buffer I2C è da 32, ma riesco a leggere correttamente solo i primi 7 float( 4 x 7= 28 byte).
è ragionevole pensare che riesca a scrivere anche solo i primi 7 float;

la prima ipotesi è che il for con la Wire.write scriva senza dare il tempo al dispositivo di digerire il tutto

lo penso anche io: in effetti ha bisogno di un paio di cicli per inserire correttamente i dati letti nella struct... al primo ciclo restituisce "nan" su tutte le voci; dal secondo ciclo restituisce i dati corretti nei primi 7 float

mi sa che dividerò la struct in due da 20 byte e aggirare il problema(soluzione piu semplice, ma con meno soddisfazione :frowning: )

mixmax122:
mi sa che dividerò la struct in due da 20 byte e aggirare il problema(soluzione piu semplice, ma con meno soddisfazione :frowning: )

Non è aggirare il problema ma farlo nel modo giusto.

E’ come se con un bicchiere da 10cc vuoi spostarne 15, devi fare due giri per forza.

I buffer possono essere utilizzati in tanti modi, ma da quello che ho letto, quello I2C lo riempi, trasmetti e viene svuotato al termine della trasmissione, quindi devi fare più trasmissioni per forza.

EUREKAAAAAAAA !!!

scrivo la soluzione x chi venisse “dopo”
Scrittura:

#define disk 0x57     //24xx32 eeprom
#include <Wire.h>

 struct Val{
  float val1 = 25.12;
  float val2 = 20 ;
  float val3= 30;
  float val4= 40;
  float val5= 50 ;
  float val6= 60;
  float val7 =7.40;
  float val8 =8.30;
  float val9  =9.9;
  float val10 = 10.0; 
  } valori;


   union Scomp{        // scompongo  byte
  struct Val;
  byte *valb = ((byte*)&valori) ;
               } Diviso;

void setup() {

Serial.begin(115200);
Wire.begin();

}

void loop() {

 int  address = 0;

Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    
    for (int i =0; i< 32; i++){
        
        Wire.write(Diviso.valb[i]) ;
        
      }
   
    Wire.endTransmission ();
      
    delay (600);
    address += 32; 
    Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    for (int i =32; i< 40; i++){
      Wire.requestFrom(disk, 1);
      
      Wire.write(Diviso.valb[i]) ;
          
      } 
      Wire.endTransmission ();


    Serial.print ("dimensione struct ");
    Serial.println(sizeof valori);
    Serial.println(valori.val1);
    Serial.println(valori.val2);
    Serial.println(valori.val3);
    Serial.println(valori.val4);
    Serial.println(valori.val5);
    Serial.println(valori.val6);
    Serial.println(valori.val7);
    Serial.println(valori.val8);
    Serial.println(valori.val9);
    Serial.println(valori.val10);
  



 delay(10000);

}

Lettura

#define disk 0x57     //24xx32 eeprom
#include <Wire.h>

 struct Val{
  float val1;
  float val2;
  float val3;
  float val4;
  float val5;
  float val6;
  float val7;
  float val8;
  float val9;
  float val10; 
  } valori;


   union Scomp{        // scompongo  byte
  struct Val;
  byte *valb = ((byte*)&valori) ;
               } Diviso;

void setup() {

Serial.begin(115200);
Wire.begin();
Serial.println("____VALORI INIZIALI");
     Serial.print ("dimensione struct ");
    Serial.println(sizeof valori);
    Serial.println(valori.val1);
    Serial.println(valori.val2);
    Serial.println(valori.val3);
    Serial.println(valori.val4);
    Serial.println(valori.val5);
    Serial.println(valori.val6);
    Serial.println(valori.val7);
    Serial.println(valori.val8);
    Serial.println(valori.val9);
    Serial.println(valori.val10);
  



 delay(5000);
}

void loop() {


int  address = 0;
 
Serial.println("LEGGO EEPROM");
//while (Wire.available()){
  

        Wire.beginTransmission ( disk);  
   /**/ Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
   // Wire.requestFrom(disk, 32);
    for (int i =0; i< 32; i++){
      Wire.requestFrom(disk, 1);
      
       Diviso.valb[i] = Wire.read();
          
      }
     
      delay(2000);
      
   Wire.endTransmission ();
   address += 32; 
    Wire.beginTransmission ( disk);
    Wire.write((byte)(address >> 8));       
    Wire.write((byte)(address  & 0xFF));
    for (int i =32; i< 40; i++){
      Wire.requestFrom(disk, 1);
      
       Diviso.valb[i] = Wire.read();
          
      } 
      Wire.endTransmission ();
 /*   Wire.requestFrom(disk, 12);
     
     for (int i =28; i< 40; i++){
      Diviso.valb[i] = Wire.read();
          
      }
      
    Wire.endTransmission ();  
      
 /* Wire.beginTransmission ( disk);
    Wire.write((byte)(address2 >> 8));       
    Wire.write((byte)(address2  & 0xFF)); 
    Wire.requestFrom(disk, 12 );
    for (int i =28; i< 40; i++){
       Diviso.valb[i] = Wire.read();  
      }
      delay(2000);
      Wire.flush();
    Wire.endTransmission ();  */
   
    
      
    delay (2000);

     Serial.print ("dimensione struct ");
    Serial.println(sizeof valori);
    Serial.println(valori.val1);
    Serial.println(valori.val2);
    Serial.println(valori.val3);
    Serial.println(valori.val4);
    Serial.println(valori.val5);
    Serial.println(valori.val6);
    Serial.println(valori.val7);
    Serial.println(valori.val8);
    Serial.println(valori.val9);
    Serial.println(valori.val10);
  

Serial.println("FATTO");


 delay(10000);

}

un sentito ringraziamento al forum - tutto - e in particolare a :
-maubarzi x l’attiva partecipazione
-nid69ita e il suggerimento
in effetti leggendo meglio(il mio inglese fa pena…) il post di nick gammon suggeriva lui stesso la soluzione

for (int x = 0; x < 194; x++)
    {
    Wire.beginTransmission (ADDRESS);
    Wire.send (x);
    Wire.endTransmission ();
    }

ovvero mandare un byte alla volta…

Puoi mandarne 32 alla volta, quello di mandarne uno alla volta lo avevo suggerito anche io ma più come test, la capacità massima la puoi sfruttare mandandone 32 alla volta.
Comunque se l'inefficienza non è un problema anche mandarne uno alla volta va bene solo un pizzico più lento.

ciao

:confused: :confused: :confused: :confused: :confused:

sono un po perplesso

il codice non funziona :o