SAMD51 Metro M4 ADC Code Help

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, 

I have an adafruit Metro M4 Express board and I would like to learn how to use the ADC. According to their schematics, their "A5" pin is connected to the PB09 pin on the SAMD51, and I believe I am initializing the registers correctly but for some reason, the adc value stays close to around 17 which I believe is around 0V. I have also successfully set up an DAC on a different port and pin. Strangely enough, when I apply voltage to the DAC output pin PA02, the ADC value printed out behaves like I am applying it to the ADC pin. It's a real head scratcher. Also pin PA03 is set up as a voltage reference, this is the "AREF" pin on the Metro M4 Express. I would appreciate any feedback/criticism/replies that would help me. Thanks in advance.

 

void DAC_Init(void)
{
	
	//////////////////////////////////////////////////////////////////////////
	/// DAC CLOCKS INIT
	//////////////////////////////////////////////////////////////////////////
	
	//division factor of 6 for Generic Clock 1 for 48MHz/6 = 8 MegHertz GClock1 Speed
	//GCLK->GENCTRL[1].reg = GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_IDC | GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(1);
	GCLK->GENCTRL[1].reg = GCLK_GENCTRL_SRC_DFLL | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(6);
	
//	GCLK->GENCTRL[1].bit.SRC = 6; // DFLL oscillator
//	GCLK->GENCTRL[1].bit.DIV = 6; // Divide 48 /6 = 8MHz
//	GCLK->GENCTRL[1].bit.GENEN = 1;
	
	
	while ( GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL1 )
	{
		/* Wait for synchronization */
	}
	
	//32-bit register, enable DAC bus clock in Main Clock registers
	MCLK->APBDMASK.bit.DAC_= 1;
	
	// enable gen 1 clock as source for DAC Channel
	GCLK->PCHCTRL[DAC_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK1;
	

		//Now that clock registers are configured, reset the DAC registers and begin configuring DAC
	DAC->CTRLA.bit.SWRST = 1;
	
	//wait for reset to complete, bit will stay high until reset clears the bit
	while(DAC->CTRLA.bit.SWRST);
	
	//Configure DAC0
	DAC->DACCTRL[0].reg =  DAC_DACCTRL_REFRESH(2) | DAC_DACCTRL_CCTRL_CC12M | DAC_DACCTRL_ENABLE;
	
	//Configure DAC1
//	DAC->DACCTRL[1].reg =  DAC_DACCTRL_REFRESH(2) | DAC_DACCTRL_CCTRL_CC12M | DAC_DACCTRL_ENABLE;
	
	//Configure External 3.3V reference. Internal reference does not work
	DAC->CTRLB.reg = DAC_CTRLB_REFSEL_VREFPU;
	//Set to single ended mode
	//DAC->CTRLB.bit.DIFF = 0;
	
	//Continuous run during debug
	DAC->DBGCTRL.bit.DBGRUN = 1;
	
	//ENABLE DACs
	DAC->CTRLA.bit.ENABLE = 1;
	
	//Set pin PA3 as voltage reference input
	PORT->Group[0].PINCFG[3].bit.PMUXEN = 1;
	PORT->Group[0].PMUX[1].bit.PMUXO = 1;
	
	//wait for DACs to be ready
	while(DAC->SYNCBUSY.bit.ENABLE);
//	while(!DAC->STATUS.bit.READY1);
	while(!DAC->STATUS.bit.READY0);
	
	//Set port pins
	// PA02 is A0 on adaruit metro m4 
	PORT->Group[0].PINCFG[2].bit.PMUXEN = 1;
	PORT->Group[0].PMUX[1].bit.PMUXE = 1;
	
}

void ADC_Init(void)
{
	 //////////////////////////////////////////////////////////////////////////
	 ///ADC Clock Config
	 //////////////////////////////////////////////////////////////////////////
	 MCLK->APBDMASK.bit.ADC0_ = 1;
	 GCLK->PCHCTRL[ADC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1 | GCLK_PCHCTRL_CHEN; // enable gen clock 1 as source for ADC channel
	
	// After configuring ADC Clock, reset ADC registers
	ADC0->CTRLA.bit.SWRST = 1;
	
	// Wait for ADC to finish reset, bit will stay high until reset clears the bit
	while(ADC0->CTRLA.bit.SWRST);
	
	//Divide 8MHz clock by 16 to obtain 500kHz clock to adc
	ADC0->CTRLA.reg = ADC_CTRLA_PRESCALER_DIV16;
	
	//Select VDDANA (3.3V chip supply voltage as reference)
	ADC0->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1;
	
	//Choose 12-bit resolution
	ADC0->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT;
	
	//Accumulate 16 samples and average according to table 45-3 before conversion ready to read
	ADC0->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_16 | ADC_AVGCTRL_ADJRES(4);
	
	//Enable ADC
	ADC0->CTRLA.bit.ENABLE = 1;
	
	//wait for ADC to be ready
	while(ADC0->SYNCBUSY.bit.ENABLE);
	
	//Set PB09 or "A5" on Metro M4 as ADC
	PORT->Group[1].PINCFG[9].bit.PMUXEN = 1;
	PORT->Group[1].PMUX[4].bit.PMUXO = 1;
		
}

 

P.S.

Below is my ADC read function, if that helps anything.

 

void ADC0_read(void)
{
	ADC0->SWTRIG.bit.START = 1; //start adc conversion
	while(!ADC0->INTFLAG.bit.RESRDY);	//wait for adc data to be ready
	ADC0_VAL = ADC0->RESULT.reg;	//copy data to variable
}

 

This topic has a solution.
Last Edited: Fri. Apr 12, 2019 - 05:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you apply an analog reference on IOH, pin 3, or close the AREF jumper on the back of the board? If not, analog behavior will be undefined.

Josh @ CIHOLAS Inc - We fill the gaps from chips to apps

Last Edited: Thu. Apr 11, 2019 - 09:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The jumper is closed on the back of the board. I attempted to switch the analog reference to the AREFA but I got the same result: I only get ADC behavior when I apply a voltage to the DAC output "A0", not the intended "A5" pin. Thanks for the reply, I thought that could have solved the issue. Is my pin peripheral multiplexing correct? I understood today how I believe that works.

 

	//Select VDDANA (3.3V chip supply voltage as reference)
	//ADC0->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1;
	
	//Select AREF (tied to 3.3V on Metro M4 when jumper is closed)
	ADC0->REFCTRL.reg = ADC_REFCTRL_REFSEL_AREFA;

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

INPUTCTRL setting is missing.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


I have added this after setting the reference control registers, per Lajon's suggestion, and now the intended pin PB09 ("A5" on the Metro M4) is successfully sampling adc values from 0 to 3.3V. 

Please see the code snippet below for the edited section of the updated ADC init code. See my first post for context. Thanks again, my deepest respects.

 

P.S. Selecting the internal 3.3V chip supply voltage as a reference also works.

 

	//Select VDDANA (3.3V chip supply voltage as reference)
	//ADC0->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1;
	
	//Select AREF (tied to 3.3V on Metro M4 when jumper is closed)
	ADC0->REFCTRL.reg = ADC_REFCTRL_REFSEL_AREFA;
	
	//Select AIN3(PB09) as positive input and gnd as negative input reference, non-diff mode by default
	ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_MUXPOS_AIN3;
	
	//Choose 12-bit resolution
	ADC0->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT;