/***********************************************
公司：轮趣科技（东莞）有限公司
品牌：WHEELTEC
官网：wheeltec.net
淘宝店铺：shop114407458.taobao.com 
速卖通: https://minibalance.aliexpress.com/store/4455017
版本：5.7
修改时间：2021-04-29

 
Brand: WHEELTEC
Website: wheeltec.net
Taobao shop: shop114407458.taobao.com 
Aliexpress: https://minibalance.aliexpress.com/store/4455017
Version:5.7
Update：2021-04-29

All rights reserved
***********************************************/
#include "sys.h" 
/**************************************************************************
Function: Set the vector table offset address
Input   : Base site 	 Offsets
Output  : none
函数功能：设置向量表偏移地址
入口参数：NVIC_VectTab:基址		Offset:偏移量	
返回  值：无
**************************************************************************/ 		 
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)	 
{ 	   	 
	SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//设置NVIC的向量表偏移寄存器
																											//用于标识向量表是在CODE区还是在RAM区
}
/**************************************************************************
Function: Set NVIC group
Input   : NVIC_Group
Output  : none
函数功能：设置中断分组
入口参数：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;  //设置分组	    	  				   
}
/**************************************************************************
Function: Set NVIC group
Input   : NVIC_PreemptionPriority	NVIC_SubPriority	NVIC_Channel	NVIC_Group
Output  : none
函数功能：设置中断分组
入口参数：抢占优先级	响应优先级 中断编号	中断分组号
返回  值：无
* 中断分组 | 作用
 * --------+--------------------------------------
 * 组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);//使能中断位(要清除的话,相反操作就OK) 
	NVIC->IP[NVIC_Channel]|=temp<<4;									//设置响应优先级和抢断优先级   	    	  				   
} 
/**************************************************************************
Function: External interrupt function configuration
Input   : GPIOx：General-purpose input/output	 BITx：The port needed enable
					TRIM：Trigger mode
Output  : none
函数功能：外部中断函数配置
入口参数：GPIOx:0~6,代表GPIOA~G；
					BITx:需要使能的位;		TRIM:触发模式,1,下升沿;2,上降沿;3，任意电平触发
返回  值：无
**************************************************************************/
//该函数一次只能配置1个IO口,多个IO口,需多次调用
//该函数会自动开启对应中断,以及屏蔽线     	    
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM) 
{
	u8 EXTADDR;
	u8 EXTOFFSET;
	EXTADDR=BITx/4;//得到中断寄存器组的编号
	EXTOFFSET=(BITx%4)*4; 
	RCC->APB2ENR|=0x01;//使能io复用时钟			 
	AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET);//清除原来设置！！！
	AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;//EXTI.BITx映射到GPIOx.BITx 
	//自动设置
	EXTI->IMR|=1<<BITx;//  开启line BITx上的中断
	//EXTI->EMR|=1<<BITx;//不屏蔽line BITx上的事件 (如果不屏蔽这句,在硬件上是可以的,但是在软件仿真的时候无法进入中断!)
 	if(TRIM&0x01)EXTI->FTSR|=1<<BITx;//line BITx上事件下降沿触发
	if(TRIM&0x02)EXTI->RTSR|=1<<BITx;//line BITx上事件上升降沿触发
} 	  
/**************************************************************************
Function: Reset all clock registers
Input   : none
Output  : none
函数功能：把所有时钟寄存器复位	
入口参数：无
返回  值：无
**************************************************************************/
//不能在这里执行所有外设复位!否则至少引起串口不工作.		    
//把所有时钟寄存器复位			  
void MYRCC_DeInit(void)
{	
 	RCC->APB1RSTR = 0x00000000;//复位结束			 
	RCC->APB2RSTR = 0x00000000; 
	  
  RCC->AHBENR = 0x00000014;  //睡眠模式闪存和SRAM时钟使能.其他关闭.	  
  RCC->APB2ENR = 0x00000000; //外设时钟关闭.			   
  RCC->APB1ENR = 0x00000000;   
	RCC->CR |= 0x00000001;     //使能内部高速时钟HSION	 															 
	RCC->CFGR &= 0xF8FF0000;   //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]					 
	RCC->CR &= 0xFEF6FFFF;     //复位HSEON,CSSON,PLLON
	RCC->CR &= 0xFFFBFFFF;     //复位HSEBYP	   	  
	RCC->CFGR &= 0xFF80FFFF;   //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE 
	RCC->CIR = 0x00000000;     //关闭所有中断		 
	//配置向量表				  
#ifdef  VECT_TAB_RAM
	MY_NVIC_SetVectorTable(0x20000000, 0x0);
#else   
	MY_NVIC_SetVectorTable(0x08000000,0x0);
#endif
}
//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI  
__asm void WFI_SET(void)
{
	WFI;		  
}
//关闭所有中断
__asm void INTX_DISABLE(void)
{
	CPSID I;		  
}
//开启所有中断
__asm void INTX_ENABLE(void)
{
	CPSIE I;		  
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr) 
{
    MSR MSP, r0 			//set Main Stack value
    BX r14
}

/**************************************************************************
Function: Go to standby mode
Input   : none
Output  : none
函数功能：进入待机模式
入口参数：无
返回  值：无
**************************************************************************/  	  
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指令		 
}	     
/**************************************************************************
Function: System soft reset
Input   : none
Output  : none
函数功能：系统软复位
入口参数：无
返回  值：无
**************************************************************************/  
void Sys_Soft_Reset(void)
{   
	SCB->AIRCR =0X05FA0000|(u32)0x04;	  
} 		 
/**************************************************************************
Function: Set JTAG mode
Input   : mode:JTAG, swd mode settings；00，all enable；01，enable SWD；10，Full shutdown
Output  : none
函数功能：设置JTAG模式
入口参数：mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;	
返回  值：无
**************************************************************************/
//#define JTAG_SWD_DISABLE   0X02
//#define SWD_ENABLE         0X01
//#define JTAG_SWD_ENABLE    0X00	
void JTAG_Set(u8 mode)
{
	u32 temp;
	temp=mode;
	temp<<=25;
	RCC->APB2ENR|=1<<0;     //开启辅助时钟	   
	AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
	AFIO->MAPR|=temp;       //设置jtag模式
} 
/**************************************************************************
Function: System clock initialization function
Input   : pll：Selected frequency multiplication，Starting at 2, the maximum value is 16
Output  : none
函数功能：系统时钟初始化函数
入口参数：pll:选择的倍频数，从2开始，最大值为16		
返回  值：无
**************************************************************************/ 
void Stm32_Clock_Init(u8 PLL)
{
	unsigned char temp=0;   
	MYRCC_DeInit();		  		//复位并配置向量表
 	RCC->CR|=0x00010000;  	//外部高速时钟使能HSEON
	while(!(RCC->CR>>17));	//等待外部时钟就绪
	RCC->CFGR=0X00000400; 	//APB1=DIV2;APB2=DIV1;AHB=DIV1;
	PLL-=2;									//抵消2个单位
	RCC->CFGR|=PLL<<18;   	//设置PLL值 2~16
	RCC->CFGR|=1<<16;	 			//PLLSRC ON 
	FLASH->ACR|=0x32;	  		//FLASH 2个延时周期

	RCC->CR|=0x01000000;  	//PLLON
	while(!(RCC->CR>>25));	//等待PLL锁定
	RCC->CFGR|=0x00000002;	//PLL作为系统时钟	 
	while(temp!=0x02)     	//等待PLL作为系统时钟设置成功
	{   
		temp=RCC->CFGR>>2;
		temp&=0x03;
	}    
}		    


