Kinnetis K22 using PIT triggered ADC with Compare

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Kinnetis K22 using PIT triggered ADC with Compare

1,589 Views
ashesman
Contributor III

Hi,

 

I am stuck here.  I have a FRDMK22F dev kit.  I started by using the SDK example for PIT triggered ADC.  I changed it to 16 bit differential and set the PIT rate as I desired.  Works mint!

 

BUT...  When I enable the compare function in the ADC, I get only one ADC conversion complete interrupt if the compare conditions are met on the very first sample, otherwise I never get an interrupt.

 

My intention is to wait until a sample is measured outside of a range, then switch the compare function off and continue sampling at a fixed interval.  Any ideas on this, I am stuck and burning time away...

 

Relevant Code, the rest is as per the PIt hardware triggered ADC example:

 

/*!
 * @brief ADC channel0 callback for fetching sample data.
 */
static void adc_chn0_isr_callback(void)
{
    gCurChan = 0;
    gAdcDone = true;
}

#define ACCEL_ADC_CHANNEL (kAdc16Chn0d)


adc16_status_t res;
/*!
 * @brief Initialize the ADCx for HW trigger.
 *
 * @param instance The ADC instance number
 */
static int32_t init_adc(uint32_t instance)
{
     // Initiaslise ADC to default
     adc16_converter_config_t adcUserConfig;
    ADC16_DRV_StructInitUserConfigDefault(&adcUserConfig);
    ADC16_DRV_Init(instance, &adcUserConfig);

    // Initialise ADC for calibration process
    // Note this enables the ADC Async Clock which is within the correct frequency range for calibration
    // Set hardware averaging to maximum
    adc16_hw_average_config_t adcAverageConfig =
    {
      .hwAverageEnable = true,
      .hwAverageCountMode = kAdc16HwAverageCountOf32
    };
    ADC16_DRV_ConfigHwAverage(instance, &adcAverageConfig);

    adc16_chn_config_t adcCalibrationChnConfig;
    adcCalibrationChnConfig.diffConvEnable = true;
    adcCalibrationChnConfig.convCompletedIntEnable = false;
    // Configure channel 0
    ADC16_DRV_ConfigConvChn(instance, 0U, &adcCalibrationChnConfig);
    // Auto calibration.
    adc16_calibration_param_t adcCalibrationParam;
    ADC16_DRV_GetAutoCalibrationParam(instance, &adcCalibrationParam);
    ADC16_DRV_SetCalibrationParam(instance, &adcCalibrationParam);

    // Initialise ADC for
    // Bus Clock (5MHz RUN mode, 7.5MHz HSRUN mode), async clock disabled
    ADC16_DRV_StructInitUserConfigDefault(&adcUserConfig);
    adcUserConfig.clkSrc = kAdc16ClkSrcOfBusClk;
    adcUserConfig.clkDividerMode = kAdc16ClkDividerOf8;
    adcUserConfig.lowPowerEnable = false;
    // 16 bit resolution, differential.  VREFH/L as reference
    adcUserConfig.resolution = kAdc16ResolutionBitOfDiffModeAs16;
    adcUserConfig.refVoltSrc = kAdc16RefVoltSrcOfVref;
    // Sampling: Gives 14.925us (67 kHz max) conversion time in RUN mode or 11.616us in HSRUN mode
    adcUserConfig.asyncClkEnable = false;
    adcUserConfig.longSampleTimeEnable = true;
     adcUserConfig.longSampleCycleMode = kAdc16LongSampleCycleOf16; // 12 extra cycles, 16 in total
     adcUserConfig.highSpeedEnable = false;
    // Interrupt mode, HW trigger enabled, disable continuous convert mode.
    adcUserConfig.hwTriggerEnable = true;
    adcUserConfig.continuousConvEnable = false;
    adcUserConfig.dmaEnable = false;
    ADC16_DRV_Init(instance, &adcUserConfig);
    // Disable averaging
    adcAverageConfig.hwAverageEnable = false;
    ADC16_DRV_ConfigConvChn(instance, 0U, &adcCalibrationChnConfig);

    // Install Callback function into ISR
    ADC_TEST_InstallCallback(instance, 0U, adc_chn0_isr_callback);

    adc16_hw_cmp_config_t compareVals =
    {
         .hwCmpEnable = true,
          .hwCmpRangeEnable = false,//true,
          .hwCmpGreaterThanEnable = true,
          .cmpValue1 = 10000//,
         //.cmpValue2 = (uint16_t)-10000
    };
    res = ADC16_DRV_ConfigHwCompare(instance, &compareVals);

    // Setup channel 0
    adc16_chn_config_t adcChnConfig;
    adcChnConfig.chnIdx = ACCEL_ADC_CHANNEL;
    adcChnConfig.diffConvEnable = true;
    adcChnConfig.convCompletedIntEnable = true;

    // Configure channel 0
    ADC16_DRV_ConfigConvChn(instance, 0U, &adcChnConfig);



    return 0;
}
Labels (1)
9 Replies

979 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Ashley,

Pls refer to the section 32.4.5 Automatic compare function in the RM of K22, I think what you see matches with the comparing function setting:

 adc16_hw_cmp_config_t compareVals =
    {
         .hwCmpEnable = true,   //ACFE=1
          .hwCmpRangeEnable = false,//true, //ACREN=0
          .hwCmpGreaterThanEnable = true, //ACFGT=1
          .cmpValue1 = 10000//,
         //.cmpValue2 = (uint16_t)-10000
    };

With above setting, "Greater than or equal to threshold Compare" is  true if the result is greater than or equal to CV1 registers, only in the condition that Greater than or equal to threshold Compare is true can the COCO bit become true which triggeres complete ADC interrupt. In other words, the ADC triggeres ADC complete interrupt only the ADC result is greater than the compare value.

For you requirement "My intention is to wait until a sample is measured outside of a range, then switch the compare function off and continue sampling at a fixed interval.  Any ideas on this, I am stuck and burning time away...",  I think you can change the compare setting in the ISR of ADC by disableing compare function(clearing the ACFE bit), it is okay.

Hope it can help you

BR

XiangJun Rong

If CV1 is greater than CV2, setting SC2[ACFGT] will select a trigger-if-outsidecompare-
range, inclusive-of-endpoints function. Clearing SC2[ACFGT] will select a
trigger-if-inside-compare-range, not-inclusive-of-endpoints function.
If the condition selected evaluates true, SC1n[COCO] is set.

0 Kudos

979 Views
ashesman
Contributor III

Thanks for your reply.  Sorry, I may not have been clear in my question...  The code I posted had the window compare commented out for testing.  But whether I use window or single compare, the actual problem I have is that I only get a working compare on the first ADC measurement, after that the ADC does not trigger...

0 Kudos

979 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

I think the ADC is triggered, but only your sample is greater than the threshold defined in CV1 can the ADC conversion complete interrupt happens. For example, pls connect the 3.3V to the ACCEL_ADC_CHANNEL, what is the result?

BR

Xiangjun Rong

0 Kudos

979 Views
ashesman
Contributor III

I can not tell if the ADC is triggered or runs.  But I did already try ensuring a higher voltage was on the ADC pins continuously and still I only got an interrupt on the very first conversion.   After that it just did nothing.  I expected a continuous series of interrupts while the voltage was above the threshold.

0 Kudos

979 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Ashley,

Can you attach your project so that I can test on my board? which tools do you use?

BR

Xiangjun Rong

0 Kudos

979 Views
ashesman
Contributor III

Hi,

Thanks for your offer to help.  I am using a Freedom K22F development board.  KDS IDE.  I generated a SDK 2.0 from the web site.  That includes an example for hardware triggered ADC from PIT.  Using that example, paste my ADC initialisation code from above.  You can connect to ADC0_P and ADC0_N to trigger the ADC interrupt.

Thanks

Ashley

0 Kudos

979 Views
larchard
Contributor I

Hi Ashley

I'm just getting started with the FRDM-K22F. I've also generated the SDKv2 but I can't find the example for the ADC triggered from the PIT. Where did you find it?

Cheers

0 Kudos

979 Views
ashesman
Contributor III

Bugger, Sorry,  The PIT example is in SDK V1.3.  I had forgotten about that.  I actually started with the ADC low power example and converted it to PIT triggered!  Ooops... 

SDK 1.3 and 2.0 are very different and require a lot of conversion.

Here is some code to get the ADC going with PIT trigger as a starting point.  It is part of a larger project I can not post. 

    // Initialise ADC
    if (!InitADC16Diff16Bit(BOARD_ACCEL_ADC16_BASEADDR))
    {
        // ADC Initialisation Error
    }

    // setup the HW trigger source
    InitADCTriggerSourceToPit0();
    // Enable ADC Interrupt
    NVIC_EnableIRQ(BOARD_ACCEL_ADC16_IRQ_ID);



static bool InitADC16Diff16Bit(ADC_Type *base)
{
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
    // Auto calibration
    uint16_t offsetValue = 0; // Offset error from correction value
    ADC16_DoAutoCalibration(base);
    offsetValue = base->OFS;
    ADC16_SetOffsetValue(base, offsetValue);
#endif
    // Initialise ADC for
    // Bus Clock (5MHz RUN mode, 7.5MHz HSRUN mode), async clock disabled
    adc16_config_t adcUserConfig;
    ADC16_GetDefaultConfig(&adcUserConfig);
    adcUserConfig.clockSource = kADC16_ClockSourceAlt0;
    adcUserConfig.clockDivider = kADC16_ClockDivider8;
    adcUserConfig.enableAsynchronousClock = false;
    adcUserConfig.enableLowPower = false;
    // 16 bit resolution, differential.  VREFH/L as reference
     adcUserConfig.resolution = kADC16_ResolutionDF16Bit;
     adcUserConfig.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
     // Sampling: Gives 14.925us (67 kHz max) conversion time in RUN mode or 11.616us in HSRUN mode
     adcUserConfig.longSampleMode = kADC16_LongSampleCycle16; // 12 extra cycles, 16 in total
     adcUserConfig.enableHighSpeed = false;
     // Interrupt mode, HW trigger enabled, disable continuous convert mode.
    ADC16_EnableHardwareTrigger(base, true);
    adcUserConfig.enableContinuousConversion = false;
    ADC16_Init(base, &adcUserConfig);

    // Disable Averaging
    ADC16_SetHardwareAverage(base, kADC16_HardwareAverageDisabled);

    // Setup channel 0
    adc16_channel_config_t adcChnConfig;
    adcChnConfig.channelNumber = BOARD_ACCEL_ADC_CHANNEL;
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
    adcChnConfig.enableDifferentialConversion = true;
#endif
    adcChnConfig.enableInterruptOnConversionCompleted = true;
    /* Configure channel 0 */
    ADC16_SetChannelConfig(base, BOARD_ACCEL_ADC16_CHANNEL_GROUP, &adcChnConfig);
    return true;
}

void InitADCTriggerSourceToPit0(void)
{
    const pit_chnl_t ADCTrigCh = kPIT_Chnl_0;

     // Initialise PIT0 module and enable run in debug
     pit_config_t pitCfg =
     {
          .enableRunInDebug = true
     };
     PIT_Init(PIT, &pitCfg);
    // Initialise PIT0 timer 0
    // 907.0294785 counts per ADC sample at 44100kHz sample rate @ Bus Clock = 40MHz (RUN mode), 907 counts gives actual sample rate of 44101.43 kHz
    // 1360.544218 counts per ADC sample at 44100kHz sample rate @ Bus Clock = 60MHz (HSRUN mode), 1361 counts gives actual sample rate of 44085.23 kHz
    // 2441.40625 counts per ADC sample at 16384kHz sample rate @ Bus Clock = 40MHz (RUN mode). 2441 counts gives actual sample rate of 16386.726 kHz
     PIT_SetTimerPeriod(PIT, ADCTrigCh, 2441 - 1);
    // Start the PIT timer
    PIT_StartTimer(PIT, ADCTrigCh);

    // Configure SIM for ADC hw trigger source selection
    SIM->SOPT7 |= (SIM_SOPT7_ADC0ALTTRGEN(1) | SIM_SOPT7_ADC0PRETRGSEL(0) | SIM_SOPT7_ADC0TRGSEL(0x4));
}


void BOARD_ACCEL_ADC16_IRQ_HANDLER_FUNC(void)
{
     // NOTE:  There is some overhead to this ISR in the ADC library!
     // Remember runs at 16.384 kHz so needs to be short and sweet
     static uint16_t sampleIndex = 0;

    int16_t result = (int16_t)ADC16_GetChannelConversionValue(BOARD_ACCEL_ADC16_BASEADDR, BOARD_ACCEL_ADC16_CHANNEL_GROUP);

979 Views
larchard
Contributor I

Thanks for this Ashley. I'm away in meetings today, but will try it tomorrow.

Each time I've tried working with Kinetis (and worse with TI) over the last couple of years, I struggle to find introductory resources, battle on unproductively against revision differences for a while, then occasionally discover a stash of documentation that I never knew existed. I don't mind rewriting and datasheet-mining where it's needed, just so long as it's not pointless effort.

Cheers

0 Kudos