I want to sample the ADC at somewhere between the PWM channel's top and bottom points of its sawtooth waveform for left aligned PWM. The output of the ADC goes to DAC0 on the Due. I have tried to implement this but I don't get any DAC output at all. I did include a 4kOhm resistor in series with the DAC pin.
Also I am using PWMH2 and PWML2 for PWM waves in sync with my PWML4 which is the channel set up in PWM_clockinit();. That part is working fine, so I have not included that bit of the code. This should be a minimal working example.
void setup () {
PWM_clockinit();
pwmc_setup();
adc_setup();
dac_setup();
}
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_DIS //Free run mode
| DACC_MR_USER_SEL_CHANNEL0 //selecting DAC0
| DACC_MR_STARTUP_8
| DACC_MR_MAXS
| DACC_MR_REFRESH(1);
DACC->DACC_IER |= DACC_IER_EOC;
NVIC_EnableIRQ(DACC_IRQn);
DACC->DACC_CHER = DACC_CHER_CH0; //enable DAC0 (i.e, channel0)
}
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 | ADC_MR_TRGSEL_ADC_TRIG5;
//Select hardware trigger and trigger by PWM event line 1
// Next two lines are concerned with the output of the ADC and subsequent triggers
ADC->ADC_IER = ADC_IER_EOC7; //Pin A0 = AD7 so channel 7 of the ADC
NVIC_EnableIRQ(ADC_IRQn); //Enables the ADC interrupt
ADC->ADC_CHER = ADC_CHER_CH7; //Enable Channel 7 on A0
}
// Under the ADC handler we will include the direct bit manipulated write operation as a status to ensure ADC is being called at the right time
void ADC_Handler()
{
if(ADC->ADC_ISR & ADC_ISR_EOC7){ //if data is ready
PIOC->PIO_CODR = 1 << 1; //Low at pin 33 at the bottom of Due
result = ADC->ADC_CDR[7]; //store it inside this variable
result = map(result, 0, 4095, 0, 255); //Map from 12 bits to 8 bits
analogWrite(DAC0, result); //output at DAC0
}
}
// Big clock is being used to find the instants to trigger the ADC on PWM event line 1
void PWM_clockinit() {
// PWM Set-up on pins PC21 (PWML4 = D9)
PMC->PMC_PCER1 |= PMC_PCER1_PID36; // PWM power ON
PWM->PWM_DIS = PWM_DIS_CHID4; // Disable PWM channel 4
// Select Instance=PWM; Signal=PWML4 (channel 4); I/O Line=PC21; Peripheral type B
PIOC->PIO_PDR |= PIO_PDR_P21; // Set the pin to the peripheral PWM, not the GPIO
PIOC->PIO_ABSR |= PIO_PC21B_PWML4; // Set PWM pin perhipheral type B
PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(7); // Set the PWM clock rate to 2MHz (84MHz/42) (?)
PWM->PWM_CH_NUM[4].PWM_CMR = PWM_CMR_CPRE_CLKA; // clock source as CLKA on channel 2
PWM->PWM_CH_NUM[4].PWM_CPRD = 500; // Channel 2 : Set the PWM frequency 2MHz/(2* CPRD) = F ;
PWM->PWM_CH_NUM[4].PWM_CDTY = 250; // Channel 2: Set the PWM duty cycle to x%= (CDTY/ CPRD) * 100 %
PWM->PWM_CMP[4].PWM_CMPV = PWM_CMPV_CV(1500); //The value to be compared with the counter of channel 4 (val btwn 1 - PWM_CPRD)
PWM->PWM_CMP[4].PWM_CMPM = PWM_CMPM_CEN; // ENable comparison
PWM->PWM_ELMR[1] = PWM_ELMR_CSEL4; //Event line triggering per CMPV value of channel 4 (thus CSEL 4)
PWM->PWM_IER1 = PWM_IER1_CHID4; // Interrupt on end of counter period (2*CPRD)
NVIC_EnableIRQ(PWM_IRQn); // Enable PWM interrupt
PWM->PWM_ENA = PWM_ENA_CHID4; // Enable PWM Channel 4
}
void PWM_Handler() {
PWM->PWM_ISR1; // Clear status register
if (State == Idle) {
PIOC->PIO_SODR = 1 << 24; // Business monitor set
digitalWrite(BM,HIGH);
PIOC -> PIO_CODR = 1 << 13; //R1 RED ON
PIOC -> PIO_SODR = 1 << 12; //G1 GREEN OFF
PIOB -> PIO_CODR = 1 << 14; //B1 BLUE OFF
PWM->PWM_CH_NUM[2].PWM_CDTY = 500; //100% duty cycle
PIOC -> PIO_CODR = 1 << 24; //Business monitor low
}
if (State == Run) {
PIOC->PIO_SODR = 1 << 24; // Business monitor set
PIOC -> PIO_CODR = 1 << 14; //R1 RED OFF
PIOC -> PIO_SODR = 1 << 13; //G1 GREEN ON
PIOB -> PIO_CODR = 1 << 14; //B1 BLUE OFF
PWM->PWM_CH_NUM[2].PWM_CDTY = 100; //1/3rd duty cycle
PIOC -> PIO_CODR = 1 << 24;
}
}
void loop(){}
Can someone say where I'm going wrong?