#include <avr/io.h>
+#include <avr/eeprom.h>
#include <util/delay.h>
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+
+volatile uint16_t adcval;
+unsigned char pwmval = 0x10;
+volatile uint16_t adc_exp = 0x10;
+unsigned char led_is_on = 0;
+volatile unsigned char adccount = 0;
+
+volatile struct
+{
+ uint8_t pwm_int: 1;
+ uint8_t adc_int: 1;
+ uint8_t tmr_int: 1;
+}
+intflags;
+
+static void inline led_on()
+{
+ DDRB |= _BV( PB5 );
+ led_is_on = 1;
+}
+
+static void inline led_off()
+{
+ led_is_on = 0;
+ DDRB &= ~_BV( PB5 );
+// ADCSRA &= ~(_BV(ADIE) | _BV(ADIF));
+}
+
+/* ------------ Logging/Debugging ----------- */
+
+unsigned char debug_state EEMEM;
+
+static void inline debug_setstate(unsigned char val)
+{
+ eeprom_write_byte(&debug_state, val);
+}
+
+#define LOG_BUFFER 64
+uint16_t log_buffer[LOG_BUFFER] EEMEM;
+unsigned char log_buffer_count;
+uint16_t log_buffer2[LOG_BUFFER];
+volatile unsigned char stop = 0;
+
+static void inline init_log()
+{
+ debug_setstate(1);
+ log_buffer_count = 0;
+}
+
+static void log_word(uint16_t word) {
+ if (log_buffer_count >= LOG_BUFFER)
+ return;
+
+ // eeprom_write_word(&log_buffer[log_buffer_count], word);
+ log_buffer2[log_buffer_count] = word;
+ log_buffer_count++;
+
+ if (log_buffer_count == LOG_BUFFER) {
+ unsigned char i;
+ for (i=0; i < LOG_BUFFER; i++) {
+ eeprom_write_word(&log_buffer[i],
+ log_buffer2[i]);
+ }
+ debug_setstate(0x42);
+ }
+}
+
+/* ------------ Timer ----------- */
+
+volatile uint16_t clock = 0;
+
+static void inline init_tmr()
+{
+ TCCR0A = _BV(WGM00);
+ TCCR0B = _BV(CS02) | _BV(CS00); // 1 kHz
+ OCR0A = 12; // 100 Hz
+ TIMSK |= _BV(OCIE0A);
+ DDRA |= _BV( PA0 );
+
+ clock = 0;
+}
+
+static void inline tmr_handler()
+{
+ unsigned char c = clock & 0x1F;
+ unsigned char c1 = clock & 0xFF;
+
+ ++clock;
+#if 0
+ if (c == 10 || c == 30)
+ led_on();
+
+ if (c == 20 || c == 40)
+ led_off();
+#endif
+
+ if (c == 0x02 || c == 0x08)
+ led_on();
+ if (c == 0x05 || c == 0x0b)
+ led_off();
+
+ if ((clock & 0x7F) == 0x1F) {
+ if (c1 < 0x80) {
+ adc_exp = 0x80;
+ } else {
+ adc_exp = 0x20;
+ }
+ }
+ ADCSRA |= _BV(ADSC);
+#if 0
+ if (led_is_on && adcval != 0xFFEE) {
+ adcval = 0xFFEE;
+
+ ADCSRA |= _BV(ADIF) | _BV(ADIE) | _BV(ADSC);
+ }
+#endif
+}
+
+ISR(TIMER0_COMPA_vect)
+{
+ tmr_handler();
+}
+
+/* ------------ PWM ----------- */
+
+static void inline init_pwm()
+{
+ /* Async clock */
+ PLLCSR = _BV(LSM) | _BV(PLLE);
+ _delay_ms(1);
+ while (PLLCSR & _BV(PLOCK) == 0)
+ ;
+ PLLCSR |= _BV(PCKE);
+
+ TCCR1C = _BV(COM1D0) | _BV(COM1D1) | _BV(PWM1D);
+ TCCR1A = _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(PWM1A) | _BV(PWM1B);
+ // TCCR1B = 0x80| _BV(CS13) | _BV(CS11);
+ TCCR1B = _BV(7) // PWM1X: PWM inversion mode
+ | _BV(CS10) // no clock prescaling
+ ;
+ OCR1C = 0xFF; // TOP value
+ OCR1D = OCR1B = OCR1A = pwmval;
+ // OCR1D = 0;
+ // DDRB |= _BV( PB5 );
+ PORTB &= ~(_BV( PB5 ) | _BV( PB1 ) | _BV( PB3 ));
+
+ // led_off();
+ // TIMSK |= _BV(TOIE1);
+}
+
+#if 0
+static void inline pwm_handler()
+{
+ // TIMSK &= ~_BV(TOIE1);
+ // OCR1D = pwmval;
+}
+
+ISR(TIMER1_OVF_vect)
+{
+ pwm_handler();
+}
+#endif
+
+/* ------------ A/D Converter ----------- */
+
+static void inline init_adc()
+{
+ ADCSRA = _BV(ADEN) // enable
+ | _BV(ADPS1) | _BV(ADPS0) // CLK/8 = 125 kHz
+ // | _BV(ADPS2) // CLK/16 = 62.5 kHz
+ ;
+ ADMUX = _BV(REFS1) // 1.1V internal reference
+ | _BV(MUX4)|_BV(MUX3) // port ADC5-6, gain 1
+ ;
+ // ADCSRB = _BV(REFS2);
+ ADCSRB |= _BV(GSEL);
+ // Disable digital input on all bits used by ADC
+ DIDR0 = _BV(ADC5D)|_BV(ADC6D) | _BV(AREFD);
+ ADCSRA |= _BV(ADIE);
+}
+
+static void inline adc_handler()
+{
+ uint16_t new_pwm = pwmval;
+ uint16_t old_pwm = pwmval;
+ uint16_t old_adc = adcval;
+ adcval = ADCW;
+ adccount++;
+
+ // log_word(((adcval & 0x3FC) << 6) | pwmval);
+ log_word(((adcval & 0xFF) << 8) | pwmval);
+
+ if (!led_is_on)
+ return;
+ // adcval = (adcval + 3*old_adc)/4;
+
+ // ADCSRA &= ~(_BV(ADIE) | _BV(ADIF));
+
+ if (adcval < 1) {
+ adcval = 1;
+ } else if (adcval > adc_exp) {
+ new_pwm = old_pwm*adc_exp/adcval;
+ } else if (adcval < adc_exp && 2 * adcval > adc_exp) {
+ new_pwm = old_pwm*adc_exp/adcval;
+ } else if (adcval < adc_exp) {
+ new_pwm = 2 * old_pwm;
+ }
+
+ new_pwm = (3*old_pwm + new_pwm) / 4;
+ if (new_pwm > 0x60) { // odpojeno?
+ new_pwm = 0x60;
+ }
+ if (new_pwm < 2) { // zkrat?
+ new_pwm = 2;
+ }
+
+ // if (new_pwm < 15*old_pwm/16 || new_pwm > 17*old_pwm/16) {
+ pwmval = new_pwm;
+ OCR1D = pwmval;
+ // }
+ // ADCSRA |= _BV(ADSC);
+}
+
+ISR(ADC_vect)
+{
+ adc_handler();
+}
int main(void)
{
+ init_log();
+
+ init_pwm();
+ init_adc();
+ init_tmr();
+
+ debug_setstate(2);
+
+ sei();
+ while (1)
+ ;// sleep_mode();
+
+#if 0
DDRA |= _BV( PA0 );
while( 1 ) {
PORTA |= _BV( PA0 );
- _delay_ms(2000);
+ _delay_ms(200);
PORTA &=~ _BV( PA0 );
- _delay_ms(2000);
}
+#endif
}