FPGA学习笔记(九)SPI学习总结及stm32的HAL库下SPI配置

news2024/11/24 12:30:23

系列文章目录

一、FPGA学习笔记(一)入门背景、软件及时钟约束

二、FPGA学习笔记(二)Verilog语法初步学习(语法篇1)

三、FPGA学习笔记(三) 流水灯入门FPGA设计流程

四、FPGA学习笔记(四)通过数码管学习顶层模块和例化的编写

五、FPGA学习笔记(五)Testbench(测试平台)文件编写进行Modelsim仿真

六、FPGA学习笔记(六)Modelsim单独仿真和Quartus联合仿真

七、FPGA学习笔记(七)verilog的深入学习之任务与函数(语法篇3)

八、FPGA学习笔记(八)同步/异步信号的打拍分析及处理


参考文章

FPGA实现的SPI协议(一)----SPI驱动

文章目录

  • 系列文章目录
  • 参考文章
  • SPI协议概念
    • 概念
    • 工作方式
    • 协议
  • stm32的HAL库下的SPI
    • 配置SPI工作模式
    • 配置SPI工作参数
    • 程序代码
  • FPGA下的SPI


SPI协议概念

概念

SPI(Serial Peripheral Interface,串行外围设备接口)通讯协议,是一个重要的低速协议。支持全双工通信,且传输速度相对较快,缺点是没有指定的流控制,没有应答机制,在数据可靠性上有一定缺陷。也有人说SPI就是数据交换,想要接收一个数据就必须发送一个数据。一般的实现通常能达到甚至超过10 Mbps。

工作方式

在这里插入图片描述
SCK (Serial Clock):时钟信号线,用于同步通讯数据。

MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。

MISO (Master Input,Slave Output):主设备输入/从设备输出引脚。

CS (Chip Select):片选信号线。当有多个 SPI 从 设备与 SPI 主机相连时,每个从设备都有独立的片选信号线,通过CS片选信号来决定通信的从机设备是哪一台。通信期间低电平有效,表示对应从机被选中。
有的也把CS叫SS( Slave Select),NSS就是(Negetive Slave Select:低电平开始传输)

协议

SPI协议中,时钟上升沿或下降沿读取、空闲时是高电平还是低电平(时钟信号)都是可以选择的。
时钟极性(CPOL,Clock Polarity):规定了SCK时钟信号空闲状态的电平。0低电平,1高电平。
时钟相位(CPHA,Clock Phase):0上升沿,1下降沿。(通常用下降沿采样的少)

在这里插入图片描述
SPI 每次传输的单位数不受限制,一般是八个单位,也就是一个字节。在传输过程中,没有规定LSB(Least Significant Bit最低有效位)和MSB(Most Significant Bit最高有效位),一般采用的MSB高位先传输。

stm32的HAL库下的SPI

配置SPI工作模式

在这里插入图片描述

这里的主机接收模式相当下图:(后四个相当是单工模式,只支持单方向的传输)
在这里插入图片描述
半双工模式(数据传输上支持双方向传输,但是不能同时进行双向传输):
stm32支持半双工模式,可以(通过使能BIDIMODE reg位来)选择单线双向通信模式或单线单向模式。
在这里插入图片描述
又在网上找了找,因为还没有实际接触SPI的单线、双线、四线模式,所以只能先简单概括一下:(不一定对)
1.单线模式:就是普通的最常见的SPI接线方式,MOSI主机发从机接,MISO:主机接收从机发送
2.双线模式:MOSI和MISO都用来发送数据,同时单方向传输(感觉变成了IIC方式)
在这里插入图片描述
3.四线模式:QSPI是Queued SPI的简写,是Motorola公司推出的SPI接口的扩展,比SPI应用更加广泛。
同时使用MOSI、MISO、WP、HOLD作为数据传输,使得SPI传输带宽增加四倍;
改掉了原来引脚的功能:WP(Write Protect)是防止QSPI Flash的状态寄存器被写入错误的数据,WP信号低电平有效;HOLD信号的作用是暂停QSPI Flash的操作。当HOLD信号为低,并且CS也为低时,串行输出信号DO将处于高阻态,串行输入信号DI与串行时钟信号SCLK将被QSPI Flash忽略。当HOLD拉高以后,QSPI Flash的读写操作能继续进行。当多个SPI设备共享同一组SPI总线相同的信号的时候,可以通过HOLD来切换信号的流向。
在这里插入图片描述

在这里插入图片描述

配置SPI工作参数

在这里插入图片描述

配置NSS 引脚的使用模式,可以选择为硬件模式(SPI_NSS_HARD )与软件模式( SPI_NSS_SOFT ),在硬件模式中的SPI 片选信号由SPI 硬件自动产生,而软件模式则需要我们亲自把相应的GPIO 端口拉高或置低产生非片选和片选信号。实际中软件模式应用比较多。
在这里插入图片描述
CRC Calculation:指定是否启用CRC 计算,若我们使用CRC 校验时,就使用这个成员的参数(多项式),来计算CRC 的值。
Baud Rate是计算出的sck速率
在这里插入图片描述
摩托罗拉协议就是一般的SPI协议,TI协议的一般指的SSP协议。

程序代码

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,
                                          uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
                                             uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
                                              uint16_t Size);
HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi);

这里有一个问题,就是从机的SCK是input,那么主机如何接收从机数据呢,我想还是通过主机发送数据,从机与此同时接收数据并发送数据,主机才能接收,这也是为什么网上有人说SPI是数据交换。

FPGA下的SPI

以下是FPGA作为主机的时候,是参考文章里面的代码


module spi_drive
(
// 系统接口
    input               sys_clk		, 			// 全局时钟50MHz
    input               sys_rst_n	, 			// 复位信号,低电平有效
// 用户接口	
    input               spi_start	,			// 发送传输开始信号,一个高电平
    input              	spi_end		,			// 发送传输结束信号,一个高电平
    input        [7:0]  data_send   , 			// 要发送的数据
    output  reg  [7:0]  data_rec  	, 			// 接收到的数据
    output  reg         send_done	, 			// 主机发送一个字节完毕标志位    
    output  reg         rec_done	, 			// 主机接收一个字节完毕标志位    
// SPI物理接口
    input               spi_miso	, 			// SPI串行输入,用来接收从机的数据
    output  reg         spi_sclk	, 			// SPI时钟
    output  reg         spi_cs    	, 			// SPI片选信号,低电平有效
    output  reg         spi_mosi				// SPI输出,用来给从机发送数据          
);
 
reg	[1:0]	cnt;								//4分频计数器
reg	[3:0]	bit_cnt_send;						//发送计数器
reg	[3:0]	bit_cnt_rec;						//接收计数器
reg			spi_end_req;						//结束请求
 
//4分频计数器 
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cnt <= 2'd0;						
	else if(!spi_cs)begin
		if(cnt == 2'd3)
			cnt <= 2'd0;
		else
		cnt <= cnt + 1'b1;		
	end
	else 
		cnt <= 2'd0;	
end
// 生成spi_sclk时钟  
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		spi_sclk <= 1'b0;			//模式0默认为低电平,CPOL=0				
	else if(!spi_cs)begin			//在SPI传输过程中
		if(cnt == 2'd0 )
			spi_sclk <= 1'b0;
		else if (cnt == 2'd2)
			spi_sclk <= 1'b1;
		else 
			spi_sclk <= spi_sclk;	
	end
	else 
		spi_sclk <= 1'b0;			//模式0默认为低电平		
end
// 生成片选信号spi_cs
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		spi_cs <= 1'b1;				//默认为高电平,低电平选中						
	else if(spi_start)				//开始SPI准备传输,拉低片选信号
		spi_cs <= 1'b0;
	//收到了SPI结束信号,且结束了最近的一个BYTE
	else if(spi_end_req && (cnt == 2'd1 && bit_cnt_rec == 4'd0))
		spi_cs <= 1'b1;				//拉高片选信号,结束SPI传输
end
// 生成结束请求信号(捕捉spi_end信号)
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		spi_end_req <= 1'b0;		//默认不使能					
	else if(spi_cs)					
		spi_end_req <= 1'b0;		//结束SPI传输后拉低请求
	else if(spi_end)				
		spi_end_req <= 1'b1;		//接收到SPI结束信号后就把结束请求拉高
end
// 发送数据过程--------------------------------------------------------------------
 
// 发送数据
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		spi_mosi <= 1'b0;						//模式0空闲
		bit_cnt_send <= 4'd0;
	end
	else if(cnt == 2'd0 && !spi_cs)begin		//模式0的上升沿
		spi_mosi <= data_send[7-bit_cnt_send];	//发送数据移位
		if(bit_cnt_send == 4'd7)				//发送完8bit
			bit_cnt_send <= 4'd0;
		else
			bit_cnt_send <= bit_cnt_send + 1'b1;	
	end
	else if(spi_cs)begin						//非传输时间段
		spi_mosi <= 1'b0;						//模式0空闲
		bit_cnt_send <= 4'd0;
	end
	else begin
		spi_mosi <= spi_mosi;
		bit_cnt_send <= bit_cnt_send;
	end
end
// 发送数据标志
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		send_done <= 1'b0;			
	else if(cnt == 2'd0 && bit_cnt_send == 4'd7)		//发送完了8bit数据
		send_done <= 1'b1;								//拉高一个周期,表示发送完成	
	else 
		send_done <= 1'b0;			
end
 
// 接收数据过程--------------------------------------------------------------------
 
// 接收数据spi_miso
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		data_rec <= 8'd0;		
		bit_cnt_rec <= 4'd0;
	end
	else if(cnt == 2'd2 && !spi_cs)begin				//模式0的上升沿
		data_rec[7-bit_cnt_rec] <= 	spi_miso;			//移位接收
		if(bit_cnt_rec == 4'd7)							//接收完了8bit
			bit_cnt_rec <= 4'd0;
		else
			bit_cnt_rec <= bit_cnt_rec + 1'b1;	
	end
	else if(spi_cs)begin								
		bit_cnt_rec <= 4'd0;
	end
	else begin
		data_rec <= data_rec;
		bit_cnt_rec <= bit_cnt_rec;
	end
end
// 接收数据标志
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		rec_done <= 1'b0;									
	else if(cnt == 2'd2 && bit_cnt_rec == 4'd7)			//接收完了8bit
		rec_done <= 1'b1;								//拉高一个周期,表示接收完成			
	else 
		rec_done <= 1'b0;					
end
 
endmodule

上面程序的结构就是4分频发出去一个SCK信号,然后分频产生的cnt 信号来发送和接收数据,最后有传输开始和传输结束信号,不过这两个信号感觉…,主机不需要别的输入控制,想发的时候发送?那么从机跟不上咋办,就像stm32是串行的,不像FPGA是并行的,所以stm32接受前发送一个起始信号和结束信号

想想FPGA作为从机的时候:
打拍收集SCK的信号就行了,然后在对应的主机的设置,在SCK的上升沿或者下降沿收集信号就行。FPGA是并行的,主机发什么,它都能跟上

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/66434.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

上海亚商投顾:沪指继续震荡向上 零售等消费股表现活跃

上海亚商投顾前言&#xff1a;无惧大盘大跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪三大指数今日低开高走&#xff0c;深成指盘中涨超1%&#xff0c;创业板指一度涨逾1.5%&#xff0c;随后均上演冲高回…

【C++进阶】引用 函数提高

文章目录一 、引用1.1 引用的基本使用1.2 引用的注意事项1.3 引用做函数参数1.4 引用的本质 &#xff1a;指针的常量1.5 常量引用二、函数提高1 函数默认参数2 函数占位参数3 函数重载一 、引用 1.1 引用的基本使用 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型 &a…

Python计算目标检测中的IoU

Python计算目标检测中的IoU前言前提条件相关介绍实验环境IoU概念代码实现前言 本文是个人使用PythonPython处理文件的电子笔记&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xff0c;可点击进入我的个人主页查看 前提条件 熟悉P…

​寒武纪思元370系列与飞桨完成II级兼容性测试,联合赋能AI落地实践

2022年12月2日&#xff0c;寒武纪思元370系列与飞桨已完成II级兼容性测试&#xff0c;兼容性表现良好。 本次II级兼容性测试基于寒武纪MLU370系列&#xff0c;测试了包含PP-YOLO、YOLOv3、ResNet50、DeepLabv3、BERT、OCR-DB等共计15个模型的验证&#xff0c;覆盖了计算机视觉…

01-go基础-07-map(声明map、初始化map、map赋值、遍历map、判断key是否在map中、删除map成员)

文章目录1. 声明 map2. 初始化 map3. map赋值3.1 直接声明并赋值3.2 分别定义每一组键值对4. 遍历map5. 判断key是否在map中6. 删除成员&#xff08;delete()&#xff09;1. 声明 map 语法 var MapName map[keyType]valueType语法示例 var warlords map[string]string仅声明…

Eureka 服务端搭建入门与集群搭建

前言 Eureka在2022年已经确定的是&#xff0c;2.x版本开源计划已经停止了&#xff0c;1.x版本陆陆续续还是有人在维护的。还有很多最早使用微服务的公司还在继续用着eureka作为注册中心&#xff0c;也是很多同学学习微服务的敲门砖。 搭建Eureka服务端 创建一个平平无奇的ma…

2203 CSDN课程-python入门课

Python入门课&#xff0c;较为基础。 1 简介 1.1 前言 事实上&#xff0c;Python已经走过很多年的发展历程了&#xff0c;笔者最一开始学习的时候还是2.x版本&#xff0c;现在早就3.xx版本了。在当提笔&#xff0c;不是青春年少。确实是这样&#xff0c;我记得是2018年开始接…

【Linux从入门到放弃】Linux权限详解

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《Linux从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; L…

m基于遗传优化的复杂工序调度matlab仿真,输出甘特图和优化收敛图

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 遗传算法 (Genetic Algorithm&#xff0c;GA) 是一种基于规律进化的随机优化搜索算法&#xff0c;该算法最早是由Holland在1975年提出的。遗传算法的主要优势是通过对目标对象进行优化操作&#…

力扣-234-回文链表

回文链表 CategoryDifficultyLikesDislikesalgorithmsEasy (52.70%)1576- TagsCompanies给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff…

FTP文件传输服务

FTP 服务概述2-1 FTP连接及连接模式 控制连接&#xff1a;TCP 21&#xff0c;用于发送FTP命令信息 数据连接&#xff1a;TCP 20&#xff0c;用于上传、下载数据 数据连接的建立类型 主动模式&#xff1a;服务端从 20 端口主动向客户端发起连接 被动模式&#xff1a;服务端在指…

SIM8262E-M2,SIM8262A-M2,SIM8260C-M2,SIM8260C 5G定位模组支持多频段

SIM8262&#xff1a;支持R16标准的5G模组&#xff0c;支持多频段5G NR / LTE-FDD / LTE TDD / HSPA&#xff0c;支持SA和NSA双组网模式&#xff0c;高达 2.4Gbps的数据传输&#xff1b;扩展能力强&#xff0c;接口丰富&#xff0c;包括PCIe、USB3.1、GPIO等。该模块为客户的应用…

Polygon zkEVM中的子约束系统

1. 引言 前序博客有&#xff1a; Polygon zkEVM工具——PIL和CIRCOM Polygon zkEVM中主要设计了3种子约束系统&#xff1a; 1&#xff09;Permutation check子约束系统&#xff1a;PIL中的关键字为is。 2&#xff09;Plookup 子约束系统&#xff1a;PIL中的关键字为in。 …

数据结构——栈,队列,及其结构特点应用。

​✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;数据结构——栈&#xff0c;队列。 &#x1f525;<3>创作者&#xff1a;我的代码爱吃辣 ☂️<4>开发环境&#xff1a;Visual Studio 2022 &#x1f3e1;<5>系统环境…

路由查找原理

最近在设计Netflow采集系统时&#xff0c;我想要将客户端的公网IP根据IP库转为对应的国家&#xff0c;此外在CACHE机房中&#xff0c;交换机上是没有AS信息的&#xff0c;因此我们也需要根据IP去查路由库&#xff0c;转换出AS信息。 这两个问题的本质是类似的&#xff0c;无论是…

棱镜七彩作为首批成员单位入选工信部网络安全产业发展中心重点实验室!

近日&#xff0c;工信部网络安全产业发展中心公布了网络安全技术与产业发展工信部重点实验室专项工作组成员单位名单。棱镜七彩首批入选&#xff0c;成为信息技术应用创新基础软硬件安全工作组的成员单位&#xff01; 为深入贯彻落实网络强国战略&#xff0c;充分发挥网络安全技…

FOC控制之小A小B小C是如何追求小D的

1、写在前面 随着电动汽车的热火&#xff0c;关于FOC控制技术的文章这几年在网络上可谓是一搜一大把&#xff0c;各种理论分析&#xff0c;公式推导&#xff0c;应有尽有。通过这些文章&#xff0c;可以看出大佬还是很多的。另外也有FOC的开源硬件。而在大几年前&#xff0c;第…

党务管理系统搭建,答题获积分,学习有好礼

党务管理系统搭建是以服务党员群众为目的的&#xff0c;然后通过互联网信息化手段&#xff0c;将党建工作与大数据等新技术融合&#xff0c;实现党建资源答题学习的数字化整合&#xff0c;也提升了党建科学化水平。 党务管理系统搭建助力党建数字化、规范化&#xff1a;利用信息…

快来生成你专属的英文名吧(使用字符级RNN)!

目录 一.前言 二.准备数据 三.构造神经网络 四.训练 五.网络采样&#xff08;预测&#xff09; 一.前言 数据集为18个国家的姓氏&#xff0c;任务是根据训练得到的模型&#xff0c;在给定国家类别和首字母后&#xff0c;能得到一个与该国人名非常相似的一个人名。 > …

openstack基本命令小结

文章目录Openstack0、进入1、查看日志日志位置日志格式举例2、CLI命令格式基本格式使用帮助3、命令文档&#xff08;常用&#xff09;4、基础组件的常用命令1、keystone查询类查看所有组件状态查看所有服务的状态查看域列表查看服务列表查看节点列表查询用户列表查询用户详细信…