]> www.fi.muni.cz Git - bike-lights.git/blob - lights.c
PWM + ADC + code cleanups
[bike-lights.git] / lights.c
1 #include <avr/io.h>
2 #include <avr/eeprom.h>
3 #include <util/delay.h>
4 #include <avr/sleep.h>
5 #include <avr/interrupt.h>
6
7 volatile uint16_t adcval;
8 unsigned char pwmval = 0x28;
9 uint16_t pwmints = 0;
10
11 volatile struct
12 {
13   uint8_t pwm_int: 1;
14   uint8_t adc_int: 1;
15   uint8_t tmr_int: 1;
16 }
17 intflags;
18
19 static void inline led_on()
20 {
21         DDRB |= _BV( PB5 );
22 }
23
24 static void inline led_off()
25 {
26         DDRB &= ~_BV( PB5 );
27 }
28
29 /* ------------ Logging/Debugging ----------- */
30
31 unsigned char debug_state EEMEM;
32
33 static void inline debug_setstate(unsigned char val)
34 {
35         eeprom_write_byte(&debug_state, val);
36 }
37
38 #define LOG_BUFFER 192
39 uint16_t log_buffer[LOG_BUFFER] EEMEM;
40 uint16_t log_buffer_count;
41
42 static void inline init_log()
43 {
44         debug_setstate(1);
45         log_buffer_count = 0;
46 }
47
48 static void log_word(uint16_t word) {
49         if (log_buffer_count == LOG_BUFFER) {
50                 debug_setstate(0x42);
51                 log_buffer_count++;
52         }
53         if (log_buffer_count >= LOG_BUFFER)
54                 return;
55         
56         eeprom_write_word(&log_buffer[log_buffer_count], word);
57         log_buffer_count++;
58 }
59
60 /* ------------ Timer ----------- */
61
62 uint16_t clock = 0;
63
64 static void inline init_tmr()
65 {
66         TCCR0A = _BV(WGM00);
67         TCCR0B = _BV(CS02) | _BV(CS00); // 1 kHz
68         OCR0A = 10; // 100 Hz
69         TIMSK |= _BV(OCIE0A);
70         DDRA |= _BV( PA0 );
71
72         clock = 0;
73 }
74
75 static void inline tmr_handler()
76 {
77         unsigned char c = clock & 0x7F;
78         ++clock;
79
80         if (c == 10 || c == 30) 
81                 led_on();
82
83         if (c == 20 || c == 40)
84                 led_off();
85
86         log_word(adcval);
87         if (adcval != 0xFFEE) {
88                 adcval = 0xFFEE;
89
90                 ADCSRA |= _BV(ADIE) | _BV(ADSC);
91         }
92 }
93
94 ISR(TIMER0_COMPA_vect)
95 {
96         tmr_handler();
97 }
98
99 /* ------------ PWM ----------- */
100
101 static void inline init_pwm()
102 {
103         /* Async clock */
104         PLLCSR = _BV(LSM) | _BV(PLLE);
105         _delay_ms(1);
106         while (PLLCSR & _BV(PLOCK) == 0)
107                 ;
108         PLLCSR |= _BV(PCKE);
109
110         TCCR1C = _BV(COM1D0) | _BV(COM1D1) | _BV(PWM1D);
111         TCCR1A = _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(PWM1A) | _BV(PWM1B);
112         // TCCR1B = 0x80| _BV(CS13) | _BV(CS11);
113         TCCR1B = 0x80 | _BV(CS10);
114         OCR1C = 0xFF;
115         OCR1D = OCR1B = OCR1A = pwmval;
116         TCNT1 = 0;
117         DDRB |= _BV( PB5 );
118         PORTB &= ~(_BV( PB5 ) | _BV( PB1 ) | _BV( PB3 ));
119
120         led_off();
121         // TIMSK |= _BV(TOIE1);
122 }
123
124 #if 0
125 static void inline pwm_handler()
126 {
127         TCNT1 = 0;
128         OCR1D = pwmval;
129 }
130
131 ISR(TIMER1_OVF_vect)
132 {
133         TIMSK &= ~_BV(TOIE1);
134         pwm_handler();
135 }
136 #endif
137
138 /* ------------ A/D Converter ----------- */
139
140 static void inline init_adc()
141 {
142         ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADPS1) | _BV(ADPS0);
143         ADMUX = _BV(REFS1) | _BV(MUX0);
144         // ADCSRB = _BV(REFS2); 
145         DIDR0 = _BV(ADC1D) | _BV(AREFD);
146 }
147
148 static void inline adc_handler()
149 {
150         static unsigned char last_pwmval = 0;
151         static unsigned char counter = 0;
152         uint16_t tmp = pwmval;
153         static uint16_t discard = 5;
154
155         adcval = ADCW;
156         ADCSRA &= ~_BV(ADIE);         /* disable ADC interrupt */
157 #if 0
158         if (--discard > 0)
159                 goto out;
160
161         if (adcval > 0x300)
162                 tmp = 3*tmp/4;
163         else if (adcval > 0x280)
164                 tmp = 7*tmp/8;
165         else if (adcval > 0x201)
166                 tmp--;
167         else if (adcval < 0x100)
168                 tmp = 5*tmp/4;
169         else if (adcval < 0x180)
170                 tmp = 9*tmp/8;
171         else if (adcval < 0x1ff)
172                 tmp++;
173
174         if (tmp > 0xFF)
175                 tmp = 0xFF;
176         if (tmp == 0)
177                 tmp = 1;
178
179         counter++;
180         if ((last_pwmval > tmp && last_pwmval - tmp > 10)
181                 || (last_pwmval < tmp && tmp - last_pwmval > 10)
182                 || (counter > 2)) {
183                 counter = 0;
184         
185                 if (rv_count < BUFFER-1) {
186                         eeprom_write_word(&readval[rv_count++], adcval);
187                         eeprom_write_word(&readval[rv_count++], pwmval);
188                         if (rv_count >= BUFFER)
189                                 eeprom_write_byte(&debug, 42);
190                 }
191         }
192
193         last_pwmval = pwmval;
194         pwmval = tmp;
195
196         if (pwmval != last_pwmval) {
197                 TIMSK |= _BV(TOIE1);
198                 
199                 discard = 1000;
200         } else {
201                 discard = 0;
202         }
203
204 out:
205         //TIMSK |= _BV(TOIE1);
206         ADCSRA |= _BV(ADIE) | _BV(ADSC);
207 #endif
208 }
209
210 ISR(ADC_vect)
211 {
212         adc_handler();
213 }
214
215 #if 0
216         if (--pcount == 0) {
217                 ppos++;
218                 pcount = pattern[ppos].length;
219                 if (!pcount) {
220                         ppos = 0;
221                         pcount = pattern[ppos].length;
222                 }
223                 if (pattern[ppos].intensity) {
224                         PORTA |= _BV(PA0);
225                 } else {
226                         PORTA &= ~_BV(PA0);
227                 }
228         }
229 #endif
230
231 int main(void)
232 {
233         char seen = 0;
234         char pcount, ppos;
235         unsigned char adcidx = 0;
236         uint16_t adcvals[16];
237
238         init_log();
239
240         init_pwm();
241         init_adc();
242         init_tmr();
243
244         debug_setstate(2);
245
246         sei();
247         while (1)
248                 ; //sleep_mode();
249 #if 0
250                 if (!seen) {
251                         seen = 1;
252                         eeprom_write_byte(&debug, 2);
253                 }
254 #endif
255
256     DDRA |= _BV( PA0 );
257     while( 1 ) { 
258         PORTA |=  _BV( PA0 );
259         _delay_ms(200);
260         PORTA &=~ _BV( PA0 );
261     }
262 }