Archiv verlassen und diese Seite im Standarddesign anzeigen : TLC59116 Led Treiber
Hallo,
Ich versuche schon seit langer Zeit den Led Treiber von Atmel (TLC59116) per I2C Bus in gang zu bekommen. Jedoch klappt das mit dem I2C Bus überhaupt nicht. Kann mir bitte jemand helfen? Sonst verzweifle ich so langsam.
Ich benutze dazu einen Atmega644 und schreibe in C.
Danke,
lg Kurt
Die erste Frage dazu: Wie ist denn der Treiber an den Controller angeschlossen? Also welche Leitungen sind wie verbunden?
Klassischer Fehler (passiert mir auch immer): Die Pullups an SCL/SDA fehlen.
Dem Wert in TWBR nach geh ich davon aus, dass du den AVR mit 16MHz und I2C mit 400kHz betreibst. Korrekt?
Danke für die schnelle Antwort, hier ist meine Schaltung.
In der Schaltung denke ich ist kein Fehler, i gehe von einen Softwarefehler aus. Ich betreibe den Atmega mit 20Mhz und den Bus mit 500kHz, später wenn alles funktioniert vieleicht auch noch mit mehr Hz.
Das merkwürdige ist, dass ich auch mit dem Oszi nichts messe, aber die Ports funktionieren wenn ich sie einzeln beschalte.
lg
Hi!
Da der Atmega als Master arbeitet brauchst du keine ACK hinter jedem Byte zu senden. Der Slave sendet das ack oder nack nach jedem byte das er empfängt.
Um zu sehen, ob ein byte richtig angekommen (ack) ist mußt du nach dem Senden TWSR anschaun.
// ****** send i2c byte, return TWSR & 0xf8
uint8_t i2csendbyte(uint8_t txbyte) {
// --- send data byte
.......
// --- return status
return(TWSR & 0xf8);
}
0x18 für vom Slave korrekt empfangene Adresse
0x28 für vom Slave korrekt empfangenes Datenbyte
Da kann man die Adresse auch einfach als Datenbyte senden, muss halt nur die Antwort (TWSR) stimmen.
Das Gleiche solltest du auch für Start tun, dann ist 0x08 die richtige Antwort.
Immer schön eins nach dem Andern (Start, Adresse, Datenbytes) und jedesmal den Status prüfen.
Im Datenblatt des ATmega ist irgendwo eine Tabelle mit den Inhalten vom TWSR für alle möglichen Zustände. :)
PS: den Status als hex vorzudefinieren ist unschön, da gibs auch defines für..
Also hänge ich an jeder funktion in der ich etwas sende, dieses return dran. Soll ich dann den Befehl wiederholen lassen,wenn ein Byte nicht korrekt gesendet wurde?
Ja die Tabelle habe ich schon gefunden. Danke.
Also nochmal zusammengefasst:
Startbedingung
warten bis ack gesendet wurde
return(TWSR & 0xf8);
Adresse senden
warten bis ack gesendet wurde
return(TWSR & 0xf8);
Daten senden
warten bis ack gesendet wurde
return(TWSR & 0xf8);
Stopbedingung
Jain:
Start senden
warten bis start ist raus
return(TWSR & 0xf8);
checken ob start korrekt rausgegangen ist (kann immer mal schief gehen, u.a. bei mehreren mastern)
Adresse senden
warten bis adresse draussen ist
return(TWSR & 0xf8);
checken, ob adresse vom slave bestätigt wurde (ack)
Daten senden
warten, bis byte draussen ist
return(TWSR & 0xf8);
checken, ob slave das byte mit ack bestätigt hat
Stopbedingung
geht einfach so, jedenfalls tu ich da nix mehr checken :)
Im Fehlerfall ein Stop rausschicken.
Im Anhang ein Beispiel mit ein paar kleinen Erweiterungen wie timeouts und der Versuch im Fehlerfall die Slaves etwas wachzurütteln. Geht mit Sicherheit schöner, aber tut so seit Monaten im Dauerbetrieb. Waitalittle() sind nur ein paar us.
Ach ja, zwischen einzelnen Nachrichten etwas warten kann nicht schlecht sein.
Achso, ich muss jedes Bit einzeln senden, ich dachte das geht einfach so wenn ich die Adresse reinschreibe.
Wenn ich Pullups habe, muss ich trotzdem DDRC und PORTC initialisieren?
Danke für dein Beispielcode, der hilft mir sehr und es sind einige interessante Lösungen drinnen. Ich werde nach der Arbeit versuchen ob es klappt.
Danke
lg
Die Pins für SCL/SDA brauchst du nicht initialisieren, da hier die interne TWI-Hardware arbeitet und sich selber darum kümmert.
Die wieder sauber auf Input schalten ist nur dann (sicherheitshalber) empfohlen, wenn die Pins im Programm zuvor für was anderes verwendet werden. Aber sowas macht normalerweise keiner *g*
Noch eine kurze Frage, in deinem Code sendest du die Adresse als Byte (0x9e) aber die Daten Bitweise mit maintime[i]. Ist das nur zur Sicherheit?
Hi!
Die gesamte letzte Routine sendet nur eine einzige Nachricht, allerdings zusammengesetzt aus den Inhalten von mehreren Feldern, u.a. den Inhalt von maintime[i]. Alles byteweise. Zwischendurch wird noch nen Feld kopiert, was ausgerechnet und das Ergebnis als einzelnes byte verschickt.
Sorry, wollte damit keine Verwirrung stiften aber auch nichts falsch verändern vorm Posten. So gehts halt ;)
Im Schaltplan vermisse ich die Pull Up Widerstände! Oder habe
ich die übersehen?
Gruß Richard
Hallo Richard, ich habe 3 Pullup widerstände zu 3k3ohm an SDA, SCL un Reset. ( sie sind in der mitte)
Ich habe gerade das Programm raufgespielt, und ich messe schon wieder nichts an den ausgänen von SCL, SDA. Kann es sein, dass ich irgendwelche Fuses setzen muss?
lg
mit nichts meine ich keine impulse, es liegen dauernd 5V an
Misst du mit nem Oszi? Mit nem normalen Multimeter siehst du da nix; die Zeiten, die die Signale mal auf GND gehen, sind zu kurz dafür.
Nein, nein, schon mit dem Oszi.
Wenn ich den PortC periodisch ein und ausschalte. Dann sehe ich die Periode, aber so nichts...
Du kannst auch zum Testen den Takt I²C und Prozessor möglichst
klein wählen. Dann kann man besser etwas Sehen/Messen und auch
sonst einfacher Fehler finden. Wie lang ist denn der I²C Bus bei Dir?
bei den von Dir gewählten Frequenzen muss auch Bus Länge und
Art (Verlegung) beachtet werden.
Gruß Richard
Ok dann werde ich den Bus auf 100kHz runterschrauben. Der Bus ist auf einer Platine die ich geätzt habe, der weg ist zum längstem Slave ca. 8cm.
8 cm sollten kein Problem sein, zur Fehlersuche und Testen
ist ein niedriger Takt aber hilfreich.
Tut sich am Ozzi an der Trigger Anzeige denn was wenn
Daten gesendet werden?
Gruß Richard
Ich werde darauf achtgeben, ich probier das am Abend, denn jetzt bin ich wieder bei meiner Arbeit. Ich habe aber zu Mittag die Übertragung vom SmartUSB -> Atmega gemessen und dabei habe ich ein paar Flanken gesehen.
lg
Jaaa endlich, ich sehe was, aber mein Oszi hat eine Bandbreite von 60Mhz, warum sehe ich die 500kHz dann nicht? oder Menschliches versagen?
Also ich sehe die Übertragung, aber mein Reset an PC2 überträgt auch irgendwas, vileicht liegt es daran das ich kein Led zum leuchten bringe, oder habt ihr noch eine Idee?
Hmmmm, bei 400 kHz sind die Impulse ~0,0000025 s Lang
oder 2,5 µs auf was hast Du die Zeitbasis stehen? Lege PC2 nicht nur über einen Pull Up auf Vcc, setze zusätzlich einen 100nF gegen GND. Kann
sein das der sonst dauend Resettet..
Gruß Richard
Hi!
Poste mal deinen Code und wenns geht nen Bild vom Osci, 2 Kanal SCK/SDA wär am schönsten :)
Also hier sind die Bilder, bei SDA&SCK ist das obere Signal SCK und der Code ist auch dabei.
SDA und SCK passen vom Takt her gar nicht zusammen...
Die clock läuft, aber es werden keine Daten auf SDA rausgeshifted. Imho zieht da irgendas von aussen sda auf low nach dem start.
Überprüf noch mal was du da geätzt hast, gib dem Bus mehr Zeit zwischen den Nachrichten um sich zu fangen und mach das alles für den Anfang mal was langsamer.
Ih habe jetzt eher gedacht das zwischen RESET und SCK eine verbindung besteht die nicht sein soll. Soll RESET wirklich so aussehen?
Ja ich werde heute nochmal die Platine nach Fehlern untersuchen, langsamer ist schwer, da die Slaves eine Mindesfrequenz von 100kHz haben.
Leute! Die übertragung steht :)
Es liegen schöne Signale an :)
Jetzt muss ich nur noch die richtigen Adressen finden ;)
lg und Danke für Alles, ihr habt mir sehr geholfen
Naja, wenn du PC2 auf high setzt, zieht ja der AVR und der Pullup die Leitung auf 5V. Wenn du PC2 auf low setzt, wird die Leitung vom AVR aus auf GND gezogen, der Pullup hat dann quasi nichts mehr zu melden.
Also wenn du die Reset-Leitung benutzen willst, musst du statt zwischen
High und Low (PORT) zwischen Input und Output (DDR) umschalten.
Low und Input: Hochohmig, Pullup zieht Leitung auf 5V.
Low und Output: Leitung wird vom AVR auf GND gezogen.
High und Input: gleiche wirkung wie Low und Input.
High und Output: geht nur solange gut, bis jemand anders die Leitung auf GND zieht => Kurzschluss.
EDIT: Scheinbar wurde der letzte Beitrag gerade editiert, so dass die Antwort von mir jetzt wohl nicht mehr gebraucht wird. Lass ich aber trotzdem mal da.
Ja entschuldigung, ich hatte im Programm ein DDRC = 0xff versteckt. Aber danke das ist sehr interessant.
Witzig ist das ich nun verschiedene Adressen ausprobiert habe, aber keine Leds leuchten:|
I²C Adressen haben 7 Bit, das 8. Bit ist das schreib lese Bit.
Deshalb können nur Adresse 2,4,......128 als Adressen benutzt
werden. An den Port Expandern können die Adressen Hartware
mäßig geändert werden. Möglich das Dui deshalb Probleme hast?
Gruß Richard
Bo ich weiß nicht, also meine Adressen
Slave suchen: 1100000(0) schreiben
register: 10010100: Ledout0 register
Led: 01010101
ack vom slave und ende.
so ist auch das Beispiel im Datenblatt Seite 25.
Ich glaube ich weiß warum es nicht geht, laut Osci überträgt es 1 Byte und nicht weiter.
Aber bei einem anderem Slave:
Nach dem 8. Bit ist beim darauffolgendem Clock SDA auf Low dann wird die 2. Adresse gesendet. Ist das Normal, sollte nicht ein ACK zu sehen sein?
Entschudligung dass ich mit meinen ganzen Nachrichten nerve.
Aber ich bin draufgekommen, dass alle 3 Bytes übertragen werden sobald man das erste Bit auf Write setzt. Nur leuchtet immer noch nichts, obwol die Adressen stimmen müssten.
Noch eine grundlegende Frage: Sobald ich eine Adresse zum TLC sende, führt er diesen so lange aus, bis diese Überschrieben oder der Baustein resetiert wird? stimmt das?
lg
Mein, bis der Master ein ACK bekommen hat, bekommt der Master
ein NAC darf das nächste Byte gesendet werden... Mal ein Beispiel
aus RN Motor Control...
I2cstart
I2cwbyte Slaveid
I2cwbyte 35 'Kennung
I2cwbyte 5 'Befehl
I2cwbyte 3 'Motorwahl
I2cwbyte 0 'Richtung
I2cstop
'Beide Motoren mit Geschwindigkeit 100 anlaufen lassen
I2cstart
I2cwbyte Slaveid ´Adresse
I2cwbyte 35 'Befehlstyp kennungKennung
I2cwbyte 2 'Befehl
I2cwbyte 3 'Motorwahl
I2cwbyte 100 'Geschwindigkeit
I2cstop
Du siehst jedes Byte musst (DU) explizit übertragen, In c sieht das
anders aus der Ablauf dürfte ähnlich sein.
Gruß Richard
Ja aber ich glaube ich versteh das trotzdem nicht.
Also leuchten meine Leds so lange, so lange auch der selbe Code auf dem Bus ist?
Bei mir hat jetzt ein Led geleuchtet, aber so bald ich die Stromzufuhr abgeschaltet habe und wieder den selben Code raufgespielt habe, leuchtete die Led nicht mehr... aber wenn ich ein neues Programm raufspielte leuchtete Sie immer noch?!?!?!
Ich kenn mich nicht mehr aus
Du kannst das wie einen normalen Port Pin sehen, Mit einer 1
schaltest Du EIn mit einer 0 Aus. Du braust als zum Einschalten
einen Befehl und zum Ausschalten noch einen. Kommt jetzt natürlich
darauf an wie Du die Leds angeschlossen hast.
Gruß Richard
Tip: http://www.mikrocontroller.net/articles/Port-Expander_PCF8574
Nach viele kalte Lötstellen, funktioniert jetzt alle, danke euch allen, ohne euch hätte ich das nie geschafft.
lg Kurt
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.