AD9361项目Flash双冗余系统设计与实现指南
目录
1. 项目概述
1.1 功能简介
本项目基于Xilinx Zynq-7000平台开发的AD9361射频系统,实现了在单一QSPI Flash芯片上存储两套不同程序并通过网络接口远程选择启动程序的功能。这种设计为系统提供了双重冗余保障,特别适用于无法现场操作或需要远程维护的应用场景。
系统通过以太网UDP协议接收特定命令,根据命令内容选择从Flash的主区域或备份区域启动,无需增加额外的Flash芯片,大大提高了系统的可靠性和可维护性。
1.2 应用场景
- 远程部署设备:位于偏远地区或难以到达的设备,可通过网络远程切换程序
- 高可靠性系统:需要双冗余保障的关键设备,如通信基站、监控系统等
- 持续运行系统:需要在线升级但不能长时间中断的系统
- 射频信号处理系统:基于AD9361的无线通信设备,需要灵活切换不同协议栈
1.3 主要特点
- 双重冗余存储:在单一Flash芯片上划分两个独立区域,分别存储主程序和备份程序
- 远程切换能力:通过以太网UDP协议发送命令控制启动程序的选择
- 无需硬件冗余:不增加额外的Flash芯片,降低硬件复杂度和成本
- 系统可靠性提升:在主程序出现问题时,可立即切换到备份程序继续运行
- 兼容原有系统:对原有硬件系统改动小,易于集成
- 完整开发支持:提供命令格式定义、工具示例及详细操作文档
2. 系统硬件架构
2.1 硬件平台
该项目基于Vivado 2018.3开发环境,在Xilinx Zynq-7000系列FPGA平台上实现。主要硬件组件包括:
- 处理系统(PS):Zynq-7000系列SoC,集成ARM Cortex-A9双核处理器
- 可编程逻辑(PL):实现自定义逻辑和接口控制
- AD9361射频收发器:高性能RF前端,支持2x2 MIMO操作
- QSPI Flash:系统启动和程序存储介质,典型容量16-32MB
- DDR内存:系统运行时数据存储,典型容量512MB-1GB
- 以太网接口:10G以太网PHY,用于高速数据传输和远程控制
2.2 硬件连接图
+---------------+ +---------------+ +-----------------+
| | | | | |
| 以太网 |---->| 网卡PHY |---->| FPGA/Zynq SoC |
| (RJ45) | | (10G/1G) | | |
| | | | | |
+---------------+ +---------------+ |------+----------+
| |
+---------------+ +---------------+ | |
| | | | | |
| JTAG接口(烧写) |---->| QSPI Flash |<---+ |
| | | | |
+---------------+ +---------------+ |
|
+---------------+ |
| | |
| AD9361模块 |<-----------+
| |
+---------------+
2.3 系统逻辑框图
双冗余Flash系统的逻辑结构如下:
+---------------------+ +-------------------+ +-------------------+
| | | | | |
| 网络命令(UDP包) +---->+ 以太网控制器 +---->+ Flash选择逻辑 |
| | | | | (GPIO寄存器) |
+---------------------+ +-------------------+ +------+------------+
|
v
+---------------------+ +-------------------+ +------+------------+
| | | | | |
| 处理系统(PS) <-----+ First Stage <-----+ QSPI Flash |
| ARM Cortex-A9 | | Boot Loader | | (双区域存储) |
+---------------------+ +-------------------+ +-------------------+
| / \
| / \
v v v
+---------------------+ +----------+---+ +-----+--------+
| | | | | |
| AD9361/应用程序 | | 主程序区域 | | 备份程序区域 |
| | | (0x0) | | (0x800000) |
+---------------------+ +--------------+ +--------------+
3. 双冗余实现原理
3.1 技术概述
本项目实现了在单一QSPI Flash芯片上存储两套不同程序的冗余机制。通过合理的存储空间划分和特定的引导逻辑,系统可以根据网络命令或硬件信号选择从Flash的不同区域启动程序。这种方式不需要额外的硬件,只通过软件和固件修改实现双重保障。
3.2 存储区域划分示意图
Flash存储区域划分如下图所示:
+----------------------------+ 0x000000
| |
| |
| 主程序区域 |
| |
| |
+----------------------------+ 0x800000 (默认偏移地址)
| |
| |
| 备份程序区域 |
| |
| |
+----------------------------+ Flash末尾(视容量而定)
在同一片QSPI Flash上,我们采用以下区域划分方案:
- 主程序区域:从Flash起始地址(0x0)开始,用于存储主要系统程序
- 备份程序区域:从Flash的偏移地址(默认0x800000,8MB处)开始,用于存储备份系统程序
每个区域存储的内容结构完全相同,包括:
- First Stage Boot Loader (FSBL)
- FPGA比特流文件(bitstream)
- U-Boot/应用程序
- 配置文件等
3.3 启动选择机制详解
系统启动过程中的程序选择机制如下:
- 加电复位:系统加电或复位后,处理器开始执行内部BootROM
- 读取选择标志:修改后的FSBL在初始化阶段读取Flash选择寄存器值
- 判断区域:根据标志值(0或1)确定启动区域:
- 标志为0:从主程序区域(0x0)加载程序
- 标志为1:从备份程序区域(0x800000)加载程序
- 程序加载:FSBL从选定区域加载后续程序(比特流、应用程序等)
- 系统启动:完成程序加载后,控制权交给应用程序,系统正常运行
3.4 启动流程时序图
上电/复位 FSBL初始化 读取选择标志 加载程序 系统运行
| | | | |
| | | | |
v v v v v
+------+------+ +---+----+ +-----+------+ +---+----+ +----+-----+
| | | | | | | | | |
| BootROM执行 |-->| 初始化 |-->| 检查标志位 |-->| 加载 |-->| 应用程序 |
| | | 硬件 | | (GPIO) | | 程序区 | | 运行 |
+-------------+ +--------+ +-----+------+ +---+----+ +----------+
| ^
| / \
v / \
+------+------+ / \
| | / \
| 确定启动区域 |--+ |
| | | |
+------+------+ | |
/ \ | |
/ \ | |
v v v |
+-------+ +-------+----- |
| | | | |
| 主区域 | | 备份区域 |←---+
| (0x0) | | (0x800000) |
+-------+ +------------+
4. 详细设计与实现
4.1 UDP通信模块设计
UDP通信模块负责接收网络命令并解析Flash启动选择指令。此部分是实现远程控制功能的核心,由以下几个子模块组成:
4.1.1 UDP顶层模块(udp_look_back)
该模块实现了以太网物理层和数据链路层接口,负责UDP数据包的收发。主要功能:
- 初始化以太网控制器
- 管理数据包收发
- 提供Flash选择信号接口
module udp_look_back(
// 系统接口
input sys_clk_i,
// 以太网物理接口
input gtrefclk1_p, gtrefclk1_n,
output [0:0] sfp_tx_p, sfp_tx_n,
input [0:0] sfp_rx_p, sfp_rx_n,
// UDP数据接口
input [63:0] udp_rx_data,
input udp_rx_data_valid,
// Flash选择输出 - 添加的新接口
output flash_sel,
output flash_sel_valid
);
// 内部逻辑...
// 将channel_wrapper的信号连接到外部接口
channel_wrapper channel_wrapper_i(
// 其他连接...
.flash_sel (flash_sel),
.flash_sel_valid (flash_sel_valid)
);
endmodule
4.1.2 通道包装模块(channel_wrapper)
该模块封装了UDP协议栈,处理具体的数据包解析与转发。主要功能:
- UDP数据包处理
- 协议状态管理
- 数据分包与组包
- Flash指令解析与转发
module channel_wrapper(
// 系统接口
input coreclk,
input areset_n,
// MAC层接口
output m_axis_tx_tvalid,
input m_axis_tx_tready,
// 数据接口
input [63:0] udp_rx_data,
input udp_rx_data_valid,
// Flash选择信号 - 添加的新接口
output flash_sel,
output flash_sel_valid
);
// 内部逻辑...
// 实例化UDP接收模块,处理命令解析
udp_rx udp_rx_inst (
// 其他连接...
.flash_sel (flash_sel),
.flash_sel_valid (flash_sel_valid)
);
endmodule
4.1.3 UDP接收模块(udp_rx)
该模块实现了网络命令解析功能,是双冗余实现的核心部分。代码示例:
module udp_rx #(
parameter [15:0] LOCAL_PORT = 16'd5000, // 本地UDP端口号
// 其他参数...
)(
// 系统和数据接口...
// Flash选择输出 - 新增接口
output reg flash_sel = 1'b0, // Flash启动选择信号: 0-主程序, 1-备份程序
output reg flash_sel_valid = 1'b0 // Flash选择有效标志
);
// UDP命令解析常量定义
localparam CMD_FLASH_SEL_MAIN = 32'hF1A5_0000; // 选择主程序命令
localparam CMD_FLASH_SEL_BACKUP = 32'hF1A5_0001; // 选择备份程序命令
// 内部状态和逻辑...
// 命令解析逻辑
always @(posedge clk) begin
if (!rst_n) begin
flash_sel <= 1'b0;
flash_sel_valid <= 1'b0;
end else begin
// 当接收到完整的UDP包时,检查是否包含Flash启动选择命令
if (udp_rx_cnt >= 4) begin // 确保已接收到至少4字节数据(命令字)
// 检查数据包前32位是否为Flash选择命令
if (udp_rx_data[0:31] == CMD_FLASH_SEL_MAIN) begin
flash_sel <= 1'b0; // 选择主程序
flash_sel_valid <= 1'b1; // 设置命令有效标志
end else if (udp_rx_data[0:31] == CMD_FLASH_SEL_BACKUP) begin
flash_sel <= 1'b1; // 选择备份程序
flash_sel_valid <= 1'b1; // 设置命令有效标志
end
end else if (udp_rx_cnt == 0) begin
// 在新数据包开始时复位命令有效标志
flash_sel_valid <= 1'b0;
end
end
end
endmodule
该模块核心功能是识别特定的命令码并生成相应的Flash选择信号。当收到选择主程序命令(0xF1A5_0000)时,设置flash_sel
为0;当收到选择备份程序命令(0xF1A5_0001)时,设置flash_sel
为1。
4.2 Flash启动控制实现
Flash启动控制相关部分负责管理Flash选择信号并修改启动过程,主要由以下部分组成:
4.2.1 顶层模块(AD9361_prj)
顶层模块将网络解析出的Flash选择信号连接到硬件引脚,并维护当前的选择状态:
module AD9361_prj(
// 标准系统接口
input [14:0]DDR_addr,
// 其他标准接口...
// Flash启动控制信号 - 新增接口
output flash_sel_pin, // Flash启动选择引脚
output flash_program_pin // Flash编程启动信号
);
// 内部信号声明
// ...
// Flash双重启动控制信号
wire flash_sel;
wire flash_sel_valid;
// 状态寄存器,保存当前Flash启动状态
reg flash_sel_reg = 1'b0;
reg flash_program_reg = 1'b0;
// 当收到有效的Flash选择信号时,更新状态寄存器
always @(posedge ui_clk) begin
if (flash_sel_valid) begin
flash_sel_reg <= flash_sel; // 保存当前选择状态
flash_program_reg <= 1'b1; // 触发Flash编程信号脉冲
end else begin
flash_program_reg <= 1'b0; // 复位Flash编程信号
end
end
// 将状态寄存器连接到输出引脚
assign flash_sel_pin = flash_sel_reg;
assign flash_program_pin = flash_program_reg;
// 实例化UDP模块,接收网络命令
udp_look_back udp_look_back_inst (
// 其他连接...
.flash_sel(flash_sel),
.flash_sel_valid(flash_sel_valid)
);
// 其他模块实例化...
endmodule
该模块的主要功能是:
- 接收UDP模块解析出的Flash选择信号
- 将选择状态保存在寄存器中
- 生成编程信号脉冲,通知系统更新配置
- 通过物理引脚输出选择和编程信号
4.2.2 First Stage Boot Loader修改
FSBL代码修改是实现双冗余启动的关键部分,主要修改了以下文件:
1) qspi.h - 增加双冗余区域定义
/*
* 双冗余Flash区域定义
*/
/* Flash区域定义 */
// 双重Flash区域偏移量 - 在Flash的中间位置开始存放备份程序
#define FLASH_BACKUP_OFFSET 0x800000 // 8MB偏移量,根据实际Flash大小可调整
#define FLASH_SEL_REG_ADDR 0x43C00000 // Flash选择寄存器地址,需要与PS端GPIO映射一致
// Flash选择标志
#define FLASH_SEL_MAIN 0 // 选择主程序区域
#define FLASH_SEL_BACKUP 1 // 选择备份程序区域
此头文件定义了关键的偏移量和寄存器地址。FLASH_BACKUP_OFFSET
指定了备份程序的起始地址,默认设为8MB(0x800000)。FLASH_SEL_REG_ADDR
指定了存储选择标志的寄存器地址。
2) qspi.c - 修改Flash访问函数,实现从不同区域读取
/**
* QspiAccess - 提供QSPI Flash访问功能,支持双区域启动
*
* @param SourceAddress 要读取的Flash地址
* @param DestinationAddress 目标内存地址
* @param LengthBytes 要读取的字节数
*
* @return XST_SUCCESS 成功, XST_FAILURE 失败
*/
u32 QspiAccess(u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes)
{
u32 FlashSel;
u32 SrcAddr;
u32 Length;
u32 BankSel;
u32 Status;
// 读取Flash选择标志
FlashSel = Xil_In32(FLASH_SEL_REG_ADDR);
// 根据标志调整源地址
if (FlashSel == FLASH_SEL_BACKUP) {
fsbl_printf(DEBUG_INFO, "Booting from backup flash region (offset: 0x%08x)\r\n",
FLASH_BACKUP_OFFSET);
SrcAddr = SourceAddress + FLASH_BACKUP_OFFSET;
} else {
fsbl_printf(DEBUG_INFO, "Booting from main flash region\r\n");
SrcAddr = SourceAddress;
}
// 线性模式访问处理
if (LinearBootDeviceFlag == 1) {
// 银行选择逻辑 (用于大容量Flash)
if (QspiFlashSize > FLASH_SIZE_16MB) {
BankSel = SrcAddr/FLASH_SIZE_16MB;
Status = SendBankSelect(BankSel);
if (Status != XST_SUCCESS) {
fsbl_printf(DEBUG_INFO, "Bank selection Failed\r\n");
return XST_FAILURE;
}
}
// 处理地址超过16MB的情况
if (SrcAddr >= FLASH_SIZE_16MB) {
SrcAddr = SrcAddr % FLASH_SIZE_16MB;
}
// 计算当前银行的读取长度
if ((SrcAddr + LengthBytes) > FLASH_SIZE_16MB) {
Length = FLASH_SIZE_16MB - SrcAddr;
} else {
Length = LengthBytes;
}
// 读取数据
memcpy((void*)DestinationAddress,
(void*)(FlashReadBaseAddress + SrcAddr),
Length);
// 处理跨银行读取
if((SrcAddr + LengthBytes) > FLASH_SIZE_16MB){
memcpy((void*)(DestinationAddress + Length),
(void*)(FlashReadBaseAddress),
LengthBytes - Length);
}
}
// 非线性模式访问逻辑...
return XST_SUCCESS;
}
此函数的修改是双冗余功能的核心,主要逻辑是:
- 读取Flash选择标志
- 如果选择备份区域,将源地址加上偏移量
- 处理Flash银行选择和地址映射
- 执行实际的数据读取操作
3) main.c - 初始化阶段检查Flash选择标志
int main(void)
{
u32 BootModeRegister = 0;
u32 Status = XST_SUCCESS;
u32 RegVal;
// 映射Flash选择信号寄存器
// 将物理I/O地址映射到PS可访问区域
Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR, 0x00000000); // 设置GPIO为输入模式
// PS7初始化...
// 在初始化阶段显示Flash选择信息
RegVal = Xil_In32(FLASH_SEL_REG_ADDR);
if (RegVal == FLASH_SEL_BACKUP) {
fsbl_printf(DEBUG_GENERAL, "Boot Mode: QSPI Flash Backup Region\r\n");
} else {
fsbl_printf(DEBUG_GENERAL, "Boot Mode: QSPI Flash Main Region\r\n");
}
// 正常的FSBL启动流程...
}
main.c的修改主要是:
- 初始化GPIO寄存器,使其能够读取Flash选择信号
- 在启动早期读取并显示当前的启动区域
4.2.3 硬件信号连接
为了将Flash选择信号连接到物理引脚,在约束文件(AD9361_prj.xdc)中添加了相应的引脚定义:
# Flash启动选择引脚和编程信号引脚
# 选择引脚:指示当前使用的Flash区域(0=主区域, 1=备份区域)
set_property PACKAGE_PIN G15 [get_ports flash_sel_pin]
set_property IOSTANDARD LVCMOS25 [get_ports flash_sel_pin]
# 编程信号引脚:触发更新Flash选择状态
set_property PACKAGE_PIN G16 [get_ports flash_program_pin]
set_property IOSTANDARD LVCMOS25 [get_ports flash_program_pin]
这些约束将flash_sel_pin
和flash_program_pin
信号分别映射到FPGA的G15和G16引脚,使用LVCMOS25电平标准。可根据实际硬件设计调整引脚分配。
4.3 数据流程图
下图展示了Flash选择命令从网络接收到系统启动的完整数据流:
+----------------+ +----------------+ +----------------+ +----------------+
| | | | | | | |
| UDP网络命令 |--->| UDP数据包解析 |--->| Flash选择标志 |--->| GPIO引脚输出 |
| 0xF1A50000/1 | | (udp_rx模块) | | (寄存器存储) | | (物理连接) |
| | | | | | | |
+----------------+ +----------------+ +----------------+ +----------------+
|
| 系统重启
v
+----------------+ +----------------+ +----------------+ +----------------+
| | | | | | | |
| 系统正常运行 |<---| 应用程序加载 |<---| FSBL读取选择 |<---| 读取GPIO状态 |
| (选定的程序) | | (从选定区域) | | (QspiAccess) | | (寄存器值) |
| | | | | | | |
+----------------+ +----------------+ +----------------+ +----------------+
5. 使用指南
5.1 环境准备
在使用双冗余Flash系统前,需要准备以下开发环境和工具:
工具/环境 | 版本 | 用途 |
---|---|---|
Vivado | 2018.3 | FPGA设计、综合、实现及Flash编程 |
Xilinx SDK | 2018.3 | 软件开发、FSBL编译及BOOT.bin生成 |
Wireshark | 任意 | 网络数据包分析,验证UDP命令 |
网络测试工具 | netcat/Python | 发送UDP命令测试 |
JTAG下载器 | Xilinx兼容 | 连接目标板进行编程 |
串口终端 | PuTTY/SecureCRT等 | 系统调试信息查看 |
开发环境搭建步骤:
- 安装Xilinx Vivado 2018.3及SDK
- 配置Vivado开发环境和安装板卡支持包
- 准备网络连接,确保可以与目标板通信
- 安装串口驱动,确保可以查看调试信息
5.2 项目构建流程
完成双冗余系统的整体构建流程如下:
-
FPGA设计修改
- 添加Flash选择逻辑
- 更新UDP命令解析模块
- 添加Flash选择信号输出
-
FSBL修改
- 修改Flash访问逻辑支持双区域
- 添加选择标志检测代码
-
系统编译与生成
- 综合、实现FPGA设计
- 生成比特流
- 编译修改后的FSBL
- 创建BOOT.bin文件
-
系统测试与部署
- 烧写主区域程序
- 烧写备份区域程序
- 测试网络命令切换功能
5.3 程序烧写详细步骤
5.3.1 主程序烧写
以下是将主程序烧写到Flash主区域的步骤:
-
准备BOOT.bin文件
- 在SDK中,选择
File -> New -> Application Project
- 选择FSBL和应用程序
- 右键项目,选择
Create Boot Image
- 选择组件:FSBL、FPGA比特流、应用程序
- 生成BOOT.bin文件
- 在SDK中,选择
-
烧写主区域
- 通过JTAG连接开发板
- 打开Vivado Hardware Manager
- 右键点击目标设备,选择
Add Configuration Memory Device
- 从列表中选择正确的Flash型号(查看开发板文档确认)
- 在出现的对话框中设置以下参数:
- 选择BOOT.bin文件
- 起始地址设为
0x0
(默认) - 选择"执行擦除"
- 点击"Program"开始烧写,等待完成
5.3.2 备份程序烧写
备份程序的烧写过程与主程序类似,但关键是要设置正确的偏移地址:
-
准备备份BOOT.bin文件
- 可以使用与主程序相同的BOOT.bin或创建不同版本
- 对于测试,可以修改应用程序以区分不同版本(如启动信息)
-
烧写备份区域
- 通过JTAG连接开发板
- 打开Vivado Hardware Manager
- 右键点击目标设备,选择
Add Configuration Memory Device
- 选择与主程序相同的Flash型号
- 在对话框中设置:
- 选择备份版本的BOOT.bin文件
- 关键步骤: 将起始地址设为
0x800000
(或您自定义的偏移量) - 选择"不执行擦除"选项(避免擦除主程序区域)
- 点击"Program"开始烧写
-
使用命令行工具烧写(可选)
如果Vivado界面无法直接设置偏移地址,可以使用Vivado提供的命令行工具:
# 连接到硬件
open_hw
connect_hw_server
open_hw_target
# 添加Flash设备
create_hw_cfgmem -hw_device [current_hw_device] -mem_dev [lindex [get_cfgmem_parts {mt25qu128-spi-x1_x2_x4}] 0]
# 设置属性
set_property PROGRAM.ADDRESS_RANGE {use_file} [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
set_property PROGRAM.FILES [list "path/to/backup/BOOT.bin" ] [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
set_property PROGRAM.BLANK_CHECK 0 [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
set_property PROGRAM.ERASE 0 [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
set_property PROGRAM.CFG_PROGRAM 1 [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
set_property PROGRAM.VERIFY 1 [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
# 关键属性 - 设置起始偏移地址
set_property PROGRAM.START_ADDRESS 0x00800000 [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
# 执行烧写
program_hw_cfgmem -hw_cfgmem [ get_property PROGRAM.HW_CFGMEM [current_hw_device]]
5.4 网络命令详解
5.4.1 命令格式详细说明
UDP命令包格式如下:
+-------------------------+------------------------+-----------------+
| 命令识别码 (4字节) | 保留字段 (4字节) | 数据 (可选) |
| 0xF1A5_0000/0xF1A5_0001 | 0x00000000 | ... |
+-------------------------+------------------------+-----------------+
命令包字段说明:
字段 | 长度 | 格式 | 说明 |
---|---|---|---|
命令识别码 | 4字节 | 十六进制 | 0xF1A5_0000(主程序) 0xF1A5_0001(备份程序) |
保留字段 | 4字节 | 十六进制 | 全0,预留扩展 |
数据(可选) | 可变 | - | 可选,当前版本未使用 |
命令需要发送到设备的UDP端口(默认5000)。
5.4.2 发送命令的多种方法
1. 使用Python脚本发送命令
以下是一个完整可用的Python脚本,用于发送Flash选择命令:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Flash启动选择命令发送工具
用途: 向目标设备发送UDP命令以切换Flash启动区域
作者: FPGA开发团队
日期: 2023-01-01
"""
import socket
import argparse
import sys
import time
# 命令定义
CMD_SELECT_MAIN = b'\xF1\xA5\x00\x00\x00\x00\x00\x00' # 选择主程序
CMD_SELECT_BACKUP = b'\xF1\xA5\x00\x01\x00\x00\x00\x00' # 选择备份程序
def send_flash_command(ip_address, port, is_backup=False, verbose=False):
"""
发送Flash启动选择命令
参数:
ip_address: 目标设备IP地址
port: UDP端口号
is_backup: True=选择备份程序, False=选择主程序
verbose: 是否显示详细信息
返回:
成功返回True,失败返回False
"""
try:
# 创建UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(2.0) # 设置2秒超时
# 准备命令数据
if is_backup:
command = CMD_SELECT_BACKUP
cmd_name = "备份程序"
else:
command = CMD_SELECT_MAIN
cmd_name = "主程序"
if verbose:
print(f"正在发送命令: 选择{cmd_name}")
print(f"目标设备: {ip_address}:{port}")
print(f"命令数据: {command.hex()}")
# 发送命令
sock.sendto(command, (ip_address, port))
print(f"已发送选择{cmd_name}命令到 {ip_address}:{port}")
# 尝试接收响应(如果有)
try:
response, addr = sock.recvfrom(1024)
print(f"收到响应: {response.hex()} 来自 {addr}")
except socket.timeout:
if verbose:
print("未收到响应(正常情况)")
return True
except Exception as e:
print(f"错误: {e}")
return False
finally:
# 关闭套接字
sock.close()
def main():
"""命令行入口函数"""
parser = argparse.ArgumentParser(description='Flash启动选择命令发送工具')
parser.add_argument('ip', help='目标设备IP地址')
parser.add_argument('-p', '--port', type=int, default=5000, help='UDP端口号(默认:5000)')
parser.add_argument('-b', '--backup', action='store_true', help='选择备份程序(默认选择主程序)')
parser.add_argument('-v', '--verbose', action='store_true', help='显示详细信息')
parser.add_argument('-r', '--reboot', action='store_true', help='发送命令后重启设备(需要实现)')
args = parser.parse_args()
# 发送命令
success = send_flash_command(args.ip, args.port, args.backup, args.verbose)
# 返回状态码
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()
使用方法:
# 选择主程序
python flash_select.py 192.168.1.100
# 选择备份程序
python flash_select.py 192.168.1.100 -b
# 显示详细信息
python flash_select.py 192.168.1.100 -b -v
2. 使用netcat发送命令
对于Linux/macOS用户,可以使用netcat(nc)工具发送命令:
选择主程序命令:
echo -ne '\xF1\xA5\x00\x00\x00\x00\x00\x00' | nc -u 192.168.1.100 5000
选择备份程序命令:
echo -ne '\xF1\xA5\x00\x01\x00\x00\x00\x00' | nc -u 192.168.1.100 5000
3. 使用Packet Sender工具(GUI方式)
对于不熟悉命令行的用户,可以使用Packet Sender工具:
- 下载并安装Packet Sender (https://packetsender.com/)
- 创建新的UDP数据包
- 设置目标IP和端口(默认5000)
- 选择"HEX"输入模式
- 输入命令数据:
- 主程序: F1A50000 00000000
- 备份程序: F1A50001 00000000
- 点击"发送"按钮
5.5 完整切换流程演示
以下是切换从主程序到备份程序的完整操作流程演示:
-
确认当前启动状态
- 通过串口终端连接设备(通常为115200波特率)
- 观察启动日志中的"Boot Mode"信息
- 确认当前运行的是哪个区域的程序
-
发送切换命令
- 使用上述任一方法发送选择备份程序的命令
- 命令:
0xF1A5_0001_0000_0000
- 目标: 设备IP地址,端口5000(默认)
-
重启设备
- 可通过以下方式重启设备:
- 硬件复位按钮
- 通过串口发送复位命令
- 使用网络复位命令(如果实现)
- 断电重启
- 可通过以下方式重启设备:
-
验证切换结果
- 观察启动日志,确认启动模式变为"Boot Mode: QSPI Flash Backup Region"
- 验证系统是否正确加载备份程序
- 检查应用程序特定标识(如版本号、启动信息等)
-
切换回主程序(可选)
- 发送选择主程序命令:
0xF1A5_0000_0000_0000
- 重启设备
- 验证系统已切换回主程序
- 发送选择主程序命令:
6. 修改与配置说明
6.1 修改的文件清单与功能说明
本项目实现过程中,修改或添加了以下关键文件。下表详细列出了每个文件的修改内容和功能说明:
文件路径 | 修改内容 | 功能说明 |
---|---|---|
AD9361_Prj.srcs/net_src/01_rtl/udp_rx.sv | • 添加命令解析逻辑 • 新增Flash选择信号输出 • 定义命令识别码 | UDP命令接收与解析模块,识别特定命令并生成控制信号 |
AD9361_Prj.srcs/net_src/01_rtl/channel_wrapper.v | • 添加Flash控制信号接口 • 连接UDP接收模块和顶层模块 | UDP数据包处理与转发模块,为UDP接收模块提供接口 |
AD9361_Prj.srcs/net_src/01_rtl/udp_look_back.v | • 添加Flash选择信号连接 • 引出信号到顶层模块 | 以太网通信顶层模块,管理以太网数据收发 |
AD9361_Prj.srcs/sources_1/new/AD9361_prj.v | • 添加Flash启动逻辑 • 增加选择信号寄存器 • 添加输出引脚接口 | 项目顶层模块,连接所有子模块并输出控制信号 |
AD9361_Prj.srcs/constrs_1/new/AD9361_prj.xdc | • 添加Flash控制引脚定义 • 设置引脚电气特性 | 引脚约束文件,定义FPGA引脚分配和电气特性 |
AD9361_Prj.sdk/FSBl/src/qspi.h | • 添加Flash双区域定义 • 定义寄存器地址和偏移量 | QSPI Flash头文件,定义Flash访问相关常量 |
AD9361_Prj.sdk/FSBl/src/qspi.c | • 修改访问函数支持双区域 • 添加区域选择逻辑 | QSPI Flash访问实现,根据标志选择加载区域 |
AD9361_Prj.sdk/FSBl/src/main.c | • 添加寄存器映射 • 初始化代码 • 启动信息输出 | FSBL主程序,初始化系统并启动后续程序 |
6.2 关键参数配置详解
实际部署时,需要根据具体硬件环境和应用需求调整以下关键参数:
6.2.1 Flash备份区域偏移量
文件:AD9361_Prj.sdk/FSBl/src/qspi.h
参数:FLASH_BACKUP_OFFSET
默认值:0x800000
(8MB)
说明:此参数定义了备份程序在Flash中的起始位置。应根据以下因素调整:
- 实际Flash芯片容量:不同设备的Flash大小不同,需确保偏移量不超过Flash容量
- 主程序所需存储空间:主程序完整大小,包括FSBL、比特流和应用程序
- 备份程序大小:备份程序可能与主程序大小不同,需确保有足够空间存储
计算方法:
- 确保
FLASH_BACKUP_OFFSET
> (主程序大小 + 安全裕量) - 主程序大小可以通过查看BOOT.bin文件大小估算
- 建议添加1-2MB安全裕量
实际选择例子:
Flash容量 | 主程序大小 | 建议偏移量 | 备注 |
---|---|---|---|
16MB | 4MB | 0x800000 (8MB) | 标准分配,各占一半 |
32MB | 5MB | 0x800000 (8MB) | 标准分配,备份区域较大 |
16MB | 7MB | 0xA00000 (10MB) | 主程序区域较大 |
8MB | 3MB | 0x400000 (4MB) | 小容量Flash,各占一半 |
6.2.2 Flash选择寄存器地址
文件:AD9361_Prj.sdk/FSBl/src/qspi.h
参数:FLASH_SEL_REG_ADDR
默认值:0x43C00000
说明:此地址必须映射到系统中的有效GPIO或自定义寄存器,用于存储Flash选择标志。
配置要点:
- 在Zynq系统中,此地址通常需要映射到AXI GPIO模块的地址
- 地址必须在PS可访问的地址空间内(Zynq-7000通常为0x40000000-0x7FFFFFFF)
- 不应与其他外设地址冲突
- 需要在PS与PL之间建立正确的地址映射
调整方法:
- 使用Vivado的地址编辑器(
Address Editor
)查看和分配地址 - 确认地址与硬件设计中的GPIO基地址一致
- 更新FSBL代码中的地址定义
6.2.3 UDP命令识别码
文件:AD9361_Prj.srcs/net_src/01_rtl/udp_rx.sv
参数:
CMD_FLASH_SEL_MAIN
:0xF1A5_0000
CMD_FLASH_SEL_BACKUP
:0xF1A5_0001
说明:这些命令码用于识别Flash启动选择命令。选择时应考虑:
- 独特性:与系统中其他命令不冲突
- 可识别性:容易辨认的模式(如F1A5作为前缀)
- 可扩展性:预留空间用于未来添加更多命令
调整建议:
- 保持命令识别码的前缀相同,仅改变低位值表示不同操作
- 如有多种命令,建议统一命令格式,便于扩展
- 命令码可根据项目需求自定义,但修改后需要同步更新命令发送工具
6.2.4 Flash控制引脚
文件:AD9361_Prj.srcs/constrs_1/new/AD9361_prj.xdc
引脚:
flash_sel_pin
:G15flash_program_pin
:G16
说明:这些引脚用于输出Flash选择状态和编程信号。选择时应考虑:
- 引脚可用性:确保引脚未被其他功能占用
- 电气特性:符合连接设备的电气要求(电压、电流等)
- 布线要求:位置便于PCB布线,避免信号完整性问题
- 信号稳定性:考虑上拉/下拉电阻配置,确保信号稳定
调整方法:
# 示例:修改为不同引脚
set_property PACKAGE_PIN M15 [get_ports flash_sel_pin]
set_property IOSTANDARD LVCMOS33 [get_ports flash_sel_pin]
set_property PACKAGE_PIN N15 [get_ports flash_program_pin]
set_property IOSTANDARD LVCMOS33 [get_ports flash_program_pin]
# 添加上下拉电阻配置
set_property PULLDOWN true [get_ports flash_sel_pin]
6.3 添加更多功能的扩展方法
基于当前设计,可以进行以下功能扩展:
6.3.1 添加状态反馈功能
为了确认命令是否成功接收,可以添加状态反馈:
-
在
udp_rx.sv
中添加状态反馈信号:output reg [7:0] flash_status; // 状态反馈
-
在命令处理逻辑中更新状态:
if (udp_rx_data[0:31] == CMD_FLASH_SEL_MAIN) begin flash_sel <= 1'b0; flash_sel_valid <= 1'b1; flash_status <= 8'h01; // 成功接收主程序选择命令 end
-
添加UDP响应逻辑,将状态发送回客户端
6.3.2 添加多备份区域支持
扩展设计以支持多个备份区域:
-
在
qspi.h
中定义多个偏移量:#define FLASH_BACKUP1_OFFSET 0x800000 // 第一备份区域 #define FLASH_BACKUP2_OFFSET 0x1000000 // 第二备份区域
-
扩展Flash选择标志位宽:
output reg [1:0] flash_sel = 2'b00; // 2位以支持多达4个区域
-
更新命令识别码:
localparam CMD_FLASH_SEL_MAIN = 32'hF1A5_0000; // 主程序 localparam CMD_FLASH_SEL_BACKUP1 = 32'hF1A5_0001; // 备份区域1 localparam CMD_FLASH_SEL_BACKUP2 = 32'hF1A5_0002; // 备份区域2
7. 常见问题与故障排除
7.1 启动问题
问题:系统无法从备份区域启动
现象:
- 命令已成功发送,但系统重启后仍从主区域启动
- FSBL输出中没有显示"Booting from backup flash region"
- 系统无法正常加载备份程序
可能原因:
- 备份程序未正确烧写到指定偏移地址
- FSBL未正确读取Flash选择标志
- Flash选择信号未正确连接
- 命令接收模块未正确工作
排查步骤:
-
验证备份程序烧写:
- 使用Flash读取工具确认备份程序已正确烧写
# Vivado TCL命令读取Flash内容 read_cfgmem -format bin -interface SPIx4 -size 32 -file backup_verify.bin -start_address 0x800000 -end_address 0x900000
- 确认读取的数据与BOOT.bin文件匹配
-
检查FSBL日志:
- 启用FSBL详细调试输出:在
fsbl_debug.h
中设置FSBL_DEBUG_INFO=1
- 通过串口监视启动过程,查看读取的选择标志值
- 检查是否正确读取到GPIO状态
- 启用FSBL详细调试输出:在
-
检查硬件信号:
- 使用示波器或逻辑分析仪检查
flash_sel_pin
引脚信号 - 确认信号在命令处理后正确变化,且保持稳定
- 检查信号从FPGA到GPIO接口的连接
- 使用示波器或逻辑分析仪检查
-
测试命令接收:
- 添加调试LED指示命令接收状态
- 使用ILA (Integrated Logic Analyzer)监控UDP接收逻辑
- 验证UDP数据包是否被正确接收和解析
解决方案:
-
手动验证启动区域选择:
// 在qspi.c中临时强制使用备份区域 u32 QspiAccess(u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) { // 强制使用备份区域进行测试 u32 FlashSel = FLASH_SEL_BACKUP; // 强制选择备份区域 // 其余代码不变... }
-
验证寄存器映射:
- 在FSBL初始化阶段添加测试代码:
// 测试写入和读取 Xil_Out32(FLASH_SEL_REG_ADDR, FLASH_SEL_BACKUP); u32 RegVal = Xil_In32(FLASH_SEL_REG_ADDR); fsbl_printf(DEBUG_GENERAL, "寄存器测试: 写入=%d, 读取=%d\n", FLASH_SEL_BACKUP, RegVal);
-
修复偏移量计算:
- 确保SrcAddr计算正确:
// 正确的偏移量计算 if (FlashSel == FLASH_SEL_BACKUP) { SrcAddr = SourceAddress + FLASH_BACKUP_OFFSET; fsbl_printf(DEBUG_INFO, "计算后的地址: 0x%08x\n", SrcAddr); }
问题:切换命令没有效果
现象:
- 发送UDP命令后,没有任何响应或状态变化
- 系统重启后启动区域未改变
- 没有错误消息或异常现象
可能原因:
- UDP命令格式错误
- 目标IP地址或端口错误
- 网络连接问题
- 命令解析逻辑错误
- 防火墙或网络设备阻止UDP包
排查工具:
- Wireshark: 网络数据包分析
- netcat/nmap: 网络连接测试
- LED指示灯: 硬件状态显示
- ILA: FPGA内部逻辑分析
排查步骤:
-
验证网络连接:
# 测试网络连通性 ping 192.168.1.100 # 测试UDP端口可达性 nmap -sU -p 5000 192.168.1.100
-
使用Wireshark捕获数据包:
- 监听设备网口,筛选UDP协议和目标端口
- 确认命令已发送并到达设备
- 检查数据包内容是否正确
-
添加硬件调试接口:
- 配置LED显示命令接收状态
// 在顶层模块中添加 assign debug_led[0] = flash_sel; // 显示当前选择状态 assign debug_led[1] = flash_sel_valid; // 命令有效指示
-
实现简单回显测试:
- 在UDP处理模块中添加回显功能,接收到命令后将内容发送回发送方
- 验证UDP接收和处理功能正常工作
解决方案:
-
修复命令格式:
- 确保命令字节顺序正确(注意大小端顺序)
- 使用十六进制编辑器构建正确的UDP数据包
-
网络设置调整:
- 检查设备IP配置和子网设置
- 关闭防火墙或添加例外规则
- 尝试在同一子网中测试
-
简化测试:
- 临时修改命令解析逻辑,识别任何UDP包
// 简化测试 - 任何UDP包都触发状态变化 if (udp_rx_cnt > 0) begin flash_sel <= ~flash_sel; // 切换状态 flash_sel_valid <= 1'b1; end
7.2 Flash操作问题
问题:Flash编程失败
现象:
- Vivado报错:Programming failed
- 验证失败,数据不匹配
- 程序无法烧写到指定地址
可能原因:
- Flash保护机制启用
- Flash写入时序不正确
- 编程工具与Flash型号不匹配
- Flash硬件连接问题
- Flash已损坏或老化
排查步骤:
-
检查Flash状态和保护:
- 读取Flash状态寄存器查看保护状态
# Vivado TCL命令读取Flash状态 create_hw_cfgmem -hw_device [current_hw_device] -mem_dev [get_cfgmem_parts {mt25qu128-spi-x1_x2_x4}] get_property STATUS [get_hw_cfgmem]
- 查看Flash制造商ID和设备ID,确认型号正确
-
尝试不同的编程设置:
- 降低编程速度
- 修改编程算法
- 尝试不同的编程模式(SPIx1/SPIx4等)
-
硬件检查:
- 测量Flash供电电压是否正常(通常3.3V)
- 检查JTAG信号质量和连接稳定性
- 测试Flash引脚连接(CS/CLK/DI/DO等)
解决方案:
-
解除Flash保护:
# 解除写保护的Vivado TCL命令示例 create_hw_cfgmem -hw_device [current_hw_device] -mem_dev [get_cfgmem_parts {mt25qu128-spi-x1_x2_x4}] set_property PROGRAM.ERASE 1 [get_property PROGRAM.HW_CFGMEM [current_hw_device]] set_property PROGRAM.CFG_PROGRAM 1 [get_property PROGRAM.HW_CFGMEM [current_hw_device]] set_property PROGRAM.VERIFY 1 [get_property PROGRAM.HW_CFGMEM [current_hw_device]] create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]] program_hw_devices [current_hw_device]
-
使用分步编程:
- 先执行擦除操作
- 确认擦除成功后再执行编程
- 最后执行验证
-
使用替代工具:
- 尝试使用XSPI Flash工具
- 使用第三方Flash编程器
- 通过FSBL或U-Boot的Flash实用程序编程
问题:程序在备份区域无法正常运行
现象:
- 系统成功从备份区域启动,但程序行为异常
- 出现意外的重启或死机
- 特定功能无法正常工作
可能原因:
- 备份程序编译时未考虑偏移地址
- 程序中硬编码了Flash地址
- 备份区域Flash质量问题
- 程序依赖特定内存地址或硬件配置
排查步骤:
-
检查程序编译:
- 确认程序是否使用位置无关代码(PIC)
- 检查链接脚本中的地址分配
- 确保程序不直接访问绝对地址
-
Flash内容验证:
- 读取备份区域内容并与原始BOOT.bin比较
- 检查是否有数据损坏或不完整
-
添加调试信息:
- 在应用程序中添加启动阶段日志,显示当前运行的区域
- 记录关键操作的执行情况和参数
解决方案:
-
修复位置依赖:
- 修改应用程序,使用相对地址而非绝对地址
- 更新链接脚本,适应不同的加载地址
// 使用相对地址访问 volatile uint32_t *base_addr = (volatile uint32_t *)(获取当前基地址());
-
重新烧写备份程序:
- 确保使用正确编译的位置无关程序
- 校验烧写过程和结果
-
添加运行时检测:
- 在程序中添加代码检测当前运行区域
// 检测当前运行区域 bool is_running_from_backup = (CURRENT_EXECUTION_ADDR >= BACKUP_REGION_START); printf("当前运行区域: %s\n", is_running_from_backup ? "备份" : "主要");
7.3 硬件连接问题
问题:Flash选择信号不稳定
现象:
- 选择状态随机变化
- 系统有时从主区域启动,有时从备份区域启动
- 命令处理行为不一致
可能原因:
- 信号未正确上拉/下拉
- 引脚浮空
- 信号干扰
- 时钟域问题
- 系统掉电时状态丢失
排查步骤:
-
信号稳定性测试:
- 使用示波器测量信号电平和噪声
- 观察信号在不同操作条件下的稳定性
- 测试温度变化、电源波动等情况下的信号质量
-
检查上拉/下拉配置:
- 验证引脚的上拉/下拉配置是否正确
- 检查外部电阻值是否合适
-
时钟域分析:
- 检查信号跨时钟域传输是否正确处理
- 使用ILA观察同步逻辑行为
解决方案:
-
改进信号稳定性:
- 添加适当的上拉/下拉电阻
# 在约束文件中添加 set_property PULLDOWN true [get_ports flash_sel_pin]
- 增加去耦电容减少电源噪声
- 优化PCB布线,减少干扰
-
使用寄存器存储状态:
- 实现非易失性存储(例如使用EEPROM)
- 使用带电池的RTC保持状态
- 冗余存储选择状态,采用多数表决
-
实现健壮的同步逻辑:
// 双触发器同步器 reg flash_sel_meta; reg flash_sel_sync; always @(posedge clk) begin if (!rst_n) begin flash_sel_meta <= 1'b0; flash_sel_sync <= 1'b0; end else begin flash_sel_meta <= flash_sel_async; flash_sel_sync <= flash_sel_meta; end end
8. 技术术语表
术语 | 全称 | 说明 |
---|---|---|
QSPI | Quad Serial Peripheral Interface | 四线串行外设接口,一种高速Flash接口协议,比标准SPI提供更高的数据传输速率 |
FSBL | First Stage Boot Loader | 第一阶段引导加载程序,Zynq系统中负责初始化硬件并加载后续程序 |
UDP | User Datagram Protocol | 用户数据报协议,一种无连接的网络传输协议,无需建立连接即可发送数据包 |
Zynq | - | Xilinx公司的SoC(System-on-Chip)芯片系列,集成ARM处理器和FPGA |
PS | Processing System | Zynq中的处理系统部分,基于ARM Cortex-A9处理器核心 |
PL | Programmable Logic | 可编程逻辑部分,即FPGA部分,用于实现自定义硬件功能 |
Flash | Flash Memory | 闪存,一种非易失性存储器,用于存储启动程序和配置数据 |
冗余 | Redundancy | 系统设计中的备份机制,用于提高可靠性和容错能力 |
比特流 | Bitstream | FPGA配置文件,包含PL部分的硬件配置信息 |
AD9361 | - | Analog Devices公司的高性能射频收发器芯片,用于无线通信应用 |
GPIO | General Purpose Input/Output | 通用输入/输出端口,可编程控制的数字信号接口 |
BOOT.bin | Boot Binary | Zynq启动文件,包含FSBL、比特流和应用程序 |
ILA | Integrated Logic Analyzer | 集成逻辑分析仪,Vivado中用于调试FPGA内部信号的工具 |
AXI | Advanced eXtensible Interface | 先进可扩展接口,ARM定义的高性能总线协议 |
TCL | Tool Command Language | 工具命令语言,Vivado中用于自动化操作的脚本语言 |
9. 附录:项目文件结构
完整的项目文件结构及主要文件说明:
AD9361_Prj/
├── AD9361_Prj.srcs/ # 源代码目录
│ ├── constrs_1/ # 约束文件目录
│ │ └── new/
│ │ └── AD9361_prj.xdc # 引脚约束文件
│ │
│ ├── net_src/ # 网络相关源代码
│ │ └── 01_rtl/
│ │ ├── udp_look_back.v # UDP顶层模块
│ │ ├── channel_wrapper.v # 通道包装模块
│ │ ├── udp_rx.sv # UDP接收模块(包含命令解析)
│ │ └── udp_tx.v # UDP发送模块
│ │
│ └── sources_1/ # 主源代码目录
│ └── new/
│ └── AD9361_prj.v # 顶层设计文件
│
├── AD9361_Prj.sdk/ # SDK工程目录
│ ├── FSBl/ # FSBL项目
│ │ └── src/
│ │ ├── qspi.h # QSPI头文件(添加Flash区域定义)
│ │ ├── qspi.c # QSPI实现(修改Flash访问逻辑)
│ │ ├── main.c # FSBL主程序(初始化和启动)
│ │ └── ... (其他FSBL文件)
│ │
│ ├── AD9361_prj/ # 应用程序项目
│ │ └── src/
│ │ └── ... (应用程序源代码)
│ │
│ └── AD9361_prj_bsp/ # 板级支持包
│
├── AD9361_Prj.xpr # Vivado项目文件
├── 双冗余.md # 本说明文档
└── tools/ # 辅助工具(可选)
├── flash_select.py # Flash选择命令发送工具
└── README.md # 工具使用说明
9.1 关键文件详细说明
9.1.1 顶层设计文件(AD9361_prj.v)
顶层设计文件集成了所有系统组件,包括PS接口、网络模块和Flash控制逻辑。该文件是理解系统整体结构的入口点。
9.1.2 UDP接收模块(udp_rx.sv)
UDP接收模块负责解析网络命令,是实现远程控制功能的核心。该模块定义了命令格式并生成Flash选择信号。
9.1.3 QSPI访问函数(qspi.c)
QSPI访问函数实现了从Flash不同区域读取数据的逻辑,是双冗余启动的关键部分。该函数根据选择标志决定从哪个区域加载程序。
9.1.4 FSBL主程序(main.c)
FSBL主程序负责系统初始化和启动流程,包括读取Flash选择标志和显示启动信息。了解这个文件有助于掌握系统启动过程。
9.2 使用示例脚本
为便于测试和使用,可以在tools
目录下创建以下示例脚本:
9.2.1 Flash选择命令发送工具(flash_select.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Flash启动选择命令发送工具
"""
import socket
import argparse
import sys
def send_flash_command(ip_address, port, is_backup=False, verbose=False):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
if is_backup:
command = b'\xF1\xA5\x00\x01\x00\x00\x00\x00'
cmd_name = "备份程序"
else:
command = b'\xF1\xA5\x00\x00\x00\x00\x00\x00'
cmd_name = "主程序"
sock.sendto(command, (ip_address, port))
print(f"已发送选择{cmd_name}命令到 {ip_address}:{port}")
return True
except Exception as e:
print(f"错误: {e}")
return False
finally:
sock.close()
def main():
parser = argparse.ArgumentParser(description='Flash启动选择命令发送工具')
parser.add_argument('ip', help='目标设备IP地址')
parser.add_argument('-p', '--port', type=int, default=5000, help='UDP端口号(默认:5000)')
parser.add_argument('-b', '--backup', action='store_true', help='选择备份程序(默认选择主程序)')
parser.add_argument('-v', '--verbose', action='store_true', help='显示详细信息')
args = parser.parse_args()
success = send_flash_command(args.ip, args.port, args.backup, args.verbose)
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()
使用方法:
# 选择主程序
python flash_select.py 192.168.1.100
# 选择备份程序
python flash_select.py 192.168.1.100 -b
# 显示详细信息
python flash_select.py 192.168.1.100 -b -v
2. 使用netcat发送命令
对于Linux/macOS用户,可以使用netcat(nc)工具发送命令:
选择主程序命令:
echo -ne '\xF1\xA5\x00\x00\x00\x00\x00\x00' | nc -u 192.168.1.100 5000
选择备份程序命令:
echo -ne '\xF1\xA5\x00\x01\x00\x00\x00\x00' | nc -u 192.168.1.100 5000
3. 使用Packet Sender工具(GUI方式)
对于不熟悉命令行的用户,可以使用Packet Sender工具:
- 下载并安装Packet Sender (https://packetsender.com/)
- 创建新的UDP数据包
- 设置目标IP和端口(默认5000)
- 选择"HEX"输入模式
- 输入命令数据:
- 主程序: F1A50000 00000000
- 备份程序: F1A50001 00000000
- 点击"发送"按钮