- 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文件
2.4.SVD文件校验
CMSIS提供了一个SVD生成和检验工具,“SVDConv.exe”通过这个工具,我们可以生成芯片的头文件,在生成头文件时还可以检测SVD文件的正确性,确保SVD文件是0 Errors,0 Warnings!在制作的过程中,有些是因为XML语法的问题,有些是寄存器属性和位域属性不一致,通过细心的修改,都是可以解决掉的。
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,这种方式在第一种的基础上,添加了寄存器位域的宏定义,包含了位域的起始位置和掩码值;
第三:SVDConv.exe MM32G0001.svd --generate=header --fields=macro --fields=struct,这种方式在第二种的基础上,添加了寄存器结构体定义时的具体化,在把寄存器都定义出来的同时,把每一个寄存器的位域都做了共用体,这样在编写代码时方便了不少!
我也是比较喜欢第三种生成方式,比较详细!!!
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”获取下载算法的模板工程,下载算法中提供了一些函数接口,有必要实现的,也有可选实现的:
我们完善必要实现的函数功能就可以了,在实现函数功能时,我们需要注意一下芯片看门狗,如果看门狗在打开的状态下,芯片烧录时间超过了喂狗时间,会导致芯片下载中断而失败,所以需要在下载算法中耗时的位置添加喂狗操作!最后就是通过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的设置。
在完成上述函数和配置修改之后,需要在工程的配置中,Output选项卡中,修改一下生成下载算法的文件名,如下所示:
最后编译整个工程,生成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文件
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支持包进行安装:
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开发板,来创建一个基础工程:
这边就是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,当前已经在间隔闪烁了!
7.附件
自定义MM32G0001 Keil Pack支持包:
MindMotion.MM32G0001_DFP.0.0.1.pack.zip
(22.45 KB, 下载次数: 9)
SVD生成的3种不同方式的头文件:
MM32G0001-Header.zip
(81.51 KB, 下载次数: 10)
MM32G0001数据源:
MM32G0001数据源.zip
(555.67 KB, 下载次数: 14)
Python自动化生成工具源代码:
Python.zip
(2.83 KB, 下载次数: 10)
下载算法工程源文件:
下载算法.zip
(60.35 KB, 下载次数: 10)
工程模板及LED闪烁工程源代码:
Project.zip
(476.98 KB, 下载次数: 19)