Hallo Leute,
versuche seit einiger Zeit TWI per USI am ATTiny 2313 zum Laufen zu
bringen. Bin schon kurz davor auf Bit banging zu wechseln, da die
Vereinfachung per USI nur gering zu sein scheint (vor allem als Master).
Und es funktioniert nicht. Also Start und Stop bekomme ich hin. Ich kann
mitlerweise sogar das erste Byte ausgeben. Seit dem ich das aber so weit
habe, dass ein ACK vom Slave zurückkommt, geht danach gar nichts mehr.
Das ACK setzt nämlich SDA auf L und da bleibt es dann auch. Schon nach
dem Senden des ersten Bytes ist USIDC im USISR gesetzt (da habe ich
ACK/NACK noch gar nicht ausgewertet). Sende ich Daten, die kein ACK
ergeben, passiert das nicht und ich kann auch ein zweites Byte senden.
Jetzt setze ich auch das Schieberegister von Hand weiter, aber
eigentlich müsste das per SCL passieren (USICS1:0 = 1). So könnte man
auch ACK und NACK darüber generieren bzw. einlesen. Das funktioniert
aber bei mir gar nicht.
Was auf dem Bus passiert haben ich mit Logicanalyzer verfolgt.
Systemtakt ist 7,37MHz.
1 | cli
| 2 | rcall I2Cinit
| 3 | rcall I2Cstart
| 4 | ldi tmp,0x81 ;Adresse $40 + W (Si7021)
| 5 | rcall I2Csenddata
| 6 | ; brts end ;NACK?
| 7 | ldi tmp,0xE0 ;Kommando
| 8 | rcall I2Csenddata
| 9 | end:
| 10 | rcall I2Cstop
| 11 |
| 12 | loop: rjmp loop
| 13 |
| 14 | I2Cinit:
| 15 | sbi portb,7 ;SCL high
| 16 | sbi portb,5 ;SDA high
| 17 | sbi ddrb,7 ;Port B7 (SCL) als Ausgang
| 18 | sbi ddrb,5 ;Port B5 (SDA) als Ausgang
| 19 | sbi ddrb,0
| 20 | out usidr,ff ;Datenregister mit FF initialisieren
| 21 | ldi tmp,(1<<USIWM1) ; | (3<<USICS0) ;USI-Mode TWI manuellem Clock [163-165]
| 22 | out usicr,tmp
| 23 | ret
| 24 |
| 25 | I2Cdown:
| 26 | clr tmp
| 27 | out usicr,tmp ;I2C abschalten
| 28 | ret
| 29 |
| 30 | I2Cstop:
| 31 | cbi usidr,7 ;SDA auf L (falls H war)
| 32 | nop
| 33 | nop
| 34 | sbi portb,7 ;SCL auf H
| 35 | I2Cstop1:
| 36 | sbis pinb,7 ;warten, dass auf H geht (falls Clock Stretching)
| 37 | rjmp I2Cstop1
| 38 | sbi usidr,7 ;SDA auf H
| 39 | ret
| 40 |
| 41 | I2Cstart:
| 42 | ; out usidr,ff
| 43 | sbi usidr,7 ;SDA auf high (für Restart)
| 44 | nop
| 45 | sbi portb,7 ;SCL auf high (für Restart)
| 46 | I2Cstart1:
| 47 | sbis pinb,7 ;SCL high?
| 48 | rjmp I2Cstart1 ;nein - warten
| 49 | ; out usidr,null
| 50 | cbi usidr,7 ;SDA auf low
| 51 | nop
| 52 | cbi portb,7 ;SCL auf low
| 53 | nop
| 54 | nop
| 55 | nop
| 56 | ret
| 57 |
| 58 | ; Adresse schicken (Adresse + R/W-Bit in tmp)
| 59 | I2Csenddata:
| 60 | out usidr,tmp ;Adresse in Schieberegister
| 61 | ldi tmp,0xf8 ;Interrupt-Flags löschen, Counter auf 8
| 62 | out usisr,tmp
| 63 | ldi tmp,8 ;Bitzähler auf 8
| 64 | I2Csenddata1:
| 65 | sbi usicr,usitc ;SCL toggle H
| 66 | I2Csenddata2:
| 67 | sbis pinb,7 ;SCL high?
| 68 | rjmp I2Csenddata2 ;noch nicht
| 69 | nop
| 70 | sbi usicr,usitc ;CLK toggle L
| 71 | nop
| 72 | sbi usicr,usiclk ;SR eins weiter
| 73 | dec tmp ;Bitzähler, nächstes Bit
| 74 | brne I2Csenddata1 ;fertig? nein
| 75 | ; in tmp,usisr
| 76 | ; rcall u_printhex
| 77 | ; ldi tmp,13
| 78 | ; rcall serout
| 79 | ldi tmp,0xff
| 80 | out usisr,tmp
| 81 | cbi ddrb,5 ;SDA als Eingang
| 82 | sbi usicr,usitc ;CLK toggle H (liest ACK/NACK)
| 83 | nop
| 84 | nop
| 85 | nop
| 86 | nop
| 87 | set
| 88 | sbis pinb,5 ;SDA auf H (NAK)?
| 89 | clt ;nein
| 90 | sbi usicr,usitc ;CLK toggle L
| 91 | sbi ddrb,5 ;SDA auf Ausgang
| 92 | ret
|
Fehler gefunden... Wenn man noch was schreiben will, sollte das LSB 0
sein in der Adresse.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|