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_flight.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/ao_flight.c') 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; -- 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/ao_flight.c') 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/ao_flight.c') 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