新聞中心
Linux設(shè)備樹是一種描述硬件設(shè)備拓?fù)浣Y(jié)構(gòu)、資源分配等信息的機(jī)制,它的出現(xiàn)為移植嵌入式系統(tǒng)帶來了很大的便利性,但也帶來了新的學(xué)習(xí)和應(yīng)用難度。SPI(Serial Peripheral Interface)總線是一種高速串行總線協(xié)議,常用于連接嵌入式系統(tǒng)中的外設(shè)。本文將從設(shè)備樹的角度出發(fā),詳細(xì)介紹如何在Linux內(nèi)核中配置和使用SPI總線設(shè)備驅(qū)動。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:國際域名空間、虛擬空間、營銷軟件、網(wǎng)站建設(shè)、新華網(wǎng)站維護(hù)、網(wǎng)站推廣。
一、設(shè)備樹中SPI總線設(shè)備的描述
設(shè)備樹是一棵樹形結(jié)構(gòu),每個節(jié)點(diǎn)對應(yīng)一個硬件設(shè)備或資源。下圖是一個簡單的設(shè)備樹結(jié)構(gòu)示例:
“`
/ {
spi@a0001000 {
compatible = “atmel,at91sam9263-spi”;
reg = ;
interrupt-parent = &pioA;
interrupts = ;
pinctrl-names = “default”;
pinctrl-0 = ;
};
};
“`
我們來逐個研究每個節(jié)點(diǎn)的含義和屬性:
1. 根節(jié)點(diǎn)“/”
在設(shè)備樹中,根節(jié)點(diǎn)表示整個硬件平臺。它常常是唯一的一個節(jié)點(diǎn),也可以有多個,比如多核處理器系統(tǒng)可以為每個核心生成一個根節(jié)點(diǎn)。根節(jié)點(diǎn)的屬性通常是平臺相關(guān)的,可以包括CPU類型、時鐘頻率、內(nèi)存布局等等。
2. SPI總線設(shè)備節(jié)點(diǎn)“spi@a0001000”
這是SPI設(shè)備的節(jié)點(diǎn)名,它由兩部分組成:“spi”表示節(jié)點(diǎn)類型,”a0001000”是設(shè)備的物理地址。SPI節(jié)點(diǎn)的屬性可以包括以下內(nèi)容:
* compatible:表示設(shè)備的兼容性信息,通常是一個字符串?dāng)?shù)組,字符串的格式由具體的硬件廠商或芯片開發(fā)者定義。
* reg:表示設(shè)備在總線上的地址范圍。
* interrupt-parent:表示IRQ控制器的父節(jié)點(diǎn),在AT91SAM9263芯片中使用的是PIOA。
* interrupts:表示設(shè)備的中斷號。
* pinctrl-names和pinctrl:表示設(shè)備的引腳控制信息,用于配置設(shè)備的引腳(IO口)。
3. 設(shè)備樹編譯
設(shè)備樹用源碼形式編寫,通常保存在.dts或.dtb文件中。為了將設(shè)備樹文件編譯成.dtb文件,要使用dtc工具。我們可以在Linux內(nèi)核源碼中找到dtc,并使用以下命令編譯設(shè)備樹:
“`
$ dtc -I dts -O dtb -o spi.dtb spi.dts
“`
其中-I參數(shù)指定輸入格式為dts,-O參數(shù)指定輸出格式為dtb。編譯成功后,將得到一個名為spi.dtb的設(shè)備樹二進(jìn)制文件。
二、設(shè)備驅(qū)動模型
Linux內(nèi)核的設(shè)備驅(qū)動模型通過一套抽象的結(jié)構(gòu)體和接口,將設(shè)備和驅(qū)動程序之間進(jìn)行解耦,以便更好地支持平臺移植和驅(qū)動模塊化。我們來看一下涉及到SPI總線設(shè)備驅(qū)動的關(guān)鍵結(jié)構(gòu)體和接口。
1. struct spi_master
該結(jié)構(gòu)體表示SPI總線控制器的主設(shè)備,它具有如下字段:
* bus_num:SPI總線控制器的編號,一般從0開始分配。
* max_speed_hz:該總線的更大總線速度,單位為Hz。
* mode_bits:該總線支持的SPI總線模式。
* chip_select:該總線所連接的芯片。
* num_chipselect:該總線支持的CS信號線數(shù)量。
* mode_bits:支持的SPI總線模式。
2. struct spi_device
該結(jié)構(gòu)體表示一個SPI設(shè)備,它具有如下字段:
* max_speed_hz:該設(shè)備的更大總線速度,單位為Hz。
* chip_select:設(shè)備所使用的芯片選擇線。
* mode:設(shè)備的SPI總線模式。
* bits_per_word:設(shè)備使用的每個字的位數(shù)。
* controller_data:和控制器相關(guān)的設(shè)備數(shù)據(jù)。
3. struct spi_board_info
該結(jié)構(gòu)體描述了一個SPI設(shè)備的常規(guī)屬性,用于創(chuàng)建一個spi_device結(jié)構(gòu)體。
* modalias:設(shè)備驅(qū)動名稱。
* max_speed_hz:更大總線速度。
* bus_num:控制器編號。
* chip_select:芯片選擇線編號。
* mode:SPI總線模式。
* platform_data:設(shè)備的平臺數(shù)據(jù)。
4. SPI傳輸函數(shù)
主要使用以下函數(shù)與SPI設(shè)備進(jìn)行數(shù)據(jù)傳輸:
* spi_setup:對SPI傳輸進(jìn)行一些基礎(chǔ)的設(shè)置,如極性、相位、總線速率等。
* spi_setup_transfer:配置傳輸參數(shù)(字長、模式、速度等)。
* spi_message_init:初始化SPI消息,用于將多個傳輸組織在一起。
* spi_sync:發(fā)送數(shù)據(jù)到SPI設(shè)備并等待回應(yīng)。
* spi_write_then_read:從設(shè)備中讀取和寫入數(shù)據(jù)。
* spi_write:寫入數(shù)據(jù)到設(shè)備。
以上函數(shù)的具體定義和使用方法詳見Linux內(nèi)核源碼和相關(guān)文檔。
三、SPI設(shè)備驅(qū)動的實(shí)現(xiàn)步驟
SPI設(shè)備驅(qū)動的實(shí)現(xiàn)步驟如下:
1. 注冊SPI主設(shè)備
SPI主設(shè)備的注冊可以在平臺設(shè)備的probe函數(shù)中執(zhí)行,可以使用spi_register_master函數(shù)進(jìn)行注冊。在注冊SPI主設(shè)備時,需要先通過platform_get_resource函數(shù)獲取到一個指向設(shè)備樹節(jié)點(diǎn)的指針,再從該指針中讀取設(shè)備節(jié)點(diǎn)的屬性。
“`
static int spi_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
struct device *dev = &pdev->dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, “spi”);
if (!res) {
dev_err(dev, “no memory resource specified\n”);
return -ENXIO;
}
master = spi_alloc_master(&pdev->dev, sizeof(struct sam_spi));
if (!master)
return -ENOMEM;
master->bus_num = pdev->id;
master->num_chipselect = SAM_CS_NUM;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->max_speed_hz = 24000000;
master->dev.of_node = dev->of_node;
platform_set_drvdata(pdev, master);
return spi_register_master(master);
}
“`
其中,spi_alloc_master函數(shù)用于創(chuàng)建一個新的SPI主設(shè)備,sizeof(struct sam_spi)表示設(shè)備私有數(shù)據(jù)結(jié)構(gòu)的大小。
2. 注冊SPI子設(shè)備
SPI子設(shè)備的注冊可以在平臺設(shè)備的probe函數(shù)中執(zhí)行。需要使用spi_new_device函數(shù)創(chuàng)建一個spi_device結(jié)構(gòu)體,并傳入spi_master指針、spi_board_info結(jié)構(gòu)體等參數(shù)。在注冊SPI子設(shè)備時,需要根據(jù)設(shè)備樹節(jié)點(diǎn)的屬性設(shè)置相應(yīng)的參數(shù)。
“`
static int spi_probe(struct platform_device *pdev)
{
……
for (i = 0; i
if (!board_info[i].modalias)
continue;
if (board_info[i].bus_num != pdev->id)
continue;
/* create a new slave device */
slave = spi_new_device(master, &board_info[i]);
if (!slave) {
dev_err(&master->dev, “can’t create SPI slave %d\n”, i);
continue;
}
priv = spi_master_get_devdata(master);
priv->devices[i] = slave;
}
……
return 0;
}
“`
spi_new_device函數(shù)將會自動設(shè)置spi_device的max_speed_hz、chip_select、mode、bits_per_word四個參數(shù)。其中max_speed_hz的值依據(jù)設(shè)備樹節(jié)點(diǎn)的某個屬性值自動設(shè)置的。
3. SPI傳輸
在驅(qū)動程序中使用SPI傳輸數(shù)據(jù)的例子:
“`
static int spi_xfer(struct spi_device *spi, struct spi_transfer *tfr)
{
int ret;
ret = spi_setup_transfer(spi, tfr);
if (ret)
return ret;
ret = spi_sync(spi, tfr);
if (ret)
return ret;
return 0;
}
“`
該函數(shù)將使用spi_setup_transfer函數(shù)以及spi_sync函數(shù)來實(shí)現(xiàn)SPI傳輸。spi_setup_transfer函數(shù)用于設(shè)置SPI傳輸?shù)哪J胶蜁r鐘速度等參數(shù);spi_sync函數(shù)用于發(fā)送SPI信號并等待響應(yīng)。在spi_transfer結(jié)構(gòu)體中,填充好了tx_buf和rx_buf兩個緩沖區(qū),它們分別存放待發(fā)送和接收的數(shù)據(jù)。spi_transfer結(jié)構(gòu)體中的屬性例如bit_per_word、speed_hz等,表示該傳輸?shù)奈粩?shù)和時鐘速度,之前已經(jīng)通過spi_new_device函數(shù)自動設(shè)置。
四、設(shè)備樹使用示例
設(shè)備樹的配置有很多種方式,下面給出一種情況下SPI設(shè)備樹的相關(guān)配置方式。
在設(shè)備樹文件中添加SPI節(jié)點(diǎn):
“`
spi@11007000 {
compatible = “atmel,sam9x60-spi”;
reg = ;
interrupts = ;
clocks = , ;
clock-names = “spi”, “peripheral_clk”;
pinctrl-names = “default”;
pinctrl-0 = ;
};
pinctrl_spi0_default: spi0-default {
atmel,pins = ;
atmel,groups = “spi0_grp”;
};
“`
其中spi節(jié)點(diǎn)描述如前面二節(jié)所述,pinctrl_spi0_default節(jié)點(diǎn)描述了該SPI總線的引腳控制信息。
用戶驅(qū)動程序代碼:
“`
static struct spi_board_info spidev_board_info[] = {
{
.modalias = “spidev”,
.max_speed_hz = 1000000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
},
};
static int __init spidev_init(void)
{
struct spi_master *master;
struct spi_device *spi;
master = spi_busnum_to_master(0);
if (!master) {
pr_err(“spi_busnum_to_master(%d) returned NULL\n”, 0);
return -ENODEV;
}
spi = spi_new_device(master, &spidev_board_info[0]);
if (!spi) {
pr_err(“spi_new_device fled\n”);
return -EBUSY;
}
spi_setup(spi);
return 0;
}
module_init(spidev_init);
“`
以上代碼使用spi_busnum_to_master函數(shù)獲取到SPI主設(shè)備,然后使用spi_new_device函數(shù)創(chuàng)建一個SPI子設(shè)備,并進(jìn)行spi_setup。由于在設(shè)備樹文件中設(shè)置了唯一的一個SPI總線節(jié)點(diǎn),因此我們可以在代碼中寫死SPI總線的bus_num為0,而不必再通過設(shè)備樹來查找SPI總線的節(jié)點(diǎn)。
相關(guān)問題拓展閱讀:
- linux環(huán)境可以跑c語言跑spi
linux環(huán)境可以跑c語言跑spi
?。?!
(1)打開Linux虛擬機(jī)在桌面創(chuàng)建一個文件夾,在文件夾里面創(chuàng)建一個以.c或者.cpp為后綴的文件
(2)把你的源程序敲在你的.c/.cpp文件里面,保存!
(3)ctrl+alt+t 同時按住打開終端
(4)輸入cd 然后把你在之一步創(chuàng)建的文件夾拖到終端里,你就會得到“cd 這個文件夾森早的位置”
(5)把文件路徑的引號刪掉,回車后你就會發(fā)現(xiàn)讀到這個文件夾里面了
(6)然后輸入gcc 文件全名(g++ 文件全名)例如:gcc a.c 然后運(yùn)行
這時如果你沒有安裝編譯器,終端上會提示你??!會提示你!會提示你!就像下面這樣
然此激雀后你復(fù)制自鉛瞎己的提示運(yùn)行就可以了,安裝會要你輸入密碼,輸入的時候是沒有符號提示的!輸入了就回車等下載好就可以
(7)然后會在你的文件夾里生成一個名為a.out的文件
(8)輸入./a.out就可以執(zhí)行了!
linux下設(shè)備樹spi使用的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于linux下設(shè)備樹spi使用,Linux設(shè)備樹中的SPI驅(qū)動使用詳解,linux環(huán)境可以跑c語言跑spi的信息別忘了在本站進(jìn)行查找喔。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
當(dāng)前標(biāo)題:Linux設(shè)備樹中的SPI驅(qū)動使用詳解(linux下設(shè)備樹spi使用)
標(biāo)題鏈接:http://www.fisionsoft.com.cn/article/djidodp.html


咨詢
建站咨詢
