Mercurial > templog
annotate main.c @ 8:c55321727d02
deep sleep works
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 18 May 2012 20:38:40 +0800 |
parents | 52cb08a01171 |
children | 7da9a3f23592 |
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" |
17 | |
0 | 18 // configuration params |
19 // - measurement interval | |
20 // - transmit interval | |
21 // - bluetooth params | |
22 // - number of sensors (and range?) | |
23 | |
1 | 24 // 1 second. we have 1024 prescaler, 32768 crystal. |
2 | 25 #define SLEEP_COMPARE 32 |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
26 #define MEASURE_WAKE 60 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
27 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
28 #define COMMS_WAKE 3600 |
2 | 29 |
30 #define BAUD 9600 | |
7 | 31 #define UBRR ((F_CPU)/8/(BAUD)-1) |
32 | |
33 #define PORT_LED PORTC | |
34 #define DDR_LED DDRC | |
35 #define PIN_LED PC4 | |
1 | 36 |
6 | 37 #define NUM_MEASUREMENTS 300 |
38 | |
0 | 39 static int uart_putchar(char c, FILE *stream); |
40 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, | |
41 _FDEV_SETUP_WRITE); | |
42 | |
7 | 43 static uint8_t n_measurements = 0; |
6 | 44 // stored as 1/5 degree above 0 |
45 static uint8_t measurements[NUM_MEASUREMENTS]; | |
46 static uint8_t internal_measurements[NUM_MEASUREMENTS]; | |
0 | 47 |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
48 // boolean flags |
7 | 49 static uint8_t need_measurement = 0; |
50 static uint8_t need_comms = 0; | |
51 static uint8_t comms_done = 0; | |
1 | 52 |
7 | 53 static uint8_t readpos = 0; |
0 | 54 static char readbuf[30]; |
55 | |
7 | 56 static uint8_t measure_count = 0; |
57 static uint16_t comms_count = 0; | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
58 |
8 | 59 #define DEBUG(str) printf_P(PSTR(str)) |
60 | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
61 static void deep_sleep(); |
1 | 62 |
0 | 63 static void |
7 | 64 uart_on() |
0 | 65 { |
8 | 66 // Power reduction register |
67 //PRR &= ~_BV(PRUSART0); | |
68 | |
0 | 69 // baud rate |
7 | 70 UBRR0H = (unsigned char)(UBRR >> 8); |
71 UBRR0L = (unsigned char)UBRR; | |
72 // set 2x clock, improves accuracy of UBRR | |
73 UCSR0A |= _BV(U2X0); | |
6 | 74 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); |
0 | 75 //8N1 |
7 | 76 UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); |
6 | 77 } |
78 | |
79 static void | |
80 uart_off() | |
81 { | |
82 // Turn of interrupts and disable tx/rx | |
83 UCSR0B = 0; | |
84 | |
85 // Power reduction register | |
8 | 86 //PRR |= _BV(PRUSART0); |
0 | 87 } |
88 | |
89 static int | |
90 uart_putchar(char c, FILE *stream) | |
91 { | |
8 | 92 if (c == '\n') |
93 { | |
94 uart_putchar('\r', stream); | |
95 } | |
0 | 96 // XXX should sleep in the loop for power. |
2 | 97 loop_until_bit_is_set(UCSR0A, UDRE0); |
98 UDR0 = c; | |
0 | 99 return 0; |
100 } | |
101 | |
102 static void | |
103 cmd_fetch() | |
104 { | |
105 uint16_t crc = 0; | |
106 int i; | |
6 | 107 printf_P(PSTR("%d measurements\n"), n_measurements); |
0 | 108 for (i = 0; i < n_measurements; i++) |
109 { | |
6 | 110 printf_P(PSTR("%3d : %d\n"), i, measurements[i]); |
1 | 111 crc = _crc_ccitt_update(crc, measurements[i]); |
0 | 112 } |
6 | 113 printf_P(PSTR("CRC : %d\n"), crc); |
0 | 114 } |
115 | |
116 static void | |
117 cmd_clear() | |
118 { | |
7 | 119 n_measurements = 0; |
120 printf_P(PSTR("Cleared\n")); | |
0 | 121 } |
122 | |
123 static void | |
124 cmd_btoff() | |
125 { | |
7 | 126 printf_P(PSTR("Turning off\n")); |
127 _delay_ms(50); | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
128 comms_done = 1; |
0 | 129 } |
130 | |
131 static void | |
132 read_handler() | |
133 { | |
6 | 134 if (strcmp_P(readbuf, PSTR("fetch")) == 0) |
0 | 135 { |
136 cmd_fetch(); | |
137 } | |
6 | 138 else if (strcmp_P(readbuf, PSTR("clear")) == 0) |
0 | 139 { |
140 cmd_clear(); | |
141 } | |
6 | 142 else if (strcmp_P(readbuf, PSTR("btoff")) == 0) |
0 | 143 { |
144 cmd_btoff(); | |
145 } | |
146 else | |
147 { | |
6 | 148 printf_P(PSTR("Bad command\n")); |
0 | 149 } |
150 } | |
151 | |
2 | 152 ISR(USART_RX_vect) |
0 | 153 { |
2 | 154 char c = UDR0; |
8 | 155 printf_P(PSTR("wake up '%c'\n"), c); |
0 | 156 if (c == '\n') |
157 { | |
158 readbuf[readpos] = '\0'; | |
159 read_handler(); | |
160 readpos = 0; | |
161 } | |
162 else | |
163 { | |
164 readbuf[readpos] = c; | |
165 readpos++; | |
166 if (readpos >= sizeof(readbuf)) | |
167 { | |
168 readpos = 0; | |
169 } | |
170 } | |
171 } | |
172 | |
2 | 173 ISR(TIMER2_COMPA_vect) |
1 | 174 { |
8 | 175 DEBUG("wake up\n"); |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
176 measure_count ++; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
177 comms_count ++; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
178 if (measure_count == MEASURE_WAKE) |
1 | 179 { |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
180 measure_count = 0; |
1 | 181 need_measurement = 1; |
182 } | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
183 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
184 if (comms_count == COMMS_WAKE) |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
185 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
186 comms_count = 0; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
187 need_comms = 1; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
188 } |
7 | 189 |
190 PORT_LED ^= _BV(PIN_LED); | |
1 | 191 } |
192 | |
3 | 193 DWORD get_fattime (void) |
194 { | |
195 return 0; | |
196 } | |
197 | |
1 | 198 static void |
199 deep_sleep() | |
200 { | |
8 | 201 DEBUG("deep sleep\n"); |
1 | 202 // p119 of manual |
2 | 203 OCR2A = SLEEP_COMPARE; |
204 loop_until_bit_is_clear(ASSR, OCR2AUB); | |
1 | 205 |
8 | 206 DEBUG("really about to\n"); |
207 | |
1 | 208 set_sleep_mode(SLEEP_MODE_PWR_SAVE); |
8 | 209 DEBUG("done.\n"); |
1 | 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); | |
316 _delay_ms(100); | |
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 | |
0 | 337 int main(void) |
338 { | |
7 | 339 DDR_LED |= _BV(PIN_LED); |
8 | 340 blink(); |
7 | 341 |
6 | 342 stdout = &mystdout; |
7 | 343 uart_on(); |
344 | |
6 | 345 fprintf_P(&mystdout, PSTR("hello %d\n"), 12); |
8 | 346 uart_off(); |
0 | 347 |
6 | 348 // turn off everything except timer2 |
8 | 349 //PRR = _BV(PRTWI) | _BV(PRTIM0) | _BV(PRTIM1) | _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC); |
350 | |
351 // for testing | |
352 uart_on(); | |
353 | |
354 DEBUG("power off\n"); | |
355 sei(); | |
356 DEBUG("sei done\n"); | |
357 | |
0 | 358 |
1 | 359 // set up counter2. |
360 // COM21 COM20 Set OC2 on Compare Match (p116) | |
361 // WGM21 Clear counter on compare | |
8 | 362 TCCR2A = _BV(COM2A1) | _BV(COM2A0) | _BV(WGM21); |
1 | 363 // CS22 CS21 CS20 clk/1024 |
2 | 364 TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); |
1 | 365 // set async mode |
366 ASSR |= _BV(AS2); | |
8 | 367 // interrupt |
368 TIMSK2 = _BV(OCIE2A); | |
0 | 369 |
8 | 370 DEBUG("async setup\n"); |
7 | 371 |
6 | 372 #ifdef TEST_MODE |
373 for (;;) | |
374 { | |
375 do_comms() | |
376 } | |
377 #else | |
0 | 378 for(;;){ |
379 /* insert your main loop code here */ | |
1 | 380 if (need_measurement) |
381 { | |
382 do_measurement(); | |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
383 continue; |
1 | 384 } |
4
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
385 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
386 if (need_comms) |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
387 { |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
388 do_comms(); |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
389 continue; |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
390 } |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
391 |
54d369e3d689
Fill out more main.c structure
Matt Johnston <matt@ucc.asn.au>
parents:
3
diff
changeset
|
392 deep_sleep(); |
0 | 393 } |
6 | 394 #endif |
0 | 395 return 0; /* never reached */ |
396 } |