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)
#include "lights.h"
-#define BATTERY_ADC (N_PWMLEDS + 0)
-#define BUTTON_ADC (N_PWMLEDS + 1)
-#define ZERO_ADC (N_PWMLEDS + 2)
+#define ZERO_ADC 1
//#define NUM_ADCS ZERO_ADC
#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;
-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)
{
#endif
adc_sum = 0;
- // we use the last iteration of zero_count to set up the MUX
- // to its final destination, hence the "1 +" below:
- if (adc_params[current_adc].read_zero_log)
- zero_count = 1 + (1 << (adc_params[current_adc].read_zero_log-1));
- else
- zero_count = 1;
+ read_zero = 0;
+ drop_count = 1;
- if (adc_params[current_adc].read_drop_log)
- drop_count = 1 << (adc_params[current_adc].read_drop_log - 1);
- else
- drop_count = 0;
-
- read_count = 1 << adc_params[current_adc].read_keep_log;
- n_reads_log = adc_params[current_adc].read_keep_log;
+ read_count = 1 << PWMLED_ADC_SHIFT;
+ n_reads_log = PWMLED_ADC_SHIFT;
// set up mux, start one-shot conversion
- if (zero_count > 1)
+ if (read_zero)
setup_mux(ZERO_ADC);
else
setup_mux(current_adc);
ADCSRA |= _BV(ADSC);
}
+#if 0
void timer_start_slow_adcs()
{
if (current_slow_adc > N_PWMLEDS) { // Don't start if in progress
// TODO: kick the watchdog here
}
}
+#endif
/*
* Single synchronous ADC conversion.
void init_adc()
{
- unsigned char i;
current_slow_adc = NUM_ADCS;
current_adc = 0;
}
#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
uint16_t adcval = ADCW;
- if (zero_count) {
- if (zero_count > 1) {
- ADCSRA |= _BV(ADSC);
- zero_count--;
- return;
- } else {
- setup_mux(current_adc);
- zero_count = 0;
- /* fall through */
- }
+ adc_based_timer();
+
+ if (read_zero) {
+ setup_mux(current_adc);
+ read_zero = 0;
+ ADCSRA |= _BV(ADSC); // drop this one, start the next
+ return;
}
if (drop_count) {
}
if (read_count) {
- ADCSRA |= _BV(ADSC);
+ ADCSRA |= _BV(ADSC); // immediately start the next conversion
adc_sum += adcval;
read_count--;
return;
switch (current_adc) {
case 0:
// pwmled_adc(current_adc, adc_sum);
- pwmled_adc(1, adc_sum);
+ pwmled_adc(adc_sum);
break;
}
#define TESTING_FW 1
-#define N_LEDS 7
-#define N_PWMLEDS 2
#define N_PWMLED_MODES 4
#define N_BUTTONS 2
/* pwmled.c */
void init_pwmled();
-void pwmled_adc(unsigned char n, uint16_t adcval);
-void pwmled_set_mode(unsigned char n, unsigned char mode);
+void pwmled_adc(uint16_t adcval);
+void pwmled_set_target(unsigned char mode);
+void pwmled_on_off(unsigned char on);
/* gpio.c */
void init_gpio();
#include "lights.h"
+#define N_LEDS 1
static unsigned char led_counters[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[] = {
{ 0, 0x5 },
{ 1, 0x1 }, /* 10 */
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)
{
- if (n < N_PWMLEDS) {
- pwmled_set_mode(n, mode);
- } else if (n < N_LEDS) {
- gpio_set(n - N_PWMLEDS, mode);
+ if (n == 0) {
+ pwmled_on_off(mode);
}
}
for (i = 0; i < N_LEDS; i++)
led_set_pattern(i, NULL);
-
- led_set_pattern(N_PWMLEDS+1, boot_pattern);
}
pattern_t *number_pattern(unsigned char num, unsigned char inv)
static pattern_t *pattern_select(unsigned char n)
{
+ static unsigned char count;
+ static unsigned char mode;
switch(n) {
- case 0: return pwmled0_pattern_select();
- case 1: return pwmled1_pattern_select();
- case 2: return pwmled2_pattern_select();
- case 3: return status_led_pattern_select();
- case 4: return illumination_led_pattern_select();
- case 6: return laser_pattern_select();
+ case 0:
+ if (++count > 2) {
+ count = 0;
+ if (mode == 0) {
+ mode = 3;
+ } else {
+ mode = 0;
+ }
+
+ pwmled_set_target(mode);
+ }
+ return number_pattern(mode ? 2 : 3, 0);
default: return NULL;
}
}
led_patterns[n] = NULL;
- if (n < N_PWMLEDS) {
- for (i = 0; i < N_PWMLEDS; i++)
- if (led_patterns[i])
- return;
-
- /* all pwmleds finished; restart them */
- for (i = 0; i < N_PWMLEDS; i++)
- led_set_pattern(i, pattern_select(i));
+ if (n == 0) {
+ led_set_pattern(0, pattern_select(0));
+ }
+#if 0
} else if (n == 3) {
if (!led_patterns[4])
led_set_pattern(4, pattern_select(4));
} else {
led_set_pattern(n, pattern_select(n));
}
+#endif
}
void patterns_next_tick()
#include "lights.h"
-typedef struct {
- uint16_t target, pwm;
- int16_t err_sum;
- unsigned char mode, state;
- union {
- 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];
+static uint16_t target;
+static uint16_t pwm_val;
+static int16_t err_sum;
+static unsigned char state;
+unsigned char mode_changed;
#define SENSE_MOHM 3000 /* 1 Ohm */
/*
* ADC module returns sum of 1 << PWMLED_ADC_SHIFT measurements
* 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) \
* (SENSE_MOHM) \
* (1 << (PWMLED_ADC_SHIFT)) \
* 1024 \
- / (1100000/(gain))))
+ / 1100000))
-static uint16_t adc_max[N_PWMLEDS] = {
- MA_GAIN_TO_ADC( 30, 1),
- MA_GAIN_TO_ADC( 30, 1),
-};
+static uint16_t adc_max = MA_TO_ADC(30);
-static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES] = {
- /* pwmled0 */
- MA_GAIN_TO_ADC( 2, 1),
- MA_GAIN_TO_ADC( 5, 1),
- MA_GAIN_TO_ADC( 10, 1),
- 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),
+static uint16_t targets[N_PWMLED_MODES] = {
+ MA_TO_ADC( 2),
+ MA_TO_ADC( 8),
+ MA_TO_ADC(14),
+ MA_TO_ADC(20),
};
#define ST_DISABLED 0
void init_pwmled()
{
- unsigned char i, j;
-
- for (i = 0; i < N_PWMLEDS; i++) {
- pwmled_t *led = pwmleds + i;
- 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;
+ pwm_val = 0;
+ err_sum = 0;
+ target = targets[0];
+ state = ST_OFF;
}
-void pwmled_set_mode(unsigned char n, unsigned char mode)
+void pwmled_set_target(unsigned char mode)
{
- pwmled_t *led = pwmleds + n;
-
- 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();
- }
+ target = targets[mode];
+ mode_changed = 1;
}
-#define PWMLED_PROBE_STEADY_COUNT 10
-
-static inline unsigned char pwmled_probed_ok(unsigned char n, uint16_t old_pwm)
+void pwmled_on_off(unsigned char mode)
{
- pwmled_t *led = pwmleds + n;
-
- 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];
+ if (!ST_CAN_SET_MODE(state))
+ return;
- return 0;
+ if (mode) {
+ state = ST_ON;
+ mode_changed = 1;
+ pwm_set(pwm_val);
} else {
- unsigned char i;
-
- led->state = ST_OFF;
+ state = ST_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();
log_byte(0xF1);
- log_byte(n);
- // log_word(jiffies);
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;
unsigned char shift;
- if (!ST_IS_ON(led->state))
+ if (!ST_IS_ON(state))
return;
- if (led->state == ST_ON && led->mode_changed) {
- led->mode_changed--;
+ // skip the first reading after mode change
+ if (state == ST_ON && mode_changed) {
+ mode_changed--;
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)
- + led->err_sum + led->target - adcval;
+ sum = ((int32_t)pwm_val << shift)
+ + err_sum + target - adcval;
if (sum < 0)
sum = 0;
- led->pwm = sum >> shift;
- sum -= led->pwm << shift;
- led->err_sum = sum;
+ pwm_val = sum >> shift;
+ sum -= pwm_val << shift;
+ err_sum = sum;
- if (led->pwm >= PWM_MAX
- || (led->pwm > (2*PWM_MAX/3) && adcval < 0x08)) {
- pwmled_err(n);
+ if (pwm_val >= PWM_MAX
+ || (pwm_val > (2*PWM_MAX/3) && adcval < 0x08)) {
+ pwmled_err();
return;
}
- if (led->state == ST_PROBING)
- if (pwmled_probed_ok(n, old_pwm))
- return;
-
- if (led->pwm == old_pwm)
- return;
-
- pwm_set(led->pwm);
+ pwm_set(pwm_val);
}