0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

浅谈SPI驱动API的使用方法

英创信息技术 作者:英创信息技术 2019-10-12 11:42 次阅读

EM9280系列产品包括EM9280、EM9287和EM9281,是英创公司新一代的低成本嵌入式主板产品。该主板的SPI接口,在内部DMA(Direct Memory Access直接内存存取)机制的驱动下,其最高数据传输速度可达20Mbps。另外SPI接口可支持4bit、8bit、16bit位长的数据通讯;也可对SPI时序的极性及相位进行设置。

针对SPI接口的应用特点,EM9280的SPI的驱动进行了专门的优化,不仅可支持常规的SPI读、写操作,还可支持外部中断触发的读写操作。中断触发的读写操作,主要应用于工业控制的高速数据采集。另一方面,针对AD芯片控制需求,SPI驱动还支持混合读写模式的数据传输操作。

本文以下部分重点介绍SPI驱动API的使用方法。

操作SPI设备的基本步骤

1、打开SPI设备文件,其设备文件名为“SPI1:”
2、根据应用需求,设置SPI数据帧的基本参数,包括数据长度、波特率、时钟极性等参数。
3、若需要用到外部中断触发SPI读取操作,则需要设置外部GPIO中断管脚,及中断后的读取数据的长度。
4、设置完成后,对常规操作,即可使用标准的ReadFile函数接收SPI数据、使用WriteFile发送SPI数据。
5、对需要读写混合操作的,则需要调用DeviceIoControl来实现。
6、当启动了外部中断,则通过调用DeviceIoControl来等待外部事件,然后再调用ReadFile函数来读取已缓冲在驱动程序内部的SPI数据。
7、调用CloseHandle将关闭SPI接口并清除相关设置。即使重新打开SPI设备文件,需重新设置SPI的参数,才能进行读写。

SPI数据帧参数设置

初始化SPI,需要用到下面这个数据结构:
typedef struct _SPIFrame
{
UCHAR ucBitLength; //SPI数据bit长度,= 4、8、16
DWORD dwBitRate; //SPI波特率,20000000对应20Mbps
BOOL bPhase; //时钟相位
BOOL bPolarity; //时钟极性
} SPIFrame , *PSPIFrame;

该数据结构在hw_spi.h头文件中进行的定义,数据结构中的变量说明:
ucBitLength:SPI通讯的数据位长,EM9280/EM9287支持4bit、8bit、16bit三种数据位长格式,在hw_spi.h中定义了这三种数据位长的常量。
dwBitRate:SPI时钟速率,为每秒传输的bit数,参数20000000表示20Mbps,
bPhase:SPI时序相位设置(如下图所示)
bPolarity:SPI时序极性设置(如下图所示)

bPhase=0 , bPolarity=0

bPhase=1 , bPolarity=0

bPhase=0 , bPolarity=1

bPhase=1 , bPolarity=1

SPI设备的初始化例子

HANDLE hSPI;
SPIFrame ConfigSPI;
//打开设备驱动文件
hSPI = CreateFile(L”SPI1:”, //name of device
GENERIC_READ|GENERIC_WRITE, //desired access
FILE_SHARE_READ|FILE_SHARE_WRITE, //sharing mode
NULL, //security attributes (ignored)
OPEN_EXISTING, //creation disposition
FILE_FLAG_RANDOM_ACCESS, //flags/attributes
NULL); //template file (ignored)

if(hSPI == FALSE )
{
printf('SPI Open False!!!\r\n');
return 0;
}
//配置SPI参数
ConfigSPI.ucBitLength=SSP_WORD_LENGTH_8BITS; //Len_8BITS
ConfigSPI.dwBitRate=10000000; //10Mbps
ConfigSPI.bPhase=0;
ConfigSPI.bPolarity=0;
DeviceIoControl(hSPI, //file handle to the driver
SPI_IOCTL_SSPCONFIGURE, //I/O control code
&ConfigSPI, //in buffer
sizeof(ConfigSPI), //in buffer size
NULL,
0,
NULL,
NULL)

SPI接口的单向读写操作

用标准的ReadFile和WriteFile就可实现常规的SPI数据接收(读)或发送(写)。

SPI数据接收的函数调用:
ReadFile(hSPI, //设备驱动文件句柄
pDatBuf, //数据buffer指针,注意指针类型!
dwBufLength, //数据buffer的字节长度
pdwBytesRead, //实际读取的SPI数据字节数
NULL)

pDatBuf:数据BUFF指针。需要注意的是SPI数据帧长度若为4-bit或8-bit,则每个SPI数据占用一个字节,而对16-bit的SPI数据,则占用2个字节。一般来说,对4-bit或8-bit的SPI传输,其数据buffer应当是BYTE类型的;对16-bit的SPI传输,数据buffer则为WORD类型的。

dwBufLength:需要传输的数据字节长度。该参数是以字节为单位,其涵义也与SPI数据长度有关,对16-bit的SPI传输,dwBufLength应为2的倍数。

pdwBytesRead:SPI数据实际接收的字节数。一个正确的SPI数据接收调用后,指针pdwByteRead所包含的数据应等于dwBufLength,才能表示SPI数据接收执行完全正确。

SPI数据发送的函数调用:
WriteFile(hSPI, //设备驱动文件句柄
pDatBuf, //数据buffer指针,事先应把数据填入
dwBufLength, //数据buffer的字节长度
pdwBytesWritten, //实际发送的SPI数据字节数
NULL)

发送函数的参数定义与接收函数的参数定义是一致的。特别的,一个正确的SPI数据发送调用后,指针pdwByteWritten所包含的数据应等于dwBufLength。

读写混合型的SPI操作

在SPI的实际应用,有时需要在一个连续的片选过程中,既有读操作,也有写操作。这时间需要用到所谓的混合型SPI操作。

混合型SPI操作需要用到以下数据结构:
typedef struct _SPITransfer
{
LPVOID pTxBuff; //SPI发送buffer指针
LPVOID pRxBuff; //SPI接收buffer指针
DWORD dwBufLength; //本次SPI传输的字节数
} SPITransfer;

pTxBuff:SPI输出数据BUFF指针
pRxBuff:SPI读入数据BUFF指针
dwBufLength:SPI数据传输长度,以字节为单位

注意,EM9280的SPI接口仅支持半双工操作,因此在上述结构中,只能有一个buffer指针为有效指针,另一个必须为NULL。dwBufLength的定义与单向读写的定义一致。具体的传输是通过DeviceIoControl来实现的,举例说明,本例首先进行发送1个字节(8-bit SPI),然后接收2个字节。

SPITransfer Trans[2];
BYTE Tx[16], Rx[16]; //buffer足够大
Tx[0] = 0xE5; //发送的字节
Trans[0].pTxBuf = Tx;
Trans[0].pRxBuf = NULL;
Trans[0].dwBufLength = 1; //要发送1字节
Trans[1].pTxBuf = NULL;
Trans[1].pRxBuf = Rx;
Trans[1].dwBufLength = 2; //要接收2字节
DeviceIoControl(hSPI,
SPI_IOCTL_EXCHANGE,
Trans, //in buffer
sizeof(Trans) , //in buffer size
NULL,
0,
NULL,
NULL))

在上述调用中需要注意的是,DeviceIoControl()输入参数中的buffer长度必须是数据结构SPITransfer大小的整倍数,否则将被视作无效参数。

外部中断触发的SPI操作

外部中断触发的SPI操作,主要是利用SPI的高速特性,进行实时的大数据量读取。因为SPI的接线非常简单,作为一种高效低成本的接口模式在工业控制领域有广泛的应用。使用这种SPI操作方式,需要用到以下数据结构:
typedef struct _SPI_IrqTransfer
{
DWORD dwGpioPin; //外部中断管脚,上升沿触发中断
DWORD dwBufLength; //中断触发的SPI传输的字节数,小于64KB
DWORD dwRVSD; //保留,必须设置为0
} SPI_IrqTransfer;

dwGpioPin:要用作外部中断源的GPIO引脚
dwBufLength:要读取的数据字节长度
dwRVSD:系统保留,必须设置为0

在上述结构中,dwBufLength的定义与单向读写的定义一致,如果dwGpioPin与dwBufLength同时设置为0,则将关闭已打开的GPIO中断资源并禁止该功能启动。dwGpioPin为EM9280主板的GPIO引脚编号,与GPIO操作时的引脚数据一致。注意:由于系统功能的占用,不是所有的GPIO引脚都可以用作外部中断触发源。

•EM9280可以使用的GPIO引脚有:GPIO0、GPIO1、GPIO6、GPIO7、GPIO10、GPIO11、GPIO20、GPIO21、GPIO22、GPIO23。

•EM9287和EM9281可以使用的GPIO引脚有:GPIO0 - GPIO23。

该操作的具体的设置操作仍然需要调用DeviceIoControl()来实现。
SPI_IrqTransfer irq_transfer;
irq_transfer. dwGpioPin=GPIO0; //使用GPIO0作为SPI的外部中断源
irq_transfer. dwBufLength=1024; //中断产生后需要读取1024字节的数据
irq_transfer. dwRVSD=0;
DeviceIoControl(hSPI,
SPI_IOCTL_SSP_IRQTransfer,
& irq_transfer, //输入参数
sizeof(SPI_IrqTransfer), //输入参数字节数
NULL,
0,
NULL,
NULL);

设置完成即启动外部中断自动触发SPI操作,一旦中断产生,驱动程序将自动接收dwBufLength长度的数据,存储在驱动程序的内部缓冲区中。数据接收完成后,将发送事件通知应用层。应用程序可通过DeviceIoControl()调用来等待该事件,得到事件后再调用ReadFile读取数据。通过调用DeviceIOControl()等待SPI事件,可以给定一个时间参数作为等待超时的条件,以ms为单位。成功等到SPI执行完成的消息时,DeviceIoControl会返回TRUE,否则返回FALSE。SPI事件等待的调用方法如下:
DeviceIoControl(hSPI,
SPI_IOCTL_SSP_WaitSPIEvent,
&DelayTime, //等待超时,时间为ms
Sizeof(DWORD),
NULL,
0,
NULL,
NULL)

调用上述方法启动了外部中断触发SPI读取数据的功能后,该功能将一直存在,即每次在所设置的GPIO引脚上产生中断信号,都会执行一次SPI读取操作,直到应用程序关闭该中断,即设置dwGpioPin和dwBufLength等于0,再调用DeviceIoControl()进行设置操作。

SPI操作相关的范例代码请参考光盘中的EM9280_SPIDemo,或来邮件索取或咨询。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    1471

    浏览量

    61741
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1688

    浏览量

    91174
  • 嵌入式主板
    +关注

    关注

    7

    文章

    6084

    浏览量

    35151
收藏 人收藏

    评论

    相关推荐

    LED驱动电源灌封胶的使用方法

    LED驱动电源灌封胶的使用方法LED驱动电源灌封胶适用于一般电子元器件、电源模块和线路板的灌封保护,以及各种电子电器的灌封,如开关电源、驱动电源、汽车HID灯模块电源、汽车点火系统模块
    发表于 02-15 10:22

    MLDL之API:关于各国内外大平台API简介、使用方法之详细攻略

    MLDL之API:关于各国内外大平台API简介、使用方法之详细攻略
    发表于 12-19 17:00

    串行通信基础知识与UART驱动构件使用方法

    慕课苏州大学.嵌入式开发及应用.第二章.入门与软件框架.串行通信基础知识与UART驱动构件使用方法0 目录2 入门与软件框架2.1 串行通信基础知识与UART驱动构件使用方法2.1.1
    发表于 12-20 06:21

    介绍SPI使用方法

    ,这篇介绍SPI使用方法,流程与TIM类似。大致总结为以下几个步骤:在RT-thread settings中使能对应的驱动框架在stm32f4xx_hal_conf.h中使能对应的模块(HAL_XX_MODULE_ENABLE
    发表于 02-17 06:32

    IGBT驱动模块EXB841使用方法的改进

    IGBT驱动模块EXB841使用方法的改进 摘要: 本文对目前在电力电子技术中广泛使用的IGBT驱动模块EXB841的使用方法进行了改进,克服了EXB841本身的缺陷,提高了保护
    发表于 05-08 15:11 84次下载

    浅谈电脑灯控制台的基本使用方法

    浅谈电脑灯控制台的基本使用方法 电脑灯自1981年问世以来,就在各类演出、演播室的节目制作中得到应用。可以说电脑灯的出现是舞
    发表于 12-12 10:18 4318次阅读

    对高级驱动辅助系统的传感器的使用方法

    本文档介绍了对高级驱动辅助系统的传感器的使用方法,供网友参考。
    发表于 09-13 18:37 1次下载

    浅谈光耦的使用方法_章圣焰

    浅谈光耦的使用方法及设计电路的分析技巧
    发表于 10-16 13:44 6次下载

    LUA脚本的绘图API函数的使用方法及使用函数的注意事项

    物联型串口屏通过 LUA 脚本配合工程可以完成大部分的内部逻辑处理,可以做到让 MCU 只参与数据处理,不参与屏的逻辑处理。本文将介绍大彩 LUA 脚本 API 函数中的绘图 API 函数使用方法,以及使用函数的注意事项。
    发表于 10-17 08:00 9次下载
    LUA脚本的绘图<b class='flag-5'>API</b>函数的<b class='flag-5'>使用方法</b>及使用函数的注意事项

    LUA脚本API函数中的回调函数使用方法和注意事项资料和程序免费下载

    本文档的主要内容详细介绍的是LUA脚本API函数中的回调函数使用方法和注意事项资料和程序免费下载。
    发表于 10-17 08:00 5次下载
    LUA脚本<b class='flag-5'>API</b>函数中的回调函数<b class='flag-5'>使用方法</b>和注意事项资料和程序免费下载

    浅谈keil软件的使用方法

    Keil的使用方法 - 常用功能(三)
    的头像 发表于 04-07 14:50 4834次阅读
    <b class='flag-5'>浅谈</b>keil软件的<b class='flag-5'>使用方法</b>

    浅谈压力传感器的使用方法及注意事项

    浅谈压力传感器的使用方法及注意事项
    发表于 03-10 17:36 14次下载
    <b class='flag-5'>浅谈</b>压力传感器的<b class='flag-5'>使用方法</b>及注意事项

    Compose中的动画API概览及使用方法

    我们将通过本文介绍 Compose 中的一些动画 API,并探讨如何有效地使用它们。Compose 中的动画 API 是我们构想的全新 API,这些 API 中有许多是声明式的,您可以
    的头像 发表于 06-06 17:48 2317次阅读

    Linux驱动-spidev驱动使用方法

    Linux内核集成了spidev驱动,提供了SPI设备的用户空间API,支持用于半双工通信的read()和write()访问接口以及用于全双工通信和I/O配置的ioctl()接口;使用时,只需
    的头像 发表于 04-07 10:22 4738次阅读

    浅谈锡膏的储存及使用方法

    锡膏(焊锡膏)是电子组装过程中常用的材料,它的储存和使用方法对保证焊接质量和性能至关重要。以下是详细的储存及使用方法
    的头像 发表于 06-27 10:02 700次阅读