- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在介绍下面的内容前, 先看一下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
这些容量类型与型号的对应关系为 。
可以看到 CH32V208 全系列属于 CH32V20x_D8W 容量类型 。
数据手册中对存储部分的说明为 。
下图是 CH32V208 的存储器地址映射 。
地址分配和 ARM Cortex M 几乎是一样的 。
其中 Flash 大小是 480KB, 而 RAM 是可以配置的(应该是一块总计192KB的RAM), 根据零等待Flash的大小不同, 有三种划分选项 128KF + 64KR, 144KF + 48KR, 160KF + 32KR. 当启动时, 对应大小的code从 Flash 载入到 RAM 中执行, 实现零等待. 。
CH32V208 的 Flash 分为三块: 最开始的128KB固定映射到RAM, 在复位后复制到RAM; 之后的32KB是可配置区域; 除了前面的160KB, 后面的320KB是固定的非零等待代码区域. 。
| Fixed | Dynamic |
| ----- | -------- | ------- | -------------------- | ------ |
| Flash | 128KB | 32KB | 320KB | 32KB |
------------------------------------------
└───480K 用户可擦写可执行
| ----- | -------- | ------- | ------ | -------------------- |
| RAM | 128KB | 32KB | 32KB |
-------- ------- ------
| | └─── 32K固定RAM
| └───32K可配置为RAM或Flash映射
└───128K固定Flash映射, 复位后硬件拷贝
编辑项目中的 link.ld, 在 MEMORY 部分修改, 下面的例子将 Flash 设置为 448KB 。
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
}
注意 Flash 的 ORIGIN 从 0x0000 0000 开始, 不是 0x0800 0000, 因为执行时 Flash 会被映射到 0 地址, 连接时代码的地址都以0地址为偏移量. 。
在启动时, 通过自举引脚(BOOT0 和 BOOT1), 可以选择三种自举模式中的一种 。
BOOT0 | BOOT1 | 启动模式 |
---|---|---|
0 | X | 从Code Flash 启动 |
1 | 0 | 从System FLASH 启动 |
1 | 1 | 从内部 SRAM 启动 |
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 的时钟相对于 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 和代码示例中, 与时钟相关的代码主要是这两个文件 。
文件中定义了外置时钟源的频率 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 */
这个文件存在于每个示例项目的 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的储存结构,启动模式和时钟的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!