当前位置:首页 > 嵌入式 > 嵌入式大杂烩
[导读]关注「嵌入式大杂烩」,选择「星标公众号」一起进步!作者 |  Acuity1.写在前面spi(SerialPeripheralInterface)即串行外设接口。与i2c一样,spi也常用外设设备通信的总线,从事嵌入式开发必不可少的掌握。根据本人以往的经历,对spi进行总结(主要...

关注「嵌入式大杂烩」,选择「星标公众号」一起进步!



作者 |  Acuity


1.写在前面

spi(Serial Peripheral Interface)即串行外设接口。与i2c一样,spi也常用外设设备通信的总线,从事嵌入式开发必不可少的掌握。


根据本人以往的经历,对spi进行总结(主要是MCU范畴,Linux已有成熟的驱动设备),主要目的及实现:


1)spi总线与spi设备分离;


2)快速使用新的硬件spi或者模拟spi;


3)方便移植spi总线设备及spi外设程序到不同mcu平台。


2.spi总线抽象

此部分实现源码为:spi_core.c spi_core.h


2.1 spi总线模型对外接口(API)

/*extern function*/
extern int spi_send_then_recv(struct spi_dev_device *spi_dev,const void *send_buff,
unsigned short send_size,void *recv_buff,unsigned short recv_size)
;
extern int spi_send_then_send(struct spi_dev_device *spi_dev,const void *send_buff1,
unsigned short send_size1,const void *send_buff2,unsigned short send_size2)
;
extern int spi_send_recv(struct spi_dev_device *spi_dev,const void *send_buff,void *recv_buff,unsigned short data_size);
extern int spi_send(struct spi_dev_device *spi_dev,const void *send_buff,unsigned short send_size);
1)spi_send_then_recv,标准spi,常规操作,发送完一帧再接收,如读取某芯片寄存器的值;


2)spi_send_then_send,标准spi,常规操作,发送完一帧再发送,如向某芯片寄存器(地址)写入数据;


3)spi_send_recv,非标spi,具体看芯片时序图,产生时钟信号,发送完成的同时,也接收完成;第二种情况是,只接收,发送动作只是用来产生时钟信号,如一些AD芯片;


4)spi_send,标准或非标spi都使用,只发送无返回值或者无须理会返回值,如spi LCD屏。


2.2 spi总线抽象API实现

以“spi_send_then_recv”函数为例:


1)spi_dev:spi设备指针,类型为“struct spi_dev_device”,驱动一个spi外设时,首先需要对此指针进行初始化;


2)send_buff:待发送数据(缓存);


3)send_size:发送数据量大小(单位字节);


4):recv_buff:存放返回值数据缓存(地址);


5):recv_size:返回数据量大小。


另外3个函数,第一个参数都为spi设备指针,其他参数为发送/接收缓冲区,收发数据量等,通过变量名即可看出。


2.3 struct spi_de_device

该结构体为关键,调用API驱动一个外设时,需要先初始化(类似Linux的注册设备驱动)。一个完整的spi外设,包括片选和总线量部分,一个总线可和多个片选组成,驱动多个外设,因此struct spi_dev_device设计原型为:


struct spi_dev_device
{

void (*spi_cs)(unsigned char state);
struct spi_bus_device *spi_bus;
};
1)第一个参数为函数指针,主要功能的实现spi外设片选的选择(拉低/拉高)功能;


2)第二个参数为spi总线相关的结构体指针,主要是底层相关收据收发的的功能,具体继续往下看改结构体。


2.4 struct spi_bus_device *spi_bus

该结构体为底层硬件相关的spi总线实现,具体由实际需求实现,如用硬件spi还是用模拟spi。struct spi_bus_device*spi_bus原型为:


struct spi_bus_device
{

int (*spi_bus_xfer)(struct spi_dev_device *spi_bus,struct spi_dev_message *msg);
void *spi_phy;
unsigned char data_width;
};
1)第一个参数是函数指针,为spi总线收发函数,这部分就是我们平常写裸机代码时候写到的,只是这里把它放在一个结构体里面,以函数指针的方式实现;这样的好处是,上层接口不变,更好其他MCU或者使用模拟spi时,只需修改此部分的函数实体,上层代码不需变动。


2)第二个参数,一个指针,表示具体物理spi,如stm32的SPI1、SPI2,或者模拟spi;


3)第三参数,数据宽度,一般是8bit或者16bit。


其他参数,如数据速率、spi模式等,其实也可以放在此处,只是个人觉得此类参数不常变动,为了节约内存,故不加入此结构体配置中。下面中断分析函数指针


int (*spi_bus_xfer) (struct spi_dev_device *spi_bus,struct spi_dev_message *msg)”的实现。

2.5 spi_bus_xfer

该函数指针入口参数为spi设备指针(struct spi_dev_device )、spi设备信息帧指针(struct spi_dev_message)。struct spi_dev_device与前面提及的为同一类参数,struct spi_dev_message为收发数据信息帧,其原型如下:


struct spi_dev_message
{

const void *send_buf;
void *recv_buf;
int length;
unsigned char cs_take    : 1;
unsigned char cs_release : 1;
};
1)send_buf:待发送数据(缓存);


2)recv_buf:存放返回值数据缓存(地址);


3)length:发送/接收数据长度;


4)cs_take:使能片选;


5)cs_release:释放片选。


3. spi总线抽象实现

此部分实现源码为:spi_hw.c spi_hw.h


3.1 spi总线抽象API实现

第一步:“spi_send_then_recv”,实现代码如下:


int spi_send_then_recv(struct spi_dev_device *spi_dev,const void *send_buff,unsigned short send_size,void *recv_buff,unsigned short recv_size)
{
struct spi_dev_message message;

message.length     = send_size;
message.send_buf   = send_buff;
message.recv_buf   = 0;
message.cs_take    = 1;
message.cs_release = 0;
spi_dev->spi_bus->spi_bus_xfer(spi_dev,
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭