Хочу переключаться с PLL на MSI и наоборот.
Программа:
1. Настраивается опорный клок (PLL или MSI);
2. Конфигурируется таймер (периоды и делители задаются абсолютно - без привязки к текущему клоку), по прерыванию которого мигает лампочка;
3. По нажатию кнопки меняется опорный клок PLL <-> MSI.
При этом SysClock(PLL) == 4MHz, SysClock(MSI) == 65538 КГц. Делители шин AHB/APB1 и AHB/APB2 равны 1 (это влияет коэффициент опорной частоты таймеров).
Таймер настроен так, что при работе SysClock от MSI частота мигания лампочки - 1Гц (при PLL, соответственно, 4MHz/65538КГц ~ 60Гц).
Проблема в том, что при использовании MSI как опорного клока во время инициализации МК всё работает нормально (частота мигания, действительно, равна 1Гц), но при переключении MSI->PLL->MSI частота мигания сильно уменьшена (~ в 16 раз). При этом мигание во время работы от PLL всегда имеет расчётную частоту. Опытным путём обнаружил, что ошибка где-то в функции SetSysClockToPLL() или в некорректном переходе PLL->MSI.
CODE
void SystemInit (void)
{
/*!< Set MSION bit */
RCC->CR |= (uint32_t)0x00000100;
/*!< Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], MCOSEL[2:0] and MCOPRE[2:0] bits */
RCC->CFGR &= (uint32_t)0x88FFC00C;
/*!< Reset HSION, HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xEEFEFFFE;
/*!< Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/*!< Reset PLLSRC, PLLMUL[3:0] and PLLDIV[1:0] bits */
RCC->CFGR &= (uint32_t)0xFF02FFFF;
/*!< Disable all interrupts */
RCC->CIR = 0x00000000;
//SetSysClockToPLL();
SetSysClockToMSI();
}
От PLL:
CODE
void SetSysClockToPLL(void)
{
__IO uint32_t StartUpCounter = 0, HSIStatus = 0, PLLStatus = 0;
/* Enable HSI */
RCC->CR |= ((uint32_t)RCC_CR_HSION);
/* Wait till HSI is ready and if Time out is reached exit */
do
{
HSIStatus = RCC->CR & RCC_CR_HSIRDY;
StartUpCounter++;
} while((HSIStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSIRDY) != RESET)
{
HSIStatus = (uint32_t)0x01;
}
else
{
HSIStatus = (uint32_t)0x00;
}
if (HSIStatus == (uint32_t)0x01)
{
/* Configure PLL
* PLLMUL = 6 (96MHz)
* PLLDIV = 3 (32MHz)
*/
RCC->CFGR |= (RCC_CFGR_PLLMUL6 | RCC_CFGR_PLLDIV3);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY))
{}
FLASH->ACR |= FLASH_ACR_ACC64;
FLASH->ACR |= FLASH_ACR_PRFTEN;
FLASH->ACR |= FLASH_ACR_LATENCY;
/* Enable the PWR APB1 Clock */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
/* Select the Voltage Range 1 (1.8V) */
PWR->CR = PWR_CR_VOS_0;
/* Wait Until the Voltage Regulator is ready */
while((PWR->CSR & PWR_CSR_VOSF) != RESET)
{
}
/* HCLK/8 = SYSCLK (4MHz) */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV8;
/* PCLK2 = HCLK (4MHz) */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK (4MHz) */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x0C)
{
}
SystemCoreClockUpdate();
}
else
{
/* If HSI fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
От MSI:
CODE
void SetSysClockToMSI(void)
{
__IO uint32_t StartUpCounter = 0, MSIStatus = 0;
/* Enable MSI */
RCC->CR |= ((uint32_t)RCC_CR_MSION);
/* Wait till MSI is ready and if Time out is reached exit */
do
{
MSIStatus = RCC->CR & RCC_CR_MSIRDY;
StartUpCounter++;
} while((MSIStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_MSIRDY) != RESET)
{
MSIStatus = (uint32_t)0x01;
}
else
{
MSIStatus = (uint32_t)0x00;
}
if (MSIStatus == (uint32_t)0x01)
{
FLASH->ACR &= ~FLASH_ACR_LATENCY;
FLASH->ACR &= ~FLASH_ACR_PRFTEN;
FLASH->ACR &= ~FLASH_ACR_ACC64;
/* Enable the PWR APB1 Clock */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
/* Select the Voltage Range 3 (1.2V) */
PWR->CR = PWR_CR_VOS;
/* Wait Until the Voltage Regulator is ready */
while((PWR->CSR & PWR_CSR_VOSF) != RESET)
{
}
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
/* 65.536KHz */
RCC->ICSCR &= (uint32_t)((uint32_t)~(RCC_ICSCR_MSIRANGE));
RCC->ICSCR |= (uint32_t)RCC_ICSCR_MSIRANGE_0;
/* Select MSI as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_MSI;
/* Wait till MSI is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x00)
{
}
SystemCoreClockUpdate();
}
else
{
/* If MSI fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
Соответственно, по нажатию кнопки, я проверяю, от чего работает SysClock в данный момент и вызываю SetSysClockToMSI() или SetSysClockToPLL().