STM32:STM32F1-RCC,Reset&ClockControl

STM32:STM32F1-RCC,Reset&ClockControl

前提摘要

  1. 个人说明:

  2. 参考:

    • 正点原子
    • 野火
    • ST数据手册

正文

Reset

  1. 系统复位
  2. 电源复位
  3. 备份域复位

Clock Control

三种不同的时钟驱动系统时钟

  • HSI

  • HSE

  • PLL

RCC时钟树

在这里插入图片描述

STM32F1推荐SYSYCLK时钟为72MHz,所以各个时钟设置如下:

  • HSE = 8MHz,AHB = 72MHZ,APB1 = 36MHz,APB2 = 72MHz;
    • USB = 48Mhz;
    • HCLK = 72MHz;
    • Cortex系统时钟(SysTick Clock) = 9Mhz;
    • PCLK1 = 36MHz
    • PCLK2 = 72MHz
    • TIMxCLK = 72MHz
    • ADCCLK = 12MHz
  • LSE = 32.768kHz
  • HSI = 8Mhz
  • LSI = 40kHz

RCC寄存器

typedef struct
{
  __IO uint32_t CR;
  __IO uint32_t CFGR;
  __IO uint32_t CIR;
  __IO uint32_t APB2RSTR;
  __IO uint32_t APB1RSTR;
  __IO uint32_t AHBENR;
  __IO uint32_t APB2ENR;
  __IO uint32_t APB1ENR;
  __IO uint32_t BDCR;
  __IO uint32_t CSR;
} RCC_TypeDef;

HSE作为时钟来源,经过PLL倍频作为系统时钟

void HSE_SetSysClock(void)
{
	__IO uint32_t HSEStatus = 0;
	/* Resets the RCC clock configuration to the default reset state.*/
	RCC_DeInit();

	/* Enable HSE */  
	RCC_HSEConfig(RCC_HSE_ON);

	/* Wait till HSE is ready*/
	HSEStatus = RCC_WaitForHSEStartUp();
	
	if (HSEStatus == SUCCESS)
	{
		/* Enable Prefetch Buffer */
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

		/* Flash 2 wait state */
		// 0:0 < SYSCLK <= 24M
		// 1:24< SYSCLK <= 48M
		// 2:48< SYSCLK <= 72M
		FLASH_SetLatency(FLASH_Latency_2);
	 
		/* HCLK = SYSCLK */
		RCC_HCLKConfig(RCC_SYSCLK_Div1); 
	  
		/* PCLK2 = HCLK */
		RCC_PCLK2Config(RCC_HCLK_Div1); 

		/* PCLK1 = HCLK/2 */
		RCC_PCLK1Config(RCC_HCLK_Div2);
			
		/*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

		/* Enable PLL */
		RCC_PLLCmd(ENABLE);

		/* Wait till PLL is ready */
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
		{
		}

		/* Select PLL as system clock source */
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

		/* Wait till PLL is used as system clock source */
		while (RCC_GetSYSCLKSource() != 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 */
		while (1)
		{
		}
	}
}

HSI/2作为时钟来源,经过PLL倍频作为系统时钟

#define HSI_STARTUP_TIMEOUT		((uint16_t)0x0500) /*!< Time out for HSI start up */
void HSI_SetSysClock(void)
{
	__IO uint32_t StartUpCounter = 0,HSIStatus = 0;

	/* Resets the RCC clock configuration to the default reset state.*/
	RCC_DeInit();

	/* Enable HSI */ 
	RCC_HSICmd(ENABLE);
	
	/* Wait till HSI is ready and if Time out is reached exit */
	do{
		HSIStatus = RCC->CR & RCC_CR_HSIRDY;
		StartUpCounter++;
	}while((HSIStatus == 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT));
	
	if ((HSIStatus & RCC_CR_HSIRDY) != RESET)
	{
		/* Enable Prefetch Buffer */
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

		/* Flash 2 wait state */
		// 0:0 < SYSCLK <= 24M
		// 1:24< SYSCLK <= 48M
		// 2:48< SYSCLK <= 72M
		FLASH_SetLatency(FLASH_Latency_2);

		 /* HCLK = SYSCLK */
		RCC_HCLKConfig(RCC_SYSCLK_Div1); 

		/* PCLK2 = HCLK */
		RCC_PCLK2Config(RCC_HCLK_Div1); 

		/* PCLK1 = HCLK/2 */
		RCC_PCLK1Config(RCC_HCLK_Div2);
			
		/*  PLL configuration: PLLCLK = HSI * 16 = 64 MHz */
		RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);
		//------------------------------------------------------------------//

		 /* Enable PLL */
		RCC_PLLCmd(ENABLE);

		/* Wait till PLL is ready */
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
		{
		}

		/* Select PLL as system clock source */
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

		/* Wait till PLL is used as system clock source */
		while (RCC_GetSYSCLKSource() != 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 */
		while (1)
		{
		}
	}
}

MCO时钟输出

RCC MCO硬件相关宏定义,bsp_mco.h

#ifndef __BSP_RCCMCO_H
#define __BSP_RCCMCO_H

#include "stm32f10x.h"

#define BSP_RCC_MCO_Clk             RCC_APB2Periph_GPIOA      
#define BSP_RCC_MCO_Clk_Cmd         RCC_APB2PeriphClockCmd 
#define BSP_RCC_MCO_Port            GPIOA
#define BSP_RCC_MCO_Pin             GPIO_Pin_8


#endif /* __BSP_RCCMCO_H */

配置MCO GPIO

static void BSP_MCO_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	BSP_RCC_MCO_Clk_Cmd(BSP_RCC_MCO_Clk, ENABLE);

    GPIO_InitStructure.GPIO_Pin = BSP_RCC_MCO_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(BSP_RCC_MCO_Port, &GPIO_InitStructure);
}

void BSP_MCO_Init(void)
{
	BSP_MCO_GPIO_Config();
    //RCC_MCOConfig(RCC_MCO_HSE);	             	        
	//RCC_MCOConfig(RCC_MCO_HSI);	                   
	//RCC_MCOConfig(RCC_MCO_PLLCLK_Div2);
	RCC_MCOConfig(RCC_MCO_SYSCLK);		     
}

时间安全系统CSS

时钟安全系统可以通过软件被激活。一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被使能,并在HSE时钟关闭后关闭。

void RCC_ClockSecuritySystemCmd(ENABLE);

如果HSE时钟发生故障,HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和TIM8)的刹车输入端,并产生时钟安全中断CSSI,允许软件完成营救操作。此CSSI中断连接到Cortex™-M3的NMI中断(不可屏蔽中断)。

注意: 一旦CSS被激活,并且HSE时钟出现故障,CSS中断就产生,并且NMI也自动产生。NMI将被不断执行,直到CSS中断挂起位被清除。因此,在NMI的处理程序中必须通过设置时钟中断寄存器(RCC_CIR)里的CSSC位来清除CSS中断。

如果HSE振荡器被直接或间接地作为系统时钟,(间接的意思是:它被作为PLL输入时钟,并且PLL时钟被作为系统时钟),时钟故障将导致系统时钟自动切换到HSI振荡器,同时外部HSE振荡器被关闭。在时钟失效时,如果HSE振荡器时钟(被分频或未被分频)是用作系统时钟的PLL的输入时钟,PLL也将被关闭。

void NMI_Handler(void)
{
    if (RCC_GetITStatus(RCC_IT_CSS) != RESET)
    {    // HSE、PLL 已被禁止(但是PLL 设置未变)
         /* …… */ // 客户添加相应的系统保护代码处
        // 下面为HSE恢复后的预设置代码
       RCC_HSEConfig(RCC_HSE_ON);  // 使能HSE
       RCC_ ITConfig(RCC_IT_HSERDY,ENABLE); // 使能HSE就绪中断
       RCC_ ITConfig(RCC_IT_PLLRDY,ENABLE); // 使能PLL 就绪中断
       RCC_ClearITPendingBit(RCC_IT_CSS);  // 清除时钟安全系统中断的挂起位
 
       // 至此,一旦HSE时钟恢复,将发生HSERDY中断,
 
       //在RCC中断处理程序里, 系统时钟可以设置到以前的状态 
    }
}
void RCC_IRQHandler(void)
{
    __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
    
	if(RCC_GetITStatus(RCC_IT_HSERDY) != RESET)
    {
        RCC_ClearITPendingBit(RCC_IT_HSERDY);  // 清除时钟安全系统中断的挂起位
        RCC_DeInit();
        /* Enable HSE */  
        RCC_HSEConfig(RCC_HSE_ON);
        /* Wait till HSE is ready and if Time out is reached exit */
        HSEStatus = RCC_WaitForHSEStartUp();
        if(HSEStatus == SUCCESS)
        {
            FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
            FLASH_SetLatency(FLASH_Latency_2);
            
            RCC_HCLKConfig(RCC_SYSCLK_Div1);
         	RCC_PCLK1Config(RCC_HCLK_Div2);
         	RCC_PCLK2Config(RCC_HCLK_Div1);
            RCC_PLLConfig(RCC_PLLSource_HSE_Div1,9);
            RCC_PLLCmd(ENABLE);
            /* Wait till HSE is ready */
            while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
            /* SYSCLK is PLLCLK ,nor HSE CLK*/
            RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
            /* Wait till PLL is ready */
            while (RCC_GetSYSCLKSource() != 0x08);
        }
    }
}

mark:由于之前在上一家公司工作对于系统稳定性有很高的要求,所以看到CSS决定写尝试写一下这部分的代码。

上述代码未经过实际工程验证,只是在看完STM32F10x参考手册中关于CSS部分所写。

总结


本文均为原创,欢迎转载,请注明文章出处:CSDN:https://blog.csdn.net/ZipingPan/ARM。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

非原创博客会在文末标注出处,由于时效原因,可能并不是原创作者地址(已经无法溯源)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pan2iping

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值