Я недавно купил плату NUCLEO-F446RE (продукт STM32F4), и у меня серьезные проблемы с включением битов в регистре PWR.
Моя цель - мигать светодиодом с помощью таймера, и я пытаюсь настроить тактовую частоту HSI на максимальную системную частоту 180 МГц.
Я выполнил инструкции в справочном руководстве на букву «Т». Ниже приведен снимок экрана с инструкциями: Снимок экрана к справочному руководству
IDE: Keil v5
На плате установлена последняя версия прошивки.
Это мой код:
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
/* Private function prototypes -----------------------------------------------*/
static void sysClockConfig(void);
static void tim3Config(void);
/**
******************************************************************************
* @brief Main program.
* @note None
* @param None
* @retval None
******************************************************************************
*/
int main(void) {
sysClockConfig();
tim3Config();
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; //Enable GPIOA CLK
GPIOA->MODER |= GPIO_MODER_MODE5_0; //GPIOA pin5 selected as output
GPIOA->ODR |= GPIO_ODR_OD5; //GPIOA pin5 set high
volatile int i;
while(1) {
GPIOA->ODR |= GPIO_ODR_OD5;
for(i=0; i<1000000; i++);
GPIOA->ODR &= ~GPIO_ODR_OD5;
for(i=0; i<1000000; i++);
}
}
/**
******************************************************************************
* @brief Configures sysmtem clock and main PLL.
* Initializes voltage regulator scaling and overdrive mode.
* Initializes flash memory.
* @note CLK SRC = HSI -> PLL
# SYS CLK = 180 MHz
* AHB CLK = 180 MHz
* APB1 CLK = 45 MHz
* APB2 CLK = 90 MHz
* Change latency depending on freq and voltage (see table 5, pg.63)
* Look at pg.94 for CLK config sequence
* @param None
* @retval None
******************************************************************************
*/
static void sysClockConfig(void) {
RCC->CR |= RCC_CR_HSION; //Enables HSI clock
while( !(RCC->CR & RCC_CR_HSIRDY) ); //Waits until HSI is stable
RCC->CFGR |= RCC_CFGR_SW_HSI; //Select HSI is SYS CLK
while( RCC->CFGR & RCC_CFGR_SWS_HSI ); //Wait until HSI is SYS CLK
RCC->CR &= ~RCC_CR_PLLON; //Disables PLL
//-----> ISSUE #1 <-----
PWR->CR |= PWR_CR_VOS; //Voltage reg = scale 3
while( !(PWR->CSR & PWR_CSR_VOSRDY) ); //Waits until scaling is ready
/** PLL config: I2S/SAI/SPDIF = VCO / R
* USB/SDIO = VCO / Q
* SYS CLK = VCO / P
* VCO = HSI * (N/M)
*/
RCC->PLLCFGR |= ( 8u | //PLL_M = 8
(180u << 6) | //PLL_N = 180
( 0u << 16) | //PLL_P = 2
(RCC_PLLCFGR_PLLSRC_HSI)| //PLL SRC = HSI
( 8u << 24) | //PLL_Q = 8
( 4u << 28) ); //PLL_R = 4
RCC->CR |= RCC_CR_PLLON; //Enable PLL
//-----> ISSUE #2 <-----
PWR->CR |= PWR_CR_ODEN; //Enables Overdrive mode
while( !(PWR->CSR & PWR_CSR_ODRDY) ); //Waits until OD is ready
PWR->CR |= PWR_CR_ODSWEN; //Swites Overdrive mode
while( !(PWR->CSR & PWR_CSR_ODSWRDY) ); //Waits until OD switch is ready
FLASH->ACR |= (FLASH_ACR_PRFTEN | //Prefetch enable
FLASH_ACR_ICEN | //Intruction cache enable
FLASH_ACR_DCEN | //Data cache enable
FLASH_ACR_LATENCY_5WS ); //FLASH 5 wait states
while( !(RCC->CR & RCC_CR_PLLRDY) ); //Waits until PLL is locked
RCC->CFGR |= (RCC_CFGR_HPRE_DIV1 | //AHB = Sys CLK DIV_1
RCC_CFGR_PPRE1_DIV4 | //APB1 = AHB CLK DIV_4
RCC_CFGR_PPRE2_DIV2 | //APB2 = AHB CLK DIV_2
RCC_CFGR_SW_PLL ); //Select PLL as SYS CLK
while( !(RCC->CFGR & RCC_CFGR_SWS_PLL) ); //Waits until PLL is SYS CLK
}
/**
******************************************************************************
* @brief Configures TIM3.
* @note None
* @param None
* @retval None
******************************************************************************
*/
static void tim3Config(void) {
}
Я не закончил настройку таймера, поэтому я просто использую цикл потери ресурсов процессора, чтобы мигать светодиодом.
Есть 2 проблемы (1 второстепенная и 1 большая):
1.
PWR->CR |= PWR_CR_VOS;
while( !(PWR->CSR & PWR_CSR_VOSRDY) );
Когда я выполняю приведенный выше код, он застревает в бесконечном цикле. Это не имеет большого значения, учитывая, что значение включено по умолчанию. Хотя хотелось бы знать, почему это происходит. Я комментировал этот блок, чтобы выполнить следующий блок кода.
2.
PWR->CR |= PWR_CR_ODEN;
while( !(PWR->CSR & PWR_CSR_ODRDY) );
PWR->CR |= PWR_CR_ODSWEN;
while( !(PWR->CSR & PWR_CSR_ODSWRDY) );
Приведенный выше код вызывает наибольшее беспокойство. Когда я отлаживаю свой код, PWR_CR_ODEN не включается и в конечном итоге застревает в бесконечном цикле на второй строке. Я также пробовал включить бит, используя:
PWR->CR |= (1 << 16);
Но он по-прежнему застревает на второй строке кода.
В справочнике ничего особенного по настройке этого регистра не указано. Я совершенно потерялся здесь.
Как ни странно, если я полностью пропущу 2 блока кода, программа выполнится и замигает светодиодом. Однако я хотел бы решить проблемы, показанные выше, и понять, почему это происходит.
Любая помощь приветствуется. И извините за длинный пост.