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
Warum?:
1 | _delay_us(10); |
2 | _delay_us(10); |
3 | _delay_us(10); |
... und nicht:
1 | _delay_us(30); |
????
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
Wieso 37? 24 Kanäle a 12 Bit: 24 * 12 = 288 aufgeteilt in 8 Bit 288 / 8 = 36
Moin sollte es nicht bei < 37 bis 36 laufen ? Oder habe ich da in meiner Müdigkeit einen Denkfehler gemacht ? Gruß Martin
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)
Moin, ok, aber der Fehler ist der Gleiche. bei z.B. 0xFF als erstem Wert. sind zwei Kanäle gesetzt. MfG Martin
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.
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
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.
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
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.
Tomaten auf den Augen :-)
1 | //send the next data
|
2 | for(i=0;i<37;i++){ |
3 | SPDR = (send[i]); |
4 | }
|
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.
1 | //send the next data
|
2 | for( i = 0; i < 36; i++ ) { |
3 | spi_wait(); |
4 | SPDR = send[i]; |
5 | }
|
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
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 =)
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!)
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.
1 | /*
|
2 | * TLC5947_Adafruit.c
|
3 | *
|
4 | * Created: 12.04.2015 19:56:15
|
5 | * Author: Joe
|
6 |
|
7 | Test with the Adafruit TLC5947 Breakout Board and a ATmega 328P Controller
|
8 |
|
9 | R(Iref) = 3k3 => 15mA per channel
|
10 |
|
11 | 18 Channels connected to a standard 5mm throuh-hole LED
|
12 |
|
13 | => 270mA for all LED channels
|
14 |
|
15 | DIN -> Digital 11 --/-- PB3 (MOSI)
|
16 | CLK -> Digital 13 --/-- PB5 (SCK)
|
17 | LAT -> Digital 9 --/-- PB1 (OC1A/PCINT1)
|
18 | /OE -> Digital 10 --/-- PB2 (SS)
|
19 | */
|
20 | |
21 | #define numdrivers 1
|
22 | #define F_CPU 1000000
|
23 | |
24 | #define SIN PB3
|
25 | #define SCK PB5
|
26 | #define XLAT PB1
|
27 | #define BLANK PB2
|
28 | #include <avr/io.h> |
29 | #include <stdlib.h> |
30 | #include <util/delay.h> |
31 | |
32 | uint16_t *pwmbuffer; |
33 | |
34 | void TLC5947_init() |
35 | {
|
36 | DDRB |= (1 << XLAT) | (1 << BLANK) | (1 << SIN) | (1 << SCK); |
37 | |
38 | pwmbuffer = (uint16_t *)calloc(2, 24*numdrivers); |
39 | }
|
40 | |
41 | void setPWM(uint8_t chan, uint16_t pwm) |
42 | {
|
43 | if(pwm > 4095) |
44 | {
|
45 | pwm = 4095; |
46 | }
|
47 | if(chan > 24*numdrivers) |
48 | {
|
49 | return; |
50 | }
|
51 | |
52 | pwmbuffer[chan] = pwm; |
53 | }
|
54 | |
55 | void writePWM(void) |
56 | {
|
57 | PORTB &= ~(1 << XLAT); |
58 | //digitalWrite(_lat, LOW);
|
59 | // 24 channels per TLC5974
|
60 | for (int8_t c=24*numdrivers - 1; c >= 0 ; c--) |
61 | {
|
62 | // 12 bits per channel, send MSB first
|
63 | for (int8_t b=11; b>=0; b--) |
64 | {
|
65 | PORTB &= ~(1 << SCK); |
66 | |
67 | |
68 | if (pwmbuffer[c] & (1 << b)) |
69 | {
|
70 | //PORTB |= (1 << SIN);
|
71 | PORTB = (1 << SIN); |
72 | }
|
73 | else
|
74 | {
|
75 | //PORTB &= ~(1 << SIN);
|
76 | PORTB = (0 << SIN); |
77 | }
|
78 | //Pulse SCK to shift in Grayscale-Data
|
79 | PORTB |= (1 << SCK); |
80 | PORTB &= ~(1 << SCK); |
81 | |
82 | }
|
83 | }
|
84 | //Pulse XLAT to transfer from Grayscale-Shift-Register to Latch-Register
|
85 | PORTB |= (1 << XLAT); |
86 | PORTB &= ~(1 << XLAT); |
87 | }
|
88 | |
89 | void clearAll_2(void) |
90 | {
|
91 | //XLAT low
|
92 | PORTB &= ~(1 << XLAT); |
93 | |
94 | for(int i = 0; i < 12; i++) |
95 | {
|
96 | //SCK low
|
97 | PORTB &= ~(1 << SCK); |
98 | |
99 | //SIN low
|
100 | PORTB = (0 << SIN); |
101 | //PORTB &= (1 << SIN);
|
102 | |
103 | //Pulse SCK
|
104 | PORTB |= (1 << SCK); |
105 | PORTB &= ~(1 << SCK); |
106 | }
|
107 | //Pulse XLAT
|
108 | PORTB |= (1 << XLAT); |
109 | PORTB &= ~(1 << XLAT); |
110 | }
|
111 | |
112 | |
113 | |
114 | |
115 | int main(void) |
116 | {
|
117 | TLC5947_init(); |
118 | |
119 | //Turn On LED-channels
|
120 | PORTB &= ~(1 << BLANK); |
121 | //clearAll();
|
122 | |
123 | |
124 | while(1) |
125 | {
|
126 | |
127 | setPWM(0, 4095); |
128 | writePWM(); |
129 | _delay_ms(2000); |
130 | clearAll_2(); |
131 | _delay_ms(2000); |
132 | |
133 | }
|
134 | }
|
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 User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.