system/sys.c

275 lines
6.7 KiB
C
Raw Permalink 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.

/*
* @Author:
* @Date: 2023-04-11 18:46:58
* @LastEditors: xxx
* @LastEditTime: 2023-08-25 11:31:06
* @Description:
* email:
* Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "sys.h"
#include "delay.h"
clock_config_t original_clock_config; // 原始时钟配置
__IO uint32_t uw_tick;
__IO uint32_t scheduler_start_time; // 调度器开始时间
__IO uint32_t scheduler_end_time; // 调度器结束时间
__IO uint32_t scheduler_occupancy_time = 0; // 调度器占用时间
/**
* @brief 设置中断向量表偏移地址
* @param baseaddr : 基址
* @param offset : 偏移量
* @retval 无
*/
void sys_nvic_set_vector_table(uint32_t baseaddr, uint32_t offset)
{
/* 设置NVIC的向量表偏移寄存器,VTOR低9位保留,即[8:0]保留 */
SCB->VTOR = baseaddr | (offset & (uint32_t)0xFFFFFE00);
}
/**
* @brief 执行: WFI指令(执行完该指令进入低功耗状态, 等待中断唤醒)
* @param 无
* @retval 无
*/
void sys_wfi_set(void)
{
__ASM __IO("wfi");
}
/**
* @brief 关闭所有中断(但是不包括fault和NMI中断)
* @param 无
* @retval 无
*/
void sys_intx_disable(void)
{
__ASM __IO("cpsid i");
}
/**
* @brief 开启所有中断
* @param 无
* @retval 无
*/
void sys_intx_enable(void)
{
__ASM __IO("cpsie i");
}
/**
* @brief 设置栈顶地址
* @note 左侧若有红X, 属于MDK误报, 实际是没问题的
* @param addr: 栈顶地址
* @retval 无
*/
void sys_msr_msp(uint32_t addr)
{
__set_MSP(addr); /* 设置栈顶地址 */
}
/**
* @brief 进入待机模式
* @param 无
* @retval 无
*/
void sys_standby(void)
{
// LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); /* 使能电源时钟 */
// SET_BIT(PWR->CR, PWR_CR_PDDS); /* 进入待机模式 */
}
/**
* @brief 系统软复位
* @param 无
* @retval 无
*/
void sys_soft_reset(void)
{
NVIC_SystemReset();
}
/**
* @brief 10ms滴答定时器,需要单独放到定时器中断中执行
* @param 无
* @retval 提供给sys_millis()函数使用,之前放在SysTick_Handler中执行影响精度
*/
__weak void LL_IncTick(void)
{
uw_tick += 1;
}
/**
* @brief 获取系统当前滴答计数
* @param 无
* @retval 当前滴答计数
*/
uint32_t sys_get_tick(void)
{
return uw_tick;
}
/**
* @brief 获取系统当前毫秒级时间戳。
* @return {uint32_t} 当前毫秒级时间戳
* @note: 请注意这个函数仅用于模拟硬件延时实际应用中可能需要使用其他时钟源如RTC或外部时钟。
*/
uint32_t sys_millis(void)
{
return uw_tick * 10;
}
/**
* @brief 系统计时器重新开始
* @return {*}
* @note
*/
void sys_millis_reset(void)
{
uw_tick = 0;
}
/**
* @brief 将系统时间戳转换为秒级时间戳。
* @param {uint32_t} start_time 开始时间戳
* @return {uint32_t} 秒级时间戳
* @note: 请注意这个函数仅用于模拟硬件延时实际应用中可能需要使用其他时钟源如RTC或外部时钟。
*/
uint32_t sys_to_seconds(uint32_t start_time)
{
return (sys_millis() - start_time) / 1000;
}
/**
* @brief 记录调度器开始时间
* @return {*}
* @note
*/
void scheduler_time_start(void)
{
scheduler_start_time = sys_millis();
}
/**
* @brief 返回调度器运行时间
* @return {*}
* @note
*/
uint32_t scheduler_time_stop(void)
{
uint32_t scheduler_end_time = sys_millis() - scheduler_start_time;
scheduler_occupancy_time += scheduler_end_time;
return scheduler_end_time;
}
/**
* @brief 计算任务占用时间百分比
* @param {uint32_t} run_time 运行时间
* @return {*} 任务占用时间百分比,单位为%
* @note
*/
uint32_t scheduler_time_occupancy_get(uint32_t run_time)
{
float32 percent = 0.0f;
percent = (float32)(scheduler_occupancy_time) / (float32)run_time;
scheduler_occupancy_time = 0;
return (uint32_t)(percent * 100);
}
// 切换到新的时钟配置
void change_system_clock(clock_config_t *new_config)
{
#if CLOCK_CHANGE_ENABLE == TRUE
// 1. 切换到HSE作为临时时钟源,根据你的硬件配置来调整
LL_RCC_HSE_Enable();
while (LL_RCC_HSE_IsReady() != 1)
{
}
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE)
{
}
// 2. 关闭PLL
LL_RCC_PLL_Disable();
while (LL_RCC_PLL_IsReady() != 0)
{
}
// 3. 配置新的PLL参数
// 注意这里假设HSE作为PLL的时钟源你需要根据你的硬件配置来调整
LL_RCC_PLL_ConfigDomain_SYS(new_config->pll_source, new_config->pll_m, new_config->pll_n, new_config->pll_r);
// 4. 重新启用PLL
LL_RCC_PLL_EnableDomain_SYS();
LL_RCC_PLL_Enable();
while (LL_RCC_PLL_IsReady() != 1)
{
}
// 5. 切换回PLL作为系统时钟源
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
{
}
// 6. 更新时钟分频器
LL_RCC_SetAHBPrescaler(new_config->ahb_div);
LL_RCC_SetAPB1Prescaler(new_config->apb1_div);
LL_RCC_SetAPB2Prescaler(new_config->apb2_div);
// 7. 更新SystemCoreClock变量
LL_Init1msTick(new_config->sysclk);
LL_SetSystemCoreClock(new_config->sysclk);
original_clock_config.sysclk_change = new_config->sysclk;
delay_init((SystemCoreClock / 1000000));
#endif
}
// 恢复到原始时钟配置
void restore_system_clock(void)
{
#if CLOCK_CHANGE_ENABLE == TRUE
change_system_clock(&original_clock_config);
#endif
}
// 获取原始时钟配置
clock_config_t *get_original_clock_config(void)
{
return &original_clock_config;
}
// 在系统启动时调用此函数来初始化时钟并保存原始配置
void system_clock_read(void)
{
#if CLOCK_CHANGE_ENABLE == TRUE
// 保存原始时钟配置
original_clock_config.pll_source = LL_RCC_PLL_GetMainSource();
original_clock_config.pll_m = LL_RCC_PLL_GetDivider();
original_clock_config.pll_n = LL_RCC_PLL_GetN();
original_clock_config.pll_r = LL_RCC_PLL_GetR();
original_clock_config.ahb_div = LL_RCC_GetAHBPrescaler();
original_clock_config.apb1_div = LL_RCC_GetAPB1Prescaler();
original_clock_config.apb2_div = LL_RCC_GetAPB2Prescaler();
original_clock_config.sysclk = SystemCoreClock;
#endif
}
/**
* @brief Write a character to a file stream, used for FLASHDB printf
*
* Writes the specified character to the given file stream and returns the written character.
*
* @param ch The character to be written
* @param stream Pointer to the file stream
*
* @return The written character
*/
int fputc(int ch, FILE *stream)
{
return ch;
}