Hi everyone,
I am quite new to Arduino DUE and microC programming in general and my question may seem dumb. Yhe task I have to accomplish is to generate one single sine wave at 4kHz and do two adc at 1 kHz, exactly when the sine wave has its peak, and then send them via Serial.
I have do that with interupts or DMA, I have searched on this forum and on SAM3X8E datasheet but I cannot get how to solve my specific case. I have seen a post with the code I attach below but I can't understand where ADCs are stored (how to "extract" and use them), how to use just one DAC and what does this cycle (in ADC_Handler) do:
boolean chsel;
for (uint8_t i = 0; i < bufsize; i++) {
buf[Oldbufn][i] |= chsel << 12; // Select alternatively DAC0 and DAC1
chsel = !chsel;
}
Thank you for your time and I apologize for these noob doubts.
Luigi
Here is the code,by ard_newbie, I mentioned before:
/*********************************************************************************************************/
/* 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
}