关于DDS的正弦波ROM裁剪问题

关于DDS的正弦波ROM裁剪问题

质疑著
在这里感谢电子森林的苏老师对上一篇博客提出的质疑

基于FPGA的两路信号发生器

问题是这样的

在上一篇博客中我曾经写到:

a
1 8 \frac18 是在一个别人写的专利交底书的里面看到的,当时心理想了想觉得是可以的,没有实际地操作过

然后我把博客分享到朋友圈后收到了电子森林苏老师的一些质疑,其中一个便是这个应该是 1 4 \frac14 还是 1 8 \frac18 的问题,当时年少轻狂的我说着应该是 1 8 \frac18 ,结果吃完饭想着实验一下,便发现,这错的离谱了。。。史称秒打脸,故作此篇实地操作一下这个 1 4 \frac14 的ROM表压缩,也算是对自己的一个小警示…

MATLAB生成1/4的ROM表

这里本来应该是8192个点的,因为我中途意识到自己的错误的时候,为了偷懒不重新配置ROM,所以就把这里改成了4096个点,其他的唯一改动就在于在文件写入操作的时候只写了前 1 4 \frac14 个点,和修复了以前mif文件没有自动加END;结尾的BUG.

这并不是很重要

depth = 4096;
width = 14;
x = 0 : 2*pi/(depth-1) :2*pi;
y = sin(x);

y=(y+1)/2*16383/16384;      %转正
disp(y);
y_qua = round(y*2^width);

%编写mif文件
fid = fopen('/home/heweibao/project_matlab/fpga_dds/sindiv8.mif','wt'); %将信号写入一个.mif文件中
fprintf(fid,'WIDTH=%d;\n',width);%写入存储位宽
fprintf(fid,'DEPTH=%d;\n',depth/4);%写入存储深度
fprintf(fid,'ADDRESS_RADIX=UNS;\n');%写入地址类型为无符号整型
fprintf(fid,'DATA_RADIX=UNS;\n');%写入数据类型为无符号整型
fprintf(fid,'CONTENT BEGIN\n');%起始内容
for num=0 : (depth-1)/4 
fprintf(fid,'%d:%14.0f;\n',num,y_qua(num+1));
end
fprintf(fid,'END;');
fclose(fid);

plot(x,y_qua);

FPGA状态机控制地址和加减

这里直接上图看一个周期:
bb
至于为什么是这样,大家可以从导数的角度自己理解一下,所以写出来的状态机是这样的:

module fsm_control(
	input clk,rst_n,
	
	output reg oper_add_sub,	// 0 for add ,1 for sub 
	output reg [9:0] phase_address
);

parameter s0 = 2'b00,
			 s1 = 2'b01,
			 s2 = 2'b10,
			 s3 = 2'b11;

reg [2:0] now_state;

always @(posedge clk or negedge rst_n)
begin 
	if(!rst_n)
		begin
			now_state <= s0;
			phase_address <= 10'd0;
			oper_add_sub <= 1'b0;
		end
	else
		case(now_state)
			
			s0:begin			
					phase_address <= phase_address + 1'b1;
					oper_add_sub  <= 1'b0;
					
					if(phase_address == 10'd1023) 
						begin 
						   phase_address <= 10'd1023;
							now_state	<= s1;
						end
					else	now_state <= s0;
				end
			s1:begin	
					phase_address <= phase_address - 1'b1;
					oper_add_sub  <= 1'b1;
					
					if(phase_address == 10'd0) 
						begin 
							phase_address <= 10'd0;
							now_state	<= s2;
						end
					else	now_state <= s1;
				end
			s2:begin	
					phase_address <= phase_address + 1'b1;
					oper_add_sub  <= 1'b1;
					
					if(phase_address == 10'd1023 ) 
						begin 
						   phase_address <= 10'd1023;
							now_state	<= s3;
						end
					else	now_state <= s2;
				end
			s3:begin	
					phase_address <= phase_address - 1'b1;
					oper_add_sub  <= 1'b0;
					
					if(phase_address == 10'd0 ) 
						begin 
							phase_address <= 10'd0;
							now_state	<= s0;
						end
					else	now_state <= s3;
				end
		endcase
end
endmodule

意外的收获

在写上面的状态机的时候,因为我是写一个状态然后复制粘贴修改的,所以当时的有一个信号的非阻塞赋值我给了阻塞赋值,所以提供了一个真正学习非阻塞赋值和阻塞赋值的区别的机会,大家可以将每个状态的前一个phase_address<=phase_address+1改成阻塞赋值试试看(虽然我当时错的并不是这个)

ROM操作端

这里要考虑就是我的数据是没有符号位的,所以取加减的时候需要求出变化量的绝对值,而且变化量要防止因为状态切换而突然变大导致波形失真,要做一个阈值判断.最后就是初始值给最大值的一半.

module data_process(
	input clk,rst_n,
	input oper_add_sub,	// 0 for add ,1 for sub 
	input [9:0] phase_address,
	
	output wire [13:0] data_out
);

wire [13:0] rom_data_out;

rom_sin_8	rom_sin_8_inst (
	.address ( phase_address ),
	.clock ( clk ),
	.q ( rom_data_out )
	);

reg [13:0] data_shift ,data_shift_pre;
always @(posedge clk or negedge rst_n)
begin 
	if(!rst_n)
		begin
			data_shift <= 14'd0;
			data_shift_pre <= 14'd0;
		end
	else
		begin 
			data_shift <= data_shift_pre;
			data_shift_pre <= rom_data_out;
		end
end

wire [13:0] delta_data;
assign	delta_data = data_shift<data_shift_pre ? (data_shift_pre - data_shift) :
													 (data_shift-data_shift_pre);

reg [13:0] out_data;
always @(posedge clk or negedge rst_n)
begin 
	if(!rst_n)
			out_data <= 14'd8192;
	else
	//	out_data <= oper_add_sub ? (out_data-delta_data<14'b0)? 14'b0  : (out_data-delta_data) : 
	//					 	  (out_data+delta_data>14'h3fff)? 14'h3fff : (out_data+delta_data);
		out_data <= oper_add_sub ? (out_data-delta_data) :(out_data+delta_data);
end

assign data_out = out_data;

endmodule

仿真结果

CC

结语

这次确实是年少轻狂,没认真思考惹的问题. 不过错了就应该大大方方承认嘛.

自省年少显轻狂,俯首道歉表心怀

再一次谢谢电子森林苏老师的质疑.

如果你觉得有丶收获的话

猜你喜欢

转载自blog.csdn.net/weixin_38071135/article/details/94774515