尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32与FPGA通过FSMC通信的时序协同与跨时钟域实现

STM32与FPGA通过FSMC通信的时序协同与跨时钟域实现 简介本资源是一份面向嵌入式开发工程师与STM32进阶学习者的FSMC通信技术详解文档聚焦STM32与FPGA之间的高速并行接口实现方案。文档系统阐述FSMC控制器架构、NOR Flash子BANK映射机制、外部SRAM类设备如FPGA的地址/时序配置要点并深入解析BCRi寄存器中MTYPE、MUXEN、MWID等关键位设置逻辑以及ADDSET、DATAST等时序参数的工程化计算方法。资源为单文件Word文档.doc共1个文件大小314KB内容完整覆盖引言、FSMC机制、SRAM配置流程、实例难点分析及代码映射示例如0x60000000地址写操作自动触发WE信号结构清晰、理论结合实践。目前已有201人学习下载适合需快速掌握STM32外设总线与FPGA协同设计、解决硬件接口调试与时序匹配问题的中级以上开发者。1. STM32与FPGA通过FSMC通信不是“接上线就通”而是时序、地址映射与状态协同的硬核握手很多工程师拿到“STM32和FPGA通过FSMC通信”这个需求时第一反应是查FSMC寄存器手册、配好GPIO复用、写几行*(uint16_t*)0x60000000 data就以为完事了——结果FPGA端收不到有效数据或STM32读回全0甚至总线锁死。根本原因在于FSMC不是UART那种带自动起停和校验的串行协议它是并行异步/同步总线接口本质是硬件级地址-数据-控制信号的严格时序协同。FPGA作为从设备必须精确建模FSMC的读写周期如Setup Time、Hold Time、Access Time、地址锁存时机、NWAIT采样窗口而STM32主控端若仅靠CubeMX自动生成初始化代码常忽略关键时序参数如Timing.AddressSetupTime设为0导致地址未稳定就发使能和总线宽度匹配FSMC_NORSRAM_InitTypeDef中DataAddressMux误设为ENABLE。本文面向已掌握STM32基础外设GPIO、RCC、时钟树和Verilog基础语法的嵌入式开发者不讲FSMC原理图符号定义只聚焦如何在Keil MDK Vivado 2022.2环境下用最小可验证设计跑通16位数据双向读写并定位三类高频失效点地址偏移错位、读写时序竞争、FPGA内部状态机未对齐FSMC时钟域。2. FSMC硬件连接与STM32端寄存器级配置从引脚复用到时序参数的逐项校准FSMC通信成败的第一道关卡是物理层信号连接与STM32寄存器配置的严丝合缝。常见错误是直接照抄某开发板原理图却忽略自己所用STM32型号如STM32F407ZGT6 vs STM32H743VI的FSMC引脚复用差异或误将FSMC_NBL0/1当作普通GPIO使用。本节以STM32F407ZGT6为例给出可直接复用的连接表与CubeMX不可替代的手动寄存器配置逻辑。2.1 FPGA侧关键信号定义与STM32引脚映射表FPGA作为FSMC从设备需响应以下核心信号。注意FSMC_NWAIT必须接FPGA输出且FPGA需在读操作中主动拉低该信号以插入等待周期这是实现可靠异步读取的关键而非简单悬空或上拉。STM32引脚F407ZGT6FSMC信号名FPGA端功能说明必须性备注PE7FSMC_D0数据线 bit0必须16位模式下D0-D15全部启用PE8FSMC_D1数据线 bit1必须—............D0-D15共16根数据线PD0FSMC_D2数据线 bit2必须—PD1FSMC_D3数据线 bit3必须—PD14FSMC_D0数据线 bit0替代可选若PE口被占用可重映射至PD口但需同步修改AFIO寄存器PD4FSMC_NOE输出使能读必须低电平有效FPGA据此启动读数据流程PD5FSMC_NWE写使能写必须低电平有效FPGA据此锁存数据PD7FSMC_NE1片选1Bank1必须低电平有效决定访问哪个NOR/PSRAM BankPD11FSMC_A16地址线 A16必须用于区分16MB空间内不同地址段FPGA解码关键PD12FSMC_A17地址线 A17必须同上与A16组合扩展地址范围PD13FSMC_A18地址线 A18必须—PD15FSMC_NWAIT等待请求必须FPGA输出STM32读操作时采样此信号为0则插入等待周期提示FPGA地址线实际只需接入A16-A18对应FSMC Bank1地址空间0x60000000–0x6FFF_FFFF无需全接A0-A24。FPGA内部用这3根线解码出4个独立寄存器区域如0x00: 控制寄存器, 0x02: 状态寄存器, 0x04: 数据输入寄存器, 0x06: 数据输出寄存器避免地址译码逻辑过载。2.2 CubeMX生成代码的致命缺陷与手动寄存器修正CubeMX对FSMC的配置存在两个硬伤一是默认将DataAddressMux设为ENABLE地址数据复用但FPGA无法处理AD0-AD15复用总线必须禁用二是Timing.AddressSetupTime常设为0导致地址信号在NE1下降沿前未建立稳定。必须在MX_FSMC_Init()函数后插入手动修正// 在 MX_FSMC_Init() 调用之后立即执行以下修正 FSMC_NORSRAM_TimingInitTypeDef Timing; Timing.AddressSetupTime 2; // 地址建立时间2个HCLK周期F407 HCLK168MHz即约11.9ns Timing.AddressHoldTime 1; // 地址保持时间1个HCLK周期 Timing.DataSetupTime 4; // 数据建立时间4个HCLK周期关键FPGA需此时间锁存数据 Timing.BusTurnAroundDuration 0; Timing.CLKDivision 0; Timing.DataLatency 0; FSMC_NORSRAM_InitTypeDef sram_init; sram_init.NSBank FSMC_NORSRAM_BANK1; // 使用Bank1 sram_init.DataAddressMux FSMC_DATA_ADDRESS_MUX_DISABLE; // 强制禁用复用 sram_init.MemoryType FSMC_MEMORY_TYPE_SRAM; // 类型为SRAMFPGA模拟 sram_init.MemoryDataWidth FSMC_NORSRAM_MEM_BUS_WIDTH_16; // 16位总线宽度 sram_init.BurstAccessMode FSMC_BURST_ACCESS_MODE_DISABLE; // 禁用突发简化时序 sram_init.WaitSignalPolarity FSMC_WAIT_SIGNAL_POLARITY_LOW; sram_init.WrapMode FSMC_WRAP_MODE_DISABLE; sram_init.WaitSignalActive FSMC_WAIT_TIMING_BEFORE_WS; sram_init.WriteOperation FSMC_WRITE_OPERATION_ENABLE; // 允许写操作 sram_init.WaitSignal FSMC_WAIT_SIGNAL_ENABLE; // 启用WAIT信号 sram_init.ExtendedMode FSMC_EXTENDED_MODE_ENABLE; // 启用扩展模式以配置读写时序 sram_init.AsynchronousWait FSMC_ASYNCHRONOUS_WAIT_DISABLE; sram_init.WriteBurst FSMC_WRITE_BURST_DISABLE; // 分别配置读/写时序关键CubeMX不支持单独设置 sram_init.ReadWriteTimingStruct Timing; sram_init.WriteTimingStruct Timing; // 读写时序相同也可差异化设置 HAL_SRAM_Init(hsram1, sram_init, Timing);注意Timing.DataSetupTime 4是经实测验证的底线值。若设为3FPGA在NWE下降沿采样数据时可能遇到亚稳态设为5虽更安全但降低吞吐率。该值需与FPGA内部always (negedge NWE)触发的数据锁存逻辑严格匹配。2.3 验证FSMC物理连接的三步法在烧录代码前必须用万用表/逻辑分析仪确认硬件连通性片选与使能信号验证向FSMC地址0x60000000写入任意值如*(__IO uint16_t*)0x60000000 0x55AA;用逻辑分析仪抓取PD7(NE1)、PD5(NWE)、PD4(NOE)波形确认NE1先拉低NWE在其后约10ns内下降沿触发地址线有效性检查向0x60000002写入0x1234向0x60000004写入0x5678观察PD11(A16)、PD12(A17)、PD13(A18)电平组合是否分别为001、010因0x022, 0x044A16-A18对应bit0-bit2数据线驱动能力测试短接STM32的PE7(D0)与PE8(D1)向0x60000000写入0x0001用万用表测PE7应为低电平0VPE8应为高电平3.3V排除PCB短路或GPIO驱动不足。3. FPGA端Verilog实现从时序建模到跨时钟域处理的完整状态机FPGA端不是被动接收信号而是必须主动建模FSMC的完整读写时序并解决STM32 HCLK168MHz与FPGA内部逻辑时钟常为50MHz的跨时钟域问题。本节基于Xilinx Artix-7系列如XC7A35T提供可综合、可调试的Verilog RTL代码重点解析三个易错模块FSMC时序状态机、地址译码器、跨时钟域同步器。3.1 FSMC读写状态机精确复现FSMC时序图FPGA需实现一个有限状态机FSM其状态转换严格遵循STM32 FSMC datasheet中的时序图。核心状态包括IDLE空闲、ADDR_DECODE地址译码、READ_SETUP读建立、READ_SAMPLE读采样、WRITE_SETUP写建立、WRITE_LATCH写锁存。关键约束是所有状态跳转必须由NE1、NOE、NWE的边沿驱动而非电平检测避免毛刺干扰。// FSMC顶层模块精简版含跨时钟域处理 module fsmc_interface ( input wire clk_50m, // FPGA主时钟50MHz input wire rst_n, // FSMC输入信号来自STM32 input wire ne1, // 片选低有效 input wire noe, // 读使能低有效 input wire nwe, // 写使能低有效 input wire nwait, // 等待请求低有效FPGA输出 input wire [18:16] addr_a, // A16-A183位地址线 inout wire [15:0] data_bus, // 16位双向数据总线 // FPGA内部寄存器接口 output reg [15:0] reg_ctrl, // 控制寄存器地址0x00 output reg [15:0] reg_status, // 状态寄存器地址0x02 input wire [15:0] reg_data_in, // 数据输入寄存器地址0x04 output reg [15:0] reg_data_out // 数据输出寄存器地址0x06 ); // 跨时钟域同步器将STM32信号同步到FPGA 50MHz时钟域 wire ne1_sync, noe_sync, nwe_sync, nwait_sync; sync_2ff #(.WIDTH(1)) sync_ne1 (.clk(clk_50m), .rst_n(rst_n), .din(ne1), .dout(ne1_sync)); sync_2ff #(.WIDTH(1)) sync_noe (.clk(clk_50m), .rst_n(rst_n), .din(noe), .dout(noe_sync)); sync_2ff #(.WIDTH(1)) sync_nwe (.clk(clk_50m), .rst_n(rst_n), .din(nwe), .dout(nwe_sync)); sync_2ff #(.WIDTH(1)) sync_nwait (.clk(clk_50m), .rst_n(rst_n), .din(nwait), .dout(nwait_sync)); // FSM状态定义 localparam IDLE 3b000; localparam ADDR_DECODE 3b001; localparam READ_SETUP 3b010; localparam READ_SAMPLE 3b011; localparam WRITE_SETUP 3b100; localparam WRITE_LATCH 3b101; reg [2:0] state, next_state; reg [15:0] data_out_reg; reg data_dir; // 0in, 1out // 主状态机 always (posedge clk_50m or negedge rst_n) begin if (!rst_n) state IDLE; else state next_state; end always (*) begin next_state state; case(state) IDLE: if (!ne1_sync) next_state ADDR_DECODE; // 检测NE1下降沿 ADDR_DECODE: next_state (noe_sync 0) ? READ_SETUP : (nwe_sync 0) ? WRITE_SETUP : IDLE; READ_SETUP: next_state READ_SAMPLE; READ_SAMPLE: next_state IDLE; WRITE_SETUP: next_state WRITE_LATCH; WRITE_LATCH: next_state IDLE; default: next_state IDLE; endcase end // 根据状态和地址驱动数据总线方向与内容 always (posedge clk_50m or negedge rst_n) begin if (!rst_n) begin data_dir 0; data_out_reg 16h0000; end else begin case(state) IDLE: begin data_dir 0; // 高阻态 data_out_reg 16h0000; end READ_SAMPLE: begin data_dir 1; // 输出使能 case(addr_a) 3b000: data_out_reg reg_ctrl; // 0x00 3b001: data_out_reg reg_status; // 0x02 3b010: data_out_reg reg_data_out; // 0x04 3b011: data_out_reg 16hDEAD; // 预留地址返回固定值 default: data_out_reg 16h0000; endcase end WRITE_LATCH: begin data_dir 0; // 输入模式 case(addr_a) 3b000: reg_ctrl data_bus; // 写控制寄存器 3b001: /* 状态寄存器只读忽略写 */ ; 3b010: reg_data_in data_bus; // 写数据输入寄存器 default: ; endcase end default: begin data_dir 0; data_out_reg 16h0000; end endcase end end // 双向数据总线驱动 assign data_bus (data_dir) ? data_out_reg : 16hz; // nwait输出仅在READ_SAMPLE状态且地址有效时拉低否则高阻由外部上拉电阻置高 assign nwait (state READ_SAMPLE (addr_a 3b000 || addr_a 3b001 || addr_a 3b010)) ? 1b0 : 1bz; endmodule // 跨时钟域同步器模块双触发器 module sync_2ff #( parameter WIDTH 1 ) ( input wire clk, input wire rst_n, input wire [WIDTH-1:0] din, output reg [WIDTH-1:0] dout ); reg [WIDTH-1:0] ff1, ff2; always (posedge clk or negedge rst_n) begin if (!rst_n) begin ff1 {WIDTH{1b0}}; ff2 {WIDTH{1b0}}; end else begin ff1 din; ff2 ff1; end end assign dout ff2; endmodule逻辑说明nwait信号被声明为wire并直接赋值而非reg是因为它需在READ_SAMPLE状态期间持续为低且必须由FPGA主动驱动不能依赖外部上拉。当state退出READ_SAMPLEnwait变为高阻态由外部10kΩ上拉电阻拉高符合FSMC规范。sync_2ff模块是跨时钟域同步的标准做法避免ne1等异步信号引发亚稳态导致状态机跑飞。3.2 地址译码与寄存器映射避免地址偏移的硬编码陷阱FPGA内部地址译码必须与STM32的FSMC Bank1基地址0x60000000严格对齐。常见错误是认为写0x60000000就对应FPGA地址0实则FSMC将0x60000000映射到A16-A18000因此FPGA只需用addr_a[2:0]即A18,A17,A16做3-8译码。下表为推荐的寄存器布局兼顾可读性与地址连续性STM32访问地址FSMC地址线A18-A16FPGA内部寄存器功能说明访问权限0x600000003b000reg_ctrl控制寄存器bit0软复位bit1启动数据采集R/W0x600000023b001reg_status状态寄存器bit0忙标志bit1数据就绪R-only0x600000043b010reg_data_in数据输入寄存器STM32写入FPGA读取W-only0x600000063b011reg_data_out数据输出寄存器FPGA写入STM32读取R-only注意0x60000002与0x60000004之间间隔2字节是因为FSMC按字16位寻址每个地址对应一个16位数据单元。若STM32代码中误用*(uint32_t*)0x60000000会因地址对齐错误导致读写异常。3.3 跨时钟域同步的深度实践为什么两个触发器不够尽管sync_2ff是标准方案但在FSMC场景下需额外警惕nwait信号由FPGA产生并反馈给STM32其变化沿必须被STM32在正确周期采样。若FPGA内部逻辑时钟50MHz与STM32 HCLK168MHz频率比非整数倍nwait的脉宽可能被采样为1或2个HCLK周期导致STM32误判等待周期数。解决方案是在FPGA端增加脉宽展宽逻辑// 在fsmc_interface内部添加 reg [3:0] nwait_counter; reg nwait_prolonged; always (posedge clk_50m or negedge rst_n) begin if (!rst_n) begin nwait_counter 4d0; nwait_prolonged 1b0; end else begin if (state READ_SAMPLE (addr_a 3b000 || addr_a 3b001 || addr_a 3b010)) begin nwait_counter 4d15; // 保持nwait低电平至少15个50MHz周期300ns nwait_prolonged 1b1; end else if (nwait_counter 0) begin nwait_counter nwait_counter - 1; nwait_prolonged 1b1; end else begin nwait_prolonged 1b0; end end end assign nwait nwait_prolonged ? 1b0 : 1bz;此逻辑确保nwait低电平宽度≥300ns远超STM32 FSMC最小要求典型值25ns彻底规避因时钟异步导致的采样失败。4. STM32端C语言驱动与FPGA端联合调试用寄存器读写验证通信链路驱动编写不是简单指针赋值而是要构建一套可验证、可追踪、可复位的通信框架。本节提供完整的C语言驱动模板并详解如何用J-Link RTT和逻辑分析仪进行四层联合调试信号层、寄存器层、时序层、应用层直击“写进去读不出”的核心痛点。4.1 可调试的FSMC驱动封装带状态检查与超时机制直接操作*(uint16_t*)0x60000000缺乏错误反馈。以下驱动封装强制每次读写后检查FPGA返回的状态寄存器并内置超时保护避免程序卡死。// fsmc_driver.h #ifndef FSMC_DRIVER_H #define FSMC_DRIVER_H #include stm32f4xx_hal.h #define FSMC_BASE_ADDR 0x60000000U #define CTRL_REG_ADDR (FSMC_BASE_ADDR 0x00U) // 控制寄存器 #define STATUS_REG_ADDR (FSMC_BASE_ADDR 0x02U) // 状态寄存器 #define DATA_IN_REG_ADDR (FSMC_BASE_ADDR 0x04U) // 数据输入寄存器 #define DATA_OUT_REG_ADDR (FSMC_BASE_ADDR 0x06U) // 数据输出寄存器 typedef enum { FSMC_OK 0, FSMC_TIMEOUT, FSMC_BUSY, FSMC_ERROR } FSMC_StatusTypeDef; FSMC_StatusTypeDef FSMC_WriteCtrlReg(uint16_t value); FSMC_StatusTypeDef FSMC_ReadStatusReg(uint16_t *value); FSMC_StatusTypeDef FSMC_WriteDataIn(uint16_t value); FSMC_StatusTypeDef FSMC_ReadDataOut(uint16_t *value); #endif // fsmc_driver.c #include fsmc_driver.h #include main.h // 包含hsram1句柄 // 超时计数单位ms #define FSMC_TIMEOUT_MS 100 FSMC_StatusTypeDef FSMC_WriteCtrlReg(uint16_t value) { __IO uint16_t *ctrl_reg (__IO uint16_t*)CTRL_REG_ADDR; *ctrl_reg value; // 写入后立即读状态寄存器确认FPGA已接收 HAL_Delay(1); // 简单延时确保FPGA有足够时间更新状态 return FSMC_ReadStatusReg(NULL); } FSMC_StatusTypeDef FSMC_ReadStatusReg(uint16_t *value) { __IO uint16_t *status_reg (__IO uint16_t*)STATUS_REG_ADDR; uint32_t timeout HAL_GetTick(); while (1) { uint16_t status *status_reg; if (value ! NULL) *value status; // 检查忙标志bit0若为0表示空闲 if ((status 0x0001) 0) { return FSMC_OK; } if ((HAL_GetTick() - timeout) FSMC_TIMEOUT_MS) { return FSMC_TIMEOUT; } HAL_Delay(1); } } FSMC_StatusTypeDef FSMC_WriteDataIn(uint16_t value) { __IO uint16_t *data_in_reg (__IO uint16_t*)DATA_IN_REG_ADDR; *data_in_reg value; return FSMC_OK; // 数据输入寄存器为W-only无状态反馈 } FSMC_StatusTypeDef FSMC_ReadDataOut(uint16_t *value) { __IO uint16_t *data_out_reg (__IO uint16_t*)DATA_OUT_REG_ADDR; uint32_t timeout HAL_GetTick(); while (1) { *value *data_out_reg; // 检查数据就绪标志bit1 uint16_t status; if (FSMC_ReadStatusReg(status) ! FSMC_OK) return FSMC_TIMEOUT; if ((status 0x0002) ! 0) { // bit11表示数据就绪 return FSMC_OK; } if ((HAL_GetTick() - timeout) FSMC_TIMEOUT_MS) { return FSMC_TIMEOUT; } HAL_Delay(1); } }参数说明FSMC_TIMEOUT_MS设为100ms是经验安全值。若FPGA处理耗时超过此值说明内部逻辑存在死循环或时序错误需回溯Verilog代码。HAL_Delay(1)在调试阶段保留量产时可替换为更精确的DWT周期计数。4.2 四层联合调试法从波形到寄存器的逐级穿透当驱动调用返回FSMC_TIMEOUT按以下顺序排查每层耗时不超过5分钟调试层级工具关键操作预期现象失败含义信号层逻辑分析仪如Saleae抓取NE1,NWE,NOE,A16-A18,D0-D15NE1下降沿后A16-A18在NWE/NOE有效前稳定D0-D15在NWE下降沿锁存地址或数据线未建立检查STM32 GPIO复用配置或FPGA地址译码逻辑寄存器层J-Link RTT printf在FSMC_ReadStatusReg()中添加printf(Status0x%04X\r\n, status);打印值如0x0002数据就绪或0x0000空闲若始终打印0x0000说明FPGA未进入READ_SAMPLE状态检查ne1_sync同步是否失败时序层示波器Ch1:NE1, Ch2:nwait观察nwait低电平宽度宽度≥300ns对应FPGA 50MHz下15周期宽度不足检查FPGAnwait_prolonged逻辑是否被综合掉或clk_50m未正确约束应用层STM32CubeIDE调试器在FSMC_WriteDataIn()后设置断点查看data_in_reg地址处内存值内存窗口显示写入值如0x1234若显示0x0000说明FSMC总线未激活检查HAL_SRAM_Init()返回值是否为HAL_OK提示在main()中首次调用FSMC_WriteCtrlReg(0x0001)软复位后务必调用FSMC_ReadStatusReg()并打印结果。若返回0x0000证明通信链路已通若返回0xFFFF极可能是FPGA未上电或JTAG下载失败。4.3 实战案例用FSMC传输ADC采样数据流验证通信可靠性的终极方法是持续数据流。以下代码在STM32端每10ms通过FSMC向FPGA发送一个16位ADC值并读取FPGA处理后的FFT幅值// main.c 中添加 extern SRAM_HandleTypeDef hsram1; uint16_t adc_value 0; uint16_t fft_magnitude 0; while (1) { // 1. 读取ADC假设已配置好HAL_ADC_Start() HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 10); adc_value HAL_ADC_GetValue(hadc1); // 2. 写入FPGA数据输入寄存器 if (FSMC_WriteDataIn(adc_value) ! FSMC_OK) { Error_Handler(); // 通信中断 } // 3. 等待FPGA处理完成状态寄存器bit1置位 if (FSMC_ReadStatusReg(NULL) ! FSMC_OK) { Error_Handler(); } // 4. 读取FPGA计算的FFT幅值 if (FSMC_ReadDataOut(fft_magnitude) FSMC_OK) { // 将fft_magnitude通过UART发送到PC用串口助手观察波形 char buf[32]; sprintf(buf, ADC%d, FFT%d\r\n, adc_value, fft_magnitude); HAL_UART_Transmit(huart2, (uint8_t*)buf, strlen(buf), 100); } HAL_Delay(10); }此案例将FSMC从“静态寄存器访问”升级为“实时数据通道”暴露了高负载下的时序瓶颈。若HAL_Delay(10)缩短至1FPGA可能来不及处理FSMC_ReadDataOut()将超时——这正是优化FPGA内部流水线深度的明确信号。5. 常见失效模式与根因定位表三分钟锁定90%的通信故障FSMC与FPGA通信的故障具有高度模式化。本节将高频问题浓缩为一张可快速查阅的根因定位表每项均标注验证命令、关键寄存器地址及FPGA Verilog修复点避免在错误方向上浪费数小时。现象可能根因验证命令/操作关键寄存器/信号FPGA修复点STM32修复点向0x60000000写入后读0x60000002始终返回0xFFFFFPGA未上电或JTAG配置失败用万用表测FPGA VCCINT电压检查JTAG链是否识别到器件nwait信号应为高阻态检查sync_2ff模块是否被综合工具优化掉添加(* keep *)属性检查HAL_SRAM_Init()返回值若为HAL_ERROR确认hsram1.Instance是否指向正确FSMC寄存器基址逻辑分析仪看到NE1下降沿但A16-A18电平全为高STM32地址线GPIO未正确复用HAL_GPIO_Init()中检查GPIO_InitStruct.Alternate是否设为GPIO_AF12_FSMCGPIOE-AFR[0]PE7-PE9无在CubeMX中勾选“FSMC”并生成代码或手动设置GPIOE-AFR[0] 0xCCCCCCCC;CAF12FSMC_ReadDataOut()超时但FSMC_ReadStatusReg()返回0x0002FPGA内部reg_data_out未被正确赋值在Vivado中添加ILA核监控reg_data_out信号reg_data_out寄存器输出检查WRITE_LATCH状态是否触发了reg_data_in写入但reg_data_out更新逻辑缺失无属FPGA逻辑缺陷STM32读0x60000006返回随机值非0xDEADFPGA数据总线方向控制错误用逻辑分析仪抓D0-D15看其在NOE有效时是否为高阻态data_dir信号检查state READ_SAMPLE时data_dir是否为1以及data_bus赋值是否正确无通信初期正常运行10分钟后突然卡死FPGA跨时钟域同步失败导致状态机跑飞在ILA中观察state寄存器看其是否进入非法状态如3b111state寄存器在状态机default分支中强制回到IDLE并添加$display(FSMC FSM error!)仿真提示无属FPGA鲁棒性设计缺陷最后一行技术内容当state进入非法状态时在Verilog中添加default: next_state IDLE;并配合ILA触发条件state 3本文还有配套的精品资源点击获取
返回列表