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
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
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)
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.
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.
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
voidTLC5947_init()
35
{
36
DDRB|=(1<<XLAT)|(1<<BLANK)|(1<<SIN)|(1<<SCK);
37
38
pwmbuffer=(uint16_t*)calloc(2,24*numdrivers);
39
}
40
41
voidsetPWM(uint8_tchan,uint16_tpwm)
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
voidwritePWM(void)
56
{
57
PORTB&=~(1<<XLAT);
58
//digitalWrite(_lat, LOW);
59
// 24 channels per TLC5974
60
for(int8_tc=24*numdrivers-1;c>=0;c--)
61
{
62
// 12 bits per channel, send MSB first
63
for(int8_tb=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
voidclearAll_2(void)
90
{
91
//XLAT low
92
PORTB&=~(1<<XLAT);
93
94
for(inti=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
intmain(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!