ToR_TDA 0 16 мая, 2021 Опубликовано 16 мая, 2021 · Жалоба Приветствую форумчане! Захотелось мне для опыта запустить блок аппаратного фильтра на 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 (тактирование) /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© 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****/ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ToR_TDA 0 17 мая, 2021 Опубликовано 17 мая, 2021 · Жалоба В общем, сам спросил сам и отвечаю:) Все сделал в точности по примеру "Example 2: 3p3z compensator" из приведенного выше документа только с изменением на КИХ фильтр и вывод на ЦАП по ДМА. Показываю ключевые моменты кода. Главная идея, что данные от АЦП передаем через DMA напрямую в FMAС "perip to perip". На самом деле там в примере есть "секреточка", а в целом все проблемы связаны с тем, что ST еще не допилили ни CMSIS, ни CubeMX, ни свои библиотеки под этот новый блок до конца. #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(); } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться