multiple ADC sync'ed to pwm

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

multiple ADC sync'ed to pwm

1,305 次查看
leonggz
Contributor I

hi, 

i was able to follow the https://www.nxp.com/docs/en/application-note/AN5303.pdf to synchronize the ADC with the PWM center using PDB. while in the example only ONE channel of the adc is used, to measure multiple ADC channels, I followed another instruction to use the back-to-back feature of the PDB to do three adc conversions. But when i measure the timing using PDB and ADC interrupt, i found that the PDB trigger is no longer sync'ed with the PWM center any more. 

the code is pasted below.

in summary, the FTM0 is configured to trigger PDB0 and PDB1 via TRGMUX; 

PDB1 has only 1 ADC conversion, if i place a gpio set/clear in the PDB1 and ADC interrupt handlers, respectively, i see the gpio is centered with the PWM; 

PDB0 has three ADC conversions, similar gpio toggle would not show the synchronization between the PDB interrupt and the pwm center any more. 

thanks in advance.

gzhang


uint16_t ADC1_R[3] = {0,0,0};
uint16_t ADC0_R[3] = {0,0,0};


void FTM0_PTB_Center_Align_PWM_Init()
{
/* Enable clock for PORTB */
PCC->PCCn[PCC_PORTB_INDEX] = PCC_PCCn_CGC_MASK;
/* Select and enable clock for FTM0 */
PCC->PCCn[PCC_FTM0_INDEX] = PCC_PCCn_PCS(6) | PCC_PCCn_CGC_MASK;

/* Set PORTB pins for FTM0 */
PORTB->PCR[12] = PORT_PCR_MUX(2);
PORTB->PCR[13] = PORT_PCR_MUX(2);
PORTB->PCR[14] = PORT_PCR_MUX(2);
PORTB->PCR[15] = PORT_PCR_MUX(2);
PORTB->PCR[16] = PORT_PCR_MUX(2);
PORTB->PCR[17] = PORT_PCR_MUX(2);

/* Select up-down counter for Center-Align PWM */
FTM0->SC = FTM_SC_CPWMS_MASK;
/* Combine mode and dead-time enable for channel0 and channel1 */
FTM0->COMBINE = FTM_COMBINE_SYNCEN0_MASK | FTM_COMBINE_COMP0_MASK | FTM_COMBINE_DTEN0_MASK;
/* Combine mode and dead-time enable for channel2 and channel3 */
FTM0->COMBINE |= FTM_COMBINE_SYNCEN1_MASK | FTM_COMBINE_COMP1_MASK | FTM_COMBINE_DTEN1_MASK;

/* Combine mode and dead-time enable for channel4 and channel5 */
FTM0->COMBINE |= FTM_COMBINE_SYNCEN2_MASK | FTM_COMBINE_COMP2_MASK | FTM_COMBINE_DTEN2_MASK;


/* Set Modulo (10kHz PWM frequency @112MHz system clock) */
FTM0->MOD = FTM_MOD_MOD(1000);
/* Set CNTIN */
FTM0->CNTIN = FTM_CNTIN_INIT(0);
/* High-true pulses of PWM signals */
FTM0->CONTROLS[0].CnSC = FTM_CnSC_ELSB_MASK;
FTM0->CONTROLS[1].CnSC = FTM_CnSC_ELSB_MASK;
FTM0->CONTROLS[2].CnSC = FTM_CnSC_ELSB_MASK;
FTM0->CONTROLS[3].CnSC = FTM_CnSC_ELSB_MASK;
FTM0->CONTROLS[4].CnSC = FTM_CnSC_ELSB_MASK;
FTM0->CONTROLS[5].CnSC = FTM_CnSC_ELSB_MASK;
/* Set Channel Value */
FTM0->CONTROLS[0].CnV=FTM_CnV_VAL(0); // 0 duty cycle
FTM0->CONTROLS[1].CnV=FTM_CnV_VAL(0); // 0 duty cycle
FTM0->CONTROLS[2].CnV=FTM_CnV_VAL(0); // 0 duty cycle
FTM0->CONTROLS[3].CnV=FTM_CnV_VAL(0); // 0 duty cycle
FTM0->CONTROLS[4].CnV=FTM_CnV_VAL(0); // 0 duty cycle
FTM0->CONTROLS[5].CnV=FTM_CnV_VAL(0); // 0 duty cycle
/* FTM counter reset */
FTM0->CNT = 0;
/* Insert DeadTime (1us) */
FTM0->DEADTIME = FTM_DEADTIME_DTPS(3) | FTM_DEADTIME_DTVAL(7);

/* Enable trigger generation when FTM counter = CNTIN */
FTM0->EXTTRIG = FTM_EXTTRIG_INITTRIGEN_MASK;

/* Clock selection and enabling PWM generation */
FTM0->SC |= FTM_SC_CLKS(1) | FTM_SC_PWMEN0_MASK | FTM_SC_PWMEN1_MASK | FTM_SC_PWMEN2_MASK | FTM_SC_PWMEN3_MASK | FTM_SC_PWMEN4_MASK | FTM_SC_PWMEN5_MASK;
}


/* TRGMUX Initialization */
void TRGMUX_Init()
{
PCC->PCCn[PCC_TRGMUX_INDEX] = PCC_PCCn_CGC_MASK; // Enable clock for TRGMUX module
/* Set FTM as a trigger source for PDB0 */
TRGMUX->TRGMUXn[TRGMUX_PDB1_INDEX] = TRGMUX_TRGMUXn_SEL0(0x16);
TRGMUX->TRGMUXn[TRGMUX_PDB0_INDEX] = TRGMUX_TRGMUXn_SEL0(0x16);
}

/* PDB1 Initialization */
void PDB1_Init()
{
PCC->PCCn[PCC_PDB1_INDEX] = PCC_PCCn_CGC_MASK; // Enable clock for PDB0
FSL_NVIC->ISER[PDB1_IRQn / 32] |= (1 << (PDB1_IRQn % 32)); // Enable interrupt
PDB1->MOD = 1000; // Set Modulo
PDB1->CH[0].C1 = PDB_C1_TOS(1) | PDB_C1_EN(1); // Select and enable Channel0
PDB1->CH[0].DLY[0] = 500; // Set delay


PDB1->IDLY = 0; // Set interrupt delay
PDB1->SC |= PDB_SC_PRESCALER(0) | PDB_SC_MULT(0); // Select clock prescaler and mult factor
/* Select trigger input source and enable interrupt */
PDB1->SC |= PDB_SC_TRGSEL(0) | PDB_SC_PDBIE_MASK;
/* Enable PDB and update PDB registers */
PDB1->SC |= PDB_SC_PDBEN_MASK | PDB_SC_LDOK_MASK;
}

void ADC1_Init()
{
PCC->PCCn[PCC_ADC1_INDEX] = 0; // Disable clock for ADC0
PCC->PCCn[PCC_ADC1_INDEX] = PCC_PCCn_PCS(6) | PCC_PCCn_CGC_MASK; // Enable clock for ADC0
FSL_NVIC->ISER[ADC1_IRQn / 32] |= (1 << (ADC1_IRQn % 32)); // Enable interrupt
/* Set divide ratio to 1 and select 8-bit conversion */
ADC1->CFG1 = ADC_CFG1_ADIV(0) | ADC_CFG1_MODE(0) | ADC_CFG1_ADICLK(0);
/* Select hardware trigger, by default it comes from PDB1 */
ADC1->SC2 = ADC_SC2_ADTRG_MASK;
/* Select channel 12 as an input and enable conversion complete interrupt */
ADC1->SC1[0] = ADC_SC1_AIEN_MASK | ADC_SC1_ADCH(11);
ADC1->SC1[1] = ADC_SC1_AIEN_MASK | ADC_SC1_ADCH(10);
ADC1->SC1[2] = ADC_SC1_AIEN_MASK | ADC_SC1_ADCH(12);
}
/* ADC0 interrupt routine */
void ADC1_IRQHandler()
{
ADC1_R[0] = ADC1->R[0]; // Read ADC result register
ADC1_R[1] = ADC1->R[1]; // Read ADC result register
ADC1_R[2] = ADC1->R[2]; // Read ADC result register
PTD->PCOR |= 1<<13;
}


/* PDB0 interrupt routine */
void PDB1_IRQHandler()
{
PTD->PSOR |= 1<<13;
PDB1->SC &= ~PDB_SC_PDBIF_MASK; // Clear PDB interrupt flag
}

/* PDB0 Initialization */
void PDB0_Init()
{
PCC->PCCn[PCC_PDB0_INDEX] = PCC_PCCn_CGC_MASK; // Enable clock for PDB0
FSL_NVIC->ISER[PDB0_IRQn / 32] |= (1 << (PDB0_IRQn % 32)); // Enable interrupt
PDB0->MOD = 1000; // Set Modulo
PDB0->CH[0].C1 = PDB_C1_BB(0x06) | PDB_C1_TOS(0) | PDB_C1_EN(0x07); // Select and enable Channel0
PDB0->CH[0].DLY[0] = 500; // Set delay


PDB0->IDLY = 0; // Set interrupt delay
PDB0->SC |= PDB_SC_PRESCALER(0) | PDB_SC_MULT(0) | PDB_SC_CONT(1); // Select clock prescaler and mult factor
/* Select trigger input source and enable interrupt */
PDB0->SC |= PDB_SC_TRGSEL(0) | PDB_SC_PDBIE_MASK;
/* Enable PDB and update PDB registers */
PDB0->SC |= PDB_SC_PDBEN_MASK | PDB_SC_LDOK_MASK;
}

void ADC0_Init()
{
PCC->PCCn[PCC_ADC0_INDEX] = 0; // Disable clock for ADC0
PCC->PCCn[PCC_ADC0_INDEX] = PCC_PCCn_PCS(6) | PCC_PCCn_CGC_MASK; // Enable clock for ADC0
FSL_NVIC->ISER[ADC0_IRQn / 32] |= (1 << (ADC0_IRQn % 32)); // Enable interrupt
/* Set divide ratio to 1 and select 8-bit conversion */
ADC0->CFG1 = ADC_CFG1_ADIV(0) | ADC_CFG1_MODE(0) | ADC_CFG1_ADICLK(0);
/* Select hardware trigger, by default it comes from PDB */
ADC0->SC2 = ADC_SC2_ADTRG_MASK;
/* Select channels as an input and enable conversion complete interrupt */
ADC0->SC1[0] = ADC_SC1_ADCH(8);
ADC0->SC1[1] = ADC_SC1_ADCH(15);
ADC0->SC1[2] = ADC_SC1_AIEN_MASK | ADC_SC1_ADCH(12);
}

/* ADC0 interrupt routine */
void ADC0_IRQHandler()
{

ADC0_R[0] = ADC0->R[0]; // Read ADC result register
ADC0_R[1] = ADC0->R[1]; // Read ADC result register
ADC0_R[2] = ADC0->R[2]; // Read ADC result register


}


/* PDB0 interrupt routine */
void PDB0_IRQHandler()
{

PDB0->SC &= ~PDB_SC_PDBIF_MASK; // Clear PDB interrupt flag
}

标记 (1)
0 项奖励
1 回复

1,230 次查看
leonggz
Contributor I

self answered:

PDB_C1_TOS(0) => PDB_C1_TOS(0x01) : the first one cannot be bypassed.

also no need to set modulo or delay since the pdb is triggered by pwm. 

0 项奖励