江科大SPI串行外设接口hal库实现

article/2025/7/15 3:53:09

hal库相关函数

初始化结构体 

typedef struct
{uint32_t Mode;                /*SPI模式*/uint32_t Direction;           /*SPI方向*/uint32_t DataSize;            /*数据大小*/uint32_t CLKPolarity;         /*时钟默认极性控制CPOL*/uint32_t CLKPhase;            /*有效边延控制CPOA*/uint32_t NSS;                 /*外设选中*/uint32_t BaudRatePrescaler;   /*波特率分频*/uint32_t FirstBit;            /*设置先行位*/uint32_t TIMode;              /*仅当需要通过定时器触发SPI传输(如周期性发送数据)时启用,否则保持默认 DISABLE。*/uint32_t CRCCalculation;      /*CRC校验*/uint32_t CRCPolynomial;       /*循环冗余校验多项式*/
} SPI_InitTypeDef;

SPI句柄

typedef struct __SPI_HandleTypeDef
{SPI_TypeDef                *Instance;      /*SPI外设地址*/SPI_InitTypeDef            Init;           /*SPI初始化结构体*/const uint8_t              *pTxBuffPtr;    /*发送缓存区*/uint16_t                   TxXferSize;     /*发送数据大小 */__IO uint16_t              TxXferCount;    /*剩余发送数量*/uint8_t                    *pRxBuffPtr;    /*接收缓存区*/uint16_t                   RxXferSize;     /*接受数据大小*/__IO uint16_t              RxXferCount;    /*剩余接收量*/void (*RxISR)(struct __SPI_HandleTypeDef *hspi);   /*接收的中断服务函数*/void (*TxISR)(struct __SPI_HandleTypeDef *hspi);   /*发送的中断服务函数*/DMA_HandleTypeDef          *hdmatx;        /*SPI搭配DMA的发送部分*/DMA_HandleTypeDef          *hdmarx;        /*SPI搭配DMA的接受部分*/HAL_LockTypeDef            Lock;           /*配置锁存*/__IO HAL_SPI_StateTypeDef  State;          /*SPI通讯状态*/__IO uint32_t              ErrorCode;      /*SPI的错误状态*/#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1U)void (* TxCpltCallback)(struct __SPI_HandleTypeDef *hspi);             /*!< SPI Tx Completed callback          */void (* RxCpltCallback)(struct __SPI_HandleTypeDef *hspi);             /*!< SPI Rx Completed callback          */void (* TxRxCpltCallback)(struct __SPI_HandleTypeDef *hspi);           /*!< SPI TxRx Completed callback        */void (* TxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);         /*!< SPI Tx Half Completed callback     */void (* RxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);         /*!< SPI Rx Half Completed callback     */void (* TxRxHalfCpltCallback)(struct __SPI_HandleTypeDef *hspi);       /*!< SPI TxRx Half Completed callback   */void (* ErrorCallback)(struct __SPI_HandleTypeDef *hspi);              /*!< SPI Error callback                 */void (* AbortCpltCallback)(struct __SPI_HandleTypeDef *hspi);          /*!< SPI Abort callback                 */void (* MspInitCallback)(struct __SPI_HandleTypeDef *hspi);            /*!< SPI Msp Init callback              */void (* MspDeInitCallback)(struct __SPI_HandleTypeDef *hspi);          /*!< SPI Msp DeInit callback            */#endif  /* USE_HAL_SPI_REGISTER_CALLBACKS */
} SPI_HandleTypeDef;

SPI初始化函数 

HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi);
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi);
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi);

SPI收发相关函数

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, const 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, const uint8_t *pTxData, uint8_t *pRxData,uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, const 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, const uint8_t *pTxData, uint8_t *pRxData,uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, const 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, const 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);
/* Transfer Abort functions */
HAL_StatusTypeDef HAL_SPI_Abort(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_Abort_IT(SPI_HandleTypeDef *hspi);

SPI发送接收,收发一体函数,以及DMA暂停恢复停止,SPI通讯中断

SPI读写W25Q64

按照江科大的配置来配置CubeMx

全双工主模式,数据宽度为8位,高位先行,波特率分频为128,CPOL为低,CPOA为1

NSS为软件触发(GPIO那边配置PA4为推完输出模式)

首先说一个通用的错误,我们得把数据的获取和处理,放在初始化函数后面... 

CubeMx生成的初始化结构注释太多是带点混乱的,注意这个问题即可。

主函数我们直接把江科大的cv过来即可,对于SPI.c这个文件,我们需要进行修改,把江科大的SPI相关函数全部修改成hal库版本的SPI函数.

通过对GPIO口的PA4进行操作来选择时序的开启和关闭。

void MySPI_Start(void)
{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);//根据BitValue,设置SS引脚的电平//拉低SS,开始时序
}void MySPI_Stop(void)
{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);				//拉高SS,终止时序
}
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{uint8_t gid[3];uint8_t id = W25Q64_JEDEC_ID;MySPI_Start();								//SPI起始HAL_SPI_Transmit(&hspi1,&id,1,1000);HAL_SPI_Receive(&hspi1,gid,3,1000);//一次性接收三位数据MySPI_Stop();								//SPI终止*MID = gid[0];	//交换接收MID,通过输出参数返回*DID = (gid[1] << 8) | gid[2];	//高8位移到高位,或上交换接收DID的低8位,通过输出参数返回}void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{MySPI_Start();								//SPI起始MySPI_SwapByte(W25Q64_JEDEC_ID);			//交换发送读取ID的指令*MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);	//交换接收MID,通过输出参数返回*DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);	//交换接收DID高8位*DID <<= 8;									//高8位移到高位*DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);	//或上交换接收DID的低8位,通过输出参数返回MySPI_Stop();								//SPI终止
}

江科大的交换函数我们可以通过hal库自带的交换函数来实现

HAL_SPI_TransmitReceive()

或者说对于数据的收发,我们通过hal库的收发函数来进行。

其他的几个函数也是通过类似的手段进行修改即可。

void W25Q64_WriteEnable(void)
{uint8_t temp = W25Q64_WRITE_ENABLE;MySPI_Start();								//SPI起始HAL_SPI_Transmit(&hspi1,&temp,1,1000);		//发送写使能的指令MySPI_Stop();								//SPI终止
}void W25Q64_WriteEnable(void)
{MySPI_Start();								//SPI起始MySPI_SwapByte(W25Q64_WRITE_ENABLE);		//交换发送写使能的指令MySPI_Stop();								//SPI终止
}
void W25Q64_WaitBusy(void)
{uint32_t Timeout;uint8_t temp = W25Q64_READ_STATUS_REGISTER_1;MySPI_Start();								//SPI起始HAL_SPI_Transmit(&hspi1,&temp,1,1000);				//交换发送读状态寄存器1的指令Timeout = 100000;							//给定超时计数时间HAL_SPI_Receive(&hspi1,&temp,1,1000);while ((temp & 0x01) == 0x01)	//循环等待忙标志位{HAL_SPI_Receive(&hspi1,&temp,1,1000);Timeout --;								//等待时,计数值自减if (Timeout == 0)						//自减到0后,等待超时{/*超时的错误处理代码,可以添加到此处*/break;								//跳出等待,不等了}}MySPI_Stop();								//SPI终止
}void W25Q64_WaitBusy(void)
{uint32_t Timeout;MySPI_Start();								//SPI起始MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);				//交换发送读状态寄存器1的指令Timeout = 100000;							//给定超时计数时间while ((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01)	//循环等待忙标志位{Timeout --;								//等待时,计数值自减if (Timeout == 0)						//自减到0后,等待超时{/*超时的错误处理代码,可以添加到此处*/break;								//跳出等待,不等了}}MySPI_Stop();								//SPI终止
}
void W25Q64_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count)
{uint8_t temp[4];temp[0] = W25Q64_PAGE_PROGRAM;temp[1] = (Address >> 16);temp[2] = (Address >> 8);temp[3] = (Address);W25Q64_WriteEnable();						//写使能MySPI_Start();								//SPI起始HAL_SPI_Transmit(&hspi1,temp,4,1000);		//交换发送页编程的指令,交换发送地址23~16位,交换发送地址15~8位,交换发送地址7~0位HAL_SPI_Transmit(&hspi1,DataArray,Count,1000);//循环Count次,依次在起始地址后写入数据MySPI_Stop();								//SPI终止W25Q64_WaitBusy();							//等待忙
}void W25Q64_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count)
{uint16_t i;W25Q64_WriteEnable();						//写使能MySPI_Start();								//SPI起始MySPI_SwapByte(W25Q64_PAGE_PROGRAM);		//交换发送页编程的指令MySPI_SwapByte(Address >> 16);				//交换发送地址23~16位MySPI_SwapByte(Address >> 8);				//交换发送地址15~8位MySPI_SwapByte(Address);					//交换发送地址7~0位for (i = 0; i < Count; i ++)				//循环Count次{MySPI_SwapByte(DataArray[i]);			//依次在起始地址后写入数据}MySPI_Stop();								//SPI终止W25Q64_WaitBusy();							//等待忙
}
void W25Q64_SectorErase(uint32_t Address)
{uint8_t temp[4];temp[0] = W25Q64_SECTOR_ERASE_4KB;temp[1] = (Address >> 16);temp[2] = (Address >> 8);temp[3] = (Address);W25Q64_WriteEnable();						//写使能MySPI_Start();								//SPI起始HAL_SPI_Transmit(&hspi1,temp,4,1000);	//交换发送扇区擦除的指令MySPI_Stop();								//SPI终止W25Q64_WaitBusy();							//等待忙
}void W25Q64_SectorErase(uint32_t Address)
{W25Q64_WriteEnable();						//写使能MySPI_Start();								//SPI起始MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB);	//交换发送扇区擦除的指令MySPI_SwapByte(Address >> 16);				//交换发送地址23~16位MySPI_SwapByte(Address >> 8);				//交换发送地址15~8位MySPI_SwapByte(Address);					//交换发送地址7~0位MySPI_Stop();								//SPI终止W25Q64_WaitBusy();							//等待忙
}

 

void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{uint8_t temp[4];temp[0] = W25Q64_READ_DATA;temp[1] = (Address >> 16);temp[2] = (Address >> 8);temp[3] = (Address);MySPI_Start();								//SPI起始HAL_SPI_Transmit(&hspi1,temp,4,1000);			//交换发送读取数据的指令HAL_SPI_Receive(&hspi1,DataArray,Count,1000);//循环Count次,依次在起始地址后读取数据MySPI_Stop();								//SPI终止
}void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{uint32_t i;MySPI_Start();								//SPI起始MySPI_SwapByte(W25Q64_READ_DATA);			//交换发送读取数据的指令MySPI_SwapByte(Address >> 16);				//交换发送地址23~16位MySPI_SwapByte(Address >> 8);				//交换发送地址15~8位MySPI_SwapByte(Address);					//交换发送地址7~0位for (i = 0; i < Count; i ++)				//循环Count次{DataArray[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE);	//依次在起始地址后读取数据}MySPI_Stop();								//SPI终止
}

修改Swap函数实现江科大 

或者说按照江科大的写法自己修改swap函数和nss即可

void MySPI_W_SS(uint8_t BitValue)
{HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, (GPIO_PinState)BitValue);		//根据BitValue,设置SS引脚的电平
}
/*** 函    数:SPI交换传输一个字节,使用SPI模式0* 参    数:ByteSend 要发送的一个字节* 返 回 值:接收的一个字节*/
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t tx,rx;tx = ByteSend;HAL_SPI_TransmitReceive(&hspi1,&tx,&rx,1,1000);return rx;
//	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);	//等待发送数据寄存器空
//	
//	SPI_I2S_SendData(SPI1, ByteSend);								//写入数据到发送数据寄存器,开始产生时序
//	
//	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);	//等待接收数据寄存器非空
//	
//	return SPI_I2S_ReceiveData(SPI1);								//读取接收到的数据并返回
}

 直接用hal库自带的交换函数来替换江科大的swap函数,在修改一下软件控制nss的GPIO函数就能完成移植,移植的时候别忘记头文件这些都得移植过来。


http://www.hkcw.cn/article/FjYvfFEYUS.shtml

相关文章

【笔记】Suna 部署之获取 OpenAI API key

#工作记录 API Platform | OpenAI 一、注册或登录 OpenAI 账号 访问 OpenAI 官方网站&#xff08;platform.openai.com &#xff09;。若已有 ChatGPT 账号&#xff0c;可直接使用该账号登录。若无账号&#xff0c;点击注册&#xff08;Sign Up&#xff09;&#xff0c;填写有…

Java八股文——Java基础「概念篇」

参考小林Coding和Java Guide 说一下Java的特点 平台无关性&#xff1a;“Write Once, Run Anywhere”其最大的特点之一。Java编译器将源代码编译成字节码&#xff0c;该字节码可以在任何安装了JVM的系统上运行。面向对象&#xff1a;Java是一门严格的面向对象编程语言&#xf…

NHANES指标推荐:CQI

文章题目&#xff1a;The impact of carbohydrate quality index on menopausal symptoms and quality of life in postmenopausal women 中文标题&#xff1a;碳水化合物质量指数对绝经后妇女更年期症状和生活质量的影响 发表杂志&#xff1a;BMC Womens Health 影响因子&…

91.评论日记

2025年5月30日20:27:06 AI画减速器图纸&#xff1f; 呜呜为什么读到机械博士毕业了才有啊 | 新迪数字2025新品发布会 | AI工业软件 | 三维CAD | 国产自主_哔哩哔哩_bilibili

循环神经网络(RNN)全面教程:从原理到实践

循环神经网络(RNN)全面教程&#xff1a;从原理到实践 引言 循环神经网络(Recurrent Neural Network, RNN)是处理序列数据的经典神经网络架构&#xff0c;在自然语言处理、语音识别、时间序列预测等领域有着广泛应用。本文将系统介绍RNN的核心概念、常见变体、实现方法以及实际…

OrCAD X Capture CIS 设计小诀窍第二季 | 10. 如何自动将 270° 放置的网络名称修正为 90°

背景介绍&#xff1a;我们在进行原理图设计时&#xff0c;经常需要统一原理图的格式&#xff0c;从而保证原理图的美观和统一。而通过把所有270放置的网络名称修正为90可以避免因网络名称放置的方向不一致而造成混淆&#xff0c;比如6和9。但如果依靠设计师手动进行修改&#x…

核心机制:确认应答和超时重传

核心机制一:确认应答 实现让发送方知道接受方是否收到数据 发送方发送了数据之后,接受方,一旦接收到了,就会给发送方返回一个"应答报文"告诉发送方"我已经收到了数据" 网络上会出现"后发先至"的情况 为了解决上述问题,就引入了"序号和确…

特朗普:仍希望有国际学生在美国学习

当地时间5月30日,美国总统特朗普在白宫表示,仍希望有国际学生在美国学习。据美国政治新闻网站“Politico”27日的报道,特朗普政府已暂停新的学生签证面谈,同时考虑扩大对国际学生社交媒体审查范围。此外,据路透社30日援引一份美国国务卿发送给所有美国外交和领事馆的电报称…

两阶段uplift建模(因果估计+预算分配)的讲座与自己动手实践(一)

来自分享嘉宾在datafun论坛的分享&#xff0c;孙泽旭 中国人民大学高瓴人工智能学院 博士生分享的【面向在线营销场景的高效 Uplift 方法】 听讲座听的云里雾里&#xff0c;自己做点力所能及的小实践… 关于uplift笔者之前的博客&#xff1a; 因果推断笔记——uplift建模、met…

2025年通用 Linux 服务器操作系统该如何选择?

2025年通用 Linux 服务器操作系统该如何选择&#xff1f; 服务器操作系统的选择对一个企业IT和云服务影响很大&#xff0c;主推的操作系统在后期更换的成本很高&#xff0c;而且也有很大的迁移风险&#xff0c;所以企业在选择服务器操作系统时要尤为重视。 之前最流行的服务器…

Ubuntu20.04服务器开启路由转发让局域网内其他电脑通过该服务器连接外网

要让你的 Ubuntu作为路由器&#xff0c;通过 Wi-Fi 上网&#xff0c;并给连接到 UsbNetwork 的设备提供网络&#xff0c;需要做以下配置&#xff1a; 1. 网络拓扑 [互联网] ← (Wi-Fi, wlo1) → [Ubuntu] ← (USB网络/USB以太网, UsbNetwork) → [设备]Ubuntu&#xff1a; Wi-…

ONLYOFFICE深度解锁系列.4-OnlyOffice客户端原理-真的不支持多端同步

最近很多客户多要求直接部署onlyoffice服务端,还问能否和onlyoffice的客户端进行文件同步,当时真是一脸懵,还有的是老客户,已经安装了onlyoffice协作空间的,也在问如何配置客户端和协作空间的对接。由于问的人太多了,这里统一回复,先说结论,再说原理: 1.onlyoffice document s…

手撕Java+硅基流动实现MCP服务器教程

手撕Java硅基流动实现MCP服务器教程 一、MCP协议核心概念 MCP是什么 MCP 是 Anthropic (Claude) 主导发布的一个开放的、通用的、有共识的协议标准。 ● MCP 是一个标准协议&#xff0c;就像给 AI 大模型装了一个 “万能接口”&#xff0c;让 AI 模型能够与不同的数据源和工…

BG22L和BG24L精简版蓝牙SoC推动智能物联网走向更广天地

作者&#xff1a;Aashish Chaddha&#xff0c;芯科科技无线产品营销经理 随着物联网&#xff08;IoT&#xff09;领域的复杂性和互联性不断提高&#xff0c;对无线设备的需求正在发生变化。它不再只是将数据从A点传输到B点&#xff0c;现在的设备需要更智能、更节能&#xff0…

拉普拉斯噪声

1. 概念 拉普拉斯噪声是一种连续概率分布生成的随机噪声&#xff0c;其核心特点是符合拉普拉斯分布。这种噪声被特意添加到数据&#xff08;尤其是查询结果或统计量&#xff09;中&#xff0c;以实现差分隐私这一严格的隐私保护框架。 核心目的&#xff1a; 在保护数据集中的个…

JavaSwing之--JPasswordField

Java Swing之–JPasswordField应用详解 JPasswordField是一个轻量级组件&#xff0c;允许编辑单行文本&#xff0c;不会显示键入的原始字符&#xff0c;而是显示替代文本或图形。 JPasswordField的直接父类是JTextField&#xff0c;它继承了父类中的常用构造方法与普通方法。…

ACS期刊的投稿查重要求

ACS的查重要求在其官网写到&#xff1a;ACS Publications uses the Crossref Similarity Check Powered by iThenticate to screen submitted manuscripts for similarity to published material. Note that your manuscript may be screened during the submission process.&a…

一文速通Python并行计算:11 Python多进程编程-进程之间的数据安全传输-基于队列和管道

一文速通 Python 并行计算&#xff1a;11 Python 多进程编程-进程之间的数据安全传输-基于队列和管道 摘要&#xff1a; Python 多进程中&#xff0c;Queue 和 Pipe 提供进程间安全通信。Queue 依赖锁和缓冲区&#xff0c;保障数据原子性和有序性&#xff1b;Pipe 实现点对点单…

基于云模型与TOPSIS评价算法的综合应用研究

一、理论基础与算法特点 &#xff08;一&#xff09;云模型的核心原理 云模型是由李德毅院士于1995年提出的不确定性转换模型&#xff0c;通过三个数字特征量实现定性概念与定量描述的转换&#xff1a; 期望Ex&#xff1a;概念在论域中的中心值 熵En&#xff1a;表征概念的模…

Jenkins 2.479.1安装和邮箱配置教程

1.安装 在JDK安装并设置环境变量完成后&#xff0c;下载官网对应的war版本&#xff0c;在对应目录下打开命令行窗口并输入 java -jar jenkins.war其余参数感兴趣可以自行查阅&#xff0c;这里启动的 jenkins 服务默认占用8080端口&#xff0c;在浏览器输入 localhost:8080进入…