Commit 8c7d049f authored by Pavel Semerad's avatar Pavel Semerad
Browse files

measure ADC every 1ms at timer code, compute averaged ADC value when used

parent e0e4a285
......@@ -3,6 +3,7 @@
minimum battery voltage set to 2V for those experimenting with 1S cell
PPM length shortened to "NUM_CHANNELS x 2ms + 5ms" to send new data
to receiver as soon as possible
ADC measuring every 1ms, averaging last 4 samples when used
*0.4.1 (17 Aug 2011)
......
......@@ -23,12 +23,14 @@ ppm_interrupt
- wakeups task CALC during SYNC signal
timer_interrupt
- timer2 overflow
- every 1ms read ADC values
- every 5ms
- increments time from start
- count LCD blink time and wakeups task LCD
- handles buzzer
- wakeups task INPUT
- handles task MENU delay and wakeups this task
- increments time from start
- count LCD blink time and wakeups task LCD
- handles buzzer
- wakeups task INPUT
- wakeups task MENU when it wants ADC values (calibrate, ...)
- handles task MENU delay and wakeups this task
......@@ -40,7 +42,7 @@ LCD
- is waked up by lcd_update(), lcd_clear()
- is waked up from timer to do automatic blinking
INPUT
- is doing reading of ADC values and key matrix
- is doing reading key matrix and some ADC checks
- is waked up from timer every 5ms
CALC
- is computing values for each servo and sync signal
......@@ -48,10 +50,9 @@ CALC
- also needed to wakeup after changing number of PPM channels in MENU
MENU
- is main program handling keys, menus, lcd
- is waked up from timer when menu_delay expired
- is waked up from timer when menu_delay expired or when ADC values needed
- is waked up from INPUT task when
- buttons state changed
- MENU task wanted ADC values (for calibrate) or battery voltage
- status of battery low changed
......
ADC wakeups - only every 1/2s instead of checking time at menu code
ADC - measure every 1ms - timer 1ms, buttons code still every 5ms
CALC - calc at end of SYNC signal
- measure durations of CALC
- at end of CALC PPM pulse and servo pulses
......
......@@ -118,7 +118,7 @@ u16 buttons;
u16 buttons_long; // >1s press
// variables for ADC values
@near u16 adc_all_last[3], adc_battery_last;
@near u16 adc_all_ovs[3], adc_battery;
@near u16 adc_battery;
@near u32 adc_battery_filt;
......@@ -305,43 +305,26 @@ static void read_keys(void) {
// ADC buffers, last 4 values for each channel
#define ADC_BUFFERS 4
@near static u16 adc_buffer[ADC_BUFFERS][3];
static u8 adc_buffer_pos;
// define missing ADC buffer registers
volatile u16 ADC_DB0R @0x53e0;
volatile u16 ADC_DB1R @0x53e2;
volatile u16 ADC_DB2R @0x53e4;
volatile u16 ADC_DB3R @0x53e6;
// read ADC values and compute sum of last 4 for each channel
#define ADC_NEWVAL(id) \
adc_all_last[id] = ADC_DB ## id ## R; \
buf[id] = adc_all_last[id]; \
adc_all_ovs[id] = adc_buffer[0][id] + adc_buffer[1][id] \
+ adc_buffer[2][id] + adc_buffer[3][id];
static void read_ADC(void) {
u16 *buf = adc_buffer[adc_buffer_pos];
u8 dead;
@near u16 adc_buffer0[ADC_BUFFERS];
@near u16 adc_buffer1[ADC_BUFFERS];
@near u16 adc_buffer2[ADC_BUFFERS];
u16 adc_buffer_pos;
ADC_NEWVAL(0);
ADC_NEWVAL(1);
ADC_NEWVAL(2);
adc_battery_last = ADC_DB3R;
adc_buffer_pos++;
adc_buffer_pos &= 3;
// read ADC values
static void read_ADC(void) {
READ_ADC();
}
BRES(ADC_CSR, 7); // remove EOC flag
BSET(ADC_CR1, 0); // start new conversion
// average battery voltage and check battery low
// average battery voltage and check battery low
static void update_battery(void) {
// ignore very low, which means that it is supplied from SWIM connector
adc_battery_filt = adc_battery_filt * (ADC_BAT_FILT - 1); // splitted - compiler hack
adc_battery_filt = (adc_battery_filt + (ADC_BAT_FILT / 2)) / ADC_BAT_FILT
+ adc_battery_last;
adc_battery = (u16)((adc_battery_filt + (ADC_BAT_FILT / 2)) / ADC_BAT_FILT);
// start checking battery after 5s from power on
if (time_sec >= 5) {
// wakeup task only when something changed
......@@ -360,13 +343,12 @@ static void read_ADC(void) {
}
}
}
}
// wakeup MENU task when showing battery or at calibrate
if (menu_wants_adc)
awake(MENU);
// reset inactivity timer when some steering or throttle applied
dead = cg.steering_dead_zone;
// reset inactivity timer when some steering or throttle applied
static void check_inactivity(void) {
u8 dead = cg.steering_dead_zone;
if (dead < 20) dead = 20; // use some minimal dead zone for this check
if (adc_steering_last < (cg.calib_steering_mid - dead) ||
adc_steering_last > (cg.calib_steering_mid + dead))
......@@ -388,9 +370,8 @@ static void read_ADC(void) {
// input task, awaked every 5ms
_Bool input_initialized;
#define ADC_BUFINIT(id) \
adc_buffer[1][id] = adc_buffer[2][id] = adc_buffer[3][id] = \
adc_buffer[0][id]; \
adc_all_ovs[id] = adc_buffer[0][id] << ADC_OVS_SHIFT;
adc_buffer ## id ## [1] = adc_buffer ## id ## [2] = \
adc_buffer ## id ## [3] = adc_buffer ## id ## [0];
static void input_loop(void) {
// read initial ADC values
......@@ -410,10 +391,9 @@ static void input_loop(void) {
input_initialized = 1;
while (1) {
// read ADC only when EOC flag (only for first it will not be ready)
if (BCHK(ADC_CSR, 7))
read_ADC();
read_keys();
check_inactivity();
update_battery();
stop();
}
}
......
......@@ -64,23 +64,6 @@ extern volatile u16 buttons_long; // >1s presses buttons
#define btnl_all(mask) ((buttons_long & (mask)) == (mask))
// variables for ADC values
extern @near volatile u16 adc_all_ovs[3]; // oversampled from 4 samples and is 4* more
#define ADC_OVS_SHIFT 2
#define ADC_OVS_ROUND 2
#define adc_steering_ovs adc_all_ovs[0]
#define adc_throttle_ovs adc_all_ovs[1]
#define adc_ch3_ovs adc_all_ovs[2]
extern @near volatile u32 adc_battery_filt; // battery will be filtered more times
#define ADC_BAT_FILT 512
extern @near volatile u16 adc_battery; // adc_battery_filt >> ADC_BATTERY_SHIFT
extern @near volatile u16 adc_all_last[3]; // last readed value
#define adc_steering_last adc_all_last[0]
#define adc_throttle_last adc_all_last[1]
#define adc_ch3_last adc_all_last[2]
extern @near volatile u16 adc_battery_last;
// reset pressed button(s)
// do it after used that button in code
extern void button_reset(u16 btn);
......@@ -95,6 +78,65 @@ extern void button_autorepeat(u8 btn);
// variables for ADC values
// define missing ADC buffer registers
volatile u16 ADC_DB0R @0x53e0;
volatile u16 ADC_DB1R @0x53e2;
volatile u16 ADC_DB2R @0x53e4;
volatile u16 ADC_DB3R @0x53e6;
// last readed values
extern @near volatile u16 adc_all_last[3];
#define adc_steering_last adc_all_last[0]
#define adc_throttle_last adc_all_last[1]
#define adc_ch3_last adc_all_last[2]
extern @near volatile u16 adc_battery_last;
// ADC buffers, last 4 values for each channel
// average will be computed when used
#define ADC_BUFFERS 4
extern @near u16 adc_buffer0[ADC_BUFFERS];
extern @near u16 adc_buffer1[ADC_BUFFERS];
extern @near u16 adc_buffer2[ADC_BUFFERS];
#define ADC_OVS_SHIFT 2
#define ADC_OVS_ROUND 2
#define adc_steering_ovs (adc_buffer0[0] + adc_buffer0[1] + adc_buffer0[2] \
+ adc_buffer0[3])
#define adc_throttle_ovs (adc_buffer1[0] + adc_buffer1[1] + adc_buffer1[2] \
+ adc_buffer1[3])
#define adc_ch3_ovs (adc_buffer2[0] + adc_buffer2[1] + adc_buffer2[2] \
+ adc_buffer2[3])
#define ADC_OVS(name) \
((adc_ ## name ## _ovs + ADC_OVS_ROUND) >> ADC_OVS_SHIFT)
// battery will be filtered more times
extern @near volatile u32 adc_battery_filt;
#define ADC_BAT_FILT 512
extern @near volatile u16 adc_battery; // adc_battery_filt / ADC_BAT_FILT
// code reading last ADC values
// retypes to force more optimized code produced by compiler
extern u16 adc_buffer_pos; // step 2 (skip 16bit values)
#define ADC_NEWVAL(id) \
*(u16 *)((u8 *)adc_buffer ## id ## + adc_buffer_pos) = \
adc_all_last[id] = \
ADC_DB ## id ## R;
#define READ_ADC() \
ADC_NEWVAL(0); \
ADC_NEWVAL(1); \
ADC_NEWVAL(2); \
adc_battery_last = ADC_DB3R; \
*((u8 *)&adc_buffer_pos + 1) = (u8)((u8)((u8)adc_buffer_pos + 2) & 7); \
BRES(ADC_CSR, 7); /* remove EOC flag */ \
BSET(ADC_CR1, 0); // start new conversion
// INPUT task
E_TASK(INPUT);
extern _Bool input_initialized;
......
......@@ -88,7 +88,7 @@ void menu_calibrate(void) {
// select actual voltage for channel 4
if (channel == 1) {
key_beep();
val = (adc_steering_ovs + ADC_OVS_ROUND) >> ADC_OVS_SHIFT;
val = ADC_OVS(steering);
if (val < CALIB_ST_LOW_MID) {
cg.calib_steering_left = val;
seg = LS_MENU_MODEL;
......@@ -106,7 +106,7 @@ void menu_calibrate(void) {
}
else if (channel == 2) {
key_beep();
val = (adc_throttle_ovs + ADC_OVS_ROUND) >> ADC_OVS_SHIFT;
val = ADC_OVS(throttle);
if (val < CALIB_TH_LOW_MID) {
cg.calib_throttle_fwd = val;
seg = LS_MENU_TRIM;
......@@ -157,8 +157,22 @@ void menu_calibrate(void) {
}
// show ADC value if other than last val
if (channel == 4) val = adc_battery;
else val = (adc_all_ovs[channel-1] + ADC_OVS_ROUND) >> ADC_OVS_SHIFT;
switch (channel) {
case 1:
val = ADC_OVS(steering);
break;
case 2:
val = ADC_OVS(throttle);
break;
case 3:
val = ADC_OVS(ch3);
break;
case 4:
val = adc_battery;
break;
default: // to eliminate compiler warning
val = 0;
}
// only update display every 1s
if (time_sec >= update_time) {
update_time = time_sec + 1;
......
......@@ -33,14 +33,15 @@ static @near u16 inactivity;
// initialize timer 2 used to count seconds
#define TIMER_5MS (KHZ / 2 * 5)
#define TIMER_1MS (KHZ / 2)
void timer_init(void) {
BSET(CLK_PCKENR1, 5); // enable clock to TIM2
TIM2_CNTRH = 0; // start at 0
TIM2_CNTRL = 0;
TIM2_PSCR = 1; // clock / 2
TIM2_IER = 0b00000001; // enable update interrupt
TIM2_ARRH = hi8(TIMER_5MS - 1); // count till 5ms time
TIM2_ARRL = lo8(TIMER_5MS - 1);
TIM2_ARRH = hi8(TIMER_1MS - 1); // count till 1ms time
TIM2_ARRL = lo8(TIMER_1MS - 1);
TIM2_CR1 = 0b00000101; // URS-overflow, enable
inactivity = cg.inactivity_alarm * 60;
......@@ -50,13 +51,23 @@ void timer_init(void) {
// count seconds from power on
volatile u16 time_sec;
volatile u8 time_5ms;
volatile u8 time_1ms;
static u16 menu_delay; // timer for delay in MENU task
// interrupt every 5ms
// interrupt every 1ms
@interrupt void timer_interrupt(void) {
BRES(TIM2_SR1, 0); // erase interrupt flag
// read ADC only when EOC flag (only for first it will not be ready)
if (input_initialized && BCHK(ADC_CSR, 7)) {
READ_ADC();
}
// increment 1ms steps
if (++time_1ms < 5) return;
time_1ms = 0;
// increment time from start
if (++time_5ms >= 200) {
......@@ -116,6 +127,10 @@ static u16 menu_delay; // timer for delay in MENU task
// wakeup INPUT task
awake(INPUT);
// wakeup MENU task every 40ms when showing battery or at calibrate
if (menu_wants_adc && !(time_5ms & 0b00000111))
awake(MENU);
// task MENU delay
if (menu_delay && !--menu_delay)
awake(MENU);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment