www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik USI: I²C/TWI Slave sendet kein ACK :-/


Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi mal wieder,...

Ich habe es nun soweit geschafft dass er die Start Condition erkennt und 
darauf die ISR ausführt in der der Overflow interrupt aktiviert wird. 
Beim Empfangen des ersten Bytes, also Adresse + R/W wird die 
Overflow-ISR ausgeführt in der anhand meines virtuellen TWI 
Statusregisters im SRAM entschieden wird was nun getan wird. Das 
funktioniert soweit alles ganz prima. Nur das USI weigert sich strikt 
ein ACK zu senden.

Hierfür leere ich nämlich das Schieberegister, stelle die 
SDA-Portleitung über das DDRB als Ausgang ein und stelle den Counter auf 
den Wert 14. Bei den nächsten 2 Taktflanken in denen das ACK nun vom 
Master sozusagen "abgeholt" wird läuft der 4-bit-Counter wieder über und 
die Overflow ISR wird ausgeführt.

Das funktioniert alles soweit gut aber das ACK kommt einfach nicht an. 
Der Master meldet mir dass er ein NOT ACK empfangen hat und bricht wie 
erwartet ab. Fehlt irgendwas?
.include "tn26def.inc"        ; Deklarationen für ATtiny26

.equ  adress = 127        ; TWI Adresse


.cseg                ; Programm-Flash
    rjmp  init        ; Reset-Einsprung

.org  0x007            ; USI Start Interrupt
    rjmp  usi_start

.org  0x008            ; USI Overflow Interrupt
    rjmp  twis


.org  0x00C            ; Interrupteinsprünge übergehen

init:  ldi    R16, RAMEND      ; Stapel anlegen
    out    SP, R16

    ldi    R16, 0b11111111    ; PortA als Ausgang
    out    DDRA, R16

    ; USI Control Register
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
    out    USICR, R16

    sei              ; Interrupts aktivieren

loop:  rjmp  loop        ; Endlosschleife



usi_start:
    push  R16          ; Register retten

    ; Start Condition Interrupt Flag zurücksetzen
    ldi    R16, (1 << USISIF)
    out    USISR, R16

    ; Overflow Interrupt aktivieren
    ldi    R16, (1 << USISIE) | (1 << USIOIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
    out    USICR, R16

    ldi    R16, 10        ; Neuen Status laden
    sts    TWSR, R16      ; Status im SRAM speichern

    pop    R16          ; Register wiederherstellen
    reti            ; Kehre zurück



twis:  push  R16          ; Register retten

    ; Counter Overflow Interrupt Flag zurücksetzen
    ldi    R16, (1 << USIOIF)
    out    USISR, R16

;- Adresse ---------------------------------------------------------------------------

    lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
    cpi    R16, 10        ; 10 = A START condition has been transmitted
    brne  twis2        ; Springe zu twis2 wenn ungleich

    ; Adresse überprüfen
    in    R16, USIDR      ; Adresse + R/W in R16 laden
    andi  R16, 0b11111110    ; Maskieren

    push  R17          ; Register retten
    ldi    R17, (adress << 1)  ; Slave Adresse laden

    cp    R16, R17      ; Vergleichen
    pop    R17          ; Register wiederherstellen
    breq  twis1        ; Überspringe nächste 3 Befehle wenn gleich

    ; Adresse stimmt nicht überein
    ; Overflow Interrupt bis zur nächsten START condition deaktivieren
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
    out    USICR, R16

    rjmp  twis_end      ; Springe zum Ende der ISR

    ; Adresse stimmt überein, ACK senden
twis1:  clr    R16          ; Schieberegister leeren
    out    USIDR, R16

    sbi    DDRB, 0        ; Ausgangstreiber an SDA aktivieren

    ldi    R16, 14        ; Counter laden
    out    USISR, R16

    sbi    PORTA, 0      ; Status-LED 1 an

    ldi    R16, 20        ; Neuen Status laden
    sts    TWSR, R16      ; Status im SRAM speichern

    rjmp  twis_end      ; Springe zum Ende der ISR

;- Daten ---------------------------------------------------------------------------

twis2:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
    cpi    R16, 20        ; 20 = Own SLA+W has been received; ACK has been returned
    brne  twis_end      ; Springe wenn ungleich

    sbi    PORTA, 1      ; Status-LED 2 an

    cbi    DDRB, 0        ; DDR an SDA auf low

twis_end:  
    pop    R16          ; Register wiederherstellen
    reti            ; Kehre zurück



.DSEG


; USI - TWI Status Register
TWSR:
.byte  1

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besteht denn eine geringe Chance das Problem jemals gelöst zu bekommen? 
Ich weiß ja dass USI nicht gemocht wird und nicht so verbreitet ist aber 
irgendwen muss das doch auch interessieren oder jemand muss sich damit 
doch mal beschäftigt haben :-(

mfg PoWl

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du schon mal die Atmel Application notes dazu studiert?
z.B. -> AVR312

auf dieser Webseite:
http://www.atmel.com/dyn/products/app_notes.asp?fa...

Gruss Andi

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, hab mich jetzt mal getraut. Da gehts aber schon gleich mit der Frage 
los warum die die SCL-Leitung als Ausgang setzen und auf High ziehen. 
Damit erzeug ich dochn satten Kurzschluss wenn mein Master versucht die 
SCL leitung aktiv auf LOW zu ziehen und ich darf mir mal wieder n neuen 
ATmega8 und n neuen ATtiny26 kaufen. Solche befehle habe ich auch drin 
aber Daten werden trotzdem empfangen von meinem Tiny. Nur das ACK mag er 
nicht senden, trotz dass ich SDA kurzzeitig als Ausgang schalte.

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Got it..

ich habs.. allerdings wird mich jeder Atmelkönig für diesen Code 
hinrichten lassen. Diesen Käse, die SCL leitung aktiv auf high zu 
ziehen, habe ich garnicht drin!? Desweiteren wird der Counter auf 13 
anstatt auf 14 gestellt um das ACK zu senden.. ziemlich paradox aber es 
funktioniert nur so.

Der Empfang funktioniert soweit. Je nach Masterprogramm sollte ein 
Empfang von mehreren Datenbytes hintereinander auch möglich sein.. da 
muss man aber das Programm für die Datenauswertung noch individuell 
anpassen. Ausserdem wird Repeatet Start noch nicht unterstützt, 
irgendwie müsste man die Stop-Condition erkennen? Könnte man in der 
Start-Condition ISR vielleicht überprüfen und entsprechend dem inhalt 
des TWI Statusregisters reagieren... will das mal jemand ausprobieren?

Aehm, das Programm empfängt als Slave unter der Adresse 127 ein 
Datenbyte. Auf R/W wird derzeit noch nicht eingegangen.. da müsste man 
auch noch ne Weiche einbauen.

Immerhin schonmal ein Anfang :-)

mfg PoWl
.include "tn26def.inc"        ; Deklarationen für ATtiny26

.equ  adress = 127        ; TWI Adresse


.cseg                ; Programm-Flash
    rjmp  init        ; Reset-Einsprung

.org  0x007            ; USI Start Interrupt
    rjmp  usi_start

.org  0x008            ; USI Overflow Interrupt
    rjmp  twis


.org  0x00C            ; Interrupteinsprünge übergehen

init:  ldi    R16, RAMEND      ; Stapel anlegen
    out    SP, R16

    ldi    R16, 0b11111111    ; PortA als Ausgang
    out    DDRA, R16

    ; USI Control Register
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
    out    USICR, R16

    ldi    R16, 0xF0
    out    USISR, R16

    sei              ; Interrupts aktivieren

loop:  rjmp  loop        ; Endlosschleife



usi_start:
    push  R16          ; Register retten

    ; Start Condition Interrupt Flag zurücksetzen
    ldi    R16, (1 << USISIF)
    out    USISR, R16

    ; Overflow Interrupt aktivieren
    ldi    R16, (1 << USISIE) | (1 << USIOIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
    out    USICR, R16

    ldi    R16, 10        ; Neuen Status laden
    sts    TWSR, R16      ; Status im SRAM speichern

    pop    R16          ; Register wiederherstellen
    reti            ; Kehre zurück



twis:  push  R16          ; Register retten

    ; Counter Overflow Interrupt Flag zurücksetzen
    ldi    R16, (1 << USIOIF)
    out    USISR, R16

;- Adresse überprüfen -----------------------------------------------------------------

    lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
    cpi    R16, 10        ; 10 = Start Condition wurde erkannt, Adresse wurde gesendet
    brne  twis2        ; Springe zu twis2 wenn ungleich

    in    R16, USIDR      ; Adresse + R/W in R16 laden
    andi  R16, 0b11111110    ; Maskieren

    push  R17          ; Register retten
    ldi    R17, (adress << 1)  ; Slave Adresse laden

    cp    R16, R17      ; Vergleichen
    pop    R17          ; Register wiederherstellen
    breq  twis1        ; Überspringe nächste 3 Befehle wenn gleich

    ; Adresse stimmt nicht überein
    ; Overflow Interrupt bis zur nächsten START condition deaktivieren
    ldi    R16, (1 << USISIE) | (1 << USIWM1) | (1 << USIWM0) | (1 << USICS1)
    out    USICR, R16

    rjmp  twis_end      ; Springe zum Ende der ISR

;- Adresse stimmt überein, ACK senden -------------------------------------------------

twis1:  clr    R16          ; Schieberegister leeren
    out    USIDR, R16

    sbi    DDRB, 0        ; Ausgangstreiber an SDA aktivieren

    ldi    R16, 13        ; Counter laden
    out    USISR, R16

    ldi    R16, 20        ; Neuen Status laden
    sts    TWSR, R16      ; Status im SRAM speichern

    rjmp  twis_end      ; Springe zum Ende der ISR

;- Datenempfang vorbereiten------------------------------------------------------------

twis2:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
    cpi    R16, 20        ; 20 = Eigene Slave-Adresse + R/W wurde empfangen; ACK wurde gesendet
    brne  twis3        ; Springe wenn ungleich

    cbi    DDRB, 0        ; DDR an SDA auf low

    ldi    R16, 30        ; Neuen Status laden
    sts    TWSR, R16      ; Status im SRAM speichern

    rjmp  twis_end      ; Springe zum Ende der ISR

;- Daten wurden empfangen -------------------------------------------------------------

twis3:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
    cpi    R16, 30        ; 30 = Daten wurden empfangen
    brne  twis4        ; Springe wenn ungleich

    in    R16, USIDR      ; Daten einlesen
    out    PORTA, R16

;- Daten wurden empfangen, ACK senden -------------------------------------------------

    clr    R16          ; Schieberegister leeren
    out    USIDR, R16

    sbi    DDRB, 0        ; Ausgangstreiber an SDA aktivieren

    ldi    R16, 13        ; Counter laden
    out    USISR, R16

    ldi    R16, 40        ; Neuen Status laden
    sts    TWSR, R16      ; Status im SRAM speichern

    rjmp  twis_end      ; Springe zum Ende der ISR

;- Datenempfang vorbereiten------------------------------------------------------------

twis4:  lds    R16, TWSR      ; Virtuelles statusregister aus dem SRAM laden
    cpi    R16, 40        ; 40 = Daten wurden empfangen; ACK wurde gesendet
    brne  twis_end      ; Springe wenn ungleich

    cbi    DDRB, 0        ; DDR an SDA auf low

    ldi    R16, 20        ; Neuen Status laden
    sts    TWSR, R16      ; Status im SRAM speichern

twis_end:  
    pop    R16          ; Register wiederherstellen
    reti            ; Kehre zurück



.DSEG


; USI - TWI Status Register
TWSR:
.byte  1

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.