Commit 37d45fd9 authored by Jan Kasprzak's avatar Jan Kasprzak
Browse files
parents 3079ccda b02a7f77
PROGRAM=lights PROGRAM=lights
SRC=main.c logging.c pwm.c adc.c pwmled.c SRC=main.c logging.c pwm.c adc.c pwmled.c pattern.c
OBJ=$(SRC:.c=.o) OBJ=$(SRC:.c=.o)
......
...@@ -5,32 +5,13 @@ ...@@ -5,32 +5,13 @@
#include "lights.h" #include "lights.h"
#define BATTERY_ADC (N_PWMLEDS + 0) #define ZERO_ADC 1
#define BUTTON_ADC (N_PWMLEDS + 1)
#define ZERO_ADC (N_PWMLEDS + 2)
//#define NUM_ADCS ZERO_ADC //#define NUM_ADCS ZERO_ADC
#define NUM_ADCS 1 #define NUM_ADCS 1
struct {
unsigned char read_zero_log : 2;
unsigned char read_drop_log : 2;
unsigned char read_keep_log : 4;
} adc_params[NUM_ADCS] = {
{ 0, 1, PWMLED_ADC_SHIFT }, // pwmled 1
#if 0
{ 0, 1, PWMLED_ADC_SHIFT }, // pwmled 2
{ 0, 1, PWMLED_ADC_SHIFT }, // pwmled 3
{ 0, 1, AMBIENT_ADC_SHIFT }, // ambient
{ 0, 1, 0 }, // battery
{ 0, 1, 0 }, // gain20
{ 0, 1, 0 }, // buttons
#endif
};
volatile static unsigned char current_adc, current_slow_adc; volatile static unsigned char current_adc, current_slow_adc;
static uint16_t adc_sum, zero_count, drop_count, read_count, n_reads_log; static uint16_t adc_sum, read_zero, drop_count, read_count, n_reads_log;
static void setup_mux(unsigned char n) static void setup_mux(unsigned char n)
{ {
...@@ -73,23 +54,14 @@ void start_next_adc() ...@@ -73,23 +54,14 @@ void start_next_adc()
#endif #endif
adc_sum = 0; adc_sum = 0;
// we use the last iteration of zero_count to set up the MUX read_zero = 0;
// to its final destination, hence the "1 +" below: drop_count = 1;
if (adc_params[current_adc].read_zero_log)
zero_count = 1 + (1 << (adc_params[current_adc].read_zero_log-1));
else
zero_count = 1;
if (adc_params[current_adc].read_drop_log) read_count = 1 << PWMLED_ADC_SHIFT;
drop_count = 1 << (adc_params[current_adc].read_drop_log - 1); n_reads_log = PWMLED_ADC_SHIFT;
else
drop_count = 0;
read_count = 1 << adc_params[current_adc].read_keep_log;
n_reads_log = adc_params[current_adc].read_keep_log;
// set up mux, start one-shot conversion // set up mux, start one-shot conversion
if (zero_count > 1) if (read_zero)
setup_mux(ZERO_ADC); setup_mux(ZERO_ADC);
else else
setup_mux(current_adc); setup_mux(current_adc);
...@@ -97,6 +69,7 @@ void start_next_adc() ...@@ -97,6 +69,7 @@ void start_next_adc()
ADCSRA |= _BV(ADSC); ADCSRA |= _BV(ADSC);
} }
#if 0
void timer_start_slow_adcs() void timer_start_slow_adcs()
{ {
if (current_slow_adc > N_PWMLEDS) { // Don't start if in progress if (current_slow_adc > N_PWMLEDS) { // Don't start if in progress
...@@ -106,6 +79,7 @@ void timer_start_slow_adcs() ...@@ -106,6 +79,7 @@ void timer_start_slow_adcs()
// TODO: kick the watchdog here // TODO: kick the watchdog here
} }
} }
#endif
/* /*
* Single synchronous ADC conversion. * Single synchronous ADC conversion.
...@@ -129,7 +103,6 @@ static uint16_t read_adc_sync() ...@@ -129,7 +103,6 @@ static uint16_t read_adc_sync()
void init_adc() void init_adc()
{ {
unsigned char i;
current_slow_adc = NUM_ADCS; current_slow_adc = NUM_ADCS;
current_adc = 0; current_adc = 0;
...@@ -171,19 +144,26 @@ static void adc1_gain20_adc(uint16_t adcsum) ...@@ -171,19 +144,26 @@ static void adc1_gain20_adc(uint16_t adcsum)
} }
#endif #endif
static void inline adc_based_timer()
{
static uint16_t pattern_counter;
if (++pattern_counter > 250) {
pattern_counter = 0;
patterns_next_tick();
}
}
ISR(ADC_vect) { // IRQ handler ISR(ADC_vect) { // IRQ handler
uint16_t adcval = ADCW; uint16_t adcval = ADCW;
if (zero_count) { adc_based_timer();
if (zero_count > 1) {
ADCSRA |= _BV(ADSC); if (read_zero) {
zero_count--;
return;
} else {
setup_mux(current_adc); setup_mux(current_adc);
zero_count = 0; read_zero = 0;
/* fall through */ ADCSRA |= _BV(ADSC); // drop this one, start the next
} return;
} }
if (drop_count) { if (drop_count) {
...@@ -193,7 +173,7 @@ ISR(ADC_vect) { // IRQ handler ...@@ -193,7 +173,7 @@ ISR(ADC_vect) { // IRQ handler
} }
if (read_count) { if (read_count) {
ADCSRA |= _BV(ADSC); ADCSRA |= _BV(ADSC); // immediately start the next conversion
adc_sum += adcval; adc_sum += adcval;
read_count--; read_count--;
return; return;
...@@ -206,7 +186,7 @@ ISR(ADC_vect) { // IRQ handler ...@@ -206,7 +186,7 @@ ISR(ADC_vect) { // IRQ handler
switch (current_adc) { switch (current_adc) {
case 0: case 0:
// pwmled_adc(current_adc, adc_sum); // pwmled_adc(current_adc, adc_sum);
pwmled_adc(1, adc_sum); pwmled_adc(adc_sum);
break; break;
} }
......
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
#define TESTING_FW 1 #define TESTING_FW 1
#define N_LEDS 7
#define N_PWMLEDS 2
#define N_PWMLED_MODES 4 #define N_PWMLED_MODES 4
#define N_BUTTONS 2 #define N_BUTTONS 2
...@@ -44,8 +42,9 @@ void susp_tmr(); ...@@ -44,8 +42,9 @@ void susp_tmr();
/* pwmled.c */ /* pwmled.c */
void init_pwmled(); void init_pwmled();
void pwmled_adc(unsigned char n, uint16_t adcval); void pwmled_adc(uint16_t adcval);
void pwmled_set_mode(unsigned char n, unsigned char mode); void pwmled_set_target(unsigned char mode);
void pwmled_on_off(unsigned char on);
/* gpio.c */ /* gpio.c */
void init_gpio(); void init_gpio();
......
...@@ -3,29 +3,10 @@ ...@@ -3,29 +3,10 @@
#include "lights.h" #include "lights.h"
#define N_LEDS 1
static unsigned char led_counters[N_LEDS]; static unsigned char led_counters[N_LEDS];
static pattern_t *led_patterns[N_LEDS]; static pattern_t *led_patterns[N_LEDS];
static pattern_t boot_pattern[] = {
{ 1, 0x6 },
{ 0, 0x6 },
{ 1, 0x3 },
{ 0, 0x3 },
{ 1, 0x2 },
{ 0, 0x2 },
{ 1, 0x1 },
{ 0, 0x1 },
{ 1, 0x1 },
{ 0, 0x1 },
{ 1, 0x1 },
{ 0, 0x1 },
{ 1, 0x1 },
{ 0, 0x1 },
{ 1, 0x10 },
{ 0, 0x10 },
PATTERN_END
};
static pattern_t pattern_num[] = { static pattern_t pattern_num[] = {
{ 0, 0x5 }, { 0, 0x5 },
{ 1, 0x1 }, /* 10 */ { 1, 0x1 }, /* 10 */
...@@ -81,12 +62,20 @@ pattern_t off_pattern[] = { ...@@ -81,12 +62,20 @@ pattern_t off_pattern[] = {
PATTERN_END PATTERN_END
}; };
pattern_t on1_pattern[] = {
{ 1, 1 },
{ 0, 2 },
{ 1, 1 },
{ 0, 8 },
{ 1, 1 },
{ 0, 8 },
PATTERN_END
};
static void led_set_mode(unsigned char n, unsigned char mode) static void led_set_mode(unsigned char n, unsigned char mode)
{ {
if (n < N_PWMLEDS) { if (n == 0) {
pwmled_set_mode(n, mode); pwmled_on_off(mode);
} else if (n < N_LEDS) {
gpio_set(n - N_PWMLEDS, mode);
} }
} }
...@@ -107,8 +96,6 @@ void init_pattern() ...@@ -107,8 +96,6 @@ void init_pattern()
for (i = 0; i < N_LEDS; i++) for (i = 0; i < N_LEDS; i++)
led_set_pattern(i, NULL); led_set_pattern(i, NULL);
led_set_pattern(N_PWMLEDS+1, boot_pattern);
} }
pattern_t *number_pattern(unsigned char num, unsigned char inv) pattern_t *number_pattern(unsigned char num, unsigned char inv)
...@@ -129,13 +116,21 @@ pattern_t *number_pattern(unsigned char num, unsigned char inv) ...@@ -129,13 +116,21 @@ pattern_t *number_pattern(unsigned char num, unsigned char inv)
static pattern_t *pattern_select(unsigned char n) static pattern_t *pattern_select(unsigned char n)
{ {
static unsigned char count;
static unsigned char mode;
switch(n) { switch(n) {
case 0: return pwmled0_pattern_select(); case 0:
case 1: return pwmled1_pattern_select(); if (++count > 2) {
case 2: return pwmled2_pattern_select(); count = 0;
case 3: return status_led_pattern_select(); if (mode == 0) {
case 4: return illumination_led_pattern_select(); mode = 3;
case 6: return laser_pattern_select(); } else {
mode = 0;
}
pwmled_set_target(mode);
}
return number_pattern(mode ? 2 : 3, 0);
default: return NULL; default: return NULL;
} }
} }
...@@ -154,14 +149,10 @@ static void inline pattern_finished(unsigned char n) ...@@ -154,14 +149,10 @@ static void inline pattern_finished(unsigned char n)
led_patterns[n] = NULL; led_patterns[n] = NULL;
if (n < N_PWMLEDS) { if (n == 0) {
for (i = 0; i < N_PWMLEDS; i++) led_set_pattern(0, pattern_select(0));
if (led_patterns[i]) }
return; #if 0
/* all pwmleds finished; restart them */
for (i = 0; i < N_PWMLEDS; i++)
led_set_pattern(i, pattern_select(i));
} else if (n == 3) { } else if (n == 3) {
if (!led_patterns[4]) if (!led_patterns[4])
led_set_pattern(4, pattern_select(4)); led_set_pattern(4, pattern_select(4));
...@@ -171,6 +162,7 @@ static void inline pattern_finished(unsigned char n) ...@@ -171,6 +162,7 @@ static void inline pattern_finished(unsigned char n)
} else { } else {
led_set_pattern(n, pattern_select(n)); led_set_pattern(n, pattern_select(n));
} }
#endif
} }
void patterns_next_tick() void patterns_next_tick()
......
...@@ -2,18 +2,11 @@ ...@@ -2,18 +2,11 @@
#include "lights.h" #include "lights.h"
typedef struct { static uint16_t target;
uint16_t target, pwm; static uint16_t pwm_val;
int16_t err_sum; static int16_t err_sum;
unsigned char mode, state; static unsigned char state;
union { unsigned char mode_changed;
unsigned char probe_steady, mode_changed;
};
uint16_t mode_pwm[N_PWMLED_MODES];
int16_t err_sums[N_PWMLED_MODES];
} pwmled_t;
pwmled_t pwmleds[N_PWMLEDS];
#define SENSE_MOHM 3000 /* 1 Ohm */ #define SENSE_MOHM 3000 /* 1 Ohm */
/* /*
...@@ -21,29 +14,20 @@ pwmled_t pwmleds[N_PWMLEDS]; ...@@ -21,29 +14,20 @@ pwmled_t pwmleds[N_PWMLEDS];
* ADC module returns sum of 1 << PWMLED_ADC_SHIFT measurements * ADC module returns sum of 1 << PWMLED_ADC_SHIFT measurements
* Voltage in uV measured is current in mA * sense resistance in mOhm * Voltage in uV measured is current in mA * sense resistance in mOhm
*/ */
#define MA_GAIN_TO_ADC(ma, gain) ((uint16_t) \ #define MA_TO_ADC(ma) ((uint16_t) \
((uint32_t)(ma) \ ((uint32_t)(ma) \
* (SENSE_MOHM) \ * (SENSE_MOHM) \
* (1 << (PWMLED_ADC_SHIFT)) \ * (1 << (PWMLED_ADC_SHIFT)) \
* 1024 \ * 1024 \
/ (1100000/(gain)))) / 1100000))
static uint16_t adc_max[N_PWMLEDS] = { static uint16_t adc_max = MA_TO_ADC(30);
MA_GAIN_TO_ADC( 30, 1),
MA_GAIN_TO_ADC( 30, 1),
};
static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES] = { static uint16_t targets[N_PWMLED_MODES] = {
/* pwmled0 */ MA_TO_ADC( 2),
MA_GAIN_TO_ADC( 2, 1), MA_TO_ADC( 8),
MA_GAIN_TO_ADC( 5, 1), MA_TO_ADC(14),
MA_GAIN_TO_ADC( 10, 1), MA_TO_ADC(20),
MA_GAIN_TO_ADC( 20, 1),
/* pwmled1 */
MA_GAIN_TO_ADC( 2, 1),
MA_GAIN_TO_ADC( 8, 1),
MA_GAIN_TO_ADC( 14, 1),
MA_GAIN_TO_ADC( 20, 1),
}; };
#define ST_DISABLED 0 #define ST_DISABLED 0
...@@ -56,159 +40,80 @@ static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES] = { ...@@ -56,159 +40,80 @@ static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES] = {
void init_pwmled() void init_pwmled()
{ {
unsigned char i, j; pwm_val = 0;
err_sum = 0;
for (i = 0; i < N_PWMLEDS; i++) { target = targets[0];
pwmled_t *led = pwmleds + i; state = ST_OFF;
led->err_sum = 0;
led->target = adc_vals[i*N_PWMLED_MODES];
led->pwm = 0;
led->mode = 1;
led->state = ST_PROBING;
led->probe_steady = 0;
for (j = 0; j < N_PWMLED_MODES; j++) {
led->mode_pwm[j] = 0;
led->err_sums[j] = 0;
}
}
pwmleds[0].state = ST_DISABLED;
} }
void pwmled_set_mode(unsigned char n, unsigned char mode) void pwmled_set_target(unsigned char mode)
{ {
pwmled_t *led = pwmleds + n; target = targets[mode];
mode_changed = 1;
if (!ST_CAN_SET_MODE(led->state))
return;
if (led->mode) { // save the previous state
led->mode_pwm[led->mode - 1] = led->pwm;
led->err_sums[led->mode - 1] = led->err_sum;
}
led->mode = mode;
if (mode > 0 && mode <= N_PWMLED_MODES) {
led->target = adc_vals[n*N_PWMLED_MODES + mode - 1];
led->state = ST_ON;
led->pwm = led->mode_pwm[mode - 1];
led->err_sum = led->err_sums[mode - 1];
led->mode_changed = 1;
pwm_set(led->pwm);
} else {
led->state = ST_OFF;
pwm_off();
}
} }
#define PWMLED_PROBE_STEADY_COUNT 10 void pwmled_on_off(unsigned char mode)
static inline unsigned char pwmled_probed_ok(unsigned char n, uint16_t old_pwm)
{ {
pwmled_t *led = pwmleds + n; if (!ST_CAN_SET_MODE(state))
return;
if (led->pwm == old_pwm) {
if (led->probe_steady < PWMLED_PROBE_STEADY_COUNT)
led->probe_steady++;
} else {
led->probe_steady = 0;
}
if (led->probe_steady < PWMLED_PROBE_STEADY_COUNT
&& old_pwm <= led->pwm)
return 0;
// probed OK
led->mode_pwm[led->mode - 1] = led->pwm;
led->err_sums[led->mode - 1] = 0;
// next mode to probe?
if (led->mode < N_PWMLED_MODES) {
led->probe_steady = 0;
led->err_sum = 0;
led->mode++;
led->target = adc_vals[n*N_PWMLED_MODES+led->mode-1];
return 0; if (mode) {
state = ST_ON;
mode_changed = 1;
pwm_set(pwm_val);
} else { } else {
unsigned char i; state = ST_OFF;
led->state = ST_OFF;
pwm_off(); pwm_off();
log_byte(0xF0);
log_byte(n);
// log_word(jiffies);
for (i = 0; i < N_PWMLED_MODES; i++)
log_word(led->mode_pwm[i]);
log_flush();
// pattern_reload();
// pwmled_set_mode(n, 2);
return 1;
} }
} }
static inline void pwmled_err(unsigned char n) static inline void pwmled_err()
{ {
pwmleds[n].state = ST_DISABLED; state = ST_DISABLED;
pwm_off(); pwm_off();
log_byte(0xF1); log_byte(0xF1);
log_byte(n);
// log_word(jiffies);
log_flush(); log_flush();
} }
void pwmled_adc(unsigned char n, uint16_t adcval) void pwmled_adc(uint16_t adcval)
{ {
pwmled_t *led = pwmleds + n;
uint16_t old_pwm;
int32_t sum; int32_t sum;
unsigned char shift; unsigned char shift;
if (!ST_IS_ON(led->state)) if (!ST_IS_ON(state))
return; return;
if (led->state == ST_ON && led->mode_changed) { // skip the first reading after mode change
led->mode_changed--; if (state == ST_ON && mode_changed) {
mode_changed--;
return; return;
} }
// FIXME: test for maximum adcval value (adc_max[n])
old_pwm = led->pwm; if (adcval > adc_max) {
pwmled_err();
return;
}
shift = led->state == ST_PROBING ? 3 : 8; shift = 5;
sum = ((int32_t)led->pwm << shift)