Begin to sample a sine wave from phase angle 0

Hi everyone.

Pardon my english.

The problem: I am utilizing the AD9850 sine wave generator to input a wave into the Arduino Due ADC and I want to sample this signal beginning from phase angle 0.

I was able to get a code from the community to convert the signal using the DMA, but it always sample beginning at an arbitrary point of the wave, which is expected.

The solution I've come: build a pulse generation from a zero crossing circuit and use digital ports to put an ADC convertion starting point.

The question: Is there any solution that do not involve extra hardware such as the solution I said?

I hope you have understand the point and I thank in advance.

The ADC comparison window feature (chap 43.6.7) can trigger an interrupt when the input voltage crosses a threshold:
The ADC Controller features automatic comparison functions. It compares converted values to a low threshold or a
high threshold or both, according to the CMPMODE function chosen in the Extended Mode Register (ADC_EMR).

Let's say the input sin wave swings around e.g. 1.65 V and you set a low threshold at 1.4 and an high threshold at 1.6. When an interrupt is triggered, you test whether it's due to the high or the low threshold to determine if the sin wave is going to cross the 0° phase ( and you trigger the sampling) or the 180° phase.

I thank you for your response ard_newbie
I get it, interesting feature.

Let me explain a little bit further my needs.
Actually I need to sample with a pre-set sampling frequency.
This sampling I already can do, with codes you supplied in other topics.

I found this code to set this interrupt.

ADC->ADC_EMR = ADC_EMR_CMPMODE_IN                   // Generates an event when the converted data[color=#222222][/color]
                                                       //is out of the comparison window.[color=#222222][/color]
                 | ADC_EMR_CMPSEL(7)                    // Compare channel 7 = A0[color=#222222][/color]
[color=#222222][/color]
  ADC->ADC_CWR = ADC_CWR_LOWTHRES(2047) | ADC_CWR_HIGHTHRES(2050); // Compare with a high and low thresholds of conversion

This interrupt I can set to initiate this sampling? How to do so? In my beginner understanding (may be wrong) I would read a ON state from some register yet to be found (I think is ADC_ISR_COMPE) and start the sampling.

I'm not a great master on microcontrollers, so I ask for some help.

EDIT
When I use ADC -> ADC_IER = ADC_IER_COMPE, the conversion stops. Maybe because I have already set an interrupt? How it works?

I am working on a phase sensitive detector.
I am generating a sine wave with the DAC and sampling it with the ADC.
Both utilize the DMA/PDC.

It outputs the amplitude and phase, as you may know.
The goal here is to sample at phase 0° to an application.

I tried to test the code you given, but was unable to get good results.
I input the sine wave, put a threshold and nothing happened.
I should be missing something.
Question: This interrupt can be done with the PDC/DMA?

I tried this code.
It is outputting a 6 kHz sine wave.
The flag is always FALSE.

#include <math.h>
const uint32_t sinsize  = 128 ;   // Size of buffer must be a power of 2, DAC samples
volatile boolean Flag;
int k;
int count[360];
//Aliasing sampling is F/1.25

//DACC variables
uint32_t sinus[2][sinsize];  //Sine wave from DAC
volatile uint32_t bufn;

void setup() {
  //DAC output
  for (int16_t i = 0; i < sinsize; i++)
  {
    uint32_t chsel = (0 << 12) | (1 << 28);                  // LSB on DAC0, MSB on DAC1 !!
    sinus[0][i]  = 2047 * sinf(i * 2 * PI / sinsize) + 2047;  //  0 < sinus [i] < 4096
    sinus[1][i] = sinus[0][i] |= sinus[0][i] << 16 | chsel;  // two buffers formated
  }
  
  tc_dac_setup();
  dac_setup();
  
  Serial.begin(115200);                      // Serial port baudrate
}

void loop() {
  count[k] = Flag;
  k=k+1;

for (int i = 0; i < 360; i++)
{
  Serial.println(count[k]); 
}
if (Flag == true)
  {
    Flag = false;
  //Do something
  }
}

void dac_setup () {

  PMC->PMC_PCER1 = PMC_PCER1_PID38;     // DACC power ON
  DACC->DACC_CR = DACC_CR_SWRST ;       // Reset DACC

  DACC->DACC_MR = DACC_MR_TRGEN_EN                   // Hardware trigger select
                  | DACC_MR_TRGSEL(0b011)            // Trigger by TIOA2
                  | DACC_MR_TAG_EN                   // enable TAG to set channel in CDR
                  | DACC_MR_WORD_WORD                // write to both channels
                  | DACC_MR_REFRESH (1)
                  | DACC_MR_STARTUP_8
                  | DACC_MR_MAXS;

  DACC->DACC_IER |= DACC_IER_TXBUFE;                 // Interrupt used by PDC DMA

  DACC->DACC_ACR = DACC_ACR_IBCTLCH0(0b10)
                   | DACC_ACR_IBCTLCH1(0b10)
                   | DACC_ACR_IBCTLDACCORE(0b01);

  NVIC_EnableIRQ(DACC_IRQn);                         // Enable DACC interrupt

  DACC->DACC_CHER = DACC_CHER_CH0                    // enable channel 0 = DAC0
                    | DACC_CHER_CH1;                 // enable channel 1 = DAC1

  /*************   configure PDC/DMA  for DAC *******************/

  DACC->DACC_TPR  = (uint32_t)sinus[0];         // DMA buffer
  DACC->DACC_TCR  = sinsize;
  DACC->DACC_TNPR = (uint32_t)sinus[1];         // next DMA buffer (circular buffer)
  DACC->DACC_TNCR = sinsize;
  bufn = 1;
  DACC->DACC_PTCR = DACC_PTCR_TXTEN;            // Enable PDC Transmit channel request

}

void DACC_Handler() {

  uint32_t status = DACC->DACC_ISR;   // Read and save DAC status register
  if (status & DACC_ISR_TXBUFE) {     // move DMA pointer to next buffer
    bufn = (bufn + 1) & 1;
    DACC->DACC_TNPR = (uint32_t)sinus[bufn];
    //Flag = true;
    DACC->DACC_TNCR = sinsize;
  }
}

void tc_dac_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_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 TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match


  TC0->TC_CHANNEL[2].TC_RC = 14;  //<*********************  Frequency = (Mck/8)/TC_RC = 44.1 MHz
  TC0->TC_CHANNEL[2].TC_RA = 7;  //<********************   Any Duty cycle in between 1 and TC_RC

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable
}
/*************  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_FREERUN_ON                     // ADC in free running
                  | ADC_MR_LOWRES_BITS_12               // 12 bits resolution
                  | ADC_MR_PRESCAL(1)
                  | ADC_MR_SETTLING_AST3
                  | ADC_MR_TRACKTIM(10)
                  | ADC_MR_TRANSFER(2);

  ADC->ADC_EMR = ADC_EMR_CMPMODE_HIGH                   // Compare with high threshold
                 | ADC_EMR_CMPSEL(7)                    // Compare channel 7 = A0
                 | ADC_EMR_CMPFILTER(10);               // Number of consecutive compare events necessary
                                                        // to raise the flag = CMPFILTER+1                                                     
  ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequencies > 500 KHz                                                     

  ADC->ADC_CWR = ADC_CWR_HIGHTHRES(3000);               // Compare with a high threshold of conversion

  ADC->ADC_CHER = ADC_CHER_CH7;                         // Enable Channel 7 = A0

  ADC->ADC_IER = ADC_IER_COMPE;                         // Interrupt on Compare match enable
  NVIC_EnableIRQ(ADC_IRQn);                             // Enable ADC interrupt
}

void ADC_Handler() { // One Comparison Event has occurred since the last read of ADC_ISR.

  ADC->ADC_ISR;      // Read ADC_ISR;
  ADC->ADC_CDR[7];   // Maybe should be read to allow next interrupt
  // Do some stuff (keep this as short as possible, e.g. set a flag to be proceed in loop())
  Flag = true;                         
}

Note that DAC output is within 1/6 * 3.3V and 5/6 * 3.3V. I guess the 4000 threshold ( ~ 3V) is never reached …

If you need a DAC full swing (0V <-> 3.3V), you will have to add some hadware (Search in the DUE sub forum for the components needed for that).