/* * led.c * * Created: 6/13/2014 1:44:28 AM * Author: true */ #include "led.h" /* led */ uint8_t rgbled_pwm_lf[4]; // pwm value for TIMER1 OCA LED outputs uint8_t rgbled_pwm_rt[4]; // pwm value for TIMER1 OCB LED outputs static uint8_t rgbled_read_sel; // LED light sensor select static uint8_t rgbled_sensitivity[4] = {1, 1, 1, 1}; /* adc */ volatile uint8_t adc_busy; volatile uint16_t adc_result[ADC_MAX_FEEDBACK + 1]; volatile uint8_t adc_read_mode; /* functions */ // sets up the IO pins for LED output function. void rgbled_io_init() { // PortD[4:7] (left) and PortC[0:3] (right) are LEDs // Also, Right LEDs are capable of ADC input on ALL pins (ADC[0:3]) // set all pins as outputs DDRD |= 0xf0; DDRC |= 0x0f; #ifdef LED_COMMON_ANODE // com-anode: pin is high to disable PORTD |= 0xf0; PORTC |= 0x0f; #else // com-cathode: pin is low to disable PORTD &= 0x0f; PORTC &= 0xf0; #endif } // sets the appropriate pins and PWM values for the LED index specified in rgbled_idx. // note: this index is updated externally, and not by this function. void rgbled_update() { // clear all selected LED pins // we have to clear the select line then set it because we can't fully disable the PWM for some reason #ifdef LED_COMMON_ANODE // make sure all pins are high PORTD |= 0xf0; PORTC |= 0x0f; #else // make sure all pins are low PORTD &= 0x0f; PORTC &= 0xf0; #endif // set pwm OCx registers to max timer1_set_oca(TIMER1_COMPARE); timer1_set_ocb(TIMER1_COMPARE); // and set pwm counter value to 1 before expiry timer1_set(TIMER1_COMPARE - 1); // now we set the desired LED // turn on one LED in each group #ifdef LED_COMMON_ANODE // make sure active pin is output low and others are high PORTD &= ~(_BV(rgbled_idx + 4)); PORTC &= ~(_BV(rgbled_idx)); #else // make sure active pin is output high and others are low PORTD |= _BV(rgbled_idx) << 4; PORTC |= _BV(rgbled_idx); #endif // load new pwm OCx values for this LED timer1_set_oca(rgbled_pwm_lf[rgbled_idx]); timer1_set_ocb(rgbled_pwm_rt[rgbled_idx]); } // sets up the PortC LED matrix as a diode light sensor. // configures the specified LED on the ADC. // this function assumes common anode. void rgbled_sensor_init(uint8_t led) { // set the left eye high (fixes color flash/tearing) PORTD |= 0xf0; // disable both eye's PWM (required for right eye, fixes color flash/tearing in left eye) TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(COM1B0)); // ground the LED DDRC &= 0xf0; // set all LEDs cathode as inputs MCUCR |= (_BV(PUD)); // globally disable pullups DDRC |= (_BV(led)); // set our LED as an output PORTC = (PORTC & 0xf0); // set all LEDs cathode low PORTB |= (_BV(PORTB2)); // set anode high // reverse LED bias PORTC |= (_BV(led)); // set cathode high PORTB &= ~(_BV(PORTB2)); // set anode low _delay_us(3); // allow it to charge fully // set LED as input DDRC &= ~(_BV(led)); // set led cathode as input PORTC &= ~(_BV(led)); // set led cathode pullup off MCUCR &= ~(_BV(PUD)); // re-enable global pullups } // starts ADC to read the value of charge remaining on the LED void rgbled_sensor_sensitivity(uint8_t ledidx, uint8_t sensitivity) { if (ledidx <= 0x03) { if (sensitivity) { rgbled_sensitivity[ledidx] = sensitivity; } } } void rgbled_sensor_read_idx(uint8_t ledidx) { rgbled_read_sel = ledidx & 0x03; } void rgbled_sensor_read() { uint8_t sens; sens = rgbled_sensitivity[rgbled_read_sel]; if (!sens) sens = 1; if (adc_read_step == 0) { // adc_init(); // clear ADC bias by reading ground adc_channel(ADC_CHAN_GND, ADC_REF_AVCC); } else if (adc_read_step == 1) { adc_start(0, 0); } else if (adc_read_step == 2) { // if the ADC is done, charge up LED for reading if (adc_busy) { adc_read_step--; } else { rgbled_sensor_init(rgbled_read_sel); adc_channel(rgbled_read_sel, ADC_REF_NO_SET); } } else if (adc_read_step == (2 + sens)) { // if vref has changed, it should be stable by now; start reading LED value adc_start(3, 1); } else if (adc_read_step > (2 + sens)) { adc_read_step--; if (!adc_busy) { // we are done! :) finish up... adc_channel(ADC_CHAN_GND, ADC_REF_NO_SET); // change ADC to not look at a real pin rgbled_io_init(); // set LED pins up again timer1_pwm_reinit(); // and set up PWM again adc_read_mode = 0; // clear ADC read mode } } }