Dear all,
I'm working with the FRDM-K22F, and want to read several signals using ADC, and use PIT to timing for the sample period, also according the value of the single output digital signal. Settings as follows(from demo driver):
int main(void) ADC16_GetDefaultConfig(&adc16ConfigStruct);
{
...............
/**************************ADC INIT***********************************************************************/
ADC16_Init(DEMO_ADC16_BASE, &adc16ConfigStruct);
ADC16_EnableHardwareTrigger(DEMO_ADC16_BASE, false); /* Make sure the software trigger is used. */
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
if (kStatus_Success == ADC16_DoAutoCalibration(DEMO_ADC16_BASE))
{
//PRINTF("ADC16_DoAutoCalibration() Done.\r\n");
}
else
{
//PRINTF("ADC16_DoAutoCalibration() Failed.\r\n");
}
#endif
adc16ChannelConfigStruct1.channelNumber = DEMO_ADC16_USER_CHANNEL1;
adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
adc16ChannelConfigStruct.enableDifferentialConversion = false;
#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
...............
adc16ChannelConfigStructn.channelNumber = DEMO_ADC16_USER_CHANNELn;
adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
adc16ChannelConfigStruct.enableDifferentialConversion = false;
#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
/*********************************************************************************************************/
/*****************************************PIT INIT*******************************************************/
...............
}
void PIT_IRS_HANDLER(void)
{
/* Clear interrupt flag.*/
PIT_ClearStatusFlags(PIT, kPIT_Chnl_0, PIT_TFLG_TIF_MASK);
/********************************GET the ADC Value**************************************************/
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct1);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{
}
Analog_Signal_1 = ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
/*********************************************************************************************************/
...............
/*********************************************************************************************************/
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStructn);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{
}
Analog_Signal_n = ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
/*********************************************************************************************************/
cnt = (cnt + 1) & 0xff;
if (cnt < 20)
{
GPIO_ClearPinsOutput(BOARD_PIN1_GPIO, 1U << BOARD_GPIO_PIN1);
}
else if(cnt <150)
{
GPIO_SetPinsOutput(BOARD_PIN1_GPIO, 1U << BOARD_GPIO_PIN1);
}
else
{
GPIO_ClearPinsOutput(BOARD_PIN1_GPIO, 1U << BOARD_GPIO_PIN1);
}
...............
}
When in debug, the cycle of the PIN1 is wrong, will be much more than PIT cycle. After banned the
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStructn);
then the cycle of PIN1 will be the same as designed.
Is there got a better solution to read the analog signals without delay? if got, please show it to me.
Thanks in advance!
- Jack
Hi Jack,
not sure what did you really want to achieve by your application. Definitelly, I do not recommend to wait for conversion flag in timer interrupt. ADC conversion is not done immediatelly - depends on ADC configuration (roughly it starts from ~1us) as it works as successive approximation converter (if the 16 bit mode of ADC is selected it will takes 16 aproximation steps to conversion complete + sampling process done at the beginning of converison to store measured value in sampling capacitance).
1. suggestion: using PIT to trigger conversion
in this case the PIT isr handler is not really required, just PIT selected as HW trigger for ADC (see SIM_SOPT7 register description). It is better to use ADC converison complete isr handler to handle ADC data and change of channel to be measured next, as well as you counter values. However, in such case it is reuired to calculate total conversion time (see in reference manual - Sample time and total conversion time chapter). Or simple way to use ADC calculator:
ADC Calculator for Kinetis/ColdFire+|NXP
After getting the total conversion time interval you can be sure if selected PIT periodic interval is higher that the total conversion time.
NOTE 1: be sure that the interrupt handler routine execution is not longer than PIT period (this most probably happend in you case).
NOTE 2: if you measure 16 channels in sequence then I suggest to divide your sampling period (your measured waveform sampling period) by 16 (and this time should be higher than total conversion time). With such configuration you will properly get ADC conversion complete interrupt after each measuremnt. In th einterrupt handler you need to change the channel to be measured next. After 16th measurement the process is repeated (it means the first channel need to be configured).
2. suggestion: recommended is to use PDB to trigger ADC in such case
At first you need to know how many ADCs your microcontroller include. K22 should have 2 ADCs (ADC0 and ADC1) and each ADC have two result registers (ADCx_RA and ADCx_B). This allow you to do two converison in parallel and two conversion in sequence without any SW intervention. In general Kinetis platform PDB mode is suggested to be used for periodical sampling done by ADC. PDB module includes channels with the same number as ADC converters, it means PDB CH0 and PDB CH1. Each PDB channel includes pre-triggers with the same number as ADC converter results register. At the end each conversion of ADCx Ry starts based on generation of trigger of PDB CHx pre-trigger z. It means:
ADC0 RA start of conversion is generated by PDB CH0 pre-trigger 0
ADC0 RB start of conversion is generated by PDB CH0 pre-trigger 1
ADC1 RA start of conversion is generated by PDB CH1 pre-trigger 0
ADC1 RB start of conversion is generated by PDB CH1 pre-trigger 1
To allow all of this concversion to be done without any SW intervention there is a special automatic process of PDB triggering called back to back mode. It means that after PDB CHo pre-trigger 0 trigger generation the ADC0 RA conversion starts. After this conversion there is automatic process of generation of PDB CH0 pre-trigger 1 generation which starts ADC0 RB conversion, etc till the ADC1 RB conversion complete.
I know that now you see to much difficulties in developing. However, it is only way to do it without facing any issue you see.
regards
R.
Hi Rastislav,
Thanks for your suggestion, and i'm try to using PIT to trigger the conversion, but i found the conversion do not happen.
In the following routine i use PIT3 as the timer, after 500*BusCLK, hope can get the ADC data, using "ADC_FLAG" to mark whether the data is read by other ISR Handler or routine.
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, 500);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
DisableIRQ(PIT_IRQ_ID3);
PIT_StartTimer(PIT, kPIT_Chnl_3);
if (true == PIT_GetStatusFlags(PIT, kPIT_Chnl_3))
{
PIT_ClearStatusFlags(PIT, kPIT_Chnl_3, PIT_TFLG_TIF_MASK);
/***************************************************************************************/
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{
}
Signal1 = ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
/**************************************************************************************/
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct2);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{
}
Signal2 = ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
/**************************************************************************************/
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct3);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{
}
Signal3= ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
/**************************************************************************************/
ADC_FLAG = true;
/**************************************************************************************/
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, 500);
PIT_StartTimer(PIT, kPIT_Chnl_3);
}
Is there some problem?
Thanks in advance!
-Jack
Hi Jack,
You need selected PIT as HW trigger for ADC (see SIM_SOPT7 register description).
Best Regards,
Robin