АЦП на плате NUCLEO-STM32F401RE не работает за пределами 10 кГц входного сигнала - PullRequest
2 голосов
/ 05 июня 2019

Plot of 60-80kHz using continuous conversion- DMAEdit 1:Image of 10kHz to 50kHz input signal using continuous conversion Я использую АЦП на плате NUCLEO-STM32F401RE.Я запрограммировал АЦП, используя прерывания, храню около 10000 значений в массиве и читаю их, используя файл .ini.Код не работает за пределами 10 кГц входного сигнала.АЦП имеет разрешение 12 бит с 3 циклами дискретизации;Тактовая частота АЦП составляет 21 кГц.Ниже приведен мой код и график значений для диапазона входных частот синусоидальной волны 1-200 кГц.Входное напряжение составляет 1,3 В.Чего мне не хватает?

#include "main.h"
#include "stm32f4xx_hal.h" 
ADC_HandleTypeDef hadc1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);

uint32_t adc_data[10000];
uint32_t i=0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{   if (i<10000) {
adc_data[i]= HAL_ADC_GetValue(&hadc1);
    i++;
HAL_ADC_Start_IT(&hadc1);
}
    else {
    HAL_ADC_Stop_IT(&hadc1);
}
}

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_ADC1_Init();
  /* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc1);

while (1)
  {

  }

}


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_SCALE2);
  /**Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /**Initializes the CPU, AHB and APB busses 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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};

  /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of     conversion) 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and              its sample time. 
   */
   sConfig.Channel = ADC_CHANNEL_0;
   sConfig.Rank = 1;
   sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
   {
     Error_Handler();
   }
 }

 static void MX_GPIO_Init(void)
 { 
   /* GPIO Ports Clock Enable */
   __HAL_RCC_GPIOA_CLK_ENABLE();

 }

 void Error_Handler(void)
 {

 }

 #ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{ 
}
#endif /* USE_FULL_ASSERT */

график значений для диапазона входных частот 1-200 кГц

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Я предполагаю, что 21 кГц является опечаткой, и АЦП работает на APB2 / 4 = 21 МГц.Время выборки составляет 3 цикла, время преобразования при разрешении 12 битов составляет 12 циклов, поэтому частота дискретизации АЦП равна = 1,4 МГц (21/(12+3)).Когда ядро ​​работает на частоте 84 МГц, это одна выборка каждые 60 ядерных циклов.

60 циклов едва хватает даже для запуска выполнения обработчика прерываний с учетом состояний ожидания флэш-памяти.

Глядя на график, который вы прикрепили, выглядит, что фактическая частота дискретизации составляет 300 кГц (в полном цикле сигнала 10 кГц 30 выборок), то есть 3,33 мкс,или 25200 тактов.Учитывая нелепое количество служебных данных в HAL , это кажется реалистичным.

Ваш код выполняет однократное преобразование с прерыванием, которое запускается после его завершения, затем читает и сохраняет значение и только после этого инструктируетАЦП, чтобы начать следующее преобразование, вводя переменную задержку, которая зависит от пары трудно прогнозируемых факторов.

Использование непрерывного преобразования

АЦП может перезапустить покрытие (или последовательностьесли он есть), либо сразу после окончания последнего, либо с помощью таймера, см. описание битов EXTSEL, EXTEN, SCAN и CONT регистров управления в Справочном руководстве.Он может даже инициировать передачу DMA после каждого преобразования, поэтому вы можете настроить канал DMA для сохранения показаний в буфере.Это гарантировало бы равные интервалы дискретизации даже при максимально возможной частоте дискретизации.

0 голосов
/ 05 июня 2019

Пожалуйста, взгляните на Частота Найквиста

Короче говоря: С частотой АЦП 21 кГц вы можете сэмплировать вход с 7 кГц, а это означает, что ваш максимально возможная частота сигнала составляет ~ 3,5 кГц.

...