STM32F429 >> 13. SPI 通讯(code)

44 篇文章 7 订阅
36 篇文章 1 订阅

=========================== SPI 详细教程在这 ===============================

bsp_spi_flash.h

/**
  ******************************************************************************
  * @file    bsp_spi_flash.h
  * @author  Waao
  * @version V1.0.0
  * @date    19-Jan-2019
  * @brief   This file contains some board support package's definitions for the SPI.
  *            
  ******************************************************************************
  * @attention
  *
  * None
	*
  ******************************************************************************
  */
#ifndef _BSP_SPI_FLASH_H_
#define _BSP_SPI_FLASH_H_


#include <stm32f4xx_spi.h>
#include <stm32f4xx_gpio.h>
#include <bsp_usart.h>


#define SPIT_FLAG_TIMEOUT          ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT          ((uint32_t)(10*SPIT_FLAG_TIMEOUT))

#define SPI_FLASH_PageSize              256
#define SPI_FLASH_PerWritePageSize      256

#define FLASH_ERROR(fmt, arg...)   printf("Error Code:"fmt"\n", ##arg)

//============================ SPI =================================
#define SPI_                       SPI5 
#define SPI_CLK                    RCC_APB2Periph_SPI5

//====================== Signal Line GPIO ==========================
#define SPI_GPIO_CLK               RCC_AHB1Periph_GPIOF
#define SPI_GPIO_PORT              GPIOF

//=== NSS ===
#define SPI_NSS_GPIO_PORT          GPIOF          
#define SPI_NSS_GPIO_PIN           GPIO_Pin_6          
#define SPI_NSS_GPIO_RCC           RCC_AHB1Periph_GPIOF  

//=== SCK ===
#define SPI_SCK_GPIO_PORT          GPIOF          
#define SPI_SCK_GPIO_PIN           GPIO_Pin_7          
#define SPI_SCK_GPIO_RCC           RCC_AHB1Periph_GPIOF  
#define SPI_SCK_GPIO_PinSource     GPIO_PinSource7
#define SPI_SCK_GPIO_AF            GPIO_AF_SPI5

//=== MISO ===
#define SPI_MISO_GPIO_PORT         GPIOF          
#define SPI_MISO_GPIO_PIN          GPIO_Pin_8          
#define SPI_MISO_GPIO_RCC          RCC_AHB1Periph_GPIOF  
#define SPI_MISO_GPIO_PinSource    GPIO_PinSource8
#define SPI_MISO_GPIO_AF           GPIO_AF_SPI5
  
//=== MOSI ===
#define SPI_MOSI_GPIO_PORT         GPIOF          
#define SPI_MOSI_GPIO_PIN          GPIO_Pin_9          
#define SPI_MOSI_GPIO_RCC          RCC_AHB1Periph_GPIOF          
#define SPI_MOSI_GPIO_PinSource    GPIO_PinSource9
#define SPI_MOSI_GPIO_AF           GPIO_AF_SPI5

//=== CS/NSS Control ===
#define SPI_FLASH_CS_1             {SPI_NSS_GPIO_PORT->BSRRL=SPI_NSS_GPIO_PIN;}
#define SPI_FLASH_CS_0             {SPI_NSS_GPIO_PORT->BSRRH=SPI_NSS_GPIO_PIN;}
//================================================================

//=== Commonly Used Command ===
#define W25X_WriteEnable		       0x06 
#define W25X_WriteDisable		       0x04 
#define W25X_ReadStatusReg		     0x05 
#define W25X_WriteStatusReg		     0x01 
#define W25X_ReadData			         0x03 
#define W25X_FastReadData		       0x0B 
#define W25X_FastReadDual		       0x3B 
#define W25X_PageProgram		       0x02 
#define W25X_BlockErase			       0xD8 
#define W25X_SectorErase		       0x20 
#define W25X_ChipErase			       0xC7 
#define W25X_PowerDown			       0xB9 
#define W25X_ReleasePowerDown	     0xAB 
#define W25X_DeviceID			         0xAB 
#define W25X_ManufactDeviceID   	 0x90 
#define W25X_JedecDeviceID		     0x9F 

#define WIP_Flag                   0x01  /* Write In Progress (WIP) flag */
#define Dummy_Byte                 0xFF


void SPI_GPIO_Config(void);
void SPI_Config(void);
uint8_t SPI_FLASH_SendByte(uint8_t byte);
uint8_t SPI_FLASH_ReadByte(void);
uint32_t SPI_FLASH_ReadID(void);
u32 SPI_FLASH_ReadDeviceID(void);
void SPI_FLASH_WriteEnable(void);
u8 SPI_FLASH_WaitForWriteEnd(void);
void SPI_FLASH_SectorErase(u32 SectorAddr);
void SPI_FLASH_PageWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite);
void SPI_FLASH_BufferWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite);
void SPI_FLASH_BufferRead(u8 *pBuffer, u32 ReadAddr, u16 NumByteToWrite);
uint8_t SPI_TIMEOUT_Callback(uint8_t errorcode);


#endif

bsp_spi_flash.c

/**
  ******************************************************************************
  * @file    bsp_spi_flash.c
  * @author  Waao
  * @version V1.0.0
  * @date    19-Jan-2019
  * @brief   This file contains some board support package's functions for the SPI.
  *            
  ******************************************************************************
  * @attention
  *
  * None
	*
  ******************************************************************************
  */

#include <bsp_spi_flash.h>


static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
static uint32_t WAITING_TIME = SPIT_FLAG_TIMEOUT;

/**
  * @brief  Initialize the SPI_GPIO.
  * @param  None  
  * @retval None
  */
void SPI_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(SPI_GPIO_CLK, ENABLE);
	
	GPIO_PinAFConfig(SPI_SCK_GPIO_PORT, SPI_SCK_GPIO_PinSource, SPI_SCK_GPIO_AF);
	GPIO_PinAFConfig(SPI_MISO_GPIO_PORT, SPI_MISO_GPIO_PinSource, SPI_MISO_GPIO_AF);
	GPIO_PinAFConfig(SPI_MOSI_GPIO_PORT, SPI_MOSI_GPIO_PinSource, SPI_MOSI_GPIO_AF);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	//SCK
	GPIO_InitStructure.GPIO_Pin = SPI_SCK_GPIO_PIN;
	GPIO_Init(SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
	
	//MISO
	GPIO_InitStructure.GPIO_Pin = SPI_MISO_GPIO_PIN;
	GPIO_Init(SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
	
	//MOSI
	GPIO_InitStructure.GPIO_Pin = SPI_MOSI_GPIO_PIN;
	GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
	
	//NSS
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Pin = SPI_NSS_GPIO_PIN;
	GPIO_Init(SPI_NSS_GPIO_PORT, &GPIO_InitStructure);
	
	SPI_FLASH_CS_1;
}


/**
  * @brief  Initialize the SPI.
  * @param  None  
  * @retval None
  */
void SPI_Config(void)
{
	SPI_InitTypeDef SPI_InitStructure;
	
	SPI_GPIO_Config();
	
	RCC_APB2PeriphClockCmd(SPI_CLK, ENABLE);
	
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	//Since we not use the CRC verify mode, so this CRCPolynomial is invalid
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	
	SPI_Init(SPI_, &SPI_InitStructure);
	SPI_Cmd(SPI_, ENABLE);
}


/**
  * @brief  Send a byte of data.
	* @param  byte: The data you want to transmit  
  * @retval The data have been received from flash.
  */
u8 SPI_FLASH_SendByte(u8 byte)
{
	//Waiting the transmit register to be empty
	WAITING_TIME = SPIT_FLAG_TIMEOUT;
	while(!SPI_I2S_GetFlagStatus(SPI_, SPI_I2S_FLAG_TXE))
	{
		if((WAITING_TIME--) == 0)
		{
			printf("timeout");
			return SPI_TIMEOUT_Callback(0);
		}
	}
	
	SPI_I2S_SendData(SPI_, byte);
	
	//Waiting the receive register to be not empty
	WAITING_TIME = SPIT_FLAG_TIMEOUT;
	while(!SPI_I2S_GetFlagStatus(SPI_, SPI_I2S_FLAG_RXNE))
	{
		
		if((WAITING_TIME--) == 0)
		{
			printf("timeout");
			return SPI_TIMEOUT_Callback(1);
		}
	}
	
	return SPI_I2S_ReceiveData(SPI_);
}


/**
  * @brief  Receive a byte of data.
	* @param  Since the process of receiving and sending is synchronous, So we must
	*  				sending a byte of data if we want to read data from flash, the send data is random.
  * @retval The data have been received from flash.
  */
u8 SPI_FLASH_ReadByte(void)
{
	return (SPI_FLASH_SendByte(Dummy_Byte));
}


/**
  * @brief  Read the flash's ID
	* @param  None 
	* @retval temp: The ID of the FLASH
  */
u32 SPI_FLASH_ReadID(void)
{
	u32 temp = 0, temp_1 = 0, temp_2 = 0, temp_3 = 0;
	
	SPI_FLASH_CS_0;
	
	SPI_FLASH_SendByte(W25X_JedecDeviceID);
	
	temp_1 = SPI_FLASH_ReadByte();
	temp_2 = SPI_FLASH_ReadByte();
	temp_3 = SPI_FLASH_ReadByte();
	
	SPI_FLASH_CS_1;
	
	temp = (temp_1 << 16) | (temp_2 << 8) | temp_3;
	
	return temp;
}


/**
  * @brief  Read the flash device's ID
	* @param  None 
	* @retval temp: The ID of the FLASH device
  */
u32 SPI_FLASH_ReadDeviceID(void)
{
  u32 Temp = 0;

  /* Select the FLASH: Chip Select low */
  SPI_FLASH_CS_0;

  /* Send "RDID " instruction */
  SPI_FLASH_SendByte(W25X_DeviceID);
  SPI_FLASH_SendByte(Dummy_Byte);
  SPI_FLASH_SendByte(Dummy_Byte);
  SPI_FLASH_SendByte(Dummy_Byte);
  
  /* Read a byte from the FLASH */
  Temp = SPI_FLASH_SendByte(Dummy_Byte);

  /* Deselect the FLASH: Chip Select high */
  SPI_FLASH_CS_1;

  return Temp;
}


/**
  * @brief  Write enable
	* @param  None
	* @retval None
  */
void SPI_FLASH_WriteEnable(void)
{
	SPI_FLASH_CS_0;
	
	SPI_FLASH_SendByte(W25X_WriteEnable);
	
	SPI_FLASH_CS_1;
}


/**
  * @brief  Wait for the FLASH idle
	* @param  None
	* @retval 0: Succeed
	*					1: False
  */
u8 SPI_FLASH_WaitForWriteEnd(void)
{
	u8 FLASH_Status = 0;
	
	SPI_FLASH_CS_0;
	
	SPI_FLASH_SendByte(W25X_ReadStatusReg);
	
	// There is better to be SPIT_LONG_TIMEOUT rather than SPIT_FLAG_TIMEOUT, or it will make a mistake
	SPITimeout = SPIT_LONG_TIMEOUT;
	
	do
	{
		FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);//SPI_FLASH_ReadByte();
		
		if((SPITimeout--) == 0)
		{
			SPI_TIMEOUT_Callback(2);
			return 1;
		}
	}
	while((FLASH_Status & WIP_Flag) == SET);
	
	SPI_FLASH_CS_1;
	return 0;
}


/**
  * @brief  Erase the sector that you specified
	* @param  SectorAddr: The address of the buffer that you want to erase
	* @retval None
  */
void SPI_FLASH_SectorErase(u32 SectorAddr)
{
	SPI_FLASH_WriteEnable();
	
  SPI_FLASH_WaitForWriteEnd();
	
	SPI_FLASH_CS_0;
	SPI_FLASH_SendByte(W25X_SectorErase);
	SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
	SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 18);
	SPI_FLASH_SendByte(SectorAddr & 0xFF);
	
	SPI_FLASH_CS_1;
	
  SPI_FLASH_WaitForWriteEnd();
}


/**
  * @brief  Write a page of data
	* @param  pBuffer: The pointer point to our data
	*					WriteAddr: The place that we want to restore the data
	*					NumByteToWrite: The number of bytes that we want to write
	* @retval None
  */
void SPI_FLASH_PageWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
	SPI_FLASH_WriteEnable();
	
	SPI_FLASH_CS_0;
	
	SPI_FLASH_SendByte(W25X_PageProgram);
	SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
	SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 18);
	SPI_FLASH_SendByte(WriteAddr & 0xFF);
	
	if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
	{
		NumByteToWrite = SPI_FLASH_PerWritePageSize;
		FLASH_ERROR("SPI_FLASH_PageWrite too large!");
	}
	
	while(NumByteToWrite--)
	{
		SPI_FLASH_SendByte(*pBuffer);
		pBuffer++;
	}
	
	SPI_FLASH_CS_1;
	
  SPI_FLASH_WaitForWriteEnd();
}



/**
  * @brief  Write a buffer of data
	* @param  pBuffer: The pointer point to our data
	*					WriteAddr: The place that we want to restore the data
	*					NumByteToWrite: The number of bytes that we want to write
	* @retval None
  */
void SPI_FLASH_BufferWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
	//The Addr_Surplus_page is the difference value that WriteAddr reach a page
	u32 Addr_Surplus_page = WriteAddr - (WriteAddr % SPI_FLASH_PageSize);
	//The Byte_Numpage is the integer of WriteAddr devided by SPI_FLASH_PageSize
	u32 Byte_Numpage = (NumByteToWrite - Addr_Surplus_page) / SPI_FLASH_PageSize;
	//The Byte_Remainder is the remainder of WriteAddr devided by SPI_FLASH_PageSize
	u32 Byte_Remainder = (NumByteToWrite - Addr_Surplus_page) % SPI_FLASH_PageSize;
	
	u32 i = 0;

	SPI_FLASH_SendByte(W25X_PageProgram);
	SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
	SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 18);
	SPI_FLASH_SendByte(WriteAddr & 0xFF);
	
	/* First we consider the situation of the Addr_Surplus_page is not equal with WriteAddr, the mean is that 
	 * the WriteAddr isn't reach the integer times of SPI_FLASH_PageSize.
	 */
	if(Addr_Surplus_page != WriteAddr)
	{
		// We should fill the first page
		SPI_FLASH_PageWrite(pBuffer, WriteAddr, Addr_Surplus_page);
		pBuffer += Addr_Surplus_page;
		WriteAddr += Addr_Surplus_page;
		// Then we consider the situation of the number of bytes of data is more than one page after it fill the first page.
		if(Byte_Numpage > 0)
		{
			while(Byte_Numpage--)
			{
				SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
				pBuffer += SPI_FLASH_PageSize;
				WriteAddr += SPI_FLASH_PageSize;
			}
			// And we consider the situation of the data can't reach a new page after it fill the ahead page.
			if(Byte_Remainder > 0)
			{
				while(Byte_Remainder--)
				{
					SPI_FLASH_PageWrite(pBuffer, WriteAddr, Byte_Remainder);
					pBuffer += Byte_Remainder;
					WriteAddr += Byte_Remainder;
				}
			}
		}
		// Or the situation is the data can't reach a new page after it fill the first page.
		if(Byte_Numpage == 0 && Byte_Remainder > 0)
		{	
			for(i=0; i<Byte_Remainder; i++)
			{
				SPI_FLASH_PageWrite(pBuffer, WriteAddr, Byte_Remainder);
				pBuffer += Byte_Remainder;
				WriteAddr += Byte_Remainder;
			}
		}
		
	}
	/* Another situation is the WriteAddr is just the integer times of the SPI_FLASH_PageSize, the mean is
	 * that we can write the data from a new page directly.
	 */
	if(Addr_Surplus_page == WriteAddr)
	{
		if(Byte_Numpage > 0)
		{
			while(Byte_Numpage--)
			{
				SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
				pBuffer += SPI_FLASH_PageSize;
				WriteAddr += SPI_FLASH_PageSize;
			}
			if(Byte_Remainder > 0)
			{
				SPI_FLASH_PageWrite(pBuffer, WriteAddr, Byte_Remainder);
				pBuffer += Byte_Remainder;
				WriteAddr += Byte_Remainder;
			}
		}
		if(Byte_Numpage == 0 && Byte_Remainder > 0)
		{	
			SPI_FLASH_PageWrite(pBuffer, WriteAddr, Byte_Remainder);
			pBuffer += Byte_Remainder;
			WriteAddr += Byte_Remainder;
		}
	}
}


/**
  * @brief  Read a buffer of data
	* @param  pBuffer: The pointer point to the data
	*					WriteAddr: The place that we want to find the data
	*					NumByteToWrite: The number of bytes that we want to read
	* @retval None
  */
void SPI_FLASH_BufferRead(u8 *pBuffer, u32 ReadAddr, u16 NumByteToWrite)
{
	u32 i;
	
	SPI_FLASH_CS_0;
	
	SPI_FLASH_SendByte(W25X_ReadData);
	SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
	SPI_FLASH_SendByte((ReadAddr & 0xFF00) >> 18);
	SPI_FLASH_SendByte(ReadAddr & 0xFF);
	
	for(i=0; i<NumByteToWrite; i++)
	{
		pBuffer[i] = SPI_FLASH_SendByte(Dummy_Byte);
	}
	
	SPI_FLASH_CS_1;
}


/**
  * @brief  Throw a error prompt.
	* @param  errorcode: The code of the error.  
	* @retval 0
  */
uint8_t SPI_TIMEOUT_Callback(uint8_t errorcode)
{
	FLASH_ERROR("Ack Wait TimeOut! Error Code: %d", errorcode);
	return 0;
}


main.c

#include <bsp_spi_flash.h>
#include <bsp_usart.h>
#include <bsp_led.h>


u32 Buffercmp(uint8_t *pBuffer1, uint8_t *pBuffer2, uint16_t BufferLength);


typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;

/* »ñÈ¡»º³åÇøµÄ³¤¶È */
#define TxBufferSize1   				(countof(TxBuffer1) - 1)
#define RxBufferSize1           (countof(TxBuffer1) - 1)
#define countof(a)              (sizeof(a) / sizeof(*(a)))
#define  BufferSize             (countof(Tx_Buffer)-1)

#define  FLASH_WriteAddress     0x00000
#define  FLASH_ReadAddress      FLASH_WriteAddress
#define  FLASH_SectorToErase    FLASH_WriteAddress


uint8_t Tx_Buffer[] = "Hello!";
uint8_t Rx_Buffer[BufferSize];

u32 TransferStatus1 = 0;

__IO uint32_t DeviceID = 0;
__IO uint32_t FlashID = 0;

int main(void)
{
	LED_GPIO_Config();
	
	USART_GPIO_Config();
	USART1_Config();
	printf("Why so serious ?\n  Just begin.\n");
	
	//SPI_GPIO_Config();
	
	SPI_Config();
	DeviceID = SPI_FLASH_ReadDeviceID();
	while(SPI_I2S_GetFlagStatus(SPI_, SPI_I2S_FLAG_BSY));
	FlashID = SPI_FLASH_ReadID();
	//Here is so strange, it always print the FlashID is 0xFFFFFF until I print the DeviceID.
	printf("\r\nFlashID is 0x%X,  Manufacturer Device ID is 0x%X\r\n", FlashID, DeviceID);
	
	SPI_FLASH_SectorErase(FLASH_SectorToErase);
	
	SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);
	printf("\r\nдÈëµÄÊý¾ÝΪ£º\r\n%s", Tx_Buffer);
	
	
	SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
	printf("\r\n¶Á³öµÄÊý¾ÝΪ£º\r\n%s", Rx_Buffer);
	
	TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
	
	if(!TransferStatus1)
	{
		LED2_ON;
		printf("Succeed");
	}
	else
	{
		LED1_ON;
		printf("Failure");
	}
	
	while(1);
}


/**
  * @brief  Compare two figure is euqal or not
	* @param  pBuffer1: The pointer point to the first figure
	*					pBuffer2: The pointer point to the second figure
	*					BufferLength: The number of bytes that we want to compare
	* @retval 0: The two pBuffer is equal
	*					1: The two pBuffer is unequal
  */
u32 Buffercmp(uint8_t *pBuffer1, uint8_t *pBuffer2, uint16_t BufferLength)
{
	while(BufferLength--)
	{
		if(*pBuffer1 != *pBuffer2)
		{
			return 1;
		}
		
		pBuffer1++;
		pBuffer2++;
	}
	return 0;
}

void Delay(__IO uint32_t nCount)
{
  for(; nCount != 0; nCount--);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺亚方包

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值