前言:
作为我的FPGA入门项目,我需要在FPGA上实现一个可以通过I2C接口来访问的GPIO扩展以及PWM生成的功能.原因是我在ESP32-S3接了一块i8080接口的LCD屏,这个屏基本占用了ESP32-S3的所有IO,剩余的IO不够实现其他功能了,所以需要一个GPIO扩展IC,另外控制屏幕的背光亮度又需要一个生成指定占空比的PWM的功能,以及后续可能还需要有读写SPI Flash以及播放音频的功能,这些如果都使用现有的IC的话,器件就比较多,而且因为ESP32-S3的IO不够用,所以只能指定使用某种总线,比如I2C或者SPI,但是SPI需要为每个从器件分配一个CS引脚,这又加重了ESP32-S3的IO负担,所以只能选择I2C,但是这样就要求上面提到的所有功能都需要有I2C接口的器件,这增加了设计难度.
为了完成这个项目,我需要首先在FPGA上实现一个I2C从机接口.在这期间,我用到下面这几种局部设计(啊....果然初学的时候闭门造车是不对的,要多看别人的设计,多用通用的设计):
一.边沿检测:
边沿检测是检测一个信号的上升沿,下降沿,并输出对应的脉冲.
verilog实现方法如下:
module edge_detect(
input clk,
input rst_n,
input signal,
output pos_edge,
output neg_edge,
output both_edge
);
reg [1:0]sig_fifo;
always @ (posedge clk or negedge rst_n)begin
if (!rst_n) begin
sig_fifo <= 2'b0;
end
else begin
sig_fifo <= {sig_fifo[0], signal};
end
end
assign pos_edge = (sig_fifo == 2'b01);
assign neg_edge = (sig_fifo == 2'b10);
assign both_edge = pos_edge|neg_edge;
endmodule
二.计数器
计数器是对输入的脉冲进行计数,并以并行输出的形式输出计数的值.
verilog实现方法如下:
module count
(
input clk,
input rst_n,
output reg[ 3:0] cnt
);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 4'b0;
end
else begin
cnt <= cnt + 1'b1;
end
end
endmodule
三.串行转并行(移位寄存器)
串行转并行是将输入的串行输入转为指定位数的并行数据输出(注意有高位优先和低位优先的区别).
verilog实现方法如下:
module serial_parallel_msb_first(
input clk,
input rst_n,
input int, //一位输入
output reg [7:0] out //8位并行输出
);
always @(posedge clk or negedge rst_n)begin
if (rst_n == 1'b0)begin
out <= 8'b0;
end
else begin
out <= {int,out[7:1]}; //高位先赋值
end
end
endmodule
四.时钟分频(偶数分频)
时钟分频用在对高速时钟进行分频,以生成低速的时钟信号.
verilog实现方法如下:
module clk_div(clk_out,clk_in,rst_n,clk_div);
input clk_in;
input rst_n;
input [15:0]clk_div;
output clk_out;
reg[15:0]cnt;
reg clk_out;
always@(posedge clk_in or negedge rst_n)
begin
if(!rst_n)begin
cnt<=0;
clk_out<=0;
end
else begin
if(cnt==((clk_div/16'd2)-16'd1))begin
clk_out<=~clk_out;
cnt<=0;
end
else begin
cnt<=cnt+1'b1;
end
end
end
endmodule
五.独热码转二进制码
这个应用是因为做状态机的时候,当状态数量比较多时,最好用独热码来表示不同状态,但是在使用逻辑分析仪调试的时候,要通过io口输出状态机状态的话,如果用独热码就占用了太多引脚,所以需要一个独热码转二进制码的功能,方便调试输出,因为只是一个debug工具,所以我直接用查表的方式去实现了.
verilog实现方法如下:
module one_hot_to_binary
(
input[31:0] one_hot,
output reg[ 4:0] binary
);
always @(*)begin
case(one_hot)
32'b0000_0000_0000_0000_0000_0000_0000_0001:
begin
binary=5'd1;
end
32'b0000_0000_0000_0000_0000_0000_0000_0010:
begin
binary=5'd2;
end
32'b0000_0000_0000_0000_0000_0000_0000_0100:
begin
binary=5'd3;
end
32'b0000_0000_0000_0000_0000_0000_0000_1000:
begin
binary=5'd4;
end
32'b0000_0000_0000_0000_0000_0000_0001_0000:
begin
binary=5'd5;
end
32'b0000_0000_0000_0000_0000_0000_0010_0000:
begin
binary=5'd6;
end
32'b0000_0000_0000_0000_0000_0000_0100_0000:
begin
binary=5'd7;
end
32'b0000_0000_0000_0000_0000_0000_1000_0000:
begin
binary=5'd8;
end
32'b0000_0000_0000_0000_0000_0001_0000_0000:
begin
binary=5'd9;
end
32'b0000_0000_0000_0000_0000_0010_0000_0000:
begin
binary=5'd10;
end
32'b0000_0000_0000_0000_0000_0100_0000_0000:
begin
binary=5'd11;
end
32'b0000_0000_0000_0000_0000_1000_0000_0000:
begin
binary=5'd12;
end
32'b0000_0000_0000_0000_0001_0000_0000_0000:
begin
binary=5'd13;
end
32'b0000_0000_0000_0000_0010_0000_0000_0000:
begin
binary=5'd14;
end
32'b0000_0000_0000_0000_0100_0000_0000_0000:
begin
binary=5'd15;
end
32'b0000_0000_0000_0000_1000_0000_0000_0000:
begin
binary=5'd16;
end
32'b0000_0000_0000_0001_0000_0000_0000_0000:
begin
binary=5'd17;
end
32'b0000_0000_0000_0010_0000_0000_0000_0000:
begin
binary=5'd18;
end
32'b0000_0000_0000_0100_0000_0000_0000_0000:
begin
binary=5'd19;
end
32'b0000_0000_0001_0000_0000_0000_0000_0000:
begin
binary=5'd20;
end
32'b0000_0000_0010_0000_0000_0000_0000_0000:
begin
binary=5'd21;
end
32'b0000_0000_0100_0000_0000_0000_0000_0000:
begin
binary=5'd22;
end
32'b0000_0000_1000_0000_0000_0000_0000_0000:
begin
binary=5'd23;
end
32'b0000_0001_0000_0000_0000_0000_0000_0000:
begin
binary=5'd24;
end
32'b0000_0010_0000_0000_0000_0000_0000_0000:
begin
binary=5'd25;
end
32'b0000_0100_0000_0000_0000_0000_0000_0000:
begin
binary=5'd26;
end
32'b0000_1000_0000_0000_0000_0000_0000_0000:
begin
binary=5'd27;
end
32'b0001_0000_0000_0000_0000_0000_0000_0000:
begin
binary=5'd28;
end
32'b0010_0000_0000_0000_0000_0000_0000_0000:
begin
binary=5'd29;
end
32'b0100_0000_0000_0000_0000_0000_0000_0000:
begin
binary=5'd30;
end
32'b1000_0000_0000_0000_0000_0000_0000_0000:
begin
binary=5'd31;
end
default:
begin
binary=5'd0;
end
endcase
end
endmodule
Comments | NOTHING