www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik TLC5947 Ansteuerung


Autor: Martin H. (martin_h85)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Abend,

ich habe gerade einen kleinen Testaufbau mit einem TLC5947 gemacht. Dazu 
habe ich erst mal 2 RGB Leds angeschlossen, also Kanal 0-5.

Nun wollte ich das IC per Hardware SPI ansteuern. Dazu habe ich mich am 
Datenblatt orientiert. Leider klappt es noch nicht so richtig.
Die Ausgabe ist eher zufällig, was bedeutet wenn ich die ersten 8 bit 
komplett High setzte sind zwei Kanäle an.

Kann mal wer bitte ein paar Anmerkungen dazu machen, den ich sehe den 
Fehler noch nicht.



Die Belegung ist im Code dokumentiert, mein Atmel läuft mit 20MhZ. Iref 
ist auf 1,8k und auch sonst sollte der Hardware Aufbau OK sein.


MfG Martin

Autor: Silvan König (silvan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum?:
_delay_us(10);
_delay_us(10);
_delay_us(10);

... und nicht:
_delay_us(30);

????

Autor: Martin H. (martin_h85)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

das war nur durchs kopieren, hatte es nicht raus genommen. Aber die 
Funktion ist ja gleich.

Ich werde es beim nächsten mal zusammenfassen.


MfG Martin

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso 37?

24 Kanäle a 12 Bit:   24 * 12 = 288
aufgeteilt in 8 Bit   288 / 8 = 36

Autor: Martin H. (martin_h85)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin

sollte es nicht bei < 37 bis 36 laufen ? Oder habe ich da in meiner 
Müdigkeit einen Denkfehler gemacht ?


Gruß Martin

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin H. schrieb:
> Moin
>
> sollte es nicht bei < 37 bis 36 laufen ? Oder habe ich da in meiner
> Müdigkeit einen Denkfehler gemacht ?

Probiers mit einer kleineren Zahl aus

for ( i = 0; i < 8; ++i )

ergibt Werte für i von

 0, 1, 2, 3, 4, 5, 6, 7

zähl nach. Sind genau 8 Stück.

(Du hast die 0 vergessen)

Autor: Martin H. (martin_h85)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

ok, aber der Fehler ist der Gleiche. bei z.B. 0xFF als erstem Wert. sind 
zwei Kanäle gesetzt.


MfG Martin

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin H. schrieb:
> Moin,
>
> ok, aber der Fehler ist der Gleiche. bei z.B. 0xFF als erstem Wert. sind
> zwei Kanäle gesetzt.

Was bedeutet für dich "gesetzt"

Da die ersten 12 Bit für den ersten Kanal sind, bleiben noch 4 Bit 
übrig, die im 2.ten Kanal eine von 0 verschiedene PWM erzeugen. 2 Leds 
sind hell. Die eine mehr, die andere weniger. Insofern ist das zu 
erwarten.

Autor: Martin H. (martin_h85)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen,

Also es ist ja so das die ersten 8 Bit High sind und der Rest Low. Wenn
ich nicht irre sollte so doch der erste Kanal den Wert 255 Dezimal
haben, wobei 4096 volle Helligkeit wäre. Der zweite Kanal bleibt
unberührt.

Könntest du nochmal etwas näher erklären wieso das logisch ist, das zwei
Leds an sind ?


MfG Martin

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin H. schrieb:
> Morgen,
>
> Also es ist ja so das die ersten 8 Bit High sind und der Rest Low.

Arg.
Du hast recht: 0xFF sind ja nur 8 Bit.

Mein Fehler.

Wenn du alles 0 rausschiebst: Sind dann alle Kanäle 0?


Ich würde an deiner Stelle nicht damit anfangen in einer Schleife da 
Daten rauszublasen. Ich würde so vorgehen (und werde das die nächsten 
Tage auch tun, meine Samples sind von TI eingetroffen):

Erst mal eine Belegung raustakten. Dann mittels einem XLATCH Puls 
übernehmen und nachsehen, ob die Ausgänge stimmen.

Im Moment hab ich einen Knopf im Hirn (muss die Hitze sein). Ich komm 
nicht damit zurecht, ob deine XLATCH und BLANK Pulsflanken-reihenfole 
korrekt ist oder nicht.

Autor: Martin H. (martin_h85)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen,

ja wenn ich nur 0x00 schreibe ist alles aus. Bei 0xFF sind zwei an. Aber 
bei 0x0F nur einer, ich denke das ich da irgendwo einen Dreher drin 
habe. Ich werde es nochmal testen.

Kann man mit dem Hardware SPI eigentlich gezielt 12 Bit senden ?

Oder muss ich mir eine Funktion schreiben um das zu zerlegen.



MfG Martin

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin H. schrieb:

> ja wenn ich nur 0x00 schreibe ist alles aus. Bei 0xFF sind zwei an. Aber
> bei 0x0F nur einer, ich denke das ich da irgendwo einen Dreher drin
> habe. Ich werde es nochmal testen.
>
> Kann man mit dem Hardware SPI eigentlich gezielt 12 Bit senden ?

Nicht das ich wüsste.
Das ist alles auf Byte ausgelegt

> Oder muss ich mir eine Funktion schreiben um das zu zerlegen.

Wirst du wohl müssen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tomaten auf den Augen :-)
    //send the next data
    for(i=0;i<37;i++){
      SPDR = (send[i]); 
    }

He - du kannst doch nicht einfach 36 (37) Bytes in das SPDR stopfen! Du 
musst schon warten, bis das Byte draussen ist und das SPDR wieder 
aufnahmefähig ist.
    //send the next data
    for( i = 0; i < 36; i++ ) {
      spi_wait();
      SPDR = send[i]; 
    }

Autor: Martin H. (martin_h85)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen,


oh ja guter Einwand, das stimmt, jetzt scheint es auch besser zu laufen. 
Manchmal passieren einem echt die dümmsten Fehler.

Ich werde es nachher wenn ich von der Arbeit komme nochmal genauer 
überprüfen. Aber es sieht jetzt schon wesentlich besser aus ;)


MfG Martin

Autor: Joe D. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,
ich lese in immer mehr Foren und Beiträgen und auch in meinem Buch die 
folgende Zeile, wenn es um die SPI-Kommunikation geht:

// Wait for transmission complete
while(!(SPSR & (1 << SPIF)));

Mir ist der logische &-Operator an sich klar. Was ich aber nicht 
verstehe:
wie kann diese Zeile funktionieren?
In dieser Zeile ver-UND-et man ein komplettes Register mit einer 
logischen 1 an Bit Stelle 7, in welchem auch das SPIF-Bit sitzt.


Danke für jede hilfreiche Antwort =)

Autor: ohne Worte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joe D. schrieb:
> In dieser Zeile ver-UND-et man ein komplettes Register mit einer
> logischen 1 an Bit Stelle 7, in welchem auch das SPIF-Bit sitzt.

ganz genau, man testet damit ob das Bit gesetzt ist oder nicht (das 
Register wird damit nicht verändert!)

Autor: Joe D. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Antwort.

Inzwischen habe ich schon die nächste Frage und hoffe auch dieses mal 
auf Feedback.

Ich habe inzwischen mit der Implementierung von Adafruit für den Arduino 
mit TLC 5947 eine Referenzimplementierung für meinen ATmega328P 
vorgenommen.
/*
 * TLC5947_Adafruit.c
 *
 * Created: 12.04.2015 19:56:15
 *  Author: Joe
 
 Test with the Adafruit TLC5947 Breakout Board and a ATmega 328P Controller
 
 R(Iref) = 3k3 => 15mA per channel 
 
 18 Channels connected to a standard 5mm throuh-hole LED
 
 => 270mA for all LED channels 
 
 DIN -> Digital 11 --/-- PB3 (MOSI)
 CLK -> Digital 13 --/-- PB5 (SCK)
 LAT -> Digital 9  --/-- PB1 (OC1A/PCINT1) 
 /OE -> Digital 10 --/-- PB2 (SS)
 */ 

#define numdrivers 1
#define F_CPU 1000000

#define SIN PB3
#define SCK PB5
#define XLAT PB1
#define BLANK PB2
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>

uint16_t *pwmbuffer;

void TLC5947_init()
{
  DDRB |= (1 << XLAT) | (1 << BLANK) | (1 << SIN) | (1 << SCK);
  
  pwmbuffer = (uint16_t *)calloc(2, 24*numdrivers);
}

void setPWM(uint8_t chan, uint16_t pwm)
{
  if(pwm > 4095)
  {
    pwm = 4095;
  }
  if(chan > 24*numdrivers)
  {
    return;
  }
  
  pwmbuffer[chan] = pwm;
}

void writePWM(void)
{
  PORTB &= ~(1 << XLAT);
   //digitalWrite(_lat, LOW);
   // 24 channels per TLC5974
   for (int8_t c=24*numdrivers - 1; c >= 0 ; c--) 
   {
    // 12 bits per channel, send MSB first
     for (int8_t b=11; b>=0; b--) 
     {
    PORTB &= ~(1 << SCK);
       
       
       if (pwmbuffer[c] & (1 << b))
       {
         //PORTB |= (1 << SIN);
         PORTB = (1 << SIN);
       }
       else
       {
         //PORTB &= ~(1 << SIN);
         PORTB = (0 << SIN); 
       }
       //Pulse SCK to shift in Grayscale-Data
                         PORTB |= (1 << SCK);
       PORTB &= ~(1 << SCK);
       
     }
   }
   //Pulse XLAT to transfer from Grayscale-Shift-Register to Latch-Register
   PORTB |= (1 << XLAT);
   PORTB &= ~(1 << XLAT);
}

void clearAll_2(void)
{
  //XLAT low
  PORTB &= ~(1 << XLAT);
  
  for(int i = 0; i < 12; i++)
  {
    //SCK low
    PORTB &= ~(1 << SCK);
    
    //SIN low
    PORTB = (0 << SIN);
                //PORTB &= (1 << SIN);
    
    //Pulse SCK
    PORTB |= (1 << SCK);
    PORTB &= ~(1 << SCK);
  }
  //Pulse XLAT
  PORTB |= (1 << XLAT);
  PORTB &= ~(1 << XLAT);
}




int main(void)
{
  TLC5947_init();
  
  //Turn On LED-channels
  PORTB &= ~(1 << BLANK);
  //clearAll();
  
  
    while(1)
    {
    
    setPWM(0, 4095);
    writePWM();
    _delay_ms(2000);
    clearAll_2();
    _delay_ms(2000);
    
    }
}
Wenn ich nun in der "writePWM" Fkt. die Zeile
PORTB &= ~(1 << SIN);
so arbeitet der TLC5947 ordnungsgemäß wie er soll.

Verwende ich allerdings in meiner eigens geschriebenen Fkt. "clearAll_2" 
dieselbe Zeile
PORTB &= ~(1 << SIN);
treten Fehler auf.

Beispielsweise setze ich über setPWM(0, 4095) zunächst Channel 0 auf PWM 
100% und will dann die in das GS-Shift-Register geschobenen "1"en um 12 
verschieben, also, sodass Channel 1 auf PWM 100% ist.

Das sieht dann aber so aus, dass dann erst CHannel 0 aufleuchtet und 
Channel 1 auch, während Channel 0 an bleibt ?!?!?

Mir ist klar, dass, wenn PB3 vorher "0" war, dann durch &= aus 0&0 auch 
wieder null wird.
Aber anscheinend sieht der µController das anders oder habe ich einen 
Denkfehler?

Verwende ich
PORTB = (0 << SIN);
klappt es so wie gewollt.

Hat einer ne Idee?
Vielen Dank!

: Bearbeitet durch Moderator
Autor: ohne Worte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joe D. schrieb:
> PORTB = (0 << SIN);

statt dessen kannst du auch PORTB = 0 schreiben

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.