spi 驱动程序

FPGA学习之SPI通讯--MASTER以及SLAVE端数据收发 1、MASTER端SPI代码:配置为模式0,一次传输8bit数据,可实现数据的收发;sclk,cs信号均由MASTER端产生。 2、SLAVE端SPI代码:配置为模式0,一次传输8bit数据。 阅读详情

spi 驱动


版权声明

spi 驱动

:欢迎转载,转载请注明出处 http://blog.youkuaiyun.com/lizuobin2/ https://blog.youkuaiyun.com/lizuobin2/article/details/51742443

SPI协议参考:

SPI协议及其工作原理浅析 

    http://bbs.chinaunix.net/thread-1916003-1-1.html

SPI总线协议及SPI时序图详解

    http://blog.163.com/sunshine_linting/blog/static/44893323201181482335951  


一、概述
    SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允许 MCU 以全双工的同步串行方式, 与各种外围设备进行高速数据通信.
    SPI 主要应用在 EEPROM, Flash, 实时时钟(RTC), 数模转换器(ADC), 数字信号处理器(DSP) 以及数字信号解码器之间. 它在芯片中只占用四根管脚 (Pin) 用来控制以及数据传输, 节约了芯片的 pin 数目, 同时为 PCB 在布局上节省了空间. 正是出于这种简单易用的特性, 现在越来越多的芯片上都集成了 SPI技术.

二、 特点

  1. 采用主-从模式(Master-Slave) 的控制方式
    SPI 规定了两个 SPI 设备之间通信必须由主设备 (Master) 来控制次设备 (Slave). 一个 Master 设备可以通过提供 Clock 以及对 Slave 设备进行片选 (Slave Select) 来控制多个 Slave 设备, SPI 协议还规定 Slave 设备的Clock 由 Master 设备通过 SCK 管脚提供给 Slave 设备, Slave 设备本身不能产生或控制 Clock, 没有 Clock 则 Slave 设备不能正常工作.
  2. 采用同步方式(Synchronous)传输数据
    Master 设备会根据将要交换的数据来产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号(Clock Signal) , 时钟信号通过时钟极性 (CPOL) 和 时钟相位 (CPHA) 控制着两个 SPI 设备间何时数据交换以及何时对接收到的数据进行采样, 来保证数据在两个设备之间是同步传输的.

  3. 数据交换(Data Exchanges)
    SPI 设备间的数据传输之所以又被称为数据交换, 是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 "发送者(Transmitter)" 或者 "接收者(Receiver)".在每个 Clock 周期内, SPI 设备都会发送并接收一个 bit 大小的数据, 相当于该设备有一个 bit 大小的数据被交换了.
    一个 Slave 设备要想能够接收到 Master 发过来的控制信号, 必须在此之前能够被 Master 设备进行访问 (Access). 所以, Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上.

    在数据传输的过程中,  每次接收到的数据必须在下一次数据传输之前被采样. 如果之前接收到的数据没有被读取, 那么这些已经接收完成的数据将有可能会被丢弃,  导致 SPI 物理模块最终失效. 因此, 在程序中一般都会在 SPI 传输完数据后, 去读取 SPI 设备里的数据, 即使这些数据(Dummy Data)在我们的程序里是无用的.

三、 工作机制 

  1. 概述


    通常情况下, 我们只需要对上图所描述的四个管脚(pin) 进行编程即可控制整个 SPI 设备之间的数据通信:
    SCK :Serial Clock主要的作用是 Master 设备往 Slave 设备传输时钟信号, 控制数据交换的时机以及速率;
    SS/CS:Slave Select/Chip Select, 用于 Master 设备片选 Slave 设备, 使被选中的 Slave 设备能够被 Master 设备所访问;
    SDO/MOSI: Serial Data Output/Master Out Slave In, 在 Master 上面也被称为 Tx-Channel, 作为数据的出口, 主要用于 SPI 设备发送数据;
    SDI/MISO: Serial Data Input/Master In Slave Out, 在 Master 上面也被称为 Rx-Channel, 作为数据的入口, 主要用于SPI 设备接收数据;
    SPI 设备在进行通信的过程中, Master 设备和 Slave 设备之间会产生一个数据链路回环(Data Loop), 就像上图所画的那样, 通过 SDO 和 SDI 管脚, SSPSR 控制数据移入移出 SSPBUF, Controller 确定 SPI 总线的通信模式, SCK 传输时钟信号.

  2.工作模式

    CPOL位表示初始时钟极性:
      CPOL = 0表示时钟初始为低电平,所以开始的第一(leading)边缘是上升沿,第二边缘(trailing)是下降沿。 
      CPOL = 1时的时钟启动为高电平,所以第一(leading)的边缘是下降沿。
    CPHA的指示用于采样数据的时钟相位(注意是采样数据,采样是指的将数据线上的数据所存起来)
      CPHA = 0时表示边沿超前
      CPHA = 1表示边沿滞后
  以 S3C2440 为例:


    模式0:CPOL = 0 CPHA = 0 主机从机的数据均是在下降沿改变,上升沿锁存
    模式1:CPOL = 0 CPHA = 1 主机从机的数据均是在上升沿改变,下降沿锁存
    模式2:CPOL = 1 CPHA = 0 主机从机的数据均是在上升沿改变,下降沿锁存
    模式3:CPOL = 0 CPHA = 1 主机从机的数据均是在下降沿改变,上升沿锁存
  以模式0为例,看看具体时序图:



     通常情况下,我们并不关心初始时钟电平状态,大多采用上升沿锁存,下降沿改变数据的方式,也就是模式0和模式3,下面看一个具体的spi_flash读数据的时序图

    显然,主机和从机都是在上升沿锁存数据,下降沿改变数据。

四、裸机程序
    在使用spi控制器的情况下,裸机程序十分简单,以 S3C2440 为例,简单说明一下。
      1、配置引脚
        1. 设置片选输出低电平
        2. 配置 GPE11 SPIMISO 、GPE12 SPIMOSI 、GPE13 SPICLK 为特殊功能引脚
      2、配置控制寄存器
        SPCONn[6-5]: SPI模式选择,查询 中断 DMA等
        SPCONn[4]  : 时钟使能
        SPCONn[3]  : 主机模式、从机模式
        SPCONn[2]  : CPOL
        SPCONn[1]  : CPHA
        SPCONn[0]  : 接收数据是是否自动发送,这里选普通模式,我们自己发送就好
      3、发送数据
        1、检查状态寄存器 传输是否可用 SPSTAn[0] 1表示可用,0表示正在发送或者接收
        2、将数据写入 SPTDATn
      4、接收数据
        1、检查状态寄存器 传输是否可用 SPSTAn[0] 1表示可用,0表示正在发送或者接收
        2、写数据 0xff 到 SPTDATn ,这就是普通模式的要求,接收的同时发送,0xff发送完了,数据也就接收完了
        3、检查状态寄存器 传输是否可用 SPSTAn[0] 1表示可用,0表示正在发送或者接收
        4、从 SPRDATn 取数据

static void SPIFlash_Set_CS(char val)
{
    if (val)
        GPGDAT |= (1<<10);
    else
        GPGDAT &= ~(1<<10);
}
static void SPI_GPIO_Init(void)
{
    /* GPG1 OLED_CSn output 
    * GPG10 FLASH_CSn output
    */
    GPGCON &= ~((3<<(1*2)) | (3<<(10*2)));
    GPGCON |= (1<<(1*2)) | (1<<(10*2));
    GPGDAT |= (1<<1) | (1<<10);
<span class="hljs-comment">/* 
* GPF3  OLED_DC   output
* GPE11 SPIMISO   
* GPE12 SPIMOSI   
* GPE13 SPICLK    
*/</span>
GPFCON &amp;= ~(<span class="hljs-number">3</span>&lt;&lt;(<span class="hljs-number">3</span>*<span class="hljs-number">2</span>));    
GPFCON |= (<span class="hljs-number">1</span>&lt;&lt;(<span class="hljs-number">3</span>*<span class="hljs-number">2</span>));    

GPECON &amp;= ~((<span class="hljs-number">3</span>&lt;&lt;(<span class="hljs-number">11</span>*<span class="hljs-number">2</span>)) | (<span class="hljs-number">3</span>&lt;&lt;(<span class="hljs-number">12</span>*<span class="hljs-number">2</span>)) | (<span class="hljs-number">3</span>&lt;&lt;(<span class="hljs-number">13</span>*<span class="hljs-number">2</span>)));
GPECON |= ((<span class="hljs-number">2</span>&lt;&lt;(<span class="hljs-number">11</span>*<span class="hljs-number">2</span>)) | (<span class="hljs-number">2</span>&lt;&lt;(<span class="hljs-number">12</span>*<span class="hljs-number">2</span>)) | (<span class="hljs-number">2</span>&lt;&lt;(<span class="hljs-number">13</span>*<span class="hljs-number">2</span>)));

}

void SPISendByte(unsigned char val)
{
while (!(SPSTA0 & 1));
SPTDAT0 = val;
}

unsigned char SPIRecvByte(void)
{
SPTDAT0 = 0xff;
while (!(SPSTA0 & 1));
return SPRDAT0;
}

static void SPIControllerInit(void)
{
/* OLED : 100ns, 10MHz
* FLASH : 104MHz
* 取10MHz
* 10 = 50 / 2 / (Prescaler value + 1)
* Prescaler value = 1.5 = 2
* Baud rate = 50/2/3=8.3MHz
*/

SPPRE0 = 2;
SPPRE1 = 2;

<span class="hljs-comment">/* [6:5] : 00, polling mode
* [4]   : 1 = enable 
* [3]   : 1 = master
* [2]   : 0
* [1]   : 0 = format A
* [0]   : 0 = normal mode
*/</span>
SPCON0 = (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">4</span>) | (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">3</span>);
SPCON1 = (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">4</span>) | (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">3</span>);

}

void SPIInit(void)
{
/* 初始化引脚 */
SPI_GPIO_Init();

SPIControllerInit();

}

    实际的SPI通信中,是由片选函数、字节读、字节写三部分组合而成~例如:

void SPIFlashRead(unsigned int addr, unsigned char *buf, int len)
{
    int i;
SPIFlash_Set_CS(<span class="hljs-number">0</span>);
SPISendByte(<span class="hljs-number">0x03</span>);
SPISendByte(addr &gt;&gt; <span class="hljs-number">16</span>);
SPISendByte(addr &gt;&gt; <span class="hljs-number">8</span>);
SPISendByte(addr &amp; <span class="hljs-number">0xff</span>);
<span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i &lt; len; i++)
    buf[i] = SPIRecvByte();

SPIFlash_Set_CS(<span class="hljs-number">1</span>);    

}

五、master 驱动实例详细分析
    上一篇文章中,分析了 master 和 spi 设备驱动的框架,我们知道 master 是在 atmel_spi_probe 函数中分配、设置、注册。其实在哪不重要,主要是设置的那些东西,我们再来看一下都设置了哪些东西

    master = spi_alloc_master(&pdev->dev, sizeof *as);  
  
    /* 设置 master  */  
    master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;   // 所支持的模式  
    master->bus_num = pdev->id;   // 控制器编号,用于分辨外围spi设备是连接在哪一个控制器上  
    master->num_chipselect = 4;  // 片选最大值+1,spi设备的片选值要小于它  
    master->setup = atmel_spi_setup; // 一个控制器上可能接有多个spi设备,它们的频率和模式是不一样的,用于设备之间切换时设置这些信息。  
    master->transfer = atmel_spi_transfer;   // 最重要的发送函数  
    ret = request_irq(irq, atmel_spi_interrupt, 0,  dev_name(&pdev->dev), master);
    master->transfer 函数,就跟I2c里的adapter->xxx_i2c_xfer函数一样,是最底层的发送接收函数,在spi中,设备驱动层调用到master层transfer函数的过程是这样的spi_sync(spi, &m)->spi_async(spi,&m)->master->transfer(spi, &m),也就是说,设备驱动层传递给我们一个spi_device 和 一个 spi_message ,还有一点值得注意的。

int spi_sync(struct spi_device *spi, struct spi_message *message)
{
	DECLARE_COMPLETION_ONSTACK(done);
	int status;
message-&gt;complete = spi_complete;
message-&gt;context = &amp;done;
status = spi_async(spi, message);
<span class="hljs-keyword">if</span> (status == <span class="hljs-number">0</span>) {
	wait_for_completion(&amp;done);
	status = message-&gt;status;
}
message-&gt;context = <span class="hljs-literal">NULL</span>;
<span class="hljs-keyword">return</span> status;

}

    在 spi_sync 中,调用 spi_async(spi, message) 之后,会 wait_for_completion(&done)休眠,那么我们在master的发送函数中,发送完成,自然要 mesg->complete(mesg->context),还要设置 mesg->status = 0

    在 spi_new_device 我们根据 Board_list 里的信息创建了 spi_device,它含有一下信息

struct spi_device *spi_new_device(struct spi_master *master,  
                  struct spi_board_info *chip)  
{  
    struct spi_device   *proxy;  
    int         status;  
proxy = spi_alloc_device(master);  

proxy-&gt;chip_select = chip-&gt;chip_select;  
proxy-&gt;max_speed_hz = chip-&gt;max_speed_hz;  
proxy-&gt;mode = chip-&gt;mode;  
proxy-&gt;irq = chip-&gt;irq;  
strlcpy(proxy-&gt;modalias, chip-&gt;modalias, <span class="hljs-keyword">sizeof</span>(proxy-&gt;modalias));  
proxy-&gt;dev.platform_data = (<span class="hljs-keyword">void</span> *) chip-&gt;platform_data;  
proxy-&gt;controller_data = chip-&gt;controller_data;  
proxy-&gt;controller_state = <span class="hljs-literal">NULL</span>;  

status = spi_add_device(proxy);  

<span class="hljs-keyword">return</span> proxy;  

}

    对于 spi_message,它对应于一个不可打断的spi传输过程,可以理解为片选选中直到取消选中的过程(特殊情况下,一个spi_message里面是可以取消片选再选中的),而 spi_message 由 spi_transfer 组成,根据 tx_buf  rx_buf 是否为空来判断是 写还是读 操作。

    那么,我们master->transfer函数需要做什么?

      1、传输前,根据 spi_device 里的信息,对 master 进行设置(调用master->setup),因为一个spi控制器可能接有多个spi设备,它们的频率 模式可能是不一样的
      2、取出 spi_message 里的 spi_transfer 进行寄存器操作,发送或接收,这个过程和 I2C 的传输过程是类似的。
    下面开始分析代码,先看setup函数。代码参考:韦东山老师的spi教程

static int s3c2440_spi_setup(struct spi_device *spi)
{
    struct s3c_spi_info *info;
    struct clk *clk;
<span class="hljs-keyword">int</span> cpol = <span class="hljs-number">0</span>;
<span class="hljs-keyword">int</span> cpha = <span class="hljs-number">0</span>;

<span class="hljs-keyword">int</span> div;

info = spi_master_get_devdata(spi-&gt;master);
clk = clk_get(<span class="hljs-literal">NULL</span>, <span class="hljs-string">"plck"</span>);

<span class="hljs-comment"><span class="hljs-comment">/* 设置传输模式 : mode</span>

* 传输频率 : max_speed_hz
* bits_per_word : 不用管
*/

<span class="hljs-comment">/* spi_mode: CPOL,CPHA组成一个值,0,1,2,3
 */</span>

<span class="hljs-keyword">if</span> (spi-&gt;mode &amp; <span class="hljs-number">1</span>)
{
    cpha = <span class="hljs-number">1</span>;
}
<span class="hljs-keyword">if</span> (spi-&gt;mode &amp; <span class="hljs-number">2</span>)
{
    cpol = <span class="hljs-number">1</span>;
}

<span class="hljs-comment">/* 写入SPCON0,1 */</span>
<span class="hljs-comment">/* [6:5] : 01, polling mode
 * [4]   : 1 = enable 
 * [3]   : 1 = master
 * [2]   : CPOL
 * [1]   : CPHA
 * [0]   : 0 = normal mode
 */</span>
writeb((<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">5</span>) | (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">4</span>) | (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">3</span>) | (cpol &lt;&lt; <span class="hljs-number">2</span>) | (cpha &lt;&lt; <span class="hljs-number">1</span>), info-&gt;reg_base + S3C2410_SPCON);

<span class="hljs-comment">/*
 * Baud rate = PCLK / 2 / (Prescaler value + 1)
 * Prescaler value = PCLK/(2*Baud rate) - 1
 * Prescaler Value : 0,1,...,255
 */</span>
div = DIV_ROUND_UP(clk_get_rate(clk), spi-&gt;max_speed_hz * <span class="hljs-number">2</span>) - <span class="hljs-number">1</span>;
clk_put(clk);

<span class="hljs-keyword">if</span> (div &gt; <span class="hljs-number">255</span>)
	div = <span class="hljs-number">255</span>;

writeb(div, info-&gt;reg_base + S3C2410_SPPRE);
    
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

}

    info 是我们用 spi_alloc_master 申请内存时多申请出来的那个自定义结构体,韦东山老师在里面放了 寄存器基地址等信息,后面完整代码会看到,setup 函数很简单,就是根据 spi_device 里的模式,设置master的模式,根据 spi_device 的最大频率,设置 master 的工作频率。

  下面来看transfer函数
    思路:

      1、首先一个 spi_message 对应一个 片选过程,我们要先片选

      2、master->setup
      3、取出 spi_message 中的 第一个 spi_transfer

        如果是读:跟裸机一样,先写0xff,等待中断

        如果是写:那么将 spi_transfer->tx_buf[0]里的数据写到寄存器,等待休眠

     何时唤醒?

        在中断服务程序里,判断当前 spi_transfer 的发送接收完毕了,唤醒,取出下一个 spi_transfer ,如果有所得 spi_transfer 传输完了,则唤醒设备驱动层进程

     中断服务程序:

        读:先把上次读的取出来,判断是否还有数据要读?如果有则继续发送0xff,等待中断,没有则唤醒,进入下一个spi_transfer

        写:判断当前 spi_transfer 的发送是否完成,没有完成则把下一个Buf里的数据发送或接收。完成了,则唤醒,进入下一个spi_transfer。


附上韦东山老师完整源码:

#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/slab.h>

#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/spi/s3c24xx.h>
#include <linux/module.h>

#include <plat/regs-spi.h>
#include <mach/regs-gpio.h>

/* 构造注册spi_master */

static struct spi_master *spi0_controller;
static struct spi_master *spi1_controller;

struct s3c_spi_info {
int irq;
unsigned int reg_base;
struct completion done;
struct spi_transfer *cur_t;
int cur_cnt;
struct platform_device *pdev;
};

static int s3c2440_spi_setup(struct spi_device *spi)
{
struct s3c_spi_info *info;
struct clk *clk;

<span class="hljs-keyword">int</span> cpol = <span class="hljs-number">0</span>;
<span class="hljs-keyword">int</span> cpha = <span class="hljs-number">0</span>;

<span class="hljs-keyword">int</span> div;

info = spi_master_get_devdata(spi-&gt;master);
clk = clk_get(<span class="hljs-literal">NULL</span>, <span class="hljs-string">"plck"</span>);

<span class="hljs-comment"><span class="hljs-comment">/* 设置传输模式 : mode</span>

* 传输频率 : max_speed_hz
* bits_per_word : 不用管
*/

<span class="hljs-comment">/* spi_mode: CPOL,CPHA组成一个值,0,1,2,3
 */</span>

<span class="hljs-keyword">if</span> (spi-&gt;mode &amp; <span class="hljs-number">1</span>)
{
    cpha = <span class="hljs-number">1</span>;
}
<span class="hljs-keyword">if</span> (spi-&gt;mode &amp; <span class="hljs-number">2</span>)
{
    cpol = <span class="hljs-number">1</span>;
}

<span class="hljs-comment">/* 写入SPCON0,1 */</span>
<span class="hljs-comment">/* [6:5] : 01, polling mode
 * [4]   : 1 = enable 
 * [3]   : 1 = master
 * [2]   : CPOL
 * [1]   : CPHA
 * [0]   : 0 = normal mode
 */</span>
writeb((<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">5</span>) | (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">4</span>) | (<span class="hljs-number">1</span>&lt;&lt;<span class="hljs-number">3</span>) | (cpol &lt;&lt; <span class="hljs-number">2</span>) | (cpha &lt;&lt; <span class="hljs-number">1</span>), info-&gt;reg_base + S3C2410_SPCON);

<span class="hljs-comment">/*
 * Baud rate = PCLK / 2 / (Prescaler value + 1)
 * Prescaler value = PCLK/(2*Baud rate) - 1
 * Prescaler Value : 0,1,...,255
 */</span>
div = DIV_ROUND_UP(clk_get_rate(clk), spi-&gt;max_speed_hz * <span class="hljs-number">2</span>) - <span class="hljs-number">1</span>;
clk_put(clk);

<span class="hljs-keyword">if</span> (div &gt; <span class="hljs-number">255</span>)
	div = <span class="hljs-number">255</span>;

writeb(div, info-&gt;reg_base + S3C2410_SPPRE);
    
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

}

static int s3c2440_spi_transfer(struct spi_device *spi, struct spi_message *mesg)
{
struct spi_master *master = spi->master;
struct s3c_spi_info *info;
struct spi_transfer *t = NULL;

info = spi_master_get_devdata(master);

<span class="hljs-comment">/* 1. 选中芯片 */</span>
s3c2410_gpio_setpin(spi-&gt;chip_select, <span class="hljs-number">0</span>);  <span class="hljs-comment">/* 默认为低电平选中 */</span>

<span class="hljs-comment">/* 2. 发数据 */</span>

<span class="hljs-comment">/* 2.1 发送第1个spi_transfer之前setup */</span>
master-&gt;setup(spi);

<span class="hljs-comment">/* 2.2 从spi_message中逐个取出spi_transfer,执行它 */</span>
list_for_each_entry (t, &amp;mesg-&gt;transfers, transfer_list) {
    <span class="hljs-comment">/* 处理这个spi_transfer */</span>
    info-&gt;<span class="hljs-keyword">cur_t</span> = t;
    info-&gt;cur_cnt = <span class="hljs-number">0</span>;
	init_completion(&amp;info-&gt;done);

    <span class="hljs-comment">/* 如果该spi_transfer的speed_hz或bits_per_word
     * 不是0, 则调用setup来设置
     */</span>

    <span class="hljs-keyword">if</span> (t-&gt;tx_buf)
    {
        <span class="hljs-comment">/* 发送 */</span>
        writeb(((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)t-&gt;tx_buf)[<span class="hljs-number">0</span>], info-&gt;reg_base + S3C2410_SPTDAT);

        <span class="hljs-comment">/* 它会触发中断 */</span>

        <span class="hljs-comment">/* 休眠 等待当前transfer 发送完毕 */</span>
        wait_for_completion(&amp;info-&gt;done);
    }
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(t-&gt;rx_buf)
    {
        <span class="hljs-comment">/* 接收 */</span>
        writeb(<span class="hljs-number">0xff</span>, info-&gt;reg_base + S3C2410_SPTDAT);
        <span class="hljs-comment">/* 它会触发中断 */</span>

        <span class="hljs-comment">/* 休眠 等待当前 transfer 接收完毕 */</span>
        wait_for_completion(&amp;info-&gt;done);
    }

    <span class="hljs-comment">/* 如果该spi_transfer的cs_change为1
     * 则取消片选
     */</span>
}


<span class="hljs-comment">/* 2.3 唤醒等待的进程 */</span>
mesg-&gt;status = <span class="hljs-number">0</span>;
mesg-&gt;complete(mesg-&gt;context);    

<span class="hljs-comment">/* 3. 取消片选 */</span>
s3c2410_gpio_setpin(spi-&gt;chip_select, <span class="hljs-number">1</span>);  <span class="hljs-comment">/* 默认为低电平选中 */</span>

<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

}

static irqreturn_t s3c2440_spi_irq(int irq, void *dev_id)
{
struct spi_master *master = (struct spi_master *)dev_id;
struct s3c_spi_info *info = spi_master_get_devdata(master);
struct spi_transfer *t = info->cur_t;

<span class="hljs-keyword">if</span> (!t)
{
    <span class="hljs-comment">/* 误触发 */</span>
	<span class="hljs-keyword">return</span> IRQ_HANDLED;            
}

<span class="hljs-comment">/* 处理 spi_transfer */</span>

<span class="hljs-keyword">if</span> (t-&gt;tx_buf) <span class="hljs-comment">/* 是发送 */</span>
{
    info-&gt;cur_cnt++;
    
    <span class="hljs-keyword">if</span> (info-&gt;cur_cnt &lt; t-&gt;len)<span class="hljs-comment">/* 没发完? */</span>
        writeb(((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)t-&gt;tx_buf)[info-&gt;cur_cnt], info-&gt;reg_base + S3C2410_SPTDAT);        
    <span class="hljs-keyword">else</span>
        complete(&amp;info-&gt;done); <span class="hljs-comment">/* 唤醒 */</span>
}
<span class="hljs-keyword">else</span> <span class="hljs-comment">/* 接收 */</span>
{
    <span class="hljs-comment">/* 读/存数据 */</span>
    ((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)t-&gt;rx_buf)[info-&gt;cur_cnt] = readb(info-&gt;reg_base + S3C2410_SPRDAT);
    info-&gt;cur_cnt++;
    
    <span class="hljs-keyword">if</span> (info-&gt;cur_cnt &lt; t-&gt;len)<span class="hljs-comment">/* 没收完? */</span>
        writeb(<span class="hljs-number">0xff</span>, info-&gt;reg_base + S3C2410_SPTDAT);        
    <span class="hljs-keyword">else</span>
        complete(&amp;info-&gt;done); <span class="hljs-comment">/* 唤醒 */</span>
}
<span class="hljs-keyword">return</span> IRQ_HANDLED;    

}

static void s3c2440_spi_controler_init(int which)
{
struct clk *clk = clk_get(NULL, “spi”);

<span class="hljs-comment">/* 使能spi controller 0/1的时钟 */</span>
clk_enable(clk);
clk_put(clk);

<span class="hljs-comment">/* GPIO */</span>
<span class="hljs-keyword">if</span> (which == <span class="hljs-number">0</span>)
{
    <span class="hljs-comment">/* SPI controller 0 */</span>
    <span class="hljs-comment">/*
     * GPE11 SPIMISO   
     * GPE12 SPIMOSI   
     * GPE13 SPICLK    
     */</span>
    s3c2410_gpio_cfgpin(S3C2410_GPE(<span class="hljs-number">11</span>), S3C2410_GPE11_SPIMISO0);
    s3c2410_gpio_cfgpin(S3C2410_GPE(<span class="hljs-number">12</span>), S3C2410_GPE12_SPIMOSI0);
    s3c2410_gpio_cfgpin(S3C2410_GPE(<span class="hljs-number">13</span>), S3C2410_GPE13_SPICLK0);        

}
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (which == <span class="hljs-number">1</span>)
{
    <span class="hljs-comment">/* SPI controller 1 */</span>
    <span class="hljs-comment">/*
     * GPG5 SPIMISO   
     * GPG6 SPIMOSI   
     * GPG7 SPICLK    
     */</span>
    s3c2410_gpio_cfgpin(S3C2410_GPG(<span class="hljs-number">5</span>), S3C2410_GPG5_SPIMISO1);
    s3c2410_gpio_cfgpin(S3C2410_GPG(<span class="hljs-number">6</span>), S3C2410_GPG6_SPIMOSI1);
    s3c2410_gpio_cfgpin(S3C2410_GPG(<span class="hljs-number">7</span>), S3C2410_GPG7_SPICLK1);        

    <span class="hljs-comment">/* 使能spi controller 1的时钟 */</span>
}

}

static struct spi_master *create_spi_master_s3c2440(int bus_num, unsigned int reg_base_phy, int irq)
{
int ret;
struct spi_master *master;
struct s3c_spi_info *info;
struct platform_device *pdev;

pdev = platform_device_alloc(<span class="hljs-string">"s3c2440_spi"</span>, bus_num);
platform_device_add(pdev);

master = spi_alloc_master(&amp;pdev-&gt;dev, <span class="hljs-keyword">sizeof</span>(struct s3c_spi_info));
master-&gt;bus_num = bus_num;
master-&gt;num_chipselect = <span class="hljs-number">0xffff</span>;
master-&gt;mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;

master-&gt;setup    = s3c2440_spi_setup;
master-&gt;transfer = s3c2440_spi_transfer;

info = spi_master_get_devdata(master);
info-&gt;reg_base = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)ioremap(reg_base_phy, <span class="hljs-number">0x18</span>);
info-&gt;irq = irq;
info-&gt;pdev = pdev;

<span class="hljs-comment">/* 硬件初始化 */</span>
s3c2440_spi_controler_init(bus_num);

ret = request_irq(irq, s3c2440_spi_irq, <span class="hljs-number">0</span>, <span class="hljs-string">"s3c2440_spi"</span>, master);

spi_register_master(master);

<span class="hljs-keyword">return</span> master;

}

static void destroy_spi_master_s3c2440(struct spi_master *master)
{
struct s3c_spi_info *info = spi_master_get_devdata(master);;

spi_unregister_master(master);
platform_device_del(info-&gt;pdev);
platform_device_put(info-&gt;pdev);
free_irq(info-&gt;irq, master);
iounmap((<span class="hljs-keyword">void</span> *)info-&gt;reg_base);
<span class="hljs-comment">//kfree(master);</span>

}

static int spi_s3c2440_init(void)
{
spi0_controller = create_spi_master_s3c2440(0, 0x59000000, IRQ_SPI0);
spi1_controller = create_spi_master_s3c2440(1, 0x59000020, IRQ_SPI1);

<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

}

static void spi_s3c2440_exit(void)
{
destroy_spi_master_s3c2440(spi0_controller);
destroy_spi_master_s3c2440(spi1_controller);
}

module_init(spi_s3c2440_init);
module_exit(spi_s3c2440_exit);
MODULE_DESCRIPTION(“SPI Controller Driver”);
MODULE_AUTHOR("weidongshan@qq.com,www.100ask.net");
MODULE_LICENSE(“GPL”);







SPI通讯原理,SPI驱动程序编写,EEPROM,Tja1145,CAN收发器驱动程序,嵌入式,单片机,软件 一、SPI通信原理讲解 0.架构讲解 1.通常CPU芯片(如TI的280049、英飞凌的TC234)中集成了SPI模块,CPU可使用SPI通讯模块实现与外部设备的通讯,如CPU与EEPROM模块的通讯,CPU与Tja1145模块的通讯,都是通过SPI模块实现的 2.当需要实现与Tja1145的通讯,在软件上需要两个驱动程序才能实现:SPI驱动程序、Tja1145驱动程序 2.1 SPI驱动程序,需要参考280049的芯片手册,芯片手册中会注明一系列SPI相关的系统寄存器,通过操作SPI系统寄存器就可以实现调 阅读详情

相关推荐

SPI驱动学习六(SPI_Master驱动程序)

SPI 是“串行外设接口”的缩写,它在嵌入式系统中广泛使用,因为它是一个简单且高效的接口:基本上是一个多路复用的移位寄存器。它的三个信号线分别为时钟线(SCK,通常在 1-20 MHz 范围内)一个“主机输出从机输入”(MOSI)数据线和一个“主机输入从机输出”(MISO)数据线。SPI 是一种全双工协议;每在MOSI线上移出一位(每时钟一位),MISO线上就会移入一位。这些位在去往和从系统内存传送的过程中会被组装成各种大小的字。一个额外的芯片选择线通常是低电平有效的(nCS);

小嵌同学的博客 2323

spi协议->裸机程序->master驱动程序分析

SPI协议参考: SPI协议及其工作原理浅析      http://bbs.chinaunix.net/thread-1916003-1-1.html SPI总线协议及SPI时序图详解                                                                                 http://blog.163.com/sun

漫不经心 5130

SPI驱动学习七(SPI_Slave_Mode驱动程序框架)

使用SPI传输时,最小的传输单位是"spi_transfer",对于一个设备,可以发起多个spi_transfer,这些spi_transfer,会放入一个spi_message里。从spi_master的队列里取出每一个spi_message从spi_message的队列里取出一个spi_transfer处理spi_transfer。

小嵌同学的博客 3787

spi总线概述1(spi-summary)

什么是SPI? ------------ “串行外设接口”(SPI)是一个同步的四线串行链接用于微控制器连接传感器,内存和外设的。这是一个简单的“时点”的标准,获取一个标准化结构也不复杂。 SPI使用主/从配置。   三个信号线外加一个时钟(SCK,往往在10 MHz),并行数据线“主机输出,从机输入”(MOSI)或“主机输入,从机输出”(MISO)。数据交换有四种时钟模式:模式0和模式3

zhangxiaopeng0829的专栏 4896

SpiIdleTime/SpiTrailingTime/SpiTimeClk2Cs三个配置项的含义(三)

在对SPI模块进行MCAL配置时,有三个时间相关参数SpiIdleTime/ SpiTrailingTime/ SpiTimeClk2Cs,很多人不了解其具体含义,下面对其做一个具体的说明,并通过示波器测试SPI传输波形,验证与实际配置值是否一致。

m0_38045338的博客 1981

《我的 Classic Platform AUTOSAR之路》 SPI介绍与EB配置

AUTOSAR SPI配置解析 AUTOSAT SPI 以下内容基于标准AUTOSAR文档以及EB Tresos工具说明 SPI 在AUTOSAR的配置主要参数 波特率 极性相位 CS使能电平 CLK Idle电平 数据大小端 数据位宽 数据长度 CS2CLK时间 CLK2CS时间 CS2CS时间 SPI通信模式(同步 or 异步) Buffer模式(IB or EB) … SPI波特率设置 ...

libuping2023的博客 1万+

SPI驱动(二) -- SPI驱动程序模型

本文描述了SPI驱动程序模型。

zpz979994367的博客 1086

全面掌握OLED驱动程序开发与SPI通信

OLED驱动集成电路(IC)是OLED显示屏的心脏,负责管理和控制像素点的发光。这些IC可以分为两大类:通用驱动IC和专用驱动IC。通用驱动IC提供基本的显示功能,适用于标准分辨率和简单的应用需求。专用驱动IC则提供更高级的功能,如色彩深度扩展、复杂图形处理能力以及更高效的电源管理。例如,SSD1306是一款广泛使用的通用OLED驱动IC,常用于小型显示屏,其具有内置RAM和简单命令集,可以轻松控制文本显示和基本图形。

weixin_35516624的博客 1053

编写SPI_Master驱动程序_老方法

在SPI Master对应的设备树节点下,每一个子节点都对应一个SPI设备,这个SPI设备连接在该SPI Master下面。在这样一个速食的时代,坚持做自己,慢下来,潜心琢磨,心怀敬畏,领悟知识,才能向下扎到根,向上捅破天,背着世界往前行!其他属性都是驱动程序相关的,不同的SPI Master驱动程序要求的属性可能不一样。仅此向嵌入行业里的每一个认真做技术的从业者致敬!

jia_weihui的博客 1025

Cortex-M0 SPI驱动程序及CMSIS接口应用

Cortex-M0处理器作为ARM架构中的低成本、低能耗解决方案,其对SPI(Serial Peripheral Interface)驱动程序的支持是实现高效、稳定外设通信的关键。了解和掌握Cortex-M0处理器的SPI驱动程序设计,对于提升嵌入式系统整体性能至关重要。串行外设接口(Serial Peripheral Interface,简称SPI)是一种高速的,全双工,同步的通信总线。这种接口最早由Motorola公司于1980年代早期开发,最初用于连接微处理器(MCU)和周边设备。

weixin_42588555的博客 852

WK2124芯片SPI驱动程序开发历程与实践

SPI(Serial Peripheral Interface)是一种常见的串行通信协议,它允许微控制器(MCU)与各种外围设备以串行方式通信,包括传感器、模数转换器(ADC)、数字信号处理器(DSP)等。SPI协议以其高速率和全双工通信特性在嵌入式系统中得到广泛应用。WK2124是一个高性能的微控制器(MCU),通常用于需要实时处理和I/O控制的嵌入式系统。它集成了丰富的外设接口和高性能处理能力,使其在工业控制、消费电子、智能设备等领域有着广泛的应用。

weixin_32102617的博客 1261

SPI master驱动程序概述

<br />  SPI驱动程序包括两部分,一部分是SPI设备的驱动程序,另一部分是SPI Master的驱动程序。SPI设备驱动程序架设在SPI Master驱动程序的上层,它通过SPI Master驱动提供的接口来对SPI设备进行操作。SPI设备一般都是EEPROM或者FLASH等比较简单的设备,其设备驱动程序比较简单。本文主要描述SPI Master的驱动程序。<br />  首先描述一下SPI Master和SPI设备之间的硬件连线,有CLK,MOSI,MISO,片选等。CLK是时钟信号。MOSI即M

biger410的专栏 1927

Win10家庭版中文用户名改英文全攻略:从注册表到环境变量一步不落

本文详细介绍了Windows 10家庭版中文用户名改为英文的完整流程,包括注册表编辑、环境变量调整等关键步骤。通过激活管理员账户、重命名用户文件夹、修改注册表键值等操作,彻底解决因中文路径导致的软件兼容性问题,并提供常见错误解决方案和系统维护建议。

weixin_29227425的博客 427

SPI驱动程序(ICM20608)

在之前的文章中写了i2c的驱动程序,我们可以知道i2c的传输速度较慢,且为半双工的通信模式。而这篇文章讲解的SPI解决了以上的两个缺点包含了与 SPI 传输相关的各种信息,如传输的长度、数据缓冲区指针、传输标志等,使得 SPI 控制器能够根据这些信息正确地执行数据传输操作。在使用spi_transfer函数前应该先使用kzalloc函数为结构体在内核内存中分配一块内存地址,在使用tx_buf和rx_buf时也同样要分配一份内存地址给它们,当然在声明完之后应该使用kfree函数去释放内存,防止内存泄漏。

2201_75493615的博客 722

SAP物料分类账实战:从配置到月结的关键步骤(基于S/4HANA1909)

本文详细解析了在SAP S/4HANA 1909系统中,物料分类账从基础配置到月结操作的全流程。作为成本核算的核心,物料分类账通过多级价格确定实现实际成本核算,关键步骤包括激活物料分类账、配置自动过账科目(OBYC)、运行CKMLCP进行差异分摊与结算。文章旨在帮助财务与成本会计人员确保成本差异的准确归集与分摊,顺利完成月结。

weixin_28314575的博客 195

Crossformer实战:从零开始搭建多变量时间序列预测模型(附ETTh1数据集调参指南)

本文提供了从零开始搭建Crossformer多变量时间序列预测模型的实战指南,并附有详细的ETTh1数据集调参攻略。文章深入解析了Crossformer的核心设计,重点探讨了seg_len和win_size等关键参数对模型性能的影响,并分享了环境配置、训练调试及常见问题的解决方案,帮助开发者高效应用这一前沿深度学习模型。

weixin_29281915的博客 317

STM32F407的CAN,USART,SPI的驱动程序

STM32F407的CAN,USART,SPI的驱动程序 去发现同类优质开源项目:https://gitcode.com/ 简介 本仓库包含了STM32F407微控制器的CAN、USART和SPI通信接口的驱动程序代码。这些代码是作者针对STM32F407微控制器自主编写的,涵盖了CAN接收和中断接收、USART的DMA接收和中断接收,以及SPI的中断接收。SPI的DMA接收功能尚未调试成功。 驱...

gitblog_06737的博客 334

手把手教你用Simulink给C2000配置SCI串口发送数据(附模型与避坑点)

本文详细介绍了如何使用Simulink为C2000系列微控制器配置SCI串口发送数据,包括硬件资源分配、模型搭建、参数设置及调试技巧。通过代码生成和串口通信实践,帮助开发者高效实现嵌入式系统开发,避免常见通信问题。

weixin_30831529的博客 295

AD7789 SPI接口驱动程序

AD7789 SPI接口驱动程序 去发现同类优质开源项目:https://gitcode.com/ 简介 本仓库提供了适用于STM32微控制器的AD7789芯片的SPI接口驱动程序。该程序通过IO模拟SPI通信方式,实现与AD7789芯片的可靠连接和数据交互。 文件内容 spi接口AD7789.rar:包含STM32平台下的AD7789驱动程序及相关文档。 使用说明 解压spi接口AD778...

gitblog_06709的博客 407

3D深度饼图的QT实现

首先,我们需要创建一个QT项目并创建一个窗口,用于显示我们的饼图。在QT Creator中,选择创建一个新的QT Widgets应用程序项目,并创建一个新的窗口类。在本文中,我将介绍如何使用QT实现一个3D深度饼图(Pie 3D)的可视化效果。在构造函数中,我们将创建一个饼图(QChartView)并设置饼图的数据。这是一个简单的示例,您可以根据需要自定义和扩展代码来创建更复杂的饼图。现在,我们已经完成了3D深度饼图的QT实现。您将看到一个具有相应数据的3D深度饼图显示在窗口中。3D深度饼图的QT实现。

CodeJolt的博客 277

六、数据资产平台功能架构

该架构图展示了一个功能完善的数据资产平台,它涵盖了数据资产管理的各个方面,从数据采集、模型设计、编目到使用和分析。通过该平台,企业可以更好地管理数据资产,提高数据利用效率,并为业务决策提供有力支持。

moton2017的博客 1626

STM32OLED显示屏SPI驱动程序:让显示变得简单

STM32OLED显示屏SPI驱动程序:让显示变得简单 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在现代嵌入式开发中,STM32微控制器与OLED显示屏的结合日益常见。今天,我们为您推荐一款开源项目——STM32 OLED显示屏SPI驱动程序。该项目专注于提供一种高效、稳定的驱动程序,让STM32与OLED显示屏的集成变得更为便捷。 项目技术分析 核心功能 STM...

gitblog_06766的博客 886

NX二次开发-用户自定义资源栏选项卡RegisterActivationCallback

NX二次开发-用户自定义资源栏选项卡RegisterActivationCallback

阿飞2018 1385

STM32 SPI Flash驱动程序

STM32 SPI Flash驱动程序 【下载地址】STM32SPIFlash驱动程序 本仓库提供了一套针对STM32微控制器的SPI Flash驱动程序,特别适配了W25Q系列Flash存储器,包括但不限于W25Q64、W25Q128、W25Q256等型号。驱动程序设计简洁,经过实际测试,确保了良好的稳定性和兼容性。此...

gitblog_09756的博客 434

迫零均衡前与迫零均衡后眼图对比附Matlab代码

迫零均衡(Decision Feedback Equalization,DFE)是一种常用的数字通信技术,用于抑制信号传输中的多径干扰。迫零均衡(Decision Feedback Equalization,DFE)是一种常用的数字通信技术,用于抑制信号传输中的多径干扰。眼图是一种常用的信号质量评估工具,通过绘制接收到的信号在时域上的波形,可以直观地观察到噪声、失真和干扰等问题。眼图是一种常用的信号质量评估工具,通过绘制接收到的信号在时域上的波形,可以直观地观察到噪声、失真和干扰等问题。

ByteSparkX的博客 459

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

w25qxx SPI FLASH驱动程序

w25qxx SPI FLASH驱动程序 去发现同类优质开源项目:https://gitcode.com/ 本仓库提供了一个适用于STM32 HAL库的w25qxx SPI FLASH驱动程序,旨在帮助开发者更便捷地在STM32项目中使用w25qxx系列SPI FLASH存储器。 功能简介 支持STM32 HAL库 实现了基本的读写操作 提供了擦除、编程和读取ID等接口 支持多种w25qxx系列...

gitblog_06705的博客 368

深度学习工具包 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")

下一篇: csdn如何转载别人的文章
文心雕龍3
博客等级 码龄8年 5粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值