Hi.
For me it has appeared a surprise that it is impossible
to avoid start ADC at transition in a idle state (needed
to reduce power consumption). MCU is ATmega168 (and 48).
It was tryed:
1. Disable ADC interrapt enable: ADIE==0
2. No clear ADC ready: ADIE==0, ADIF==1
3. (!) Auto Trigger Mode: ADATE==1 (with timer source)
==> No results: ADC starts with each 'sleep' instruction.
Certainly, the disabling of interruption (ADIE=0) limits
quantity of starts, but it is no matter, when external
interruptions act in the casual manner. To stop ADC it is
impossible: it is switched off internal AREF.
The most insulting, that in Auto Trigger mode it is
impossible to obtain a regular period.
I attach a small test of this. I shall be grateful,
if somebody will try on other ATmega.
Thanks,
Dmitry.
/* t_ademo.c
Is it possible to avoid an ADC start in Idle mode?
This program has been tested with ATmega168. Test cases 1,2 and 3 give
a negative result: ADC is started.
*/
#define ADCSRA_PS 5 /* Prescaler Selector, 5 for 4MHz/32 */
#define ADC_DIVFAC 32 /* Division factor */
#define ADMUX_BYTE 0x0F /* External AREF, GND chan */
#define BUFSIZE 100 /* Message buffer size */
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#ifndef SMCR /* Sleep Control Register */
# define SMCR MCUCR
#endif
static char msg[BUFSIZE];
#ifndef SIG_OUTPUT_COMPARE1A
# error
#endif
__attribute__((naked))
void SIG_OUTPUT_COMPARE1A (void)
{
asm volatile ("reti");
}
static int test (void)
{
int tm;
/* Initalize. */
TCCR1B = 1;
ADMUX = ADMUX_BYTE;
ADCSRA = 1<<ADEN | 1<<ADIF | ADCSRA_PS;
/* Check ADC settings. */
tm = TCNT1;
ADCSRA |= 1<<ADSC;
do {} while (bit_is_set (ADCSRA, ADSC));
if (bit_is_clear (ADCSRA, ADIF)) {
snprintf (msg, sizeof(msg), "ADIF is't set");
return __LINE__;
}
tm = TCNT1 - tm;
if (tm < 25 * ADC_DIVFAC || tm > 28 * ADC_DIVFAC) {
snprintf (msg, sizeof(msg), "Wrong conversion time: %d", tm);
return __LINE__;
}
ADCSRA |= 1<<ADIF;
if (bit_is_set (ADCSRA, ADIF)) {
snprintf (msg, sizeof(msg), "ADIF is't clear");
return __LINE__;
}
/* For timer interrupts. */
SMCR = 1<<SE;
asm volatile ("sei");
OCR1A = TCNT1;
TIFR1 = 1<<OCF1A;
TIMSK1 = 1<<OCIE1A;
/* 1. Check ADIE==0. */
tm = TCNT1;
OCR1A = tm + 5 * ADC_DIVFAC; /* to middle of conversion */
asm volatile ("sleep");
tm = TCNT1 - tm;
/// if (0) /* uncomment to skip test case */
if (bit_is_set (ADCSRA, ADSC)) {
snprintf (msg, sizeof(msg), "ADC starts with ADIE==0");
return __LINE__;
}
if (tm < 5 * ADC_DIVFAC || tm > 6 * ADC_DIVFAC) {
snprintf (msg, sizeof(msg), "Wrong interrupt: %d", tm);
return __LINE__;
}
do {} while (bit_is_set (ADCSRA, ADSC));
/* 2. Check ADIF==1, ADIE==0. */
tm = TCNT1;
OCR1A = tm + 5 * ADC_DIVFAC; /* to middle of conversion */
asm volatile ("sleep");
tm = TCNT1 - tm;
/// if (0) /* uncomment to skip test case */
if (bit_is_set (ADCSRA, ADSC)) {
snprintf (msg, sizeof(msg), "ADC starts with ADIF==1, ADIE==0");
return __LINE__;
}
if (tm < 5 * ADC_DIVFAC || tm > 6 * ADC_DIVFAC) {
snprintf (msg, sizeof(msg), "Wrong interrupt: %d", tm);
return __LINE__;
}
do {} while (bit_is_set (ADCSRA, ADSC));
/* 3. Check Auto Trigger, ADIE==0. */
ADCSRB = 4; /* TCNT0 Overflow */
ADCSRA |= 1<<ADATE | 1<<ADIF;
tm = TCNT1;
OCR1A = tm + 5 * ADC_DIVFAC; /* to middle of conversion */
asm volatile ("sleep");
tm = TCNT1 - tm;
/// if (0) /* uncomment to skip test case */
if (bit_is_set (ADCSRA, ADSC)) {
snprintf (msg, sizeof(msg), "ADC starts in ADATE case");
return __LINE__;
}
if (tm < 5 * ADC_DIVFAC || tm > 6 * ADC_DIVFAC) {
snprintf (msg, sizeof(msg), "Wrong interrupt: %d", tm);
return __LINE__;
}
do {} while (bit_is_set (ADCSRA, ADSC));
/* 4. Test of test. ADEN==0, must work! */
ADCSRA &= ~1<<ADEN;
tm = TCNT1;
OCR1A = tm + 5 * ADC_DIVFAC; /* to middle of conversion */
asm volatile ("sleep");
tm = TCNT1 - tm;
if (bit_is_set (ADCSRA, ADSC)) {
snprintf (msg, sizeof(msg), "ADC starts without ADEN ???");
return __LINE__;
}
if (tm < 5 * ADC_DIVFAC || tm > 6 * ADC_DIVFAC) {
snprintf (msg, sizeof(msg), "Wrong interrupt: %d", tm);
return __LINE__;
}
return 0;
}
/* --------------------------------------------------------------------
Modify below for yours system.
Periphery (such as serial i/o) initialization -- after test run.
*/
#include "t_ademo.h"
int main ()
{
int i;
pio_init (); /* set pins (PORT*,DDR*) */
if (crc16_allprog ()) {
DDRD |= 1<<PD_TXD;
for (;;) PORTD ^= 1<<PD_TXD;
}
i = test ();
Minit ();
t_init ();
asm volatile ("sei");
if (i) {
t_msg ("*** At line %d: %s\n", i, msg);
return 1;
} else {
t_msg ("OK\n");
return 0;
}
}
/* -------------------- end of file ----------------------------------- */
_______________________________________________
AVR-chat mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/avr-chat