cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G474 TIM triggered ADC + DMA limited to 50kHz (50ksps)

acsatue
Associate II

Hi all, I am triggering ADC conversion from TIM1 and I can't achieve sampling rate higher than 50kHz. I am using STM32G474RE and HAL library. Based on AN5496 and AN5497 I should be able to do it up to 200kHz and my target is 100kHz.

 

I am testing STM32G474 (STEVAL-DPSG474) for a power converter application where i need to sample ADC at 100kHz (Timer TRGO driven). For that purpose I use ADC + DMA sampling without FMAC, and SPI transfering the sampled data.

As ADC samples in 16bit format (12bit converter) I am using 2 bytes per data for SPI transfer. A tests would send 2 values through SPI, one comming from ADC (2 variable bytes), and the other a fixed one for debug (2 fixed bytes):

 

// main.c

/* USER CODE BEGIN PV */

#define Buflen 1
uint16_t adcValue = 0;
volatile uint16_t adc_dma_result[Buflen];
uint8_t SPI_buffer_tx[4] = {20, 60, 160, 200};

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
void MX_RTC_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM15_Init(void);
static void MX_TIM16_Init(void);
static void MX_TIM17_Init(void);
static void MX_TIM1_Init(void);
static void MX_SPI3_Init(void);

/* USER CODE END PV */

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_RTC_Init();
  MX_ADC1_Init();
  MX_TIM15_Init();
  MX_TIM16_Init();
  MX_TIM17_Init();
  MX_TIM1_Init();
  MX_SPI3_Init();
  /* USER CODE BEGIN 2 */

  /* Perform an ADC automatic self-calibration and enable ADC */
  if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }

  /* Start the ADC DMA */
  if (  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_dma_result, Buflen) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }

  // start pwm generation
  if(HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK) {
                Error_Handler();
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  }
}

 

In order to debug the development I am sending an SPI message with logged ADC data every Transfer Completed using HAL predefined function

 

// stm32g4xx_it.c

/* USER CODE BEGIN 1 */

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  /* Prevent unused argument(s) compilation warning */
  //UNUSED(hadc);
	if (hadc == &hadc1) {

		  adcValue = adc_dma_result[0];

		  SPI_buffer_tx[1]=adcValue & 0xFF;
		  SPI_buffer_tx[0]=(adcValue >>  & 0xFF;

		  HAL_SPI_Transmit(&hspi3, SPI_buffer_tx, sizeof(SPI_buffer_tx), 1000);

		//If continuousconversion mode is DISABLED uncomment below
		HAL_ADC_Start_DMA(&hadc1, (uint32_t*)dmaBuffer, Buflen);
			
	}
}

/* USER CODE END 1 */

 

Main clock is HSI + PLL (170MHz) for TIM and ADC is configured at 56.66MHz, so a single ADC input should be done in less than 10us (1/100kHz).

Clock Config.png

 

To configure TIM1 to trigger TRGO at 100kHz I am configuring it with PSC = 0 and ARR = 1699. 170MHz TIM1 CLK would result on 100kHz period as stated in this support note.

 

What I achieve is a 50kHz sampling (20us between SPI transfers). If I increase TIM1 ARR over 3.399 (value for 50kHz) the sampling rate starts to decrease from 50kHz. I can sample at exact 20kHz, 30kHz, 40kHz... but under ARR=3.399 I can't see any sampling increase over 50kHz. Could it be because AN5497 is based on CRM SRAM memory instead of flash? Could it be because they use DMA+FMAC instead of DMA register reading? Could it be because I use HAL library and LL is more optimised for register programming?

In next figure I represent 50kHz ADC sampling and SPI sending (20us between SPI send) sending 4 bytes.

50kHz_spi.png

When I RUN the code (no matter if Debug or Release version) it samples just once, and in ADC I can measure a decreasing value from original value. In numbers:

ADC input is 0V, that with right alignment corresponds to around 17000 ADC value (12 bits). In SPI (hex coded) I can see around 10-20 samples starting from 17000 and ending at 0. Could it be the ADC SAR capacities discharging? (as If I only sample once)

 

Thanks in advance for any help or tip!

11 REPLIES 11

> My optimization level is None (-O0)

So use any other, start perhaps with -O2. Some recommend -Og, optimized for debug, as a tradeoff. Anything but -O0.

Debug level is irrelevant for this issue.

JW

acsatue
Associate II

Finally I switched to Simulink Embedded Coder for the application (it is based on LL library, not HAL), and the problem is solved.

ADC triggered by HRTIM at 100kHz is working using DMA TC interrupts.

SPI baud rate is limited due to the SPI clock (20Mbps), and data buffer size to be transferred (6 values with 2 bytes/value for now).

 

Pros: Fast prototyping

Cons: Difficulty to reduce non-deterministic transfer time and baud rate for SPI. Here I show how data transfer at 20kbauds (desired 50us between data package) could result in a conversion time from 12us (24% of real time) to 31us (62%). I will consider reducing SPI clock to 10Mbps and reduce baud rate to 1kHz or even 100Hz as it is only for external datalogging.

acsatue_0-1702991028101.png

Thank you all for your tips and support!