/* atmega88_ac_test.c Copyright 2017 Konstantin Begun This file is part of simavr. simavr is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. simavr is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with simavr. If not, see . */ #include #include #include #include #include #include /* * This demonstrate how to use the avr_mcu_section.h file * The macro adds a section to the ELF file with useful * information for the simulator */ #include "avr_mcu_section.h" AVR_MCU(F_CPU, "atmega88"); static int uart_putchar(char c, FILE *stream) { if (c == '\n') uart_putchar('\r', stream); loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = c; return 0; } static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); volatile uint8_t int_done; ISR(ANALOG_COMP_vect) { int_done = 1; } ISR(TIMER1_CAPT_vect) { int_done = 2; } static inline void output_value() { putchar(ACSR & _BV(ACO) ? '1':'0'); } static inline void output_test(uint8_t expected) { putchar(int_done == expected ? 'Y':'N'); } int main(void) { stdout = &mystdout; sei(); ACSR = 0; printf("Check analog comparator with polling values\n"); // check all the inputs for(uint8_t t = 0; t < 2; ++t) { // run twice, first with AIN0, second with bandgap ADCSRB = 0; // multiplexer off _NOP(); // for sync delay output_value(); // now with multiplexer ADCSRB = _BV(ACME); _NOP(); for(uint8_t i = 0; i < 8;++i) { // this is relying that all 3 mux bits are next to each other, which is the case for atmega88 output_value(); ADMUX += _BV(MUX0); _NOP(); } // switch to bandgap ACSR |= _BV(ACBG); _NOP(); } putchar('\n'); // check interrupts printf("Check analog comparator interrupts\n"); // in this test bandgap is expected to be above ADC0 and below ADC1 ADCSRB = _BV(ACME); ADMUX = 0; // ADC0 ACSR = _BV(ACBG) | _BV(ACIE) | _BV(ACI); // enable interrupts on output triggering // switch to ADC1 int_done = 0; ADMUX = _BV(MUX0); _delay_us(500); output_test(1); // back to ADC0 int_done = 0; ADMUX = 0; _delay_us(500); output_test(1); // change to trigger on falling edge ACSR = _BV(ACBG) | _BV(ACIE) | _BV(ACI) | _BV(ACIS1); // switch to ADC1 (falling edge) int_done = 0; ADMUX = _BV(MUX0); _delay_us(500); output_test(1); // switch to ADC0 (rising edge) int_done = 0; ADMUX = 0; _delay_us(500); output_test(0); // expect no interrupt // change to trigger on rising edge ACSR = _BV(ACBG) | _BV(ACIE) | _BV(ACI) | _BV(ACIS1) | _BV(ACIS0); // switch to ADC1 (falling edge) int_done = 0; ADMUX = _BV(MUX0); _delay_us(500); output_test(0); // expect no interrupt // switch to ADC0 (rising edge) int_done = 0; ADMUX = 0; _delay_us(500); output_test(1); putchar('\n'); // now check timer1 input capture printf("Check analog comparator triggering timer capture\n"); // setup AC for rising edge, disable comparator own interrupt and enable timer1 capture ACSR = _BV(ACBG) | _BV(ACIC) | _BV(ACIS1) | _BV(ACIS0); // now set up timer to capture on rising edge TCCR1A = 0; TCNT1 = 5555; TIMSK1 = _BV(ICIE1); // enable capture interrupt TCCR1B = _BV(ICES1) | _BV(CS10); // switch to ADC1 (falling edge) int_done = 0; ADMUX = _BV(MUX0); _delay_us(500); output_test(0); // expect no interrupt // switch to ADC0 (rising edge) int_done = 0; ADMUX = 0; _delay_us(500); output_test(2); cli(); sleep_cpu(); }