本项目通过spi协议读取TW29的64位包得到编码器信息,目前关于spi的例子大部分都是8位宽,位宽较短,本工程64位宽包含信息较多,且采用计数器逻辑巧妙,通过singaltap检验。
可读取编码器旋转的圈数与位置信息,实现25位细分,在超精密控制领域有着重要的作用,以下是项目的框架图与代码以及验证。
module spi_rd_ctrl
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_flag ,
input wire miso ,
output reg cs_n ,
output reg sck ,
output reg mosi
);
parameter CNT_MAX = 9'd275,
CNT_MAX1 = 7'd64; //64位
parameter WREN_IN = 64'B0_0_0_100_00_00000000000000000000000000000000000000000000000000000000;//读指令60 59 58 为4
parameter IDLE = 4'B0001,
WREN = 4'B0010;
reg [3:0] state ;
reg [8:0] cnt_clk ;//修改,0-275,276
reg [6:0] cnt_byte;//0-64,
reg [1:0] cnt_sck ;
reg [1:0] cnt_sck_a ;
reg [63:0] data/*synthesis noprune*/;
reg [63:0] data_reg/*synthesis noprune*/;
reg [11:0] RC/*synthesis noprune*/;//圈数/4095 42:31
reg [24:0] NR/*synthesis noprune*/;//脉冲计数值/33554432 30:6 25位
//按键按下,进入写状态
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else if(key_flag == 1'b1)
state <= WREN;
一个周期系统时钟计数276个,cnt_clk
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 9'd0;
else if(state == WREN && cnt_clk < CNT_MAX)
cnt_clk <= cnt_clk + 1'b1;
else if(cnt_clk == CNT_MAX)
cnt_clk <= 9'd0;
//片选,根据案件按下拉低,系统时钟计数拉低
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cs_n <= 1'b1;
else if(key_flag == 1'b1)//按键按下,拉低,进入写
cs_n <= 1'b0;
else if(cnt_clk == 9'd264)//写结束,拉高,等待时间
cs_n <= 1'b1;
else if(cnt_clk == 9'd275)//等待结束,拉低,进入下一个周期
cs_n <= 1'b0;
//cnt_sck_a,系统时钟分频计数,0123
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sck_a <= 2'd0;
else if(state == WREN )
cnt_sck_a <= cnt_sck_a + 1'b1;
//cnt_sck,系统时钟分频计数,0123 只有在写入的时候工作3-259
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sck <= 2'd0;
else if(cnt_clk >= 9'd3 &&cnt_clk <= 9'd258)
cnt_sck <= cnt_sck + 1'b1;
//sck信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sck <= 1'b0;
else if(cnt_sck == 2'd0)
sck <= 1'b0;
else if(cnt_sck == 2'd2)
sck <= 1'b1;
//0-68
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_byte <= 7'd0;
else if(cnt_sck == 2'd2)
cnt_byte <= cnt_byte + 1'b1;
else if(cnt_byte == CNT_MAX1 )
cnt_byte <= 7'd0;
//写入指令
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
mosi <= 1'b0;
else if(cnt_sck == 2'd0 &&(cnt_clk >= 9'd3 && cnt_clk <= 9'd256))
mosi <= WREN_IN[63 - cnt_byte];
//data读取信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 1'b0;
else if(cnt_sck == 2'd0 &&(cnt_clk >= 9'd3 && cnt_clk <= 9'd256))
data <= {data[63:0],miso};
//data_reg传递信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_reg <= 1'b0;
else if(cnt_clk == 9'd260)
data_reg <= data;
//读取脉冲计数值32位4095
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
RC <= 1'b0;
else if(cnt_clk == 9'd260)
RC <= data[42:31];
//读取NR 25位
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
NR <= 1'b0;
else if(cnt_clk == 9'd260)
NR <= data[30:6];
endmodule
右图为IC-HAUS官方软件,显示编码器的位置信息,验证通过。