SmartOS/Sys.cpp

315 lines
9.8 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.

#include "Sys.h"
TSys Sys;
#ifndef BIT
#define BIT(x) (1 << (x))
#endif
#define RCC_CFGR_USBPRE_Div1 ((uint32_t)0x00400000) /*!< USB Device prescaler */
#define RCC_CFGR_USBPRE_1Div5 ((uint32_t)0x00000000) /*!< USB Device prescaler */
#define RCC_CFGR_USBPRE_Div2 ((uint32_t)0x00C00000) /*!< USB Device prescaler */
#define RCC_CFGR_USBPRE_2Div5 ((uint32_t)0x00800000) /*!< USB Device prescaler */
#define GD32_PLL_MASK 0x20000000
byte fac_us;//全局变量
volatile uint TickStat;//全局变量 为延时函数服务
/****************************************************
函数功能:延时初始化
输入参数SYSCLK : 系统时钟
输出参数:无
备 注:无
*****************************************************/
void delay_init(uint clk)
{
NVIC_InitTypeDef NVIC_InitStructure;
/****************************************
*SystemFrequency/1000 1ms中断一次 *
*SystemFrequency/100000 10us中断一次 *
*SystemFrequency/1000000 1us中断一次 *
*****************************************/
SysTick->CTRL &=~BIT(2);//选择外部时钟
SysTick->CTRL |=BIT(1);//开启定时器减到0后的中断请求
fac_us = clk/8;//计算好SysTick加载值
/*初始化部分代码*/
SysTick->LOAD = (uint)fac_us*1000-1;//加载时间值
SysTick->VAL = 1;//随便写个值,清除加载寄存器的值
SysTick->CTRL |= BIT(0);//SysTick使能
/* Configure the NVIC Preemption Priority Bits */
NVIC_InitStructure.NVIC_IRQChannel = (byte)SysTick_IRQn;
#ifdef STM32F10X
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
#else
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00; //想在中断里使用延时函数就必须让此中断优先级最高
#endif
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
__asm void TSys::DisableInterrupts()
{
/*
register UINT32 Primask __asm("primask");
UINT32 m = Primask;
__disable_irq();
return m ^ 1;
*/
#ifdef STM32F10X //stm32f030的汇编与此有所区别
MRS r0,PRIMASK
CPSID i
EOR r0,r0,#1
BX lr
#else
BX lr
#endif
}
__asm void TSys::EnableInterrupts()
{
/*
register UINT32 Primask __asm("primask");
UINT32 m = Primask;
__enable_irq();
return m ^ 1;
*/
// 这里打开中断以后,经常发生各种各样的异常,没有关系,并不是这里的错,而是之前可能就已经发生了异常,只不过无法产生中断,等到这里而已
#ifdef STM32F10X //stm32f030的汇编与此有所区别
MRS r0,PRIMASK
CPSIE i
EOR r0,r0,#1
BX lr
#else
BX lr
#endif
}
//利用SysTick定时器产生1ms时基
// SysTick_Handler 滴答定时器中断
void SysTick_Handler(void) //需要最高优先级 必须有抢断任何其他中断的能力才能 //供其他中断内延时使用
{
if(TickStat)
TickStat--;
}
/****************************************************
函数功能ms级延时
输入参数nms : 毫秒
输出参数:无
备 注调用此函数前需要初始化Delay_Init()函数
*****************************************************/
void TSys::Sleep(uint ms)
{
TickStat = ms;
while(TickStat);
}
/****************************************************
函数功能us级延时
输入参数nus : 微秒
输出参数:无
备 注调用此函数前需要初始化Delay_Init()函数
*****************************************************/
void TSys::Delay(uint us)
{
uint t = SysTick->CTRL&0x00ffffff; //SysTick 为24位倒计数定时器
uint tc = fac_us * us;
//if(nus<100){for();retrun} //低于100微秒的延时就没有必要使用定时器作为时基了
if(us > 1000) //如果延迟超过1ms
{
Sleep(us / 1000);
// if(tc%1000==0)return; //几率比较小 忽略此句、
tc=(tc%1000)*fac_us;
}
if((t-tc)>0)
{
while(SysTick->CTRL>(t-tc));
return;
}
else if((t-tc)==0)
{
while(SysTick->CTRL);
return;
}
else
{
tc= SysTick->LOAD -(tc-t); //低于1s 所以
while(SysTick->CTRL!=tc);
return;
}
}
#if GD32F1
// 获取JTAG编号ST是0x041GD是0x7A3
uint16_t Get_JTAG_ID()
{
if( *( uint8_t *)( 0xE00FFFE8 ) & 0x08 )
{
return ((*(uint8_t *)(0xE00FFFD0) & 0x0F ) << 8 ) |
((*(uint8_t *)(0xE00FFFE4) & 0xFF ) >> 3 ) |
((*(uint8_t *)(0xE00FFFE8) & 0x07 ) << 5 ) + 1 ;
}
return 0;
}
void STM32_BootstrapCode()
{
uint n = 0;
uint RCC_CFGR_ADC_BITS = RCC_CFGR_ADCPRE_DIV8;
uint FLASH_ACR_LATENCY_BITS = 0;
uint RCC_CFGR_USBPRE_BIT = 0;
uint mull, mull2;
// 是否GD
bool isGD = Get_JTAG_ID() == 0x7A3;
if(isGD && Sys.Clock == 72000000) Sys.Clock = 120000000;
// 确保关闭中断为了方便调试Debug时不关闭
#ifndef DEBUG
//__disable_irq();
#endif
n = Sys.Clock / 14000000;
if (n < 6)
RCC_CFGR_ADC_BITS = RCC_CFGR_ADCPRE_DIV6;
else
RCC_CFGR_ADC_BITS = RCC_CFGR_ADCPRE_DIV8;
// GD32的Flash零等待
if (isGD)
FLASH_ACR_LATENCY_BITS = FLASH_ACR_LATENCY_0; // 不允许等待
else
FLASH_ACR_LATENCY_BITS = FLASH_ACR_LATENCY_2; // 等待两个
// 配置JTAG调试支持
DBGMCU->CR = DBGMCU_CR_DBG_TIM2_STOP | DBGMCU_CR_DBG_SLEEP;
// 允许访问未对齐内存不强制8字节栈对齐
SCB->CCR &= ~(SCB_CCR_UNALIGN_TRP | SCB_CCR_STKALIGN);
// 捕获所有异常
CoreDebug->DEMCR |= CoreDebug_DEMCR_VC_HARDERR_Msk | CoreDebug_DEMCR_VC_INTERR_Msk |
CoreDebug_DEMCR_VC_BUSERR_Msk | CoreDebug_DEMCR_VC_STATERR_Msk |
CoreDebug_DEMCR_VC_CHKERR_Msk | CoreDebug_DEMCR_VC_NOCPERR_Msk |
CoreDebug_DEMCR_VC_MMERR_Msk;
// 为了配置时钟CPU必须运行在8MHz晶振上
RCC->CR |= RCC_CR_HSION;
while(!(RCC->CR & RCC_CR_HSIRDY));
// 切换到内部时钟
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
// RCC_CFGR_SW_HSI是0一点意义都没有
RCC->CFGR |= RCC_CFGR_SW_HSI; // sysclk = AHB = APB1 = APB2 = HSI (8MHz)
// 关闭 HSE 时钟
RCC->CR &= ~RCC_CR_HSEON;
// 关闭 HSE & PLL
RCC->CR &= ~RCC_CR_PLLON;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
while(!(RCC->CR & RCC_CR_HSERDY));
// 设置Flash访问时间并打开预读缓冲
FLASH->ACR = FLASH_ACR_LATENCY_BITS | FLASH_ACR_PRFTBE;
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
// 支持超频主频必须是8M的倍频
mull = Sys.Clock / Sys.CystalClock;
mull2 = (mull - 2) << 18;
// 处理0.5倍频
if( (mull * Sys.CystalClock + Sys.CystalClock / 2) == Sys.Clock )
{
mull = 2 * Sys.Clock / Sys.CystalClock;
// 对于GD32的108MHz没有除尽。
if( isGD && mull > 17 )
mull2 = (mull - 17) << 18 | RCC_CFGR_PLLXTPRE_HSE_Div2 | GD32_PLL_MASK;
else
mull2 = (mull - 2 ) << 18 | RCC_CFGR_PLLXTPRE_HSE_Div2;
}
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | mull2);
switch ( 2 * Sys.Clock / 48000000 )
{
case 2:
RCC_CFGR_USBPRE_BIT = RCC_CFGR_USBPRE_Div1;
break;
case 3:
RCC_CFGR_USBPRE_BIT = RCC_CFGR_USBPRE_1Div5;
break;
case 4:
RCC_CFGR_USBPRE_BIT = RCC_CFGR_USBPRE_Div2;
break;
case 5:
RCC_CFGR_USBPRE_BIT = RCC_CFGR_USBPRE_2Div5;
break;
default:
RCC_CFGR_USBPRE_BIT = RCC_CFGR_USBPRE_Div1;
break;
}
// 最终时钟配置
RCC->CFGR |= RCC_CFGR_USBPRE_BIT // USB clock
| RCC_CFGR_HPRE_DIV1 // AHB clock
| RCC_CFGR_PPRE1_DIV2 // APB1 clock
| RCC_CFGR_PPRE2_DIV1 // APB2 clock
| RCC_CFGR_ADC_BITS; // ADC clock (max 14MHz)
// 打开 HSE & PLL
RCC->CR |= RCC_CR_PLLON;// | RCC_CR_HSEON;
// 等到 PPL 达到时钟频率
while(!(RCC->CR & RCC_CR_PLLRDY));
// 最终时钟配置
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL; // sysclk = pll out (SYSTEM_CLOCK_HZ)
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08);
// 最小化外设时钟
RCC->AHBENR = RCC_AHBENR_SRAMEN | RCC_AHBENR_FLITFEN;
RCC->APB2ENR = RCC_APB2ENR_AFIOEN;
RCC->APB1ENR = RCC_APB1ENR_PWREN;
// 关闭 HSI 时钟
RCC->CR &= ~RCC_CR_HSION;
// 计算当前工作频率
mull = RCC->CFGR & ((int)0x3C0000 | GD32_PLL_MASK);
if((mull & GD32_PLL_MASK) != 0) // 兼容GD32的108MHz
mull = (((mull)&(0x003C0000)) >> 18) + 17;
else
mull = ( mull >> 18) + 2;
//TSys::Frequency = HSI_VALUE * pllmull;
// 不能直接用HSI_VALUE因为不同的硬件设备使用不同的晶振
Sys.Clock = Sys.CystalClock * mull;
if( (RCC->CFGR & RCC_CFGR_PLLXTPRE_HSE_Div2) && !isGD ) Sys.Clock /= 2;
}
#endif
void TSys::Init(void)
{
#ifndef GD32F1
RCC_ClocksTypeDef clock;
RCC_GetClocksFreq(&clock);
Clock = clock.SYSCLK_Frequency;
#endif
#ifdef STM32F10X
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4); //中断优先级分配方案4 四位都是抢占优先级
#endif
ID[0] = *(__IO uint *)(0X1FFFF7F0); // 高字节
ID[1] = *(__IO uint *)(0X1FFFF7EC); //
ID[2] = *(__IO uint *)(0X1FFFF7E8); // 低字节
FlashSize = *(__IO ushort *)(0X1FFFF7E0); // 容量
#if GD32F1
STM32_BootstrapCode();
#endif
delay_init(Clock/1000000);
}