Skip to main content
Dave Jones
Associate III
September 16, 2017
Question

ADC running at half speed

  • September 16, 2017
  • 2 replies
  • 1999 views
Posted on September 17, 2017 at 00:41

I am working with an STM32L452 on a custom board. I use System Workbench as my development system. The initialization code is generated by CubeMX. All of those have been updated (today) to the latest versions.

I have the part configured using an internal oscillator and PLL to run at 80MHz. The system clock, bus clocks, and ADC clock are all at 80 MHZ. I am converting 5 channels through the ADC. They are 'slow' channels, which according to the reference manual simply means they require a longer sampling time. The data sheet shows them capable of sampling and converting at up to 4.21Msps. I am using a slightly longer sampling time (12.5 cycles instead of the 6.5 cycles minimum required for slow channels). The data sheet shows the conversion is 12.5 cycles, so with 12.5 cycles sample time that adds up to a total of 25 cycles for the sampling and conversion.

With an 80MHZ clock and 25 cycles total conversion time, that means it should take 312ns per channel to convert. With 5 channels converting, that should mean I get back 5 results every 1.562 uSec. I double checked these calculations based on the datasheet saying the slow channels can run at 4.21Msps on an 80 MHz clock. That uses a 6.5 cycle sample time and 12.5 cycle conversion. 80MHz/19 cycles = 4.21Msps. So my math is correct, and I should be converting at 3.2Msps. (and 5 channels at 640Ksps each)

I  have it configured to use DMA and a 10 sample buffer, so I get 5 channels on the half complete interrupt and an updated 5 channels on the fully complete interrupt. I am toggling a GPIO pin in those interrupts and watching it on a scope.

Discontinuous mode is disabled, as are injections.

The actual times between interrupts are measuring at about 3 uSec for the first one and about 3.5 uSec for the second one. That is half the calculated speed I described above. If I change the ADC clock pre-scaler from 1 to 8, those same times are 8 times slower as expected, and still half what the calculated speeds are.

I searched here and the only thing I found was from 2 years ago where somebody pointed out that CubeMX was setting the JAUTO bit even when no injection channels were being used, and that was slowing down the ADC.

https://community.st.com/0D50X00009XkhErSAJ

 

But, I checked that by reading the ADC1->CFGR register during my interrupts, saving it, and at a later time reading the saved value via an external device on a serial port where I could examine the value. The JAUTO bit was not set. Neither were any other bits that seemed suspicious.

So, what is going on here???    Anybody have any ideas??

null
    This topic has been closed for replies.

    2 replies

    Tesla DeLorean
    Guru
    September 17, 2017
    Posted on September 17, 2017 at 02:33

    I'm not keen to recreate the scenario, post at least initialization code, ideally a minimal template

    Review clocks actually in use, I tend to crack the running state, so I can change/tune parameters yet still understand the gearing.

    printf('Core=%d, %d MHz\n', SystemCoreClock, SystemCoreClock / 1000000);

    {

      RCC_OscInitTypeDef  RCC_OscInitStruct;

      HAL_RCC_GetOscConfig(&RCC_OscInitStruct);

      if (RCC_OscInitStruct.HSEState == RCC_HSE_BYPASS)    

          printf('HSE BYPASS\n');

      if (RCC_OscInitStruct.HSEState == RCC_HSE_ON)    

          printf('HSE ON\n');

      if (RCC_OscInitStruct.HSEState == RCC_HSE_OFF)    

          printf('HSE OFF\n');

      if (RCC_OscInitStruct.HSIState == RCC_HSI_ON)    

          printf('HSI ON\n');

      if (RCC_OscInitStruct.HSIState == RCC_HSI_OFF)    

          printf('HSI OFF\n');

      if (RCC_OscInitStruct.MSIState == RCC_MSI_ON)    

          printf('MSI ON\n');

      if (RCC_OscInitStruct.MSIState == RCC_MSI_OFF)    

          printf('MSI OFF\n');

      printf('RCC SR HSEBYP %s\n', (RCC->CR & (1 << 18)) ? 'High' : 'Low');

      printf('RCC SR HSERDY %s\n', (RCC->CR & (1 << 17)) ? 'High' : 'Low');

      printf('RCC SR HSEON  %s\n', (RCC->CR & (1 << 16)) ? 'High' : 'Low');

      printf('RCC SR PLLRDY %s\n', (RCC->CR & (1 << 25)) ? 'High' : 'Low');

      printf('RCC SR PLLON  %s\n', (RCC->CR & (1 << 24)) ? 'High' : 'Low');

      printf('RCC CFGR %08X\n', RCC->CFGR);

      switch((RCC->CFGR >> 2) & 3) // SWS

      {

            case 0 : printf('CLOCK SOURCE MSI\n'); break;

            case 1 : printf('CLOCK SOURCE HSI16\n'); break;

            case 2 : printf('CLOCK SOURCE HSE\n'); break;

            case 3 : printf('CLOCK SOURCE PLL\n'); break;    

      }

        

      switch((RCC->CCIPR >> 28) & 3) // ADCSEL

      {

            case 0 : printf('ADCSEL NONE\n'); break;

            case 1 : printf('ADCSEL PLLSAI1 R PLLADC1CLK\n'); break;

            case 2 : printf('ADCSEL PLLSAI2 R PLLADC2CLK\n'); break;

            case 3 : printf('ADCSEL SYSCLK\n'); break;    

      }

        

      printf('APB1=%d\n', HAL_RCC_GetPCLK1Freq());

      printf('APB2=%d\n', HAL_RCC_GetPCLK2Freq());

    }
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Dave Jones
    Associate III
    September 17, 2017
    Posted on September 17, 2017 at 07:39

    I don't have a terminal, or UART port, or display to send printf output to. I have one GPIO pin that I can watch on an oscilloscope, and I have an I2C port that a small external device can probe and read a pair of bytes from (displayed on a small LCD screen on that device, in decimal). So I will have to add code to read a value or bits from the ARM chip and place those bits in one of the two byte variables. Compile, run, then read the values on the external device. Then do it again for another location. Etc.... over and over until I get all the data you mention in your code.

    I'll then post the init functions that CubeMX created, and the results of the probing of those locations.

    Tesla DeLorean
    Guru
    September 17, 2017
    Posted on September 17, 2017 at 14:26

    If you connected SWO on your debug interface you could use the SWV rather than USART terminal. 

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Dave Jones
    Associate III
    September 18, 2017
    Posted on September 18, 2017 at 22:36

    Is there an official place to submit bug reports, such as this one I described above with the HAL_ADC_Start_DMA function in the FW package, and used by CubeMX?

     

    Pevy.Andy
    Associate III
    September 19, 2017
    Posted on September 19, 2017 at 10:11

    Hi Dave,

    It has already been reported...

    https://community.st.com/0D50X00009XkYdJSAV

    Hopefully the documentation will be fixed in a new version of the docs.

    Andy