cancel
Showing results for 
Search instead for 
Did you mean: 

can't print ADC data at high Sample Rate

smile
Associate II

I configured dual DAC synchronous sampling,DMA is in normal mode for data transfer.

When the timer frequency of the ADC is 10KHz, the main cycle can print serial port information, but when the timer frequency is 50KHz, the main cycle does not print ADC data information. What is the reason for this? Below is my cubemx software configuration and related code.

smile_1-1749565503034.png

 

int main()

smile_2-1749565669615.png

CallBack:

smile_4-1749565734482.png

smile_11-1749566098919.png

smile_12-1749566139894.png

 

ADC

smile_5-1749565884302.png

smile_6-1749565897240.png

smile_7-1749565923182.png

smile_8-1749565933535.png

 

DMA

smile_9-1749565948108.png

 

NVIC

smile_10-1749565962406.png

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

Printing out samples over UART at 50 kHz is a non-starter. The bandwidth is insufficient.

In general, don't put long blocking calls like UART transmissions in your interrupt handlers.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

5 REPLIES 5
Andrew Neil
Super User

Please see How to insert source code - not as images.

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.
TDK
Super User

Printing out samples over UART at 50 kHz is a non-starter. The bandwidth is insufficient.

In general, don't put long blocking calls like UART transmissions in your interrupt handlers.

If you feel a post has answered your question, please click "Accept as Solution".
smile
Associate II
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dac.h"
#include "dma.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//#include "AD9833.h"
#include "Key.h"  
#include "LCD.h"
#include "LowPowerCtrl.h"
// #include "stm32f4xx_hal_rcc.h"
#include "SignalGenerator.h"
#include "SignalSampling.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint32_t adc_buffer[ADC_BUFFER_SIZE]; // 注意是uint32_t,因为双ADC打包成32位

uint16_t adc_buffer1[ADC_BUFFER_SIZE]; 
uint16_t adc_buffer2[ADC_BUFFER_SIZE]; 
#define ADC_TIM_Clock 84e6 // 定时器时钟频率
#define ADC1_TRIGGER htim3
#define ADC_BUFFER_SIZE 128  // 假设采2048组数据(FFT一般要2的幂次)
#define ADC_SampleRate 50e3

void ADC_SetSampleRate(TIM_HandleTypeDef *htim, float sample_rate)
{
    uint32_t Timer_Clock = ADC_TIM_Clock / (htim->Instance->PSC + 1);
    uint32_t timer_reload_value = (uint32_t)(Timer_Clock / sample_rate) - 1;
    if (timer_reload_value < 1) timer_reload_value = 1;

    HAL_TIM_Base_Stop(htim);                   // 安全:暂停 TIM
    __HAL_TIM_SET_AUTORELOAD(htim, timer_reload_value);
    __HAL_TIM_SET_COUNTER(htim, 0);            // 重置计数器
    HAL_TIM_Base_Start(htim);                  // 重新启动 TIM

    USART_Printf(&huart1, "ADC TimerClock=%lu, ARR=%lu, SampleRate=%.1f Hz\r\n",
                 Timer_Clock, timer_reload_value, sample_rate);
}



// RTC_AlarmTypeDef RTCB_sTime;



//按键库测试

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  MX_TIM2_Init();
  MX_TIM1_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_DAC_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  MX_TIM5_Init();
  MX_TIM6_Init();
  /* USER CODE BEGIN 2 */

  // while(HAL_GPIO_ReadPin(WKUP_GPIO_Port,WKUP_Pin) == GPIO_PIN_SET);  

  if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB)) 
  { 
       USART_Printf(&huart1,"IF:SB:%d  WU:%d\n",__HAL_PWR_GET_FLAG(PWR_FLAG_SB),__HAL_PWR_GET_FLAG(PWR_FLAG_WU));
      __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);  // 
      __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);  // 
      
  }

  HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
  USART_Printf(&huart1,"SB:%d  WU:%d\n",__HAL_PWR_GET_FLAG(PWR_FLAG_SB),__HAL_PWR_GET_FLAG(PWR_FLAG_WU));


  // DAC_Init();


  Key_Init(); // 

  // HAL_TIM_Base_Start_IT(&htim6);
  USART_Printf(&huart1,"reset!\r\n");



  ADC_SetSampleRate(&ADC1_TRIGGER,ADC_SampleRate);
  HAL_Delay(2000);
  HAL_ADC_Start(&hadc2);
  HAL_ADCEx_MultiModeStart_DMA(&hadc1,adc_buffer,ADC_BUFFER_SIZE);
  HAL_TIM_Base_Start_IT(&ADC1_TRIGGER);
  /* USER CODE END 2 */

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


    if(ADC1_CompleteFlag == 1)
    {
      for(uint16_t i = 0 ; i< ADC_BUFFER_SIZE ; i++)
      {
        adc_buffer1[i] = (adc_buffer[i] & 0x0000FFFF);
        adc_buffer2[i] = (adc_buffer[i] & 0xFFFF0000) >> 16;

        // USART_Printf(&huart1,"%d,%d,%d\n",adc_buffer[i],adc_buffer1[i],adc_buffer2[i]);
        // USART_Printf(&huart1,"%d,%d\n",adc_buffer1[i],adc_buffer2[i]);
        USART_Printf(&huart1,"%d\n",adc_buffer2[i]);
      }
      ADC1_CompleteFlag =  0;
    }
      



    
      // Key_Process();  

      // HAL_Delay(10); 




    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }

  /** Enables the Clock Security System
  */
  HAL_RCC_EnableCSS();
}

/* USER CODE BEGIN 4 */


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  if(hadc == &hadc1)
  {

    USART_Printf(&huart1,"ADC Complete!\n");
    ADC1_CompleteFlag = 1; // 

  }

}

void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
{
  if(hadc == &hadc1)
    ADC1_CompleteFlag = 1;
}



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim == &ADC1_TRIGGER)
  {
    USART_Printf(&huart1, "ADC_Timer Interrupt\n");
  }

  if(htim == &htim5)
  {


  }

  if(htim == &htim6)
  {
    
  }
}
smile
Associate II

I still don't understand
My DMA works in normal mode and only starts once after powering up, and no more after that. Just set the flag of the ADC sampling in the ADC callback function. Waiting for the ADC to complete the acquisition in the main cycle, and then printing out the data, what does this have to do with the serial port rate?


@smile wrote:

what does this have to do with the serial port rate?


12 bit ADC data printed in decimal with a line ending takes max 4 digits and 1 line ending character. So 5 characters.
With 1 startbit,1 stop bit, 8 bit data, you need 10 bit times for 1 byte, so 50 bit times per sample. of your UART. 50ks/s would require 2.5MBaud if data is send back to back.That's very high. You can save a little by switching to 7-bit mode, but you still would need 2.25MBaud
Sending it in binary mode would mean each sample will take 2 bytes. If you combine 2 samples you can send 2 samples in 3 bytes with 1.5 bytes per sample. That would require 750KBaud. Much more doable. Using 1MBaud would add some headroom.
In theory you could even do some type of compression. Such as sending the differences between samples and not the absolute value. And then using a variable length int to save space. In that case a sample would take a little over 1 byte on average, and 2 bytes max.

If latency is acceptable you can save samples in a buffer. Convert them and then send them in batches. I would use the DMA for transmitting.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.