电阻测试板软件设计
1 功能需求分析
电阻测试板的主要功能是通过分压法测量多路电阻的阻值大小。通过两个STM32的多路路ADC采集被测电阻两端的电压,将该值通过SPI通信传送给FPGA,然后FPGA通过LOCAL端总线把该值传送给PLX9054,PLX9054再通过PCI总线将该值传送给主机,主机根据分压公式,计算出电压对应的电阻值。其结构组成如图1.1所示。
图1.1 电阻测试板卡构成
两片STM32F4有总共50路ADC,用了其中的48路来获取被测电阻两端的电压,一个电阻需要两路ADC采集,分别采集Vh和Vl;
两片STM32F4采集到ADC的数据以后,计算压差Vh-Vl,并且通过SPI总线和FPGA通信,把采集到所有通道压差和指定通道的Vl(R3、R4、R9、R10)发送给FPGA;
FPGA与PLX9054实现PCI总线功能,将STM32发送过来的数据通过PCI总线透传给主机,主机根据电阻计算公式计算各路电阻数值。
2 管脚分配
- 第一片STM32的引脚分配:
管脚功能 | 通道号 | 管脚号 | 配置属性 |
ADC_H_R0 | ADC1通道13 | PC3 | ADC复用 |
ADC_H_R1 | ADC1通道8 | PB0 |
|
ADC_H_R2 | ADC1通道4 | PA4 |
|
ADC_H_R3 | ADC1通道12 | PC2 |
|
ADC_H_R4 | ADC1通道3 | PA3 |
|
ADC_H_R5 | ADC1通道11 | PC1 |
|
ADC_H_R6 | ADC1通道1 | PA1 |
|
ADC_H_R7 | ADC1通道6 | PA6 |
|
ADC_H_R8 | ADC3通道6 | PF8 |
|
ADC_H_R9 | ADC3通道4 | PF6 |
|
ADC_H_R10 | ADC3通道9 | PF3 |
|
ADC_H_R11 | ADC3通道5 | PF7 |
|
ADC_L_R0 | ADC1通道15 | PC5 |
|
ADC_L_R1 | ADC1通道9 | PB1 |
|
ADC_L_R2 | ADC1通道5 | PA5 |
|
ADC_L_R3 | ADC1通道14 | PC4 |
|
ADC_L_R4 | ADC1通道7 | PA7 |
|
ADC_L_R5 | ADC1通道2 | PA2 |
|
ADC_L_R6 | ADC1通道10 | PC0 |
|
ADC_L_R7 | ADC1通道0 | PA0 |
|
ADC_L_R8 | ADC3通道7 | PF9 |
|
ADC_L_R9 | ADC3通道14 | PF4 |
|
ADC_L_R10 | ADC3通道15 | PF5 |
|
ADC_L_R11 | ADC3通道8 | PF10 |
|
SPI4_NSS | SPI片选 | PE11 | SPI复用 |
SPI4_SCK | SPI时钟 | PE12 |
|
SPI4_MISO | SPI主机输入 | PE13 |
|
SPI4_MOSI | SPI主机输出 | PE14 |
|
- 第二片STM32的引脚分配:
管脚功能 | 通道号 | 管脚号 | 配置属性 |
ADC_H_R12 | ADC1通道6 | PA6 | ADC复用 |
ADC_H_R13 | ADC1通道11 | PC1 |
|
ADC_H_R14 | ADC3通道7 | PF9 |
|
ADC_H_R15 | ADC1通道2 | PA2 |
|
ADC_H_R16 | ADC1通道14 | PC4 |
|
ADC_H_R17 | ADC1通道5 | PA5 |
|
ADC_H_R18 | ADC1通道7 | PA7 |
|
ADC_H_R19 | ADC1通道8 | PB0 |
|
ADC_H_R20 | ADC3通道6 | PF8 |
|
ADC_H_R21 | ADC3通道13 | PC3 |
|
ADC_H_R22 | ADC3通道4 | PF6 |
|
ADC_L_R12 | ADC1通道0 | PA0 |
|
ADC_L_R13 | ADC1通道10 | PC0 |
|
ADC_L_R14 | ADC1通道1 | PA1 |
|
ADC_L_R15 | ADC1通道3 | PA3 |
|
ADC_L_R16 | ADC1通道12 | PC2 |
|
ADC_L_R17 | ADC1通道4 | PA4 |
|
ADC_L_R18 | ADC1通道9 | PB1 |
|
ADC_L_R19 | ADC1通道15 | PC5 |
|
ADC_L_R20 | ADC3通道8 | PF10 |
|
ADC_L_R21 | ADC3通道5 | PF7 |
|
ADC_L_R22 | ADC3通道9 | PF3 |
|
SPI4_NSS | SPI片选 | PE11 | SPI复用 |
SPI4_SCK | SPI时钟 | PE12 |
|
SPI4_MISO | SPI主机输入 | PE13 |
|
SPI4_MOSI | SPI主机输出 | PE14 |
|
3 设计流程
流程中需要设计的模块主要是两个部分:第一部分为STM32的驱动模块编写,包含ADC驱动的编写、SPI驱动的编写等;第二部分为PCI上位机的驱动接口的封装。
3.1 STM32的驱动模块设计
STM32主要是SPI模块的驱动设计、ADC驱动模块的设计以及定时器模块的设计。SPI模块完成和FPGA的通信,STM32作为SPI的主机,周期性的将获取到的ADC数据通过SPI发送给FPGA,完成数据的传输;ADC完成电阻测量电路中被测电阻两端电压的采集,定时器模块完成整个系统的周期定时功能。
由STM32的SPI4控制器做主设备将采集到的ADC数据发送给FPGA,时序上的规定为:SPI的时钟配置为5M左右;空闲时候SPI时钟配置为高电平,在时钟的第二个边沿采样数据;数据配置为16bit;
SPI驱动的配置流程如下:
- 使能SPI的时钟并且使能SPI的GPIO口的时钟;
- 初始化SPI对应IO为SPI功能IO口;
- 将SPI的片选线拉高,保证初始化后没有片选;
- 初始化配置SPI的属性,时钟频率:90/16=5.625MHz;工作模式:时钟空闲时为高电平,在时钟的第二个边沿采样数据;数据传输模式:16bit,高位在前低位在后;传输方向:全双工模式的主设备模式;
- 使能SPI外设功能;每隔50ms更新一次数据buffer,并将该ADC数据发送给FPGA;
SPI驱动配置流程如图3.1所示。
图3.1 SPI驱动配置流程
由STM32的ADC1和ADC3控制器去采集电阻测量电路中被测电阻两端的电压值。ADC1的16个通道全部用上,ADC3用了8个通道。通过独立配置两个通道ADC为扫描模式,通过DMA形式一次性将所有的通道的采集值搬运到指定的缓存中,然后通过定时器周期性的将对应的AD值发送给FPGA。其驱动配置流程如下:
- 使能ADC1和ADC3的IO口的时钟;
- 使能ADC1和ADC3外设的时钟;
- 配置ADC1与ADC3的所有需要配置的IO为模拟输入,并且使能ADC1与ADC3对应DMA的时钟;
- 配置ADC1与ADC3的DMA属性:ADC1选择DMA2的数据流0的通道0,ADC3选择DMA2的数据流1的通道2;ADC1对应缓存空间大小为16,ADC3对应缓存空间大小为8;DMA传输方向为外设到内存;DMA的Burst为单次模式;DMA内存端地址为自增模式,DMA外设端内存为非自增模式;DMA优先级配置为高。
- 配置ADC模式属性:ADC1与ADC3都配置为独立采集模式;配置ADC的时钟周期和采样周期;配置ADC为连续转换模式;配置ADC数据为右对齐模式;配置ADC为非外部触发;配置ADC精度为12位模式;使能ADC扫描采样模式;
- 配置ADC1的规则转换序列顺序(0-15通道);配置ADC3的规则转换序列顺序(4-9通道、14-15通道);使能ADC的DMA功能;使能ADC1和ADC3外设;
- 开启ADC的软件转换;
- 每隔5ms将采集到的ADC数据进行一次更新,采集到十次以后进行一个均值计算,并且将均值通过SPI口发送给FPGA。
ADC驱动配置流程如图3.2所示。
图3.2 ADC驱动配置流程
板子运行需要有时间基准,解析接收串口指令需要进行周期性操作,需要时间基准,更新电流传感器的数据需要时间基准,本系统解析串口指令的周期定为20ms一次;更新电流传感器的数据的周期定为5ms一次;判断电流传感器数值是否大于阈值的操作周期定为5ms一次。保证整个流程能够周期性的运行。定时器驱动配置流程如下:
- 配置定时器驱动组优先级;
- 使能定时器驱动的时钟;
- 配置定时器分频系数:定时器时钟源clk = 2 * pclk1 TIMCLK = 180M / 2 = 90M 定时器频率 = TIMCLK / (TIM_Prescaler + 1) 1M = 90 / (90 - 1);
- 配置定时周期数;
- 使能定时器中断和定时器外设;
- 定时器中断中设置定时标识,每次触发中断将定时标识置1;
定时器驱动配置流程如图3.3所示:
图3.3 定时器驱动配置流程
3.2 上位机驱动接口封装
上位机的驱动接口函数主要是PCI驱动函数,分为寻找板卡函数、打开板卡函数、关闭板卡函数、电阻数据采集函数等。在使用电阻采集板卡的时候,需要先通过寻找板卡函数从卡槽中找到板卡句柄,然后通过打开板卡函数将电阻测试板卡打开,再通过电阻数据采集函数将对应通道的电阻值获取给用户使用。其使用流程如图3.4所示。
图3.4 电阻测试函数调用流程
1,寻找板卡函数是通过调用PLX官方函数PlxPci_DeviceFind,去获取数据类型为PLX_DEVICE_KEY的板卡信息。通过轮询形式去遍历所有卡槽中的板卡,并把各个卡槽中的板卡信息反馈给用户。
调用实例:DATA_TYPE P_Data;
Pci_DeviceFind(&P_Data);
将所有板卡信息获取到P_Data数据结构中。
2,打开板卡函数是通过调用PLX官方函数PlxPci_DeviceOpen,去打开指定板卡信息的板卡,并且调用PlxPci_DmaChannelOpen函数打开指定的DMA通道,并把打开的板卡的句柄反馈给用户。
调用实例:BOOL rc;
rc = Open(&(P_Data.D_1553B.Key_data),
&(P_Data.D_1553B.Device_data),0,&hChrComCard,&hADCar);
if (rc != TRUE)
{
AfxMessageBox("OPen 1553B Card Failed!");
}
3,电阻测试函数需要通过读取PCI总线上的寄存器来获取,其寄存器属性列表如表3.1所示。通过调用寄存器读取函数PlxPci_PciBarSpaceRead获取到对应寄存器的数据,然后计算电阻值。
表3.1 测试电阻寄存器
测试电阻寄存器各位位域 | 功能描述 |
31:12 | 保留 |
11:0 | ADC的数据 |
电阻测试寄存器的基地址为0x2C0000,其寄存器分两组,第一组是0-11通道,第二组是12-22通道,第一组的偏移量为(0x800 * ((n)),第二组的偏移量为0x8000 + (0x800 * ((n)),其中n表示通道号。其低12为表示下位机传输过来的ADC电压值,根据计算公式计算出对应通道的电阻值。
调用实例:
Drv_RTEST_In(&(P_Data.D_RTEST.Device_data),
RTEST_channel_Value,&RTEST_Value);
4,关闭板卡函数是通过调用PLX官方函数PlxPci_DeviceClose,去关闭指定板卡信息的板卡,并且调用PlxPci_DmaChannelClose函数关闭指定的DMA通道,并把打开的板卡的句柄销毁。
调用实例:
rc = Close(&(P_Data.D_1553B.Device_data),0,hChrComCard,hADCar);
if(rc == FALSE)
{
AfxMessageBox("Close 1553B Card Failed!");
}