FPGA&MSP430实现等精度频率计
前段时间依次实现了FPGA的等精度频率计和FPGA与430的通信测试。
FPGA频率计:Verilog设计练习 基于FPGA的等精度频率计_Krism0912的博客-CSDN博客_用verilog设计等精度频率计
FPGA与430通信测试:
FPGA与MSP430G2553通信 UART串口操作_Krism0912的博客-CSDN博客
由于FPGA中对数据运算过于麻烦,所以此次将上述两个成果进行了整合,将FPGA的数据通过串口传至MSP430后再进行运算。
在整合过程中碰到的一个百思不得其解的问题:串口测试中发现传输过去的Nx的值总是理论值的2倍。花了几个小时才最终弄清楚原因,下面稍做记录。
错误出现在FPGA的uart_tx原代码的改写。
改写的代码如下:
module uart_tx_1(
input clk, //9600Hz
input [39:0]data_Nx,
input [39:0]data_Nb,
input rst,
input send_start_flag,
output reg txd
);
//串口发送状态机分为四个状态:等待、发送起始位、发送数据、发送完成
localparam IDLE = 0,
SEND_START = 1,
SEND_DATA = 2,
SEND_END = 3;
reg [3:0] state = IDLE;
reg [4:0] count = 0;
reg [39:0] data_o_tmp=0;
reg send_flag=0;reg [6:0] send_data_num =0;
always @(posedge clk or negedge rst)
begin
if(!rst)
state <= IDLE;
else
begin
case (state)
IDLE: begin
if (send_start_flag) state<= SEND_START;
else state <= IDLE;
end
SEND_START: state <= SEND_DATA;
SEND_DATA: begin
if (count == 7) state <= SEND_END;
else state <= SEND_DATA;
end
SEND_END: begin
if (send_data_num>0 && send_data_num<80)
state <= SEND_START;
else state <= IDLE;
end
default: state <= IDLE;
endcase
end
end
always @(posedge clk or negedge rst)
begin
if(!rst)
count<=0;
else if (state == SEND_DATA)
count <= count + 1;
else if (state == IDLE | state == SEND_END)
count <= 0;
end
always @(posedge clk or negedge rst)
if(!rst)
data_o_tmp <=0;
else if (send_start_flag)
data_o_tmp <= data_Nb; //data_o_tmp是某个数字
else if (send_data_num==40)
data_o_tmp <= data_Nx;
else if (state == SEND_DATA)
data_o_tmp[38:0] <= data_o_tmp[39:1]; //将要发送的数据位放在 data_o_tmp[0]
else
data_o_tmp <= data_o_tmp;
always @(posedge clk or negedge rst)
begin
if(!rst)
send_data_num <=0;
else if(state == SEND_DATA)
send_data_num = send_data_num+1;
else if(send_data_num == 80)
send_data_num <= 0;
else
send_data_num <= send_data_num;
end
always @(posedge clk or negedge rst)
if (!rst)
txd <=1;
else if (state == SEND_START)
txd <= 0; //发送起始位
else if (state == SEND_DATA)
txd <= data_o_tmp[0]; //发送数据低位在先,高位在后
else if (state == SEND_END)
txd <= 1; //发送停止位
endmodule
原程序仅发送一个40位的数据进行测试,而根据实际结果,FPGA需要将Nx,Nb两个40位数据接连发送给MSP430。
我理所当然地想到只需把send_data_num由原来的40改为80,并且在 send_data_num=40时将待发送的数据由Nb改为Nx即可。
然而测试了很久,Nx的值一直是理论值的两倍,而Nb没什么问题。
之后写了一大堆仿真程序观察Nx和Nb的值,发现没有任何不对。
后来脑子一抽随手改了自定义的标识符:
assign data_Nx={8'b0,Nx};
assign data_Nb={8'b1,Nb};
改为:
assign data_Nx={8'd2,Nx};
assign data_Nb={8'b1,Nb};
发现UART传过去的标识符也不对,最后的是04而不是02。
于是恍然大悟,觉得是UART的改写部分存在问题。
于是又花了一大把时间仿真UART。仿真中给定Nx和Nb的值为:
Nx=32'b10101010_11110000_11110000_10101010;
Nb=32'b01100000_11111111_11110000_00001111;
波形图不仔细看还真的看不出有什么问题、、
但确确实实有问题。。
以send_data_num从33到40位为例(上图左方),对应的txd是:10000000(发送的数据是Nb的标识符8'b1,由低位发送至高位)
send_data_num=40共占有3个uart_clk周期(当然 send_data_num=32时也同样如此)。
根据时序,第一个T对应的txd是0,是Nb的最后一位数据;
第二个T对应的txd是1,是发完Nb的第40位数据之后的停止位;
第三个T对应的txd是0,是发送新一个数据前的起始位。
如此,send_data_num从41到48位对应的txd应该是:01010101(Nx的低8位)
但是txd的波形上是0010101...(多了个0)
所以最后发送的数据差了一个倍数。如果不是把标识符从0换掉还发现不了。
正常情况下(上图),在SEND_DATA状态时,data_o_tmp[0](也就是待发送的那一位数据)的波形应该提前txd波形一个uart_clk周期。
按照时序,发送完一位数据后(比如第24位)data_o_tmp[0]的值应该马上替换为下一位数据(第25位)以在下一个时钟周期时被发送。 代码的棕色加粗部分体现了这一逻辑。
然而在40位时多发了一个0,因为上述的移位过程并没有发生。在黄线后(num=41的周期),data_o_tmp[0]应该从0变为1。(Nx=32'b10101010_11110000_11110000_10101010
--->Nx=32'b10101010_11110000_11110000_10101010)
原因清楚了,在黄线处的uart_clk的posedge_clk上升沿执行代码时,send_num_data=40(请参考同步时序和异步时序的区别,弄清楚代码里的变量值到底是多少),于是红色加粗部分的代码被执行,所以未发生移位。
红色加粗部分原意是在发送完40个数据时将data及时更换(波形图中也可以看出确实已经正确更换),但是却因此出错。
至此,出错原因已经确定。参考的改错方法:将红色加粗处的else if的判断条件变为:
else if (send_data_num==40&&state==SEND_END)
MSP430中则比较好解决,代码很简单。
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
if(i==1)
{
a=UCA0RXBUF; i++;
}
else if(i==2)
{
b=UCA0RXBUF; i++;
}
else if(i==3)
{
c=UCA0RXBUF; i++;
}
else if(i==4)
{
d=UCA0RXBUF; i++;
}
else if(i==5)
{
e=UCA0RXBUF;
IE2&=~UCA0RXIE;
if(e==1)
Nb = a+b*256+(unsigned long) c*256*256+(unsigned long) d*256*256*256;
else if(e==2)
{
Nx = a+b*256+(unsigned long) c*256*256+(unsigned long) d*256*256*256;
frequency = (double)Nx/(double)Nb*fb;
}
IE2|=UCA0RXIE;
i=1;
}
}
参考的测量结果:(来自硬木口袋信号发生器)
50kHz
5kHz
2Hz
低频的测量还不是很理想,还需要进一步改进。
END
更新
SIGENT示波器测量结果
2Hz
100Hz
1kHz
20kHz
100kHz
1MHz
10MHz
40MHz
再往上就出不来结果了QAQ。。
等精度测频的基准时钟clk是由FPGA的PLL模块生成的400MHz时钟