at45db161e

本文详细描述了如何配置STM32F10x的SPI2接口与AT45DB161E闪存进行通信,包括GPIO初始化、SPI初始化、发送和接收数据、读取ID、擦除和写入页操作,以及检查写入是否成功的方法。
摘要由CSDN通过智能技术生成

谁能看看为什么这个程序写入总是不成功

#ifndef _SPIFLASH_H
#define _SPIFLASH_H

#include "stm32f10x.h"

#define SPIx                           SPI2  

#define SPI2_GPIO_CLK_PORT             RCC_APB2Periph_GPIOB
#define SPI2_CLK_PORT                  RCC_APB1Periph_SPI2


#define SPI2_CS_GPIO_PIN               GPIO_Pin_12
#define SPI2_CS_GPIO_PORT			         GPIOB

#define SPI2_SCK_GPIO_PIN              GPIO_Pin_13
#define SPI2_SCK_GPIO_PORT		         GPIOB

#define SPI2_MISO_GPIO_PIN             GPIO_Pin_14
#define SPI2_MISO_GPIO_PORT		         GPIOB

#define SPI2_MOSI_GPIO_PIN             GPIO_Pin_15
#define SPI2_MOSI_GPIO_PORT		         GPIOB



//CS与PB12直连
#define SPI_CS_HIGH()                  GPIO_SetBits(SPI2_CS_GPIO_PORT,SPI2_CS_GPIO_PIN)
#define SPI_CS_LOW()                   GPIO_ResetBits(SPI2_CS_GPIO_PORT,SPI2_CS_GPIO_PIN)

//AT45DB161E设备ID
#define AT45DB161E_ID                  0X1F260001

//AT45DB161E命令
#define READ_ID                        0X9F
#define SECTOR_ERASE                   0X7C
#define READ_STATUS          				   0XD7
#define READ_DATA            				   0XD2
#define PAGE_ERASE           				   0X81                 
#define BUFFER1_TO_MM                  0X85                  
 

#define DUMMY               				   0XA5




void Spi_Flash_GPIO_Config(void);
void Spi_Flash_Config(void);
uint8_t SPI_FLASH_SendByte(uint8_t data);
uint8_t SPI_FLASH_ReadByte(void);
uint32_t SPI_FLASH_ReadID(void);
void SPI_WaitForWriteEnd(void);
void SPI_Read_Data(uint32_t pageaddr,uint8_t *buff,uint32_t NumByteToRead);
void SPI_PageErase(uint32_t addr);
void SPI_Write_Bufferf1ToPage(uint32_t pageaddr,uint32_t bufaddr,uint8_t* pBuffer, uint32_t NumByteToWrite);
uint8_t SPI_WriteSuccess(void);

#endif

 

#include "SpiFlash.h"



void Spi_Flash_GPIO_Config(void)
{
	//GPIOB初始化结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//开启SPI2的GPIOB时钟和SPI2时钟
	RCC_APB2PeriphClockCmd(SPI2_GPIO_CLK_PORT,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	RCC_APB1PeriphClockCmd(SPI2_CLK_PORT,ENABLE);
	
	//PB13和PB15设置复用推挽输出
	GPIO_InitStructure.GPIO_Pin = SPI2_SCK_GPIO_PIN | SPI2_MOSI_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SPI2_SCK_GPIO_PORT,&GPIO_InitStructure);
	
	//设置CS片选引脚为推挽输出
	GPIO_InitStructure.GPIO_Pin = SPI2_CS_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(SPI2_CS_GPIO_PORT,&GPIO_InitStructure);
	
	//设置MISO引脚为浮空输入
	GPIO_InitStructure.GPIO_Pin  = SPI2_MISO_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(SPI2_MISO_GPIO_PORT,&GPIO_InitStructure);
}

void Spi_Flash_Config(void)
{	
	//SPI2初始化结构体
	SPI_InitTypeDef SPI_InitStructure;
	
	Spi_Flash_GPIO_Config();
	
	//片选CS引脚高电平,停止信号
	SPI_CS_HIGH();
	
	//设置SPI2通信时钟速度
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
	//时钟相位,可选奇和偶
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
	//时钟极性,可选高和低
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
	//设置CRC校验
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	//设置数据帧长度
	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(SPIx,&SPI_InitStructure);
	
	//SPI2使能
	SPI_Cmd(SPIx,ENABLE);
}


/**
  *   函数名称:SPI_FLASH_SendByte
  *   函数功能:向AT45DB161E发送一个字节的数据并返回从AT45DB161E收到的数据
  *   使用范围:AT45DB161E
  *	  传入参数:data
  *   传出参数:AT45DB161E发回的数据
 **/
uint8_t SPI_FLASH_SendByte(uint8_t data)
{
	//检查等待TX缓冲区为空
	while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE) == RESET);
	
	//发送数据data
	SPI_I2S_SendData(SPIx,data);
	
	//检查并等待RX缓冲区非空
	while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE) == RESET);
	
	//返回由Flash发回的数据
	return SPI_I2S_ReceiveData(SPIx);
}

/**
  *   函数名称:SPI_FLASH_ReadByte
  *   函数功能:主机读取一个字节
  *   使用范围:AT45DB161E
  *	  传入参数:无
  *   传出参数:从AT45DB161E读取的数据
 **/
uint8_t SPI_FLASH_ReadByte(void)
{
	return SPI_FLASH_SendByte(DUMMY);
}

/**
  *   函数名称:SPI_FLASH_ReadID
  *   函数功能:读取AT45DB161E的ID
  *   使用范围:AT45DB161E
  *	  传入参数:无
  *   传出参数:AT45DB161E的4个字节的ID
 **/
uint32_t SPI_FLASH_ReadID(void)
{
	uint32_t Temp = 0, Temp0 = 0, Temp1 = 0,Temp2 = 0, Temp3 = 0;
	//片选使能
	SPI_CS_LOW();
	
	//发送读取设备ID命令
	SPI_FLASH_SendByte(READ_ID);
	
	//保存第一个字节
	Temp0 = SPI_FLASH_SendByte(DUMMY);
	
	//保存第二个字节
	Temp1 = SPI_FLASH_SendByte(DUMMY);
	
	//保存第三个字节
	Temp2 = SPI_FLASH_SendByte(DUMMY);
	
	//保存第四个字节
	Temp3 = SPI_FLASH_SendByte(DUMMY);
	
	//将四个字节ID存在一起
	Temp = (Temp0 << 24) | (Temp1 << 16) | (Temp2 << 8) | (Temp3);
	 
	
	//停止信号
	SPI_CS_HIGH();
	
	return Temp;
}
	


/**
  *   函数名称:SPI_WaitForWriteEnd
  *   函数功能:等待写结束
  *   使用范围:AT45DB161E
  *	  传入参数:无
  *   传出参数:无
 **/
void SPI_WaitForWriteEnd(void)
{
	uint8_t flashstatus = 0;
	
	//片选使能
	SPI_CS_LOW();
	
	//发送读取状态寄存器命令
	SPI_FLASH_SendByte(READ_STATUS);
	
	//一直读取状态寄存器的BUSY位,直到BUSY位为0
	do
	{
		flashstatus = SPI_FLASH_SendByte(DUMMY);
	}while(flashstatus & 0X01 == 1);
	
	//停止信号
	SPI_CS_HIGH();
}

/**
  *   函数名称:SPI_Read_Data
  *   函数功能:读取指定地址的指定长度数据
  *   使用范围:AT45DB161E
  *	  传入参数:读取地址,存放数据的数组,读取数据的长度
  *   传出参数:无
 **/
void SPI_Read_Data(uint32_t pageaddr,uint8_t *buff,uint32_t NumByteToRead)
{
	uint8_t i;
		//片选使能
	SPI_CS_LOW();
	
	//发送扇区擦除命令
	SPI_FLASH_SendByte(READ_DATA);
	
 	//发送高位地址
	SPI_FLASH_SendByte(pageaddr >> 6);
	
	//发送第二个字节的地址
	SPI_FLASH_SendByte((pageaddr & 0X3F) << 2);
	
	
	SPI_FLASH_SendByte(pageaddr >> 0);
	
	for(i=0;i<4;i++)
	{
		SPI_FLASH_SendByte(0xff);
	}
	//将读取的DATA放到buff里
	while(NumByteToRead--)
	{
		*buff = SPI_FLASH_SendByte(DUMMY);
		buff++;
	}
	
	//停止信号
	SPI_CS_HIGH();
	
	SPI_WaitForWriteEnd();
}

/**
  *   函数名称:SPI_PageErase
  *   函数功能:页擦除
  *   使用范围:AT45DB161E
  *	  传入参数:擦除地址
  *   传出参数:无
 **/
void SPI_PageErase(uint32_t addr)
{

  SPI_CS_LOW();
  
  SPI_FLASH_SendByte(PAGE_ERASE);
 
 	//发送高位地址
	SPI_FLASH_SendByte(addr >> 6);
	
	//发送第二个字节的地址
	SPI_FLASH_SendByte((addr & 0X3F) << 2);
	
	//发送低位地址,但是低8位无用,所以全置零
	SPI_FLASH_SendByte(addr & 0x00);
	
  SPI_CS_HIGH();					
 
  SPI_WaitForWriteEnd();
}



/**
  *   函数名称:SPI_Write_Bufferf1ToPage
  *   函数功能:页写入
  *   使用范围:AT45DB161E
  *	  传入参数:写入地址,写入数据,写入数量
  *   传出参数:无
 **/
void SPI_Write_Bufferf1ToPage(uint32_t pageaddr,uint32_t bufaddr,uint8_t* pBuffer, uint32_t NumByteToWrite)
{
  
  SPI_CS_LOW();
  
  SPI_FLASH_SendByte(BUFFER1_TO_MM);
 
 	//发送高位地址
	SPI_FLASH_SendByte((uint32_t)(pageaddr >> 6));
	
	//发送第二个字节的地址
	SPI_FLASH_SendByte((uint32_t)(((pageaddr & 0X3F) << 2) | (bufaddr >>8)));
	
	
	SPI_FLASH_SendByte((uint32_t)(bufaddr >> 0));
	
  while (NumByteToWrite--)
  {
    
    SPI_FLASH_SendByte(*pBuffer);
    
    pBuffer++;
  }

  SPI_CS_HIGH();					
 
  SPI_WaitForWriteEnd();
}



uint8_t SPI_WriteSuccess(void)
{
	uint8_t flashstatus = 0;
	
	//片选使能
	SPI_CS_LOW();
	
	//发送读取状态寄存器命令
	SPI_FLASH_SendByte(READ_STATUS);
	
	//一直读取状态寄存器的BUSY位,直到BUSY位为0
	
	flashstatus = SPI_FLASH_SendByte(DUMMY);

	
	//停止信号
	SPI_CS_HIGH();
		if(flashstatus & 0X40 == 1)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}















AT45DB161E是一款串行数据存储器,可以通过串口进行烧录。串口烧录是一种将程序或数据通过串行通信接口下载到目标设备的方法。 首先,我们需要准备好一台已经配置好的电脑或开发板,并将其与AT45DB161E连接起来。连接时,我们需要正确地接线并选择合适的通信参数,如波特率、数据位数和停止位等。 接下来,我们需要使用烧录工具或者命令行工具来与AT45DB161E进行通信。一般来说,厂商会提供相应的烧录工具和软件文档,我们可以根据文档的指引来进行烧录操作。一种常见的方式是使用串口助手等工具,通过串口与AT45DB161E进行通信。 在烧录之前,我们需要确保目标设备处于一个可以接收烧录数据的状态。这通常包括将目标设备进入烧录模式或重启设备进入烧录模式等操作。 接着,我们可以通过烧录工具将程序或数据文件发送到目标设备。烧录工具会将文件内容按照串口通信协议进行拆分和封装,然后通过串口传输到AT45DB161E中。在传输过程中,我们需要确保传输的正确性和完整性。 最后,烧录完成后,我们需要验证程序或数据是否成功烧录到AT45DB161E中。可以通过读取AT45DB161E中的内容,与原始文件进行比较,以验证烧录的正确性。 总的来说,AT45DB161E通过串口进行烧录是一种方便快捷的方法,可以有效地将程序或数据烧录到目标设备中,并且可以通过适当的工具进行验证和调试。只需正确连接设备,并使用相应的烧录工具,按照烧录文档的指引进行操作,即可完成烧录过程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值