ADC with DMA on the STM32F769I Discovery
Hello,
problem was not solved as I thought previously.
I’ve added only pin PA6 (as analog) configuration (GPIOA init) to the “main” or to the ADC_Config (doesn’t matter where) and the HardFault error occured again at the same place - possible step debugging into HAL_DMA_Start_IT(), not out of this. I was not able to get rid of it. To change MPU_InitStruct.BaseAddress is not solution or I don’t know what parametres. Different sizes of MPU_InitStruct.Size also do not change the behaviour of the program. HardFault_Handler is called again and again. It was a try and an error.
A few days later I found that before the Hard Fault parameters of the functions were OK, but after the Hard Fault came I was able to find that parametres (arguments) of the functions
usage: HAL_DMA_Start_IT(hadc->DMA_Handle, (uint32_t)&hadc->Instance->DR, (uint32_t)pData, Length)
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength)
where pData is destination buffer address or DstAddress is &ConvertedValue,
DataLength or Length is 1UL (1 word)
were changed or mixed (if the debugger was not lying).
So when the Hard Fault occured the debugger showed SrcAddress was &ConvertedValue, DataLength was DMA2 peripheral address (0x40026400) and DstAddress was 1. It was strange to me. But was not able to find the cause.
In the main.c I have ADC configuration (I don’t use _msp config file), now.
/*Global variables in the main.c file*/
ADC_HandleTypeDef AdcHandle;
volatile uint32_t ConvertedValue = 0UL;
/*func. prototype*/
static void ADC_Config(void);
...
... int main(void) {...}
...
static void ADC_Config(void)
{
static ADC_ChannelConfTypeDef sConfig;
static DMA_HandleTypeDef hdma_adc;
GPIO_InitTypeDef gpio_adc_struct;
gpio_adc_struct.Pin = GPIO_PIN_6;
gpio_adc_struct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &gpio_adc_struct);
/* Configure the ADC peripheral */
AdcHandle.Instance = ADC1;
AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV8;
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
AdcHandle.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
AdcHandle.Init.ContinuousConvMode = ENABLE; /* Continuous mode enabled to have continuous conversion */
AdcHandle.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */
AdcHandle.Init.NbrOfDiscConversion = 0;
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Conversion start NOT trigged by an external event */
AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
AdcHandle.Init.NbrOfConversion = 1;
AdcHandle.Init.DMAContinuousRequests = ENABLE;
AdcHandle.Init.EOCSelection = DISABLE;
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* ADC1 Periph clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
/* Enable DMA2 clock */
__HAL_RCC_DMA2_CLK_ENABLE();
/*##-2- Configure the DMA streams ##########################################*/
/* Set the parameters to be configured */
hdma_adc.Instance = DMA2_Stream0; // DMA2_Stream4
hdma_adc.Init.Channel = DMA_CHANNEL_0;
hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc.Init.MemInc = DMA_MINC_DISABLE;
hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_adc.Init.Mode = DMA_CIRCULAR;
hdma_adc.Init.Priority = DMA_PRIORITY_HIGH;
hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_adc.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
hdma_adc.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_adc.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_Init(&hdma_adc);
/* Associate the initialized DMA handle to the ADC handle */
__HAL_LINKDMA(&AdcHandle, DMA_Handle, hdma_adc); //(&AdcHandle)->DMA_Handle = &(hdma_adc)
/*##-3- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
// HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
{
/* ADC initialization Error */
Error_Handler();
}
/* Configure ADC Temperature Sensor Channel */
sConfig.Channel = ADC_CHANNEL_6; //CN14_A0=ADC1_IN6=PA6 //ADC_CHANNEL_TEMPSENSOR = ADC_CHANNEL_18;
//CN14_A1=ADC_IN4=PA4
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_112CYCLES; //ADC_SAMPLETIME_56CYCLES;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
/* Channel Configuration Error */
Error_Handler();
}
}
Result:
If ADC_ChannelConfTypeDef sConfig declaration is used, Hard Fault occurs.
If DMA_HandleTypeDef hdma_adc decalration is used, ConvertedValue is still 0 (and program runs without any other faults.)
If I use these declarations with the static keyword, the program runs and ADC converts without faults.
Then I found that DMA_Handle was placed in the DTCM RAM region (0x2000XXXX) in the working code. In the defective code the DMA_Handle was placed at the end of the SRAM1 (0x2007fef8). However I don’t know why this should be the problem to have the variable at the end of the SRAM.
I will be happy if somebody has similar experience or can give me a comment why I should use static keyword in the config function (generally) or if it is needed to define static functions in the main.c. (However void SystemClock_Config(void) is defined in the main.c without static keyword. In all examples.)
vt23