openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

120 lines
5.1 KiB

/*
HSE: 25MHz
PLL1Q: 80MHz (for FDCAN)
HSI48 enabled (for USB)
CPU: 240MHz
CPU Systick: 240MHz
AXI: 120MHz
HCLK3: 60MHz
APB3 per: 60MHz
AHB1,2 per: 120MHz
APB1 per: 60MHz
APB1 tim: 120MHz
APB2 per: 60MHz
APB2 tim: 120MHz
AHB4 per: 120MHz
APB4 per: 60MHz
PCLK1: 60MHz (for USART2,3,4,5,7,8)
*/
typedef enum {
PACKAGE_UNKNOWN = 0,
PACKAGE_WITH_SMPS = 1,
PACKAGE_WITHOUT_SMPS = 2,
} PackageSMPSType;
// TODO: find a better way to distinguish between H725 (using SMPS) and H723 (lacking SMPS)
// The package will do for now, since we have only used TFBGA100 for H723
static PackageSMPSType get_package_smps_type(void) {
PackageSMPSType ret;
RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN; // make sure SYSCFG clock is enabled. does seem to read fine without too though
switch(SYSCFG->PKGR & 0xFU) {
case 0b0001U: // TFBGA100 Legacy
case 0b0011U: // TFBGA100
ret = PACKAGE_WITHOUT_SMPS;
break;
case 0b0101U: // LQFP144 Legacy
case 0b0111U: // LQFP144 Industrial
case 0b1000U: // UFBGA169
ret = PACKAGE_WITH_SMPS;
break;
default:
ret = PACKAGE_UNKNOWN;
}
return ret;
}
void clock_init(void) {
/*
WARNING: PWR->CR3's lower byte can only be written once
* subsequent writes will silently fail
* only cleared with a full power-on-reset, not soft reset or reset pin
* some H7 have a bootrom with a DFU routine that writes (and locks) CR3
* if the CR3 config doesn't match the HW, the core will deadlock and require immediately going into DFU from a cold boot
In a normal bootup, the bootstub will be the first to write this. The app section calls clock_init again, but the CR3 write will silently fail. This is fine for most cases, but caution should be taken that the bootstub and app always write the same config.
*/
// Set power mode to direct SMPS power supply (depends on the board layout)
PackageSMPSType package_smps = get_package_smps_type();
if (package_smps == PACKAGE_WITHOUT_SMPS) {
register_set(&(PWR->CR3), PWR_CR3_LDOEN, 0xFU); // no SMPS, so powered by LDO
} else if (package_smps == PACKAGE_WITH_SMPS) {
register_set(&(PWR->CR3), PWR_CR3_SMPSEN, 0xFU); // powered only by SMPS
} else {
while(true); // unknown package, let's hang here
}
// Set VOS level (VOS3 to 170Mhz, VOS2 to 300Mhz, VOS1 to 400Mhz, VOS0 to 550Mhz)
register_set(&(PWR->D3CR), PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0, 0xC000U); //VOS1, needed for 80Mhz CAN FD
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U);
while ((PWR->CSR1 & PWR_CSR1_ACTVOS) != (PWR->D3CR & PWR_D3CR_VOS)); // check that VOS level was actually set
// Configure Flash ACR register LATENCY and WRHIGHFREQ (VOS0 range!)
register_set(&(FLASH->ACR), FLASH_ACR_LATENCY_2WS | 0x20U, 0x3FU); // VOS2, AXI 100MHz-150MHz
// enable external oscillator HSE
register_set_bits(&(RCC->CR), RCC_CR_HSEON);
while ((RCC->CR & RCC_CR_HSERDY) == 0U);
// enable internal HSI48 for USB FS kernel
register_set_bits(&(RCC->CR), RCC_CR_HSI48ON);
while ((RCC->CR & RCC_CR_HSI48RDY) == 0U);
// Specify the frequency source for PLL1, divider for DIVM1, DIVM2, DIVM3 : HSE, 5, 5, 5
register_set(&(RCC->PLLCKSELR), RCC_PLLCKSELR_PLLSRC_HSE | RCC_PLLCKSELR_DIVM1_0 | RCC_PLLCKSELR_DIVM1_2 | RCC_PLLCKSELR_DIVM2_0 | RCC_PLLCKSELR_DIVM2_2 | RCC_PLLCKSELR_DIVM3_0 | RCC_PLLCKSELR_DIVM3_2, 0x3F3F3F3U);
// *** PLL1 start ***
// Specify multiplier N and dividers P, Q, R for PLL1 : 48, 1, 3, 2 (clock 240Mhz, PLL1Q 80Mhz for CAN FD)
register_set(&(RCC->PLL1DIVR), 0x102002FU, 0x7F7FFFFFU);
// Specify the input and output frequency ranges, enable dividers for PLL1
register_set(&(RCC->PLLCFGR), RCC_PLLCFGR_PLL1RGE_2 | RCC_PLLCFGR_DIVP1EN | RCC_PLLCFGR_DIVQ1EN | RCC_PLLCFGR_DIVR1EN, 0x7000CU);
// Enable PLL1
register_set_bits(&(RCC->CR), RCC_CR_PLL1ON);
while((RCC->CR & RCC_CR_PLL1RDY) == 0U);
// *** PLL1 end ***
//////////////OTHER CLOCKS////////////////////
// RCC HCLK Clock Source / RCC APB3 Clock Source / RCC SYS Clock Source
register_set(&(RCC->D1CFGR), RCC_D1CFGR_HPRE_DIV2 | RCC_D1CFGR_D1PPRE_DIV2 | RCC_D1CFGR_D1CPRE_DIV1, 0xF7FU);
// RCC APB1 Clock Source / RCC APB2 Clock Source
register_set(&(RCC->D2CFGR), RCC_D2CFGR_D2PPRE1_DIV2 | RCC_D2CFGR_D2PPRE2_DIV2, 0x770U);
// RCC APB4 Clock Source
register_set(&(RCC->D3CFGR), RCC_D3CFGR_D3PPRE_DIV2, 0x70U);
// Set SysClock source to PLL
register_set(&(RCC->CFGR), RCC_CFGR_SW_PLL1, 0x7U);
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL1);
//////////////END OTHER CLOCKS////////////////////
// Configure clock source for USB (HSI48)
register_set(&(RCC->D2CCIP2R), RCC_D2CCIP2R_USBSEL_1 | RCC_D2CCIP2R_USBSEL_0, RCC_D2CCIP2R_USBSEL);
// Configure clock source for FDCAN (PLL1Q at 80Mhz)
register_set(&(RCC->D2CCIP1R), RCC_D2CCIP1R_FDCANSEL_0, RCC_D2CCIP1R_FDCANSEL);
// Configure clock source for DFSDM1
register_set_bits(&(RCC->D2CCIP1R), RCC_D2CCIP1R_DFSDM1SEL);
// Configure clock source for ADC1,2,3 (per_ck(currently HSE))
register_set(&(RCC->D3CCIPR), RCC_D3CCIPR_ADCSEL_1, RCC_D3CCIPR_ADCSEL);
//Enable the Clock Security System
register_set_bits(&(RCC->CR), RCC_CR_CSSHSEON);
//Enable Vdd33usb supply level detector
register_set_bits(&(PWR->CR3), PWR_CR3_USB33DEN);
}