Hier ein kleiner I2C Ansteuerungssource für das Hardware TWI als Master. Der Source ist in WinAVR Assembler/C, benötigt fürs I²C 56 Bytes an Code und für die Routinen zum Ansprechen der meisten I²C EEPROMS 164 Bytes an Code. Das komplette TWI arbeitet im Polling Mode, also nicht Interrupt basiert. In den meisten Fällen ist dies ausreichend und wesentlich unkomplizierter und Resourcesparender als Interruptbasiertes TWI. Allerdings werden alle Staties des TWI ausgewertet, d.h. alle Routinen enthalten eine Fehlerauswertung. Der komplette Source ist in Assembler. Das TWI wird einmalig im Statupcode mit i2cInit(400000); initialisiert. Dafür sollte das Define XTAL auf die Taktfrequenz des Zielprozessors gesetzt werden. Ist dies nicht der Fall geht die Library im Makro i2cInit() von einem 16Mhz Processor aus. Der Source wurde auf einem ATmega8L mit ST24C64 EEPROM's getestet. I²C EEPROM's werden so angesprochen: const char Text[] PROGMEM = "Test Text\n"; { if (i2cMemWrite(0xA0, 123, Text, sizeof Text, 1) == sizeof Text) { printf("Daten geschrieben"); } char Daten[sizeof Text]; if (i2cMemRead(0xA0, 123, Daten, sizeof Daten) == sizeof Daten) { printf(Daten); } } 0xA0 ist die I²C EEPROM Device Adresse, 123 die Speicheradresse im EEPROM. Der letzte Parameter von i2cMemWrite() gibt an ob die Daten im RAM oder FLASH gespeichert sind. i2cMemWrite() berücksichtigt beim Schreiben das Pageboundary der EEPROM Chips. WICHTIG! In der Datei i2c.S muß EEPROM_ADDRESS_BYTES entweder auf 1 oder 2 gesetzt werden, abhängig vom verwendeten I²C EEPROM Chip. Chips mit geringer Kapazität bis 256 Bytes benutzen EEPROM_ADDRESS_BYTES = 1, alle anderen bis 64K EEPROM_ADDRESS_BYTES=2. Desweiteren muß EEPROM_PAGE_SIZE = 32 eventuell geändert werden. Die meisten EEPROM Chips benutzen aber beim Schreiben der Daten einen 32 Bytes Latch. Bei diesem Source wurde absichtlich darauf geachtet einen möglichst kompakten Code zu erzeugen, aber mit Fehlerbehandlung. Dies hat zur Folge das die Performance unwesentlich ein par Taktzyklen darunter leidet. Gruß Hagen
Moin Hagen, ich versuche Deinen Code mit einem Mega 16 (16 MHz) und einem Atmel C64 EEPROM zu benutzen. Die Pagesize habe ich auf 8 Byte verkleinert, aber es funktioniert nicht wirklich. Bei calculate adress im send page muss ich unsigned short address = 8*page+1; eintragen und bei read page unsigned short address = 8*page; damit ich die gleichen Speicherplätze schreibe und lese. Für einen Schreibzyklus funktiniert es auch, aber wenn ich das ganze in einer for Schleife mit verschiedenen Adressen mache bleibt das Programm nach der zweiten Seite hängen. Wenn ich dann zu page andere Werte addiere oder subtrahiere, dann gibt es mal mehr, mal weniger funktionierende Lesezyklen!?! Woran könnte das liegen???? Vielen Dank Dirk
Gib mir mal den genauen Typ des EEPROM's damit ich mal selber ins Datenblatt schauen kann. Meine obigen Routinen sind für größere Standard EEPROMs wie von TI, MicroChip, ST ausgelegt. Getestet habe ich sie mit einem 24C64MN6 und EE24LC64SM. Gruß Hagen
Moin Hagen, na das ging ja schnell. Es ist ein ATMEL 24C64A bzw. C32A. Ich habe mal den Code mit angehangen. Dabei gebe ich die gelesenen Bytes auf dem LCD aus und kann die erste Seite wieder korrekt auslesen und beim zweiten Durchlauf hängt das Prog beim Read. (Das sehe ich an den LED´s die mit toggeln.) Mit leichten Änderungen bringe ich das Prog auch zum weiterlesen, allerdings werden mir dann völlig unlogische Werte für "seite" ausgegeben. Irgendwie blicke ich das gar nicht mehr... Vielen Dank Dirk
Hi Dirk, dein Source sieht erstmal ganz gut aus, er basiert aber nicht auf meinem obigen Source. Ich verstehe aber nicht warum du diese Dummy Writes mit reingebaut hast. Gruß Hagen
- Rot werd - Ups, das stimmt... Ich habe mir aus einigen Quellen Beispielcode für I2C besorgt und war irgendwie der Meinung, das dieser Code von Dir ist. Das ist mir jetzt doch etwas peinlich. Mein Testprogramm mit Deinem Code habe ich angehangen, das bekomme ich leider nicht dazu mir sinnvolle Werte zu schreiben/lesen... Wäre super, wenn Du Dir das auch nochmal anschaust. Deinen Vorschlag zu dem anderen Code werde ich morgen mal einarbeiten (Wenn ich die richtige Stelle finde -> Bin noch Anfänger). Leider ist der Code nicht kommentiert, jetzt weiß ich nicht mal mehr von wem der ist... Vielen Dank Dirk
Hi Dirk, in Main.c #include "i2c.h" #include <stdlib.h> #include <avr/iom16.h> #include "lcd.h" //Defines #define XTAL 16000000 //16MHz I2C solltest du das XTAL vor dem include i2c.h setzen oder besser noch mit DEFS = -DXTAL=16000000 ins Makefile setzen. Im Falle der i2c Routinen spielt das aber weniger ne Rolle da der Source bei nicht definiertem XTAL mit 16MHz arbeitet. Desweiteren solltest du erstmal mit i2cInit(100000) arbeiten statt also mit 400KHz. Und überprüfe mal die I2C Busaddresse des EEPROMS ob diese auch wirklich 0xA0 ist. In i2c.S musst du noch #ifndef EEPROM_ADDRESS_BYTES #define EEPROM_ADDRESS_BYTES 2 // set to 1 for 1 byte memory address #endif #ifndef EEPROM_PAGE_SIZE #define EEPROM_PAGE_SIZE 32 // page size of i2c eeprom chip #endif anpassen. EEPROM_ADDRESS_BYTES auf 2 oder 1 stellen. 2 für 16 Bit Addressen was wohl für deinen C64/C32 richtig wäre. EEPROM_PAGE_SIZE auf 8 wenn ich dich richtig verstanden habe. Das Datenblatt des ATMEL habe ich mir aber bisher noch nicht angeschaut. Gruß Hagen
Also ich habe jetzt doch mal schnell ins Datenblatt geschaut http://www.atmel.com/dyn/products/product_card.asp?part_id=2484 In i2c.h EEPROM_ADDRESS_BYTES 2 EEPROM_PAGE_SIZE 32 Page Size ist 32 Bytes NICHT 8 Bytes, siehe Datenblatt Seite 1. i2cInit(400000) also 400kHz geht ok, probiers denoch erstmal mit 100Khz. Die Pins A0,A1,A2,WP lässt du erstmal offen oder legst sie auf GND. SCL,SDA,VCC und GND dürften ja klar sein wie du sie verbindest. Auf Seite 11 im Datenblatt findest du die "Device Address" sie ist "1010 A2 A1 A0 W/R". Bei obiger Beschaltung musst du also 0xA0 als Device Address angeben. Im Grunde müsste also mein i2c Source sofort ohne Änderung bei dir funktionieren. Du musst nur A0-A2 und WP auf GND legen oder offen lassen. Gruß Hagen
Denkt bitte daran, dass die Zeilen in i2c.S .... #define I2C_TWCR TWCR //_SFR_IO_ADDR(TWCR) #define I2C_TWSR TWSR //_SFR_IO_ADDR(TWSR) #define I2C_TWDR TWDR //_SFR_IO_ADDR(TWDR) .... bei winavr nicht wirken. Erst nach der obigen Änderung ging die i2c.S Datei bei mir auch. Mattias
Nur der ATMega64/128 haben die TWI Register im Addressbereich > 63 definiert. Somit müsste der alte Source 1 zu 1 auf dem ATmega16 laufen. Ich habe denoch mal eine verbesserte Version von i2c.S angehangen. Diese sollte mit allen AVR's laufen. Gruß Hagen
Hi Leute, ich habe mal weiter getestet, aber leider funktioniert es noch immer nicht richtig. Daher mal ein Zwischenstand in Stichworten: - Die Busgeschwindigkeit habe ich reduziert - Die Hardwareadresse muss stimmen, weil ich ein 256Byte EEPROM mit der Peter Fleury Routine schreiben und lesen kann - Die Änderung der Pagesize macht nichts, ausserdem steht auf dem Titelblatt "Partial Page Writes Allowed", sollte dann doch auch mit 8 gehen!? - Wenn ich Mattias Änderungen in die i2c.S einfüge wirft mir WinAVR einen Fehler aus: i2c.S:42: Error: number must be less than 64 i2c.S:44: Error: number must be less than 64 i2c.S:59: Error: number must be less than 64 i2c.S:63: Error: number must be less than 64 i2c.S:70: Error: number must be less than 64 - Die neue i2c.S führt auch zu keinem besseren Ergebnis Ich werde noch mal weiter testen und auch mein Mega8 Board in Betrieb nehmen, mal schauen was ich falsch mache. Zum Verständnis: Es werden Werte in die erste Page des EEPROM geschrieben, die sind aber völlig falsch (Ich kann das EEPROM ja mit dem twitest Demo von WinAVR lesen). Ausgelesen wird das EEPROM, die angezeigten Werte stimmen aber auch nicht mit dem überein was twitest auswirft... Falls noch jemand Interesse hat, ich habe das aktuelle Projekt angehangen. Erstmal vielen Dank für die Tipps, ich werde es so lange versuchen bis ich es verstanden habe und es funzt :-) Dirk
Hm, probier mal folgendes DDRB = 0xFF; PORTB = 0xFF; DDRC = 0; PORTC = (1 << PC0) | (1 << PC1); i2cInit(1000000); uint8_t Buffer[8]; uint8_t i; for (i = 0; i < 8; i++) Buffer[i] = i; i2cMemWrite(0xA0, 0, Buffer, 8, 0); for (i = 0; i < 8; i++) Buffer[i] = 0x55; i2cMemRead(0xA0, 0, Buffer, 8); for (i = 0; i < 8; i++) { if Buffer[i] != i { PORTB = 0; break; } } Ansonsten solltest du versuchen externe Pullups an SDA und SCL anzuschließen. Mehr fällt mir dann aber auch nicht mehr ein :( Gruß Hagen
Patsch (Hand vorn Kopp geknallt)!!! Wieso ist denn nicht aufgefallen, dass ich beim i2cMemWrite Parameter 5 immer eine '1' stehen hatte??? Ich hatte diesen Satz: "If FlashStored != 0 Source points to programmemory." so verstanden das ich eine 0 brauche um in das RAM zu verweisen?!? Vielen Dank an alle Beteiligten, besonders an Hagen. So habe ich zumindestens einiges mehr gelernt als es bei sofortigen Funktionieren der Fall gewesen wäre... Ich habe übrigens externe PullUp´s. Gruß Dussel-Dirk
wenn FlashStored ungleich 0 ist dann liegt der Datenbuffer im Programmspeicher == Flash, wenn FlashStored gleich 0 ist, also "not FlashStored" dann liegt der Buffer im RAM. >>> "If FlashStored != 0 Source points to programmemory." >> so verstanden das ich eine 0 brauche um in das RAM zu verweisen?!? jo, und das ist ja auch richtig so ?!? :) Sorry falls das für Verwirrung gesorgt hat. Ich benutze aber diese Methode sehr gerne, statt eben zwei verschiedene und denoch fast gleiche Funktionen für den Flash und RAM zu schreiben. Meistens spart man so einiges an Programspeicher und die Performance leidet ebenfalls nicht. Gruß Hagen
achso, falls es dir hilft kannste ja zwei Makros benutzen #define i2cMemWriteP(Device, Address, Source, Count) i2cMemWrite(Device, Address, Source, Count ,1) #define i2cMemWriteR(Device, Address, Source, Count) i2cMemWrite(Device, Address, Source, Count, 0) i2cMemWriteP() falls Source in den FLASH zeigt und i2cMemWriteR() falls Source im RAM liegt. Gruß Hagen
ach und setzte für deine EEPROM's die Pagesize wieder auf 32, das ist wichtig. Du musst dich bei den Funktionen in keinster Weise um dieses Pageboundary kümmern. Du kannst also auch ohne Probleme einen 137 Bytes Buffer an Addresse 17 in den EEPROM speichern, in einem Rutsch mit einem Aufruf von i2cMemWrite() eg. i2cMemRead(). Desweiteren brauchst du dich nicht um das verzögerte Timing beim Speichern ins EEPROM kümmern. i2cMemWrite() kehrt erst dann zurück wenn der EEPROM Chip seine Daten tatsächlich gespeichert hat. Danach befindet sich der EEPROM im Power Save Mode. Alles natürlich nur wenn i2cMemWrite() und i2cMemRead() als Rückgabewert exakt die Anzahl der Bytes die übergeben wurden zurückliefert. Sollte der Rückgabewert 0 sein so trat ein Fehler schon beim Ansprechen des EEPROMs auf. Mit i2cStatus() kannst du dann den TWI Fehlercode ermitteln. Das TWI ist mit i2cStop() korrekt terminiert. Sollte der Rückgabewert kleiner als die Größe des Buffers sein so wurde nur teilweise gespeichert bzw. gelesen und es tratt mittendrin ein Fehler auf. i2cMemSelect() benötigst du im Grunde nicht. Es dient nur zur Selektierung des EEPROM Chips und der anschließenden Auswahl der Speicheraddresse die gelesen oder geschrieben werden soll. Diese Funktion wird also intern von i2cMemWrite() und i2cMemRead() gemeinsam benutzt. Gruß Hagen
Moin Hagen, vielen Dank, jetzt funktioniert alles :-) >>> "If FlashStored != 0 Source points to programmemory." >> so verstanden das ich eine 0 brauche um in das RAM zu verweisen?!? >>jo, und das ist ja auch richtig so ?!? :) Und warum habe ich dann eine 1 geschrieben ??? Das es so oft solche einfachsten Kleinigkeiten sind... Gruß Dirk
Hallo! Ich verwende hier Hagens Routine (vielen Dank, wennst eine Miwula-Freikarte brauchst, einfach mailen), habe aber ein Problem: Es wird nur geschrieben, wenn an SDA z.B. ein Oszi-Tastkopf dranhängt. Hänge ich an SCL auch einen an, dann schreibt er nicht, schalte ich bei einen von beiden den Vorteiler ein, dann schreibt er. i2cMemWrite liefert aber immer die richtige Länge zurück. Ich hab an SDA und SDL je einen 4,7k externen Pullup. Hat jemand eine Ahnung was das sein könnte? Wenn ich an SDA einen 20pF parallelschalte, dann geht es bestimmt auch, aber das ist ja Murks. Das Oszi zeigt bei beiden Fällen das selbe Bild. LG, Fritz
Achja, es ist ein AT24C256, mit: EEPROM_ADDRESS_BYTES 2 EEPROM_PAGE_SIZE 64
Ich hab jetzt festgestellt, dass i2cwait hängt, auch wenn das schreiben funktioniert. Ich hab da einen Verdacht, der Prozessor ist ein Mega64, und da liegt TWSR anscheinend nicht im I/O Bereich. Ich hasse Assembler!
Vergiss voriges Posting, dass mit den hohen Portaddressen beim Mega64 ist eh schon drin. (im letzten geposteten i2c.S). Ich such noch immer...
sorry Fritz, dann dürfte mein Assembler Source nicht das Richtige für dich sein. Ich kann dich aber echt verstehen :) Die Sache ist nur das ich damals unbedingt einen sehr kompakten Code benötigte und der vergleichbare C Source verbrauchte doppelt soviele Resourcen. Meine Routinen haben keinerlei Timeout Funktionen und so kann es durchaus vorkommen das i2cWait() in einer Endlossschleife hängen bleibt. Allerdings, wenn i2cMemWrite() die korrekte Datengröße zurückgibt dann heist dies das auch keine HW Fehler im TWI aufgetreten sind. Die Routinen verlassen sich dabei voll und ganz auf die Funktionalität und "Fehlererkennung" der AVR Chips. In deinem Falle solltest du mal das Datenblatt vom AT24C256 mit anderen I2C EEPROMs vergleichen, besonders die Timing Diagramme. Eventuell ergeben sich dort dann Unterschiede, wäre ja durchaus möglich. Gruß Hagen
Hallo Hagen! Da ich ja weitermaachen musste, hab ich als Notlösung einen 47pF auf SDA gehängt. Es tut zumindest und ich kann weiterprogrammieren. Ich verstehs echt nicht, meine Kollegen auch nicht. Wir haben das Layout etwas geändert (mehr Massefläche, Abblockkondensatoren besser platziert), bei der nächsten Platine tuts dann vielleicht.
So, ich hab den Fehler gefunden: i2cStop: ldi P0L, (1 << TWEN) | (1 << TWINT) | (1 << TWSTO) out_ TWCR, P0L ldi P0L, 14 // small wait loop before deactivation of TWI Der ursprüngliche Wert von 3 bei "ldi POL, 3" war zu klein, mit 10 tuts auch, bin aber sicherheitshalber auf 14 gegangen.
Ah danke und ich hätte da selber drazf kommen müssen. Ich habe mit 400Khz und 8Mhz Takt gearbeitet. Der Wert in P0L sollte die nachfolgende Schleife mindestens ein TWI Takt warten lasssen. Du hast auf 14 = 42 Takte gesetzt. Ich vermute MCU takt ist 16Mhz und TWI läuft mit 400KHz, ergo 40 in P0L würde 1 TWI takt warten lassen. Das Problem entstand einfach weil ich nicht weis wie man auf dem AVR im TWI abfragen kann ob alle Transaktionen erfolgt sind, das scheint wohl nicht auf universelle Art zu gehen. Also habe ich einfach eine kleine Waitloop reingebaut so das es bei mir funktionierte. Geplant war es aber das noch variabel an XTAL der MCU anzupassen, tja leider vergessen :) Wenn man sichergehen will so wäre es am besten P0L auf 107 zusetzen. Das garantiert bei 16MHz XTAL ein minimalen TWI Takt von 50Khz. Formel dafür ist P0L == (MCU_Takt / TWI_Takt +2) / 3. Jetzt past auch deine Lösung mit den zusätzlichen C's am Bus. Dies erschien mir ziemlich suspekt, wird aber jetzt logisch. Sorry nochmal für meine Schusslichkeit und deinen dadurch entstandenen Aufwand. Gruß Hagen
Ja, ich fahr 16MHz mit 400kHz, da waren die 14 doch gut geraten :-) Bin eigentlich nur draufgekommen weil heute mein Fernseher kaputtgegangen ist, und ich aus lauter Verzweiflung in die Firma arbeiten gegangen bin, und mir dann in Ruhe das Problem angeschaut hab.
Das Problem warum ich einen Delay benutzen musste war weil ich nicht in den Datenblättern herausfinden konnte wann das TWI eine beliebige Aktion tatsächlich beendet hat. Nun i2cStop kann zu einem beliebigen Zeitpunt aufgerufen werden und als erstes wird ein STOP geendet. Eventuell muß ich noch mal genauer ins Datenblatt schauen ob in TWSR sich daraufhin ein bestimmter Status ändert. Um eben so lange warten zu können bis man auf sichere Weise TWCR komplett löschen kann und somit das TWI deaktiviert. Problem mit so einer Vorgehensweise ist der Punkt das am I2C Bus kein Gerät sauber reagiert, es könnt also zu einer Endlosschleife kommen. Deshalb eben die Methode mit einem Delay. Gruß Hagen
hallo, bei mir läuft der code von hagen bestens. ich kann ein eeprom 24c256 beschreiben und lesen und das compasmodul cmps03 von 0-3600 einheiten auslesen, entspricht 0-360 grad. das compassmodul am robby steuert den roboter sehr genau durch die gegend. mfg pebisoft
hallo, hagen, mich würde jetzt einmal interessieren, wie man mit deinem programm ein srf08-i2c ultramodul auslesen kann und beschreiben kann. mfg pebisoft
Hm, das hängt vom Modul ab. Normalerweise inetwa so i2cInit(100000); i2cStart(); i2cWrite(Addresse | ReadWriteBit); -- ab hier abhängig vom Modul i2cWrite(Daten); Daten = i2cRead(); -- i2cStop(); Natürlich sollten die SCL/SDA Pins vorher korrekt eingestellt sein, sprich Ein/Ausgang mit/ohne Pullups. Komplizierter wird es nur falls dein Modul sich nicht an der gängigen Paxis orientiert, zb. kein 8Bit=1Byte I2C benutzt,sondern zb. 9Bit oder 11Bit. Dann kannst du das Hardware TWI des Atmels eh vergessen. Gruß Hagen
Hallo Leute, ich benutze den i2c-Treiber von Hagen mit ATmega32 in einer Interupt-gesteuerten Datenerfassung (INT 0). Der INT wird mit mit 400Hz angesprochen. Beim Versuch, im laufenden Betrieb größere Mengen Daten aus dem EEPROM zu lesen, schmiert alles ab. Es scheint mir, dass der INT in die i2c-Routinen reinfunkt. Die Schreib/Leseroutine wird in main() aufgerufen (nicht in einer ISR). Eine Erhöhung des TWI-Taktes von 100 auf 400kHz hat Besserung gebracht, ändert an der grundsätzlichen Problematik aber nichts. Wenn ich den Interrupt während der EEPROM-Zugriffe abschalte, gehen Daten verloren. Geht also nicht. Kann man da was machen? Oder gibt es andere i2c-Routinen, die trotz Interrupts funktionieren? Gruß Malte
Moin Malte, so wie ich das sehe ist das nicht so einfach zu lösen. Der AVR kann ja kein echtes Multitasking (Warum auch). Du musst also selber dafür sorgen das sich die Interrupte nicht gegenseitig oder den Programmablauf stören. Wenn der INT0 so regelmäßig vorkommt, warum stimmst Du die zu lesende Datenmenge nicht auf die zur Verfügung stehende Zeit ab? Bis dann Dirk
Moin Dirk, danke für den Kommentar. Gibt es nicht eine Möglichkeit, die Priorität der i2c Routine gegenüber dem externen INT (es muss nicht INT0 sein) zu erhöhen? Ich meine, nicht den INT während des Lesens abzuschalten, sondern ihn nach Abschluß des Lesens auszuführen. Ich habe gelernt, dass sowas bei Verwendung von zB. INT0 und INT1 geht. Ich stelle mir das etwa so vor: Datenerfassung (ist nicht so zeitkritisch) an INT1 und i2c-Routinen irgendwie an INT0 koppeln. Geht das? Gruß Malte
Moin Malte, wenn der Interrupt nicht zeitkritisch ist, warum schaltest Du ihn dann nicht beim Lesen ab und führst die Erfassung danach manuell durch? Wenn das I-bit nicht gesetzt ist sollte der Interrupt nicht auslösen, aber trotzdem das INTF0-bit setzten. Das kannst Du nach dem lesen kontrollieren und gegebenenfalls Deine Erfassung durchführen, danach das Bit Löschen und den Interrupt wieder freigeben... Bis dann Dirk
Hallo, habe noch mal rumprobiert und dabei festgestellt, dass der Interrupt gar nicht das Problem ist, sondern die relativ geringe Geschwindigkeit des Schreibvorgangs. Ich habe 3400byte/sec (schreiben) und 12500byte/sec (lesen) ermittelt, bei 400kHz TWI und 16MHz f_cpu. Dadurch kommt in meinem Programm so einiges aus dem Takt und ich muss sehen, ob ich das irgendwie hinkriege. Bei mir kommen zwar nur 1000byte/sec, aber die will ich im EEPROM zwischenspeichern und dann en bloc wegschicken (UART/XPORT, SD...). Dadurch kommt es zu Engpässen. Wahrscheinlich wäre ein paralleles RAM günstiger, oder? Dazu fehlen mir aber freie Ports. Gruß Malte
Hallo Hagen, ich verwende deine Routine erfolgreich um einen EEPROM mit einem Mega8 anzusteuern. Vielen Dank an dieser Stelle! Nun bin ich bei unveränderter Hardware auf den Mega168 umgestigen, beim lesen des EEPROMS bleibt der Controller jetzt hängen. Gibts es beim TWI Unteschiede zweischen beiden Controllern? Was kann ich ändern, damit es wieder funktioniert? Vielen Dank
Kene Ahnung, ich habe mich in's TWI vom ATmega168 noch nicht eingearbeitet. Müsste erstmal ins Datenblatt schauen. Gruß Hagen
Hallo, habe es gerade nochmal mit dem mega8 getestet und es geht. Fehler liegt also wahrscheinlich nicht in der Hardware. Muss ich die Pins irgendwie initialisieren, oder macht das deine init-routine schon? Wo könnte ich anfangen den Fehler zu suchen? Die TWI-Register überprüfen? Danke
Hi, danke für die Lib. Anpassungen: +XTAL -> F_CPU Konstante +Wie in den Kommentaren erwähnt, das Timeout etwas erhöht, sonst schlug bei mir das Schreiben fehl +Include Pfade an neue avr-libc angepasst +Und in den ganzen 10 Jahren hat niemand von den 1000 Downloadern bemerkt, dass beim SCHREIBEN DIE REGISTER R16 UND R17 ÜBER GEBÜGELT WERDEN, DIE ABER AUF DER CALL-SAVED LISTE DER AVR-LIBC STEHEN und es somit zu beliebigen Fehlern im restlichen C Programm kommen kann! -> Auf r26 und r27 geändert. Sonstige Hinweise: +Ist die Adresse falsch gewählt, bleiben die Routinen hängen +Die Adresse ist als 8 Bit Wert (also Bit 0 immer 0 für R/W) zu wählen, andere Libs (zb die XMEGA lib von Atmel) wollen die Parameter als 7 Bit Adresse +Der Parameter FlashStored bezieht sich auf den Adressraum der Quelle (RAM/Flash), nicht wie von mir erst angenommen auf die verschiedenen Byte/Page Schreibmodi des I2C Eeproms.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.