]> www.fi.muni.cz Git - tinyboard.git/blobdiff - projects/step-up/pwmled.c
Experimental step-up driver for chain of 5630 LEDs.
[tinyboard.git] / projects / step-up / pwmled.c
index 52993308edf3fa31daeaee91c11a61ab4676e7e9..2ede13b3026bec1ac80ef2d68bf755125ff045b2 100644 (file)
@@ -2,18 +2,11 @@
 
 #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 */
 /*
@@ -21,29 +14,19 @@ pwmled_t pwmleds[N_PWMLEDS];
  * 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(10),
+       MA_TO_ADC(20),
 };
 
 #define ST_DISABLED 0
@@ -56,159 +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;
-               }
-       }
-       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;
+               need_pwmled_adc = 1;
+               pwm_set(pwm_val);
        } else {
-               unsigned char i;
-
-               led->state = ST_OFF;
+               state = ST_OFF;
+               need_pwmled_adc = 0;
                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();
+
+       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(led->pwm);
+       pwm_set(pwm_val);
 }