Перейти к содержанию
    

STM32G474 Nucleo ADC+DMA+FMAC

Приветствую форумчане!

Захотелось мне для опыта запустить блок аппаратного фильтра на STM32G474 в режиме реального времени. То есть данные с АЦП поступают через DMA на FMAC, там LP FIR фильтр, а дальше опять через DMA на ЦАП. Честно говоря я похоже переоценил свои знания и полностью завяз в попытки это написать и даже понять как это должно выглядеть. Использую CubeIDE и, соответственно, кодогенератор MX, специализированных знаний по Cortex-M4 не имею, поможИте как говорится.

Писал КИХ по ПЛИС-ы но там все как-то прозрачнее, а тут я даже не понимаю как сигнал по линии задержки должен двигаться и как тактируется блок так как все скрыто структурами.

Для тактирования запустил таймер 4 на 100кГц, все хочу тактировать от него. АЦП работает скидывает данные по ПДП в единичный буфер. Вспомогательный ЦАП так же через ПДП считывает оттуда и выводит наружу, тут все ОК.

Второй ЦАП должен выводить уже отфильтрованные , ну естессно тут ничего не работает))

Вот что накидал из кусков кода

https://www.st.com/resource/en/application_note/dm00605584-digital-filter-implementation-with-the-fmac-using-stm32cubeg4-mcu-package-stmicroelectronics.pdf

https://www.compel.ru/lib/139617

Но не понимаю даже почему кодогенератор не делает инициализации для FMAC DMA, или делает, но я не понимаю.

Не пинайте сильно)

Еще осциллограф прикрепил, желтый входной, синий - отсчеты АЦП (выведенные церез ЦАП), зеленый тестовая синусоида на ЦАП2, красный - таймер 4 (тактирование)

image.thumb.png.7684e9bf111d20009b4bf74d7f641300.png

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* 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 ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

DAC_HandleTypeDef hdac1;
DAC_HandleTypeDef hdac2;
DMA_HandleTypeDef hdma_dac1_ch1;
DMA_HandleTypeDef hdma_dac2_ch1;

FMAC_HandleTypeDef hfmac;
DMA_HandleTypeDef hdma_fmac_read;
DMA_HandleTypeDef hdma_fmac_write;

UART_HandleTypeDef hlpuart1;

TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim4;

/* USER CODE BEGIN PV */

uint16_t ADC_data[1]; // Данные с АЦП
uint16_t FMAC_out[1]; // Данные на выходе фильтра

// Тестовый синус для проверки ЦАП-ов
uint16_t Test_data[64] =
{2048,2248,2447,2642,2831,3013,3185,3346,3495,3630,3750,3853,3939,4007,4056,4085,
4095,4085,4056,4007,3939,3853,3750,3630,3495,3346,3185,3013,2831,2642,2447,2248,
2048,1847,1648,1453,1264,1082,910,749,600,465,345,242,156,88,39,10,
0,10,39,88,156,242,345,465,600,749,910,1082,1264,1453,1648,1847};

// Коэффициенты КИХ фильтра
static int16_t FilterCoeffB[51] =
{0,11,25,46,78,122,182,261,360,481,623,787,970,1169,1382,1603,1828,2051,2266,2468,2649,2806,2934,3028,3086,3105,
3086,3028,2934,2806,2649,2468,2266,2051,1828,1603,1382,1169,970,787,623,481,360,261,182,122,78,46,25,11,0};

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_LPUART1_UART_Init(void);
static void MX_TIM1_Init(void);
static void MX_ADC1_Init(void);
static void MX_DAC1_Init(void);
static void MX_TIM4_Init(void);
static void MX_FMAC_Init(void);
static void MX_DAC2_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

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

void delay_us (uint16_t us)
{
	__HAL_TIM_SET_COUNTER(&htim1,0);  // set the counter value a 0
	while (__HAL_TIM_GET_COUNTER(&htim1) < us);  // wait for the counter to reach the us input in the parameter
}

/* 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_LPUART1_UART_Init();
  MX_TIM1_Init();
  MX_ADC1_Init();
  MX_DAC1_Init();
  MX_TIM4_Init();
  MX_FMAC_Init();
  MX_DAC2_Init();
  /* USER CODE BEGIN 2 */

  HAL_TIM_Base_Start(&htim1);
  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);

  HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*)&ADC_data, 1, DAC_ALIGN_12B_R); // Выводим входные данные на ЦАП для контроля

  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); 		// ADC Calibration
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_data, 1); 			// Запускаем АЦП с сохранением по DMA

  HAL_DAC_Start_DMA(&hdac2, DAC_CHANNEL_1, (uint32_t*)&FMAC_out, 1, DAC_ALIGN_12B_R); // Выводим входные данные КИХ фильра на ЦАП
//  HAL_DAC_Start_DMA(&hdac2, DAC_CHANNEL_1, (uint32_t*)&Test_data, 64, DAC_ALIGN_12B_R); // Тестовая синусоида для проверки ЦАП-а

  __HAL_RCC_FMAC_CLK_ENABLE();
  FMAC_FilterConfigTypeDef sFmacConfig; 			/* declare a filter configuration structure */
  sFmacConfig.CoeffBaseAddress = 0; 				/* Set the coefficient buffer base address */
  sFmacConfig.CoeffBufferSize = 51; 				/* Set the coefficient buffer size to the number of coeffs */
  sFmacConfig.InputBaseAddress = 51; 				/* Set the Input buffer base address to the next free address */
  sFmacConfig.InputBufferSize = 100; 				/* Set the input buffer size greater than the number of coeffs */
  sFmacConfig.InputThreshold = 0; 					/* Set the input watermark to zero since we are using DMA */
  sFmacConfig.OutputBaseAddress = 151; 				/* Set the Output buffer base address to the next free address */
  sFmacConfig.OutputBufferSize = 100; 				/* Set the output buffer size */
  sFmacConfig.OutputThreshold = 0; 					/* Set the output watermark to zero since we are using DMA */
  sFmacConfig.pCoeffA = NULL; 						/* No A coefficients since FIR */
  sFmacConfig.CoeffASize = 0;
  sFmacConfig.pCoeffB = FilterCoeffB; 				/* Pointer to the coefficients in memory */
  sFmacConfig.CoeffBSize = 51; 						/* Number of coefficients */
  sFmacConfig.Filter = FMAC_FUNC_CONVO_FIR; 		/* Select FIR filter function */
  sFmacConfig.InputAccess = FMAC_BUFFER_ACCESS_DMA; /* Enable DMA input transfer */
  sFmacConfig.OutputAccess = FMAC_BUFFER_ACCESS_DMA;/* Enable DMA output transfer */
  sFmacConfig.Clip = FMAC_CLIP_ENABLED; 			/* Enable clipping of the output at 0x7FFF and 0x8000 */
  sFmacConfig.P = 51; 								/* P parameter contains number of coefficients */
  sFmacConfig.Q = 0; 								/* Q parameter is not used */
  sFmacConfig.R = 0;  								/* R parameter contains the post-shift value (none) */
  if (HAL_FMAC_FilterConfig(&hfmac, &sFmacConfig) != HAL_OK) /* Configure the FMAC */
  Error_Handler(); 									/* Configuration Error */

  if (HAL_FMAC_AppendFilterData(&hfmac, (int16_t*)&ADC_data[0], (uint16_t*)1) != HAL_OK)
   Error_Handler();

  if (HAL_FMAC_FilterStart(&hfmac, (int16_t*)&FMAC_out, (uint16_t*)1) != HAL_OK)
  Error_Handler();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
//	  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
//	  HAL_Delay(50);
//	  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
//	  HAL_Delay(50);

    /* 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};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
  /** 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 = RCC_PLLM_DIV6;
  RCC_OscInitStruct.PLL.PLLN = 85;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  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_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the peripherals clocks
  */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1|RCC_PERIPHCLK_ADC12;
  PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1;
  PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief ADC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T4_TRGO;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

/**
  * @brief DAC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_DAC1_Init(void)
{

  /* USER CODE BEGIN DAC1_Init 0 */

  /* USER CODE END DAC1_Init 0 */

  DAC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN DAC1_Init 1 */

  /* USER CODE END DAC1_Init 1 */
  /** DAC Initialization
  */
  hdac1.Instance = DAC1;
  if (HAL_DAC_Init(&hdac1) != HAL_OK)
  {
    Error_Handler();
  }
  /** DAC channel OUT1 config
  */
  sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_AUTOMATIC;
  sConfig.DAC_DMADoubleDataMode = DISABLE;
  sConfig.DAC_SignedFormat = DISABLE;
  sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
  sConfig.DAC_Trigger = DAC_TRIGGER_T4_TRGO;
  sConfig.DAC_Trigger2 = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_EXTERNAL;
  sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
  if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN DAC1_Init 2 */

  /* USER CODE END DAC1_Init 2 */

}

/**
  * @brief DAC2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_DAC2_Init(void)
{

  /* USER CODE BEGIN DAC2_Init 0 */

  /* USER CODE END DAC2_Init 0 */

  DAC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN DAC2_Init 1 */

  /* USER CODE END DAC2_Init 1 */
  /** DAC Initialization
  */
  hdac2.Instance = DAC2;
  if (HAL_DAC_Init(&hdac2) != HAL_OK)
  {
    Error_Handler();
  }
  /** DAC channel OUT1 config
  */
  sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_AUTOMATIC;
  sConfig.DAC_DMADoubleDataMode = DISABLE;
  sConfig.DAC_SignedFormat = DISABLE;
  sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
  sConfig.DAC_Trigger = DAC_TRIGGER_T4_TRGO;
  sConfig.DAC_Trigger2 = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_EXTERNAL;
  sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
  if (HAL_DAC_ConfigChannel(&hdac2, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN DAC2_Init 2 */

  /* USER CODE END DAC2_Init 2 */

}

/**
  * @brief FMAC Initialization Function
  * @param None
  * @retval None
  */
static void MX_FMAC_Init(void)
{

  /* USER CODE BEGIN FMAC_Init 0 */

  /* USER CODE END FMAC_Init 0 */

  /* USER CODE BEGIN FMAC_Init 1 */

  /* USER CODE END FMAC_Init 1 */

  hfmac.Instance = FMAC;
  if (HAL_FMAC_Init(&hfmac) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN FMAC_Init 2 */

  /* USER CODE END FMAC_Init 2 */

}

/**
  * @brief LPUART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_LPUART1_UART_Init(void)
{

  /* USER CODE BEGIN LPUART1_Init 0 */

  /* USER CODE END LPUART1_Init 0 */

  /* USER CODE BEGIN LPUART1_Init 1 */

  /* USER CODE END LPUART1_Init 1 */
  hlpuart1.Instance = LPUART1;
  hlpuart1.Init.BaudRate = 115200;
  hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
  hlpuart1.Init.StopBits = UART_STOPBITS_1;
  hlpuart1.Init.Parity = UART_PARITY_NONE;
  hlpuart1.Init.Mode = UART_MODE_TX_RX;
  hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&hlpuart1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN LPUART1_Init 2 */

  /* USER CODE END LPUART1_Init 2 */

}

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 170-1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */

}

/**
  * @brief TIM4 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM4_Init(void)
{

  /* USER CODE BEGIN TIM4_Init 0 */

  /* USER CODE END TIM4_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM4_Init 1 */

  /* USER CODE END TIM4_Init 1 */
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 1;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 849;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 425;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */

  /* USER CODE END TIM4_Init 2 */
  HAL_TIM_MspPostInit(&htim4);

}

/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMAMUX1_CLK_ENABLE();
  __HAL_RCC_DMA1_CLK_ENABLE();
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
  /* DMA2_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : B1_Pin */
  GPIO_InitStruct.Pin = B1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 

ScreenImg (43).png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В общем, сам спросил сам и отвечаю:)

Все сделал в точности по примеру "Example 2: 3p3z compensator" из приведенного выше документа только с изменением на КИХ фильтр и вывод на ЦАП по ДМА.

Показываю ключевые моменты кода. Главная идея, что данные от АЦП передаем через DMA напрямую в FMAС  "perip to perip".

На самом деле там в примере есть "секреточка", а в целом все проблемы связаны с тем, что ST еще не допилили ни CMSIS, ни CubeMX, ни свои библиотеки под этот новый блок до конца.

1146543756_ScreenImg(44).thumb.png.f0a693bac2b991efdcbd9e7151d67720.png

#define FILTER_OUT_BUFFER_SIZE 1
#define FILTER_IN_BUFFER_SIZE 1
#define FILTER_TAP 127
  
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
DAC_HandleTypeDef hdac2;
DMA_HandleTypeDef hdma_dac2_ch1;
FMAC_HandleTypeDef hfmac;
DMA_HandleTypeDef hdma_fmac_read;
TIM_HandleTypeDef htim4;

uint16_t ADC_data[FILTER_IN_BUFFER_SIZE];  // Данные с АЦП
uint16_t FMAC_out[FILTER_OUT_BUFFER_SIZE]; // Данные на выходе фильтра

static int16_t FilterCoeffB[127] =			// Коэффициенты КИХ
{-10,-10,-10,-9,-9,-9,-8,-8,-7,-6,-5,-4,-2,0,3,6,10,14,19,25,32,40,48,57,68,79,91,104,118,134,150,
166,184,203,222,242,263,284,306,328,350,373,396,418,441,463,485,506,527,547,566,585,602,618,633,
646,659,669,679,686,692,696,699,700,699,696,692,686,679,669,659,646,633,618,602,585,566,547,527,
506,485,463,441,418,396,373,350,328,306,284,263,242,222,203,184,166,150,134,118,104,91,79,68,57,
48,40,32,25,19,14,10,6,3,0,-2,-4,-5,-6,-7,-8,-8,-9,-9,-9,-10,-10,-10};

int main(void)
{
  __HAL_RCC_FMAC_CLK_ENABLE();
  // Структура для настройки фильтра
  FMAC_FilterConfigTypeDef sFmacConfig; 			// declare a filter configuration structure
  sFmacConfig.CoeffBaseAddress = 0; 				// Set the coefficient buffer base address
  sFmacConfig.CoeffBufferSize = FILTER_TAP; 		// Set the coefficient buffer size to the number of coeffs
  sFmacConfig.InputBaseAddress = FILTER_TAP; 		// Set the Input buffer base address to the next free address
  sFmacConfig.InputBufferSize = FILTER_TAP + 1;		// Set the input buffer size greater than the number of coeffs
  sFmacConfig.InputThreshold = 0; 					// Set the input watermark to zero since we are using DMA
  sFmacConfig.OutputBaseAddress = FILTER_TAP*2 + 1; // Set the Output buffer base address to the next free address
  sFmacConfig.OutputBufferSize = FILTER_OUT_BUFFER_SIZE;// Set the output buffer size
  sFmacConfig.OutputThreshold = 0; 					// Set the output watermark to zero since we are using DMA
  sFmacConfig.pCoeffA = NULL; 						// No A coefficients since FIR
  sFmacConfig.CoeffASize = 0;
  sFmacConfig.pCoeffB = FilterCoeffB; 				// Pointer to the coefficients in memory
  sFmacConfig.CoeffBSize = FILTER_TAP; 				// Number of coefficients
  sFmacConfig.Filter = FMAC_FUNC_CONVO_FIR; 		// Select FIR filter function
//sFmacConfig.InputAccess = FMAC_BUFFER_ACCESS_DMA; // Enable DMA input transfer
  sFmacConfig.InputAccess = FMAC_BUFFER_ACCESS_NONE;// Disable DMA input transfer
  sFmacConfig.OutputAccess = FMAC_BUFFER_ACCESS_DMA;// Enable DMA output transfer
  sFmacConfig.Clip = FMAC_CLIP_ENABLED; 			// Enable clipping of the output at 0x7FFF and 0x8000
  sFmacConfig.P = FILTER_TAP; 						// P parameter contains number of coefficients
  sFmacConfig.Q = 0; 								// Q parameter is not used
  sFmacConfig.R = 0;  								// R parameter contains the post-shift value (none)
  if (HAL_FMAC_FilterConfig(&hfmac, &sFmacConfig) != HAL_OK) // Configure the FMAC
  Error_Handler(); 									// Configuration Error
  
  uint16_t Filter_output_Size = FILTER_OUT_BUFFER_SIZE;					  // Только так:)
  HAL_FMAC_FilterStart(&hfmac, (int16_t*)&FMAC_out, &Filter_output_Size); // Запускаем FMAC

  uint32_t *Fmac_Wdata;
//  Fmac_Wdata = (uint32_t *) FMAC->WDATA;	// Так работать не будет
  Fmac_Wdata = (uint32_t *) 0x40021418;	// Секреточка:)
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);	// ADC Calibration
  HAL_ADC_Start_DMA(&hadc1, Fmac_Wdata, FILTER_IN_BUFFER_SIZE);	// Запускаем АЦП с сохранением по DMA
  HAL_DAC_Start_DMA(&hdac2, DAC_CHANNEL_1, (uint32_t*)&FMAC_out, FILTER_OUT_BUFFER_SIZE, DAC_ALIGN_12B_R); // Выводим входные данные FIR фильтра на ЦАП
  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);	// Запускаем таймер для тактирования всего
  
    while (1)
  {
      
  }
 }

static void MX_ADC1_Init(void)
{
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};
  /** Common config*/
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T4_TRGO;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the ADC multi-mode*/
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel*/
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 1;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...