国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux驅(qū)動(dòng)開(kāi)發(fā):SPI子系統(tǒng)

這篇具有很好參考價(jià)值的文章主要介紹了Linux驅(qū)動(dòng)開(kāi)發(fā):SPI子系統(tǒng)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1、SPI簡(jiǎn)介

1.1 四根線

MISO:主設(shè)備數(shù)據(jù)輸入,從設(shè)備數(shù)據(jù)輸出。
MOSI:主設(shè)備數(shù)據(jù)輸出,從設(shè)備數(shù)據(jù)輸入。
SCLK:時(shí)鐘信號(hào),由主設(shè)備產(chǎn)生。
CS:? ? 從設(shè)備片選信號(hào),由主設(shè)備控制。

1.2 四種模式

CPOL(時(shí)鐘極性) :? ?0:時(shí)鐘起始位低電平 ? ? ?1:時(shí)鐘起始為高電平 ?
CPHA(時(shí)鐘相位) :0:第一個(gè)時(shí)鐘周期采樣? ?1:第二個(gè)時(shí)鐘周期采樣

1、CPOL=0,CPHA=0:此時(shí)空閑態(tài)時(shí),SCLK處于低電平,數(shù)據(jù)采樣是在第1個(gè)邊沿,也就是 SCLK由低電平到高電平的跳變,所以數(shù)據(jù)采樣是在上升沿,數(shù)據(jù)發(fā)送是在下降沿

2、CPOL=0,CPHA=1:此時(shí)空閑態(tài)時(shí),SCLK處于低電平,數(shù)據(jù)發(fā)送是在第1個(gè)邊沿,也就是 SCLK由低電平到高電平的跳變,所以數(shù)據(jù)采樣是在下降沿,數(shù)據(jù)發(fā)送是在上升沿

3、CPOL=1,CPHA=0:此時(shí)空閑態(tài)時(shí),SCLK處于高電平,數(shù)據(jù)采集是在第1個(gè)邊沿,也就是 SCLK由高電平到低電平的跳變,所以數(shù)據(jù)采集是在下降沿,數(shù)據(jù)發(fā)送是在上升沿。

4、CPOL=1,CPHA=1:此時(shí)空閑態(tài)時(shí),SCLK處于高電平,數(shù)據(jù)發(fā)送是在第1個(gè)邊沿,也就是 SCLK由高電平到低電平的跳變,所以數(shù)據(jù)采集是在上升沿,數(shù)據(jù)發(fā)送是在下降沿。

1.3 SPI數(shù)據(jù)傳輸

Linux驅(qū)動(dòng)開(kāi)發(fā):SPI子系統(tǒng)????????

????????從圖中可以看出,主機(jī)和從機(jī)都有一個(gè)串行移位寄存器,主機(jī)通過(guò)向它的SPI串行寄存器寫入一個(gè)字節(jié)來(lái)發(fā)起一次傳輸。寄存器通過(guò)MOSI信號(hào)線將字節(jié)傳送給從機(jī),從機(jī)也將自己的移位寄存器中的內(nèi)容通過(guò)MISO信號(hào)線返回給主機(jī)。這樣,兩個(gè)移位寄存器中的內(nèi)容就被交換。外設(shè)的寫操作和讀操作是同步完成的。如果只進(jìn)行寫操作,主機(jī)只需忽略接收到的字節(jié);反之,若主機(jī)要讀取從機(jī)的一個(gè)字節(jié),就必須發(fā)送一個(gè)空字節(jié)來(lái)引發(fā)從機(jī)的傳輸。

1.4?SPI驅(qū)動(dòng)框架簡(jiǎn)介

????????SPI 驅(qū)動(dòng)框架和 I2C 很類似,都分為主機(jī)控制器驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng),主機(jī)控制器也就是 SOC 的 SPI 控制器接口。樣。和 I2C適配器驅(qū)動(dòng)一樣,SPI主機(jī)驅(qū)動(dòng)一般都是 SOC 廠商去編寫的,所以我們作為 SOC的使用者,這一部分的驅(qū)動(dòng)就不用操心了。

2、SPI設(shè)備驅(qū)動(dòng)

2.1 SPI相關(guān)API

2.1.1 spi_driver

struct spi_driver {
	int			(*probe)(struct spi_device *spi);
	int			(*remove)(struct spi_device *spi);
	struct device_driver	driver;
};

struct device_driver {
	const char	*name;
	const struct of_device_id	*of_match_table;
}

2.1.2 注冊(cè):spi_register_driver

#define spi_register_driver(driver) 
	__spi_register_driver(THIS_MODULE, driver)

2.1.3 注銷:spi_unregister_driver

static inline void spi_unregister_driver(struct spi_driver *sdrv)

2.1.4 module_spi_driver:一鍵注冊(cè),不需要以上注冊(cè)注銷的過(guò)程

#define module_spi_driver(__spi_driver) 
	module_driver(__spi_driver, spi_register_driver, 
			spi_unregister_driver)

#define module_driver(__driver, __register, __unregister, ...) 
static int __init __driver##_init(void) 
{ 
	return __register(&(__driver) , ##__VA_ARGS__); 
} 
module_init(__driver##_init); 
static void __exit __driver##_exit(void) 
{ 
	__unregister(&(__driver) , ##__VA_ARGS__); 
} 
module_exit(__driver##_exit);
module_spi_driver(myspi);

#define module_spi_driver(myspi) 
	module_driver(myspi, spi_register_driver, 
			spi_unregister_driver)

#define module_driver(myspi, spi_register_driver, spi_unregister_driver) 
static int __init myspi_init(void) 
{ 
	return spi_register_driver(&myspi); 
} 

static void __exit myspi_exit(void) 
{ 
	spi_unregister_driver(&myspi); 
} 
module_init(myspi_init); 
module_exit(myspi_exit);

2.1.5 spi_write

spi_write(struct spi_device *spi, const void *buf, size_t len)
{
	struct spi_transfer	t = {
			.tx_buf		= buf,
			.len		= len,
		};

	return spi_sync_transfer(spi, &t, 1);
}

2.1.6 spi_read

spi_read(struct spi_device *spi, void *buf, size_t len)
{
	struct spi_transfer	t = {
			.rx_buf		= buf,
			.len		= len,
		};

	return spi_sync_transfer(spi, &t, 1);
}

2.1.7 spi_write_then_read?

extern int spi_write_then_read(struct spi_device *spi,
		const void *txbuf, unsigned n_tx,
		void *rxbuf, unsigned n_rx);

2.1.8 以上三種spi傳輸函數(shù)解析,實(shí)際接收發(fā)送只需spi_write、spi_read

struct spi_transfer {
	const void	*tx_buf;  //用于保存發(fā)送的數(shù)據(jù)
	void		*rx_buf;  //用于保存接收到的數(shù)據(jù)
	unsigned	len;      //是要進(jìn)行傳輸?shù)臄?shù)據(jù)長(zhǎng)度, SPI是全雙工通信,
                          //因此在一次通信中發(fā)送和接收的字節(jié)數(shù)都是一樣的,
                          //所以 spi_transfer中也就沒(méi)有發(fā)送長(zhǎng)度和接收長(zhǎng)度之分。
};

spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers,
	unsigned int num_xfers)
{
	struct spi_message msg;

	spi_message_init_with_transfers(&msg, xfers, num_xfers);

	return spi_sync(spi, &msg);
}

struct spi_message {
	struct list_head	transfers;
	struct spi_device	*spi;
};

spi_message_init_with_transfers(struct spi_message *m,
struct spi_transfer *xfers, unsigned int num_xfers)
{    
	unsigned int i;
	spi_message_init(m);
	for (i = 0; i < num_xfers; ++i)
		spi_message_add_tail(&xfers[i], m);
}

總體流程:

①、申請(qǐng)并初 始化 spi_transfer,設(shè)置 spi_transfer的 tx_buf成員變量, tx_buf為要發(fā)送的數(shù)
據(jù)。然后設(shè)置 rx_buf成員變量, rx_buf保存著接收到的數(shù)據(jù)。最后設(shè)置 len成員變量,也就是要進(jìn)行數(shù)據(jù)通信的長(zhǎng)度。
②、使用 spi_message_init函數(shù)初始化 spi_message。
③、使用 spi_message_add_tail函數(shù)將前面設(shè)置好的 spi_transfer添加到 spi_message隊(duì)列中。
④、使用 spi_sync函數(shù)完成 SPI數(shù)據(jù)同步傳輸。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-461604.html

?2.1.9?spi_message_init

int spi_sync(struct spi_device *spi, struct spi_message *message) 
/*
功能:初始化spi_message
參數(shù):
    @spi    :要進(jìn)行數(shù)據(jù)傳輸?shù)?spi_device
    @message:要傳輸?shù)?spi_message
返回值:無(wú)
*/

2.1.10?spi_message_add_tail

void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
/*
功能:初始化完成以后需要將 spi_transfer添加到 spi_message隊(duì)列中
參數(shù):
    @t:要添加到隊(duì)列中的 spi_transfer
    @m:spi_transfer要加入的 spi_message
返回值: 無(wú)
*/

2.1.11?spi_sync:同步傳輸

int spi_sync(struct spi_device *spi, struct spi_message *message)
/*
功能:同步傳輸,會(huì)阻塞的等待 SPI 數(shù)據(jù)傳輸完成
參數(shù):
    @spi:要進(jìn)行數(shù)據(jù)傳輸?shù)?spi_device
    @message:要傳輸?shù)?spi_message
返回值:成功返回0,失敗返回錯(cuò)誤碼
*/

2.1.12?spi_async:異步傳輸

int spi_async(struct spi_device *spi, struct spi_message *message)
/*
功能:異步傳輸不會(huì)阻塞的等到 SPI數(shù)據(jù)傳輸完成,異步傳輸需要設(shè)置 spi_message中的 complete成員變量,
      complete是一個(gè)回調(diào)函數(shù),當(dāng) SPI異步傳輸完成以后此函數(shù)就會(huì)被調(diào)用。
參數(shù):        
    @spi:要進(jìn)行數(shù)據(jù)傳輸?shù)?spi_device
    @message:要傳輸?shù)?spi_message
返回值:成功返回0,失敗返回錯(cuò)誤碼
*/

3、驅(qū)動(dòng)程序

3.1 修改設(shè)備樹(shù)

&spi4{
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&spi4_pins_b>;
    pinctrl-1 = <&spi4_sleep_pins_b>;
    cs-gpios = <&gpioe 11 0>;
    status = "okay";
    
    m74hc595@0{
        compatible = "aaa,m74hc595";
        reg = <0>;
        spi-max-frequency = <10000000>; //10Mhz
    };
};

3.2?驅(qū)動(dòng)程序編寫

#ifndef __M74HC595_H__
#define __M74HC595_H__

#define SEG_WHICH _IOW('k',0,int)
#define SEG_DAT  _IOW('k',1,int)
#endif
#define NAME "m74hc595"
int major = 0;
struct class *cls;
struct device *dev;
struct spi_device *gspi;
u8 code[] = {
	0x3f, 0x06, 0x5b, 0x4f, 0x6d, 0x7d, 0x07, 0x7f, 
	0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 
};

u8 which[] = {
	0x1, 0x2, 0x4, 0x8, 
};

int m74hc595_open(struct inode *inode, struct file *file)
{
	return 0;
}
long m74hc595_ioctl(struct file *file, 
	unsigned int cmd, unsigned long args)
{	
	switch(cmd){
		case SEG_WHICH:
			spi_write(gspi,&which[args],1);
			break;
		case SEG_DAT:
			spi_write(gspi,&code[args],1);
			break;
		default: printk("ioctl error\n");break;
	}
	
	return 0;
}

int m74hc595_close(struct inode *inode, struct file *file)
{
	return 0;
}
struct file_operations fops = {
	.open = m74hc595_open,
	.unlocked_ioctl = m74hc595_ioctl,
	.release = m74hc595_close,
};

int	m74hc595_probe(struct spi_device *spi)
{
	u8 buf[2] = {0xf,0x0};
	gspi = spi;
	spi_write(gspi,buf,ARRAY_SIZE(buf));
	
	major = register_chrdev(0,NAME,&fops);
	cls = class_create(THIS_MODULE,NAME);
	dev = device_create(cls,NULL,MKDEV(major,0),NULL,NAME);

	return 0;
}

int	m74hc595_remove(struct spi_device *spi)
{
	device_destroy(cls,MKDEV(major,0));
	class_destroy(cls);
	unregister_chrdev(major,NAME);
	return 0;
}

const struct of_device_id of_match[] = {
	{.compatible = "aaa,m74hc595",},
	{},
};

struct spi_driver m74hc595 = {
	.probe = m74hc595_probe,
	.remove = m74hc595_remove,
	.driver = {
		.name = "bbb",
		.of_match_table = of_match,
	},	
};
module_spi_driver(m74hc595);

4、應(yīng)用程序 ?

int main(int argc, const char *argv[])
{
	int which=0;
	int data=0;
	int fd;
	fd = open("/dev/m74hc595",O_RDWR);
	if(fd < 0){
		perror("open error");
		return -1;
	}

	while(1){
		ioctl(fd,SEG_WHICH,which++);
		ioctl(fd,SEG_DAT,data++);
		if(which >= 4)which=0;
		if(data >= 16)data = 0;
		sleep(1);
	}

	close(fd);
	return 0;
}

到了這里,關(guān)于Linux驅(qū)動(dòng)開(kāi)發(fā):SPI子系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Linux驅(qū)動(dòng)開(kāi)發(fā)】010 pinctrl子系統(tǒng)

    【Linux驅(qū)動(dòng)開(kāi)發(fā)】010 pinctrl子系統(tǒng)

    上一章我們編寫了基于設(shè)備樹(shù)的 LED 驅(qū)動(dòng),但是驅(qū)動(dòng)的本質(zhì)還是沒(méi)變,都是配置 LED 燈所使用的 GPIO 寄存器,驅(qū)動(dòng)開(kāi)發(fā)方式和裸機(jī)基本沒(méi)啥區(qū)別。本章我們就來(lái)學(xué)習(xí)一下如何借助 pinctrl 和 gpio 子系統(tǒng)來(lái)簡(jiǎn)化 GPIO 驅(qū)動(dòng)開(kāi)發(fā)。? ?Linux 內(nèi)核針對(duì) PIN 的配置推出了 pinctrl 子系統(tǒng),對(duì)于

    2024年02月14日
    瀏覽(21)
  • <Linux開(kāi)發(fā)>驅(qū)動(dòng)開(kāi)發(fā) -之-基于pinctrl/gpio子系統(tǒng)的beep驅(qū)動(dòng)

    <Linux開(kāi)發(fā)>驅(qū)動(dòng)開(kāi)發(fā) -之-基于pinctrl/gpio子系統(tǒng)的beep驅(qū)動(dòng)

    <Linux開(kāi)發(fā)>驅(qū)動(dòng)開(kāi)發(fā) -之-基于pinctrl/gpio子系統(tǒng)的beep驅(qū)動(dòng) 交叉編譯環(huán)境搭建: <Linux開(kāi)發(fā)> linux開(kāi)發(fā)工具-之-交叉編譯環(huán)境搭建 uboot移植可參考以下: <Linux開(kāi)發(fā)> -之-系統(tǒng)移植 uboot移植過(guò)程詳細(xì)記錄(第一部分) <Linux開(kāi)發(fā)> -之-系統(tǒng)移植 uboot移植過(guò)程詳細(xì)記錄(第二部分

    2024年02月13日
    瀏覽(18)
  • Linux驅(qū)動(dòng)開(kāi)發(fā)之【pinctrl和gpio子系統(tǒng)】

    Linux驅(qū)動(dòng)開(kāi)發(fā)之【pinctrl和gpio子系統(tǒng)】

    目錄 一、?pinctrl和gpio子系統(tǒng) 1.pinctrl子系統(tǒng) 1.1 pinctrl子系統(tǒng)簡(jiǎn)介 1.2 pinctrl子系統(tǒng)驅(qū)動(dòng) 1.3 設(shè)備樹(shù)中添加pinctrl節(jié)點(diǎn)模版 2. gpio子系統(tǒng) 2.1 gpio子系統(tǒng)簡(jiǎn)介 2.2 gpio子系統(tǒng)驅(qū)動(dòng) 2.3 gpio子系統(tǒng)API函數(shù) 2.4 設(shè)備樹(shù)中添加gpio節(jié)點(diǎn)模板 2.5 與gpio相關(guān)的OF函數(shù) 3. 驅(qū)動(dòng)程序編寫 3.1 驅(qū)動(dòng)入口函數(shù) 3

    2024年02月06日
    瀏覽(16)
  • 【Linux驅(qū)動(dòng)開(kāi)發(fā)】012 gpio子系統(tǒng)API函數(shù)

    設(shè)置好設(shè)備樹(shù)以后, 在驅(qū)動(dòng)程序中就可以使用 gpio 子系統(tǒng)提供的 API 函數(shù)來(lái)操作指定的 GPIO, gpio 子系統(tǒng)向驅(qū)動(dòng)開(kāi)發(fā)人員屏蔽了具體的讀寫寄存器過(guò)程。這就是驅(qū)動(dòng)分層與分離的好處,大家各司其職,做好自己的本職工作即可。 gpio 子系統(tǒng)提供的常用的 API 函數(shù)有下面幾個(gè):

    2023年04月18日
    瀏覽(24)
  • 【LED子系統(tǒng)深度剖析】一、開(kāi)篇詞|Linux驅(qū)動(dòng)開(kāi)發(fā)必讀

    我的圈子: 高級(jí)工程師聚集地 我是董哥,高級(jí)嵌入式軟件開(kāi)發(fā)工程師,從事嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)和系統(tǒng)開(kāi)發(fā),曾就職于世界500強(qiáng)公司! 創(chuàng)作理念:專注分享高質(zhì)量嵌入式文章,讓大家讀有所得!

    2024年02月09日
    瀏覽(19)
  • Linux SPI子系統(tǒng)(2):SPI核心層

    目錄 SPI核心層? 1. SPI子系統(tǒng)初始化 2. 重要的數(shù)據(jù)結(jié)構(gòu) 2.1?struct spi_controller 2.2 struct spi_driver 2.3?struct spi_device 2.4 struct spi_transfer和struct spi_message 3. 重要的API 3.1?spi_register_controller 3.2 數(shù)據(jù)準(zhǔn)備函數(shù):spi_message_init和spi_message_add_tail 3.3 數(shù)據(jù)傳輸函數(shù):spi_sync和spi_async 4. 參考文章

    2024年02月01日
    瀏覽(45)
  • 【IMX6ULL驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)】14.Linux驅(qū)動(dòng)開(kāi)發(fā) - GPIO中斷(設(shè)備樹(shù) + GPIO子系統(tǒng))

    【IMX6ULL驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)】14.Linux驅(qū)動(dòng)開(kāi)發(fā) - GPIO中斷(設(shè)備樹(shù) + GPIO子系統(tǒng))

    代碼自取 【14.key_tree_pinctrl_gpios_interrupt】: https://gitee.com/chenshao777/imx6-ull_-drivers 主要接口函數(shù): 1. of_gpio_count (獲得GPIO的數(shù)量) 2. kzalloc (向內(nèi)核申請(qǐng)空間) 3. of_get_gpio (獲取GPIO子系統(tǒng)標(biāo)號(hào)) 4. gpio_to_irq (根據(jù)GPIO子系統(tǒng)標(biāo)號(hào)得到軟件中斷號(hào)) 5. request_irq (根據(jù)軟件中斷號(hào)

    2024年02月12日
    瀏覽(35)
  • 【IMX6ULL驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)】21.Linux驅(qū)動(dòng)之PWM子系統(tǒng)(以SG90舵機(jī)為例)

    【IMX6ULL驅(qū)動(dòng)開(kāi)發(fā)學(xué)習(xí)】21.Linux驅(qū)動(dòng)之PWM子系統(tǒng)(以SG90舵機(jī)為例)

    首先在 imx6ull.dtsi 文件中已經(jīng)幫我們定義好了一些pwm的設(shè)備樹(shù)節(jié)點(diǎn),這里以pwm2為例 我們要在設(shè)備樹(shù)(.dts)文件中引用和使能該節(jié)點(diǎn),同時(shí)指定好pwm映射到的GPIO引腳(即pinctrl子系統(tǒng),我這里映射到了GPIO1_9上) 使用pwm 只需要在設(shè)備樹(shù)節(jié)點(diǎn)中添加兩條屬性信息,如下所示 pwms :屬

    2024年02月12日
    瀏覽(90)
  • Linux Mii management/mdio子系統(tǒng)分析之三 mii_bus注冊(cè)、注銷及其驅(qū)動(dòng)開(kāi)發(fā)流程

    Linux Mii management/mdio子系統(tǒng)分析之三 mii_bus注冊(cè)、注銷及其驅(qū)動(dòng)開(kāi)發(fā)流程

    (轉(zhuǎn)載)原文鏈接:https://blog.csdn.net/u014044624/article/details/123303174 ????? 本篇是mii management/mdio模塊分析的第三篇文章,本章我們主要介紹mii-bus的注冊(cè)與注銷接口。在前面的介紹中也已經(jīng)說(shuō)過(guò),我們可以將mii-bus理解為mdio總線的控制器的抽象,就像spi-master、i2c-adapter一樣。 本

    2024年01月16日
    瀏覽(39)
  • Linux IIO 子系統(tǒng)簡(jiǎn)介

    Linux IIO 子系統(tǒng)簡(jiǎn)介

    IIO 子系統(tǒng)系統(tǒng)框架 而在IIO子系統(tǒng)內(nèi)部,則主要包括如下四部分的內(nèi)容: iio buffer用于處理需要進(jìn)行連續(xù)采集的數(shù)據(jù),當(dāng)一個(gè)IIO device的各通道數(shù)據(jù)支持連續(xù)采集時(shí),則調(diào)用iio buffer模塊提供的接口,創(chuàng)建iio buffer用于存儲(chǔ)連續(xù)存儲(chǔ)的數(shù)據(jù),同時(shí)該模塊提供字符設(shè)備文件的注冊(cè),因

    2024年02月16日
    瀏覽(20)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包