How to manipulate control registers

I am working on a project which requires me to occasionally disable all output from the DAC, and I am wondering how to do this. I know that the output of the DAC is ~ 0.5-2.75V, but on powerup the DAC sits at 0V until a write command is used.

As I was reading through this article it seems that control register DACC_CR can be used to perform a reset on the DAC, which seems like it would bring it back down to 0V until a new write is initiated. This would be perfect for what I'm looking to do, except that I don't understand how to use that control register.

I also see that DACC_CHDR is a disable register and DACC_CHER is an enable register (noting that both can only be written to if write protection is off, and should only be changed safely when no conversion is taking place), however, I run into the same situation where I don't understand how to use these registers.

Can someone help me understand how to write to these registers? I have a basic knowledge of bitwise operations, I believe I simply lack the understanding of how to implement this in code

Search in the DUE sub forum for DAC example sketches.

This one works with DAC and ADC peripherals:

/*********************************************************************************************************/
/*  44.1 KHz ADC conversions of A0 , idem for A1, triggered by Timer Counter 0 channel 1 TIOA1           */
/*  44.1 KHz DAC output on DAC0, idem for DAC1, triggered by Timer Counter 0 channel 2 TIOA2             */
/*********************************************************************************************************/

volatile uint8_t bufn, Oldbufn, bufn_dac;
const uint16_t bufsize = 128;           
const uint8_t bufnumber = 4;             
const uint8_t _bufnumber = bufnumber - 1;
volatile uint16_t buf[bufnumber][bufsize];       
void setup()
{

  pinMode(LED_BUILTIN, OUTPUT);  // For ADC debugging
  pinMode(12, OUTPUT);           // For DACC debugging

  adc_setup();
  dac_setup();
  tc_adc_setup();
  tc_dac_setup();
}

void loop()
{

}

/*************  Configure adc_setup 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_TRIG2             // Trigger by TIOA1
                  | ADC_MR_PRESCAL(1);

  // ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                 // For frequencies > 500 KHz

  ADC->ADC_IDR = ~ADC_IDR_ENDRX;
  ADC->ADC_IER = ADC_IER_ENDRX;                         // End Of Conversion interrupt enable for channel 7
  //NVIC_SetPriority(ADC_IRQn, 0xFF);
  NVIC_EnableIRQ(ADC_IRQn);                             // Enable ADC interrupt
  ADC->ADC_CHER = ADC_CHER_CH6 | ADC_CHER_CH7;          // Enable Channels 7 = A0 and 6 = A1; Trigger frequency is multiplied by 2
                                                        // The sampling frequency for 1 channel times the number of channels !!

  /*********  PDC/DMA  buffer filling sequence **********/
  ADC->ADC_RPR = (uint32_t)buf[2];                      // DMA buffer - First one will be buf[1]
  ADC->ADC_RCR = bufsize;
  ADC->ADC_RNPR = (uint32_t)buf[3];                     // next DMA buffer
  ADC->ADC_RNCR = bufsize;
  bufn = 3;
  ADC->ADC_PTCR |= ADC_PTCR_RXTEN;                      // Enable PDC Receiver channel request
  ADC->ADC_CR = ADC_CR_START;
}

/*********  Call back function for ADC PDC/DMA **************/
void ADC_Handler () {

  //if ( ADC->ADC_ISR & ADC_ISR_ENDRX) {               // Useless because the only one
  Oldbufn = bufn;

  bufn = (bufn + 1) & _bufnumber;
  ADC->ADC_RNPR = (uint32_t)buf[bufn];
  ADC->ADC_RNCR = bufsize;

  /*******************************************/
  boolean chsel;
  for (uint8_t i = 0; i < bufsize; i++) {
    buf[Oldbufn][i] |= chsel << 12;                    // Select alternatively DAC0 and DAC1
    chsel = !chsel;
  }

  // Todo : digital filtering before DAC output
 
 /*************************************************/
  // For debugging only
  static uint32_t Count;
  if (Count++ == 689) { //84000000/8/238/2/128  = ~689
    Count = 0;
    PIOB->PIO_ODSR ^= PIO_ODSR_P27;  // Toggle LED_BUILTIN every 1 Hz
  }
  /*************************************************/
  // }
}

/*************  Configure adc_setup function  *******************/
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                    // Output on DAC0 and DAC1
                  | DACC_MR_WORD_HALF                 
                  | DACC_MR_REFRESH (1)
                  | DACC_MR_STARTUP_8
                  | DACC_MR_MAXS;

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

  DACC->DACC_IDR = ~DACC_IDR_ENDTX;
  DACC->DACC_IER = DACC_IER_ENDTX;                    // TXBUFE works too !!!
  //NVIC_SetPriority(DACC_IRQn, 0xFF);
  NVIC_EnableIRQ(DACC_IRQn);
  DACC->DACC_CHER = DACC_CHER_CH0 | DACC_CHER_CH1;    // enable channels 1 = DAC1 and 0 = DAC0

  /*************   configure PDC/DMA  for DAC *******************/
  DACC->DACC_TPR  = (uint32_t)buf[0];                 // DMA buffer
  DACC->DACC_TCR  = bufsize;
  DACC->DACC_TNPR = (uint32_t)buf[1];                 // next DMA buffer
  DACC->DACC_TNCR =  bufsize;
  bufn_dac = 1;
  DACC->DACC_PTCR = DACC_PTCR_TXTEN;                  // Enable PDC Transmit channel request

}

/*********  Call back function for DAC PDC/DMA **************/
void DACC_Handler() {   // DACC_ISR_HANDLER()         // move Sinus/PDC/DMA pointers to next buffer

  //if ( DACC->DACC_ISR & DACC_ISR_ENDTX) {           // Useless because the only one

  bufn_dac = (bufn_dac + 1) & _bufnumber;
  DACC->DACC_TNPR = (uint32_t)buf[bufn_dac];
  DACC->DACC_TNCR = bufsize;
 
  /*****************************************/
  // For debugging only
  static uint32_t Count;
  if (Count++ == 689) { //84000000/8/119/128 = ~689
    Count = 0;
    PIOD->PIO_ODSR ^= PIO_ODSR_P8;  // Toggle LED_BUILTIN every 1 Hz
  }
  /****************************************/
  //}
}

/*******  Timer Counter 0 Channel 1 to generate PWM pulses thru TIOA1  for ADC ********/
void tc_adc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID28;                      // TC1 power ON : Timer Counter 0 channel 1 IS TC1
  TC0->TC_CHANNEL[1].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 TIOA1 on RA compare match
                              | TC_CMR_ACPC_SET;          // Set TIOA1 on RC compare match

  TC0->TC_CHANNEL[1].TC_RC = 238;  //<*********************  Frequency = (Mck/8)/TC_RC  Hz = 22.05 Hz
  TC0->TC_CHANNEL[1].TC_RA = 40;  //<********************   Any Duty cycle in between 1 and TC_RC

  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKEN;               // TC1 enable

}

/*******  Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2  for DACC ********/
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_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 = 119;  //<*********************  Frequency = (Mck/8)/TC_RC  Hz = 44.1 Hz
  TC0->TC_CHANNEL[2].TC_RA = 20;  //<********************   Any Duty cycle in between 1 and TC_RC

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_CLKEN;               // TC2 enable
  TC0->TC_BCR = TC_BCR_SYNC;                              // Synchro TC1 and TC2
}

Sam3x datasheet plus header files are needed:
https://android.googlesource.com/platform/external/arduino-ide/+/f876b2abdebd02acfa4ba21e607327be4f9668d4/hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/component

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.