Mercurial > templog
comparison main.c @ 13:4838bfcb3504
Add eeprom stuff
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 19 May 2012 23:59:12 +0800 |
parents | 3c27bfbd7f3a |
children | 426fb44ece3f |
comparison
equal
deleted
inserted
replaced
12:3c27bfbd7f3a | 13:4838bfcb3504 |
---|---|
4 * License: <insert your license reference here> | 4 * License: <insert your license reference here> |
5 */ | 5 */ |
6 | 6 |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <stddef.h> | |
9 #include <avr/io.h> | 10 #include <avr/io.h> |
10 #include <avr/interrupt.h> | 11 #include <avr/interrupt.h> |
11 #include <avr/sleep.h> | 12 #include <avr/sleep.h> |
12 #include <util/delay.h> | 13 #include <util/delay.h> |
13 #include <avr/pgmspace.h> | 14 #include <avr/pgmspace.h> |
15 #include <avr/eeprom.h> | |
14 #include <util/crc16.h> | 16 #include <util/crc16.h> |
15 | 17 |
16 // for DWORD of get_fattime() | 18 // for DWORD of get_fattime() |
17 #include "integer.h" | 19 #include "integer.h" |
18 | 20 |
19 #include "simple_ds18b20.h" | 21 #include "simple_ds18b20.h" |
22 #include "onewire.h" | |
20 | 23 |
21 // configuration params | 24 // configuration params |
22 // - measurement interval | 25 // - measurement interval |
23 // - transmit interval | 26 // - transmit interval |
24 // - bluetooth params | 27 // - bluetooth params |
26 | 29 |
27 // 1 second. we have 1024 prescaler, 32768 crystal. | 30 // 1 second. we have 1024 prescaler, 32768 crystal. |
28 #define SLEEP_COMPARE 32 | 31 #define SLEEP_COMPARE 32 |
29 #define MEASURE_WAKE 60 | 32 #define MEASURE_WAKE 60 |
30 | 33 |
34 #define VALUE_NOSENSOR -9000 | |
35 #define VALUE_BROKEN -8000 | |
36 | |
31 #define COMMS_WAKE 3600 | 37 #define COMMS_WAKE 3600 |
32 | 38 |
33 #define BAUD 19200 | 39 #define BAUD 19200 |
34 #define UBRR ((F_CPU)/8/(BAUD)-1) | 40 #define UBRR ((F_CPU)/8/(BAUD)-1) |
35 | 41 |
36 #define PORT_LED PORTC | 42 #define PORT_LED PORTC |
37 #define DDR_LED DDRC | 43 #define DDR_LED DDRC |
38 #define PIN_LED PC4 | 44 #define PIN_LED PC4 |
39 | 45 |
40 #define NUM_MEASUREMENTS 300 | 46 #define NUM_MEASUREMENTS 100 |
47 #define MAX_SENSORS 5 | |
41 | 48 |
42 int uart_putchar(char c, FILE *stream); | 49 int uart_putchar(char c, FILE *stream); |
43 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, | 50 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, |
44 _FDEV_SETUP_WRITE); | 51 _FDEV_SETUP_WRITE); |
45 | 52 |
46 static uint8_t n_measurements = 0; | 53 static uint16_t n_measurements = 0; |
47 // stored as 1/5 degree above 0 | 54 // stored as decidegrees |
48 static uint8_t measurements[NUM_MEASUREMENTS]; | 55 static int16_t measurements[MAX_SENSORS][NUM_MEASUREMENTS]; |
49 static uint8_t internal_measurements[NUM_MEASUREMENTS]; | |
50 | 56 |
51 // boolean flags | 57 // boolean flags |
52 static uint8_t need_measurement = 0; | 58 static uint8_t need_measurement = 0; |
53 static uint8_t need_comms = 0; | 59 static uint8_t need_comms = 0; |
54 static uint8_t comms_done = 0; | 60 static uint8_t comms_done = 0; |
56 static uint8_t readpos = 0; | 62 static uint8_t readpos = 0; |
57 static char readbuf[30]; | 63 static char readbuf[30]; |
58 | 64 |
59 static uint8_t measure_count = 0; | 65 static uint8_t measure_count = 0; |
60 static uint16_t comms_count = 0; | 66 static uint16_t comms_count = 0; |
67 | |
68 // thanks to http://projectgus.com/2010/07/eeprom-access-with-arduino/ | |
69 #define eeprom_read_to(dst_p, eeprom_field, dst_size) eeprom_read_block((dst_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (dst_size)) | |
70 #define eeprom_read(dst, eeprom_field) eeprom_read_to((&dst), eeprom_field, sizeof(dst)) | |
71 #define eeprom_write_from(src_p, eeprom_field, src_size) eeprom_write_block((src_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (src_size)) | |
72 #define eeprom_write(src, eeprom_field) { eeprom_write_from(&src, eeprom_field, sizeof(src)); } | |
73 | |
74 #define EXPECT_MAGIC 0x67c9 | |
75 | |
76 struct __attribute__ ((__packed__)) __eeprom_data { | |
77 uint16_t magic; | |
78 uint8_t n_sensors; | |
79 uint8_t sensor_id[MAX_SENSORS][8]; | |
80 }; | |
61 | 81 |
62 #define DEBUG(str) printf_P(PSTR(str)) | 82 #define DEBUG(str) printf_P(PSTR(str)) |
63 | 83 |
64 static void deep_sleep(); | 84 static void deep_sleep(); |
65 | 85 |
110 | 130 |
111 static void | 131 static void |
112 cmd_fetch() | 132 cmd_fetch() |
113 { | 133 { |
114 uint16_t crc = 0; | 134 uint16_t crc = 0; |
115 int i; | 135 uint16_t sens; |
136 eeprom_read(sens, n_sensors); | |
137 | |
116 printf_P(PSTR("%d measurements\n"), n_measurements); | 138 printf_P(PSTR("%d measurements\n"), n_measurements); |
117 for (i = 0; i < n_measurements; i++) | 139 for (uint16_t i = 0; i < n_measurements; i++) |
118 { | 140 { |
119 printf_P(PSTR("%3d : %d\n"), i, measurements[i]); | 141 printf_P(PSTR("%3d :"), i); |
120 crc = _crc_ccitt_update(crc, measurements[i]); | 142 for (uint8_t s = 0; s < sens; s++) |
143 { | |
144 printf_P(PSTR(" %6d"), measurements[s][i]); | |
145 crc = _crc_ccitt_update(crc, measurements[s][i]); | |
146 } | |
147 putchar('\n'); | |
121 } | 148 } |
122 printf_P(PSTR("CRC : %d\n"), crc); | 149 printf_P(PSTR("CRC : %d\n"), crc); |
123 } | 150 } |
124 | 151 |
125 static void | 152 static void |
146 | 173 |
147 static void | 174 static void |
148 cmd_sensors() | 175 cmd_sensors() |
149 { | 176 { |
150 uint8_t ret = simple_ds18b20_start_meas(NULL); | 177 uint8_t ret = simple_ds18b20_start_meas(NULL); |
151 printf("All sensors, ret %d, waiting...\n", ret); | 178 printf_P(("All sensors, ret %d, waiting...\n"), ret); |
152 _delay_ms(DS18B20_TCONV_12BIT); | 179 _delay_ms(DS18B20_TCONV_12BIT); |
153 simple_ds18b20_read_all(); | 180 simple_ds18b20_read_all(); |
154 } | 181 } |
155 | 182 |
183 // 0 on success | |
184 static uint8_t | |
185 get_hex_string(const char *hex, uint8_t *out, uint8_t size) | |
186 { | |
187 uint8_t upper; | |
188 uint8_t o; | |
189 for (uint8_t i = 0, z = 0; o < size; i++) | |
190 { | |
191 uint8_t h = hex[i]; | |
192 if (h >= 'A' && h <= 'F') | |
193 { | |
194 // lower case | |
195 h += 0x20; | |
196 } | |
197 uint8_t nibble; | |
198 if (h >= '0' && h <= '9') | |
199 { | |
200 nibble = h - '0'; | |
201 } | |
202 else if (h >= 'a' && h <= 'f') | |
203 { | |
204 nibble = 10 + h - 'a'; | |
205 } | |
206 else if (h == ' ' || h == ':') | |
207 { | |
208 continue; | |
209 } | |
210 else | |
211 { | |
212 printf_P(PSTR("Bad hex 0x%x '%c'\n"), hex[i], hex[i]); | |
213 return 1; | |
214 } | |
215 | |
216 if (z % 2 == 0) | |
217 { | |
218 upper = nibble << 4; | |
219 } | |
220 else | |
221 { | |
222 out[o] = upper | nibble; | |
223 o++; | |
224 } | |
225 | |
226 z++; | |
227 } | |
228 | |
229 if (o != size) | |
230 { | |
231 printf_P(PSTR("Short hex\n")); | |
232 return 1; | |
233 } | |
234 return 0; | |
235 } | |
236 | |
237 static void | |
238 add_sensor(uint8_t *id) | |
239 { | |
240 uint8_t n; | |
241 eeprom_read(n, n_sensors); | |
242 if (n < MAX_SENSORS) | |
243 { | |
244 cli(); | |
245 eeprom_write_from(id, sensor_id[n], 8); | |
246 n++; | |
247 eeprom_write(n, n_sensors); | |
248 sei(); | |
249 printf_P(PSTR("Added sensor %d : "), n); | |
250 printhex(id, 8); | |
251 putchar('\n'); | |
252 } | |
253 else | |
254 { | |
255 printf_P(PSTR("Too many sensors\n")); | |
256 } | |
257 } | |
258 | |
259 static void | |
260 cmd_add_all() | |
261 { | |
262 uint8_t id[OW_ROMCODE_SIZE]; | |
263 uint8_t sp[DS18X20_SP_SIZE]; | |
264 printf_P("Adding all\n"); | |
265 ow_reset(); | |
266 for( uint8_t diff = OW_SEARCH_FIRST; diff != OW_LAST_DEVICE; ) | |
267 { | |
268 diff = ow_rom_search( diff, &id[0] ); | |
269 if( diff == OW_PRESENCE_ERR ) { | |
270 printf_P( PSTR("No Sensor found\r") ); | |
271 return; | |
272 } | |
273 | |
274 if( diff == OW_DATA_ERR ) { | |
275 printf_P( PSTR("Bus Error\r") ); | |
276 return; | |
277 } | |
278 add_sensor(id); | |
279 } | |
280 } | |
281 | |
282 static void | |
283 cmd_add_sensor(const char* hex_addr) | |
284 { | |
285 uint8_t id[8]; | |
286 uint8_t ret = get_hex_string(hex_addr, id, 8); | |
287 if (ret) | |
288 { | |
289 return; | |
290 } | |
291 add_sensor(id); | |
292 | |
293 } | |
294 | |
295 static void | |
296 cmd_init() | |
297 { | |
298 printf_P(PSTR("Resetting sensor list\n")); | |
299 uint8_t zero = 0; | |
300 cli(); | |
301 eeprom_write(zero, n_sensors); | |
302 sei(); | |
303 printf_P(PSTR("Done.\n")); | |
304 } | |
305 | |
306 static void | |
307 check_first_startup() | |
308 { | |
309 uint16_t magic; | |
310 eeprom_read(magic, magic); | |
311 if (magic != EXPECT_MAGIC) | |
312 { | |
313 printf_P(PSTR("First boot, looking for sensors...\n")); | |
314 cmd_init(); | |
315 cmd_add_all(); | |
316 } | |
317 } | |
318 | |
156 static void | 319 static void |
157 read_handler() | 320 read_handler() |
158 { | 321 { |
159 if (strcmp_P(readbuf, PSTR("fetch")) == 0) | 322 if (strcmp_P(readbuf, PSTR("fetch")) == 0) |
160 { | 323 { |
173 cmd_measure(); | 336 cmd_measure(); |
174 } | 337 } |
175 else if (strcmp_P(readbuf, PSTR("sensors")) == 0) | 338 else if (strcmp_P(readbuf, PSTR("sensors")) == 0) |
176 { | 339 { |
177 cmd_sensors(); | 340 cmd_sensors(); |
341 } | |
342 else if (strncmp_P(readbuf, PSTR("adds "), strlen("adds ")) == 0) | |
343 { | |
344 cmd_add_sensor(readbuf + strlen("adds ")); | |
345 } | |
346 else if (strcmp_P(readbuf, PSTR("addall"))== 0) | |
347 { | |
348 cmd_add_all(); | |
349 } | |
350 else if (strcmp_P(readbuf, PSTR("init")) == 0) | |
351 { | |
352 cmd_init(); | |
178 } | 353 } |
179 else | 354 else |
180 { | 355 { |
181 printf_P(PSTR("Bad command\n")); | 356 printf_P(PSTR("Bad command\n")); |
182 } | 357 } |
273 float res_volts = 1.1 * f_measure / f_11; | 448 float res_volts = 1.1 * f_measure / f_11; |
274 | 449 |
275 // 10mV/degree | 450 // 10mV/degree |
276 // scale to 1/5 degree units above 0C | 451 // scale to 1/5 degree units above 0C |
277 int temp = (res_volts - 2.73) * 500; | 452 int temp = (res_volts - 2.73) * 500; |
278 measurements[n_measurements] = temp; | 453 // XXX fixme |
454 //measurements[n_measurements] = temp; | |
279 // XXX something if it hits the limit | 455 // XXX something if it hits the limit |
280 | 456 |
281 // measure AVR internal temperature against 1.1 ref. | 457 // measure AVR internal temperature against 1.1 ref. |
282 ADMUX = _BV(ADLAR) | _BV(MUX3) | _BV(REFS1) | _BV(REFS0); | 458 ADMUX = _BV(ADLAR) | _BV(MUX3) | _BV(REFS1) | _BV(REFS0); |
283 ADCSRA |= _BV(ADSC); | 459 ADCSRA |= _BV(ADSC); |
287 | 463 |
288 float internal_volts = res_internal * (1.1 / 1024.0); | 464 float internal_volts = res_internal * (1.1 / 1024.0); |
289 | 465 |
290 // 1mV/degree | 466 // 1mV/degree |
291 int internal_temp = (internal_volts - 2.73) * 5000; | 467 int internal_temp = (internal_volts - 2.73) * 5000; |
292 internal_measurements[n_measurements] = internal_temp; | 468 // XXX fixme |
469 //internal_measurements[n_measurements] = internal_temp; | |
293 | 470 |
294 printf_P("measure %d: external %d, internal %d, 1.1 %d\n", | 471 printf_P("measure %d: external %d, internal %d, 1.1 %d\n", |
295 n_measurements, temp, internal_temp, f_11); | 472 n_measurements, temp, internal_temp, f_11); |
296 | 473 |
297 n_measurements++; | 474 n_measurements++; |
299 } | 476 } |
300 | 477 |
301 static void | 478 static void |
302 do_measurement() | 479 do_measurement() |
303 { | 480 { |
304 printf("do_measurement\n"); | 481 uint8_t n_sensors; |
305 need_measurement = 0; | 482 eeprom_read(n_sensors, n_sensors); |
306 | 483 |
484 uint8_t ret = simple_ds18b20_start_meas(NULL); | |
485 printf_P(("Read all sensors, ret %d, waiting...\n"), ret); | |
486 _delay_ms(DS18B20_TCONV_12BIT); | |
487 | |
488 if (n_measurements == NUM_MEASUREMENTS) | |
489 { | |
490 printf_P(PSTR("Measurements overflow\n")); | |
491 n_measurements = 0; | |
492 } | |
493 | |
494 for (uint8_t n = 0; n < MAX_SENSORS; n++) | |
495 { | |
496 int16_t decicelsius; | |
497 if (n >= n_sensors) | |
498 { | |
499 decicelsius = VALUE_NOSENSOR; | |
500 } | |
501 else | |
502 { | |
503 uint8_t id[8]; | |
504 eeprom_read_to(id, sensor_id[n], 8); | |
505 | |
506 uint8_t ret = simple_ds18b20_read_decicelsius(id, &decicelsius); | |
507 if (ret != DS18X20_OK) | |
508 { | |
509 decicelsius = VALUE_BROKEN; | |
510 } | |
511 } | |
512 measurements[n_measurements][n] = decicelsius; | |
513 } | |
307 //do_adc_335(); | 514 //do_adc_335(); |
308 } | 515 } |
309 | 516 |
310 static void | 517 static void |
311 do_comms() | 518 do_comms() |
346 PORT_LED &= ~_BV(PIN_LED); | 553 PORT_LED &= ~_BV(PIN_LED); |
347 _delay_ms(1); | 554 _delay_ms(1); |
348 PORT_LED |= _BV(PIN_LED); | 555 PORT_LED |= _BV(PIN_LED); |
349 } | 556 } |
350 | 557 |
558 #if 0 | |
351 static void | 559 static void |
352 long_delay(int ms) | 560 long_delay(int ms) |
353 { | 561 { |
354 int iter = ms / 100; | 562 int iter = ms / 100; |
355 | 563 |
356 for (int i = 0; i < iter; i++) | 564 for (int i = 0; i < iter; i++) |
357 { | 565 { |
358 _delay_ms(100); | 566 _delay_ms(100); |
359 } | 567 } |
360 } | 568 } |
569 #endif | |
361 | 570 |
362 ISR(BADISR_vect) | 571 ISR(BADISR_vect) |
363 { | 572 { |
364 uart_on(); | 573 uart_on(); |
365 printf_P(PSTR("Bad interrupt\n")); | 574 printf_P(PSTR("Bad interrupt\n")); |
373 // divide by 4 | 582 // divide by 4 |
374 CLKPR = _BV(CLKPS1); | 583 CLKPR = _BV(CLKPS1); |
375 sei(); | 584 sei(); |
376 } | 585 } |
377 | 586 |
378 static void | |
379 dump_ds18x20() | |
380 { | |
381 } | |
382 | |
383 int main(void) | 587 int main(void) |
384 { | 588 { |
385 set_2mhz(); | 589 set_2mhz(); |
386 | 590 |
387 DDR_LED |= _BV(PIN_LED); | 591 DDR_LED |= _BV(PIN_LED); |
389 | 593 |
390 stdout = &mystdout; | 594 stdout = &mystdout; |
391 uart_on(); | 595 uart_on(); |
392 | 596 |
393 fprintf_P(&mystdout, PSTR("hello %d\n"), 12); | 597 fprintf_P(&mystdout, PSTR("hello %d\n"), 12); |
598 | |
599 check_first_startup(); | |
600 | |
394 uart_off(); | 601 uart_off(); |
395 | 602 |
396 // turn off everything except timer2 | 603 // turn off everything except timer2 |
397 //PRR = _BV(PRTWI) | _BV(PRTIM0) | _BV(PRTIM1) | _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC); | 604 //PRR = _BV(PRTWI) | _BV(PRTIM0) | _BV(PRTIM1) | _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC); |
398 | 605 |
399 // for testing | 606 // for testing |
400 uart_on(); | 607 uart_on(); |
401 | 608 |
402 sei(); | 609 sei(); |
403 | 610 |
404 #if 0 | |
405 // set up counter2. | 611 // set up counter2. |
406 // COM21 COM20 Set OC2 on Compare Match (p116) | 612 // COM21 COM20 Set OC2 on Compare Match (p116) |
407 // WGM21 Clear counter on compare | 613 // WGM21 Clear counter on compare |
408 TCCR2A = _BV(COM2A1) | _BV(COM2A0) | _BV(WGM21); | 614 TCCR2A = _BV(COM2A1) | _BV(COM2A0);// | _BV(WGM21); |
409 // CS22 CS21 CS20 clk/1024 | 615 // CS22 CS21 CS20 clk/1024 |
410 TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); | 616 TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); |
411 // set async mode | 617 // set async mode |
412 ASSR |= _BV(AS2); | 618 ASSR |= _BV(AS2); |
413 // interrupt | 619 // interrupt |
414 TIMSK2 = _BV(OCIE2A); | 620 TIMSK2 = _BV(OCIE2A); |
415 #endif | |
416 | 621 |
417 for (;;) | 622 for (;;) |
418 { | 623 { |
419 do_comms(); | 624 do_comms(); |
420 } | 625 } |