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

科技资讯 投稿 5500 0 评论

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

目录

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

CH32V 存储容量命名方式

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 的存储

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

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

CH32V208 的存储器地址映射

    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 启动模式
0 X 从Code Flash 启动
1 0 从System FLASH 启动
1 1 从内部 SRAM 启动
    BOOT0 为独立的pin
  • BOOT1 为PB2

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

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

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

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

CH32V208 的时钟

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

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

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

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

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

时钟设置代码

ch32v20x.h

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

#if defined(CH32V20x_D8 || defined(CH32V20x_D8W
  #define HSE_VALUE    ((uint32_t32000000 /* Value of the External oscillator in Hz */
#else
  #define HSE_VALUE    ((uint32_t8000000 /* Value of the External oscillator in Hz */
#endif

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

#define HSI_VALUE              ((uint32_t8000000 /* 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_tRESET
        {
#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_tRCC_HPRE_DIV2;

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

#define RCC_HPRE                                ((uint32_t0x000000F0 /* HPRE[3:0] bits (AHB prescaler */
#define RCC_HPRE_0                              ((uint32_t0x00000010 /* Bit 0 */
#define RCC_HPRE_1                              ((uint32_t0x00000020 /* Bit 1 */
#define RCC_HPRE_2                              ((uint32_t0x00000040 /* Bit 2 */
#define RCC_HPRE_3                              ((uint32_t0x00000080 /* Bit 3 */

#define RCC_HPRE_DIV1                           ((uint32_t0x00000000 /* SYSCLK not divided */
#define RCC_HPRE_DIV2                           ((uint32_t0x00000080 /* SYSCLK divided by 2 */
#define RCC_HPRE_DIV4                           ((uint32_t0x00000090 /* SYSCLK divided by 4 */

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

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

赞同 (34) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽