Starting FMAC kills Systick in STM32G431
I have the STM32G431 set up to sample ADC2, send the data to the FMAC and then out to DAC1. It works fine, I have tested all kinds of filters with it. However, none of the HAL functions that use SysTick work after I start the FMAC.
I'm using the small NUCLEO board. With the attached code, only "St" gets transmitted in the HAL_UART_Transmit call and the LD2 LED only blink once. However, if I just comment out the HAL_FMAC_FilterStart line, the LD2 LED blinks and the full "Starting..." message gets transmitted. The FMAC obviously stops working after that line is commented out.
I have tried re-creating the project several times and I get the same result. I've tried changing the priorities of the System tick timer and DMA interrupts without any success. I'm not seeing anything in the HAL_FMAC_FilterStart function that should affect SysTick.
/* 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 */
#define FILTER_OUT_BUFFER_SIZE 1
#define FILTER_IN_BUFFER_SIZE 1
#define FILTER_TAP 127
#define TXBUFFERSIZE 60 // UART TX buffer size
#define DLY_1S 1000 // 1 second delay (1000 microseconds)
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc2;
DMA_HandleTypeDef hdma_adc2;
DAC_HandleTypeDef hdac1;
DMA_HandleTypeDef hdma_dac1_ch1;
FMAC_HandleTypeDef hfmac;
DMA_HandleTypeDef hdma_fmac_read;
TIM_HandleTypeDef htim7;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
uint16_t ADC_data[FILTER_IN_BUFFER_SIZE]; // Data from ADC
uint16_t FMAC_out[FILTER_OUT_BUFFER_SIZE]; // Filter output data
/* https://fiiir.com/
*
* Low pass (windowed-sinc FIR)
* Window type: Blackman
* Sampling rate: 100kHz
* Cutoff: 25kHz
* Transition bandwidth: 3.65kHz
* Number of coefficients: 127
*
* Notes:
* -Coefficients must be in q1.15 format. -> value_q15 = (int16_t)(value_f32*0x8000)
* -Maximum 127 taps
*
* PROBABLY THE BEST AT 100KHZ!
*/
static int16_t FilterCoeffB[127] =
{0,0,0,0,-1,0,2,0,-3,0,5,0,-7,0,11,0,-15,0,21,0,-28,0,37,0,-48,0,61,0,-77,0,96,0,
-119,0,146,0,-177,0,215,0,-260,0,313,0,-377,0,455,0,-551,0,674,0,-837,0,1067,0,
-1417,0,2033,0,-3445,0,10420,16384,10420,0,-3445,0,2033,0,-1417,0,1067,0,-837,0,
674,0,-551,0,455,0,-377,0,313,0,-260,0,215,0,-177,0,146,0,-119,0,96,0,-77,0,61,
0,-48,0,37,0,-28,0,21,0,-15,0,11,0,-7,0,5,0,-3,0,2,0,-1,0,0,0,0
};
uint8_t TxBuffer[200];
int TxBufSize;
/* 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_USART2_UART_Init(void);
static void MX_DAC1_Init(void);
static void MX_FMAC_Init(void);
static void MX_TIM7_Init(void);
static void MX_ADC2_Init(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_USART2_UART_Init();
MX_DAC1_Init();
MX_FMAC_Init();
MX_TIM7_Init();
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
uint16_t Filter_output_Size = FILTER_OUT_BUFFER_SIZE;
HAL_FMAC_FilterStart(&hfmac, (int16_t*)&FMAC_out, &Filter_output_Size); // Running the filter
HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED); // Calibrating the ADC
HAL_ADC_Start_DMA(&hadc2, (uint32_t*)&FMAC->WDATA, FILTER_IN_BUFFER_SIZE); // We launch the ADC with DMA storage using the pointer to FMAC->WDATA
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*)&FMAC_out, FILTER_OUT_BUFFER_SIZE, DAC_ALIGN_12B_R); // We output the input data of the FIR filter to the DAC
HAL_TIM_Base_Start(&htim7); // Start the timer
TxBufSize = sprintf(TxBuffer,"Starting...\n\r");
HAL_UART_Transmit(&huart2, TxBuffer, TxBufSize, DLY_1S);
HAL_Delay(1);
/* 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(200);
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
HAL_Delay(200);
/* 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_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
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 = RCC_PLLM_DIV2;
RCC_OscInitStruct.PLL.PLLN = 25;
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_3) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief ADC2 Initialization Function
* @PAram None
* @retval None
*/
static void MX_ADC2_Init(void)
{
/* USER CODE BEGIN ADC2_Init 0 */
/* USER CODE END ADC2_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC2_Init 1 */
/* USER CODE END ADC2_Init 1 */
/** Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.GainCompensation = 0;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc2.Init.LowPowerAutoWait = DISABLE;
hadc2.Init.ContinuousConvMode = DISABLE;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T7_TRGO;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc2.Init.DMAContinuousRequests = ENABLE;
hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc2.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
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(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */
/* USER CODE END ADC2_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 = ENABLE;
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_T7_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 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 */
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_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
/* USER CODE END FMAC_Init 2 */
}
/**
* @brief TIM7 Initialization Function
* @PAram None
* @retval None
*/
static void MX_TIM7_Init(void)
{
/* USER CODE BEGIN TIM7_Init 0 */
/* USER CODE END TIM7_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM7_Init 1 */
/* USER CODE END TIM7_Init 1 */
htim7.Instance = TIM7;
htim7.Init.Prescaler = 0;
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = 999;
htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM7_Init 2 */
/* USER CODE END TIM7_Init 2 */
}
/**
* @brief USART2 Initialization Function
* @PAram None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMAMUX1_CLK_ENABLE();
__HAL_RCC_DMA1_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_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
/**
* @brief GPIO Initialization Function
* @PAram None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : LD2_Pin */
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* 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 */
HAL_StatusTypeDef HAL_FMAC_FilterStart(FMAC_HandleTypeDef *hfmac, int16_t *pOutput, uint16_t *pOutputSize)
{
uint32_t tmpcr = 0U;
HAL_StatusTypeDef status;
/* Check the START bit state */
if (FMAC_GET_START_BIT(hfmac) != 0U)
{
return HAL_ERROR;
}
/* Check that a valid configuration was done previously */
if (hfmac->FilterParam == 0U)
{
return HAL_ERROR;
}
/* Check handle state is ready */
if (hfmac->State == HAL_FMAC_STATE_READY)
{
/* Change the FMAC state */
hfmac->State = HAL_FMAC_STATE_BUSY;
/* CR: Configure the input access (error interruptions enabled only for IT or DMA) */
if (hfmac->InputAccess == FMAC_BUFFER_ACCESS_DMA)
{
tmpcr |= FMAC_DMA_WEN;
}
else if (hfmac->InputAccess == FMAC_BUFFER_ACCESS_IT)
{
tmpcr |= FMAC_IT_WIEN;
}
else
{
/* nothing to do */
}
/* CR: Configure the output access (error interruptions enabled only for IT or DMA) */
if (hfmac->OutputAccess == FMAC_BUFFER_ACCESS_DMA)
{
tmpcr |= FMAC_DMA_REN;
}
else if (hfmac->OutputAccess == FMAC_BUFFER_ACCESS_IT)
{
tmpcr |= FMAC_IT_RIEN;
}
else
{
/* nothing to do */
}
/* CR: Write the configuration */
MODIFY_REG(hfmac->Instance->CR, \
FMAC_IT_RIEN | FMAC_IT_WIEN | FMAC_DMA_REN | FMAC_CR_DMAWEN, \
tmpcr);
/* Register the new output buffer */
status = FMAC_ConfigFilterOutputBufferUpdateState(hfmac, pOutput, pOutputSize);
if (status == HAL_OK)
{
/* PARAM: Start the filter ( this can generate interrupts before the end of the HAL_FMAC_FilterStart ) */
WRITE_REG(hfmac->Instance->PARAM, (uint32_t)(hfmac->FilterParam));
}
/* Reset the busy flag (do not overwrite the possible write and read flag) */
hfmac->State = HAL_FMAC_STATE_READY;
}
else
{
status = HAL_ERROR;
}
return status;
}
