Trenly
January 12, 2021, 4:00am
1
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
system
Closed
May 12, 2021, 4:22am
3
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.