ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于MAX V 5M570的CPLD实现I2C RTC(PCF8563)驱动设计

基于MAX V 5M570的CPLD实现I2C RTC(PCF8563)驱动设计 简介面向CPLD/FPGA开发者和硬件设计学习者这套MAXV 5M570 CPLD开发板原理图与PCF8563高精度温补RTC芯片的Verilog驱动源码以完整的Quartus 13.0工程形式提供可直接打开分析或二次开发。核心模块pcf8563以mclk和reset作为输入通过scl、sda两根总线与RTC芯片通信完成秒、分、时、日期等寄存器的读写并输出led、seg、com信号驱动状态灯与数码管进行显示清晰示范了I2C时序控制、分频计数和寄存器访问流程。PCF8563内置温度补偿电路可提高时钟长期精度适合需要精确计时的工业控制、数据采集或竞赛作品场景。资源共93个文件压缩包约1MB除原理图PDF外还包括工程配置、Verilog源码、仿真波形、烧写文件、引脚分配、readme说明以及编译报告等便于查看从设计到上板的完整实现与验证流程。通过学习这套工程可以掌握模拟I2C时序的状态机编写方法以及如何在CPLD中例化分频器、锁存器与译码显示电路对后续自主移植其他RTC芯片也有帮助。目前已有412人学习下载适合需要参考完整CPLD工程结构、理解PCF8563驱动逻辑或上手MAXV系列开发板的读者。1. 从 MAX V 5M570 到 PCF8563一块 CPLD 做 I2C RTC 的起点当一块主控板的 I2C 设备不止一颗软件轮询很容易被中断打断读秒寄存器的动作晚了几毫秒下一秒的值就跳过去了。把 RTC 的时序下沉给 CPLD让 PCF8563 的 100kHz I2C 通信完全由硬件状态机负责主控只需要在需要时间时读一次并行寄存器这是一个在很多仪器板卡里被验证过的架构。这套资源正好是完整闭环MAXV 5M570 开发板原理图、PCF8563 的 Verilog 驱动和 Quartus 13.0 工程已经编译出了 .pof 和 .pin 报告。适合正在把裸机 I2C 读写改成硬件逻辑的 FPGA/嵌入式工程师也适合想从真实工程里学 Verilog 状态机和 inout 端口的人。顺便说一句标题里“内置高精度温补”通常指板载 TCXO 或温补晶振模组PCF8563 芯片本身没有片上温度补偿寄存器操作仍然一样这个在后文会看到。2. 原理图上的三件事I2C 上拉、32.768 kHz 晶振和 PCF8563 地址映射拿到开发板原理图 PDF先不要急着看 Verilog把 PCF8563 那一页找出来。这颗芯片能不能跑起来硬件上只需确认 SCL/SDA 上拉、晶振和电源三件事。这些在原理图里都能找到网络标号。2.1 在 MAXV 5M570 原理图里定位 I2C 信号和 bank 电压打开原理图 PDF 后直接搜索“8563”或者“RTC”找到芯片 U。PCF8563 通常放在板子边缘旁边有一颗 32.768 kHz 晶体。开发板上即使叫“PCF8563”网络标号也未必叫 SCL/SDA常见的是I2C_SCL、I2C_SDA、RTC_SDA所以不要只搜 SCL。顺着网络标号可以找到它们连到 MAX V 5M570 的哪个引脚。提示如果原理图上 SCL/SDA 网络同时挂了多个器件比如常见的 AT24C02 也挂在同一总线上那么 I2C 地址必然不能重复。PCF8563 的 7 位地址是 0x51AT24C02 常用地址是 0x50A2A1A0 接地时恰好不同可以共总线。确定连接的 bank 很重要。5M570 的 I/O 分成多个 bank如果 PCF8563 供电是 3.3V那么 SCL/SDA 必须接在配置为 3.3V 电平的 bank 上并且引脚约束里要写3.3-V LVTTL不能依赖默认电平。原理图里每个引脚旁边通常会标注电源域比如VCCIO 3.3这就是你写 IO_STANDARD 的依据。2.2 PCF8563 寄存器映射秒、分、时都是 BCD还要留意 VL 位PCF8563 的寄存器从 0x00 到 0x0F本工程只关心 0x02 到 0x08 这几个时间寄存器。写 Verilog 之前把地址和位定义写清楚比什么都重要。寄存器地址名称bit7bit6:00x02秒/VLVL1 表示时钟无效或掉电秒的 BCD 码0x03分钟保留常为0分钟的 BCD 码0x04小时保留小时的 BCD 码0x05日保留日期的 BCD 码0x06星期保留1-7 表示星期0x07月/世纪C世纪位月份的 BCD 码0x08年保留年的 BCD 码这套 Verilog 工程里把所有时间都设计成 8 位s_reg、m_reg、h_reg、d_reg和上面表格一一对应。代码里建议用参数而不是魔法数字localparam I2C_ADDR_W 8hA2; // PCF8563 写地址7位地址0x51左移1位 localparam I2C_ADDR_R 8hA3; // 读地址写地址最低位置1 localparam REG_CTRL1 8h00; localparam REG_SEC 8h02; localparam REG_MIN 8h03; localparam REG_HOUR 8h04; localparam REG_DAY 8h05;I2C_ADDR_W是字节形式即 7 位地址0x51左移一位得到0xA2读地址就是0xA3。很多第一次写 Verilog I2C 的人会把这两个地址搞反写成了0x51和0x53导致从机永远不回 ACK。还有秒寄存器地址是 0x02不是 0x000x00 是控制状态寄存器写错会直接改掉芯片的运行模式这个坑很隐蔽。如果你把驱动读回来的时间打印出来发现秒是 0xFF、分是 0xFF先去查 0x02 的 bit7上电后 VL 位可能是 1代表时钟源无效。处理办法是先写一遍秒寄存器保持 BCD 值不变把 VL 清为 0。本工程的 Verilog 在初始化序列里通常也会做一次这个动作不过源码里没有出现显式的状态名我建议你在读操作之前单独加一个“清 VL”步骤。2.3 I2C 上拉电阻与 32.768 kHz 晶振抄原理图也要会算PCF8563 的 SCL/SDA 是开漏输出必须在外部各接一个上拉电阻到 VDD。原理图上一般都标了阻值常见是 4.7kΩ。如果电路板走线比较长、挂载设备多总线电容变大4.7k 的上升沿变慢100kHz 下可能顶不住。此时换 2.2kΩ 可以加快上升沿但会增加电流。反过来低速、短走线用 10kΩ 也能工作。最稳妥的是按 I2C 规范里的公式估算tr ≈ 0.8473 × Rp × Cb取 Cb100pF、tr 要求 1μs算出来 Rp 约 11.8k所以 10k 是上限附近的常用值。32.768 kHz 晶振直接接在 PCF8563 的 OSCI/OSCO 两个引脚上负载电容典型值 12.5pF。画板时晶振和两颗负载电容要尽量贴近芯片晶振走线周围包地避免高频串扰。CPLD 侧的 mclk 通常是板上 50MHz 独立有源晶振不参与 RTC 计数所以不需要担心两边的时钟漂移——PCF8563 自己靠 32.768 kHz 走时间CPLD 的 mclk 只决定 I2C 时序快慢。3. pcf8563.v 逻辑拆解分频计数、I2C 状态机和 inout 双向口模块端口在摘要里写得很清楚input mclk, input reset, inout scl, inout sda, output [7:0] led, seg, com。其中led和seg/com是用来把读回来的秒分时日直接显示到板上的。下面我把这份源码最关键的三块逐个拆开讲。3.1 先从 mclk 分频出 I2C 时钟为什么不能直接用 50MHz 跑 I2CPCF8563 标准模式最高 100kHz快速模式 400kHz。CPLD 输入mclk如果来自 50MHz 有源晶振必须分频。源码里有cnt3、cnt4这些计数器典型做法是计数到某个阈值后翻转clk。我一般这么写reg [9:0] cnt; reg scl_clk; always (posedge mclk or negedge reset) begin if (!reset) begin cnt 10d0; scl_clk 1b0; end else if (cnt 10d249) begin cnt 10d0; scl_clk ~scl_clk; end else begin cnt cnt 1b1; end endmclk 为 50MHz 时cnt计数 250 个周期翻转一次也就是 50MHz/250200kHz 的方波再翻转得到占空比 50% 的 100kHzscl_clk。如果mclk是 25MHz计数阈值应是 124如果是 400kHz阈值是 61。这个计数器不要省直接用系统时钟做单周期操作状态机的所有状态翻转都以scl_clk为主时钟但 I2C 的建立保持时间还需要在scl_clk内部再分相位不能让状态机按 50MHz 狂跳否则 SDA 数据变化会离 SCL 边沿太近。3.2 状态机怎么设计一次完整读时间需要经过哪些状态读回秒分时需要做的 I2C 事务是START → 写地址(0xA2) → ACK → 寄存器地址(0x02) → ACK → 重复 START → 读地址(0xA3) → ACK → 读数据 → 主机回 NACK → STOP。注意第一个 ACK 是从机回给主机的最后一个 NACK 是主机回给从机的顺序不能反。源码里的p_state是一个 4 位状态寄存器从保留的变量名看作者把读写状态放在同一个状态机里。如果让我重写我会把状态编码写成这样localparam IDLE 4d0; localparam START 4d1; localparam W_ADDR 4d2; localparam ACK_W 4d3; localparam REG_AD 4d4; localparam ACK_RG 4d5; localparam RSTART 4d6; localparam R_ADDR 4d7; localparam ACK_R 4d8; localparam RD_SEC 4d9; localparam RD_OTH 4d10; localparam NACK 4d11; localparam STOP 4d12;从RD_SEC开始连续读 5 个字节是典型的多字节收发PCF8563 的地址指针在读完一个字节后自动加一所以第一个数据字节是秒之后是分、时、日、星期、月、年。这个特性比“读一个字节再发一次地址”快得多也是 I2C RTC 和 EEPROM 读写的一个重要区别。如果你写过 I2C 读写 EEPROM 的 Verilog会发现 EEPROM 连续读也有同样的自动地址递增只是在最后你必须让主机回 NACK而不是继续发 ACK否则从机会一直把数据送上来。状态机的主体是一个always (posedge clk or negedge reset)块case (p_state)里判断当前状态并给出下一个状态。这里我不会贴整段源码但强调一个关键判断ACK 采样必须在第 9 个时钟下降沿之后、下一个数据位移出之前完成。常见错误是收到 ACK 就立刻把 SDA 拉低开始发下一位此时从机可能还没释放 SDA总线冲突就出现了。这个工程用的是一段式状态机即次态、状态寄存器和组合输出写在一个 always 块里。对 100kHz I2C 来说一段式完全够用输出寄存器天然滤掉组合毛刺。如果你平时习惯写三段式状态机想把这套代码改成三段式需要注意 I2C 的 SDA 在 SCL 低电平时变化三段式把组合输出和寄存器输出分开后需要在每个状态里显式让scl_hi_z、sda_hi_z保持住不能出现两个周期之间的空洞。3.3 inout 处理SCL/SDA 为什么各自还要配一个高阻控制在 Verilog 顶层scl和sda都声明成inout。最容易被忽略的是inout端口不能直接赋值必须通过三态门控制。源码里的scl_hi_z和sda_hi_z就是为此存在assign scl scl_hi_z ? 1bz : scl_reg; assign sda sda_hi_z ? 1bz : sda_reg;sc_hi_z为 1 时SCL 引脚进入高阻态外部上拉电阻把电平拉高为 0 时把内部scl_reg的值驱动到引脚。SDA 同理。通常 SCL 可以一直做推挽输出不需要高阻但源码把 SCL 也做成三态好处是将来接入多主 I2C 总线时可以做时钟同步坏处是一旦scl_hi_z拉错时机SCL 会在不稳定的边沿停留从机误判。我的建议是保持源码的做法但在仿真里一定要给 sda 加上拉模型否则高阻态在波形里是 Z读回来的数据全是 X看起来像代码 bug其实是仿真环境缺了上拉pullup(sda); pullup(scl);这句要写在 testbench 里而不是 pcf8563.v 里。如果在 Quartus 的 vwf 里直接观察 sda没有上拉模型你会看到 sda 长时间处于高阻这时不要急着改源码。另外在准备读取数据前要把sda_hi_z置 1让 SDA 被外部从机驱动如果读数据期间 SDA 一直被 CPLD 强拉低从机拉不低也拉不高总线就死了。时序上起始条件sda_reg0必须发生在scl_reg1期间停止条件正好相反。这个顺序错了示波器上看到的波形就是不规则的脉冲PCF8563 永远不会 ACK。4. Quartus 13.0 工程实操从 qsf 约束到 pcf8563.pof 烧录原理图确认过Verilog 也读懂了接下来要让这个工程真正落到板子上。Quartus 13.0 对 MAX V 的支持已经很成熟但有几个配置点特别容易把第一次用 CPLD 的人卡住。4.1 打开工程确认 .qpf 里的器件型号与已安装器件库下载解压后直接双击pcf8563.qpf。如果 Quartus 提示版本升级说明工程是用 13.0 或更早版本建的新版本打开后 qsf 会自动转换但转换后的引脚约束可能需要检查。打开工程后菜单 Assignments → Device 里确认器件是 MAX V 系列的 5M570具体封装以你自己的板子为准。如果型号不对很可能是安装 Quartus 13.0 时没有勾选 MAX V device support重新运行安装程序在 device 选项里把 MAX V 勾上工程才能正常编译。命令行也能完成全流程quartus_sh --flow compile pcf8563这条命令会在工程目录下重新跑完分析和综合、布局布线、时序分析、汇编最终生成pcf8563.pof。在 GUI 里编译是 Processing → Start Compilation快捷键 CtrlL。4.2 引脚分配qsf 里的 set_location_assignment 和 IO_STANDARD工程自带的pcf8563.qsf里应该已经有完整引脚绑定。如果换了板子需要重新分配。qsf 的引脚约束格式是 Tcl 指令以scl和sda为例set_location_assignment PIN_N1 -to scl set_location_assignment PIN_N2 -to sda set_location_assignment PIN_R8 -to mclk set_location_assignment PIN_T9 -to reset set_instance_assignment -name IO_STANDARD 3.3-V LVTTL -to scl set_instance_assignment -name IO_STANDARD 3.3-V LVTTL -to sdaPIN_N1这类名字要对照 MAXV 5M570 开发板原理图里的 FPGA 引脚来填不能照抄示例。关键在于IO_STANDARD要和 PCF8563 的供电一致芯片 VDD 是 3.3V那 scl/sda 所在的 bank 必须用 3.3-V LVTTL否则引脚接收门限不匹配读回的 ACK 可能一直为高。mclk是时钟输入最好单独指定 fast input register 相关约束但对 RTC 这种低速外设不额外约束也能工作。下面是这份工程里常见信号的约束对照表具体引脚以你自己的原理图为准信号名方向电平QSF 中的 -to 名称50MHz 主时钟input3.3-V LVTTLmclk复位按键input3.3-V LVTTLresetI2C 时钟inout3.3-V LVTTLsclI2C 数据inout3.3-V LVTTLsdaLED 指示output3.3-V LVTTLled[0] ... led[7]数码管段选output3.3-V LVTTLseg[0] ... seg[7]数码管位选output3.3-V LVTTLcom[0] ... com[7]对于总线信号qsf 里不能直接把led当整体约束要展开到每一位。也可以在 Assignment Editor 里框选后统一设置它会自动生成led[0]到led[7]的条目。信号的电平时序可以在.pin文件里快速核对编译完打开pcf8563.pin能看到每个顶层信号的实际摆放位置和 IO bank。这个文件是文本按信号名排序适合写脚本批量比对。4.3 时序约束与编译报告别只盯着 fit 是 Pass 还是 Fail不要把 I2C 控制器当成纯组合逻辑mclk 必须有时钟约束时序分析才有意义。在工程里新建一个pcf8563.sdccreate_clock -name mclk -period 20.000 [get_ports mclk]这句告诉 Quartus 全局时钟是 50MHz。没有这条约束STA 会默认按 1ns 周期检查逻辑稍微长一点就报时序违规导致 fit.rpt 里出现一堆红色告警。加上这条之后时序分析器只会检查真实路径。编译完成后最关心的两个文件pcf8563.fit.summary资源使用率。I2C 主机状态机加上数码管扫描逻辑单元通常只占 5M570 的一小部分几十到一百个 LE 之间。如果发现某一项使用率超过 90%先检查是不是把 seg 和 com 每个位都做成了独立译码而不是用 BCD 译码器。pcf8563.flow.rpt流程汇总能看到每个阶段是否通过。如果 fit 失败多半是引脚约束冲突例如某个引脚被你写成 led但开发板上实际连接了按键。烧录时在 Quartus Programmer 里选择 JTAG添加pcf8563.pof勾上 Program/Configure。MAX V 是 CPLD配置数据存在芯片内部烧完断电再上电仍然保留不需要像 FPGA 那样外挂配置芯片。这也是用 5M570 做 RTC 胶合逻辑的一个现实好处上电立刻就有 I2C 波形不用等 FPGA 配置完成。提示如果烧录报 “device chain contains no devices”先检查 JTAG 线序和板子的 JTAG 跳线MAX V 的 TMS/TCK/TDI/TDO 四根线不能接反。5. 用 .vwf 仿真秒回环只观察内部寄存器不纠结 I2C 波形这套工程里保留了pcf8563.vwf它和常见 testbench 仿真的思路不一样vwf 只提供顶层激励然后用 ModelSim 跑功能仿真。很多人在 vwf 里盯着 sda 信号看几秒后发现 sda 一直是 Z就以为源码有问题。实际上 pcf8563.v 内部没有 PCF8563 从机模型sda 高阻完全正常。验证驱动逻辑是否正确更有效的做法是观察内部寄存器。在 Quartus 里打开pcf8563.vwf前先确认仿真网表类型。Assignments → Settings → EDA Tool Settings → Simulation 里ModelSim-Altera 的仿真选项选 “Verilog HDL”编译时生成功能仿真网表。然后在 vwf 窗口里添加节点点 Node FinderFilter 选 “Register Pre-Synthesis”把s_reg、m_reg、h_reg、d_reg、p_state加进来。这些是综合前网表的内部寄存器能看到 I2C 状态机跳到哪一步比看 sda 引脚直观很多。设置激励时给mclk加周期 20ns 的时钟reset先低电平保持 1μs 再拉高。如果 vwf 里没有 PCF8563 从机读回来的 s_reg 会是 X这是预期现象。此时重点看p_state是否走完 IDLE → START → W_ADDR → ACK_W → REG_AD → ACK_RG → RSTART → R_ADDR → ACK_R → RD_SEC。只要状态机停过 ACK_W说明代码里采样 ACK 的逻辑可能有误或者在等待 sda 被拉低如果状态机停在 W_ADDR说明发送地址字节的移位循环没有退出。把 breakpoint 加在p_state ACK_W分支跑仿真单步能很快定位是移位计数器没递增还是 ACK 判断条件写反。实际板子上验证就更直接了。把led接到秒寄存器s_reg的低 4 位或者把seg和com接到数码管显示秒。正常工作时显示每秒变化一次。如果秒数完全不动先用示波器量 PCF8563 的 OSCI 引脚确认 32.768 kHz 振荡有没有起振再量 SCL 对地波形频率应该在 100kHz 附近。两个都没有回到 qsf 检查 scl/sda 引脚是不是和原理图对应。最后一个技巧如果你不想依赖 vwf可以直接写一个几十行的 testbench在仿真模型里做一个最小 I2C 从机应答接收到 0xA2 后拉低 sda 一个时钟表示 ACK再接收 0x02之后每读一个地址返回一个递增 BCD 数据。这样s_reg会跟着仿真里的秒值变化整个验证闭环就完整了。资源里没有附 testbench但按上面的思路补一个就能把仿真从“看波形”升级为“对比读写数据”这也是工程落板前最可靠的一步。本文还有配套的精品资源点击获取
返回列表