Um Daten zwischen einem Raspberry Pi und einem AVR-Microcontroller
auszutauschen, kann man das I2C/TWI-Protokoll benutzen. Es braucht nur
zwei Leitungen und ist relativ simpel.
- ATmega8 (weil der Hardware-I2C/TWI hat, es gehen auch andere von AVR,
im Datenblatt sollte aber unter Features "Byte-oriented Two-wire Serial
Interface" aufgeführt sein)
- Raspberry Pi
*ACHTUNG: Beim Verbinden des AVR mit dem RPi darauf achten, dass der AVR
mit 3,3V läuft! Ansonsten wird der RPi beschädigt!*
Zur Verbindung muss man einfach SDA und SCL des Raspberry (siehe [3],
also Pin 3 und 5) jeweils mit SDA und SCL am AVR verbinden, beim ATmega8
sind das Pin 27 und 28. Die Leitungen müssen außerdem jeweils mittels
Pull-up-Widerstand mit Vcc verbunden werden.
Beim ATmega der Code ist einfach die Bibliothek von [1].
Beim Raspberry benutze ich die I2C-Bibliothek von [2] und den folgenden
Code:
Du kannst mittels eines Levelshifters wie dem hier
http://www.watterott.com/de/Level-Shifter natürlich auch einen 5V AVR
verwenden. Außerdem, warum braucht man PullUP Widerstände für SDA und
SCL?
Hier zum Beispiel wird erklärt der RPI habe bereits PullUp Widerstände.
http://binerry.de/post/26685647322/raspberry-pi-and-i2c
Wenn du weitere Widerstände hinzufügst hast du die parallel geschaltet
Widerstände was im Endeffekt dazu führen kann, dass der PullUp zu gering
ist.
Ansonsten danke für deinen Beitrag, genau das habe ich gesucht!
Hallo !
kurze Info falls das wirklich jemand (so wie ich) probiert und dann
stundenlang den Fehler sucht !
Der Raspberry Pi unterstützt kein clock stretching !!
Die (SCL) Taktleitung wird nur maskiert und demaskiert wodurch spikes
entstehen die beide Kommunikationspartner stören kann.
http://www.advamation.de/technik/raspberrypi/rpi-i2c-bug.html
Marco Oklitz schrieb:> Der Raspberry Pi unterstützt kein clock stretching !!
hi, in den application notes von Atmel zum TWI heisst es, dass der Takt
des Slave mindestens 16x so schnell sein muss, wie der Takt des TWI vom
Master. also bei standartmäßigen 100KHz wären das dann min 1,6MHz. Mit
dem internen Takt kommt ma da nicht hin.
Nochwas: die vorgeschlagene lib für den Atmega unterstützt, so wie man
sie downloaden kann, keine Rückmeldung für den "general call". Um darauf
zu reagieren ist die lib wie unten in den Kommentaren vermerkt zu
ergänzen.
Ebenso die Adresse: diese umfasst, zumindest beim Atmega 8, 16 und 32,
eine Größe von 7Bit. Der Rpi liest sogar nur Adressen bis 0x77 aus. die
Adresse muss also eine Stelle nach links geschoben werden und zusätzlich
das niederwertigste Bit gesetzt werden um auf einen "general call" zu
reagieren.
Ich kämpfe auch schon die ganze Zeit damit rum, heut mittag werd ich das
mal testen.
Hallo,
ich bin neu hier und versuche jetzt schon seit einigen Tagen eine
Kommunikation zwischen meinem Raspberry und ATMEGA8 herzustellen. Ohne
Erfolg. Versuche es auch wie oben von "McLovin" beschrieben mit der
Libary von jtronics. Ich habe aber keine Ahnung wie ich die einbinden
muss. Vlt. kann mir ja hier einer helfen. Benutze ATMEL Studio6.
Hab grad die umgekehrte Richtung in Arbeit, also den RasPi als I2C
Slave. Sinn: Ersatz eines bisher auf AVR basierenden Datenloggers mit
Webinterface durch den RasPi. Da der RasPi aber von sich aus keinen I2C
Slave unterstützt, setzt ein ATtiny841 das I2C in UART um. UART kann der
RasPi besser.
So ist der RasPi nicht nur wesentlich besser als Datenlogger und kann
die Daten auch selbst auswerten und präsentieren. Er kann ausserdem auch
die eigentliche Steuerung programmieren. Was den Firmware-Update
deutlich erleichtert, indem das SPI des RasPi für Atmel-ISP genutzt
wird. Bisher lief das über Turnschuhnetzwerk, dann kann man direkt vom
Entwicklungsrechner aus per Ethernet aktualisieren.
Ich will den Atmega zur Temperaturregelung benutzen. Dazu soll der Rpi
dem Atmega den Sollwert und den Istwert senden. Das bekomme ich nicht
hin irgendwie. Oder hat jemand nen Tip wie das noch anders geht?
Du kannst auch einen EEPROM dazwischen hängen. Das mache ich. Allerdings
nur weil ich mit dem Microcntroller größere Datenmengen sammle. In der
Messpause werden die Daten dann vom Pi ausgelesen und in einer DB
gespeichert.
Der Pi kann übrigens die meisten Sensoren auch selbst auslesen.
Möglcihrerweise brauchst du den zusätzlichen Microcontroller gar nicht.
Ja, da hast Du recht, das würde auch nur mit dem Pi gehen. Ich würde
trotzdem gerne die Kommunikation über TWI hinbekommen. Hat denn evtl.
irgend jemand eine Ahnung wie "McLovin" das gemacht hat und wie ich die
Libary von jtronics korrekt einbinden kann. Wie gesagt ich benutze Atmel
Studio6. Habe die Header-Datei in das entsprechende Verzeichnis kopiert
und versuche nun irgendwie zumindest mal was hinzubekommen, dass ich den
Atmel mit i2c detect vom Raspberry aus sehen kann. Ich weiß aber nicht
wie das gehen soll. Und wozu jeweils die main- und twislave c-dateien
sind. Wenn jemand schonmal sowas gemacht hat und mir weiter helfen kann
wäre ich echt sehr dankbar.
Man sollte auch nochmal darauf hinweisen, dass der I2C-Bus low-aktiv ist
und es daher hinreichend ist, dass nur der RPI den Pull-Up Richtung 3,3V
macht. Der Atmel darf dann ohne eigenen Pull-UP durchaus mit 5V
betrieben werden. Ein Levelshifter ist überflüssig. In vielen
Schaltungen sieht man zur Strombegrenzung im Fehlerfall häufig
Serienwiderstände von ca. 100 Ohm in den Leitungen von SCL und SDA.
Marco Oklitz schrieb:> Der Raspberry Pi unterstützt kein clock stretching !!
Worauf ich aus gegebenem Anlass nochmal hinweisen will.
Ein ATtiny841, mit echtem Hardware-Slave ausgestattet, war bei mir bei
7,37 Mhz nicht in der Lage, einem kein Clock Stretching unterstützenden
100 kHz Master (*) zu folgen, weil durch das Clock Stretching
Nadelimpulse auf SCL auftraten. Bei 50 kHz I2C-Takt funktionierte es.
Dabei ist zudem zu bedenken, dass dieser Effekt direkt von der
Interrupt-Latenz abhängt. Ein mit vielen Interrupt-Quellen versehener
AVR wird eine dementsprechend hohe maximale Reaktionszeit auf
I2C-Interrupts haben, dass auch bei einem Takt von 50 kHz sporadische
Probleme auftreten werden.
M.a.W: Wer einen µC als Slave an einen RPi hängen will, der sollte
entweder den I2C-Takt extrem niedrig legen, oder einen µC mit sehr
kurzer worst case Reaktion auf Interrupts verwenden (wie etwa STM32 mit
Priorisierung). Auch sollte die Kommunikation mit einer CRC abgesichert
werden.
Hopper schrieb:> hi, in den application notes von Atmel zum TWI heisst es, dass der Takt> des Slave mindestens 16x so schnell sein muss, wie der Takt des TWI vom> Master. also bei standartmäßigen 100KHz wären das dann min 1,6MHz. Mit> dem internen Takt kommt ma da nicht hin.
Andere Baustelle. Das hat damit nichts zu tun.
Clock Stretching ist ein Teil der I2C Definition und wird von jedem
mir bekannten per Mikrocontroller implementierten I2C-Slave aktiv
verwendet. Es wirkt sich immer dann aus, wenn ein I2C-Interrupt im Slave
erst quittiert wird, wenn der Master bereits versucht, den Takt
loszulassen, d.h. auf High zu legen. Der Slave hält den Takt dann unten
und wenn der Master darauf nicht korrekt reagiert, dann gibts u.U. einen
zu kurzen SCL.
Die meisten nicht per Mikrocontroller implementierte I2C-Slaves, wie
etwa EEPROMs und viele Sensoren, verwenden kein Clock Stretching, so
dass das Problem dabei nicht auftritt. So ist ein FRAM vom RPi auch bei
1MHz problemlos ansprechbar (steht dort auch drin, dass Clock Stretching
nicht auftritt).
*: Das war bei dem Test zwar kein RPi, sondern ein Bus Pirate, aber das
ändert reinweg nichts am zu Grunde liegenden Problem.
Hallo,
für alle die noch mit der Lib kämpfen: Die Slave-Adresse in der jtronics
Lib muss man noch um ein Bit nach Links verschieben => Für eine Slave
Adresse von z.B. 3 (0011) muss man hier eine 7 (0111) oder eine 6 (0110)
vorgeben je nachdem ob man auch einen General-Call zulassen will! =>
Dies hat auch schon Hopper weiter oben geschrieben, aber man überliest
es leicht ...ging zumindests mir so...
Marco Oklitz schrieb:> Der Raspberry Pi unterstützt kein clock stretching !!
Das ist so nicht ganz richtig.
Wenn das Clock-stretching mindestens eine Clock-periode dauert, macht
der Raspi alles richtig.
Außerdem scheint stretching nur nach dem jeweiligen ACK zu
funktionieren. Das ist beim Empfang etwas ungünstig, da man erst ACK-en
muss und dann erst verarbeiten kann.
Jedenfalls ist es nicht richtig, dass der Raspi die Clock nur maskiert
oder überhaupt kein Clock-stretching unterstützt.
Hallo,
das mit dem Clock-Stretch-Bug des Raspberry Pi (bei mir RPi3b) löst sich
in Luft auf, wenn man das betreffende Timeout-Register auf 0 setzt:
sudo busybox devmem 0x3F80401C 32 0
Erklärung: Laut "BCM2835 ARM Peripherals.pdf" Seite 35 darf das Register
TOUT Null enthalten, um das Timeout des BSC-Moduls (a.k.a. I²C oder TWI)
zu deaktivieren. Standardmäßig enthält es einen von 0 verschiedenen
Wert. Damit verschwindet auch das Problem mit den SCL-Spikes. Ohne
Timeout gibt es bei mir mit dem (recht stark beschäftigten) AVR
keinerlei Probleme mehr.
Ich habe hier eine Konfiguration (in /boot/config.txt) die kein
"dtoverlay = i2c_irgendwas" enthält sondern nur diese beiden Zeilen mit
i2c:
dtparam=i2c1=on
dtparam=i2c_arm=on,i2c_arm_baudrate=400000
Anscheinend lädt das System einen (unbekannten?) Standardtreiber der das
Timeout-Register auf 0 setzt. 400 kHz sind übrigens kein Problem, selbst
mit einer 1 m langen Leitung dazwischen.
Zu der o.a. Zeile mit "sudo busybox":
busybox ist ein Werkzeugsammelsurium genau für Raspberrys und sonstiges
Embedded Linux. Mit der Option "devmem" öffnet es "/dev/mem" auf
funktionierende Weise, mit mmap(). "hexdump -C /dev/mem" geht nämlich
nicht.
Genau wie alle anderen Prozesse benötigt es zum Zugriff Root-Rechte,
deshalb "sudo" davor.
Mit der Adressangabe 0x3F80401C liest man von diesem Offset
(defaultmäßig) einen 32-Bit-Wert. Dabei ist "3F" vom System abhängig (wo
Linux die Hardwareadresse 0x2000'0000 - siehe Datenblatt - einblendet),
die "8040" ist die BSC-Basisadresse aus dem Datenblatt, und "1C" der
Register-Offset von TOUT.
Der nachfolgende Parameter "32" legt die Bitbreite fest, danach die "0"
zum Schreiben derselben (sonst lesen). Die ARM-Hardware weigert sich,
etwas anderes als 32-Bit-Quantitäten entgegenzunehmen.
Schließlich kann man das Byte "3F" der Datei
/proc/device_tree/soc/ranges am Offset 4 entnehmen; beim Raspberry 4
sollte es "FE" lauten. Wer es genau will liest einen 32-Bit-Addierwert
ab Offset 4 und muss den mit ntohl() byte-swappen. Wer auch immer auf
die Idee gekommen sein mag, in dieser Datei Big-Endian unterzubringen:
Ist doch schon lange ausgestorben.
Die ganze (recht kurze) Datei kann man mit "hexdump -C
/proc/device_tree/soc/ranges" angucken.
henni