ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PGL22G-324评估板Cortex-M1软核移植与调试要点

PGL22G-324评估板Cortex-M1软核移植与调试要点 简介面向嵌入式与FPGA开发者的ARM Cortex-M1 SoC设计工程包基于PGL22_324评估板演示如何在FPGA中集成Cortex-M1处理器并搭建可灵活配置的片上系统。压缩包共616个文件约27.81MB以Verilog/VHDL源文件.v、.vhdl、.vh、Cortex-M1 IP核相关文件.vp、仿真与脚本配置.do、.bat、.tcl以及工程文档、PDF手册为主覆盖从RTL编写、IP集成、综合实现到仿真验证的主要流程。已有488人学习下载适合希望掌握FPGASoC设计方法、Cortex-M1处理器应用以及快速原型验证思路的硬件工程师、嵌入式开发者与相关专业学生。包内不仅包含完整的工程目录结构和示例设计还提供测试脚本与说明文档能够帮助使用者理解SoC架构和Cortex-M1与FPGA协同工作的细节可直接基于此环境进行功能扩展与二次开发是学习FPGA上处理器集成的高价值参考资源。1. 为什么在 PGL22G-324 上把 Cortex-M1 软核当作独立项目来做标题这种命名方式往往会出现在评估板项目的目录树里pgr_ 是工程代号Cortex_M1 是 ARM 提供的软核处理器PGL22_324 指紫光同创 PGL22G 器件的 324 引脚封装eval 则透露出这块板子的用途是评估验证。很多从 MCU 转过来的工程师拿到板子后第一件事是点灯第二件事就是把一个软核 CPU 塞进 FPGA 里跑起来而 Cortex-M1 正是面积小、能直接挂 AHB-Lite 总线的最小软核选择。这篇文章要解决的是从一块 PGL22G-324 评估板的原理图出发如何在国产 FPGA 工具链里把 M1 的时钟、复位、内存映射、GPIO/UART 外设和 SWD 调试链路打通并指出过程中最容易让项目陷入僵局的几个细节。适合手里已经有板子、想验证软核方案的嵌入式或 FPGA 工程师也适合用软核做外设控制器的原型开发人员。2. 先看懂 PGL22G-324 的引脚和时钟再决定 Cortex-M1 该落在哪个 bank2.1 324 封装的 IO bank 与 M1 的固定信号324 引脚的 PGL22G 器件在评估板上不会把所有 GPIO 都引出来常见的做法是分成若干 8 位或 16 位的排针每个排针对应一个 IO bank并单独提供 VCCIO 电压。Cortex-M1 本身是软核不占用物理引脚它只通过 AHB-Lite 总线与片内逻辑连接因此你真正需要提前锁定的引脚只有四类时钟输入、复位输入、调试接口、以及一个用于启动后做基本观察的 UART/GPIO。我在布局时习惯先把晶振引脚和 SWD 引脚在原理图上标红后续所有代码都围绕这个物理约束展开。评估板的时钟常见为 50MHz 有源晶振接在标有 GCLK 功能的全局时钟引脚上。M1 内核不挑时钟频率但片内 SRAM 和外设总线都直接挂在同一个 HCLK 上所以时钟规划实际上就是系统总线频率规划。如果之后要通过 PLL 倍频注意 M1 的 AHB 接口对时钟占空比和抖动没有特殊要求真正限速的是片内 RAM 的读写时序和 AHB 仲裁逻辑的组合逻辑深度。我开始做 PGL22 系列项目时先把 50MHz 作为单一时钟跑通再逐步加 PLL这样遇到问题时能快速定位是内核还是外设侧的问题。2.2 最小系统的电源轨与复位同步评估板一般已经把电源树画好但做软核原型时仍然要确认三个关键电源轨VCCINT 负责 FPGA 内部逻辑包含 M1 核VCCIO 由 bank 分组决定直接决定 GPIO 电平标准VCCPLL 给模拟锁相环使用必须在原理图上确认是否通过磁珠隔离。M1 对复位的要求比普通状态机高因为内核在复位释放后的前几个周期就要取向量表如果 HRESETN 解除时刻与 HCLK 沿没有对齐M1 会进入未知状态。我的做法是加一个专用复位同步模块把外部按键复位通过两级触发器同步后再作为 HRESETN 输出并且让这个复位信号同时覆盖所有 AHB 外设和片内 SRAM 的复位端口。module reset_sync ( input wire clk, input wire rst_n_ext, output wire rst_n_sync ); reg [3:0] rst_sr; always (posedge clk or negedge rst_n_ext) begin if (rst_n_ext 1b0) begin rst_sr 4b0000; end else begin rst_sr {rst_sr[2:0], 1b1}; end end assign rst_n_sync rst_sr[3]; endmodule上面这个模块用四级移位寄存器实现异步复位、同步释放。rst_n_ext 是外部按钮经过消抖动后的低有效复位rst_sr 的低 3 位在复位释放后逐拍拉高第四拍才会把 rst_n_sync 真正释放给内部逻辑。这样做的好处是让 M1、总线矩阵和所有外设看到的是同一个延迟释放的复位信号避免在复位释放瞬间出现高组态毛刺。CLK 频率在 50MHz 时四级同步延迟只有 4 个周期对内核启动没有影响但能显著降低时序分析中复位释放路径上的亚稳态风险。2.3 用工具链把引脚约束与 bit 流生成串起来PGL22G 系列的开发软件通常提供图形化引脚规划界面但命令行方式更容易在版本控制里体现差异。常见流程是先把 RTL 和约束文件加入工程再指定顶层模块然后依次执行综合、布局、布线并生成 bit 流。工程脚本大致如下create_project -name m1_pgl22 -dir ./prj set_device PGL22G-324 set_top cortex_m1_top add_files -global_include ./rtl add_files -constraints ./m1_top.fdc run synthesis run place run route generate_bitstream这段脚本里的set_top指明了设计顶层是cortex_m1_top后续所有引脚分配都在顶层接口上体现。add_files -constraints导入的约束文件至少需要包含时钟周期、引脚位置和 IO 电平标准三部分。PGL22 的引脚命名通常由工具自动从原理图导入如果你的板子没有配套约束模板需要手工对照原理图把clk_in、uart_tx、uart_rx、swclk、swdio这五个引脚先固定下来。生成 bit 流后下载到评估板并检查时钟引脚的 LED 是否按预期翻转这一步能确认综合后的工程确实落到目标器件上。3. 把 Cortex-M1 例化进 FPGAAHB-Lite 总线与内存映射的设计细节3.1 软核 M1 与硬核 Cortex-M 的差异Cortex-M1 是被 ARM 设计成可综合软核的 M 系列内核它和芯片里硬核 Cortex-M 的处理能力类似但有一个关键区别M1 的所有总线接口都以 AHB-Lite 从/主接口形式暴露在 RTL 里你可以在 FPGA 中自由决定哪个地址放 SRAM、哪个地址放外设甚至可以把外设直接映射到统一地址空间。这让 M1 更像一个可裁剪的 CPU 实例而不是固定地址映射的 MCU。实际工程中我通常使用 DesignStart 评估授权方式获得 M1 的 RTL拿到后先不做任何修改在顶层直接例化把所有 AHB 信号引到一个总线互联模块。使用软核时需要关注占用资源PGL22G 这类中小型器件上 M1 核加上最小 SRAM 和 UART/GPIOLUT 和寄存器消耗通常在百分之十几到百分之三十之间具体取决于是否包含调试逻辑和乘法指令。减少资源占用的常见做法是关闭不用的指令扩展例如不启用单周期乘法器但这会影响后续跑算法时的性能。我一般先保留默认配置等功能稳定后再针对性关掉权重较大的扩展选项直到综合报告里的资源占用落入项目预算内。3.2 M1 顶层例化与 AHB 信号命名约定ARM 提供的 M1 RTL 接口有几十个信号直接从顶层连出去很容易出错。我会在 M1 外面包一层cm1_wrapper把 HCLK、HRESETN、HADDR、HTRANS、HSIZE、HWRITE、HWDATA、HRDATA、HREADY、HSEL、HSELPP 等信号先整理成统一的内部总线命名再交给一个简单的 AHB-Lite 互联模块。这样做的好处是如果以后换用别的 AHB 主设备只需要改这一层 wrapper。下面是一个手写的最小例化片段CORTEXM1 #( define INSTR_REPLACE_BITS 0 ) u_m1 ( .HCLK (m1_hclk), .HRESETN (m1_reset_n), .HADDR (ahb_haddr), .HTRANS (ahb_htrans), .HSIZE (ahb_hsize), .HWRITE (ahb_hwrite), .HWDATA (ahb_hwdata), .HRDATA ({AHB_WIDTH{1b0}}), .HREADY (1b1), .HREADYOUT (), .HSEL (1b1), .HSELPP (1b1), .HRESP_S (1b0), .HRDATA_RX (ahb_hrdata), .HREADYIN (ahb_hready), .HMASTLOCK (), .HEXCLK (1b0), .NMI (1b1), .IRQ_DWT (1b0), .IRQ_EXT0 (1b0), .IRQ_EXT1 (1b0), .IRQ_CTI (1b0), .IRQ_PMU (1b0), .IRQ_PMU_OVFL (1b0), .IRQ_SYSTICK (1b0), .IRQ_SW (1b0) );这段代码的关键是把没有用到的只读数据总线接成常量同时把HREADY和HSEL先固定为高电平让 M1 在单主设备场景下直接访问整个地址空间。HRDATA_RX才是真正用于回读的写数据返回路径HREADYIN是外部总线给出的等待信号当外设比较慢时必须由互联模块拉低否则片内 RAM 读写跟不上时会丢数据。对于第一次上板验证不建议立即加多主设备固定HSEL1可以让 M1 的启动流程不受其他主设备仲裁干扰。3.3 SRAM、外设的地址映射与启动入口PGL22G 的片内 RAM 通过厂商的存储器 IP 生成器产生接口可以配置为 AHB-Lite 或者简单的双端口 RAM。为了让 M1 复位后能直接取指令需要把 SRAM 的起始地址放在0x00000000并将向量表和启动代码烧录到该地址。常见的做法是用分散加载文件把只读代码段定位到 SRAM 起始地址固件编译好后通过调试器写入片内 RAM再由复位释放后进入启动流程。映射关系建议如下地址范围用途0x00000000 - 0x0000FFFF片内 SRAM存放向量表和程序0x40000000 - 0x40000FFFUART 控制寄存器0x40001000 - 0x40001FFFGPIO 数据/方向寄存器0xE000E010 - 0xE000EFFFCortex-M 内核私有外设区内核私有外设区包括 SysTick、NVIC 和调试组件它在 M1 硬核内部已经实现不需要额外挂到 AHB 总线上。而 SRAM 和 GPIO/UART 都在总线互联模块中通过地址译码器分配HSEL信号。如果后续加上外部 SDRAM需要把该区域地址安排到不与 SRAM 冲突的位置并在 AHB 互联模块里插入等待周期这也是 M1 在国产 FPGA 上最容易出现访问超时的地方。4. 写外设与中断GPIO、UART 和 NVIC 之间的坑4.1 一个可写可读的 GPIO AHB-Lite 从模块外设寄存器挂在 AHB-Lite 上时必须遵守其传输规则当HTRANS为非 2b00 且HWRITE1时写入 HWDATA当HWRITE0时把数据驱动到 HRDATA并且用 HREADY 表示传输完成。M1 会连续发起多个传输若外设没有等待机制则必须保证一拍完成读写。最稳妥的做法是在外设内部把所有寄存器都用寄存器输出并让组合逻辑地址译码只产生寄存器写使能这一个信号。下面是 GPIO 外设的简化实现module gpio_ahb ( input wire HCLK, input wire HRESETN, input wire HSEL, input wire [11:0] HADDR, input wire [1:0] HTRANS, input wire HWRITE, input wire [31:0] HWDATA, output reg [31:0] HRDATA, output wire [7:0] gpio_out ); reg [7:0] gpio_data; wire reg_sel HSEL (HTRANS[0]); wire wr_sel reg_sel HWRITE; always (posedge HCLK or negedge HRESETN) begin if (!HRESETN) begin gpio_data 8b0000_0000; end else if (wr_sel) begin gpio_data HWDATA[7:0]; end end always (posedge HCLK or negedge HRESETN) begin if (!HRESETN) begin HRDATA 32b0; end else if (reg_sel !HWRITE) begin HRDATA {24b0, gpio_data}; end end assign gpio_out gpio_data; endmodule这段 Verilog 里reg_sel用 HSEL 与 HTRANS[0] 组合可以避免在 IDLE 总线周期产生多余的写操作。wr_sel只在写传输周期有效这样地址、数据和写使能天然对齐到 HCLK 上升沿。读取路径在非写周期把寄存器的当前值放到 HRDATA 上M1 在下一个时钟上升沿采集总线上的数据。如果你的外设被 AHB 仲裁器分配了较宽的地址间距比如 4KB那么HADDR只需取地址译码所需的高位不需要完整接入每个外设模块这样可以省下不少 LUT。GPIO 外设在设计时需要注意与 MCU 上 GPIO 的差异FPGA 侧方向控制需要额外寄存器实现。上面的代码是一个只读/只写的简单寄存器真实项目还会再加入方向寄存器和上拉使能寄存器。M1 没有像片上硬核那样直接给出 GPIO 启动状态复位瞬间所有 IO 都受 FPGA 约束控制默认应该是内部下拉或高阻避免驱动外部设备导致电流倒灌。4.2 UART 波特率产生与 AHB 状态机UART 外设比 GPIO 复杂因为它需要产生一个与系统时钟不同频率的波特率时钟。PGL22 评估板上如果用 50MHz 作为 HCLK那么 115200 波特率的分频数约等于 434 次整数溢出实际误差可以控制在允许范围内。UART 的 AHB 接口建议采用寄存器组方式软件通过写发送数据寄存器触发移位通过读状态寄存器判断忙标志。这里需要特别注意的是不要把波特率产生逻辑放在 AHB 总线的关键路径上而应当独立成一个计数器用 HCLK 沿触发这样不会导致回读时序延迟过长。reg [15:0] baud_div; reg [15:0] baud_cnt; wire baud_tick (baud_cnt 16d0); always (posedge HCLK or negedge HRESETN) begin if (!HRESETN) begin baud_cnt 16d0; end else if (baud_tick) begin baud_cnt baud_div - 16d1; end else begin baud_cnt baud_cnt - 16d1; end end这段代码实现了一个可重装的波特率分频器。每次baud_tick为高时计数器装载一次分频值等于在 AHB 时钟基础上产生一个窄脉冲这个脉冲可以分别用于发送移位寄存器和接收采样计数器。baud_div的值需要由软件在初始化阶段写入计算公式是HCLK_FREQ / baud_rate。由于 M1 的软件启动最早会从复位向量执行建议把 UART 初始化放到系统启动代码中并用轮询方式等待发送完成以免在中断未使能时丢失第一个字符。4.3 把中断控制器接到 NVIC 而不是自己写优先级M1 内部包含 NVIC但外部外设的中断请求需要通过IRQ_EXT0和IRQ_EXT1或者更多外部中断引脚送入内核。实际项目里通常把 UART 接收中断和定时器中断汇聚成多个向量通过写 NVIC 使能寄存器来开启。这里最常犯的错误是在 AHB 外设内部自行判断中断优先级再统一给 M1 一个中断信号这样会导致 NVIC 无法统计多个挂起中断也无法正确处理抢占。正确做法是让每个需要中断的外设都输出一个独立的中断请求信号在顶层把这些信号直接接到 M1 的中断输入上NVIC 的优先级完全由软件配置。中断在 M1 上还有一个特点外部中断默认是电平触发如果外设的中断源在中断服务程序还没读取状态寄存器时就一直被拉高NVIC 会认为事件仍未处理完成导致同一个中断反复进入。因此写外设时最好让中断请求信号读后自动清零或者提供一个写 1 清 0 的中断状态位。我用 UART 接收时会让接收数据有效标志同时作为中断源软件读走数据寄存器后硬件自动拉低这样中断服务程序结束前不需要额外写操作。5. 调试与验证把 M1 的启动状态从总线上“看”出来在 PGL22 评估板上调试 M1我通常会先用 GPIO 观察启动是否活着再连调试器。由于软核的 SWD 调试接口不是通过芯片内置调试访问端口直接暴露的而是由 ARM CoreSight 调试逻辑综合到 FPGA 中因此常见错误名no cortex-m sw device found往往不是调试器故障而是 M1 核心复位没有释放或调试时钟与内核时钟不是同一相位。调试器连接失败时先用逻辑分析仪抓 SWCLK 和 SWDIO 的电平变化确认目标板上确实有 50MHz 时钟并且 SWD 引脚没有被误设为其他功能。验证内核最直接的技巧是读取 CPUID 寄存器。M1 的 CPUID 地址固定在0xE000ED00复位后该寄存器会自动返回 ARM 定义的处理器 ID不需要安装额外外设。下面是一条可以在调试器命令行中执行的伪汇编通过 DAP 总线读取该地址并写入 GPIO 数据寄存器dap apreg write dp-sel 0x00000000 dap apreg write ap-sel 0x00000000 dap apreg read 0xE000ED00执行这条命令前需要确保调试器能够进入 JTAG/SWD 模式并且 M1 的调试组件已经上电。读取回来的值如果符合 M1 的 CPUID 编码说明内核时钟、复位和 AHB 总线三者已经完全正常工作。此时再用内存写命令向0x20000000写入一个简单的跳转指令配合复位向量表里的SP和PC值就能验证取指路径是否畅通。这个方法比直接看示波器上的 GPIO 翻转更准确因为它直达 CPU 内部。最后建议在综合时为 AHB 总线的HADDR、HWDATA、HREADY这三个信号加一两个观测点不需要抓完整总线就能在工具自带的波形窗口里看到 M1 复位后第一次访问内存时的地址序列。如果HADDR在复位后停留在0x00000000不再变化基本可以确定向量表内容没有正确写入 SRAM如果HREADY长期为低则需要回头检查 AHB 互联模块里的等待状态信号拼接优先级高于任何外设代码改动。本文还有配套的精品资源点击获取
返回列表