103的工程模板改105的大体步骤和上一篇ZET6改C8T6的相差不大,只是改成105之后,问题就来了,发现它的 HSE_VALUE 默认定义为25MHz,WTF,板子都做回来了,晶振买的也是8MHz,搞个锤子
#if !defined HSE_VALUE#ifdef STM32F10X_CL #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */#else #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */
看了一下105的时钟树:那些主要的外设都是挂在SYSCLK上面,也就是来源于PLLCLK的时钟。
首先看一下官方的对于系统时钟的配置:为了方便起见,我把多余的代码删掉了
void SystemInit (void)
{/* Reset the RCC clock configuration to the default reset state(for debug purpose) *//* Set HSION bit 确保内部8MHz振荡器开启。*/RCC->CR |= (uint32_t)0x00000001;/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */RCC->CFGR &= (uint32_t)0xF0FF0000;/* Reset HSEON, CSSON and PLLON bits */RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset HSEBYP bit */RCC->CR &= (uint32_t)0xFFFBFFFF;/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */RCC->CFGR &= (uint32_t)0xFF80FFFF;/* Reset PLL2ON and PLL3ON bits */RCC->CR &= (uint32_t)0xEBFFFFFF;/* Disable all interrupts and clear pending bits */RCC->CIR = 0x00FF0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers *//* Configure the Flash Latency cycles and enable prefetch buffer */SetSysClock();SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
}
首先对 RCC->CR、RCC->CFGR、RCC->CIR三个寄存器进行复位或者设置,之后调用SetSysClock(); 正式对系统时钟进行设置。由于我们要将系统时钟设置为 72MHz,所以在 SetSysClock() 中后面调用的就是 SetSysClockTo72(void) 这个函数。函数原型如下:为了方便阅读,将部分无关代码删除。
static void SetSysClockTo72(void)
{__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ /* Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;} if (HSEStatus == (uint32_t)0x01){/* Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/* Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK/2 */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL/* Configure PLLs ------------------------------------------------------*//* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz *//* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);/* Enable PLL2 */RCC->CR |= RCC_CR_PLL2ON;/* Wait till PLL2 is ready */while((RCC->CR & RCC_CR_PLL2RDY) == 0){}/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLMULL9);
#else #endif /* STM32F10X_CL *//* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* 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)0x08){}}else{ /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */}
}
以下对程序进行分析。
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ /* Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}
以上代码主要是为了对使能外部时钟并等待HSE稳定,当HSE时钟稳定之后,HSEStatus = (uint32_t)0x01;之后执行以下代码
/* Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/* Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /* HCLK = SYSCLK 设置HPRE[3:0]位,即0xxx: SYSCLK不分频*/RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK 设置PPRE2[2:0]位,即高速APB预分频(APB2)不分频*/RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK 设置PPRE1[2:0]位,即低速APB预分频(APB1)二分频*/RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
之后最重要的配置来了,代码分析在注释中给出:
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz *//* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz *//*PLL2作为PREDIV1的时钟源,PLL2 8倍频输出,PREDIV2对输入时钟5分频,PREDIV1对输入时钟5分频*/ RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);/*这一步需要改,这一步做到的事为将PREDIV2设置为/5;然后将PLL2MUL设置为*8;将PREDIV1SRC设置为PLL2作为PREDIV1的时钟源;将PREDIV1设置为/5,此时到达PLLSCR的时钟为8MHz*//*-----------------以下代码为 HSE_VALUE == 25000000 时使用-----------------*/RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);/*--------------------------------------------------------------------------*/
标记1:以上这一步的配置为:将PREDIV2配置为5分频,PLL2MUL配置为8倍频,PREDIV1SCR的输入源配置来源于PLL2(PLL2CLK),PREDIV1配置为5分频。当外部输入时钟为25MHz时,经过PREDIV2分频之后,输出5MHz,再经过PLL2MUL倍频之后输出40MHz,也就是PLL2CLK=40MHz,之后经过PREDIV分频之后,输入PLLSCR的时钟为8MHz,之后只需经过PLLMUL倍频之后就可以得到72MHz的时钟(PLLMUL倍频在后续代码。)
/*--------------------------------------------------------------------------*//* Enable PLL2 */RCC->CR |= RCC_CR_PLL2ON;/* Wait till PLL2 is ready */while((RCC->CR & RCC_CR_PLL2RDY) == 0){}/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ /**/RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);/*RCC_CFGR_PLLXTPRE_PREDIV1 :PREDIV1分频因子的低位,不对输入时钟分频(PLLXPRE=0);RCC_CFGR_PLLSRC_PREDIV1 :PREDIV1输出作为PLL输入时钟RCC_CFGR_PLLMULL9:PLLMULL设置为*9*/RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLMULL9);
上面代码就是把PLL2CLK时钟使能,刚开始默认是关闭的,之后RCC_CFGR_PLLXTPRE_PREDIV1 参数表示RCC->CFGR寄存器不对PREDIV1分频器进行设置,表示默认使用RCC->CFGR2对PREDIV1分频器的设置,之后PLLSRC选择PREDIV1的输出作为时钟源,之后再将PLLMUL的倍频设置为9倍频,这样就得到了PLLCLK的时钟为72MHz。
/* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* 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)0x08){}
后面的这一些就只是使能PLLCLK时钟,然后等待PLLCLK时钟就绪,之后SW选择PLLCLK时钟作为SYSCLK时钟源,再确保PLLCLK已经作为SYSCLK的时钟源。
官方时钟配置代码讲解到这里,回到先前那个话题,如果外部时钟源是8MHz怎么办?如果继续按照官方的代码,回到标记1此时时钟配置明显错误。
以下给出两种配置为8MHz的方法。
方法一:对官方代码修改最少。当外部时钟HSE变为8MHz时,我们只需将PREDIV2设置为2分频,在将PLL2MUL配置为10倍频,此时我们就能得到PLL2CLK为40MHz,如下图所示:
即将代码:
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
修改为:
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV2 | RCC_CFGR2_PLL2MUL10 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5)
其他不变。
方法二:PREDIV1SCR不选择PLL2CLK作为时钟源输入,直接使用外部时钟HSE作为时钟源输入,之后PREDIV1配置为1分频,此时进入PLLSCR的时钟源为8MHz,之后PLLMUL配置9倍频,照样可以得到PLLCLK==72MHz,如下图所示:
static void SetSysClockTo72(void)
{__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/*!< SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ /*!< Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON); //使能HSE/*!< Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;} //当外部HSE时钟准备就绪之后HSEStatus == 0x01if (HSEStatus == (uint32_t)0x01){/*!< Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/*!< Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /*!< HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //AHB预分频器/*!< PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/*!< PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;/*!< PLLCLK = 8MHz * 9 = 72 MHz */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));//设置PLLSCR的时钟来源于PREDIV1,PLLMUL配置为9倍频//为什么上面看不到 PREDIV1SCR 和 PREDIV1 的配置,因为 PREDIV1SCR 默认配置来源为HSE时钟, PREDIV1 默认不分频RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLMULL9);/*!< Enable PLL */RCC->CR |= RCC_CR_PLLON;/*!< Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/*!< 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)0x08){}}else{ /*!< If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */ }
}
至此,stm32f105的时钟修改完毕。最后别忘了修改HSE_VALUE的值
#if !defined HSE_VALUE#ifdef STM32F10X_CL #define HSE_VALUE ((uint32_t)8000000) /*!<25000000 Value of the External oscillator in Hz */#else #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */
————————————————
版权声明:本文为CSDN博主「大文梅」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40831436/article/details/114702068