Atmega328p I²C
-
- Beiträge: 6918
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Atmega328p I²C
Ich wollte die I²C-Schnittstelle Hardwaremässig ansteuern. Nur bleibt mein Code bei TWIReadACK; hängen.
Ist es richtig, das man bei Lesen die Adresse mit (addr or 1) Verknüpfen muss ?
Nehme ich das or 1 raus, dann läuft da Programm durch, aber es kommt ein falscher Wert, es wird immer 18504 zurückgeliefert.
Was mache ich falsch ?
Als Quelle habe ich dies hier verwendet: https://github.com/g4lvanix/I2C-master- ... c_master.c
Die Hardware ist in Ordnung, ansonsten würde der Arduino-Code nicht funktionieren.
Ist es richtig, das man bei Lesen die Adresse mit (addr or 1) Verknüpfen muss ?
Nehme ich das or 1 raus, dann läuft da Programm durch, aber es kommt ein falscher Wert, es wird immer 18504 zurückgeliefert.
Was mache ich falsch ?
Als Quelle habe ich dies hier verwendet: https://github.com/g4lvanix/I2C-master- ... c_master.c
Die Hardware ist in Ordnung, ansonsten würde der Arduino-Code nicht funktionieren.
- Dateianhänge
-
Project1.pas.tar.gz
- (1.1 KiB) 102-mal heruntergeladen
-
arduino.ino.tar.gz
- (1.12 KiB) 103-mal heruntergeladen
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Atmega328p I²C
Ich gebe zu, ein Grund warum ich die Software-TWI gemacht habe ist, dass ich den Hardware-TWI nie zuverlässig zum Laufen gebracht habe. 
Und weil die Software-TWI schon da war, von einem Projekt wo der Controller das in Hardware nicht konnte.
Dein Code wird spätestens hängen, wenn etwas den SCL auf low zieht. Dann denkt der Master das ist ein Clock-Stretch und wartet ewig.

Und weil die Software-TWI schon da war, von einem Projekt wo der Controller das in Hardware nicht konnte.
Dein Code wird spätestens hängen, wenn etwas den SCL auf low zieht. Dann denkt der Master das ist ein Clock-Stretch und wartet ewig.
-
- Beiträge: 760
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Atmega328p I²C
Guten Morgen,
das Bit 0 in der Adresse gibt ja an, ob es eine Lese oder Schreib Operation ist.
Damit MUSS beim Lesen das Bit 0 auf "1" = READ sein.
OR 1 ist also zwingend erforderlich.
grad mal in den Code geschaut:
muss deine addr nicht einmal nach links geschoben werden ? in der Procedure TWIStart ?
ansonsten, ich hoffe ich irre nicht, müsste das so sein
schreiben:
TWIStart(($48 << 1) OR 0); // RW Bit Low or 0 kann man sich natürllich sparen..., macht der Compiler aber selbst weg
lesen:
TWIStart(($48 << 1) OR 1); // RW Bit High
das Bit 0 in der Adresse gibt ja an, ob es eine Lese oder Schreib Operation ist.
Damit MUSS beim Lesen das Bit 0 auf "1" = READ sein.
OR 1 ist also zwingend erforderlich.
grad mal in den Code geschaut:
muss deine addr nicht einmal nach links geschoben werden ? in der Procedure TWIStart ?
ansonsten, ich hoffe ich irre nicht, müsste das so sein
schreiben:
TWIStart(($48 << 1) OR 0); // RW Bit Low or 0 kann man sich natürllich sparen..., macht der Compiler aber selbst weg
lesen:
TWIStart(($48 << 1) OR 1); // RW Bit High
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Atmega328p I²C
Das mit der Adresse ist oft ein Fallstrick: Manche Datenblätter geben die Adresse als 7bit und das R/W Bit extra an, manche geben die Adresse als 8bit an.
Ich hab mir angewöhnt, die Adresse als 8bit Konstante in den Code zu schreiben, genaugenommen als 2 Konstanten, einmal Read Adresse ohne Bit0 gesetzt und einmal Write Adresse mit Bit 0 gesetzt. Dann muss man die nur an der richtigen Stelle so ausgeben, wie sie sind.
Ich hab mir angewöhnt, die Adresse als 8bit Konstante in den Code zu schreiben, genaugenommen als 2 Konstanten, einmal Read Adresse ohne Bit0 gesetzt und einmal Write Adresse mit Bit 0 gesetzt. Dann muss man die nur an der richtigen Stelle so ausgeben, wie sie sind.
-
- Beiträge: 6918
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Atmega328p I²C
Habe ich das richtig verstanden, die Writeadresse ist immer eine gerade Zahl und bei Read ist sie immer 1 höher ?
Am Pulup kann es nicht liegen, ansonsten würde es unter Arduino auch nicht gehen, oder ?
Am Pulup kann es nicht liegen, ansonsten würde es unter Arduino auch nicht gehen, oder ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Atmega328p I²C
Ohne dass ich mir das zip nochmal laden und durchsuchen möchte: Was ist es denn für ein Sensor?
Doch, es kann am Pullup liegen, wenn Deine Taktfrequenz höher ist als im Arduino-Sketch. Für I2C ist ein Oszi oder eine Logikanalyser echt eine feine Sache. Damit hab ich letztens auch in akribischer Suche einen Fehler gefunden, der nur ab und zu aufgetreten ist, aber dann verheerend war: Ein Register falsch initalisiert - hat sich an ganz anderer Stelle ausgewirkt.
Doch, es kann am Pullup liegen, wenn Deine Taktfrequenz höher ist als im Arduino-Sketch. Für I2C ist ein Oszi oder eine Logikanalyser echt eine feine Sache. Damit hab ich letztens auch in akribischer Suche einen Fehler gefunden, der nur ab und zu aufgetreten ist, aber dann verheerend war: Ein Register falsch initalisiert - hat sich an ganz anderer Stelle ausgewirkt.
-
- Beiträge: 6918
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Atmega328p I²C
ADS1115 http://henrysbench.capnfatz.com/henrys- ... -tutorial/Was ist es denn für ein Sensor?
So wie ich es da sehe, sind dort Pulups verlötet.
Ich muss heute Abend probieren, die Adresse um ein Bit nach Links zu verschieben.
Vielleicht mach Arduino das im Hintergrund selbst.
Da sieht man, wie viel Arbeit einem Ardunio abnimmt, aber dafür sieht man nicht, was wirklich läuft.

Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Atmega328p I²C
Das Datenblatt sagt:
Mithin muss die "wahre" Adresse größer $80 sein, wenn das höchste Bit gesetzt ist. Die im Sketch angegebene Adresse 0x48 ist also die unverschobene 7bit-Adresse für Adresspin nach GND.
Wären die "wahren" Adressen in Pascal.
Code: Alles auswählen
ADDR PIN CONNECTION SLAVE ADDRESS
GND 1001000
VDD 1001001
SDA 1001010
SCL 1001011
Code: Alles auswählen
const
ads1115wr = %10010000; // geändert, Write ist 0, Read ist 1
ads1115rd = %10010001;
Zuletzt geändert von Timm Thaler am Sa 28. Okt 2017, 17:18, insgesamt 1-mal geändert.
-
- Beiträge: 760
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Atmega328p I²C
Ohne Pullups funktioniert das ganze garnicht.
Du brauchst auf BEIDEN Leitungen einen Widerstand nach Plus. Um die volle Übertragungsrate zu bekommen, sprich Flanken steil zu machen
solltest Du jeweils einen 1K Widerstand nehmen. Da bist Du auf Nummer sicher, sofern nicht schon irgendwo auf den Leitungen Widerstände dran sind.
Das unterte Bit ist immer das Read/Write Bit, deshalb musst Du deine Adresse einmal nach links schieben und dann das R/W Bit ranbasteln.
Damit sind dein Adressen tatsächlich alle über $80 das ist richtig.
Wenn die Adresse von dem angesprochenem Chip nicht stimmt, dann macht der Chip auch nix und dein Software verweilt unendlich in einer Warteschleife.
Du brauchst auf BEIDEN Leitungen einen Widerstand nach Plus. Um die volle Übertragungsrate zu bekommen, sprich Flanken steil zu machen
solltest Du jeweils einen 1K Widerstand nehmen. Da bist Du auf Nummer sicher, sofern nicht schon irgendwo auf den Leitungen Widerstände dran sind.
Das unterte Bit ist immer das Read/Write Bit, deshalb musst Du deine Adresse einmal nach links schieben und dann das R/W Bit ranbasteln.
Damit sind dein Adressen tatsächlich alle über $80 das ist richtig.
Wenn die Adresse von dem angesprochenem Chip nicht stimmt, dann macht der Chip auch nix und dein Software verweilt unendlich in einer Warteschleife.
Zuletzt geändert von siro am Sa 28. Okt 2017, 16:59, insgesamt 1-mal geändert.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
-
- Beiträge: 6918
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Atmega328p I²C
Juhu jetzt läufts.

Genau, dies war das Problem, anscheinend war beim Muster-Code das Linksschieben schon berücksichtigt.Mithin muss die "wahre" Adresse größer $80 sein, wenn das höchste Bit gesetzt ist. Die im Sketch angegebene Adresse 0x48 ist also die unverschobene 7bit-Adresse für Adresspin nach GND.
Auf den ADS1115-Platinen sich 10K Widerstände verlötet. Momentan hab ich 2 Platinen, somit habe ich 5K.Du brauchst auf BEIDEN Leitungen einen Widerstand nach Plus. Um die volle Übertragungsrate zu bekommen, sprich Flanken steil zu machen
solltest Du jeweils einen 1K Widerstand nehmen. Da bist Du auf Nummer sicher, sofern nicht schon irgendwo auf den Leitungen Widerstände dran sind.
Code: Alles auswählen
procedure WriteADS1115(addr: UInt16);
begin
Buf[0] := 1;
Buf[1] := %11000011;
Buf[2] := %11100011;
TWIStart(addr shl 1);
TWIWrite(Buf[0]);
TWIWrite(Buf[1]);
TWIWrite(Buf[2]);
TWIStop;
end;
function ReadADS1115(addr: UInt16): UInt16;
begin
Buf[0] := 0;
Buf[1] := 0;
Buf[2] := 0;
TWIStart(addr shl 1); // geändert
TWIWrite(Buf[0]);
TWIStop;
TWIStart((addr shl 1) or 1); // geändert
Buf[0] := TWIReadACK;
Buf[1] := TWIReadNACK;
TWIStop;
Result := Buf[0] * $100 + Buf[1];
end;
begin
cli;
UARTInit;
TWIInit;
sei;
repeat
WriteADS1115(ADSaddr0);
Data := ReadADS1115(ADSaddr0);
str(Data: 10, s);
UARTSendString(s);
WriteADS1115(ADSaddr1);
Data := ReadADS1115(ADSaddr1);
str(Data: 10, s);
UARTSendString(s);
UARTSendString(#13#10);
until 1 = 2;
end.
Zuletzt geändert von Mathias am Sa 28. Okt 2017, 18:02, insgesamt 1-mal geändert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 760
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Atmega328p I²C
Hm, sind nicht deine Read Writes vertauscht
RW Bit Write = LOW
RW Bit Read = HIGH
oder ich hab grad nen Knoten im Kopf....

RW Bit Write = LOW
RW Bit Read = HIGH
oder ich hab grad nen Knoten im Kopf....
Zuletzt geändert von siro am Sa 28. Okt 2017, 17:09, insgesamt 1-mal geändert.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
-
- Beiträge: 6918
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Atmega328p I²C
Meinst du dies ? Wen ja, diese habe ich noch getauscht .deine beiden definierten Konstanten sind glaube ich vertauscht, die hast Du aber auch nicht benutzt.
Code: Alles auswählen
Buf[1] := %11000011;
Buf[2] := %11100011;
Diese Muster hatte ich auch in den Fingern, da wird 3 und 7 geschiftet. http://www.embedds.com/programming-avr-i2c-interface/
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 6918
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Atmega328p I²C
Dies stimmt schon, zuerst muss eine 0 in den ADS geschrieben werden, erst dann kann man lesen.Hm, sind nicht deine Read Writes vertauscht![]()
RW Bit Write = LOW
RW Bit Read = HIGH
oder ich hab grad nen Knoten im Kopf.
Code: Alles auswählen
TWIStart(addr shl 1);
TWIWrite(Buf[0]);
TWIStop;
TWIStart((addr shl 1) or 1);
Buf[0] := TWIReadACK;
Buf[1] := TWIReadNACK;
TWIStop;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 760
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Atmega328p I²C
Ja ich meinte die Konstanten..
const
ads1115wr = %10010001;
ads1115rd = %10010000;
const
ads1115wr = %10010001;
ads1115rd = %10010000;
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Atmega328p I²C
Dennoch bleibt in Deinem Programm das Problem mit dem Slave Clock Stretch beim Lesen.
Die Definition vom I2C umfasst, dass der Slave den Clock auf low ziehen darf, wenn er mehr Zeit zum Antworten braucht. Dann muss der Master warten, bis der Slave wieder bereit ist. Das ist afaik beim Hardware-TWI der Atmegas eingebaut.
Zieht jetzt irgendwas den SCL dauerhaft auf low, z.B. ein Kurzschluss, dann bleibt der Controller in der Read-Routine hängen. Du solltest da ein Timeout einbauen, sowas wie: Wenn die while-Schleife nach xx Durchläufen nicht beendet ist, dann beende sie mit einem ungültigen Wert.
Die Definition vom I2C umfasst, dass der Slave den Clock auf low ziehen darf, wenn er mehr Zeit zum Antworten braucht. Dann muss der Master warten, bis der Slave wieder bereit ist. Das ist afaik beim Hardware-TWI der Atmegas eingebaut.
Zieht jetzt irgendwas den SCL dauerhaft auf low, z.B. ein Kurzschluss, dann bleibt der Controller in der Read-Routine hängen. Du solltest da ein Timeout einbauen, sowas wie: Wenn die while-Schleife nach xx Durchläufen nicht beendet ist, dann beende sie mit einem ungültigen Wert.