Thanks everyone for their input! After looking through this, researching elsewhere, and after more tinkering, I finally got it working. Even though it was valuable learning how to make my own drivers from scratch (I understand way better now what other drivers do now), I decided I was comfortable enough using the CMSIS header definitions. Though I am still hesitant to use the ST HAL as what I am doing greatly benefits from direct register manipulation (emulating game controller protocols). Below is my final code for the STM32F407VG, to run at 180MHz, using 8MHz external crystal, so that someone else may benefit in the future.
static void configure_clock()
{
/* Clock Settings for 168MHz
HCLK = 168
PLL: M = 8, N = 336, P = 2, Q = 7
AHB prescaler = 1
APB prescaler1 = 4, APB prescaler2 = 2
MCO1 prescaler = 2 */
// Configures flash latency.
// LATENCY: bits 2-0
MODIFY_REG(FLASH->ACR,
FLASH_ACR_LATENCY,
_VAL2FLD(FLASH_ACR_LATENCY,
FLASH_ACR_LATENCY_5WS) //FLASH_ACR_LATENCY_5WS << FLASH_ACR_LATENCY_Pos
);
// Enables HSE.
// HSE_ON: bit 16
SET_BIT(RCC->CR, RCC_CR_HSEON);
// Waits until HSE is stable.
// HSERDY: bit 17
while (!READ_BIT(RCC->CR, RCC_CR_HSERDY));
// Configures PLL: source = HSE, PLLCLK = 168MHz.
// M: bits 5-0, N: bits 14-6, P: bits 17-16, PLLSRC: bit 22, Q: bits 27-24
MODIFY_REG(RCC->PLLCFGR,RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLQ | RCC_PLLCFGR_PLLSRC
| RCC_PLLCFGR_PLLP,_VAL2FLD(RCC_PLLCFGR_PLLM, 8) | _VAL2FLD(RCC_PLLCFGR_PLLN, 336)
| _VAL2FLD(RCC_PLLCFGR_PLLQ, 7) | RCC_PLLCFGR_PLLSRC_HSE);
// Enables PLL module.
// PLLON: bit 24
SET_BIT(RCC->CR, RCC_CR_PLLON);
// Waits until PLL is stable.
// PLLRDY: bit 25
while (!READ_BIT(RCC->CR, RCC_CR_PLLRDY));
// Switches system clock to PLL.
// SW: bits 1-0
MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, _VAL2FLD(RCC_CFGR_SW, RCC_CFGR_SW_PLL));
// Configures PPRE1 = 4
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, _VAL2FLD(RCC_CFGR_PPRE1, 5));
// Configures PPRE2 = 2
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, _VAL2FLD(RCC_CFGR_PPRE1, 4));
// Configures HPRE = 1
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, _VAL2FLD(RCC_CFGR_PPRE1, 1));
// Waits until PLL is used.
while(READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// Disables HSI.
CLEAR_BIT(RCC->CR, RCC_CR_HSION);
}
void configure_mco1()
{
// Configures MCO1: source = PLLCLK, MCO1PRE = 2.
MODIFY_REG(RCC->CFGR,
RCC_CFGR_MCO1 | RCC_CFGR_MCO1PRE,
_VAL2FLD(RCC_CFGR_MCO1, 3) | _VAL2FLD(RCC_CFGR_MCO1PRE, 7)
);
// Enables GPIOA (MCO1 is connected to PA8).
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);
// Configures PA8 as medium speed.
MODIFY_REG(GPIOA->OSPEEDR,
GPIO_OSPEEDR_OSPEED8,
_VAL2FLD(GPIO_OSPEEDR_OSPEED8, 1)
);
// Configures PA8 to work in alternate function mode.
MODIFY_REG(GPIOA->MODER,
GPIO_MODER_MODER8,
_VAL2FLD(GPIO_MODER_MODER8, 2)
);
}