㈠ linux自帶的SPI驅動,默認情況下是以什麼方式讀取數據的
一位一位來傳輸數據的。如果只是要在linux上開發應用,可以不去理會具體的SPI驅動細節。
可以在linux中寫個簡單的程序,只完成讀spi並在屏幕輸出的功能,不要涉及編寫驅動的部分。
㈡ linux spi 應用程序。
你所指的spidev.c是SPI的用戶模式設備介面的驅動,可以通過應用程序去操作/dev/spidev*達到與硬體設備的SPI通信,對於操作SPI NOR FLASH,更多是注冊為MTD設備,詳細可參考drivers/mtd/device/m25p80.c,裡面已經有相關實現。
但無論如何,前提是你的內核里已經有SPI控制器的驅動,否則如何通信呢。代碼一般在drivers/spi/里。
那是應該是給spi設備驅動範本吧,可以籍此寫自己的spi設備驅動,沒有設備節點就自己創建個嘛。或者在驅動中添加創建設備節點的函數。
㈢ linux下的SPI使用方法是怎樣的
如果linux中已經提供了驅動,並且在/dev/目錄下已經提供了相應的設備文件節點。那麼可以和串口一樣直接打開設置讀寫。如果內核中有驅動,但是沒有生成設備文件節點,那麼只要知道設備的主次設備號,可以使用mknode建立設備文件節點,然後直接來使用。如果沒有驅動就需要自己添加設備驅動了。這個也分兩種情況,看你外設怎麼和你的板子連接的。如果接到板子上的spi控制器上,可以直接編寫通過控制器來控制外設的驅動,這種情況一般生產主控晶元的廠家都已經提供了驅動。如果沒有接到spi控制器上,而是通過gpio連接的外設,你編寫的驅動就需要自己來模擬spi協議來控制外設。
㈣ 怎麼寫linux的spi設備驅動
回復
1#
我也是新手,不過調通了SPI,
在SPI
驅動裡面是分為
設備
匯流排
驅動的。。這個你要搞清楚。你所說的幾個文件就是在這個層次關系裡面的代碼,如果你只是簡單的使用SPI,內核自帶的spidev.c就已經能夠滿足要求了。。我就這么用的。。。你可以參照內核裡面的常式來分析分析。
另外,你也可以試著寫一個裸驅試試。。。
㈤ spi是通過什麼判斷是讀還是寫
void SpiWriteRegister (uchar reg,uchar value)
{
\x05RF_NSEL = 0; // 片選拉低啟動SPI通訊
\x05SPI0DAT = (reg|0x80); // 寫入1個位元組的寄存器地址
\x05while( SPIF == 0);\x05\x05 // 等待SPI傳輸完成
\x05SPIF = 0;
\x05SPI0DAT = value; // 繼續寫入第二個位元組(寄存器值)
\x05while( SPIF == 0);\x05 // 等待SPI傳輸完成
\x05SPIF = 0;\x05
\x05RF_NSEL = 1; // 片選拉高結束SPI通訊
}
//-----------------------------------------------------------------------------
//函數描述:SPI讀取函數
//相關參數:
//返回信息:
//
//-----------------------------------------------------------------------------
uchar SpiReadRegister (uchar reg)
{
\x05RF_NSEL = 0; // 片選拉低啟動SPI通訊
\x05SPI0DAT = reg;\x05\x05\x05 // 寫入1個位元組的寄存器地址
\x05while( SPIF == 0);\x05\x05 // 等待SPI傳輸完成
\x05SPIF = 0;
\x05SPI0DAT = 0xFF;\x05\x05\x05 // 寫一個Dummy位元組(因為要讀取的話必須用寫入來啟動一個交換數據的傳輸),當寫入完成後從機的數據也完成了讀入.
\x05while( SPIF == 0);\x05\x05 // 等待SPI傳輸完成\x05\x05\x05\x05
\x05SPIF = 0;
\x05RF_NSEL = 1; // 片選拉高結束SPI通訊 \x05
\x05return SPI0DAT; // 返回讀取的值(在SPI0DAT=0xFF中完成讀取)
}
需要注意的是讀寫操作實際上完成的都是數據的交換,即主機傳送1個位元組給從機,從機同時傳送1個位元組給主機.所以讀操作看起來像是寫數據,但實際上寫入完成後就可以從SPI0DAT中獲得從機的應答數據了.
㈥ linux下spi驅動里的spi_write_then_read函數該怎麼使用
水平不行,不一定對,僅供參考哈。
如果只是從AD里讀數據的話,用spi_read就可以了,定義一個8位的緩沖區和一個16位的緩沖區。然後把讀到的2個8bit的數據組合成1個16bit的數據。每次讀到的數據量通過該函數的參數設定。
如果是想實現全雙工,可以使用spi_write_then_read
讀是一樣的,寫的話自己先把16位數據轉換成2個8bit的數據,存放在一個8bit的緩沖區,作為該函數的參數。
㈦ 幫忙分析一個這個spi讀寫程序,詳細一點的,解釋一下。怎麼覺得讀和寫的內容怎麼差不多呢,怎麼實現的讀寫
void SpiWriteRegister (uchar reg, uchar value)
{
RF_NSEL = 0; // 片選拉低啟動SPI通訊
SPI0DAT = (reg|0x80); // 寫入1個位元組的寄存器地址
while( SPIF == 0); // 等待SPI傳輸完成
SPIF = 0;
SPI0DAT = value; // 繼續寫入第二個位元組(寄存器值)
while( SPIF == 0); // 等待SPI傳輸完成
SPIF = 0;
RF_NSEL = 1; // 片選拉高結束SPI通訊
}
//-----------------------------------------------------------------------------
//函數描述: SPI讀取函數
//相關參數:
//返回信息:
//
//-----------------------------------------------------------------------------
uchar SpiReadRegister (uchar reg)
{
RF_NSEL = 0; // 片選拉低啟動SPI通訊
SPI0DAT = reg; // 寫入1個位元組的寄存器地址
while( SPIF == 0); // 等待SPI傳輸完成
SPIF = 0;
SPI0DAT = 0xFF; // 寫一個Dummy位元組(因為要讀取的話必須用寫入來啟動一個交換數據的傳輸),當寫入完成後從機的數據也完成了讀入。
while( SPIF == 0); // 等待SPI傳輸完成
SPIF = 0;
RF_NSEL = 1; // 片選拉高結束SPI通訊
return SPI0DAT; // 返回讀取的值(在SPI0DAT=0xFF中完成讀取)
}
需要注意的是讀寫操作實際上完成的都是數據的交換,即主機傳送1個位元組給從機,從機同時傳送1個位元組給主機。所以讀操作看起來像是寫數據,但實際上寫入完成後就可以從SPI0DAT中獲得從機的應答數據了。
㈧ linux spi設備驅動中probe函數何時被調用
這兩天被設備文件快搞瘋了,也怪自己學東西一知半解吧,弄了幾天總算能把設備注冊理清楚一點點了。就以spi子設備的注冊為例總結一下,免得自己忘記。
首先以注冊一個spidev的設備為例:
static struct spi_board_info imx5_spi_printer_device[] __initdata =
{
{
.modalias = "spidev",
.max_speed_hz = 8000000,
.bus_num = 1,
.chip_select = 1,
.mode = SPI_MODE_0,
},
};
spi_register_board_info(imx5_spi_printer_device,ARRAY_SIZE(imx5_spi_printer_device));
在mx5_loco.c文件中添加上面結構體spi_board_info,modalias必須指定已有的一個驅動,至於bus_num和chip_select,如果你不知道bus_num是多少,可以在你的父驅動中列印出來,這里的bus_num一定要和父類的bus_num一致,否則是無法生成設備文件的。如果spi一直沒有時鍾信號,很有可能是bus_num不對。
這樣系統起來之後就會在/dev目錄下出現一個名為spidev1.1的設備文件,讀寫這個文件就可以實現spi的操作
還有下面這種情況:
static struct spi_board_info prt_spi_device[] __initdata = {
{
.modalias = "HotPRT",
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
.bus_num = 1,
.chip_select = 1,
// .mode = SPI_MODE_0,
.platform_data = 0,
},
};
spi_register_board_info(prt_spi_device, ARRAY_SIZE(prt_spi_device));
我自己實現了一個spi的驅動,然後需要創建一個設備文件,設備文件的創建是在probe中完成。
static struct spi_driver prt_driver = {
.driver = {
.name = "HotPRT",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = prt_probe,
.remove = __devexit_p(prt_remove),
};
spi_register_driver(&prt_driver);
但是我開始一直觸發不了probe,於是找啊找,總算知道probe的調用過程了,如下:
int spi_register_driver(struct spi_driver *sdrv)
{
sdrv->driver.bus = &spi_bus_type;
if (sdrv->probe)
sdrv->driver.probe = spi_drv_probe;
if (sdrv->remove)
sdrv->driver.remove = spi_drv_remove;
if (sdrv->shutdown)
sdrv->driver.shutdown = spi_drv_shutdown;
return driver_register(&sdrv->driver);
}
然後調用driver_register
<pre name="code" class="cpp">int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
直接看bus_add_driver
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
mole_add_driver(drv->owner, drv);
這里只截取一部分,最後調用的是driver_attach
int driver_attach(struct device_driver * drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
真正起作用的是__driver_attach:
static int __driver_attach(struct device * dev, void * data)
{
。。。
if (!dev->driver)
driver_probe_device(drv, dev);
。。。
}
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
。。。
//1.先是判斷bus是否match:
if (drv->bus->match && !drv->bus->match(dev, drv))
goto done;
//2.再具體執行probe:
ret = really_probe(dev, drv);
。。。
}
really_probe才是我們要找的函數:
static int really_probe(struct device *dev, struct device_driver *drv)
{
。。。
//1.先是調用的驅動所屬匯流排的probe函數:
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
//2.再調用你的驅動中的probe函數:
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
。。。
}
其中,drv->probe(dev),才是真正調用你的驅動實現的具體的probe函數。至此probe函數被調用。
在板文件中添加spi_board_info,並在板文件
㈨ 請教linux的SPI驅動問題
內核版本2.6.30。編進內核的SPI驅動,通過看代碼我明白了,大致過程是這樣:
1、先創建一個spi_board_info結構描述spi設備信息,調用spi_register_board_info將這個結構添加到board_list中。
2、然後調用spi_register_master注冊SPI控制器驅動,此時會調用scan_boardinfo掃描board_list,根據spi_board_info調用spi_new_device生成spi_device結構,用spi_add_device添加設備。
3、調用spi_register_driver注冊spi_driver,通過與device匹配驅動設備。