Converting a Digital Pin to Analog

I got sloppy and made some assumptions when I designed a board based upon the Zero. In the Variants file I saw that PA08 (Arduino pin 4) was also analog capable (ADC/AIN[16]). So I went ahead and routed an analog signal to it. Now, it looks like I need to do some non-standard configuration to get that pin to operate as an analog input.

Do I need to do it in the Variants files, or can I do it in my sketch. I'd like to avoid creating a "unique" variants file for my project.

Can this be done?

Has anyone successfully done it?

Any pointers?

Thanks,

John

I tried the following in the Variants files:

#define NUM_ANALOG_INPUTS    (9u)

#define PIN_A8               (4ul)

static const uint8_t A8  = PIN_A8 ;

{ PORTA, 17, PIO_PWM, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM2_CH1, NOT_ON_TIMER, EXTERNAL_INT_1 }, // TCC2/WO[1]

But that didn’t work.

As I was typing his I noticed this:

#define analogInputToDigitalPin(p)  ((p < 6u) ? (p) + 14u : -1)

I need to figure out if that’s the cause behind it not working…

Well, I got lucky.

I couldn't get any of that to work, so I was looking around at mechanically swapping pins (cutting traces, etc.) Looking at my schematic I noticed I hadn't used a couple of the Arduino native AN pins. And... I had actually brought them out to test points for cases just like this. Looks like there'll be at least a rev3 of this board.

However, I'd still like to know how to do this for those times when 8 analogs aren't enough.

Any bright ideas?

Well, I came up with an ugly hack. It is a modified copy of the analogRead function that is in the wiring_analog.c file. Use at your own peril.

void syncADC() {
  while (ADC->STATUS.bit.SYNCBUSY == 1)
    ;
}

uint32_t analogRead_custom( byte adc_channel_number )
{
  uint32_t valueRead = 0;

  syncADC();
  ADC->INPUTCTRL.bit.MUXPOS = adc_channel_number; // Selection for the positive ADC input

  syncADC();
  ADC->CTRLA.bit.ENABLE = 0x01;             // Enable ADC

  // Start conversion
  syncADC();
  ADC->SWTRIG.bit.START = 1;

  // Clear the Data Ready flag
  ADC->INTFLAG.bit.RESRDY = 1;

  // Start conversion again, since The first conversion after the reference is changed must not be used.
  syncADC();
  ADC->SWTRIG.bit.START = 1;

  // Store the value
  while ( ADC->INTFLAG.bit.RESRDY == 0 );   // Waiting for conversion to complete
  valueRead = ADC->RESULT.reg;

  syncADC();
  ADC->CTRLA.bit.ENABLE = 0x00;             // Disable ADC
  syncADC();

  return valueRead;
}