mikrocontroller.net

Forum: Compiler & IDEs TWI Slave Programmieren


Autor: TWI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo.

Mein Ziel ist es eine Kommunikation zwischen 2 Atmegas über das TWI 
Interface herzustellen. Für den Master verwende ich die Library von 
Peter Fleury. Damit bin ich eigentlich recht zufrieden.
Nun ist die Programmierung des Slave Bausteins an der Reihe. Mit dem 
Master möchte ich immer so etwas senden, was dann vom Slave ausgewertet 
werden soll:
i2c_start_wait(0x00+I2C_WRITE);
i2c_write(byte0);
i2c_write(byte1);
i2c_write(byte2);
i2c_write(byte3);
i2c_write(byte4);
i2c_stop();

Dazu habe ich jetzt ein paar allgemeine Fragen, wie man das am besten 
realisiert. Zum einen erst einmal prüfen und auswerten von TWSR in der 
ISR, oder in einer externen Funktion?
Eigentlich sollte man die ISRs ja so kurz wie möglich halten. Aber ich 
habe im Datenblatt keine Möglichkeit gesehen, die Signalisiert, dass ein 
neues Byte da ist. Hat da einer eine Idee?

Die nächste Frage ist, wie realisiert man die Auswertung. Ich würde die 
ganzen Bytes jetzt einfach in ein Array schreiben, was eben mit der 
Start Condition gelöscht wird, und nach der stop ausgewertet wird.

Autor: TWI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fehlen noch Infos meinerseits, oder hat keiner von euch eine Idee?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kennst du

AVR315: Using the TWI module as I2C master
http://www.atmel.com/dyn/resources/prod_documents/...

AVR311: Using the TWI module as I2C slave
http://www.atmel.com/dyn/resources/prod_documents/...

Den Code gibt es auf
http://www.atmel.com/dyn/products/app_notes.asp?fa...

Autor: TWI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo.

die Dokumente habe ich mir schon angesehen. Aber ich finde da nirgends 
Code, nur Funktionsnamen. Das einzige, was ich erst einmal machen möchte 
ist ein paar Bytes empfangen und auszuwerten.

Autor: TWI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK. Den Code habe ich jetzt gefunden. Leider ist der etwas komplex und 
deckt wesentlich mehr ab, als ich brauche.

Autor: Florian Müller (flomll)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich finde den Code nicht! Kann mir jemand den genauen Link posten?

Autor: ... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Kurt Harders (Firma: KHTronik) (kurtharders)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dieser Code sollte als Basis reichen:
/*
 * Beispielprogramm eines TWI (I2C) Slave. Getestet mit ATMega8
 *
 * Die gesamte Behandlung der TWI-Zustände erfolgt in der Interrupt-Routine. Das Hauptprogramm tut nichts.
 * Wenn die Daten nicht direkt in der Interruptroutine bearbeitet werden können, muss man am Ende den Interrupt ausschalten
 * und nach der Verarbeitung im Haptprogramm wieder einschalten. Aber Achtung: wenn der Prozessor nicht auf TWI-Adressanfragen reagiert,
 * gibt es einen SLA_NACK beim Sender.
 *
 */

#include "util/delay.h"
#include "avr/interrupt.h"
#include "util/twi.h"

static uint8_t data[64];    // Datenpuffer
volatile uint8_t ind;      // Index in den Datenpuffer
volatile uint8_t max;      // Anzahl der zu sendenden Bytes bei Slave-Transmitter-Betrieb

/*
 * Die einzelnen Zustände der TWI-State-machine findet man in der Atmel Dokumentation.
 * Der Kommentar gibt die Ursache des Interrupts an.
 */
ISR(TWI_vect) {
  switch (TWSR & TW_STATUS_MASK) {
  // TW_SR.... Slave Receiver
  // Erkennung der eigene Adresse nach verschiedenen Startbedingungen
  case TW_SR_ARB_LOST_SLA_ACK:
  case TW_SR_ARB_LOST_GCALL_ACK:
  case TW_SR_GCALL_ACK:
  case TW_SR_SLA_ACK:
    ind = 0;
    // Adresse quittieren
    TWCR = (1 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    break;
  // Datenbyte erkannt und mit ACK quittiert
  case TW_SR_GCALL_DATA_ACK:
  case TW_SR_DATA_ACK:
    // Noch Platz im Puffer?
    if (ind < sizeof data) {
      data[ind++] = TWDR;
    }
    // Quittieren und nächstes Byte anfordern
    TWCR = (1 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    break;
  // NACK im Receiver-Mode führt zum Rücksetzen des TWI-Interfaces
  case TW_SR_GCALL_DATA_NACK:
  case TW_SR_DATA_NACK:
    TWCR = (1 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    ind = 0;
    break;
  // STOP erkannt: TWI-Interface in Grundstellung bringen.
  case TW_SR_STOP:
    TWCR = (1 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    ind = 0;
    break;
  // TW_ST.... Slave Transmitter
  // Adresse erkannt, erstes Byte (Länge) senden
  case TW_ST_ARB_LOST_SLA_ACK:
  case TW_ST_SLA_ACK:
    ind = 0;
    max = 8;    // Länge des Sendetelegramms
    TWDR = max;
    TWCR = (1 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    break;
  // Byte wurde quittiert, nächstes Byte ist angefordert
  case TW_ST_DATA_ACK:
    if (ind < max) {
      // Es sind noch Daten da, also ACK
      TWDR = data[32 + ind++];
      TWCR = (1 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    } else {
      // Zu viele Daten angefordert, also NACK
      TWCR = (1 << TWINT) | (0 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    }
    break;
  // NACK bzw. ACK auf letztes Datenbyte erhalten: TWI-Interface in Grundstellung
  case TW_ST_DATA_NACK:
  case TW_ST_LAST_DATA:
    // hier die Daten verarbeiten. Z.B. umkopieren o.ä. Wenn es längere Aktionen sind, in das Hauptprogramm auslagern
    TWCR = (1 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
    ind = 0;
    break;
  }
}

int main(int argc, char** argv) {
  uint8_t i;

  DDRB = 0x00;
  PORTB = 0xff;
  DDRC = ((0 << DDC0) | (0 << DDC1) | (0 << DDC2) | (0 << DDC3) | (1 << DDC4) | (1 << DDC5));
  PORTC = ((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3) | (0 << DDC4) | (0 << DDC5));
  DDRD = 0x00;
  PORTD = 0xff;

  for (i = 0; i < sizeof data; i++) {
    data[i] = i;
  }

  // Adressregister (TWAR) auf Adresse setzen. Achtung: 1x links schieben, da Bit 0 für Global call verwendet wird
  TWAR = (1 << 1);
  // Interrupt erlauben und ACK auf Adresse aktivieren
  TWCR = (0 << TWINT) | (1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (1 << TWEN) | (1 << TWIE);
  sei();

  // alles läuft jetzt im Interrupt
  for (;;) {
  }
}
Grüße, Kurt

Autor: XMEGA (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

< TWI schrieb:
> Dazu habe ich jetzt ein paar allgemeine Fragen

schau dir mal die Seite an. Plus Beispieldateien!

http://www.kramann.info/73_COACH3/10_Ergaenzungen/...


Gruß XMEGA

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.