]> www.fi.muni.cz Git - bike-lights.git/blob - lights.c
pins.txt: pin-out modifications
[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 led_is_on = 0;
9 volatile unsigned char adccount = 0;
10
11 typedef struct {
12         unsigned char pwmval, expected;
13 } led_level_t;
14
15 led_level_t led_modes[2] = {
16         { 0x50, 0x38 },
17         { 0x38, 0x04 },
18 };
19
20 unsigned char led_mode = 0;
21 unsigned char led_mode_changed = 0;
22
23 static void inline led_on()
24 {
25         DDRB |= _BV( PB5 );
26         PORTA |=  _BV( PA0 );
27         led_is_on = 1;
28 }
29
30 static void inline led_off()
31 {
32         led_is_on = 0;
33         DDRB &= ~_BV( PB5 );
34         PORTA &=~  _BV( PA0 );
35 //        ADCSRA &= ~(_BV(ADIE) | _BV(ADIF));
36 }
37
38 /* ------------ Logging/Debugging ----------- */
39
40 unsigned char debug_state EEMEM;
41
42 static void inline debug_setstate(unsigned char val)
43 {
44         eeprom_write_byte(&debug_state, val);
45 }
46
47 #define LOG_BUFFER 64
48 uint16_t log_buffer[LOG_BUFFER] EEMEM;
49 unsigned char log_buffer_count;
50 uint16_t log_buffer2[LOG_BUFFER];
51 volatile unsigned char stop = 0;
52
53 static void inline init_log()
54 {
55         debug_setstate(1);
56         log_buffer_count = 0;
57 }
58
59 static void log_word(uint16_t word) {
60         if (log_buffer_count >= LOG_BUFFER)
61                 return;
62         
63         // eeprom_write_word(&log_buffer[log_buffer_count], word);
64         log_buffer2[log_buffer_count] = word;
65         log_buffer_count++;
66
67         if (log_buffer_count == LOG_BUFFER) {
68                 unsigned char i;
69                 for (i=0; i < LOG_BUFFER; i++) {
70                         eeprom_write_word(&log_buffer[i],
71                                 log_buffer2[i]);
72                 }
73                 debug_setstate(0x42);
74         }
75 }
76
77 /* ------------ Timer ----------- */
78
79 volatile uint16_t jiffies = 0;
80
81 static void inline init_tmr()
82 {
83         TCCR0A = _BV(WGM00);
84         TCCR0B = _BV(CS02) | _BV(CS00); // 1 kHz
85         OCR0A = 12; // 100 Hz
86         TIMSK |= _BV(OCIE0A);
87         DDRA |= _BV( PA0 );
88
89         jiffies = 0;
90 }
91
92 static void inline tmr_handler()
93 {
94         unsigned char c = jiffies & 0x0F;
95         unsigned char c1 = jiffies & 0x7F;
96
97         ++jiffies;
98
99 #if 0
100         if (c == 1)
101                 led_on();
102
103         if (c == 9)
104                 led_off();
105 #endif
106
107         if (c == 0x02 || c == 0x08)
108                 led_on();
109                 
110         if (c == 0x05 || c == 0x0b)
111                 led_off();
112
113 #if 1
114         if (c1 == 0x10) {
115                 led_mode = 0;
116                 led_mode_changed = 1;
117                 OCR1D = led_modes[led_mode].pwmval;
118         } else if (c1 == 0x70) {
119                 led_mode = 1;
120                 led_mode_changed = 1;
121                 OCR1D = led_modes[led_mode].pwmval;
122         }
123 #endif
124
125         ADCSRA |= _BV(ADSC);
126 #if 0
127         if (led_is_on && adcval != 0xFFEE) {
128                 adcval = 0xFFEE;
129
130                 ADCSRA |= _BV(ADIF) | _BV(ADIE) | _BV(ADSC);
131         }
132 #endif
133 }
134
135 ISR(TIMER0_COMPA_vect)
136 {
137         tmr_handler();
138 }
139
140 /* ------------ PWM ----------- */
141
142 static void inline init_pwm()
143 {
144         /* Async clock */
145         PLLCSR = _BV(LSM) | _BV(PLLE);
146         _delay_ms(1);
147         while (PLLCSR & _BV(PLOCK) == 0)
148                 ;
149         PLLCSR |= _BV(PCKE);
150
151         TCCR1C = _BV(COM1D0) | _BV(COM1D1) | _BV(PWM1D);
152         TCCR1A = _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(PWM1A) | _BV(PWM1B);
153         // TCCR1B = 0x80| _BV(CS13) | _BV(CS11);
154         TCCR1B = _BV(7)                         // PWM1X: PWM inversion mode
155                 | _BV(CS10)                     // no clock prescaling
156                 ;
157         OCR1C = 0xFF;                           // TOP value
158         OCR1D = OCR1B = OCR1A = 0;
159         // OCR1D = 0;
160         DDRB |= _BV( PB5 );
161         PORTB &= ~(_BV( PB5 ) | _BV( PB1 ) | _BV( PB3 ));
162
163         // led_off();
164         // TIMSK |= _BV(TOIE1);
165 }
166
167 #if 0
168 static void inline pwm_handler()
169 {
170         // TIMSK &= ~_BV(TOIE1);
171         // OCR1D = pwmval;
172 }
173
174 ISR(TIMER1_OVF_vect)
175 {
176         pwm_handler();
177 }
178 #endif
179
180 /* ------------ A/D Converter ----------- */
181
182 static void inline init_adc()
183 {
184         ADCSRA = _BV(ADEN)                      // enable
185                 | _BV(ADPS1) | _BV(ADPS0)       // CLK/8 = 125 kHz
186                 // | _BV(ADPS2)                 // CLK/16 = 62.5 kHz
187                 ;
188         ADMUX = _BV(REFS1)                      // 1.1V internal reference
189                 | _BV(MUX4)|_BV(MUX3)   // port ADC5-6, gain 1
190                 ;
191         // ADCSRB = _BV(REFS2); 
192         ADCSRB |= _BV(GSEL); 
193         // Disable digital input on all bits used by ADC
194         DIDR0 = _BV(ADC5D)|_BV(ADC6D) | _BV(AREFD);
195         ADCSRA |= _BV(ADIE);
196 }
197
198 static void inline adc_handler()
199 {
200         uint16_t new_pwm = led_modes[led_mode].pwmval;
201         uint16_t old_pwm = new_pwm;
202         uint16_t adc_exp = led_modes[led_mode].expected;
203
204         adcval = ADCW;
205         adccount++;
206
207         // log_word(((adcval & 0x3FC) << 6) | pwmval);
208
209         if (!led_is_on)
210                 return;
211
212         // ADCSRA &= ~(_BV(ADIE) | _BV(ADIF));
213
214         if (led_mode_changed) {
215                 led_mode_changed = 0;
216                 goto set_pwm;
217         }
218
219         log_word(((adcval & 0xFF) << 8) | old_pwm);
220
221         if (2*adcval > 5*adc_exp) { // >2.5x expected, lower significantly
222                 new_pwm = 2*old_pwm/3;
223         } else if (3*adcval > 4*adc_exp) { // >1.33x expected, lower a bit
224                 new_pwm = old_pwm - 1;
225         } else if (4*adcval < 3*adc_exp) { // 0.75x expected, raise a bit
226                 new_pwm = old_pwm + 1;
227         }
228
229         if (new_pwm > 0x60) { // odpojeno?
230                 new_pwm = 0x60;
231         }
232         if (new_pwm < 2) { // zkrat?
233                 new_pwm = 2;
234         }
235
236 set_pwm:
237         if (new_pwm != old_pwm) {
238                 led_modes[led_mode].pwmval = new_pwm;
239                 OCR1D = new_pwm;
240         }
241         // ADCSRA |= _BV(ADSC);
242 }
243
244 ISR(ADC_vect)
245 {
246         adc_handler();
247 }
248
249 int main(void)
250 {
251         _delay_ms(1500);
252         init_log();
253
254         init_pwm();
255         init_adc();
256         init_tmr();
257
258         led_on();
259         debug_setstate(3);
260
261         sei();
262         while (1)
263                 ; // sleep_mode();
264
265 #if 0
266         while (1) {
267                 PORTA |=  _BV( PA0 );
268                 _delay_ms(200);
269                 PORTA &=~ _BV( PA0 );
270                 _delay_ms(200);
271         }
272 #endif
273 }