2 #include <util/delay.h>
4 #include <avr/interrupt.h>
9 // init PLL clock for timer/counter 1
10 // datasheet sekce 12.2.1
11 static void enable_pll_clock()
14 PLLCSR = _BV(PLLE) | _BV(LSM); // low-speed mode (32 MHz)
16 // Synchronize to the phase lock
18 while((PLLCSR & _BV(PLOCK)) == 0)
23 // Timer/Counter 1 initialization
25 static void init_tc1()
27 power_timer1_enable();
29 TCCR1 = _BV(CTC1) // clear on compare match
30 | _BV(CS10) // clock = PCK (no divisor)
31 | _BV(COM1A1) // clear output line on compare match
32 | _BV(PWM1A); // PWM mode
34 OCR1C = 255; // TOP value
39 // Tohle pripadne povoli PWM i na OC1B (PB4)
40 // GTCCR = _BV(COM1B1) | _BV(PWM1B);
42 // OCR1B = 0; // stride
45 // Precte synchronne (busy-waitem) jednu hodnotu z A/D prevodniku.
46 // Alternativa je nastavit bit ADSC a ADIE, delat neco jineho,
47 // a pockat az prijde ADC interrupt (viz firmware "step-up" na strance
49 static uint16_t read_adc_sync()
53 ADCSRA |= _BV(ADSC); // start the conversion
55 // wait for the conversion to finish
56 while((ADCSRA & _BV(ADIF)) == 0)
60 ADCSRA |= _BV(ADIF); // clear the IRQ flag
65 // vyber kanalu A/D prevodniku (datasheet tabulka 17-4 v sekci 17.13.1)
66 typedef enum { ADC1, ADC3, ADC4 } adc_channel;
67 static void select_adc_channel(adc_channel c)
71 ADMUX = _BV(REFS1) | _BV(MUX0); // ADC1 (PB2), 1.1V ref
74 ADMUX = _BV(REFS1) | _BV(MUX1) | _BV(MUX0); // ADC3 (PB3), 1.1V ref
77 ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0) // ADC4 (temperature), 1.1V ref
84 // analog to digital converter
86 static void init_adc()
89 ACSR |= _BV(ACD); // enable ADC, disable AC
91 ADCSRA = _BV(ADEN) // enable
92 | _BV(ADPS1) | _BV(ADPS0) // CLK/8 = 125 kHz
95 DIDR0 = _BV(ADC1D) | _BV(ADC3D); // disable dig. input on ADC1, ADC3 (PB2, PB3)
97 select_adc_channel(ADC4);
98 // do the first conversion, drop the result
102 // priklad vselijakych moznosti, co tenhle HW umi
107 init_log(); // viz logging.c - detekce poctu resetu, atd.
109 log_byte(0x42); // zkouska logovani
110 log_flush(); // nezapomenout vylit buffer
112 power_all_disable(); /* vypneme cele I/O, pak zapneme co bude potreba */
114 DDRB |= _BV(DDB4); // PB4 as output (lze misto tohoto pouzit jako PWM)
116 PORTB |= _BV(PB0); // PB0 interni pull-up (aby tady byla 1, pokud je plovak rozepnuty)
122 // po skonceni inicializace muzeme i zapnout preruseni,
123 // pokud je budeme potrebovat
126 // priklad prace s A/D prevodnikemo
127 select_adc_channel(ADC4); // interni teplomer na cipu
128 log_word(read_adc_sync()); // nacteme teplotu cipu, zalogujeme
129 // interpretace vysledku: datasheet sekce 17.12
132 // ve smycce budeme merit jak se meni hodnota na ADC3 (PB3)
133 select_adc_channel(ADC3);
136 // PB4 (motor 2) zapínáme podle sepnutí plováku PB0
137 if (PINB & _BV(PINB0)) { // rozepnuto (1)
138 PORTB &= ~_BV(PORTB4);
139 } else { // sepnuto (0)
140 PORTB |= _BV(PORTB4);
143 // hodnota PWM pro PB1 (OC1A)
144 // jdeme od 128 do 248, napriklad:
145 OCR1A = 0x80 + (i << 3);
147 // busy-wait, nebo se muzeme nechat casovat
148 // pomoci watchdogu (WDT, datasheet sekce 7.4.5)
149 // nebo pomoci Timer/Counter 0 (datasheet sekce 11)
155 log_word(read_adc_sync()); // nacteme hodnotu, zalogujeme