32BIT的SPI主機控制

SPI傳輸位數可參數化配置。

SPI_MASTER:

`timescale 1ns / 1ps
module SPI_Master #(parameter CLK_FREQ = 50,parameter SPI_CLK  = 1000,parameter CPOL = 0,parameter CPHA = 0 
)(input         clk,input         rst_n,input         WrRdReq,   //讀/寫數據請求output        WrRdReqAck,output        WrRdFinish,input  [6:0]  WrRdDataBits,  //輸入數據位寬input  [31:0] WrData,        //要寫入的數據 output [31:0] RdData,        //讀取到的數據//SPI接口output        SCK,output        MOSI,input         MISO,output        CS
);//采樣信號
wire datain_en;
wire dataout_en;SPI_Master_Clock#
(.CLK_FREQ(CLK_FREQ),.CPOL(CPOL),.CPHA(CPHA),.SPI_CLK_FREQ(SPI_CLK)
)
u_SPI_Master_Clock
(
.clk(clk),
.rst_n(rst_n),.datain_en(datain_en),
.dataout_en(dataout_en),
.SCK(SCK)
);SPI_Master_ctrl u_SPI_Master_ctrl
(.clk(clk),         .rst_n(rst_n),       .WrRdReq(WrRdReq),   .WrRdReqAck(WrRdReqAck),  .WrRdFinish(WrRdFinish),  .WrRdDataBits(WrRdDataBits),.WrData(WrData),      .RdData(RdData),      .datain_en(datain_en),   .dataout_en(dataout_en),  .MOSI(MOSI),     .MISO(MISO),        .CS(CS)          
);
endmodule

SPI_MATSER_CLOCK

module SPI_Master_Clock#(parameter CLK_FREQ = 50,  //MHZparameter CPOL = 1'b0,parameter CPHA = 1'b0,parameter SPI_CLK_FREQ = 1000   //Khz
)(input clk,input rst_n,output datain_en,  //數據采樣控制信號output dataout_en, //數據輸出控制信號output SCK
);localparam sck_idle = CPOL;
localparam CLK_DIV_CNT = (CLK_FREQ *1000)/SPI_CLK_FREQ; //分頻計數器,此處分頻時鐘一個周期,分頻時鐘計數器要計數50,50個主時鐘周期//位寬計算
function integer clogb2(input integer depth);beginfor(clogb2 = 0;depth > 0;clogb2= clogb2 + 1)depth = depth >> 1;       end
endfunction
reg[clogb2(CLK_DIV_CNT)-1:0]  clkdiv_cnt; //[(6-1):0]reg SPI_SCK;
reg datain_en_o = 1'b0,dataout_en_o = 1'b0;//分頻時鐘計數器,計數到最大值表明經歷了一個SCK周期
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)beginclkdiv_cnt <= 1'b0; end else if(clkdiv_cnt == CLK_DIV_CNT - 1'b1)beginclkdiv_cnt <= 1'b0;end else beginclkdiv_cnt <= clkdiv_cnt + 1'b1;end
end//sck 
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)beginSPI_SCK <= sck_idle;end  else if((clkdiv_cnt == (CLK_DIV_CNT - 1'b1)) || (clkdiv_cnt == (CLK_DIV_CNT >> 1) -1'b1))beginSPI_SCK <= ~SPI_SCK;end else beginSPI_SCK <= SPI_SCK;end   
end   //輸入輸出使能
always@(posedge clk or negedge rst_n)beginif(!rst_n)begindatain_en_o <= 1'b0;dataout_en_o  <= 1'b0;end else begin        dataout_en_o <= (clkdiv_cnt == (CLK_DIV_CNT  - 'd3))?1'b1:1'b0;datain_en_o  <= (clkdiv_cnt == (CLK_DIV_CNT >> 1) - 'd1)?1'b1:1'b0;end endassign datain_en  = datain_en_o;assign dataout_en = dataout_en_o;assign SCK = SPI_SCK; 
endmodule

SPI_MATSER_CTRL:

module SPI_Master_ctrl
(input         clk,input         rst_n,input         WrRdReq,   //讀/寫數據請求output        WrRdReqAck,output        WrRdFinish,input  [6:0]  WrRdDataBits,  //輸入數據位寬input  [31:0] WrData,        //要寫入的數據 output [31:0] RdData,        //讀取到的數據//SPI寫讀控制信號input         datain_en,input         dataout_en,//SPI接口output        MOSI,input         MISO,output        CS
);localparam [7:0] S_IDLE =8'd0;
localparam [7:0] S_ACK  =8'd1;
localparam [7:0] S_RUN  =8'd2;
localparam [7:0] S_END  =8'd3;
localparam [7:0] S_RST  =8'd4;reg [7:0] current_state = S_IDLE;
reg [7:0] next_state    = S_IDLE; 
reg       CS_O = 1'b1;
reg [7:0]  WrRdBitsCnt = 8'd0,WrRdBitsLatch = 8'd0;  //用于計數已經發送或接收的位數 //用于存儲發送或接收的數據位數
reg [31:0] WrDataLatch = 32'd0,RdDataLatch  = 32'd0; //用于存儲要發送的數據  //用于存儲從 SPI 設備接收到的數據//reg MOSI_o;always@(posedge clk or negedge rst_n)beginif(!rst_n)begincurrent_state <= S_RST;end else begincurrent_state <= next_state;end
endalways@(*)beginnext_state = S_RST;case(current_state)S_RST:next_state = S_IDLE;S_IDLE:next_state = (WrRdReq)?S_ACK:S_IDLE;S_ACK:next_state = (WrRdReq)?S_ACK:S_RUN;S_RUN:next_state = (WrRdBitsCnt == WrRdBitsLatch)? S_END : S_RUN;S_END:next_state = S_IDLE;default:next_state = S_RST;endcase
end//發送數據模塊 
always@(posedge clk)begincase(current_state)S_RST,S_IDLE: WrDataLatch <= 32'd0;S_ACK: WrDataLatch <= WrData;S_RUN:beginif(dataout_en)beginWrDataLatch <= {WrDataLatch[30:0],1'b0}; //先輸出高位數據出來
//                MOSI_o <= WrDataLatch[31];end else beginWrDataLatch <= WrDataLatch;endenddefault:WrDataLatch <= 32'd0;endcase
end//接收數據模塊 
always@(posedge clk)begincase(current_state)S_RST,S_ACK:RdDataLatch <=32'd0;S_RUN:beginif(datain_en)beginRdDataLatch <= {RdDataLatch[30:0],MISO}; //先把高位數據輸入進去end else beginRdDataLatch <= RdDataLatch;endenddefault:RdDataLatch <= RdDataLatch;endcase
end//時鐘邊沿計數 已處理的位數計數器
always@(posedge clk)begincase(current_state)S_RST:WrRdBitsCnt <= 8'd0;S_RUN:beginif(datain_en || dataout_en)beginWrRdBitsCnt <= WrRdBitsCnt + 1'b1;end else beginWrRdBitsCnt <= WrRdBitsCnt;endenddefault:WrRdBitsCnt <= 8'd0;endcase
end//片選信號
always@(posedge clk)begincase(current_state)  //其余狀態保持默認值1S_RUN:CS_O <= 1'b0;default:CS_O <= 1'b1;endcase
end//鎖存要處理的數據位數
always@(posedge clk)begincase(current_state)S_RST:WrRdBitsLatch <= 8'd0;S_ACK:WrRdBitsLatch <= {WrRdDataBits,1'b0};default:WrRdBitsLatch <= WrRdBitsLatch;endcase
end assign WrRdFinish = (current_state == S_END);
assign RdData = RdDataLatch;
//請求ack信號
assign WrRdReqAck = (current_state == S_ACK);
assign MOSI = WrDataLatch[31];
assign CS =CS_O;
endmodule

TB:

`timescale 1ns / 1psmodule tb_SPI_Master;// 參數定義parameter CLK_FREQ = 50;  // 時鐘頻率 50 MHzparameter SPI_CLK = 1000; // SPI 時鐘頻率 1 MHzparameter CPOL = 0;       // 時鐘極性parameter CPHA = 0;       // 時鐘相位// 信號定義reg clk;reg rst_n;reg WrRdReq;wire WrRdReqAck;wire WrRdFinish;reg [6:0] WrRdDataBits;reg [31:0] SPIMasterWrData;  // 主機發送的數據wire [31:0] SPIMasterRdData; // 主機接收的數據wire SCK;wire MOSI;reg MISO;wire CS;// 從機接收數據寄存器reg [31:0] SPISlaveRdData = 0; // 從機接收的數據// 從機發送數據寄存器reg [31:0] SPISlaveWrData = 0; // 從機發送的數據// 實例化 SPI_Master 模塊SPI_Master #(.CLK_FREQ(CLK_FREQ),.SPI_CLK(SPI_CLK),.CPOL(CPOL),.CPHA(CPHA)) uut (.clk(clk),.rst_n(rst_n),.WrRdReq(WrRdReq),.WrRdReqAck(WrRdReqAck),.WrRdFinish(WrRdFinish),.WrRdDataBits(WrRdDataBits),.WrData(SPIMasterWrData),.RdData(SPIMasterRdData),.SCK(SCK),.MOSI(MOSI),.MISO(MISO),.CS(CS));// 時鐘生成always #10 clk = ~clk;// 模擬從機行為:接收數據always @(posedge SCK) beginif (CS == 0) beginSPISlaveRdData <= {SPISlaveRdData[30:0], MOSI}; // 從機接收數據endend//    reg [31:0] SPISlaveWrData_o;// 模擬從機行為:發送數據always @(posedge SCK) beginif (CS == 0) beginMISO <= SPISlaveWrData[31]; // 從機發送最高位SPISlaveWrData <= SPISlaveWrData << 1; // 數據左移endend// 測試過程initial begin// 初始化信號clk = 0;rst_n = 0;WrRdReq = 0;WrRdDataBits = 32;  // 發送 32 位數據SPIMasterWrData = 32'h82345678;  // 主機發送的數據SPISlaveWrData = 32'h12312345;MISO = 0;// 復位系統#20 rst_n = 0;#20 rst_n = 1;// 發送數據請求#100 WrRdReq = 1;  // 模擬發送請求#100 WrRdReq = 0;  // 結束發送請求// 等待發送完成wait(WrRdFinish == 1);// 檢查從機接收到的數據if (SPISlaveRdData == 32'h82345678) begin$display("Test Passed: SPISlaveRdData = %h", SPISlaveRdData);end else begin$display("Test Failed: SPISlaveRdData = %h, Expected = %h", SPISlaveRdData, 32'h82345678);end// 等待主機接收完成#100;// 檢查主機接收到的數據if (SPIMasterRdData == 32'h12312345) begin$display("Test Passed: SPIMasterRdData = %h", SPIMasterRdData);end else begin$display("Test Failed: SPIMasterRdData = %h, Expected = %h", SPIMasterRdData, 32'h12312345);end// 結束仿真#100 $stop;endendmodule

仿真圖略

參考:Verilog實現的SPI通信協議(主機模式)_spi 控制器的狀態機跳轉-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78466.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78466.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78466.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue響應式原理——vue2和vue3的響應式實現區別

Vue的核心功能點之一是響應式&#xff1a;Vue 會自動跟蹤 JavaScript 狀態并在其發生變化時響應式地更新 DOM。 簡單的來說就是&#xff0c;頁面的渲染效果會隨著數據變化而變化&#xff0c;不用我們去手動操作DOM樹進行數據變化后的渲染。為了實現這一目的&#xff0c;我們最簡…

Kaamel白皮書:2025版COPPA落地實操指南

COPPA簡介 《兒童在線隱私保護法案》&#xff08;COPPA&#xff09;于1998年在美國頒布&#xff0c;其最初的動因源于人們日益增長的對互聯網上收集兒童個人信息的擔憂。為了響應這一問題&#xff0c;聯邦貿易委員會&#xff08;FTC&#xff09;被授權制定并執行相關法規。COP…

測試基礎筆記第十四天

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 一、字符串1.字符串2.字符串切片3.查找find&#xff08;&#xff09;4.去除兩端空白字符 strip5.字符串轉換大小寫 lower、upper5.拆分 split()6.字符串的其他常見方…

什么是Lua模塊?你會如何使用NGINX的Lua模塊來定制請求處理流程?

大家好&#xff0c;我是鋒哥。今天分享關于【什么是Lua模塊&#xff1f;你會如何使用NGINX的Lua模塊來定制請求處理流程&#xff1f;】面試題。希望對大家有幫助&#xff1b; 什么是Lua模塊&#xff1f;你會如何使用NGINX的Lua模塊來定制請求處理流程&#xff1f; 1000道 互聯…

ubuntu擴展邏輯卷并調整文件系統大小步驟

安裝好ubuntu如果沒有調整磁盤空間,一般默認給你100G的空間,在用完時再調整也還來得及,下面是 ubuntu擴展邏輯卷并調整文件系統大小步驟&#xff1a; 1. 擴展邏輯卷 運行以下命令來擴展邏輯卷 /dev/ubuntu-vg/ubuntu-lv&#xff0c;使其使用卷組中所有未分配的空間&#xff…

復雜背景下無人機影像小目標檢測:MPE-YOLO抗遮擋與抗背景干擾設計

目錄 一、引言 二、挑戰和貢獻 密集小目標和遮擋 實時性要求與精度權衡 復雜背景 三、MPE-YOLO模型細節 多級特征集成器&#xff08;MFI&#xff09; 感知增強卷積&#xff08;PEC&#xff09; 增強范圍C2f模塊&#xff08;ES-C2f&#xff09; 四、Coovally AI模型訓…

【C++】13.list的模擬實現

首先&#xff0c;我們需要把鏈表管理起來&#xff0c;也就是把一個個節點管理起來&#xff0c;但是每個節點的信息我們也需要管理&#xff0c;例如節點的前驅指針和后驅指針&#xff0c;以及節點的值&#xff0c;所以我們這里先封裝兩個類來管理節點和鏈表。 namespace Ro {te…

TinyVue v3.22.0 正式發布:深色模式上線!集成 UnoCSS 圖標庫!TypeScript 類型支持全面升級!

我們非常高興地宣布&#xff0c;2025年4月7日&#xff0c;TinyVue發布了v3.22.0&#x1f389;。 本次 3.22.0 版本主要有以下重大變更&#xff1a; 支持深色模式增加基于 UnoCSS 的圖標庫更豐富的 TypeScript 類型聲明支持 XSS 配置 詳細的 Release Notes 請參考&#xff1a…

超級創新思路:基于CBAM-Transformer的強化學習時間序列預測模型(Python\matlab實現)

首先聲明,該模型為原創!原創!原創!且該思路還未有成果發表,感興趣的小伙伴可以借鑒!需要完整代碼可私信或評論! 本方案可用于醫療、金融、交通、零售、光伏功率預測、估計預測、天氣預測、流量預測、故障檢測等領域! 目錄 首先聲明,該模型為原創!原創!原創!且該思…

Apache Sqoop數據采集問題

Sqoop數據采集格式問題 一、Sqoop工作原理二、Sqoop命令格式三、Oracle數據采集格式問題四、Sqoop增量采集方案 Apache Sqoop是一款開源的工具&#xff0c;主要用于在Hadoop(Hive)與傳統的數據庫(mysql、postgresql…)間進行數據的傳遞&#xff0c;可以將一個關系型數據庫&…

Grok發布了Grok Studio 和 Workspaces兩個強大的功能。該如何使用?如何使用Grok3 API?

最近Grok又更新了幾個功能&#xff1a;Grok Studio 和 Workspaces。 其中 Grok Studio 主要功能包括&#xff1a; 代碼執行&#xff1a;在預覽標簽中運行 HTML 片段、Python、JavaScript 等。 Google Drive 集成&#xff1a;附加并處理 Docs、Sheets、Slides等文件。 協作工…

Vue選項式 API 與組合式 API

選項式 API 與組合式 API 選項式 API 選項式 API 是 Vue 2 中常用的開發方式&#xff0c;在 Vue 3 里依舊得到支持。它把組件邏輯劃分為不同的選項&#xff0c;像 data、methods、computed 等。 <template><div><p>Count: {{ count }}</p><button…

SiamMask中的分類分支、回歸分支與Mask分支,有何本質差異?

SiamMask中的分類分支、回歸分支與Mask分支&#xff0c;有何本質差異&#xff1f; 一、引言二、分支定位與任務目標三、網絡結構與感受野設計3.1 分類分支&#xff08;Classification Head&#xff09;3.2 回歸分支&#xff08;Regression Head&#xff09;3.3 Mask分支&#x…

threejs學習day02

場景、相機、渲染器 一、創建3D場景 // 引入threejs import * as THREE from three// 創建一個三維場景scene const scene new THREE.Scene();// 給三維場景添加物品 const geometry new THREE.BoxGeometry(100,100,100) // 形狀 const meterial new THREE.MeshBasicMat…

K8S Pod 常見數據存儲方案

假設有如下三個節點的 K8S 集群&#xff1a; k8s31master 是控制節點 k8s31node1、k8s31node2 是工作節點 容器運行時是 containerd 一、理論介紹 1.1、Volumes 卷 Kubernetes 的卷是 pod 的?個組成部分&#xff0c;因此像容器?樣在 pod 的規范&#xff08;pod.spec&#x…

【MySQL數據庫】函數操作

目錄 1&#xff0c;日期函數 2&#xff0c;字符串函數 3&#xff0c;數學函數 1&#xff0c;日期函數 樣例&#xff1a; 獲得年月日 select current_date(); 獲取時分秒 select current_time(); 獲得時間戳 select current_timestamp(); 在日期的基礎上加日期 在2025年4月27…

【每日隨筆】文化屬性 ① ( 天機 | 強勢文化與弱勢文化 | 文化屬性的形成與改變 | 強勢文化 具備的特點 )

文章目錄 一、文化屬性1、天機2、文化屬性的強勢文化與弱勢文化強勢文化弱勢文化 二、文化屬性的形成與改變1、文化屬性形成2、文化屬性改變3、文化知識的階層 三、強勢文化 具備的 特點 一、文化屬性 1、天機 如果想要 了解這個世界的 底層架構 , 就需要掌握 洞察事物本質 的能…

【Fifty Project - D18】

感覺自己就不是計劃星球人&#xff0c;雖然fifty project要求每天早上完成一天的計劃&#xff0c;但是對于一個p人腦子&#xff0c;強制自己按照計劃行事真的太難了。我也理解在早晨花費時間做好一天的計劃有很多好處&#xff0c;但是實際行動起來完成率極低。p人的世界里變動太…

Linux系統編程 day11 鎖 (兩天沒有更新了,中期完就休息了)

鎖的注意事項 1、盡量保證鎖的粒度&#xff0c;越小越好。(訪問共享數據前&#xff0c;加鎖&#xff0c;訪問結束后立即解鎖) 2、互斥鎖&#xff0c;本質是結構體&#xff0c;但是可以看成整數&#xff0c;初值為1。(pthread_mutex_init調用成功) 3、加鎖&#xff1a; --操作…

【Maven】特殊pom.xml配置文件 - BOM

文章目錄 特殊pom.xml配置文件 - BOM一、例子二、注意事項1.特殊的子pom.xml文件2.dependencyManagement 特殊pom.xml配置文件 - BOM 僅用于集中管理項目依賴版本 在 Maven 中&#xff0c;BOM 用于定義一個項目的依賴版本的集合&#xff0c;通常用于管理一組共享的依賴版本。這…