这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【gd32f527移植Zephyr】4、移植串口实现printk

共5条 1/1 1 跳转至

【gd32f527移植Zephyr】4、移植串口实现printk

高工
2026-02-17 21:02:47     打赏

一、前期准备

1.1 环境搭建

 安装 west 和 Zephyr SDK

pip install west

west sdk install


初始化 Zephyr 项目

west init zephyrproject

cd zephyrproject

west update


1.2 获取官方SDK

从GigaDevice官网下载GD32F527 SDK V1.4.0,获取:

- CMSIS头文件

- HAL库源码

- 官方例程参考

二、核心文件修改

2.1 系统时钟配置

文件: modules/hal/gigadevice/gd32f5xx/cmsis/gd/gd32f5xx/source/system_gd32f5xx.c

--- 修改前 ---

#include "gd32f5xx.h"
#include "gd32f5xx_rcu.h"
#define __SYSTEM_CLOCK_IRC16M    (uint32_t)(__IRC16M)
#define __SYSTEM_CLOCK_200M_PLL

--- 修改后 ---

#include "gd32f5xx.h"
#include "gd32f5xx_rcu.h"

/* PLL startup timeout */
#ifndef PLL_STARTUP_TIMEOUT
#define PLL_STARTUP_TIMEOUT   ((uint16_t)0x0500)
#endif

/* FMC/FLASH access latency register for GD32F5XX */
#define FMC_ACR              (*(volatile uint32_t *)(0x40023C00UL + 0x00UL))
#define FMC_ACR_PRFTEN       BIT(1)
#define FMC_ACR_LATENCY      BITS(0,2)

/* select system clock - 200MHz PLL with HXTAL=25MHz */
#define __SYSTEM_CLOCK_200M_PLL

2.2 SOC复位初始化

文件: zephyr/soc/gd/gd32/gd32f5xx/soc.c

--- 在soc_reset_hook函数中实现完整时钟配置 ---

void soc_reset_hook(void)
{
    volatile uint32_t *rcu_ctl = (uint32_t *)0x40023800;
    volatile uint32_t *rcu_cfg0 = (uint32_t *)0x40023804;
    volatile uint32_t *rcu_ahben = (uint32_t *)0x40023830;
    volatile uint32_t *fmc_acr = (uint32_t *)0x40023C00;
    volatile uint32_t *gpiof_ctl = (uint32_t *)0x40021400;
    volatile uint32_t *gpiof_octl = (uint32_t *)0x40021414;
    volatile uint32_t *gpiof_bc = (uint32_t *)0x40021428;

    /* Enable IRC16M first */
    *rcu_ctl |= (1 << 0);
    while (!(*rcu_ctl & (1 << 1))) {}

    /* Try to enable HXTAL (25MHz crystal) with timeout */
    uint32_t timeout = 0;
    *rcu_ctl |= (1 << 15);
    while (!(*rcu_ctl & (1 << 17)) && timeout < 0xFFFF) {
        timeout++;
    }

    if (*rcu_ctl & (1 << 17)) {
        /* HXTAL ready - use 200MHz PLL */
        *fmc_acr = (*fmc_acr & ~0x07) | 5;      /* 5 wait states for 200MHz */
        *rcu_cfg0 &= ~(0x07 << 7);              /* AHB = 200MHz */
        *rcu_cfg0 |= (4 << 10);                 /* APB2 = 100MHz */
        *rcu_cfg0 |= (4 << 13);                 /* APB1 = 100MHz */

        /* PLL = 25MHz * 16 / 2 = 200MHz */
        *(volatile uint32_t *)0x4002382C = (25U << 0) | (0x01U << 16) | (0x10U << 6);
        *rcu_ctl |= (1 << 24);                   /* Enable PLL */
        while (!(*rcu_ctl & (1 << 25))) {}       /* Wait PLL ready */
        *rcu_cfg0 = (*rcu_cfg0 & ~0x03) | 0x02; /* Select PLL as system clock */
        while (((*rcu_cfg0 >> 2) & 0x03) != 0x02) {}
    } else {
        /* HXTAL not ready - use IRC16M (16MHz) */
        *fmc_acr = (*fmc_acr & ~0x07) | 0;      /* 0 wait states */
        *rcu_cfg0 = (*rcu_cfg0 & ~0x03) | 0x00; /* Select IRC16M */
    }

    /* LED initialization (PF7) */
    *rcu_ahben |= 0x20;      /* Enable GPIOF clock */
    *gpiof_ctl = 0xC000;     /* PF7 output mode */
    *gpiof_octl |= (1 << 7);  /* Push-pull */
    *gpiof_bc = (1 << 7);     /* LED ON (active low) */
}

2.3 串口驱动修复

文件: zephyr/drivers/serial/usart_gd32.c

--- 添加GPIOA时钟使能 ---

#define GPIOA_BASE      0x400200UL
#define RCU_BASE       0x40023800UL
#define RCU_AHBEN     (*(volatile uint32_t *)(RCU_BASE + 0x30UL))
#define RCU_AHBEN_GPIOAEN   BIT(17)  /* GPIOA clock enable bit */

static int usart_gd32_init(const struct device *dev)
{
    /* ... */

    /* Enable GPIOA clock for USART0 TX/RX pins (PA9/PA10) */
    RCU_AHBEN |= RCU_AHBEN_GPIOAEN;

    ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
    /* ... */
}

2.4 PinCtrl配置

文件: zephyr/drivers/pinctrl/pinctrl_gd32_af.c

--- 添加GD32F5XX支持 ---

BUILD_ASSERT((GD32_OSPEED_2MHZ == GPIO_OSPEED_2MHZ) &&
#if defined(CONFIG_SOC_SERIES_GD32F3X0) || \
    defined(CONFIG_SOC_SERIES_GD32A50X) || \
    defined(CONFIG_SOC_SERIES_GD32F5XX) || \    // 添加此行
    defined(CONFIG_SOC_SERIES_GD32L23X)
    (GD32_OSPEED_10MHZ == GPIO_OSPEED_10MHZ) &&
    (GD32_OSPEED_50MHZ == GPIO_OSPEED_50MHZ) &&

2.5 配置文件

文件: zephyr/boards/gd/gd32f527_eval/gd32f527_eval_defconfig

CONFIG_NO_OPTIMIZATIONS=y
CONFIG_ARM_MPU=n
CONFIG_HW_STACK_PROTECTION=n
CONFIG_SOC_RESET_HOOK=y
CONFIG_SOC_EARLY_INIT_HOOK=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=200000000
CONFIG_GPIO=y
CONFIG_GD32_EXTI=y
CONFIG_PINCTRL=y
CONFIG_SERIAL=y
CONFIG_USART_GD32=y
CONFIG_UART_CONSOLE=y
CONFIG_CONSOLE=y
CONFIG_PRINTK=y

2.6 设备树配置

文件: zephyr/boards/gd/gd32f527_eval/gd32f527_eval.dts

/* Enable USART0 for console */
&usart0 {
    status = "okay";
    current-speed = <115200>;
    pinctrl-0 = <&usart0_default>;
    pinctrl-1 = <&usart0_sleep>;
    pinctrl-names = "default", "sleep";
};


文件: zephyr/boards/gd/gd32f527_eval/gd32f527_eval-pinctrl.dtsi

&pinctrl {
    usart0_default: usart0_default {
        group1 {
            pinmux = <USART0_TX_PA9>, <USART0_RX_PA10>;
        };
    };
    usart0_sleep: usart0_sleep {
        group1 {
            pinmux = <GD32_PINMUX_AF('A', 9, ANALOG)>,
                     <GD32_PINMUX_AF('A', 10, ANALOG)>;
        };
    };
};

2.7 PinCtrl头文件

文件: modules/hal/gigadevice/include/dt-bindings/pinctrl/gd32f527xx-pinctrl.h

#include "gd32-af.h"

/* USART0 */
#define USART0_TX_PA9    GD32_PINMUX_AF('A', 9, AF7)
#define USART0_RX_PA10   GD32_PINMUX_AF('A', 10, AF7)


三、关键问题排查

3.1 常见问题速查表

image.png

3.2 GD32F5XX USART寄存器偏移

注意:GD32F5XX与GD32F4XX寄存器偏移不同!

image.png

3.3 波特率计算公式

官方GD32公式:

    USARTDIV = (APB2CLK + BAUD/2) / BAUD

    BAUD寄存器 = (USARTDIV & 0xFFF0) | (USARTDIV & 0xF)

常用配置:

    - 16MHz IRC16M + 115200波特率 = 0x8B

    - 100MHz APB2 + 115200波特率 = 0x364

四、测试代码

文件: zephyr/samples/hello_world/src/main.c

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>

#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led_spec = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int main(void)
{
    gpio_pin_configure_dt(&led_spec, GPIO_OUTPUT_ACTIVE);

    printk("=== GD32F527 Zephyr Test ===\r\n");
    printk("UART working!\r\n");

    while (1) {
        gpio_pin_set_dt(&led_spec, 0);
        printk("LED ON\r\n");
        k_msleep(500);

        gpio_pin_set_dt(&led_spec, 1);
        printk("LED OFF\r\n");
        k_msleep(500);
    }
}

六、总结

移植GD32F527到Zephyr的关键点:

1. 时钟配置

   - PLL 200MHz需要Flash等待状态配置

   - HXTAL晶振超时回退到IRC16M

2. GPIO时钟

   - USART使用GPIOA,需要单独使能时钟

   - 关键: RCU_AHBEN |= BIT(17)

3. Pinctrl

   - 正确配置PA9/PA10为AF7模式

   - 添加GD32F5XX到BUILD_ASSERT检查

4. 控制台配置

   - 启用 CONFIG_UART_CONSOLE=y

   - 启用 CONFIG_PRINTK=y

5. 容错处理

   - HXTAL超时时自动回退到IRC16M

【日志打印效果】

image.png





关键词: gd32f527     Zephyr     串口     printk    

院士
2026-02-18 00:17:07     打赏
2楼

怎么感觉弄得好复杂啊


院士
2026-02-18 09:04:49     打赏
3楼

我就是觉得Zephyr的这个特性有点不理解。

是不是国外的主控会经常更换?

所以,需要完美的适配性?


高工
2026-02-19 21:23:29     打赏
4楼

有个问题,为啥大家配置defconfig文件时都是直接手撸,而不是用zepyhr默认支持的west的menuconfig命令?


院士
2026-02-19 22:23:56     打赏
5楼

我是主张嵌入式系统的软件与硬件有一定的关联性。没有太大必要这么完美的分层。


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]