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.
262 lines
7.9 KiB
262 lines
7.9 KiB
#include "sys.h"
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
|
|
//ALIENTEK STM32F407开发板
|
|
//系统时钟初始化
|
|
//包括时钟设置/中断管理/GPIO设置等
|
|
//正点原子@ALIENTEK
|
|
//技术论坛:www.openedv.com
|
|
//创建日期:2014/5/2
|
|
//版本:V1.1
|
|
//版权所有,盗版必究。
|
|
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
|
|
//All rights reserved
|
|
//********************************************************************************
|
|
//修改说明
|
|
//V1.1 20150411
|
|
//1,修改WFI_SET/INTX_DISABLE/INTX_ENABLE等函数的实现方式
|
|
//2,修改SYSTEM_SUPPORT_UCOS为SYSTEM_SUPPORT_OS
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//设置向量表偏移地址
|
|
//NVIC_VectTab:基址
|
|
//Offset:偏移量
|
|
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab,u32 Offset)
|
|
{
|
|
SCB->VTOR=NVIC_VectTab|(Offset&(u32)0xFFFFFE00);//设置NVIC的向量表偏移寄存器,VTOR低9位保留,即[8:0]保留。
|
|
}
|
|
//设置NVIC分组
|
|
//NVIC_Group:NVIC分组 0~4 总共5组
|
|
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
|
|
{
|
|
u32 temp,temp1;
|
|
temp1=(~NVIC_Group)&0x07;//取后三位
|
|
temp1<<=8;
|
|
temp=SCB->AIRCR; //读取先前的设置
|
|
temp&=0X0000F8FF; //清空先前分组
|
|
temp|=0X05FA0000; //写入钥匙
|
|
temp|=temp1;
|
|
SCB->AIRCR=temp; //设置分组
|
|
}
|
|
//设置NVIC
|
|
//NVIC_PreemptionPriority:抢占优先级
|
|
//NVIC_SubPriority :响应优先级
|
|
//NVIC_Channel :中断编号
|
|
//NVIC_Group :中断分组 0~4
|
|
//注意优先级不能超过设定的组的范围!否则会有意想不到的错误
|
|
//组划分:
|
|
//组0:0位抢占优先级,4位响应优先级
|
|
//组1:1位抢占优先级,3位响应优先级
|
|
//组2:2位抢占优先级,2位响应优先级
|
|
//组3:3位抢占优先级,1位响应优先级
|
|
//组4:4位抢占优先级,0位响应优先级
|
|
//NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先
|
|
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)
|
|
{
|
|
u32 temp;
|
|
MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组
|
|
temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
|
|
temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
|
|
temp&=0xf; //取低四位
|
|
NVIC->ISER[NVIC_Channel/32]|=1<<NVIC_Channel%32;//使能中断位(要清除的话,设置ICER对应位为1即可)
|
|
NVIC->IP[NVIC_Channel]|=temp<<4; //设置响应优先级和抢断优先级
|
|
}
|
|
//外部中断配置函数
|
|
//只针对GPIOA~I;不包括PVD,RTC,USB_OTG,USB_HS,以太网唤醒等
|
|
//参数:
|
|
//GPIOx:0~8,代表GPIOA~I
|
|
//BITx:需要使能的位;
|
|
//TRIM:触发模式,1,下升沿;2,上降沿;3,任意电平触发
|
|
//该函数一次只能配置1个IO口,多个IO口,需多次调用
|
|
//该函数会自动开启对应中断,以及屏蔽线
|
|
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)
|
|
{
|
|
u8 EXTOFFSET=(BITx%4)*4;
|
|
RCC->APB2ENR|=1<<14; //使能SYSCFG时钟
|
|
SYSCFG->EXTICR[BITx/4]&=~(0x000F<<EXTOFFSET);//清除原来设置!!!
|
|
SYSCFG->EXTICR[BITx/4]|=GPIOx<<EXTOFFSET; //EXTI.BITx映射到GPIOx.BITx
|
|
//自动设置
|
|
EXTI->IMR|=1<<BITx; //开启line BITx上的中断(如果要禁止中断,则反操作即可)
|
|
if(TRIM&0x01)EXTI->FTSR|=1<<BITx; //line BITx上事件下降沿触发
|
|
if(TRIM&0x02)EXTI->RTSR|=1<<BITx; //line BITx上事件上升降沿触发
|
|
}
|
|
//GPIO复用设置
|
|
//GPIOx:GPIOA~GPIOI.
|
|
//BITx:0~15,代表IO引脚编号.
|
|
//AFx:0~15,代表AF0~AF15.
|
|
//AF0~15设置情况(这里仅是列出常用的,详细的请见407数据手册,56页Table 7):
|
|
//AF0:MCO/SWD/SWCLK/RTC AF1:TIM1/TIM2; AF2:TIM3~5; AF3:TIM8~11
|
|
//AF4:I2C1~I2C3; AF5:SPI1/SPI2; AF6:SPI3; AF7:USART1~3;
|
|
//AF8:USART4~6; AF9;CAN1/CAN2/TIM12~14 AF10:USB_OTG/USB_HS AF11:ETH
|
|
//AF12:FSMC/SDIO/OTG/HS AF13:DCIM AF14: AF15:EVENTOUT
|
|
void GPIO_AF_Set(GPIO_TypeDef* GPIOx,u8 BITx,u8 AFx)
|
|
{
|
|
GPIOx->AFR[BITx>>3]&=~(0X0F<<((BITx&0X07)*4));
|
|
GPIOx->AFR[BITx>>3]|=(u32)AFx<<((BITx&0X07)*4);
|
|
}
|
|
//GPIO通用设置
|
|
//GPIOx:GPIOA~GPIOI.
|
|
//BITx:0X0000~0XFFFF,位设置,每个位代表一个IO,第0位代表Px0,第1位代表Px1,依次类推.比如0X0101,代表同时设置Px0和Px8.
|
|
//MODE:0~3;模式选择,0,输入(系统复位默认状态);1,普通输出;2,复用功能;3,模拟输入.
|
|
//OTYPE:0/1;输出类型选择,0,推挽输出;1,开漏输出.
|
|
//OSPEED:0~3;输出速度设置,0,2Mhz;1,25Mhz;2,50Mhz;3,100Mh.
|
|
//PUPD:0~3:上下拉设置,0,不带上下拉;1,上拉;2,下拉;3,保留.
|
|
//注意:在输入模式(普通输入/模拟输入)下,OTYPE和OSPEED参数无效!!
|
|
void GPIO_Set(GPIO_TypeDef* GPIOx,u32 BITx,u32 MODE,u32 OTYPE,u32 OSPEED,u32 PUPD)
|
|
{
|
|
u32 pinpos=0,pos=0,curpin=0;
|
|
for(pinpos=0;pinpos<16;pinpos++)
|
|
{
|
|
pos=1<<pinpos; //一个个位检查
|
|
curpin=BITx&pos;//检查引脚是否要设置
|
|
if(curpin==pos) //需要设置
|
|
{
|
|
GPIOx->MODER&=~(3<<(pinpos*2)); //先清除原来的设置
|
|
GPIOx->MODER|=MODE<<(pinpos*2); //设置新的模式
|
|
if((MODE==0X01)||(MODE==0X02)) //如果是输出模式/复用功能模式
|
|
{
|
|
GPIOx->OSPEEDR&=~(3<<(pinpos*2)); //清除原来的设置
|
|
GPIOx->OSPEEDR|=(OSPEED<<(pinpos*2));//设置新的速度值
|
|
GPIOx->OTYPER&=~(1<<pinpos) ; //清除原来的设置
|
|
GPIOx->OTYPER|=OTYPE<<pinpos; //设置新的输出模式
|
|
}
|
|
GPIOx->PUPDR&=~(3<<(pinpos*2)); //先清除原来的设置
|
|
GPIOx->PUPDR|=PUPD<<(pinpos*2); //设置新的上下拉
|
|
}
|
|
}
|
|
}
|
|
|
|
//THUMB指令不支持汇编内联
|
|
//采用如下方法实现执行汇编指令WFI
|
|
void WFI_SET(void)
|
|
{
|
|
__ASM volatile("wfi");
|
|
}
|
|
//关闭所有中断(但是不包括fault和NMI中断)
|
|
void INTX_DISABLE(void)
|
|
{
|
|
__ASM volatile("cpsid i");
|
|
}
|
|
//开启所有中断
|
|
void INTX_ENABLE(void)
|
|
{
|
|
__ASM volatile("cpsie i");
|
|
}
|
|
//设置栈顶地址
|
|
//addr:栈顶地址
|
|
__asm void MSR_MSP(u32 addr)
|
|
{
|
|
MSR MSP, r0 //set Main Stack value
|
|
BX r14
|
|
}
|
|
//进入待机模式
|
|
void Sys_Standby(void)
|
|
{
|
|
SCB->SCR|=1<<2; //使能SLEEPDEEP位 (SYS->CTRL)
|
|
RCC->APB1ENR|=1<<28;//使能电源时钟
|
|
PWR->CSR|=1<<8; //设置WKUP用于唤醒
|
|
PWR->CR|=1<<2; //清除Wake-up 标志
|
|
PWR->CR|=1<<1; //PDDS置位
|
|
WFI_SET(); //执行WFI指令,进入待机模式
|
|
}
|
|
//系统软复位
|
|
void Sys_Soft_Reset(void)
|
|
{
|
|
SCB->AIRCR =0X05FA0000|(u32)0x04;
|
|
}
|
|
//时钟设置函数
|
|
//Fvco=Fs*(plln/pllm);
|
|
//Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));
|
|
//Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));
|
|
|
|
//Fvco:VCO频率
|
|
//Fsys:系统时钟频率
|
|
//Fusb:USB,SDIO,RNG等的时钟频率
|
|
//Fs:PLL输入时钟频率,可以是HSI,HSE等.
|
|
//plln:主PLL倍频系数(PLL倍频),取值范围:64~432.
|
|
//pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
|
|
//pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
|
|
//pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
|
|
|
|
//外部晶振为8M的时候,推荐值:plln=336,pllm=8,pllp=2,pllq=7.
|
|
//得到:Fvco=8*(336/8)=336Mhz
|
|
// Fsys=336/2=168Mhz
|
|
// Fusb=336/7=48Mhz
|
|
//返回值:0,成功;1,失败。
|
|
u8 Sys_Clock_Set(u32 plln,u32 pllm,u32 pllp,u32 pllq)
|
|
{
|
|
u16 retry=0;
|
|
u8 status=0;
|
|
RCC->CR|=1<<16; //HSE 开启
|
|
while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//等待HSE RDY
|
|
if(retry==0X1FFF)status=1; //HSE无法就绪
|
|
else
|
|
{
|
|
RCC->APB1ENR|=1<<28; //电源接口时钟使能
|
|
PWR->CR|=3<<14; //高性能模式,时钟可到168Mhz
|
|
RCC->CFGR|=(0<<4)|(5<<10)|(4<<13);//HCLK 不分频;APB1 4分频;APB2 2分频.
|
|
RCC->CR&=~(1<<24); //关闭主PLL
|
|
RCC->PLLCFGR=pllm|(plln<<6)|(((pllp>>1)-1)<<16)|(pllq<<24)|(1<<22);//配置主PLL,PLL时钟源来自HSE
|
|
RCC->CR|=1<<24; //打开主PLL
|
|
while((RCC->CR&(1<<25))==0);//等待PLL准备好
|
|
FLASH->ACR|=1<<8; //指令预取使能.
|
|
FLASH->ACR|=1<<9; //指令cache使能.
|
|
FLASH->ACR|=1<<10; //数据cache使能.
|
|
FLASH->ACR|=5<<0; //5个CPU等待周期.
|
|
RCC->CFGR&=~(3<<0); //清零
|
|
RCC->CFGR|=2<<0; //选择主PLL作为系统时钟
|
|
while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作为系统时钟成功.
|
|
}
|
|
return status;
|
|
}
|
|
|
|
//系统时钟初始化函数
|
|
//plln:主PLL倍频系数(PLL倍频),取值范围:64~432.
|
|
//pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
|
|
//pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
|
|
//pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
|
|
void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
|
|
{
|
|
RCC->CR|=0x00000001; //设置HISON,开启内部高速RC振荡
|
|
RCC->CFGR=0x00000000; //CFGR清零
|
|
RCC->CR&=0xFEF6FFFF; //HSEON,CSSON,PLLON清零
|
|
RCC->PLLCFGR=0x24003010; //PLLCFGR恢复复位值
|
|
RCC->CR&=~(1<<18); //HSEBYP清零,外部晶振不旁路
|
|
RCC->CIR=0x00000000; //禁止RCC时钟中断
|
|
Sys_Clock_Set(plln,pllm,pllp,pllq);//设置时钟
|
|
//配置向量表
|
|
#ifdef VECT_TAB_RAM
|
|
MY_NVIC_SetVectorTable(1<<29,0x0);
|
|
#else
|
|
MY_NVIC_SetVectorTable(0,0x0);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|