8 years, 11 months ago.

ADC0 Interrupt on kl25z

Hey

I'm currently biting my nails trying to get a basic ADC0 Interrupt working on the Kinetis kl25z. After looking into some examples from the Freescale SDK I've assembled tried the following:

void ADC_Init()
{
    ADC0->SC1[0] = ADC_SC1_AIEN_MASK | ADC_SC1_ADCH(11);
    ADC0->SC1[1] = ADC_SC1_ADCH(11);
    ADC0->CFG1 = ADC_CFG1_MODE(1) | ADC_CFG1_ADICLK(2) | ADC_CFG1_ADLSMP_MASK;
    ADC0->SC3 = ADC_SC3_ADCO_MASK | ADC_SC3_AVGS_MASK | ADC_SC3_AVGS(4);
    __enable_irq();
    NVIC_SetVector(ADC0_IRQn, (uint32_t)&ADC0_IRQHandler);
    NVIC_EnableIRQ(ADC0_IRQn);
}

with the above snippet goes this Handler

extern "C" void ADC0_IRQHandler()
{
    NVIC_ClearPendingIRQ(ADC0_IRQn);
    // Write some code here
}

So in summary: - Enable global interrupt - Enable interrupt register in peripheral (ADC_SC1_AIEN_MASK) - Enable interrupt in NVIC: NVIC_EnableIRQ(ADC0_IRQn);

Yet, my interrupt on conversion complete is never fired.

Working with the AnalogIn component is not a problem and works fine, even after using some of the above code to select 12 bits instead of the default 16. But this would require a polling approach which is something I'd like to avoid.

Any thoughts?

I dont directly see wh it doesnt work. How are you sure it never enters the interrupt? Since your handler here does nothing.

However two random thoughts: First of all, especially in 12-bit mode I wonder if bothering with interrupts is worth it, considering how little time it costs to do an AD conversion. Second one: You can also consider putting it in continious mode, then you always have the latest conversion directly available.

posted by Erik - 24 May 2015

In the final code there is a printf and a breakpoint (I'm using openocd with GCC) and it is not being hit. I thought of using a ticker but I'm afraid that in the final application I'll have too many and I don't yet want to go to an rtos.

Are contnious mode and the interrupt mutually exclusive? I did not know that.

posted by K. N. L. V. 24 May 2015

I have no idea if interrupts are exclusive with interrupts, I just meant that if you run it in continious mode you can always read the last conversion directly.

You can't have too many tickers, but they will have more overhead than just ADC interrupt.

posted by Erik - 24 May 2015

For future reference: The following code worked. Due to the "ping pong" nature of the kl25z ADC both SC1[0] and SC1[1] have to be set correctly. SC1[1] is the n + 1 acquisition.

Even with continuous trigger enabled, a first write has to be given to SC1[0] to start the ping pong. So the Interrupt Handler and enable have to be set before the first write to SC1[0]

void ADC_Config()
{
    NVIC_SetVector(ADC0_IRQn, (uint32_t)&ADC0_IRQHandler);
    NVIC_EnableIRQ(ADC0_IRQn);


    ADC0->SC1[1] = ADC_SC1_AIEN_MASK | ADC_SC1_ADCH(11);
    ADC0->CFG1 = ADC_CFG1_MODE(1) | ADC_CFG1_ADICLK(2) | ADC_CFG1_ADLSMP_MASK;
    ADC0->SC3 = ADC_SC3_ADCO_MASK | ADC_SC3_AVGS_MASK | ADC_SC3_AVGS(4); // continuous conversion


    ADC0->SC1[0] = ADC_SC1_AIEN_MASK | ADC_SC1_ADCH(11); // this will trigger first conversion
}
posted by K. N. L. V. 25 May 2015
Be the first to answer this question.