I'd like to use the internal AD converter. But it doesn't work correctly.
I connected a continue voltage on PTB 0 labeled as ADC0/SE8 adc channel.(using FRDMKL27)
I follow the data sheet just to start the module but the register R it is always at the value of 65535.
If I break at ADC0 interrupr handler I see this.
The ADc is triggered from a timer every 500 ms.
What's miss on my code ?
Any suggestion ?
Thanks in advance.
Attilio
void ADC0_IRQHandler(void)
{
static UINT32 value = 0;
value = ADC0->R[0];
}
BOOL Adc_Calibration(void)
{
UINT16 cal_data;
ADC_Type *adc;
adc = ADC0; // just to see the register in the debug window
adc->CFG1 |= ADC_CFG1_ADICLK(0x01) + // adc input clock = busclk/ 2 --> (24 Mhz / 2) = 12 Mhz
ADC_CFG1_ADIV(2) + // adc division = 8 --> adc clock = 12 Mz / 8 = 1Mhz
ADC_CFG1_ADLPC(0) + // no low power
ADC_CFG1_ADLSMP(0x01) + // long sample time
ADC_CFG1_MODE(0x03); // with DIFF = 0 --> 16 bit single ended
adc->SC2 = 0x00; // software trigger selected
// compare function disabled
// DMA transfert disabled
// voltage ref is default ref (vrefh / vrefl)
adc->SC3 |= ADC_SC3_AVGE_MASK + // enable hw average
ADC_SC3_AVGS(3) + // set for 32 samples
ADC_SC3_CAL_MASK; // start calibration
while(adc->SC3 & ADC_SC3_CAL_MASK); // wait for calibration end
if(adc->SC3 & ADC_SC3_CALF_MASK) // check calibration success ?
return FALSE; // calibration was fault
// compute & store calibration data
cal_data = 0;
cal_data += adc->CLPS + adc->CLP4 + adc->CLP3 +
adc->CLP2 + adc->CLP1 + adc->CLP0;
cal_data >>= 1;
cal_data |= 0x8000;
adc->PG = cal_data;
cal_data = 0;
cal_data += adc->CLMS + adc->CLM4 + adc->CLM3 +
adc->CLM2 + adc->CLM1 + adc->CLM0;
cal_data >>= 1;
cal_data |= 0x8000;
adc->MG = cal_data;
adc->SC3 &= ~ADC_SC3_CAL_MASK; // clear CAL bit
return TRUE;
}
void InitAdc(void)
{
SIM->SCGC6 |= SIM_SCGC6_ADC0_MASK; // adc0 clock gating
if(Adc_Calibration() == FALSE)
{
ErrorTrap(); // just for debug
}
// change adc config after calibration
ADC0->CFG1 |= ADC_CFG1_ADICLK(0x01) + // adc input clock = busclock --> 24 Mhz
ADC_CFG1_ADIV(0) + // adc division = 1 --> adc clock = 24 Mz
ADC_CFG1_ADLPC(0) + // no low power
ADC_CFG1_ADLSMP(0x01) + // long sample time
ADC_CFG1_MODE(0x03); // with DIFF = 0 --> 16 bit single ended
ADC0->SC1[0] |= ADC_SC1_ADCH(0x1F); // disable ADC module
ConnectInterruptToCortex(ADC0_IRQn); // set ADC0 interrupts
}
void TriggerAdc(void)
{
ADC0->SC1[0] = ADC_SC1_ADCH(8) | ADC_SC1_AIEN_MASK;
}
void main(void)
{
InitAdc();
ENABLE_INTERRUPTS;
while(1)
{
}
}
Hello Attilio,
Hope you are going well. We have drivers examples in the SDK. You can download it here: SDK Builder. To see all driver examples you need to select the FRDM-KL27Z board. I recommend consulting the adc16_interrupt example, it does the ADC initialization and calibration. Try this example and, if it works, I can help you to modify your initialization function, or you can take the example and adapt it to your desired configuration.
Let me know your results and if you have further questions.
Best Regards,
Ricardo
Hi Ricardo.
Thanks for your answer.
I'm looking for adc driver examples as you told me. To be onest about my problem, I just found out an hardware problem too.
In my think, the sdk are very useful but I can prefer to write the driver. But now seem to work properly. I have to adjust the adc hardware interrupt and remove the PRINTF console debug. It is a useful function but very very slow.
Best regards.
Attilio
Hello Attilio,
I'm glad you were able to solve this. The printf function should only be used for debugging, however, for the actual implementation of your application, minimal or no use should be made, since you mention that it slows down the application, since it takes time to perform the printing routine and return to the application.
If you have any questions please don't hesitate to ask.
Best Regards,
Ricardo