本系列將帶來FPGA的系統性學習,從最基本的數字電路基礎開始,最詳細操作步驟,最直白的言語描述,手把手的“傻瓜式”講解,讓電子、信息、通信類專業學生、初入職場小白及打算進階提升的職業開發者都可以有系統性學習的機會。
系統性的掌握技術開發以及相關要求,對個人就業以及職業發展都有著潛在的幫助,希望對大家有所幫助。后續會陸續更新 Xilinx 的 Vivado、ISE 及相關操作軟件的開發的相關內容,學習FPGA設計方法及設計思想的同時,實操結合各類操作軟件,會讓你在技術學習道路上無比的順暢,告別技術學習小BUG卡破腦殼,告別目前忽悠性的培訓誘導,真正的去學習去實戰應用。話不多說,上貨。
SPI 協議驅動設計
本篇實現基于叁芯智能科技的SANXIN -B01 FPGA開發板,以下為配套的教程,如有入手開發板,可以登錄官方淘寶店購買,還有配套的學習視頻。SANXIN-B01 Verilog教程-郝旭帥團隊
SPI是串行外設接口(Serial Peripheral Interface)的縮寫。SPI,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節約了芯片的管腳,同時為PCB的布局上節省空間,提供方便,正是出于這種簡單易用的特性,如今越來越多的芯片集成了這種通信協議。
SPI的通信原理很簡單,它以主從方式工作,這種模式通常有一個主設備和一個或多個從設備,中間靠三線或者四線連接(三線時為單向傳輸或者數據線雙向傳輸)。所有基于SPI的設備共有的,它們是MISO、MOSI、SCLK、CS。
MISO– Master Input Slave Output,主設備數據輸入,從設備數據輸出。
MOSI– Master Output Slave Input,主設備數據輸出,從設備數據輸入。
SCLK – Serial Clock,時鐘信號,由主設備產生。
CS – Chip Select,從設備使能信號,由主設備控制。
cs是從芯片是否被主芯片選中的控制信號,也就是說只有片選信號為預先規定的使能信號時(高電位或低電位),主芯片對此從芯片的操作才有效。這就使在同一條總線上連接多個spi設備成為可能。
通訊是通過數據交換完成的,由sclk提供時鐘脈沖,mosi、miso則基于此脈沖完成數據傳輸。數據輸出通過 mosi線,數據在時鐘上升沿或下降沿時改變,在緊接著的下降沿或上升沿被讀取。完成一位數據傳輸,輸入也使用同樣原理。因此,至少需要N次時鐘信號的改變(上沿和下沿為一次),才能完成N位數據的傳輸。
spi通信有四種不同的模式,不同的從設備可能在出廠時就已經配置為某種模式。通信的雙方必須是工作在同一模式下,所以我們可以對主設備的spi模式進行配置,通過CPOL(時鐘極性)和CPHA(時鐘相位)來控制我們主設備的通信模式。
mode0:CPOL=0,CPHA=0;
mode1:CPOL=0,CPHA=1;
mode2:CPOL=1,CPHA=0;
mode3:CPOL=1,CPHA=1;
時鐘極性CPOL是用來配置SCLK在空閑時,應該處于的狀態;時鐘相位CPHA用來配置在第幾個邊沿進行采樣。
CPOL=0,表示在空閑狀態時,時鐘SCLK為低電平。
CPOL=1,表示在空閑狀態時,時鐘SCLK為高電平。
CPHA=0,表示數據采樣是在第1個邊沿。
CPHA=1,表示數據采樣是在第2個邊沿。
即:
CPOL=0,CPHA=0:此時空閑態時,SCLK處于低電平,數據采樣是在第1個邊沿,也就是SCLK由低電平到高電平的跳變,所以數據采樣是在上升沿,數據發送是在下降沿。
CPOL=0,CPHA=1:此時空閑態時,SCLK處于低電平,數據發送是在第1個邊沿,也就是SCLK由低電平到高電平的跳變,所以數據采樣是在下降沿,數據發送是在上升沿。
CPOL=1,CPHA=0:此時空閑態時,SCLK處于高電平,數據采集是在第1個邊沿,也就是SCLK由高電平到低電平的跳變,所以數據采集是在下降沿,數據發送是在上升沿。
CPOL=1,CPHA=1:此時空閑態時,SCLK處于高電平,數據發送是在第1個邊沿,也就是SCLK由高電平到低電平的跳變,所以數據采集是在上升沿,數據發送是在下降沿。
硬件簡介
FLASH閃存 的英文名稱是"Flash Memory",一般簡稱為"Flash",它屬于內存器件的一種,是一種非易失性( Non-Volatile )內存。
在開發板上有一塊flash(M25P16),用來保存FPGA的硬件配置信息,也可以用來存儲用戶的應用程序或數據。
M25P16是一款帶有寫保護機制和高速SPI總線訪問的2M字節串行Flash存儲器,該存儲器主要特點:2M字節的存儲空間,分32個扇區,每個扇區256頁,每頁256字節;能單個扇區擦除和整片擦除;每扇區擦寫次數保證10萬次、數據保存期限至少20年。
C(serial clock:串行時鐘)為D和Q提供了數據輸入或者輸出的時序。D的數據總是在C的上升沿被采樣。Q的數據 在C的下降沿被輸出。
ˉS(Chip Select:芯片選擇端),當輸入為低時,該芯片被選中,可以允許進行讀寫操作。當輸入為高時,該芯片被釋放,不能夠進行操作。
對于H——o——l——d——和W——, 為保持功能和硬件寫保護功能,在本設計中不使用此管腳,在硬件設計時,這兩個管腳全部被拉高了,即全部失效。
flash采用spi的通信協議,flash當做從機。serial clcok等效于spi中的sclk,chip select等效于spi中的cs,D等效于spi中的mosi,Q等效于spi中的miso。
flash可以支持mode0和mode3,這兩種模式中,都是在時鐘的上升沿采樣,在時鐘的下降沿發送數據。
flash的每一頁都可以被寫入,但是寫入只能是把1改變為0。擦除可以把0改變為1。所以在正常寫入數據之前,都要將flash進行擦除。
flash的命令表如下:
下面介紹幾個常用的命令
RDID(Read Identification :讀ID):發送命令RDID(9F),然后接收第1個字節的memory type(20H),第二個字節的memory capacity(15H)。后續的字節暫不關心。
WREN(Write Enable :寫使能):在任何寫或者擦除的命令之前,都必須首先打開寫使能。打開寫使能為發送命令WREN(06h)。
RDSR(Read Status Register:讀狀態寄存器):發送命令RDSR(05h),然后返回一個字節的狀態值。
狀態寄存器的格式如下:
WIP(Write In Progress bit)表示flash內部是否正在進行內部操作,寫和擦除都會導致flash內部進行一段時間的工作,在內部工作期間,外部的命令會被忽略,所以在進行任何命令之前,都需要查看flash內部是否正在工作。WIP為1時,表示flash內部正在工作;WIP為0時,表示flash內部沒有在工作。
READ(Read DATA Bytes:讀數據):發送命令READ(03H),后續發送3個字節的地址,然后就可以接收數據,內部的地址會不斷遞增。一個讀命令就可以把整個flash全部讀完。
PP(Page Program :頁編寫):發送命令PP(02H),接著發送3個字節的地址,然后發送數據即可。切記所寫的數據不能超過本頁的地址范圍。
SE(Sector Erase :扇區擦除):發送命令SE(D8H),接著發送3個字節的地址。
BE(Bulk Erase:整片擦除):發送命令BE(C7H)。
關于flash的其他的介紹,可以參考03_芯片手冊->FLASH->M25P16.pdf。
設計要求
設計flash(M25P16)控制器。
設計分析
根據M25P16的數據手冊得知,其接口為spi接口,且支持模式0和模式3,本設計中選擇模式0。
輸入時序圖如下:
輸出時序如下:
時序圖中所對應的符號說明:
根據輸入和輸出的時序圖以及參數表,將SPI的時鐘的頻率定為10MHz。
在設計中,FPGA作為主機,M25P16作為從機。
架構設計和信號說明
此模塊命名為m25p16_drive。
二級模塊(分模塊)(第一頁)
二級模塊(分模塊)(第二頁)
設計中,各個命令單獨寫出控制器,通過多路選擇器選擇出對應的命令,然后控制spi_8bit_drive將數據按照spi的協議發送出去。各個命令的脈沖通過ctrl模塊進行控制各個命令控制器,寫入的數據首先寫入到寫緩沖區,讀出的數據讀出后寫入到讀緩沖區。
暫不分配的端口,在應用時都是由上游模塊進行控制,本設計測試時,編寫上游模塊進行測試。
各個模塊的功能,和連接線的功能在各個模塊設計中說明。
spi_8bit_drive設計實現
本模塊負責將8bit的并行數據按照spi協議發送出去,以及負責按照spi協議接收數據,將接收的數據(8bit)并行傳輸給各個模塊。
spi_send_en為發送數據使能信號(脈沖信號),spi_send_data為所要發送數據,spi_send_done為發送完成信號(脈沖信號)。
spi_read_en為接收數據使能信號(脈沖信號),spi_read_data為所接收的數據,spi_read_done為接收完成信號(脈沖信號)。
在發送邏輯控制中,全部的信號采用下降沿驅動。利用外部給予的spi_send_en作為啟動信號,啟動send_cnt。send_cnt在不發送數據時為8,發送數據時,從0到7。
在接收邏輯中,全部的信號采用上升沿驅動。利用外部給予的spi_read_en作為啟動信號,啟動rec_en,經過移位接收數據。
在spi_sclk輸出時,采用組合邏輯。由于設計采用spi的模式0,故而spi_sclk不發送或者接收數據時為0,接收數據時為時鐘信號。因為要求為模式0,所以在接收數據時,spi_sclk的輸出不能夠先有下降沿,即要求spi_sclk的控制信號不能由上升沿信號驅動,所以將rec_en同步到下降沿的rec_en_n。
仿真代碼為:
在仿真中,將時鐘設置為10MHz。
所有的信號采用上升沿驅動。發送一個8bit的隨機數值,接收一個8bit的隨機數值。
spi_miso信號為從機下降沿驅動信號。
通過RTL仿真,可以看出發送和接收全部正常。
mux7_1設計實現
本模塊負責將7個命令模塊發出的命令(寫使能、寫數據和讀使能)經過選擇發送給spi_8bit_drive模塊。
在設計中,有的命令模塊不需要進行讀取(pp和se等等),此時將輸出的讀使能信號輸出為低電平。
be設計實現
該模塊接收到be_en(整片擦除的脈沖信號)信號后,發送對應的使能和數據,等待發送完成脈沖。發送完成后,輸出擦除完成的脈沖。
整片擦除的命令為8’hc7。
wren設計實現
該模塊接收到wren_en(打開flash內部的寫使能的脈沖信號)信號后,發送對應的使能和數據,等待發送完成脈沖。發送完成后,輸出擦除完成的脈沖。
打開flash內部寫使能的命令碼為8’h06。
se設計實現
該模塊接收到se_en(擦除扇區的寫使能的脈沖信號)信號后,發送對應的使能和數據,等待發送完成脈沖。發送完成后,接著發送高八位地址,中間八位地址和低八位地址。全部發送完成后,發送se_done信號。
該模塊采用狀態機實現。SE_STATE(扇區擦除命令發送)、H_ADDR(高八位地址發送)、M_ADDR(中間八位地址發送)、L_ADDR(低八位地址發送)、SE_DONE(扇區擦除完成)。所有的脈沖信號在未標注的時刻,輸出全部為0。
設計代碼為:
在發送過程中,由于是每8bit發送一次,所以在時序上將看到發送時,每8個脈沖一組,中間會有明顯的間隔。
pp設計實現
該模塊負責將外部寫fifo中的數據寫入到flash中。wr_fifo_rd為寫fifo的讀使能信號,wrdata為從寫fifo中讀出的數據,wr_len為需要寫入flash中數據的長度,wr_addr為寫入地址。
該模塊采用狀態機實現。PP_STATE(發送pp命令),H_ADDR(發送高八位地址)、M_ADDR(發送中間八位地址),L_ADDR(發送低八位地址)、RDFIFO(讀寫fifo)、FIFO_WAIT(等待讀寫fifo的數據輸出)、SEND(發送8bit數據)、SEND_WAIT(發送等待,發送完成后判斷是否發送完成)。對于所有的脈沖信號,沒有賦值的位置,全部賦值為0。
cnt為記錄已經發送的數據個數。
設計代碼為:
rdsr設計實現
本模塊的功能為讀取m25p16的狀態寄存器,主要檢測狀態寄存器的最低位(WIP)。
WIP(write in progress :正在進行寫進程),該bie位表示了flash內部是否在進行寫進程。如果處于寫進程時,flash忽略外部所有的命令,所以建議在執行任何命令前,首先進行檢測該位。1表示正在寫進程中,0表示不處于寫進程。
如果檢測到正在寫進程中,進行延遲1ms,然后再次讀取該位狀態。直到寫進程結束。
本模塊采用狀態機設計實現。ILDE(發送讀狀態寄存器命令)、RDSRSTATE(發送讀使能)、WIP(判斷wip位)、 DELAY1ms(延遲1ms)。cnt為延遲1ms的計數器。
設計代碼為:
rdid設計實現
該模塊負責讀取flash的ID(2015),驗證ID的正確性。
該模塊采用狀態機的方式實現。IDLE(等待讀取ID的命令)、IDSTATE1(讀取高八位ID)、IDSTATE2(讀取中間八位ID)、IDSTATE3(讀取低八位ID)、ID_CHECK(檢測ID的正確性)。
狀態轉移圖如下:
設計代碼為:
read_ctrl設計實現
該模塊負責將flash的數據讀出,寫入到輸出緩存中。
該模塊采用狀態機實現。RD_STATE(等待讀命令)、H_ADDR(發送高八位地址)、M_ADDR(發送中間八位地址)、L_ADDR(發送低八位地址)、RDDATA(讀取數據)、WRFIFO(將讀出的數據寫入到FIFO中)、CHECK_LEN(判斷讀取的長度)。
狀態轉移圖如下:
設計代碼為:
wr_fifo和rd_fifo調用
兩個fifo的寬度設置為8,深度設置為256,同步fifo,帶有復位。
ctrl設計實現
該模塊根據外部的命令,按照m25p16的執行規則,進行控制各個模塊的執行。
該模塊采用狀態機實現。INIT_RDSR(讀WIP),INIT_RDID(讀ID),INIT_ID(判斷ID),WIP(讀WIP),WIP_DONE(等待WIP),IDLE(空閑狀態),**STATE(執行對應的命令),**WREN(打開flash的寫使能)。在進行任何命令前,都檢查wip。
狀態轉移圖如下:
在不同的狀態,mux_sel選擇對應的命令通過。
drive_busy只有在IDLE狀態才是低電平。
spi_cs_n信號, DLE狀態為高電平、WIP_DONE(INIT_RDID)中spi_read_done信號為高時 (保證能夠多次讀取狀態寄存器)、在其他狀態發生切換時,spi_cs_n 為高電平,否則為低電平。
設計代碼為:
m25p16_drive設計實現
本模塊負責連接所有二級模塊,實現所有的功能。
RTL仿真
本次設計涉及到讀取flash的id以及狀態寄存器,所以在仿真時需要加入仿真模型。仿真模型放在msim的m25p16_sim_module中。m25p16為仿真模型的頂層文件。
由于讀寫和擦除的時間較長,RTL仿真中,將只仿真RDSR和RDID,其他的功能測試在板級測試時進行。
仿真代碼如下:
在設置testbench時,注意將所有文件全部添加到文件中。
選擇testbench時,注意選中設置的m25p16_drive_tb。
利用modelsim仿真,可以得出如下RTL仿真波形。
讀到ID,以及檢測WIP都是正確的。
板級測試
由于m25p16的時序原因,整個設計工作在10MHz(利用PLL產生)。
在進行測試控制時,對最后一個扇區進行擦除;對最后一個扇區的第一頁進行寫入數據100個(1至100);對最后一個扇區的第一個進行讀取,驗證數據是否為1至100。
測試的控制模塊命名為test_ctrl。
此模塊采用狀態機實現。WRFIFO(將1至100寫入wrfifo中)、SE(扇區擦除)、PP(寫入flash)、RD(讀出flash)、WAIT_RD(等待讀取)、CHECK( 檢測讀出的數據的正確性)。
設計代碼為:
將test模塊設置為頂層。在test模塊中,m25p16_drive例化中,對于整片擦除不做控制,對于addr直接指向最后一個扇區的第一頁,len指定為100。
代碼為:
由于開發板上的flash是為FPGA進行保存配置信息的,所以管腳都連接在專用管腳上,本次實驗需要將這專用管腳配置為普通io。
右擊器件型號,選擇device。
點擊device and pin options。
選擇Dual-purpose pins,將其中所有的功能改為普通IO。
點擊ok后,即可進行綜合分析。
連接開發板和PC,打開邏輯分析儀。
采樣時鐘選擇10MHz(PLL 的c0),采樣深度設置為2K。
觀測信號如下圖所示。
首先將wrfifo_wr的觸發條件設置為上升沿。點擊觸發后,按下復位按鍵。觸發后,可以看到寫入數據1至100后,然后進行SE命令。
將rdfifo_rd的觸發條件設置為上升沿(將wrfifo_wr觸發條件修改為donot care)。點擊觸發后,按下復位按鍵。
通過仿真和下板實測,驗證控制器設計正確。
更多熱點文章閱讀
-
電子技術
+關注
關注
18文章
884瀏覽量
55858 -
電子發燒友論壇
+關注
關注
4文章
197瀏覽量
1056
原文標題:【教程分享】FPGA零基礎學習:SPI 協議驅動設計
文章出處:【微信號:gh_9b9470648b3c,微信公眾號:電子發燒友論壇】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論