尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

FPGA GPIO扩展实战:基于TCA6424A的PMOD模块设计与I2C控制器实现

FPGA GPIO扩展实战:基于TCA6424A的PMOD模块设计与I2C控制器实现 1. 项目缘起当FPGA的GPIO不够用时最近在做一个FPGA项目需要连接一堆传感器、按键和LED指示灯。板子上的FPGA引脚资源本来还算充裕但架不住外设越来越多算来算去GPIO口还是不够用了。直接换一个引脚更多的FPGA芯片成本太高项目周期也不允许。这时候一个老朋友的身影浮现在脑海I2C IO扩展芯片。在嵌入式领域通过I2C或SPI总线扩展GPIO是再常规不过的操作。但在FPGA的世界里尤其是面向快速原型开发的场景我们往往希望有一个更“即插即用”的方案。这就是PMOD接口的魅力所在。PMODPeripheral Module是Digilent公司推出的一种简单、低成本的扩展接口标准广泛应用于其FPGA开发板如Basys3, Nexys, Zybo等后来也被很多其他厂商采纳。它本质上就是一组标准的2x6引脚排针定义了电源、地和一些通用的通信信号线比如SPI、I2C、UART或者直接是GPIO。我的需求很明确找一个能通过PMOD接口方便地插在FPGA开发板上并能提供大量额外GPIO的模块。一番搜索和对比后德州仪器TI的TCA6424A进入了视线。这是一款24位、低电压、可配置的I2C GPIO扩展器支持中断输出正好符合我的需求。市面上似乎没有现成的TCA6424A PMOD模块但这反而激起了我的动手欲望——自己设计一个不仅解决问题还能彻底吃透这颗芯片和I2C总线在FPGA上的实现细节。于是“为TCA6424A设计一个PMOD模块”就成了这个项目的核心标题。这个项目看似简单就是一个转接板但深入下去会涉及硬件电路设计、I2C协议在FPGA中的软核实现、FPGA与外部低速外设的接口设计等多个层面。对于FPGA初学者这是一个绝佳的从数字逻辑走向实际系统集成的练手项目对于有经验的开发者如何写出稳定、健壮、可复用的I2C控制器IP核也是一个值得深究的话题。2. 核心器件TCA6424A深度剖析在动手画原理图之前必须把核心芯片TCA6424A摸透。选择它而不是其他IO扩展芯片是基于几个关键的考量。2.1 为何是TCA6424A市面上IO扩展芯片很多比如经典的PCF85748位、PCA955516位等。TCA6424A吸引我的点在于24位端口提供了P0, P1, P2三个8位端口总计24个可独立配置的IO数量上非常充裕足以应对大多数扩展场景。宽电压支持其VCC供电范围为1.65V到5.5VIO口电压VCCP可独立设置1.65V到5.5V。这意味着它既可以连接3.3V的FPGA也可以直接驱动5V的老式器件或者与1.8V的低压逻辑对接灵活性极强。丰富的功能每个IO口可独立配置为输入、输出。输入模式支持内部可编程上拉/下拉电阻省去了外部电阻。输出模式支持高阻态。这大大简化了外围电路。中断功能有一个开漏的中断输出引脚/INT当任何配置为输入的端口状态发生变化时可屏蔽可以触发中断通知主机FPGA去读取数据避免了轮询的开销对于检测按键等事件非常高效。地址可配置通过三个地址引脚A0, A1, A2可以在同一I2C总线上挂载最多8个同型号设备理论上可以扩展出24*8192个GPIO扩展能力惊人。2.2 关键引脚与内部寄存器映射理解TCA6424A本质上是理解其内部寄存器如何控制外部引脚。它通过I2C接口访问一系列8位寄存器。输入端口寄存器0x00, 0x01, 0x02只读。反映P0, P1, P2三个端口当前的电平状态。输出端口寄存器0x04, 0x05, 0x06读写。当引脚配置为输出时向这些寄存器写入的值会直接驱动到对应引脚。极性反转寄存器0x08, 0x09, 0x0A读写。这是一个很实用的功能。如果置位某一位则对应引脚的输入极性会被反转。例如默认高电平输入读为1低电平读为0。如果设置了极性反转则高电平读为0低电平读为1。这在处理低电平有效的按键或传感器时非常方便可以让逻辑更直观。配置寄存器0x0C, 0x0D, 0x0E读写。这是最重要的寄存器。每一位对应一个引脚0表示配置为输出1表示配置为输入。上电默认所有引脚都是输入值为0xFF。内部上拉/下拉使能寄存器这是通过间接寄存器Bank 1配置的允许为每个输入引脚选择内部上拉电阻、下拉电阻或者不连接高阻。这再次减少了外部元件。注意TCA6424A的寄存器分为Bank 0和Bank 1。我们常用的输入/输出/配置寄存器在Bank 0。像上拉/下拉配置、输出驱动强度配置等高级功能在Bank 1。需要通过一个命令寄存器Command Byte来切换Bank。对于基本应用使用Bank 0的寄存器就足够了。2.3 与FPGA的电压匹配问题这是硬件设计中的一个关键细节。FPGA开发板的PMOD接口电压通常是3.3V。TCA6424A的VCC核心电压和VCCP端口电压是分开的。VCC必须连接到PMOD的3.3V电源为芯片内核供电。VCCP决定了IO引脚输出的高电平电压和输入的逻辑阈值。为了与FPGA的3.3V IO直接通信而不需要电平转换VCCP也必须连接到3.3V。这样TCA6424A输出的高电平就是3.3VFPGA可以正确识别FPGA输出的3.3V高电平对于TCA6424A的输入也是有效的“高”。I2C总线TCA6424A的SDA和SCL引脚是开漏输出需要外部上拉电阻。它们的电压域由VCCP决定因此上拉电阻也必须拉到3.3V。这样FPGA的I2C控制器也需要配置为开漏模式才能与之正常通信。如果未来需要驱动5V设备可以将VCCP接5V但此时TCA6424A与FPGA的3.3V IO之间就必须加入电平转换电路例如使用TXS0108E等双向电平转换芯片否则会损坏FPGA。3. PMOD模块硬件设计与实战要点设计PMOD模块目标是小巧、可靠、易于使用。遵循标准的PMOD规范是兼容性的保证。3.1 PMOD接口引脚定义与连接标准的6引脚单排PMOD接口Type 1A有12个引脚。我们只需要用到其中一部分。电源引脚12VCC和6GND必须连接为模块提供3.3V电源。I2C信号我们需要两个引脚用于I2C。可以选择引脚4和10作为SDA和SCL。PMOD规范中这两根线通常也被标记为可用于SPI的MOSI和SCK但在这里我们将其用作I2C。关键点必须在模块上为SDA和SCL各自放置一个4.7kΩ的上拉电阻到VCC3.3V。这是I2C总线正常工作的必要条件。中断信号TCA6424A的/INT引脚非常有用。我们可以将其连接到PMOD的另一个引脚上例如引脚3。这样FPGA可以通过检测这个引脚的下拉中断是低电平有效来及时响应IO状态变化。地址选择为了灵活性将TCA6424A的A0, A1, A2地址引脚通过模块上的微型拨码开关或焊盘跳线引出。这样用户可以根据需要设置I2C设备地址默认全接地是0x20。扩展IOTCA6424A的24个IOP00-P07, P10-P17, P20-P27通过2.54mm排针或排母引出。我选择用双排排针整齐且牢固。每个端口旁最好预留一个去耦电容100nF的焊盘。3.2 原理图设计核心电源处理VCC从PMOD接入后先经过一个10uF的钽电容和一个100nF的陶瓷电容进行退耦再供给TCA6424A的VCC和VCCP引脚。I2C上拉在模块上紧挨着TCA6424A的SDA和SCL引脚放置两个4.7kΩ的电阻另一端接到VCC。不要在FPGA开发板上依赖可能不存在的上拉电阻。中断线上拉/INT是开漏输出同样需要在模块上用一个10kΩ电阻上拉到VCC。地址配置电路使用3位拨码开关。开关一端分别接A0-A2另一端通过一个10kΩ电阻下拉到地。当开关断开时地址引脚为低0当开关闭合时地址引脚被连接到VCC通过一个较小的电阻如1kΩ以防短路变为高1。这样就能组合出8种地址。ESD保护对于暴露在外的IO排针可以考虑在每个引脚到地之间添加一个ESD保护二极管如SMAJ3.3A以提高模块的 robustness尤其是在实验室频繁插拔的环境下。3.3 PCB布局与打样心得尺寸严格按照PMOD的孔位2.54mm间距两排间距是30.48mm来布局连接器。模块宽度通常就固定了长度可以尽量做短显得精致。层数双面板完全足够。顶层走信号线底层铺地。关键走线I2C的SDA和SCL线尽量短并保持平行走线包地处理有助于减少干扰。电源线要宽。丝印清晰标注PMOD引脚号、扩展IO的编号P0_0, P0_1…、拨码开关的“ON”位置含义0或1、以及VCC/GND的极性。好的丝印能节省大量调试时间。打样嘉立创等平台5元打样非常方便。板材选择FR-4厚度1.6mm。阻焊颜色选个醒目的如蓝色方便观察焊接。实操心得第一次打样时我犯了一个错误忘记把TCA6424A的RESET引脚低电平有效通过一个10kΩ电阻上拉到VCC。结果芯片一直处于复位状态完全不响应I2C。飞线焊上一个电阻后才正常工作。所以对于任何带有RESET或/CE片选引脚的芯片一定要在原理图上明确处理好它们的默认状态。4. FPGA端的I2C控制器软核设计与实现硬件模块做好了接下来就是让FPGA能够通过I2C总线与之对话。在FPGA里实现I2C控制器是一个经典的有限状态机FSM设计问题。4.1 I2C协议精要与FPGA实现难点I2C协议是同步、半双工、多主多从的串行总线。对我们这个应用FPGA唯一主机TCA6424A为从机来说关键是实现作为主机的以下时序起始条件SSCL高电平时SDA从高到低跳变。停止条件PSCL高电平时SDA从低到高跳变。数据传输SCL低电平期间SDA可以变化准备数据SCL高电平期间SDA必须保持稳定数据有效。数据以字节8bit为单位传输MSB先行。应答ACK/NACK每传输完一个字节接收方需要在第9个时钟周期拉低SDAACK或保持高NACK。主机发送时需要检测从机的ACK主机接收最后一个字节时应发送NACK。在FPGA中实现难点在于时钟生成I2C标准模式100kHz或快速模式400kHz的时钟相对于FPGA的内部时钟如100MHz来说非常慢。我们需要用一个计数器来分频产生SCL时钟。精确的时序控制起始、停止、数据建立/保持时间都有规范要求纳秒级。在低速下FPGA很容易满足但状态机设计必须严格区分SCL的高、低电平阶段。开漏输出模拟FPGA的IO通常可以配置为开漏模式。如果没有则需要用三态逻辑来模拟输出0时驱动低电平输出1时设置为高阻态Z依靠外部上拉电阻拉到高电平。4.2 一个简洁可靠的I2C Master状态机设计这里分享一个我经过多次项目验证的、易于理解和扩展的状态机设计。我们定义几个状态localparam [3:0] IDLE 4d0, // 空闲 START 4d1, // 发送起始位 SEND_ADDR 4d2, // 发送7位地址1位读写 WAIT_ACK1 4d3, // 等待地址ACK SEND_DATA 4d4, // 发送数据字节 WAIT_ACK2 4d5, // 等待数据ACK RECV_DATA 4d6, // 接收数据字节 SEND_NACK 4d7, // 发送NACK接收结束时 STOP 4d8; // 发送停止位工作流程IDLE当收到一个“开始传输”命令时进入START状态。START控制SDA在SCL高时产生下降沿然后进入SEND_ADDR。SEND_ADDR在一个SCL周期内先拉低SCL改变SDA输出地址或数据位再拉高SCL保持SDA。循环8次7位地址1位R/W。完成后进入WAIT_ACK1。WAIT_ACK1在第9个SCL的高电平期间将SDA方向设置为输入读取SDA线上的电平。如果是低表示从机应答ACK继续下一步如果是高NACK则跳转到STOP状态报告错误。SEND_DATA/RECV_DATA类似SEND_ADDR但内容是数据字节。发送完成后进入WAIT_ACK2等待从机ACK接收完成后进入SEND_NACK。STOP控制SDA在SCL高时产生上升沿然后回到IDLE。这个状态机的关键是用一个位计数器bit_cnt来记录当前发送或接收到了第几位用一个字节计数器byte_cnt来记录在多字节读写中处理到了第几个字节。4.3 驱动TCA6424A的具体操作序列有了I2C Master我们就可以组合出访问TCA6424A寄存器的具体操作。所有操作都始于起始条件终于停止条件。写入配置寄存器将P0全部设为输出发送起始位S。发送从机地址0x20 1 | 0 0x40其中R/W位为0写。等待ACK。发送寄存器指针0x0C即P0的配置寄存器地址。等待ACK。发送数据0x00表示P0所有引脚为输出。等待ACK。发送停止位P。读取输入端口寄存器读取P0的状态S 地址(0x40) ACK。 // 写操作阶段为了设置寄存器指针发送寄存器指针0x00即P0的输入寄存器地址 ACK。S 地址(0x41) ACK。 // 重新起始切换为读操作地址 | 1 0x41接收一个字节的数据从机发送P0状态 主机发送NACK表示读取结束。P。避坑指南很多初学者在实现连续读写时容易出错。例如想先写配置再写输出值。正确的序列是S 地址写 ACK 寄存器指针(0x0C) ACK 数据(配置值) ACK 寄存器指针(0x04) ACK 数据(输出值) ACK P。注意只要不发送停止位且从机都正确应答就可以在一个通信帧内连续发送多个“数据字节”。TCA6424A的寄存器指针在写入一个字节后会自动递增这个特性非常利于连续读写多个端口寄存器。5. 系统集成、测试与高级应用硬件模块焊接完毕FPGA的I2C控制器也验证通过接下来就是系统集成与功能测试。5.1 上电自检与基础功能测试首先编写一个简单的FPGA测试程序Verilog/VHDL功能是上电后延时一段时间如100ms等待电源稳定。将TCA6424A的P0端口配置为输出写寄存器0x0C为0x00。向P0输出端口寄存器0x04循环写入0xAA和0x55间隔1秒。这样连接到P0端口上的LED应该会交替闪烁假设LED阴极接地阳极通过电阻接IO口。将P1端口配置为输入并使能内部上拉这可能需要切换到Bank 1进行配置。循环读取P1输入端口寄存器0x01并将读取到的值直接显示到FPGA开发板上的LED或七段数码管上。此时用杜邦线将P1的某些引脚接地对应的显示位应该会变化。这个测试涵盖了基本的写配置、写输出、读输入操作。使用逻辑分析仪或者FPGA内部集成逻辑分析仪如Xilinx的ILA抓取PMOD接口上的SDA和SCL信号对照I2C时序图仔细检查是调试的不二法门。要确保起始、停止、应答、数据位都完全正确。5.2 中断功能的实现与优化轮询读取输入状态效率低下。利用/INT引脚才是王道。配置中断将TCA6424A的某些端口如P2配置为输入。默认情况下输入状态变化就会触发/INT引脚变低。FPGA边沿检测在FPGA端将/INT信号引入进行边沿检测检测下降沿。一旦检测到下降沿就触发一个中断标志。中断服务FPGA主状态机检测到这个标志后启动一次I2C读取序列读取相应的输入端口寄存器。读操作完成后/INT信号会自动被芯片释放变回高电平除非状态又有新的变化。中断屏蔽TCA6424A允许屏蔽特定端口的中断。如果你只关心P2口的变化可以通过相关寄存器设置避免其他端口变化产生干扰中断。5.3 项目进阶与扩展思路这个基础的PMOD模块可以衍生出很多有趣的应用矩阵键盘扫描用8个IO做行线输出8个IO做列线输入并启用内部上拉配合中断功能可以实现一个16键的矩阵键盘几乎不占用FPGA主逻辑资源。多路LED驱动24个输出口可以直接驱动LED实现复杂的灯光效果。利用PWM寄存器在Bank 1甚至可以实现每个LED独立的亮度调节。传感器集线器连接多个I2C或SPI传感器到扩展IO上FPGA通过模拟相应的协议与传感器通信。TCA6424A在这里主要提供片选/CS或使能信号。多模块级联利用可配置的地址在同一PMOD接口上插多个本模块。FPGA通过切换I2C地址来访问不同的模块几何级数地扩展GPIO数量。需要注意的是所有模块的SDA/SCL是并联的/INT线也需要通过线与逻辑所有/INT输出开漏连接到一起用一个上拉电阻连接到FPGA的一个引脚上。封装成通用IP核将I2C Master控制器和TCA6424A的特定驱动封装成一个可参数化的FPGA IP核。用户只需要提供时钟、复位、以及类似“设置端口方向”、“写输出”、“读输入”的简单接口底层复杂的I2C时序全部由IP核搞定。这极大提高了复用性。5.4 调试过程中遇到的典型问题与解决无应答NACK这是最常见的问题。首先检查硬件电源是否正常上拉电阻是否焊上I2C线是否接反地址是否正确注意7位地址和8位写地址的区别然后用逻辑分析仪看到底是哪个环节从机没有应答。往往是起始条件或停止条件不符合规范或者数据建立/保持时间不够。读写数据错误确保你的FPGA I2C控制器在接收数据时采样点是在SCL高电平的中间附近。发送数据时数据变化要在SCL低电平期间完成。时序稍有偏差在低速下可能勉强工作但可靠性差。中断不触发检查/INT引脚的上拉电阻。确认输入端口配置寄存器是否正确设置为输入。检查中断屏蔽寄存器是否默认屏蔽了所有中断。有时需要先读取一次输入寄存器才能清除可能存在的旧中断状态。驱动能力不足当扩展IO上连接多个LED或继电器时单个IO的驱动电流通常10-20mA可能不足。TCA6424A的驱动能力有限必要时需要在IO口外加三极管或MOS管来驱动大电流负载。自己动手从芯片手册研究、设计电路、编写驱动、调试排错到最后看到LED随着自己的代码闪烁传感器数据被正确读取这种成就感远非使用现成模块可比。这个TCA6424A PMOD模块项目麻雀虽小五脏俱全它串起了数字电路、通信协议、硬件设计、FPGA逻辑和嵌入式软件如果你用软核处理器控制它等多个知识点是一个综合性极强的练手项目。希望我的这些经验和细节能帮你绕过我踩过的那些坑更顺畅地完成自己的IO扩展之旅。
返回列表