1. 项目概述
在FPGA开发中,AXI IIC控制器与EEPROM存储器的通信是一个经典应用场景。本实验基于Xilinx Zynq平台,通过PL端的AXI IIC IP核实现对AT24C256 EEPROM的读写操作。AT24C256是一款32KB的串行EEPROM,采用I2C接口通信,在嵌入式系统中广泛用于参数存储。
这个实验的价值在于:
- 掌握AXI IIC控制器的配置与使用
- 理解I2C协议在FPGA中的实现方式
- 构建完整的EEPROM读写测试流程
- 为后续更复杂的FPGA设计打下基础
2. 硬件设计解析
2.1 硬件平台选型
本实验采用Xilinx Zynq-7000系列SoC作为硬件平台,其优势在于:
- 集成ARM处理器(PS)和FPGA逻辑(PL)的混合架构
- 提供丰富的AXI接口用于PS-PL通信
- 内置DDR控制器和各类外设接口
- 开发工具链成熟,文档资料丰富
2.2 外设连接方案
AT24C256与Zynq PL端的连接需要注意以下要点:
-
电气特性匹配:
- I2C总线需要上拉电阻(通常4.7kΩ)
- 工作电压需匹配(通常3.3V)
- 总线长度不宜过长(建议<30cm)
-
地址配置:
- AT24C256的A0/A1/A2引脚决定器件地址
- 7位地址格式为1010(A2)(A1)(A0)
- 实验板上通常已固定为000(地址0x50)
-
信号连接:
- SDA接FPGA的IIC_SDA
- SCL接FPGA的IIC_SCL
- WP引脚接地(禁用写保护)
3. Vivado工程搭建
3.1 IP核配置
在Vivado中创建Block Design时,关键配置步骤如下:
-
添加AXI IIC IP核:
tcl复制
create_bd_cell -type ip -vlnv xilinx.com:ip:axi_iic axi_iic_0 -
参数设置:
- IIC Frequency: 100kHz (标准模式)
- 启用IIC复位信号
- 关闭动态速度切换
-
时钟配置:
- 输入时钟频率需≥2倍IIC时钟
- 典型配置50MHz系统时钟
-
中断设置:
- 可选启用中断功能
- 连接至Zynq PS的中断控制器
3.2 地址空间分配
AXI IIC控制器的寄存器需要正确的地址映射:
| 寄存器名 | 偏移地址 | 功能描述 |
|---|---|---|
| IIC_CR | 0x00 | 控制寄存器 |
| IIC_SR | 0x04 | 状态寄存器 |
| IIC_TX_FIFO | 0x08 | 发送FIFO |
| IIC_RX_FIFO | 0x0C | 接收FIFO |
| IIC_ADR | 0x10 | 从机地址寄存器 |
| IIC_TX_FIFO_OC | 0x14 | 发送FIFO占用计数 |
注意:实际地址需加上AXI接口的基地址偏移量
4. 软件程序设计
4.1 驱动开发要点
Xilinx提供了XIicPs驱动程序,但PL端AXI IIC需要自行实现底层驱动。关键函数包括:
c复制// 初始化函数
int iic_init(uint32_t base_addr) {
// 复位IIC控制器
IIC_CR_REG = 0x01;
while(IIC_SR_REG & 0x01);
// 配置时钟分频
uint32_t div = SYSTEM_CLK / (5 * IIC_FREQ) - 1;
IIC_CR_REG |= (div << 2);
}
// 单字节写入
int iic_write_byte(uint8_t dev_addr, uint16_t mem_addr, uint8_t data) {
// 发送起始条件
IIC_CR_REG |= 0x100;
// 发送设备地址(写模式)
IIC_TX_FIFO = (dev_addr << 1);
// 发送内存地址(16位)
IIC_TX_FIFO = (mem_addr >> 8);
IIC_TX_FIFO = (mem_addr & 0xFF);
// 发送数据
IIC_TX_FIFO = data;
// 发送停止条件
IIC_CR_REG |= 0x200;
}
4.2 读写时序分析
AT24C256的标准读写时序如下:
-
字节写操作:
- 起始条件
- 发送设备地址(写)+ACK
- 发送高字节地址+ACK
- 发送低字节地址+ACK
- 发送数据+ACK
- 停止条件
-
页写操作:
- 最多连续写入64字节
- 地址自动递增
- 超过页边界会回绕
-
随机读操作:
- 先执行"伪写"设置地址
- 重新起始条件
- 发送设备地址(读)
- 读取数据+NACK结束
5. 调试技巧与常见问题
5.1 信号完整性检查
当通信失败时,建议按以下步骤排查:
-
用示波器检查SCL/SDA信号:
- 上升/下降时间是否符合规格
- 是否存在过冲/振铃
- 高低电平是否达到标准
-
总线冲突检测:
- 监测总线是否被意外拉低
- 检查多主设备时的仲裁机制
-
时序验证:
- 建立/保持时间是否满足
- 时钟频率是否准确
5.2 典型错误处理
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无ACK响应 | 设备地址错误 | 检查A0/A1/A2引脚配置 |
| 数据校验错误 | 时序不满足 | 调整时钟分频系数 |
| 随机读写失败 | 页边界处理不当 | 实现地址自动回绕逻辑 |
| 连续操作失败 | 写周期未完成 | 增加5ms延时 |
| 部分数据丢失 | FIFO溢出 | 检查FIFO状态位 |
6. 性能优化建议
6.1 提高传输速率
在可靠通信的基础上,可尝试以下优化:
-
提升IIC时钟频率:
- 标准模式:100kHz
- 快速模式:400kHz
- 高速模式:3.4MHz
-
使用DMA传输:
- 配置AXI DMA IP
- 批量传输减少中断开销
-
实现乒乓缓冲:
- 双缓冲交替读写
- 隐藏EEPROM写周期延迟
6.2 可靠性增强措施
-
写操作验证:
c复制void write_with_verify(uint16_t addr, uint8_t data) { do { iic_write_byte(addr, data); delay(5); } while(iic_read_byte(addr) != data); } -
错误恢复机制:
- 超时检测
- 自动重试
- 总线复位
-
坏块管理:
- 实现磨损均衡
- 保留区替换坏块
在实际项目中,我发现EEPROM的页写操作最容易出现问题。特别是在跨页边界写入时,必须手动处理地址回绕。我的经验是预先计算剩余空间,将跨页写入拆分为两次操作,这样可以避免数据错位的问题。
