Go Down

Topic: Arduino DUE ADC - Differential (Read 495 times) previous topic - next topic

talafghani

Hello,

I am using a DUE in order to utilize it's differential ADC to measure from a PCB meant to sense pH changes. However, my code below is not giving me the proper voltage difference when applying a voltage between the analog terminals A0 and A1. For example, if I apply 1.5V on one terminal and 2.5V on the other I do not get 1V (doesn't have to be exact).

Unfortunately, my experience with programming the SAM is terrible, I have never used it before, thus any help modifying the code is appreciated!


void setup()
{


  adc_setup();
  Serial.begin(9600);
}


void loop()
{
  //float Diff67Value;
  int16_t Diff67Value;
  Diff67Value =  ADC->ADC_LCDR;
  float Diff = Diff67Value * 3.3/4095.0;
 
 
  Serial.println(Diff);
  //Serial.println(Diff67Value *3.3/4095);
  //Serial.println(Diff67Value);
 
}


void adc_setup() {
adc_set_resolution(ADC, ADC_12_BITS);
  PMC->PMC_PCER1 |= PMC_PCER1_PID37;      // ADC power on
  ADC->ADC_CR = ADC_CR_SWRST;            // Reset ADC

  ADC->ADC_MR |=  ADC_MR_FREERUN
                  | ADC_MR_ANACH_ALLOWED; 
  ADC->ADC_COR =  ADC_COR_DIFF7 // Differential mode for channel 7 and channel 6 (6 - 7); Gain = 0.5;
                 
                  | ADC_COR_DIFF6
                  | ADC_COR_OFF6  // Offset is mandatory
                  | ADC_COR_OFF7;

  ADC->ADC_CHER |=  ADC_CHER_CH6 | ADC_CHER_CH7; // Enable Channels 7,6 = A0,A1 

}

ard_newbie

This sketch should work better (1 KHz ADC conversions , ADC fully differential between A0(CH7) and A1(CH6)):

Code: [Select]

/***********************************************************************************************/
/*   Differential mode for analog channels 6 and 7, hardware trigger by TCO channel 2 = TIOA2  */
/*                     ADC  Conversion frequency = 1 KHz                                       */
/***********************************************************************************************/

#define ADC_REFERENCE_VALUE (3.3)
#define ADC_12BIT_FULL_SCALE_VALUE (4095)

volatile uint16_t Result6_7;
volatile boolean Flag;

void setup()
{
  Serial.begin(250000);

  adc_setup();
  tc_setup();
}
void loop()
{
  float Result;
  if (Flag)
  {
    Flag = false;
    Result = Result6_7 * (float)ADC_REFERENCE_VALUE / (float)ADC_12BIT_FULL_SCALE_VALUE;
    Serial.println(Result);
  }
}

/*************  Configure ADC function  *******************/
void adc_setup() {

  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                    // ADC power on
  ADC->ADC_CR = ADC_CR_SWRST;                           // Reset ADC

  ADC->ADC_MR |=  ADC_MR_TRGEN_EN |                     // Hardware trigger select
                  ADC_MR_TRGSEL_ADC_TRIG1 |             // Trigger by TIOA0 rising edge
                  ADC_MR_LOWRES_BITS_12 |
                  ADC_MR_SLEEP_NORMAL |
                  ADC_MR_PRESCAL(1) |
                  ADC_MR_STARTUP_SUT0 |
                  ADC_MR_SETTLING_AST9 |
                  ADC_MR_ANACH_ALLOWED |
                  ADC_MR_TRACKTIM(10) |
                  ADC_MR_TRANSFER(2) |
                  ADC_MR_USEQ_NUM_ORDER;

  //Differential mode for channels 7 and 6 (6 - 7); Gain = 0.5
  //AD7 will be automatically enabled for differential operation
  ADC->ADC_COR = ADC_COR_DIFF6 |
                 ADC_COR_OFF6;

  //ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);   // Only if 1 MHz > conversion frequency > 500 KHz

  ADC->ADC_IER = ADC_IER_EOC6;

  NVIC_EnableIRQ(ADC_IRQn);
  ADC->ADC_CHER |= ADC_CHER_CH6 | ADC_CHER_CH7;    // Enable Channels 7,6 = A0,A1
}
/*************  Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0  ************/
void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                       // Timer Counter 0 channel 0 IS TC0

  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1   // MCK/2, clk on rising edge
                              | TC_CMR_WAVE                // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA0 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA0 on RC compare match

  TC0->TC_CHANNEL[0].TC_RC = 42000;  //<*********************  Frequency = (Mck/2)/TC_RC = 1KHz
  TC0->TC_CHANNEL[0].TC_RA = 20;  //<********************   Duty cycle = (TC_RA/TC_RC) * 100  %

  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Reset TC0 counter and enable
}

void ADC_Handler(void)
{
  //Result can be read either from the ADC->ADC_LCDR or from ADC->ADC_CDR[6],
  //But EOC6 bit is cleard only after reading ADC-ADC_CDR[6] (contrary to what states the datasheet !)
  //You want to read ADC_CDR to make the interrupt fired again and again
  Result6_7 = ADC->ADC_CDR[6];
  Flag = true;
}


Go Up