c2cf898d1cf7243242ff6c35054323786cdd3549
[dmxpainter.git] / src / tlc.c
1 #include <avr/io.h>
2
3 #include "tlc.h"
4
5 #include "mcu.h"
6
7 #include "buffer.h"
8
9 /////////////////////////////////////////
10
11 volatile uint8_t g_data_available;
12
13 /////////////////////////////////////////
14
15 volatile uint8_t g_data_shifting;
16 void send_data(void);
17 void start_gscycle(void);
18 void tlc_wait_for_data()
19 {
20   if (g_data_shifting) return;
21   send_data();
22   start_gscycle();
23   // Continue in background...
24 }
25 void set_shifting_off(void)
26 {
27   g_data_shifting = 0;
28 }
29
30 /////////////////////////////////////////
31
32 // XLAT pulse to apply data to internal register.
33 void clock_xlat(void)
34 {
35   pin_on(PIN_TLC_XLAT);
36   pin_off(PIN_TLC_XLAT);
37 }
38
39 // SCLK pulse to clock in serial data from SIN.
40 void clock_sclk(void)
41 {
42   pin_on(PIN_TLC_SCLK);
43   pin_off(PIN_TLC_SCLK);
44 }
45
46 void set_blnk_on(void)
47 {
48   pin_on(PIN_TLC_BLNK);
49 }
50
51 void set_blnk_off(void)
52 {
53   pin_off(PIN_TLC_BLNK);
54 }
55
56 void set_vprg_gs_mode(void)
57 {
58   pin_off(PIN_TLC_VPRG);
59 }
60
61 void set_vprg_dc_mode(void)
62 {
63   pin_on(PIN_TLC_VPRG);
64 }
65
66 /////////////////////////////////////////
67
68 void tlc_init(void)
69 {
70   // Initialize blanked (ie. LEDs off).
71   pin_out(PIN_TLC_BLNK);
72   pin_on( PIN_TLC_BLNK);
73
74   // Timer 1 is for our GSCLK:  We refresh with a GS cycle of
75   // about 100 Hz (cf. Timer 2), for each full cycle we need to
76   // clock the PWM 4096 times.
77   // We need about 38 clocks to get 4096 cycles at 100 Hz.
78   mcu_set_timer1_ic(38);
79   // 50% duty cycle.
80   mcu_set_timer1_ocma(1);
81   // * CS1 = 0001:  No prescaler. (p100)
82   // * WGM1 = 1110: Fast PWM, TOP at ICR1
83   // * COM1A = 10: Set at 0, clear at Output Compare Match)
84   TCCR1B = bits_value(CS10) | bits_value(WGM13) | bits_value(WGM12);
85   TCCR1A = bits_value(WGM11) | bits_value(COM1A1);
86
87   /* Timer 2: Refresh-Timer */
88   // * AS2 = 0: Use IO-clock (16 MHz) for base frequency (p119)
89   // * Mode: Normal mode, no PWM, count upwards (WGM21:0 = 00) (p117)
90   // * Disable Output on OC2, needed for SPI (COM21:0 = 00) (p117)
91   // * Prescaler: 1024 (CS22:0 = 111) => 15625 Hz
92   TCCR2 = bits_value(CS22) | bits_value(CS21) | bits_value(CS20);
93   // To get a 100 Hz clock we need to count 157 times (~ 99.5 Hz).
94   mcu_set_timer2_ocm(156);
95
96   // All these pins write to the painter.
97   pin_out(PIN_TLC_GSCK);
98   pin_out(PIN_TLC_VPRG);
99   pin_out(PIN_TLC_XLAT);
100   pin_out(PIN_TLC_SCLK);
101   pin_out(PIN_TLC_SIN);
102
103   // Wait for first DMX packet.
104 }
105
106 void tlc_set_data_done(void)
107 {
108   g_data_available = 1;
109 }
110
111 /////////////////////////////////////////
112
113 void start_gscycle(void)
114 {
115   g_data_shifting = 1;
116   // Start counter with next GS pulse.
117   mcu_int_timer1_ocma_enable();
118 }
119
120 void tlc_int_timer1_ocma(void)
121 {
122   // First, disable this interrupt.
123   mcu_int_timer1_ocma_disable();
124
125   // Restart and enable timeout timer.
126   mcu_set_timer2_cnt(0);
127   mcu_int_timer2_ocm_enable();
128
129   // Switch off BLNK.
130   set_blnk_off();
131   // Hack: Switch on GSCLK
132   pin_out(PIN_TLC_GSCK);
133 }
134
135 void tlc_int_timer2_ocm(void)
136 {
137   // Hack: Switch off GSCLK
138   pin_in(PIN_TLC_GSCK);
139   // Go into BLNK mode (switch off LEDs and reset GSCLK counter)
140   set_blnk_on();
141
142   // Disable GS cycle timeout timer.
143   mcu_int_timer2_ocm_disable();
144
145   // Wait for next DMX packet.
146   set_shifting_off();
147 }
148
149 /////////////////////////////////////////
150
151 void shift8(uint8_t byte)
152 {
153   // Shift out all eight bits.
154   for (uint8_t bit = bits_uint8(1, 0, 0, 0, 0, 0, 0, 0); bit; bit >>= 1) {
155     if (byte & bit) {
156       pin_on(PIN_TLC_SIN);
157     } else {
158       pin_off(PIN_TLC_SIN);
159     }
160     clock_sclk();
161   }
162 }
163
164 void shift12(uint8_t byte)
165 {
166   // The data in the upper 8 bits.
167   shift8(byte);
168
169   // Plus 4 zero bits (makes a shift by 4).
170   pin_off(PIN_TLC_SIN);
171   for (uint8_t bit = 4; bit; bit--) {
172     clock_sclk();
173   }
174 }
175
176 /////////////////////////////////////////
177
178 void send_gs_data(void)
179 {
180   // Set VPRG to GS mode.
181   set_vprg_gs_mode();
182   // Because the TLCs are daisy-chained, we have to shift out the RGB data
183   // starting at the end.  Each painter has 3 TLCs (with 16 channels each), 
184   // for the colors red, green, blue.  So we've got to shift out the 16 blue
185   // channels of the last TLC first, then 16 green ones and finally 16 red 
186   // ones.  The last data we shift out is thus the first red of the first
187   // painter.
188   // This will always point to the start of the current painter data, 
189   // starting with the last one.
190   char * painter_gs = gg_buffer_gs
191                     + TLC_N_CHANNELS
192                     - TLC_N_CHANNELS_PER_PAINTER;
193   // Find the current data byte to shift out, starting with the last one.
194   // Its signed so we can determine when we reached the end/start, eight
195   // bit are enough to index 48 channels per painter.
196 #if TLC_N_CHANNELS_PER_PAINTER != 48
197 #error What a weird painter...
198 #endif
199   while (1) {
200     int8_t index = TLC_N_CHANNELS_PER_PAINTER - 1;
201     while (1) {
202       // Shift out current channel.
203       shift12(painter_gs[index]);
204
205       // Skip two colors.
206       index -= 3;
207
208       // If we reached the start, we jump to the next color.
209       if (index < 0) {
210         // Did we just finish the last (ie. red) channel?
211         if (index == -3)
212           break;
213
214         // Jump to end again and skip to next color.
215         index += TLC_N_CHANNELS_PER_PAINTER - 1;
216       }
217     }
218
219     // Did we just finish the last (ie. first) painter?
220     if (painter_gs == gg_buffer_gs)
221       break;
222
223     // Move to next painter.
224     painter_gs -= TLC_N_CHANNELS_PER_PAINTER;
225   }
226 }
227
228 void send_dc_data(void)
229 {
230   // Set VPRG to DC mode. 
231   set_vprg_dc_mode();  
232
233   // All TLCs on all the connected painters will get the same DC value.
234   // That makes it easy to generate the 6-Bit format we need:  We just
235   // create a constant buffer for the packed rgb values, containing four
236   // values for each color.
237   uint8_t dc_out[3][3];
238   for (int8_t rgb = 2; rgb >= 0; rgb--) {
239     uint8_t dc_data = gg_buffer_dc[rgb] & bits_uint8(1, 1, 1, 1, 1, 1, 0, 0);
240     dc_out[rgb][2] = (dc_data << 0) | (dc_data >> 6);
241     dc_out[rgb][1] = (dc_data << 2) | (dc_data >> 4);
242     dc_out[rgb][0] = (dc_data << 4) | (dc_data >> 2);
243   }
244
245   // Now, shift out the dc-data like we do it with the gs-data:  First the
246   // last blue, then green and red of the last painter, until we reach the
247   // first red.
248   int8_t painter = N_PAINTER;
249   do {
250     int8_t rgb = 3 - 1;
251     do {
252       int8_t index = (TLC_N_CHANNELS_PER_TLC / 4) * 3 - 1;
253       do {
254         shift8(dc_out[rgb][index % 3]);
255         index--;
256       } while (index != -1);
257       rgb--;
258     } while (rgb != -1);
259     painter--;
260   } while (painter != 0);
261 }
262
263 void send_data(void)
264 {
265   // Always shift out DC first.
266   send_dc_data();
267   clock_xlat();
268
269   // No extra SCLK needed, just shift out all GS data.
270   send_gs_data();
271   clock_xlat();
272
273   clock_sclk();
274
275   g_data_available = 0;
276 }
277
278
279 /////////////////////////////////////////