2019-11-20 03:58 AM
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
2019-11-20 04:18 AM
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..
2019-11-21 11:07 AM
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?