HAL库之硬件SPI配置

发布时间:2024年01月06日

一、设置RCC时钟(复位和时钟控制)

设置高速外部时钟HSE 选择外部晶振

  • Disable:内部时钟
  • BYPASS Clock Source:外部旁路时钟源,指无需使用外部晶体时所需的芯片内部时钟驱动组件(%外部晶振起振需要内部有时钟驱动组件,此选项是将其屏蔽,也就意味着外部直接输入时钟信号,如示波器等%),直接从外界输入时钟信号。
  • Crystal/Ceramic Resonator:使用晶振驱动电路,用外部晶振作为时钟源

二、SPI设置

1、配置SPI模式为主机全双工

2、配置NSS为软件控制?

SIP1的片选NSS : SPI1_NSS(PA4),如果片选引脚没有连接 SPI1_NSS(PA4),则需要选择软件片选?。

硬件片选和软件片选的区别
所谓硬件片选指的是SPI本身具有片选信号,当我们通过SPI发送数据时,SPI外设自动拉低CS信号使能从机,发送完成后自动拉高CS信号释放从机,这个过程是不需要软件操作的。而软件片选则是需要使用GPIO作为片选信号,SPI在发送数据之前,需要先通过软件设置作为片选信号的GPIO输出低电平,发送完成之后再设置该GPIO输出高电平。

3、配置SPI的参数

三、SPI函数详解?

在stm32f1xx_hal_spi.h头文件中可以看到spi的操作函数。分别对应轮询,中断和DMA三种控制方式。

  • 轮询:?最基本的发送接收函数,就是正常的发送数据和接收数据
  • 中断:?在SPI发送或者接收完成的时候,会进入SPI回调函数,用户可以编写回调函数,实现设定功能
  • DMA:?DMA传输SPI数据

一般使用SPI传输用下面两个函数

//发送数据
HAL_StatusTypeDef  HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
*hspi: 选择SPI1/2,比如&hspi1,&hspi2
*pData : 需要发送的数据,可以为数组
Size: 发送数据的字节数,1 就是发送一个字节数据
Timeout: 超时时间,就是执行发送函数最长的时间,超过该时间自动退出发送函数


//接收数据
HAL_StatusTypeDef  HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
*hspi: 选择SPI1/2,比如&hspi1,&hspi2
*pData : 接收发送过来的数据的数组
Size: 接收数据的字节数,1 就是接收一个字节数据
Timeout: 超时时间,就是执行接收函数最长的时间,超过该时间自动退出接收函数

四、 W25Qx部分函数讲解

#define SPI_CS_Enable() 	HAL_GPIO_WritePin(SPI1_CS_Port, SPI1_CS_Pin,GPIO_PIN_RESET)
#define SPI_CS_Disable() 	HAL_GPIO_WritePin((SPI1_CS_Port, SPI1_CS_Pin, GPIO_PIN_SET)

#define W25Qx_TIMEOUT_VALUE 1000

/*W25QXX读函数时序
函数开始先将要发送的数据(命令和地址)存储在cmd数组中,
拉低片选信号,开始SPI通信
然后后通过HAL_SPI_Transmit()函数发送出去
接着通过HAL_SPI_Receive()接收读取的数据。
拉高片选信号,关闭SPI通信*/
//pData 存放读取到的数据的数组 ;ReadAddr 读取数据的地址 ;Size 读取数据的大小
uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
	uint8_t cmd[4];

	/* Configure the command */
	cmd[0] = READ_CMD;
	cmd[1] = (uint8_t)(ReadAddr >> 16);
	cmd[2] = (uint8_t)(ReadAddr >> 8);
	cmd[3] = (uint8_t)(ReadAddr);
	
	W25Qx_Enable();
	/* Send the read ID command */
	HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);	
	/* Reception of the data */
	if (HAL_SPI_Receive(&hspi2, pData,Size,W25Qx_TIMEOUT_VALUE) != HAL_OK)
    {
        return W25Qx_ERROR;
    }
	W25Qx_Disable();

	return W25Qx_OK;
}

/*向FLASH发送0x06 写使能命令
即可开启写使能,首先CS片选拉低,控制写入字节函数写入命令,CS片选拉高。*/
uint8_t BSP_W25Qx_WriteEnable(void)
{
	uint8_t cmd[] = {WRITE_ENABLE_CMD};
	uint32_t tickstart = HAL_GetTick();

	/*Select the FLASH: Chip Select low */
	W25Qx_Enable();

	/* Send the read ID command */
	HAL_SPI_Transmit(&hspi2, cmd, 1, W25Qx_TIMEOUT_VALUE);	

	/*Deselect the FLASH: Chip Select high */
	W25Qx_Disable();
	
	/* Wait the end of Flash writing */
	while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
	{
		/* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE)
        {        
			return W25Qx_TIMEOUT;
        }
	}
	return W25Qx_OK;
}

/*扇区擦除指令,数据写入前必须擦除对应的存储单元,并且使能写操作,该指令先拉低/CS引脚电平,接着传输“20H”指令和要24位要擦除扇区的地址。判断flash是否为忙状态,如果不为忙则擦除操作完成。*/
uint8_t BSP_W25Qx_Erase_Block(uint32_t Address)
{
	uint8_t cmd[4];
	uint32_t tickstart = HAL_GetTick();
	cmd[0] = SECTOR_ERASE_CMD;
	cmd[1] = (uint8_t)(Address >> 16);
	cmd[2] = (uint8_t)(Address >> 8);
	cmd[3] = (uint8_t)(Address);
	
	/* Enable write operations */
	BSP_W25Qx_WriteEnable();
	
	/*Select the FLASH: Chip Select low */
	W25Qx_Enable();
	/* Send the read ID command */
	HAL_SPI_Transmit(&hspi2, cmd, 4, W25Qx_TIMEOUT_VALUE);	
	/*Deselect the FLASH: Chip Select high */
	W25Qx_Disable();
	
	/* Wait the end of Flash writing */
	while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
	{
		/* Check for the Timeout */
    if((HAL_GetTick() - tickstart) > W25Q128FV_SECTOR_ERASE_MAX_TIME)
    {        
			return W25Qx_TIMEOUT;
    }
	}
	return W25Qx_OK;
}


文章来源:https://blog.csdn.net/m0_61973119/article/details/135410194
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。