PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TWI Slave "drückt" Clock



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. ](*,)

PicNick
01.09.2009, 08:39
Hi, kann ich mir momentan nicht erklären. die Library verwendet ja die HW-TWI, d.h. Clock-Stretching oder sowas könnt' ich garnicht.
Ich schau mir aber den Slave-Code nochmal genauer an (dürfte ja ziemlich genau mein Beispiel sein), ob der vielleicht irgendwie in die Sache reinpfuscht.
Ev. Dauert vielleicht das printen der Empfangsdaten zu lange ? (und er ist noch garnicht fertig, wenn das 2.BYte kommt ?)

(1 Byte bei 9600 Baud dauert 1 mS)

mat-sche
01.09.2009, 09:36
Hallo,

nach dem ich gestern meine Master/Slave - Kombination zum laufen bekommen habe, habe ich mitbekommen, dass ein Printbefehl die Fehlerquelle war.
Ich würde jetzt die Printbefehle aus der "Ergebnis als SLave auswerten" und auch überall wo anders herausnehmen. Die Printanweisung oder die Ausgabe der Daten über serielle Schnittstelle verbraucht zu viel Zeit und bremst somit die I2C Kommunikation aus.
Vielleicht ist dies das Problem.

Gruß MAT

TiRe
01.09.2009, 13:23
Hallo,

habe kurzerhand alle Print-Anweisungen in der Slave-Routine rausgenommen, aber das Oszi-Bild zeigt noch immer das gleiche Verhalten.
Damit lässt sich dies als Ursache ausschließen, zumal der AVR doch relativ autonom bereit sein sollte, das zweite Byte zu empfangen?!

@Mat-sche: kannst Du mir vielleicht Deinen Sourcecode zuschicken? Adresse : trnospam02 at arcor Dot de

PicNick
01.09.2009, 14:07
2.Byte ist natürlich Blödsinn, die Library setzt ja den Flag erst, wenn ein Stop oder Restart kommt, also nicht bei jedem Byte.
Wenn, dann ginge also um die 2. "MESSAGE"

Wie oben erwähnt, kann man bei der HW-TWI die Clock- und Datenleitungen nicht beeinflussen.


Clock runterziehen wäre ein Stretching, d.h. der Master müsste eigentlich warten, bis die CLK-Leitung wieder raufgeht. Das tut er anscheinend nicht, die Implementierung beim Master ist wohl nicht recht sauber.

Du sagst, bei AVR /AVR geht das. Hast du dir da zum Vergleich schon mal das Oszi-Bild angesehen ?

TiRe
01.09.2009, 15:01
Ja, hab ich natürlich auch angesehen. Die Gesamtsequenz ist im angehängten Bild zu sehen; alle ACK kommen sauber, die Botschaft wird ordentlich ausgewertet.
Der Master (vom PC gesteuert) ist relativ doof, d.h. Clockstretching oder Arbitration wird nicht unterstützt. Aber wie schon erwähnt: mit zahlreichen anderen Slaves funktioniert es tadellos.

Angenommen hier ist es ein Clockstretching, dann wäre wohl eine Abhilfe (quick'n'dirty) den Clockpuls zu verlängern. :-k Das könnte ich versuchen, da im Interface kein readback vom Clock vorgesehen ist.
Wobei richtig Sinn macht es nicht, denn bei AVR2AVR kommt kein Stretching und die Datenrate ist bei der PC-Lösung auch nicht sonderlich hoch?! Noch dazu sollte die Geschwindigkeit für den AVR @8MHz kein Thema sein. :-s

PicNick
01.09.2009, 15:08
Da doch wohl der Slave nicht weiss, ob der PC oder ein anderer AVR die Daten schickt, kann man sich den Effekt eigentlich garnicht erklären.

Hast du auch ein Oszigramm von PC-I2C Baustein ? (irgendwas)

EDIT: was mir vorkommt, kann mich aber täuschen:
Beim AVR-AVR scheint mir der Abstand 1. - 2. Byte grösser ?
(wär aber auch noch keine erklärung)

TiRe
01.09.2009, 15:50
Bilder im Attachment, auf die schnelle habe ich sie nicht so gut hinbekommen, man sieht aber das Wesentliche

Der zeitliche Unterschied (Abstand zw. Bytes) kommt wohl daher, da ich mit verschiedenne "Waitzyklen" herumexperimentiere.

Die AVR2AVR-Variante ist deutlich schneller, was nochmals ein evtl. Clockstreching unwahrscheinlicher macht.

Rätsel über Rätsel.....

mat-sche
01.09.2009, 17:30
Hi TiRe,

mein Programmcode unterscheidet sich für das Empfangen/Senden nicht von dem aus der WIKI.
Wenn würde ich mal die I2C-Daten mal mit nem Logicanalyzer aufnehmen, stimmen sie mit dem Oszi überein?
Wie schauts mit der Elektronik aus, sind alle Spannungs/Masseleitungen richtig miteinander verbunden?

MAT

TiRe
01.09.2009, 17:56
Hi Mat,
Logikanalyzer habe ich nicht, es gibt ein paar Projekte dieserart auf meiner Wishlist....

Aber dem Scope würde ich im Zweifelsfall eher glauben.

Ja, Masse und VCC sind ordentlich verbunden. Ich hatte da schon einige Erfahrungen mit floating GND :-b

TiRe
04.09.2009, 21:13
Hallo,

ich bin noch immer auf der Suche nach der Lösung meines Problems mit dem Slave.
Ich habe mal versucht, den Clock zu puffern (74xx245). Das Ergebnis war wie zu erwarten: Puffer Eingang (vom PC), astreiner CLK, Puffer-Ausgang CLK gedrückt, ergo Verursacher ist definitv der AVR (gut, woher soll es auch sonst kommen =P~ )

folgendes habe ich heute herausgefunden (vielleicht ein Schritt voran...an den Abgrund):
Sofern die zu empfangenen Bytes als MSB=0 haben, kommen die Daten an!!! Ist aber das MSB=1, dann wird der Clock wieder gestaucht. Eine Vergleichsmessung habe ich angehängt.
Hilft das vielleicht???? :-s

PicNick
05.09.2009, 15:09
es ist ja so, dass innerhalb eines Bytes ja überhaupt nur die HW am Zuge ist, d.h. da fällt mir garkeine Schraube ein, an der man drehen könnte.

Kann man den Fehler wandern lassen ?
d.h. wenn erst das dritte Byte mit MSB=1 kommt, tritt der Fehler dann im dritten Byte auf ?
Oder ist das immer das 2.Bit im 2.Byte ?

Very strange.
Hast du schon mal den Mega austauschen können ?

TiRe
06.09.2009, 21:57
Hallo,

den Fehler kann ich tatsächlich am MSB festmachen: Belieb viele Bytes mit MSB=0 => kein Problem.
Auch mit einen anderen ATMega ist der Effekt noch vorhanden

Ich habe nicht erwähnt (oder vernachlässigt) dass ich noch vor dem Ziel-Slave einen Buffer in Form PCA9515 hängen habe. Das Problem bleibt bestehen, das Aussehen ändert sich: Nach einem ACK geht der Slave auf SCK=1 (??), MSB=1 liegt an (=ungültiger Datenwechsel währen CLK=1 ist), beim nächsten Clock merkts der Slave offensichtlich und zieht den Clock runter.

Momentan kann ich den Fehler bei AVR auf AVR nachvollziehen, indem ich zwischen dem Senden des Commandworts und des ersten Datenbytes eine Delay von 1 ms einbaue => somit gleiches Fehlerbild wie beim PC-Interface, also wenn MSB=1 dann Fehler! Wenn das mal nicht kurios ist!

Der Mastercode sieht dann so aus:


$regfile = "M8def.dat" ' the used chip
$crystal = 8e6 ' frequency used
$baud = 9600

Config Sda = Portc.4
Config Scl = Portc.5

Config Pind.4 = Input
Config Pind.5 = Input

$lib "i2c_twi.lbx" ' Für Hardware TWI

Waitms 100

Config Twi = 100000 ' setzt die TWI-Register
Twsr = 0 ' Status reset
Twbr = 220 ' Bus Geschwindigkeit 400kHz @ 16MHz
Twcr = &B00000100 ' TWI Modul aktivieren, nur TWEN

Dim Nr As Byte ' Servo-Nr
Dim Position As Byte ' Position



Do

I2cstart
I2cwbyte &H64
'I2cwbyte &H53 ' "S" Kennzeichen für Servo ansteuern
If Pind.4 = 0 Then
Waitms 1
End If

If Pind.5 = 0 Then
I2cwbyte &HAA 'MSB =1
Else
I2cwbyte &H53 'MSB=0
End If
'I2cwbyte &HBB
I2cstop


Wait 1
Loop

End

Per Taste an PD4 und PD5 kann der Fehler provoziert werden

TiRe
06.09.2009, 22:28
#-o #-o #-o #-o #-o #-o #-o

Kommunikation läuft: Ich habe meine Buffer PCA9515 rausgenommen und Wunder-oh-Wunder die Kommunikation läuft. Es musste ja was blödes sein. Jetzt geht es noch an die genau Analyse, ich werde es Euch wissen lassen...

PicNick
07.09.2009, 08:46
Ich habe nicht erwähnt...
:-( Rüge