ADC interrupt handling question

I’m in the process of creating a sketch to control an AD9851 DDS chip/board, and I’ve come across something very strange. The hardware is an UNO clone (SparkFun RedBoard), a 3 x 4 keypad configured for a single wire analog value, an I2C 20 x 4 LCD, and the AD9851 board.

Individually, the I2C LCD display, the AD9851, and the keypad work fine. All of the testing, using Serial.xxx() shows the expected results. But here is where it gets really strange.

If I use analogRead() to read A1 (where the keypad is connected) everything works fine. I can get the keypad inputs, do the appropriate programming of the AD9851, and show results on the LCD. However, if I use the ADC interrupt instead of analogRead(), the board appears to “hang”.

Here are the various connections: LCD uses SCL & SDA, the AD9851 uses serial programming with D5 through D8, and the keypad uses A1; all with the appropriate VCC & GND connections.

One thing I noticed was the LCD & keypad (using ADC interrupts) work fine until I hook up the AD9851. It appears there is some interaction between A1 and D5-D8 that I am missing. I’m hoping to have someone help me identify what I’m doing incorrectly.

Here is the ADC interrupt setup function:

void setupAdcInt() {
 // NOTE: The order of the following appears to be important.

 // Clear ADLAR then set the reference voltage.
 ADMUX &= ~(1<ADLAR);
 ADMUX |= (1 << REFS0);
 // Clear all MUX bits, then set the analog pin to watch (A1 = MUX 0).
 ADMUX &= ~((1 << MUX3) || (1 << MUX2) || (1 << MUX1) || (1 << MUX0));
 ADMUX |= (1 << MUX0);

 // Set ADEN then ADATE.
 ADCSRA |= (1 << ADEN);
 ADCSRA |= (1 << ADATE);
 // Set free running; ACME unchanged
 ADCSRB &= ~((1 << ADTS2) || (1 << ADTS1) || (1 << ADTS0));
 // Set prescale = 128 then enable interrupts.
 ADCSRA |= (1 << ADPS2) || (1 << ADPS1) | (1 << ADPS0);
 ADCSRA |= (1 << ADIE);

 // NOTE: The order of the preceding appears to be important.

 // Enable global interrupts.
 sei();

 // Kick off the first ADC.
 analogVal = 0;
 readFlag = 0;

 // Set ADSC to start ADC conversion.
 ADCSRA |= (1 << ADSC);
}

Here is the interrupt service function:

ISR(ADC_vect) {
 int valTemp;
 
 // Read low first
 valTemp = ADCL | (ADCH << 8);
 
 // If quiescent, ready to read
 if (valTemp == 0) readFlag = 1;
 
 // If the analog value just read is greater than the previously read, save it.
 // Otherwise ignore it; assuming the key is just being pressed and low pressure
 // might cause the value to be low.
 if (valTemp > analogVal) analogVal = valTemp;
}

Thank you in advance.

  • Mark

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

I just had another thought. Acting on a hunch, I looked at the Amtel 328 spec, and it appears many of the pins have "alternate functions". I'm wondering if I'm running into problems not correctly setting up the pins I want to use for the ADC (A1) and the AD9851 (D5 - D8).

Am I on the right track?

Thanks in advance.

  • Mark

Well it seems the root cause was completely unrelated to the AD9851.

Tracking down an I2C LCD issue (I2C LCD not reliably displaying text), I discovered I needed to add pullup resistors to the I2C lines (SCL & SDA). Moving on the DDS problem, I discovered it was now fixed as well.

So it would see the lack of pullup resistors for the LCD had an undesired impact on the ADC interrupt handling.

Now on to the next sub-module :slight_smile:

Thanks for listening.

  • Mark