Loading...
 

SW4STM32 and SW4Linux fully supports the STM32MP1 asymmetric multicore Cortex/A7+M4 MPUs

   With System Workbench for Linux, Embedded Linux on the STM32MP1 family of MPUs from ST was never as simple to build and maintain, even for newcomers in the Linux world. And, if you install System Workbench for Linux in System Workbench for STM32 you can seamlessly develop and debug asymmetric applications running partly on Linux, partly on the Cortex-M4.
You can get more information from the ac6-tools website and download (registration required) various documents highlighting:

System Workbench for STM32


ADC with DMA on the STM32F769I Discovery

Hello guys,

I want to share my experience with using HAL Examples (STM32CubeF7 Firmware Package). I have STM32F769I Discovery board
In my program I needed UART and ADC. I implemented UART6 in interrupt mode (Rx, Tx). After many problems with receiving variable length data it was settled. Then I wanted to use analog to digital conversion of one channel on one analog pin. I used ADC1, ADC_CHANNEL_6, ADC_SAMPLETIME_56CYCLES, continous conversion mode. MCU is on max. frequency 216 MHz, ADC has PRESCALER_PCLK_DIV8.

For ADC I was inspired with example project file ADC_TemperatureSensor, it uses DMA2_Stream0, DMA_CHANNEL_0, circular mode. Interruption is done with DMA2_Stream0_IRQn. (I found that this example program does not crash when I remove MPU_Config().)
I copied configuration of the ADC (changed channel and little things) and add it to my program with the UART communication. First I started without MPU_Config(); and CPU_CACHE_Enable(); and after build and run, it ended in the HardFault (HardFault_Handler). It crashed during conversion process HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&ConvertedValue, 1); I was not able to find the cause for a couple of days. AN4031 (about DMA) did not help me. After a lot of searching I found AN4667. Part of the setting of the MPU (default) was

MPU_InitStruct.BaseAddress = 0x20010000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256KB;

According to AN4667 (later I found it also in the reference manual RM0410, first it was not so obvious) I found the base address for the MPU is maybe wrong. I changed the address to
MPU_InitStruct.BaseAddress = 0x20020000;

and now the program is running. For the STM32F76xxx/STM32F77xxx DTCM is from 0x2000 0000 to 0x2001 FFFF and SRAM1 is from 0x20020000 to 0x2007 BFFF.

Still I don’t understand when it is needed to use CPU_CACHE_Enable() or MPU_Config(). I read MPU should be used when 2 masters can be in the conflict on the bus or in the RAM. Can someone explain to me why I need to use MPU and use it for SRAM1 region for example?

vt23

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

HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)

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