From 1b8d7313504240ed04e0747e9b0f6e9a83d323e2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 16 Jan 2011 15:57:15 -0800 Subject: altos: Auto-calibrate linux-based flight testing code Use the provided ground acceleration average to set the two accelerometer calibration values so that the flight code will detect pad/idle mode correctly. Signed-off-by: Keith Packard --- src/ao_flight_test.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index e0cfa47a..108d2c19 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -238,6 +238,8 @@ ao_sleep(void *wchan) switch (type) { case 'F': ao_flight_ground_accel = a; + ao_config.accel_plus_g = a; + ao_config.accel_minus_g = a + 530; ao_flight_started = 1; break; case 'S': -- cgit v1.2.3 From 69290588980bb15732a99eca5c911a3b6e9a37b9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:12:02 -0800 Subject: altos: Ensure flight code gets first crack at new ADC data Instead of having everyone wait on the raw ADC ring, have the flight code wait on that and have everyone else wait for the flight code to finish looking at the data and move its pointer forwards. Signed-off-by: Keith Packard --- src/ao.h | 2 +- src/ao_adc.c | 10 ++-------- src/ao_config.c | 6 +++--- src/ao_flight.c | 3 ++- src/ao_flight_test.c | 2 +- src/ao_ignite.c | 1 - src/ao_log.c | 4 ++-- src/ao_test.c | 2 +- 8 files changed, 12 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/ao.h b/src/ao.h index 5721c344..abac22a3 100644 --- a/src/ao.h +++ b/src/ao.h @@ -649,7 +649,7 @@ enum ao_flight_state { ao_flight_invalid = 9 }; -extern __xdata struct ao_adc ao_flight_data; +extern __data uint8_t ao_flight_adc; extern __pdata enum ao_flight_state ao_flight_state; extern __pdata uint16_t ao_flight_tick; extern __pdata int16_t ao_flight_accel; diff --git a/src/ao_adc.c b/src/ao_adc.c index 49d2519e..f577b458 100644 --- a/src/ao_adc.c +++ b/src/ao_adc.c @@ -27,16 +27,10 @@ ao_adc_poll(void) ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0; } -void -ao_adc_sleep(void) -{ - ao_sleep(&ao_adc_ring); -} - void ao_adc_get(__xdata struct ao_adc *packet) { - uint8_t i = ao_adc_ring_prev(ao_adc_head); + uint8_t i = ao_adc_ring_prev(ao_flight_adc); memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc)); } @@ -65,7 +59,7 @@ ao_adc_isr(void) __interrupt 1 /* record this conversion series */ ao_adc_ring[ao_adc_head].tick = ao_time(); ao_adc_head = ao_adc_ring_next(ao_adc_head); - ao_wakeup(ao_adc_ring); + ao_wakeup(DATA_TO_XDATA(&ao_adc_head)); } } diff --git a/src/ao_config.c b/src/ao_config.c index e97b7eb1..bbee3b44 100644 --- a/src/ao_config.c +++ b/src/ao_config.c @@ -209,10 +209,10 @@ ao_config_accel_calibrate_auto(char *orientation) __reentrant puts("Calibrating..."); flush(); i = ACCEL_CALIBRATE_SAMPLES; accel_total = 0; - cal_adc_ring = ao_adc_head; + cal_adc_ring = ao_flight_adc; while (i) { - ao_sleep(&ao_adc_ring); - while (i && cal_adc_ring != ao_adc_head) { + ao_sleep(DATA_TO_XDATA(&ao_flight_adc)); + while (i && cal_adc_ring != ao_flight_adc) { accel_total += (int32_t) ao_adc_ring[cal_adc_ring].accel; cal_adc_ring = ao_adc_ring_next(cal_adc_ring); i--; diff --git a/src/ao_flight.c b/src/ao_flight.c index e99692a3..9eb9a014 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -146,7 +146,8 @@ ao_flight(void) ao_raw_pres = 0; ao_flight_tick = 0; for (;;) { - ao_sleep(&ao_adc_ring); + ao_wakeup(DATA_TO_XDATA(&ao_flight_adc)); + ao_sleep(DATA_TO_XDATA(&ao_adc_head)); while (ao_flight_adc != ao_adc_head) { __pdata uint8_t ticks; __pdata int16_t ao_vel_change; diff --git a/src/ao_flight_test.c b/src/ao_flight_test.c index 108d2c19..5c619518 100644 --- a/src/ao_flight_test.c +++ b/src/ao_flight_test.c @@ -180,7 +180,7 @@ void ao_sleep(void *wchan) { ao_dump_state(); - if (wchan == &ao_adc_ring) { + if (wchan == &ao_adc_head) { char type; uint16_t tick; uint16_t a, b; diff --git a/src/ao_ignite.c b/src/ao_ignite.c index f2b15dd2..603fcd25 100644 --- a/src/ao_ignite.c +++ b/src/ao_ignite.c @@ -52,7 +52,6 @@ ao_igniter_status(enum ao_igniter igniter) __xdata uint8_t request, firing, fired; __critical { - ao_adc_sleep(); ao_adc_get(&adc); request = ao_ignition[igniter].request; fired = ao_ignition[igniter].fired; diff --git a/src/ao_log.c b/src/ao_log.c index fa072550..099c5f6f 100644 --- a/src/ao_log.c +++ b/src/ao_log.c @@ -99,10 +99,10 @@ ao_log(void) /* Write the whole contents of the ring to the log * when starting up. */ - ao_log_adc_pos = ao_adc_ring_next(ao_adc_head); + ao_log_adc_pos = ao_adc_ring_next(ao_flight_adc); for (;;) { /* Write samples to EEPROM */ - while (ao_log_adc_pos != ao_adc_head) { + while (ao_log_adc_pos != ao_flight_adc) { log.type = AO_LOG_SENSOR; log.tick = ao_adc_ring[ao_log_adc_pos].tick; log.u.sensor.accel = ao_adc_ring[ao_log_adc_pos].accel; diff --git a/src/ao_test.c b/src/ao_test.c index b9f7d338..14c2eb75 100644 --- a/src/ao_test.c +++ b/src/ao_test.c @@ -53,7 +53,7 @@ blink_1(void) static __xdata struct ao_adc adc; for (;;) { - ao_sleep(&ao_adc_ring); + ao_sleep(&ao_adc_head); ao_adc_get(&adc); if (adc.accel < 15900) ao_led_on(AO_LED_RED); -- cgit v1.2.3 From 2681a17500913cbaf3966f09380bb1d6b59e3863 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:18:32 -0800 Subject: altos: Sample the accelerometer reference voltage on v1.1 boards This places the 5v reference samples in an array parallel to the basic ADC values. It doesn't do anything with the values, just stores them. Signed-off-by: Keith Packard --- src/ao.h | 8 ++++++++ src/ao_adc.c | 28 ++++++++++++++++++++++------ src/ao_pins.h | 3 +++ 3 files changed, 33 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/ao.h b/src/ao.h index abac22a3..cef20e61 100644 --- a/src/ao.h +++ b/src/ao.h @@ -163,6 +163,11 @@ struct ao_adc { #endif #if HAS_ADC + +#ifndef HAS_ACCEL_REF +#error Please define HAS_ACCEL_REF +#endif + /* * ao_adc.c */ @@ -178,6 +183,9 @@ struct ao_adc { */ extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; extern volatile __data uint8_t ao_adc_head; +#if HAS_ACCEL_REF +extern volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; +#endif /* Trigger a conversion sequence (called from the timer interrupt) */ void diff --git a/src/ao_adc.c b/src/ao_adc.c index f577b458..3adf9b2e 100644 --- a/src/ao_adc.c +++ b/src/ao_adc.c @@ -19,12 +19,19 @@ #include "ao_pins.h" volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING]; +#if HAS_ACCEL_REF +volatile __xdata uint16_t ao_accel_ref[AO_ADC_RING]; +#endif volatile __data uint8_t ao_adc_head; void ao_adc_poll(void) { +#if HAS_ACCEL_REF + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2; +#else ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 0; +#endif } void @@ -41,20 +48,29 @@ ao_adc_isr(void) __interrupt 1 uint8_t __xdata *a; sequence = (ADCCON2 & ADCCON2_SCH_MASK) >> ADCCON2_SCH_SHIFT; - if (sequence == ADCCON3_ECH_TEMP) - sequence = 2; - a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence); +#if HAS_ACCEL_REF + if (sequence == 2) { + a = (uint8_t __xdata *) (&ao_accel_ref[ao_adc_head]); + sequence = 0; + } else +#endif + { + if (sequence == ADCCON3_ECH_TEMP) + sequence = 2; + a = (uint8_t __xdata *) (&ao_adc_ring[ao_adc_head].accel + sequence); + sequence++; + } a[0] = ADCL; a[1] = ADCH; - if (sequence < 5) { + if (sequence < 6) { #if HAS_EXTERNAL_TEMP == 0 /* start next channel conversion */ /* v0.2 replaces external temp sensor with internal one */ - if (sequence == 1) + if (sequence == 2) ADCCON3 = ADCCON3_EREF_1_25 | ADCCON3_EDIV_512 | ADCCON3_ECH_TEMP; else #endif - ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | (sequence + 1); + ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; } else { /* record this conversion series */ ao_adc_ring[ao_adc_head].tick = ao_time(); diff --git a/src/ao_pins.h b/src/ao_pins.h index 9446964e..2c5b9db5 100644 --- a/src/ao_pins.h +++ b/src/ao_pins.h @@ -31,6 +31,7 @@ #define AO_LED_RED 1 #define LEDS_AVAILABLE (AO_LED_RED) #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 0 #endif #if defined(TELEMETRUM_V_1_1) @@ -46,6 +47,7 @@ #define AO_LED_RED 1 #define LEDS_AVAILABLE (AO_LED_RED) #define HAS_EXTERNAL_TEMP 0 + #define HAS_ACCEL_REF 1 #define SPI_CS_ON_P1 1 #define SPI_CS_ON_P0 0 #define M25_CS_MASK 0x02 /* CS0 is P1_1 */ @@ -81,6 +83,7 @@ #define AO_LED_GREEN 1 #define LEDS_AVAILABLE (AO_LED_RED|AO_LED_GREEN) #define HAS_EXTERNAL_TEMP 1 + #define HAS_ACCEL_REF 0 #define SPI_CS_ON_P1 1 #define SPI_CS_ON_P0 0 #endif -- cgit v1.2.3 From 2887fe7affc0706dbeb2f04df9a00a9b799903ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:25:57 -0800 Subject: altos: Optimize fetching of ADC data in flight code This stores the address of the desired sample in a local variable and then fetches through that. Saves quite a few instructions. Signed-off-by: Keith Packard --- src/ao_flight.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ao_flight.c b/src/ao_flight.c index 9eb9a014..637acd52 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -151,12 +151,14 @@ ao_flight(void) while (ao_flight_adc != ao_adc_head) { __pdata uint8_t ticks; __pdata int16_t ao_vel_change; + __xdata struct ao_adc *ao_adc; ao_flight_prev_tick = ao_flight_tick; /* Capture a sample */ - ao_raw_accel = ao_adc_ring[ao_flight_adc].accel; - ao_raw_pres = ao_adc_ring[ao_flight_adc].pres; - ao_flight_tick = ao_adc_ring[ao_flight_adc].tick; + ao_adc = &ao_adc_ring[ao_flight_adc]; + ao_flight_tick = ao_adc->tick; + ao_raw_accel = ao_adc->accel; + ao_raw_pres = ao_adc->pres; ao_flight_accel -= ao_flight_accel >> 4; ao_flight_accel += ao_raw_accel >> 4; -- cgit v1.2.3 From 4b71c4f4ed6cae23a7f4a2e7ae697da9ec614898 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 15 Jan 2011 12:26:53 -0800 Subject: altos: Use 5V reference data to correct accelerometer measurements. When the 3.3V and 5V values shift relative to each other (usually due to changes in power consumption), the measured acceleration will appear to shift. This patch converts the 3.3V referenced acceleration value into a 5V referenced acceleration, eliminating this error. Signed-off-by: Keith Packard --- src/ao_flight.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'src') diff --git a/src/ao_flight.c b/src/ao_flight.c index 637acd52..81aecad3 100644 --- a/src/ao_flight.c +++ b/src/ao_flight.c @@ -158,6 +158,90 @@ ao_flight(void) ao_adc = &ao_adc_ring[ao_flight_adc]; ao_flight_tick = ao_adc->tick; ao_raw_accel = ao_adc->accel; +#if HAS_ACCEL_REF + /* + * Ok, the math here is a bit tricky. + * + * ao_raw_accel: ADC output for acceleration + * ao_accel_ref: ADC output for the 5V reference. + * ao_cook_accel: Corrected acceleration value + * Vcc: 3.3V supply to the CC1111 + * Vac: 5V supply to the accelerometer + * accel: input voltage to accelerometer ADC pin + * ref: input voltage to 5V reference ADC pin + * + * + * Measured acceleration is ratiometric to Vcc: + * + * ao_raw_accel accel + * ------------ = ----- + * 32767 Vcc + * + * Measured 5v reference is also ratiometric to Vcc: + * + * ao_accel_ref ref + * ------------ = ----- + * 32767 Vcc + * + * + * ao_accel_ref = 32767 * (ref / Vcc) + * + * Acceleration is measured ratiometric to the 5V supply, + * so what we want is: + * + * ao_cook_accel accel + * ------------- = ----- + * 32767 ref + * + * + * accel Vcc + * = ----- * --- + * Vcc ref + * + * ao_raw_accel 32767 + * = ------------ * ------------ + * 32737 ao_accel_ref + * + * Multiply through by 32767: + * + * ao_raw_accel * 32767 + * ao_cook_accel = -------------------- + * ao_accel_ref + * + * Now, the tricky part. Getting this to compile efficiently + * and keeping all of the values in-range. + * + * First off, we need to use a shift of 16 instead of * 32767 as SDCC + * does the obvious optimizations for byte-granularity shifts: + * + * ao_cook_accel = (ao_raw_accel << 16) / ao_accel_ref + * + * Next, lets check our input ranges: + * + * 0 <= ao_raw_accel <= 0x7fff (singled ended ADC conversion) + * 0x7000 <= ao_accel_ref <= 0x7fff (the 5V ref value is close to 0x7fff) + * + * Plugging in our input ranges, we get an output range of 0 - 0x12490, + * which is 17 bits. That won't work. If we take the accel ref and shift + * by a bit, we'll change its range: + * + * 0xe000 <= ao_accel_ref<<1 <= 0xfffe + * + * ao_cook_accel = (ao_raw_accel << 16) / (ao_accel_ref << 1) + * + * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It + * is, however, one bit too large for our signed computations. So, we + * take the result and shift that by a bit: + * + * ao_cook_accel = ((ao_raw_accel << 16) / (ao_accel_ref << 1)) >> 1 + * + * This finally creates an output range of 0 - 0x4924. As the ADC only + * provides 11 bits of data, we haven't actually lost any precision, + * just dropped a bit of noise off the low end. + */ + ao_raw_accel = (uint16_t) ((((uint32_t) ao_raw_accel << 16) / (ao_accel_ref[ao_flight_adc] << 1))) >> 1; + ao_adc->accel = ao_raw_accel; +#endif ao_raw_pres = ao_adc->pres; ao_flight_accel -= ao_flight_accel >> 4; -- cgit v1.2.3