我们学员在项目中需要编码盘来了解电机的位置,工程中采用了AS5600,该编码盘采用I2C接口来传输当前位置,theta角度。在设计FPGA与编码盘通信的代码中需要AS5600的模型,网上没有公开资料,我们开发了以上资料。模型对FPGA开发过程中的重要性不言而喻,需要的朋友可以与我们联系沟通。
我们在这篇文章贴出部分代码,以供参考。
`timescale 1ns/1ns
`define timeslice 380
module model_as5600(
scl,
sda
);
input scl;
inout sda;
reg out_flag;
reg[7:0] memory[15:0]; //宽度为8 :menmory数量16
reg[7:0]register_addr; //寄存器地址
reg[7:0]memory_buf; //缓存
reg[7:0]sda_buf; //sda数据缓存
reg[7:0]shift; //移位寄存器
reg[7:0]addr_byte;
reg[7:0]ctrl_byte; //设备地址
reg[1:0]State; //状态
integer i; //integer整型(不可综合)
reg sda_state;
//设备地址
parameter
r = 8'b01101101, w = 8'b01101100;
assign sda = (out_flag == 1) ? sda_buf[7] : 1'bz;
initial
begin
addr_byte = 0;
ctrl_byte = 0;
out_flag = 0;
sda_buf = 0;
State = 2'b00;
memory_buf = 0;
register_addr = 0;
shift = 0;
for(i=0;i<=15;i=i+1)
memory[i] = i;
end
always@(negedge sda)
begin
if(scl == 1)
begin
State = State + 1;
if(State == 2'b11)
disable write_to_as5600; //disable 不能
end
@(negedge scl) sda_state = 1;
#`timeslice sda_state = 0;
end
always@(posedge sda_state)
begin
if(scl == 1)
stop_W_R;
else
begin
casex(State)
2'b01:begin
read_in;
if( ctrl_byte == w)
begin
State = 2'b10;
write_to_as5600;
end
else
State = 2'b00;
end
2'b11:
read_from_as5600;
default:
State = 2'b00;
endcase
end
end
task stop_W_R;
begin
State = 2'b00;
addr_byte = 0;
ctrl_byte = 0;
out_flag = 0;
sda_buf = 0;
end
endtask
task read_in;
begin
shift_in(ctrl_byte);
shift_in(addr_byte);
end
endtask
task write_to_as5600;
begin
shift_in(memory_buf);
register_addr = addr_byte;
memory[register_addr] = memory_buf;
State = 2'b00;
end
endtask
task read_from_as5600;
begin
shift_in(ctrl_byte);
if( ctrl_byte == r)
begin
register_addr = addr_byte;
sda_buf = memory[register_addr];
shift_out;
State = 2'b00;
end
end
endtask
task shift_in;
output[7:0]shift;
begin
@(posedge scl) shift[7] = sda;
@(posedge scl) shift[6] = sda;
@(posedge scl) shift[5] = sda;
@(posedge scl) shift[4] = sda;
@(posedge scl) shift[3] = sda;
@(posedge scl) shift[2] = sda;
@(posedge scl) shift[1] = sda;
@(posedge scl) shift[0] = sda;
@(negedge scl)
begin
#(`timeslice); ////延时看是否上拉电阻有效
out_flag = 1;
sda_buf = 0;
end
@(negedge scl)
begin
#(`timeslice-60);
out_flag = 0;
end
end
endtask
task shift_out;
begin
out_flag = 1;
for(i=6; i>=0; i=i-1)
begin
@(negedge scl);
#`timeslice;
sda_buf = sda_buf << 1; //读数据高位往低读
end
@(negedge scl) #`timeslice sda_buf[7] = 1;
@(negedge scl) #`timeslice out_flag = 0;
end
endtask
endmodule
发表回复