#include "lights.h"
static uint16_t pwm_vals[N_PWMLEDS*N_PWMLED_MODES];
-static uint16_t pwm_max[N_PWMLEDS] = { 0x70, 0x70, 0x1F0 };
-static uint16_t adc_max[N_PWMLEDS] = { 0x70, 0x70, 0xF0 };
+static uint16_t pwm_max[N_PWMLEDS] = {
+ 2*PWM_MAX/3,
+ PWM_MAX - (PWM_MAX >> 4), // step-up
+ 2*PWM_MAX/3
+};
+
+#define PWMLED2_TESTING_WITH_350MA_LED
+
+#define SENSE_MOHM 33 /* 0.033 Ohm */
+#define MA_MOHM_GAIN_TO_ADC(ma, mohm, gain) (\
+ ((unsigned long)(ma))*(mohm) /* voltage at sensing resistor in uV */ \
+ /(1100000UL/gain/1024UL) /* voltage of ADC reading == 1 */ \
+)
+static uint16_t adc_max[N_PWMLEDS] = {
+ MA_MOHM_GAIN_TO_ADC( 400, SENSE_MOHM, 20),
+ MA_MOHM_GAIN_TO_ADC( 30, SENSE_MOHM, 20),
+#ifdef PWMLED2_TESTING_WITH_350MA_LED
+ MA_MOHM_GAIN_TO_ADC( 400, SENSE_MOHM, 1)
+#else
+ MA_MOHM_GAIN_TO_ADC(2500, SENSE_MOHM, 1)
+#endif
+};
static uint16_t adc_vals[N_PWMLEDS*N_PWMLED_MODES] = {
/* pwmled0 */
- 0x04, 0x14, 0x24, 0x38,
+ MA_MOHM_GAIN_TO_ADC( 20, SENSE_MOHM, 20),
+ MA_MOHM_GAIN_TO_ADC( 50, SENSE_MOHM, 20),
+ MA_MOHM_GAIN_TO_ADC( 100, SENSE_MOHM, 20),
+ MA_MOHM_GAIN_TO_ADC( 350, SENSE_MOHM, 20),
/* pwmled1 */
- 0x04, 0x14, 0x24, 0x38,
+ MA_MOHM_GAIN_TO_ADC( 5, SENSE_MOHM, 20),
+ MA_MOHM_GAIN_TO_ADC( 12, SENSE_MOHM, 20),
+ MA_MOHM_GAIN_TO_ADC( 16, SENSE_MOHM, 20),
+ MA_MOHM_GAIN_TO_ADC( 20, SENSE_MOHM, 20),
/* pwmled2 */
- 0x0c, 0x24, 0x48, 0x90,
+#ifdef PWMLED2_TESTING_WITH_350MA_LED
+ MA_MOHM_GAIN_TO_ADC( 100, SENSE_MOHM, 1),
+ MA_MOHM_GAIN_TO_ADC( 140, SENSE_MOHM, 1),
+ MA_MOHM_GAIN_TO_ADC( 250, SENSE_MOHM, 1),
+ MA_MOHM_GAIN_TO_ADC( 350, SENSE_MOHM, 1),
+#else
+ MA_MOHM_GAIN_TO_ADC( 150, SENSE_MOHM, 1),
+ MA_MOHM_GAIN_TO_ADC( 350, SENSE_MOHM, 1),
+ MA_MOHM_GAIN_TO_ADC( 700, SENSE_MOHM, 1),
+ MA_MOHM_GAIN_TO_ADC(2400, SENSE_MOHM, 1),
+#endif
};
// TODO: maybe convert this to bitmask to simplify pwmled_needs_adc() ?
static unsigned char pwmled_mode_set[N_PWMLEDS];
static uint16_t pwm_probes[N_PWMLEDS];
+static int16_t differences[N_PWMLEDS];
static void start_probing(unsigned char n)
{
}
for (i = 0; i < N_PWMLEDS; i++) {
+ differences[i] = 0;
start_probing(i);
}
}
-unsigned char pwmled_needs_adc(unsigned char n)
-{
- unsigned char st = pwmled_state[n];
- if (st == ST_PROBING || st == ST_ON)
- return 1;
- else
- return 0;
-}
-
unsigned char pwmled_enabled(unsigned char n)
{
unsigned char st = pwmled_state[n];
log_byte(n);
log_byte(mode);
#endif
-
- if (mode == 0) {
- pwm_off(n);
- pwmled_state[n] = ST_OFF;
- return;
- }
-
- if (mode <= N_PWMLED_MODES) {
+ if (mode > 0 && mode <= N_PWMLED_MODES) {
uint16_t pwmval;
mode--;
pwmval = pwm_vals[n*N_PWMLED_MODES+mode];
pwmled_state[n] = ST_ON;
pwmled_mode[n] = mode;
pwmled_mode_set[n] = 1;
+ differences[n] = 0;
+ } else {
+ pwm_off(n);
+ pwmled_state[n] = ST_OFF;
}
}
#endif
if (adcval > adc_max[n] // Too high
- || (pwm == 0 && adcval > 0) // non-zero voltage with zero PWM
+ || (pwm == 0 && adcval > 2) // non-zero voltage with zero PWM
) {
pwm_off(n);
pwmled_state[n] = ST_DISABLED;
static void inline on_adc(unsigned char n, uint16_t adcval)
{
unsigned char mode = pwmled_mode[n];
- uint16_t adc_exp = adc_vals[n*N_PWMLED_MODES+mode];
- uint16_t *pwm_p = &pwm_vals[n*N_PWMLED_MODES+mode];
- uint16_t old_pwm = *pwm_p;
- uint16_t new_pwm = old_pwm;
+ uint16_t adc_exp = adc_vals[n*N_PWMLED_MODES+mode];
+ uint16_t *pwm_p = &pwm_vals[n*N_PWMLED_MODES+mode];
+ int16_t old_pwm = *pwm_p;
+ int16_t new_pwm = old_pwm;
#if 0
log_byte(0xF5);
log_word(adcval);
#endif
+
if (pwmled_mode_set[n]) { // ignore the first reading
pwmled_mode_set[n] = 0;
return;
}
- // FIXME: running average?
- if (2*adcval > 5*adc_exp) { // >2.5x expected, lower significantly
- new_pwm = 2*old_pwm/3;
- } else if (3*adcval > 4*adc_exp) { // >1.33x expected, lower a bit
- new_pwm = old_pwm - 1;
- } else if (4*adcval < 3*adc_exp) { // 0.75x expected, raise a bit
- new_pwm = old_pwm + 1;
- }
+ differences[n] += adcval;
+ differences[n] -= adc_exp;
+
+ if (differences[n] > 16)
+ new_pwm -= 2;
+ else if (differences[n] > 4)
+ new_pwm--;
+ else if (differences[n] < -16)
+ new_pwm += 2;
+ else if (differences[n] < -4)
+ new_pwm++;
+ // new_pwm -= differences[n] >> 3;
+
+ if (new_pwm == old_pwm)
+ return;
+
+ differences[n] = 0;
- // FIXME: better disconnect detection
- if (new_pwm > pwm_max[n]) { // FIXME: disconnected?
- new_pwm = pwm_max[n];
+ if (new_pwm > (int16_t)pwm_max[n]) {
+ // FIXME: disconnected?
+ log_byte(0xE1);
+ log_byte(n);
+ log_word(new_pwm);
+ log_word(adcval);
+ log_word(jiffies);
+ pwmled_state[n] = ST_DISABLED;
+ pwm_off(n);
+ return;
}
- if (new_pwm < 2) { // short-circuit?
- new_pwm = 2;
+
+ if (new_pwm < 1) {
+ // FIXME: short-circuit?
+ new_pwm = 1;
}
- if (new_pwm != old_pwm) {
- *pwm_p = new_pwm;
- pwm_set(n, new_pwm);
-#if 0
- log_byte(0xF9);
+ *pwm_p = new_pwm;
+ pwm_set(n, new_pwm);
+
+ if (jiffies > 500 && n == 1) {
+ log_byte(adcval & 0xFF);
log_byte(new_pwm);
-#endif
}
}
void pwmled_adc(unsigned char n, uint16_t adcval)
{
unsigned char i, probing;
+
switch (pwmled_state[n]) {
case ST_PROBING:
probing_adc(n, adcval);
-
#if 1
probing = 0;
for (i = 0; i < N_PWMLEDS; i++)
probing = 1;
if (!probing) {
+ log_word(0x5555);
+ log_word(jiffies);
for (i = 0; i < N_PWMLEDS; i++)
log_byte(pwmled_state[i]);
log_word(pwm_vals[i]);
log_flush();
log_set_state(4);
+ for (i = 0; i < N_PWMLEDS; i++)
+ led_set_pattern(i, mode1_pattern);
}
#endif