165 lines
4.4 KiB
C
165 lines
4.4 KiB
C
/*
|
|
* 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
|
|
}
|
|
}
|
|
}
|