SPI_driver_IMPL_v0.1
用户空间的spi驱动
如果想要在用户空间编写spi驱动,这就要在内核的arch/.../mach-*/board-*.c 中声明一个spi_board_info,它的名字一定要是“spidev”,比如:struct spi_board_info info ={.modalias = ";spidev";,.max_speed_hz = 5000000,.bus_num = 0,.chip_select = 0,};return spi_register_board_info(&;info, 1);这样只要控制器驱动加载了,spidev模块就会和这个设备绑定,并为设备申请一个设备号,主设备号为153,次设备号和设备加载的次序有关。
目前spidev支持最多32个设备。
设备的名字是spidevX.D,其中X是总线编号,D是设备的片选号。
如果正确安装并配置了udev,/dev目录下便会生成spidevX.D设备节点。
直接对这些设备节点操作就行了。
spidev的设备节点的接口包括open/close/read/write/ioctl。
~~~~~~~~~~~~~~~~~~~~~~~~~其中open/close没有什么特别之处。
read/write的话有大小的限制,读写的大小默认不能超过4096字节。
这个大小是一个模块加载参数,可以修改。
允许多个用户同时打开设备节点,spidev使用mutext进行互斥,多个用户同时读写时只有一个活动的用户,其他用户睡眠。
spidev的ioctl命令。
~~~~~~~~SPI_IOC_RD_MODE:读取spi_device的mode。
SPI_IOC_RD_LSB_FIRST:如果是SPI_LSB_FIRST的方式则返回1。
SPI_IOC_RD_BITS_PER_WORD:读取spi_device的bits_per_word.SPI_IOC_RD_MAX_SPEED_HZ:读取spi_device的max_speed_hz.SPI_IOC_WR_MODE:设置spi_device的mode,并调用spi_setup立即使设置生效。
spi驱动代码
while((SPI2->SR&1<<0)==0)//等待接收完一个byte
{
retry++;
if(retry>=0XFFFE)return 0;//超时退出
}
return SPI2->DR;//返回收到的数据
}
#ifndef__SPI_H
#define __SPI_H
#include "sys.h"
//APB1时钟一般为36Mhz
voidSPБайду номын сангаас2_SetSpeed(u8SpeedSet)
{
SpeedSet&=0X07;//限制范围
SPI2->CR1&=0XFFC7;
SPI2->CR1|=SpeedSet<<3;//设置SPI2速度
SPI2->CR1|=1<<6;//SPI设备使能
}
//SPI2读写一个字节
#include "spi.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//////////////////////////////////////////////////////////////////////////////////
// SPI总线速度设置
#define SPI_SPEED_20
#define SPI_SPEED_41
#define SPI_SPEED_82
SPI driver
今天折腾了一天的SPI设备的驱动加载,甚至动用了逻辑分析仪来查看spi总线的波形,主要包括两个SPI设备,at45db321d和mcp2515,一个是串行的dataflash,一个是can总线设备芯片。
前者对于我们来说非常重要,我们可以借助该设备对uboot和kernel以及根文件系统进行更新。
预备知识:设备和驱动是如何匹配的?系统的热插拔是如何实现的?首先一点,设备和驱动是严格区分的,设备是设备,驱动是驱动,设备通过struct device来定义,当然用户也可以将该结构体封装到自己定义的device结构体中,例如,struct platform_device,这是我们采用platform_bus_type总线的设备定义的结构体形式:include/linux/platform_device.h文件中:struct platform_device {const char * name;u32 id;struct device dev;u32 num_resources;struct resource * resource;};只要是9260的外围模块,就像IIC硬件控制器,SPI硬件控制器,都被完全的定义成这种结构体的格式,这种结构体主要包含了硬件资源和名称,硬件资源分为寄存器和IRQ两种。
platform_device通过向内核注册struct device dev这个结构体来告诉内核加载这个设备,方法就是device_register(&platform_device->dev)内核不关心你使用的是platform_device还是spi_device,内核只关心你的struct device结构体,内核通过这个struct device结构体自然能够顺藤摸瓜找到你是platform_device还是spi_device,这就是linux最引以为傲的contian_of()大法。
Brother PT-9500PC 打印机 Linux 驱动程序说明书
Appendix A Printer properties..........................................................................................................................9
This software provides the installer package that automatically copies the appropriate driver file (from those mentioned above) to your Linux distribution.
Table of Contents
1. Overview 1
1.1.
Introduction ..................................................................................................................................1
F.1. Retrieving print error information...............................................................................................23
F.2. MFC-compatible Linux drivers...................................................................................................23
Linux内核驱动之spi子系统(二)用户空间spi驱动
一概念用户空间驱动就是指在用户空间实现的驱动程序。
可以认为它跟普通的用户程序没有什么两样,它使用用户进程空间和栈,下面来看看用户态驱动的优点和缺点优点:1 可以和整个C库链接2 驱动的问题不会导致整个系统挂起3 容易调试缺点:1 中断和DMA在用户态是无法使用的(现在在用户态其实也是可以使用中断和DMA但是比较麻烦,比如可以使用poll函数来等待基于GPIO的中断,同样也可以使用/dev/mem来使用DMA)2 响应时间慢, 因为需要上下文切换在客户和硬件之间传递信息或动作所以总的来说对于一个较为慢速的不需要实时交互的设备,可以使用用户态的驱动来实现。
二spi用户态驱动spi用户驱动主要是依赖于内核模块spidev,该模块实现了一个通用的spi驱动,在用户空间调用该通用驱动提供的接口,操作相应的spi设备,其实这就是spi用户态驱动。
下面是配置内核模块spidev图1首先进入Device Drive==>,然后进入如上图1所示spi support图2如上图2选择用户态spi设备驱动,这样内核模块spidev就配置成功一添加spi_board_info首先需要在内核的arch/arm/mach-*/board-*.c 即BSP信息中添加一个spi_board_info(无论是用户态spi驱动还是内核态spi驱动都需要这样),同时名字必须是“spidev”,那么为什么要这么做了,这就是从 2.6内核起linux 驱动使用了一个叫做Device Model即设备模型的东东,总线,驱动和设备,总线将设备和驱动进行匹配,为了要能够使spi驱动的probe函数能够被调用,则必须存在一个设备与该驱动进行匹配,匹配成功后,spi子系统才会自动调用该驱动的probe函数,对于没有使用热插拔机制总线的设备比如platform,,spi,i2c,则必须手动在BSP信息中间手动添加设备信息,spi总线就是通过添加spi_board_info,来触发内核创建spi设备(struct spi_device),i2c则是添加i2c_board_info。
关于linux spi驱动的那些事
SPI设备的驱动程序通过spi_register_driver注册进SPI子系统,驱动类型为struct spi_driver。典型例子如at25.c。
spi_dev* pdev = spi_alloc(master);
proxy-》chip_select = chip-》chip_select;
proxy-》max_speed_hz = chip-》max_speed_hz;
proxy-》mode = chip-》mode;
proxy-》irq = chip-》irq;
};
staTIc struct class spi_master_class = {
.name = spi_master,
.owner = THIS_MODULE,
.dev_release = spi_master_release,
};
spi_bus_type对应sys中的spi bus总线,Linux设备模型对这个结构体有详细介绍。
struct spi_board_info {
char modalias[32]; //设备名
const void *platform_data; //私有数据,会被设置到spi_device.dev.platform_data
void *controller_data; //私有数据,会被设置到spi_device.controller_data
int irq; //中断号
u32 max_speed_hz; //最大速率
[Note][Aurix2G_TC397_MCAL]SPI相关配置
[Note][Aurix2G_TC397_MCAL]SPI相关配置0 SPI1 General1.1 SpiDriverSpiSystemClock在MCU模块配置的系统时钟。
主要参考McuQSPIFrequency和McuQspiClockSourceSelection1.2 Spi GeneralSpiCancelApi默认是禁⽤的SpiChannelBuffersAllowed (0 -> 2)⽤户可以决定采⽤哪⼀个buffer0:内部buffer1:外部buffer2:内部外部都可以默认是外部bufferSpiInitDeInitApiMode默认选择 SPI_MCAL_SUPERVISOR,因为driver的代码⼤多在supervisor下运⾏的SpiMulticoreCheckEnable多核检查是否开启。
我理解是看driver是否是在单核还是多核上运⾏。
SpiInitCheckApi默认关闭,如果APP有安全⽅⾯的需求和功能,则打开。
SpiRuntimeApiMode决定运⾏时,采⽤什么模式。
默认是SPI_MCAL_SUPERVISOR,理由同上。
SpiDevErrorDetect决定开发时错误是否被检测。
也就是DET。
在debug的时候默认打开。
SpiSafetyCheckEnable是否开启安全检查。
默认关闭,但是如果APP有安全⽅⾯的要求,必须打开。
SpiHwStatusApi决定 API Spi_GetHWUnitStatus是否启⽤。
主要决定,是否app需要了解硬件的状态。
SpiInterruptibleSeqAllowed默认关闭。
决定是否可以中断序列。
只有在SPI level 1or2时才有⽤。
SpiLevelDelivered决定启⽤什么通讯驱动。
1. L0:同步传输,也就是不适⽤DMA⽅式,只是采⽤CPU。
2. L1:异步传输,采⽤DMA⽅式。
3. L2:同时启⽤DMA和CPU两种⽅式。
如何在Zynq 7000平台上使用Linux spidev.c驱动
如何在Zynq 7000平台上使用Linux spidev.c驱动在上一篇博客中,介绍了如何配置Vivado下的硬件工程、例化SPI硬件接口和如何使用petalinux加载Xilinx提供的SPI总线驱动,如果要通过SPI控制外部器件,还需要添加SPI的设备驱动以实现SPI的对外控制逻辑。
在Linux内核的driver/spi目录下有许多外设的设备驱动可以参考,这篇博客主要介绍如何使用其中的spidev,c这个设备驱动来实现对外设的控制。
spidev是一个通用的SPI外设驱动,它提供了spi字符驱动的注册,并向上层应用程序提供了I/O控制接口,当我们仅需要利用SPI接口向外设发送和接收简单的控制序列时,可直接使用该驱动,下面介绍具体的使用方法。
一、在前一篇博客中,我们采用xilinx针对Zynq 7000处理器提供的spi-cadence.c驱动实现了芯片上SPI总线驱动的注册,接下来需要修改设备树文件以时我们的外设挂接在SPI 总线下。
在petalinux工程的../subsystems/linux/configs/device-tree目录下找到zynq相关的设备树文件,目录所包含的文件如下图所示。
打开其中的zynq-7000.dtsi文件,找到其中的spi0节点(具体使用spi0还是spi1根据硬件工程的配置情况),并在该节点下添加如下内容:其中spidev名字对应spidev.c文件中的驱动名,Linux系统启动时会自动找到对应的驱动模块并加载。
reg0对应SPI下的第几个设备,由于Zynq PS端的SPI控制器每个可以外接控制3个从设备,所以reg的值可以设为0、1或2.由于在上一篇博客中,Vivado硬件工程中对SPI的接口spi0_csn_0_o进行了例化并引出接口,所以本工程使用的是SPI使能第0个端口。
同时,spidev.c该驱动不支持片选功能,因此若在spi0下挂接了多个从设备,切硬件工程中spi0_csn_0片选接口引出了多个,则spiddev驱动在注册时,会在/dev目录下注册多个。
linuxSPI驱动——gpio模拟spi驱动(三)
linuxSPI驱动——gpio模拟spi驱动(三)⼀:⾸先在我的平台注册platform_device,保证能让spi-gpio.c能执⾏到probe函数。
1: struct spi_gpio_platform_data {2: unsigned sck;3: unsigned mosi;4: unsigned miso;5:6: u16 num_chipselect;7: };1: //#define NCS GPIO_PB(2) //定义SS所对应的GPIO接⼝编号2: //#define SCLK GPIO_PB(0) //定义SCLK所对应的GPIO接⼝编号3: //#define MOSI GPIO_PB(4) //定义SCLK所对应的GPIO接⼝编号4: //#define MISO GPIO_PB(1)5: static struct spi_gpio_platform_data jz_spi_gpio_data = {6: .sck = GPIO_PB(0), //GPIO_SPI_SCK,7: .mosi = GPIO_PB(4), //GPIO_SPI_MOSI,8: .miso = GPIO_PB(1), //GPIO_SPI_MISO,9: .num_chipselect = 1,10: };11:12: struct platform_device jz_spi_gpio_device = {13: .name = "spi_gpio",14: .id = 0,15: .dev = {16: .platform_data = &jz_spi_gpio_data,17: },18: };注册platform device1: platform_device_register(&jz_spi_gpio_device);⼆:注册platform_driver在spi_gpio.c⾥⾯注册platform driver1: MODULE_ALIAS("platform:" DRIVER_NAME);2:3: static struct platform_driver spi_gpio_driver = {4: = DRIVER_NAME,5: .driver.owner = THIS_MODULE,6: .remove = __exit_p(spi_gpio_remove),7: };8:9: static int __init spi_gpio_init(void)10: {11: return platform_driver_probe(&spi_gpio_driver, spi_gpio_probe);12: }13: module_init(spi_gpio_init);14:15: static void __exit spi_gpio_exit(void)16: {17: platform_driver_unregister(&spi_gpio_driver);18: }19: module_exit(spi_gpio_exit);20:21:22: MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO ");23: MODULE_AUTHOR("David Brownell");24: MODULE_LICENSE("GPL");三:具体算法分析1: struct spi_gpio {2: struct spi_bitbang bitbang; /* gpio 模拟spi算法相关的结构 */3: struct spi_gpio_platform_data pdata; /* spi platform data 对应模拟spi的四个gpio编号 */4: struct platform_device *pdev; /* 对应注册的 platform device */5: };1:2: static int __init spi_gpio_probe(struct platform_device *pdev)3: {4: int status;5: struct spi_master *master;6: struct spi_gpio *spi_gpio;7: struct spi_gpio_platform_data *pdata;8: u16 master_flags = 0;9:10: pdata = pdev->dev.platform_data; /* 存放spi的四根gpio */11: #ifdef GENERIC_BITBANG12: if (!pdata || !pdata->num_chipselect)13: return -ENODEV;14: #endif15:16: /* 申请注册四个gpio */17: status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);18: if (status < 0) {19: return status;20: }21:22: /* alloc a spi master ,master->dev->p->driver_data = &master[1]*/23: master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);24: if (!master) {25: status = -ENOMEM;26: goto gpio_free;27: }28: /* spi_gpio指向⼀块空间, 即指向mstaer[1]29: pdev->dev->p->driver_data = spi_gpio;30: 初始化spi_gpio31: */32: spi_gpio = spi_master_get_devdata(master);33: platform_set_drvdata(pdev, spi_gpio);34:35: spi_gpio->pdev = pdev;36: if (pdata)37: spi_gpio->pdata = *pdata;38:39: master->flags = master_flags;40: master->bus_num = pdev->id;41: master->num_chipselect = SPI_N_CHIPSEL;42: master->setup = spi_gpio_setup; /* setup ⽐如cs引脚申请 */43: master->cleanup = spi_gpio_cleanup;44: /* spi_gpio->bitbang.master = master */45: spi_gpio->bitbang.master = spi_master_get(master);46: spi_gpio->bitbang.chipselect = spi_gpio_chipselect;47: /* spi_gpio->bitbang.txrx_word 数组函数四个元素指针,分别指向spi四种mode算法函数 */ 48: if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {49: spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;50: spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;51: spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;52: spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;53: } else {54: spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;55: spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;56: spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;57: spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;58: }59: /* spi_gpio->bitbang.setup_transfer初始化传输的bits_per_word和speed */60: spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;61: spi_gpio->bitbang.flags = SPI_CS_HIGH;62: /* spi_gpio->bitbang相关算法接⼝初始化 */63: status = spi_bitbang_start(&spi_gpio->bitbang);64: if (status < 0) {65: spi_master_put(spi_gpio->bitbang.master);66: gpio_free:67: if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)68: gpio_free(SPI_MISO_GPIO);69: if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)70: gpio_free(SPI_MOSI_GPIO);71: gpio_free(SPI_SCK_GPIO);72: spi_master_put(master);73: }74:75: return status;76: }四:总之最终让spi_gpi0整个对象存放了整个gpio模拟spi的算法结构;⽽pdev->dev->p->driver_data = spi_gpio; platform device和 platform driver两者match结果是:root@CarRadio:/# ls /sys/bus/platform/devices/spi_gpio.0/driver modalias power spi0.0 spi_master subsystem ueventroot@CarRadio:/# ls /sys/bus/platform/devices/spi_gpio.0/driver/spi_gpio.0 uevent。
Winsock服务提供者接口SPI概述
Winsock服务提供者接口SPI概述Winsock SPI由两个核心接口组成:Layered Service Provider(LSP)接口和Transport Service Provider(TSP)接口。
这些接口允许开发人员创建定制的网络协议栈,以满足特定的需求。
LSP接口是Winsock SPI中较为常见和常用的接口。
LSP允许开发人员在标准协议栈之上插入自定义的协议处理过程,以处理网络数据包的传输和处理。
通过LSP接口,开发人员可以实现各种功能,例如流量监控、带宽控制、数据过滤等。
LSP接口的使用非常灵活,可以在应用程序级别或系统级别进行网络流量的处理和管理。
TSP接口则提供了更底层的网络协议栈开发能力。
TSP接口允许开发人员创建自定义的网络传输协议,以便更好地控制数据包的传输过程。
TSP接口的使用相对较复杂,需要对网络协议栈和数据包传输过程有较深入的了解。
除了LSP和TSP接口,Winsock SPI还提供了一些辅助接口和函数,以便开发人员更方便地使用和管理自定义的网络协议栈。
例如,接口提供了注册和注销自定义协议栈的功能,使应用程序能够动态地切换和管理不同的网络协议栈。
Winsock SPI的使用场景非常广泛。
例如,在网络安全领域,开发人员可以使用LSP接口实现防火墙、入侵检测系统等功能;在网络优化领域,开发人员可以使用TSP接口实现自定义的传输协议,以提高网络传输的效率和性能。
虽然Winsock SPI提供了强大的功能和灵活性,但它也带来了一些挑战。
开发人员需要具备深入的网络协议和传输知识,以及熟练的编程技能。
错误的使用Winsock SPI接口可能会导致应用程序的不稳定性和安全问题。
因此,在使用Winsock SPI进行网络开发时,开发人员需要仔细考虑和测试自己的实现,并遵循相关的安全和稳定性最佳实践。
总之,Winsock服务提供者接口是一组用于开发网络应用程序的接口,它提供了创建定制的网络协议栈的能力。
STM32固件库使用手册【中文】
所有的驱动源代码都符合“Strict ANSI-C”标准(项目于范例文件符合扩充 ANSI-C 标准)。我们已经把驱动 源代码文档化,他们同时兼容 MISRA-C 2004 标准(根据需要,我们可以提供兼容矩阵)。由于整个固态 函数库按照“Strict ANSI-C”标准编写,它不受不同开发环境的影响。仅对话启动文件取决于开发环境。
1.3.1 变量 ................................................................................................................................................ 28 1.3.2 布尔型 ............................................................................................................................................ 28 1.3.3 标志位状态类型 ........................................................................................................................... 29 1.3.4 功能状态类型 ...............................................
spi driver
今天折腾了一天的SPI设备的驱动加载,甚至动用了逻辑分析仪来查看spi总线的波形,主要包括两个SPI设备,at45db321d和 mcp2515,一个是串行的dataflash,一个是can总线设备芯片。
前者对于我们来说非常重要,我们可以借助该设备对uboot和kernel 以及根文件系统进行更新。
预备知识:设备和驱动是如何匹配的?系统的热插拔是如何实现的?首先一点,设备和驱动是严格区分的,设备是设备,驱动是驱动,设备通过struct device来定义,当然用户也可以将该结构体封装到自己定义的device 结构体中,例如,struct platform_device,这是我们采用platform_bus_type 总线的设备定义的结构体形式:include/linux/platform_device.h文件中:struct platform_device {const char* name;u32 id;struct device dev;u32 num_resources;struct resource* resource;};只要是9260的外围模块,就像IIC硬件控制器,SPI硬件控制器,都被完全的定义成这种结构体的格式,这种结构体主要包含了硬件资源和名称,硬件资源分为寄存器和IRQ两种。
platform_device通过向内核注册struct device dev这个结构体来告诉内核加载这个设备,方法就是 device_register(&platform_device->dev)内核不关心你使用的是platform_device还是spi_device,内核只关心你的struct device结构体,内核通过这个struct device结构体自然能够顺藤摸瓜找到你是platform_device还是spi_device,这就是linux最引以为傲的contian_of()大法。
GPIO模拟SPI通讯接口的驱动
GPIO模拟SPI通讯接口的驱动一,某些时候我们会不得不使用GPIO来模拟SPI,I2C等通讯接口,如本例中,需要使用SPI接口发送9位的数据,如果使用linux内核提供的SPI子系统来做这个驱动是无法实现9位传输数据的。
二,用GPIO模拟SPI总的来说是比较简单,把相应的管脚配置成GPIO功能,再按需要配置管脚的输入输出方向,然后根据SPI总线的时序设定IO口的电平。
三,驱动代码如下,以备今后作参考:(linux-2.6.28 + TCC8900, 这个驱动是用来控制LCD的初始化的(型号为LW350AC9001))#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/ioport.h>#include <asm/uaccess.h>#include <linux/delay.h>#include <bsp.h>#include <asm/io.h>#define PDEBUG#ifdef PDEBUG#define PLOG(fmt,args...) printk(fmt,##args)#else#define PLOG(fmt,args...) /*do nothing*/#endif#define SPI_CMD 0#define SPI_DATA 1#define FUN_GPIO 0#define PIN_SDO 15 //GPIOF[15]#define PIN_SDI 14#define PIN_SCLK 16#define PIN_CS 29 //GPIOC[29]#define GPC_BASE 0xF0102080#define GPF_BASE 0xF0102140#define OFFSET_DAT 0x0#define OFFSET_EN 0x4#define OFFSET_FUN0 0x24#define OFFSET_FUN1 0x28#define OFFSET_FUN2 0x2c#define OFFSET_FUN3 0x30// select pin used for gpiostatic int tcc_set_pin_fun(int pin, int fun){if(pin<8)tcc_writel(((tcc_readl(GPF_BASE+OFFSET_FUN0) & ~(0x0f<<(4*pin))) | (fun<<(4 * pin))), GPF_BASE+OFFSET_FUN0);else if(pin<16)tcc_writel(((tcc_readl(GPF_BASE+OFFSET_FUN1) & ~(0x0f<<(4*(pin-8)))) | (fun<<(4 * (pin-8)))), GPF_BASE+OFFSET_FUN1);else if(pin<24)tcc_writel(((tcc_readl(GPF_BASE+OFFSET_FUN2) & ~(0x0f<<(4*(pin-16)))) | (fun<<(4 *(pin-16)))),GPF_BASE+OFFSET_FUN2);else if(pin<32)tcc_writel(((tcc_readl(GPF_BASE+OFFSET_FUN3) & ~(0x0f<<(4*(pin-24)))) | (fun<<(4 *(pin-24)))),GPF_BASE+OFFSET_FUN3);return 0;}static int tcc_set_cs_fun(void){tcc_writel(((tcc_readl(GPC_BASE+OFFSET_FUN3) & ~(0x0f<<(4*(PIN_CS-24)))) ),GPC_BASE+OFFSET_FUN3);return 0;}// set gpio direction, output: 1 for output, 0 for inputstatic int tcc_set_gpio_direction(int pin, int output){tcc_writel(((tcc_readl(GPF_BASE+OFFSET_EN) & ~(1<<pin)) | (output<< pin)),GPF_BASE+OFFSET_EN);return 0;}static int tcc_set_cs_output(void){tcc_writel(((tcc_readl(GPC_BASE+OFFSET_EN) | (1<< PIN_CS)) ),GPC_BASE+OFFSET_EN);return 0;}// set gpio pin level, high: 1, low: 0static int tcc_set_gpio_data(int pin, int level){tcc_writel(((tcc_readl(GPF_BASE+OFFSET_DAT) & ~(1<<pin) )| (level<< pin)),GPF_BASE+OFFSET_DAT);return 0;}static int tcc_set_cs_data(int level){tcc_writel(((tcc_readl(GPC_BASE+OFFSET_DAT) & ~(1<<PIN_CS) )| (level<< PIN_CS)), GPC_BASE+OFFSET_DAT);return 0;}// get gpio pin level, high: 1, low: 0static int tcc_get_gpio_data(int pin){return ((tcc_readl(GPF_BASE+OFFSET_DAT) >>pin) & 1);}void SPI_init(void){tcc_set_pin_fun(PIN_SDO, FUN_GPIO); //configure pin sdo and sda as GPIOtcc_set_pin_fun(PIN_SDI, FUN_GPIO);tcc_set_pin_fun(PIN_SCLK, FUN_GPIO);tcc_set_gpio_direction(PIN_SDO,1);tcc_set_gpio_direction(PIN_SDI,1);tcc_set_gpio_direction(PIN_SCLK,1);tcc_set_gpio_data(PIN_SDO,1);tcc_set_gpio_data(PIN_SDI,1);tcc_set_gpio_data(PIN_SCLK,1);tcc_set_cs_fun();tcc_set_cs_output();tcc_set_cs_data(1);}void SPI_send(bool is_parameter,unsigned char w_data){unsigned char vsignbit;//send DNC-bittcc_set_gpio_data(PIN_SCLK,0);tcc_set_gpio_data(PIN_SDO,is_parameter);ndelay(20);tcc_set_gpio_data(PIN_SCLK,1);ndelay(20);for(vsignbit=0x80;vsignbit>0;vsignbit>>=1) {tcc_set_gpio_data(PIN_SCLK,0);if(w_data&vsignbit)tcc_set_gpio_data(PIN_SDO,1);elsetcc_set_gpio_data(PIN_SDO,0);ndelay(20);tcc_set_gpio_data(PIN_SCLK,1);ndelay(20);}tcc_set_gpio_data(PIN_SDO,1);}unsigned char SPI_read(void){unsigned char vsignbit,r_data=0;tcc_set_gpio_direction(PIN_SDI,1);tcc_set_gpio_data(PIN_SDI,1);tcc_set_gpio_direction(PIN_SDI,0);for(vsignbit=0x80;vsignbit>0;vsignbit>>=1) {tcc_set_gpio_data(PIN_SCLK,0);ndelay(20);if(tcc_get_gpio_data(PIN_SDI)){r_data = r_data|vsignbit;}tcc_set_gpio_data(PIN_SCLK,1);ndelay(20);}return r_data;}static void set_value(){SPI_send(SPI_CMD, 0xB9);SPI_send(SPI_DATA, 0xFF);SPI_send(SPI_DATA, 0x83);SPI_send(SPI_DATA, 0x63);SPI_send(SPI_CMD, 0xB1);SPI_send(SPI_DATA, 0x81);SPI_send(SPI_DATA, 0x30);SPI_send(SPI_DATA, 0x02);SPI_send(SPI_DATA, 0x13);SPI_send(SPI_DATA, 0x11);SPI_send(SPI_DATA, 0x00);SPI_send(SPI_DATA, 0x3A);SPI_send(SPI_DATA, 0x42);SPI_send(SPI_DATA, 0x3F);SPI_send(SPI_DATA, 0x3F);SPI_send(SPI_CMD, 0x11);mdelay(150);SPI_send(SPI_CMD, 0x36);SPI_send(SPI_DATA, 0x08);SPI_send(SPI_CMD, 0x3A);SPI_send(SPI_DATA, 0x77);SPI_send(SPI_CMD, 0xB3);SPI_send(SPI_DATA,0x09);SPI_send(SPI_CMD, 0xB4);SPI_send(SPI_DATA, 0x08);SPI_send(SPI_DATA, 0x12);SPI_send(SPI_DATA, 0x72);SPI_send(SPI_DATA, 0x12);SPI_send(SPI_DATA, 0x06);SPI_send(SPI_DATA, 0x03);SPI_send(SPI_DATA, 0x54);SPI_send(SPI_DATA, 0x03);SPI_send(SPI_DATA, 0x4E);SPI_send(SPI_DATA, 0x00);SPI_send(SPI_DATA, 0x00);SPI_send(SPI_CMD, 0xBF);SPI_send(SPI_DATA, 0x00);SPI_send(SPI_DATA, 0x01);SPI_send(SPI_CMD, 0xB6);SPI_send(SPI_DATA, 0x00);SPI_send(SPI_CMD, 0xCC);SPI_send(SPI_DATA, 0x0A);mdelay(10);SPI_send(SPI_DATA, 0x40);SPI_send(SPI_DATA, 0x42);SPI_send(SPI_DATA, 0xC1);SPI_send(SPI_DATA, 0x4B);SPI_send(SPI_DATA, 0xA7);SPI_send(SPI_DATA, 0x06);SPI_send(SPI_DATA, 0x0D);SPI_send(SPI_DATA, 0x51);SPI_send(SPI_DATA, 0x56);SPI_send(SPI_DATA, 0x18);SPI_send(SPI_DATA, 0x56);SPI_send(SPI_DATA, 0x17);SPI_send(SPI_DATA, 0x89);SPI_send(SPI_DATA, 0x11);SPI_send(SPI_DATA, 0x00);SPI_send(SPI_DATA, 0x40);SPI_send(SPI_DATA, 0x42);SPI_send(SPI_DATA, 0xC1);SPI_send(SPI_DATA, 0x4B);SPI_send(SPI_DATA, 0xA7);SPI_send(SPI_DATA, 0x06);SPI_send(SPI_DATA, 0x0D);SPI_send(SPI_DATA, 0x51);SPI_send(SPI_DATA, 0x56);SPI_send(SPI_DATA, 0x18);SPI_send(SPI_DATA, 0x56);SPI_send(SPI_DATA, 0x17);SPI_send(SPI_DATA, 0x89);SPI_send(SPI_DATA, 0x11);mdelay(5);SPI_send(SPI_CMD, 0x29);}static int __init spi_lcd_init(void){PLOG("Register lcd spi control.\n");SPI_init();tcc_set_cs_data(0);ndelay(20);set_value();tcc_set_cs_data(1);return 0;}static void __exit spi_lcd_exit(void){printk(KERN_INFO "unregister lcd spi control.\n");}module_init(spi_lcd_init);module_exit(spi_lcd_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("J.H.Luo<sparkle-cliz@>");MODULE_VERSION("0.1");MODULE_DESCRIPTION("lcd spi control driver");四,测试结果,insmod此驱动模块之后,LCD显示出开机LOGO了,说明SPI控制成功。
A10+Linux+SPI设备驱动开发-2012.1.31
SPI 总线通过四条线完成 MCU 与各种外围器件的通讯,这四条线分别是: 串行时钟线(SCLK)、主机输出/从机输入数据线(MOSI)、主机输入/从机输出 数据线(MISO)、从机片选线(SS)。
当 SPI 工作时,在移位寄存器中的数据被逐位从输出引脚(MOSI)输出(高 位在前),同时将输入引脚(MISO)中接收到的数据逐位移入到移位寄存器(高 位在前)。因此,在主机发送完一个字节后,从外围器件接收到的数据被移入到 主机的移位寄存器中,即完成一个字节数据传输的实质是两个器件寄存器内容的 交换。主机的 SPI 时钟信号(SCLK)使传输同步,SPI 总线的内部结构如图 1 所示。
1.1. SPI 总线工作原理....................................................................................................................1 1.2. SPI 总线工作模式....................................................................................................................1
Copyright © All Winner Technology. All Rights Reserved.
Allwinner Technology CO., Ltd.
A10
1. SPI 总线简介
SPI(Serial Peripheral Interface)总线是一种由 Motorola 公司开发的串行总 线,用于 CPU 与各种外围器件进行全双工、同步串行通讯。SPI 总线最主要的 优点是时钟速度快,范围可从几 MHz 到几十 MHz,且没有系统开销,但它有一 个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。
spi驱动文档
SPI驱动修改一,修改板子的型号为Test:修改的路径:/a9/linux-3.0.35/arch/arm/mach-mx6/board-mx6q_my.cMACHINE_START(MX6Q_ZH_YH2, "Test")二,支持双SPI。
按要求第二个SPI片选是KEY_COL4所以在board-mx6q_zh_yh2.h的static iomux_v3_cfg_t mx6q_sabresd_pads[] 中增加:MX6Q_PAD_KEY_COL4_GPIO_4_14接下来在board-mx6q_zh_yh2.c中宏定义一下#define SABRESD_ECSPI2_CS0 IMX_GPIO_NR(4, 14)static int mx6q_sabresd_spi_cs[] = {SABRESD_ECSPI1_CS0,};static int mx6q_marsboard_spi2_cs[] = {SABRESD_ECSPI2_CS0, //增加的SPI2片选};static const struct spi_imx_master mx6q_sabresd_spi_data __initconst = {.chipselect = mx6q_sabresd_spi_cs,.num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs),};static const struct spi_imx_master mx6q_sabresd_spi2_data __initconst = {.chipselect = mx6q_marsboard_spi2_cs, //增加的命名SPI2片选.num_chipselect = ARRAY_SIZE(mx6q_marsboard_spi2_cs),};static struct flash_platform_data imx6_sabresd__spi_flash_data = { .name = "spidev",//修改m25p80为spidev.parts = imx6_sabresd_spi_nor_partitions,.nr_parts = ARRAY_SIZE(imx6_sabresd_spi_nor_partitions),.type = "sst25vf016b",};//初始化双spistatic struct spi_board_info imx6_sabresd_spi_nor_device[] __initdata = { {.modalias = "spidev",.max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */.bus_num = 0,.chip_select = 0,.platform_data = &imx6_sabresd__spi_flash_data,},{.modalias = "spidev",.max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */.bus_num = 1,// 增加的SPI.chip_select = 0,.platform_data = &imx6_sabresd__spi_flash_data,},}static void spi_device_init(void){spi_register_board_info(imx6_sabresd_spi_nor_device,ARRAY_SIZE(imx6_sabresd_spi_nor_device));}static void __init mx6_sabresd_board_init(void){…mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_pads,ARRAY_SIZE(mx6q_sabresd_pads));…/* SPI */imx6q_add_ecspi(0, &mx6q_sabresd_spi_data);imx6q_add_ecspi(1, &mx6q_sabresd_spi2_data);//增加的spispi_device_init();…}三,SPI测试程序该文件在路径:\a9\spi_teststatic const char *device = "/dev/spidev1.0"; 修改此处是根据/dev/spidev*来决定的。
linux设备驱动spi详解5-应用到驱动的完整流程
linux设备驱动spi详解5-应⽤到驱动的完整流程所有的应⽤程序使⽤dev/⽬录下创建的设备,这些字符设备的操作函数集在⽂件spidev.c中实现。
1static const struct file_operations spidev_fops = {2 .owner = THIS_MODULE,3/* REVISIT switch to aio primitives, so that userspace4 * gets more complete API coverage. It'll simplify things5 * too, except for the locking.6*/7 .write = spidev_write,8 .read = spidev_read,9 .unlocked_ioctl = spidev_ioctl,10 .open = spidev_open,11 .release = spidev_release,12 };1 spidev_ioctl函数以上是所有应⽤程序所能够做的所有操作,由此开始追踪spi 驱动程序的完整执⾏流程其中,最重要的就是ioctl, 从这⾥开始先重点剖析ioctl函数1 spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)2 {3int err = 0;4int retval = 0;5struct spidev_data *spidev;6struct spi_device *spi;7 u32 tmp;8 unsigned n_ioc;9struct spi_ioc_transfer *ioc;10//ioctl cmd 检查11/* Check type and command number */12if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)13return -ENOTTY;1415/* Check access direction once here; don't repeat below.16 * IOC_DIR is from the user perspective, while access_ok is17 * from the kernel perspective; so they look reversed.18*/19if (_IOC_DIR(cmd) & _IOC_READ)20 err = !access_ok(VERIFY_WRITE,21 (void __user *)arg, _IOC_SIZE(cmd));22if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)23 err = !access_ok(VERIFY_READ,24 (void __user *)arg, _IOC_SIZE(cmd));25if (err)26return -EFAULT;2728/* guard against device removal before, or while,29 * we issue this ioctl.30*/31//通过以下⽅式获取spi_device-----spi(是之后操作的基础)32 spidev = filp->private_data;33 spin_lock_irq(&spidev->spi_lock);34 spi = spi_dev_get(spidev->spi);35 spin_unlock_irq(&spidev->spi_lock);3637if (spi == NULL)38return -ESHUTDOWN;3940/* use the buffer lock here for triple duty:41 * - prevent I/O (from us) so calling spi_setup() is safe;42 * - prevent concurrent SPI_IOC_WR_* from morphing43 * data fields while SPI_IOC_RD_* reads them;44 * - SPI_IOC_MESSAGE needs the buffer locked "normally".45*/46 mutex_lock(&spidev->buf_lock);47//以上是进⾏check,检查命令有效性,以及进⾏初始化数据,这⾥不在多做说明48switch (cmd) {49/* read requests */50case SPI_IOC_RD_MODE://获取模式信息,将信息发送给⽤户51 retval = __put_user(spi->mode & SPI_MODE_MASK,52 (__u8 __user *)arg);53break;54case SPI_IOC_RD_LSB_FIRST://获取spi最低有效位55 retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,56 (__u8 __user *)arg);57break;58case SPI_IOC_RD_BITS_PER_WORD:59 retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);61case SPI_IOC_RD_MAX_SPEED_HZ:62 retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);63break;6465/* write requests */66case SPI_IOC_WR_MODE://设置数据传输模式,这⾥只是把设置的数据保存在spi 中,但并没有对spi device做任何操作,对spi device的操作⼀并在最后进⾏ 67 retval = __get_user(tmp, (u8 __user *)arg);68if (retval == 0) {69 u8 save = spi->mode;7071if (tmp & ~SPI_MODE_MASK) {72 retval = -EINVAL;73break;74 }7576 tmp |= spi->mode & ~SPI_MODE_MASK;77 spi->mode = (u8)tmp;78 retval = spi_setup(spi);79if (retval < 0)80 spi->mode = save;81else82 dev_dbg(&spi->dev, "spi mode %02xn", tmp);83 }84break;85case SPI_IOC_WR_LSB_FIRST://设置设置spi写最低有效位,同上86 retval = __get_user(tmp, (__u8 __user *)arg);87if (retval == 0) {88 u8 save = spi->mode;8990if (tmp)91 spi->mode |= SPI_LSB_FIRST;92else93 spi->mode &= ~SPI_LSB_FIRST;94 retval = spi_setup(spi);95if (retval < 0)96 spi->mode = save;97else98 dev_dbg(&spi->dev, "%csb firstn",99 tmp ? 'l' : 'm');100 }101break;102case SPI_IOC_WR_BITS_PER_WORD://设置spi写每个字含多个个位,同上103 retval = __get_user(tmp, (__u8 __user *)arg);104if (retval == 0) {105 u8 save = spi->bits_per_word;106107 spi->bits_per_word = tmp;108 retval = spi_setup(spi);109if (retval < 0)110 spi->bits_per_word = save;111else112 dev_dbg(&spi->dev, "%d bits per wordn", tmp);113 }114break;115case SPI_IOC_WR_MAX_SPEED_HZ://设置spi写最⼤速率,同上116 retval = __get_user(tmp, (__u32 __user *)arg);117if (retval == 0) {118 u32 save = spi->max_speed_hz;119120 spi->max_speed_hz = tmp;121 retval = spi_setup(spi);122if (retval < 0)123 spi->max_speed_hz = save;124else125 dev_dbg(&spi->dev, "%d Hz (max)n", tmp);126 }127break;128129default:130/* segmented and/or full-duplex I/O request */131if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))//查看是否为数据write命令132 || _IOC_DIR(cmd) != _IOC_WRITE) {133 retval = -ENOTTY;134break;135 }136//pay more time on understanding below method137 tmp = _IOC_SIZE(cmd);//从命令参数中解析出⽤户数据⼤⼩138if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {//数据⼤⼩必须是struct spi_ioc_transfer的整数倍139 retval = -EINVAL;140break;141 }142 n_ioc = tmp / sizeof(struct spi_ioc_transfer);//将要传输的数据分成n个传输数据段143if (n_ioc == 0)145146/* copy into scratch area */147 ioc = kmalloc(tmp, GFP_KERNEL);//获取n个数据段的数据管理结构体的内存空间148if (!ioc) {149 retval = -ENOMEM;150break;151 }152if (__copy_from_user(ioc, (void __user *)arg, tmp)) {//从⽤户空间获取数据管理结构体的初始化值153 kfree(ioc);154 retval = -EFAULT;155break;156 }157158/* translate to spi_message, execute */159 retval = spidev_message(spidev, ioc, n_ioc);//数据传输,这是整个流程中的核⼼160 kfree(ioc);161break;162 }163164 mutex_unlock(&spidev->buf_lock);165 spi_dev_put(spi);166return retval;167 }通过调⽤函数spi->master->setup()来设置SPI模式。
Linux系统自带spi驱动加载及应用程序编写方法详解
Linux系统自带spi驱动加载及应用程序编写方法详解硬件平台:飞思卡尔IMX6,内核版本:kernel3.0.35Linux系统中,和I2C一样,SPI也有系统自带的设备驱动程序,位于源码目录下drivers/spi/spidev.c,以下为驱动的移植和对应应用程序编写方法驱动代码移植要将此设备驱动加入到内核中,要做两件事情第一:将此驱动编译进内核步骤:make menuconfigDevice Drivers -><*>SPI support -><*>User mode SPI device driver support第二:在平台文件arch/arm/mach-mx6/board-mx6q_sabresd.c 中添加对spidev的设备注册步骤:1、准备spi_board_info变量(全局变量)static struct spi_board_info spidev_ecspi2_board_info[] __initdata = {{/* The modalias must be the same as spi device driver name */.modalias = "spidev",.max_speed_hz = 20000000,.bus_num = 1,.chip_select = 0,},};2、注册spi_board_info变量到内核中,要在平台硬件初始化的函数中执行本段代码spi_register_board_info(spidev_ecspi2_board_info,ARRAY_SIZE(spidev_ecspi2_board_info));注意:上面两个步骤是原则,必不可少的,但是具体的平台会有一些其他更多的修改,比如笔者使用的是飞思卡尔IMX6,还需要将GPIO口进行初始化,初始化为SPI功能具体操作见以下补丁,源码下载地址点击打开链接在对驱动代码进行移植之后,重新编译内核,下载到开发板上,即可看到spi设备/dev/spidev1.0,标识着SPI驱动移植成功应用程序编写在对驱动代码进行修改之后,需要根据驱动的架构来完成应用程序的编写,在内核源代码Documentation/spi目录下有一个spidev_test.c文件,是内核作者提供给Linux开发人员的参考文档,笔者也是参考此文件来编写的应用程序应用程序无非是open、close、read、write、ioctl的使用。
linux SPI 驱动框架源码分析
SPI协议是一种同步的串行数据连接标准,由摩托罗拉公司命名,可工作于全双工模式。
相关通讯设备可工作于m/s模式。
主设备发起数据帧,允许多个从设备的存在。
每个从设备有独立的片选信号,SPI一般来说是四线串行总线结构。
接口:SCLK——Serial Clock(output from master)时钟(主设备发出)MOSI/SIMO——Master Output, Slave Input(output from master)数据信号线mosi(主设备发出)MISO/SOMI——Master Input,Slave Outpu(output from slave)数据信号线(从设备) SS——Slave Select(active low;output from master)片选信号下面来看一下Linux中的SPI驱动。
在Linux设备驱动框架的设计中,有一个重要的主机,外设驱动框架分离的思想,如下图。
外设a,b,c的驱动与主机控制器A,B,C的驱动不相关,主机控制器驱动不关心外设,而外设驱动也不关心主机,外设只是访问核心层的通用的API进行数据的传输,主机和外设之间可以进行任意的组合。
如果我们不进行如图的主机和外设分离,外设a,b,c和主机A,B,C进行组合的时候,需要9种不同的驱动。
设想一共有个主机控制器,n个外设,分离的结构是需要m+n个驱动,不分离则需要m*n个驱动。
下面介绍spi子系统的数据结构:在Linux中,使用spi_master结构来描述一个SPI主机控制器的驱动。
view plain分配,注册和注销的SPI主机的API由SPI核心提供:view plain在Linux中用spi_driver来描述一个SPI外设驱动。
view plain可以看出,spi_driver结构体和platform_driver结构体有极大的相似性,都有probe(),remove(),suspend(),resume()这样的接口。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
v 0.1, 10 Sep 2007
SPI Driver Implementation
Tianjin University—Infineon Automotive Electronic Joint Laboratory
State Key Laboratory of Engines
TianJin University, China
v 0.1, 10 Sep 2007
v 0.1, 10 Sep 2007 Revision history
v 0.1, 10 Sep 2007
Contents
1 Introduction (5)
1.1 Overview (5)
1.2 Reference (5)
2. Type definition (6)
3 Global V ariable (7)
4 Function Definitions (8)
4.1 OCSPI_InitSync (8)
4.2 OCSPI_DeInitSync (9)
4.3 OCSPI_ReadAsync (10)
4.4 OCSPI_WriteAsync (12)
4.5 OCSPI_SuspendAsync (14)
4.6 OCSPI_Notification (15)
4.7 OCSPI Interrupt Functions. (16)
5 Resources Configuration (18)
5.1 Periperal Config (18)
5.2 Interrupt Config (18)
6 Compile Environment (19)
v 0.1, 10 Sep 2007
1 Introduction
1.1 Overview
This document describes the implementations of the SPI driver to be developed in the frame of the GEMS-K1 project.
The SPI driver configures the microcontroller internal peripherals, so that transmission and reception of data is possible using serial synchronous communication. The microcontroller acts as the master of the communication, and it is connected to several slave devices.
Note:
1. This driver is specified for master mode only.
2. A channel is a SW logical entity which is mapped to a hardware chip select signal.
3. Errors (Transmit, Receive, phase and baud rate) are not handled by the driver.
1.2 Reference
[1] SPI driver specification document
[2] TC1766_um_v1.1_2005_08.pdf document
v 0.1, 10 Sep 2007 2. Type definition
v 0.1, 10 Sep 2007 3 Global Variable
v 0.1, 10 Sep 2007 4 Function Definitions
4.1 OCSPI_InitSync
v 0.1, 10 Sep 2007 4.2 OCSPI_DeInitSync
v 0.1, 10 Sep 2007 4.3 OCSPI_ReadAsync
v 0.1, 10 Sep 2007
v 0.1, 10 Sep 2007 4.4 OCSPI_WriteAsync
v 0.1, 10 Sep 2007
v 0.1, 10 Sep 2007 4.5 OCSPI_SuspendAsync
v 0.1, 10 Sep 2007 4.6 OCSPI_Notification
v 0.1, 10 Sep 2007 4.7 OCSPI Interrupt Functions.
4.7.1 Receive Interrupt
v 0.1, 10 Sep 2007 4.7.2 Configure Channel
Note:
This function should be inlined 4.7.3 CheckInit
Note:
This function should be inlined
v 0.1, 10 Sep 2007 5 Resources Configuration The resource used by SPI driver
5.1 Periperal Config
5.2 Interrupt Config
v 0.1, 10 Sep 2007 6 Compile Environment Compile Tool: Tasking for Tricore。