本次测评项借助该平台学习FPGA并在FPGA上实现FOC。
读取角度
根据数据手册编写了SPI通信接口,用于读取磁编码器返回的角度值。
module encoder(
input clk,
input rst_n,
input [31:0] spi_trans_cycle,
input [31:0] spi_clock_cycle,
input [31:0] spi_waite_cycle,
output spi_cs,
output spi_dat_io_e,
input spi_dat_in,
output spi_dat_out,
output spi_clk,
input [15:0] tx_dat,
output [14:0] rx_dat
);
reg [7:0] reg_spi_ctrl;
reg reg_spi_dat_io_e; /* 1 in 0 out */
reg reg_spi_clk;
reg reg_spi_dat_out;
reg reg_spi_cs;
reg [3:0] reg_spi_bit_cnt;
reg [31:0] spi_trans_cycle_cnt;
reg [31:0] spi_clock_cycle_cnt;
reg [31:0] spi_waite_cycle_cnt;
reg [15:0] reg_rx_dat;
reg [14:0] reg_rx_dat15;
reg spi_trans_en;
reg spi_trans_ok;
reg spi_waite_en;
reg spi_waite_ok;
reg spi_receive_en;
reg spi_receive_ok;
task tx_task;
input reg clk_in;
if( spi_clock_cycle_cnt < spi_clock_cycle ) begin
spi_clock_cycle_cnt <= spi_clock_cycle_cnt + 1'd1;
end
else begin
spi_clock_cycle_cnt <= 32'd0;
reg_spi_clk <= clk_in;
reg_spi_ctrl <= reg_spi_ctrl + 8'd1;
end
endtask
always @(posedge clk) begin
if(!rst_n) begin
reg_spi_ctrl <= 1'd0;
reg_spi_dat_io_e <= 1'd1;
reg_spi_clk <= 1'd0;
reg_spi_cs <= 1'd1;
spi_trans_cycle_cnt <= 32'd0;
spi_clock_cycle_cnt <= 32'd0;
spi_waite_cycle_cnt <= 32'd0;
spi_trans_en <= 1'd0;
spi_trans_ok <= 1'd0;
spi_waite_en <= 1'd0;
spi_waite_ok <= 1'd0;
spi_receive_en <= 1'd0;
spi_receive_ok <= 1'd0;
reg_spi_bit_cnt <= 1'd0;
end
else begin
if( spi_trans_cycle_cnt < spi_trans_cycle ) begin
spi_trans_cycle_cnt <= spi_trans_cycle_cnt + 1'd1;
end
else begin
spi_trans_en <= 1'd1;
spi_trans_ok <= 1'd0;
reg_spi_ctrl <= 8'd1;
spi_trans_cycle_cnt <= 32'd0;
end
case (reg_spi_ctrl)
0: begin
reg_spi_dat_io_e <= 1'd1;
end
1: begin
reg_spi_cs <= 1'd0;
if( spi_clock_cycle_cnt < spi_clock_cycle ) begin
spi_clock_cycle_cnt <= spi_clock_cycle_cnt + 1'd1;
end
else begin
spi_clock_cycle_cnt <= 32'd0;
reg_spi_ctrl <= reg_spi_ctrl + 8'd1;
end
end
2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34: begin
reg_spi_dat_io_e <= 1'd1;
tx_task(reg_spi_ctrl[0]);
end
35: begin
if( spi_waite_cycle_cnt < spi_waite_cycle ) begin
spi_waite_cycle_cnt <= spi_waite_cycle_cnt + 1'd1;
end
else begin
spi_waite_cycle_cnt <= 32'd0;
reg_spi_ctrl <= reg_spi_ctrl + 8'd1;
end
if( spi_waite_cycle_cnt > spi_waite_cycle[31:2] ) begin
reg_spi_dat_io_e <= 1'd0;
spi_receive_en <= 1'd1;
spi_trans_en <= 1'd0;
end
end
36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68: begin
reg_spi_dat_io_e <= 1'd0;
tx_task(reg_spi_ctrl[0]);
end
69: begin
if( spi_clock_cycle_cnt < spi_clock_cycle ) begin
spi_clock_cycle_cnt <= spi_clock_cycle_cnt + 1'd1;
end
else begin
spi_clock_cycle_cnt <= 32'd0;
reg_spi_ctrl <= reg_spi_ctrl + 8'd1;
end
end
70: begin
reg_spi_dat_io_e <= 1'd1;
reg_spi_clk <= 1'd0;
reg_spi_ctrl <= 8'd0;
spi_receive_en <= 1'd0;
reg_spi_cs <= 1'd1;
end
endcase
end
end
reg [7:0] tx_dat_cnt;
reg [7:0] rx_dat_cnt;
always @(posedge reg_spi_clk) begin
if(!rst_n ) begin
reg_spi_dat_out <= 1'd1;
tx_dat_cnt <= 8'd15;
end
else if( spi_trans_en == 1'd1 ) begin
reg_spi_dat_out <= tx_dat[ tx_dat_cnt ];
if( tx_dat_cnt > 8'd0 ) begin
tx_dat_cnt <= tx_dat_cnt - 1'd1;
end
else begin
tx_dat_cnt <= 8'd15;
end
end
else begin
tx_dat_cnt <= 8'd15;
reg_spi_dat_out <= 1'd1;
end
end
always @(negedge reg_spi_clk) begin
if(!rst_n ) begin
rx_dat_cnt <= 8'd15;
end
else if( spi_receive_en == 1'd1 ) begin
reg_rx_dat[rx_dat_cnt] <= spi_dat_in;
if( rx_dat_cnt > 8'd0 ) begin
rx_dat_cnt <= rx_dat_cnt - 1'd1;
end
else begin
rx_dat_cnt <= 8'd15;
reg_rx_dat15 <= reg_rx_dat[14:0];
end
end
else begin
rx_dat_cnt <= 8'd15;
end
end
assign spi_dat_io_e = reg_spi_dat_io_e;
assign spi_clk = reg_spi_clk;
assign spi_dat_out = reg_spi_dat_out;
assign rx_dat = reg_rx_dat15 - 15'd2475;
assign spi_cs = reg_spi_cs;
endmodule
为了方便查看结果,我将返回的角度值传递给了数码管显示模块,文末有视频演示。
角度变换
验证角度变换时使用的时规律变换的角度值,这样方便验证计算结果。
使用在线逻辑分析仪捕获模块的输入和输出:
将捕获到的数据导出到文件:
将导出的数据导入到matlab中,方便验证和查看结果是否正确。
经过验证,计算无误。