2
\$\begingroup\$

I'm new to microcontroller programming and I have a problem I can't solve.

I am using STM32 Nucleo board L4R5ZI and I try to read the analog value on one of the pins, and then use the ADC to convert it and send it to the PC using the UART.

But when using this code, I only get a "0" in my PC. It looks like the HAL_ADC_start() function returns HAL_ERROR. Do you know what it could be?

I hope that you understand, English is not my native language :)

ADC_HandleTypeDef hadc1;
UART_HandleTypeDef hlpuart1;

...

uint16_t raw;
char msg[10];

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();
MX_LPUART1_UART_Init();
MX_USART3_UART_Init();
MX_USB_OTG_FS_PCD_Init();
MX_ADC1_Init();


    while (1){
    
      HAL_ADC_Start(&hadc1);
      HAL_ADC_PollForConversion(&hadc1, 100);
      raw = HAL_ADC_GetValue(&hadc1);
      sprintf(msg, "%hu\r\n", raw);

      HAL_UART_Transmit(&hlpuart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
      HAL_Delay(5);
    }

...

  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.NbrOfDiscConversion = 1;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;

EDIT 1
I find out that HAL_ADC_start function return HAL_ERROR in this section of code:

while (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == 0UL)
    {
      /*  If ADEN bit is set less than 4 ADC clock cycles after the ADCAL bit
          has been cleared (after a calibration), ADEN bit is reset by the
          calibration logic.
          The workaround is to continue setting ADEN until ADRDY is becomes 1.
          Additionally, ADC_ENABLE_TIMEOUT is defined to encompass this
          4 ADC clock cycle duration */
      /* Note: Test of ADC enabled required due to hardware constraint to     */
      /*       not enable ADC if already enabled.                             */
      if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
      {
        LL_ADC_Enable(hadc->Instance);
      }

      if ((HAL_GetTick() - tickstart) > ADC_ENABLE_TIMEOUT)
      {
        /* Update ADC state machine to error */
        SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);

        /* Set ADC error code to ADC peripheral internal error */
        SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);

        return HAL_ERROR;
      }
    }
return HAL_OK;

It is part of function ADC_Enable() which is used in HAL_ADC_start(). Condition in while() is still TRUE that means, a timeout occurs later.

Still don't know how to solve it.

\$\endgroup\$
3
  • 6
    \$\begingroup\$ You can debug into the HAL_ADC_Start function to check the condition that causes it to return HAL_ERROR. \$\endgroup\$ Commented Jun 24, 2020 at 15:47
  • 1
    \$\begingroup\$ This is usually a result of some piece of missing initialization or an invalid option choice attempt. See if there's a manufacturer example you can run absolutely unmodified first. \$\endgroup\$ Commented Nov 27, 2020 at 13:36
  • \$\begingroup\$ Do we have a solution at the end? I am facing similar problem on my end with STM32U5. \$\endgroup\$ Commented Dec 9, 2021 at 12:21

1 Answer 1

0
\$\begingroup\$

Some things you could try:

  1. Check that the clock for the ADC is enabled -- so in the SystemClock_Config() functionlook for the line that sets PeriphClkInit.PeriphClockSelection and make sure it contains RCC_PERIPHCLK_ADC.

  2. Check that the frequency of the clock for the ADC is acceptable -- use STM32CubeMX and look at the "Clock Configuration" tab and make sure it isn't throwing up any errors.

  3. Your code is running the ADC as a one-shot, but is configuring it for continuous sampling -- hadc1.Init.ContinuousConvMode = ENABLE;. It may be worth setting this to DISABLE instead.


Old answer left here for posterity:

I'm seeing the same issue (HAL_ADC_Start() returning HAL_ERROR), although with a PlaformIO + STM32CubeMX build. In this case PlatformIO builds the CMSIS code and the CubeMX HAL driver code separately into two libraries: libFrameworkCMSISDevice.a and libFrameworkHALDriver.a.

In the libFrameworkHALDriver library there exist a number of functions that are defined twice, once with weak linkage, and a second time with strong linkage.

For me, the final link produces output that only has the weak version of many of these functions. For the HAL_ADC_Start() function in question it only has the weak version, which does nothing and returns HAL_ERROR, which is the symptom reported in the question.

Looking into this some more it appears that when linking static libraries, the linker doesn't override weak symbols seen early in the link with strong ones seen later. E.g. See this discussion: https://stackoverflow.com/a/37191811/1770902.

Thus if this is what is causing your issue solution would appear to be to put the files with the strong symbols earlier in the link than the weak symbols they should override.

In my case I haven't yet figured out how to fix this issue as there doesn't appear to be any way to influence the order in which the PlatformIO library builds have included the object files.

\$\endgroup\$
8
  • \$\begingroup\$ The hal "library" is typically compiled as part of a project, not precompiled into a static library and linked, so the library mechanism is not normally utilized for this at all. The .o files show here are not "libraries" \$\endgroup\$ Commented Nov 27, 2020 at 13:26
  • \$\begingroup\$ Perhaps my answer gives mixed messages, but in my case of using PlatformIO with STM32CubeMX to build for the STM32F323C-EVAL board makes two static libraries, which it links with automatically. These are libFrameworkCMSISDevice.a and libFrameworkHALDriver.a. In the libFrameworkHALDriver.a, the HAL_ADC_Start() function appears twice, the first is a weak version, the second strong. In the final linked output there is only the weak version. \$\endgroup\$
    – timfoden
    Commented Nov 27, 2020 at 14:14
  • \$\begingroup\$ I updated my answer to give some more information about the situation in which I have a problem with the same symptoms. \$\endgroup\$
    – timfoden
    Commented Nov 27, 2020 at 14:30
  • \$\begingroup\$ That would appear to be distinct from this question \$\endgroup\$ Commented Nov 27, 2020 at 14:35
  • \$\begingroup\$ Yes, I accept that it may be. But it also may not be, as the OP doesn't specify what his setup is. If he's using PlatformIO with STM32CubeMX to get his HAL setup, then my answer would be pertinent to his case. Otherwise this may help someone else is using PlatformIO with STM32CubeMX who gets to this question, as I did, by looking for why I'm seeing HAL_ADC_Start() fail with HAL_ERROR. \$\endgroup\$
    – timfoden
    Commented Nov 27, 2020 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.