cancel
Showing results for 
Search instead for 
Did you mean: 

MemMnage_handle Fault After Enabling MPU for ADC1 (STM32)

SRMahalakshmi
Associate II

Hello,

Why am I getting a Memory Management fault when enabling the MPU for ADC1, even though the MPU region is configured correctly?

Could it be due to alignment issues or internal access within the HAL code (e.g., ADC12_Common)?

Any guidance would be appreciated!

Thanks in advance.

 

MPU Configuration

 

/* Update MPU settings for newly activating Zone */ void osZoneSetup_Callback (uint32_t zone) { ARM_MPU_Disable(); ARM_MPU_Load(mpu_table[zone], MPU_REGIONS); ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); }

MPU Region for ADC

// ADC1, ADC12_Common (0x40022000..0x400227FF) { .RBAR = ARM_MPU_RBAR(3U, 0x40022000), .RASR = ARM_MPU_RASR_EX(1U, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_DEVICE(0U), 0x00U, ARM_MPU_REGION_SIZE_16KB) }, // VREFBUF (0x58003C00..0x58003FFF) { .RBAR = ARM_MPU_RBAR(4U, 0x58003C00), .RASR = ARM_MPU_RASR_EX(1U, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_DEVICE(0U), 0x00U, ARM_MPU_REGION_SIZE_1KB) },

 

ADC1 Initialization

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_ASYNC_DIV1; hadc1.Init.Resolution = ADC_RESOLUTION_8B; 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_SOFTWARE_START; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; hadc1.Init.OversamplingMode = DISABLE; hadc1.Init.Oversampling.Ratio = 1; 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_2; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_387CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; sConfig.OffsetSignedSaturation = DISABLE; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ }
View more

Kindly help me.

 

SRMahalakshmi_1-1747897685287.png

8 REPLIES 8
SRMahalakshmi
Associate II

Hello ST team,

 

I’m following up on query as I haven’t received a response yet. Please let me know if there’s any update or if you need more details from my side to move forward.

Thank you, and I look forward to your reply.

SRMahalakshmi
Associate II

SRMahalakshmi_0-1748262096799.png

Please refer to the image above. I can now confirm that hadc1.Instance correctly points to ADC1 at address 0x40022000; however, sConfig.Channel appears to be mapped to an incorrect memory location. Any suggestions to help resolve this issue would be helpful. Thank you.

 

> ... however, sConfig.Channel appears to be mapped to an incorrect memory location.

I don't know what this sConfig / Channel parameter are used for, I don't use Cube/HAL in any of my projects.
But it is supposedly related to the channel setup, and most probably not the cause for the MPU fault.

I suggest to debug in single-step mode, to see which access actually triggers the MPU fault.
Or retrieve the fault address from the respective Syscfg register in the fault handler afterwards, and crosscheck with the map file.

 

Thank you for your assistance.

I am working with the STM32H733 microcontroller and handling multiple ADC channels as shown in the example below:

ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_19; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_387CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; sConfig.OffsetSignedSaturation = DISABLE; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); }
 
 

The function HAL_ADC_ConfigChannel internally calls the low-level driver functions, and during this process, the line

 

adc1.Instance->PCSEL_RES0 |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB((uint32_t)sConfig.Channel) & 0x1FUL));

is executed, which triggers a Memory Management fault.

 

if (LL_ADC_REG_IsConversionOngoing(hadc->Instance) == 0UL) { if (!(__LL_ADC_IS_CHANNEL_INTERNAL(sConfig->Channel))) { #if defined(ADC_VER_V5_V90) if (hadc->Instance != ADC3) { /* ADC channels preselection */ hadc->Instance->PCSEL_RES0 |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB((uint32_t)sConfig->Channel) & 0x1FUL)); } #ifndef __ARM_COMPAT_H __STATIC_FORCEINLINE void __disable_irq(void) { __ASM volatile ("cpsid i" : : : "memory"); }

Could you please clarify the following points:

  1. Is the PCSEL_RES0 register valid and accessible for ADC channel preselection on my STM32 MCU?

  2. Are there specific conditions or initializations required before accessing this register?

  3. Is it safe to use the macro __LL_ADC_CHANNEL_TO_DECIMAL_NB() with channels?

  4. Are there any known issues or recommended debugging steps related to this part of the ADC HAL/LL drivers?

I don't even have a H7 board to begin with. Perhaps someone from the ST staff here can try.

> ...is executed, which triggers a Memory Management fault.

And at what address exactly ?
Switch to instruction stepping mode (assember), and execute until the fault occurs, and show the line and the core register contents.


Does the ADC initialisation work as expected when you disable the MPU ?
I'm not sure ST has ever tested this use case.

Does the ADC initialization work as expected when you disable the MPU ?

>> ..Yes, With the MPU disabled, ADC initialization functions correctly without errors. However, when the MPU is enabled, Memory Management faults occur specifically with ADC1/2 peripherals, whereas ADC3 continues to operate normally.

 

The Memory Management fault occurs when executing the following line:

 
 
tmpOffsetShifted = ADC_OFFSET_SHIFT_RESOLUTION(hadc, (uint32_t)sConfig->Offset);

 

/* Shift the offset with respect to the selected ADC resolution. */ /* Offset has to be left-aligned on bit 11, the LSB (right bits) are set to 0 */ #if defined(ADC_VER_V5_V90) if (hadc->Instance == ADC3) { tmpOffsetShifted = ADC3_OFFSET_SHIFT_RESOLUTION(hadc, (uint32_t)sConfig->Offset); } else #endif /* ADC_VER_V5_V90 */ { tmpOffsetShifted = ADC_OFFSET_SHIFT_RESOLUTION(hadc, (uint32_t)sConfig->Offset); }

 

 

 

Please find the Memory address.

SRMahalakshmi_0-1748350059604.png

 

>> ..Yes, With the MPU disabled, ADC initialization functions correctly without errors. However, when the MPU is enabled, Memory Management faults occur specifically with ADC1/2 peripherals, whereas ADC3 continues to operate normally.

I'm not sure if you understand the functionality of such a unit.
A MPU does no address translation or manipulation like e.g. a MMU. You can define restrictions to the read, write and execution access of memory ranges, so as to block parts of code from accessing data or code reserved for other parts. The most common use case is to separate OS code from user application code, e.g. in FreeRTOS or similiar OSes.

Thus : 

> The Memory Management fault occurs when executing the following line:  ...

The C source code does not help.
The actual memory address the access to which causes the fault is required, which is unambigiously visible only in assembler code - and core register contents.


I don't know what your use case for the MPU is here.
As an example, referring to the FreeRTOS example mentioned above, user code is usually not allowed to access peripherals directly, only via the OS API. All of the ECUs my company employs enforce this rule strictly.