2025-06-10 7:36 AM - last edited on 2025-06-10 8:06 AM by Andrew Neil
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.
int main()
CallBack:
ADC
DMA
NVIC
Solved! Go to Solution.
2025-06-10 8:02 AM
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.
2025-06-10 8:02 AM
Please see How to insert source code - not as images.
2025-06-10 8:02 AM
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.
2025-06-10 8:15 AM
/* 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)
{
}
}
2025-06-10 8:32 AM
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?
2025-06-10 9:20 AM - edited 2025-06-10 9:24 AM
@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.