STM32之SPI学习笔记2(实战部分)

【>>>>>以下所写如果难以理解的部分或有什么建议,可留言交流<<<<<】

spi编程要点:

1 初始化spi结构体

2 功能操作函数

1主体函数部分main.c

uint8_t readbuff[4096];
uint8_t Writebuff[4096];
int main(void)
{	
        uint32_t id;
	

	uint16_t i;
	//串口
	USART_Config();


	//spi配置
	SPI_FLASH_Config();
        //读取设备id
	id=SPI_Read_ID();
	printf("0x%x\r\n",id);
	
	
	
	//清除扇区
	SPI_ERASE_SECTOR(0);
	
	
	for(i=0;i<4096;i++)
	{
	    Writebuff[i]=i;
	}
        //往spi-flash 里写入数据
	SPI_Write_Data(0,Writebuff,4096);
        //从里面读取数据
	SPI_Read_Data(0,readbuff,4096);
	for(i=0;i<4096;i++)
	{
	
		printf("0x%x",readbuff[i]);
		if(i%10==0)
		{
			printf("\n");
		}
	}
}

2 相关函数bsp_flash_spi.c

#include "bsp_spi.h"


uint16_t FLASH_ADDRESS;

static __IO uint32_t  SPITimeout = SPIT_LONG_TIMEOUT;   



static  uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);


/*spi_flash 配置*/
void SPI_FLASH_Config(void){

	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef SPI_InitStructure;

	// 打开SPI GPIO的时钟
	FLASH_SPI_GPIO_APBxClkCmd(FLASH_SPI_GPIO_CLK, ENABLE);
	// 打开SPI外设的时钟
	FLASH_SPI_APBxClkCmd(FLASH_SPI_CLK, ENABLE);

	// 将FLASH_SPI SCL 的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCLK_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(FLASH_SPI_SCLK_GPIO_PORT, &GPIO_InitStructure);

         // 将FLASH_SPI MOSI  的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
	// 将FLASH_SPI MISO  的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(FLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
	
	
	//初始化CS引脚,因为是用软件,所以为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure);
	
	FLASH_SPI_CS_HIGH;
	
	// 配置SPI的工作参数

	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;
	SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;
	SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;
	SPI_InitStructure.SPI_CRCPolynomial=0;//不使用CRC功能
	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;
	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;
	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;
	SPI_Init(FLASH_SPIx,&SPI_InitStructure);
	
	
//	// 串口中断优先级配置
//	NVIC_Configuration();
//	
//	// 使能串口接收中断
//	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	
//	
	// 使能SPI
		SPI_Cmd(FLASH_SPIx, ENABLE);	 
	
}
/*写使能函数*/
void SPI_Write_Enable(void){
	

	FLASH_SPI_CS_LOW;
	SPI_FLASH_Send_Byte(Write_Enable);
	FLASH_SPI_CS_HIGH;
	
}
        /*发送一字节,并接收一字节*/
 uint16_t SPI_FLASH_Send_Byte(uint8_t data){
//检查并等待至TX缓冲区为空
	while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_TXE)==RESET){
	
		if(SPITimeout--==0)
		{
			return SPI_TIMEOUT_UserCallback(0);
		}
	}
	//程序执行到此,TX缓冲区已空 
	
	SPI_I2S_SendData(FLASH_SPIx,data);
	//检查并等待至rx缓冲区为空
	while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_RXNE)==RESET);
	
	return SPI_I2S_ReceiveData(FLASH_SPIx);
}

/**
  * @brief  Basic management of the timeout situation.
  * @param  errorCode:错误代码,可以用来定位是哪个环节出错.
  * @retval 返回0,表示SPI读取失败.
  */

        /*超时回调函数*/
static  uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
{
  /* Block communication and all processes */
  FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
  
  return 0;
}
/*读取一字节*/
//uint8_t SPI_FLASH_Read_Byte(void){
//	return SPI_FLASH_Send_Byte(DUMMY);
//}
/*读取设备id*/
uint32_t SPI_Read_ID(void)
	{
		
	
		uint32_t flash_id;
		FLASH_SPI_CS_LOW;
		
		SPI_FLASH_Send_Byte(Read_jedecc_ID);
		
		flash_id =SPI_FLASH_Send_Byte(DUMMY);
		flash_id<<=8;
		flash_id |=SPI_FLASH_Send_Byte(DUMMY);
		flash_id<<=8;
		flash_id |=SPI_FLASH_Send_Byte(DUMMY);
		
		FLASH_SPI_CS_HIGH;
		
		return flash_id;
	
}

/*读取数据*/
void SPI_Read_Data(uint32_t addr,uint8_t*buff,uint32_t numBytetoRead){
	
	//SPI_Write_Enable();
	FLASH_SPI_CS_LOW;
	SPI_FLASH_Send_Byte(Read_data);
	SPI_FLASH_Send_Byte(addr>>16&0xff);
	SPI_FLASH_Send_Byte(addr>>8&0xff);
	SPI_FLASH_Send_Byte(addr&0xff);
	while(numBytetoRead--)
{
	*buff=SPI_FLASH_Send_Byte(DUMMY);
	buff++;
}
	FLASH_SPI_CS_HIGH;
	SPI_WaitForWriteEnd();
	
	
}
/*写数据*/
void SPI_Write_Data(uint32_t addr,uint8_t*Writebuff,uint32_t numBytetoRead){
	
	

	FLASH_SPI_CS_LOW;
	SPI_Write_Enable();
	SPI_WaitForWriteEnd();
	SPI_FLASH_Send_Byte(Write_Data);
	SPI_FLASH_Send_Byte((addr & 0xFF0000) >> 16);
	SPI_FLASH_Send_Byte((addr & 0xFF00) >> 8);
	SPI_FLASH_Send_Byte((addr & 0xFF));
	while(numBytetoRead--)
{
	SPI_FLASH_Send_Byte(*Writebuff);
	Writebuff++;
}
	FLASH_SPI_CS_HIGH;
	
	SPI_WaitForWriteEnd();
}
/*擦出扇区*/
void SPI_ERASE_SECTOR(uint32_t addr){
	
	FLASH_SPI_CS_LOW;
	SPI_Write_Enable();
	SPI_WaitForWriteEnd();
	SPI_FLASH_Send_Byte(ERASE_SECTOR);
	SPI_FLASH_Send_Byte((addr & 0xFF0000) >> 16);
	SPI_FLASH_Send_Byte((addr & 0xFF00) >> 8);
	SPI_FLASH_Send_Byte(addr & 0xFF);
	FLASH_SPI_CS_HIGH;
	SPI_WaitForWriteEnd();
}
/等待操作完成/
void SPI_WaitForWriteEnd(void){
	uint8_t status_reg=0;
	SPI_FLASH_Send_Byte(READ_STATUS);
	do{
		status_reg=SPI_FLASH_Send_Byte(DUMMY);
	}while((status_reg&0x01)==1);
	FLASH_SPI_CS_HIGH;
	
}

3 相关头文件bsp_spi_flash.h

/*spi_flash*/
#ifndef  _BSP_SPI_H
#define  _BSP_SPI_H

#include "stm32f10x.h"
#include <stdio.h>





/*等待超时时间*/
#define SPIT_FLAG_TIMEOUT         ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT         ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
#define FLASH_ERROR(fmt,arg...)          printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)


//板配spi获取信息时所需的各种命令
#define USE_BD 1
#define DUMMY 0x00
#define  Read_jedecc_ID  0x9f
#define ERASE_SECTOR	0x20
#define READ_STATUS 0x05
#define Write_Enable 0x06
#define	Read_data  0x03
#define Write_Data 0x02

#define  FLASH_SPIx                  	 SPI1
#define  FLASH_SPI_APBxClkCmd          RCC_APB2PeriphClockCmd
#define  FLASH_SPI_CLK                 RCC_APB2Periph_SPI1
#define  FLASH_SPI_BAUDRATE            400000


// USART GPIO 引脚宏定义
#define  FLASH_SPI_GPIO_APBxClkCmd   		  RCC_APB2PeriphClockCmd


#if (USE_BD ==1)
	#define  FLASH_SPI_GPIO_CLK           	(RCC_APB2Periph_GPIOA)
	#define  FLASH_SPI_CS_GPIO_PORT       	GPIOA
	#define  FLASH_SPI_CS_GPIO_PIN       		GPIO_Pin_4
#else
	#define  FLASH_SPI_GPIO_CLK           	(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC)
	#define  FLASH_SPI_CS_GPIO_PORT       	GPIOC
	#define  FLASH_SPI_CS_GPIO_PIN       		GPIO_Pin_0
#endif

    
#define  FLASH_SPI_SCLK_GPIO_PORT       	GPIOA   
#define  FLASH_SPI_SCLK_GPIO_PIN        	GPIO_Pin_5

#define  FLASH_SPI_MOSI_GPIO_PORT       	GPIOA
#define  FLASH_SPI_MOSI_GPIO_PIN       		GPIO_Pin_7

#define  FLASH_SPI_MISO_GPIO_PORT       	GPIOA
#define  FLASH_SPI_MISO_GPIO_PIN       		GPIO_Pin_6


/*宏定义*/
#define  FLASH_SPI_CS_HIGH	GPIO_SetBits(FLASH_SPI_CS_GPIO_PORT,FLASH_SPI_CS_GPIO_PIN)
#define  FLASH_SPI_CS_LOW	GPIO_ResetBits(FLASH_SPI_CS_GPIO_PORT,FLASH_SPI_CS_GPIO_PIN)




void SPI_Write_Enable(void);
void SPI_FLASH_Config(void);
uint16_t SPI_FLAHS_Send_Byte(uint8_t data);
static  uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
uint8_t SPI_FLASH_Read_Byte(void);
uint32_t SPI_Read_ID(void);
void SPI_Read_Data(uint32_t addr,uint8_t*buff,uint32_t numBytetoRead);
void SPI_Write_Data(uint32_t addr,uint8_t*Writebuff,uint32_t numBytetoRead);
void SPI_ERASE_SECTOR(uint32_t addr);
void SPI_WaitForWriteEnd(void);
#endif/* _BSP_SPI_H*/

猜你喜欢

转载自blog.csdn.net/iubuntu_qi/article/details/82315066
今日推荐