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