Forum: Mikrocontroller und Digitale Elektronik Codeanpassung des Projekts "Demystifying the TLC5940" auf ATMEGA8


von Frank (Gast)


Lesenswert?

Hallo, ich bin gerade dabei den Artikel "Demystifying the TLC5940" von 
https://sites.google.com/site/artcfox/demystifying-the-tlc5940 durch 
zuarbeiten. Ich möchte statt des verwendeten ATMEGA328 allerdings einen 
ATMEGA8 verwenden. Dies macht einige Anpassungen im Code nötig. Mir ist 
zunächst nur der Timer aufgefallen der angepasst werden muss:

Original:
1
  // CTC with OCR0A as TOP
2
  TCCR0A = (1 << WGM01);
3
  // clk_io/1024 (From prescaler)
4
  TCCR0B = ((1 << CS02) | (1 << CS00));
5
  // Generate an interrupt every 4096 clock cycles
6
  OCR0A = 3;
7
  // Enable Timer/Counter0 Compare Match A interrupt
8
  TIMSK0 |= (1 << OCIE0A);

Meine Anpassung:
1
  // CTC with OCR0A as TOP
2
  // TCCR0A = (1 << WGM01);
3
  TCCR1A = (1 << WGM12); //EDIT
4
5
  // clk_io/1024 (From prescaler)
6
  //TCCR0B = ((1 << CS02) | (1 << CS00));
7
  TCCR1B = ((1 << CS12) | (1 << CS10)); //EDIT
8
  
9
  // Generate an interrupt every 4096 clock cycles
10
  //OCR0A = 3;
11
  OCR1A = 3; //EDIT
12
13
  // Enable Timer/Counter0 Compare Match A interrupt
14
  //TIMSK0 |= (1 << OCIE0A);
15
  TIMSK |= (1 << OCIE2); //EDIT S.119

der komplette code ist folgender:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#define GSCLK_DDR DDRB
6
#define GSCLK_PORT PORTB
7
#define GSCLK_PIN PB0
8
9
#define SIN_DDR DDRB
10
#define SIN_PORT PORTB
11
#define SIN_PIN PB3
12
13
#define SCLK_DDR DDRB
14
#define SCLK_PORT PORTB
15
#define SCLK_PIN PB5
16
17
#define BLANK_DDR DDRB
18
#define BLANK_PORT PORTB
19
#define BLANK_PIN PB2
20
21
#define DCPRG_DDR DDRD
22
#define DCPRG_PORT PORTD
23
#define DCPRG_PIN PD4
24
25
#define VPRG_DDR DDRD
26
#define VPRG_PORT PORTD
27
#define VPRG_PIN PD7
28
29
#define XLAT_DDR DDRB
30
#define XLAT_PORT PORTB
31
#define XLAT_PIN PB1
32
33
#define TLC5940_N 1
34
35
#define setOutput(ddr, pin) ((ddr) |= (1 << (pin)))
36
#define setLow(port, pin) ((port) &= ~(1 << (pin)))
37
#define setHigh(port, pin) ((port) |= (1 << (pin)))
38
#define pulse(port, pin) do { \
39
                           setHigh((port), (pin)); \
40
                           setLow((port), (pin)); \
41
                         } while (0)
42
#define outputState(port, pin) ((port) & (1 << (pin)))
43
44
uint8_t dcData[96 * TLC5940_N] = {
45
// MSB            LSB
46
  1, 1, 1, 1, 1, 1,      // Channel 15
47
  1, 1, 1, 1, 1, 1,      // Channel 14
48
  1, 1, 1, 1, 1, 1,      // Channel 13
49
  1, 1, 1, 1, 1, 1,       // Channel 12
50
  1, 1, 1, 1, 1, 1,      // Channel 11
51
  1, 1, 1, 1, 1, 1,      // Channel 10
52
  1, 1, 1, 1, 1, 1,      // Channel 9
53
  1, 1, 1, 1, 1, 1,       // Channel 8
54
  1, 1, 1, 1, 1, 1,       // Channel 7
55
  1, 1, 1, 1, 1, 1,      // Channel 6
56
  1, 1, 1, 1, 1, 1,      // Channel 5
57
  1, 1, 1, 1, 1, 1,       // Channel 4
58
  1, 1, 1, 1, 1, 1,       // Channel 3
59
  1, 1, 1, 1, 1, 1,       // Channel 2
60
  1, 1, 1, 1, 1, 1,       // Channel 1
61
  1, 1, 1, 1, 1, 1,       // Channel 0
62
};
63
64
uint8_t gsData[192 * TLC5940_N] = {
65
// MSB                              LSB
66
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // Channel 15
67
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      // Channel 14
68
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      // Channel 13
69
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,      // Channel 12
70
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,      // Channel 11
71
  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,      // Channel 10
72
  0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,      // Channel 9
73
  0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,      // Channel 8
74
  0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,      // Channel 7
75
  0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,      // Channel 6
76
  0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,      // Channel 5
77
  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,      // Channel 4
78
  0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,      // Channel 3
79
  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      // Channel 2
80
  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,      // Channel 1
81
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,      // Channel 0
82
};
83
84
void TLC5940_Init(void) {
85
  setOutput(GSCLK_DDR, GSCLK_PIN);
86
  setOutput(SCLK_DDR, SCLK_PIN);
87
  setOutput(DCPRG_DDR, DCPRG_PIN);
88
  setOutput(VPRG_DDR, VPRG_PIN);
89
  setOutput(XLAT_DDR, XLAT_PIN);
90
  setOutput(BLANK_DDR, BLANK_PIN);
91
  setOutput(SIN_DDR, SIN_PIN);
92
  
93
  setLow(GSCLK_DDR, GSCLK_PIN);
94
  setLow(SCLK_PORT, SCLK_PIN);
95
  setLow(DCPRG_PORT, DCPRG_PIN);
96
  setHigh(VPRG_PORT, VPRG_PIN);
97
  setLow(XLAT_PORT, XLAT_PIN);
98
  setHigh(BLANK_PORT, BLANK_PIN);
99
100
  // CTC with OCR0A as TOP
101
  // TCCR0A = (1 << WGM01);
102
  TCCR1A = (1 << WGM12); //EDIT
103
104
  // clk_io/1024 (From prescaler)
105
  //TCCR0B = ((1 << CS02) | (1 << CS00));
106
  TCCR1B = ((1 << CS12) | (1 << CS10)); //EDIT
107
  
108
  // Generate an interrupt every 4096 clock cycles
109
  //OCR0A = 3;
110
  OCR1A = 3; //EDIT
111
112
  // Enable Timer/Counter0 Compare Match A interrupt
113
  //TIMSK0 |= (1 << OCIE0A);
114
  TIMSK |= (1 << OCIE2); //EDIT S.119
115
}
116
117
void TLC5940_ClockInDC(void) {
118
  setHigh(DCPRG_PORT, DCPRG_PIN);
119
  setHigh(VPRG_PORT, VPRG_PIN);
120
121
  uint8_t Counter = 0;
122
  
123
  for (;;) {
124
    if (Counter > TLC5940_N * 96 - 1) {
125
      pulse(XLAT_PORT, XLAT_PIN);
126
      break;
127
    } else {
128
      if (dcData[Counter])
129
        setHigh(SIN_PORT, SIN_PIN);
130
      else
131
        setLow(SIN_PORT, SIN_PIN);
132
      pulse(SCLK_PORT, SCLK_PIN);
133
      Counter++;
134
    }
135
  }
136
}
137
138
ISR(TIMER0_COMPA_vect) {
139
  uint8_t firstCycleFlag = 0;
140
  static uint8_t xlatNeedsPulse = 0;
141
142
  setHigh(BLANK_PORT, BLANK_PIN);
143
144
  if (outputState(VPRG_PORT, VPRG_PIN)) {
145
    setLow(VPRG_PORT, VPRG_PIN);
146
    firstCycleFlag = 1;
147
  }
148
149
  if (xlatNeedsPulse) {
150
    pulse(XLAT_PORT, XLAT_PIN);
151
    xlatNeedsPulse = 0;
152
  }
153
  
154
  if (firstCycleFlag)
155
    pulse(SCLK_PORT, SCLK_PIN);
156
  
157
  setLow(BLANK_PORT, BLANK_PIN);
158
  
159
  // Below this we have 4096 cycles to shift in the data for the next cycle
160
  uint8_t Data_Counter = 0;
161
  for (;;) {
162
    if (!(Data_Counter > TLC5940_N * 192 - 1)) {
163
      if (gsData[Data_Counter])
164
        setHigh(SIN_PORT, SIN_PIN);
165
      else
166
        setLow(SIN_PORT, SIN_PIN);
167
      pulse(SCLK_PORT, SCLK_PIN);
168
      Data_Counter++;
169
    } else {
170
      xlatNeedsPulse = 1;
171
      break;
172
    }
173
  }
174
}
175
176
int main(void) {
177
  TLC5940_Init();
178
  TLC5940_ClockInDC();
179
  
180
  // Enable Global Interrupts
181
  sei();
182
183
  for (;;) {
184
  }
185
  
186
  return 0;
187
}

leider funktioniert die ganze Sache noch nicht wirklich. Habe ich noch 
eine Anpassung übersehen?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Frank schrieb:
> ISR(TIMER0_COMPA_vect)

Wenn du alles auf Timer 1 umschreibst, dann solltest du das auch für die 
ISR machen. Die steht ja immer noch auf Timer 0 :-P

von Frank (Gast)


Lesenswert?

Danke, das war ein Fehler, aber es funktioniert leider immer noch nicht. 
Es soll ja der "clock output buffer" verwendet werden. Zitat: "we can 
begin to modify it toward our original goal of using the clock output 
buffer to drive GSCLK". Am PIN PB0 des ATMEGA328 gibt es den CLKO beim 
ATMEGA8 gibt es diesen jedoch nicht. Kann er durch etwas anderes ersetzt 
werden?

von spess53 (Gast)


Lesenswert?

Hi

>Kann er durch etwas anderes ersetzt werden?

Nicht wirklich. Ein Timer kann im CTC-Mode mit OCRnx=0 den halben 
Systemtakt am OC-Pin ausgeben.

MfG Spess

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wäre vermutlich am einfachsten, doch einen Mega48/88/168/328 zu nehmen, 
du kannst allerdings, wenn du mit Quarzoszillator arbeitest, mit einem 
CMOS Buffer das Signal an XTAL2 (PB7) abgreifen und verstärken. Ist 
allerdings bestimmt aufwendiger und teurer, als einfach einen Mega48 in 
den Sockel zu setzen.

von holger (Gast)


Lesenswert?

>Wenn du alles auf Timer 1 umschreibst, dann solltest du das auch für die
>ISR machen. Die steht ja immer noch auf Timer 0 :-P

Tja, der Typ hat es irgendwie nicht so mit den Interruptnummern.
Mal 0, mal 1 , mal 2;)

  //TIMSK0 |= (1 << OCIE0A);
  TIMSK |= (1 << OCIE2); //EDIT S.119
                     ^
                     |
                     |

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
Noch kein Account? Hier anmelden.