一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

完善資料讓更多小伙伴認識你,還能領(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 以主從方式工作,通常是有一個主設(shè)備和一個或多個從設(shè)備,無應(yīng)答機制。

本文我們講解標準的 4 線 SPI,四根線如下:

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

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

③、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 有四種工作模式,通過時鐘極性(CPOL)和時鐘相位(CPHA)的搭配來得到四種工作模式:

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

示例波形圖如下:

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

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

3、SPI 傳輸機制

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

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

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

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

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

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

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

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

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

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

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

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

4、SPI timing diagram

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

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

這里的參數(shù),一般 spi 驅(qū)動不需要設(shè)置,但是半導體廠商提供的 spi 控制器驅(qū)動中,可以修改這些參數(shù)。我們寫 SPI 驅(qū)動時候,可以根據(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)
主機數(shù)量 >=1 ==1
類型 半雙工 全雙工
回應(yīng)機制 yes no
速度 <=3.4Mbps high
應(yīng)用 重要數(shù)據(jù) 大量數(shù)據(jù)
流控 yes no
設(shè)備地址 yes no
常規(guī)用途 命令 數(shù)據(jù)

I2C 和 SPI 的速率如下:

I2C模式 速度
標準 100KHz
快速 400KHz
快速+ 1MHz
高速 3.4MHz

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

STM32F103 的 SPI 最高支持 18MHz,imx6ull 的 SPI 最高支持 52MHz,其他芯片一般用不到更高的,因為速度越快波形質(zhì)量越不好,越容易出問題。

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

7、擴展

SPI 協(xié)議其實是包括: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è)備的具體功能,它只負責把上層協(xié)議驅(qū)動準備好的數(shù)據(jù)按 SPI 總線的時序要求發(fā)送給 SPI 設(shè)備,同時把從設(shè)備收到的數(shù)據(jù)返回給上層的協(xié)議驅(qū)動,因此,內(nèi)核把 SPI 控制器的驅(qū)動程序獨立出來。

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

SPI 通用接口封裝層

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

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

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

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

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

2、SPI 通用接口層

  1. SPI 通用接口層把具體的 SPI 設(shè)備的協(xié)議驅(qū)動和 SPI 控制器驅(qū)動連接在一起。
  2. 負責 SPI 系統(tǒng)與 Linux 設(shè)備模型相關(guān)的初始化工作。
  3. 為協(xié)議驅(qū)動和控制器驅(qū)動提供一系列的標準接口 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é)點
status=bus_register(&spi_bus_type);
if(status0)
gotoerr1;

//創(chuàng)建/sys/class/spi_master節(jié)點
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é)點和 /sys/class/spi_master 節(jié)點。

重要數(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

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

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

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

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

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

//此spi_master設(shè)備在全局spi_master鏈表中的節(jié)點
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;

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

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

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

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

int(*prepare_transfer_hardware)(structspi_master*master);

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

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

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

structspi_device{
//Linux驅(qū)動模型中的設(shè)備
structdevicedev;
structspi_master*master;//設(shè)備所連接的spi主機設(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:描述一個 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時的回調(diào)函數(shù)
void(*shutdown)(structspi_device*spi);
structdevice_driverdriver;
};

spi_board_info:描述一個 spi 從機設(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中一個word占的bits
u16delay_usecs;//兩個spi_transfer直接的等待延遲
u32speed_hz;//spi_transfer的傳輸速率

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

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

structspi_message{
//掛載在此msg上的transfer鏈表頭
structlist_headtransfers;
//此msg需要通信的spi從機設(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實際成功發(fā)送的字節(jié)數(shù)
intstatus;//此 msg 的發(fā)送狀態(tài),0:成功,負數(shù),失敗

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

隊列化

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è)置一個回調(diào)函數(shù),傳輸完成后,該回調(diào)函數(shù)會被調(diào)用以通知發(fā)起者數(shù)據(jù)傳送已經(jīng)完成。

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

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

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

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

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

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

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

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

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

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

SPI 主機驅(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 主機驅(qū)動的加載

以 MTK 為例,源碼來自于小米開源項目

https://github.com/MiCode/Xiaomi_Kernel_OpenSource

小米每做一個項目,都會把 kernel 部分開源,因為需要遵循 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ū)動加載時,是靠 platform 總線匹配設(shè)備(控制器)與驅(qū)動。spi 設(shè)備驅(qū)動加載時,是靠 spi 總線匹配設(shè)備(外設(shè)IC)與驅(qū)動。

init flow

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

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

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

隊列化的工作機制及過程

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

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

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

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ū)動的時候需要實現(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隊列*/
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隊列*/
ret=spi_sync(spi,&m);/*同步傳輸*/
returnret;
}

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

6、總結(jié)

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

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

end

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

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

審核編輯:湯梓紅

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

    關(guān)注

    87

    文章

    11509

    瀏覽量

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

    關(guān)注

    0

    文章

    2

    瀏覽量

    885
  • 傳輸機制
    +關(guān)注

    關(guān)注

    0

    文章

    3

    瀏覽量

    1219

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

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

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

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

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

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

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

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

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

    硬件設(shè)計基礎(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ǔ)知識。如果初學的話非常有必要對這部分知識有一個了解。因為示波器是硬件調(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基本使用如何看懂時序圖(以SPI/I2C為例)ESP8266配網(wǎng)思路(不使用...
    發(fā)表于 12-01 06:36

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

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

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

    的,畢竟速率夠高,數(shù)據(jù)量能傳的比較大。1. 準備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ǔ)知識

    本文的主要目的,是簡單介紹時下流行的深度學習算法的基礎(chǔ)知識,本人也看過許多其他教程,感覺其中大部分講的還是太過深奧,于是便有了寫一篇科普文的想法。博主也是現(xiàn)學現(xiàn)賣,文中如有不當之處,請各位指出
    發(fā)表于 11-10 14:49 ?1875次閱讀
    【<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ǔ)知識 目的:基于實際經(jīng)驗與實際項目詳細理解并掌握成為合格的硬件工程師的最基本知識。
    發(fā)表于 10-30 08:00 ?0次下載

    單片機基礎(chǔ)知識學習筆記

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

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

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

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

    作為一個資深硬件工程師,我們需要掌握一些硬件基礎(chǔ)知識,今天總結(jié)一下哪些算是基礎(chǔ)知識。給學電子方面想從事硬件工作的同學們一點提示。給未走出大學
    的頭像 發(fā)表于 12-02 09:22 ?1745次閱讀
    <b class='flag-5'>硬件</b>工程師需要掌握的<b class='flag-5'>硬件</b><b class='flag-5'>基礎(chǔ)知識</b>