I'm trying to compute the FFT of a 100 kHz signal from the STM32f746G discovery board using the HAL and CMSIS DSP libraries and I've run into a few issues.
My first issue was trying to trigger the ADC conversion using a Timer2 Trigger Update but it seems there's an issue with Timer2 TRGO
based on section 2.2.1 of the errata sheet here. I finally got it to work using Timer 1 with the following settings.
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_TRGO;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; // 1 Msps Sampling rate.
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
And my Timer setup looks like this:
static void MX_TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = ((SystemCoreClock/2) / 100000) - 1; // APB1 Timer clock is HCLK/2 for 100 Khz signal.
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
My issue is when I start DMA and try to populate a buffer, only part of the array is populated and this seems to happen at random. I've come across something similar here
but the suggestion of setting hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD
and initialising the buffer to uint32_t
doesn't seem to work for me. A sample output of my buffer looks like this:
My main function looks like this:
uint32_t ADC1ConvertedValue_s[2048];
uint32_t ConvertedValue_s[2048];
int endConv;
\\initialise Timers and ADCs
HAL_TIM_Base_Start(&htim1);
HAL_ADC_Start_DMA(&hadc1, ADC1ConvertedValue_s, 2048);
while (1)
{
if(endConv == 1)
{
HAL_TIM_Base_Stop(&htim1);
HAL_ADC_Stop_DMA(&hadc1);
}
}
And I copy the values in the HAL_ADC_ConvCpltCallback
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
UNUSED(hadc);
endConv = 1;
for(i= 0; i< 2048; i++)
{
ConvertedValue_s[index_fill_adc_buffer] =
ADC1ConvertedValue_s[index_fill_adc_buffer];
}
}
Where am I going wrong here? I think the timer Period
and Prescaler
values are fine so I'm not sure that's the issue. I also think the ADC sampling rate of 1 Msps is correct and more than adequate. I've been tearing my head out trying to figure this out and some help would be appreciated.