Generar señal con el DAC

Hola buenas tardes.

Soy un aficionado que me he hecho con Arduino DUE por sus salidas DAC.

La cosa es que quiero empezar por generar una señal senoidal simple de unos Hz dados por una variable X, para empezar por ejemplo 1000Hz o 100Hz lo que sea.

El caso es que se crear señales senoidales pero no se como decirle los Hz a los que quiero que la genere.

¿como lo veis?

Muchas gracias de antemano.

Un ejemplo aqui (Atención: ponga al menos una resistencia de 2 KOhms en serie en la salida de cada DAC):

/***********************************************************************************/
/*   DAC0 and DAC1 output of a sin wave - Frequency of sin = 44.1 KHz / sinsize    */
/***********************************************************************************/

const uint32_t sinsize  = 256 ;   // Size of buffer must be a power of 2
uint32_t sinus[2][sinsize];
  
volatile uint32_t bufn;

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];
    DACC->DACC_TNCR = sinsize;
  }
}

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 = 238;  //<*********************  Frequency = (Mck/8)/TC_RC = 44.1 MHz
  TC0->TC_CHANNEL[2].TC_RA = 40;  //<********************   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
}

void setup() {

  for(int i = 0; i < sinsize; i++) 
    {
   uint32_t chsel = (0<<12) | (1<<28);                      // LSB on DAC0, MSB DAC1 !!
   sinus[0][i]  = 2047*sin(i * 2 * PI/sinsize) + 2047;      //  0 < sinus [i] < 4096
   sinus[1][i] = sinus[0][i] |= sinus[0][i] <<16 | chsel;   // two buffers formated
                                                            // MSB [31:16]on channel 1
                                                            // LSB [15:0] on chanel 0
    }
  tc_setup();
  dac_setup();
}

void loop() {

}

Muchas gracias por el ejemplo.

es mucho mas complejo de lo que tenia en mente para empezar.. casi no entiendo nada xD

Le echare un vistazo y cuento experiencias.

¿Habría otra manera mas simple de llevar a cabo el cometido que nos ocupa?

Muchas gracias.

Tienes manejo avanzado y manejo estilo Arduino

Usando

analogWrite(DAC0, value );

puedes controlar que saldrá por el DAC
Tambén puedes usar el DAC1 porque recuerda que tiene 2.
Y se puede controlar la resolución con

analogWriteResolution(12);

Asi que puedes escribir un código simple y ver con el tester/multímetro si entrega lo que deseas.

surbyte:
analogWrite(DAC0, value );
analogWriteResolution(12);

Esto me resulta mas agradable para empezar.

Para crear la Onda usarían algún conteo con millis() por ejemplo y cada tanto sacar por el DAC la salida que se quiera? o lo harian de otra manera?

Si, esa podría ser una forma de ir incrementando la salida o bien puedes tener una tabla de datos y que en cada conteo de millis() cambies el indice y lo redirecciones al DAC.
Asi se generan señales cualquiera.

Tienes un vector con los valores.. digamos 256 o mas, y los vas barriendo a intervalos determinados.
La cantidad de muestras del vector x el intervalo determina el períiodo y su inversa la frecuencia.

Toma este link como ejemplo de lo que digo, ojo, esto es para generar señales por PWM que no es lo mismo que usar un DAC pero usa la idea del vector

http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-dds-sinewave-generator/

Muchas gracias por vuestra ayuda.

al decir lo de los vectores con los valores pre guardados, pensé en hacer una pasada a la función y guardar los valores en una array para así posteriormente ir leyendo los datos en vez de tener de calcularlos cada vez ahorrando tiempo de ejecución y energía.

Ahora poco a poco iré complicando más el asunto.

Gracias.

Justamente esa es la idea. Al no tener que calcular nada ahorras mucho tiempo y te permite generar señales de modo muy rapido y con el nivel de detalle que tu decidas.