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 !
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.
Code:' 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
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 !
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:
Code: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
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.
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...
Zum auffinden des Fehlers könntest Du noch ein
nach jedem I2C-Befehl einbauen, um zu sehen was der letzte Befehl ergeben hat.Code:Print hex(TWSR)
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
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
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
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.Code:[I2CSLAVE] POSSIBLE=YES ; software slave mode possible but TWI mode also PORT=D,7,0 ; PORTD , SCL D.7(T0) , SDA D.0(INT0)
Aber kanns trotzdem sein, dass dieser Abschnitt das ganze stört?
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" 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 ?
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?...
Ab jetzt muss dann jemand anders beim weiterforschen helfen, da ich (noch) kein M2560 im Zugriff habe !
Lesezeichen