cancel
Showing results for 
Search instead for 
Did you mean: 

Conversion time ADC too low

MKlos.1
Associate II

Hi,

I have a NUCLEO-F429ZI board and am trying to get ADC1 to convert one channel (channel 3) when triggered by TIM2 (every second).

As I don't have an oscilloscope I wanted to measure the conversion time - to make sure everything is configured correctly - using Segger SystemView.

With the code below I set ADCCLK to 22.5 MHz and sample time to 480 clock cycles so I would expect the ADC interrupt to occur roughly 22 µs after the timer interrupt.

What I am seeing though is that the ADC interrupt (ISR34) occurs 2.6 µs after the timer ISR (ISR 44) (see screenshot).

0693W000001qkj0QAA.png

Quesion: Why is the ADC interrupt so fast?

The attached ZIP-file is the complete Segger Studio project, ready to compile.

Here's the complete code:

/*********************************************************************
*                    SEGGER Microcontroller GmbH                     *
*                        The Embedded Experts                        *
**********************************************************************
*                                                                    *
*            (c) 2014 - 2020 SEGGER Microcontroller GmbH             *
*                                                                    *
*           www.segger.com     Support: support@segger.com           *
*                                                                    *
**********************************************************************
*                                                                    *
* All rights reserved.                                               *
*                                                                    *
* Redistribution and use in source and binary forms, with or         *
* without modification, are permitted provided that the following    *
* conditions are met:                                                *
*                                                                    *
* - Redistributions of source code must retain the above copyright   *
*   notice, this list of conditions and the following disclaimer.    *
*                                                                    *
* - Neither the name of SEGGER Microcontroller GmbH                  *
*   nor the names of its contributors may be used to endorse or      *
*   promote products derived from this software without specific     *
*   prior written permission.                                        *
*                                                                    *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *
* DISCLAIMED.                                                        *
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR        *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
* DAMAGE.                                                            *
*                                                                    *
**********************************************************************
 
-------------------------- END-OF-HEADER -----------------------------
 
File    : main.c
Purpose : Generic application start
 
*/
 
#include <stm32f4xx.h>
#include "SEGGER_SYSVIEW.h"
 
void ClockInit(void)
{
    uint32_t timeout = 1000000;
    
    // enable flash prefetch
    FLASH->ACR |= FLASH_ACR_PRFTEN;
    // set 5 wait states (needed for high PLL frequency)
    FLASH->ACR &= ~FLASH_ACR_LATENCY_Msk;
    FLASH->ACR |= FLASH_ACR_LATENCY_5WS;
    do
    {
        timeout--;
    } while (((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != FLASH_ACR_LATENCY_5WS) && (timeout > 0));
    
    // switch on external clock, bypass HSE with it and wait for clock to be ready
    RCC->CR |= (RCC_CR_HSEON | RCC_CR_HSEBYP);
    timeout = 1000000;
    do
    {
        timeout--;
    } while (((RCC->CR & RCC_CR_HSERDY_Msk) != RCC_CR_HSERDY) && (timeout > 0));
    
    // configure (HSE as clock source, M = 4, N = 180, P = 2), enable and wait for PLL
    RCC->PLLCFGR = (RCC_PLLCFGR_PLLSRC_HSE | (4 << RCC_PLLCFGR_PLLM_Pos) | (180 << RCC_PLLCFGR_PLLN_Pos));
    RCC->CR |= RCC_CR_PLLON;
    timeout = 1000000;
    do
    {
        timeout--;
    } while (((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY) && (timeout > 0));
    
    // configure rest of clock tree
    RCC->CFGR &= ~(RCC_CFGR_PPRE2_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_HPRE_Msk);
    RCC->CFGR |= (RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1);
    
    // set PLL as clock source and wait until clock is ready
    RCC->CFGR &= ~(RCC_CFGR_SW_Msk);
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    timeout = 1000000;
    do
    {
        timeout--;
    } while (((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) && (timeout > 0));
    
    SystemCoreClockUpdate();
    
    // enable GPIOA, ADC1 and TIM2 clocks
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
}
 
void TimerInit(void)
{
    // counter direction down, generate update event only on underflow
    TIM2->CR1 |= (TIM_CR1_DIR | TIM_CR1_URS);
    // set update event as trigger source
    TIM2->CR2 &= ~TIM_CR2_MMS_Msk;
    TIM2->CR2 |= TIM_CR2_MMS_1;
    // enable update interrupt
    TIM2->DIER |= TIM_DIER_UIE;
    // set timer and reload value for update generation every 1000 ms
    TIM2->ARR = TIM2->CNT = 90000000;
}
 
void TimerStart(void)
{
    TIM2->CR1 |= TIM_CR1_CEN;
}
 
void AdcInit(void)
{
    // PA3 as analog input
    GPIOA->MODER |= GPIO_MODER_MODE3;
    // set clock prescaler to 4 -> 22,5 MHz
    ADC123_COMMON->CCR |= ADC_CCR_ADCPRE_0;
    // enable timer 2 trigger event as start trigger on rising edge and generate EOC interrupt after each conversion
    ADC1->CR2 |= (ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_EXTEN_0 | ADC_CR2_EOCS);
    // set 480 cycles sample time for channel 3
    ADC1->SMPR2 |= ADC_SMPR2_SMP3;
    // set channel 3 as first (any only) regular channel
    ADC1->SQR3 |= (ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_1);
    // enable EOC interrupt
    ADC1->CR1 |= ADC_CR1_EOCIE;
    // enable ADC
    ADC1->CR2 |= ADC_CR2_ADON;
}
 
void InterruptInit(void)
{
    // Timer 2
    NVIC_SetPriority(TIM2_IRQn, 3);
    NVIC_ClearPendingIRQ(TIM2_IRQn);
    NVIC_EnableIRQ(TIM2_IRQn);
    // ADC
    NVIC_SetPriority(ADC_IRQn, 2);
    NVIC_ClearPendingIRQ(ADC_IRQn);
    NVIC_EnableIRQ(ADC_IRQn);
}
 
void TIM2_IRQHandler(void)
{
    SEGGER_SYSVIEW_RecordEnterISR();
    NVIC_ClearPendingIRQ(TIM2_IRQn);
    TIM2->SR &= ~TIM_SR_UIF;
}
 
void ADC_IRQHandler(void)
{
    uint16_t Value;
    SEGGER_SYSVIEW_RecordEnterISR();
    Value = ADC1->DR;
    NVIC_ClearPendingIRQ(ADC_IRQn);
}
 
int main(void)
{
    ClockInit();
    
    SEGGER_SYSVIEW_Conf();
    
    TimerInit();
    AdcInit();
    InterruptInit();
    
    TimerStart();
    while(1);
}
 
/*************************** End of file ****************************/

1 ACCEPTED SOLUTION

Accepted Solutions

> // set channel 3 as first (any only) regular channel

> ADC1->SQR3 |= (ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_1);

Isn't this setting channel 6 rather than 3?

JW

View solution in original post

4 REPLIES 4

> // set channel 3 as first (any only) regular channel

> ADC1->SQR3 |= (ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_1);

Isn't this setting channel 6 rather than 3?

JW

MKlos.1
Associate II

Yes, you are correct, that's the wrong channel! But does that really explain why the ADC interrupt occurs too fast?

I would have expected (without knowing for sure) the values to be different from the ones I would have expected but haven't even checked yet (as the input is not configured correctly) but not that the conversion is finished in a tenth of the time.

I can only try tonight as I don't have the hardware with me at the moment.

Best regards

> Yes, you are correct, that's the wrong channel! But does that really explain why the ADC interrupt occurs too fast?

How's channel 6 sample rate set?

JW

Oh man, you are so right! It was - of course - set to 0 (its reset value) and therefore to 3 cycles. I will have to get used to this per-channel sampling time configuration and take even better care about setting the correct bits!

After setting channel 3 in register ADC_SQR3 I now get a conversion time - measured with SystemView - of 21.9 µs!

Thanks a lot for the help!