These pieces come from the old telemetrum firmware.
Signed-off-by: Keith Packard <keithp@keithp.com>
ao_cmd.c \
ao_dma.c \
ao_ee.c \
+ ao_flight.c \
ao_led.c \
+ ao_log.c \
ao_mutex.c \
ao_panic.c \
+ ao_report.c \
ao_task.c \
ao_timer.c \
ao_usb.c \
/* Stack runs from above the allocated __data space to 0xfe, which avoids
* writing to 0xff as that triggers the stack overflow indicator
*/
-#define AO_STACK_START 0x75
+#define AO_STACK_START 0x7f
#define AO_STACK_END 0xfe
#define AO_STACK_SIZE (AO_STACK_END - AO_STACK_START + 1)
#define AO_PANIC_DMA 2 /* Attempt to start DMA while active */
#define AO_PANIC_MUTEX 3 /* Mis-using mutex API */
#define AO_PANIC_EE 4 /* Mis-using eeprom API */
+#define AO_PANIC_LOG 5 /* Failing to read/write log data */
/* Stop the operating system, beeping and blinking the reason */
void
* ao_adc.c
*/
-#define ADC_RING 128
+#define AO_ADC_RING 128
/*
* One set of samples read from the A/D converter
* A/D data is stored in a ring, with the next sample to be written
* at ao_adc_head
*/
-extern volatile __xdata struct ao_adc ao_adc_ring[ADC_RING];
+extern volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
extern volatile __data uint8_t ao_adc_head;
/* Trigger a conversion sequence (called from the timer interrupt) */
#define AO_EE_CONFIG_BLOCK ((uint16_t) (AO_EE_DATA_SIZE / AO_EE_BLOCK_SIZE))
void
-ao_ee_flush(void);
+ao_ee_flush(void) __reentrant;
/* Write to the eeprom */
uint8_t
-ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len);
+ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;
/* Read from the eeprom */
uint8_t
-ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len);
+ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant;
/* Write the config block (at the end of the eeprom) */
uint8_t
-ao_ee_write_config(uint8_t *buf, uint16_t len);
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant;
/* Read the config block (at the end of the eeprom) */
uint8_t
-ao_ee_read_config(uint8_t *buf, uint16_t len);
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant;
/* Initialize the EEPROM code */
void
ao_ee_init(void);
+/*
+ * ao_log.c
+ */
+
+/*
+ * The data log is recorded in the eeprom as a sequence
+ * of data packets.
+ *
+ * Each packet starts with a 4-byte header that has the
+ * packet type, the packet checksum and the tick count. Then
+ * they all contain 2 16 bit values which hold packet-specific
+ * data.
+ *
+ * For each flight, the first packet
+ * is FLIGHT packet, indicating the serial number of the
+ * device and a unique number marking the number of flights
+ * recorded by this device.
+ *
+ * During flight, data from the accelerometer and barometer
+ * are recorded in SENSOR packets, using the raw 16-bit values
+ * read from the A/D converter.
+ *
+ * Also during flight, but at a lower rate, the deployment
+ * sensors are recorded in DEPLOY packets. The goal here is to
+ * detect failure in the deployment circuits.
+ *
+ * STATE packets hold state transitions as the flight computer
+ * transitions through different stages of the flight.
+ */
+#define AO_LOG_FLIGHT 'F'
+#define AO_LOG_SENSOR 'A'
+#define AO_LOG_TEMP_VOLT 'T'
+#define AO_LOG_DEPLOY 'D'
+#define AO_LOG_STATE 'S'
+
+#define AO_LOG_POS_NONE (~0UL)
+
+struct ao_log_record {
+ uint8_t type;
+ uint8_t csum;
+ uint16_t tick;
+ union {
+ struct {
+ uint16_t serial;
+ uint16_t flight;
+ } flight;
+ struct {
+ int16_t accel;
+ int16_t pres;
+ } sensor;
+ struct {
+ int16_t temp;
+ int16_t v_batt;
+ } temp_volt;
+ struct {
+ int16_t drogue;
+ int16_t main;
+ } deploy;
+ struct {
+ uint16_t state;
+ uint16_t reason;
+ } state;
+ struct {
+ uint16_t d0;
+ uint16_t d1;
+ } anon;
+ } u;
+};
+
+/* Write a record to the eeprom log */
+void
+ao_log_data(struct ao_log_record *log);
+
+/* Flush the log */
+void
+ao_log_flush(void);
+
+/* Log dumping API:
+ * ao_log_dump_first() - get first log record
+ * ao_log_dump_next() - get next log record
+ */
+extern __xdata struct ao_log_record ao_log_dump;
+
+/* Retrieve first log record for the current flight */
+uint8_t
+ao_log_dump_first(void);
+
+/* return next log record for the current flight */
+uint8_t
+ao_log_dump_next(void);
+
+/* Logging thread main routine */
+void
+ao_log(void);
+
+/* Start logging to eeprom */
+void
+ao_log_start(void);
+
+/* Initialize the logging system */
+void
+ao_log_init(void);
+
+/*
+ * ao_flight.c
+ */
+
+enum ao_flight_state {
+ ao_flight_startup,
+ ao_flight_idle,
+ ao_flight_launchpad,
+ ao_flight_boost,
+ ao_flight_coast,
+ ao_flight_apogee,
+ ao_flight_drogue,
+ ao_flight_main,
+ ao_flight_landed,
+ ao_flight_invalid
+};
+
+extern __xdata struct ao_adc ao_flight_data;
+extern __data enum flight_state ao_flight_state;
+extern __data uint16_t ao_flight_state_tick;
+extern __data int16_t ao_flight_accel;
+extern __data int16_t ao_flight_pres;
+extern __data int16_t ao_ground_pres;
+extern __data int16_t ao_ground_accel;
+extern __data int16_t ao_min_pres;
+extern __data uint16_t ao_launch_time;
+
+/* Flight thread */
+void
+ao_flight(void);
+
+/* Initialize flight thread */
+void
+ao_flight_init(void);
+
+/*
+ * ao_report.c
+ */
+
+void
+ao_report_notify(void);
+
+void
+ao_report_init(void);
+
#endif /* _AO_H_ */
#include "ao.h"
-volatile __xdata struct ao_adc ao_adc_ring[ADC_RING];
+volatile __xdata struct ao_adc ao_adc_ring[AO_ADC_RING];
volatile __data uint8_t ao_adc_head;
void
{
uint8_t i = ao_adc_head;
if (i == 0)
- i = ADC_RING;
+ i = AO_ADC_RING;
i--;
memcpy(packet, &ao_adc_ring[i], sizeof (struct ao_adc));
}
/* record this conversion series */
ao_adc_ring[ao_adc_head].tick = ao_time();
ao_adc_head++;
- if (ao_adc_head == ADC_RING)
+ if (ao_adc_head == AO_ADC_RING)
ao_adc_head = 0;
ao_wakeup(ao_adc_ring);
}
static void
dump_log(void)
{
-#if 0
uint8_t more;
- for (more = log_first(); more; more = log_next()) {
- putchar(log_dump.type);
+ for (more = ao_log_dump_first(); more; more = ao_log_dump_next()) {
+ putchar(ao_log_dump.type);
putchar(' ');
- put16(log_dump.tick);
+ put16(ao_log_dump.tick);
putchar(' ');
- put16(log_dump.u.anon.d0);
+ put16(ao_log_dump.u.anon.d0);
putchar(' ');
- put16(log_dump.u.anon.d1);
+ put16(ao_log_dump.u.anon.d1);
putchar('\n');
}
-#endif
}
static const uint8_t help_txt[] =
ao_ee_cs_high();
}
-void
-ao_ee_flush(void)
+static void
+ao_ee_flush_internal(void)
{
if (ao_ee_block_dirty) {
ao_ee_write_block();
ao_ee_block_dirty = 0;
}
}
-
+
static void
ao_ee_fill(uint16_t block)
{
}
uint8_t
-ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len)
+ao_ee_write(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant
{
uint16_t block;
uint16_t this_len;
if (this_len != 256)
ao_ee_fill(block);
else {
- ao_ee_flush();
+ ao_ee_flush_internal();
ao_ee_block = block;
}
memcpy(ao_ee_data + this_off, buf, this_len);
}
uint8_t
-ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len)
+ao_ee_read(uint32_t pos, uint8_t *buf, uint16_t len) __reentrant
{
uint16_t block;
uint16_t this_len;
return 1;
}
+void
+ao_ee_flush(void) __reentrant
+{
+ ao_mutex_get(&ao_ee_mutex); {
+ ao_ee_flush_internal();
+ } ao_mutex_put(&ao_ee_mutex);
+}
+
/*
* Read/write the config block, which is in
* the last block of the ao_eeprom
*/
uint8_t
-ao_ee_write_config(uint8_t *buf, uint16_t len)
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant
{
if (len > AO_EE_BLOCK_SIZE)
return 0;
}
uint8_t
-ao_ee_read_config(uint8_t *buf, uint16_t len)
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant
{
if (len > AO_EE_BLOCK_SIZE)
return 0;
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+/* Main flight thread. */
+
+__xdata struct ao_adc ao_flight_data;
+__data enum flight_state ao_flight_state;
+__data uint16_t ao_flight_state_tick;
+__data int16_t ao_flight_accel;
+__data int16_t ao_flight_pres;
+__data int16_t ao_ground_pres;
+__data int16_t ao_ground_accel;
+__data int16_t ao_min_pres;
+__data uint16_t ao_launch_time;
+
+/* Accelerometer calibration
+ *
+ * We're sampling the accelerometer through a resistor divider which
+ * consists of 5k and 10k resistors. This multiplies the values by 2/3.
+ * That goes into the cc1111 A/D converter, which is running at 11 bits
+ * of precision with the bits in the MSB of the 16 bit value. Only positive
+ * values are used, so values should range from 0-32752 for 0-3.3V. The
+ * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what
+ * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV,
+ * for a final computation of:
+ *
+ * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g
+ *
+ * Zero g was measured at 16000 (we would expect 16384)
+ */
+
+#define ACCEL_G 265
+#define ACCEL_ZERO_G 16000
+#define ACCEL_NOSE_UP (ACCEL_ZERO_G - ACCEL_G * 2 /3)
+#define ACCEL_BOOST (ACCEL_NOSE_UP - ACCEL_G * 2)
+
+/*
+ * Barometer calibration
+ *
+ * We directly sample the barometer. The specs say:
+ *
+ * Pressure range: 15-115 kPa
+ * Voltage at 115kPa: 2.82
+ * Output scale: 27mV/kPa
+ *
+ * If we want to detect launch with the barometer, we need
+ * a large enough bump to not be fooled by noise. At typical
+ * launch elevations (0-2000m), a 200Pa pressure change cooresponds
+ * to about a 20m elevation change. This is 5.4mV, or about 3LSB.
+ * As all of our calculations are done in 16 bits, we'll actually see a change
+ * of 16 times this though
+ *
+ * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa
+ */
+
+#define BARO_kPa 268
+#define BARO_LAUNCH (BARO_kPa / 5) /* .2kPa */
+#define BARO_APOGEE (BARO_kPa / 10) /* .1kPa */
+
+/* We also have a clock, which can be used to sanity check things in
+ * case of other failures
+ */
+
+#define BOOST_TICKS_MAX AO_SEC_TO_TICKS(10)
+
+void
+ao_flight(void)
+{
+ __data static uint8_t nsamples = 0;
+
+ for (;;) {
+ ao_sleep(&ao_adc_ring);
+ ao_adc_get(&ao_flight_data);
+ ao_flight_accel -= ao_flight_accel >> 4;
+ ao_flight_accel += ao_flight_data.accel >> 4;
+ ao_flight_pres -= ao_flight_pres >> 4;
+ ao_flight_pres += ao_flight_data.pres >> 4;
+
+ switch (ao_flight_state) {
+ case ao_flight_startup:
+ if (nsamples < 100) {
+ ++nsamples;
+ continue;
+ }
+ ao_ground_accel = ao_flight_accel;
+ ao_ground_pres = ao_flight_pres;
+ ao_min_pres = ao_flight_pres;
+ if (ao_flight_accel < ACCEL_NOSE_UP) {
+ ao_flight_state = ao_flight_launchpad;
+ ao_flight_state_tick = ao_time();
+ ao_report_notify();
+ } else {
+ ao_flight_state = ao_flight_idle;
+ ao_flight_state_tick = ao_time();
+ ao_report_notify();
+ }
+ break;
+ case ao_flight_launchpad:
+ if (ao_flight_accel < ACCEL_BOOST ||
+ ao_flight_pres + BARO_LAUNCH < ao_ground_pres)
+ {
+ ao_flight_state = ao_flight_boost;
+ ao_flight_state_tick = ao_time();
+ ao_log_start();
+ ao_report_notify();
+ break;
+ }
+ break;
+ case ao_flight_boost:
+ if (ao_flight_accel > ACCEL_ZERO_G ||
+ (int16_t) (ao_flight_data.tick - ao_launch_time) > BOOST_TICKS_MAX)
+ {
+ ao_flight_state = ao_flight_coast;
+ ao_flight_state_tick = ao_time();
+ ao_report_notify();
+ break;
+ }
+ break;
+ case ao_flight_coast:
+ if (ao_flight_pres < ao_min_pres)
+ ao_min_pres = ao_flight_pres;
+ if (ao_flight_pres - BARO_APOGEE > ao_min_pres) {
+ ao_flight_state = ao_flight_apogee;
+ ao_flight_state_tick = ao_time();
+ ao_report_notify();
+ }
+ break;
+ case ao_flight_apogee:
+ break;
+ }
+ }
+}
+
+static __xdata struct ao_task flight_task;
+
+void
+ao_flight_init(void)
+{
+ ao_flight_state = ao_flight_startup;
+
+ ao_add_task(&flight_task, ao_flight);
+}
+
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__data uint32_t ao_log_current_pos;
+__data uint32_t ao_log_start_pos;
+__xdata uint8_t ao_log_running;
+__xdata uint8_t ao_log_mutex;
+
+static uint8_t
+ao_log_csum(uint8_t *b)
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_record); i++)
+ sum += *b++;
+ return -sum;
+}
+
+void
+ao_log_data(struct ao_log_record *log)
+{
+ /* set checksum */
+ log->csum = 0;
+ log->csum = ao_log_csum((uint8_t *) log);
+ ao_mutex_get(&ao_log_mutex); {
+ if (ao_log_running) {
+ ao_ee_write(ao_log_current_pos,
+ (uint8_t *) log,
+ sizeof (struct ao_log_record));
+ ao_log_current_pos += sizeof (struct ao_log_record);
+ if (ao_log_current_pos >= AO_EE_DATA_SIZE)
+ ao_log_current_pos = 0;
+ if (ao_log_current_pos == ao_log_start_pos)
+ ao_log_running = 0;
+ }
+ } ao_mutex_put(&ao_log_mutex);
+}
+
+void
+ao_log_flush(void)
+{
+ ao_ee_flush();
+}
+
+__xdata struct ao_log_record ao_log_dump;
+static __data uint16_t ao_log_dump_flight;
+static __data uint32_t ao_log_dump_pos;
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+ if (ao_log_csum((uint8_t *) &ao_log_dump) != 0)
+ return 0;
+ return 1;
+}
+
+static uint8_t
+ao_log_dump_scan(void)
+{
+ if (!ao_ee_read(0, (uint8_t *) &ao_log_dump, sizeof (struct ao_log_record)))
+ ao_panic(AO_PANIC_LOG);
+ if (ao_log_dump_check_data() && ao_log_dump.type == AO_LOG_FLIGHT) {
+ ao_log_dump_flight = ao_log_dump.u.flight.flight;
+ return 1;
+ } else {
+ ao_log_dump_flight = 0;
+ return 0;
+ }
+}
+
+uint8_t
+ao_log_dump_first(void)
+{
+ ao_log_dump_pos = 0;
+ if (!ao_log_dump_scan())
+ return 0;
+ return 1;
+}
+
+uint8_t
+ao_log_dump_next(void)
+{
+ ao_log_dump_pos += sizeof (struct ao_log_record);
+ if (ao_log_dump_pos >= AO_EE_DEVICE_SIZE)
+ return 0;
+ if (!ao_ee_read(ao_log_dump_pos, (uint8_t *) &ao_log_dump,
+ sizeof (struct ao_log_record)))
+ return 0;
+ return ao_log_dump_check_data();
+}
+
+uint8_t ao_log_adc_pos;
+enum flight_state ao_log_state;
+
+void
+ao_log(void)
+{
+ static __xdata struct ao_log_record log;
+
+ ao_log_dump_scan();
+
+ while (!ao_log_running)
+ ao_sleep(&ao_log_running);
+
+ log.type = AO_LOG_FLIGHT;
+ log.tick = ao_flight_state_tick;
+ log.u.flight.serial = 0;
+ log.u.flight.flight = ao_log_dump_flight + 1;
+ ao_log_data(&log);
+ for (;;) {
+ /* Write state change to EEPROM */
+ if (ao_flight_state != ao_log_state) {
+ ao_log_state = ao_flight_state;
+ log.type = AO_LOG_STATE;
+ log.tick = ao_flight_state_tick;
+ log.u.state.state = ao_log_state;
+ log.u.state.reason = 0;
+ ao_log_data(&log);
+ }
+ /* Write samples to EEPROM */
+ while (ao_log_adc_pos != ao_adc_head) {
+ 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;
+ log.u.sensor.pres = ao_adc_ring[ao_log_adc_pos].pres;
+ ao_log_data(&log);
+ if (ao_log_adc_pos == 0) {
+ log.type = AO_LOG_TEMP_VOLT;
+ log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+ log.u.temp_volt.temp = ao_adc_ring[ao_log_adc_pos].temp;
+ log.u.temp_volt.v_batt = ao_adc_ring[ao_log_adc_pos].v_batt;
+ ao_log_data(&log);
+ log.type = AO_LOG_DEPLOY;
+ log.tick = ao_adc_ring[ao_log_adc_pos].tick;
+ log.u.deploy.drogue = ao_adc_ring[ao_log_adc_pos].sense_d;
+ log.u.deploy.main = ao_adc_ring[ao_log_adc_pos].sense_m;
+ ao_log_data(&log);
+ }
+ ao_log_adc_pos++;
+ if (ao_log_adc_pos == AO_ADC_RING)
+ ao_log_adc_pos = 0;
+ }
+
+ /* Wait for a while */
+ ao_delay(AO_MS_TO_TICKS(100));
+ }
+}
+
+void
+ao_log_start(void)
+{
+ /* start logging */
+ ao_log_running = 1;
+ ao_wakeup(&ao_log_running);
+}
+
+static __xdata struct ao_task ao_log_task;
+
+void
+ao_log_init(void)
+{
+ ao_log_running = 0;
+
+ /* For now, just log the flight starting at the begining of eeprom */
+ ao_log_start_pos = 0;
+ ao_log_current_pos = ao_log_start_pos;
+ ao_log_state = ao_flight_invalid;
+
+ /* Create a task to log events to eeprom */
+ ao_add_task(&ao_log_task, ao_log);
+}
--- /dev/null
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+static const char * __xdata flight_reports[] = {
+ "...", /* startup, 'S' */
+ "..", /* idle 'I' */
+ ".--.", /* launchpad 'P' */
+ "-...", /* boost 'B' */
+ "-.-.", /* coast 'C' */
+ ".-", /* apogee 'A' */
+ "-..", /* drogue 'D' */
+ "--", /* main 'M' */
+ ".-..", /* landed 'L' */
+ ".-.-.-", /* invalid */
+};
+
+#if 1
+#define signal(time) ao_beep_for(AO_BEEP_MID, time)
+#else
+#define signal(time) ao_led_for(AO_LED_RED, time)
+#endif
+#define pause(time) ao_delay(time)
+
+static void
+ao_report_state(void)
+{
+ char *r = flight_reports[ao_flight_state];
+ char c;
+
+ if (!r)
+ return;
+ while (c = *r++) {
+ if (c == '.')
+ signal(AO_MS_TO_TICKS(200));
+ else
+ signal(AO_MS_TO_TICKS(600));
+ pause(AO_MS_TO_TICKS(200));
+ }
+}
+
+static __xdata ao_report_wait;
+
+void
+ao_report_notify(void)
+{
+ ao_wakeup(&ao_report_wait);
+}
+
+void
+ao_report(void)
+{
+ for(;;) {
+ ao_report_state();
+ ao_sleep(&ao_report_wait);
+ }
+}
+
+static __xdata struct ao_task ao_report_task;
+
+void
+ao_report_init(void)
+{
+ ao_add_task(&ao_report_task, ao_report);
+}
#define T1_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */
#define T1_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */
+__data uint8_t ao_adc_interval = 1;
+__data uint8_t ao_adc_count;
+
void ao_timer_isr(void) interrupt 9
{
++ao_tick_count;
- ao_adc_poll();
+ if (++ao_adc_count >= ao_adc_interval) {
+ ao_adc_count = 0;
+ ao_adc_poll();
+ }
ao_wakeup(DATA_TO_XDATA(&ao_tick_count));
}