From: Michel Pollet Date: Wed, 14 Apr 2010 17:15:23 +0000 (+0100) Subject: test: Add a test/example for the ADC subsystem X-Git-Url: http://git.rot13.org/?a=commitdiff_plain;h=6b34bedf4f80f155bee3c3a2fe7b542ee875fbc1;p=simavr test: Add a test/example for the ADC subsystem Loads ADC values, also reads the V1.1 reference voltage of an Atmega644 Signed-off-by: Michel Pollet --- diff --git a/tests/atmega644_adc_test.c b/tests/atmega644_adc_test.c new file mode 100644 index 0000000..0a0c2b3 --- /dev/null +++ b/tests/atmega644_adc_test.c @@ -0,0 +1,106 @@ +/* + atmega644_adc_test.c + + Copyright 2008, 2009 Michel Pollet + + 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 + +/* + * 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, "atmega644"); +AVR_MCU_VOLTAGES(3300, 3300, 3300); // 3.3V VCC, AVCC, VREF + +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 uint16_t adc_val[8]; + +ISR(ADC_vect) +{ + uint8_t mux = ADMUX, l = ADCL, h = ADCH; + uint8_t i = mux & 7; + adc_val[i] = l | (h << 8); + i = (i + 1) & 7; + ADMUX = (mux & 0xF0) | i; + if (i) + ADCSRA |= (1 << ADSC); // restart one now on the new channel +} + +void adc_init() +{ + // set ADC + ADMUX = (1 << REFS0); // use internal AVCC (3.3) + // enable ADC, start a conversion, with the interrupt + // and with a /128 integration clock + ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIE) | 0x5; + // doesn't do anything in simavr for now + DIDR0 = 3; // disable digital on these 2 pins ADC0 and ADC1 +} + +int main(void) +{ + stdout = &mystdout; + + sei(); + printf("Read 8 ADC channels to test interrupts\n"); + + adc_init(); + + /* + * The interupt reads all 8 ADCs then stop... + * so this loop will eventually exits + */ + while (ADCSRA & (1 << ADSC)) + sleep_cpu(); + + printf("All done. Now reading the 1.1V value in pooling mode\n"); + ADCSRA &= ~(1 << ADIE); // remove interrupt + + // 1.1 reference voltage, left aligned + ADMUX = (ADMUX & ~0x1f)| (1 << ADLAR) | 0x1e; + ADCSRA |= (1 << ADSC) ; // start conversion + while (ADCSRA & (1 << ADSC)) + ; + uint16_t v = ADCL | (ADCH << 8); + uint16_t volts = (v * 3300L) >> 10; // div 1024 + printf("Read ADC value %04x = %d mvolts -- ought to be 1098\n", v, volts); + + ADCSRA &= ~(1 << ADEN); // disable ADC... + + cli(); + sleep_cpu(); + +} +