添加普冉 PY32F040 OTA 双工程代码生成模板

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-18 18:59:56 +08:00
co-authored by Cursor
commit 331864dc64
496 changed files with 329040 additions and 0 deletions
+504
View File
@@ -0,0 +1,504 @@
/**
******************************************************************************
* @file boot_main.c
* @brief 可配置 OTA Bootloader — PY32F040
*
* 三种模式(由 ota_config.h 的 OTA_BACKUP_MODE / OTA_SWAP_STRATEGY 决定):
*
* ① 单备份(SINGLE):
* PENDING → 校验 BAK → 拷贝覆盖主区 → 跳转主区(无回滚)
* 掉电:PENDING 不清除,下次启动重新校验+拷贝(BAK 完好,天然安全)
*
* ② 双备份 + RAM 缓冲交换(AB + RAM):
* PENDING → 校验 B 区 → 逐页交换(RAM 双页缓冲)→ BOOT_NEW → 跳转 A 区
* SWAPPING → 交换掉电中断,续做(phase/progress 恢复)
* BOOT_NEW 未确认(崩溃/IWDG 复位)→ 反向交换回滚 → 跳转 A 区
*
* ③ 双备份 + Flash 暂存区交换(AB + SCRATCH):
* 同上,但交换用 scratch 暂存一页(Flash 持久),掉电恢复可完整保留两页,
* 回滚永远可用;升级耗时更短。
*
* 跳转新固件前使能 IWDG:新固件崩溃则看门狗复位,Bootloader 再次判定并回滚。
* 交换/拷贝期间使能 IWDG 并逐页喂狗(单页耗时 < 100ms,远小于 1s 超时)。
******************************************************************************
*/
#include "boot_main.h"
#include "flash.h"
#include "crc32.h"
#include "iwdg_config.h"
#define DEBUG
/* Private variables ---------------------------------------------------------*/
static ota_param_t g_ota;
/* Private function prototypes -----------------------------------------------*/
static int fw_vector_ok(uint32_t base);
static int fw_validate(uint32_t base, uint32_t size, uint32_t crc);
static void boot_iwdg_enable(void);
static void boot_iwdg_feed(void);
static void boot_jump(uint32_t base);
#if (OTA_BACKUP_MODE == OTA_MODE_SINGLE)
static void copy_bak_to_run(void);
#else
static void swap_execute(int reverse);
#endif
/**
* @brief 系统复位
*/
void mcuRestart(void)
{
Log("[OTA] Restarting MCU...\r\n");
HAL_NVIC_SystemReset();
}
/* ── OTA 状态区读写 ─────────────────────────────────────────────────────────
* 由 flash.h 的 ota_param_load / ota_param_store 提供(4 页轮换磨损均衡)。
* 状态区无效时 load 自动回退默认 IDLE。 */
/* ── 固件校验 ─────────────────────────────────────────────────────────────── */
/* 向量表合法性:栈顶在 RAM,复位向量落在运行区 Flash 范围内。
* 注意:固件始终链接运行区 OTA_RUN_ADDR_BASEBAK/B 区只是下载/备份缓冲,
* 存储位置 ≠ 链接地址。无论 base 传 RUN 还是 BAK,都应校验复位向量是否指向
* 运行区(固件真正执行处),否则 BAK 校验会因复位向量指向 RUN 而被误判非法。 */
static int fw_vector_ok(uint32_t base)
{
uint32_t sp = *(volatile uint32_t *)base;
uint32_t rv = *(volatile uint32_t *)(base + 4);
(void)base;
if ((sp < RAM_BASE_ADDR) || (sp >= RAM_END_ADDR))
{
return 0;
}
if ((rv < OTA_RUN_ADDR_BASE) || (rv >= (OTA_RUN_ADDR_BASE + OTA_SLOT_MAX_SIZE)))
{
return 0;
}
return 1;
}
/* 完整校验:向量表合法 + CRC32 匹配 */
static int fw_validate(uint32_t base, uint32_t size, uint32_t crc)
{
if ((size == 0) || (size > OTA_SLOT_MAX_SIZE))
{
Log("[BL] fw size invalid: %lu\r\n", (unsigned long)size);
return 0;
}
if (!fw_vector_ok(base))
{
Log("[BL] fw vector invalid @ %08X\r\n", (unsigned int)base);
return 0;
}
if (crc32_compute((uint8_t *)base, size) != crc)
{
Log("[BL] fw CRC32 mismatch @ %08X\r\n", (unsigned int)base);
return 0;
}
Log("[BL] fw validate OK @ %08X (size %lu)\r\n", (unsigned int)base, (unsigned long)size);
return 1;
}
/* ── IWDG:跳转前使能,新固件崩溃则由看门狗复位回滚;交换/拷贝期间逐页喂狗 ── */
static void boot_iwdg_enable(void)
{
/* 使能 LSI 并等待就绪 */
SET_BIT(RCC->CSR, RCC_CSR_LSION);
for (uint32_t i = 0; i < 10000; i++)
{
if (READ_BIT(RCC->CSR, RCC_CSR_LSIRDY))
{
break;
}
}
/* IWDG 配置:参数见 Shared/iwdg_config.h */
IWDG->KR = 0x5555; /* 解锁 */
IWDG->PR = IWDG_PR_REG; /* /16 */
IWDG->RLR = IWDG_RELOAD_VALUE;
IWDG->KR = 0xAAAA; /* 重装 */
IWDG->KR = 0xCCCC; /* 启动 */
Log("[BL] IWDG enabled (~1s)\r\n");
}
static void boot_iwdg_feed(void)
{
IWDG->KR = 0xAAAA; /* 重装计数,防交换/拷贝期间复位 */
}
/* ── 跳转到 APP ───────────────────────────────────────────────────────────── */
typedef void (*iapfun)(void);
__asm void MSR_MSP(uint32_t addr)
{
MSR MSP, r0
BX r14
}
static void boot_jump(uint32_t base)
{
uint32_t sp, rv;
if (!fw_vector_ok(base))
{
Log("[BL] Jump target vector invalid! Hang.\r\n");
while (1)
{
}
}
sp = *(volatile uint32_t *)base;
rv = *(volatile uint32_t *)(base + 4);
Log("[BL] Jump to APP @ %08X\r\n", (unsigned int)base);
/* 关闭全局中断,设置向量表与栈,跳转 */
__disable_irq();
SCB->VTOR = base; /* PY32F040 支持 VTOR */
MSR_MSP(sp);
((iapfun)rv)();
while (1)
{
}
}
/* ── 单备份:BAK 拷贝覆盖主区 ─────────────────────────────────────────────── */
#if (OTA_BACKUP_MODE == OTA_MODE_SINGLE)
static void copy_bak_to_run(void)
{
uint8_t buf[OTA_PAGE_SIZE];
uint32_t i, pages = OTA_SLOT_PAGE_NB;
Log("[BL] copy BAK(%08X) -> RUN(%08X), %lu pages\r\n",
(unsigned int)OTA_BAK_ADDR_BASE, (unsigned int)OTA_RUN_ADDR_BASE,
(unsigned long)pages);
for (i = 0; i < pages; i++)
{
uint32_t src = OTA_BAK_ADDR_BASE + i * OTA_PAGE_SIZE;
uint32_t dst = OTA_RUN_ADDR_BASE + i * OTA_PAGE_SIZE;
APP_FlashRead(src, buf, OTA_PAGE_SIZE);
APP_FlashEraseWithCheck(dst, OTA_PAGE_SIZE);
APP_FlashWrite(dst, buf, OTA_PAGE_SIZE);
boot_iwdg_feed();
}
/* 拷贝完成:置 BOOT_NEW(等待 App 确认并回复 OTA 完成;单备份无回滚目标,
* 若 App 未确认崩溃,下次启动见 BOOT_NEW 直接继续运行)。
* 中途掉电则下次重新拷贝(PENDING 未清,BAK 完好) */
g_ota.state = OTA_STATE_BOOT_NEW;
ota_param_store(&g_ota);
Log("[BL] copy done\r\n");
}
#endif /* SINGLE */
/* ── 双备份:A/B 区交换 ───────────────────────────────────────────────────── */
#if (OTA_BACKUP_MODE == OTA_MODE_AB)
#if (OTA_SWAP_STRATEGY == OTA_SWAP_SCRATCH)
/**
* @brief Flash 暂存区交换(scratch 持久保存一页,掉电可完整恢复)
* @param reverse 0=正向(A=旧,B=新 → A=新,B=旧,部署新固件)
* 1=反向(A=新,B=旧 → A=旧,B=新,回滚旧固件)
*/
static void swap_execute(int reverse)
{
uint32_t a = OTA_RUN_ADDR_BASE;
uint32_t b = OTA_BAK_ADDR_BASE;
uint32_t i, total_pages = OTA_SLOT_PAGE_NB;
uint8_t buf[OTA_PAGE_SIZE];
if (g_ota.state != OTA_STATE_SWAPPING)
{
g_ota.state = OTA_STATE_SWAPPING;
g_ota.progress = 0;
g_ota.phase = 0;
ota_param_store(&g_ota);
}
Log("[BL] swap(%s) %lu pages\r\n", reverse ? "rollback" : "forward",
(unsigned long)total_pages);
for (i = g_ota.progress; i < total_pages; i++)
{
uint32_t addr_a = a + i * OTA_PAGE_SIZE;
uint32_t addr_b = b + i * OTA_PAGE_SIZE;
/* 掉电恢复:phase==1 时 scratch 保存着 addr_a 的原内容,
* 直接补写 addr_b 完成本页,再继续(scratch 持久,不丢) */
if ((g_ota.phase == 1) && (i == g_ota.progress))
{
APP_FlashRead(OTA_SCRATCH_ADDR, buf, OTA_PAGE_SIZE);
APP_FlashEraseWithCheck(addr_b, OTA_PAGE_SIZE);
APP_FlashWrite(addr_b, buf, OTA_PAGE_SIZE);
g_ota.phase = 0;
g_ota.progress = (uint16_t)(i + 1);
ota_param_store(&g_ota);
boot_iwdg_feed();
continue;
}
/* 1) scratch ← A[i](持久保存被覆盖方) */
APP_FlashRead(addr_a, buf, OTA_PAGE_SIZE);
APP_FlashEraseWithCheck(OTA_SCRATCH_ADDR, OTA_SCRATCH_SIZE);
APP_FlashWrite(OTA_SCRATCH_ADDR, buf, OTA_PAGE_SIZE);
g_ota.phase = 1;
ota_param_store(&g_ota);
/* 2) A[i] ← B[i] */
APP_FlashRead(addr_b, buf, OTA_PAGE_SIZE);
APP_FlashEraseWithCheck(addr_a, OTA_PAGE_SIZE);
APP_FlashWrite(addr_a, buf, OTA_PAGE_SIZE);
/* 3) B[i] ← scratch(原 A[i] */
APP_FlashRead(OTA_SCRATCH_ADDR, buf, OTA_PAGE_SIZE);
APP_FlashEraseWithCheck(addr_b, OTA_PAGE_SIZE);
APP_FlashWrite(addr_b, buf, OTA_PAGE_SIZE);
g_ota.phase = 0;
g_ota.progress = (uint16_t)(i + 1);
ota_param_store(&g_ota);
boot_iwdg_feed();
}
g_ota.state = reverse ? OTA_STATE_IDLE : OTA_STATE_BOOT_NEW;
ota_param_store(&g_ota);
Log("[BL] swap done, state=%u\r\n", g_ota.state);
}
#else /* OTA_SWAP_STRATEGY == OTA_SWAP_RAM */
/**
* @brief RAM 缓冲交换(不预留暂存区,A/B 各 55K;掉电恢复见 phase 说明)
* @param reverse 0=正向(部署新) 1=反向(回滚)
*
* 正向每页顺序(关键:先部署新到 A,再备份旧到 B):
* phase=1 写入后 → 擦/写 A[i](若中断,B[i] 仍是新固件页,可重建 A[i])
* → 擦/写 B[i](若中断,旧固件页丢失,但新固件完整 → 升级成功、回滚失效)
* 掉电恢复(phase==1 且 i==progress):从 B[i] 重建 A[i]
* 放弃本页旧备份(B[i] 保持新固件页),继续后续页 —— 保证新固件永远可收敛。
*/
static void swap_execute(int reverse)
{
uint32_t a = OTA_RUN_ADDR_BASE;
uint32_t b = OTA_BAK_ADDR_BASE;
uint32_t i, total_pages = OTA_SLOT_PAGE_NB;
uint8_t buf_new[OTA_PAGE_SIZE];
uint8_t buf_old[OTA_PAGE_SIZE];
if (g_ota.state != OTA_STATE_SWAPPING)
{
g_ota.state = OTA_STATE_SWAPPING;
g_ota.progress = 0;
g_ota.phase = 0;
ota_param_store(&g_ota);
}
Log("[BL] swap(%s) %lu pages (RAM buf)\r\n", reverse ? "rollback" : "forward",
(unsigned long)total_pages);
for (i = g_ota.progress; i < total_pages; i++)
{
uint32_t addr_a = a + i * OTA_PAGE_SIZE;
uint32_t addr_b = b + i * OTA_PAGE_SIZE;
/* 掉电恢复:phase==1 时 A[i] 可能半写,B[i] 必为新固件页(未动)→ 重建 A[i] */
if ((g_ota.phase == 1) && (i == g_ota.progress))
{
APP_FlashRead(addr_b, buf_new, OTA_PAGE_SIZE);
APP_FlashEraseWithCheck(addr_a, OTA_PAGE_SIZE);
APP_FlashWrite(addr_a, buf_new, OTA_PAGE_SIZE);
/* 旧固件页已在掉电时丢失 → 本页放弃旧备份(B[i] 保持新固件页) */
g_ota.phase = 0;
g_ota.progress = (uint16_t)(i + 1);
ota_param_store(&g_ota);
boot_iwdg_feed();
continue;
}
APP_FlashRead(addr_a, buf_old, OTA_PAGE_SIZE);
APP_FlashRead(addr_b, buf_new, OTA_PAGE_SIZE);
/* 先写 A(部署新):中断时 B[i] 完好可重建 */
g_ota.phase = 1;
ota_param_store(&g_ota);
APP_FlashEraseWithCheck(addr_a, OTA_PAGE_SIZE);
APP_FlashWrite(addr_a, buf_new, OTA_PAGE_SIZE);
/* 再写 B(备份旧) */
APP_FlashEraseWithCheck(addr_b, OTA_PAGE_SIZE);
APP_FlashWrite(addr_b, buf_old, OTA_PAGE_SIZE);
g_ota.phase = 0;
g_ota.progress = (uint16_t)(i + 1);
ota_param_store(&g_ota);
boot_iwdg_feed();
}
g_ota.state = reverse ? OTA_STATE_IDLE : OTA_STATE_BOOT_NEW;
ota_param_store(&g_ota);
Log("[BL] swap done, state=%u\r\n", g_ota.state);
}
#endif /* OTA_SWAP_STRATEGY */
#endif /* OTA_BACKUP_MODE == AB */
/**
* @brief Main program.
* @retval int
*/
int main(void)
{
HAL_Init();
#ifdef DEBUG
DEBUG_USART_Config(); /* 将串口配置成日志口 */
#endif
Log("\r\n==== PY32F040 OTA Bootloader V3.0 ====\r\n");
#if (OTA_BACKUP_MODE == OTA_MODE_SINGLE)
Log("[BL] mode: SINGLE backup\r\n");
#else
/* 双备份:OTA_SWAP_STRATEGY / OTA_SCRATCH_* 由 ota_config.h 的
* #if (OTA_BACKUP_MODE == OTA_MODE_AB) 保护,此处一定已定义 */
#if (OTA_SWAP_STRATEGY == OTA_SWAP_SCRATCH)
Log("[BL] mode: AB backup, SCRATCH swap\r\n");
#else
Log("[BL] mode: AB backup, RAM swap\r\n");
#endif
#endif
ota_param_load(&g_ota);
Log("[BL] state=%u fw_size=%lu\r\n", g_ota.state, (unsigned long)g_ota.fw_size);
#if (OTA_BACKUP_MODE == OTA_MODE_SINGLE)
/* ── ① 单备份 ── */
switch (g_ota.state)
{
case OTA_STATE_PENDING:
Log("[BL] Pending: validate BAK ...\r\n");
if (fw_validate(OTA_BAK_ADDR_BASE, g_ota.fw_size, g_ota.fw_crc32))
{
boot_iwdg_enable();
copy_bak_to_run();
Log("[BL] Switch to NEW fw in RUN area\r\n");
boot_jump(OTA_RUN_ADDR_BASE);
}
else
{
/* 新固件无效 → 继续跑主区旧固件(BAK 被丢弃) */
Log("[BL] New fw invalid, keep old RUN fw\r\n");
g_ota.state = OTA_STATE_IDLE;
ota_param_store(&g_ota);
boot_iwdg_enable();
boot_jump(OTA_RUN_ADDR_BASE);
}
break;
case OTA_STATE_BOOT_NEW:
/* 单备份无回滚目标:App 未确认(崩溃/掉电)也只能继续运行主区 */
Log("[BL] SINGLE: BOOT_NEW not confirmed, keep RUN fw\r\n");
g_ota.state = OTA_STATE_IDLE;
ota_param_store(&g_ota);
boot_iwdg_enable();
boot_jump(OTA_RUN_ADDR_BASE);
break;
case OTA_STATE_IDLE:
default:
Log("[BL] Normal boot, RUN area\r\n");
boot_iwdg_enable();
boot_jump(OTA_RUN_ADDR_BASE);
break;
}
#else /* OTA_BACKUP_MODE == AB */
/* ── ②/③ 双备份 ── */
switch (g_ota.state)
{
case OTA_STATE_PENDING:
Log("[BL] Pending: validate B area ...\r\n");
if (fw_validate(OTA_BAK_ADDR_BASE, g_ota.fw_size, g_ota.fw_crc32))
{
boot_iwdg_enable(); /* 交换期间逐页喂狗,跳转后由新固件喂狗 */
swap_execute(0); /* 正向交换:A=新, B=旧 */
Log("[BL] Switch to NEW fw\r\n");
boot_jump(OTA_RUN_ADDR_BASE);
}
else
{
/* 新固件无效 → 继续跑 A 区旧固件 */
Log("[BL] New fw invalid, keep old RUN fw\r\n");
g_ota.state = OTA_STATE_IDLE;
ota_param_store(&g_ota);
boot_iwdg_enable();
boot_jump(OTA_RUN_ADDR_BASE);
}
break;
case OTA_STATE_SWAPPING:
/* 上次交换掉电中断 → 续做(部署新固件) */
Log("[BL] Resuming interrupted swap ...\r\n");
boot_iwdg_enable();
swap_execute(0);
Log("[BL] Switch to NEW fw (resumed)\r\n");
boot_jump(OTA_RUN_ADDR_BASE);
break;
case OTA_STATE_BOOT_NEW:
/* 上次启动的新固件未确认(崩溃/掉电)→ 回滚旧固件 */
Log("[BL] New fw not confirmed, ROLLBACK ...\r\n");
boot_iwdg_enable();
swap_execute(1); /* 反向交换:A=旧, B=新 */
Log("[BL] Rollback done, boot old fw\r\n");
boot_jump(OTA_RUN_ADDR_BASE);
break;
case OTA_STATE_IDLE:
default:
Log("[BL] Normal boot, RUN area\r\n");
boot_iwdg_enable();
boot_jump(OTA_RUN_ADDR_BASE);
break;
}
#endif /* OTA_BACKUP_MODE */
while (1)
{
}
}
/***********************************************************************************************************************
* Function Name: Error_Handler
* @brief 错误处理函数
* @param *file:文件名,line:行号
* @return None
***********************************************************************************************************************/
void Error_Handler(uint8_t *file, uint32_t line)
{
while (1)
{
appPrintf(LOG_ERROR, "%s %d\r\n", file, line);
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
while (1)
{
}
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
+51
View File
@@ -0,0 +1,51 @@
/**
******************************************************************************
* @file py32f040_hal_msp.c
* @author MCU Application Team
* @brief This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
* All rights reserved.</center></h2>
*
* This software component is licensed by Puya under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "boot_main.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* External functions --------------------------------------------------------*/
/**
* @brief Initialize global MSP.
*/
void HAL_MspInit(void)
{
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
}
/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
+93
View File
@@ -0,0 +1,93 @@
/**
******************************************************************************
* @file py32f040_it.c
* @author MCU Application Team
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
* All rights reserved.</center></h2>
*
* This software component is licensed by Puya under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "boot_main.h"
#include "py32f040_it.h"
/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/******************************************************************************/
/* Cortex-M0+ Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
}
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
while (1)
{
}
}
/**
* @brief This function handles System service call via SWI instruction.
*/
void SVC_Handler(void)
{
}
/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
}
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
HAL_IncTick();
}
/******************************************************************************/
/* PY32F040 Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file. */
/******************************************************************************/
/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
+154
View File
@@ -0,0 +1,154 @@
/**
******************************************************************************
* @file system_py32f040.c
* @author MCU Application Team
* @brief CMSIS Cortex-M0+ Device Peripheral Access Layer System Source File
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
* All rights reserved.</center></h2>
*
* This software component is licensed by Puya under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
#include "py32f0xx.h"
#if !defined (HSE_VALUE)
#define HSE_VALUE 24000000U /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
#if !defined (LSI_VALUE)
#define LSI_VALUE 32768U /*!< Value of LSI in Hz*/
#endif /* LSI_VALUE */
#if !defined (LSE_VALUE)
#define LSE_VALUE 32768U /*!< Value of LSE in Hz*/
#endif /* LSE_VALUE */
/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to relocate your vector Table in
Internal SRAM. */
/* #define FORBID_VECT_TAB_MIGRATION */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
This value must be a multiple of 0x100. */
/******************************************************************************/
/*----------------------------------------------------------------------------
Clock Variable definitions
*----------------------------------------------------------------------------*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock; then there
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
uint32_t SystemCoreClock = HSI_VALUE;
const uint32_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint32_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
const uint32_t HSIFreqTable[8] = {4000000U, 8000000U, 16000000U, 22120000U, 24000000U, 4000000U, 4000000U, 4000000U};
/**
* @brief Clock functions.
* @param none
* @return none
*/
void SystemCoreClockUpdate(void) /* Get Core Clock Frequency */
{
uint32_t tmp;
uint32_t hsidiv;
uint32_t hsifs;
#if defined(RCC_PLL_SUPPORT)
uint32_t pllmul=0;
const uint8_t pllMulValue[4] = {2,3,2,2};
#endif /* RCC_PLL_SUPPORT */
/* Get SYSCLK source -------------------------------------------------------*/
switch (RCC->CFGR & RCC_CFGR_SWS)
{
case RCC_SYSCLKSOURCE_STATUS_HSE: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case RCC_SYSCLKSOURCE_STATUS_LSI: /* LSI used as system clock */
SystemCoreClock = LSI_VALUE;
break;
#if defined(RCC_LSE_SUPPORT)
case RCC_SYSCLKSOURCE_STATUS_LSE: /* LSE used as system clock */
SystemCoreClock = LSE_VALUE;
break;
#endif /* RCC_LSE_SUPPORT */
#if defined(RCC_PLL_SUPPORT)
case RCC_SYSCLKSOURCE_STATUS_PLLCLK: /* PLL used as system clock */
pllmul = pllMulValue[((RCC->PLLCFGR & RCC_PLLCFGR_PLLMUL)>>RCC_PLLCFGR_PLLMUL_Pos)] ;
if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSI) /* HSI used as PLL clock source */
{
hsifs = ((READ_BIT(RCC->ICSCR, RCC_ICSCR_HSI_FS)) >> RCC_ICSCR_HSI_FS_Pos);
SystemCoreClock = pllmul * (HSIFreqTable[hsifs]);
}
else /* HSE used as PLL clock source */
{
SystemCoreClock = pllmul * HSE_VALUE;
}
break;
#endif /* RCC_PLL_SUPPORT */
case RCC_SYSCLKSOURCE_STATUS_HSI: /* HSI used as system clock */
default: /* HSI used as system clock */
hsifs = ((READ_BIT(RCC->ICSCR, RCC_ICSCR_HSI_FS)) >> RCC_ICSCR_HSI_FS_Pos);
hsidiv = (1UL << ((READ_BIT(RCC->CR, RCC_CR_HSIDIV)) >> RCC_CR_HSIDIV_Pos));
SystemCoreClock = (HSIFreqTable[hsifs] / hsidiv);
break;
}
/* Compute HCLK clock frequency --------------------------------------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
/**
* @brief Setup the microcontroller system.
* Initialize the System.
* @param none
* @return none
*/
void SystemInit(void)
{
/* Set the HSI clock to 8MHz by default */
/* Set the LSI clock to 32.768KHz by default */
RCC->ICSCR = (RCC->ICSCR & 0xFE000000) | (0x1 << 13) | ((*(uint32_t *)(0x1fff3208)) & 0x0000FFFF) | ((*(uint32_t *)(0x1fff3348))<<16);
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif /* VECT_TAB_SRAM */
}
/************************ (C) COPYRIGHT Puya *****END OF FILE******************/