PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C Bus mit USI



Nightflyer
19.05.2013, 19:24
Hallo Zusammen

Ich bin dabei eine Verbindung mit einem I2C bus zwischen einem Attin45 (Master) und einem Attiny85 (Slave) aufzubauen. Der Master macht die I2C Schnittstelle per Software. Beim Slave verwende ich das USI mit Start und OVF Interrupt. Der Master_write_mode funktioniert, ich kann mehrere bytes zum Slave übertragen. Nun habe ich Probleme beim Master_read_mode. Slaveadresse kommt beim Slave an, und jetzt sollte der Slave ein byte zurück an den Master senden, geht aber irgendwie nicht. Ich weiss nicht genau, ob ich das DDRB Register richtig setzte, habe da schon mehrere Varianten versucht.

Ich probiere nun seit Tagen, aber ich sehe vor lauter Bäume den Wald nicht mehr:confused:
Wahrscheinlich ist es nur eine kleine Sache...

Nightflyer
26.05.2013, 12:18
So habe den I2C Bus mit dem Oszi unter die Lupe genommen. Mit dem bisherigen Code vom Slave wurde das ACK nach dem empfangen der Adresse, nicht an Master gesendet.

Theoretisch sollte der Ablauf des Slaves doch so sein:
-START ISR, Counter auf 0 setzten
-wenn Counteroverflow, dann wurde die Adresse empfangen, nun ACK senden -> SDA auf Output, Counter = 14

wenn ich SDA auf Output setzte, geht SDA auf low, verlasse ich nun die OVF-ISR, geht SDA sofort wieder auf high. Ich kann also nicht einmal ein ACK vom Slave zum Master senden.



$regfile = "attiny85.dat"
$crystal = 8000000

Dim Slave_adress As Byte
Dim Master_read As Byte
Dim I2c_mode As Byte
Dim Data_byte As Byte
Dim Command As Byte
Dim Input_buffer(12) As Byte
Dim Count As Byte



Slave_adress = &H30 'Slave Adresse
Master_read = Slave_adress + 1


Enable Interrupts 'Interrupts einschalten

Usicr = &B10101100 'Start enable, i2c mode, ext. clock
'Config Portb.0 = Input 'SDA

On Usi_start I2c_start Nosave
On Usi_ovf I2c_read_write Nosave


Open "comb.4:1200,8,n,1" For Output As #1


Do 'Hauptprogramm
'Printbin #1 , Count
'Printbin #1 , Input_buffer(1) , 12
'Waitms 250
Loop


End



I2c_start:
I2c_mode = 0
Count = 0
Config Portb.0 = Input 'SDA
Bitwait Portb.2 , Reset 'Warte bis Start kondition fertig
Usicr = &B11111000 'Start enable, Owerflow enable, i2c mode, SCL low, ext. clock
'Usidr = 0
Usisr = &B11110000 'Reset Flags
Return


I2c_read_write:
Select Case I2c_mode
Case 0 'Adress Mode
Select Case Usidr
Case Slave_adress
I2c_mode = 11
Usidr = 0
Usisr = 14
Case Master_read
I2c_mode = 12
Ddrb.0 = 1 '<--- SDA auf Output setzten
Usisr = 14
Case Else
Usisr = 0
Usicr = &B10101000 'Start enable, i2c mode, ext. clock
End Select
Case 1 'Master write Mode
If Count = 0 Then
Command = Usidr
Else
Input_buffer(count) = Usidr
End If
Incr Count
I2c_mode = 11
Usidr = 0
Usisr = 14
Case 2 'Master read Mode
I2c_mode = 12
Usidr = 0
Usisr = 14
Case 11 'write ACK to Master
I2c_mode = 1
Usidr = 255
Usisr = 0
Case 12 'read ACK from Master
I2c_mode = 2
Usidr = &B01101000 '<-- Byte das zum Master ¸bertragen werden soll !!!
Usisr = 0
End Select
Set Usisr.6 'Reset Counteroverflow
Return



25594


Im Datenblatt steht:
When the output driver is enabled for the SDA pin it will force the line SDA low if the output of the USI Data Register or the corresponding bit in the PORTB register is zero. Otherwise, the SDA line will not be driven (i.e., it is released).


Mein Problem ist, wenn ich SDA auf Output schalte, wird das Daten Register nicht gesendet.


Ich blicke da einfach nicht durch, sollte doch eigentlich mit dem Code funktionieren ?? :(:(
Was habe ich vergessen ? Hat jemand mit dem USI Erfahrung, der mir da weiter helfen kann ?