Preface
AT Official Tutorial AT32 MCU is being developed in the VSCode (Visual Studio Code) environment - 21ic Electronic Technology Development Forum
Or the official website Yateli Technology: 32 innovative leaders in microcontrollers! (arterytek.com)
APNote:AN0130, which provides a way to develop VScode using Cmake and Notex Debug.
I am more used to EIDE and can provide convenient project management tools, so this article aims to develop AT32F4 single-chip computer with EIDE of VScode.
Dead work
Hardware:
- AT32F421C8T7 Minimum System Board (same as other AT32F4 series)
- ATLink (or JLink, this article uses ATLink+OpenOCD)
Software:
-
OpenOCD (only available with AT's official distribution, open source on github) ArteryTek/openocd It seems that there is a problem with Flash driver and it is not compatible with the burner of FT2232 device)
-
GCC Tool Chain for Arm
-
MinGW
-
VScode: Install the EIDE and Cortex Debug extensions.
Code:
- Modified from the project template in AT's official AN0130 to work with the smallest system (with only one 8M HEXT, one 32.768 for RTC, one LED and UserKey connected to PC13 pins, all remaining digital pins coming out)
EIDE Project Creation
Create a new project with settings as shown in the diagram:
Then write a blink LED program to control the pin of PC13. Use the most basic external CRM, systick, GPIO.
The standard library files are in. /libraries/drivers and do not need to be changed.
startup.s file, linker file and svd file are in. /project, do not change.
Need to change/write by yourself, only
- main.c: Configure SCKL and AHB (to systick and CPU core) clocks. Enables APB (to GPIOC) peripheral clock. Initialize GPIOC. Enter the blink LED main cycle.
#include "at32f421_clock.h" #include "systick.h" /** * @brief main function. * @param none * @retval none */ int main(void) { system_clock_config(); gpio_init_type gpio_init_struct; /* enable the led clock */ crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); /* set default parameter */ gpio_default_para_init(&gpio_init_struct); /* configure the led gpio */ gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; gpio_init_struct.gpio_pins = GPIO_PINS_13; // gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(GPIOC, &gpio_init_struct); delay_init(); while (1) { gpio_bits_set(GPIOC,GPIO_PINS_13); delay_ms(400); gpio_bits_reset(GPIOC,GPIO_PINS_13); delay_ms(400); } }
- systick.c: Defines the delay function of us, ms, s. It is important to configure the systick CTRL register (bit 2) before using the delay function to specify whether the systick clock source is CPU FCLK or its 8-crossover frequency.
#include "systick.h" #define STEP_DELAY_MS 50 /* delay variable */ static __IO uint32_t fac_us; static __IO uint32_t fac_ms; /** * @brief initialize delay function * @param none * @retval none */ void delay_init() { /* configure systick */ systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV); fac_us = system_core_clock / (1000000U); fac_ms = fac_us * (1000U); } /** * @brief inserts a delay time. * @param nus: specifies the delay time length, in microsecond. * @retval none */ void delay_us(uint32_t nus) { uint32_t temp = 0; SysTick->LOAD = (uint32_t)(nus * fac_us); SysTick->VAL = 0x00; SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; do { temp = SysTick->CTRL; } while ((temp & 0x01) && !(temp & (1 << 16))); SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; SysTick->VAL = 0x00; } /** * @brief inserts a delay time. * @param nms: specifies the delay time length, in milliseconds. * @retval none */ void delay_ms(uint16_t nms) { uint32_t temp = 0; while (nms) { if (nms > STEP_DELAY_MS) { SysTick->LOAD = (uint32_t)(STEP_DELAY_MS * fac_ms); nms -= STEP_DELAY_MS; } else { SysTick->LOAD = (uint32_t)(nms * fac_ms); nms = 0; } SysTick->VAL = 0x00; SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; do { temp = SysTick->CTRL; } while ((temp & 0x01) && !(temp & (1 << 16))); SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; SysTick->VAL = 0x00; } } /** * @brief inserts a delay time. * @param sec: specifies the delay time, in seconds. * @retval none */ void delay_sec(uint16_t sec) { uint16_t index; for (index = 0; index < sec; index++) { delay_ms(500); delay_ms(500); } }
- at32f421_clock.c: You need to change the clock tree when you want to change it. It doesn't change here.
/** ************************************************************************** * @file at32f421_clock.c * @version v2.0.5 * @date 2022-04-02 * @brief system clock config program ************************************************************************** * Copyright notice & Disclaimer * * The software Board Support Package (BSP) that is made available to * download from Artery official website is the copyrighted work of Artery. * Artery authorizes customers to use, copy, and distribute the BSP * software and its related documentation for the purpose of design and * development in conjunction with Artery microcontrollers. Use of the * software is governed by this copyright notice and the following disclaimer. * * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * ************************************************************************** */ /* includes ------------------------------------------------------------------*/ #include "at32f421_clock.h" /** @addtogroup AT32F421_periph_template * @{ */ /** @addtogroup 421_System_clock_configuration System_clock_configuration * @{ */ /** * @brief system clock config program * @note the system clock is configured as follow: * - system clock = hext * pll_mult * - system clock source = pll (hext) * - hext = 8000000 * - sclk = 120000000 * - ahbdiv = 1 * - ahbclk = 120000000 * - apb2div = 1 * - apb2clk = 120000000 * - apb1div = 1 * - apb1clk = 120000000 * - pll_mult = 15 * - flash_wtcyc = 3 cycle * @param none * @retval none */ void system_clock_config(void) { /* config flash psr register */ flash_psr_set(FLASH_WAIT_CYCLE_3); /* reset crm */ crm_reset(); crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE); /* wait till hext is ready */ while(crm_hext_stable_wait() == ERROR) { } /* config pll clock resource */ crm_pll_config(CRM_PLL_SOURCE_HEXT, CRM_PLL_MULT_15); /* enable pll */ crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE); /* wait till pll is ready */ while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET) { } /* config ahbclk */ crm_ahb_div_set(CRM_AHB_DIV_1); /* config apb2clk */ crm_apb2_div_set(CRM_APB2_DIV_1); /* config apb1clk */ crm_apb1_div_set(CRM_APB1_DIV_1); /* enable auto step mode */ crm_auto_step_mode_enable(TRUE); /* select pll as system clock source */ crm_sysclk_switch(CRM_SCLK_PLL); /* wait till pll is used as system clock source */ while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL) { } /* disable auto step mode */ crm_auto_step_mode_enable(FALSE); /* update system_core_clock global variable */ system_core_clock_update(); } /** * @} */ /** * @} */
-
at32f421_int.c: Change when a custom interrupt service program is required, not here.
/** ************************************************************************** * @file at32f421_int.c * @version v2.0.5 * @date 2022-04-02 * @brief main interrupt service routines. ************************************************************************** * Copyright notice & Disclaimer * * The software Board Support Package (BSP) that is made available to * download from Artery official website is the copyrighted work of Artery. * Artery authorizes customers to use, copy, and distribute the BSP * software and its related documentation for the purpose of design and * development in conjunction with Artery microcontrollers. Use of the * software is governed by this copyright notice and the following disclaimer. * * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * ************************************************************************** */ /* includes ------------------------------------------------------------------*/ #include "at32f421_int.h" /** @addtogroup AT32F421_periph_template * @{ */ /** @addtogroup 421_LED_toggle * @{ */ /** * @brief this function handles nmi exception. * @param none * @retval none */ void NMI_Handler(void) { } /** * @brief this function handles hard fault exception. * @param none * @retval none */ void HardFault_Handler(void) { /* go to infinite loop when hard fault exception occurs */ while(1) { } } /** * @brief this function handles memory manage exception. * @param none * @retval none */ void MemManage_Handler(void) { /* go to infinite loop when memory manage exception occurs */ while(1) { } } /** * @brief this function handles bus fault exception. * @param none * @retval none */ void BusFault_Handler(void) { /* go to infinite loop when bus fault exception occurs */ while(1) { } } /** * @brief this function handles usage fault exception. * @param none * @retval none */ void UsageFault_Handler(void) { /* go to infinite loop when usage fault exception occurs */ while(1) { } } /** * @brief this function handles svcall exception. * @param none * @retval none */ void SVC_Handler(void) { } /** * @brief this function handles debug monitor exception. * @param none * @retval none */ void DebugMon_Handler(void) { } /** * @brief this function handles pendsv_handler exception. * @param none * @retval none */ void PendSV_Handler(void) { } /** * @brief this function handles systick handler. * @param none * @retval none */ void SysTick_Handler(void) { } /** * @} */ /** * @} */
Compile and Download
Compile as F7.
If there is an error, check the EIDE project settings. In especial
- Compiler configuration, environment variables, path problems, etc.
- Include library directories
- Preprocessor Macro Definition
Burning
Note that the interface and target of OpenOCD are selected correctly.
Here is the EIDE project configuration file:
{ "name": "AT32F421_eide_temp", "type": "ARM", "dependenceList": [], "srcDirs": [ ".eide/deps", "libraries", "project" ], "virtualFolder": { "name": "<virtual_root>", "files": [], "folders": [] }, "outDir": "build", "deviceName": null, "packDir": null, "miscInfo": { "uid": "4d69a5f133c15cd63d6e4f3e0be364f3" }, "targets": { "Debug": { "excludeList": [ "libraries/cmsis/dsp", "libraries/cmsis/cm4/device_support/startup/iar", "libraries/cmsis/cm4/device_support/startup/mdk", "project/src/startup_at32f421.s" ], "toolchain": "GCC", "compileConfig": { "cpuType": "Cortex-M4", "floatingPointHardware": "none", "useCustomScatterFile": false, "scatterFilePath": "project/misc/AT32F421x8_FLASH.ld", "storageLayout": { "RAM": [ { "tag": "IRAM", "id": 1, "mem": { "startAddr": "0x20000000", "size": "0x5000" }, "isChecked": true, "noInit": false } ], "ROM": [ { "tag": "IROM", "id": 1, "mem": { "startAddr": "0x08000000", "size": "0x10000" }, "isChecked": true, "isStartup": true } ] }, "options": "null" }, "uploader": "OpenOCD", "uploadConfig": { "bin": "", "target": "at32f421xx", "interface": "atlink", "baseAddr": "0x08000000" }, "uploadConfigMap": { "JLink": { "bin": "", "baseAddr": "", "cpuInfo": { "vendor": "null", "cpuName": "null" }, "proType": 1, "speed": 8000, "otherCmds": "" } }, "custom_dep": { "name": "default", "incList": [ ".eide/deps", ".", "project/inc", "libraries/cmsis/cm4/core_support", "libraries/cmsis/cm4/device_support", "libraries/drivers/inc", "c:\\SysGCC\\arm-eabi\\arm-none-eabi\\include" ], "libList": [], "sourceDirList": [], "defineList": [ "_DEBUG", "UNICODE", "_UNICODE", "AT32F421C8T7", "USE_STDPERIPH_DRIVER" ] } } }, "version": "3.3" }
debugging
Once launch.json is configured, press F5 to start debugging directly.
{ "version": "0.2.0", "configurations": [ { "cwd": "${workspaceRoot}", "type": "cortex-debug", "request": "launch", "name": "openocd-launch", "armToolchainPath": "C:/Users/hyq/.eide/tools/gcc_arm/10 2021.10/bin", "gdbPath": "C:/Users/hyq/.eide/tools/gcc_arm/10 2021.10/bin/arm-none-eabi-gdb.exe", "interface": "swd", "servertype": "openocd", "configFiles": [ "D:/OpenHardware/AT32/Tool/vscode/Tool/OpenOCD_V2.0.2/scripts/interface/atlink.cfg", "D:/OpenHardware/AT32/Tool/vscode/Tool/OpenOCD_V2.0.2/scripts/target/at32f421xx.cfg" ], "executable": "build/Debug/AT32F421_eide_temp.elf", "runToMain": true, "svdFile": "./project/misc/AT32F421xx_v2.svd", } ] }
The Cortex Debug extension relies on the launch.json file and uses openocd in the system environment variable Path. The exe path is the default OpenOCD, so here's a pit because my computer has multiple OpenOCDs installed on it and is not configured properly (OpenOCD paths are also filled in on the EIDE), so if you don't specify the version of OpenOCD you want to use for Cortex Debug, you'll probably make a mistake.
Therefore, it is best to specify the OpenOCD path used by the extension in settings.json:
"cortex-debug.openocdPath": "D:\\OpenHardware\\AT32\\Tool\\vscode\\Tool\\OpenOCD_V2.0.2\\bin\\openocd.exe",
Output EIDE Template
The resulting EIDE template file (.ept) is located in the project's root directory.
When you create a new AT32F4 project later, you can import the template.