ARM嵌入式学习笔记(十) SPI

1.前言

上一篇文章介绍了ADC采集的内容,这篇文章我们来介绍一下STM32单片机中的SPI通信部分,并驱动WS2812灯带。同样地,我们所使用的硬件设备仍然是STM32RCT6单片机等基础设备,关于单片机的原理图在前文均已详细介绍,这里我们就不再赘述。

2.SPI详解

SPI简介

SPI是串行外设接口的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议。

SPI通信原理

 系统框图

引脚

SPI通常有以下几个引脚:

  • SCLK 串口时钟,作为主设备的输出,从设备的输入。
  • NSS 从设备选择。这是一个可选的引脚,用来选择主/从设备。
  • MOSI 主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
  • MISO 主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。

SPI是一种同步通信方式,所以它有时钟线,时钟由主设备提供。CS为片选线,片选线用来区分和哪个从机进行交互,通常由主机来控制。通常片选线被拉低,代表该从机被选中。当总线上有两个从机地片选线被拉低时会产生错误。MOSI和MISO用来做数据传输线,如果我们去掉其中一根,那么SPI就变成了一个单工通信,也是可以的,所以SPI即使只有三根线,也可以使用。

SPI通信中可作为从机也可以作为主机,这取决于硬件设计和软件设置。

当器件作为主机时,使用一个IO引脚拉低相应从机的选择引脚(NSS),传输的起始由主机发送数据来启动,时钟(SCK)信号由主机产生。通过MOSI发送数据,同时通过MISO引脚接收从机发出的数据。    

当器件作为从机时,传输在从机选择引脚(NSS)被主机拉低后开始,接收主机输出的时钟信号,在读取主机数据的同时通过MISO引脚输出数据。

时序图

该图显示了SPI传输的4CPHACPOL位组合。这里可以解释为主设备和从设备的SCK脚、

MISO 脚、 MOSI 脚直接连接的主或从时序图。

3.软件部分

串行flash初始化

串行flash初始化主要用到以下函数:

SPI_FLASH_Init();

 让我们看看这个函数具体内容是怎么样的。

void SPI_FLASH_Init(void)
{
  SPI_InitTypeDef  SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;	
  
	FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );
  FLASH_SPI_SCK_APBxClock_FUN ( FLASH_SPI_SCK_CLK, ENABLE );
 	FLASH_SPI_MISO_APBxClock_FUN ( FLASH_SPI_MISO_CLK, ENABLE );
  FLASH_SPI_MOSI_APBxClock_FUN ( FLASH_SPI_MOSI_CLK, ENABLE );
  FLASH_SPI_CS_APBxClock_FUN ( FLASH_SPI_CS_CLK, ENABLE );
  
  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
	
  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
  GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
  GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;	
  GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);

  FLASH_SPI_CS_DISABLE();

  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_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(FLASH_SPIx , &SPI_InitStructure);

  SPI_Cmd(FLASH_SPIx , ENABLE);	
}

该函数中首先使能了GPIO和SPI时钟,再配置了MISO主机输入从机输出引脚,又配置了MISO主机输出,从机输入的引脚,然后配置CS串行Flash片选引脚,最后使能SPI外设。

擦除扇区

void SPI_FLASH_SectorErase(u32 SectorAddr)
{
  SPI_FLASH_WriteEnable();
  SPI_FLASH_WaitForWriteEnd();
  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_SectorErase);

  SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
  SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
  SPI_FLASH_SendByte(SectorAddr & 0xFF);
  FLASH_SPI_CS_DISABLE();

  SPI_FLASH_WaitForWriteEnd();
}

串行Flash最小擦除块大小为4KB,在往串行Flash芯片内写入数据时要求先擦除扇区。

擦除整片

void SPI_FLASH_BulkErase(void)
{
  SPI_FLASH_WriteEnable();

  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_ChipErase);

  FLASH_SPI_CS_DISABLE();
  SPI_FLASH_WaitForWriteEnd();
}

写入数据

void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
  u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;

  Addr = WriteAddr % SPI_FLASH_PageSize;
  count = SPI_FLASH_PageSize - Addr;
  NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
  NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;

  if (Addr == 0) 
  {
    if (NumOfPage == 0) 
    {
      SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
    }
    else 
    {
      while (NumOfPage--)
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
        WriteAddr +=  SPI_FLASH_PageSize;
        pBuffer += SPI_FLASH_PageSize;
      }

      SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
    }
  }
  else 
  {
    if (NumOfPage == 0)
    {
      if (NumOfSingle > count) 
      {
        temp = NumOfSingle - count;

        SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
        WriteAddr +=  count;
        pBuffer += count;

        SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
      }
      else
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
      }
    }
    else 
    {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
      NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;

      SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
      WriteAddr +=  count;
      pBuffer += count;

      while (NumOfPage--)
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
        WriteAddr +=  SPI_FLASH_PageSize;
        pBuffer += SPI_FLASH_PageSize;
      }

      if (NumOfSingle != 0)
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      }
    }
  }
}

PS:使用该函数写入数据时,要先擦除扇区

读取数据

void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_ReadData);

  SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);

  SPI_FLASH_SendByte(ReadAddr & 0xFF);

  while (NumByteToRead--)
  {
    *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
    pBuffer++;
  }

  FLASH_SPI_CS_DISABLE();
}

注意:该函数可以任意设置读取数据长度

4.完整代码

Main.c


#include "stm32f10x.h"
#include "bsp/led/bsp_led.h"
#include "bsp/usart/bsp_debug_usart.h"
#include "bsp/spi_flash/bsp_spi_flash.h"

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

#define  FLASH_WriteAddress     0x0000
#define  FLASH_ReadAddress      FLASH_WriteAddress
#define  FLASH_SectorToErase    FLASH_WriteAddress

uint8_t Tx_Buffer[6] = {1,50,100,150,200,250};
uint8_t Rx_Buffer[6] = {0};

__IO uint32_t DeviceID = 0;
__IO uint32_t FlashID = 0;
__IO TestStatus TransferStatus = FAILED;

static void Delay(uint32_t time);
static TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);


int main(void)
{   
  uint8_t i;

  DEBUG_USART_Init();  
  
  LED_GPIO_Init();  
 
  printf("ÕâÊÇÒ»¸ö16M byte´®ÐÐflash(W25Q128)¶Áд²âÊÔʵÑé\n");  

	SPI_FLASH_Init();

	DeviceID = SPI_FLASH_ReadDeviceID();
	
	Delay( 1 );
	
	FlashID = SPI_FLASH_ReadID();
	
	printf("FlashID is 0x%X,  Manufacturer Device ID is 0x%X\n", FlashID, DeviceID);
	
	if (FlashID == SPI_FLASH_ID)  
	{	
		printf("¼ì²âµ½»ª°î´®ÐÐflash W25Q128 !\n");
    SPI_FLASH_SectorErase(FLASH_SectorToErase);
    SPI_FLASH_BufferWrite(Tx_Buffer,FLASH_WriteAddress, sizeof(Tx_Buffer));
    printf("дÈëµÄÊý¾ÝΪ£º\n");
    for(i=0; i<sizeof(Tx_Buffer);i++ )
      printf("%d ", Tx_Buffer[i]);
    printf("\n");
    
		SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, sizeof(Rx_Buffer));
    printf("¶Á³öµÄÊý¾ÝΪ£º\n");
    for(i=0; i<sizeof(Rx_Buffer);i++ )
      printf("%d ", Rx_Buffer[i]);
    printf("\n");
		
		TransferStatus = Buffercmp(Tx_Buffer, Rx_Buffer, sizeof(Tx_Buffer));
		
		if( PASSED == TransferStatus )
		{    
			printf("16M´®ÐÐflash(W25Q128)Êý¾Ý¶Áд²âÊԳɹ¦!\n");
      LED1_ON;
		}
		else
		{        
			printf("16M´®ÐÐflash(W25Q128)Êý¾Ý¶Áд²âÊÔʧ°Ü!\n");
      LED2_ON;
		}
	}
	else
	{    
		printf("»ñÈ¡²»µ½ W25Q128 ID!\n");
    LED3_ON;
	}
 
  while (1)
  {    
  }
}

static void Delay(uint32_t time)
{
  uint32_t i,j;

  for(i=0;i<time;++i)
  {
    for(j=0;j<10000;++j)
    {       
      
    }
  }
}


static TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
  while(BufferLength--)
  {
    if(*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }

    pBuffer1++;
    pBuffer2++;
  }
  return PASSED;
}

bsp_spi_flash.c


#include "bsp/spi_flash/bsp_spi_flash.h"

#define SPI_FLASH_PageSize              256
#define SPI_FLASH_PerWritePageSize      256
#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_FLASH_Init(void)
{
  SPI_InitTypeDef  SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;	

	FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );
  FLASH_SPI_SCK_APBxClock_FUN ( FLASH_SPI_SCK_CLK, ENABLE );
 	FLASH_SPI_MISO_APBxClock_FUN ( FLASH_SPI_MISO_CLK, ENABLE );
  FLASH_SPI_MOSI_APBxClock_FUN ( FLASH_SPI_MOSI_CLK, ENABLE );
  FLASH_SPI_CS_APBxClock_FUN ( FLASH_SPI_CS_CLK, ENABLE );
  
  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
  GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);


  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
  GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
  

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;	
  GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);


  FLASH_SPI_CS_DISABLE();


  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_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(FLASH_SPIx , &SPI_InitStructure);

  SPI_Cmd(FLASH_SPIx , ENABLE);	
}

void SPI_FLASH_SectorErase(u32 SectorAddr)
{
  SPI_FLASH_WriteEnable();
  SPI_FLASH_WaitForWriteEnd();

  FLASH_SPI_CS_ENABLE();
  SPI_FLASH_SendByte(W25X_SectorErase);

  SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);

  SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);

  SPI_FLASH_SendByte(SectorAddr & 0xFF);
  FLASH_SPI_CS_DISABLE();
  SPI_FLASH_WaitForWriteEnd();
}


void SPI_FLASH_BulkErase(void)
{

  SPI_FLASH_WriteEnable();
  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_ChipErase);

  FLASH_SPI_CS_DISABLE();

  SPI_FLASH_WaitForWriteEnd();
}

void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{

  SPI_FLASH_WriteEnable();


  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_PageProgram);

  SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);

  SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);

  SPI_FLASH_SendByte(WriteAddr & 0xFF);

  if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
  {
     NumByteToWrite = SPI_FLASH_PerWritePageSize;
     //printf("Err: SPI_FLASH_PageWrite too large!\n");
  }


  while (NumByteToWrite--)
  {

    SPI_FLASH_SendByte(*pBuffer);
    pBuffer++;
  }


  FLASH_SPI_CS_DISABLE();

  SPI_FLASH_WaitForWriteEnd();
}


void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
  u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;

  Addr = WriteAddr % SPI_FLASH_PageSize;
  count = SPI_FLASH_PageSize - Addr;
  NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
  NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;

  if (Addr == 0)
  {
    if (NumOfPage == 0) 
    {
      SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
    }
    else 
    {
      while (NumOfPage--)
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
        WriteAddr +=  SPI_FLASH_PageSize;
        pBuffer += SPI_FLASH_PageSize;
      }

      SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
    }
  }
  else 
  {
    if (NumOfPage == 0)
    {
      if (NumOfSingle > count) 
      {
        temp = NumOfSingle - count;

        SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
        WriteAddr +=  count;
        pBuffer += count;

        SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
      }
      else
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
      }
    }
    else
    {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
      NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;

      SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
      WriteAddr +=  count;
      pBuffer += count;

      while (NumOfPage--)
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
        WriteAddr +=  SPI_FLASH_PageSize;
        pBuffer += SPI_FLASH_PageSize;
      }

      if (NumOfSingle != 0)
      {
        SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
      }
    }
  }
}


void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_ReadData);

  SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);

  SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);

  SPI_FLASH_SendByte(ReadAddr & 0xFF);

  while (NumByteToRead--)
  {

    *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
    pBuffer++;
  }

  FLASH_SPI_CS_DISABLE();
}

u32 SPI_FLASH_ReadID(void)
{
  u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;


  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_JedecDeviceID);

  Temp0 = SPI_FLASH_SendByte(Dummy_Byte);

  Temp1 = SPI_FLASH_SendByte(Dummy_Byte);


  Temp2 = SPI_FLASH_SendByte(Dummy_Byte);

  FLASH_SPI_CS_DISABLE();
  
  Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
  return Temp;
}

u32 SPI_FLASH_ReadDeviceID(void)
{
  u32 Temp = 0;

  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_DeviceID);
  SPI_FLASH_SendByte(Dummy_Byte);
  SPI_FLASH_SendByte(Dummy_Byte);
  SPI_FLASH_SendByte(Dummy_Byte);
  
  Temp = SPI_FLASH_SendByte(Dummy_Byte);

  FLASH_SPI_CS_DISABLE();

  return Temp;
}


void SPI_FLASH_StartReadSequence(u32 ReadAddr)
{

  FLASH_SPI_CS_ENABLE();
 
  SPI_FLASH_SendByte(W25X_ReadData);

  SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  SPI_FLASH_SendByte(ReadAddr & 0xFF);
}

u8 SPI_FLASH_ReadByte(void)
{
  return (SPI_FLASH_SendByte(Dummy_Byte));
}

u8 SPI_FLASH_SendByte(u8 byte)
{
  while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET);

  SPI_I2S_SendData(FLASH_SPIx , byte);
  while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET);

  return SPI_I2S_ReceiveData(FLASH_SPIx );
}


u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
{
  while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET);

  SPI_I2S_SendData(FLASH_SPIx , HalfWord);
  while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET);

  return SPI_I2S_ReceiveData(FLASH_SPIx );
}

void SPI_FLASH_WriteEnable(void)
{

  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_WriteEnable);
  FLASH_SPI_CS_DISABLE();
}

void SPI_FLASH_WaitForWriteEnd(void)
{
  u8 FLASH_Status = 0;

  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_ReadStatusReg);

  do
  {
    FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);	 
  }
  while ((FLASH_Status & WIP_Flag) == SET);
  FLASH_SPI_CS_DISABLE();
}

void SPI_Flash_PowerDown(void)   
{ 
  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_PowerDown);

  FLASH_SPI_CS_DISABLE();
}   

void SPI_Flash_WAKEUP(void)   
{
  FLASH_SPI_CS_ENABLE();

  SPI_FLASH_SendByte(W25X_ReleasePowerDown);
  FLASH_SPI_CS_DISABLE(); 
}   
   

bsp_spi_flash.h

#ifndef __SPI_FLASH_H__
#define __SPI_FLASH_H__

#include <stm32f10x.h>

//#define  SPI_FLASH_ID                       0xEF3015     //W25X16
//#define  SPI_FLASH_ID                       0xEF4015	    //W25Q16
//#define  SPI_FLASH_ID                       0XEF4017     //W25Q64
#define  SPI_FLASH_ID                       0XEF4018     //W25Q128  YS-F1Pro¿ª·¢Ä¬ÈÏʹÓÃ

#define FLASH_SPIx                        SPI1
#define FLASH_SPI_APBxClock_FUN           RCC_APB2PeriphClockCmd
#define FLASH_SPI_CLK                     RCC_APB2Periph_SPI1

#define FLASH_SPI_SCK_APBxClock_FUN       RCC_APB2PeriphClockCmd
#define FLASH_SPI_SCK_CLK                 RCC_APB2Periph_GPIOA   
#define FLASH_SPI_SCK_PORT                GPIOA   
#define FLASH_SPI_SCK_PIN                 GPIO_Pin_5

#define FLASH_SPI_MISO_APBxClock_FUN      RCC_APB2PeriphClockCmd
#define FLASH_SPI_MISO_CLK                RCC_APB2Periph_GPIOA    
#define FLASH_SPI_MISO_PORT               GPIOA 
#define FLASH_SPI_MISO_PIN                GPIO_Pin_6

#define FLASH_SPI_MOSI_APBxClock_FUN      RCC_APB2PeriphClockCmd
#define FLASH_SPI_MOSI_CLK                RCC_APB2Periph_GPIOA    
#define FLASH_SPI_MOSI_PORT               GPIOA 
#define FLASH_SPI_MOSI_PIN                GPIO_Pin_7

#define FLASH_SPI_CS_APBxClock_FUN        RCC_APB2PeriphClockCmd
#define FLASH_SPI_CS_CLK                  RCC_APB2Periph_GPIOA    
#define FLASH_SPI_CS_PORT                 GPIOA
#define FLASH_SPI_CS_PIN                  GPIO_Pin_4

#define FLASH_SPI_CS_ENABLE()             GPIO_ResetBits(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN)
#define FLASH_SPI_CS_DISABLE()            GPIO_SetBits(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN)


#define CALIBRATE_DATA_ADDR               2*4096

void SPI_FLASH_Init(void);
void SPI_FLASH_SectorErase(uint32_t SectorAddr);
void SPI_FLASH_BulkErase(void);
void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
uint32_t SPI_FLASH_ReadID(void);
uint32_t SPI_FLASH_ReadDeviceID(void);
void SPI_FLASH_StartReadSequence(uint32_t ReadAddr);
void SPI_Flash_PowerDown(void);
void SPI_Flash_WAKEUP(void);

uint8_t SPI_FLASH_ReadByte(void);
uint8_t SPI_FLASH_SendByte(uint8_t byte);
uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord);
void SPI_FLASH_WriteEnable(void);
void SPI_FLASH_WaitForWriteEnd(void);

#endif 

5.实验效果

                

6.结束语

本次实验讲解了使用Stm32的SPI通信内容,这也是STM32单片机应用很多的一部分内容,希望以上内容对各位朋友有所帮助。

最后,欢迎大家在评论区留言批评指正。谢谢!

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值