|
【Altera SoC体验之旅】+I2C接口读写AT24模块
[复制链接]
最近在搞OV9655模块刚好SCCB接口兼容I2C接口,并且刚好手头有一个AT24的存储器也是I2C接口的所以调试了一下下。部分代码如下不含串口部分的一下贴出了太多了。。。自己百度吧一大堆呢。。只是贴出了一部分,这个应该也不少行列,不过很多都是重复的只用看红色标记的即可,一般都能看懂的。
主要应用了状态机咯。。大部分代码就是复制一下下修改修改就搞定了。。主要有一个主状态机主要控制AT24模块的初始化、读写等操作,然后就是嵌套一个I2C的状态机各个状态咯。
然后谈谈感想咯:个人觉得FPGA和别的控制器比起来自由度大一点。你需要什么协议的接口就可以写什么样的接口协议模块。而别的微控制器则需要用IO口模拟。之前用IO口模拟过一次SPI接口,当时也不知道什么原因搞得工作有点不正常。所以各人感觉用IO口模拟的协议终归没有实实在在的硬件语言写出来实在。初步感觉就是FPGA很强大但是很麻烦。各种代码不好找,找个OV9655的代码就没有找到的全是stm32的代码。由此看来FPGA的想要抢占市场还需要跟多的开源啊。。。本人拙见,不喜勿喷。。
晒张图咯
本人的串口线是用的51板子得串口和MAX232电源是从soc板子取给AT24再给串口。。线看着有点不清晰大家体谅。。
module i2c(clk,rst,data_in,scl,sda,wr_input,rd_input,en);
input clk,rst;
output scl;//I2C时钟线
inout sda;//I2C数据线
input[7:0] data_in;//想写入EEPROM的数据
input wr_input;//要求写的输入
input rd_input;//要求读的输入
//output lowbit; //输出一个低电平给矩阵键盘的某一行
reg scl;
reg[1:0] en;
reg sda_buf;//sda输入输出数据缓存
reg link; //sda输出标志
reg phase0,phase1,phase2,phase3;//一个scl时钟周期的四个相位阶段,将一个scl周期分为4段
//phase0对应scl的上升沿时刻,phase2对应scl的下降沿时刻,phase1对应从scl高电平的中间时刻,phase2对应从scl低电平的中间时刻,
reg[7:0] clk_div;//分频计数器
reg[1:0] main_state;
reg[2:0] i2c_state;//对i2c操作的状态
reg[3:0] inner_state;//i2c每一操作阶段内部状态
reg[7:0] writeData_reg,readData_reg;//要写的数据的寄存器和读回数据的寄存器
reg[7:0] addr;//被操作的EEPROM字节的地址
parameter div_parameter=100;// 分频系数,AT24C02最大支持400K时钟速率
parameter start=4'b0000, //开始
first=4'b0001, //第1位
second=4'b0010,//第2位
third=4'b0011, //第3位
fourth=4'b0100, //第4位
fifth=4'b0101, //第5位
sixth=4'b0110, //第6位
seventh=4'b0111, //第7位
eighth=4'b1000, //第8位
ack=4'b1001, //确认位
stop=4'b1010; //结束位
parameter ini=3'b000, //初始化EEPROM状态
sendaddr=3'b001, //发送地址状态
write_data=3'b010, //写数据状态?
read_data=3'b011, //读数据状态
read_ini=6'b100; //发送读信息状态
assign sda=(link)? sda_buf:1'bz; //是否输出模式不是则输出高阻态
always@(posedge clk or negedge rst)
begin
if(!rst) begin
clk_div<=0;
phase0<=0;
phase1<=0;
phase2<=0;
phase3<=0;
end
else begin
if(clk_div!=div_parameter-1)
clk_div<=clk_div+1;
else
clk_div<=0;
if(phase0)
phase0<=0;
else if(clk_div==99)
phase0<=1;
if(phase1)
phase1<=0;
else if(clk_div==24)
phase1<=1;
if(phase2)
phase2<=0;
else if(clk_div==49)
phase2<=1;
if(phase3)
phase3<=0;
else if(clk_div==74)
phase3<=1;
end
end
///////////////////////////EEPROM操作部分/////////////
always@(posedge clk or negedge rst)
begin
if(!rst) begin
main_state<=2'b00;
i2c_state<=ini;
inner_state<=start;
scl<=1;
sda_buf<=1;
link<=0;
writeData_reg<=5;
readData_reg<=0;
addr<=10;
end
else begin
case(main_state)
2'b00: begin //等待读写要求
writeData_reg<=data_in;
scl<=1;
sda_buf<=1;
link<=0;
inner_state<=start;
i2c_state<=ini;
if(!wr_input)
main_state<=2'b01;
else if(!rd_input)
main_state<=2'b10;
end
2'b01: begin //向EEPROM写入数据
if(phase0)
scl<=1;
else if(phase2)
scl<=0;
case(i2c_state)
ini: begin //初始化EEPROM
case(inner_state)
start: begin
if(phase1) begin
link<=1;
sda_buf<=0;
end
if(phase3&&link) begin
inner_state<=first;
sda_buf<=1;
link<=1;
end
end
first:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=second;
end
second:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=third;
end
third:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fourth;
end
fourth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fifth;
end
fifth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=sixth;
end
sixth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=seventh;
end
seventh:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=3'b000;
end
if(phase3) begin
link<=1;
sda_buf<=addr[7];
inner_state<=first;
i2c_state<=sendaddr;
end
end
endcase
end
sendaddr: begin //送相应字节的地址
case(inner_state)
first:
if(phase3) begin
link<=1;
sda_buf<=addr[6];
inner_state<=second;
end
second:
if(phase3) begin
link<=1;
sda_buf<=addr[5];
inner_state<=third;
end
third:
if(phase3) begin
link<=1;
sda_buf<=addr[4];
inner_state<=fourth;
end
fourth:
if(phase3) begin
link<=1;
sda_buf<=addr[3];
inner_state<=fifth;
end
fifth:
if(phase3) begin
link<=1;
sda_buf<=addr[2];
inner_state<=sixth;
end
sixth:
if(phase3) begin
link<=1;
sda_buf<=addr[1];
inner_state<=seventh;
end
seventh:
if(phase3) begin
link<=1;
sda_buf<=addr[0];
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=3'b000;
end
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[7];
inner_state<=first;
i2c_state<=write_data;
end
end
endcase
end
write_data: begin //写入数据
case(inner_state)
first:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[6];
inner_state<=second;
end
second:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[5];
inner_state<=third;
end
third:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[4];
inner_state<=fourth;
end
fourth:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[3];
inner_state<=fifth;
end
fifth:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[2];
inner_state<=sixth;
end
sixth:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[1];
inner_state<=seventh;
end
seventh:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[0];
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
else if(phase3) begin
link<=1;
sda_buf<=0;
inner_state<=stop;
end
end
stop: begin
if(phase1)
sda_buf<=1;
if(phase3)
main_state<=2'b00;
end
endcase
end
default:
main_state<=2'b00;
endcase
end
2'b10: begin //读EEPROM
if(phase0)
scl<=1;
else if(phase2)
scl<=0;
case(i2c_state)
ini: begin //初始化EEPROM
case(inner_state)
start: begin
if(phase1) begin
link<=1;
sda_buf<=0;
end
if(phase3&&link) begin
inner_state<=first;
sda_buf<=1;
link<=1;
end
end
first:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=second;
end
second:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=third;
end
third:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fourth;
end
fourth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fifth;
end
fifth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=sixth;
end
sixth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=seventh;
end
seventh:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
if(phase3) begin
link<=1;
sda_buf<=addr[7];
inner_state<=first;
i2c_state<=sendaddr;
end
end
endcase
end
sendaddr: begin //送相应要读字节的地址
case(inner_state)
first:
if(phase3) begin
link<=1;
sda_buf<=addr[6];
inner_state<=second;
end
second:
if(phase3) begin
link<=1;
sda_buf<=addr[5];
inner_state<=third;
end
third:
if(phase3) begin
link<=1;
sda_buf<=addr[4];
inner_state<=fourth;
end
fourth:
if(phase3) begin
link<=1;
sda_buf<=addr[3];
inner_state<=fifth;
end
fifth:
if(phase3) begin
link<=1;
sda_buf<=addr[2];
inner_state<=sixth;
end
sixth:
if(phase3) begin
link<=1;
sda_buf<=addr[1];
inner_state<=seventh;
end
seventh:
if(phase3) begin
link<=1;
sda_buf<=addr[0];
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
if(phase3) begin
link<=1;
sda_buf<=1;
inner_state<=start;
i2c_state<=read_ini;
end
end
endcase
end
read_ini: begin //发出读要求
case(inner_state)
start: begin
if(phase1) begin
link<=1;
sda_buf<=0;
end
if(phase3&&link) begin
inner_state<=first;
sda_buf<=1;
link<=1;
end
end
first:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=second;
end
second:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=third;
end
third:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fourth;
end
fourth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fifth;
end
fifth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=sixth;
end
sixth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=seventh;
end
seventh:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
if(phase3) begin
link<=0;
inner_state<=first;
i2c_state<=read_data;
end
end
endcase
end
read_data: begin //读出数据
case(inner_state)
first: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=second;
end
second: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=third;
end
third: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=fourth;
end
fourth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=fifth;
end
fifth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=sixth;
end
sixth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=seventh;
end
seventh: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=eighth;
end
eighth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=ack;
end
ack: begin
if(phase3) begin
link<=1;
sda_buf<=0;
inner_state<=stop;
end
end
stop: begin
if(phase1)
sda_buf<=1;
if(phase3)
main_state<=2'b00;
end
endcase
end
endcase
end
endcase
end
end
|
|