AD+FPGA+STM32示波器设计 串口传输到MATLAB(设计报告)

Posted by 橙叶 on Fri, Apr 9, 2021

一体化简易信号源与示波器设计

[TOC]

系统方案

​ 整体设计框图:

​ FPGA部分由DE0开发板(Cyclone Ⅲ)和AD/DA子板组成。本设计使用了AD/DA子板上配备的并行ADC AD9200 和并行DAC AD9762。输入到示波器的信号由AD/DA子板上SMA接口RF IN输入;从信号源输出的信号由AD/DA板上的SMA接口RF OUT输出。

1. 信号源

​ 信号源采用DDS(直接数字式频率合成)设计,使用FPGA驱动AD9762产生不同频率的正弦信号。并由STM32控制信号频率。将FPGA时钟倍频至200MHz,输出足够高频率的信号。因为一个完整周期正弦波可以由前1/4个周期反折、取反后组成,所以只需要在ROM中存储1/4个周期的正弦波形,就可以输出完整的正弦信号。

​ AD9762是一个12位分辨率、125MSPS刷新率的DAC,可以保证1MHz~40MHz的信号输出。

​ 信号源设计框图:

2. 示波器

​ 示波器使用FPGA+STM32的设计,由FPGA从AD9200上采集信号,连续采集一定长度的信号并存储到RAM中,之后由STM32从RAM中读取数据后将波形显示到LCD屏上。

​ STM32控制FPGA波形采集模块,设定采样速率、触发电平、触发方式。使用STM32开发板上的按键进行控制。

​ 示波器设计框图

​ 受2017 年全国大学生电子设计竞赛试题H题“远程幅频特性测试装置”的启发,考虑到STM32本身难以对采集到的数据进行复杂的处理和显示,因此需要将数据实时导出到电脑上,在电脑上可以使用MATLAB等工具进行分析。本设计中,使用串口进行电脑和STM32间的数据传输。

3. 通信模块设计

通信模块简介

​ 通信协议上,为了满足读写需要,STM32与FPGA之间使用四线SPI协议进行通信,STM32为主机,FPGA为从机,传输速度2Mbps。STM32F407自带SPI外设,直接配置后调用即可。

​ 由于本设计需要STM32同时控制信号源和示波器两个功能模块,为了便于通信操作,在SPI协议的基础上增加通信模块,定义一系列寄存器和操作命令,将SPI通信简化成寄存器和RAM的读写。SPI模块与命令解码模块解耦设计,可以将SPI替换成其他通信协议,以满足更广泛的使用。

​ 本设计中的通信模块的特点是通信协议与功能无关。通信模块内置了一组通用寄存器,只需要约定好寄存器号,将该寄存器引出到功能模块上,STM32端使用读写寄存器命令读写该寄存器,即可实现对功能模块的控制。同时,也可以将一部分寄存器划会保留寄存器,控制通信模块本身状态。

​ 在本设计中,引出通信模块中的几个寄存器到信号源模块和示波器模块作为它们的工作参数,STM32通过操作寄存器的方式即可控制这两个模块。

通信模块控制协议

​ 向通信模块发送命令前,应当确保通信模块处于等待状态,否则应当先发送RST复位信号使其复位。命令帧的长度、命令帧内命令和参数长度均作了参数化设计,本设计中,命令帧长度为16bit,其中前8bit为命令,后8bit为参数,寄存器宽度为32bit。

​ 当通信模块处于等待状态时,接收到的第一个16bit数据为命令帧,命令帧包括命令部分(OPCODE)和参数部分(PARAM)。

 0                   1          
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+---------------+---------------+
| OPCODE(8bits) | PARAM(8bits)  |
+---------------+---------------+
|            DATA[0]            |
+-------------------------------+
|            DATA[1]            |
+-------------------------------+
|            .........          |
+-------------------------------+

​ 写寄存器命令WR_REG,参数为寄存器号。发送写寄存器命令后,发送32bit数据到相应寄存器中。

​ 读寄存器指令RD_REG,参数为寄存器号。发送读寄存器命令后,接收相应寄存器中的32bit数据。

 0                   1                   
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+---------------+---------------+
| WR_REG/RD_REG |    REG_NUM    |   Send command
+---------------+---------------+
|            DATA[31:16]        |   Send / Recieve data
+-------------------------------+
|            DATA[15: 0]        |   Send / Recieve data
+-------------------------------+

​ 写RAM命令WR_RAM,参数为空。写RAM命令的参数来自参数寄存器,因此在发送写RAM命令前,应当先设置读写RAM用到的参数寄存器。参数寄存器也是由通用寄存器划分出来,因此可以直接使用写寄存器指令WR_REG修改。写RAM命令需要两个参数:起始地址和读写长度。发送写RAM命令后,通信模块开始接收数据,同时将数据写入RAM。完成指定长度的数据写入后,通信模块自动回归到等待状态。

​ 读RAM命令RD_RAM,参数为空。读RAM命令与写RAM命令相似,共用参数寄存器(起始地址和读写长度)。发送读RAM命令后,通信模块开始发送数据,第一个数据帧为固定的核对标识(MEM_OK),STM32在接收时应当先确认标识是否正确。之后开始接收数据。

 0                   1                   
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+---------------+---------------+
|   RD_RAM      |               |   Send command
+---------------+---------------+
|            MEM_OK             |   Recieve OK flag
+-------------------------------+
|           DATA[0]             |   Recieve data
+-------------------------------+
|           DATA[1]             |   Recieve data
+-------------------------------+
|          ........             |   Recieve more...
+-------------------------------+

​ 以读RAM为例,下面是读RAM的操作流程:

理论分析和计算

信号源频率字计算

​ DDS相位累加器的时钟速度f_{clk},由频率计算得到频率字f_{word},相位累加器宽度为32位,要产生频率为f的正弦波信号,则f_{word}应为:

f_{word} = 2^{32}\frac{f}{f_s}

​ DAC芯片AD9762最大刷新率为125MSPS,可以满足1~40MHz波形要求。

程序设计

1. 信号源

​ 在时钟驱动下,相位累加器不断累加频率字。将相位累加器的[31:20]部分作为地址,地址高2位[11:10]是相位phase, 低10位[9:0]是ROM地址addr。ROM的地址宽度为10位,ROM中存放了正弦波[0, \frac{\pi}{2})的部分共N=1024个值。

  • 当相位在[0, \frac{\pi}{2})时(phase=00_2),直接输出y_{out}=x_{rom}(addr)

  • 当相位在[\frac{\pi}{2}, \pi)时(phase=01_2),波形反折输出y_{out}=x_{rom}(N-addr)

  • 当相位在[\pi, \frac{3\pi}{2})时(phase=10_2),波形取反输出y_{out}=-x_{rom}(addr)

  • 当相位在[\frac{3\pi}{2}, 2\pi)时(phase=11_2),波形反折取反输出y_{out} = -x_{rom}(N-addr)

    信号源的频率字参数从通信模块中的寄存器引出,STM32以读写寄存器方式即可修改频率字参数。

    DDS原理图

    DDS ROM原理图(相位判断和波形转换)

2. 示波器-FPGA部分

​ 示波器的FPGA部分设计为一个AD模块,包括信号触发、数据采集和存储两个功能。

​ 信号触发功能使用简单的阈值触发设计,当信号超过或低于阈值(取决于设置的触发方式),将触发信号的电平转为有效。这样设计既简单又能正确捕获信号上升沿或下降沿。实际测试中发现,输入信号频率较低时可能存在的不稳定会导致错误触发,因此引入两级缓存,同时判断连续的两个样值,测试表明这样的设计可以正确工作。

​ 查阅AD9200的手册可知,该ADC芯片最大采样频率为20MHz。首先将200MHz的主时钟经过主分频器10分频得到20MHz时钟,再由次分频器按照设定的分频系数进行分频。可以控制LCD屏幕上每单元格水平时间在1ms~10us(1ms、500us、200us、100us、50us、20us、10us)间调整。

​ 为了避免RAM出现同时读写的冲突,AD模块在完成一次连续采集后暂停采集,将采集完成的信号置高后等待,STM32捕获到采集完成的信号后开始传输数据,此时通信模块会将RAM占用信号置高,直至数据传输完成。数据传输完成后,通信模块将RAM占用信号置低,AD模块解除等待,继续采集数据并写入RAM。

3. 示波器-STM32部分

​ 完成一次波形采集后,FPGA向STM32发出完成信号,示波器的STM32部分通过SPI协议将FPGA的RAM中存放采集结果传输到内存中,并显示到LCD屏上。

​ 使用STM32开发板上的按键控制示波器的采样速率、触发电平和触发方式。按下按键改变设置时,STM32通过通信模块修改FPGA对应寄存器中设置项的值。其中当采样速率达到最大速率时,则保持当前采样速率,直接以插值的方式放大LCD上的波形。

3. 通信模块-FPGA部分

​ 通信模块定义了两种资源:通用寄存器组和RAM。其中通用寄存器组位于模块内部,外部可以通过地址访问通用寄存器或直接将寄存器从端口引出,从通用寄存器组划分一部分出来作为保留寄存器,用于配置通信模块本身的状态(例如读写RAM的参数);RAM位于通信模块外部,通信模块使用地址进行访问。本设计中,不需要寄存器组和RAM对内外同时可读可写,为了简化设计,寄存器组设计为内部可读、外部可写,RAM设计为内部可写、外部可读。

​ 通信模块定义了两种操作:读/写寄存器(RD_REG/WR_REG)、读/写RAM(PACKED_READ/PACKED_WRITE)。通过参数化设计,通信模块命令和数据宽度可以调整。在本设计中,SPI采用16位数据格式,所以每条命令设置为为8位命令和8位参数。

​ 本设计中,通用寄存器位宽为32位,地址宽度为8位,通过读写寄存器命令操作,参数为寄存器号。因为SPI每次传输16bit,所以需要进行两次传输才能完成一次寄存器读写。

​ 读写RAM需要的参数较多(读写起点、读写长度),无法作为命令参数传输。考虑到设计的简洁性,读写RAM所需的参数将从通用寄存器(存放这些参数所需的寄存器已被划分为保留寄存器)中读出,因此在读写RAM前,先将参数写入寄存器,然后再执行读写RAM的操作。

​ 通信模块借助一系列状态转换来实现:

​ 将通信模块与SPI模块相连,即可从SPI模块接收/发送命令和数据:

​ 通过将通信模块内的通用寄存器引出到其他模块,主机(STM32)可以通过写寄存器的方式控制其他模块的状态,不需要关心SPI的传输细节。

4. 通信模块-STM32部分

​ 按照通信模块的设计,将SPI通信封装成一系列函数:

void COM_WriteReg(uint8_t reg_num, uint32_t data);
uint32_t COM_ReadReg(uint8_t reg_num, uint32_t *data);
void COM_StartMemWrite(uint32_t addr, uint32_t length);
void COM_StartMemRead(uint32_t addr, uint32_t length);
void COM_MemWrite(uint16_t *data, uint32_t length);
COM_STATE COM_MemRead(uint16_t *data, uint32_t length);

​ 例如,控制信号源频率的寄存器号为0x0A,调用函数void COM_WriteReg(uint8_t reg_num, uint32_t data)来设置频率字:

void UpdateFrequency(u32 fs)
{
        u32 fclk = 200;
        u32 fword, fclkword;
        char buf[100];
        fclkword = 0xffffffff/fclk;
        fword = fclkword*fs;  // 计算频率字
        COM_WriteReg(0x0A, fword);  // 将频率字写入寄存器0x0A
}

​ 调用函数uint32_t COM_ReadReg(uint8_t reg_num, uint32_t *data)读取这个寄存器的值:

void ReadFrequencyWord(void)
{
    u32 freq;
    COM_ReadReg(0x0A, &freq);
    printf("Freq word: %d", freq);
}

5. 控制和显示

​ STM32F4探索者开发板上共有4个按键供输入使用。因为设置项较多(触发方式、触发电平、采样速度、信号源频率),以及考虑到未来的功能扩展,采用菜单式的设计,KEY_1和KEY_UP选择设置项,KEY_2和KEY_0修改设置项。

​ 波形显示部分,一个完整的波形图包含背景色(黑色)、网格(暗蓝色)、波形(黄色)。因此,本设计中波形显示部分利用了LCD屏地址自增的特性,通过判断像素点属于背景/网格/波形,写入不同的颜色,一次性完成一张波形图的刷新,提高了绘图速度,避免了闪烁的问题。

测试记录

信号源

频率准确度测试

​ 信号源测试工具:带频率计功能的信号发生器DG1022U。

​ 测试方法:将信号发生器的频率计端口连接到信号源,使用频率计功能测量信号源产生的信号的频率。

信号源设置频率(MHz) 1 5 10 13 20 25 30 33 40
实际测量频率(MHz) 0.99999 4.99995 9.99991 12.9998 19.9996 24.9995 29.9995 32.9989 39.9984

频谱分析

​ 频谱分析工具:示波器MSO9104A。

​ 测试方法:将示波器连接到信号源,使用示波器的FFT功能查看信号的频谱。

1MHz:

5MHz:

30MHz:

40MHz:

示波器测试

​ 示波器测试工具:信号发生器DG1022U。

​ 测试方法:将信号发生器连接到AD输入端口,输入100kH7z和1MHz的正弦波和方波信号,在LCD屏和MATLAB上观察采集结果。

100kHz

1MHz

1MHz 5倍放大

设计总结

​ 本设计中,信号源采用DDS技术,使用AD9762输出波形,可较准确地产生1MHz~40MHz的正弦波信号。示波器使用AD9200采集波形,将采集到的波形显示到LCD上,并传输至电脑。为了方便对以上两个功能的控制,编写了一个通信模块,简化了控制逻辑。

​ 本实验设计尚有诸多不足之处,例如没有缩放LCD屏幕显示的波形的功能、示波器的可配置项较少、无法查看触发前的波形等。

​ 未来可增添幅度挡位切换功能:通过添加前置的处理电路,控制继电器和程控运放改变放大、缩小信号幅度后输入AD。



comments powered by Disqus