Mercurial > templog
annotate main.c @ 11:06bedbe8540d
all these optimisations make it 30% smaller
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 19 May 2012 17:15:50 +0800 |
parents | 1bfe28c348dd |
children | 3c27bfbd7f3a |
rev | line source |
---|---|
0 | 1 /* Name: main.c |
2 * Author: <insert your name here> | |
3 * Copyright: <insert your copyright message here> | |
4 * License: <insert your license reference here> | |
5 */ | |
6 | |
7 #include <stdio.h> | |
8 #include <string.h> | |
1 | 9 #include <avr/io.h> |
10 #include <avr/interrupt.h> | |
11 #include <avr/sleep.h> | |
7 | 12 #include <util/delay.h> |
6 | 13 #include <avr/pgmspace.h> |
0 | 14 #include <util/crc16.h> |
15 | |
3 | 16 #include "integer.h" |
9 | 17 #include "onewire.h" |
10 | 18 #include "ds18x20.h" |
3 | 19 |
0 | 20 // configuration params |
21 // - measurement interval | |
22 // - transmit interval | |
23 // - bluetooth params | |
24 // - number of sensors (and range?) | |
25 | |
1 | 26 // 1 second. we have 1024 prescaler, 32768 crystal. |
2 | 27 #define SLEEP_COMPARE 32 |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
28 #define MEASURE_WAKE 60 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
29 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
30 #define COMMS_WAKE 3600 |
2 | 31 |
10 | 32 #define BAUD 19200 |
7 | 33 #define UBRR ((F_CPU)/8/(BAUD)-1) |
34 | |
35 #define PORT_LED PORTC | |
36 #define DDR_LED DDRC | |
37 #define PIN_LED PC4 | |
1 | 38 |
6 | 39 #define NUM_MEASUREMENTS 300 |
40 | |
10 | 41 int uart_putchar(char c, FILE *stream); |
0 | 42 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, |
43 _FDEV_SETUP_WRITE); | |
44 | |
7 | 45 static uint8_t n_measurements = 0; |
6 | 46 // stored as 1/5 degree above 0 |
47 static uint8_t measurements[NUM_MEASUREMENTS]; | |
48 static uint8_t internal_measurements[NUM_MEASUREMENTS]; | |
0 | 49 |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
50 // boolean flags |
7 | 51 static uint8_t need_measurement = 0; |
52 static uint8_t need_comms = 0; | |
53 static uint8_t comms_done = 0; | |
1 | 54 |
7 | 55 static uint8_t readpos = 0; |
0 | 56 static char readbuf[30]; |
57 | |
7 | 58 static uint8_t measure_count = 0; |
59 static uint16_t comms_count = 0; | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
60 |
8 | 61 #define DEBUG(str) printf_P(PSTR(str)) |
62 | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
63 static void deep_sleep(); |
1 | 64 |
0 | 65 static void |
7 | 66 uart_on() |
0 | 67 { |
8 | 68 // Power reduction register |
69 //PRR &= ~_BV(PRUSART0); | |
70 | |
0 | 71 // baud rate |
7 | 72 UBRR0H = (unsigned char)(UBRR >> 8); |
73 UBRR0L = (unsigned char)UBRR; | |
74 // set 2x clock, improves accuracy of UBRR | |
75 UCSR0A |= _BV(U2X0); | |
6 | 76 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); |
0 | 77 //8N1 |
7 | 78 UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); |
6 | 79 } |
80 | |
81 static void | |
82 uart_off() | |
83 { | |
84 // Turn of interrupts and disable tx/rx | |
85 UCSR0B = 0; | |
86 | |
87 // Power reduction register | |
8 | 88 //PRR |= _BV(PRUSART0); |
0 | 89 } |
90 | |
10 | 91 int |
0 | 92 uart_putchar(char c, FILE *stream) |
93 { | |
10 | 94 // XXX should sleep in the loop for power. |
8 | 95 if (c == '\n') |
96 { | |
10 | 97 loop_until_bit_is_set(UCSR0A, UDRE0); |
98 UDR0 = '\r';; | |
8 | 99 } |
2 | 100 loop_until_bit_is_set(UCSR0A, UDRE0); |
101 UDR0 = c; | |
10 | 102 if (c == '\r') |
103 { | |
104 loop_until_bit_is_set(UCSR0A, UDRE0); | |
105 UDR0 = '\n';; | |
106 } | |
0 | 107 return 0; |
108 } | |
109 | |
110 static void | |
111 cmd_fetch() | |
112 { | |
113 uint16_t crc = 0; | |
114 int i; | |
6 | 115 printf_P(PSTR("%d measurements\n"), n_measurements); |
0 | 116 for (i = 0; i < n_measurements; i++) |
117 { | |
6 | 118 printf_P(PSTR("%3d : %d\n"), i, measurements[i]); |
1 | 119 crc = _crc_ccitt_update(crc, measurements[i]); |
0 | 120 } |
6 | 121 printf_P(PSTR("CRC : %d\n"), crc); |
0 | 122 } |
123 | |
124 static void | |
125 cmd_clear() | |
126 { | |
7 | 127 n_measurements = 0; |
128 printf_P(PSTR("Cleared\n")); | |
0 | 129 } |
130 | |
131 static void | |
132 cmd_btoff() | |
133 { | |
7 | 134 printf_P(PSTR("Turning off\n")); |
135 _delay_ms(50); | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
136 comms_done = 1; |
0 | 137 } |
138 | |
139 static void | |
140 read_handler() | |
141 { | |
6 | 142 if (strcmp_P(readbuf, PSTR("fetch")) == 0) |
0 | 143 { |
144 cmd_fetch(); | |
145 } | |
6 | 146 else if (strcmp_P(readbuf, PSTR("clear")) == 0) |
0 | 147 { |
148 cmd_clear(); | |
149 } | |
6 | 150 else if (strcmp_P(readbuf, PSTR("btoff")) == 0) |
0 | 151 { |
152 cmd_btoff(); | |
153 } | |
154 else | |
155 { | |
6 | 156 printf_P(PSTR("Bad command\n")); |
0 | 157 } |
158 } | |
159 | |
2 | 160 ISR(USART_RX_vect) |
0 | 161 { |
2 | 162 char c = UDR0; |
0 | 163 if (c == '\n') |
164 { | |
165 readbuf[readpos] = '\0'; | |
166 read_handler(); | |
167 readpos = 0; | |
168 } | |
169 else | |
170 { | |
171 readbuf[readpos] = c; | |
172 readpos++; | |
173 if (readpos >= sizeof(readbuf)) | |
174 { | |
175 readpos = 0; | |
176 } | |
177 } | |
178 } | |
179 | |
2 | 180 ISR(TIMER2_COMPA_vect) |
1 | 181 { |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
182 measure_count ++; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
183 comms_count ++; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
184 if (measure_count == MEASURE_WAKE) |
1 | 185 { |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
186 measure_count = 0; |
1 | 187 need_measurement = 1; |
188 } | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
189 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
190 if (comms_count == COMMS_WAKE) |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
191 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
192 comms_count = 0; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
193 need_comms = 1; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
194 } |
1 | 195 } |
196 | |
3 | 197 DWORD get_fattime (void) |
198 { | |
199 return 0; | |
200 } | |
201 | |
1 | 202 static void |
203 deep_sleep() | |
204 { | |
205 // p119 of manual | |
2 | 206 OCR2A = SLEEP_COMPARE; |
207 loop_until_bit_is_clear(ASSR, OCR2AUB); | |
1 | 208 |
209 set_sleep_mode(SLEEP_MODE_PWR_SAVE); | |
210 sleep_mode(); | |
211 } | |
212 | |
213 static void | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
214 idle_sleep() |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
215 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
216 set_sleep_mode(SLEEP_MODE_IDLE); |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
217 sleep_mode(); |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
218 } |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
219 |
6 | 220 static void |
221 do_adc_335() | |
222 { | |
8 | 223 //PRR &= ~_BV(PRADC); |
6 | 224 |
225 ADMUX = _BV(ADLAR); | |
226 | |
227 // ADPS2 = /16 prescaler, 62khz at 1mhz clock | |
228 ADCSRA = _BV(ADEN) | _BV(ADPS2); | |
229 | |
230 // measure value | |
231 ADCSRA |= _BV(ADSC); | |
232 loop_until_bit_is_clear(ADCSRA, ADSC); | |
233 uint8_t low = ADCL; | |
234 uint8_t high = ADCH; | |
235 uint16_t f_measure = low + (high << 8); | |
236 | |
237 // set to measure 1.1 reference | |
238 ADMUX = _BV(ADLAR) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
239 ADCSRA |= _BV(ADSC); | |
240 loop_until_bit_is_clear(ADCSRA, ADSC); | |
241 uint8_t low_11 = ADCL; | |
242 uint8_t high_11 = ADCH; | |
243 uint16_t f_11 = low_11 + (high_11 << 8); | |
244 | |
245 float res_volts = 1.1 * f_measure / f_11; | |
246 | |
247 // 10mV/degree | |
248 // scale to 1/5 degree units above 0C | |
249 int temp = (res_volts - 2.73) * 500; | |
250 measurements[n_measurements] = temp; | |
251 // XXX something if it hits the limit | |
252 | |
253 // measure AVR internal temperature against 1.1 ref. | |
254 ADMUX = _BV(ADLAR) | _BV(MUX3) | _BV(REFS1) | _BV(REFS0); | |
255 ADCSRA |= _BV(ADSC); | |
256 loop_until_bit_is_clear(ADCSRA, ADSC); | |
257 uint16_t res_internal = ADCL; | |
258 res_internal |= ADCH << 8; | |
259 | |
260 float internal_volts = res_internal * (1.1 / 1024.0); | |
261 | |
262 // 1mV/degree | |
263 int internal_temp = (internal_volts - 2.73) * 5000; | |
264 internal_measurements[n_measurements] = internal_temp; | |
265 | |
266 printf_P("measure %d: external %d, internal %d, 1.1 %d\n", | |
267 n_measurements, temp, internal_temp, f_11); | |
268 | |
269 n_measurements++; | |
8 | 270 //PRR |= _BV(PRADC); |
6 | 271 } |
272 | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
273 static void |
1 | 274 do_measurement() |
275 { | |
276 need_measurement = 0; | |
6 | 277 |
278 do_adc_335(); | |
1 | 279 } |
280 | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
281 static void |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
282 do_comms() |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
283 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
284 need_comms = 0; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
285 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
286 // turn on bluetooth |
7 | 287 uart_on(); |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
288 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
289 // write sd card here? same 3.3v regulator... |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
290 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
291 comms_done = 0; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
292 for (;;) |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
293 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
294 if (comms_done) |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
295 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
296 break; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
297 } |
6 | 298 |
299 if (need_measurement) | |
300 { | |
301 do_measurement(); | |
302 } | |
303 | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
304 idle_sleep(); |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
305 } |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
306 |
6 | 307 uart_off(); |
308 | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
309 // turn off bluetooth |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
310 } |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
311 |
7 | 312 static void |
313 blink() | |
314 { | |
315 PORT_LED &= ~_BV(PIN_LED); | |
9 | 316 _delay_ms(1); |
7 | 317 PORT_LED |= _BV(PIN_LED); |
318 } | |
319 | |
320 static void | |
321 long_delay(int ms) | |
322 { | |
323 int iter = ms / 100; | |
324 | |
325 for (int i = 0; i < iter; i++) | |
326 { | |
327 _delay_ms(100); | |
328 } | |
329 } | |
330 | |
8 | 331 ISR(BADISR_vect) |
332 { | |
333 uart_on(); | |
334 printf_P(PSTR("Bad interrupt\n")); | |
335 } | |
336 | |
9 | 337 static void |
338 set_2mhz() | |
339 { | |
340 cli(); | |
341 CLKPR = _BV(CLKPCE); | |
342 // divide by 4 | |
343 CLKPR = _BV(CLKPS1); | |
344 sei(); | |
345 } | |
346 | |
347 static void | |
348 test1wire() | |
349 { | |
10 | 350 //ow_reset(); |
351 | |
352 uint8_t ret = DS18X20_start_meas( DS18X20_POWER_PARASITE, NULL); | |
353 printf("ret %d\n", ret); | |
354 _delay_ms(DS18B20_TCONV_12BIT); | |
355 DS18X20_read_meas_all_verbose(); | |
9 | 356 } |
357 | |
0 | 358 int main(void) |
359 { | |
9 | 360 set_2mhz(); |
361 | |
7 | 362 DDR_LED |= _BV(PIN_LED); |
8 | 363 blink(); |
7 | 364 |
6 | 365 stdout = &mystdout; |
7 | 366 uart_on(); |
367 | |
6 | 368 fprintf_P(&mystdout, PSTR("hello %d\n"), 12); |
8 | 369 uart_off(); |
0 | 370 |
6 | 371 // turn off everything except timer2 |
8 | 372 //PRR = _BV(PRTWI) | _BV(PRTIM0) | _BV(PRTIM1) | _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC); |
373 | |
374 // for testing | |
375 uart_on(); | |
376 | |
10 | 377 //sei(); |
8 | 378 |
10 | 379 for (;;) |
380 { | |
381 test1wire(); | |
382 long_delay(2000); | |
383 } | |
0 | 384 |
1 | 385 // set up counter2. |
386 // COM21 COM20 Set OC2 on Compare Match (p116) | |
387 // WGM21 Clear counter on compare | |
8 | 388 TCCR2A = _BV(COM2A1) | _BV(COM2A0) | _BV(WGM21); |
1 | 389 // CS22 CS21 CS20 clk/1024 |
2 | 390 TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); |
1 | 391 // set async mode |
392 ASSR |= _BV(AS2); | |
8 | 393 // interrupt |
394 TIMSK2 = _BV(OCIE2A); | |
0 | 395 |
6 | 396 #ifdef TEST_MODE |
397 for (;;) | |
398 { | |
399 do_comms() | |
400 } | |
401 #else | |
0 | 402 for(;;){ |
9 | 403 |
404 test1wire(); | |
405 | |
0 | 406 /* insert your main loop code here */ |
1 | 407 if (need_measurement) |
408 { | |
409 do_measurement(); | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
410 continue; |
1 | 411 } |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
412 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
413 if (need_comms) |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
414 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
415 do_comms(); |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
416 continue; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
417 } |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
418 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
419 deep_sleep(); |
9 | 420 blink(); |
10 | 421 printf("."); |
0 | 422 } |
6 | 423 #endif |
0 | 424 return 0; /* never reached */ |
425 } |