通过FPGA内部DDS模块模拟产生一个正弦信号数据源给外部SRAM,STM32处理器通过控制总线将SRAM的数据读出后从USB口送出给上位机
RTL原理图
RTL原理图
1、时钟模块
通过该模块将FPGA外部50M晶振分频至50M和100M,提供一次计数产生20个ns和10个ns的延时功能
module clk_50(clk,rst,locked,STM32_FLAG,n_STM32_FLAG,clk_test); input clk; input rst; input STM32_FLAG; input locked; output reg clk_test; output reg n_STM32_FLAG; reg [3:0]delay; reg [6:0]delay1; /******************************************* 50MHz时钟检测引脚 *******************************************/ always@(posedge clk or negedge rst) begin if(rst==1'b0) begin clk_test<=0; delay1<=0; end else if(delay1==7'd100&&locked==1) begin delay1<=0; clk_test<=0; end else begin delay1<=delay1+1'b1; clk_test<=1; end end /******************************************* SRAM逻辑控制 *******************************************/ always@(posedge clk or negedge rst) begin if(rst==1'b0) begin delay<=0;//延时清零 n_STM32_FLAG<=1'b1; end else if(STM32_FLAG==0) begin if(delay==4'd10)//延时200ns begin delay<=0; n_STM32_FLAG<=1'b0; end else begin delay<=delay+1'b1; n_STM32_FLAG<=1'b1; end end else n_STM32_FLAG<=1'b1; end endmodule
2、SRAM读写模块
通过该模块实现FPGA对外部SRAM芯片的数据读写功能,数据来源由DDS模块产生一个正弦信号并行写入SRAM中
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 17:00:22 04/16/2022 // Design Name: // Module Name: wr_SRAM // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module wr_SRAM(clk,rst,n_STM32_FLAG,data_temp,FPGA_FLAG,addr_sram,data_sram,led); input clk; input rst; input n_STM32_FLAG; input [7:0]data_temp; output reg FPGA_FLAG; output reg [15:0]addr_sram;//申请8位地址总线 output reg [7:0]data_sram;//申请8位数据总线 output reg [1:0]led; parameter IDLE=0; parameter SRAM_WRITE=1; parameter SRAM_READ=2; parameter SRAM_STOP=3; reg [3:0] state; //reg [7:0]data_in; reg [15:0]addr_in; //地址和数据赋值 always@(posedge clk or negedge rst) begin if(rst==1'b0) begin addr_in<=16'b0000_0000_0000_0000;//地址清零 //data_in<=8'b0000_0000; end else if(addr_in==16'b1111_1111_1111_1111) begin addr_in<=16'b0000_0000_0000_0000;//地址清零 //data_in<=8'b0000_0000; end else if(state==SRAM_WRITE) begin //data_in<=data_in+8'd1; addr_in<=addr_in+16'd1;//写入地址 end end always@(posedge clk or negedge rst) begin if(!rst)//如果复位,将拉高所有控制线 begin FPGA_FLAG<=0; led<=2'b00; state<=IDLE; end else case(state) IDLE: begin if(n_STM32_FLAG==0) begin FPGA_FLAG<=0; led<=2'b01; state<=SRAM_WRITE; end else begin led<=2'b10; state<=SRAM_READ; end end SRAM_WRITE://开始向地址总线和数据总线送地址和数据 begin data_sram<=data_temp; addr_sram<=addr_in; state<=SRAM_STOP; FPGA_FLAG<=1; end SRAM_READ: begin//开始从数据总线读取数据 //data_in<=databus; //addr_in<=addrbus; state<=SRAM_STOP; end SRAM_STOP: begin//停止对SRAM操作 /*CE<=1; WE<=1; UB<=1; LB<=1; OE<=1;*/ state<=IDLE; end default:; endcase end endmodule
3、DDS模块
该模块利用那FPGA内部ROM块读取事先准备好的正弦离散信号给SRAM
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 21:49:42 04/18/2022 // Design Name: // Module Name: dds // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module dds(clk,rst,data_dds); input clk; input rst; output wire [7:0]data_dds; //wire [7:0]douta; reg [31:0]fre_add; reg [11:0]rom_addr_reg; reg [11:0]addr_dds; parameter FREQ_CTRL = 32'd42949; parameter PHASE_CTRL = 12'd1024; always@(posedge clk or negedge rst) if(rst == 1'b0) fre_add <= 32'd0; else fre_add <= fre_add + FREQ_CTRL; always@(posedge clk or negedge rst) if(rst == 1'b0) begin rom_addr_reg <=12'd0; addr_dds <=12'd0; end else begin rom_addr_reg <= fre_add[31:20] + PHASE_CTRL; addr_dds <= rom_addr_reg; end /******************************************* ROM正弦信号操作 *******************************************/ blockMemory bm_instance ( .clka(clk), // input clka .addra(addr_dds), // input [11 : 0] addra .douta(data_dds) // output [7 : 0] douta ); endmodule
3、顶层模块
该模块主要对所使用的模块进行例化
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 16:06:39 04/06/2022 // Design Name: // Module Name: Xilinx_Spartan6_SRAMTest // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module Demo(clk,rst,STM32_FLAG,FPGA_FLAG,addr_sram,data_sram,led,clk_test); input clk; input rst; input STM32_FLAG; output FPGA_FLAG; output [15:0]addr_sram; output [7:0]data_sram; output [1:0]led; output clk_test; //wire [10:0]addr; wire [7:0]data_temp; wire [7:0]data_dds; wire n_STM32_FLAG; wire locked; wire clkout_50; /******************************************* 分频进行延时 *******************************************/ clk_50 clk_50_instance( .clk(clkout_50), .rst(rst), .STM32_FLAG(STM32_FLAG), .n_STM32_FLAG(n_STM32_FLAG), .clk_test(clk_test), .locked(locked) ); /******************************************* SRAM写操作 *******************************************/ wr_SRAM wr_SRAM_instance( .clk(clkout_50), .rst(rst), .n_STM32_FLAG(n_STM32_FLAG), .FPGA_FLAG(FPGA_FLAG), .addr_sram(addr_sram), .data_temp(data_dds), .data_sram(data_sram), .led(led) ); /******************************************* PLL分频操作 *******************************************/ /*IBUFG IBUFG_INST ( .O(clk_bufg), .I(clk) );*/ assign sys_clk_ibufg = clk ; pll pll_instance (// Clock in ports .clk(sys_clk_ibufg), // IN // Clock out ports .clkout_50(clkout_50), // OUT .clkout_100(clkout_100), // OUT // Status and control signals .rst(~rst),// IN .locked(locked)); // OUT /******************************************* DDS正弦信号操作 *******************************************/ dds dds_instance( .clk(clkout_50), .rst(rst), //.addr(addr), .data_dds(data_dds) ); endmodule
4、引脚约束
//NET "clk" LOC = P76;//MCLKIN //NET "rst" LOC = P152;//SYS_RESET NET "clk" LOC = T8 | TNM_NET = sys_clk_pin; TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 50000 kHz; ## NET "rst" LOC = L3 | IOSTANDARD = "LVCMOS33"; ## reset pushbutton ## //PIN "pll_instance/clkout_50_buf.O" CLOCK_DEDICATED_ROUTE = FALSE; //PIN "pll_instance/clkout_200_buf.O" CLOCK_DEDICATED_ROUTE = FALSE; //NET "led[3]" LOC = M6;//VD4 //NET "led[2]" LOC = P5;//VD3 NET "led[1]" LOC = N5;//VD2 NET "led[0]" LOC = P4;//VD1 NET "FPGA_FLAG" LOC = D11; NET "clk_test" LOC = E11; //NET "OE" LOC = J16;//SRAM_OE# //NET "CE" LOC = K16;//SRAM_CE# NET "STM32_FLAG" LOC = H16;//SRAM_WE# //NET "UB" LOC = G16;//SRAM_BE0 //NET "LB" LOC = F15;//SRAM_BE1 NET "addr_sram[0]" LOC = N4;//SA0 NET "addr_sram[1]" LOC = N6;//SA1 NET "addr_sram[2]" LOC = M4;//SA2 NET "addr_sram[3]" LOC = R2;//SA3 NET "addr_sram[4]" LOC = R5;//SA4 NET "addr_sram[5]" LOC = T6;//SA5 NET "addr_sram[6]" LOC = T7;//SA6 NET "addr_sram[7]" LOC = T9;//SA7 NET "addr_sram[8]" LOC = T12;//SA8 NET "addr_sram[9]" LOC = T13;//SA9 NET "addr_sram[10]" LOC = R14;//SA10 NET "addr_sram[11]" LOC = R15;//SA11 NET "addr_sram[12]" LOC = P15;//SA12 NET "addr_sram[13]" LOC = N16;//SA13 NET "addr_sram[14]" LOC = M16;//SA14 NET "addr_sram[15]" LOC = K15;//SA15 NET "data_sram[0]" LOC = M5;//SD0 NET "data_sram[1]" LOC = P6;//SD1 NET "data_sram[2]" LOC = P2;//SD2 NET "data_sram[3]" LOC = R1;//SD3 NET "data_sram[4]" LOC = T4;//SD4 NET "data_sram[5]" LOC = T5;//SD5 NET "data_sram[6]" LOC = R7;//SD6 NET "data_sram[7]" LOC = L8;//SD7 //NET "databus[8]" LOC = R9;//SD8 //NET "databus[9]" LOC = R12;//SD9 //NET "databus[10]" LOC = T14;//SD10 //NET "databus[11]" LOC = T15;//SD11 //NET "databus[12]" LOC = R16;//SD12 //NET "databus[13]" LOC = P16;//SD13 //NET "databus[14]" LOC = M15;//SD14 //NET "databus[15]" LOC = L16;//SD15
数据来源为实测ADC0809采样数据
顶层
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 16:06:39 04/06/2022 // Design Name: // Module Name: Xilinx_Spartan6_SRAMTest // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module Demo(clk,rst,STM32_FLAG,EOC,DATA,FPGA_FLAG,addr_sram,data_sram,led,clk_test,START,OE,ALE,ADDA); input clk; input rst; input STM32_FLAG; input EOC; input [7:0]DATA; output FPGA_FLAG; output [7:0]addr_sram; output [7:0]data_sram; output [1:0]led; output clk_test; output START; output OE; output ALE; output ADDA; //wire [10:0]addr; wire [7:0]data_temp; //wire [7:0]data_dds; wire n_STM32_FLAG; wire clkout_500k; wire locked; wire clkout_50; wire [7:0]DATA_R; /******************************************* 分频进行延时 *******************************************/ clk_50 clk_50_instance( .clk(clkout_50), .rst(rst), .STM32_FLAG(STM32_FLAG), .n_STM32_FLAG(n_STM32_FLAG), .clk_test(clk_test), .clkout_500k(clkout_500k), .locked(locked) ); /******************************************* SRAM写操作 *******************************************/ wr_SRAM wr_SRAM_instance( .clk(clkout_50), .rst(rst), .n_STM32_FLAG(n_STM32_FLAG), .FPGA_FLAG(FPGA_FLAG), .addr_sram(addr_sram), .data_temp(DATA_R), .data_sram(data_sram), .led(led) ); /******************************************* PLL分频操作 *******************************************/ /*IBUFG IBUFG_INST ( .O(clk_bufg), .I(clk) );*/ assign sys_clk_ibufg = clk ; pll pll_instance (// Clock in ports .clk(sys_clk_ibufg), // IN // Clock out ports .clkout_50(clkout_50), // OUT .clkout_10(clkout_10), // OUT // Status and control signals .rst(~rst),// IN .locked(locked)); // OUT /******************************************* DDS正弦信号操作 *******************************************/ /*dds dds_instance( .clk(clkout_50), .rst(rst), //.addr(addr), .data_dds(data_dds) ); */ /******************************************* ADC0809采集模块操作 *******************************************/ ADC ADC_instance( .clk(clkout_500k), //脉宽(至少100ns) .rst(rst), .EOC(EOC), //约100us后EOC变为高电平转换结束 .START(START), //启动信号,上升沿有效(至少100ns) .OE(OE), //高电平打开三态缓冲器输出转换数据 .ALE(ALE), //高电平有效,选择信道口 .ADDA(ADDA), //因为ADDB,ADDC都接地了,这里只有ADDA为变量 .DATA(DATA), //转换数据 .DATA_R(DATA_R) ); endmodule
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 16:34:56 04/16/2022 // Design Name: // Module Name: clk_100 // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module clk_50(clk,rst,locked,STM32_FLAG,n_STM32_FLAG,clk_test,clkout_500k); input clk; input rst; input STM32_FLAG; input locked; output reg clk_test; output reg n_STM32_FLAG; output reg clkout_500k; reg [3:0]delay; reg [6:0]delay1; reg [5:0]counter; /******************************************* 100MHz时钟检测引脚 *******************************************/ always@(posedge clk or negedge rst) begin if(rst==1'b0) begin //clk_test<=0; delay1<=0; end else if(delay1==7'd100&&locked==1) begin delay1<=0; //clk_test<=0; end else begin delay1<=delay1+1'b1; //clk_test<=1; end end /*********************************** 产生AD时钟500Khz由PLL提供 ***********************************/ always@(posedge clk or negedge rst) begin if(rst==1'b0) begin //clk_test<=0; counter<=6'd0; end else if(counter==6'd39) begin clkout_500k <=~clkout_500k;//50MHZ clk_test<=~clk_test; //clk_test<=0; counter<=6'd0; end else begin counter<=counter+1'd1; //clk_test<=1; end end /******************************************* SRAM逻辑控制 *******************************************/ always@(posedge clk or negedge rst) begin if(rst==1'b0) begin delay<=0;//延时清零 n_STM32_FLAG<=1'b1; end else if(STM32_FLAG==0) begin if(delay==4'd10)//延时200ns begin delay<=0; n_STM32_FLAG<=1'b0; end else begin delay<=delay+1'b1; n_STM32_FLAG<=1'b1; end end else n_STM32_FLAG<=1'b1; end endmodule
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 17:00:22 04/16/2022 // Design Name: // Module Name: wr_SRAM // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module wr_SRAM(clk,rst,n_STM32_FLAG,data_temp,FPGA_FLAG,addr_sram,data_sram,led); input clk; input rst; input n_STM32_FLAG; input [7:0]data_temp; output reg FPGA_FLAG; output reg [7:0]addr_sram;//申请8位地址总线 output reg [7:0]data_sram;//申请8位数据总线 output reg [1:0]led; parameter IDLE=0; parameter SRAM_WRITE=1; parameter SRAM_READ=2; parameter SRAM_STOP=3; reg [3:0] state; //reg [7:0]data_in; reg [7:0]addr_in; //地址和数据赋值 always@(posedge clk or negedge rst) begin if(rst==1'b0) begin addr_in<=8'b0000_0000;//地址清零 //data_in<=8'b0000_0000; end else if(addr_in==8'b1111_1111) begin addr_in<=8'b0000_0000;//地址清零 //data_in<=8'b0000_0000; end else if(state==SRAM_WRITE) begin //data_in<=data_in+8'd1; addr_in<=addr_in+8'd1;//写入地址 end end always@(posedge clk or negedge rst) begin if(!rst)//如果复位,将拉高所有控制线 begin FPGA_FLAG<=0; led<=2'b00; state<=IDLE; end else case(state) IDLE: begin if(n_STM32_FLAG==0) begin FPGA_FLAG<=0; led<=2'b01; state<=SRAM_WRITE; end else begin led<=2'b10; state<=SRAM_READ; end end SRAM_WRITE://开始向地址总线和数据总线送地址和数据 begin data_sram<=data_temp; addr_sram<=addr_in; state<=SRAM_STOP; FPGA_FLAG<=1; end SRAM_READ: begin//开始从数据总线读取数据 //data_in<=databus; //addr_in<=addrbus; state<=SRAM_STOP; end SRAM_STOP: begin//停止对SRAM操作 /*CE<=1; WE<=1; UB<=1; LB<=1; OE<=1;*/ state<=IDLE; end default:; endcase end endmodule
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 11:03:19 04/21/2022 // Design Name: // Module Name: ADC0809 // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module ADC(clk,rst,EOC,START,OE,ALE,ADDA,DATA,DATA_R); input clk;//脉宽(至少100ns) input rst; input EOC;//约100us后EOC变为高电平转换结束,A/D转换结束信号,输出,当A/D转换结束时,此端输出一个高电平(转换期间一直为低电平 input [7:0] DATA;//数字量输入 output reg[7:0] DATA_R;//数字量输出 output reg START;//启动信号,上升沿有效(至少100ns), A/D转换启动信号,输入,高电平有效。 output reg OE;//数据输出允许信号,输入,高电平有效。当A/D转换结束时,此端输入一个高电平,才能打开输出三态门,输出数字量 output reg ALE;//地址锁存允许信号,输入,高电平有效 output reg ADDA; //reg START; //reg OE; //reg ALE; //reg ADDA; //reg [7:0] DATA_R; reg [4:0] CS; reg [4:0] NS; /********************************** 编码 ***********************************/ parameter IDLE=5'b00001; parameter START_H=5'b00010; parameter START_L=5'b00100; parameter CHECK_END=5'b01000; parameter GET_DATA=5'b10000; /**********************利用有限状态机设计AD工作流程************************/ always @(posedge clk) case(CS) IDLE: NS=START_H; START_H: NS=START_L; START_L: NS=CHECK_END; CHECK_END: if(EOC) NS=GET_DATA; else NS=CHECK_END; GET_DATA: NS=IDLE; default: NS=IDLE; endcase always @(posedge clk) if(!rst) CS<=IDLE; else CS<=NS; always@(posedge clk) case(NS) IDLE: //停止转换状态 begin OE<=0; START<=0; ALE<=0; ADDA<=1; end START_H: begin OE<=0; START<=1; //产生启动信号 ALE<=1; ADDA<=1;//选择信道口IN0 end START_L: begin OE<=0; START<=0; ALE<=1;//启动信号脉宽要足够长,在启动的时候ALE要一直有效 end CHECK_END: begin OE<=0; START<=0; ALE<=0; end GET_DATA: begin OE<=1; //高电平打开三态缓冲器输出转换数据 DATA_R<=DATA;//提取转换数据 START<=0; ALE<=0; end default: begin OE<=0; START<=0; ALE<=0; ADDA<=0; end endcase endmodule
//NET "clk" LOC = P76;//MCLKIN //NET "rst" LOC = P152;//SYS_RESET NET "clk" LOC = T8 | TNM_NET = sys_clk_pin; TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 50000 kHz; ## NET "rst" LOC = L3 | IOSTANDARD = "LVCMOS33"; ## reset pushbutton ## //PIN "pll_instance/clkout_50_buf.O" CLOCK_DEDICATED_ROUTE = FALSE; //PIN "pll_instance/clkout_200_buf.O" CLOCK_DEDICATED_ROUTE = FALSE; //NET "led[3]" LOC = M6;//VD4 //NET "led[2]" LOC = P5;//VD3 NET "led[1]" LOC = N5;//VD2 NET "led[0]" LOC = P4;//VD1 NET "FPGA_FLAG" LOC = D11; NET "clk_test" LOC = E11; //NET "OE" LOC = J16;//SRAM_OE# //NET "CE" LOC = K16;//SRAM_CE# NET "STM32_FLAG" LOC = H16;//SRAM_WE# //NET "UB" LOC = G16;//SRAM_BE0 //NET "LB" LOC = F15;//SRAM_BE1 NET "DATA[0]" LOC = E15; NET "DATA[1]" LOC = C16; NET "DATA[2]" LOC = B16; NET "DATA[3]" LOC = B14; NET "DATA[4]" LOC = A13; NET "DATA[5]" LOC = A12; NET "DATA[6]" LOC = B10; NET "DATA[7]" LOC = A9; NET "OE" LOC = A8; NET "START" LOC = A7; NET "ALE" LOC = B6; NET "ADDA" LOC = B5; NET "EOC" LOC = A4; NET "addr_sram[0]" LOC = N4;//SA0 NET "addr_sram[1]" LOC = N6;//SA1 NET "addr_sram[2]" LOC = M4;//SA2 NET "addr_sram[3]" LOC = R2;//SA3 NET "addr_sram[4]" LOC = R5;//SA4 NET "addr_sram[5]" LOC = T6;//SA5 NET "addr_sram[6]" LOC = T7;//SA6 NET "addr_sram[7]" LOC = T9;//SA7 //NET "addr_sram[8]" LOC = T12;//SA8 //NET "addr_sram[9]" LOC = T13;//SA9 //NET "addr_sram[10]" LOC = R14;//SA10 //NET "addr_sram[11]" LOC = R15;//SA11 //NET "addr_sram[12]" LOC = P15;//SA12 //NET "addr_sram[13]" LOC = N16;//SA13 //NET "addr_sram[14]" LOC = M16;//SA14 //NET "addr_sram[15]" LOC = K15;//SA15 NET "data_sram[0]" LOC = M5;//SD0 NET "data_sram[1]" LOC = P6;//SD1 NET "data_sram[2]" LOC = P2;//SD2 NET "data_sram[3]" LOC = R1;//SD3 NET "data_sram[4]" LOC = T4;//SD4 NET "data_sram[5]" LOC = T5;//SD5 NET "data_sram[6]" LOC = R7;//SD6 NET "data_sram[7]" LOC = L8;//SD7 //NET "databus[8]" LOC = R9;//SD8 //NET "databus[9]" LOC = R12;//SD9 //NET "databus[10]" LOC = T14;//SD10 //NET "databus[11]" LOC = T15;//SD11 //NET "databus[12]" LOC = R16;//SD12 //NET "databus[13]" LOC = P16;//SD13 //NET "databus[14]" LOC = M15;//SD14 //NET "databus[15]" LOC = L16;//SD15