PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATMega2560 und I2C... geht nicht?



Jaecko
23.12.2007, 19:48
Hiho.

Mal wieder ein Problem.
Ich hab mir mal ein (preislich gesehen) billiges 40x4-LCD (DisplayTech 404B Series) besorgt. Um dieses universell und ohne viel Verkabelungsaufwand verwenden zu können, hab ich auf eine kleine Zusatzplatine nen ATMega8 draufgepackt, der sich wie ein I2C-Slave verhält, die empfangenen Daten umsetzt und auf dem Display darstellt. Mit nem RS232-I2C-Adapter klappt die Ansteuerung auch problemlos.

Nun wollte ich das Teilchen an nem ATMega2560 per I2C ansprechen: Es passiert garnichts. Häng ich statt dem Display das RNKeyLCD hin, rührt sich ebenfalls nix. Mit LED-Überwachung zeigt sich, dass beide Leitungen (SCL/SDA) ständig High sind. Lass ich in dem Code unten den "I2CINIT" weg, so ist SDA = Hi, SCL = Lo.

Verbindungstechnisch hängt die ganze Sache an nem Flachbandkabel mit 3 Steckern; Die Geräte werden alle auch über den Bus mit Strom versorgt.
Stecker 1: Stromversorgung für Bus + 10k-Pullups für SDA/SCL; Zuschaltbarer RS232-I2C-Adapter.
Stecker 2: ATMega2560 (Keine Pullups)
Stecker 3: RNKeyLCD oder 404B (bei letzterem keine Pullups)

Hier mal der bisherige Code:
Die Sub ist noch ein überbleibsel und wird später noch "wegoptimiert".
In der Mainloop soll nur Testweise der Buchstabe X bzw. Y mit 2 verschiedenen Möglichkeiten gesendet werden.



' Wait for I2C-LCD to be ready
Wait 2

$lib "i2c.lbx"
$lib "i2c_twi.lbx"

'-------------------------------------------------------------------------------
' Declarations - SUBs
'-------------------------------------------------------------------------------
Declare SUB I2CLCD_Send


'-------------------------------------------------------------------------------
' Declarations - Ports & Pins
'-------------------------------------------------------------------------------
CONFIG PIND.0 = OUTPUT 'SCL
CONFIG PIND.1 = OUTPUT 'SDA
CONFIG PIND.5 = OUTPUT : LED ALIAS PORTD.5 'Onboard-LED


'-------------------------------------------------------------------------------
' Declarations - Constants
'-------------------------------------------------------------------------------
CONST Timer1Preload = 100
CONST SID_RNKeyLCD = &H40 ' RNKeyLCD
CONST SID_I2CLCD = &H42 ' 404B-Series
CONST SID_Nokia6100 = &H44 ' Nokia 6100 Color LCD
CONST SID_ServoBoard = &H46 ' MicroServo-Board
CONST SID_GeneralCall = &H00 ' General Call


'-------------------------------------------------------------------------------
' Declarations - Variables
'-------------------------------------------------------------------------------

'Counting Variables
DIM i as Byte
DIM i2 as Byte

'Temporary Variables
DIM tmpByte as Byte
DIM tmpString as String * 1

'LCD Text
DIM LCDString(4) AS String * 40
DIM LCDStringOld(4) AS String * 40


'-------------------------------------------------------------------------------
' Configs
'-------------------------------------------------------------------------------
CONFIG SCL = PORTD.0
CONFIG SDA = PORTD.1
CONFIG TIMER1 = TIMER , Prescale = 1024
Config Twi = 100000 '100 kHz Bus Frequency


'-------------------------------------------------------------------------------
' Initialisations
'-------------------------------------------------------------------------------
I2CINIT
TIMER1 = Timer1Preload
On Timer1 ISR_Timer1

ENABLE Timer1
ENABLE Interrupts




'************************************************* ******************************
' MAIN LOOP START
'************************************************* ******************************
DO

I2cstart
I2cwbyte SID_RNKeyLCD
I2cwbyte 88 'Send "X"
I2cstop

I2CSend SID_RNKeyLCD , 89 'Send "Y"

Toggle LED
WAITms 500

LOOP
END
'************************************************* ******************************
' MAIN LOOP END
'************************************************* ******************************



'-------------------------------------------------------------------------------
' SUBs
'-------------------------------------------------------------------------------
SUB I2CLCD_Send
For i = 1 to 4
If LCDString(i) <> LCDStringOld(i) Then
tmpByte = LEN(LCDString(i)) ' Get length of String
tmpByte = 40 - tmpByte ' Chars Needed to 40
if tmpByte > 0 Then LCDString(i) = LCDString(i) + SPACE(tmpByte)
I2CStart 'Set Cursor to Line i
I2CWByte SID_I2CLCD
I2CWByte 027 'Send System-Command
I2CWByte 079 'Set Cursor
I2CWByte 001 'Column 1
I2CWByte i 'Line i
I2CStop
I2CStart 'Transfer selected Line
I2CWByte SID_I2CLCD
I2CWByte 001 'Send Text-Command
I2CWByte 040 'Length: 40 Bytes
For i2 = 1 to 40 'Send Text-Bytes
Toggle LED
tmpString = mid(LCDString(i) , i2 , 1)
tmpByte = ASC(tmpString)
I2CWByte tmpByte
Next
I2cstop
LCDStringOld(i) = LCDString(i)
End If
Next i

END SUB


'-------------------------------------------------------------------------------
' Jump Labels / ISR
'-------------------------------------------------------------------------------
ISR_Timer1:
Timer1 = Timer1Preload
Return



Hab ich mit der Ansteuerung per I2C was übersehen?
Muss jedes Gerät selbst nochmal Pullups haben oder reichen die beiden bei der Versorgung?


MfG
S.C

linux_80
23.12.2007, 22:08
Hallo,

probier mal die Testprogramme, die ich im Wiki unter "Bascom-I2c-Master" gebaut habe. Aber für eins entscheiden, nicht Software und Hardware-TWI mischen, so wie in deinem Beispiel, immer nur eine lib einbinden !

Jaecko
25.12.2007, 18:19
Also bei den Testprogrammen rührt sich leider auch nichts.

Ich hab dann mal aus dem TWI-Multimasterbeispiel den Code verwendet und hab mittlerweile rausgefunden, dass bei diesem Code TWINT nicht gesetzt wird...
Jetzt halt die Frage: Warum wird TWINT nicht gesetzt?
Im Beispiel ist das letzte Bit (TWIE, Interrupt Enable) immer 0; muss dieses aber nicht 1 sein, damit TWINT (Interrupt) überhaupt gesetzt werden kann?


Ausschnitt:


Sub Twi_send_byte(byval slave As Byte , byval Zeichen As Byte)
Print #4 , "Sub Started"
Error = 0 ' Fehler zurücksetzen

' Startbedingung
Twcr = &B10100100 ' TWINT
Print #4 , "Set Start Cond." ; hex(TWCR)
' warten bis TWINT gesetzt ist
Gosub Twi_wait_int
Print #4 , "TWINT OK"

' wenn Zugriff auf den Bus erlaubt, Slaveadresse ausgeben
If Twi_status = &H08 Or Twi_status = &H10 Then
Print #4 , "Bus Access"
Twdr = Slave And &HFE ' slave adresse + Write
Twcr = &B10000100 ' TWINT löschen, Byte senden

' warten bis TWINT gesetzt ist
Gosub Twi_wait_int

' Slave hat sich gemeldet
If Twi_status = &H18 Or Twi_status = &H20 Then
Print #4 , "Slave OK"
Twdr = Zeichen ' Daten
Twcr = &B10000100 ' TWINT löschen, Byte senden

' warten bis TWINT gesetzt ist
Gosub Twi_wait_int

' Zeichen wurden gesendet
If Twi_status = &H28 Or Twi_status = &H30 Then
Print #4 , "Char Sent"
Error = 0 ' kein Fehler
Else
Error = Twi_status ' Fehler
End If

Else
' kein slave
Error = Twi_status ' Fehler
Print #4 , "Error: " ; Hex(Error)
End If
' STOPbedingung kommt hier immer im Ablauf, egal welcher Status
Twcr = &B10010100 ' TWINT löschen, STOP senden
' nach einem STOP wird TWINT nicht mehr gesetzt,
' man darf/kann also nicht darauf warten !
Else
' Bus belegt, wird er wieder freigegeben
Twcr = &B10000100 ' TWINT löschen, Bus freigeben
Error = Twi_status ' Fehler
End If
End Sub

Twi_wait_int:
Do
Twi_control = Twcr And &H80
waitms 500
Print #4 , "Wait... TWCR: " ; HEX(TWCR)
Loop Until Twi_control = &H80
Twi_status = Twsr And &HF8 ' status
Print #4 , "ErrStat:" ; Hex(twi_status)
Return

linux_80
25.12.2007, 19:52
Hallo,
TWIE ist nur da, damit die ISR aufgerufen wird, darin muss die nächste TWI-Aktion ausgeführt werden.
Wenn man das nicht benutzt, muss man das Flag TWINT pollen, wenn es gesetzt ist, TWSR auslesen und darauf reagieren, das wird in den meisten Beispielen auch so gemacht.
Deswegen gibts auch die Funktion TWI-wait-int, weil das bei jedem Schritt gleich ist.
Ich würde das waitms 500 da raus machen, da schläft ja jeder Slave ein ;-)
Die ganzen Prints zögern auch unnötig raus.

Die Beispiele aus der Wiki-Seite sollten funktionieren, ausser es gäbe einen Bug beim 2560 dazu.

Welche Bascom-Version ?

Hast Du die reine I2C-Softwarelösung auch probiert ? Die sollte doch immer funktionieren, ausser das Problem liegt ausserhalb des AVR. :-k

Jaecko
25.12.2007, 21:24
Die 500ms und die Prints waren nur zu Diagnosezwecken drin, da ich rausfinden wollte, wo genau das Programm stehen bleibt.

Es scheint aber tatsächlich ein Bug im Zusammenhang mit dem 2560er zu sein. Hardwaremässig sind die Pins ok, da ich sie als Output definiert auf 5V/0V schalten kann. Ich hab das Programm annähernd 1:1 (ohne Print #4 etc) auf nen ATMega32 übertragen und da läufts ohne Probleme.
Bascom-Version: 1.11.8.9

Ok, könnte ja im Zielprojekt auch den 32er verwenden, nur werd ich da in absehbarer Zeit an die Grenzen des Programmspeichers kommen...

linux_80
26.12.2007, 00:13
Zum auffinden des Fehlers könntest Du noch ein

Print hex(TWSR)
nach jedem I2C-Befehl einbauen, um zu sehen was der letzte Befehl ergeben hat.
Dann kannst Du die Werte mit dem vegleichen, wenns auf einem M32 läuft.

Mit Bug meinte ich evtl. einen in Bascom, wenn man sich aber das in ASM anschaut was dabei rauskommt (Das TWI-Master-Beispiel aus dem Wiki), scheint es soweit in Ordnung zu sein :-k
Da ich keinen M2560 da habe, kann ich das leider nicht näher nachprüfen.

Hast Du schon die Pegel der beiden Leitungen gemessen, ob sich da was rührt, bzw. ob die High sind wenn sie High sein sollen usw. ?
Oder ob sich das beim I2C-Start schon aufhängt.

Wie weit kommt Deine Debugausgabe im Programm ?

Nimm beim Master die Bascom-Befehle, da kommt man nicht so leicht durcheinander ;-)

Jaecko
26.12.2007, 13:27
Also beim Test mit dem M32 geht jede beliebige Pin-Kombination (Config SCL, Config SDA...), beim 2560 geht garnix davon. Verschiedenste Pins durchprobiert; also scheidet ein Hardwaredefekt wohl auch aus.
(Hardware OK, Software geht auch... was bleibt dann noch?...)

Wenn ich mit der Befehlsfolge

I2CStart
I2CwByte &H40
I2CwByte 81
I2Cstop

ein Zeichen senden will, bleibt der 2560 irgendwo beim ersten Write Byte stehen. Also I2CStart wird ausgeführt, I2CwByte &H40 nicht mehr bzw. nicht vollständig. Wenn direkt I2CSend verwendet wird, stoppt er dort genauso.

Beim Durchsuchen nach möglichen Fehlerquellen hab ich noch etwas gefunden. In der M2560def.dat ist ganz unten der Abschnitt


[I2CSLAVE]
POSSIBLE=YES ; software slave mode possible but TWI mode also
PORT=D,7,0 ; PORTD , SCL D.7(T0) , SDA D.0(INT0)

Der hat aber wohl nur was mit dem Slave zu tun. Dort werden nämlich die I2C-Pins "falsch" angegeben, da SDA normal D.1 ist und SCL D.0.
Aber kanns trotzdem sein, dass dieser Abschnitt das ganze stört?

linux_80
26.12.2007, 14:11
Diese Werte in der .dat sind nur da falls man das im Programm nicht angibt, deshalb sollte es immer angegeben werden !

Wenn du das Beipsiel von der Wiki-Seite unter "Software-I2C (https://www.roboternetz.de/wissen/index.php/Bascom_I2C_Master#Software_I2C)" verwendest, sollte es doch laufen, denn alle Ports liegen IO-mässig im unteren Bereich,
also ohne TWI-lib probieren !

Hast du ein Oszi, um zu sehen was sich auf dem Bus tut ?

Jaecko
26.12.2007, 14:34
Ich hab sowohl Hardware als auch Software-I2C verwendet; geht beim M32 alles problemlos, mit Software auch auf beliebigen Pins; auch ohne die lib.
Oszi wurde gerade mal verwendet:
M32: Datenverkehr sichtbar (ja auch logisch, wenns so geht).
M2560: SDA und SCL sind ständig auf High/5V; unabhängig davon ob über Software oder Hardware-I2C und unabhängig von der Auswahl der Pins bei Software-I2C; So als würden die direkt an VCC hängen.
Wird der jeweilige Pin als normaler Output definiert und mit
Do: Toggle Pinx.y: Waitms 1: Loop
gefüttert, dann ist eine saubere Rechteckspannung zu erkennen.


EDIT: 15:41 Uhr...
Hab soeben SCL auf A.0 und SDA auf A.1 gesetzt und da gehts plötzlich!... Nur warum nur auf diesen beiden und sonst nirgendwo?...

linux_80
26.12.2007, 16:12
Ab jetzt muss dann jemand anders beim weiterforschen helfen, da ich (noch) kein M2560 im Zugriff habe !

Jaecko
26.12.2007, 19:08
Naja ich werds jetzt mal auf den beiden Pins lassen. Ist sogar noch besser, da ich so die sonst besetzten INT0 und INT1 frei hab.
Trotzdem Thx soweit.

fuerstfanta
25.11.2008, 15:46
Hi!

Gibts mittlerweile ne Lösung für das Problem,... hänge gerade an der gleichen Stelle!

Danke vorab

Gruß

Christoph

Jaecko
25.11.2008, 17:08
Moin. Also wo das Problem dort war, hab ich leider nie genau rausgefunden. Es muss jedoch irgendetwas mit Bascom sein.
Ich bin mittlerweile auf C umgestiegen und da klappt an den entsprechenden Hardware-Pins des I2C/TWI alles => Hardware ok.

fuerstfanta
25.11.2008, 20:07
Hi!

Also ich versuche gerade einen Software-i2c zu programmieren, da die hardware-twi-pins schon belegt sind. Und da hängt sich der controller ja worklich vollständig auf. Da geht nix mehr. Offensichtlich gibt es dafür auch keine Lösung. Werde mal versuchen, eine Shiftout-Funktion für I2C fit zu machen! Hat das schonmal jemand gemacht?

Gruß

Christoph