I2C "passthrough" device mit Atmega328

#6974694
Lesenswert?

Für mein Retro-TV Projekt, aber sicher auch mal für andere 
I2C-Basteleien geeignet, möchte ich mir ein "Zwischenschaltgerät" für 
ein am I2C Bus bauen. Es soll vor einen zu untersuchenden Baustein in 
die SDA/SCL Leitung eingefügt werden, die Kommunikation durchleiten aber 
zusätzlich auf eine serielle Konsole ausgeben. Das Device muss also 
gleichzeitig als Slave und einmal als Master arbeiten. Fast-Mode ist 
erstmal nicht notwendig.

Also im Grunde klingt die Aufgabe trivial, aber bei genauerer 
Betrachtung ist sie das nicht.

Zum üben habe ich mir einen meiner Arduino Nanos mit dem Atmega328 
geschnappt und losgelegt, bin aber schon bald auf Probleme gestoßen für 
die ich so keine Lösung hatte.

Problem 1: "Nur ein TWI Port im Atmega328"
Der Atmega328p hat nur einen I2C (TWI) Controller, den anderen I2C Port 
muss ich per Software (Bigbang) emulieren. Da schien es mir ratsam die 
Slave-Emulation auf den HW-Port zu nehmen, da ich so per Interrupt auf 
die Sendung des Master reagieren kann und nicht immer einen Pin pollen 
muss.

Problem 2: "Timing"
Ich glaube ein Grund warum das bei mir nicht funktionierte war das 
Timing. Das ist selbst bei nur 50kHz Takt schon kritisch per Software. 
Wenn ich ein Byte vom Master empfange, dann muss ich dieses ja zum Slave 
senden und seine Antwort abwarten, welche ich dann zum Master schicke. 
Das dauert sehr viel länger als wenn Master/Slave direkt verbunden sind. 
Ich müsste also sowas wie ein Clock-Streching durchführen können um den 
Master hinzuhalten. Dazu habe ich keine Funktion in den Libs gefunden 
die ich mir so angesehen habe.

Problem 3: "NACK senden"
Wenn mein Device vom Master ein Byte empfängt auf das der Slave beim 
Empfang aber mit NACK antworten würde, dann habe ich dem Master aber 
bereits ein ACK gesendet. Ich müsste also, bevor ich dem Master ein 
ACK/NACK sende, das Byte zum Slave schicken und abwarten was er 
antwortet. Das führte mich wieder zu Problem 2

Gibt es Libs die diese Low_level Funktionalitäten unterstützen oder muss 
ich mir da was selbst machen?
Mit diesen Libs habe ich bereits rumexperimentiert:
- Standard <Wire.h>
- 
https://travis-ci.com/Seeed-Studio/Arduino_Software_I2C.svg?branch=maste
- https://github.com/bitbank2/BitBang_I2C
Gast #6974708
Lesenswert?

Olli Z. schrieb:
> Problem 2: "Timing"
> Ich glaube ein Grund warum das bei mir nicht funktionierte war das
> Timing. Das ist selbst bei nur 50kHz Takt schon kritisch per Software.

Beim I2C-Timing geht es nicht um Glauben, sondern um das Einhalten der 
Datenblätter.
I2C ist durch den Clock gesteuert, d.h. die Frequenz ist ziemlich 
unkritisch, solange sie nicht zu hoch ist.
Wenn allerdings die Daten von deinem Master schneller rein getaktet 
werden, als du sie weiterreichen kannst, brauchst du ausreichend Puffer.
Häng einen LA dran und gucke, was schief läuft.
#6974715
Lesenswert?

Olli Z. schrieb:
> Für mein Retro-TV Projekt, aber sicher auch mal für andere
> I2C-Basteleien geeignet, möchte ich mir ein "Zwischenschaltgerät" für
> ein am I2C Bus bauen. Es soll vor einen zu untersuchenden Baustein in
> die SDA/SCL Leitung eingefügt werden, die Kommunikation durchleiten aber
> zusätzlich auf eine serielle Konsole ausgeben.

Ein Logic Analyzer würde das auch machen, aber das Originalsignal nicht 
beeinflussen. Das wäre ein deutlich sinnvollerer Ansatz.

fchk
Gast #6974720
Lesenswert?

Kevin M. schrieb:
> Warum willst du die Nachricht durchschleifen? Monitor doch einfach
> die Pegel der Leitungen und gib das aus.

Da hat Kevin absolut Recht.
Das Durchschleifen verändert das I2C Timing, Bus Hookups, etc
Du wirst viel mehr Probleme mit dem Debuggen deiner Lösung haben, als du 
dann was gescheites auf dem Bus sehen wirst.
Miss die Pegel besser mit einem Oszi oder LA. Unter Umständen hast du 
dort euch schon einen Protokollanalyzer mit drin
#6974721
Lesenswert?

Bei so einem "man in the middle" braucht es schon einige Überlegungen 
zur Realisierung.
Man muss z.B. sowohl sda wie auch scl zusätzlich zur 
Hardwareschnittstelle noch auf Portpins legen. Wie sollen sonst beim 
Lesevorgang des Masters die Daten bitweise weitergegeben werden? Der 
Lauscher sieht die Daten ja sonst erst, wenn ein komplettes Byte im 
Datenregister eingetrudelt ist.

Zudem muss man am Beginn der Sitzung die Adresse des Slaves kopieren, 
sonst werden die Daten des Masters einfach ignoriert.

Mitlesen ohne die Verbindung zu unterbrechen ist wesentlich einfacher.
#6974723
Lesenswert?

Noch ein Problem zu oben: Ich kann das nicht auf Byte-Ebene 
durchschleifen, sondern muss immer eine ganze Kommunikation (Frame) 
einlesen, da ich sonst Transmission-End Signale falsch setze.
Also müsste ich wohl erstmal alles was der Master zum Slave senden will 
in einen internen Buffer laden (der TWI-HW Buffer dürfte nicht besonders 
groß sein) und dann das zum Slave senden.
1
#include <Wire.h>
2
#include "SoftwareI2C.h"
3

4
SoftwareI2C softwarei2c;
5

6
void setup()
7
{
8
  // Slave simulation, using internal TWI interface
9
  Wire.begin(0x45); // want 7-Bit address
10
  Wire.onReceive(irq_masterSend);
11
  Wire.onRequest(irq_masterRead); 
12

13
  // Master simulation, using Bitbang
14
  // SDA = Port "D2" (green) wh-vt
15
  // SCL = Port "D3" (blue)  bu-gy
16
  softwarei2c.begin(2, 3); // sda, scl
17
}
18

19
/**
20
 * I2C-Master has send data to slave (write)
21
 */
22
void irq_masterSend(int num_received_bytes)
23
{
24
  // read all bytes received into buffer
25
  uint8_t buffer[255];
26
  int i = 0;
27
  while(Wire.available())
28
  {
29
    uint8_t data = Wire.read();
30
    buffer[i++] = data;
31
  }
32

33
  // relay received message to TDA
34
  softwarei2c.beginTransmission(0x45);
35
  softwarei2c.write(num_received_bytes, buffer);
36
  softwarei2c.endTransmission();
37
}
38
...

Eigentlich wäre es für den I2C-Replicator doch besser die Symbole zu 
erkennen und weiterzuleiten, also z.B. START vom Master erkannt, gebe 
START zum Slave, Byte erhalten, sende Byte zum Slave, STOP erkennt, 
sende STOP, Repeated-START erkannt... usw.
#6974737
Lesenswert?

Woher kann mein Slave-Code wissen wieviele Bytes der Master denn gern 
lesen möchte? Ich müsste ja beim ersten Receive-Request vom Master 
eigentlich abwechseln selbst den Slave abfragen, dann das Byte senden, 
warten ob der Master noch eines möchte, usw.
Da wüsste ich garnicht wie man das mit der Wire-Lib macht.
#6974740
Lesenswert?

Den ganzen Schlunz erst einlesen und dann weitersenden wird sicher 
tricky.

Der originale Master müsste dann zwischen Adresse, Controlword, whatever 
zum Slave schicken und Response lesen die komplette Zeit warten, bis die 
Kommunikation zwischen Replikator und Slave stattgefunden hat. 
Vermutlich ließe sich das mit clockstretching realisieren - wenn der 
Master es denn beherrscht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren