cancel
Showing results for 
Search instead for 
Did you mean: 

Wakeup from Stop1 and Clock reinitialization is not working correctly on NUCLEO-L476RG

Benjamin Brammer
Senior II

Hello everybody,

I try to implement work with the Stop1 mode but sadly my clock reinitialization routine seems to be not working correctly.

When I put the MC in Stop1 mode it shall be woken up via LPTIM2 ISR on ARR match. So far this works. But since I want to use the ADC I try to reinitialize my RCC domain as it was programmed from the start. When I program the peripheral clk, especially the PLLSA1 I get a HAL_ERROR when I invoke HAL_RCCEx_PeriphCLKConfig(..). The error is happening in RCCEx_PLLSAI1_Config(..) when it is checked if the PLLSA1 clock is available. I sadly don't understand why this error occurs.

This is my system clock configuration done by STMCube after reset:

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 
  /** Configure LSE Drive Capability 
  */
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI
                              |RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 2;
  RCC_OscInitStruct.PLL.PLLN = 12;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1|RCC_PERIPHCLK_LPTIM1
                              |RCC_PERIPHCLK_LPTIM2|RCC_PERIPHCLK_USB
                              |RCC_PERIPHCLK_ADC;
  PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_LSE;
  PeriphClkInit.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
  PeriphClkInit.Lptim2ClockSelection = RCC_LPTIM2CLKSOURCE_LSE;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_MSI;
  PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSI;
  PeriphClkInit.PLLSAI1.PLLSAI1M = 2;
  PeriphClkInit.PLLSAI1.PLLSAI1N = 8;
  PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
  PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
  PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV4;
  PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_1);
  /** Configure the main internal regulator output voltage 
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Enable MSI Auto calibration 
  */
  HAL_RCCEx_EnableMSIPLLMode();
}

When I want to reprogram the RCC after wakeup I use the following function call:

void SYSCLKConfig_STOP(void)
{
	  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
	  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
	  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
	  uint32_t pFLatency = 0;
 
	  HAL_RCC_GetOscConfig(&RCC_OscInitStruct);
	  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	  {
		  Error_Handler();
	  }
 
	  HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);
	  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK)
	  {
	      Error_Handler();
	  }
 
	  HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkInit);
	  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
	  {
	      Error_Handler();
	  }
	  HAL_RCCEx_EnableMSIPLLMode();
 
}

inside HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) function RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_P_UPDATE) gets called:

HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
{
  uint32_t tmpregister, tickstart;     /* no init needed */
  HAL_StatusTypeDef ret = HAL_OK;      /* Intermediate status */
  HAL_StatusTypeDef status = HAL_OK;   /* Final status */
 
  /* Check the parameters */
  assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));
 
#if defined(SAI1)
 
  /*-------------------------- SAI1 clock source configuration ---------------------*/
  if((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_SAI1) == RCC_PERIPHCLK_SAI1))
  {
    /* Check the parameters */
    assert_param(IS_RCC_SAI1CLK(PeriphClkInit->Sai1ClockSelection));
 
    switch(PeriphClkInit->Sai1ClockSelection)
    {
    case RCC_SAI1CLKSOURCE_PLL:      /* PLL is used as clock source for SAI1*/
      /* Enable SAI Clock output generated form System PLL . */
#if defined(RCC_PLLSAI2_SUPPORT)
      __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI3CLK);
#else
      __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL_SAI2CLK);
#endif /* RCC_PLLSAI2_SUPPORT */
      /* SAI1 clock source config set later after clock selection check */
      break;
 
    case RCC_SAI1CLKSOURCE_PLLSAI1:  /* PLLSAI1 is used as clock source for SAI1*/
      /* PLLSAI1 input clock, parameters M, N & P configuration and clock output (PLLSAI1ClockOut) */
      ret = RCCEx_PLLSAI1_Config(&(PeriphClkInit->PLLSAI1), DIVIDER_P_UPDATE);
      /* SAI1 clock source config set later after clock selection check */
      break;
...
...
...

and inside RCCEx_PLLSAI1_Config the HAL_ERROR gets returned when the switch case is entered, to check if PLLSAI1 is available:

static HAL_StatusTypeDef RCCEx_PLLSAI1_Config(RCC_PLLSAI1InitTypeDef *PllSai1, uint32_t Divider)
{
  uint32_t tickstart;
  HAL_StatusTypeDef status = HAL_OK;
 
  /* check for PLLSAI1 Parameters used to output PLLSAI1CLK */
  /* P, Q and R dividers are verified in each specific divider case below */
  assert_param(IS_RCC_PLLSAI1SOURCE(PllSai1->PLLSAI1Source));
  assert_param(IS_RCC_PLLSAI1M_VALUE(PllSai1->PLLSAI1M));
  assert_param(IS_RCC_PLLSAI1N_VALUE(PllSai1->PLLSAI1N));
  assert_param(IS_RCC_PLLSAI1CLOCKOUT_VALUE(PllSai1->PLLSAI1ClockOut));
 
  /* Check that PLLSAI1 clock source and divider M can be applied */
  if(__HAL_RCC_GET_PLL_OSCSOURCE() != RCC_PLLSOURCE_NONE)
  {
    /* PLL clock source and divider M already set, check that no request for change  */
    if((__HAL_RCC_GET_PLL_OSCSOURCE() != PllSai1->PLLSAI1Source)
       ||
       (PllSai1->PLLSAI1Source == RCC_PLLSOURCE_NONE)
#if !defined(RCC_PLLSAI1M_DIV_1_16_SUPPORT)
       ||
       (((READ_BIT(RCC->PLLCFGR, RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1U) != PllSai1->PLLSAI1M)
#endif
      )
    {
      status = HAL_ERROR;
    }
  }
  else
  {
    /* Check PLLSAI1 clock source availability */
    switch(PllSai1->PLLSAI1Source)
    {
    case RCC_PLLSOURCE_MSI:
      if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_MSIRDY))
      {
        status = HAL_ERROR;
      }
      break;
    case RCC_PLLSOURCE_HSI:
      if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSIRDY))
      {
        status = HAL_ERROR;
      }
      break;
    case RCC_PLLSOURCE_HSE:
      if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSERDY))
      {
        if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSEBYP))
        {
          status = HAL_ERROR;
        }
      }
      break;
    default:
      status = HAL_ERROR;
      break;
    }
...
...

the value of PLLSai1->PLLSAI1Source is 0 and that triggers the error. I tried to manually configure the peripheral clock with the PeriphClkInit struct values from the initial SystemClock_Config() function, then the value for PLLSai1->PLLSAI1Source is 2 and seems correct, but then the switch case RCC_PLLSOURCE_HSI is netered and upon the

case RCC_PLLSOURCE_HSI:
      if(HAL_IS_BIT_CLR(RCC->CR, RCC_CR_HSIRDY))
      {
        status = HAL_ERROR;
      }
      break;

check, the error get's triggered. I think this means the HSI is not ready, but why is that? I thought it is used and active prior in my clock configuration....

has someone a hint for me?

best regards

Benjamin

2 REPLIES 2
Benjamin Brammer
Senior II

Ok...I also used the values of the initial RCC_OscInitStruc, to configure the clock after wakeup. This starts the ADC, but I later get a HardFault_Handler error. So there seems to be something wrong, still.

update: I have an unstacking error (UNSTKERR). Sadly I am not farmiliar with this kind of error. Is this because of small stack size?

2nd update: OK, I increased heap and stack size and also made sure that HSI is used as a wakeup clk. At the moment it seems that everything is working. But I will still test this over a long period of time.

3rd update: Puh.. for reasons I don't quite understand I am having a lot of errors right now. It seems really strange, as if the processor behaves differently in debug and standalone run mode. I reverted back to not having the stop mode running, but now my implemented - prior good working routines - are having faults. Interestingly I get only HAL_ERRORs from the ADC1. Sadly the errors are not repeatable and happen at different locations inside the HAL library:

one gets triggered here when I invoke HAL_ADC_Stop_DMA, inside the ADC_ConversionStop(ADC_HandleTypeDef *hadc, uint32_t ConversionGroup):

    while ((hadc->Instance->CR & tmp_ADC_CR_ADSTART_JADSTART) != 0UL)
    {
      if ((HAL_GetTick() - tickstart) > ADC_STOP_CONVERSION_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;
      }

then I get sometimes imprecise data access violation (IMPRECISERR) errors...

damn..it seems the complete processor is rebelling against me..

Benjamin Brammer
Senior II

I really don't understand what has happened: I now made a complete new project with the NUCLEO board and just set the clock to be the same as with my previous project (24MHz) but I measure an unstable clk. varying from 16MHz to 30MHz. Does anyone now how to complete reset the processor..? Like it was shipped from STM?