ADMUX register oddity

I'm developing a very simple application for the ATTiny85, which uses ADC channel 2. If I set the ADMUX register with

ADMUX = (1<<REFS2)|(1<<REFS1)|(1<<0x2);

it works fine. But if I use the macro for MUX2 it doesn't

ADMUX = (1<<REFS2)|(1<<REFS1)|(1<<MUX2); 

This despite MUX2 being defined in /usr/lib/avr/include/avr/iotn85.h as

#define ADMUX   _SFR_IO8(0x07)
...
#define MUX2    2
...

What's going on here?

Please show the error message.

Print out the hex value of ADMUX in both cases.

Error message? Where from? I just change the code, compile and write it to the chip - other than build errors there is nothing in my toolchain that can provide any kind of error message. When setting (1<<0x02) in ADMUX ADC2 on PB4 works; when setting (1<<MUX2) instead it doesn't.

How? Where? On an ATMega I could hook up a display but the ATTIny has too few pins.

The full code of my initADC function is:

void initADC(void) {
  // Enable ADC w. prescaler 128, conversion complete interrupt enabled
  ADCSRA = (1<<ADEN)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
  // Select internal ref (2.56 V), ADC channel 2
  ADMUX = (1<<REFS2)|(1<<REFS1)|(1<<0x2);
  // Disable digital input buffer on ADC2
  DIDR0 = (1<<ADC2D);
}

Some cores allow you to print to the serial console from an attiny85. You may have to reduce your code to the basics necessary to demonstrate the problem.

Other than swapping (1<<0x02) to (1<<MUX2) I make no other change. This stops ADC2 from capturing any values. The rest of the code still works. I hoped perhaps someone would recognise this issue. Seems quite odd.

I compile with avr-gcc like so:

avr-gcc -Wall -Wno-multichar -Wno-overflow -Wno-unknown-pragmas -Os -mmcu=attiny85 -DF_CPU=8000000  -o myapp.bin myapp.c

Use some error check or warning like (untested)
#warning "MUX2 = " MUX2
#if (MUX2 != 2) #error MUX2

If I put at the end of my makefile:

$(warning MUX2 is $(MUX2))

the output is

Makefile:30: MUX2 is 

So, nothing? I tried changing it to a known working macro:

$(warning OCIE0B is $(OCIE0B))

but still nothing:

Makefile:30: OCIE0B is

I know that OCIE0B is 0x03 because my TIMER1_COMPB_vect ISR fires correctly, so I'm probably not printing this correctly? If I put the #warning in my c file:

myapp.c:19:2: warning: #warning "MUX2 = " MUX2 [-Wcpp]
 #warning "MUX2 = " MUX2

Are you using ATTinyCore? If not, which one you are using?

Check the data sheet say ATtiny85 ADC tutorial with interrupts - Gadgetronicx
You have to set the whole MUX[3:0]
This probably won't do what you want: (1<<MUX2)

1 Like

I'm using plain AVR c. I realise this means I'm in the wrong forum, but I thought I'd take the chance that someone might recognise the issue regardless.

Aha! This sounds promising. One moment.

Edit: Uuuuh... how do you set the other three to 0? Other than computing the whole register value and doing e.g. `ADMUX = 0x92;"? I always thought not setting a bit would mean it is zero?

Add
#define MUX2 2
to produce an error by redefinition or fix a missing definition.

The datasheet says:

The MUX[3:0] and REFS[2:0] bits in the ADMUX Register are single buffered through a temporary register to which the CPU has random access.

And the full definition is:

If I read that correctly, to use internal 2.65 V reference without external capacitor and enable ADC channel #2 I should set the following bits (yes, they are in a weird order):

REFS1	REFS0	ADLAR	REFS2	MUX3	MUX2	MUX1	MUX0
  1       0       0       1      0       1       0       0

Or in other words 0b10010100, or 0x94. But this does not work. Curiously this has MUX2 defined as 4, while iotn85.h defines it as 2. Setting ADMUX to 0x92 does indeed work the same as my earlier configuration. Am I reading the datasheet incorrectly?

Do you simply want to use ADC channel 2 in the normal single conversion mode ?
Then it is MUX1 you want to set, not MUX2.

You can use "placeholder" notation like:

ADMUX = (1<<REFS2)|(0<<REFS1)|(0<<ADLAR) | (1<<MUX1)

1 Like

Ha! There it is! How confusing. Thank you, I can confirm that this works:

ADMUX = (1<<REFS2)|(1<<REFS1)|(1<<MUX1);