153 SPI数据传输剖析:同步、异步

SPI (四) -- spi_sync和spi_async的调用流程 内核版本:4.9.88前面我们分析了总线驱动模型,同时分析了如何编写设备驱动。只从上层使用角度去分析。因为内核的spi代码里已经提供好了相应的函数框架供我们使用,这里看一下最核心的两个函数spi_sync和spi_async。 阅读详情
AI摘要

本文深入解析了SPI控制器的驱动实现,包括spi_controller结构体、注册流程、数据传输机制及同步异步传输函数spi_sync和spi_async的具体实现。通过剖析关键函数如spi_register_controller、spi_controller_initialize_queue等,帮助读者理解SPI设备在Linux系统中的工作原理。

一、spi_controller 结构体框图

在这里插入图片描述
在这里插入图片描述

二、spi_register_master() 宏

include/linux/spi/spi.h

  • 调用流程
    spi_imx_probe
    ->spi_bitbang_start
    ->->spi_register_master
#define spi_register_master(_ctlr)	spi_register_controller(_ctlr)

spi_register_controller()函数

drivers/spi/spi.c

int spi_register_controller(struct spi_controller *ctlr)
{
	struct device		*dev = ctlr->dev.parent;
	struct boardinfo	*bi;
	int			status = -ENODEV;
	int			id, first_dynamic;
	...
	// spi控制器中的device成员设置一个名字
	dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
	// spi控制器中的device结构体加入到linux设备驱动模型
	status = device_add(&ctlr->dev);
    ...
    // 此成员是一个函数指针,此时还未初始化,第一个分支不会执行
    if (ctlr->transfer) {
		dev_info(dev, "controller is unqueued, this is deprecated\n");
	} else if (ctlr->transfer_one || ctlr->transfer_one_message) {
		status = spi_controller_initialize_queue(ctlr);// 即将执行
		...
	}
	...
	list_add_tail(&ctlr->list, &spi_controller_list);
	...
}
spi_controller_initialize_queue()函数

drivers/spi/spi.c

static int spi_controller_initialize_queue(struct spi_controller *ctlr)
{
	int ret;
	// 初始化一个成员函数指针
	ctlr->transfer = spi_queued_transfer;
	if (!ctlr->transfer_one_message)
		ctlr->transfer_one_message = spi_transfer_one_message;

	/* Initialize and start queue */
	ret = spi_init_queue(ctlr);
	if (ret) {
		dev_err(&ctlr->dev, "problem initializing queue\n");
		goto err_init_queue;
	}
	ctlr->queued = true;
	ret = spi_start_queue(ctlr);
	if (ret) {
		dev_err(&ctlr->dev, "problem starting queue\n");
		goto err_start_queue;
	}

	return 0;

err_start_queue:
	spi_destroy_queue(ctlr);
err_init_queue:
	return ret;
}
spi_init_queue()函数
  • 主要内容
    初始化内核线程工人
    初始化内核具体工作

drivers/spi/spi.c

static int spi_init_queue(struct spi_controller *ctlr)
{
	struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };

	ctlr->running = false;
	ctlr->busy = false;
	// 初始化一个内核工人
	kthread_init_worker(&ctlr->kworker);
	// 为worker创建一个内核线程
	ctlr->kworker_task = kthread_run(kthread_worker_fn, &ctlr->kworker,
					 "%s", dev_name(&ctlr->dev));
	if (IS_ERR(ctlr->kworker_task)) {
		dev_err(&ctlr->dev, "failed to create message pump task\n");
		return PTR_ERR(ctlr->kworker_task);
	}
	// 初始化一个具体的内核工作,参数2就是具体的处理函数
	kthread_init_work(&ctlr->pump_messages, spi_pump_messages);

	...

	return 0;
}
spi_start_queue()函数

启动内核具体工作(之前执行的spi_init_queue初始化worker,创建内核线程,初始化work)

drivers/spi/spi.c

static int spi_start_queue(struct spi_controller *ctlr)
{
	unsigned long flags;

	spin_lock_irqsave(&ctlr->queue_lock, flags);

	if (ctlr->running || ctlr->busy) {
		spin_unlock_irqrestore(&ctlr->queue_lock, flags);
		return -EBUSY;
	}

	ctlr->running = true;
	ctlr->cur_msg = NULL;
	spin_unlock_irqrestore(&ctlr->queue_lock, flags);
	// 将work交付给worker来完成
	kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);

	return 0;
}
spi_pump_messages()函数

内核工作具体处理函数

drivers/spi/spi.c

static void spi_pump_messages(struct kthread_work *work)
{
	struct spi_controller *ctlr =
		container_of(work, struct spi_controller, pump_messages);
	// 详见下
	__spi_pump_messages(ctlr, true);
}
__spi_pump_messages()函数

drivers/spi/spi.c

static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
{
	unsigned long flags;
	bool was_busy = false;
	int ret;
	...
	// spi_message结构体,spi_controller->queue链表链接着一系列spi_message
	// 获取链表中的第一个spi_message结构体,每次添加时都是添加到链表末尾
	ctlr->cur_msg =
		list_first_entry(&ctlr->queue, struct spi_message, queue);
	// 将第一个spi_message从上面的链表中删除
	list_del_init(&ctlr->cur_msg->queue);
	...
	// 函数指针,前面已经初始化好
	if (ctlr->prepare_message) {
		ret = ctlr->prepare_message(ctlr, ctlr->cur_msg);
		...
		ctlr->cur_msg_prepared = true;
	}
	...
	// 重要,发送,就是函数 spi_transfer_one_message
	ret = ctlr->transfer_one_message(ctlr, ctlr->cur_msg);
	...
}
	
spi_transfer_one_message()函数

drivers/spi/spi.c

static int spi_transfer_one_message(struct spi_controller *ctlr,
				    struct spi_message *msg)
{
	struct spi_transfer *xfer;
	bool keep_cs = false;
	int ret = 0;
	unsigned long long ms = 1;
	struct spi_statistics *statm = &ctlr->statistics;
	struct spi_statistics *stats = &msg->spi->statistics;
	...
	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
		...
		if (xfer->tx_buf || xfer->rx_buf) {
			reinit_completion(&ctlr->xfer_completion);
			// 其实就是spi_bitbang_taansfer_one,真正负责spi消息的发送
			ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
			...
			if (ret > 0) {
				ret = 0;
				ms = 8LL * 1000LL * xfer->len;
				do_div(ms, xfer->speed_hz);
				ms += ms + 200; /* some tolerance */

				if (ms > UINT_MAX)
					ms = UINT_MAX;

				ms = wait_for_completion_timeout(&ctlr->xfer_completion,
								 msecs_to_jiffies(ms));
			}
		
   	 	}
   	...
   	// 详见下
   	spi_finalize_current_message(ctlr);
   	...
}
spi_finalize_current_message()函数

drivers/spi/spi.c

void spi_finalize_current_message(struct spi_controller *ctlr)
{
	struct spi_message *mesg;
	unsigned long flags;
	int ret;
	
	...
	ctlr->cur_msg = NULL;
	ctlr->cur_msg_prepared = false;
	// 为内核worker添加一个新的处理工作,即spi_pump_message
	kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
	...
	mesg->state = NULL;
	// 不为空则唤醒之前阻塞的线程
	if (mesg->complete)
		mesg->complete(mesg->context);
}

三、spi_sync()函数

同步传输数据
会新创建一个内核线程去传输数据,在传输时会阻塞当前线程,传输线程在传输完会唤醒当前线程。
drivers/spi/spi.c

int spi_sync(struct spi_device *spi, struct spi_message *message)
{
	int ret;
	// 互斥锁相关
	mutex_lock(&spi->controller->bus_lock_mutex);
	ret = __spi_sync(spi, message);
	mutex_unlock(&spi->controller->bus_lock_mutex);

	return ret;
}

__spi_sync()函数

drivers/spi/spi.c

static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
	int status;
	struct spi_controller *ctlr = spi->controller;
	unsigned long flags;
	// 校验spi设备内各种通信的参数
	status = __spi_validate(spi, message);
	// 不正常直接返回
	if (status != 0)
		return status;
	// 函数指针初始化,会结束下面的阻塞
	message->complete = spi_complete;
	message->context = &done;
	message->spi = spi;
	...
	// 之前已经初始化,此处相等
	if (ctlr->transfer == spi_queued_transfer) {
		spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);

		trace_spi_message_submit(message);
		// 详见下
		status = __spi_queued_transfer(spi, message, false);

		spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
	} else {
		status = spi_async_locked(spi, message);
	}
	
	
	if (status == 0) {
		...
		// 会阻塞当前进程或线程
		wait_for_completion(&done);
		status = message->status;
	}
	message->context = NULL;
	return status;
}
__spi_queued_transfer()函数

drivers/spi/spi.c

static int __spi_queued_transfer(struct spi_device *spi,
				 struct spi_message *msg,
				 bool need_pump)
{
	struct spi_controller *ctlr = spi->controller;
	unsigned long flags;

	spin_lock_irqsave(&ctlr->queue_lock, flags);
	// 若spi控制器正在被占用,则执行此分支返回
	if (!ctlr->running) {
		spin_unlock_irqrestore(&ctlr->queue_lock, flags);
		return -ESHUTDOWN;
	}
	msg->actual_length = 0;
	msg->status = -EINPROGRESS;
	// spi_message 的链表节点链到spi_controller的链表中
	list_add_tail(&msg->queue, &ctlr->queue);
	if (!ctlr->busy && need_pump)//为内核工人添加一个具体的工作,将work交付给worker来完成
		kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);

	spin_unlock_irqrestore(&ctlr->queue_lock, flags);
	return 0;
}

四、spi_async()函数

异步传输数据

drivers/spi/spi.c

int spi_async(struct spi_device *spi, struct spi_message *message)
{
	...
	ret = __spi_async(spi, message);
	...
}

__spi_async()函数

drivers/spi/spi.c

static int __spi_async(struct spi_device *spi, struct spi_message *message)
{
	struct spi_controller *ctlr = spi->controller;
	...
	// 函数指针,即 spi_queued_transfer
	return ctlr->transfer(spi, message);
}
spi_queued_transfer()函数

drivers/spi/spi.c

static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{
	return __spi_queued_transfer(spi, msg, true);
}
__spi_queued_transfer()函数

drivers/spi/spi.c

static int __spi_queued_transfer(struct spi_device *spi,
				 struct spi_message *msg,
				 bool need_pump)
{
	struct spi_controller *ctlr = spi->controller;
	unsigned long flags;

	spin_lock_irqsave(&ctlr->queue_lock, flags);

	if (!ctlr->running) {
		spin_unlock_irqrestore(&ctlr->queue_lock, flags);
		return -ESHUTDOWN;
	}
	msg->actual_length = 0;
	msg->status = -EINPROGRESS;

	list_add_tail(&msg->queue, &ctlr->queue);
	if (!ctlr->busy && need_pump)
		kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);

	spin_unlock_irqrestore(&ctlr->queue_lock, flags);
	return 0;
}
Linux SPI子系统(2):SPI核心层 上次简单介绍了下Linux SPI子系统的系统结构,主要有3部分组成,分别是SPI核心、SPI总线驱动(控制器驱动)以及SPI设备驱动。SPI核心层代码位于drivers/spi/spi.c,头文件位于include/linux/spi/spi.h,SPI核心提供了SPI总线驱动和设备驱动的注册、注销方法,并提供一些需要控制器驱动实现的回调函数。本文主要介绍SPI核心层,包括重要的数据结构和API。 阅读详情

相关推荐

SPI全双工通信解读和调试问题分析汇总

致敬对这篇文档感兴趣的所有读者,关于对spi通信的解读,目前花费大概几个星期进行相关验证和调试,在这个过程中发生了很多奇怪的现象,一般来说spi控制形式多种多样,对于spi的全双工、半双工通信形式也会有所不同,这篇文档主要是帮助大家解读spi不同机制通信和相关问题分析,以供后期方便类似问题及时参考。本文档重点解读spi下相关控制机制,其中包括spi的控制器形式和spi的gpio通信形式多方位解读。

qq_54848172的博客 4074

spi_async 与spi_sync区别

spi_async 异步:使用spi_async()函数,它也可以用于原子上下文spi_sync 同步:使用 spi_sync函数,它可能处于睡眠状态,不用在中断上下文中,借助完成量机制,完成spi的同步通信操作(主要借助完成量的complete、wait_for_completion这两个接口,休眠不能用在中断上下文,中断或原子上下文可以用try_wait_for_completion()和completion_done()都可以在IRQ或原子上下文中安全调用)

qq_18804879的博客 1511

UART协议波特率匹配问题在工业现场的解决方案

深入解析UART协议在复杂工业环境中常见的波特率匹配难题,结合实际案例探讨通信稳定性与误差控制机制,提出有效的现场调试与容错方案,提升基于uart协议的设备间数据传输可靠性。

weixin_34725745的博客 834

Linux内核4.14版本——SPI框架(4)——spi传输以及master需要设置的字段

目录 1. spi_sync 1.1 __spi_validate(参数message检查) 1.2 transfer选择 1.2.1ctlr->transfer == spi_queued_transfer(没有定义ctlr->transfer,同步传输) 1.2.2spi_async_locked(定义ctlr->transfer)(异步传输) 1.3 等待传输完成 2. ctrl要实现的一些函数字段 2.1 如果设置ctlr->transfer则其不用设置,..

yangguoyu8023的博客 4279

SPI通信的同步与异步:如何在Linux内核中高效使用spi_sync和spi_async(含实战代码示例)

本文深入解析Linux内核中SPI通信的同步与异步机制,重点对比spi_sync和spi_async的工作原理、性能差异及适用场景。通过实战代码示例展示如何高效使用这两种接口,包括传感器数据读取和高速数据采集的实现,帮助开发者优化SPI驱动性能。文章还提供DMA集成、传输管道化等高级优化技巧,以及常见问题排查方法。

9o8p7i6u5y的博客 731

SPI (四) -- 深入解析spi_sync与spi_async的底层实现机制

本文深入解析Linux内核中SPI通信的spi_sync同步传输与spi_async异步传输的底层实现机制。通过分析调用流程、消息队列管理和工作线程处理等核心环节,揭示两种通信方式的性能差异与适用场景,并提供实战中的性能调优技巧与常见问题排查方法,帮助开发者优化嵌入式系统通信效率。

soda5的博客 910

TMS320VC5401 DSP时序分析实战:从时钟配置到PCB布局的硬件设计指南

时序分析是数字系统设计的基石,它定义了信号在时钟控制下建立、保持和传输的精确时间关系。其核心原理在于确保数据在接收端时钟的有效沿到来之前稳定(建立时间),并在之后保持足够长的时间(保持时间),从而被可靠采样。这项技术对于实现高速、稳定的数据通信至关重要,尤其在处理器与外部存储器、ADC/DAC等外设交互时。在嵌入式系统、通信设备和音视频处理等应用场景中,精确的时序控制是保障系统性能与可靠性的关键。本文聚焦于TMS320VC5401这款经典定点DSP,深入剖析其外部接口时序,涵盖时钟系统配置、存储器读写时序以

cojm55771的博客 415

【信息科学与工程学】计算机科学与自动化——第一百八十九篇 计算机硬件 系列一 微处理器01

在金融行业CDN流推送场景中,结合WebRTC over SD-RTN与SD-WAN Branch方案,需兼顾​​要求。

weixin_49199313的博客 1056

28335接两个spi设备_LINUX SPI模块之SPI 通信接口(spi_sync、spi_async)分析说明

上两篇文章完成了spi总线、设备、驱动、master的分析,下面我们分析下spi模块提供的通信方法,通过该通信方法,即可完成cpu与具体spi设备之间的通信(借助spi controller)。其实,spi_sync、spi_async的实现也不是太复杂,但是由于在新版内核中,针对spi_sync,spi核心提供了基于worker线程的处理方式,基于该方式则所有spi master均不需要提供sp...

weixin_30783947的博客 1736

【信息科学与工程学】【运营科学】第二篇 C4信息与通信网络运营 (C4) ——数据中心网络运营04

典型值:λ1​∈[−0.02,−0.01], λ2​∈[−0.01,0], η1​,η3​∈[0.1,0.3], η2​,η4​∈[0.05,0.15]参数:δ1​∈[−0.8,−0.3], δ2​∈[−0.5,−0.2], δ3​∈[−0.4,−0.1], δ4​∈[−0.6,−0.2]参数:φ1​∈[0.1,0.3], φ2​∈[−0.2,−0.05], φ3​∈[−0.1,0.1], φ4​∈[−0.3,−0.1]参数:α∈[0.3,0.6], β∈[0.2,0.4], γ∈[0.01,0.03]

weixin_49199313的博客 1207

PX4固件下VTOL固定翼的3种起飞方式对比:手抛vs弹射vs跑道

本文深度解析PX4固件下VTOL固定翼的三种起飞方式:手抛、弹射与跑道起飞,对比其技术差异与适用场景。通过详细的参数配置和工程实践指南,帮助开发者优化起飞性能,提升无人机在不同环境下的适应性和可靠性。文章特别针对PX4飞控系统的最新特性进行了技术探讨。

weixin_30296405的博客 87

LINUX SPI设备驱动模型分析之四 SPI 通信接口(spi_sync、spi_async)分析

上两篇文章完成了spi总线、设备、驱动、master的分析,下面我们分析下spi模块提供的通信方法,通过该通信方法,即可完成cpu与具体spi设备之间的通信(借助spi controller)。 其实,spi_sync、spi_async的实现也不是太复杂,但是由于在新版内核中,针对spi_sync,spi核心提供了基于worker线程的处理方式,基于该方式则所有spi ...

lickylin的专栏 1万+

spdk + fio测试nvme 设备的性能

fio的测试对象可以是块设备、文件等,在spdk的使用过程中会unbind默认的nvme driver,所以在系统中是看不到nvme块设备的,在spdk中可以通过fio_plugin的方式,将spdk的用户态driver部分的io功能打包成一个ioengine提供给fio使用,可以综合spdk的高性能和fio提供的复杂场景。更多DPDK相关学习资料有需要的可以自行报名学习,免费订阅,永久学习,或点击这里加。这个jobfile是spdk中提供的例子。领取,关注我持续更新哦!2.7 jobfile的例子。

lingshengxiyou的博客 1088

spi子系统

https://blog.youkuaiyun.com/alangaixiaoxiao/article/details/84146885 SPI协议通信 CPOL:Clock Polarity,就是时钟的极性 CPHA:Clock Phase,就是时钟的相位 如果主机在上升沿输出数据到MOSI上,从机就只能在下降沿去采样这个数据了。反之如果一方在下降沿输出数据,那么另一方就必须在上升沿采样这个数据 ...

qq_33600019的博客 2944

人脸关键点定义汇总

前几天看一份代码临时需要找49个人脸关键点位置定义的图片发现怎么百度都搜不到,最后幸好谷歌可以使用了就用谷歌搜到了。所以在这里汇总一下我所知道的人脸关键点的定义和相关的一点东西,以备不时之需。 68个关键点 最常用的工具是Dlib,网址:http://dlib.net/ dlib的68个特征点检测算法是ERT算法【1】 使用dlib检测68个特征点的python示例见:http://dlib.n...

程序媛 7642

多孔材料吸附性质模拟程序RASPA的离线和在线安装方法

RASPA-2.0是今年美国西北大学教授Randall Q. Snurr等人开发的针对于MC,MD,分子力学优化等用途的程序,相比于之前开发的MUSIC软件,RASPA的功能更加齐全,操作更加简便,可以在MC的吸附过程中考虑骨架的柔性,也可以想MUSIC一样先制作积分格点(music中的map)。 A、离线安装(centos为例): (1)、安装之前要检查一下是否装了automake,

youyno的博客 1万+

spi_sync()说明

Name spi_sync — blocking/synchronous SPI data transfers Synopsis int spi_sync ( struct spi_device * spi,   struct spi_message * message);   Arguments spi devi

wsclinux的专栏 6560

cadence CIS 库建立--建立自己维护的CIS数据库

遇到一个问题,在使用cadecnce的时候,就是没有自己的本地/分享的数据库。 在画原理图或者PCB的时候,如果能搭建一个自己的数据库,在局域网或者本地 就好了。出于这样的想法,做了一些探索,找到了一种可能的答案。 由于数据库编制知识的缺乏,要自己建一个数据库似乎花费的时间会比较多。 偶发奇想,如果能够改编CIS 自带的数据库 另建立副本进行维护 就能够省下不少麻烦。 先说下CIS 是个啥。网上一搜:总之CIS 是个好东西。 功能强大。 点击CIS capture 中的 Options CIS Config

qq_29776365的博客 2万+

Linux SPI驱动框架(1)——核心层

概述 linux SPI驱动框架主要分为核心层,控制器驱动层以及设备驱动层。具体结构可参考下图 图中,最下层是硬件空间,SPI总线控制器,总线控制器负责硬件上的数据交互, ...

深海 3391

Docker(八):Docker Compose(容器编排) 管理多容器应用—实战案例演示

🟢 Docker(八):Docker Compose(容器编排) 管理多容器应用—实战案例演示

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 6万+

基于嵌入式Linux设计的智能车库(GEC6818)

随着城市化进程的加快,传统停车管理方式存在效率低下、人工成本高、车主体验差等问题。为解决这些问题,本项目基于嵌入式Linux技术,设计并实现了一套智能车库管理系统。该系统采用GEC6818开发板作为核心控制器,运行Qt应用程序,并结合USB免驱摄像头进行车牌识别,RFID模块完成刷卡支付,SQLite数据库存储车主信息和停车记录。系统提供车主注册、用户管理、出入库管理、停车费结算、车辆查询等功能,并具备语音播报提示,提高用户体验。通过本系统,停车场管理更加高效、智能,有助于提升停车服务质量,减少人工干预,适

445

【Linux】Linux驱动开发:SPI子系统

SPI 驱动框架和 I2C 很类似,都分为主机控制器驱动和设备驱动,主机控制器也就是 SOC 的 SPI 控制器接口。样。和 I2C适配器驱动一样,SPI主机驱动一般都是 SOC 厂商去编写的,所以我们作为 SOC的使用者,这一部分的驱动就不用操心了。

W__winter的博客 3522

C#实战大华智能安防系统:从SDK封装到视频流与智能报警的全链路落地

本文将介绍C#集成大华SDK开发安防系统的实战经验,重点解决多路视频预览卡顿和报警延迟问题。文章通过三层架构设计(SDK封装层、业务服务层、应用层)实现解耦,详细分析线程安全封装、高效解码显示和智能事件联动等核心技术。针对16路摄像头同时预览时CPU占用率过高的问题,提出使用子码流拉流与异步解码的优化方案,并总结8个常见开发陷阱的解决方案。文中还提供了大华智能安防系统的完整架构图,展示从设备层到应用层的交互流程,特别强调业务服务层中视频流服务和智能报警服务的核心功能设计。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 431

SPI总线详解

SPI英文全称(Serial Perripheral Interface),即串行外围设备接口,是一种同步全双工串行接口,MCU可以通过SPI方式与各种外围设备进行高速数据通信

嵌入式学习记录站点 5736

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

SPI通信原理与异步方案介绍(RH850)

RH850 SPI异步通信方案

weixin_47348012的博客 3376

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

关于spi的半双工读写和全双工读写 spi.c spidev.c spidev_message() struct spi_ioc_transfer

一点理解,不知道是否正确,请指正. 在spidev.c有read write 以及spidev_message函数.分别实现半双工和全双工的功能.不过最后调用的都是spi控制器驱动的transfer函数.例如, atmel_spi_transfer() 【drivers/spi/atmel_spi.c 】 那么驱动如何判断应用程序要读还是写呢?简单,判断tx_buf或者

LYJ个人博客,记录技术、八卦、生活,分享各种心得,期待与朋友们一同进步 2万+

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

上一篇: 152 SPI主控制器驱动和核心函数
下一篇: 154 spidev:SPI“万能”驱动
你板子冒烟了
博客等级 码龄8年 1278粉丝 582原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值