Atmega328p I²C

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.

Atmega328p I²C

Beitragvon Mathias » 27. Okt 2017, 20:59 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.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 27. Okt 2017, 21:43 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.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon siro » 28. Okt 2017, 07:05 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
Grüße von Siro
"C" verCehnfacht die Entwicklungszeit...
siro
 
Beiträge: 221
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 28. Okt 2017, 11:39 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.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 28. Okt 2017, 12:15 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 ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 28. Okt 2017, 12:47 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.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 28. Okt 2017, 13:06 Re: Atmega328p I²C

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 28. Okt 2017, 13:49 Re: Atmega328p I²C

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 28. Okt 2017, 16:18, insgesamt 1-mal geändert.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon siro » 28. Okt 2017, 15:45 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.
Zuletzt geändert von siro am 28. Okt 2017, 15:59, insgesamt 1-mal geändert.
Grüße von Siro
"C" verCehnfacht die Entwicklungszeit...
siro
 
Beiträge: 221
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 28. Okt 2017, 15:58 Re: Atmega328p I²C

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 28. Okt 2017, 17:02, insgesamt 1-mal geändert.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon siro » 28. Okt 2017, 16:04 Re: Atmega328p I²C

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 28. Okt 2017, 16:09, insgesamt 1-mal geändert.
Grüße von Siro
"C" verCehnfacht die Entwicklungszeit...
siro
 
Beiträge: 221
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 28. Okt 2017, 16:08 Re: Atmega328p I²C

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 28. Okt 2017, 16:12 Re: Atmega328p I²C

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 gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon siro » 28. Okt 2017, 16:13 Re: Atmega328p I²C

Ja ich meinte die Konstanten..
const
ads1115wr = %10010001;
ads1115rd = %10010000;
Grüße von Siro
"C" verCehnfacht die Entwicklungszeit...
siro
 
Beiträge: 221
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 28. Okt 2017, 16:16 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.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Sonstiges



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste

porpoises-institution
accuracy-worried