Neuer i2c-eeprom-Treiber (beta) Kategorie: I²C-Bus (von Rolf - 4.08.2003 18:24) | |
| |
Hallo, wie evtl. einige mitbekommen haben, haben André und ich sehr kontroverse Ansichten zu dem EEPROM-Treiber wie er hier in der Site angeboten wird und ich konnte meine Ideen nicht einbringen. Ich habe darauf hin beschlossen, einen alternativen EEPROM-Treiber zu schreiben. Der Treiber ist vorläufig erst mal nur beta und nicht für eigene Programme geeignet. Ich hab mir auch noch keine Gedanken gemacht, in wie weit er universell und mit anderen Typen als dem 24c512 einsetzbar gemacht werden kann. Ich stelle den Treiber hier nun zur Ansicht bzw. zur Diskusion. Da er aber noch Macken hat, wird das noch nicht die endgültige Version sein. Also bitte noch nicht verwenden! Wenn euch Fehler auffallen oder Ihr Vorschläge habt, meldet euch. /******************************************************************/ /* Treiberbibliothek für eine EEPROM Disk mit 1-4 24C512 */ /* Nur für den privaten Gebrauch, jegliche Haftung ausgeschlossen */ /* */ /* Autor : (c) by Rolf Diesing rolf(at)diesing.net */ /* Version : 0.45 */ /* Datum : 4. August 2003 */ /* Getestet : ja, mit BsafEE 1.1 (liegt dem Treiber bei) */ /* Benötigt : i2c.c2 ab V1.1 und mem.c2 */ /******************************************************************/ /* History: */ /* 22.7.03 1.Fassung, erste Laufzeit Tests, Konzeptprüfung */ /* 24.7.03 2.Fassung, Optimierungen, nun ca. doppelt so schnell */ /* 25.7.03 setEEaddr und getEEaddr hinzugefügt, Verify eingebaut */ /* 29.7.03 CRC-Management, Flags, DoError */ /* 1.8.03 Umbau Basis und erweiterte Funktion, Floatfunktionen */ /* 2.8.03 Cleanup, Docu, Test, Verify überarbeitet */ /* 4.8.03 komplette �berarbeitung */ /******************************************************************/ /* Funktionsliste des Moduls //MISC function init() function setaddr(long addr,t_EE_addr t) returns long function oldaddr(long addr,t_EE_addr t) returns long function cpyaddr(t_EE_addr t1,t_EE_addr t2) returns long function DoError(t_EE_addr t) function verifybytearray (t_EE_addr t, byte data[], int len,byte f) //LESEN function readbyte (t_EE_addr t,byte f) returns byte function readint (t_EE_addr t,byte f) returns int function readlong (t_EE_addr t,byte f) returns long function readfloat (t_EE_addr t,byte f) returns float function readbytearray (t_EE_addr t, byte data[], int len,byte f) function readintarray (t_EE_addr t, int data[], int len,byte f) function readlongarray (t_EE_addr t, long data[], int len,byte f) function readfloatarray (t_EE_addr t, float data[], int len,byte f) function readstr (t_EE_addr t, byte s[],byte f) //SCHREIBEN function writebyte (t_EE_addr t, byte data,byte f) function writeint (t_EE_addr t, int data,byte f) function writelong (t_EE_addr t, long data,byte f) function writefloat (t_EE_addr t, float data,byte f) function writebytearray (t_EE_addr t, byte data[], int len,byte f) function writeintarray (t_EE_addr t, int data[], int len,byte f) function writelongarray (t_EE_addr t, long data[], int len,byte f) function writefloatarray (t_EE_addr t, float data[], int len,byte f) function writestr (t_EE_addr t, byte s[],byte f) //DEMO function readmytype (t_EE_addr t, mytype abc,byte f) function writemytype (t_EE_addr t, mytype abc,byte f) */ /******************************************************************/ /* Kurze Einführung: Die Funktionsweise des Treibers sollte gelesen und verstanden sein, wenn man den Treiber oder Teile daraus verwenden möchte. Der Aufruf von init() vor der ersten Benutzung ist zwingend notwendig. Es werden dort die Arrays der Memory-Map und des Bitfeldes initialisiert. Die Funktionen bekommen einen Adresspointer vom Typ t_EE_addr, weitere Parameter je nach Wertetyp und am Schlu� ein Flag-Byte übergeben. Arrayfunktionen erhalten zu vorletzt noch eine Längenangabe. Schreibende Funkionen können eine CRC-Summe aus den Parameterdaten generieren, die im Addr.Ptr im Typ t_EE_addr.crc eingetragen wird. Es wird die Menge an verarbeiteten Zeichen in t_EE_addr.used für Adressberechnungen eingetragen. Lesende Funktionen können eine CRC-Summe aus den gelesenen Daten generieren, die Summe wird im Addr.Ptr im Typ t_EE_addr.crc eingetragen. Die CRC-Daten können in das EEPROM geschrieben und mit den später generierten CRC-Summen verglichen werden. Die CRC-Daten werden ggf. über alle Lese- und Schreibvorgänge mitgeführt, wenn sie nicht explizit oder mit setEEaddr gelöscht werden. Es empfielt sich, für schreibende und lesende Funktionen sowie für CRC-Datenfelder getrennte Addresspointer zu nutzen. �ber Flags kann das Verhalten der Funktionen gesteuert werden. Die Konstanten der Bits können binär zu einem Flag addiert werden. Die Adressen werden automatisch in t_EE_addr.addr incrementiert, so das für sequentielle Zugriffe kein Aufwand für Adressberechnung erfolgt. Die Addresierung erfolgt als long und kann derzeit von 0 bis 262143 erfolgen. Um Speicherlücken auszugleichen, erfolgt der Zugriff über eine Memory-Map die evtl. angepasst werden mu�. Die Bausteinauswahl erfolgt dann automatisch. Die Funktionen sind durch Capture in der Nähe der i2c-Operationnen gegen gegenseitiges Stören/�berschreiben auf dem I2C-Bus geschützt. Leider klappt das Sperren mit i2c.cstart nicht, da anscheinend dann wait nicht mehr ausgeführt wird. Das führt zu einem Deadlock. Ein Capture für den jeweiligen Ard.Ptr wie ursprünglich geplant ist mit c2 nicht möglich. Es werden alle Datentypen unterstützt und ein Beispiel für eigene Typen und für die Nutzung von CRC ist am Schlu� eingefügt. */ /******************************************************************/ const default = 0; //default, Verify aus, CRC aus, 32Bit //const frei = 1; //LSB not used const DoV = 2; //1=vergleicht beim schreiben und springt DoError an,0=do nothing const DoCRC = 4; //1=schaltet CRC schreibend ein,0=do nothing const CRC16 = 8; //1=16,0=32, wirkt nur wenn DoCRC=1 //const frei = 16; //BIT not used - reserved //const frei = 32; //BIT not used - reserved //const frei = 64; //BIT not used //const frei = 128; //MSB not used const EEblock=128; //Blocksize EEPROM laut Datenblatt type t_EE_addr { long addr; long crc; int used; } byte EEmmap[7];//gehört zu init(); byte EEpw[7];//Bitarray für CRC und Bitmustervergleiche function init()//init Funktiom für Memory Map // Es sind bis max 256 KB Speicher adressierbar. Das �ndern dieser Funktion // erlaubt Eingriffe in das Speichermanagement vergleichbar mit einer einfachen // MMU und soll hardwarebedingte Speicheradressenlücken verhindern helfen. // Es wären z.Z. technisch nur EEmmap[3] nötig, es soll aber in Zukunft weitere // Erweiterungen in den Speicher ab 262144 bzw. 0x40000 gelegt werden. // Aktuell ist die EEmap als Beispiel auf Mirror Betrieb eingestellt. // Auch die Nutzung anderer EEPROM-Typen ist denkbar, dazu sind aber weitere // Anpassungen nötig: -> (160 or EEmmap[(t.addr and 262143) shr 16]) { byte i; // Normaler Betrieb 256KB Betrieb mit PCF-Uhr 192KB EEmmap[0]=0; //160 für 24c512 000=A3-A0 EEmmap[0]=0; //160 EEmmap[1]=2; //162 für 24c512 001=A3-A0 EEmmap[1]=4; //164 EEmmap[2]=4; //164 für 24c512 010=A3-A0 EEmmap[2]=6; //166 EEmmap[3]=6; //166 für 24c512 011=A3-A0 EEmmap[3]=0; //166 EEmmap[4]=0; //160 | z.Z. noch unbenutzt, Mirror Bank 0 EEmmap[5]=2; //162 | z.Z. noch unbenutzt, Mirror Bank 1 EEmmap[6]=4; //164 | z.Z. noch unbenutzt, Mirror Bank 2 EEmmap[7]=4; //164 | z.Z. noch unbenutzt, Mirror Bank 2 for i = 0 ... 7 EEpw[i] = 2 ^ i; } /*************************************/ /* Setzt Startwerte für Addr.Ptr */ /*************************************/ function setaddr(long addr,t_EE_addr t) returns long { t.addr=addr; t.used=0; t.crc=0; return addr; } /*************************************/ /* Setzt Addr neu, gibt alte zurück */ /*************************************/ function oldaddr(long addr,t_EE_addr t) returns long { long data; data=t.addr; t.addr=addr; return data; } /*************************************/ /* kopiert ganzen Addr.Ptr von 1 zu 2*/ /*************************************/ function cpyaddr(t_EE_addr t1,t_EE_addr t2) returns long { t2.addr=t1.addr; t2.used=t1.used; t2.crc=t1.crc; return t1.addr; } /*************************************/ /* Wird im Fehlerfall angesprungen */ /*************************************/ function DoError(t_EE_addr t, byte f) { //Default für verify Fehler, EEPROM defekt. quit 63; //ggf. an eigene Anforderungen anpassen. //z.b. Ausgabe des Fehlers auf LCD, Alarmton, SMS, //umschalten auf Reservespeicherbank (EEmmap) usw. } /*************************************/ /* Byte-Array verifizieren */ /*************************************/ function verifybytearray (t_EE_addr t, byte data[], int len,byte f) { int i,fault; //counter für Array fault=-1; if len > 0 // es mu� wegen i2c.readlast min. 1 Byte gelesen werden. { capture i2c.flag; //verifybytearray darf niemals mehrfach ausgeführt werden wait i2c.ready(); //wartet auf Busfreigabe und auf EEPROM aus Memorymap t.addr=t.addr-len; //Addresskorrektur DoV wait i2c.start(160 or EEmmap[(t.addr and 262143) shr 16]); i2c.write(t.addr shr 8); //schreibt Adresse im selektierten EEPROM i2c.write(t.addr); i2c.start(161 or EEmmap[(t.addr and 262143) shr 16]); //setzt lesemodus for i=0 ... len-2 if data[i] != i2c.read()//Vergleichsvorgang des Array data[] { // Abbruch des Vergleichsvorgangs, EEPROM hat falsche Daten fault=0; len=i; break; } if data[len-1] != i2c.readlast() fault=0;//letztes Byte t.used=len; //Längenanpassung t.addr=t.addr+len; //Adressanpassung i2c.stop(); //Vorgang beendet, Bus ist frei release; //verifybytearray ist fertig, if fault DoError(t,f);//Vorgang beendet -> Fehlerfall im EEPROM auf t.addr } } /*************************************/ /* Byte-Array lesen */ /*************************************/ function readbytearray (t_EE_addr t, byte data[], int len,byte f) { int i,j; //counter für Array if len > 0 // es mu� wegen i2c.readlast min. 1 Byte gelesen werden. { capture i2c.flag; //readbytearray darf niemals mehrfach ausgeführt werden wait i2c.ready(); //wartet auf Busfreigabe und auf EEPROM aus Memorymap wait i2c.start(160 or EEmmap[(t.addr and 262143) shr 16]); i2c.write(t.addr shr 8); //schreibt Adresse im selektierten EEPROM i2c.write(t.addr); i2c.start(161 or EEmmap[(t.addr and 262143) shr 16]); //setzt lesemodus for i=0 ... len-2 data[i] = i2c.read(); //Lesevorgang des Array data[] data[len-1] = i2c.readlast(); //letztes Byte if f and EEpw[DoCRC] == EEpw[DoCRC] //ggf. CRC berechnen { for i = 0 ... len-1 { for j = 7 ... 0 step -1 //msb zuerst... in asm wäre das schöner { if ((t.crc and 32768)==32768) xor ((data[i] and EEpw[j])==EEpw[j]) if f and EEpw[CRC16]==EEpw[CRC16] t.crc=((t.crc and 32767) shl 1) xor 0x1021; else t.crc=((t.crc and 32767) shl 1) xor 0x8005; // kurz und schmerzlos } } } t.used=len; //Längenanpassung t.addr=t.addr+len; //Adressanpassung i2c.stop(); //Vorgang beendet, Bus ist frei release; //readbytearray ist fertig, } } /*************************************/ /* Byte-Array schreiben */ /*************************************/ function writebytearray (t_EE_addr t, byte data[], int len,byte f) { int i,j; //counter für Array capture i2c.flag; //writebytearray darf niemals mehrfach ausgeführt werden wait i2c.ready(); //wartet auf Busfreigabe und auf EEPROM aus Memorymap wait i2c.start(160 or EEmmap[(t.addr and 262143) shr 16]); i2c.write(t.addr shr 8); //schreibt Adresse im selektierten EEPROM i2c.write(t.addr); for i=0 ... len-1 //schreibvorgang des Array data[] { if f and EEpw[DoCRC] == EEpw[DoCRC] //ggf. CRC berechnen { for j = 7 ... 0 step -1 //msb zuerst... in asm wäre das schöner { if ((t.crc and 32768)==32768) xor ((data[i] and EEpw[j])==EEpw[j]) if f and EEpw[CRC16]==EEpw[CRC16] t.crc=((t.crc and 32767) shl 1) xor 0x1021; else t.crc=((t.crc and 32767) shl 1) xor 0x8005; // kurz und schmerzlos } } i2c.write(data[i]); //schreiben if (t.addr+i+1 % EEblock)==0 //Pagebreak gefunden { i2c.stop(); //Pagebreak -> stop wait i2c.ready(); //Pagebreak ausführen -> neue Bank/EEPROM einleiten wait i2c.start(160 or EEmmap[(t.addr+i+1 and 262143) shr 16]); i2c.write(t.addr+i+1 shr 8); //schreibt Adresse im neu selektierten EEPROM i2c.write(t.addr+i+1); //von nun an kann es normal weiter gehen } } t.used=len; //Längenanpassung t.addr=t.addr+len; //Adressanpassung i2c.stop(); //Vorgang beendet, Bus ist frei release; //writebytearray ist hier fertig if f and EEpw[DoV]==EEpw[DoV] verifybytearray(t,data,len,f); } /*************************************/ /* einzelnes Byte lesen */ /*************************************/ function readbyte (t_EE_addr t,byte f) returns byte { byte buffer[0]; readbytearray (t, buffer,1,f); t.used=1; return buffer; } /*************************************/ /* einzelnes Integer lesen */ /*************************************/ function readint (t_EE_addr t,byte f) returns int { byte buffer[1]; readbytearray (t, buffer,2,f); t.used=2; return mem.getint(buffer,0); } /*************************************/ /* einzelnes long lesen */ /*************************************/ function readlong (t_EE_addr t,byte f) returns long { byte buffer[3]; readbytearray (t, buffer,4,f); t.used=4; return mem.getlong(buffer,0); } /*************************************/ /* einzelnes float lesen */ /*************************************/ function readfloat (t_EE_addr t,byte f) returns float { byte buffer[7]; readbytearray (t, buffer,8,f); t.used=8; return mem.getfloat(buffer,0); } /*************************************/ /* Integer-Array lesen */ /*************************************/ function readintarray (t_EE_addr t, int data[], int len,byte f) { int i; byte buffer[1]; for i=0 ... len { readbytearray (t, buffer,2,f); data[i]=mem.getint(buffer,0); } t.used=2*len; } /*************************************/ /* Long-Array lesen */ /*************************************/ function readlongarray (t_EE_addr t, long data[], int len,byte f) { int i; byte buffer[3]; for i=0 ... len { readbytearray (t, buffer,4,f); data[i]=mem.getlong(buffer,0); } t.used=4*len; } /*************************************/ /* Float-Array lesen */ /*************************************/ function readfloatarray (t_EE_addr t, float data[], int len,byte f) { int i; byte buffer[7]; for i=0 ... len { readbytearray (t, buffer,8,f); data[i]=mem.getfloat(buffer,0); } t.used=8*len; } /*************************************/ /* String lesen (32Byte) */ /*************************************/ function readstr (t_EE_addr t, byte s[],byte f) { readbytearray (t,s,32,f); t.used=32; } /*************************************/ /* einzelnes Byte schreiben */ /*************************************/ function writebyte (t_EE_addr t, byte data,byte f) { byte buffer[0]; // 1 Byte buffer = data; writebytearray (t, buffer,1,f); t.used=1; } /*************************************/ /* einzelnes Integer schreiben */ /*************************************/ function writeint (t_EE_addr t, int data,byte f) { byte buffer[1]; // 2 Byte mem.putint(buffer,0,data); writebytearray (t, buffer,2,f); t.used=2; } /*************************************/ /* einzelnes long schreiben */ /*************************************/ function writelong (t_EE_addr t, long data,byte f) { byte buffer[3]; // 4 Byte mem.putlong(buffer,0,data); writebytearray (t, buffer,4,f); t.used=4; } /*************************************/ /* einzelnes float schreiben */ /*************************************/ function writefloat (t_EE_addr t, float data,byte f) { byte buffer[7]; // 8 Byte mem.putfloat(buffer,0,data); writebytearray (t, buffer,8,f); t.used=8; } /*************************************/ /* Integer-Array schreiben */ /*************************************/ function writeintarray (t_EE_addr t, int data[], int len,byte f) { int i; byte buffer[1]; // 2 Byte for i=0 ... len { mem.putint(buffer,0,data[i]); writebytearray (t, buffer,2,f); } t.used=2*len; } /*************************************/ /* Long-Array schreiben */ /*************************************/ function writelongarray (t_EE_addr t, long data[], int len,byte f) { int i; byte buffer[3]; // 4 Byte for i=0 ... len { mem.putlong(buffer,0,data[i]); writebytearray (t, buffer,4,f); } t.used=4*len; } /*************************************/ /* Float-Array schreiben */ /*************************************/ function writefloatarray (t_EE_addr t, float data[], int len,byte f) { int i; byte buffer[7]; // 8 Byte for i=0 ... len { mem.putfloat(buffer,0,data[i]); writebytearray (t, buffer,8,f); } t.used=8*len; } /*************************************/ /* String schreiben (32Byte) */ /*************************************/ function writestr (t_EE_addr t, byte s[],byte f) { writebytearray (t,s,32,f); t.used=32; } /*************************************/ /* Muster für eine eigene Datentypen */ /*************************************/ /* const ARRAYsize=255; type mytype { byte BYTE; int INT; long LONG; float FLOAT; string STRING; int ANYARRAY[ARRAYsize]; } mytype abc; function readmytype (t_EE_addr t, mytype abc,byte f) { abc.BYTE=readbyte(t,f); abc.INT=readint(t,f); abc.LONG=readlong(t,f); abc.FLOAT=readfloat(t,f); readstr(t,abc.STRING,f); readintarray(t,abc.ANYARRAY,ARRAYsize,f); } function writemytype (t_EE_addr t, mytype abc,byte f) { writebyte(t,abc.BYTE,f); writeint(t,abc.INT,f); writelong(t,abc.LONG,f); writefloat(t,abc.FLOAT,f); writestr(t,abc.STRING,f); writeintarray(t,abc.ANYARRAY,ARRAYsize,f); } /--------------------------------------------------------/ Beispiel für eine geänderte Stringfunktion incl. CRC der 16 Bit CRC-Wert wird in Anschlu� an den String geschrieben, lesend kann der Wert dann verglichen werden. /--------------------------------------------------------/ function writestr (t_EE_addr t, byte s[],byte f) { writebytearray (t,s,32,f); writelong(t,t.crc,f or ModCRC); t.crc=0 } /--------------------------------------------------------/ */ /* //Typische Anwendung (als Beispiel) thread main { int testarray[399]; long a; //initialisiere Array testarray[399]; mit Daten, eigener Code t_EE_addr myaddress; init(); setaddr(48000,myaddress); //Möglichkeit 1 um Startadresse zu setzen writeintarray(myaddress,testarray,399,default); //writeintarray(48000,testarray,399,default); //Dies geht nicht! //writeintarray(setaddr(48000,myaddress),testarray,399,default);//Dies geht nicht! //lösche Array testarray[]; eigener Code myaddress.addr=48000; //Möglichkeit 2 um Startadresse zu setzen readintarray(myaddress,testarray,399,default); //zurücklesen a=setaddr(48000,myaddress)+500; // a ist 48500, nächster Vorgang ab 48000 writelong(myaddress,a,DoV); //schreibt a nach 48000 mit Verify writelong(myaddress,a,DoCRC+CRC16); //schreibt a nach 48004 mit CRC16 writeint(myaddress,myaddress.crc,default); //schreibt crc-Wert nach 48008 a=oldaddr(50000,myaddress); // alter Addresswert wird in a zurück gegeben. // a hat nun 480010, der aktuelle Pointer liegt auf 50000 // weitere Vorgänge... a=setaddr(a,myaddress); // der aktuelle Pointer liegt wieder auf 48010 writeint(myaddress,a,DoV); //Schreibt a nach 48010 mit verify // über t_EE_addr variable; können verschiedene Pointer verwaltet // und mit setEEaddr und getEEaddr komfortabel bearbeitet werden // Unabhängig laufende Schreib/Lesepointer sind leicht einzusetzen. // Beispiel.... t_EE_addr readptr; t_EE_addr writeptr; cpyaddr(readptr,writeptr); //copy der Ptr von readptr nach writeptr // Addressen neu setzen... setaddr(48000,readptr); setaddr(49000,writeptr); for a=0...9 //copy von 10 Int-Arrays[9] von 48000 nach 49000 { readintarray(readptr,testarray,10,default); writeintarray(writeptr,testarray,10,DoCRC); } writeint(myaddress,writeptr.crc,DoV); //schreibt crc32-Wert als Abschlu� // über die ganzen Schreibvorgänge aus der for-Schleife mit Verify. // Nun können die Arrays wieder eingelesen und gegen die CRC-Summe // geprüft werden. Es wäre möglich, die beiden CRC's zu vergleichen // um Verarbeitungsfehler auszuschlie�en. Allerdings dann mit DoCRC bei read. setaddr(49000,readptr); //*** for a=0...9 //einlesen der eben kopierten Arrays readintarray(readptr,testarray,10,DoCRC); if readptr.crc != writeptr.crc DoError(readptr); //CRC-Fehler, Daten wurden //offensichtlich modifiziert. DoError sollte darauf passend reagieren. setaddr(49000,readptr); //Ersatzweise als Vergleich zu *** for a=1...8 //zeilweise einlesen der eben kopierten Arrays readintarray(readptr,testarray,10,DoCRC); if readptr.crc != writeptr.crc DoError(readptr); // CRC-Fehler erzwungen. // Hier mu� ein CRC-Fehler auftreten da nicht alle CRC-relevanten Daten // verarbeitet wurden. } */ Gru� Rolf | |
Antwort schreiben Antworten: |