FlexIO是廣泛應用于恩智浦微控制器上的外設(shè),憑借高度的靈活性和可配置性,可以用來模擬常見的UART、I2C、I2S、SPI等接口。當片上的外設(shè)資源不夠用時,使用FlexIO進行模擬也是很實用的方法。
本文的介紹來自于真實客戶需求,即一個榨干了i.MX RT1010所有外設(shè)資源后不得不用FlexIO模擬SPI從機協(xié)議,不得不讓SPI從機工作在連續(xù)模式,以及從機不知道主機會傳給從機多少個數(shù)據(jù)的案例。
問題的提出
首先介紹我們要實現(xiàn)的目標,在i.MX RT1010上使用FlexIO模擬SPI Slave 設(shè)備,在連續(xù)模式下接收動態(tài)大小數(shù)據(jù)幀。硬件平臺就是我們的RT1010 EVK開發(fā)板了,軟件環(huán)境是SDK 2.9.1,工程開發(fā)基于edma_lpspi_transfer 中slave項目進行開發(fā),具體路徑如下:
boardsevkmimxrt1010driver_examplesflexiospiedma_lpspi_transferslave
本次模擬的SPI從機是工作在CPOL=0 & CPHA=0的工作狀態(tài)。
在閱讀下面的內(nèi)容前,建議學習AN12780作為基礎(chǔ),AN12780介紹了如何使用FlexIO模擬非連續(xù)模式下的SPI方法。
本次連續(xù)模式的開發(fā)也是基于非連續(xù)模式的方法進行改動后實現(xiàn)的。
連續(xù)模式下SPI從機設(shè)置
連續(xù)模式與非連續(xù)模式的區(qū)別在于,SPI在傳輸完一個byte(也可以是多個byte,此處為方便描述,使用1個byte)數(shù)據(jù)后,是否需要拉高片選信號(CS);連續(xù)模式下,傳輸完一個byte后不拉高片選信號。因此需要在非連續(xù)模式的基礎(chǔ)上進行一些改動。
首先Timer0需要在CS pin拉高時關(guān)閉,即CS pin的上升沿時關(guān)閉。其次,Timer0在傳輸數(shù)據(jù)幀傳輸過程中需要一直開啟。此時的數(shù)據(jù)幀不是特指1個byte的數(shù)據(jù),而是廣泛的指一個或多個byte組成的數(shù)據(jù)幀。
然而,因為Timer0無法在一幀數(shù)據(jù)的最后關(guān)閉——CS信號拉高總是晚于最后一個數(shù)據(jù)的收發(fā)——這意味著,總會在最后一個字符的最后一位傳輸后發(fā)生一次額外的加載。請注意下圖中用綠色標記的地方。
額外加載的原因在于當shifter工作在發(fā)送模式時,Timer計滿之后將會從SHIFBUF加載新的數(shù)據(jù)到TX shifter。這意味在下一輪數(shù)據(jù)傳輸時,一個無效的數(shù)字將會被傳輸。
實際上,這個額外的加載在數(shù)據(jù)幀的每一個字符傳輸過程中都會發(fā)生,但是因為工作在連續(xù)模式,因此不會出現(xiàn)異常。
對于RX shifter, 它將會在CS拉高的時候觸發(fā)一次額外的存儲事件。因為當CS拉高的時候,Timer會被關(guān)閉,此時RX shifter將會把shifter內(nèi)的數(shù)據(jù)存儲到SHIFBUF中,隨后馬上發(fā)起了新的一次DMA搬運。這意味著一個無效的數(shù)據(jù)被存儲并且該數(shù)據(jù)通常是0。
為了避免這些問題,清空shifter內(nèi)的數(shù)據(jù)即可解決問題。因為FlexIO模塊沒有相關(guān)的bit可以清空shifter寄存器的功能,所以可以使用下面的方法實現(xiàn)清空shifter的功能。
TXshifter:關(guān)閉shifter后再次配置為TX 模式,對應的shifter內(nèi)數(shù)據(jù)即可清空。
RXshifter:讀一下shifter對應的buffer寄存器,shifter內(nèi)的數(shù)據(jù)即可清空。
在例程代碼中,shifter0是TX移位器,shifter1是RX移位器。因此在完成一幀數(shù)據(jù)的傳輸后,調(diào)用下面的接口函數(shù)即可實現(xiàn)共兩個shifter數(shù)據(jù)的清空。
void FLEXIO_SPI_FlushShifters(FLEXIO_SPI_Type *base)
{
volatile uint32_t tmp;
base-》flexioBase-》SHIFTCTL[base-》shifterIndex[0]] &= ~FLEXIO_SHIFTCTL_SMOD_MASK;
base-》flexioBase-》SHIFTCTL[base-》shifterIndex[0]] |= FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
tmp = base-》flexioBase-》SHIFTBUF[base-》shifterIndex[1]];
__DSB();
}
下面的表格介紹了Timer0的具體設(shè)置,用紅色高亮標記的地方是區(qū)別于非連續(xù)模式的設(shè)置,完成更改之后即可實現(xiàn)從機在連續(xù)模式下工作。
1. 因為pin Polarity 設(shè)置為active low, 所以時序極性發(fā)生改變,因此使能信號為上升沿(真實的輸入使能信號為下降沿)。
RX shifter的設(shè)置為:
此時,我們便可以讓從機設(shè)備工作在連續(xù)工作模式了,另外各位小伙伴還要記得,這種連續(xù)工作模式,是有一點點不太完美的瑕疵的,就是額外的加載事件,因此要記得在每次數(shù)據(jù)接收完畢之后,要用上文提到的shifter清潔函數(shù)刷新shifter的內(nèi)容哦。
連續(xù)模式下SPI從機
接收動態(tài)幀大小的設(shè)置
SDK默認例程中,DMA被用來搬運數(shù)據(jù)以提升效率。但是DMA中斷通常是在接收到一定數(shù)量的數(shù)據(jù)后產(chǎn)生。
但在實際的應用中,每幀傳輸?shù)臄?shù)據(jù)大小可能不是固定的,從機也不知道在一幀數(shù)據(jù)中有多少數(shù)據(jù)。在這種未知一幀數(shù)據(jù)大小的情況下,使用DMA接收到固定數(shù)量的數(shù)據(jù)后產(chǎn)生中斷的方法不能滿足實際需求。
在LPSPI傳輸過程中,CS引腳的下降沿表示傳輸開始,CS引腳的上升沿表示傳輸結(jié)束。因此,從機可以通過檢測CS引腳的上升沿和下降沿來知道一幀數(shù)據(jù)已經(jīng)完成傳輸。
為了實現(xiàn)這個功能,可以增加一個定時器(Timer)來檢測CS引腳的狀態(tài)。
基本方法是讓定時器在16位計數(shù)器模式下工作,計數(shù)值為0。這意味著一旦定時器超時,它會產(chǎn)生一個比較事件,并會產(chǎn)生一個FLEXIO中斷。從機再處理此中斷并且解析接收數(shù)據(jù)的數(shù)量。
現(xiàn)在,有兩個問題。第一個是定時器何時啟用(timer enables source)以及定時器遞減源(timer decrement source)是什么,第二個是從機如何知道它使用DMA 接收了多少數(shù)據(jù)。
對于第一個問題,定時器可以通過引腳的下降沿或觸發(fā)信號的下降沿使能。關(guān)于定時器遞減源,引腳輸入遞減或觸發(fā)輸入遞減均可使用。定時器可以通過CS引腳的下降沿使能,然后當CS引腳上升時,比較事件(compare envet)發(fā)生,同時產(chǎn)生FlexIO中斷。除此之外,定時器還需要在定時器比較事件時關(guān)閉。
下表描述了使用pin下降沿作為定時器使能遞減源的具體配置。
1. 因為pin Polarity 設(shè)置為active low, 所以時序極性發(fā)生改變,因此使能信號為上升沿(真實的輸入使能信號為下降沿)。
下表描述了使用trigger下降沿作為定時器使能遞減源的具體配置:
1. 因為trigger Polarity 設(shè)置為active low, 所以時序極性發(fā)生改變,因此使能信號為上升沿(真實的輸入使能信號為下降沿)。
第二個問題是從機如何知道它使用DMA接收了多少數(shù)據(jù)。下面的這個接口函數(shù)API可以用來實現(xiàn)這個功能:
static inline status_t FLEXIO_SPI_SlaveTransferGetCountEDMA(FLEXIO_SPI_Type *base,
flexio_spi_slave_edma_handle_t *handle,
size_t *count)
對于這個API函數(shù),有兩點需要注意。
第一點是這個API的注釋描述不是很準確(將會在SDK 2.11.0版本進行更新)。這個API的功能是:獲取當前通過FlexIO SPI DMA的方法,接收到的數(shù)據(jù)數(shù)量。
第二點是這個API返回的結(jié)果(count,API中第三個參數(shù))不能直接使用,正如上文所述,因為在CS拉高的時候會觸發(fā)額外的一次DMA搬運。
因此,接收到的數(shù)據(jù)大小應該是:
size = count - 1; //The count is the thirdparameter on API
在獲取數(shù)據(jù)幀大小后,需要使用下面的API終止FlexIO SPI DMA的傳輸。但是現(xiàn)在,這個API實現(xiàn)的功能是暫停傳輸而不是終止傳輸。這意味著這個API需要進行一些改動才能滿足要求。這個問題將會在SDK 2.11.0進行更新。
void FLEXIO_SPI_SlaveTransferAbortEDMA(FLEXIO_SPI_Type *base,flexio_spi_slave_edma_handle_t *handle)
在fsl_flexio_spi_edma.c 的第409 和 410行使用下面的代碼替代即可。
EDMA_AbortTransfer(handle-》txHandle);EDMA_AbortTransfer(handle-》rxHandle);
解決這兩個問題后,從機就可以接收數(shù)據(jù)大小變化的數(shù)據(jù)幀了。但是在這種情況下仍然有一個限制,即幀的大小應小于或等于 DMA 可接收的數(shù)量。
例程代碼運行
在運行代碼之前,EVK板需要進行一定的改動:
去掉電阻R90,使用0Ω電阻焊接到R800。
按照下面的設(shè)置將SPI的主機和從機連接起來。
具體實現(xiàn)代碼可以在應用筆記的附件中找到,打開edma_lpspi_transfer slave 工程,使用附件中的文件替換。具體路徑為:
boardsevkmimxrt1010driver_examplesflexiospiedma_lpspi_transferslave
在默認設(shè)置下,主機將向從機發(fā)送16個字節(jié),從機將產(chǎn)生一個FlexIO中斷。從站可以接收的最大數(shù)量為64字節(jié)。
用戶可以更改以下參數(shù)來配置主機發(fā)送數(shù)據(jù)幀的大小。
masterXfer.dataSize = TRANSFER_SIZE;
在一幀數(shù)據(jù)完成發(fā)送/接收后,將會進行一次簡單的校驗。如果校驗通過,在串口終端輸入任意一個字符即可開啟新的一輪數(shù)據(jù)傳輸。
責任編輯:haq
-
控制器
+關(guān)注
關(guān)注
114文章
17082瀏覽量
183960 -
恩智浦
+關(guān)注
關(guān)注
14文章
5975瀏覽量
115941 -
SPI
+關(guān)注
關(guān)注
17文章
1799瀏覽量
95701
原文標題:FlexIO模擬連續(xù)模式下的SPI從機設(shè)備
文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
關(guān)于交流負載模式中的CF值設(shè)置(下)

能否提供Linux下USB轉(zhuǎn)SPI模式的測試程序?
是德示波器EXR604A滾動模式設(shè)置指南

是德示波器滾動模式設(shè)置指南

DLP4500設(shè)置好內(nèi)觸發(fā)模式開始投影并向相機發(fā)送觸發(fā)信號,用VS打開相機設(shè)置為外觸發(fā)模式可以直接觸發(fā)拍照嗎?
操作ADS1298R時,主機的spi時鐘要怎么設(shè)置?
ADS1232在SPI模式下,應該怎么配置引腳?
請問ADS1232轉(zhuǎn)換模式都是連續(xù)轉(zhuǎn)換模式嗎?
iic協(xié)議與spi協(xié)議的區(qū)別
ADS1246連續(xù)轉(zhuǎn)換模式怎么設(shè)置?
請問ADS1115能否配置為多個通道連續(xù)轉(zhuǎn)換模式?
ADS1259 SPI連續(xù)讀模式下突然中斷,突然不出現(xiàn)下降沿了,是什么原因?
TDC7201的SPI從模式下DOUT無輸出響應怎么解決?
瀚海微SD NAND之SD 協(xié)議(40)SPI模式CMD8的操作

評論