沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟

2023-06-14,,

目录

沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置
沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟

CH32V 存储容量命名方式

在介绍下面的内容前, 先看一下CH32V系列和存储相关的命名格式, 以CH32V203为例, 前面的CH32V203代表一个系列, 后面的字符分别代表了Pin脚数量, Flash大小, 封装和工作温度范围

CH32V203G6U6
||||
|||`-> Temperature range
||`--> Package: QFN
|`---> Flash Size
`----> Pin Count

其中的Flash大小表示为

4 = 16K
6 = 32K
8 = 64K
B = 128K
C = 256K

以及以D开头的容量表示形式(在用户手册中会出现)

D6 32KB or 64KB, Low-and-medium-density general
D8 128KB or 256KB, High-density general
D8C 128KB or 256KB, Connectivity or interconnectivity
D8W 128KB or 256KB, Wireless

这些容量类型与型号的对应关系为

CH32V20x_D6

CH32V203F6, CH32V203G6, CH32V203K6, CH32V203F8, CH32V203G8, CH32V203K8, CH32V203C6, CH32V203C8
CH32V20x_D8

CH32V203RB
CH32V20x_D8W

CH32V208GB, CH32V208CB, CH32V208RB, CH32V208WB
CH32V30x_D8

CH32V303CB, CH32V303RB, CH32V303RC, CH32V303VC
CH32V30x_D8C

CH32V305FB, CH32V305RB, CH32V307RC, CH32V307WC, CH32V307VC

可以看到 CH32V208 全系列属于 CH32V20x_D8W 容量类型

CH32V208 的存储

数据手册中对存储部分的说明为

内置最大 64K 字节 SRAM 区, 用于存放数据, 掉电后数据丢失. 具体容量要对应芯片型号.
内置最大 480K 字节程序闪存存储区(Code FLASH), 用于用户的应用程序和常量数据存储. 其中包括零等待程序运行区域和非零等待区域.
内置 28K 字节系统存储区(System FLASH)用于系统引导程序存储(厂家固化自举加载程序).
128 字节用于系统非易失配置信息存储区, 128 字节用于用户选择字存储区

CH32V208 的存储器地址映射

下图是 CH32V208 的存储器地址映射

地址分配和 ARM Cortex M 几乎是一样的

Flash地址从 0x0800 0000 开始
RAM地址从 0x2000 0000 开始
根据 BOOT pin 的设置, 启动时将对应的地址映射到 0x0000 0000

其中 Flash 大小是 480KB, 而 RAM 是可以配置的(应该是一块总计192KB的RAM), 根据零等待Flash的大小不同, 有三种划分选项 128KF + 64KR, 144KF + 48KR, 160KF + 32KR. 当启动时, 对应大小的code从 Flash 载入到 RAM 中执行, 实现零等待.

启动模式

在启动时, 通过自举引脚(BOOT0 和 BOOT1), 可以选择三种自举模式中的一种

BOOT0 BOOT1 启动模式
0 X 从Code Flash 启动
1 0 从System FLASH 启动
1 1 从内部 SRAM 启动

BOOT0 为独立的pin
BOOT1 为PB2

QFN28封装的 CH32V208GBU6 比较特殊, 一是没有引出 BOOT1, 默认接地, 二是 BOOT0 与 PB8 共用同一个物理PIN脚, 在手册第19页有单独说明:

BOOT0引脚引出, 但BOOT1/PB2引脚未引出的芯片, 内部BOOT1/PB2引脚将下拉到GND. 此时如果进入低功耗模式配置IO口状态时, 建议BOOT1/PB2引脚使用输入下拉模式防止产生额外电流.

BOOT0和PB8引脚合封芯片, 建议外接500K下拉电阻, 保证芯片上电稳定进入程序闪存存储器自举模式. 另外, 此PB8引脚及其复用功能只保留了输出驱动功能, 所有输入功能已被禁止.

这个500K下拉可以保证BOOT0不浮空的同时, 对PB8作为输出不造成影响.

28引脚封装芯片有许多合封引脚(至少2个IO功能引脚物理合为一个引脚), 此时驱动不要同时配置输出功能, 否则可能损坏引脚. 有功耗要求的注意引脚状态.

简单说就是合封的pin脚, 不要同时设为输出模式

CH32V208 的时钟

根据数据手册, 时钟树结构如下

CH32V208 的时钟相对于 CH32V307 的不同点: 在CH307中没有 ETH-PHY

对于 CH32F20x_D8C 和 CH32V30x_D8C, 当使用 USB 功能时,CPU 的频率必须是48MHz、96MHz 或 144MH

而在 CH32V208中, ETH-PHY 的时钟通过 HCLK 提供

CH32F20x_D8W, CH32V20x_D8 和 CH32V20x_D8W 若同时使用 USB 和 ETH 功能, 需将 USBPRE[1:0]置为 11b

对于 USBPRE[1:0] 这个寄存器值为 0B11 时的说明

5 分频, 且 PLL 的源为 HSE 二分频(适用于PLLCLK=240MHz , 仅 适 用 于 CH32V20x_D8W/ CH32F20x_D8W) 注: CH32V20x_D8W、CH32F20x_D8W 具有 11b 选项, 其余型号该选项保留

可以看到, CH32V208 如果要同时使用 USB 和 ETH, 为了同时满足 USB 的48MHz, ETH-PHY 的60MHz, 需要将 PLLCLK 升至240MHz, 5分频后输出给 USB, 而 ETH-PHY 则从 120MHz 的 HCLK 通过2分频得到 60MHz

另一个需要注意的点是, BLE的 RFCLK 时钟是由 HSE 提供的, 如果时钟树没错的话, 可以理解为只有外接时钟源才能使用 BLE.

时钟设置代码

在沁恒提供的 SDK 和代码示例中, 与时钟相关的代码主要是这两个文件

ch32v20x.h

文件中定义了外置时钟源的频率 HSE_VALUE, CH32V208 默认使用的是 32MHz, 如果使用其他频率的晶振, 需要在这里修改

#if defined(CH32V20x_D8) || defined(CH32V20x_D8W)
#define HSE_VALUE ((uint32_t)32000000) /* Value of the External oscillator in Hz */
#else
#define HSE_VALUE ((uint32_t)8000000) /* Value of the External oscillator in Hz */
#endif

而内建时钟源是固定的 8MHz

#define HSI_VALUE              ((uint32_t)8000000) /* Value of the Internal oscillator in Hz */

system_ch32v20x.c

这个文件存在于每个示例项目的 User 目录下, 已经实现了常用的频率值函数, 通过修改宏配置可以切换不同的系统频率

//#define SYSCLK_FREQ_HSE    HSE_VALUE
//#define SYSCLK_FREQ_48MHz_HSE 48000000
//#define SYSCLK_FREQ_56MHz_HSE 56000000
//#define SYSCLK_FREQ_72MHz_HSE 72000000
//#define SYSCLK_FREQ_96MHz_HSE 96000000
//#define SYSCLK_FREQ_120MHz_HSE 120000000
#define SYSCLK_FREQ_144MHz_HSE 144000000
//#define SYSCLK_FREQ_HSI HSI_VALUE
//#define SYSCLK_FREQ_48MHz_HSI 48000000
//#define SYSCLK_FREQ_56MHz_HSI 56000000
//#define SYSCLK_FREQ_72MHz_HSI 72000000
//#define SYSCLK_FREQ_96MHz_HSI 96000000
//#define SYSCLK_FREQ_120MHz_HSI 120000000
//#define SYSCLK_FREQ_144MHz_HSI 144000000

在里面搜索(3<<22), 对应 RCC->CFGR0, (3<<22)就是 USBPRE 寄存器, 可以看到在设置系统频率为 120MHz 时的特殊处理.

void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0; tmp = RCC->CFGR0 & RCC_SWS; switch (tmp)
{
case 0x00:
SystemCoreClock = HSI_VALUE;
break;
case 0x04:
SystemCoreClock = HSE_VALUE;
break;
case 0x08:
pllmull = RCC->CFGR0 & RCC_PLLMULL;
pllsource = RCC->CFGR0 & RCC_PLLSRC;
pllmull = ( pllmull >> 18) + 2; if(pllmull == 17) pllmull = 18; if (pllsource == 0x00)
{
if(EXTEN->EXTEN_CTR & EXTEN_PLL_HSI_PRE){
SystemCoreClock = HSI_VALUE * pllmull;
}
else{
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
}
}
else
{
#if defined (CH32V20x_D8W) // 对应 CH32V208 额外的处理逻辑
if((RCC->CFGR0 & (3<<22)) == (3<<22)) // 如果 USBPRE 为 11, 仅出现在 120MHz的配置函数中
{
SystemCoreClock = ((HSE_VALUE>>1)) * pllmull; // 系统时钟为 32 / 2 * 15 = 240MHz
}
else
#endif
if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
{
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
SystemCoreClock = ((HSE_VALUE>>2) >> 1) * pllmull;
#else
SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
#endif
}
else
{
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
SystemCoreClock = (HSE_VALUE>>2) * pllmull;
#else
SystemCoreClock = HSE_VALUE * pllmull;
#endif
}
} if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2); break;
default:
SystemCoreClock = HSI_VALUE;
break;
} tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)]; // 通过 AHBPrescTable 对应的分频系数, 降回 120MHz
SystemCoreClock >>= tmp;
}

AHBPrescTable 的分频系数数组为

__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};

在 SetSysClockTo120_HSE(void) 中, 设置了 RCC_HPRE_DIV2

RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;

而 RCC_HPRE_DIV2 的值对应的是 0x00000080, RCC_HPRE 的值是 0x000000F0

#define RCC_HPRE                                ((uint32_t)0x000000F0) /* HPRE[3:0] bits (AHB prescaler) */
#define RCC_HPRE_0 ((uint32_t)0x00000010) /* Bit 0 */
#define RCC_HPRE_1 ((uint32_t)0x00000020) /* Bit 1 */
#define RCC_HPRE_2 ((uint32_t)0x00000040) /* Bit 2 */
#define RCC_HPRE_3 ((uint32_t)0x00000080) /* Bit 3 */ #define RCC_HPRE_DIV1 ((uint32_t)0x00000000) /* SYSCLK not divided */
#define RCC_HPRE_DIV2 ((uint32_t)0x00000080) /* SYSCLK divided by 2 */
#define RCC_HPRE_DIV4 ((uint32_t)0x00000090) /* SYSCLK divided by 4 */

通过 RCC->CFGR0 & RCC_HPRE, 可以还原回 0x00000080, 再右移4位, 就变成 0x00000008, 对应 AHBPrescTable 中的第9个, 值为1, SystemCoreClock 右移1位, 相当于除以2, 值从240MHz变回120MHz.

沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟的相关教程结束。

《沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟.doc》

下载本文的Word格式文档,以方便收藏与打印。