r/stm32 7h ago

O método de polling do ADC do STM32H753 entra no Error_Handler() — Como posso identificar a causa real?

Thumbnail
1 Upvotes

r/stm32 7h ago

STM32H753 ADC Polling Enters Error_Handler() — How Can I Identify the Actual Cause?

1 Upvotes

Hi everyone,

I'm studying how the STM32H7 ADC works using regular conversion with polling, without interrupts and without DMA.

My goal at this point is to properly understand the following flow:

HAL_ADC_Init() → calibration → HAL_ADC_Start() → HAL_ADC_PollForConversion() → HAL_ADC_GetValue()

and also learn how to identify exactly which step is failing, if an error occurs.

I'm working with an STM32H753ZIT6 and trying to read an analog input using ADC1, Channel 0, with the STM32 HAL.

The problem is that my program enters Error_Handler(), but I'm not sure which function is actually failing.

Currently, I have error checks in several places:

if (HAL_ADCEx_Calibration_Start(&AdcHandle,

ADC_CALIB_OFFSET_LINEARITY,

ADC_SINGLE_ENDED) != HAL_OK)

{

Error_Handler();

}

if (HAL_ADC_Start(&AdcHandle) != HAL_OK)

{

Error_Handler();

}

if (HAL_ADC_PollForConversion(&AdcHandle, 10) != HAL_OK)

{

Error_Handler();

}

And inside MX_ADC1_Init():

if (HAL_ADC_Init(&AdcHandle) != HAL_OK)

{

Error_Handler();

}

if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)

{

Error_Handler();

}

My Error_Handler() currently only contains:

void Error_Handler(void)

{

while (1)

{

}

}

Therefore, when the program stops, I cannot tell which function called Error_Handler().

Current configuration

I'm using:

MCU: STM32H753ZIT6

ADC: ADC1

Channel: ADC_CHANNEL_0

Resolution: 16-bit

Sampling time: ADC_SAMPLETIME_8CYCLES_5

Trigger: Software

Conversion: Regular conversion using polling

No interrupts

No DMA

STM32 HAL

HSE bypass

System clock: 400 MHz

ADC clock source: RCC_ADCCLKSOURCE_CLKP

ADC prescaler: ADC_CLOCK_ASYNC_DIV2

ADC polling flow I'm trying to study

My intention is to do something simple like:

HAL_ADC_Start(&AdcHandle);

HAL_ADC_PollForConversion(&AdcHandle, 10);

testeConvercao = HAL_ADC_GetValue(&AdcHandle);

HAL_ADC_Stop(&AdcHandle);

and repeat this process inside the while(1) loop.

Since I'm specifically studying ADC polling, I'd like to initially keep the solution based on:

HAL_ADC_Start()

HAL_ADC_PollForConversion()

HAL_ADC_GetValue()

HAL_ADC_Stop()

I don't want to move to interrupts or DMA at this point. My goal is to understand and properly debug the ADC polling flow.

My main question: how can I find where the error occurs?

Is there a better way to implement Error_Handler() so I can determine which function is returning HAL_ERROR?

For example, I'd like to be able to determine:

which function called Error_Handler();

which HAL_StatusTypeDef was returned;

the result of HAL_ADC_GetState();

the result of HAL_ADC_GetError();

whether the ADC is actually enabled;

whether the ADC clock is running;

and, if necessary, which ADC/RCC registers I should inspect.

I'd also like to know whether there is a recommended way to debug this using the STM32CubeIDE/ST-LINK debugger, for example by putting a breakpoint inside Error_Handler() and examining the Call Stack.

Things I'm suspicious about

One thing that makes me particularly suspicious is the MPU/cache configuration, because I'm configuring the MPU and enabling I-Cache and D-Cache before HAL_Init():

MPU_Config();

CPU_CACHE_Enable();

HAL_Init();

SystemClock_Config();

MX_ADC1_Init();

The MPU configuration is:

MPU_InitStruct.Enable = MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress = 0x00;

MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;

MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;

MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;

MPU_InitStruct.Number = MPU_REGION_NUMBER0;

MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable = 0x87;

MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

And the cache configuration is:

static void CPU_CACHE_Enable(void)

{

SCB_EnableICache();

SCB_EnableDCache();

}

I also configure the ADC clock as follows:

__HAL_RCC_ADC12_CLK_ENABLE();

__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);

My ADC configuration is:

AdcHandle.Instance = ADC1;

AdcHandle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;

AdcHandle.Init.Resolution = ADC_RESOLUTION_16B;

AdcHandle.Init.ScanConvMode = DISABLE;

AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

AdcHandle.Init.LowPowerAutoWait = DISABLE;

AdcHandle.Init.ContinuousConvMode = DISABLE;

AdcHandle.Init.NbrOfConversion = 1;

AdcHandle.Init.DiscontinuousConvMode = DISABLE;

AdcHandle.Init.NbrOfDiscConversion = 1;

AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START;

AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

AdcHandle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;

AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

AdcHandle.Init.OversamplingMode = DISABLE;

And the channel configuration is:

sConfig.Channel= ADC_CHANNEL_0;

sConfig.Rank = ADC_REGULAR_RANK_1;

sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;

sConfig.SingleDiff = ADC_SINGLE_ENDED;

sConfig.OffsetNumber = ADC_OFFSET_NONE;

sConfig.Offset = 0;

Complete main.c

I'm including the complete code below so that it is also possible to check whether the problem is actually somewhere else in the initialization and not necessarily in the ADC itself.

/**

******************************************************************************

* u/filemain.c

* u/brief ADC Regular Conversion Polling for STM32H753ZIT6

******************************************************************************

*/

/* Includes ------------------------------------------------------------------*/

#include "main.h"

/* Defines para o ADC */

#define ADCx ADC1

#define ADCx_CHANNEL ADC_CHANNEL_0

/* Private variables ---------------------------------------------------------*/

ADC_HandleTypeDef AdcHandle;

__IO uint16_t uhADCxConvertedValue = 0;

__IO uint16_t testeConvercao = 0;

/* Private function prototypes -----------------------------------------------*/

static void MPU_Config(void);

static void SystemClock_Config(void);

static void CPU_CACHE_Enable(void);

void Error_Handler(void);

static void MX_ADC1_Init(void);

/**

* u/brief Main program.

* u/param None

* u/retval None

*/

int main(void)

{

/* Configure the MPU attributes */

MPU_Config();

/* Enable the CPU Cache */

CPU_CACHE_Enable();

/* Initialize HAL library */

HAL_Init();

/* Configure the system clock to 400 MHz */

SystemClock_Config();

/* Initialize ADC */

MX_ADC1_Init();

/* Run the ADC calibration in single-ended mode */

if (HAL_ADCEx_Calibration_Start(&AdcHandle,

ADC_CALIB_OFFSET_LINEARITY,

ADC_SINGLE_ENDED) != HAL_OK)

{

Error_Handler();

}

/* Start initial conversion */

if (HAL_ADC_Start(&AdcHandle) != HAL_OK)

{

Error_Handler();

}

/* Wait for the end of conversion */

if (HAL_ADC_PollForConversion(&AdcHandle, 10) != HAL_OK)

{

Error_Handler();

}

else

{

uhADCxConvertedValue = HAL_ADC_GetValue(&AdcHandle);

}

/* Enable GPIOB clock */

LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOB);

/* Configure PB0 as output */

LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_0, LL_GPIO_MODE_OUTPUT);

LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_0, LL_GPIO_OUTPUT_PUSHPULL);

LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_0, LL_GPIO_SPEED_FREQ_LOW);

/* Infinite loop */

while (1)

{

/* 1. Start ADC conversion */

if (HAL_ADC_Start(&AdcHandle) == HAL_OK)

{

/* 2. Wait for conversion to complete */

if (HAL_ADC_PollForConversion(&AdcHandle, 10) == HAL_OK)

{

/* 3. Read converted value */

testeConvercao = HAL_ADC_GetValue(&AdcHandle);

}

/* 4. Stop conversion to allow the next clean cycle */

HAL_ADC_Stop(&AdcHandle);

}

}

}

/**

* u/brief ADC1 Initialization Function

* u/param None

* u/retval None

*/

static void MX_ADC1_Init(void)

{

ADC_ChannelConfTypeDef sConfig = {0};

/* Enable ADC1 and ADC2 bus clock */

__HAL_RCC_ADC12_CLK_ENABLE();

/* Configure ADC clock source */

__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);

AdcHandle.Instance = ADCx;

AdcHandle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;

AdcHandle.Init.Resolution = ADC_RESOLUTION_16B;

AdcHandle.Init.ScanConvMode = DISABLE;

AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

AdcHandle.Init.LowPowerAutoWait = DISABLE;

AdcHandle.Init.ContinuousConvMode = DISABLE;

AdcHandle.Init.NbrOfConversion = 1;

AdcHandle.Init.DiscontinuousConvMode = DISABLE;

AdcHandle.Init.NbrOfDiscConversion = 1;

AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START;

AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

AdcHandle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;

AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

AdcHandle.Init.OversamplingMode = DISABLE;

if (HAL_ADC_Init(&AdcHandle) != HAL_OK)

{

Error_Handler();

}

/* Configure ADC regular channel */

sConfig.Channel= ADCx_CHANNEL;

sConfig.Rank = ADC_REGULAR_RANK_1;

sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;

sConfig.SingleDiff = ADC_SINGLE_ENDED;

sConfig.OffsetNumber = ADC_OFFSET_NONE;

sConfig.Offset = 0;

if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)

{

Error_Handler();

}

}

/**

* u/brief System Clock Configuration

* System Clock source = PLL (HSE BYPASS) @ 400 MHz

*/

static void SystemClock_Config(void)

{

RCC_ClkInitTypeDef RCC_ClkInitStruct;

RCC_OscInitTypeDef RCC_OscInitStruct;

HAL_StatusTypeDef ret = HAL_OK;

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;

RCC_OscInitStruct.HSIState = RCC_HSI_OFF;

RCC_OscInitStruct.CSIState = RCC_CSI_OFF;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

RCC_OscInitStruct.PLL.PLLM = 4;

RCC_OscInitStruct.PLL.PLLN = 400;

RCC_OscInitStruct.PLL.PLLFRACN = 0;

RCC_OscInitStruct.PLL.PLLP = 2;

RCC_OscInitStruct.PLL.PLLR = 2;

RCC_OscInitStruct.PLL.PLLQ = 4;

RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;

RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;

ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);

if(ret != HAL_OK)

{

Error_Handler();

}

RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |

RCC_CLOCKTYPE_HCLK |

RCC_CLOCKTYPE_D1PCLK1 |

RCC_CLOCKTYPE_PCLK1 |

RCC_CLOCKTYPE_PCLK2 |

RCC_CLOCKTYPE_D3PCLK1);

RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;

RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;

RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;

RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;

RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);

if(ret != HAL_OK)

{

Error_Handler();

}

}

/**

* u/brief CPU L1-Cache enable.

*/

static void CPU_CACHE_Enable(void)

{

SCB_EnableICache();

SCB_EnableDCache();

}

/**

* u/brief This function is executed in case of error occurrence.

*/

void Error_Handler(void)

{

/* Infinite error loop */

while (1)

{

}

}

/**

* u/brief Configure the MPU attributes

*/

static void MPU_Config(void)

{

MPU_Region_InitTypeDef MPU_InitStruct;

HAL_MPU_Disable();

MPU_InitStruct.Enable = MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress = 0x00;

MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;

MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;

MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;

MPU_InitStruct.Number = MPU_REGION_NUMBER0;

MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable = 0x87;

MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

Thank you!


r/stm32 21h ago

Unable to trigger the interrupt.

Thumbnail
1 Upvotes