X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?p=tinyboard.git;a=blobdiff_plain;f=projects%2Fstep-up%2Fpwmled.c;h=2ede13b3026bec1ac80ef2d68bf755125ff045b2;hp=5f34c8f8a5f6b04c8223f2397452f735cef63b63;hb=HEAD;hpb=88b18cc5d2263dd948c13f6b7eb0fd1b58fb3cb5 diff --git a/projects/step-up/pwmled.c b/projects/step-up/pwmled.c index 5f34c8f..2ede13b 100644 --- a/projects/step-up/pwmled.c +++ b/projects/step-up/pwmled.c @@ -2,48 +2,31 @@ #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]; - -#define SENSE_MOHM 1000 /* 1 Ohm */ +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 */ /* * Voltage in uV at ADC reading == 1 is 1100/gain/1024 * 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( 5, 1), - MA_GAIN_TO_ADC( 10, 1), - MA_GAIN_TO_ADC( 15, 1), - MA_GAIN_TO_ADC( 20, 1), - /* pwmled1 */ - MA_GAIN_TO_ADC( 5, 1), - MA_GAIN_TO_ADC( 10, 1), - MA_GAIN_TO_ADC( 15, 1), - MA_GAIN_TO_ADC( 20, 1), +static uint16_t targets[N_PWMLED_MODES] = { + MA_TO_ADC( 2), + MA_TO_ADC(10), + MA_TO_ADC(20), }; #define ST_DISABLED 0 @@ -56,158 +39,85 @@ static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES] = { 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; - } - } + 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(n, led->pwm); - } else { - led->state = ST_OFF; - pwm_off(n); - } + 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; + need_pwmled_adc = 1; + pwm_set(pwm_val); } else { - unsigned char i; - - led->state = ST_OFF; - pwm_off(n); - - 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; + state = ST_OFF; + need_pwmled_adc = 0; + pwm_off(); } } -static inline void pwmled_err(unsigned char n) +static inline void pwmled_err() { - pwmleds[n].state = ST_DISABLED; - pwm_off(n); + state = ST_DISABLED; + pwm_off(); log_byte(0xF1); - log_byte(n); - // log_word(jiffies); log_flush(); + + set_error(ERR_PWMLED); } -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(); + need_pwmled_adc = 0; return; } - if (led->state == ST_PROBING) - if (pwmled_probed_ok(n, old_pwm)) - return; - - if (led->pwm == old_pwm) - return; - - pwm_set(n, led->pwm); + pwm_set(pwm_val); }