Hello! 大家好,我是本次《来实战》项目第六期的执行官,小曹同学,本次项目主题是“基于FPGA的ECG信号采集与处理系统设计”,与众多STM32或Arduino等单片机直接利用软件编程调用库函数不同,本项目以底层逻辑为切入点进行数字电路设计,更加关注电路底层的细节,包括基础模块的划分、接口信号的定义、verilog代码设计、仿真验证以及板级调试,在满足性能要求下,同时会评估资源消耗问题,希望大家能和我一起一步一步的完成此次工程项目,而不是简单的copy。其中难免有错误,希望各位指正。
引言:
FPGA开发和数字IC设计十分相似,而两者最基础是verilog代码设计,verilog是硬件描述语言,实现的数字电路具备硬件并行处理的优点,所以verilog设计思想与基于软件的编程语言是有很大不同的,复杂的verilog代码设计不是随随便便直接在板子上调试成功的。
本项目侧重对设计代码的仿真验证,而不是简简单单对代码 “搬运工”,达到所谓“快速”入门的假现象。在FPGA开发中,每一行verilog代码已经决定了电路的性能和功能,仿真是对verilog代码设计的有效验证方法,因为代码存在的bug在仿真中会一一被定位出来,“速成”FPGA开发都是假的,不能一行一行代码看懂和敲出来,verilog学习的时长都是无用功,正确设计方法+动手练习是FPGA开发/数字电路设计的正确打开方法。以下是我个人设计的方法:
首先根据你的硬件条件包括FPGA板型和其他硬件(AD、VGA、LCD、舵机、摄像头等等),确定一个硬件的详细设计方案;
接着根据需求和参考资料将整体划分到各个小模块,并确定各个模块接口之间的数据信号和控制信号;画时序图主要是根据数据信号走向需要哪些控制信号,而控制信号主要实现方式就是cnt、enable、flag等等;
其次按照图纸就可以敲代码了,而verilog代码语法不是很难,主要是算术运算符、赋值运算符、关系运算符、逻辑运算符、条件运算符、位运算符以及移位拼接等,一般设计会这些足够了,而往往多数初学者觉FPGA设计很简单啊,大概指的这部分语法简单,但是在敲代码过程中还要考虑到组合逻辑以及时序逻辑中常用的模块,{组合逻辑主要包括常用逻辑门(与门、或门、非门、异或等)、比较器、半加器、全加器、乘法器、数据选择器、三态门,时序逻辑主要包括D触发器、两级D触发器、带异步复位的D触发器、带异步复位同步清零的D触发器、移位寄存器、单口RAM、伪双口RAM、真双口RAM、单口ROM、有限状态机等}。而这些基本单元在写代码过程做到心中有数,因为这些决定了设计的PPA(Performance,Power,Area);
最后再通过仿真工具对设计的代码进行验证,首先是功能仿真也就是RTL行为级仿真,主要是检查代码中的语法错误以及代码行为的正确性,但是不包括延时信息,验证之前“模块划分与接口定义”阶段。其次是后仿真也就是时序仿真,在设计布局布线后提供一个时序仿真模型,验证之前“画接口信号时序”阶段。
步骤一:项目框架
目的意义:
在我国,随着生活节奏加快,心血管疾病的发病率有逐年递增的趋势;同时由于人们生活水平和健康意识的不断提高,对心脏类疾病进行实时监护的需求也不断增加。但是,心血管疾病本身具有无症状性(病人在发生心肌缺血时并没有胸痛、心绞痛等常见症状)和间歇性。
选择这个主题主要原因之一是开发一种可以帮主人们日常生活的非侵入性设备—基于FPGA的ECG信号采集与处理。市场上有许多ECG信号检测产品可以提高效率(尺寸较小,将数据保存在云中等等),但是其中任何一件产品都很少涉及到复杂信号处理,并没有与数据库进行比对。
内容及结构安排:
本文基于Xilinx公司的Artix-7系列芯片xc7a35tcpg236-1和AD83232采集板搭建一套硬件平台用以异常ECG信号检测系统。使用Vivado和ModelSim设计和仿真各个系统模块的功能,本系统主要有AD8232信号采集,FPGA存储和处理,C#GUI显示及matlab处理。其中FPGA处理是核心部分,由以下模块构成:AD模块、RAM模块、UART模块及滤波模块。本文采用Verilog HDL硬件描述语言进行编程,XADC具有两个专用的差分输入引脚Vp和Vn,可用于采样模拟信号,通过ADC模块完成100 MHz到360 Hz的数据采样,同时采用低通滤波器消除共模噪声;在所有存储单元中存满ECG的样本数据后,将生成一个脉冲以触发向PC的传输。UART模块将接收一个信号,该信号使用TX模块进行发送,当接收UART检测到起始位时,它将开始以称为波特率的特定频率读取输入位。
本项目主要有以下方面:
1.FPGA学习流程。编写项目详细设计方案,主要包括数据通路和控制通路的设计,模块划分与接口信号的定义,数据通路原理图以及控制通路时序图,verilog代码的具体设计,以及仿真验证,下载到FPGA开发板调试。在verilog代码设计过程会描述时序图,用到IP核,数据通路的寄存器消耗资源进行评估。
2.用到的滤波处理。在信号处理中,数字滤波器是一种对采样的离散时间信号执行数学运算以减少或增强该信号某些方面的系统。数字滤波器系统通常由一个模数转换器对输入信号进行采样,使用FPGA或ASIC代替通用微处理器或具有特定并行架构的专用DSP,以加快诸如过滤之类的操作。
3.基础能力锻炼。根据IP开发文档,掌握XADC使用、RAM写读、UART数据传输以及状态机verilog代码设计。
项目简介:
包含四大部分:AD采集模块、RAM存储模块、滤波处理模块、UART模块。
首先,AD8232放大器输出是一个介于0至3.3V之间的模拟值,ADC模块的输入应为1V,因此需要进行分压。放置在放大器的输出和FPGA板的输入(Vp引脚)之间,AD模块包括PLL和XADC 完成100 MHz到360 Hz的数据采样。
其次,我们利用RAM模块存储通过ADC采集的样本。模块具有2个命令模式:读取和写入。这两种状态由启用写模式时为高电平和禁用写模式时为低电平的信号控制。
接着,尽管XADC也可以完成滤波作用,为了便于学习本项目通过Digital filter模块完成低通滤波过程。
最后,UART模块将接收脉冲信号后,等到信号指示灯的跳变,读出一帧数据,由于ADC只有12位,而UART只有8位,所以我们需要传输2组数据。
开发计划:
图1:整体计划表
Step1: 确定整个设计思路,ECG信号检测的总体框图,确定程序流程框图
Step2: AD模块、包括XADC和分频时钟接口定义,进行具体verilog代码设计和仿真验证
Step3: RAM读写模块、根据状态机进行接口定义,进行具体verilog代码设计和仿真验证
Step4: Digital filter模块、UART模块接口定义,进行具体verilog代码设计和仿真验证
Step5: 进行功能扩展,并将以上所有模块集成在一起,并且做整个仿真验证以及板级调试,通过在C#GUI中显示及保存为.csv文件,利用MATLAB进行相关算法处理,整理打包完整的开源方案所有资料(设计源码、参考资料)
图2:项目整体流程图
图3:项目整体介绍
好啦,第一期就唠嗑到这里啦,接下来,我将陆续分享“基于FPGA的ECG信号采集与处理系统设计”项目的各个步骤的内容,如果对这个项目感兴趣,想深入了解和沟通,请在右栏浮动模块中扫码申请加入“来实战技术交流群”(Q群)。
欢迎点击下方【收藏按钮】收藏本项目,持续更新中,敬请关注...
步骤二:AD采集模块
心电图分析
ECG分为两个基本间隔,即PR Interval和QT Interval,如下所述。
图2.1 正常心电图
为了确定心脏病,我们需要了解所有这些波形:
P Wave:心房的去极化,心房去极化从SA结向AV结,从右心房扩散到左心房。如果p波的持续时间异常长,则可能代表心房增大。通常,大的右心房会产生高的峰值p波,而大的左心房会产生两个峰的二裂p波。持续时间<80ms。
PR interval:PR间隔是从P波的开始到QRS波的开始测量的。 该间隔反映了电脉冲从窦房结穿过AV结所花费的时间。短于120 ms的APR间隔表明,电脉冲绕过了AV节点,如Wolf-Parkinson-White综合征。PR间隔持续超过200 ms会诊断为一级房室传导阻滞。持续时间:120到200ms。
QRS complex:QRS复合波代表左右心室的快速去极化。与心房相比,心室的肌肉较大,因此QRS复合波的振幅通常比P波大得多。如果QRS复合波较宽(大于120毫秒),则表明心脏传导系统或心室节律(如室性心动过速)中断。持续时间:80到100 ms;
ST segment:ST段连接QRS波群和T波。它代表心室去极化的时期。可能因心肌梗塞或局部缺血而降低或升高。心包炎也可引起ST升高;
T wave:T波代表心室的复极化。除aVR和V1引线外,所有引线通常都直立。倒T波可能是心肌缺血的征兆。 T波峰值可能是非常早的心肌梗塞的征兆。持续时间:160 ms;
U wave:假设U波是由室间隔的复极化引起的。它通常具有低振幅,甚至更多时候是完全不存在的。如果U波非常突出,则可能是甲亢。
心电传感器
电极贴片离心脏越近,则测量越好。根据Einthoven的三角形识别正确的位置。传感器可以放置在前臂和腿上。或者,可以将它们放置在靠近手臂的胸部上,并位于右下腹部上方(即,右髋上方),如图所示。
图2.2 传感器放置位置
AD8232放大器
全集成式ECG前段AD8232芯片,如图3.3所示。该芯片广泛应用于健身及运动心率监护仪、便携式ECG、游戏外围设备、生物电信号采集等设备。其共模抑制比为80Hz(DC至60Hz)。信号增益高(G=100)带DC阻塞能力。内部带有RFI射频干扰滤波器、3极点可调低通滤波器。电源供电2.0V-3.5V。使用该模块ADC能够轻松地采集输出信号。AD8232采用一个无使用约束运算放大器来创建一个三极点低通滤波器,消除了额外的噪声。使用时可通过限制滤波器的截止频率来满足不同类型应用的需要。芯片工作时具备导联脱落检测。
图2.3 AD8232放大器
XADC配置
Xilinx的7系列FPGA和Zynq器件创造性地在片上集成了模数转换器和相关的片上传感器(内置温度传感器和功耗传感器),XADC内部可以直接获取芯片结温和FPGA的若干供电电压,用于监控FPGA内部状况。同时提供了17对差分管脚,其中一对专用的模拟差分输入,16对复用的模拟差分输入,不使用的时候可以作为普通的User I/O。Mux除了连接到专用ADC输入引脚上(VP_0,VN_0),同时支持外部16路差分模拟电压输入,可以有不同的选通,最终复用一个ADC输入。此外可以对FPGA内部温度和各档电压监控,同时也是复用一个12bitADC转换,其中,参考电压可以是内部1.25V,也可以外接外部稳定参考电压源。转换完后,有一个控制寄存器和状态寄存器,通过FPGA的DRP接口与FPGA内部逻辑连接,也可以通过JTAG查看温度或者电压变化情况。
图2.4:XADC功能框图
当den_in信号拉高后,输入的数据di_in和输入的地址daddr_in总线就会被内部xadc接收;dwe_in拉高表示要向xadc内部指定寄存器写数据;dwe_in拉低表示当前是读数据,就会隔几个时钟周期返回drdy_out,这个drdy_out拉高后表示要把xadc内部寄存器地址、比如vp/vn转换值存放在03H地址里面,读取vp/vn寄存器地址数据也就是电压转换的数字值,就把数据总线do_out保存到adc_out寄存器里面。
图2.5:DRP接口时序图
ADC_top模块
该部分主要由pll,xadc_capture,xadc_div模块组成,xadc_top模块主要完成对数据总线100 MHz到360 Hz的AD采样。
图2.6:ADC_top模块
图2.7:ADC模块的详细设计
PLL(锁相环):是一种电子电路,可以不断调节以匹配输入信号频率的相位; PLL用于频率控制。锁相环电路通过将外部信号的相位与晶体振荡器产生的时钟信号的相位进行比较来工作。该电路调整振荡器时钟信号的相位,以使其与参考信号的相位匹配。PLL电路可以设置为倍频器或分频器,跟踪发生器,时钟恢复电路或解调器。
在该电路中,该PLL用于将输入频率(100 MHz)划分为14 MHz ,这是XADC输入的频率。使用了Clocking Wizard IP核,并且该模块已连接到:
clk_in1: 输入频率(100 MHz); clk_in2: 动态重配置端口的时钟输入(XADC输入);
图2.8:PLL模块
XADC:XADC具有两个专用的差分输入引脚Vp和Vn,可用于采样模拟信号。 您还可以使用16个辅助输入。但是,这些辅助输入的FRBW(全分辨率带宽)较低,为250kHz,而专用输入的FRBW为500kHz。 因此,如果我们要处理XADC的最大奈奎斯特频率附近的信号,则需要使用其专用输入。XADC可以以高达1Msamples /秒的速度对通道进行采样。由于XADC具有12位分辨率,因此我们需要电容器两端的电压稳定在12位值的½LSB之内。
图2.9:XADC配置界面
在我们使用的开发板中,电极的输出将连接到引脚vaux6,来自AD8232的模拟电压会被转换为数字信号,我们XADC配置的36KSPS的采样频率,这是因为数据库的采样频率是360Hz,便于后续进行分频操作,从PLL获得的所需输入DCLK频率(MHz)为14 MHz。
由于数据总线do_out是16bit,为了便于后续发送,在这里截取了高12位。
drdy_out:动态配置接口的数据准备好信号。xadc_div模块:因为ADC的输出频率为36KHz,所以我们需要将分频处理能达到360 Hz。
图2.10 xadc_div模块
通过JTAG查看输入模拟电压值
好啦,第二期就唠嗑到这里啦,接下来,我将陆续分享“基于FPGA的ECG信号采集与处理系统设计”项目的各个步骤的内容,如果对这个项目感兴趣,想深入了解和沟通,请在右栏浮动模块中扫码申请加入“来实战技术交流群”(Q群)。
欢迎点击下方【收藏按钮】收藏本项目,持续更新中,敬请关注...
步骤三:RAM模块
3.1 FIR低通滤波器
滤波器部分主要设计到FIR的verilog设计,filter_div,filter_mult。该模块完成对数据流的实现了频率为100 Hz的21阶低通滤波器,以消除ECG信号中的噪声。
图3.1 低通滤波器
在信号处理中,数字滤波器是一种对采样的离散时间信号执行数学运算以减少或增强该信号某些方面的系统。这与模拟滤波相反,模拟滤波器是一种对连续时间模拟信号进行操作的电路。
很容易就能理解是,高通滤波:高频信号可以通过,而低频信号不能通过。低通滤波:低频信号可以通过,而高频信号不能通过。数字滤波器通常由一个模数转换器对输入信号进行采样,然后由一个微处理器和一些外围组件(例如用于存储数据和滤波器系数的存储器)组成。最后,由一个数模转换器来完成输出阶段。微处理器上运行的程序指令(软件)通过对从ADC接收到的数字执行必要的数学运算来实现数字滤波器。在某些高性能应用中,使用FPGA或ASIC代替通用微处理器或具有特定并行架构的专用DSP,以加快诸如过滤之类的操作。低通滤波器是一种使频率低于某个截止频率的信号通过并衰减高于该截止频率的信号的滤波器。
该部分主要着重代码设计,滤波器具体的操作在这里不在重述,这是一位CSDN博客已经将详细叙述整个设计,按照步骤操作即可:低通FIR滤波器设计+Vivado实现
使用matlab中的filterDesigner设计滤波器
图3.2:100Hz 低通滤波器
得到滤波器系数:
进行具体的verilog代码设计
图3.3:框架
图3.4: 流水线操作
对输入的数据进行延迟操作,每1个bit数据,就会依次缓存到reg signed [9:0] prev[20:0]; 然后接下来的数据在进来时候,就会依次移位依次
在乘滤波器系数时候,调用一个乘法器IP核。
图3.5: 乘法器配置界面
然后将IP核例化到filter_21.v中
generate语法是可以可以实现某些语句的重复,在这里对例化的filter_mult.v进行了该操作,使用generate 语句同时需要定义genvar,这是因为generate语句需要的循环变量。
其中coeffs系数如下,也就是通过链接方法求得,这里always@(*)是指里面的语句是组合逻辑的,*代替了敏感变量。
最后使用20个加法器将乘积结果进行累加,结果就是滤波后的信号
最后我们做个简单RTL逻辑分析,结果如下,基本满足设计要求,高清图放在步骤3附件,感兴趣可以查看。
图3.6: RTL分析
3.2 RAM模块
需要存储ADC采集的样本,因此使用了RAM,RAM是FPGA中常用的基础模块,可广泛用于缓存数据的情况,同样它也是ROM,FIFO的基础。片内RAM具有2个命令模式:读取和写入。这两种状态由we信号启用写模式时为高电平和禁用写模式时为低电平的信号控制。
图3.7: ram写满操作
在这里使用了[11:0] memory [0:2048]的reg信号,每一个触发脉冲,index都会递增,并存储一个样本,当index等于2048时,产生一个脉冲,并且系统更改其状态,然后ram处于完全读取模式。
在ram存储单元中存储满了来自ECG的样本数据后,将生成一个脉冲pulseMEM以触发向PC的传输,UART模块将接收这个信号(该信号将允许使用TX模块进行发送),这个脉冲也是控制数据流,而且在不完整的数据的是不发送的,这会就可以减慢获得的结果,并于后续状态机操作。
图3.8: ram端口信号
该模块具有另一种良好的同步方法:dataReady1控制信号,是在ADC模块完成AD采集转换后,RAM才开始被写入数据。
仿真结果如下,从图中可以看出地址0写入的data_in数据是2049,在上个周期,也就是data_out数据是1,表明有效数据读出,整个写与读出有个memory_delay。
图3.9: 仿真
步骤四:UART模块
常见的串口通信波特率有2400 、9600、115200等,发送和接收波特率必须保持一致才能正确通信。波特率是指1秒最大传输的数据位数,包括起始位、数据位、校验位、停止位。假如通信波特率设定为9600,那么一个数据位的时间长度是1/9600秒,本实验中的波特率由100MHz时钟产生
图4.1:uart模块端口信号
接下来内容主要介绍通过状态机设计UART,在UART通信中,两个UART直接相互通信。UART_tx将并行数据转换为串行形式,以串行方式将其发送至UART_rx,然后UART_rx将接收到的串行数据转换并行数据。只需要两条线即可在两个UART之间传输数据。数据从UART_tx的Tx引脚到UART_rx的Rx引脚:
图4.2:模块端口引脚
这里以uart_tx模块为例,这里画出了控制信号接口时序图:
图4.3:uart_tx模块
本实验中的波特率由100MHz时钟产生,串口通信波特率9600,也就是10416个时钟周期传输1个数据位,
S0时候,系统空闲状态,data是需要拉高的,busy信号是串口正在发送的一个标志信号, bit_pos是对每个数据位进行计数操作,当计数最大值7的时候,相应也会进行清零操作,en信号就是发送模块工作的一个触发信号,他主要是用来检测待发送模块的一个信号,这里检测到en信号,进入S1状态
S1时候,也就是i计数到最大值时候,在这里可以看到i=10415,这个data_out会进行拉低操作,表示起始位
S2时候,bit_pos从0计数到7时候,这个时候数据进行传输,这边起始位之后,就是55,也就是10101010,从低到高这个顺序。
S3时候,这里会将out拉高,之后发送完之后各个控制信号清零,包括计数器,如果没有清零,会影响到下一次发送。
其中UART协议原理:消息帧从一个低位起始位开始,后面是7个或8个数据位,一个可用的奇偶位和一个或几个高位停止位。接收器发现开始位时它就知道数据准备发送,并尝试与发送器时钟频率同步。如果选择了奇偶校验,UART就在数据位后面加上奇偶位。奇偶位可用来帮助错误校验。在接收过程中,UART从消息帧中去掉起始位和结束位,对进来的字节进行奇偶校验,并将数据字节从串行转换成并行。UART 传输时序如下图所示:
图4.4:UART传输时序图
UART异步传输数据,这意味着没有时钟信号将发送UART的位输出与接收UART的位采样同步。发送UART代替时钟信号,将开始和停止位添加到正在传输的数据包中。这些位定义了数据包的开始和结束,因此接收UART知道何时开始读取这些位。
图4.5:verilog仿真验证
当接收UART检测到起始位时,它将开始以称为波特率的特定频率读取输入位。 波特率是数据传输速度的度量,以每秒比特数(bps)表示。两个UART必须以大约相同的波特率工作。在位的时序变得太远之前,发送和接收UART之间的波特率只能相差约10%。
· 仅使用两根电线;
· 无需时钟信号;
· 具有奇偶校验位以允许进行错误检查;
· 只要双方都设置好数据包的结构即可;
· 广泛使用的方法;
该模块还具有良好的同步方法:startT控制信号,仅当该引脚为高电平时,才会开始发送。还需要检查标志是否忙碌—是否正在进行其他传输,txDone是在传输执行时发出信号的标志。
UART块逐样本读取缓存样本并将其发送到PC,因为在UART中包的长度是8位,所以每个样本被分成两个字节。
图4.6:AD(12bit)采集到发送(8bit)
因为ADC只有12位,而UART只有8位,所以我们需要传输2组数据。在这种情况下,重要的是要知道何时进行每次传输。这就是为什么需要cntParity的原因:cntParity。在偶数奇偶校验上,我们传输8位,在奇数奇偶校验上,其他4位被传输。
步骤五:整理调试
5.1 工具要求
项目所需的工具是:
⭐Digilent的Basys3开发板
⭐AD8232心电采集模块
⭐若干导线
在Basys3 上,XADC Pmod接口拥有4组差分模拟输入输出,其相应的XADC通道是6、7、14和15。下图是XADC Pmod引脚图,该项目引用了引脚1,其中XADC配置寄存器是addr<=7'h16
分压电路:
Vivado 2016.4
ModelSim SE-64 10.5
Notepad++
Visual Studio 2017
5.2 综合设计
视频包括:顶层文件,各个模块功能,还有RTL分析,调试视频
上位机采集结果
这个上位机C#程序被设计成通过UART连接到FPGA;首先需要做的是选择合适的COM,这个可以在设备管理器中找到它。在对FPGA下载bit流文件后并设置放大器在电极后,只需点击GUI中的“Send”按钮,即可开始采集。之后,通过“Get”按钮,样本数据被发送到PC端并显示出来。
5.3 模块综合RTL
主要模块分为AD采集模块(XADC模块和分频模块),FIR滤波模块,ram存储模块,UART模块。模块之间的连接主要在顶层模块进行状态机操作,实现功能主要有:心电信号的采集、滤波、存储和发送。
AD采集模块
FIR滤波模块
RAM存储模块
UART模块
5.4 性能评估
功耗
时序
资源消耗_表
资源消耗_图
5.5 感想
这个基于FPGA的心电信号采集与处理系统既不是可以替代医学咨询的产品,也不是可以治疗任何疾病的产品,而是适合检查特定地点的人体医学状况的系统。 这种项目可用于监测无法去医院的老年患者的健康,或可用于检查患者的病情是否发生了变化。来自电极的心电信号使用AD8232(放大器)进行放大,然后将其发送到Bays3开发板,在此处进行处理。 该项目还具有一个用C#开发的GUI(图形用户界面),用来显示ECG。
该项目最大的问题之一是采集到发送精度:由于ADC的12位和UART的8位,很难在不丢失信号同步的情况下解决两者之间的差异。但是很好地通过模块之间的许多控制信号解决了该问题。
至此,本期项目挑战赛已经全部打包完成,其中难免有缺漏和错误之处,敬请谅解或提出宝贵意见,便于后期及时纠正。
版权声明:本文内容为电路城原创内容,未经授权禁止转载,侵权必究!