1. 程式人生 > >MTK 驅動開發(33)---SPI 基礎知識

MTK 驅動開發(33)---SPI 基礎知識

  SPI(Serial Peripheral Interface,序列外設介面)是Motorola公司提出的一種同步序列資料傳輸標準是一種高速的,全雙工,同步的通訊匯流排在很多器件中被廣泛應用。

SPI相關縮寫

SS: Slave Select,選中從裝置,片選。

CKPOL (Clock Polarity) = CPOL = POL = Polarity = (時鐘)極性

CKPHA (Clock Phase)   = CPHA = PHA = Phase = (時鐘)相位

SCK = SCLK = SCL = SPI的時鐘(Serial Clock)

Edge = 邊沿,即時鐘電平變化的時刻,即上升沿

(rising edge)或者下降沿(falling edge)。

對於一個時鐘週期內,有兩個edge,分別稱為:

Leading edge = 前一個邊沿 第一個邊沿,對於開始電壓是1,那麼就是1變成0的時候,對於開始電壓是0,那麼就是0變成1的時候;

Trailing edge = 後一個邊沿 第二個邊沿,對於開始電壓是1,那麼就是0變成1的時候(即在第一次1變成0之後,才可能有後面的0變成1),對於開始電壓是0,那麼就是1變成0的時候;


介面

SPI介面經常被稱為4線序列匯流排,以主/從方式工作,資料傳輸過程由主機初始化

如圖1所示,其使用的4條訊號線分別為:

1) SCLK:序列時鐘,用來同步資料傳輸,由主機輸出;

2) MOSI:主機輸出從機輸入(Master Output Slaver Input)資料線;

3) MISO:主機輸入從機輸出資料線;

4) SS:片選線,低電平有效,由主機輸出。

在SPI總線上,某一時刻可以出現多個從機,但只能存在一個主機,主機通過片選線來確定要通訊的從機。這就要求從機的MISO口具有三態特性,使得該口線在器件未被選通時表現為高阻抗。

SPI由於介面相對簡單(只需要4根線),用途算是比較廣泛,主要應用在 EEPROM,FLASH,實時時鐘,AD轉換器,還有數字訊號處理器和數字訊號解碼器之間。

即一個SPI的Master通過SPI與一個從裝置,即上述的那些Flash,ADC等的Slaver SPI進行通訊。

而主從裝置之間通過SPI進行通訊,首先要保證兩者之間時鐘SCLK要一致,互相要商量好了,要匹配,否則,就沒法正常通訊了,即保證時序上的一致才可正常訊而這裡的SPI中的時鐘和相位,指的就是SCLk時鐘的特性,即保證主從裝置兩者的時鐘的特性一致了,以保證兩者可以正常實現SPI通訊。


資料傳輸

在一個SPI時鐘週期內,會完成如下操作:

1) 主機通過MOSI線傳送1位資料,從機通過該線讀取這1位資料;

2) 從機通過MISO線傳送1位資料,主機通過該線讀取這1位資料。

這是通過移位暫存器來實現的。如圖2所示,主機和從機各有一個移位暫存器,且二者連線成環。隨著時鐘脈衝,資料按照從高位到低位的方式依次移出主機暫存器和從機暫存器,並且依次移入從機暫存器和主機暫存器。當暫存器中的內容全部移出時,相當於完成了兩個暫存器內容的交換。


時鐘極性和時鐘相位

在SPI操作中,最重要的兩項設定就是時鐘極性(CPOL或UCCKPL)和時鐘相位(CPHA或UCCKPH)。時鐘極性設定時鐘空閒時的電平,時鐘相位設定讀取資料和傳送資料的時鐘沿。

主機和從機的傳送資料是同時完成的,兩者的接收資料也是同時完成的。所以為了保證主從機正確通訊,應使得它們的SPI具有相同的時鐘極性和時鐘相位。

CPOL極性

先說什麼是SCLK時鐘的空閒時刻,其就是當SCLK在傳送8bit位元資料之前和之後的狀態,與此對應的,SCLK在傳送資料的時候,就是正常的工作的時候,有效active的時刻了。

先說英文,其精簡解釋為:Clock Polarity = IDLE state of SCK

再用中文詳解:

SPICPOL,表示當SCLK空閒idle的時候,其電平的值是低電平0還是高電平1

CPOL=0,時鐘空閒idle時候的電平是低電平,所以當SCLK有效的時候,就是高電平,就是所謂的active-high

CPOL=1,時鐘空閒idle時候的電平是高電平,所以當SCLK有效的時候,就是低電平,就是所謂的active-low

CPHA相位

首先說明一點,capture strobe = latch = read = sample,都是表示資料取樣,資料有效的時刻。

相位,對應著資料取樣是在第幾個邊沿(edge),是第一個邊沿還是第二個邊沿,0對應著第一個邊沿,1對應著第二個邊沿。

CPOL=0

對於CPHA=0idle時候的是低電平,第一個邊沿就是從低變到高,所以是上升沿;

對於CPHA=1idle時候的是低電平,第二個邊沿就是從高變到低,所以是下降沿;

CPOL=1

對於CPHA=0idle時候的是高電平,第一個邊沿就是從高變到低,所以是下降沿;

對於CPHA=1idle時候的是高電平,第二個邊沿就是從低變到高,所以是上升沿;

用圖文形式表示,更加容易看懂:


CKPCKE

CKPCKE是MicrochipPIC系列晶片中的說法。

1CKPClock Polarity Select,就是極性=CPOL

CKP,雖然名字和CPOL不一樣,但是都是指時鐘極性的選擇,定義也一樣

CKP: Clock Polarity Select bit

1 = Idle state for clock (CK) is a high level

0 = Idle state for clock (CK) is a low level

所以不多解釋。

2CKEClock Edge Select,就是相位=CPHA

CKE: SPI Clock Edge Select bit

1 = Transmit occurs on transition from active to Idle clock state

0 = Transmit occurs on transition from Idle to active clock state

意思是:

1 =(資料)傳輸發生在時鐘從有效狀態轉到空閒狀態的那一時刻

0 =(資料)傳輸發生在時鐘從空閒狀態轉到有效狀態的那一時刻

其中,資料傳輸的時刻,即上圖中標出的“資料transmit傳輸的時刻”。

CKE的定義也跟CPHA相同。

所以,CKPCKE所對應的取值的含義為:

When CKP = 0:

CKE=0 => Data transmitted on rising edge of SCKidle時候是低電平,從空閒到有效,就是從低電平到高電平,所以是上升沿)

CKE=1 => Data transmitted on falling edge of SCK(idle時候是低電平,從有效到空閒,就是從高電平到低電平,所以是下降沿)

When CKP = 1:

CKE=0 => Data transmitted on falling edge of SCKidle時候是高電平,從空閒到有效,就是從高電平到低電平,所以是下降沿)

CKE=1 => Data transmitted on rising edge of SCKidle時候是高電平,從有效到空閒,就是電平到電平,所以是上升沿


舉例來說,分別選取MSP430控制器和OLED驅動SH1101A為主從機,圖3和圖4為它們的SPI時序。由圖4可知,SH1101A的SPI時鐘空閒時為高電平,並且在後時鐘沿接收資料(後時鐘沿在資料的中間部位)則MSP430控制器SPI的設定應與此保持一致。從圖3中可以看出,要使得時鐘在空閒時為高電平,應將UCCKPL置1;要使得在後時鐘沿接收資料,應將UCCKPH清零。



下面再列出其他一些地方找到的,常見的SPI的四種模式的時序圖,供參考:



如何看懂和記憶CPOLCPHA

所以,關於在其他地方介紹的,看似多麼複雜難懂難記憶的CPOLCPHA,其實經過上面解釋,就肯容易看懂了:

去看時序圖,如果時鐘SCLK的起始電平是0,那麼CPOL=0,如果是1,那麼CPOL=1

然後看資料取樣時刻,即時序圖資料線上的資料矩形區域的中間所對應的位置,對應到上面SCLK時鐘的位置,對應著是第一個邊沿或是第二個邊沿,即CPHA01。(對應的是上升沿還是下降沿,要根據對應的CPOL的值,才能確定)。

即:

1)如何判斷CPOLSCLK的空閒時候電壓是0還是1,決定了CPOL0還是1

2)如何判斷CPHA:而資料取樣時刻對應著的SCLK的電平,是第一個邊沿還是第二個邊沿,對應著CPHA0還是1

軟體中如何設定SPI的極性和相位

SPI分主裝置和從裝置,兩者通過SPI協議通訊。

設定SPI的模式,是從裝置的模式,決定了主裝置的模式。

所以要先去搞懂從裝置的SPI是何種模式,然後再將主裝置的SPI的模式,設定和從裝置相同的模式,即可正常通訊。

對於從裝置的SPI是什麼模式,有兩種:

1)固定的,裝置硬體決定的。

SPI從裝置,具體是什麼模式,相關的datasheet中會有描述,需要自己去datasheet中找到相關的描述,即:

關於SPI從裝置,在空閒的時候,是高電平還是低電平,即決定了CPOL0還是1

然後再找到關於裝置是在上升沿還是下降沿去取樣資料,這樣就是,在定了CPOL的值的前提下,對應著可以推算出CPHA0還是1了。

舉例1

CC2500 - Low-Cost Low-Power 2.4 GHz RF TransceiverdatasheetSPI的時序圖是:


從圖中可以看到,最開始的SCLK和結束時候的SCLK,即空閒時刻的SCLK,是低電平,推匯出CPOL=0,然後可以看到資料取樣的時候,即資料最中間的那一點,對應的是SCLK的第一個邊沿,所以CPHA=0(此時對應的是上升沿)。

舉例2

SSD1289 - 240 RGB x 320 TFT LCD Controller Driverdatasheet中提到:

SDI is shifted into 8-bit shift register on everyrising edge of SCK in the order of data bit 7, data bit 6 …… data bit 0.

意思是,資料是在上升沿取樣,所以可以斷定是CPOL=0CPHA=0,或者CPOL=1CPHA=1的模式,但是至於是哪種模式。

按理來說,接下來應該再去確定SCLK空閒時候是高電平還是低電平,用以確定CPOL0還是1,但是datasheet中沒有提到這點。

所以,此處,目前不太確定,是兩種模式都支援,還是需要額外找證據卻確定CPOL0還是1.

2)可配置的,由軟體自己設定

從裝置也是一個SPI控制器,4種模式都支援,此時只要自己設定為某種模式即可。

然後知道了從裝置的模式後,再去將SPI主裝置的模式,設定為和從裝置模式一樣,即可。

對於如何配置SPICPOLCPHA的話,不多細說,多數都是直接去寫對應的SPI控制器中對應暫存器中的CPOLCPHA那兩位,寫0或寫1即可。

舉例:

此處遇到的C8051F347中的SPI就是一個SPIcontroller控制器,即支援軟體配置CPOLCPHA的值,四種模式都支援,此處C8051F347作為SPI從裝置,設定了CPOL=1CPHA=0的模式,因此,此處對應主晶片Blackfin F537中的SPI控制器,作為Master主裝置,其SPI的模式也要設定為CPOL=1CPHA=0


優缺點

SPI介面具有如下優點:

1) 支援全雙工操作;

2) 操作簡單;

3) 資料傳輸速率較高。

同時,它也具有如下缺點:

1) 需要佔用主機較多的口線(每個從機都需要一根片選線);

2) 只支援單個主機。

相關推薦

MTK 驅動開發33---SPI 基礎知識

  SPI(Serial Peripheral Interface,序列外設介面)是Motorola公司提出的一種同步序列資料傳輸標準,是一種高速的,全雙工,同步的通訊匯流排,在很多器件中被廣泛應用。SPI相關縮寫SS: Slave Select,選中從裝置,片選。CKPOL

Linux 下wifi 驅動開發—— WiFi基礎知識解析

 一、WiFi相關基礎概念 1、什麼是wifi        我們看一下百度百科是如何定義的:       Wi-Fi是一種可以將個人電腦、手持裝置(如pad、手機)等終端以無線方式互相連線的技術,事實上它是一個高頻無線電訊號。[1]  無線保真是一個無線網路通訊技術的品牌

MTK 驅動開發36---低功耗基礎知識

1、sleep /suspend suspend確切的說是MCU(ARM )的suspend,也就是cpu進入Wait for interrupt狀態(WFI);因為對整個系統來說,CPU進WFI是整個

Exynos4412 中斷驅動開發—— 中斷基礎及中斷的註冊過程

一、中斷基礎概念         所謂中斷,指CPU在執行程式的過程中,出現了某些突發事件即待處理,CPU必須暫停當前的程式。轉去處理突發事件,處理完畢後CPU又返回原程式被中斷的位置並繼續執行。 1、中斷分類 a -- 內部中斷和外部中斷       根據中斷的的來源,中

【轉】交換機開發—— ARP 基礎知識解析

一、ARP協議簡介       Internet是由各種各樣的物理網路通過使用諸如路由器之類的裝置連線在一起組成的。當主機發送一個數據包到另一臺主機的過程中 可能要經過多種不同的物理網路。主機和路由器都是在網路層通過IP地址來識別的,這個地址是在全世界內唯一的。 然而,資料

Android音訊開發1基礎知識

Android音訊開發(1):基礎知識 導讀 人的說話頻率基本上為300Hz~3400Hz,但是人耳朵聽覺頻率基本上為20Hz~20000Hz。 對於人類的語音訊號而言,實際處理一般經過以下步驟: 人嘴說話——>聲電轉換——>抽樣(模數轉換)——>量化(將數字訊號用適當的數值表示)——&g

Linux USB 驅動開發—— USB裝置基礎概念

Linux USB 驅動開發(一)—— USB裝置基礎概念           在終端使用者看來,USB裝置為主機提供了多種多樣的附加功能,如檔案傳輸,聲音播放等,但對USB主機來說,它與所有USB裝置的介面都是一致的。一個USB裝置由3個功

驅動開發1基礎知識

驅動程式是作業系統和硬體通訊的橋樑,同時,驅動程式可以實現很多特殊功能,比如,虛擬光碟機(虛擬裝置),核心級hook,檔案系統透明加密(過濾驅動),修改Windows核心等等 並非所有驅動程式都必須由裝置的設計方編寫。如果裝置根據已釋出的硬體標準來設計。這時驅動程式可以由

Linux下spi驅動開發2

Linux下spi驅動開發之m25p10驅動測試 目標:在華清遠見的FS_S5PC100平臺上編寫一個簡單的spi驅動模組,在probe階段實現對m25p10的ID號探測、flash擦除、flash狀態讀取、flash寫入、flash讀取等操作。程式碼已經經過測試,運行於

從零開始使用CodeArt實踐最佳領域驅動開發

using emp 程序集 mman his return main 更新 物理 本章內容還在整理上傳中,你可以等全部更新完畢後再查閱也可以先預覽已上傳的內容。。。。。。 7. 應用層的命令模式   在上個章節裏我們設計並編碼了領域對象Permission,但是目前Perm

linux驅動開發 字符設備驅動框架(自動創建設備節點)

The module __line__ mage fail goto div on() sys 代碼如下 #include <linux/init.h> #include <linux/module.h> #include <linux/ke

Linux驅動開發9——註冊字元裝置

static int scdev_init(void) { int ret = 0,i; dev_t num_dev; printk(KERN_EMERG "numdev_major is %d!\n",numdev_major); printk(KERN_EMERG "

Linux驅動開發8——靜態和動態申請字元裝置

先貼一段demo #include <linux/init.h> /*包含初始化巨集定義的標頭檔案,程式碼中的module_init和module_exit在此檔案中*/ #include <linux/module.h> /*包含初始化載入模組的標頭檔案,程

Linux驅動開發7——驅動模組傳參

標頭檔案在include/linux/moduleparam.h 傳遞單個引數:module_param(name,type,perm) - name:模組引數的名稱 - type: 模組引數的資料型別(支援int long short uint ulong ushort型

Linux驅動開發6——GPIO初始化

gpio-exynos4.c檔案的最後一行core_initcall(exynos4_gpiolib_init); core_initcall代表在linux初始化過程中會呼叫 exynos4_gpiolib_init函式中包括chip = exynos4_gpio_

Linux驅動開發5——生成裝置節點

項裝置可以說是對一部分字元裝置的封裝,還有一部分不好歸類驅 動也歸到雜項裝置 雜項裝置初始化部分原始檔“drivers/char/ misc.c”,這一部分通過 Makefile可知,是強制編譯的。 雜項設備註冊標頭檔案include/linux/miscdevice

Linux驅動開發4——驅動註冊

結構體platform_driver struct platform_driver { int (*probe)(struct platform_device *);//初始化 int (*remove)(struct platform_device

Linux驅動開發3——以module方式註冊裝置

通過 s3c_device_leds_ctl->*smdk4x12_devices[]->platform_add_devices()->platform_device_register() 可以直接使用“platform_device_register()”來註冊裝置

Linux驅動開發2——設備註冊

結構體platform_device 註冊裝置使用結構體platform_device,原始碼路徑include/linux/platform_device.h struct platform_device { const char * name;//裝

Linux驅動開發1——最簡Linux驅動

#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET"); static int hello_init(v