1920|4

12

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

Sipeed 高云GW2A 三线SPI读取磁编数据 [复制链接]

 

今天分享一下自己在高云GW2A上编写的三线SPI。

我准备驱动的电机上的角度传感器是三线SPI通信的磁编,所以自己尝试学习编写了一个三线SPI。

三线SPI需要将数据线在输入和输出之间切换,使用三态门可以实现这个效果。

因为对语法不太熟悉,所以我使用的按位处理整个通信过程。

源码时针对使用的器件编写的,后面会继续优化成通用型的SPI模块。

通信效果如下:

 
源码:

module my_spi(
    input         clkin_i,
    input         reset,
    input  [31:0] spi_trans_cycle,
    input  [31:0] spi_clock_cycle,
    input  [31:0] spi_waite_cycle,
    output        spi_dat_io_e,
    input         spi_dat_in,
    output        spi_dat_out,
    output        spi_clk,
    input  [15:0] tx_dat,
    output [15: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 [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 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 clkin_i) begin
    if( reset ) begin
        reg_spi_ctrl <= 1'd0;
    
        reg_spi_dat_io_e <= 1'd1;
        reg_spi_clk <= 1'd0;
        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,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: begin
                reg_spi_dat_io_e <= 1'd1;
                tx_task(reg_spi_ctrl[0]);
            end
            33: 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:1] ) begin
                    reg_spi_dat_io_e <= 1'd0;
                    spi_receive_en <= 1'd1;
                    spi_trans_en <= 1'd0;
                end
            end
            34,35,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: begin
                reg_spi_dat_io_e <= 1'd0;
                tx_task(~reg_spi_ctrl[0]);
            end
            67: begin
                reg_spi_dat_io_e <= 1'd1;
                reg_spi_clk <= 1'd0;
                reg_spi_ctrl <= 8'd0;
                spi_receive_en <= 1'd0;
            end

        endcase
    end
end

reg [7:0] tx_dat_cnt;
reg [7:0] rx_dat_cnt;

always @(posedge reg_spi_clk) begin
    if( reset ) 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( reset ) 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;
        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_dat;


endmodule


 
 

 

最新回复

还是SPI信号比较好,不管是硬件还是IO口模拟都是比较稳定的   详情 回复 发表于 2022-12-26 14:34
点赞 关注
 
 

回复
举报

12

帖子

0

TA的资源

一粒金砂(中级)

沙发
 

代码比较简单,欢迎大佬指点。

 
 
 

回复

6773

帖子

2

TA的资源

版主

板凳
 

能自己写一个通讯驱动已经很不错了!至少VHDL语言会了。

点评

谢谢~  详情 回复 发表于 2023-1-4 21:26
 
 
 

回复

6060

帖子

6

TA的资源

版主

4
 

还是SPI信号比较好,不管是硬件还是IO口模拟都是比较稳定的

个人签名

在爱好的道路上不断前进,在生活的迷雾中播撒光引

 
 
 

回复

12

帖子

0

TA的资源

一粒金砂(中级)

5
 
wangerxian 发表于 2022-12-26 09:25 能自己写一个通讯驱动已经很不错了!至少VHDL语言会了。

谢谢~

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表