SPI 配置寄存器程序

news2024/10/6 22:28:57

=========================================================================

=========================================================================

/**************************************************
*   
**************************************************/
module  zhm_mspi    #(
parameter   C_SPI_CPHA        = 1 ,// clock phase   ,0,在 SCLK 的第一个跳变沿进行采样;1,在 SCLK 的第二个跳变沿进行采样 
parameter   C_SPI_CPOL        = 1 ,// clock polarity,0,SCLK 在空闲时为低电平;         1,SCLK 在空闲时为高电平          
parameter   C_SPI_ADDR_WIDTH  = 8 ,// 地址位宽,广义上的
parameter   C_SPI_DATA_WIDTH  = 8 ,// 数据位宽
parameter   C_SPI_DIV_VALUE   = 10,// sclk 分频数
//  计数器位宽 
parameter   C_SPI_CMD_CWIDTH  = 4 ,// 地址/数据  -计数器位宽
parameter   C_SPI_DIV_CWIDTH  = 4 ,// sclk 分频数-计数器位宽
//                            
parameter   C_SPI_CMD_WIDTH   = C_SPI_ADDR_WIDTH+C_SPI_DATA_WIDTH
)(
input                                   aclk    ,//
input                                   aresetn ,//
output                                  s_tready,//
input                                   s_tvalid,//
input   [C_SPI_CMD_WIDTH-1:0]           s_tdata ,//
output                                  m_tvalid,//
output  [C_SPI_CMD_WIDTH-1:0]           m_tdata ,//
output                                  spi_cs  ,//
output                                  spi_sclk,//
output                                  spi_mosi,//
input                                   spi_miso,//
output                                  spi_t   ,//
output  [02:00]                         cursta  ,
output  [C_SPI_DIV_CWIDTH-1:0]          curcntD ,
output  [C_SPI_CMD_CWIDTH-1:0]          curcntB
);
localparam  TB_EDGE = C_SPI_DIV_VALUE/2-1;// 
/**************************************************
*   分频计数器 D
**************************************************/
localparam  CntD_End_Value = C_SPI_DIV_VALUE-1;
localparam  CntD_Width     = C_SPI_DIV_CWIDTH ;
reg     [CntD_Width-1:0]    cntD = {CntD_Width{1'b0}};
wire                        cntD_dom;
wire                        cntD_add;
wire                        cntD_end;
/**************************************************
*   位计数器 B
**************************************************/
//localparam  CntB_End_Value = 100-1;
localparam  CntB_Width     = C_SPI_CMD_CWIDTH;
reg     [CntB_Width-1:0]    cntB = {CntB_Width{1'b0}};
wire                        cntB_dom;
wire                        cntB_add;
wire                        cntB_end;
/**************************************************
*   状态机
*   IDLE==>S1==>S2==>S3==>S4==>S5==>S6==>S7==>S1
**************************************************/
localparam          IDLE = 3'd0;
localparam          S1   = 3'd1;
localparam          S2   = 3'd2;
localparam          S3   = 3'd3;
localparam          S4   = 3'd4;
localparam          S5   = 3'd5;
localparam          S6   = 3'd6;
localparam          S7   = 3'd7;
reg     [02:00]     state_c = IDLE;
reg     [02:00]     state_n       ;
wire                idle2s1_start ;
wire                s12s2_start   ;
wire                s22s3_start   ;
wire                s32s4_start   ;
wire                s42s5_start   ;
wire                s52s6_start   ;
wire                s62s7_start   ;
wire                s72s1_start   ;
always  @(posedge aclk)begin
    if(!aresetn)state_c <= IDLE;
    else        state_c <= state_n;
end
always  @(*)begin
    case(state_c)
        IDLE:begin  if(idle2s1_start)   state_n = S1;else   state_n = state_c;end
        S1  :begin  if(s12s2_start)     state_n = S2;else   state_n = state_c;end
        S2  :begin  if(s22s3_start)     state_n = S3;else   state_n = state_c;end
        S3  :begin  if(s32s4_start)     state_n = S4;else   state_n = state_c;end
        S4  :begin  if(s42s5_start)     state_n = S5;else   state_n = state_c;end
        S5  :begin  if(s52s6_start)     state_n = S6;else   state_n = state_c;end
        S6  :begin  if(s62s7_start)     state_n = S7;else   state_n = state_c;end
        S7  :begin  if(s72s1_start)     state_n = S1;else   state_n = state_c;end
        default:;
    endcase
end
assign  idle2s1_start = state_c == IDLE && 1'b1    ;// 复位中
assign  s12s2_start   = state_c == S1   && s_tvalid;// 等待数据中
assign  s22s3_start   = state_c == S2   && cntD_end;// CS 下降沿前等待
assign  s32s4_start   = state_c == S3   && cntD_end;// CS 下降沿后等待
assign  s42s5_start   = state_c == S4   && cntB_end;// 下发地址中
assign  s52s6_start   = state_c == S5   && cntB_end;// 收发数据中
assign  s62s7_start   = state_c == S6   && cntD_end;// CS 上升沿前等待
assign  s72s1_start   = state_c == S7   && cntD_end;// CS 上升沿后等待
assign  cursta        = state_c;
assign  s_tready      = (state_c == S1);
/**************************************************
*   分频计数器 D
**************************************************/
wire                cntD_flag;
assign  cntD_flag = (state_c == S2 ||
                     state_c == S3 ||
                     state_c == S4 ||
                     state_c == S5 ||
                     state_c == S6 ||
                     state_c == S7 );
always  @(posedge aclk)begin
    if(cntD_dom)begin if(cntD_add)begin
            if(cntD_end)cntD <= {CntD_Width{1'b0}};
            else        cntD <= cntD + 1'd1;
        end end else    cntD <= {CntD_Width{1'b0}};
end
assign  cntD_dom = cntD_flag;
assign  cntD_add = cntD_dom && 1'b1;
assign  cntD_end = cntD_add && cntD == CntD_End_Value;
assign  curcntD  = cntD;
/**************************************************
*   位计数器 B
**************************************************/
reg     [CntB_Width-1:0]        cntb_end_value;
always  @(*)begin 
    if(state_c == S4)   cntb_end_value = C_SPI_ADDR_WIDTH - 1'b1;
    else                cntb_end_value = C_SPI_DATA_WIDTH - 1'b1;
end 

always  @(posedge aclk)begin
    if(cntB_dom)begin if(cntB_add)begin
            if(cntB_end)cntB <= {CntB_Width{1'b0}};
            else        cntB <= cntB + 1'd1;
        end end else    cntB <= {CntB_Width{1'b0}};
end
assign  cntB_dom = (state_c == S4 || state_c == S5);
assign  cntB_add = cntB_dom && cntD_end;
assign  cntB_end = cntB_add && cntB == cntb_end_value;
assign  curcntB  = cntB;
/**************************************************
*   cs
**************************************************/
reg                         cs_r = 1'b1;
wire                        cs_w;
assign  cs_w = (state_c == S3 ||
                state_c == S4 ||
                state_c == S5 ||
                state_c == S6 );
always  @(posedge aclk)begin 
    cs_r <= !cs_w;
end 
assign  spi_cs = cs_r;
/**************************************************
*   方向控制 
**************************************************/
wire                            rhwl;
reg     [C_SPI_CMD_WIDTH-1:0]   data_sc;
assign  rhwl = data_sc[C_SPI_CMD_WIDTH-1:0];

wire                            t_flag;
assign  t_flag = (state_c == S4 ||
                  state_c == S5 );

reg                         t_r = 1'b1;
always  @(posedge aclk)begin 
    if(rhwl)    t_r <= (state_c != S4);
    else        t_r <= !t_flag;
end 
assign  spi_t = t_r;
/**************************************************
*   sclk
**************************************************/
reg                         sclk_r;
generate
    if(C_SPI_CPHA==0 && C_SPI_CPOL==0)begin: S00
        always  @(posedge aclk)begin 
            if(state_c == S4 || state_c == S5)begin 
                if(cntD == TB_EDGE) sclk_r <= 1'b1;
                else if(cntD_end)   sclk_r <= 1'b0;
            end 
            else                    sclk_r <= 1'b0;
        end 
    end 
    else if(C_SPI_CPHA==0 && C_SPI_CPOL==1)begin: S01
        always  @(posedge aclk)begin 
            if(state_c == S4 || state_c == S5)begin 
                if(cntD == TB_EDGE) sclk_r <= 1'b0;
                else if(cntD_end)   sclk_r <= 1'b1;
            end 
            else                    sclk_r <= 1'b1;
        end 
    end 
    else if(C_SPI_CPHA==1 && C_SPI_CPOL==0)begin: S10
        always  @(posedge aclk)begin 
            if(s32s4_start)         sclk_r <= 1'b1;
            else if(s52s6_start)    sclk_r <= 1'b0;
            else if(state_c == S4 || state_c == S5)begin 
                if(cntD == TB_EDGE) sclk_r <= 1'b0;
                else if(cntD_end)   sclk_r <= 1'b1;
            end 
            else                    sclk_r <= 1'b0;
        end 
    end
    else if(C_SPI_CPHA==1 && C_SPI_CPOL==1)begin: S11
        always  @(posedge aclk)begin 
            if(s32s4_start)         sclk_r <= 1'b0;
            else if(s52s6_start)    sclk_r <= 1'b1;
            else if(state_c == S4 || state_c == S5)begin 
                if(cntD == TB_EDGE) sclk_r <= 1'b1;
                else if(cntD_end)   sclk_r <= 1'b0;
            end 
            else                    sclk_r <= 1'b1;
        end 
    end
endgenerate

reg                         sclk_rr;
always  @(posedge aclk)begin 
    sclk_rr <= sclk_r;
end 
assign  spi_sclk = sclk_rr;
/**************************************************
*   数据发送 
**************************************************/
always  @(posedge aclk)begin
    if(s12s2_start) data_sc <= s_tdata;
end
reg     [C_SPI_CMD_WIDTH-1:0]   data_yw;
always  @(posedge aclk)begin
    if(cntD_end)begin 
        if(s32s4_start) data_yw <= data_sc;
        else            data_yw <= {data_yw[C_SPI_CMD_WIDTH-2:0],1'b0};
    end 
end
reg                             mosi_r;
always  @(posedge aclk)begin
    mosi_r <=  data_yw[C_SPI_CMD_WIDTH-1];
end
assign  spi_mosi = mosi_r;
/**************************************************
*   数据接收
**************************************************/
reg     [C_SPI_CMD_WIDTH-1:0]   rece_yw;
reg                             resc_sc_edge = 1'b0;
always  @(posedge aclk)begin
    resc_sc_edge <= t_flag && (cntD == TB_EDGE);
end
always  @(posedge aclk)begin
    if(resc_sc_edge)    rece_yw <= {rece_yw[C_SPI_CMD_WIDTH-2:0],spi_miso};
end

reg     [C_SPI_CMD_WIDTH-1:0]   rece_sc;
always  @(posedge aclk)begin
    if(s52s6_start)     rece_sc <= rece_yw;
end

reg                             valid_r = 1'b0;
always  @(posedge aclk)begin
    valid_r <= s52s6_start && rhwl;
end  

assign  m_tvalid = valid_r;
assign  m_tdata  = rece_sc;
endmodule
/**************************************************
zhm_mspi    #(
    .C_SPI_CPHA      (),// clock phase   ,0,在 SCLK 的第一个跳变沿进行采样;1,在 SCLK 的第二个跳变沿进行采样 
    .C_SPI_CPOL      (),// clock polarity,0,SCLK 在空闲时为低电平;         1,SCLK 在空闲时为高电平          
    .C_SPI_ADDR_WIDTH(),// 地址位宽,广义上的
    .C_SPI_DATA_WIDTH(),// 数据位宽
    .C_SPI_DIV_VALUE (),// sclk 分频数
    .C_SPI_CMD_CWIDTH(),// 地址/数据  -计数器位宽
    .C_SPI_DIV_CWIDTH())// sclk 分频数-计数器位宽                       
zhm_mspi_u(
    .aclk    (),//input                                   
    .aresetn (),//input                                   
    .s_tready(),//output                                  
    .s_tvalid(),//input                                   
    .s_tdata (),//input   [C_SPI_CMD_WIDTH-1:0]           
    .m_tvalid(),//output                                  
    .m_tdata (),//output  [C_SPI_CMD_WIDTH-1:0]           
    .spi_cs  (),//output                                  
    .spi_sclk(),//output                                  
    .spi_mosi(),//output                                  
    .spi_miso(),//input                                   
    .spi_t   (),//output                                  
    .cursta  (),//output  [02:00]                         
    .curcntD (),//output  [C_SPI_DIV_CWIDTH-1:0]          
    .curcntB () //output  [C_SPI_CMD_CWIDTH-1:0]          
);
**************************************************/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1816079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux - 复盘一次句柄数引发的故障

文章目录 Pre&#xff08;内核、用户、进程&#xff09;句柄数设置问题 shell修复 Pre Linux - 深入理解/proc虚拟文件系统&#xff1a;从基础到高级 &#xff08;内核、用户、进程&#xff09;句柄数设置 在Linux系统中&#xff0c;进程打开的最大句柄数可以通过多种方式配置…

0605 实际集成运算放大器的主要参数和对应用电路的影响

6.5.1 实际集成运放的主要参数 6.5.2 集成运放应用中的实际问题 6.5.2 集成运放应用中的实际问题

【启程Golang之旅】网络编程与反射

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt

《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书的“10.2 FFmpeg推流和拉流”提到直播行业存在RTSP和RTMP两种常见的流媒体协议。除此以外&#xff0c;还有比较两种比较新的流媒体协议&#xff0c;分别是SRT和RIST。 其中SRT全称为Secure Reliable Transport&#xf…

微信小程序毕业设计-驾校管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

WEB基础--Mybatis

了解Mybatis 什么是Mybatis 市面上最流行的技术架构&#xff1a;SSM 他们代表了 Spring业务层框架&#xff0c;SpringMvc WEB层框架以及MyBatis数据库持久层框架。 MyBatis 作为一个数据库持久层框架&#xff0c;是基于ORM规范(对象关系映射) 。类似我们以前的JDBC 和 JPA。…

【目标检测】基于深度学习的车牌识别管理系统(含UI界面)【python源码+Pyqt5界面 MX_002期】

系统简介&#xff1a; 车牌识别技术作为经典的机器视觉任务&#xff0c;具有广泛的应用前景。通过图像处理方法&#xff0c;车牌识别技术能够对车牌上的字符进行检测、定位和识别&#xff0c;从而实现计算机对车牌的智能化管理。在现实生活中&#xff0c;车牌识别系统已在小区停…

第二届京津冀现代商贸物流金融创新发展百人大会将于6月16日在廊坊举行

物流是实体经济的“筋络”&#xff0c;联接生产和消费、内贸和外贸&#xff0c;必须有效降低全社会物流成本&#xff0c;增强产业核心竞争力&#xff0c;提高经济运行效率。《京津冀协同发展规划纲要》赋予河北“三区一基地”的功能定位&#xff0c;建设全国现代商贸物流重要基…

vxeTable怎么导出excel文件

文章目录 一、代码示例二、调用导出事件参数详解下载引用 三、过滤某列数据导出 一、代码示例 <vxe-buttonclick"exportDataEvent"circleicon"vxe-icon-download">导出</vxe-button><vxe-tableborderroundstripeheight"auto"ref&…

融合商品计划与供应链管理:打造高效协同供应链生态

在当今竞争激烈的市场环境中&#xff0c;企业要想保持持续的竞争优势&#xff0c;除了拥有创新的产品和服务外&#xff0c;还需要具备高效协同的供应链管理能力。本文将探讨如何将商品计划与供应链管理紧密结合&#xff0c;以打造高效协同的供应链生态&#xff0c;从而提升企业…

3d模型转换器怎么用?---模大狮模型网

在当今数字化时代&#xff0c;3D技术被广泛应用于各行各业&#xff0c;从动画制作到工程设计再到游戏开发&#xff0c;都离不开3D模型。然而&#xff0c;由于不同软件之间的兼容性问题&#xff0c;我们常常需要将一个格式的3D模型转换成另一个格式。在这种情况下&#xff0c;3D…

CMA、CNAS软件检测报告如何收费?软件测评中心出具报告需多久?

众所周知&#xff0c;各行各业都需要资质认证&#xff0c;正如教师会有教师资格证&#xff0c;医师会有医师资格证&#xff0c;律师会有律师证&#xff0c;软件产品亦如此。对于软件测试报告来说CMA和CNAS资质认证就是获得行业甚至国家认可的重要依据。 CMA和CNAS软件检测报告…

ant组件库日期选择器汉化

ant组件库日期选择器默认英文 如何汉化 跟着官网走不能完全实现汉化。 这里提供一个解决方案&#xff0c;首先&#xff0c;通过pnpm下载moment包。 然后引入和注册文件&#xff1a; import zhCN from ant-design-vue/es/locale/zh_CN;import moment from moment;moment.loca…

导出 Whisper 模型到 ONNX

前言 在语音识别领域&#xff0c;Whisper 模型因其出色的性能和灵活性备受关注。为了在更多平台和环境中部署 Whisper 模型&#xff0c;导出为 ONNX 格式是一个有效的途径。ONNX&#xff08;Open Neural Network Exchange&#xff09;是一个开放格式&#xff0c;支持不同的深度…

Adobe Premiere 专业视频编辑软件资源下载安装!pr 2024最新版软件分享

Adobe Premiere&#xff0c;作为一款非线性视频编辑软件&#xff0c;它打破了传统线性编辑的限制&#xff0c;为用户提供了更加灵活和自由的创作空间。 在电影制作领域&#xff0c;Adobe Premiere的出色表现赢得了众多导演和剪辑师的青睐。其强大的编辑功能使得影片的剪辑过程更…

单细胞RNA测序(scRNA-seq) 理解Seurat对象存储信息含义和基本操作

单细胞测序技术是在单个细胞水平上&#xff0c;对基因组、转录组和表观基因组水平进行分析测序技术。bulk RNA-seq获得的是组织或器官等大量细胞中表达信号的均值&#xff0c;无法获取细胞之间的差异信息&#xff08;即丢失了细胞的异质性&#xff09;&#xff0c; 而单细胞测序…

快速上手 GreatSQL 8.0.32-25 with openEuler 24.03 LTS

5 月底&#xff0c;openEuler 24.03 LTS 发布&#xff0c;详情戳&#xff1a; 恭喜&#xff01;openEuler 24.03 LTS 版本发布&#xff1a;首个AI原生开源操作系统 在诸多亮点特性中&#xff0c;有一条值得注意&#xff1a; 集成 GreatSQL 数据库&#xff0c;适用于金融级应用场…

JAVA面试题:Redis分布式锁

Redis分布式锁 分布式锁使用的场景 集群情况下的定时任务,抢单,幂等性等场景 抢券场景 查询库存 -> 扣减库存 多个并发线程同时查询库存,出现超卖问题 添加互斥锁 所有线程执行操作之前必须尝试获取锁 保证一次只有一个线程能走查询库存->扣减库存的流程 Redis分…

模糊控制器实现对某个对象追踪输入

MATLAB是一个十分便捷的软件&#xff0c;里面提供了许多集成的组件&#xff0c;本文利用simulink实现模糊控制器实现对某个对象追踪输入。 这里的对象根据自己的需求可以修改&#xff0c;那么搭建一个闭环控制系统并不是难事儿&#xff0c;主要是对于模糊控制器参数的设置&…

记C#优化接口速度过程

前提摘要 首先这个项目是接手的前一任先写的项目&#xff0c;接手后&#xff0c;要求对项目一些速度相对较慢的接口进行优化&#xff0c;到第一个速度比较慢的接口后&#xff0c;发现单接口耗时4-8秒&#xff0c;是的&#xff0c;请求同一个接口&#xff0c;在参数不变的情况下…