发新帖本帖赏金 150.00元(功能说明)我要提问
返回列表
[MM32生态]

从零起步,MM32开发环境:从构建到部署的全过程

[复制链接]
2071|5
手机看帖
扫描二维码
随时随地手机跟帖
xld0932|  楼主 | 2024-3-6 15:58 | 显示全部楼层 |阅读模式
本帖最后由 xld0932 于 2024-3-6 16:12 编辑

#申请原创#   @21小跑堂

目录
  • 前言
  • 创建SVD
  • 下载算法
  • Keil Pack
  • 模板工程
  • 让LED灯闪烁
  • 附件

1.前言
先问大家一个问题:基于Keil MDK-Arm集成开发环境,准备使用某一款ARM芯片进行开发之前,都需要准备些啥?一般我们需要芯片的数据手册来了解芯片的功能特性、需要用户手册用来在编程设计时做参考、需要勘误手册来避免设计上的一些漏洞、当然还需要官方的库函数及例程,这可以使我们开发的效率得到大大的提升;但除此之外,基于Keil MDK-Arm集成开发环境,我们要使用这款芯片,首先还是得让Keil MDK-Arm集成开发环境认识我们所选择的芯片,这就是我们这篇文章需要跟大家讲解的内容,从最基础、最开始的地方,从零起步,从构建到部署,搭建我们芯片开发的软件包。

如何让Keil MDK-Arm集成开发环境认识一款芯片,我们只需要安装一个芯片对应的Keil Pack支持包,这个支持包可以让Keil MDK-Arm集成开发环境在创建工程的时候可以选择到我们的芯片型号,可以通过Keil MDK-Arm集成开发环境在线下载程序,当然也可以让Keil MDK-Arm集成开发环境在线调试我们的芯片寄存器等等,这些都是Keil Pack支持包最基础的功能,更详细的可以通过Open-CMSIS-Pack Project(https://www.open-cmsis-pack.org/)官网来了解。

下面我们以MM32G0001芯片为例作为讲解。

2.创建SVD
SVD文件是描述一个芯片所有资源的一个集合,包含了基于Arm Cortex-M处理器的微控制器系统的描述,特别是外围设备的内存映射寄存器。在我们使用Keil MDK-Arm集成开发环境在线调试功能时,可以很直观的看到寄存的值、状态、中断配置等等:
1.png

SVD的创建一般是由芯片原厂提供的,每个原厂应该都有一套自己的创建方法;但如果我们要自己创建SVD文件可不可以呢,当然是可以的哈!需要哪些步骤呢:
第一:创建SVD文件我们需要获取到芯片的用户手册,根据用户手册中提供的资讯做为我们SVD的数据源,MM32G0001的资料我们可以从灵动官方上来获取(www.mindmotion.com.cn),我们在官网,产品中选中MM32G0超值型系列的MM32G0001,在文档中可以下载我们需要的用户手册:
2.png

第二:我们需要了解SVD文件的组成结构,这可以通过SVD官网说明来了解(https://open-cmsis-pack.github.io/svd-spec/main/index.html):
3.png

SVD文件它是使用XML来对芯片进行描述的,包含了Device层、CPU层、Peripherals外设层、Registers寄存器层、以及寄存器位域Fields层;我们在Device层可以描述芯片名称、SVD文件版本、概要描述等;可以在CPU层描述芯片的内核、版本、大小端、是否带有MPU\FPU\DSP等等一些属性;可以在Peripherals外设层根据用户手册添加外设描述,每个外设描述包含1个或多个寄存器描述,每个寄存器又包含1个或多个位域描述,每个位域描述又可以定义1个或多个枚举值,这们的层级结构组成了一个完整的SVD文件。

第三:我们要有SVD的生成工具,通过上面的了解,要完成一个SVD文件的工作量是巨大的,如果没有工具而靠手动的去敲,很容易出错,也不容易检查问题;在GitHub上有人分享了一个svd_editor(https://github.com/dmitrystu/svd_editor),但使用下来感觉有点不智能,不太方便!所以我们就自己造工具吧^^

2.1.构建SVD数据源
SVD的数据源我们使用YAML来描述,第一是看上去很直接,其次就是后面维护移植起来方便!我们根据SVD的文件结构来定义了不同的层级,分别为cpu.yml、interrupt.yml、peripheral.yml,这3层作为最先被定义的yml文件,分别定义了MCU的一些特性,中断向量表、以及MCU所具备的外设,然后通过Python来自动构建具体的“外设.yml”,比如CRC.yml/ADC1.yml/GPIOA.yml等,然后在“外设.yml”中添加相应的寄存器描述,Python会根据寄存器描述自动构建“寄存器.yml”,最后我们在“寄存器.yml”中添加位域的描述,这们就数据源就构建OK啦,当然这也是一个耗时的任务,但对于一个MCU原厂来说,相同的外设其定义都差不多,所以可以在不同MCU型号中进行移植,哪怕是修改也是很方便的,所以就辛苦在第一次从无到有的这样一个过程了,加油!
cpu.yml:这个是参考用户手册第一章节:系统和存储架构提取的
MM32G0001 :
  name                : 'CM0'
  revision            : 'r0p0'
  endian              : 'little'
  mpuPresent          : 'false'
  fpuPresent          : 'false'
  fpuDP               : 'false'
  dspPresent          : 'false'
  icachePresent       : 'false'
  dcachePresent       : 'false'
  itcmPresent         : 'false'
  dtcmPresent         : 'false'
  vtorPresent         : 'false'
  nvicPrioBits        : '2'
  vendorSystickConfig : 'false'

interrupt:这个是参考用户手册7.3.2 中断和异常向量
IWDG :
  description : 'IWDG Interrupt'
  value       : '0'
  peripheral  : 'IWDG'

PVD :
  description : 'PVD Interrupt'
  value       : '1'
  peripheral  : 'PWR'

FLASH :
  description : 'Flash Global Interrupt'
  value       : '3'
  peripheral  : 'FLASH'

RCC :
  description : 'RCC Global Interrupt'
  value       : '4'
  peripheral  : 'RCC'

EXTI0_1 :
  description : 'EXTI Line[1:0] Interrupt'
  value       : '5'
  peripheral  : 'EXTI'

EXTI2_3 :
  description : 'EXTI Line[3:2] Interrupt'
  value       : '6'
  peripheral  : 'EXTI'

......

peripheral.yml:这个是参考1.2.1 存储器映像和寄存器编址
TIM3 :
  description : '16-Bit General-Purpose Timer'
  groupName   : 'TIM3'
  baseAddress : '0x40000400'
  offset      : '0x0'
  size        : '0x400'

IWDG :
  description : 'IWDG Independent watchdog'
  groupName   : 'IWDG'
  baseAddress : '0x40003000'
  offset      : '0x0'
  size        : '0x400'

USART2 :
  description : 'Universal Synchronous Asynchronous Receiver Transmitter'
  groupName   : 'USART'
  baseAddress : '0x40004400'
  offset      : '0x0'
  size        : '0x400'

I2C1 :
  description : 'Inter-Integrated Circuit Interface'
  groupName   : 'I2C1'
  baseAddress : '0x40005400'
  offset      : '0x0'
  size        : '0x400'

PWR :
  description : 'Power Controller'
  groupName   : 'PWR'
  baseAddress : '0x40007000'
  offset      : '0x0'
  size        : '0x400'

SYSCFG :
  description : 'System Controller'
  groupName   : 'SYSCFG'
  baseAddress : '0x40010000'
  offset      : '0x0'
  size        : '0x400'

EXTI :
  description : 'Interrupt and Event'
  groupName   : 'EXTI'
  baseAddress : '0x40010400'
  offset      : '0x0'
  size        : '0x400'

......

ADC1.yml :这个是参考8.12.1 寄存器总览
ADDATA :
  description   : 'A/D data register'
  addressOffset : '0x00'
  access        : 'read-only'
  resetValue    : '0x00000000'
  size          : '32'

ADCFG :
  description   : 'A/D configuration register'
  addressOffset : '0x04'
  access        : 'read-write'
  resetValue    : '0x00000000'
  size          : '32'

ADCR :
  description   : 'A/D control register'
  addressOffset : '0x08'
  access        : 'read-write'
  resetValue    : '0x00000000'
  size          : '32'

ADCMPR :
  description   : 'A/D analog watchdog comparison register'
  addressOffset : '0x10'
  access        : 'read-write'
  resetValue    : '0x00000000'
  size          : '32'

ADSTA :
  description   : 'A/D status register'
  addressOffset : '0x14'
  access        : 'read-write'
  resetValue    : '0x00000000'
  size          : '32'

......

ADC1中的寄存器 ADDATA.yml:这个是参考8.12.2 A/D数据寄存器(ADC_ADDATA)
DATA :
  description : '12-bit A/D conversion result'
  bitRange    : '[15:0]'
  access      : 'read-only'

CHANNELSEL :
  description : '4 bits show the channel corresponding to the current data'
  bitRange    : '[19:16]'
  access      : 'read-only'

OVERRUN :
  description : 'Data Overrun Flag'
  bitRange    : '[20:20]'
  access      : 'read-only'

VAILD :
  description : 'Data Valid Flag'
  bitRange    : '[21:21]'
  access      : 'read-only'


2.2.Python自动化生成SVD文件
我们安装最新的Python 3.12.0以及PyCharm社区版集成开发环境,添加和安装PyYAML组件,通过对SVD文件结构和SVD数据源的提取,最终来自动化一键生成SVD文件:
2.2.1.SVD整体创建
def svd_generate(chip):
    if not os.path.exists(fr'D:\PyCharm\{chip}'):
        os.mkdir(fr'D:\PyCharm\{chip}')

    with open(fr'D:\PyCharm\{chip}\{chip}.svd', mode='w') as svd_file:
        svd_file.write('<?xml version="1.0" encoding="utf-8"?>\n')
        svd_file.write('<device schemaVersion="1.3" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" '
                       'xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd">\n')
        svd_file.write(f'\t<name>{chip}</name>\n')
        svd_file.write('\t<version>0.0.1</version>\n')
        svd_file.write(f'\t<description>{chip}:ARM 32-bit Cortex-M Microcontroller based device</description>\n')
        svd_cpu(chip, svd_file)
        svd_peripheral(chip, svd_file)
        svd_file.write('</device>\n')
        svd_file.close()

2.2.2.创建CPU层
def svd_cpu(chip, svd_file):
    if not os.path.exists(fr'D:\PyCharm\{chip}\cpu.yml'):
        with open(fr'D:\PyCharm\{chip}\cpu.yml', mode='w') as cpu_file:
            print('create cpu.yml')
    else:
        with open(fr'D:\PyCharm\{chip}\cpu.yml', mode='r') as cpu_file:
            cpu_data = yaml.safe_load(cpu_file)
            if cpu_data is None:
                print('cpu.yml is empty!')
            else:
                svd_file.write('\t<cpu>\n')
                svd_file.write(f'\t\t<name>{cpu_data[chip]['name']}</name>\n')
                svd_file.write(f'\t\t<revision>{cpu_data[chip]['revision']}</revision>\n')
                svd_file.write(f'\t\t<endian>{cpu_data[chip]['endian']}</endian>\n')
                svd_file.write(f'\t\t<mpuPresent>{cpu_data[chip]['mpuPresent']}</mpuPresent>\n')
                svd_file.write(f'\t\t<fpuPresent>{cpu_data[chip]['fpuPresent']}</fpuPresent>\n')
                svd_file.write(f'\t\t<fpuDP>{cpu_data[chip]['fpuDP']}</fpuDP>\n')
                svd_file.write(f'\t\t<icachePresent>{cpu_data[chip]['icachePresent']}</icachePresent>\n')
                svd_file.write(f'\t\t<dcachePresent>{cpu_data[chip]['dcachePresent']}</dcachePresent>\n')
                svd_file.write(f'\t\t<itcmPresent>{cpu_data[chip]['itcmPresent']}</itcmPresent>\n')
                svd_file.write(f'\t\t<dtcmPresent>{cpu_data[chip]['dtcmPresent']}</dtcmPresent>\n')
                svd_file.write(f'\t\t<nvicPrioBits>{cpu_data[chip]['nvicPrioBits']}</nvicPrioBits>\n')
                svd_file.write(f'\t\t<vendorSystickConfig>{cpu_data[chip]['vendorSystickConfig']}</vendorSystickConfig>\n')
                svd_file.write('\t</cpu>\n')
                svd_file.write('\n')
    cpu_file.close()

2.2.3.创建Peripherals层
def svd_peripheral(chip, svd_file):
    if not os.path.exists(fr'D:\PyCharm\{chip}\peripheral.yml'):
        with open(fr'D:\PyCharm\{chip}\peripheral.yml', mode='w') as peripheral_file:
            print('create peripheral.yml')
    else:
        with open(fr'D:\PyCharm\{chip}\peripheral.yml', mode='r') as peripheral_file:
            peripheral_data = yaml.safe_load(peripheral_file)
            if peripheral_data is None:
                print('peripheral.yml is empty!')
            else:
                svd_file.write('\t<peripherals>\n')
                # create register folder
                if not os.path.exists(fr'D:\PyCharm\{chip}\peripheral'):
                    os.mkdir(fr'D:\PyCharm\{chip}\peripheral')

                for peripheral in peripheral_data:
                    svd_file.write('\t\t<peripheral>\n')
                    svd_file.write(f'\t\t\t<name>{peripheral}</name>\n')
                    svd_file.write(f'\t\t\t<description>{peripheral_data[peripheral]['description']}</description>\n')
                    svd_file.write(f'\t\t\t<groupName>{peripheral_data[peripheral]['groupName']}</groupName>\n')
                    svd_file.write(f'\t\t\t<baseAddress>{peripheral_data[peripheral]['baseAddress']}</baseAddress>\n')
                    svd_file.write(f'\t\t\t<addressBlock>\n')
                    svd_file.write(f'\t\t\t\t<offset>{peripheral_data[peripheral]['offset']}</offset>\n')
                    svd_file.write(f'\t\t\t\t<size>{peripheral_data[peripheral]['size']}</size>\n')
                    svd_file.write(f'\t\t\t\t<usage>registers</usage>\n')
                    svd_file.write(f'\t\t\t</addressBlock>\n')

                    svd_interrupt(chip, peripheral, svd_file)

                    # print('{:6s}'.format(peripheral), hex(peripheral_data[peripheral]))
                    if not os.path.exists(fr'D:\PyCharm\{chip}\peripheral\{peripheral}.yml'):
                        with open(fr'D:\PyCharm\{chip}\peripheral\{peripheral}.yml', mode='w') as register_file:
                            print(f'create {peripheral}.yml...')
                    else:
                        svd_register(chip, peripheral, svd_file)

                    svd_file.write('\t\t</peripheral>\n')
                svd_file.write('\t</peripherals>\n')
    peripheral_file.close()

2.2.4.添加Interrupt属性
def svd_interrupt(chip, peripheral, svd_file):
    if not os.path.exists(fr'D:\PyCharm\{chip}\interrupt.yml'):
        with open(fr'D:\PyCharm\{chip}\interrupt.yml', mode='w') as interrupt_file:
            print('create interrupt.yml')
    else:
        with open(fr'D:\PyCharm\{chip}\interrupt.yml', mode='r') as interrupt_file:
            interrupt_data = yaml.safe_load(interrupt_file)
            if interrupt_data is None:
                print('interrupt.yml is empty!')
            else:
                for interrupt in interrupt_data:
                    if interrupt_data[interrupt]['peripheral'] == peripheral:
                        svd_file.write('\t\t\t<interrupt>\n')
                        svd_file.write(f'\t\t\t\t<name>{interrupt}</name>\n')
                        svd_file.write(f'\t\t\t\t<description>{interrupt_data[interrupt]['description']}</description>\n')
                        svd_file.write(f'\t\t\t\t<value>{interrupt_data[interrupt]['value']}</value>\n')
                        svd_file.write('\t\t\t</interrupt>\n')
    interrupt_file.close()

2.2.5.创建Registers层
def svd_register(chip, peripheral, svd_file):
    with open(fr'D:\PyCharm\{chip}\peripheral\{peripheral}.yml', mode='r') as register_file:
        register_data = yaml.safe_load(register_file)
        if register_data is None:
            print(f'{peripheral}.yml is empty!')
        else:
            # Create REG Folder
            if not os.path.exists(fr'D:\PyCharm\{chip}\peripheral\register'):
                os.mkdir(fr'D:\PyCharm\{chip}\peripheral\register')

            if not os.path.exists(fr'D:\PyCharm\{chip}\peripheral\register\{peripheral}'):
                os.mkdir(fr'D:\PyCharm\{chip}\peripheral\register\{peripheral}')

            svd_file.write('\t\t\t<registers>\n')

            for register in register_data:
                if not os.path.exists(fr'D:\PyCharm\{chip}\peripheral\register\{peripheral}\{register}.yml'):
                    with open(fr'D:\PyCharm\{chip}\peripheral\register\{peripheral}\{register}.yml', mode='w') as field_file:
                        print(f'create {register}.yml...')
                else:
                    svd_file.write('\t\t\t\t<register>\n')
                    svd_file.write(f'\t\t\t\t\t<name>{register}</name>\n')
                    svd_file.write(f'\t\t\t\t\t<description>{register_data[register]['description']}</description>\n')
                    svd_file.write(f'\t\t\t\t\t<addressOffset>{register_data[register]['addressOffset']}</addressOffset>\n')
                    svd_file.write(f'\t\t\t\t\t<access>{register_data[register]['access']}</access>\n')
                    svd_file.write(f'\t\t\t\t\t<resetValue>{register_data[register]['resetValue']}</resetValue>\n')
                    svd_file.write(f'\t\t\t\t\t<size>{register_data[register]['size']}</size>\n')

                    svd_field(chip, peripheral, register, svd_file)

                    svd_file.write('\t\t\t\t</register>\n')

            svd_file.write('\t\t\t</registers>\n')
        register_file.close()

2.2.6.创建Field层
def svd_field(chip, peripheral, register, svd_file):
    with open(fr'D:\PyCharm\{chip}\peripheral\register\{peripheral}\{register}.yml', mode='r') as field_file:
        field_data = yaml.safe_load(field_file)
        if field_data is None:
            print(f'{register}.yml is empty')
        else:
            svd_file.write('\t\t\t\t\t<fields>\n')

            for field in field_data:
                svd_file.write('\t\t\t\t\t\t<field>\n')
                svd_file.write(f'\t\t\t\t\t\t\t<name>{field}</name>\n')
                svd_file.write(f'\t\t\t\t\t\t\t<description>{field_data[field]['description']}</description>\n')
                svd_file.write(f'\t\t\t\t\t\t\t<bitRange>{field_data[field]['bitRange']}</bitRange>\n')
                svd_file.write(f'\t\t\t\t\t\t\t<access>{field_data[field]['access']}</access>\n')
                svd_file.write('\t\t\t\t\t\t</field>\n')

            svd_file.write('\t\t\t\t\t</fields>\n')
        field_file.close()

2.3.生成SVD文件
4.png

2.4.SVD文件校验
CMSIS提供了一个SVD生成和检验工具,“SVDConv.exe”通过这个工具,我们可以生成芯片的头文件,在生成头文件时还可以检测SVD文件的正确性,确保SVD文件是0 Errors,0 Warnings!在制作的过程中,有些是因为XML语法的问题,有些是寄存器属性和位域属性不一致,通过细心的修改,都是可以解决掉的。
5.png

2.5.SVD文件产生头文件
产生头文件的3种方式:
第一:SVDConv.exe  MM32G0001.svd --generate=header,这种方式只会产生最基础的头文件,仅包含了中断、外设和寄存的定义和描述;
typedef struct {                                /*!< ([url=home.php?mod=space&uid=72445]@[/url] 0x40000400) TIM3 Structure                                             */
  __IOM uint32_t  CR1;                          /*!< ([url=home.php?mod=space&uid=72445]@[/url] 0x00000000) Control Register 1                                         */
  __IOM uint32_t  CR2;                          /*!< ([url=home.php?mod=space&uid=72445]@[/url] 0x00000004) Control Register 2                                         */
  __IOM uint32_t  SMCR;                         /*!< (@ 0x00000008) Slave Mode Control Register                                */
  __IOM uint32_t  DIER;                         /*!< (@ 0x0000000C) Interrupt Enable Register                                  */
  __IOM uint32_t  SR;                           /*!< (@ 0x00000010) Status Register                                            */
  __OM  uint32_t  EGR;                          /*!< (@ 0x00000014) Event Generation Register                                  */
  __IOM uint32_t  CCMR1;                        /*!< (@ 0x00000018) Compare Mode Register 1                                    */
  __IOM uint32_t  CCMR2;                        /*!< (@ 0x0000001C) Compare Mode Register 2                                    */
  __IOM uint32_t  CCER;                         /*!< (@ 0x00000020) Compare Enable Register                                    */
  __IOM uint32_t  CNT;                          /*!< (@ 0x00000024) Counter                                                    */
  __IOM uint32_t  PSC;                          /*!< (@ 0x00000028) Prescaler                                                  */
  __IOM uint32_t  ARR;                          /*!< (@ 0x0000002C) Auto Reload Register                                       */
  __IM  uint32_t  RESERVED;
  __IOM uint32_t  CCR1;                         /*!< (@ 0x00000034) Compare Register 1                                         */
  __IOM uint32_t  CCR2;                         /*!< (@ 0x00000038) Compare Register 2                                         */
  __IOM uint32_t  CCR3;                         /*!< (@ 0x0000003C) Compare Register 3                                         */
  __IOM uint32_t  CCR4;                         /*!< (@ 0x00000040) Compare Register 4                                         */
  __IM  uint32_t  RESERVED1[3];
  __IOM uint32_t  OR;                           /*!< (@ 0x00000050) Input Option Register                                      */
} TIM3_Type;                                    /*!< Size = 84 (0x54)                                                          */

第二:SVDConv.exe  MM32G0001.svd --generate=header --fields=macro,这种方式在第一种的基础上,添加了寄存器位域的宏定义,包含了位域的起始位置和掩码值;
/* =========================================================================================================================== */
/* ================                                           TIM3                                            ================ */
/* =========================================================================================================================== */

/* ==========================================================  CR1  ========================================================== */
#define TIM3_CR1_CEN_Pos                  (0UL)                     /*!< CEN (Bit 0)                                           */
#define TIM3_CR1_CEN_Msk                  (0x1UL)                   /*!< CEN (Bitfield-Mask: 0x01)                             */
#define TIM3_CR1_UDIS_Pos                 (1UL)                     /*!< UDIS (Bit 1)                                          */
#define TIM3_CR1_UDIS_Msk                 (0x2UL)                   /*!< UDIS (Bitfield-Mask: 0x01)                            */
#define TIM3_CR1_URS_Pos                  (2UL)                     /*!< URS (Bit 2)                                           */
#define TIM3_CR1_URS_Msk                  (0x4UL)                   /*!< URS (Bitfield-Mask: 0x01)                             */
#define TIM3_CR1_OPM_Pos                  (3UL)                     /*!< OPM (Bit 3)                                           */
#define TIM3_CR1_OPM_Msk                  (0x8UL)                   /*!< OPM (Bitfield-Mask: 0x01)                             */
#define TIM3_CR1_DIR_Pos                  (4UL)                     /*!< DIR (Bit 4)                                           */
#define TIM3_CR1_DIR_Msk                  (0x10UL)                  /*!< DIR (Bitfield-Mask: 0x01)                             */
#define TIM3_CR1_CMS_Pos                  (5UL)                     /*!< CMS (Bit 5)                                           */
#define TIM3_CR1_CMS_Msk                  (0x60UL)                  /*!< CMS (Bitfield-Mask: 0x03)                             */
#define TIM3_CR1_ARPE_Pos                 (7UL)                     /*!< ARPE (Bit 7)                                          */
#define TIM3_CR1_ARPE_Msk                 (0x80UL)                  /*!< ARPE (Bitfield-Mask: 0x01)                            */
#define TIM3_CR1_CKD_Pos                  (8UL)                     /*!< CKD (Bit 8)                                           */
#define TIM3_CR1_CKD_Msk                  (0x300UL)                 /*!< CKD (Bitfield-Mask: 0x03)                             */
/* ==========================================================  CR2  ========================================================== */
#define TIM3_CR2_MMS_Pos                  (4UL)                     /*!< MMS (Bit 4)                                           */
#define TIM3_CR2_MMS_Msk                  (0x70UL)                  /*!< MMS (Bitfield-Mask: 0x07)                             */
#define TIM3_CR2_TI1S_Pos                 (7UL)                     /*!< TI1S (Bit 7)                                          */
#define TIM3_CR2_TI1S_Msk                 (0x80UL)                  /*!< TI1S (Bitfield-Mask: 0x01)                            */
/* =========================================================  SMCR  ========================================================== */
#define TIM3_SMCR_SMS_Pos                 (0UL)                     /*!< SMS (Bit 0)                                           */
#define TIM3_SMCR_SMS_Msk                 (0x7UL)                   /*!< SMS (Bitfield-Mask: 0x07)                             */
#define TIM3_SMCR_TS_Pos                  (4UL)                     /*!< TS (Bit 4)                                            */
#define TIM3_SMCR_TS_Msk                  (0x70UL)                  /*!< TS (Bitfield-Mask: 0x07)                              */
#define TIM3_SMCR_MSM_Pos                 (7UL)                     /*!< MSM (Bit 7)                                           */
#define TIM3_SMCR_MSM_Msk                 (0x80UL)                  /*!< MSM (Bitfield-Mask: 0x01)                             */
/* =========================================================  DIER  ========================================================== */
#define TIM3_DIER_UIE_Pos                 (0UL)                     /*!< UIE (Bit 0)                                           */
#define TIM3_DIER_UIE_Msk                 (0x1UL)                   /*!< UIE (Bitfield-Mask: 0x01)                             */
#define TIM3_DIER_CC1IE_Pos               (1UL)                     /*!< CC1IE (Bit 1)                                         */
#define TIM3_DIER_CC1IE_Msk               (0x2UL)                   /*!< CC1IE (Bitfield-Mask: 0x01)                           */
#define TIM3_DIER_CC2IE_Pos               (2UL)                     /*!< CC2IE (Bit 2)                                         */
#define TIM3_DIER_CC2IE_Msk               (0x4UL)                   /*!< CC2IE (Bitfield-Mask: 0x01)                           */
#define TIM3_DIER_CC3IE_Pos               (3UL)                     /*!< CC3IE (Bit 3)                                         */
#define TIM3_DIER_CC3IE_Msk               (0x8UL)                   /*!< CC3IE (Bitfield-Mask: 0x01)                           */
#define TIM3_DIER_CC4IE_Pos               (4UL)                     /*!< CC4IE (Bit 4)                                         */
#define TIM3_DIER_CC4IE_Msk               (0x10UL)                  /*!< CC4IE (Bitfield-Mask: 0x01)                           */
#define TIM3_DIER_TIE_Pos                 (6UL)                     /*!< TIE (Bit 6)                                           */
#define TIM3_DIER_TIE_Msk                 (0x40UL)                  /*!< TIE (Bitfield-Mask: 0x01)                             */
/* ==========================================================  SR  =========================================================== */
#define TIM3_SR_UIF_Pos                   (0UL)                     /*!< UIF (Bit 0)                                           */
#define TIM3_SR_UIF_Msk                   (0x1UL)                   /*!< UIF (Bitfield-Mask: 0x01)                             */
#define TIM3_SR_CC1IF_Pos                 (1UL)                     /*!< CC1IF (Bit 1)                                         */
#define TIM3_SR_CC1IF_Msk                 (0x2UL)                   /*!< CC1IF (Bitfield-Mask: 0x01)                           */
#define TIM3_SR_CC2IF_Pos                 (2UL)                     /*!< CC2IF (Bit 2)                                         */
#define TIM3_SR_CC2IF_Msk                 (0x4UL)                   /*!< CC2IF (Bitfield-Mask: 0x01)                           */
#define TIM3_SR_CC3IF_Pos                 (3UL)                     /*!< CC3IF (Bit 3)                                         */
#define TIM3_SR_CC3IF_Msk                 (0x8UL)                   /*!< CC3IF (Bitfield-Mask: 0x01)                           */
#define TIM3_SR_CC4IF_Pos                 (4UL)                     /*!< CC4IF (Bit 4)                                         */
#define TIM3_SR_CC4IF_Msk                 (0x10UL)                  /*!< CC4IF (Bitfield-Mask: 0x01)                           */
#define TIM3_SR_TIF_Pos                   (6UL)                     /*!< TIF (Bit 6)                                           */
#define TIM3_SR_TIF_Msk                   (0x40UL)                  /*!< TIF (Bitfield-Mask: 0x01)                             */
#define TIM3_SR_CC1OF_Pos                 (9UL)                     /*!< CC1OF (Bit 9)                                         */
#define TIM3_SR_CC1OF_Msk                 (0x200UL)                 /*!< CC1OF (Bitfield-Mask: 0x01)                           */
#define TIM3_SR_CC2OF_Pos                 (10UL)                    /*!< CC2OF (Bit 10)                                        */
#define TIM3_SR_CC2OF_Msk                 (0x400UL)                 /*!< CC2OF (Bitfield-Mask: 0x01)                           */
#define TIM3_SR_CC3OF_Pos                 (11UL)                    /*!< CC3OF (Bit 11)                                        */
#define TIM3_SR_CC3OF_Msk                 (0x800UL)                 /*!< CC3OF (Bitfield-Mask: 0x01)                           */
#define TIM3_SR_CC4OF_Pos                 (12UL)                    /*!< CC4OF (Bit 12)                                        */
#define TIM3_SR_CC4OF_Msk                 (0x1000UL)                /*!< CC4OF (Bitfield-Mask: 0x01)                           */
/* ==========================================================  EGR  ========================================================== */
#define TIM3_EGR_UG_Pos                   (0UL)                     /*!< UG (Bit 0)                                            */
#define TIM3_EGR_UG_Msk                   (0x1UL)                   /*!< UG (Bitfield-Mask: 0x01)                              */
#define TIM3_EGR_CC1G_Pos                 (1UL)                     /*!< CC1G (Bit 1)                                          */
#define TIM3_EGR_CC1G_Msk                 (0x2UL)                   /*!< CC1G (Bitfield-Mask: 0x01)                            */
#define TIM3_EGR_CC2G_Pos                 (2UL)                     /*!< CC2G (Bit 2)                                          */
#define TIM3_EGR_CC2G_Msk                 (0x4UL)                   /*!< CC2G (Bitfield-Mask: 0x01)                            */
#define TIM3_EGR_CC3G_Pos                 (3UL)                     /*!< CC3G (Bit 3)                                          */
#define TIM3_EGR_CC3G_Msk                 (0x8UL)                   /*!< CC3G (Bitfield-Mask: 0x01)                            */
#define TIM3_EGR_CC4G_Pos                 (4UL)                     /*!< CC4G (Bit 4)                                          */
#define TIM3_EGR_CC4G_Msk                 (0x10UL)                  /*!< CC4G (Bitfield-Mask: 0x01)                            */
#define TIM3_EGR_TG_Pos                   (6UL)                     /*!< TG (Bit 6)                                            */
#define TIM3_EGR_TG_Msk                   (0x40UL)                  /*!< TG (Bitfield-Mask: 0x01)                              */
/* =========================================================  CCMR1  ========================================================= */
#define TIM3_CCMR1_CC1S_Pos               (0UL)                     /*!< CC1S (Bit 0)                                          */
#define TIM3_CCMR1_CC1S_Msk               (0x3UL)                   /*!< CC1S (Bitfield-Mask: 0x03)                            */
#define TIM3_CCMR1_OC1FE_Pos              (2UL)                     /*!< OC1FE (Bit 2)                                         */
#define TIM3_CCMR1_OC1FE_Msk              (0x4UL)                   /*!< OC1FE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR1_OC1PE_Pos              (3UL)                     /*!< OC1PE (Bit 3)                                         */
#define TIM3_CCMR1_OC1PE_Msk              (0x8UL)                   /*!< OC1PE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR1_OC1M_Pos               (4UL)                     /*!< OC1M (Bit 4)                                          */
#define TIM3_CCMR1_OC1M_Msk               (0x70UL)                  /*!< OC1M (Bitfield-Mask: 0x07)                            */
#define TIM3_CCMR1_CC2S_Pos               (8UL)                     /*!< CC2S (Bit 8)                                          */
#define TIM3_CCMR1_CC2S_Msk               (0x300UL)                 /*!< CC2S (Bitfield-Mask: 0x03)                            */
#define TIM3_CCMR1_OC2FE_Pos              (10UL)                    /*!< OC2FE (Bit 10)                                        */
#define TIM3_CCMR1_OC2FE_Msk              (0x400UL)                 /*!< OC2FE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR1_OC2PE_Pos              (11UL)                    /*!< OC2PE (Bit 11)                                        */
#define TIM3_CCMR1_OC2PE_Msk              (0x800UL)                 /*!< OC2PE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR1_OC2M_Pos               (12UL)                    /*!< OC2M (Bit 12)                                         */
#define TIM3_CCMR1_OC2M_Msk               (0x7000UL)                /*!< OC2M (Bitfield-Mask: 0x07)                            */
/* =========================================================  CCMR2  ========================================================= */
#define TIM3_CCMR2_CC3S_Pos               (0UL)                     /*!< CC3S (Bit 0)                                          */
#define TIM3_CCMR2_CC3S_Msk               (0x3UL)                   /*!< CC3S (Bitfield-Mask: 0x03)                            */
#define TIM3_CCMR2_OC3FE_Pos              (2UL)                     /*!< OC3FE (Bit 2)                                         */
#define TIM3_CCMR2_OC3FE_Msk              (0x4UL)                   /*!< OC3FE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR2_OC3PE_Pos              (3UL)                     /*!< OC3PE (Bit 3)                                         */
#define TIM3_CCMR2_OC3PE_Msk              (0x8UL)                   /*!< OC3PE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR2_OC3M_Pos               (4UL)                     /*!< OC3M (Bit 4)                                          */
#define TIM3_CCMR2_OC3M_Msk               (0x70UL)                  /*!< OC3M (Bitfield-Mask: 0x07)                            */
#define TIM3_CCMR2_CC4S_Pos               (8UL)                     /*!< CC4S (Bit 8)                                          */
#define TIM3_CCMR2_CC4S_Msk               (0x300UL)                 /*!< CC4S (Bitfield-Mask: 0x03)                            */
#define TIM3_CCMR2_OC4FE_Pos              (10UL)                    /*!< OC4FE (Bit 10)                                        */
#define TIM3_CCMR2_OC4FE_Msk              (0x400UL)                 /*!< OC4FE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR2_OC4PE_Pos              (11UL)                    /*!< OC4PE (Bit 11)                                        */
#define TIM3_CCMR2_OC4PE_Msk              (0x800UL)                 /*!< OC4PE (Bitfield-Mask: 0x01)                           */
#define TIM3_CCMR2_OC4M_Pos               (12UL)                    /*!< OC4M (Bit 12)                                         */
#define TIM3_CCMR2_OC4M_Msk               (0x7000UL)                /*!< OC4M (Bitfield-Mask: 0x07)                            */
/* =========================================================  CCER  ========================================================== */
#define TIM3_CCER_CC1E_Pos                (0UL)                     /*!< CC1E (Bit 0)                                          */
#define TIM3_CCER_CC1E_Msk                (0x1UL)                   /*!< CC1E (Bitfield-Mask: 0x01)                            */
#define TIM3_CCER_CC1P_Pos                (1UL)                     /*!< CC1P (Bit 1)                                          */
#define TIM3_CCER_CC1P_Msk                (0x2UL)                   /*!< CC1P (Bitfield-Mask: 0x01)                            */
#define TIM3_CCER_CC1NP_Pos               (3UL)                     /*!< CC1NP (Bit 3)                                         */
#define TIM3_CCER_CC1NP_Msk               (0x8UL)                   /*!< CC1NP (Bitfield-Mask: 0x01)                           */
#define TIM3_CCER_CC2E_Pos                (4UL)                     /*!< CC2E (Bit 4)                                          */
#define TIM3_CCER_CC2E_Msk                (0x10UL)                  /*!< CC2E (Bitfield-Mask: 0x01)                            */
#define TIM3_CCER_CC2P_Pos                (5UL)                     /*!< CC2P (Bit 5)                                          */
#define TIM3_CCER_CC2P_Msk                (0x20UL)                  /*!< CC2P (Bitfield-Mask: 0x01)                            */
#define TIM3_CCER_CC2NP_Pos               (7UL)                     /*!< CC2NP (Bit 7)                                         */
#define TIM3_CCER_CC2NP_Msk               (0x80UL)                  /*!< CC2NP (Bitfield-Mask: 0x01)                           */
#define TIM3_CCER_CC3E_Pos                (8UL)                     /*!< CC3E (Bit 8)                                          */
#define TIM3_CCER_CC3E_Msk                (0x100UL)                 /*!< CC3E (Bitfield-Mask: 0x01)                            */
#define TIM3_CCER_CC3P_Pos                (9UL)                     /*!< CC3P (Bit 9)                                          */
#define TIM3_CCER_CC3P_Msk                (0x200UL)                 /*!< CC3P (Bitfield-Mask: 0x01)                            */
#define TIM3_CCER_CC3NP_Pos               (11UL)                    /*!< CC3NP (Bit 11)                                        */
#define TIM3_CCER_CC3NP_Msk               (0x800UL)                 /*!< CC3NP (Bitfield-Mask: 0x01)                           */
#define TIM3_CCER_CC4E_Pos                (12UL)                    /*!< CC4E (Bit 12)                                         */
#define TIM3_CCER_CC4E_Msk                (0x1000UL)                /*!< CC4E (Bitfield-Mask: 0x01)                            */
#define TIM3_CCER_CC4P_Pos                (15UL)                    /*!< CC4P (Bit 15)                                         */
#define TIM3_CCER_CC4P_Msk                (0x8000UL)                /*!< CC4P (Bitfield-Mask: 0x01)                            */
/* ==========================================================  CNT  ========================================================== */
#define TIM3_CNT_CNT_Pos                  (0UL)                     /*!< CNT (Bit 0)                                           */
#define TIM3_CNT_CNT_Msk                  (0xffffUL)                /*!< CNT (Bitfield-Mask: 0xffff)                           */
/* ==========================================================  PSC  ========================================================== */
#define TIM3_PSC_PSC_Pos                  (0UL)                     /*!< PSC (Bit 0)                                           */
#define TIM3_PSC_PSC_Msk                  (0xffffUL)                /*!< PSC (Bitfield-Mask: 0xffff)                           */
/* ==========================================================  ARR  ========================================================== */
#define TIM3_ARR_ARR_Pos                  (0UL)                     /*!< ARR (Bit 0)                                           */
#define TIM3_ARR_ARR_Msk                  (0xffffUL)                /*!< ARR (Bitfield-Mask: 0xffff)                           */
/* =========================================================  CCR1  ========================================================== */
#define TIM3_CCR1_CCR1_Pos                (0UL)                     /*!< CCR1 (Bit 0)                                          */
#define TIM3_CCR1_CCR1_Msk                (0xffffUL)                /*!< CCR1 (Bitfield-Mask: 0xffff)                          */
/* =========================================================  CCR2  ========================================================== */
#define TIM3_CCR2_CCR2_Pos                (0UL)                     /*!< CCR2 (Bit 0)                                          */
#define TIM3_CCR2_CCR2_Msk                (0xffffUL)                /*!< CCR2 (Bitfield-Mask: 0xffff)                          */
/* =========================================================  CCR3  ========================================================== */
#define TIM3_CCR3_CCR3_Pos                (0UL)                     /*!< CCR3 (Bit 0)                                          */
#define TIM3_CCR3_CCR3_Msk                (0xffffUL)                /*!< CCR3 (Bitfield-Mask: 0xffff)                          */
/* =========================================================  CCR4  ========================================================== */
#define TIM3_CCR4_CCR4_Pos                (0UL)                     /*!< CCR4 (Bit 0)                                          */
#define TIM3_CCR4_CCR4_Msk                (0xffffUL)                /*!< CCR4 (Bitfield-Mask: 0xffff)                          */
/* ==========================================================  OR  =========================================================== */
#define TIM3_OR_ETR_RMP_Pos               (0UL)                     /*!< ETR_RMP (Bit 0)                                       */
#define TIM3_OR_ETR_RMP_Msk               (0x3UL)                   /*!< ETR_RMP (Bitfield-Mask: 0x03)                         */

第三:SVDConv.exe  MM32G0001.svd --generate=header --fields=macro --fields=struct,这种方式在第二种的基础上,添加了寄存器结构体定义时的具体化,在把寄存器都定义出来的同时,把每一个寄存器的位域都做了共用体,这样在编写代码时方便了不少!
typedef struct {                                /*!< (@ 0x40000400) TIM3 Structure                                             */
  
  union {
    __IOM uint32_t CR1;                         /*!< (@ 0x00000000) Control Register 1                                         */
   
    struct {
      __IOM uint32_t CEN        : 1;            /*!< [0..0] Counter enable                                                     */
      __IOM uint32_t UDIS       : 1;            /*!< [1..1] Update disable                                                     */
      __IOM uint32_t URS        : 1;            /*!< [2..2] Update request source                                              */
      __IOM uint32_t OPM        : 1;            /*!< [3..3] one-pulse mode                                                     */
      __IOM uint32_t DIR        : 1;            /*!< [4..4] Count direction                                                    */
      __IOM uint32_t CMS        : 2;            /*!< [6..5] Center alignment mode selection                                    */
      __IOM uint32_t ARPE       : 1;            /*!< [7..7] Auto reload preload enable                                         */
      __IOM uint32_t CKD        : 2;            /*!< [9..8] Clock division                                                     */
            uint32_t            : 22;
    } CR1_b;
  } ;
  
  union {
    __IOM uint32_t CR2;                         /*!< (@ 0x00000004) Control Register 2                                         */
   
    struct {
            uint32_t            : 4;
      __IOM uint32_t MMS        : 3;            /*!< [6..4] Master mode selection                                              */
      __IOM uint32_t TI1S       : 1;            /*!< [7..7] TI1 selection                                                      */
            uint32_t            : 24;
    } CR2_b;
  } ;
  
  union {
    __IOM uint32_t SMCR;                        /*!< (@ 0x00000008) Slave Mode Control Register                                */
   
    struct {
      __IOM uint32_t SMS        : 3;            /*!< [2..0] Slave mode selection                                               */
            uint32_t            : 1;
      __IOM uint32_t TS         : 3;            /*!< [6..4] Trigger selection                                                  */
      __IOM uint32_t MSM        : 1;            /*!< [7..7] Master/slave mode                                                  */
            uint32_t            : 24;
    } SMCR_b;
  } ;
  
  union {
    __IOM uint32_t DIER;                        /*!< (@ 0x0000000C) Interrupt Enable Register                                  */
   
    struct {
      __IOM uint32_t UIE        : 1;            /*!< [0..0] Update interrupt enable                                            */
      __IOM uint32_t CC1IE      : 1;            /*!< [1..1] Compare 1 interrupt enable                                         */
      __IOM uint32_t CC2IE      : 1;            /*!< [2..2] Compare 2 interrupt enable                                         */
      __IOM uint32_t CC3IE      : 1;            /*!< [3..3] Compare 3 interrupt enable                                         */
      __IOM uint32_t CC4IE      : 1;            /*!< [4..4] Compare 4 interrupt enable                                         */
            uint32_t            : 1;
      __IOM uint32_t TIE        : 1;            /*!< [6..6] Trigger interrupt enable                                           */
            uint32_t            : 25;
    } DIER_b;
  } ;
  
  union {
    __IOM uint32_t SR;                          /*!< (@ 0x00000010) Status Register                                            */
   
    struct {
      __IOM uint32_t UIF        : 1;            /*!< [0..0] Update interrupt flag                                              */
      __IOM uint32_t CC1IF      : 1;            /*!< [1..1] Compare 1 interrupt flag                                           */
      __IOM uint32_t CC2IF      : 1;            /*!< [2..2] Compare 2 interrupt flag                                           */
      __IOM uint32_t CC3IF      : 1;            /*!< [3..3] Compare 3 interrupt flag                                           */
      __IOM uint32_t CC4IF      : 1;            /*!< [4..4] Compare 4 interrupt flag                                           */
            uint32_t            : 1;
      __IOM uint32_t TIF        : 1;            /*!< [6..6] Trigger interrupt flag                                             */
            uint32_t            : 2;
      __IOM uint32_t CC1OF      : 1;            /*!< [9..9] Capture/Compare 1 overcapture flag                                 */
      __IOM uint32_t CC2OF      : 1;            /*!< [10..10] Capture/Compare 2 overcapture flag                               */
      __IOM uint32_t CC3OF      : 1;            /*!< [11..11] Capture/Compare 3 overcapture flag                               */
      __IOM uint32_t CC4OF      : 1;            /*!< [12..12] Capture/Compare 4 overcapture flag                               */
            uint32_t            : 19;
    } SR_b;
  } ;
  
  union {
    __OM  uint32_t EGR;                         /*!< (@ 0x00000014) Event Generation Register                                  */
   
    struct {
      __OM  uint32_t UG         : 1;            /*!< [0..0] Update generation                                                  */
      __OM  uint32_t CC1G       : 1;            /*!< [1..1] Compare 1 generation                                               */
      __OM  uint32_t CC2G       : 1;            /*!< [2..2] Compare 2 generation                                               */
      __OM  uint32_t CC3G       : 1;            /*!< [3..3] Compare 3 generation                                               */
      __OM  uint32_t CC4G       : 1;            /*!< [4..4] Compare 4 generation                                               */
            uint32_t            : 1;
      __OM  uint32_t TG         : 1;            /*!< [6..6] Trigger generation                                                 */
            uint32_t            : 25;
    } EGR_b;
  } ;
  
  union {
    __IOM uint32_t CCMR1;                       /*!< (@ 0x00000018) Compare Mode Register 1                                    */
   
    struct {
      __IOM uint32_t CC1S       : 2;            /*!< [1..0] Capture/Compare 1 selection                                        */
      __IOM uint32_t OC1FE      : 1;            /*!< [2..2] Output compare 1 fast enable                                       */
      __IOM uint32_t OC1PE      : 1;            /*!< [3..3] Output compare 1 preload enable                                    */
      __IOM uint32_t OC1M       : 3;            /*!< [6..4] Output compare 1 mode                                              */
            uint32_t            : 1;
      __IOM uint32_t CC2S       : 2;            /*!< [9..8] Capture/Compare 2 selection                                        */
      __IOM uint32_t OC2FE      : 1;            /*!< [10..10] Output compare 2 fast enable                                     */
      __IOM uint32_t OC2PE      : 1;            /*!< [11..11] Output compare 2 preload enable                                  */
      __IOM uint32_t OC2M       : 3;            /*!< [14..12] Output compare 2 mode                                            */
            uint32_t            : 17;
    } CCMR1_b;
  } ;
  
  union {
    __IOM uint32_t CCMR2;                       /*!< (@ 0x0000001C) Compare Mode Register 2                                    */
   
    struct {
      __IOM uint32_t CC3S       : 2;            /*!< [1..0] Capture/Compare 3 selection                                        */
      __IOM uint32_t OC3FE      : 1;            /*!< [2..2] Output compare 3 fast enable                                       */
      __IOM uint32_t OC3PE      : 1;            /*!< [3..3] Output compare 3 preload enable                                    */
      __IOM uint32_t OC3M       : 3;            /*!< [6..4] Output compare 3 mode                                              */
            uint32_t            : 1;
      __IOM uint32_t CC4S       : 2;            /*!< [9..8] Capture/Compare 4 selection                                        */
      __IOM uint32_t OC4FE      : 1;            /*!< [10..10] Output compare 4 fast enable                                     */
      __IOM uint32_t OC4PE      : 1;            /*!< [11..11] Output compare 4 preload enable                                  */
      __IOM uint32_t OC4M       : 3;            /*!< [14..12] Output compare 4 mode                                            */
            uint32_t            : 17;
    } CCMR2_b;
  } ;
  
  union {
    __IOM uint32_t CCER;                        /*!< (@ 0x00000020) Compare Enable Register                                    */
   
    struct {
      __IOM uint32_t CC1E       : 1;            /*!< [0..0] Compare 1 output enable                                            */
      __IOM uint32_t CC1P       : 1;            /*!< [1..1] Compare 1 output polarity                                          */
            uint32_t            : 1;
      __IOM uint32_t CC1NP      : 1;            /*!< [3..3] Compare 1 complementary output polarity                            */
      __IOM uint32_t CC2E       : 1;            /*!< [4..4] Compare 2 output enable                                            */
      __IOM uint32_t CC2P       : 1;            /*!< [5..5] Compare 2 output polarity                                          */
            uint32_t            : 1;
      __IOM uint32_t CC2NP      : 1;            /*!< [7..7] Compare 2 complementary output polarity                            */
      __IOM uint32_t CC3E       : 1;            /*!< [8..8] Compare 3 output enable                                            */
      __IOM uint32_t CC3P       : 1;            /*!< [9..9] Compare 3 output polarity                                          */
            uint32_t            : 1;
      __IOM uint32_t CC3NP      : 1;            /*!< [11..11] Compare 3 complementary output polarity                          */
      __IOM uint32_t CC4E       : 1;            /*!< [12..12] Compare 4 output enable                                          */
            uint32_t            : 2;
      __IOM uint32_t CC4P       : 1;            /*!< [15..15] Compare 4 complementary output polarity                          */
            uint32_t            : 16;
    } CCER_b;
  } ;
  
  union {
    __IOM uint32_t CNT;                         /*!< (@ 0x00000024) Counter                                                    */
   
    struct {
      __IOM uint32_t CNT        : 16;           /*!< [15..0] Counter value                                                     */
            uint32_t            : 16;
    } CNT_b;
  } ;
  
  union {
    __IOM uint32_t PSC;                         /*!< (@ 0x00000028) Prescaler                                                  */
   
    struct {
      __IOM uint32_t PSC        : 16;           /*!< [15..0] Prescaler value                                                   */
            uint32_t            : 16;
    } PSC_b;
  } ;
  
  union {
    __IOM uint32_t ARR;                         /*!< (@ 0x0000002C) Auto Reload Register                                       */
   
    struct {
      __IOM uint32_t ARR        : 16;           /*!< [15..0] Auto-reload value                                                 */
            uint32_t            : 16;
    } ARR_b;
  } ;
  __IM  uint32_t  RESERVED;
  
  union {
    __IOM uint32_t CCR1;                        /*!< (@ 0x00000034) Compare Register 1                                         */
   
    struct {
      __IOM uint32_t CCR1       : 16;           /*!< [15..0] Channel 1 compare value                                           */
            uint32_t            : 16;
    } CCR1_b;
  } ;
  
  union {
    __IOM uint32_t CCR2;                        /*!< (@ 0x00000038) Compare Register 2                                         */
   
    struct {
      __IOM uint32_t CCR2       : 16;           /*!< [15..0] Channel 2 compare value                                           */
            uint32_t            : 16;
    } CCR2_b;
  } ;
  
  union {
    __IOM uint32_t CCR3;                        /*!< (@ 0x0000003C) Compare Register 3                                         */
   
    struct {
      __IOM uint32_t CCR3       : 16;           /*!< [15..0] Channel 3 compare value                                           */
            uint32_t            : 16;
    } CCR3_b;
  } ;
  
  union {
    __IOM uint32_t CCR4;                        /*!< (@ 0x00000040) Compare Register 4                                         */
   
    struct {
      __IOM uint32_t CCR4       : 16;           /*!< [15..0] Channel 4 compare value                                           */
            uint32_t            : 16;
    } CCR4_b;
  } ;
  __IM  uint32_t  RESERVED1[3];
  
  union {
    __IOM uint32_t OR;                          /*!< (@ 0x00000050) Input Option Register                                      */
   
    struct {
      __IOM uint32_t ETR_RMP    : 2;            /*!< [1..0] ETR multiplex                                                      */
            uint32_t            : 30;
    } OR_b;
  } ;
} TIM3_Type;                                    /*!< Size = 84 (0x54)                                                          */

我也是比较喜欢第三种生成方式,比较详细!!!

3.下载算法
下载算法可以让Keil MDK-Arm集成开发环境在线下载程序到芯片中,他的实现是通过将下载算法函数加载到SRAM中运行,通过SRAM将数据写入到芯片FLASH当中,具体的技术文档可以参考:https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/flashAlgorithm.html

我们可以在“C:\Keil_v5\ARM\Flash\_Template”中,或者在CMSIS中“C:\Users\xld0932\AppData\Local\Arm\Packs\ARM\CMSIS\5.9.0\Device\_Template_Flash”获取下载算法的模板工程,下载算法中提供了一些函数接口,有必要实现的,也有可选实现的:
6.png

我们完善必要实现的函数功能就可以了,在实现函数功能时,我们需要注意一下芯片看门狗,如果看门狗在打开的状态下,芯片烧录时间超过了喂狗时间,会导致芯片下载中断而失败,所以需要在下载算法中耗时的位置添加喂狗操作!最后就是通过SVD生成的头文件中的寄存器和宏定义,在FlashPrg.c文件中来实现函数功能,具体函数实现如下所示:
#include "FlashOS.h"                   // FlashOS Structures
#include <stdint.h>

#define M8(adr)  (*((volatile unsigned char  *)(adr)))
#define M16(adr) (*((volatile unsigned short *)(adr)))
#define M32(adr) (*((volatile unsigned long  *)(adr)))

/* following defines should be used for structure members */
#define     __IM     volatile const    /*! Defines 'read only' structure member permissions */
#define     __OM     volatile          /*! Defines 'write only' structure member permissions */
#define     __IOM    volatile          /*! Defines 'read / write' structure member permissions */

/* =========================================================================================================================== */
/* ================                                           IWDG                                            ================ */
/* =========================================================================================================================== */

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url] IWDG Independent watchdog (IWDG)
  */

typedef struct                         /*!< (@ 0x40003000) IWDG Structure                                             */
{
    __OM  uint32_t  KR;                /*!< (@ 0x00000000) Key register                                               */
    __IOM uint32_t  PR;                /*!< (@ 0x00000004) Prescaler register                                         */
    __IOM uint32_t  RLR;               /*!< (@ 0x00000008) Reload register                                            */
    __IM  uint32_t  SR;                /*!< (@ 0x0000000C) Status register                                            */
    __IOM uint32_t  CR;                /*!< (@ 0x00000010) Control register                                           */
    __IOM uint32_t  IGEN;              /*!< (@ 0x00000014) Interrupt generate register                                */
    __IM  uint32_t  CNT;               /*!< (@ 0x00000018) Counter register                                           */
} IWDG_Type;

/* =========================================================================================================================== */
/* ================                                           FLASH                                           ================ */
/* =========================================================================================================================== */

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url] Embedded Flash (FLASH)
  */

typedef struct                         /*!< (@ 0x40022000) FLASH Structure                                            */
{
    __IOM uint32_t  ACR;               /*!< (@ 0x00000000) Flash access control register                              */
    __OM  uint32_t  KEYR;              /*!< (@ 0x00000004) Flash key register                                         */
    __OM  uint32_t  OPTKEYR;           /*!< (@ 0x00000008) Flash OPTKEY register                                      */
    __IOM uint32_t  SR;                /*!< (@ 0x0000000C) Flash status register                                      */
    __IOM uint32_t  CR;                /*!< (@ 0x00000010) Flash control register                                     */
    __OM  uint32_t  AR;                /*!< (@ 0x00000014) Flash address register                                     */
    __IM  uint32_t  RESERVED;
    __IM  uint32_t  OBR;               /*!< (@ 0x0000001C) Option byte register                                       */
    __IM  uint32_t  WRPR;              /*!< (@ 0x00000020) Write protection register                                  */
} FLASH_Type;

#define IWDG_BASE                         0x40003000UL
#define FLASH_BASE                        0x40022000UL

#define IWDG                              ((IWDG_Type *)IWDG_BASE)
#define FLASH                             ((FLASH_Type *)FLASH_BASE)

/* =========================================================================================================================== */
/* ================                                           IWDG                                            ================ */
/* =========================================================================================================================== */

/* ==========================================================  KR  =========================================================== */
#define IWDG_KR_KEY_Pos                   (0UL)       /*!< KEY (Bit 0)                                           */
#define IWDG_KR_KEY_Msk                   (0xffffUL)  /*!< KEY (Bitfield-Mask: 0xffff)                           */
/* ==========================================================  PR  =========================================================== */
#define IWDG_PR_PR_Pos                    (0UL)       /*!< PR (Bit 0)                                            */
#define IWDG_PR_PR_Msk                    (0x7UL)     /*!< PR (Bitfield-Mask: 0x07)                              */
/* ==========================================================  RLR  ========================================================== */
#define IWDG_RLR_RL_Pos                   (0UL)       /*!< RL (Bit 0)                                            */
#define IWDG_RLR_RL_Msk                   (0xfffUL)   /*!< RL (Bitfield-Mask: 0xfff)                             */
/* ==========================================================  SR  =========================================================== */
#define IWDG_SR_PVU_Pos                   (0UL)       /*!< PVU (Bit 0)                                           */
#define IWDG_SR_PVU_Msk                   (0x1UL)     /*!< PVU (Bitfield-Mask: 0x01)                             */
#define IWDG_SR_RVU_Pos                   (1UL)       /*!< RVU (Bit 1)                                           */
#define IWDG_SR_RVU_Msk                   (0x2UL)     /*!< RVU (Bitfield-Mask: 0x01)                             */
#define IWDG_SR_IVU_Pos                   (2UL)       /*!< IVU (Bit 2)                                           */
#define IWDG_SR_IVU_Msk                   (0x4UL)     /*!< IVU (Bitfield-Mask: 0x01)                             */
#define IWDG_SR_UPDATE_Pos                (3UL)       /*!< UPDATE (Bit 3)                                        */
#define IWDG_SR_UPDATE_Msk                (0x8UL)     /*!< UPDATE (Bitfield-Mask: 0x01)                          */
/* ==========================================================  CR  =========================================================== */
#define IWDG_CR_IRQ_SEL_Pos               (0UL)       /*!< IRQ_SEL (Bit 0)                                       */
#define IWDG_CR_IRQ_SEL_Msk               (0x1UL)     /*!< IRQ_SEL (Bitfield-Mask: 0x01)                         */
#define IWDG_CR_IRQ_CLR_Pos               (1UL)       /*!< IRQ_CLR (Bit 1)                                       */
#define IWDG_CR_IRQ_CLR_Msk               (0x2UL)     /*!< IRQ_CLR (Bitfield-Mask: 0x01)                         */
/* =========================================================  IGEN  ========================================================== */
#define IWDG_IGEN_IGEN_Pos                (0UL)       /*!< IGEN (Bit 0)                                          */
#define IWDG_IGEN_IGEN_Msk                (0xfffUL)   /*!< IGEN (Bitfield-Mask: 0xfff)                           */
/* ==========================================================  CNT  ========================================================== */
#define IWDG_CNT_IWDG_PS_Pos              (0UL)       /*!< IWDG_PS (Bit 0)                                       */
#define IWDG_CNT_IWDG_PS_Msk              (0xffUL)    /*!< IWDG_PS (Bitfield-Mask: 0xff)                         */
#define IWDG_CNT_IWDG_CNT_Pos             (8UL)       /*!< IWDG_CNT (Bit 8)                                      */
#define IWDG_CNT_IWDG_CNT_Msk             (0x7ff00UL) /*!< IWDG_CNT (Bitfield-Mask: 0x7ff)                       */

/* =========================================================================================================================== */
/* ================                                           FLASH                                           ================ */
/* =========================================================================================================================== */

/* ==========================================================  ACR  ========================================================== */
#define FLASH_ACR_LATENCY_Pos             (0UL)          /*!< LATENCY (Bit 0)                                       */
#define FLASH_ACR_LATENCY_Msk             (0x7UL)        /*!< LATENCY (Bitfield-Mask: 0x07)                         */
#define FLASH_ACR_PRFTBE_Pos              (4UL)          /*!< PRFTBE (Bit 4)                                        */
#define FLASH_ACR_PRFTBE_Msk              (0x10UL)       /*!< PRFTBE (Bitfield-Mask: 0x01)                          */
/* =========================================================  KEYR  ========================================================== */
#define FLASH_KEYR_FKEYR_Pos              (0UL)          /*!< FKEYR (Bit 0)                                         */
#define FLASH_KEYR_FKEYR_Msk              (0xffffffffUL) /*!< FKEYR (Bitfield-Mask: 0xffffffff)                     */
/* ========================================================  OPTKEYR  ======================================================== */
#define FLASH_OPTKEYR_OPTKEYR_Pos         (0UL)          /*!< OPTKEYR (Bit 0)                                       */
#define FLASH_OPTKEYR_OPTKEYR_Msk         (0xffffffffUL) /*!< OPTKEYR (Bitfield-Mask: 0xffffffff)                   */
/* ==========================================================  SR  =========================================================== */
#define FLASH_SR_BSY_Pos                  (0UL)          /*!< BSY (Bit 0)                                           */
#define FLASH_SR_BSY_Msk                  (0x1UL)        /*!< BSY (Bitfield-Mask: 0x01)                             */
#define FLASH_SR_PGERR_Pos                (2UL)          /*!< PGERR (Bit 2)                                         */
#define FLASH_SR_PGERR_Msk                (0x4UL)        /*!< PGERR (Bitfield-Mask: 0x01)                           */
#define FLASH_SR_WRPRTERR_Pos             (4UL)          /*!< WRPRTERR (Bit 4)                                      */
#define FLASH_SR_WRPRTERR_Msk             (0x10UL)       /*!< WRPRTERR (Bitfield-Mask: 0x01)                        */
#define FLASH_SR_EOP_Pos                  (5UL)          /*!< EOP (Bit 5)                                           */
#define FLASH_SR_EOP_Msk                  (0x20UL)       /*!< EOP (Bitfield-Mask: 0x01)                             */
/* ==========================================================  CR  =========================================================== */
#define FLASH_CR_PG_Pos                   (0UL)          /*!< PG (Bit 0)                                            */
#define FLASH_CR_PG_Msk                   (0x1UL)        /*!< PG (Bitfield-Mask: 0x01)                              */
#define FLASH_CR_PER_Pos                  (1UL)          /*!< PER (Bit 1)                                           */
#define FLASH_CR_PER_Msk                  (0x2UL)        /*!< PER (Bitfield-Mask: 0x01)                             */
#define FLASH_CR_MER_Pos                  (2UL)          /*!< MER (Bit 2)                                           */
#define FLASH_CR_MER_Msk                  (0x4UL)        /*!< MER (Bitfield-Mask: 0x01)                             */
#define FLASH_CR_OPTPG_Pos                (4UL)          /*!< OPTPG (Bit 4)                                         */
#define FLASH_CR_OPTPG_Msk                (0x10UL)       /*!< OPTPG (Bitfield-Mask: 0x01)                           */
#define FLASH_CR_OPTER_Pos                (5UL)          /*!< OPTER (Bit 5)                                         */
#define FLASH_CR_OPTER_Msk                (0x20UL)       /*!< OPTER (Bitfield-Mask: 0x01)                           */
#define FLASH_CR_STRT_Pos                 (6UL)          /*!< STRT (Bit 6)                                          */
#define FLASH_CR_STRT_Msk                 (0x40UL)       /*!< STRT (Bitfield-Mask: 0x01)                            */
#define FLASH_CR_LOCK_Pos                 (7UL)          /*!< LOCK (Bit 7)                                          */
#define FLASH_CR_LOCK_Msk                 (0x80UL)       /*!< LOCK (Bitfield-Mask: 0x01)                            */
#define FLASH_CR_OPTWRE_Pos               (9UL)          /*!< OPTWRE (Bit 9)                                        */
#define FLASH_CR_OPTWRE_Msk               (0x200UL)      /*!< OPTWRE (Bitfield-Mask: 0x01)                          */
#define FLASH_CR_ERRIE_Pos                (10UL)         /*!< ERRIE (Bit 10)                                        */
#define FLASH_CR_ERRIE_Msk                (0x400UL)      /*!< ERRIE (Bitfield-Mask: 0x01)                           */
#define FLASH_CR_EOPIE_Pos                (12UL)         /*!< EOPIE (Bit 12)                                        */
#define FLASH_CR_EOPIE_Msk                (0x1000UL)     /*!< EOPIE (Bitfield-Mask: 0x01)                           */
/* ==========================================================  AR  =========================================================== */
#define FLASH_AR_FAR_Pos                  (0UL)          /*!< FAR (Bit 0)                                           */
#define FLASH_AR_FAR_Msk                  (0xffffffffUL) /*!< FAR (Bitfield-Mask: 0xffffffff)                       */
/* ==========================================================  OBR  ========================================================== */
#define FLASH_OBR_OPTERR_Pos              (0UL)          /*!< OPTERR (Bit 0)                                        */
#define FLASH_OBR_OPTERR_Msk              (0x1UL)        /*!< OPTERR (Bitfield-Mask: 0x01)                          */
#define FLASH_OBR_RDPRT_Pos               (1UL)          /*!< RDPRT (Bit 1)                                         */
#define FLASH_OBR_RDPRT_Msk               (0x2UL)        /*!< RDPRT (Bitfield-Mask: 0x01)                           */
#define FLASH_OBR_WDG_SW_Pos              (2UL)          /*!< WDG_SW (Bit 2)                                        */
#define FLASH_OBR_WDG_SW_Msk              (0x4UL)        /*!< WDG_SW (Bitfield-Mask: 0x01)                          */
#define FLASH_OBR_nRST_STOP_Pos           (3UL)          /*!< nRST_STOP (Bit 3)                                     */
#define FLASH_OBR_nRST_STOP_Msk           (0x8UL)        /*!< nRST_STOP (Bitfield-Mask: 0x01)                       */
#define FLASH_OBR_Data0_Pos               (10UL)         /*!< Data0 (Bit 10)                                        */
#define FLASH_OBR_Data0_Msk               (0x3fc00UL)    /*!< Data0 (Bitfield-Mask: 0xff)                           */
#define FLASH_OBR_Data1_Pos               (18UL)         /*!< Data1 (Bit 18)                                        */
#define FLASH_OBR_Data1_Msk               (0xfc0000UL)   /*!< Data1 (Bitfield-Mask: 0x3f)                           */
/* =========================================================  WRPR  ========================================================== */
#define FLASH_WRPR_WRP_Pos                (0UL)          /*!< WRP (Bit 0)                                           */
#define FLASH_WRPR_WRP_Msk                (0xfUL)        /*!< WRP (Bitfield-Mask: 0x0f)                             */

/*
   Mandatory Flash Programming Functions (Called by FlashOS):
                int Init        (unsigned long adr,   // Initialize Flash
                                 unsigned long clk,
                                 unsigned long fnc);
                int UnInit      (unsigned long fnc);  // De-initialize Flash
                int EraseSector (unsigned long adr);  // Erase Sector Function
                int ProgramPage (unsigned long adr,   // Program Page Function
                                 unsigned long sz,
                                 unsigned char *buf);

   Optional  Flash Programming Functions (Called by FlashOS):
                int BlankCheck  (unsigned long adr,   // Blank Check
                                 unsigned long sz,
                                 unsigned char pat);
                int EraseChip   (void);               // Erase complete Device
      unsigned long Verify      (unsigned long adr,   // Verify Function
                                 unsigned long sz,
                                 unsigned char *buf);

       - BlanckCheck  is necessary if Flash space is not mapped into CPU memory space
       - Verify       is necessary if Flash space is not mapped into CPU memory space
       - if EraseChip is not provided than EraseSector for all sectors is called
*/

/*
*  Initialize Flash Programming Functions
*    Parameter:      adr:  Device Base Address
*                    clk:  Clock Frequency (Hz)
*                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
*    Return Value:   0 - OK,  1 - Failed
*/
int Init(unsigned long adr, unsigned long clk, unsigned long fnc)
{
    /* Add your Code */
    FLASH->ACR  = 0x00000000;           // Zero Wait State

    FLASH->KEYR = 0x45670123;           // Unlock Flash
    FLASH->KEYR = 0xCDEF89AB;

    // Test if IWDG is running (IWDG in HW mode)
    if ((FLASH->OBR & FLASH_OBR_WDG_SW_Msk) == 0)
    {
        IWDG->KR  = 0x5555;            // Enable write access to IWDG_PR and IWDG_RLR
        IWDG->PR  = 0x06;              // Set prescaler to 256
        IWDG->RLR = 4095;              // Set reload value to 4095
    }

    return (0);                        // Finished without Errors
}

/*
*  De-Initialize Flash Programming Functions
*    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
*    Return Value:   0 - OK,  1 - Failed
*/
int UnInit(unsigned long fnc)
{
    /* Add your Code */
    FLASH->CR |= FLASH_CR_LOCK_Msk;    // Lock Flash
    return (0);                        // Finished without Errors
}

/*
*  Erase complete Flash Memory
*    Return Value:   0 - OK,  1 - Failed
*/
int EraseChip(void)
{
    /* Add your Code */
    FLASH->CR |= FLASH_CR_MER_Msk;     // Mass Erase Enable
    FLASH->CR |= FLASH_CR_STRT_Msk;    // Start Erase

    while (FLASH->SR & FLASH_SR_BSY_Msk)
    {
        IWDG->KR = 0xAAAA;             // Reload IWDG
    }

    FLASH->CR &= ~FLASH_CR_MER_Msk;    // Mass Erase Disable

    return (0);                        // Finished without Errors
}

/*
*  Erase Sector in Flash Memory
*    Parameter:      adr:  Sector Address
*    Return Value:   0 - OK,  1 - Failed
*/
int EraseSector(unsigned long adr)
{
    /* Add your Code */
    FLASH->CR |= FLASH_CR_PER_Msk;     // Page Erase Enable
    FLASH->AR  = adr;                  // Page Address
    FLASH->CR |= FLASH_CR_STRT_Msk;    // Start Erase

    while (FLASH->SR & FLASH_SR_BSY_Msk)
    {
        IWDG->KR = 0xAAAA;             // Reload IWDG
    }

    FLASH->CR &= ~FLASH_CR_PER_Msk;    // Page Erase Disable

    return (0);                        // Finished without Errors
}

/*
*  Program Page in Flash Memory
*    Parameter:      adr:  Page Start Address
*                    sz:   Page Size
*                    buf:  Page Data
*    Return Value:   0 - OK,  1 - Failed
*/
int ProgramPage(unsigned long adr, unsigned long sz, unsigned char *buf)
{
    /* Add your Code */
    sz = (sz + 1) & ~1;                         // Adjust size for Half Words

    while (sz)
    {
        FLASH->CR |= FLASH_CR_PG_Msk;           // Programming Enable

        M16(adr) = *((unsigned short *)buf);    // Program Half Word

        while (FLASH->SR & FLASH_SR_BSY_Msk)
        {
            IWDG->KR = 0xAAAA;                  // Reload IWDG
        }

        FLASH->CR &= ~FLASH_CR_PG_Msk;          // Programming Disable

        if (FLASH->SR & (FLASH_SR_PGERR_Msk | FLASH_SR_WRPRTERR_Msk))
        {
            FLASH->SR |= FLASH_SR_PGERR_Msk | FLASH_SR_WRPRTERR_Msk;
            return (1);                         // Failed
        }

        // Go to next Half Word
        adr += 2;
        buf += 2;
        sz  -= 2;
    }

    return (0);                                 // Finished without Errors
}

此外就是下载算法的配置,在FlashDevice中,如下所示:
#include "FlashOS.h"        // FlashOS Structures


struct FlashDevice const FlashDevice  =  {
   FLASH_DRV_VERS,             // Driver Version, do not modify!
   "MM32G0001 16kB Flash",     // Device Name
   ONCHIP,                     // Device Type
   0x08000000,                 // Device Start Address
   0x00004000,                 // Device Size in Bytes (16kB)
   1024,                       // Programming Page Size
   0,                          // Reserved, must be 0
   0xFF,                       // Initial Content of Erased Memory
   100,                        // Program Page Timeout 100 mSec
   3000,                       // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
   0x000400, 0x000000,         // Sector Size  1kB (n Sectors)
   SECTOR_END
};

其中定义了Device Name,这个是在Keil中选择下载算法时所显示的,其实需要配置的就是Device Start Address,这个是MCU Flash的起始地址;Device Size是MCU FLASH的容量,Programming Page Size定义了MCU FLASH写入Page的大小,最后就是Specify Size and Address of Sectors的设置。
8.png

在完成上述函数和配置修改之后,需要在工程的配置中,Output选项卡中,修改一下生成下载算法的文件名,如下所示:
7.png

最后编译整个工程,生成FLM下载算法文件。

4.Keil Pack
Keil Pack是帮助我们让Keil MDK-Arm集成开发环境认识我们MCU的一个支持包,这支持包里包含了SVD、下载算法、以及一个pdsc描述文件,这是最基础的Pack包组成部分,可以参考如下链接:https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/index.html熟悉更多的Pack包配置

在pdsc文件中,除了对MCU一些描述外,对指定SVD文件、FLM下载算法也做了描述,另外可以根据芯片数据手册中提供的Part number芯片型号,添加到pdsc描述中,这样我们在创建Keil工程的时候就可以选择相应的芯片型号了。

对于Keil Pack的pdsc文件,我们也是采用了自动生成的方式,一个数据源,二是Python自动化生成;

4.1.构建pdsc数据源
pdsc的数据源一方面是cpu.yml文件中提取的,包含了处理器、调试SVD、下载算法和整体芯片描述部分,另一文件就是参考芯片数据手册中的2.1订购表,在device.yml中添加芯片型号和属性,如下所示:
cpu.yml:
Processor :
  Dcore               : 'Cortex-M0'
  DcoreVersion        : 'r0p0'
  Dfpu                : '0'
  Dmpu                : '0'
  Dendian             : 'Little-endian'
  Dclock              : '48000000'

Debug :
  SVD_PATH            : 'SVD/MM32G0001.svd'

Algorithm :
  FLM_PATH            : 'FLM/MM32G0001_16K.FLM'
  ROM_BASE            : '0x08000000'
  ROM_SIZE            : '0x4000'

description :
  description         : 'The MM32G0001 microcontrollers are based on Arm Cortex-M0 core. These devices
have a maximum clocked frequency of 48MHz, built-in 16KB Flash storage, and contain
an extensive range of peripherals and I/O ports. These devices contain 1x12-bit ADC,
1x16-bit advanced timer, 1x16-bit general purpose timer and 1x16-bit basic timer, as
well as communication interfaces including 2xUSART, 1xSPI and 1xI2C.
The operating voltage of this product series is 2.0V to 5.5V, and the operating temperature
range (ambient temperature) includes -40°C to 85°C industrial tier and -40°C to 105°C
extended industrial tier. Multiple sets of power-saving modes make the design of low-power
applications possible.'

device.yml:
MM32G0001A6T :
  RAM_BASE  : '0x20000000'
  RAM_SIZE  : '0x800'
  ROM_BASE  : '0x08000000'
  ROM_SIZE  : '0x4000'

MM32G0001A6T1 :
  RAM_BASE  : '0x20000000'
  RAM_SIZE  : '0x800'
  ROM_BASE  : '0x08000000'
  ROM_SIZE  : '0x4000'

MM32G0001A1T :
  RAM_BASE  : '0x20000000'
  RAM_SIZE  : '0x800'
  ROM_BASE  : '0x08000000'
  ROM_SIZE  : '0x4000'

MM32G0001A1N :
  RAM_BASE  : '0x20000000'
  RAM_SIZE  : '0x800'
  ROM_BASE  : '0x08000000'
  ROM_SIZE  : '0x4000'

4.2.Python自动化生成pdsc文件
pdsc也是通过XML语言来描述的,分了不同的层级,我们通过对数据源的提取完成pdsc文件的创建,具体功能函数如下所示:
def package_device(chip, pdsc_file):
    with open(fr'D:\PyCharm\{chip}\device.yml', mode='r') as device_file:
        device_data = yaml.safe_load(device_file)
        if device_data is None:
            print('device.yml is empty!')
        else:
            for device in device_data:
                pdsc_file.write(f'\t\t\t\t<device Dname=\"{device}\">\n')
                pdsc_file.write(f'\t\t\t\t\t<memory id=\"IRAM1\" '
                                f'start=\"{device_data[device]['RAM_BASE']}\" '
                                f'size=\"{device_data[device]['RAM_SIZE']}\" '
                                f'default=\"1\" init=\"0\"/>\n')
                pdsc_file.write(f'\t\t\t\t\t<memory id=\"IROM1\" '
                                f'start=\"{device_data[device]['ROM_BASE']}\" '
                                f'size=\"{device_data[device]['ROM_SIZE']}\" '
                                f'default=\"1\" startup=\"1\"/>\n')
                pdsc_file.write(f'\t\t\t\t</device>\n')



def package_family(chip, pdsc_file):
    with open(fr'D:\PyCharm\{chip}\cpu.yml', mode='r') as cpu_file:
        cpu_data = yaml.safe_load(cpu_file)
        if cpu_data is None:
            print('cpu.yml is empty!')
        else:
            pdsc_file.write(f'\t\t<family Dfamily=\"{chip} Series\" Dvendor=\"MindMotion:132\">\n')
            pdsc_file.write(f'\t\t\t<processor Dcore=\"{cpu_data['Processor']['Dcore']}\" '
                            f'DcoreVersion=\"{cpu_data['Processor']['DcoreVersion']}\"\n')
            pdsc_file.write(f'\t\t\t           Dfpu=\"{cpu_data['Processor']['Dfpu']}\" '
                            f'Dmpu=\"{cpu_data['Processor']['Dmpu']}\" '
                            f'Dclock=\"{cpu_data['Processor']['Dclock']}\"/>\n')
            pdsc_file.write(f'\t\t\t<debug     svd=\"{cpu_data['Debug']['SVD_PATH']}\"/>\n')
            pdsc_file.write(f'\t\t\t<algorithm name=\"{cpu_data['Algorithm']['FLM_PATH']}\" '
                            f'start=\"{cpu_data['Algorithm']['ROM_BASE']}\" '
                            f'size=\"{cpu_data['Algorithm']['ROM_SIZE']}\" default=\"1\"/>\n')
            pdsc_file.write(f'\t\t\t<description>\n')
            pdsc_file.write(f'\t\t\t\t{cpu_data['description']['description']}\n')
            pdsc_file.write(f'\t\t\t</description>\n')
            pdsc_file.write(f'\t\t\t<subFamily DsubFamily=\"{chip}\">\n')
            package_device(chip, pdsc_file)
            pdsc_file.write(f'\t\t\t</subFamily>\n')
            pdsc_file.write(f'\t\t</family>\n')


def package_devices(chip, pdsc_file):
    pdsc_file.write(f'\t<devices>\n')
    package_family(chip, pdsc_file)
    pdsc_file.write(f'\t</devices>\n')


def package_generate(chip, version):
    if not os.path.exists(fr'D:\PyCharm\{chip}\device.yml'):
        with open(fr'D:\PyCharm\{chip}\device.yml', mode='w') as device_file:
            print('create device.yml')
        device_file.close()

    pdsc_path = fr'MindMotion.{chip}_DFP.{version}'
    pdsc_name = fr'MindMotion.{chip}_DFP.{version}'

    if not os.path.exists(fr'D:\PyCharm\{chip}\{pdsc_path}'):
        os.mkdir(fr'D:\PyCharm\{chip}\{pdsc_path}')

    if not os.path.exists(fr'D:\PyCharm\{chip}\{pdsc_path}\FLM'):
        os.mkdir(fr'D:\PyCharm\{chip}\{pdsc_path}\FLM')

    if not os.path.exists(fr'D:\PyCharm\{chip}\{pdsc_path}\SVD'):
        os.mkdir(fr'D:\PyCharm\{chip}\{pdsc_path}\SVD')

    with (open(fr'D:\PyCharm\{chip}\{pdsc_path}\{pdsc_name}.pdsc', mode='w') as pdsc_file):
        pdsc_file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        pdsc_file.write('<package schemaVersion="1.7.7" '
                        'xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" '
                        'xs:noNamespaceSchemaLocation="PACK.xsd">\n')
        pdsc_file.write(f'\t<vendor>MindMotion</vendor>\n')
        pdsc_file.write(f'\t<name>{chip}_DFP</name>\n')
        pdsc_file.write(f'\t<description>MindMotion {chip} Series Keil Pack</description>\n')
        pdsc_file.write(f'\t<url>https://www.mindmotion.com.cn/</url>\n')
        pdsc_file.write(f'\t<releases>\n')
        pdsc_file.write(f'\t\t<release version=\"{version}\" date=\"{datetime.datetime.now().date()}\">\n')
        pdsc_file.write(f'\t\t</release>\n')
        pdsc_file.write(f'\t</releases>\n')
        package_devices(chip, pdsc_file)
        pdsc_file.write(f'</package>\n')
        pdsc_file.close()

4.3.生成pdsc文件
9.png

4.4.Keil Pack打包安装
在Python自动生成的目录结构中MindMotion.MM32G0001_DFP.0.0.1,我们将之前生成的SVD文件和FLM下载算法,添加到这个文件夹相应的目录下,然后将MindMotion.MM32G0001_DFP.0.0.1文件夹进行压缩:MindMotion.MM32G0001_DFP.0.0.1.zip,然后将zip后缀名修改为pack,就可以啦……然后我们双击这个Keil Pack支持包进行安装:
10.png 11.png

5.模板工程
一个工程的模板最主要的芯片头文件,我们已经通过SVD自动化生成了,接下来就是启动文件了;在CMSIS规范中“C:\Users\xld0932\AppData\Local\Arm\Packs\ARM\CMSIS\5.9.0\Device”包含了启动文件的示例范本,我们结合MM32G0001,来制作模板工程。因为MM32G0001芯片是基于Cortex-M0内核的,所以我们Copy刚刚目录下的ARM\ARMCM0中的所有文件夹及文件,其中Include文件夹中的ARMCM0.h就是芯片的头文件,我们使用刚刚生成的MM32G0001.h进行替换,然后将其它所有出现ARMCM0替换成MM32G0001。

接下来,我们基于官方的Mini-G0001开发板,来创建一个基础工程:
12.png

这边就是pdsc文件中描述的芯片型号和说明啦^^

因为我们本篇使用的是Keil MDK-Arm集成开发环境,在Source文件夹下包含了ARM、GCC、IAR这3个集成开发环境的启动文件,我们当前只操作ARM目录下的启动文件.s,在这个文件中,我们需要依据芯片用户手册中中断的描述,来完善中断向量表;需要将Source目录下的system_mm32g0001.c中完善System_Init函数,这个函数主要是实现系统时钟配置,这个我们可以后面再配置,当前可以使用芯片默认的时钟嘛……具体如下所示:
startup_mm32g0001.s
;/**************************************************************************//**
; * [url=home.php?mod=space&uid=288409]@file[/url]     startup_mm32g0001.s
; * [url=home.php?mod=space&uid=247401]@brief[/url]    CMSIS Core Device Startup File for
; *           MM32G0001 Device
; * [url=home.php?mod=space&uid=895143]@version[/url]  V1.0.1
; * [url=home.php?mod=space&uid=212281]@date[/url]     23. July 2019
; ******************************************************************************/
;/*
; * Copyright (c) 2009-2019 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Licensed under the Apache License, Version 2.0 (the License); you may
; * not use this file except in compliance with the License.
; * You may obtain a copy of the License at
; *
; * www.apache.org/licenses/LICENSE-2.0
; *
; * Unless required by applicable law or agreed to in writing, software
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; * See the License for the specific language governing permissions and
; * limitations under the License.
; */

;//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------


;<h> Stack Configuration
;  <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;</h>

Stack_Size      EQU      0x00000400

                AREA     STACK, NOINIT, READWRITE, ALIGN=3
__stack_limit
Stack_Mem       SPACE    Stack_Size
__initial_sp


;<h> Heap Configuration
;  <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;</h>

Heap_Size       EQU      0x00000000

                IF       Heap_Size != 0                      ; Heap is provided
                AREA     HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE    Heap_Size
__heap_limit
                ENDIF


                PRESERVE8
                THUMB


; Vector Table Mapped to Address 0 at Reset

                AREA     RESET, DATA, READONLY
                EXPORT   __Vectors
                EXPORT   __Vectors_End
                EXPORT   __Vectors_Size

__Vectors       DCD      __initial_sp                        ;     Top of Stack
                DCD      Reset_Handler                       ;     Reset Handler
                DCD      NMI_Handler                         ; -14 NMI Handler
                DCD      HardFault_Handler                   ; -13 Hard Fault Handler
                DCD      0                                   ;     Reserved
                DCD      0                                   ;     Reserved
                DCD      0                                   ;     Reserved
                DCD      0                                   ;     Reserved
                DCD      0                                   ;     Reserved
                DCD      0                                   ;     Reserved
                DCD      0                                   ;     Reserved
                DCD      SVC_Handler                         ;  -5 SVCall Handler
                DCD      0                                   ;     Reserved
                DCD      0                                   ;     Reserved
                DCD      PendSV_Handler                      ;  -2 PendSV Handler
                DCD      SysTick_Handler                     ;  -1 SysTick Handler

                ; Interrupts
                DCD      IWDG_Handler                        ;0  IWDG Interrupt
                DCD      PVD_Handler                         ;1  PVD Interrupt
                DCD      0                                   ;2  Reserved
                DCD      FLASH_Handler                       ;3  Flash Global Interrupt
                DCD      RCC_Handler                         ;4  RCC Global Interrupt
                DCD      EXTI0_1_Handler                     ;5  EXTI Line[1:0] Interrupt
                DCD      EXTI2_3_Handler                     ;6  EXTI Line[3:2] Interrupt
                DCD      EXTI4_15_Handler                    ;7  EXTI Line[15:4] Interrupt
                DCD      0                                   ;8  Reserved
                DCD      0                                   ;9  Reserved
                DCD      0                                   ;10 Reserved
                DCD      0                                   ;11 Reserved
                DCD      ADC1_Handler                        ;12 ADC Global Interrupt
                DCD      TIM1_BRK_UP_TRG_COM_Handler         ;13 TIM1 Break Update Trigger COM Interrupt
                DCD      TIM1_CC_Handler                     ;14 TIM1 Capture Compare Interrupt
                DCD      0                                   ;15 Reserved
                DCD      TIM3_Handler                        ;16 TIM3 Global Interrupt
                DCD      0                                   ;17 Reserved
                DCD      0                                   ;18 Reserved
                DCD      TIM14_Handler                       ;19 TIM14 Global Interrupt
                DCD      0                                   ;20 Reserved
                DCD      0                                   ;21 Reserved
                DCD      0                                   ;22 Reserved
                DCD      I2C1_Handler                        ;23 I2C1 Global Interrupt
                DCD      0                                   ;24 Reserved
                DCD      SPI1_Handler                        ;25 SPI1 Global Interrupt
                DCD      0                                   ;26 Reserved
                DCD      USART1_Handler                      ;27 USART1 Global Interrupt
                DCD      USART2_Handler                      ;28 USART2 Global Interrupt
                DCD      0                                   ;29 Reserved
                DCD      0                                   ;30 Reserved
                DCD      0                                   ;31 Reserved

__Vectors_End
__Vectors_Size  EQU      __Vectors_End - __Vectors


                AREA     |.text|, CODE, READONLY

; Reset Handler

Reset_Handler   PROC
                EXPORT   Reset_Handler             [WEAK]
                IMPORT   SystemInit
                IMPORT   __main

                LDR      R0, =SystemInit
                BLX      R0
                LDR      R0, =__main
                BX       R0
                ENDP

; The default macro is not used for HardFault_Handler
; because this results in a poor debug illusion.
HardFault_Handler PROC
                EXPORT   HardFault_Handler         [WEAK]
                B        .
                ENDP

; Macro to define default exception/interrupt handlers.
; Default handler are weak symbols with an endless loop.
; They can be overwritten by real handlers.
                MACRO
                Set_Default_Handler  $Handler_Name
$Handler_Name   PROC
                EXPORT   $Handler_Name             [WEAK]
                B        .
                ENDP
                MEND


; Default exception/interrupt handler

                Set_Default_Handler  NMI_Handler
                Set_Default_Handler  SVC_Handler
                Set_Default_Handler  PendSV_Handler
                Set_Default_Handler  SysTick_Handler

                Set_Default_Handler  IWDG_Handler
                Set_Default_Handler  PVD_Handler
                Set_Default_Handler  FLASH_Handler
                Set_Default_Handler  RCC_Handler
                Set_Default_Handler  EXTI0_1_Handler
                Set_Default_Handler  EXTI2_3_Handler
                Set_Default_Handler  EXTI4_15_Handler
                Set_Default_Handler  ADC1_Handler
                Set_Default_Handler  TIM1_BRK_UP_TRG_COM_Handler
                Set_Default_Handler  TIM1_CC_Handler
                Set_Default_Handler  TIM3_Handler
                Set_Default_Handler  TIM14_Handler
                Set_Default_Handler  I2C1_Handler
                Set_Default_Handler  SPI1_Handler
                Set_Default_Handler  USART1_Handler
                Set_Default_Handler  USART2_Handler


                ALIGN


; User setup Stack & Heap

                IF       :LNOT::DEF:__MICROLIB
                IMPORT   __use_two_region_memory
                ENDIF

                EXPORT   __stack_limit
                EXPORT   __initial_sp
                IF       Heap_Size != 0                      ; Heap is provided
                EXPORT   __heap_base
                EXPORT   __heap_limit
                ENDIF

                END

6.让LED灯闪烁
int main(void)
{
    uint32_t i = 0;

    /* PA15_LED1 */
    RCC->AHBENR_b.mGPIOA = 1;

    GPIOA->CRH_b.MODE15  = 1;
    GPIOA->CRH_b.CNF15   = 0;

    GPIOA->BSRR_b.BS15   = 1;

    while(1)
    {
        GPIOA->BRR_b.BR15  = 1;

        for (i = 0; i < 1000000; i++)
        {
            __NOP();
        }

        GPIOA->BSRR_b.BS15 = 1;

        for (i = 0; i < 1000000; i++)
        {
            __NOP();
        }
    }
}

程序编译无误后,有过Keil直接下载程序到开发板,通过观察Mini-G0001开发板的LED1,当前已经在间隔闪烁了!
13.png

7.附件
自定义MM32G0001 Keil Pack支持包: MindMotion.MM32G0001_DFP.0.0.1.pack.zip (22.45 KB)

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 150.00 元 2024-03-07
理由:恭喜通过原创审核!期待您更多的原创作品~

评论
21小跑堂 2024-3-7 13:59 回复TA
超级瞎折腾(手动狗头),详细介绍基于keil的从最开始一步步部署MM32开发环境 ,看起来感觉实在没必要但是却很有必要的一件事。在绝大多数工程师都在使用却不去开发的地方做详细探究。非常棒。 
www5911839| | 2024-3-6 18:32 | 显示全部楼层
大佬,太强了

使用特权

评论回复
怀揣少年梦| | 2024-3-8 08:54 | 显示全部楼层
牛啊,大佬

使用特权

评论回复
AProgrammer| | 2024-3-11 09:24 | 显示全部楼层
牛啊,大佬+1

使用特权

评论回复
[鑫森淼焱垚]| | 2024-4-16 19:54 | 显示全部楼层
牛啊,学习了

使用特权

评论回复
发新帖 本帖赏金 150.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司资深现场应用工程师
简介:诚信·承诺·创新·合作

67

主题

2992

帖子

29

粉丝