衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SPI硬件基礎(chǔ)知識科普

xCb1_yikoulinux ? 來源:一口Linux ? 作者:Jasonangel ? 2022-05-16 16:12 ? 次閱讀

SPI硬件基礎(chǔ)

1、SPI hardware

SPI:Serial Perripheral Interface,串行外圍設(shè)備接口,由 Motorola 公司提出,是一種高速、全雙工、同步通信總線。SPI 以主從方式工作,通常是有一個(gè)主設(shè)備和一個(gè)或多個(gè)從設(shè)備,無應(yīng)答機(jī)制。

本文我們講解標(biāo)準(zhǔn)的 4 線 SPI,四根線如下:

①、CS/SS,Slave Select/Chip Select,片選信號線,用于選擇需要進(jìn)行通信的從設(shè)備。

②、SCK,Serial Clock,串行時(shí)鐘,和 I2C 的 SCL 一樣,為 SPI 通信提供時(shí)鐘。

③、MOSI/SDO,Master Out Slave In/Serial Data Output,主輸出從輸入。

④、MISO/SDI,Master In Slave Out/Serial Data Input,主輸入從輸出。

c7489992-d3f7-11ec-bce3-dac502259ad0.png

2、SPI 四種工作模式

SPI 有四種工作模式,通過時(shí)鐘極性(CPOL)和時(shí)鐘相位(CPHA)的搭配來得到四種工作模式:

①、CPOL=0,串行時(shí)鐘空閑狀態(tài)為低電平。
②、CPOL=1,串行時(shí)鐘空閑狀態(tài)為高電平。
③、CPHA=0,串行時(shí)鐘的第一個(gè)跳變沿(上升沿或下降沿)采集數(shù)據(jù)。
④、CPHA=1,串行時(shí)鐘的第二個(gè)跳變沿(上升沿或下降沿)采集數(shù)據(jù)。
c77588d0-d3f7-11ec-bce3-dac502259ad0.png

示例波形圖如下:

c7a1857a-d3f7-11ec-bce3-dac502259ad0.png

SPI 是全雙工的,所以讀寫時(shí)序可以一起完成。

3、SPI 傳輸機(jī)制

c7c79b84-d3f7-11ec-bce3-dac502259ad0.png

從圖可以看出,主機(jī)和從機(jī)都有一個(gè)串行移位寄存器,主機(jī)通過向它的 SPI 串行寄存器寫入一個(gè)字節(jié)來發(fā)起一次傳輸。寄存器通過 MOSI 信號線將字節(jié)傳送給從機(jī),從機(jī)也將自己的移位寄存器中的內(nèi)容通過 MISO 信號線返回給主機(jī)。這樣,兩個(gè)移位寄存器中的內(nèi)容就被交換。

外設(shè)的寫操作和讀操作是同步完成的。如果只進(jìn)行寫操作,主機(jī)只需忽略接收到的字節(jié);反之,若主機(jī)要讀取從機(jī)的一個(gè)字節(jié),就必須發(fā)送一個(gè)空字節(jié)來引發(fā)從機(jī)的傳輸。

c7eb934a-d3f7-11ec-bce3-dac502259ad0.gifc826bc4a-d3f7-11ec-bce3-dac502259ad0.gifc846a6f4-d3f7-11ec-bce3-dac502259ad0.gif

雖然 SPI 四線制支持讀寫同時(shí)進(jìn)行,但實(shí)際上我們很多時(shí)候并不需要又讀又寫,見以下兩種情況(參考 BMA223 數(shù)據(jù)手冊):

注意:如下三幅圖示均為 CPOL=1,CPHA=1

1、主機(jī)向從機(jī)寫數(shù)據(jù)

c867a4a8-d3f7-11ec-bce3-dac502259ad0.png

主機(jī)發(fā)送先發(fā)送 8 bits,第一個(gè) bit 為 0 代表這次主機(jī)是想寫數(shù)據(jù)到從機(jī),AD6~AD0 表示要寫的寄存器地址。然后,主機(jī)就會一直寫下去。在這期間 SDO 一直沒用,一直是高阻態(tài),算是一直讀到1。

2、主機(jī)從從機(jī)讀數(shù)據(jù)

c8824ef2-d3f7-11ec-bce3-dac502259ad0.png

這種情況下,主機(jī)先發(fā)送 8 bits,第一位為 1 代表這次是讀,然后 AD6 ~ AD0 是想要讀的寄存器地址,然后 SDO 開始返回?cái)?shù)據(jù)。

4、SPI timing diagram

c8a207d8-d3f7-11ec-bce3-dac502259ad0.png
Tcsb_setup:建立時(shí)間
Tcsb_hold:保持時(shí)間
tsckl:低電平時(shí)間
tsckh:高電平時(shí)間
SCK period :Tsckl + tsckh
一般情況下Tsckl=tsckh

注意:真實(shí)的波形圖如上,高低電平并不是到達(dá)最高點(diǎn)才算,0.3Vdd 以下為低電平,0.7Vdd 以上為高電平,計(jì)算信號時(shí)間長度的時(shí)候需要注意這個(gè)微小的時(shí)間,硬件設(shè)計(jì)必須注意信號質(zhì)量風(fēng)險(xiǎn),軟件開發(fā)人員也要會看波形圖。

這里的參數(shù),一般 spi 驅(qū)動不需要設(shè)置,但是半導(dǎo)體廠商提供的 spi 控制器驅(qū)動中,可以修改這些參數(shù)。我們寫 SPI 驅(qū)動時(shí)候,可以根據(jù)從設(shè)備的要求來修改這些參數(shù)

5、DMA 與 FIFO

不同平臺對于 SPI FIFO 和 DMA 的 buffer size 設(shè)置不同:

c8bc0e8a-d3f7-11ec-bce3-dac502259ad0.png

傳輸 32bytes 以下使用 FIFO,傳輸 32bytes 以上使用 DMA。

DMA 可以自動發(fā)起多次傳輸,一次最大 256K 。

6、I2C 與 SPI 對比

功能 I2C SPI
線數(shù) 2(SDA,SCL) 4(MOSI,MISO,SCLK,CS)
主機(jī)數(shù)量 >=1 ==1
類型 半雙工 全雙工
回應(yīng)機(jī)制 yes no
速度 <=3.4Mbps high
應(yīng)用 重要數(shù)據(jù) 大量數(shù)據(jù)
流控 yes no
設(shè)備地址 yes no
常規(guī)用途 命令 數(shù)據(jù)

I2C 和 SPI 的速率如下:

I2C模式 速度
標(biāo)準(zhǔn) 100KHz
快速 400KHz
快速+ 1MHz
高速 3.4MHz

SPI 速率:幾十 MHz 甚至上百 MHz,速度取決于 CPU 的 SPI 控制器和時(shí)鐘 clock

STM32F103 的 SPI 最高支持 18MHz,imx6ull 的 SPI 最高支持 52MHz,其他芯片一般用不到更高的,因?yàn)樗俣仍娇觳ㄐ钨|(zhì)量越不好,越容易出問題。

具體采用多大速率還和外設(shè)有關(guān),比如 EEPROM 的 W25Q128 的 SPI 最高支持 80MHz,ICM20608 傳感器的 SPI 最高支持8MHz。一般用在 flash 上的速度會較快。

7、擴(kuò)展

SPI 協(xié)議其實(shí)是包括:Standard SPI、Dual SPI 和 Queued SPI 三種協(xié)議接口。

Dual SPI 還是四線制,只是傳輸線可以變?yōu)橥较颍俣仁?Standard SPI 的兩倍。

Queued SPI 是六線制,多了兩根數(shù)據(jù)線,傳輸速度是 Standard SPI 的四倍。

SPILinux驅(qū)動

1、SPI 驅(qū)動源文件目錄

Linux common spi driver

kernel-4.14/drivers/spi/spi.cLinux提供的通用接口封裝層驅(qū)動
kernel-4.14/drivers/spi/spidev.clinux提供的SPI通用設(shè)備驅(qū)動程序
kernel-4.14/include/linux/spi/spi.hlinux提供的包含SPI的主要數(shù)據(jù)結(jié)構(gòu)和函數(shù)

spi 控制器驅(qū)動,IC 廠商提供,不同廠商命名不同

kernel-4.14/drivers/spi/spi-mt65xx.cMTKSPI控制器驅(qū)動
kernel-4.14/drivers/spi/spi-mt65xx-dev.c
kernel-4.14/include/linux/platform_data/spi-mt65xx.h

dts

kernel-4.14/arch/arm/boot/dts/...
kernel-4.14/arch/arm64/boot/dts/...

以上文件對應(yīng)如下 SPI 驅(qū)動軟件架構(gòu):

c911c0d2-d3f7-11ec-bce3-dac502259ad0.png
SPI 控制器驅(qū)動程序

SPI 控制器不用關(guān)心設(shè)備的具體功能,它只負(fù)責(zé)把上層協(xié)議驅(qū)動準(zhǔn)備好的數(shù)據(jù)按 SPI 總線的時(shí)序要求發(fā)送給 SPI 設(shè)備,同時(shí)把從設(shè)備收到的數(shù)據(jù)返回給上層的協(xié)議驅(qū)動,因此,內(nèi)核把 SPI 控制器的驅(qū)動程序獨(dú)立出來。

SPI 控制器驅(qū)動負(fù)責(zé)控制具體的控制器硬件,諸如 DMA 和中斷操作等等,因?yàn)槎鄠€(gè)上層的協(xié)議驅(qū)動可能會通過控制器請求數(shù)據(jù)傳輸操作,所以,SPI 控制器驅(qū)動同時(shí)也要負(fù)責(zé)對這些請求進(jìn)行隊(duì)列管理,保證先進(jìn)先出的原則。

SPI 通用接口封裝層

為了簡化 SPI 驅(qū)動程序的編程工作,同時(shí)也為了降低【協(xié)議驅(qū)動程序】和【控制器驅(qū)動程序】的耦合程度,內(nèi)核把控制器驅(qū)動和協(xié)議驅(qū)動的一些通用操作封裝成標(biāo)準(zhǔn)的接口,加上一些通用的邏輯處理操作,組成了 SPI 通用接口封裝層。

這樣的好處是,對于控制器驅(qū)動程序,只要實(shí)現(xiàn)標(biāo)準(zhǔn)的接口回調(diào) API,并把它注冊到通用接口層即可,無需直接和協(xié)議層驅(qū)動程序進(jìn)行交互。而對于協(xié)議層驅(qū)動來說,只需通過通用接口層提供的 API 即可完成設(shè)備和驅(qū)動的注冊,并通過通用接口層的 API 完成數(shù)據(jù)的傳輸,無需關(guān)注 SPI 控制器驅(qū)動的實(shí)現(xiàn)細(xì)節(jié)。

SPI 協(xié)議驅(qū)動程序

SPI 設(shè)備的具體功能是由 SPI 協(xié)議驅(qū)動程序完成的,SPI 協(xié)議驅(qū)動程序了解設(shè)備的功能和通信數(shù)據(jù)的協(xié)議格式。向下,協(xié)議驅(qū)動通過通用接口層和控制器交換數(shù)據(jù),向上,協(xié)議驅(qū)動通常會根據(jù)設(shè)備具體的功能和內(nèi)核的其它子系統(tǒng)進(jìn)行交互。

例如,和 MTD 層交互以便把 SPI 接口的存儲設(shè)備實(shí)現(xiàn)為某個(gè)文件系統(tǒng),和 TTY 子系統(tǒng)交互把 SPI 設(shè)備實(shí)現(xiàn)為一個(gè) TTY 設(shè)備,和網(wǎng)絡(luò)子系統(tǒng)交互以便把一個(gè) SPI 設(shè)備實(shí)現(xiàn)為一個(gè)網(wǎng)絡(luò)設(shè)備。如果是一個(gè)專有的 SPI 設(shè)備,我們也可以按設(shè)備的協(xié)議要求,實(shí)現(xiàn)自己的專有協(xié)議驅(qū)動。

SPI 通用設(shè)備驅(qū)動程序

考慮到連接在 SPI 控制器上的設(shè)備的可變性,在內(nèi)核沒有配備相應(yīng)的協(xié)議驅(qū)動程序,對于這種情況,內(nèi)核為我們準(zhǔn)備了通用的 SPI 設(shè)備驅(qū)動程序,該通用設(shè)備驅(qū)動程序向用戶空間提供了控制 SPI 控制的控制接口,具體的協(xié)議控制和數(shù)據(jù)傳輸工作交由用戶空間根據(jù)具體的設(shè)備來完成,在這種方式中,只能采用同步的方式和 SPI 設(shè)備進(jìn)行通信,所以通常用于一些數(shù)據(jù)量較少的簡單 SPI 設(shè)備。

2、SPI 通用接口層

  1. SPI 通用接口層把具體的 SPI 設(shè)備的協(xié)議驅(qū)動和 SPI 控制器驅(qū)動連接在一起。
  2. 負(fù)責(zé) SPI 系統(tǒng)與 Linux 設(shè)備模型相關(guān)的初始化工作。
  3. 為協(xié)議驅(qū)動和控制器驅(qū)動提供一系列的標(biāo)準(zhǔn)接口 API 及其數(shù)據(jù)結(jié)構(gòu)。
  4. SPI 設(shè)備、SPI 協(xié)議驅(qū)動、SPI 控制器的數(shù)據(jù)抽象
  5. 協(xié)助數(shù)據(jù)傳輸而定義的數(shù)據(jù)結(jié)構(gòu)

kernel-4.14/drivers/spi/spi.c

staticint__initspi_init(void)
{
intstatus;

buf=kmalloc(SPI_BUFSIZ,GFP_KERNEL);
if(!buf){
status=-ENOMEM;
gotoerr0;
}

//創(chuàng)建/sys/bus/spi節(jié)點(diǎn)
status=bus_register(&spi_bus_type);
if(status0)
gotoerr1;

//創(chuàng)建/sys/class/spi_master節(jié)點(diǎn)
status=class_register(&spi_master_class);
if(status0)
gotoerr2;

if(IS_ENABLED(CONFIG_SPI_SLAVE)){
status=class_register(&spi_slave_class);
if(status0)
gotoerr3;
}
......
}

在這里創(chuàng)建了 SPI 總線,創(chuàng)建 /sys/bus/spi 節(jié)點(diǎn)和 /sys/class/spi_master 節(jié)點(diǎn)。

重要數(shù)據(jù)結(jié)構(gòu):

spi_device
spi_driver
spi_board_info
spi_controller/spi_master
spi_transfer
spi_message

重要 API

spi_message_init
spi_message_add_tail
spi_sync
spi_async
spi_write
spi_read

接下來詳細(xì)解析結(jié)構(gòu)體和API,只講解重點(diǎn)部分,完整解析請參考官方文檔

https://www.kernel.org/doc/html/v4.14//driver-api/spi.html

只有熟悉每個(gè)結(jié)構(gòu)體存儲的是什么東西,才能真正搞懂 SPI 模塊。

spi_master/spi_controller:描述一個(gè) spi 主機(jī)設(shè)備

structspi_master{
//Linux驅(qū)動模型中的設(shè)備
structdevicedev;

//此spi_master設(shè)備在全局spi_master鏈表中的節(jié)點(diǎn)
structlist_headlist;

//此spi_master編號
s16bus_num;

//此spi_master支持的片選信號數(shù)量
u16num_chipselect;

//dma地址對齊
u16dma_alignment;

//此spi_master支持傳輸?shù)膍ode
u16mode_bits;
u32bits_per_word_mask;
/*limitsontransferspeed*/
u32min_speed_hz;
u32max_speed_hz;

/*otherconstraintsrelevanttothisdriver*/
u16flags;

/*lockandmutexforSPIbuslocking*/
spinlock_tbus_lock_spinlock;//總線自旋鎖
structmutexbus_lock_mutex;//總線互斥鎖

//總線是否處于lock狀態(tài)
boolbus_lock_flag;

//準(zhǔn)備傳輸,設(shè)置傳輸?shù)膮?shù)
int(*setup)(structspi_device*spi);

//傳輸數(shù)據(jù)
int(*transfer)(structspi_device*spi,
structspi_message*mesg);
//設(shè)備release時(shí)的清除工作
void(*cleanup)(structspi_device*spi);

bool(*can_dma)(structspi_master*master,
structspi_device*spi,
structspi_transfer*xfer);

boolqueued;//是否采用系統(tǒng)的序列化傳輸
structkthread_workerkworker;//序列化傳輸時(shí)的線程worker
structtask_struct*kworker_task;//序列化傳輸?shù)木€程
structkthread_workpump_messages;//序列化傳輸時(shí)的處理函數(shù)
spinlock_tqueue_lock;//序列化傳輸時(shí)的queue_lock
structlist_headqueue;//序列化傳輸時(shí)的msg隊(duì)列頭
structspi_message*cur_msg;//序列化傳輸時(shí)當(dāng)前的msg
boolidling;
boolbusy;//序列化傳輸時(shí)線程是否處于busy狀態(tài)
boolrunning;//序列化傳輸時(shí)線程是否在運(yùn)行
boolrt;//是否實(shí)時(shí)傳輸
......

int(*prepare_transfer_hardware)(structspi_master*master);

//一個(gè)msg的傳輸實(shí)現(xiàn)
int(*transfer_one_message)(structspi_master*master,
structspi_message*mesg);
......

/*gpiochipselect*/
int*cs_gpios;
......
};

spi_device:描述一個(gè) spi 從機(jī)設(shè)備

structspi_device{
//Linux驅(qū)動模型中的設(shè)備
structdevicedev;
structspi_master*master;//設(shè)備所連接的spi主機(jī)設(shè)備
u32max_speed_hz;//該設(shè)備最大傳輸速率
u8chip_select;//CS片選信號編號
u8bits_per_word;//每次傳輸長度
u16mode;//傳輸模式
......
intirq;//軟件中斷號
void*controller_state;//控制器狀態(tài)
void*controller_data;//控制參數(shù)
charmodalias[SPI_NAME_SIZE];//設(shè)備名稱
//CS片選信號對應(yīng)的GPIOnumber
intcs_gpio;/*chipselectgpio*/

/*thestatistics*/
structspi_statisticsstatistics;
};

spi_driver:描述一個(gè) spi 設(shè)備驅(qū)動

structspi_driver{
//此driver所支持的spi設(shè)備list
conststructspi_device_id*id_table;
int(*probe)(structspi_device*spi);
int(*remove)(structspi_device*spi);
//系統(tǒng)shutdown時(shí)的回調(diào)函數(shù)
void(*shutdown)(structspi_device*spi);
structdevice_driverdriver;
};

spi_board_info:描述一個(gè) spi 從機(jī)設(shè)備板級信息,無設(shè)備樹時(shí)使用

structspi_board_info{
//設(shè)備名稱
charmodalias[SPI_NAME_SIZE];
constvoid*platform_data;//設(shè)備的平臺數(shù)據(jù)
void*controller_data;//設(shè)備的控制器數(shù)據(jù)
intirq;//設(shè)備的中斷號
u32max_speed_hz;//設(shè)備支持的最大速率
u16bus_num;//設(shè)備連接的spi總線編號
u16chip_select;//設(shè)備連接的CS信號編號
u16mode;//設(shè)備使用的傳輸mode
};

spi_transfer:描述 spi 傳輸?shù)木唧w數(shù)據(jù)

structspi_transfer{

constvoid*tx_buf;//spi_transfer的發(fā)送buf
void*rx_buf;//spi_transfer的接收buf
unsignedlen;//spi_transfer發(fā)送和接收的長度

dma_addr_ttx_dma;//tx_buf對應(yīng)的dma地址
dma_addr_trx_dma;//rx_buf對應(yīng)的dma地址
structsg_tabletx_sg;
structsg_tablerx_sg;

//spi_transfer傳輸完成后是否要改變CS片選信號
unsignedcs_change:1;
unsignedtx_nbits:3;
unsignedrx_nbits:3;
......
u8bits_per_word;//spi_transfer中一個(gè)word占的bits
u16delay_usecs;//兩個(gè)spi_transfer直接的等待延遲
u32speed_hz;//spi_transfer的傳輸速率

structlist_headtransfer_list;//spi_transfer掛載到的message節(jié)點(diǎn)
};

spi_message:描述一次 spi 傳輸?shù)男畔?/p>

structspi_message{
//掛載在此msg上的transfer鏈表頭
structlist_headtransfers;
//此msg需要通信的spi從機(jī)設(shè)備
structspi_device*spi;
//所使用的地址是否是dma地址
unsignedis_dma_mapped:1;

//msg發(fā)送完成后的處理函數(shù)
void(*complete)(void*context);
void*context;//complete函數(shù)的參數(shù)
unsignedframe_length;
unsignedactual_length;//此msg實(shí)際成功發(fā)送的字節(jié)數(shù)
intstatus;//此 msg 的發(fā)送狀態(tài),0:成功,負(fù)數(shù),失敗

structlist_headqueue;//此msg在所有msg中的鏈表節(jié)點(diǎn)
void*state;//此msg的私有數(shù)據(jù)
};

隊(duì)列化

SPI 數(shù)據(jù)傳輸可以有兩種方式:同步方式和異步方式

同步方式:數(shù)據(jù)傳輸?shù)陌l(fā)起者必須等待本次傳輸?shù)慕Y(jié)束,期間不能做其它事情,用代碼來解釋就是,調(diào)用傳輸?shù)暮瘮?shù)后,直到數(shù)據(jù)傳輸完成,函數(shù)才會返回。

異步方式:數(shù)據(jù)傳輸?shù)陌l(fā)起者無需等待傳輸?shù)慕Y(jié)束,數(shù)據(jù)傳輸期間還可以做其它事情,用代碼來解釋就是,調(diào)用傳輸?shù)暮瘮?shù)后,函數(shù)會立刻返回而不用等待數(shù)據(jù)傳輸完成,我們只需設(shè)置一個(gè)回調(diào)函數(shù),傳輸完成后,該回調(diào)函數(shù)會被調(diào)用以通知發(fā)起者數(shù)據(jù)傳送已經(jīng)完成。

同步方式簡單易用,很適合處理那些少量數(shù)據(jù)的單次傳輸。但是對于數(shù)據(jù)量大、次數(shù)多的傳輸來說,異步方式就顯得更加合適。

對于 SPI 控制器來說,要支持異步方式必須要考慮以下兩種狀況:

  1. 對于同一個(gè)數(shù)據(jù)傳輸?shù)陌l(fā)起者,既然異步方式無需等待數(shù)據(jù)傳輸完成即可返回,返回后,該發(fā)起者可以立刻又發(fā)起一個(gè) message,而這時(shí)上一個(gè)message還沒有處理完。
  2. 對于另外一個(gè)不同的發(fā)起者來說,也有可能同時(shí)發(fā)起一次message傳輸請求。

隊(duì)列化正是為了為了解決以上的問題,所謂隊(duì)列化,是指把等待傳輸?shù)?message 放入一個(gè)等待隊(duì)列中,發(fā)起一個(gè)傳輸操作,其實(shí)就是把對應(yīng)的 message 按先后順序放入一個(gè)等待隊(duì)列中,系統(tǒng)會在不斷檢測隊(duì)列中是否有等待傳輸?shù)?message,如果有就不停地調(diào)度數(shù)據(jù)傳輸內(nèi)核線程,逐個(gè)取出隊(duì)列中的 message 進(jìn)行處理,直到隊(duì)列變空為止。SPI 通用接口層為我們實(shí)現(xiàn)了隊(duì)列化的基本框架。

c934340a-d3f7-11ec-bce3-dac502259ad0.png

spi_message 就是一次 SPI 數(shù)據(jù)交換的原子操作,不可打斷。

3、SPI 控制器驅(qū)動層

SPI 控制器驅(qū)動層負(fù)責(zé)最底層的數(shù)據(jù)收發(fā),主要有以下功能:

  1. 申請必要的硬件資源,比如中斷、DMA 通道、DMA 內(nèi)存緩沖區(qū)等等
  2. 配置 SPI 控制器的工作模式和參數(shù),使之可以和相應(yīng)的設(shè)備進(jìn)行正確的數(shù)據(jù)交換
  3. 向通用接口層提供接口,使得上層的協(xié)議驅(qū)動可以通過通用接口層訪問控制器驅(qū)動
  4. 配合通用接口層,完成數(shù)據(jù)消息隊(duì)列的排隊(duì)和處理,直到消息隊(duì)列變空為止

SPI 主機(jī)驅(qū)動就是 SOC 的 SPI 控制器驅(qū)動。Linux 內(nèi)核使用 spi_master/spi_controller 表示 SPI 主機(jī)驅(qū)動,spi_master 是個(gè)結(jié)構(gòu)體,定義在 include/linux/spi/spi.h 文件中。

SPI 主機(jī)驅(qū)動的核心就是申請 spi_master,然后初始化 spi_master,最后向 Linux 內(nèi)核注冊 spi_master。

API 如下:

spi_alloc_master 函數(shù):申請 spi_master。
spi_master_put 函數(shù):釋放 spi_master。

spi_register_master函數(shù):注冊 spi_master。
spi_unregister_master 函數(shù):注銷 spi_master。

spi_bitbang_start函數(shù):注冊 spi_master。
spi_bitbang_stop 函數(shù):注銷 spi_master。

SPI 主機(jī)驅(qū)動的加載

以 MTK 為例,源碼來自于小米開源項(xiàng)目

https://github.com/MiCode/Xiaomi_Kernel_OpenSource

小米每做一個(gè)項(xiàng)目,都會把 kernel 部分開源,因?yàn)樾枰裱?Linux GPL 開源協(xié)議。

【設(shè)備】聲明在設(shè)備樹中

kernel-4.14/arch/arm64/boot/dts/mediatek/mt6885.dts
c9657024-d3f7-11ec-bce3-dac502259ad0.png

【驅(qū)動】

kernel-4.14/drivers/spi/spi-mt65xx.c

c97a6ea2-d3f7-11ec-bce3-dac502259ad0.pngc9a77c3a-d3f7-11ec-bce3-dac502259ad0.png

匹配以后,probe 函數(shù)執(zhí)行,申請 spi_master,初始化 spi_master,最后向 Linux 內(nèi)核注冊 spi_master。

c9c3b3f0-d3f7-11ec-bce3-dac502259ad0.pngca1e7c68-d3f7-11ec-bce3-dac502259ad0.png

4、軟件流程

ca391b9a-d3f7-11ec-bce3-dac502259ad0.png

看懂該圖,對 SPI 驅(qū)動框架就有完整的了解了。

1、2、3 按順執(zhí)行,首先有 spi 總線的注冊,然后是 spi 控制器驅(qū)動加載,然后是設(shè)備驅(qū)動加載。

區(qū)別在于,spi 控制器驅(qū)動加載時(shí),是靠 platform 總線匹配設(shè)備(控制器)與驅(qū)動。spi 設(shè)備驅(qū)動加載時(shí),是靠 spi 總線匹配設(shè)備(外設(shè)IC)與驅(qū)動。

init flow

ca6d8b28-d3f7-11ec-bce3-dac502259ad0.png

spi_register_master 的調(diào)用序列圖

ca83c424-d3f7-11ec-bce3-dac502259ad0.png

隊(duì)列化的工作機(jī)制及過程

cae4f5c8-d3f7-11ec-bce3-dac502259ad0.pngcb03331c-d3f7-11ec-bce3-dac502259ad0.png

當(dāng)協(xié)議驅(qū)動程序通過 spi_async 發(fā)起一個(gè) message 請求時(shí),隊(duì)列化和工作線程被激活,觸發(fā)一些列的操作,最終完成 message 的傳輸操作。

spi_sync 與 spi_async 類似,只是有一個(gè)等待過程。

5、SPI 設(shè)備驅(qū)動

【設(shè)備】聲明在設(shè)備樹中

cb42e03e-d3f7-11ec-bce3-dac502259ad0.pngcb55e15c-d3f7-11ec-bce3-dac502259ad0.png

注意:設(shè)備的聲明,slave device node 應(yīng)該包含在你所要掛載的 &spi node 下,將 device 綁定在 master 上。然后通過 pinctrl 方式指定 GPIO,并在驅(qū)動中操作 pinctrl 句柄。

【驅(qū)動】demo

Linux 內(nèi)核使用 spi_driver 結(jié)構(gòu)體來表示 spi 設(shè)備驅(qū)動,我們在編寫 SPI 設(shè)備驅(qū)動的時(shí)候需要實(shí)現(xiàn) spi_driver。spi_driver 結(jié)構(gòu)體定義在 include/linux/spi/spi.h 文件中。

spi_register_driver:注冊 spi_driver
spi_unregister_driver:銷掉 spi_driver
/*probe函數(shù)*/
staticintxxx_probe(structspi_device*spi)
{

/*具體函數(shù)內(nèi)容*/
return0;
}

/*remove函數(shù)*/
staticintxxx_remove(structspi_device*spi)
{

/*具體函數(shù)內(nèi)容*/
return0;
}

/*傳統(tǒng)匹配方式ID列表*/
staticconststructspi_device_idxxx_id[]={

{"xxx",0},
{}
};

/*設(shè)備樹匹配列表*/
staticconststructof_device_idxxx_of_match[]={

{.compatible="xxx"},
{/*Sentinel*/}
};

/*SPI驅(qū)動結(jié)構(gòu)體*/
staticstructspi_driverxxx_driver={

.probe=xxx_probe,
.remove=xxx_remove,
.driver={
.owner=THIS_MODULE,
.name="xxx",
.of_match_table=xxx_of_match,
},
.id_table=xxx_id,
};

/*驅(qū)動入口函數(shù)*/
staticint__initxxx_init(void)
{

returnspi_register_driver(&xxx_driver);
}

/*驅(qū)動出口函數(shù)*/
staticvoid__exitxxx_exit(void)
{

spi_unregister_driver(&xxx_driver);
}

module_init(xxx_init);
module_exit(xxx_exit);

在驅(qū)動入口函數(shù)中調(diào)用 spi_register_driver 來注冊 spi_driver。

在驅(qū)動出口函數(shù)中調(diào)用 spi_unregister_driver 來注銷 spi_driver。

spi 讀寫數(shù)據(jù)demo

/*SPI多字節(jié)發(fā)送*/
staticintspi_send(structspi_device*spi,u8*buf,intlen)
{
intret;
structspi_messagem;

structspi_transfert={
.tx_buf=buf,
.len=len,
};

spi_message_init(&m);/*初始化spi_message*/
spi_message_add_tail(t,&m);/*將spi_transfer添加到spi_message隊(duì)列*/
ret=spi_sync(spi,&m);/*同步傳輸*/
returnret;
}
/*SPI多字節(jié)接收*/
staticintspi_receive(structspi_device*spi,u8*buf,intlen)
{
intret;
structspi_messagem;

structspi_transfert={
.rx_buf=buf,
.len=len,
};

spi_message_init(&m);/*初始化spi_message*/
spi_message_add_tail(t,&m);/*將spi_transfer添加到spi_message隊(duì)列*/
ret=spi_sync(spi,&m);/*同步傳輸*/
returnret;
}

除了 init、exit、probe、remove、read、write 函數(shù)外,其他的函數(shù)看需求實(shí)現(xiàn),這幾個(gè)是最基本的。

6、總結(jié)

Linux 是 總線、設(shè)備、驅(qū)動 的框架,理解了這個(gè)框架,就能理解所有的模塊驅(qū)動框架。

SPI 驅(qū)動比 I2C 驅(qū)動還是簡單很多的。

end

原文標(biāo)題:SPI 硬件+Linux驅(qū)動詳解

文章出處:【微信公眾號:一口Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11345

    瀏覽量

    210389
  • SPI硬件
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    823
  • 傳輸機(jī)制
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    1171

原文標(biāo)題:SPI 硬件+Linux驅(qū)動詳解

文章出處:【微信號:yikoulinux,微信公眾號:一口Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    C語言基礎(chǔ)知識科普

    C語言是單片機(jī)開發(fā)中的必備基礎(chǔ)知識,本文列舉了部分STM32學(xué)習(xí)中比較常見的一些C語言基礎(chǔ)知識
    發(fā)表于 07-21 10:58 ?1931次閱讀

    科普一下CAN總線的基礎(chǔ)知識

    CAN總線是一種常用的總線,對于剛開始接觸CAN總線的,面對著各式各樣的資料,可能不知道從何看起,今天科普一下CAN總線的基礎(chǔ)知識。CAN2.0協(xié)議分為A版本和B版本,A版本協(xié)議為11位標(biāo)識符(標(biāo)準(zhǔn)幀),B版本在兼容11位ID標(biāo)識符的同時(shí),向上擴(kuò)展到29位ID標(biāo)識符。
    發(fā)表于 05-16 09:49 ?3388次閱讀
    <b class='flag-5'>科普</b>一下CAN總線的<b class='flag-5'>基礎(chǔ)知識</b>

    手機(jī)硬件設(shè)計(jì)基礎(chǔ)知識

    從別處得來的,基礎(chǔ)知識講解,純分享{:4_95:}
    發(fā)表于 01-17 15:38

    硬件設(shè)計(jì)基礎(chǔ)知識

    硬件設(shè)計(jì)基礎(chǔ)知識
    發(fā)表于 02-25 21:28

    ecs700硬件基礎(chǔ)知識

    ecs700硬件基礎(chǔ)知識,目錄1、電磁干擾1、電磁干擾
    發(fā)表于 07-14 06:35

    示波器基礎(chǔ)知識

    第1章 示波器基礎(chǔ)知識本章的內(nèi)容整理自網(wǎng)絡(luò),主要講解示波器的基礎(chǔ)知識。如果初學(xué)的話非常有必要對這部分知識有一個(gè)了解。因?yàn)槭静ㄆ魇?b class='flag-5'>硬件調(diào)試必不可少的設(shè)備。1.1 什么是示波器1.2 示波
    發(fā)表于 08-09 07:21

    五分鐘讀懂WiFi基礎(chǔ)知識

    家1、嵌入式技術(shù)常識科普【物聯(lián)網(wǎng)】WiFi基礎(chǔ)知識五分鐘讀懂TCP/IP;協(xié)議STM32開發(fā) -- Keil基本使用如何看懂時(shí)序圖(以SPI/I2C為例)ESP8266配網(wǎng)思路(不使用...
    發(fā)表于 12-01 06:36

    SPI通信協(xié)議的基礎(chǔ)知識解析

    SPI通信協(xié)議詳解寫在最前: 本文講述了SPI通信協(xié)議的基本內(nèi)容包括如下SPI基礎(chǔ)知識SPI的讀寫時(shí)序本文重點(diǎn)參考 英文維基百科 中文維基
    發(fā)表于 12-13 08:05

    記錄一下SPI基礎(chǔ)知識與軟件開發(fā)環(huán)境

    的,畢竟速率夠高,數(shù)據(jù)量能傳的比較大。1. 準(zhǔn)備1.1 SPI基礎(chǔ)知識1.2 開發(fā)環(huán)境1.2.1 軟件開發(fā)環(huán)境1.2.2 硬件環(huán)境SPI2. Demo...
    發(fā)表于 02-17 06:29

    科普】卷積神經(jīng)網(wǎng)絡(luò)基礎(chǔ)知識

    本文的主要目的,是簡單介紹時(shí)下流行的深度學(xué)習(xí)算法的基礎(chǔ)知識,本人也看過許多其他教程,感覺其中大部分講的還是太過深奧,于是便有了寫一篇科普文的想法。博主也是現(xiàn)學(xué)現(xiàn)賣,文中如有不當(dāng)之處,請各位指出
    發(fā)表于 11-10 14:49 ?1761次閱讀
    【<b class='flag-5'>科普</b>】卷積神經(jīng)網(wǎng)絡(luò)<b class='flag-5'>基礎(chǔ)知識</b>

    電源管理基礎(chǔ)知識電源管理基礎(chǔ)知識電源管理基礎(chǔ)知識

    電源管理基礎(chǔ)知識電源管理基礎(chǔ)知識電源管理基礎(chǔ)知識
    發(fā)表于 09-15 14:36 ?76次下載
    電源管理<b class='flag-5'>基礎(chǔ)知識</b>電源管理<b class='flag-5'>基礎(chǔ)知識</b>電源管理<b class='flag-5'>基礎(chǔ)知識</b>

    硬件工程師必備要了解哪些基礎(chǔ)知識

    硬件工程師必備基礎(chǔ)知識 目的:基于實(shí)際經(jīng)驗(yàn)與實(shí)際項(xiàng)目詳細(xì)理解并掌握成為合格的硬件工程師的最基本知識
    發(fā)表于 10-30 08:00 ?0次下載

    單片機(jī)基礎(chǔ)知識學(xué)習(xí)筆記

    單片機(jī)基礎(chǔ)知識學(xué)習(xí)筆記有關(guān)總線1.IIC總線2.SPI總線
    發(fā)表于 11-14 16:51 ?26次下載
    單片機(jī)<b class='flag-5'>基礎(chǔ)知識</b>學(xué)習(xí)筆記

    SPI協(xié)議基礎(chǔ)知識

    電子發(fā)燒友網(wǎng)站提供《SPI協(xié)議基礎(chǔ)知識.pdf》資料免費(fèi)下載
    發(fā)表于 11-16 10:32 ?1次下載
    <b class='flag-5'>SPI</b>協(xié)議<b class='flag-5'>基礎(chǔ)知識</b>

    硬件工程師需要掌握的硬件基礎(chǔ)知識

    作為一個(gè)資深硬件工程師,我們需要掌握一些硬件基礎(chǔ)知識,今天總結(jié)一下哪些算是基礎(chǔ)知識。給學(xué)電子方面想從事硬件工作的同學(xué)們一點(diǎn)提示。給未走出大學(xué)
    的頭像 發(fā)表于 12-02 09:22 ?536次閱讀
    <b class='flag-5'>硬件</b>工程師需要掌握的<b class='flag-5'>硬件</b><b class='flag-5'>基礎(chǔ)知識</b>
    百家乐投注哪个信誉好| 破解百家乐官网视频游戏密码| 百家乐官网投注办法| 娱乐城百家乐官网高手| 新澳门百家乐官网娱乐城| A8百家乐官网赌场娱乐网规则| 百家乐官网平台有什么优惠| 大佬百家乐官网娱乐城| 利记百家乐现金网| 大发888娱乐城 手机版| 皇冠网怎么注册| 澳门百家乐官网娱乐网| 三元风水24山水法| 多台百家乐的玩法技巧和规则 | 百家乐官网接线玩法| 百家乐官网桌手机套| 百家乐官网首选| 太阳城百家乐公司| 至棒娱乐备用| 博彩百家乐官网带连线走势图| 百家乐代理龙虎| 澳门百家乐论坛及玩法| 丰合国际网上娱乐| 百家乐官网伴侣破解版| 百家乐博彩策略| 盛世国际娱乐场| 志丹县| 周易24卦| 大发88817| 澳门百家乐官网新濠天地| 博网百家乐现金网| 皇冠足球比分网| 百家乐官网翻天粤语| 同花顺百家乐的玩法技巧和规则 | 霍城县| 百家乐有没有稳赢| 欧博线上娱乐| 百家乐攻略投注法| 明升备用| 百家乐二人视频麻将| 棋牌小游戏下载|