TiRe
31.08.2009, 23:56
Hallo,
Ich probiere gemäß dem Wiki von PicNick eine Atmega8 (intern 8MHz) als TWI-Slave laufen zu lassen. Im ersten Schritt empfängt dieser nur Bytes und gibt sie an die serielle Schnittstelle aus.
Solange als Master ein andere AVR läuft, funktioniert das auch recht gut. Der Master sendet mit den Bascom-Befehlen ein paar Bytes
$regfile = "M8def.dat" ' the used chip
$crystal = 8e6 ' frequency used
$baud = 9600
Config Sda = Portc.4
Config Scl = Portc.5
Dim Nr As Byte ' Servo-Nr
Dim Position As Byte ' Position
Do
I2cstart
I2cwbyte &H64
I2cwbyte &H53 ' "S" Kennzeichen für Servo ansteuern
I2cwbyte &HAA
I2cwbyte &HBB
I2cstop
Wait 1
Loop
End
Der Code im Slave sieht so aus
$regfile = "m8def.dat"
$crystal = 8000000
$include "MyTWI.bas"
$baud = 9600
$hwstack = 64
$swstack = 64
$framesize = 64
Const Tmr_c_prescale = 64
Const Tmr_c_preload = 131
Const Tmr_c_divis = 250
Declare Sub Twi_show_state(byref State As Byte)
Config Portc.0 = Output
Portc.0 = 1
'-------------------------------------------------
' lokale I2C Adresse (als Slave)
'-------------------------------------------------
Const Mn1_adr = &H64
'-------------------------------------------------
' fremde I2C Adresse (als Master)
'-------------------------------------------------
Const Mn2_adr = &H6E
Dim Slv_byte As Byte 'sende Byte (irgendwas)
Dim Twi_mst_buff(24) As Byte 'Buffer für Masterfunktionen
Dim Twi_slv_buff(24) As Byte 'Buffer für Slavefunktionen
'-------------------------------------------------
Config Timer0 = Timer , Prescale = Tmr_c_prescale 'Timer 1mS
On Timer0 Interrupt_ticker ' Timer for Timer Queue
Dim Timeout As Byte
Dim Timediv As Word
'-------------------------------------------------
Print "Slavetester M32slave"
Dim Temp As Byte
Twi_slv_addr = Mn1_adr 'lokale I2C-Adresse
Twi_sr_data = Varptr(twi_slv_buff(1)) 'datenbuffer empfang
Twi_st_data = Varptr(twi_slv_buff(1)) 'datenbuffer senden
Twar = Twi_slv_addr + 1 'I2C Adress Mega32 + GCA
Config Twi = 100000 'I2C Speed
On Twi Twi_mst_slv_isr , Nosave 'ISR f. TWI
Gosub Twi_sense 'Aktivieren Slave-Funktion
Enable Timer0 'Timer
Enable Interrupts 'Generell
'---------------------------------------------
'
'---------------------------------------------
Do
If Twi_slv_flag <> 0 Then
'-----------------------------------------------------------------
' Ergebnis als SLave auswerten
' Vorsicht, der Bus ist solange blockiert
'-----------------------------------------------------------------
Select Case Twi_slv_flag
Case &H60 : Print Spc(10) ; "SLAVE recv:" ; 'es ist was empfangen worden
Print Hex(twi_slv_addr) ; " ";
'Print Twi_sr_cntr ; " ";
For Temp = 1 To Twi_sr_cntr
Print Hex(twi_slv_buff(temp)) ; " "; 'print der Daten
Next
Case &HA8 : Print Spc(10) ; "SLAVE tran:" ; 'es ist was abgeholt worden
Print Hex(twi_slv_addr) ; " ";
For Temp = 1 To Twi_st_cntr
Print Hex(twi_slv_buff(temp)); 'print der Daten
Next
Case &H70 : Print Spc(10) ; "SLAVE GCA :" ; 'ein General Call ist gekommen
Print Hex(twi_slv_addr) ; " ";
For Temp = 1 To Twi_sr_cntr
Print Hex(twi_slv_buff(temp)); 'print der Daten
Next
Case Else:
Print Chr(7) ; 'Irgendein Fehler
Call Twi_show_state(twi_slv_flag) 'Print status-text
End Select
Print
Twi_slv_flag = 0 'löschen marker
Twi_slv_stat = 0 'löschen marker
Gosub Twi_sense 'alles wieder enablen
'und Bus freigeben
End If
'-----------------------------------------------------------------
' Jede Sekunde was senden & empfangen
'-----------------------------------------------------------------
' If Timeout = 1 Then
' Gosub Master_transmit
' If Twi_mst_flag = 0 Then 'Hats geklappt ?
' Timeout = 0 'ja
' ' else (sonst probieren wir's gleich nochmal)
' End If
' End If
'-----------------------------------------------------------------
Loop
End
'----------------------------------------
' 1 mS Ticker
'----------------------------------------
Interrupt_ticker: ' Timer for Timer Queue
Timer0 = Tmr_c_preload
Incr Timediv
If Timediv >= Tmr_c_divis Then
Timeout = 1 'eine Sekunde ist rum
Timediv = 0
End If
Return
'----------------------------------------
$include "Twi_show_state.bas"
'----------------------------------------
Run_wait_master:
Gosub Mst_start 'aufruf
Select Case Twi_mst_flag 'ergebnis ?
Case Twi_m_sent: 'gesendet
Print "<<<<<<MASTER sent:" ;
Print Hex(twi_mst_addr) ; " ";
For Temp = 1 To Twi_mt_cntr
Print Hex(twi_mst_buff(temp));
Next
Print
Twi_mst_flag = 0
Case Twi_m_recv: 'geholt
Print ">>>>>>MASTER read:" ;
Print Hex(twi_mst_addr) ; " ";
For Temp = 1 To Twi_mr_cntr
Print Hex(twi_mst_buff(temp));
Next
Print
Twi_mst_flag = 0
Case Else: 'irgendein Problem
Print Chr(7) ; Hex(twi_mst_addr) ; " ";
Call Twi_show_state(twi_mst_flag)
End Select
Return
'----------------------------------------
' Beispiel 8 byte senden,
' dann mit Rep.Start von gleicher adresse 3 Byte empfangen
'----------------------------------------
Master_transmit:
' sende buffer (mit testdaten) füllen
For Temp = 1 To 24
Twi_mst_buff(temp) = Slv_byte
Next
Twi_mst_addr = Mn2_adr 'I2C adresse
Twi_mt_cntr = 8 ' erstmal 8 Byte senden
Twi_mt_data = Varptr(twi_mst_buff(1)) ' adresse Daten
Twi_mr_cntr = 3 ' dann 3 Byte empfangen
Twi_mr_data = Varptr(twi_mst_buff(1)) ' empfangsbuffer
Gosub Run_wait_master ' auf gehts
Return
Wie gesagt, von AVR zu AVR alles im Butter.
Steuere ich den Bus aber via PC und RS232-Interface an, gibt im zweiten Datenbyte immer wieder einen Clock, der aussieht als sei er á la ACK heruntergeprügelt. Folglich wird der Clock vom Ziel-AVR nicht mehr erkannt und es kommt nur Schrott an. Ein Oszi-Bild vom dem "Defekt" ist angehängt. Prinzipiell bin ich für alle Fehlerquellen offen - das Interface verrichtet aber seit 3 Jahren mit zahlreichen verschiedenen echten I2C Bausteinen in der Haussteuerung seinen Dienst, will sagen das funktioniert..!
Aber was zum Kuckuck verursacht dieses Fehlerbild?
Ach so, der Bus hängt über 2k2 an der Versorgungsspannung. ](*,)
Ich probiere gemäß dem Wiki von PicNick eine Atmega8 (intern 8MHz) als TWI-Slave laufen zu lassen. Im ersten Schritt empfängt dieser nur Bytes und gibt sie an die serielle Schnittstelle aus.
Solange als Master ein andere AVR läuft, funktioniert das auch recht gut. Der Master sendet mit den Bascom-Befehlen ein paar Bytes
$regfile = "M8def.dat" ' the used chip
$crystal = 8e6 ' frequency used
$baud = 9600
Config Sda = Portc.4
Config Scl = Portc.5
Dim Nr As Byte ' Servo-Nr
Dim Position As Byte ' Position
Do
I2cstart
I2cwbyte &H64
I2cwbyte &H53 ' "S" Kennzeichen für Servo ansteuern
I2cwbyte &HAA
I2cwbyte &HBB
I2cstop
Wait 1
Loop
End
Der Code im Slave sieht so aus
$regfile = "m8def.dat"
$crystal = 8000000
$include "MyTWI.bas"
$baud = 9600
$hwstack = 64
$swstack = 64
$framesize = 64
Const Tmr_c_prescale = 64
Const Tmr_c_preload = 131
Const Tmr_c_divis = 250
Declare Sub Twi_show_state(byref State As Byte)
Config Portc.0 = Output
Portc.0 = 1
'-------------------------------------------------
' lokale I2C Adresse (als Slave)
'-------------------------------------------------
Const Mn1_adr = &H64
'-------------------------------------------------
' fremde I2C Adresse (als Master)
'-------------------------------------------------
Const Mn2_adr = &H6E
Dim Slv_byte As Byte 'sende Byte (irgendwas)
Dim Twi_mst_buff(24) As Byte 'Buffer für Masterfunktionen
Dim Twi_slv_buff(24) As Byte 'Buffer für Slavefunktionen
'-------------------------------------------------
Config Timer0 = Timer , Prescale = Tmr_c_prescale 'Timer 1mS
On Timer0 Interrupt_ticker ' Timer for Timer Queue
Dim Timeout As Byte
Dim Timediv As Word
'-------------------------------------------------
Print "Slavetester M32slave"
Dim Temp As Byte
Twi_slv_addr = Mn1_adr 'lokale I2C-Adresse
Twi_sr_data = Varptr(twi_slv_buff(1)) 'datenbuffer empfang
Twi_st_data = Varptr(twi_slv_buff(1)) 'datenbuffer senden
Twar = Twi_slv_addr + 1 'I2C Adress Mega32 + GCA
Config Twi = 100000 'I2C Speed
On Twi Twi_mst_slv_isr , Nosave 'ISR f. TWI
Gosub Twi_sense 'Aktivieren Slave-Funktion
Enable Timer0 'Timer
Enable Interrupts 'Generell
'---------------------------------------------
'
'---------------------------------------------
Do
If Twi_slv_flag <> 0 Then
'-----------------------------------------------------------------
' Ergebnis als SLave auswerten
' Vorsicht, der Bus ist solange blockiert
'-----------------------------------------------------------------
Select Case Twi_slv_flag
Case &H60 : Print Spc(10) ; "SLAVE recv:" ; 'es ist was empfangen worden
Print Hex(twi_slv_addr) ; " ";
'Print Twi_sr_cntr ; " ";
For Temp = 1 To Twi_sr_cntr
Print Hex(twi_slv_buff(temp)) ; " "; 'print der Daten
Next
Case &HA8 : Print Spc(10) ; "SLAVE tran:" ; 'es ist was abgeholt worden
Print Hex(twi_slv_addr) ; " ";
For Temp = 1 To Twi_st_cntr
Print Hex(twi_slv_buff(temp)); 'print der Daten
Next
Case &H70 : Print Spc(10) ; "SLAVE GCA :" ; 'ein General Call ist gekommen
Print Hex(twi_slv_addr) ; " ";
For Temp = 1 To Twi_sr_cntr
Print Hex(twi_slv_buff(temp)); 'print der Daten
Next
Case Else:
Print Chr(7) ; 'Irgendein Fehler
Call Twi_show_state(twi_slv_flag) 'Print status-text
End Select
Twi_slv_flag = 0 'löschen marker
Twi_slv_stat = 0 'löschen marker
Gosub Twi_sense 'alles wieder enablen
'und Bus freigeben
End If
'-----------------------------------------------------------------
' Jede Sekunde was senden & empfangen
'-----------------------------------------------------------------
' If Timeout = 1 Then
' Gosub Master_transmit
' If Twi_mst_flag = 0 Then 'Hats geklappt ?
' Timeout = 0 'ja
' ' else (sonst probieren wir's gleich nochmal)
' End If
' End If
'-----------------------------------------------------------------
Loop
End
'----------------------------------------
' 1 mS Ticker
'----------------------------------------
Interrupt_ticker: ' Timer for Timer Queue
Timer0 = Tmr_c_preload
Incr Timediv
If Timediv >= Tmr_c_divis Then
Timeout = 1 'eine Sekunde ist rum
Timediv = 0
End If
Return
'----------------------------------------
$include "Twi_show_state.bas"
'----------------------------------------
Run_wait_master:
Gosub Mst_start 'aufruf
Select Case Twi_mst_flag 'ergebnis ?
Case Twi_m_sent: 'gesendet
Print "<<<<<<MASTER sent:" ;
Print Hex(twi_mst_addr) ; " ";
For Temp = 1 To Twi_mt_cntr
Print Hex(twi_mst_buff(temp));
Next
Twi_mst_flag = 0
Case Twi_m_recv: 'geholt
Print ">>>>>>MASTER read:" ;
Print Hex(twi_mst_addr) ; " ";
For Temp = 1 To Twi_mr_cntr
Print Hex(twi_mst_buff(temp));
Next
Twi_mst_flag = 0
Case Else: 'irgendein Problem
Print Chr(7) ; Hex(twi_mst_addr) ; " ";
Call Twi_show_state(twi_mst_flag)
End Select
Return
'----------------------------------------
' Beispiel 8 byte senden,
' dann mit Rep.Start von gleicher adresse 3 Byte empfangen
'----------------------------------------
Master_transmit:
' sende buffer (mit testdaten) füllen
For Temp = 1 To 24
Twi_mst_buff(temp) = Slv_byte
Next
Twi_mst_addr = Mn2_adr 'I2C adresse
Twi_mt_cntr = 8 ' erstmal 8 Byte senden
Twi_mt_data = Varptr(twi_mst_buff(1)) ' adresse Daten
Twi_mr_cntr = 3 ' dann 3 Byte empfangen
Twi_mr_data = Varptr(twi_mst_buff(1)) ' empfangsbuffer
Gosub Run_wait_master ' auf gehts
Return
Wie gesagt, von AVR zu AVR alles im Butter.
Steuere ich den Bus aber via PC und RS232-Interface an, gibt im zweiten Datenbyte immer wieder einen Clock, der aussieht als sei er á la ACK heruntergeprügelt. Folglich wird der Clock vom Ziel-AVR nicht mehr erkannt und es kommt nur Schrott an. Ein Oszi-Bild vom dem "Defekt" ist angehängt. Prinzipiell bin ich für alle Fehlerquellen offen - das Interface verrichtet aber seit 3 Jahren mit zahlreichen verschiedenen echten I2C Bausteinen in der Haussteuerung seinen Dienst, will sagen das funktioniert..!
Aber was zum Kuckuck verursacht dieses Fehlerbild?
Ach so, der Bus hängt über 2k2 an der Versorgungsspannung. ](*,)