第一次接触国产FPGA和RISC-V软核开发时,我盯着开发板和一堆文档发呆了整整两天——网上资料零散,官方例程晦涩,连最基本的工程创建都踩了无数坑。直到成功点亮第一个LED,才真正理解"片上系统"这四个字的分量。本文将用最直白的语言,带你完整走通PGL22G上构建RISC-V SoC的全流程,从工具安装到硬件设计,从软件编写到功能验证,每个步骤都包含我踩过的坑和验证过的解决方案。
紫光同创的Pango Design Suite(PDS)是必须跨越的第一道门槛。最新版PDS 2023.3虽然改善了界面,但安装时仍需注意:
bash复制# 管理员权限运行:
bcdedit.exe /set nointegritychecks on
bash复制wget https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-10.2.0-2020.12.8-x86_64-w64-mingw32.tar.gz
注意:紫光官方提供的GCC工具链可能存在链接脚本兼容性问题,建议优先使用SiFive版本
开发板硬件检查清单:
在PDS中创建Block Design时,需要精确配置以下几个关键组件:
| 组件类型 | 参数设置 | 注意事项 |
|---|---|---|
| RISC-V CPU核 | 选择GD32VF103兼容内核 | 必须开启硬件乘除法单元 |
| AHB总线矩阵 | 主端口优先级设为Round-Robin | 避免外设争用导致死锁 |
| GPIO控制器 | 位宽设置为8bit | 匹配开发板LED数量 |
| 时钟管理 | 主频设为50MHz | 超频会导致时序违规 |
连接完成的系统架构应包含以下数据流:
verilog复制// 典型的GPIO地址映射示例
#define GPIO_BASE 0x40010000
#define GPIO_DIR *(volatile uint32_t *)(GPIO_BASE + 0x00)
#define GPIO_DATA *(volatile uint32_t *)(GPIO_BASE + 0x04)
使用VS Code搭建开发环境比Keil更高效,推荐安装以下插件:
关键配置步骤:
实测发现:如果不手动初始化PLL,系统时钟会停留在默认的8MHz,导致UART通信波特率错误
开发板LED通常连接在Bank1上,对应的约束文件应包含:
tcl复制set_property -dict {
PACKAGE_PIN J11
IOSTANDARD LVCMOS33
} [get_ports {gpio_out[0]}]
常见错误排查:
最简LED闪烁程序应包含以下关键操作:
c复制void delay_ms(uint32_t ms) {
volatile uint32_t cycles = ms * 20000;
while(cycles--);
}
int main() {
GPIO_DIR = 0xFF; // 设置全部引脚为输出
while(1) {
GPIO_DATA ^= 0x01; // 翻转第0位
delay_ms(500);
}
}
调试时遇到的典型问题:
在现有系统中添加UART16550兼容控制器需要:
c复制// 串口初始化示例
void uart_init(uint32_t baud) {
uint32_t divisor = 50000000 / (16 * baud);
UART_LCR = 0x80; // 允许设置波特率
UART_DLL = divisor & 0xFF;
UART_DLM = (divisor >> 8) & 0xFF;
UART_LCR = 0x03; // 8N1模式
}
实现printf重定向到串口:
c复制int _write(int fd, char *ptr, int len) {
for(int i=0; i<len; i++) {
while(!(UART_LSR & 0x20)); // 等待发送缓冲区空
UART_THR = ptr[i];
}
return len;
}
实测发现:在PGL22G上,UART发送间隔需要增加1us延时,否则会出现字符丢失。这可能是AHB总线仲裁导致的异常。
通过AHB总线分析仪发现,默认配置下RISC-V核的指令预取效率低下。修改缓存策略后性能提升显著:
| 优化措施 | IPC提升 | 代码体积变化 |
|---|---|---|
| 启用指令缓存 | 38% | +2KB |
| 设置WRITE缓冲 | 12% | 无 |
| 调整总线突发长度 | 7% | 无 |
在电池供电场景下,可通过以下方式降低功耗:
c复制// 进入低功耗模式示例
void enter_sleep() {
PWR_CR |= (1 << 2); // 设置睡眠深度
__asm volatile("wfi"); // 等待中断
}
实际测量显示,在50MHz全速运行下系统功耗为120mA,而睡眠模式可降至3mA以下。