Atmega328p I²C

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Mathias
Beiträge: 6166
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Atmega328p I²C

Beitrag von Mathias »

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.
Dateianhänge
Project1.pas.tar.gz
(1.1 KiB) 92-mal heruntergeladen
arduino.ino.tar.gz
(1.12 KiB) 94-mal heruntergeladen
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
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

Beitrag von Timm Thaler »

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.

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Atmega328p I²C

Beitrag von siro »

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
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Timm Thaler
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

Beitrag von Timm Thaler »

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.

Mathias
Beiträge: 6166
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Atmega328p I²C

Beitrag von Mathias »

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 ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
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

Beitrag von Timm Thaler »

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.

Mathias
Beiträge: 6166
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Atmega328p I²C

Beitrag von Mathias »

Was ist es denn für ein Sensor?

ADS1115 http://henrysbench.capnfatz.com/henrys- ... -tutorial/
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. :wink:
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
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

Beitrag von Timm Thaler »

Das Datenblatt sagt:

Code: Alles auswählen

ADDR PIN CONNECTION SLAVE ADDRESS
GND 1001000
VDD 1001001
SDA 1001010
SCL 1001011


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.

Code: Alles auswählen

const
  ads1115wr = %10010000;  // geändert, Write ist 0, Read ist 1
  ads1115rd = %10010001;


Wären die "wahren" Adressen in Pascal.
Zuletzt geändert von Timm Thaler am Sa 28. Okt 2017, 17:18, insgesamt 1-mal geändert.

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Atmega328p I²C

Beitrag von siro »

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.
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...

Mathias
Beiträge: 6166
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Atmega328p I²C

Beitrag von Mathias »

Juhu jetzt läufts. :shock:

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.
Genau, dies war das Problem, anscheinend war beim Muster-Code das Linksschieben schon berücksichtigt.

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.

Auf den ADS1115-Platinen sich 10K Widerstände verlötet. Momentan hab ich 2 Platinen, somit habe ich 5K.

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

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Atmega328p I²C

Beitrag von siro »

Hm, sind nicht deine Read Writes vertauscht :cry:

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...

Mathias
Beiträge: 6166
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Atmega328p I²C

Beitrag von Mathias »

deine beiden definierten Konstanten sind glaube ich vertauscht, die hast Du aber auch nicht benutzt.

Meinst du dies ? Wen ja, diese habe ich noch getauscht .

Code: Alles auswählen

   Buf[1] := %11000011;
   Buf[2] := %11100011;


Danke eurer Hilfe habe ich es geschafft, sonst wäre ich jetzt noch am üben.

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

Mathias
Beiträge: 6166
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Atmega328p I²C

Beitrag von Mathias »

Hm, sind nicht deine Read Writes vertauscht :cry:

RW Bit Write = LOW
RW Bit Read = HIGH

oder ich hab grad nen Knoten im Kopf.

Dies stimmt schon, zuerst muss eine 0 in den ADS geschrieben werden, erst dann kann man lesen.

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

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Atmega328p I²C

Beitrag von siro »

Ja ich meinte die Konstanten..
const
ads1115wr = %10010001;
ads1115rd = %10010000;
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Timm Thaler
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

Beitrag von Timm Thaler »

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.

Antworten