Arduino DUE and optical sensor ADC reading problem

Hi everyone,

I’m trying to use an optical sensor with an Arduino DUE, generating carrier and aquiring analog readings.

First I modulate the signal, generating a square wave with 66% of Duty Cycle at 525 Hz (which drives the emitter) and then I aquire data from the sensor through the ADC of Arduino at 10 ksps and 12-bit resolution. I aquire from a digitalRead the carrier itself, in order to demodulate the signal (and I will filter later). Eventually, I send my data via serial to the pc.

The problem is that my ADC reads the same value (or very similar values) all the time, even if I “create” a disturb on the sensor.
My PWM signal is correct and works good because I tested on a DAQ, the problem is the ADC and its code.

I just can t get the problem and ask you if someone could help me.

Thank you in advance for your time, here is the code:

// ADC 12-bit 10KHZ and PWM 525Hz

#define SampleRate  (10000)
#define nchannels (sizeof(channels))

uint8_t channels[] = {7};
uint8_t i;
uint8_t inPin=22;
uint8_t carrier=0;

uint16_t Buf[nchannels];
uint16_t temp, dat;

//float F_Conv=3.3/4096.0;

volatile boolean FlagConversion;


void setup(){
  
  Serial.begin(500000);
  while(!Serial);
  pwmD4_setup();
  adc_setup();
  tc_setup();
  pinMode(inPin, INPUT); 
}

void loop(){
  
 
  ADC_Handler();
  
  temp = millis();
  
  Serial.print( temp ); Serial.print("\t" );

  carrier = digitalRead(inPin); 
  
  if (FlagConversion == true){    
    
   FlagConversion = false;  
   
   for (int i = 0; i < nchannels-1; i++){      
      dat=carrier*Buf[nchannels-1]; //Demodulation
      Serial.print( dat );Serial.print("\t" );
    }
    
    dat = carrier*Buf[nchannels-1]; //Demodulation
    Serial.println( dat );  
     
  }  

}

// Output 66% duty cycle PWM at 525kHz on digital pins D4 and D5 using TC6
void pwmD4_setup() {
  
  REG_PMC_PCER1 |= PMC_PCER1_PID33;                 // Enable peripheral TC6 (TC2 Channel 0)
  REG_PIOC_ABSR |= PIO_ABSR_P26 | PIO_ABSR_P25;     // Switch the multiplexer to peripheral B for TIOA6 and TIOB6
  REG_PIOC_PDR |= PIO_PDR_P26 | PIO_PDR_P25;        // Disable the GPIO on the corresponding pins

  REG_TC2_CMR0 = TC_CMR_BCPC_SET |                  // Set TIOB on counter match with RC0
                 TC_CMR_ACPC_SET |                  // Set TIOA on counter match with RC0
                 TC_CMR_BCPB_CLEAR |                // Clear TIOB on counter match with RB0
                 TC_CMR_ACPA_CLEAR |                // Clear TIOA on counter match with RA0
                 TC_CMR_WAVE |                      // Enable wave mode
                 TC_CMR_WAVSEL_UPDOWN_RC |          // Count up with automatic trigger on RC compare !PHASE_CORRECT!
                 TC_CMR_EEVT_XC0 |                  // Set event selection to XC0 to make TIOB an output
                 TC_CMR_TCCLKS_TIMER_CLOCK4;        // Set the timer clock to TCLK4: /128 (MCK/128 = 84MHz/128 = 656250Hz)

  REG_TC2_RA0 = 416;                               // Load the RA0 register 66%DT 
  REG_TC2_RB0 = 0;                                 // Load the RB0 register : --
  REG_TC2_RC0 = 624;                               // Load the RC0 register as 656250/624/2(per la phase-corr)=525Hz

  REG_TC2_CCR0 = TC_CCR_SWTRG | TC_CCR_CLKEN;       // Enable the timer TC6

}

/*************  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_PRESCAL(1) |
                  ADC_MR_TRGSEL_ADC_TRIG3 |              // Trigger by TIOA2 Rising edge
                  ADC_MR_LOWRES_BITS_12;                 // Risol 12bit

  ADC->ADC_IDR = ~(0ul);
  ADC->ADC_CHDR = ~(0ul);
  
  for (int i = 0; i < nchannels; i++){    
    ADC->ADC_CHER |= ADC_CHER_CH0 << channels[i];    
  }
  
  ADC->ADC_IER |= ADC_IER_EOC0 << channels[nchannels - 1];
  //ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequencies > 500 KHz
  ADC->ADC_PTCR |= ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS;    // Disable PDC DMA
  NVIC_EnableIRQ(ADC_IRQn);                              // Enable ADC interrupt

}

/*************  Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2  ************/
void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                       // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2   // MCK/8, 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 TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match


  TC0->TC_CHANNEL[2].TC_RC = F_CPU / 8 / SampleRate; //<*********************  Frequency = (Mck/8)/TC_RC  Hz = 10000 Hz
  TC0->TC_CHANNEL[2].TC_RA = 100;  //<********************   Any Duty cycle in between 1 and (TC_RC - 1)

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable

}

void ADC_Handler() {

  for (int i = 0; i < nchannels; i++){    
    Buf[i] = (uint16_t) *(ADC->ADC_CDR + channels[i]);      
  } 
   FlagConversion = true;
   
}

Luigi

In your sketch, nchannels = 1. What is the value of nchannels - 1 ?

Thank you for your reply, channel-1 is 0 and the for loop with channel-1 is like void now (I should have commented it), because I will have to mesure more analog inputs later, but now I am just using the code part after the for loop in the main, for the print.

I don't think that that is the problem because if I comment it, it doesen't change anything.

Test your code stepwise:

Write a code to read a single ADC channel at the right pace, what result do you get ?

I tried to do so, actually i didn’t understand what you meant, I just used the same code but with only a channel (with no for loop and so on).

Now I have always 0 as input, do you have any suggestions? I have checked if it is a problem of the sensor or circuitry what on a DAQ and it shows “correct data”. I think that there is a problem in the code that I can’t spot

Thank you in advance!

// ADC 12-bit 10KHZ and PWM 525Hz

#define SampleRate  (10000)

uint8_t channel = 7;
uint8_t i;
uint16_t Buf;
uint16_t temp;

//float F_Conv=3.3/4096.0;


void setup(){
  
  Serial.begin(460800);
  while(!Serial);
  pwmD4_setup();
  adc_setup();
  tc_setup();
}

void loop(){

  temp = millis();
  Serial.print( temp ); Serial.print("\t" ); 
  Buf= (uint16_t) *(ADC->ADC_CDR + channel);         
  Serial.println( Buf );  

}

// Output 66% duty cycle PWM at 525kHz on digital pins D4 and D5 using TC6
void pwmD4_setup() {
  
  REG_PMC_PCER1 |= PMC_PCER1_PID33;                 // Enable peripheral TC6 (TC2 Channel 0)
  REG_PIOC_ABSR |= PIO_ABSR_P26 | PIO_ABSR_P25;     // Switch the multiplexer to peripheral B for TIOA6 and TIOB6
  REG_PIOC_PDR |= PIO_PDR_P26 | PIO_PDR_P25;        // Disable the GPIO on the corresponding pins

  REG_TC2_CMR0 = TC_CMR_BCPC_SET |                  // Set TIOB on counter match with RC0
                 TC_CMR_ACPC_SET |                  // Set TIOA on counter match with RC0
                 TC_CMR_BCPB_CLEAR |                // Clear TIOB on counter match with RB0
                 TC_CMR_ACPA_CLEAR |                // Clear TIOA on counter match with RA0
                 TC_CMR_WAVE |                      // Enable wave mode
                 TC_CMR_WAVSEL_UPDOWN_RC |          // Count up with automatic trigger on RC compare !PHASE_CORRECT!
                 TC_CMR_EEVT_XC0 |                  // Set event selection to XC0 to make TIOB an output
                 TC_CMR_TCCLKS_TIMER_CLOCK4;        // Set the timer clock to TCLK4: /128 (MCK/128 = 84MHz/128 = 656250Hz)

  REG_TC2_RA0 = 416;                               // Load the RA0 register 66%DT 
  REG_TC2_RB0 = 0;                                 // Load the RB0 register : --
  REG_TC2_RC0 = 625;                               // Load the RC0 register as 656250/624/2(per la phase-corr)=525Hz

  REG_TC2_CCR0 = TC_CCR_SWTRG | TC_CCR_CLKEN;       // Enable the timer TC6

}

/*************  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_PRESCAL(1) |
                  ADC_MR_TRGSEL_ADC_TRIG3 |              // Trigger by TIOA2 Rising edge
                  ADC_MR_LOWRES_BITS_12;                 // Risol 12bit

  ADC->ADC_IDR = ~(0ul);
  ADC->ADC_CHDR = ~(0ul);
   
  ADC->ADC_IER |= ADC_IER_EOC0 << channel;
  //ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequencies > 500 KHz
  ADC->ADC_PTCR |= ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS;    // Disable PDC DMA
  NVIC_EnableIRQ(ADC_IRQn);                              // Enable ADC interrupt

}

/*************  Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2  ************/
void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                       // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2   // MCK/8, 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 TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match


  TC0->TC_CHANNEL[2].TC_RC = F_CPU / 8 / SampleRate; //<*********************  Frequency = (Mck/8)/TC_RC  Hz = 10000 Hz
  TC0->TC_CHANNEL[2].TC_RA = 20;  //<********************   Any Duty cycle in between 1 and (TC_RC - 1)

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable

}