GD25Q128读写接口在stm32

简介

在这里插入图片描述

spi配置

void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  /* USER CODE BEGIN SPI2_Init 1 */

  /* USER CODE END SPI2_Init 1 */
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 7;
  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */

  /* USER CODE END SPI2_Init 2 */

}

读写代码接口示例

#include "spi.h"
#include "string.h"
#include "spi_flash.h" 
 
 
 
#define SPI2_FLASH_NSS_PORT       GPIOA
#define SPI2_FLASH_NSS_PIN        GPIO_PIN_8
 
#define CMD_PAGE_PROGRAM           0x02
#define CMD_READ_DATA_BYTES        0x03
#define CMD_READ_STA_REG           0x05
#define CMD_WRITE_ENABLE           0x06
#define CMD_SECTOR_ERASE           0x20
#define GET_DEVICE_ID              0x90
#define GET_IDENTIFICATION         0x9f
 
#define DUMMY_BYTE     					0xff 
 
#define  SFLASH_ID       						0xC84018  //Flash ID

 
#define SPI_FLASH_NSS_ENABLE 	    HAL_GPIO_WritePin(SPI2_FLASH_NSS_PORT, SPI2_FLASH_NSS_PIN, GPIO_PIN_RESET)
#define SPI_FLASH_NSS_DISENABLE 	HAL_GPIO_WritePin(SPI2_FLASH_NSS_PORT, SPI2_FLASH_NSS_PIN, GPIO_PIN_SET)
 
 
#define SPI_FLASH_PAGE_SIZE    0x100 //GD25Qxx每页有256个字节
#define WIP_FLAG         0x01     /* write in progress(wip)flag */
 
#define DEVICE_SIZE 	0x400000 	// 4M
#define BLOCK_SIZE		0x10000		// 64K
#define SECTOR_SIZE		0x1000 		// 4K
#define PAGE_SIZE		  0x100 		// 256
 
static uint8_t gs_sectorBuf[SECTOR_SIZE] = {0};

union GD32_UINT32_DATA_TYPE
{
	uint8_t b[4];
    uint32_t Uint32_Data;
};

uint8_t spi_SendRcvByte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi2, &TxData, &Rxdata, 1, 100);
    return Rxdata;
}

/*
 * @brief 读取DEVICE_ID
 * @return 返回ID号
 */
uint16_t get_DeviceId(void)
{
	uint16_t dev_id = 0;
	
	SPI_FLASH_NSS_ENABLE;
	
	spi_SendRcvByte(GET_DEVICE_ID);
	spi_SendRcvByte(DUMMY_BYTE);
	spi_SendRcvByte(DUMMY_BYTE);
	spi_SendRcvByte(DUMMY_BYTE);
 
	
	dev_id = spi_SendRcvByte(DUMMY_BYTE) << 8;
  dev_id |= spi_SendRcvByte(DUMMY_BYTE);
 
	SPI_FLASH_NSS_DISENABLE;
    	
	return dev_id;
}
 
/*
 * @brief 读取Identifica
 * @param data_out 输出ID号
 */
void get_Identifica(uint8_t *data_out)
{
	SPI_FLASH_NSS_ENABLE;
 
	spi_SendRcvByte(GET_IDENTIFICATION);
	data_out [0] = spi_SendRcvByte(DUMMY_BYTE);
	data_out [1] = spi_SendRcvByte(DUMMY_BYTE);
	data_out [2] = spi_SendRcvByte(DUMMY_BYTE);
	
	SPI_FLASH_NSS_DISENABLE;
}
 
/*
 * @brief 读取数据
 * @param dest_addr 目标地址
 * @param data 将要写入数据
 * @param len 将要写入数据长度 
 */
void get_ReadDataBytes(uint32_t dest_addr, uint8_t *data, uint32_t len)
{	
	SPI_FLASH_NSS_ENABLE;
	
	spi_SendRcvByte(CMD_READ_DATA_BYTES);
	spi_SendRcvByte((uint8_t)(dest_addr >> 16));
	spi_SendRcvByte((uint8_t)(dest_addr >> 8));
	spi_SendRcvByte((uint8_t)(dest_addr));
	
	while(len--)
	{	
		*data = spi_SendRcvByte(DUMMY_BYTE);
		data++;
	}
	
	SPI_FLASH_NSS_DISENABLE;
}
 
//函数功能:发送"写使能命令"
void spi_flash_write_enable(void)
{
	SPI_FLASH_NSS_ENABLE;
	spi_SendRcvByte(CMD_WRITE_ENABLE); //发送"写使能命令"
	SPI_FLASH_NSS_DISENABLE;
}

//函数功能:等待空闲
void spi_flash_wait_for_write_end(void)
{
	uint8_t flash_status = 0;
 
	SPI_FLASH_NSS_ENABLE;
	spi_SendRcvByte(CMD_READ_STA_REG);//发送"读状态寄存器命令"
 
	do
	{
		flash_status = spi_SendRcvByte(DUMMY_BYTE);
		//发送DUMMY_BYTE数据为的是读取状态寄存器的值
	}while( (flash_status & WIP_FLAG) == SET );
	//WIP位置1,表示芯片正处于编程/擦除/写状态
 
	SPI_FLASH_NSS_DISENABLE;
}


//函数功能:擦除扇区,其首地址为sector_addr
void spi_flash_sector_erase(uint32_t sector_addr)
{
	union GD32_UINT32_DATA_TYPE addr;
 
	addr.Uint32_Data=sector_addr;
 
	spi_flash_write_enable();//发送"写使能命令"
 
	SPI_FLASH_NSS_ENABLE;
	spi_SendRcvByte(CMD_SECTOR_ERASE); //发送扇区擦除命令
	spi_SendRcvByte( addr.b[2] );     //发送扇区地址的bit16~bit23
	spi_SendRcvByte( addr.b[1] );     //发送扇区地址的bit8~bit15
	spi_SendRcvByte( addr.b[0] );     //发送扇区地址的bit0~bit7
	SPI_FLASH_NSS_DISENABLE;

 
	spi_flash_wait_for_write_end();//等待空闲
}


//函数功能:将pbuffer[]中的num_byte_to_write个字节型数据写入首地址为write_addr的Flash空间
static void spi_flash_page_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write)
{
	union GD32_UINT32_DATA_TYPE addr;
 
	addr.Uint32_Data=write_addr;
 
	spi_flash_write_enable();//发送"写使能命令"
 
	SPI_FLASH_NSS_ENABLE;
 
	spi_SendRcvByte(CMD_PAGE_PROGRAM);//发送"页编程命令"
	spi_SendRcvByte( addr.b[2] );   //发送页地址的bit16~bit23
	spi_SendRcvByte( addr.b[1] );   //发送页地址的bit8~bit15
	spi_SendRcvByte( addr.b[0] );   //发送页地址的bit0~bit7
	while(num_byte_to_write--)
	{
		spi_SendRcvByte(*pbuffer);
		pbuffer++;
	}
 
	SPI_FLASH_NSS_DISENABLE;
 
	spi_flash_wait_for_write_end();//等待空闲
}

/*
 * @brief 写数据
 * @param write_addr 目标地址
 * @param pbuffer 将要写入数据
 * @param len 将要写入数据长度 
 */
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t len)
{
	uint8_t num_of_page = 0, num_of_single = 0, addr = 0, count = 0, temp = 0;
 
	addr          = write_addr % SPI_FLASH_PAGE_SIZE;
	count         = SPI_FLASH_PAGE_SIZE - addr; //计算当前页剩余多少个字节空间
	num_of_page   = len / SPI_FLASH_PAGE_SIZE;//计算需要写多少页
	num_of_single = len % SPI_FLASH_PAGE_SIZE;//计算不满一页的字节数量
 
	if(0 == addr)//位于页边界
	{
		if(0 == num_of_page)//所写字节数量不满一页,num_byte_to_write < SPI_FLASH_PAGE_SIZE
			spi_flash_page_write(pbuffer,write_addr, len);
		else//所写字节数量超过一页,num_byte_to_write > SPI_FLASH_PAGE_SIZE
		{
			while(num_of_page--)
			{
				spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
				write_addr += SPI_FLASH_PAGE_SIZE;
				pbuffer += SPI_FLASH_PAGE_SIZE;
			}
			spi_flash_page_write(pbuffer,write_addr,num_of_single);
		}
	}
	else
	{
		if(0 == num_of_page)//所写字节数量不满一页
		{
			if(num_of_single > count)//超过当前页
			{
				temp = num_of_single - count;//计算跨页的字节数量
				spi_flash_page_write(pbuffer,write_addr,count);
				write_addr += count;//修改Flash地址
				pbuffer += count;   //修改指针
				spi_flash_page_write(pbuffer,write_addr,temp);
			}
			else//没有超过当前页
			spi_flash_page_write(pbuffer,write_addr,len);
		}
		else//所写字节数量超过一页
		{
			len -= count;//计算写当前页后的剩余字节总数
			num_of_page = len / SPI_FLASH_PAGE_SIZE;  //剩余字节总数需要多少页
			num_of_single = len % SPI_FLASH_PAGE_SIZE;//剩余字节总数写完整页后的剩余字节数量
 
			spi_flash_page_write(pbuffer,write_addr, count);//向当前页写入count字节,凑成1整页
			write_addr += count;//修改Flash地址
			pbuffer += count;   //修改指针
 
			while(num_of_page--)
			{
				spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
				write_addr += SPI_FLASH_PAGE_SIZE;//修改Flash地址
				pbuffer += SPI_FLASH_PAGE_SIZE;   //修改指针
			}
 
			if(0 != num_of_single)//最后写剩余的字节
				spi_flash_page_write(pbuffer,write_addr,num_of_single);
		}
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

路过的小熊~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值