23K256 consigli su codice

Ciao a tutti,
Sto progettando un robottino basandomi su un ATMega644P.
Il robot prende spunto dal roomba: se riuscirò a finire il progetto sarà in grado di navigare per la casa e ritornare alla base. Ho intenzione di fare questo mediante l'algoritmo A* (Implementation of A*).

Per ovviare al problema della SRAM ho pensato di inserire su un chip esterno le variabili necessarie all'algoritmo (la mappa e le liste).
La mappa viene memorizzata in una griglia, dove ogni cella ha un valore definito da un byte che indica il suo stato (base, posizione corrente, libera, occupata, etc).

Come SRAM esterna ho deciso di utilizzare il 23K256. Guardando il datasheet (http://ww1.microchip.com/downloads/en/DeviceDoc/22100F.pdf) sono riuscito a capire come farlo funzionare (pag. 7).

Quello che chiedo è: cosa ne pensate del metodo che ho utilizzato per recuperare il valore di una cella? Oltre alla funzionalità avrei bisogno di ottimizzare al meglio l'utilizzo della memoria interna del chip, pensate che sia migliorabile?
Ho sempre lavorato su progetti piccoli, questo è il piccolo progetto grande e sopratutto scritto in completa autonomia, perdonatemi se ho scritto cavolate.

P.S.
L'indirizzo del byte da leggere/scrivere è composto da 16bit, quindi ho deciso di utilizzare come indirizzo per i bit una concantenazione del valore X e Y convertiti in binario. Credo che potrebbe funzionare, ho visto che il valore massimo per l'indirizzo è 7FFF (pag. 6 del datasheet), che quindi dovrebbe corrispondere a 32767 (111111111111111), è giusto o ho interpretato male il datasheet?

Grazie in anticipo

const byte SRAMRead[8] PROGMEM  = {0,0,0,0,0,0,1,1};
const byte SRAMWrite[8] PROGMEM = {0,0,0,0,0,0,1,0};
const byte SRAMCSDelay PROGMEM  = 1;
const byte SRAMIODelay PROGMEM  = 1;


bool setMAP(byte reqX, byte reqY, bool SET) {

    //GET BYTE ADDRESS
  byte bynaryX[8];
  byte bynaryY[8];
  for(byte i = 0;i<=7; i++){
    bynaryX[i] = bitRead(reqX, i);
    bynaryY[i] = bitRead(reqY, i);
  }

  digitalWrite(SRAMSck, LOW);
  delay(5);
  shiftRegister(1, 7); //SET PIN CS ON
  delay(SRAMCSDelay);

  while(1) {

    shiftRegister(0, 7); //SET PIN CS OFF
    delay(SRAMCSDelay);
    
    //SEND WRITE BYTE
    for(byte i = 1; i <= 8; i++) {
      digitalWrite(SRAMIn, SRAMWrite[i]);
      digitalWrite(SRAMSck, HIGH);
      delay(SRAMIODelay);
      digitalWrite(SRAMSck, LOW);
      delay(SRAMIODelay);
    }

    //SEND X BYTE AS ADDRESS
    for(byte i = 0; i<=8; i++){
      digitalWrite(SRAMIn, bynaryX[i]);
      digitalWrite(SRAMSck, HIGH);
      delay(SRAMIODelay);
      digitalWrite(SRAMSck, LOW);
      delay(SRAMIODelay);
    }

    //SEND Y BYTE AS ADDRESS
    for(byte i = 0; i<=8; i++){
      digitalWrite(SRAMIn, bynaryY[i]);
      digitalWrite(SRAMSck, HIGH);
      delay(SRAMIODelay);
      digitalWrite(SRAMSck, LOW);
      delay(SRAMIODelay);
    }

    //SEND SET BYTE
    for(byte i = 0; i<=8; i++) {
      digitalWrite(SRAMIn, bitRead(SET, i));
      digitalWrite(SRAMSck, HIGH);
      delay(SRAMIODelay);
      digitalWrite(SRAMSck, LOW);
      delay(SRAMIODelay);
    }

    shiftRegister(1, 7); //SET PIN CS ON

    //READ IF CORRECTLY SET
    if(readMAP(reqX, reqY)==SET) {
      return(true);
    }
  }
 }

bool readMAP(byte reqX, byte reqY) {
  //ANCORA DA SCRIVERE
}

Non sono entrato nel dettaglio, ma 64ms per leggere o scrivere due byte nella memoria sono follia, vuol dire poter leggere o scrivere al massimo un paio di byte quindici volte al secondo. Tutti quei delay da 1ms vanno sostituiti con delayMicroseconds(1), che sono ancora tanto, la memoria lavorerebbe con segnali venti volte più veloci. A quel punto iniziano a farsi sentire le durate delle digitalWrite, 5µs ciascuna per un totale di circa 480µs, cioè circa 2000 accessi al secondo alla memoria (abbiamo migliorato di 138 volte). Ma se al posto di quelle digitalWrite si fanno delle scritture dirette sui registri delle porte, da 480µs scendiamo a meno di 20µs, tremila volte più veloci del codice originale :slight_smile:

Ciao, molto utile il consiglio del delayMicrosends(), non ci avevo pensato. Grazie mille.

Riguardo alle scritture dirette non l'ho mai fatto. Ho trovato un articolo (Arduino Reference - Arduino Reference) che parla del Port Manipulation, è quello che intendevi te?

Essendo una SRAM perdi i dati quando togli l'alimentazione.
Inoltre la SRAM che hai scelto non puó essere alimentata con 5V ma al massimo 3,6V.
Se hai bisogno che i dati non vengono persi manvando l' aliemntazione allora usa un FRAM o EEPROM.

Ciao Uwe

TimoFran:
Riguardo alle scritture dirette non l'ho mai fatto. Ho trovato un articolo (Arduino Reference - Arduino Reference) che parla del Port Manipulation, è quello che intendevi te?

Esatto, riferendosi a questa associazione pin Arduino <-> porte processore ad esempio si può:

Alzare il pin Arduino 12: [color=blue]PORTB |= 0b00010000;[/color]
Abbassare il pin Arduino 6: [color=blue]PORTD &= 0b10111111;[/color]
Invertire il pin Arduino A0: [color=blue]PORTC ^= 0b00000001;[/color]

Con la scrittura diretta se non sbaglio i conti si possono generare via software segnali con frequenza superiore ai 2MHz (diciassette volte più alta dei 120kHz che si potevano tirare fuori in assembly da uno Z80 cloccato a 4MHz :slight_smile: ). Tutto questo però rende il codice non portabile perché legato all'architettura dello specifico micro utilizzato (in questo caso il 168/328).

L'indirizzo del byte da leggere/scrivere è composto da 16bit, quindi ho deciso di utilizzare come indirizzo per i bit una concantenazione del valore X e Y convertiti in binario.

Conversione avanti e indietro attraverso due array inutile, visto che X e Y sono già valori binari.

il valore massimo per l'indirizzo è 7FFF (pag. 6 del datasheet), che quindi dovrebbe corrispondere a 32767 (111111111111111), è giusto o ho interpretato male il datasheet?

È giusto.

uwefed:
Essendo una SRAM perdi i dati quando togli l'alimentazione.
Inoltre la SRAM che hai scelto non puó essere alimentata con 5V ma al massimo 3,6V.
Se hai bisogno che i dati non vengono persi manvando l' aliemntazione allora usa un FRAM o EEPROM.

Ciao Uwe

Grazie del consiglio, non ho bisogno di che i dati rimangano anche tolta l'alimentazione. Se in futuro ne avrò bisogno li salverò su una SD per poi caricarli all'avvio oppure modificherò tutto il codice per usare una EEPROM.

Riguardo l'alimentazione, ho pensato di abbassare l'ingresso con un resistore fino ai classici 3.3V degli arduino. Questo mi potrebbe comportare qualche problema di comunicazione con il controllore?

Claudio_FF:
Esatto, riferendosi a questa associazione pin Arduino <-> porte processore ad esempio si può:

Alzare il pin Arduino 12: [color=blue]PORTB |= 0b00010000;[/color]
Abbassare il pin Arduino 6: [color=blue]PORTD &= 0b10111111;[/color]
Invertire il pin Arduino A0: [color=blue]PORTC ^= 0b00000001;[/color]

Con la scrittura diretta se non sbaglio i conti si possono generare via software segnali con frequenza superiore ai 2MHz (diciassette volte più alta dei 120kHz che si potevano tirare fuori in assembly da uno Z80 cloccato a 4MHz :slight_smile: ). Tutto questo però rende il codice non portabile perché legato all'architettura dello specifico micro utilizzato (in questo caso il 168/328).
Conversione avanti e indietro attraverso due array inutile, visto che X e Y sono già valori binari.
È giusto.

Perfetto grazie mille per l'aiuto

Un ultima domanda sperando di non andare OT.

Il CS del 23K256 lo sto controllando con uno shift register perché ho esaurito i pin del controllore. Questo può essere un problema?

Per evitare che si possa attivare durante lo shift (per quanto sia veloce) ho inserito un NE555 in modo da generare un ritardo all'accensione, potrebbe funzionare?

Lascio uno schema work in progress allegato per spiegarmi meglio.

Il CS per me potrebbe restare sempre attivo (ma non ho letto il d.sheet per esserne sicuro). Lo shift register se è con latch sulle uscite non le fa scorrere, le cambia di colpo con il fronte di latch.