2. GPIO点灯控制
任务目标
在玄铁C906/C910开发板上,通过直接操作GPIO寄存器实现LED闪烁。本案例将引导你完成GPIO引脚的输出模式配置,并通过软件延时控制LED以约1Hz频率交替亮灭,从而掌握GPIO底层寄存器操作与基础延时方法。
硬件连接与前置条件
- 开发板:玄铁C906/C910(以C906为例,寄存器地址基于CV1800B芯片手册)
- LED连接:将LED正极通过220Ω限流电阻接至GPIOA_14(对应物理引脚),负极接GND
- 编译工具链:RISC-V 64位交叉编译器(如riscv64-unknown-elf-gcc)
- 调试方式:通过JTAG或串口下载程序,使用串口终端观察运行状态
GPIO寄存器映射
玄铁C906内部GPIO控制器基地址为0x03020000,本案例使用以下偏移寄存器(均为32位):
0x00— GPIO_SWPORT_DR(数据寄存器,写1输出高电平,写0输出低电平)0x04— GPIO_SWPORT_DDR(方向寄存器,对应位置1为输出,置0为输入)0x30— GPIO_CTRL(控制寄存器,需将对应位置1以启用软件控制,绕过硬件外设复用)
GPIOA_14对应上述寄存器中的第14位(bit 14)。
完整代码实现
#include <stdint.h>
#include <stdio.h>
// GPIO控制器基地址
#define GPIO_BASE 0x03020000UL
// 寄存器偏移
#define GPIO_DR 0x00
#define GPIO_DDR 0x04
#define GPIO_CTRL 0x30
// 目标引脚:GPIOA_14
#define LED_PIN 14
// 寄存器访问宏
#define REG32(addr) (*(volatile uint32_t *)(addr))
// 软件延时函数(约1ms @ 500MHz CPU频率)
static void delay_ms(uint32_t ms) {
// 粗略估算:500MHz下约125个周期/ms,取保守值200
volatile uint32_t count;
for (uint32_t i = 0; i < ms; i++) {
for (count = 0; count < 200000; count++);
}
}
int main(void) {
uint32_t reg_val;
// 1. 启用软件控制:将CTRL寄存器bit14置1
reg_val = REG32(GPIO_BASE + GPIO_CTRL);
reg_val |= (1UL << LED_PIN);
REG32(GPIO_BASE + GPIO_CTRL) = reg_val;
// 2. 配置方向为输出:DDR寄存器bit14置1
reg_val = REG32(GPIO_BASE + GPIO_DDR);
reg_val |= (1UL << LED_PIN);
REG32(GPIO_BASE + GPIO_DDR) = reg_val;
// 3. 初始状态:LED熄灭(输出低电平)
reg_val = REG32(GPIO_BASE + GPIO_DR);
reg_val &= ~(1UL << LED_PIN);
REG32(GPIO_BASE + GPIO_DR) = reg_val;
printf("GPIO LED Blink Test Started\r\n");
while (1) {
// LED点亮:输出高电平
reg_val = REG32(GPIO_BASE + GPIO_DR);
reg_val |= (1UL << LED_PIN);
REG32(GPIO_BASE + GPIO_DR) = reg_val;
delay_ms(500);
// LED熄灭:输出低电平
reg_val = REG32(GPIO_BASE + GPIO_DR);
reg_val &= ~(1UL << LED_PIN);
REG32(GPIO_BASE + GPIO_DR) = reg_val;
delay_ms(500);
}
return 0;
}
编译与运行
- 保存代码为
gpio_blink.c,执行交叉编译:
riscv64-unknown-elf-gcc -march=rv64imac -mabi=lp64 -O2 -o gpio_blink.elf gpio_blink.c
- 将生成的
gpio_blink.elf通过调试器(如OpenOCD + GDB)加载到开发板内存并运行,或转换为bin文件烧录至Flash启动。
验证方法与判定标准
- 静态检查:编译无报错,链接成功生成ELF文件。
- 运行观察:程序运行后,串口终端打印
GPIO LED Blink Test Started,同时LED以约1Hz频率闪烁(亮500ms、灭500ms)。 - 判定通过:LED持续闪烁且周期稳定在1秒左右,说明GPIO输出配置正确、延时控制有效。若LED常亮或常灭,检查GPIO_CTRL是否已置1(外设复用冲突)及DDR方向配置。
常见问题
- LED不亮:确认GPIO_CTRL寄存器bit14已置1,否则引脚被其他外设功能占用;检查DDR方向是否为输出。
- 闪烁频率异常:延时函数基于CPU频率估算,若实际主频不同,调整内层循环次数
200000即可。 - 寄存器地址错误:不同型号(C906/C910)GPIO基地址可能不同,请以对应芯片手册为准。