"2023年寒假在家一起练"基于STM32+iCE40的频率计设计
该项目将完成2015年电赛F题数字频率计设计,将由型号为:STM32G031G8U6单片机与型号为:ICE40UP5K的FPGA,以及前级比较电路,完成设计。
标签
嵌入式系统
FPGA
PCB设计
频率计
begin
更新2023-03-28
安徽师范大学
526

一.项目介绍

该项目将完成2015年电赛F题数字频率计设计,将由型号为:STM32G031G8U6单片机与型号为:ICE40UP5K的FPGA,以及前级比较电路,完成设计。采用FPGA+单片机的设计思路,能够发挥出它们相应的优势,将大大降低设计难度,提高设计性能。

二.设计思路

首先将信号输入到比较器的输入端,通过高速比较器,可以产生相应输入频率的方波。方波产生之后就可以由FPGA处理了。FPGA选择合适的频率的测量方法,测出频率,通过SPI发送给STM32单片机,STM32通过软件SPI接收数据后将,数据通过软件SPI发送给OLED显示屏显示。

Fr0BkdqoosCX2h4JEvS0IwSWrvyV

 

三.硬件介绍

主要有四个硬件:1.TP1961-TR高速比较器 2.STM32G031单片机 3.ICE40的FPGA 4.OLED显示屏

 

FkGk-Db4eJ8mWUc0q9QBZzzSWn1f

四.方案分析

1.硬件分析

输入级采用TP1961-TR比较器,该比较器具有7ns响应时间,输出最高频率可以大约可达到(1/7ns)/2=71Mhz,满足题目要求,但是发挥部分需要输入100Mhz正弦波,无法满足,输入失调电压由+-6mv满足题目要求。

2.软件与算法分析

测量频率的方法有许多种,比如周期测量法,频率测量法,以及等精度测量,周期测量法适合测低频,而频率测量法适合测高频。我采用的等精度测量法,这样只需选择合适的参数就可以达到较高的精度,而不需要其它两种方法来回切换。等精度测量法被测时钟信号的误差与本身无关,与“软件闸门”和和“标准时钟信号”有关 。“软件闸门”越大,“标准时钟信号”频率越高,测量的误差就越小,精度就越准确。

假设实际闸门下被测时钟信号Fx计数X次,则Tx=X/Fx;                                                                    假设实际闸门下标准时钟信号Fs计数Y次,则Tx=Y/Fs;

综上所述:可得Fx=Fs*X/Y,所以只需要确定数字闸门,然后统计标准时钟计数和被测时钟计数,之后进行计算,就可以测得被测时钟频率频率。

 

五.细节与问题处理

1.比较器连接错误:经过仔细研究测试,发现TP1961-TR比较器,并不是接在FPGA的引脚上,而是STM32上,所以导致无法直接用FPGA测量频率。对此考虑了两种方案:

(1)将STM32连接比较器的引脚用杜邦线连接到FPGA引脚上,同时讲STM32的引脚设为模拟输入模式,防止对信号的影响。

(2)外接高速比较器,采用滞回比较器接法,消除输出方波跳变时的振荡。

FkxRG673uPRU_GWHZgq4eCVS9eU0

 

2.低频计算误差:最开始采用FPGA做乘除法运算,然后将数据拆分为两个16位的数据发送给单片机。但是FPGA做除法运算后只剩下整数位了,测量低频信号有较大误差。比如测量10.1Hz,但最后显示屏上只会显示10Hz,这样就有了百分之1的误差,可以说是非常大了,而FPGA的除法要算出小数点后数字,会比较麻烦。所以就将数据X,Y发送给单片机,让单片机做乘除法运算,这样可以在低频测量时,有很高的分辨率。

 

3.数据传输问题:因为要传输数据X和Y,而这些数据各有32位,而SPI最多单次传输16位,所以总共要传输4次。而单片机是不断运行的,万一哪一次传输发生错误,则会导致后面的数据全错,所以需要再增加一个16位数据,作为接收数据标志位,以此来确认收到的数据准确无误。所以每次传输数据时,需要通过SPI发送5个16位的数据。

 

4.等精度法问题: 采用等精度法在实际测量中,如果信号被测突然消失,X,Y的值将不会改变,SPI传输的仍是上次的X,Y值,这因为实际闸门是需要采集到被测信号的上升沿,而被测信号的消失,就使得无法采集到上升沿。从而使得实际闸门一直保持打开,所以X,Y值不会被更新,但是重新加入信号就可以恢复正常测量。在实际过程中,一般会保持着被测信号一直存在,所以此问题影响并不大,就不做相应的处理。

 

六.功能代码

1.FPGA频率测量代码

 

//cnt_gate_s:软件闸门计数器
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_gate_s<=28'd0;
	else if(cnt_gate_s==CNT_GATE_S_MAX)
		cnt_gate_s<=28'd0;
	else 
		cnt_gate_s<=cnt_gate_s+1'b1;

//gate_s:软件闸门
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		gate_s<=1'b0;
	else if((cnt_gate_s>=CNT_RISE_MAX)
		  &&(cnt_gate_s<=(CNT_GATE_S_MAX-CNT_RISE_MAX)))
		gate_s<=1'b1;
	else 
		gate_s<=1'b0;

//gate_a:实际闸门
always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		gate_a<=1'b0;
	else 
		gate_a<=gate_s;

//cnt_clk_stand:标准时钟周期计数器,计数实际闸门下标准时钟周期数
always@(posedge clk_stand or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_clk_stand<=32'd0;
	else if(gate_a==1'b0)
		cnt_clk_stand<=32'b0;
	else if(gate_a==1'b1)
		cnt_clk_stand<=cnt_clk_stand+1'b1;
		
//cnt_clk_test:待检测时钟周期计数器,计数实际闸门下待检测时钟周期数
always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_clk_test<=32'b0;
	else if(gate_a==1'b0)
		cnt_clk_test<=32'b0;
	else if(gate_a==1'b1)
		cnt_clk_test<=cnt_clk_test+1'b1;
		
//gate_a_stand:实际闸门打一拍(标准时钟下)
always@(posedge clk_stand or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		gate_a_stand<=1'b0;
	else 
		gate_a_stand<=gate_a;
		
//gate_a_fall_s:实际闸门下降沿(标准时钟下)
assign gate_a_fall_s=((gate_a_stand==1'b1)&&(gate_a==1'b0))
						?1'b1:1'b0;

//cnt_clk_stand_reg:实际闸门下标准时钟周期数
always@(posedge clk_stand or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_clk_stand_reg <=32'd0;
	else if(gate_a_fall_s==1'b1)
		cnt_clk_stand_reg <=cnt_clk_stand;



//gate_a_test:实际闸门打一拍(待检测时钟下)
always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		gate_a_test<=1'b0;
	else
		gate_a_test<=gate_a;

//gate_a_fall_t:实际闸门下降沿(待检测时钟下)
assign gate_a_fall_t = ((gate_a_test == 1'b1) && (gate_a == 1'b0))
						? 1'b1 : 1'b0;
		
//cnt_clk_test_reg:实际闸门下待检测时钟周期数
always@(posedge clk_test or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		cnt_clk_test_reg<=32'd0;
	else if(gate_a_fall_t==1'b1)
		cnt_clk_test_reg<=cnt_clk_test;

//calc_flag:待检测时钟时钟频率计算标志信号
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		calc_flag<=1'b0;
	else if(cnt_gate_s==(CNT_GATE_S_MAX-1'b1))
		calc_flag<=1'b1;
	else 
		calc_flag<=1'b0;
		
//freq::待检测时钟信号时钟频率
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n==1'b0)
		begin
		stand_reg<=32'd0;
		test_reg<=32'd0;
		end
	else if(calc_flag==1'b1)
		begin
		stand_reg<=cnt_clk_stand_reg;
		test_reg<=cnt_clk_test_reg;
		end

2.STM32通过软件SPI发送数据到 OLED显示

while (1)
  {
			freq=(float)Temp2/(float)Temp1*clk_stand;
			sprintf(str1,"%d",Temp1);
			sprintf(str2,"%d",Temp2);
			sprintf(str3,"%.3f",freq);
			//HAL_Delay(100);
			OLED_ShowString(0,0,"                      ");
			OLED_ShowString(0,0,(uint8_t *)str1);
			
			OLED_ShowString(0,2,"                      ");
			OLED_ShowString(0,2,(uint8_t *)str2);
		
		  OLED_ShowString(0,4,"Freq:");
			OLED_ShowString(40,4,"                      ");
			OLED_ShowString(40,4,(uint8_t *)str3);
			HAL_Delay(5);
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
	}

3.FPGA资源占用

 

Foz6nLXOOpZ5NSFKxh3K5r0dpJOP

4.测试部分结果

FlASrKkG8wOMFB0mZ9bbAVgYysM-

FkxZ-aILPKqs-XMR7ff9MpFjv1-2

七.总结与反馈

在这次寒假练活动中,我学到会了频率计的使用,并且不断优化自己的方案,使最终指标更优。且也学会了用cubemx去编程,大大提高了开发效率,学习了新的开发平台:Lattice,对于以后无论遇到什么样的FPGA都能轻松学习。

附件下载
stm32g031代码.rar
iCE40_Verilog代码.rar
团队介绍
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号