Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Изменение опорного клока на лету
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
marco
Добрый день.

Хочу переключаться с 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().
Golikov A.
MSI идет сразу на выход без всяких делителей, при это 64КГц (почему у вас он равен максимальному беззнаковому инту 65538 кстати?) это его минимум, значит при переходе на него медленнее физически быть не может.
Отсюда надо поглядеть 2 вещи.
1. может происходит срыв переходя на MSI и проц хватается за какой то другой клок, например за HSI, а он уже идет через делители PLL и может быть меньше 64 КГц.
2. может возникает какое то прерывание из высоко приоритетных которое так часто долбит что забивает таймер.. хотя это мало вероятно.

marco
Цитата(Golikov A. @ Mar 14 2013, 19:41) *
MSI идет сразу на выход без всяких делителей, при это 64КГц (почему у вас он равен максимальному беззнаковому инту 65538 кстати?) это его минимум, значит при переходе на него медленнее физически быть не может.

Прошу прощения. 65.536 кГц


Нашёл.
Перед выбором клока нужно выполнить следующие действия (реализованы в функции RCC_DeInit()):
1. Включить MSI и установить его в качестве системного клока (думаю, HSI в данном качестве тоже подойдёт);
2. Снять все делители: AHB, APB1, APB2 (RCC_CFGR);
3. Отключить HSI, HSE и PLL; выключить CSS и HSE bypass.
4. Отключить RCC-прерывания.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.