xld0932 发表于 2025-1-22 14:53

[兆易GD32H759I-EVAL]1.熟悉开发环境、熟悉开发资料、搭建基础工程

<p>1.简介&mdash;&mdash;(摘录于GD官网,从了解MCU开始)</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;兆易创新于2023.5.11推出了GD32H737/757/759系列超高性能MCU,该系列MCU采用基于Armv7E-M架构的600MHz Arm&reg; Cortex&reg;-M7高性能内核,凭借支持分支预测的6级超标量流水线架构,以及支持高带宽的AXI和AHB总线接口,可实现更高的处理性能。内置了高级DSP硬件加速器和双精度浮点单元(FPU),以及硬件三角函数加速器(TMU)和滤波算法加速器(FAC),大幅减轻了内核的负担并有助于提升处理效率。GD32H7系列MCU最高主频下的工作性能可达1552 DMIPS,CoreMark&reg;测试取得了2888分的出色表现,同主频下的代码执行效率相比市场同类产品提升约10%,相比Cortex&reg;-M4产品的性能提升超过40%。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H7系列MCU配备了1024KB到3840KB的片上Flash及1024KB的SRAM,其中包含512KB可配置超大紧耦合内存(ITCM, DTCM),可确保关键指令与数据的零等待执行;还配备了64KB L1-Cache高速缓存(I-Cache, D-Cache),有效提升CPU处理效率和实时性。外部总线扩展(EXMC)支持访问SDRAM、SRAM、ROM、NOR Flash和NAND Flash等多种片外存储器。GD32H7内置了可实时跟踪指令和数据的宏单元ETM(Embedded Trace Macrocell),提供在不干扰CPU正常运行情况下的高级调试功能。GD32H7内置的大容量存储空间能够支持复杂操作系统及嵌入式AI、机器学习(ML)等多种高级算法,实现兼具高性能和低延迟的实时控制。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H7系列MCU新增了大量通用外设资源,包含8个USART、4个I2C、6个SPI、4个I2S、2个SDIO以及2个八线制OSPI(可向下兼容四线制QSPI)等。配备了2个USB2.0 OTG接口,支持全速(Full Speed)和高速(High Speed)模式。还集成了3路CAN-FD控制器和2路以太网,满足高速互联应用所需。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H7系列MCU提供了出色的图形显示和音视频连接方案。芯片内置了TFT LCD液晶驱动器和图形处理加速器IPA (Image Processing Accelerator), 支持2D图像叠加、旋转、缩放及多种颜色格式转换等功能。还集成了串行音频接口(SAI)和SPDIF音频接口,以及8位至14位的数字摄像头接口,便于视频图像的采集与传输。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H7系列MCU采用1.71V~3.6V供电,支持高级电源管理并提供了三种供电模式(LDO/SMPS/直接供电)和五种低功耗模式,可实施灵活的供电策略以兼顾整体能耗平衡。配备了4个32位通用定时器、12个16位通用定时器、4个64位/32位基本定时器、2个PWM高级定时器。2个14位ADC采样速率可达4MSPS,1个12位ADC采样速率高达5.3MSPS,还集成了快速比较器(COMP)、DAC等高精度模拟外设以支持各类电机控制场景。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H7产品系列支持多种安全机制,为通信过程的数据安全提供保障。内置的硬件加解密支持DES、三重DES或AES算法,以及应用于多种场合的哈希(Hash)算法,确保传输信息的完整性。GD32H7系列MCU Flash/SRAM均支持ECC校验,能够有效提升系统运行的可靠性。还集成了RTDEC模块,可以对AXI或AHB总线数据进行实时解密,保护存储在外部SPI NOR Flash设备中只读固件的机密性。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H7提供了3个全新系列,并与现有产品完美兼容。按资源配置不同,GD32H737系列支持3路CAN 2.0B,GD32H757/GD32H759系列支持3路高速CAN-FD。按管脚封装不同,GD32H757系列具备BGA100和LQFP144/100三种封装选项;GD32H759系列具备BGA176 和LQFP176封装选项,以满足差异化开发需求。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H7可广泛用于数字信号处理、电机变频、电源、储能系统、无人机、音频视频、图形图像等各类应用。得益于超高主频以及大存储容量,该系列MCU也适用于机器学习和人工智能等诸多高端创新场景。</p>

<p>&nbsp;</p>

<p>2.GD32H759I-EVAL全功能评估板</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H759I-EVAL 评估板使用 GD32H759IMK6 作为主控制器。评估板使用 GD-Link Mini USB接口或者 DC-005 连接器提供 5V 电源。提供包括扩展引脚在内的及 Reset, Boot, Wakeup KEY, Tamper KEY, User KEY, LED, ADC, DAC, CAN, DCI, ETHNET, HPDF, SAI, I2S, I2C_SMbus, OSPI, SPI_LCD, SDIO, SDRAM, TLI_LCD, USB, USART 转 USB 接口等外设资源。(摘录于GD32H759I-EVAL评估板使用指南_Rev2.1)</p>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>3.准备开发资料及开发环境</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在GD32官网(<a href="https://www.gd32mcu.com/cn/download" target="_blank">https://www.gd32mcu.com/cn/download</a>)下载一栏,找到GD32H7 MCU系列,然后在数据手册、用户手册、应用笔记、应用软件以及开发板资料下载相应的资料,如下图所示:</p>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我使用的是KEIL MDK-ARM集成开发环境,在使用之前需要安装刚刚下载的GD32H7xx AddOn软件,部署KEIL的PACK包;在GD32H7xx Firmware Library中提供了GD32H7xx标准固件库和外设示例程序,我们可以基于官方的驱动库,参考这些示例程序来开发我们的项目应用程序。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GD32H759I-EVAL全功能开发板的资料在GD32H7xx_Demo_Suites_V2.0.1.7z\GD32H7xx_Demo_Suites_V2.0.1\GD32H759I_EVAL_Demo_Suites目录下,包含了使用指南、原理图、基于开发板的示例程序等等。</p>

<p>&nbsp;</p>

<p>4.搭建基础工程</p>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了尽快的熟悉和掌握MCU的使用,我们基于官方提供的驱动库,自己创建KEIL工程,基于板载的资源去定义一些硬件驱动程序,结合上层的应用来达到演示的效果;基础工程也是后面所有程序的一个基础,本着从易到难的学习过程,在基础工程中,我们先对开发板的资源做一个了解,然后实现LED显示驱动、用户按键操作驱动、日志打印这几个功能;</p>

<div style="text-align: center;"></div>

<p>&nbsp; &nbsp; &nbsp; &nbsp; 按键的应用层,我们基于第三方的开源代码MultiButton来实现对按键的扫描检测和触发事件的处理,通过如下原理图,我们通过Wakeup按键和Tamper按键实现对LED1和LED2翻转显示操作,通过User Key按键来实现熄灭LED1和LED2的操作。</p>

<p>4.1.LED驱动程序</p>

<pre>
<code class="language-cpp">#include "bsp_led.h"

void bsp_LedInit(void)
{
    rcu_periph_clock_enable(RCU_GPIOF);
    gpio_mode_set(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10);
    gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
    gpio_bit_reset(GPIOF, GPIO_PIN_10);

    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6);
    gpio_bit_reset(GPIOA, GPIO_PIN_6);
}

void bsp_Led1On(void)
{
    gpio_bit_set(GPIOF, GPIO_PIN_10);
}

void bsp_Led1Off(void)
{
    gpio_bit_reset(GPIOF, GPIO_PIN_10);
}

void bsp_Led1Toggle(void)
{
    if (gpio_output_bit_get(GPIOF, GPIO_PIN_10) == RESET)
    {
      gpio_bit_set(GPIOF, GPIO_PIN_10);
    }
    else
    {
      gpio_bit_reset(GPIOF, GPIO_PIN_10);
    }
}

void bsp_Led2On(void)
{
    gpio_bit_set(GPIOA, GPIO_PIN_6);
}

void bsp_Led2Off(void)
{
    gpio_bit_reset(GPIOA, GPIO_PIN_6);
}

void bsp_Led2Toggle(void)
{
    if (gpio_output_bit_get(GPIOA, GPIO_PIN_6) == RESET)
    {
      gpio_bit_set(GPIOA, GPIO_PIN_6);
    }
    else
    {
      gpio_bit_reset(GPIOA, GPIO_PIN_6);
    }
}

</code></pre>

<p>4.2.KEY驱动程序</p>

<pre>
<code class="language-cpp">#include "bsp_key.h"

void bsp_KeyInit(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_0);

    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_13);

    rcu_periph_clock_enable(RCU_GPIOF);
    gpio_mode_set(GPIOF, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
}

uint8_t bsp_KeyReadPinLevel(uint8_t Index)
{
    uint8_t PinLevel = 0;

    switch (Index)
    {
      case 0:
            PinLevel = gpio_input_bit_get(GPIOA, GPIO_PIN_0);
            break;

      case 1:
            PinLevel = gpio_input_bit_get(GPIOC, GPIO_PIN_13);
            break;

      case 2:
            PinLevel = gpio_input_bit_get(GPIOF, GPIO_PIN_8);
            break;

      default:
            break;
    }

    return (PinLevel);
}

</code></pre>

<p>4.3.KEY应用程序</p>

<pre>
<code class="language-cpp">#include "key.h"
#include "bsp_key.h"
#include "bsp_led.h"
#include "multi_button.h"

struct Button keyWakeup;
struct Button keyTamper;
struct Button keyUser;

volatile uint8_t KeyRegisterFlag = 0;

void KEY_WakeupHandler(void *btn)
{
    struct Button *handle = (struct Button *)btn;

    if (handle-&gt;button_id == 0)
    {
      bsp_Led1Toggle();
    }
}

void KEY_TamperHandler(void *btn)
{
    struct Button *handle = (struct Button *)btn;

    if (handle-&gt;button_id == 1)
    {
      bsp_Led2Toggle();
    }
}

void KEY_UserHandler(void *btn)
{
    struct Button *handle = (struct Button *)btn;

    if (handle-&gt;button_id == 2)
    {
      bsp_Led1Off();
      bsp_Led2Off();
    }
}

void KEY_Init(void)
{
    button_init(&amp;keyWakeup, bsp_KeyReadPinLevel, RESET, 0);
    button_init(&amp;keyTamper, bsp_KeyReadPinLevel, RESET, 1);
    button_init(&amp;keyUser,   bsp_KeyReadPinLevel, RESET, 2);

    button_attach(&amp;keyWakeup, PRESS_DOWN, KEY_WakeupHandler);
    button_attach(&amp;keyTamper, PRESS_DOWN, KEY_TamperHandler);
    button_attach(&amp;keyUser,   PRESS_DOWN, KEY_UserHandler);

    button_start(&amp;keyWakeup);
    button_start(&amp;keyTamper);
    button_start(&amp;keyUser);

    KeyRegisterFlag = 1;
}

</code></pre>

<p>4.4.系统初始化及日志功能实现</p>

<pre>
<code class="language-cpp">#include "platform.h"

volatile uint32_t PLATFORM_DelayTick = 0;

void PLATFORM_InitCache(void)
{
    SCB_EnableICache();
    SCB_EnableDCache();
}

void PLATFORM_InitSysTick(void)
{
    if (SysTick_Config(SystemCoreClock / 1000U))
    {
      while (1)
      {
      }
    }

    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

void PLATFORM_ConfigDelay(void)
{
    /* -----------------------------------------------------------------------
       TIMER50 configuration:
       TIMER50CLK = 300MHz/300 = 1MHz, the period is 1ms(1MHz/1000 = 1ms).
       ----------------------------------------------------------------------- */
    timer_parameter_struct timer_initpara;

    rcu_periph_clock_enable(RCU_TIMER50);

    timer_deinit(TIMER50);

    timer_struct_para_init(&amp;timer_initpara);
    timer_initpara.prescaler         = 300 - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection= TIMER_COUNTER_UP;
    timer_initpara.period            = 1000 - 1;
    timer_initpara.clockdivision   = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER50, &amp;timer_initpara);

    nvic_irq_enable(TIMER50_IRQn, 0, 0);

    timer_interrupt_flag_clear(TIMER50, TIMER_INT_FLAG_UP);
    timer_interrupt_enable(TIMER50, TIMER_INT_UP);

    timer_enable(TIMER50);
}

void PLATFORM_DelayMs(uint32_t Tick)
{
    PLATFORM_DelayTick = Tick;

    while (PLATFORM_DelayTick)
    {
    }
}

void PLATFORM_InitConsole(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_USART0);

    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_9);

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_10);

    usart_deinit(USART0);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_baudrate_set(USART0, 115200U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

    nvic_irq_enable(USART0_IRQn, 0, 0);
    usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
    usart_interrupt_enable(USART0, USART_INT_RBNE);

    usart_enable(USART0);
}

int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART0, (uint8_t)ch);

    while (RESET == usart_flag_get(USART0, USART_FLAG_TBE))
    {
    }

    return (ch);
}

void PLATFORM_PrintClocks(void)
{
    printf("\r\nGD32H759 %s %s", __DATE__, __TIME__);

    printf("\r\n");
    printf("\r\nCK_SYSFrequency : %7.3f MHz", (double)rcu_clock_freq_get(CK_SYS)/ (double)1000000.0);
    printf("\r\nCK_AHBFrequency : %7.3f MHz", (double)rcu_clock_freq_get(CK_AHB)/ (double)1000000.0);
    printf("\r\nCK_APB1 Frequency : %7.3f MHz", (double)rcu_clock_freq_get(CK_APB1) / (double)1000000.0);
    printf("\r\nCK_APB2 Frequency : %7.3f MHz", (double)rcu_clock_freq_get(CK_APB2) / (double)1000000.0);
    printf("\r\nCK_APB3 Frequency : %7.3f MHz", (double)rcu_clock_freq_get(CK_APB3) / (double)1000000.0);
    printf("\r\nCK_APB4 Frequency : %7.3f MHz", (double)rcu_clock_freq_get(CK_APB4) / (double)1000000.0);
    printf("\r\n");
}

void PLATFORM_Init(void)
{
    PLATFORM_InitCache();

    PLATFORM_InitSysTick();

    PLATFORM_ConfigDelay();

    PLATFORM_InitConsole();

    PLATFORM_PrintClocks();
}

</code></pre>

<p>4.5.相关中断处理</p>

<pre>
<code class="language-cpp">#include "gd32h7xx_it.h"
#include "key.h"
#include "platform.h"
#include "multi_button.h"

void NMI_Handler(void)
{
    while (1)
    {
    }
}

void HardFault_Handler(void)
{
    while (1)
    {
    }
}

void MemManage_Handler(void)
{
    while (1)
    {
    }
}

void BusFault_Handler(void)
{
    while (1)
    {
    }
}

void UsageFault_Handler(void)
{
    while (1)
    {
    }
}

void DebugMon_Handler(void)
{
    while (1)
    {
    }
}

void SVC_Handler(void)
{
    while (1)
    {
    }
}

void PendSV_Handler(void)
{
    while (1)
    {
    }
}

void SysTick_Handler(void)
{
    if (KeyRegisterFlag)
    {
      button_ticks();
    }
}

void TIMER50_IRQHandler(void)
{
    if (RESET != timer_interrupt_flag_get(TIMER50, TIMER_INT_FLAG_UP))
    {
      if (PLATFORM_DelayTick)
      {
            PLATFORM_DelayTick--;
      }

      timer_interrupt_flag_clear(TIMER50, TIMER_INT_FLAG_UP);
    }
}

void USART0_IRQHandler(void)
{
    if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE))
    {
      printf("%c", (uint8_t)usart_data_receive(USART0));
    }
}

</code></pre>

<p>&nbsp;</p>

<p>5.注意事项及建议</p>

<p>5.1.LED的功能与TLI和USB有复用,User Key的功能与TLI有复用,所以在进行LED和KEY功能实现时,需要设置跳帽,和不与冲突的功能同时使用;</p>

<p>5.2.板载有调试器和CH340实现的USB转TTL接口;板载调试器只是实现了调试功能,没有虚拟串口功能,可以给整个单板供电;CH340部分需要通过跳帽选择USART功能,而且CH340部分的USB接口不能对单板进行供电,所以在调试打印日志的时候,需要接2个USB线;感觉比较麻烦,如果板载调试接口可以实现虚拟串口功能,那既省了CH340电路,又可以一根USB接线工作了;</p>

<p>&nbsp;</p>

<p>6.运行结果</p>

<div style="text-align: center;"></div>

<p>d9551562c38977ee981badf4ac3f2cef<br />
&nbsp;</p>

<p>7.附件:</p>

<div>软件工程源代码:</div>

生酱哥 发表于 2025-1-22 15:38

<p>每天学习一点,提升一些。</p>

xld0932 发表于 2025-1-23 09:40

生酱哥 发表于 2025-1-22 15:38
每天学习一点,提升一些。

<p><img height="50" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/wanwan33.gif" width="58" /></p>
页: [1]
查看完整版本: [兆易GD32H759I-EVAL]1.熟悉开发环境、熟悉开发资料、搭建基础工程