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

发布于:2025-05-31 ⋅ 阅读:(25) ⋅ 点赞:(0)

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函数就能完成移植,移植的时候别忘记头文件这些都得移植过来。


网站公告

今日签到

点亮在社区的每一天
去签到