我将程序贴出一部分,求大神分析一下,初来乍到
module FPGA_AD7689_SPI (
//----------- Ports Declarations -----------------------------------------------
// 时钟和复位信号
input fpga_clk_i, // 系统时钟
input adc_clk_i, // AD转换时钟
input reset_i, // 高电平复位信号
// IP 控制和 数据接口
input wr_data_n_i, // 低电平信号来启动数据写入ADC
input [15:0] data_i, // 数据被写入ADC
output reg [107:0] data_channels_o1, // FPGA从AD中读取数据
output reg [107:0] data_channels_o2,
output reg [107:0] data_channels_o3,
output reg data_rd_ready_o, // 当其为高电平时,开始从ADC读取数据
output reg data_wr_ready_o, // 用于ADC写状态信号: 0 - 正在写, 1 - 写完成
// ADC 外部连接
input MISO_1, // 主机输入,从机输出1
output MOSI_1, // 主机输出,从机输入1
output SCK1, // 串行数据时钟1
output reg SS1 , // 控制转换开始1
input MISO_2, // 主机输入,从机输出2
output MOSI_2, // 主机输出,从机输入2
output SCK2, // 串行数据时钟2
output reg SS2 , // 控制转换开始2
input MISO_3, // 主机输入,从机输出3
output MOSI_3, // 主机输出,从机输入3
output SCK3, // 串行数据时钟3
output reg SS3 // 控制转换开始3
);
//----------- Local Parameters -------------------------------------------------
// 状态机
parameter IDLE = 9'b000000001; // 起始状态
parameter START_CNV = 9'b000000010; // 开始转换
parameter CONVERSION = 9'b000000100; // 等待转换时间
parameter CNV_LOW = 9'b000001000; // CNV 为低电平
parameter READ_DATA = 9'b000010000; // 在忙busy信号之前读取数据
parameter SELECT_CHANNEL = 9'b000100000; // 根据配置选择下一个状态
parameter SYNCHRONIZE_COM = 9'b001000000; // state in which samples are referenced to COM pin
parameter SYNCHRONIZE_DIFF = 9'b010000000; // 差分采样状态
parameter WAIT_CYCLE_END = 9'b100000000; // 等待转换时间结束
localparam real FPGA_CLK = 12; // MHz
localparam real ADC_CYCLE_TIME = 4; // us
localparam real ADC_CONV_TIME = 2.2; // us
localparam integer CYCLE_CNT = (FPGA_CLK * ADC_CYCLE_TIME) - 3; // 用于周期计数
localparam integer CONV_CNT = (FPGA_CLK * ADC_CONV_TIME) - 2 ; // 用于转换计数
//----------- Registers Declarations寄存器声明 -------------------------------------------
// 状态机寄存器
reg [8:0] present_state; // 状态机的当前状态
reg [8:0] next_state; // 状态机的下一状态
reg SCLK_en; // 用于产生时钟信号,使能
reg [15:0] tx_reg1; // Transmitted data, as received from the CED1Z_interface module
reg [15:0] tx_reg2;
reg [15:0] tx_reg3;
reg [15:0] tx_reg_d1; // 发送数据寄存器1
reg [15:0] tx_reg_d2; // 发送数据寄存器2
reg [15:0] tx_reg_d3; // 发送数据寄存器3
reg [15:0] rx_reg1; // 接收数据寄存器
reg [15:0] rx_reg2;
reg [15:0] rx_reg3;
reg [31:0] cycle_cnt; // 测量周期时间寄存器
reg [31:0] conv_cnt; // 测量转换时间寄存器
reg [4:0] sclk_cnt; // 用于计数发送的时钟信号的寄存器
reg [1:0] seq; // 通道序列器,允许以IN0到IN[7:0]的方式扫描通道
reg [2:0] inx; // 通道选择寄存器,以二进制的方式选择输入通道
reg [2:0] incc; // 用于输入通道配置寄存器,选择差分、单端等
reg [2:0] channel; // Register used for keeping track of the channel acquired
//----------- Assign/Always 模块---------------------------------------------
assign SCK1 = SCLK_en ? adc_clk_i : 1'b0; // clock is idle LOW
assign SCK2 = SCLK_en ? adc_clk_i : 1'b0;
assign SCK3 = SCLK_en ? adc_clk_i : 1'b0;
assign MOSI_1 = tx_reg_d1[13]; // send data from tx_reg_d register on the MOSI data line
assign MOSI_2 = tx_reg_d2[13];
assign MOSI_3 = tx_reg_d3[13];
always @(negedge adc_clk_i) // ad7689 发送/接收数据
begin
if (reset_i == 1'b1)
begin
rx_reg1 <= 16'h0;
tx_reg_d1 <= 16'h0;
rx_reg2 <= 16'h0;
tx_reg_d2 <= 16'h0;
rx_reg3 <= 16'h0;
tx_reg_d3 <= 16'h0;
end
else if(SCLK_en == 1'b1)
begin
rx_reg1 <= { rx_reg1[14:0], MISO_1 }; // Receive data 利用拼接接收数据
tx_reg_d1 <= { tx_reg_d1[14:0], 1'b0 }; // Send data 利用拼接发送数据
rx_reg2 <= { rx_reg2[14:0], MISO_2 };
tx_reg_d2 <= { tx_reg_d2[14:0], 1'b0 };
rx_reg3 <= { rx_reg3[14:0], MISO_3 };
tx_reg_d3 <= { tx_reg_d3[14:0], 1'b0 };
end
else if (present_state == IDLE) // 清除 rx_reg 寄存器
begin
rx_reg1 <= 16'h0;
rx_reg2 <= 16'h0;
rx_reg3 <= 16'h0;
end
else if (present_state == CONVERSION) //更新 tx_reg_d 寄存器
begin
tx_reg_d1 <= {1'b0, tx_reg1[13], tx_reg1[13:0]};
tx_reg_d2 <= {1'b0, tx_reg2[13], tx_reg2[13:0]};
tx_reg_d3 <= {1'b0, tx_reg3[13], tx_reg3[13:0]};
end
end
always @(negedge fpga_clk_i) // Process for timing the conversion time
begin
if (present_state == START_CNV) // 在 START_CNV状态下复位计数器
begin
cycle_cnt <= CYCLE_CNT;
conv_cnt <= CONV_CNT;
end
else
begin
if ( cycle_cnt != 0 ) // Decrease cycle counter
begin
cycle_cnt <= cycle_cnt - 32'h1;
end
if ( conv_cnt != 0 ) // Decrease conversion counter
begin
conv_cnt <= conv_cnt - 32'h1;
end
end
end
// 状态机 - 状态选择
always @( present_state, sclk_cnt, cycle_cnt, incc, conv_cnt )
begin
next_state <= present_state;
case(present_state)
IDLE:
begin
next_state <= START_CNV;
end
START_CNV:
begin
next_state <= CONVERSION;
end
CONVERSION:
begin
if(conv_cnt == 32'b0)
begin
next_state <= CNV_LOW;
end
end
CNV_LOW:
begin
next_state <= READ_DATA;
end
READ_DATA:
begin
if(sclk_cnt == 5'b0)
begin
next_state <= SELECT_CHANNEL;
end
end
SELECT_CHANNEL: //选择差分、伪差分、单端等
begin
if( incc == 3'b000 || incc == 3'b001 || incc == 3'b100 || incc == 3'b101) // Configuration words with differential pairs
begin
next_state <= SYNCHRONIZE_DIFF;
end
else
begin
next_state <= SYNCHRONIZE_COM;
end
end
SYNCHRONIZE_COM:
begin
next_state <= WAIT_CYCLE_END;
end
SYNCHRONIZE_DIFF:
begin
next_state <= WAIT_CYCLE_END;
end
WAIT_CYCLE_END:
begin
if (cycle_cnt == 32'b0)
begin
next_state <= IDLE;
end
end
default:
begin
next_state <= IDLE;
end
endcase
end
// 状态机 - 输出选择
always @(negedge fpga_clk_i)
begin
if(reset_i == 1'b1)
begin
present_state <= IDLE;
tx_reg1 <= 16'h0000;
tx_reg2 <= 16'h0000;
tx_reg3 <= 16'h0000;
data_channels_o1 [ 107:0] <= 108'h0;
data_channels_o2 [ 107:0] <= 108'h0;
data_channels_o3 [ 107:0] <= 108'h0;
end
else
begin
present_state <= next_state;
case( present_state )
IDLE:
begin
if (wr_data_n_i == 0) // if a write has been performed from CED1Z to ADCCFG register, update the configuration register on AD7689
begin
tx_reg1 <= data_i;
tx_reg2 <= data_i;
tx_reg3 <= data_i;
data_wr_ready_o <= 1'b1;
channel <= 3'h5;
incc <= data_i[12:10];
inx <= data_i[9:7];
seq <= data_i[2:1];
data_channels_o1 [ 107:0] <= 108'h0;
data_channels_o2 [ 107:0] <= 108'h0;
data_channels_o3 [ 107:0] <= 108'h0;
end
else
begin // if no write has been performed, keep DIN low
tx_reg1 <= 16'h0;
tx_reg2 <= 16'h0;
tx_reg3 <= 16'h0;
end
SCLK_en <= 1'b0;
SS1 <= 1'b0;
data_rd_ready_o <= 1'b0;
sclk_cnt <= 5'hf;
end
START_CNV:
begin
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b0;
SS1 <= 1'b1;
data_rd_ready_o <= 1'b0;
end
CONVERSION: // The CNV pin is kept high until EOC. Configuration without busy indicator
begin
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b0;
SS1 <= 1'b1;
data_rd_ready_o <= 1'b0;
end
CNV_LOW:
begin
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b0;
SS1 <= 1'b0;
data_rd_ready_o <= 1'b0;
end
READ_DATA:
begin
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b1;
SS1 <= 1'b0;
data_rd_ready_o <= 1'b0;
if( sclk_cnt != 0 )
begin
sclk_cnt <= sclk_cnt - 5'h1;
end
end
SELECT_CHANNEL:
begin
channel <= channel + 3'h1;
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b0;
data_rd_ready_o <= 1'b0;
SS1 <= 1'b0;
end
SYNCHRONIZE_COM: // Using 11 for channel sequencer on and 00 for channel sequencer disabled. 01 and 10 should not be used to configure the AD7689
begin
case( channel )
3'h0:
begin
data_channels_o1[107:10] <= rx_reg1;
data_channels_o2[107:10] <= rx_reg2;
data_channels_o3[107:10] <= rx_reg3;
if ( seq == 2'b11 && inx == 3'h0)
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h1:
begin
data_channels_o1[107:96] <= rx_reg1;
data_channels_o2[107:96] <= rx_reg2;
data_channels_o3[107:96] <= rx_reg3;
if ( seq == 2'b11 && inx == 3'h1)
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h2:
begin
data_channels_o1[95:80] <= rx_reg1;
data_channels_o2[95:80] <= rx_reg2;
data_channels_o3[95:80] <= rx_reg3;
if (seq == 2'b11 && inx == 3'h2)
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h3:
begin
data_channels_o1[79:64] <= rx_reg1;
data_channels_o2[79:64] <= rx_reg2;
data_channels_o3[79:64] <= rx_reg3;
if (seq == 2'b11 && inx == 3'h3)
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h4:
begin
data_channels_o1[63:48] <= rx_reg1;
data_channels_o2[63:48] <= rx_reg2;
data_channels_o3[63:48] <= rx_reg3;
if (seq == 2'b11 && inx == 3'h4)
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h5:
begin
data_channels_o1[47:32] <= rx_reg1;
data_channels_o2[47:32] <= rx_reg2;
data_channels_o3[47:32] <= rx_reg3;
if (seq == 2'b11 && inx == 3'h5)
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h6:
begin
data_channels_o1[31:16] <= rx_reg1;
data_channels_o2[31:16] <= rx_reg2;
data_channels_o3[31:16] <= rx_reg3;
if (seq == 2'b11 && inx == 3'h6)
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
default:
begin
data_channels_o1[15:0] <= rx_reg1;
data_channels_o2[15:0] <= rx_reg2;
data_channels_o3[15:0] <= rx_reg3;
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
endcase
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b0;
SS1 <= 1'b0;
end
SYNCHRONIZE_DIFF:
begin
case( channel )
3'h0:
begin
data_channels_o1[107:100] <= rx_reg1;
data_channels_o2[107:100] <= rx_reg2;
data_channels_o3[107:100] <= rx_reg3;
if (seq == 2'b11 && (inx == 3'h0 || inx == 3'h1))
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h1:
begin
data_channels_o1[107:96] <= rx_reg1;
data_channels_o2[107:96] <= rx_reg2;
data_channels_o3[107:96] <= rx_reg3;
if ( seq == 2'b11 && (inx == 3'h2 || inx == 3'h3))
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h2:
begin
data_channels_o1[95:80] <= rx_reg1;
data_channels_o2[95:80] <= rx_reg2;
data_channels_o3[95:80] <= rx_reg3;
if (seq == 2'b11 && (inx == 3'h4 || inx == 3'h5))
begin
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
end
3'h6:
begin
channel <= 3'h6; //used to synchronnize channels after configuration change
end
default:
begin
data_channels_o1[79:64] <= rx_reg1;
data_channels_o2[79:64] <= rx_reg2;
data_channels_o3[79:64] <= rx_reg3;
data_rd_ready_o <= 1'b1;
channel <= 3'h7;
end
endcase
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b0;
SS1 <= 1'b0;
end
WAIT_CYCLE_END:
begin
data_wr_ready_o <= 1'b0;
SCLK_en <= 1'b0;
SS1 <= 1'b0;
data_rd_ready_o <= 1'b0;
end
endcase
end
end
endmodule
|