реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Изменение опорного клока на лету, STM32L
marco
сообщение Mar 14 2013, 09:08
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 48
Регистрация: 12-12-10
Пользователь №: 61 580



Добрый день.

Хочу переключаться с 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().

Сообщение отредактировал marco - Mar 14 2013, 10:52
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Mar 14 2013, 15:41
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



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

Go to the top of the page
 
+Quote Post
marco
сообщение Mar 15 2013, 09:57
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 48
Регистрация: 12-12-10
Пользователь №: 61 580



Цитата(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-прерывания.

Сообщение отредактировал marco - Mar 15 2013, 09:40
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th June 2025 - 22:30
Рейтинг@Mail.ru


Страница сгенерированна за 0.01392 секунд с 7
ELECTRONIX ©2004-2016