当前位置: 首页 > article >正文

关于 spi 的linux 的驱动的问题

总体说明: 这个结构 我肯定 一次是 写不完的, 框架有了, 以后 有机会了,就会 不断去填充这些内容。

一、 首先是  在 对于 linux  spi 框架的 了解。

这是它的 总体的结构, 接口部分就是 spi core 。

1.5编程的内容 跟这个就很像了。

也就是 说 , 芯片原厂 实现的 就是 在 spi_sync 以下的部分。

这个接口 我之前看过 ,但是没看懂。

这个spi_locked  的目的 是什么呢?

这个控制器的 初始化的流程 我也没看懂。

先截图下来。

二、 然后是 对于具体的函数的了解。

spi_read()

spi_write()

spi_write_then_read()

这是具体的函数的实现,

drivers/spi/spi.c

 int spi_write_then_read(struct spi_device *spi,
  ▎   ▎   const void *txbuf, unsigned n_tx,
  ▎   ▎   void *rxbuf, unsigned n_rx)
  {
  ▎   static DEFINE_MUTEX(lock);
  ▎
  ▎   int         status;
  ▎   struct spi_message  message;
  ▎   struct spi_transfer x[2];
  ▎   u8          *local_buf;
  ▎
  ▎   /* Use preallocated DMA-safe buffer if we can.  We can't avoid
  ▎   ▎* copying here, (as a pure convenience thing), but we can
  ▎   ▎* keep heap costs out of the hot path unless someone else is
  ▎   ▎* using the pre-allocated buffer or the transfer is too large.
  ▎   ▎*/
  ▎   if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {
  ▎   ▎   local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx),
  ▎   ▎   ▎   ▎       GFP_KERNEL | GFP_DMA);
  ▎   ▎   if (!local_buf)
  ▎   ▎   ▎   return -ENOMEM;
  ▎   } else {
  ▎   ▎   local_buf = buf;
  ▎   }
  ▎
  ▎   spi_message_init(&message);
  ▎   memset(x, 0, sizeof(x));
  ▎   if (n_tx) {
  ▎   ▎   x[0].len = n_tx;
  ▎   ▎   spi_message_add_tail(&x[0], &message);
  ▎   }
  ▎   if (n_rx) {
  ▎   ▎   x[1].len = n_rx;
  ▎   ▎   spi_message_add_tail(&x[1], &message);
  ▎   }
  ▎
  ▎   memcpy(local_buf, txbuf, n_tx);
  ▎   x[0].tx_buf = local_buf;
  ▎   x[1].rx_buf = local_buf + n_tx;
  ▎
  ▎   /* do the i/o */
  ▎   status = spi_sync(spi, &message);
  ▎   if (status == 0)
  ▎   ▎   memcpy(rxbuf, x[1].rx_buf, n_rx);
  ▎
  ▎   if (x[0].tx_buf == buf)
  ▎   ▎   mutex_unlock(&lock);
  ▎   else
  ▎   ▎   kfree(local_buf);
  ▎
  ▎   return status;
  }
  EXPORT_SYMBOL_GPL(spi_write_then_read);

重点关注这两个地方。

首先是 关于 tx_buf , 与 rx_buf.

local_buf+n_tx, 它这里的意思是说, 将rx_buf 的地址,放到 tx_buf 地址的 后面。

直接 重新开一个buf 不是更好吗?

疑问: 还有就是 这里有两个 spi_transfer , 一个 设置了tx_buf 的内容, 另一个 只是设置了 rx_buf 的地址,没有设置发送什么内容。这样可以吗?

网上找了一个截图:

我感觉 这里的意思是:

如果我只是 设置了 rx_buf 的地址,tx_buf 没有设置, 那么我默认就在 tx_buf 中填null ,这也是发送, 还记得 spi_transfer 中有一个 len  吗? 这个length 既是在说 发送的长度,也是在说 接收的长度。

这只是我猜的,具体的 这块的实现, 我没找到。

关于 kthread_worker , kthread_work 的理解。

先来看看这两个函数的使用

网上的截图:

在 kthread_work 中  有真正的执行的函数

kthread_worker 中 有一个 tast_struct ,我比较感兴趣。

首先是初始化  kthread_worker

注意 : kthread_worker_fn 函数 并不执行spi 的逻辑。

然后是  kthread_work 的初始化。

注意: 这里的 这个 xxx_work_fn 才是 真正的 执行 spi 的逻辑的函数。

注意: kthread_queue_work 将 work 与worker 联系起来了。

然后是   kthread_run() 函数

网上的截图:

我的理解是, threadfn 这个只是一个 进程, 我设计做具体的事情, 后面肯定还有 某些流程,将worker 里面的具体的  spi 的 执行函数, 挂到这个进程上。

然后是  kthread_worker_fn  函数

代码如下:

int kthread_worker_fn(void *worker_ptr)
{
	struct kthread_worker *worker = worker_ptr;
	struct kthread_work *work;
 
	/*
	 * FIXME: Update the check and remove the assignment when all kthread
	 * worker users are created using kthread_create_worker*() functions.
	 */
	WARN_ON(worker->task && worker->task != current);
	worker->task = current;
 
	if (worker->flags & KTW_FREEZABLE)
		set_freezable();
 
repeat:
	set_current_state(TASK_INTERRUPTIBLE);	/* mb paired w/ kthread_stop */
 
	if (kthread_should_stop()) {
		__set_current_state(TASK_RUNNING);
		spin_lock_irq(&worker->lock);
		worker->task = NULL;
		spin_unlock_irq(&worker->lock);
		return 0;
	}
 
	work = NULL;
	spin_lock_irq(&worker->lock);
	if (!list_empty(&worker->work_list)) {
		work = list_first_entry(&worker->work_list,
					struct kthread_work, node);
		list_del_init(&work->node);
	}
	worker->current_work = work;
	spin_unlock_irq(&worker->lock);
 
	if (work) {
		__set_current_state(TASK_RUNNING);
		work->func(work);
	} else if (!freezing(current))
		schedule();
 
	try_to_freeze();
	cond_resched();
	goto repeat;
}
EXPORT_SYMBOL_GPL(kthread_worker_fn);

可以看到 比较重要的是   worker->task = current  这一句。

将 worker 的 tast ,设置成了 当前进程。

但是具体的还不是很了解。

九 、 我自己 关于 spi 有设备树 与没有设备树的 配置的区别,以及 对于 spi_board_info 的理解。

三 、 然后是 关于 mcp2515 的数据手册的解析。

四、 然后是 一些 需要注意的小点。

比如 spi 时钟的 时延的理解。

关于spi bit_word 的理解。

然后是 mcp2515 的 晶振 与 can 总线速率的关系。

五、 然后是 关于 通用的 spidev 的理解。

六 、然后是关于 gpio 模拟 spi 的理解。

七、 然后是关于 移植 mcp2515 的理解。

八、  是关于 stm32 对于 mcp2515 的使用。

这部分估计我没有时间做。


http://www.kler.cn/news/323494.html

相关文章:

  • Java和C语言语法细节(持续更新中)
  • pytorch ----【输入张量.data.size()/输入张量.size()】的使用
  • 基于MATLAB的虫害检测系统
  • Java实现找色和找图功能
  • 每天一道面试题(20):锁的发生原因和避免措施
  • C++ | 定长内存池 | 对象池
  • 【C语言】动态内存管理:malloc、calloc、realloc、free
  • 每天一道面试题(19):Spring Boot 中自动装配机制的原理
  • IIS开启后https访问出错net::ERR_CERT_INVALID
  • EasyExcel使用介绍
  • 【个人笔记】数据一致性的解决方案
  • 10.C++程序中的循环语句
  • RS485ESD-Enhanced, Fail-safe, Slew-Rate-limited RS-485/RS-422 Transceivers
  • 基于Hive和Hadoop的白酒分析系统
  • 信号处理: Block Pending Handler 与 SIGKILL/SIGSTOP 实验
  • 开关电源要做哪些测试?
  • Docker精讲:基本安装,简单命令及核心概念
  • ①无需编程 独立通道 Modbus主站EtherNet/IP转ModbusRTU/ASCII工业EIP网关串口服务器
  • 染色算法的简单概述
  • altera FPGA下载失败
  • MySQL之基础篇
  • 【bug fixed】hexo d的时候Spawn failed
  • c语言200例 066
  • Spring Boot实战:构建在线商城系统
  • PyQt5中关于QLineEdit的空输入报错的简单处理
  • 华为云发布全栈可观测平台AOM,以AI赋能应用运维可观测
  • Apache Cordova/PhoneGap
  • ConstructorParameters
  • 基于elasticsearch存储船舶历史轨迹
  • 基于SpringBoot+Vue的大学生勤工助学兼职管理系统