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

12.5在Linux中編寫隊列模式的SPI控制器驅(qū)動

這篇具有很好參考價值的文章主要介紹了12.5在Linux中編寫隊列模式的SPI控制器驅(qū)動。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

在Linux內(nèi)核中更加推薦使用隊列模式的SPI控制器驅(qū)動,而且隊列模式的SPI控制器驅(qū)動也更加簡單,只需要在驅(qū)動中實現(xiàn)單個spi_transfer的傳輸即可,將spi_message拆解為spi_transfer、片選GPIO控制、統(tǒng)計信息更新等均由SPI核心去完成。

編寫驅(qū)動程序步驟

  1. 實現(xiàn)設(shè)置SPI總線的函數(shù)setup,用于設(shè)置SPI總線,若片選采用GPIO編號模式還需要在這里將GPIO設(shè)置為輸出
  2. 實現(xiàn)SPI總線數(shù)據(jù)傳輸?shù)暮瘮?shù)transfer_one,用于傳輸SPI的數(shù)據(jù)
  3. 通過spi_alloc_master分配一個struct spi_master
  4. 初始化struct spi_master,主要包含設(shè)備樹節(jié)點、支持的模式、支持的最大頻率和最小頻率、片選引腳是GPIO編號模式還是描述符模式、setup函數(shù)(用于設(shè)置SPI總線)、transfer_one函數(shù)(用于傳輸spi_transfer,若提供了transfer_one,且未提供transfer函數(shù)則是隊列模式的SPI控制器驅(qū)動)
  5. 若片選采用GPIO編號模式還需要對片選引腳進(jìn)行request操作,若片選采用GPIO描述符模式則無該步驟
  6. 通過spi_register_master注冊SPI控制器驅(qū)動
  7. 設(shè)備或驅(qū)動卸載時spi_unregister_master注銷SPI控制器

編寫驅(qū)動程

這里編寫一個虛擬的SPI控制器驅(qū)動,通過printk來輸出SPI控制器的工作狀態(tài),同時它提供軟件進(jìn)行回環(huán)(將tx_buf拷貝到rx_buf中)。

設(shè)備樹編寫

在頂層設(shè)備樹根節(jié)點中加入如下節(jié)點:

	virtual_spi_master {
			compatible = "atk,virtual_spi_master";
			status = "okay";
			//片選列表,一個spi_master至少有一個片選
			cs-gpios = <&gpioh 6 GPIO_ACTIVE_LOW>;
			//片選數(shù)量
			num-chipselects = <1>;
			//reg中地址字段的字?jǐn)?shù),必須為1
			#address-cells = <1>;
			//reg中地址空間大小的字?jǐn)?shù),必須為0
			#size-cells = <0>;

			//一個spidev的設(shè)備節(jié)點,以便在應(yīng)用層通過spidev來測試SPI控制器驅(qū)動
			virtual_spi_dev: virtual_spi_dev@0 {
					compatible = "rohm,dh2228fv";
					reg = <0>;
					spi-max-frequency = <100000>;
			};
	};

用make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs -j8編譯設(shè)備樹,用新的.dtb文件啟動系統(tǒng)

驅(qū)動代碼編寫

完整的驅(qū)動代碼如下所示:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/of_gpio.h>

static int spi_virtual_setup(struct spi_device *spi_dev)
{
	if(!gpio_is_valid(spi_dev->cs_gpio))
	{
		printk("%d is not a valid gpio\n", spi_dev->cs_gpio);
		return -EINVAL;
	}

	//若采用GPIO編號模式還需要在驅(qū)動中將gpio設(shè)置為輸出
	return gpio_direction_output(spi_dev->cs_gpio, !(spi_dev->mode & SPI_CS_HIGH));
}

static int spi_virtual_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer)
{
	int status;

	//模擬硬件傳輸數(shù)據(jù)
	if((transfer->tx_buf || transfer->rx_buf) && (transfer->len > 0))
	{
		if(transfer->rx_buf && transfer->tx_buf)
			memcpy(transfer->rx_buf, transfer->tx_buf, transfer->len);
		else if(transfer->rx_buf)
			memset(transfer->rx_buf, 0xAA, transfer->len);
		printk("transfer one\n");
		status = 0;
	}
	else if((transfer->tx_buf || transfer->rx_buf) && (transfer->len <= 0))
	{
		printk("transfer invalid\n");
		status = -EREMOTEIO;
	}
	else
		status = 0;

	//傳輸完成需要調(diào)用此函數(shù)(如果使用中斷應(yīng)該在傳輸完成中斷中調(diào)用)
	spi_finalize_current_transfer(master);

	return status;
}

static int spi_virtual_probe(struct platform_device *pdev)
{
	int result;
	int i, num_cs, cs_gpio;
	struct spi_master *virtual_master;

	printk("%s\r\n", __FUNCTION__);

	//分配spi_master
	virtual_master = spi_alloc_master(&pdev->dev, 0);
	if(!virtual_master)
	{
		printk("alloc spi_master fail\n");
		return -ENOMEM;
	}

	//設(shè)置平臺設(shè)備的驅(qū)動私有數(shù)據(jù)
	pdev->dev.driver_data = (void*)virtual_master;

	//初始化spi_master
	virtual_master->use_gpio_descriptors = 0;
	virtual_master->setup = spi_virtual_setup;
	virtual_master->transfer_one = spi_virtual_transfer_one;
	virtual_master->dev.of_node = pdev->dev.of_node;
	virtual_master->bus_num = pdev->id;
	virtual_master->max_speed_hz = 1000000000;
	virtual_master->min_speed_hz = 1000;
	virtual_master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE;

	//片選引腳采用GPIO編號模式時,SPI驅(qū)動框架僅僅是從設(shè)備樹中獲取片選引腳編號并記錄,未進(jìn)行request引腳
	num_cs = of_gpio_named_count(pdev->dev.of_node, "cs-gpios");
	for (i = 0; i < num_cs; i++)
	{
		cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i);
		if (cs_gpio == -EPROBE_DEFER)
		{
			/* 釋放前面分配的 spi_master,它通過于 spi_master 綁定的 dev 來實現(xiàn)
			* 其調(diào)用流程如下:
			* 	spi_master_put
			* 		spi_controller_put
			* 			put_device
			* 				kobject_put
			* 					kref_put
			* 						kobject_release
			* 							kobject_cleanup
			* 								t->release,這里應(yīng)該是device_initialize為其注冊的device_ktype中的device_release
			* 									dev->class->dev_release,這里應(yīng)該是分配spi_master時為dev.class綁定的spi_master_class中的spi_controller_release
			*/
			spi_master_put(virtual_master);
			return -EPROBE_DEFER;
		}

		if(gpio_is_valid(cs_gpio))
		{
			result = devm_gpio_request(&pdev->dev, cs_gpio, "virtual_spi_cs");
			if(result < 0)
			{
				spi_master_put(virtual_master);
				printk("can't get CS gpio %i\n", cs_gpio);
				return result;
			}
		}
	}

	//注冊 spi_master
	result = spi_register_master(virtual_master);
	if (result < 0)
	{
		printk("register spi_master fail\n");
		spi_master_put(virtual_master);
		return result;
	}

	return 0;
}

static int spi_virtual_remove(struct platform_device *pdev)
{
	struct spi_master *virtual_master;

	printk("%s\r\n", __FUNCTION__);

	//提取平臺設(shè)備的驅(qū)動私有數(shù)據(jù)
	virtual_master = (struct spi_master*)pdev->dev.driver_data;

	//注銷spi_master,在注銷過程中會執(zhí)行put_device操作,所以無需再次執(zhí)行spi_master_put
	spi_unregister_master(virtual_master);

	return 0;
}

static const struct of_device_id spi_virtual_of_match[] = {
	{.compatible = "atk,virtual_spi_master"},
	{ /* Sentinel */ }
};
static struct platform_driver spi_virtual_driver = {
	.probe = spi_virtual_probe,
	.remove = spi_virtual_remove,
	.driver = {
		.name = "virtual_spi",
		.of_match_table = spi_virtual_of_match,
	},
};

static int virtual_master_init(void)
{
	printk("%s\r\n", __FUNCTION__);

	return platform_driver_register(&spi_virtual_driver);
}

static void virtual_master_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	platform_driver_unregister(&spi_virtual_driver);
}

module_init(virtual_master_init);
module_exit(virtual_master_exit);

MODULE_DESCRIPTION("virtual SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("csdn");

驅(qū)動測試程序編寫

驅(qū)動測試程序基于spidev進(jìn)行編寫,它通過ioctl控制SPI總線進(jìn)行數(shù)據(jù)收發(fā),完整的代碼如下所示:文章來源地址http://www.zghlxwxcb.cn/news/detail-809003.html

/* 參考: tools\spi\spidev_fdx.c */
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <errno.h>

/* dac_test /dev/spidevB.D <val> */

int main(int argc, char **argv)
{
	int fd;
	int status;
	struct spi_ioc_transfer xfer[1];
	unsigned char tx_buf[1];
	unsigned char rx_buf[1];
	
	if(argc != 3)
	{
		printf("Usage: %s /dev/spidevB.D <val>\n", argv[0]);
		return 0;
	}

	//打開spidev設(shè)備
	fd = open(argv[1], O_RDWR);
	if (fd < 0) {
		printf("can not open %s\n", argv[1]);
		return 1;
	}

	//通過ioctl控制SPI總線發(fā)送并接收一個字節(jié)的數(shù)據(jù)
	tx_buf[0] = (unsigned char)strtoul(argv[2], NULL, 0);
	rx_buf[0] = 0;
	memset(xfer, 0, sizeof xfer);
	xfer[0].tx_buf = (unsigned long)tx_buf;
	xfer[0].rx_buf = (unsigned long)rx_buf;
	xfer[0].len = 2;
	status = ioctl(fd, SPI_IOC_MESSAGE(1), xfer);
	if(status < 0)
	{
		printf("SPI_IOC_MESSAGE %d\n", errno);
		return -1;
	}

	//打印接收到的數(shù)據(jù)
	printf("Pre val = %d\n", rx_buf[0]);

	return 0;
}

上機測試

  1. 修改設(shè)備樹,增加虛擬SPI控制器的設(shè)備樹節(jié)點,并在此節(jié)點中添加一個spidev的子節(jié)點,然后編譯設(shè)備樹,用新的設(shè)備樹啟動設(shè)備
  2. 從這里下載代碼,使用make進(jìn)行編譯,然后使用make copy拷貝到目標(biāo)板NFS跟文件系統(tǒng)的root目錄中(執(zhí)行make copy時需要確保akefile中NFS根文件系統(tǒng)的路徑正確)
  3. 在目標(biāo)板中執(zhí)行insmod spi_master.ko加載虛擬SPI控制器驅(qū)動
    12.5在Linux中編寫隊列模式的SPI控制器驅(qū)動,linux驅(qū)動開發(fā),linux,arm開發(fā),嵌入式硬件,驅(qū)動開發(fā)
  4. 執(zhí)行命令./spi_test.out /dev/spidev1.0 12通過SPI總線發(fā)送1byte數(shù)據(jù),同時將收到的數(shù)據(jù)打印出來(驅(qū)動中默認(rèn)將發(fā)送的數(shù)據(jù)賦給接收
    12.5在Linux中編寫隊列模式的SPI控制器驅(qū)動,linux驅(qū)動開發(fā),linux,arm開發(fā),嵌入式硬件,驅(qū)動開發(fā)

到了這里,關(guān)于12.5在Linux中編寫隊列模式的SPI控制器驅(qū)動的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • 【設(shè)計模式】前端控制器模式

    【設(shè)計模式】前端控制器模式

    前端控制器模式(Front Controller Pattern)是用來提供一個集中的請求處理機制,所有的請求都將由一個單一的處理程序處理。該處理程序可以做認(rèn)證/授權(quán)/記錄日志,或者跟蹤請求,然后把請求傳給相應(yīng)的處理程序。以下是這種設(shè)計模式的實體。 前端控制器(Front Controller) ?

    2024年02月13日
    瀏覽(21)
  • 森泰克sumtak控制器維修伺服驅(qū)動器維修SQ-12

    森泰克sumtak控制器維修伺服驅(qū)動器維修SQ-12

    日本森泰克sumtak控制器維修全系列型號。 控制器常見維修故障:短路,模塊損壞,帶不動負(fù)載,主軸準(zhǔn)備未緒,驅(qū)動器未使能,編碼器故障,主軸驅(qū)動模塊故障,輸出電壓低,紅色燈亮,無顯示,缺相,輸出控制點壞,使能不正常,報故障,不能啟動、過流、過壓、欠壓、過

    2024年02月09日
    瀏覽(21)
  • k8s控制器之job--第二彈編寫Job的定義

    與所有的 Kubernetes 對象一樣,Job 對象的 YAML 文件中,都需要包括如下三個字段: .apiVersion .kind .metadata Job 對象的 YAML 文件,還需要一個 .spec 字段。 .spec.template 是必填字段: 用于定義 pod template 與 Pod 有相同的字段內(nèi)容,但由于是內(nèi)嵌元素,pod template 不包括阿 apiVersion 字段和

    2024年02月10日
    瀏覽(51)
  • 第12關(guān) 精通K8s下的Ingress-Nginx控制器:生產(chǎn)環(huán)境實戰(zhàn)配置指南

    第12關(guān) 精通K8s下的Ingress-Nginx控制器:生產(chǎn)環(huán)境實戰(zhàn)配置指南

    ------ 課程視頻同步分享在今日頭條和B站 大家好,我是博哥愛運維,這節(jié)課帶來k8s的流量入口ingress,作為業(yè)務(wù)對外服務(wù)的公網(wǎng)入口,它的重要性不言而喻,大家一定要仔細(xì)閱讀,跟著博哥的教程一步步實操去理解。 Ingress基本概念 在Kubernetes集群中,Ingress作為集群內(nèi)服務(wù)對外

    2024年02月03日
    瀏覽(23)
  • thinkphp8.0多應(yīng)用模式下提示控制器不存在

    thinkphp8.0多應(yīng)用模式下提示控制器不存在

    thinkphp 8.0 開啟多應(yīng)用模式 1、按照官方文檔說明 ,已經(jīng)安裝了 think-multi-app composer require topthink/think-multi-app 2、控制器的命名空間也沒寫錯。 3、訪問路徑與目錄名、控制器、方法名一樣,訪問地址是沒錯的。 4、網(wǎng)上有說,在配置文件config/app.php中,將 ‘a(chǎn)uto_multi_app’ = flase

    2024年02月14日
    瀏覽(24)
  • k8s控制器之job--第六彈Job的模式

    Kubernetes Job 對象可以用來支持 Pod 的并發(fā)執(zhí)行,但是: Job 對象并非設(shè)計為支持需要緊密相互通信的Pod的并發(fā)執(zhí)行,例如科學(xué)計算 Job 對象支持并發(fā)處理一系列相互獨立但是又相互關(guān)聯(lián)的工作任務(wù),例如: 發(fā)送郵件 渲染頁面 轉(zhuǎn)碼文件 掃描 NoSQL 數(shù)據(jù)庫中的主鍵 其他 在一個復(fù)雜

    2024年02月10日
    瀏覽(20)
  • Linux6.39 Kubernetes Pod控制器

    Linux6.39 Kubernetes Pod控制器

    第三章 LINUX Kubernetes Pod控制器 一、Pod控制器及其功用 Pod控制器,又稱之為工作負(fù)載(workload),是用于實現(xiàn)管理pod的中間層,確保pod資源符合預(yù)期的狀態(tài),pod的資源出現(xiàn)故障時,會嘗試進(jìn)行重啟,當(dāng)根據(jù)重啟策略無效,則會重新新建pod的資源 二.pod控制器有多種類型 1.Replic

    2024年02月12日
    瀏覽(45)
  • Linux 中斷子系統(tǒng)中GIC 中斷控制器基本分析

    Linux 中斷子系統(tǒng)中GIC 中斷控制器基本分析

    GIC 是 ARM 公司給 Cortex-A/R 內(nèi)核提供的一個中斷控制器,類似 Cortex-M 內(nèi)核(STM32)中的 NVIC。 GIC:Generic Interrupt Controller,通用中斷控制器。 NVIC:Nested Vectored Interrupt Controller,嵌套中斷向量控制器。 目前 GIC 有 4 個版本:V1~V4,V1 是最老的版本,已經(jīng)被廢棄了。V2~V4 目前正在大

    2024年02月07日
    瀏覽(23)
  • linux高級---k8s中的五種控制器

    linux高級---k8s中的五種控制器

    Kubernetes中內(nèi)建了很多controller(控制器),這些相當(dāng)于一個狀態(tài)機,用來控制Pod的具體狀態(tài)和行為 總體來說,K8S有五種控制器,分別對應(yīng)處理無狀態(tài)應(yīng)用、有狀態(tài)應(yīng)用、守護(hù)型應(yīng)用和批處理應(yīng)用 無狀態(tài)服務(wù)的特點: 有狀態(tài)服務(wù)的特點: Deployment主要功能有下面幾個: 支持R

    2024年02月06日
    瀏覽(19)
  • Linux DMA子系統(tǒng)(2):DMA控制器驅(qū)動(provider)

    目錄 1. 前言 2. 重要的結(jié)構(gòu)體 2.1 struct dma_device 2.2 struct dma_chan 2.3?struct virt_dma_chan 3. 重要的API 3.1 注冊及注銷API 3.2 cookie相關(guān)API 4. DMA控制器驅(qū)動的編寫步驟 5. 參考文章 本文將從DMA控制器驅(qū)動(provider)的角度來介紹DMA Engine,包括重要的結(jié)構(gòu)體和API接口。 DMA控制器驅(qū)動主要作用

    2023年04月09日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包