Files
CherryUSB/demo/mm32/SYSTEM/sys/sys.c
2021-12-05 20:31:59 +08:00

278 lines
8.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
******************************************************************************
* @file sys.c
* @author AE Team
* @version V1.3.9
* @date 28/08/2019
* @brief This file provides all the sys firmware functions.
******************************************************************************
* @copy
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, MindMotion SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2019 MindMotion</center></h2>
*/
#include "sys.h"
extern u32 SystemCoreClock;
//设置向量表偏移地址
//NVIC_VectTab:基址
//Offset:偏移量
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)
{
SCB->VTOR = NVIC_VectTab | (Offset & (u32)0x1FFFFF80); //设置NVIC的向量表偏移寄存器
//用于标识向量表是在CODE区还是在RAM区
}
//设置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); //使能中断位(要清除的话,相反操作就OK)
NVIC->IP[NVIC_Channel] |= temp << 4; //设置响应优先级和抢断优先级
}
//外部中断配置函数
//只针对GPIOA~G;不包括PVD,RTC和USB唤醒这三个
//参数:
//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上事件上升降沿触发
}
//不能在这里执行所有外设复位!否则至少引起串口不工作.
//把所有时钟寄存器复位
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
void WFI_SET(void)
{
__ASM volatile("wfi");
}
//关闭所有中断
void INTX_DISABLE(void)
{
__ASM volatile("cpsid i");
}
//开启所有中断
void INTX_ENABLE(void)
{
__ASM volatile("cpsie i");
}
//进入待机模式
void Sys_Standby(void)
{
SCB->SCR |= SCB_SCR_SLEEPDEEP; //使能SLEEPDEEP位 (SYS->CTRL)
RCC->APB1ENR |= RCC_APB1RSTR_PWRRST; //使能电源时钟
PWR->CSR |= PWR_CSR_EWUP; //设置WKUP用于唤醒
PWR->CR |= PWR_CR_CWUF; //清除Wake-up 标志
PWR->CR |= PWR_CR_PDDS; //PDDS置位
WFI_SET(); //执行WFI指令
}
//系统软复位
void Sys_Soft_Reset(void)
{
SCB->AIRCR = 0X05FA0000 | (u32)0x04;
}
//JTAG模式设置,用于设置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 |= RCC_APB2RSTR_AFIORST; //开启辅助时钟
AFIO->MAPR &= 0XF8FFFFFF; //清除MAPR的[26:24]
AFIO->MAPR |= temp; //设置jtag模式
}
//系统时钟初始化函数
//pll:选择的倍频数从2开始最大值为16
void System_Clock_Init(u8 PLL)
{
unsigned char temp = 0;
MYRCC_DeInit(); //复位并配置向量表
RCC->CR |= RCC_CR_HSEON; //外部高速时钟使能HSEON
while(!(RCC->CR & RCC_CR_HSERDY)); //等待外部时钟就绪
RCC->CFGR = RCC_CFGR_PPRE1_2; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
RCC->CFGR |= RCC_CFGR_PLLSRC; //PLLSRC ON
RCC->CR &= ~(RCC_CR_PLLON); //清PLL// RCC->CR &=~(7<<20); //清PLL
RCC->CR &= ~(0x1f << 26);
RCC->CR |= (PLL - 1) << 26; //设置PLL值 2~16
FLASH->ACR |= FLASH_ACR_LATENCY_1 | FLASH_ACR_PRFTBE | FLASH_ACR_PRFTBS; //FLASH 2个延时周期
RCC->CR |= RCC_CR_PLLON; //PLLON
while(!(RCC->CR & RCC_CR_PLLRDY)); //等待PLL锁定
RCC->CFGR |= RCC_CFGR_SW_PLL; //PLL作为系统时钟
while(temp != 0x02) //等待PLL作为系统时钟设置成功
{
temp = RCC->CFGR >> 2;
temp &= 0x03;
}
}
/*
HSE 外部时钟 8M
*/
#if 0
void RCC_MCOConfig(uint8_t RCC_MCO)
{
/* Check the parameters */
assert_param(IS_RCC_MCO(RCC_MCO));
/* Perform Byte access to MCO[2:0] bits to select the MCO source */
*(__IO uint8_t *) CFGR_BYTE4_ADDRESS = RCC_MCO;
}
#endif
void SystemClk_Output(void)
{
// GPIO_InitTypeDef GPIO_InitStructure;
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //mco pa8
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推免复用输出
// GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //使能PORTA时钟
GPIOA->CRH &= 0XFFFFFFF0;
GPIOA->CRH |= GPIO_CRH_MODE8; //PA8 推挽输出
GPIOA->ODR |= GPIO_ODR_ODR8; //PA8 输出高
//------------------------------------------------------------
//add start
/*
#define RCC_CFGR_MCO_2 ((uint32_t)0x04000000)
位26:24
MCO 微控制器时钟输出
由软件置1或清零。
00x没有时钟输出
010LSI 时钟输出;
011LSE 时钟输出;
100系统时钟(SYSCLK)输出;
101HSI 时钟输出;
110HSE 时钟输出;
111PLL 时钟2分频后输出。
注意:
- 该时钟输出在启动和切换MCO时钟源时可能会被截断。
- 在系统时钟作为输出至MCO管脚时请保证输出时钟频率不超过50MHz (IO口最高频率)
*/
// RCC->CR &= (uint32_t)~RCC_CFGR_MCO; //CLEAR pll PARAMETERS
//-------------------------------------------------
// RCC->CFGR |= (uint32_t)RCC_CFGR_MCO_PLL ;//PLL/2
if(SystemCoreClock < 8000000)
{
//RCC_MCOConfig(RCC_MCO_HSE); //通过PA8 pin 观察频率
RCC->CFGR |= (uint32_t)RCC_CFGR_MCO_HSE ;//PLL/2
}
else if(SystemCoreClock <= 48000000)
{
//RCC_MCOConfig(RCC_MCO_SYSCLK); //通过PA8 pin 观察频率 SYSCLK<48M
RCC->CFGR |= (uint32_t)RCC_CFGR_MCO_SYSCLK ;//PLL/2
}
else
{
//RCC_MCOConfig(RCC_MCO_PLLCLK_Div2); //通过PA8 pin 观察频率
RCC->CFGR |= (uint32_t)RCC_CFGR_MCO_PLL ;//PLL/2
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/*-------------------------(C) COPYRIGHT 2019 MindMotion ----------------------*/