使用GD32F10x的SPI0接口读写GD25Q128

 

 

#include "SPI0.h"

void SPI0_Init(void);
uint8_t SPI0_ReadWriteByte(uint8_t byte);
void SPI0_SetSpeed(uint32_t SpeedSet);

/*
PA5复用为SPI0_SCK
PA6复用为SPI0_MISO
PA7复用为SPI0_MOSI
SPI0使用NSS软件模式,这里使用PE4
*/
void SPI0_Init(void)
{
	spi_parameter_struct spi_init_struct;

	rcu_periph_clock_enable(RCU_GPIOA); //使能GPIOA的外设时钟
	rcu_periph_clock_enable(RCU_SPI0);  //使能SPI0的外设时钟

	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
	//SPI0_SCK:配置GPIOA5的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
	//SPI0_MOSI:配置GPIOA7的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
	//SPI0_MISO:将GPIOA6设置为浮空输入

///配置SPI0的CS引脚开始///
	rcu_periph_clock_enable(RCU_GPIOE);
	gpio_init(GPIOE, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
	SPI0_CS_HIGH();//设置SPI0的CS引脚输出高电平
///配置SPI0的CS引脚结束///

	spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX; //SPI在全双工通讯中接收/发送数据
	spi_init_struct.device_mode          = SPI_MASTER;               //SPI为主机模式且SWNSS=1
	spi_init_struct.nss                  = SPI_NSS_SOFT;             //使用NSS软件模式:NSS电平取决于SWNSS位;
	spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;       //SPI使用8位数据帧格式
	spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
	//在SPI为空闲状态时,CLK引脚拉低,且"在第1个时钟跳变沿时开始采集第1位数据"
	spi_init_struct.prescale             = SPI_PSC_8;                //SPI时钟预分频器值为8
	spi_init_struct.endian               = SPI_ENDIAN_MSB;           //先发送最高位
	spi_init(SPI0, &spi_init_struct);//使用spi_init_struct结构参数初始化SPI0

	spi_crc_polynomial_set(SPI0,7); //将7写入"SPI的CRC多项式寄存器"
	spi_enable(SPI0);               //使能SPI0
}

//函数功能:SPI0发送8位的byte,并将读到的8位数据返回
uint8_t SPI0_ReadWriteByte(uint8_t byte)
{
	uint8_t ret_Data;

	while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE))
	{//读取"SPI发送缓冲区空"标志
	 //等待SPI发送完成
	}

	spi_i2s_data_transmit(SPI0,byte);
	//将byte写入"SPI0数据寄存器"
	while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE))
	{//读取"SPI接收缓冲区非空"标志
	 //等待SPI接收完成
	}

	ret_Data=spi_i2s_data_receive(SPI0);
	//从"SPI数据寄存器"读取数据

	return(ret_Data);
}

//函数功能:SPI0发送16位的half_word,并将读到的16位数据返回
uint16_t spi_flash_send_halfword(uint16_t half_word)
{
	uint16_t ret_Data;

	while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE))
	{//读取"SPI发送缓冲区空"标志
	 //等待SPI发送完成
	}

	spi_i2s_data_transmit(SPI0,half_word);//将byte写入"SPI0数据寄存器"
	while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE))
	{//读取"SPI接收缓冲区非空"标志
	 //等待SPI接收完成
	}

	ret_Data=spi_i2s_data_receive(SPI0);//从"SPI数据寄存器"读取数据
	return(ret_Data);
}

//当使用SPI0时,PCLK=PCLK2,预分频器输入时钟最大为108MHz
//当使用SPI1和SPI2时,PCLK=PCLK1,预分频器输入时钟最大为54MHz
//SPI_PSC_2,SPI时钟预分频器值为2,SPI时钟为54MHz
//SPI_PSC_4,SPI时钟预分频器值为4,SPI时钟为27MHz
//SPI_PSC_8,SPI时钟预分频器值为8,SPI时钟为13.5MHz
//SPI_PSC_16,PI时钟预分频器值为16,SPI时钟为6.75MHz
//SPI_PSC_32,SPI时钟预分频器值为32,SPI时钟为3.375MHz
//SPI_PSC_64,SPI时钟预分频器值为64,SPI时钟为1.6875MHz
//SPI_PSC_128,SPI时钟预分频器值为128,SPI时钟为843.75KHz
//SPI_PSC_256,SPI时钟预分频器值为256,SPI时钟为421.875KHz
//函数功能:将SpeedSet的值写入主机模式中的预分频器
void SPI0_SetSpeed(uint32_t SpeedSet)
{
	uint32_t reg;

	reg=SPI_CTL0(SPI0);//读取SPI控制寄存器0
	reg=(uint32_t)( reg & (uint32_t)( ~SPI_CTL0_PSC ) );//清除主机模式中的预分频器
	reg=(uint32_t)( reg | SpeedSet );                   //将SpeedSet写入到bit3~bit5
}

 

#include "GD25Qxx.h"
#include "SPI0.h"
#include "LED.h"

uint32_t flash_id;
uint8_t  Flash_Write_Buffer[Flash_Write_Buffer_Size];
uint8_t  Flash_Read_Buffer[Flash_Read_Buffer_Size];

uint8_t spi_flash_send_byte(uint8_t byte);
uint8_t spi_flash_read_byte(void);
void spi_flash_write_enable(void);
void spi_flash_wait_for_write_end(void);
void GD25Qxx_Init(void);

//函数功能:SPI0发送byte,并将读到的数据返回
uint8_t spi_flash_send_byte(uint8_t byte)
{
	uint8_t ret_Data;

	ret_Data=SPI0_ReadWriteByte(byte);

	return(ret_Data);
}

//函数功能:SPI0发送DUMMY_BYTE,为的是读取数据,并返回读到的值
uint8_t spi_flash_read_byte(void)
{
	uint8_t ret_Data;

	ret_Data=SPI0_ReadWriteByte(DUMMY_BYTE);
	//SPI0发送byte,并将读到的数据返回
	return(ret_Data);
}

//函数功能:发送"写使能命令"
void spi_flash_write_enable(void)
{
	SPI0_CS_LOW();
	spi_flash_send_byte(WriteEnable_CMD);//发送"写使能命令"
	SPI0_CS_HIGH();
}

//函数功能:等待空闲
void spi_flash_wait_for_write_end(void)
{
	uint8_t flash_status = 0;

	SPI0_CS_LOW();
	spi_flash_send_byte(ReadStatusRegister1_CMD);//发送"读状态寄存器命令"

	do
	{
		flash_status = spi_flash_send_byte(DUMMY_BYTE);
		//发送DUMMY_BYTE数据为的是读取状态寄存器的值
	}while( (flash_status & WIP_FLAG) == SET );
	//WIP位置1,表示芯片正处于编程/擦除/写状态

	SPI0_CS_HIGH();
}

//函数功能:擦除扇区,其首地址为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();//发送"写使能命令"

擦出扇区开始///
	SPI0_CS_LOW();
	spi_flash_send_byte(SectorErase_CMD); //发送扇区擦除命令
	spi_flash_send_byte( addr.b[2] );     //发送扇区地址的bit16~bit23
	spi_flash_send_byte( addr.b[1] );     //发送扇区地址的bit8~bit15
	spi_flash_send_byte( addr.b[0] );     //发送扇区地址的bit0~bit7
	SPI0_CS_HIGH();
擦出扇区结束///

	spi_flash_wait_for_write_end();//等待空闲
}

//函数功能:擦除整个芯片
void spi_flash_bulk_erase(void)
{
	spi_flash_write_enable();//发送"写使能命令"

	SPI0_CS_LOW();
	spi_flash_send_byte(ChipErase_CMD);//发送"芯片擦除命令"
	SPI0_CS_HIGH();

	spi_flash_wait_for_write_end();//等待空闲
}

//函数功能:将pbuffer[]中的num_byte_to_write个字节型数据写入首地址为write_addr的Flash空间
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();//发送"写使能命令"

	SPI0_CS_LOW();

	spi_flash_send_byte(PageProgram_CMD);//发送"页编程命令"
	spi_flash_send_byte( addr.b[2] );   //发送页地址的bit16~bit23
	spi_flash_send_byte( addr.b[1] );   //发送页地址的bit8~bit15
	spi_flash_send_byte( addr.b[0] );   //发送页地址的bit0~bit7
	while(num_byte_to_write--)
	{
		spi_flash_send_byte(*pbuffer);
		pbuffer++;
	}

	SPI0_CS_HIGH();

	spi_flash_wait_for_write_end();//等待空闲
}

//函数功能:将pbuffer[num_byte_to_write]写入Flash,其首地址为write_addr
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write)
{
	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   = num_byte_to_write / SPI_FLASH_PAGE_SIZE;//计算需要写多少页
	num_of_single = num_byte_to_write % 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,num_byte_to_write);
		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,num_byte_to_write);
		}
		else//所写字节数量超过一页
		{
			num_byte_to_write -= count;//计算写当前页后的剩余字节总数
			num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;  //剩余字节总数需要多少页
			num_of_single = num_byte_to_write % 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);
		}
	}
}

//函数功能:从Flash中读取num_byte_to_read个字节,保存到pbuffer[]中
void spi_flash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read)
{
	union GD32_UINT32_DATA_TYPE addr;

	addr.Uint32_Data=read_addr;
	SPI0_CS_LOW();

	spi_flash_send_byte(ReadData_CMD);//读数据命令
	spi_flash_send_byte( addr.b[2] );//发送地址的bit16~bit23
	spi_flash_send_byte( addr.b[1] );//发送地址的bit8~bit15
	spi_flash_send_byte( addr.b[0] );//发送地址的bit0~bit7
	while(num_byte_to_read--)
	{
		*pbuffer = spi_flash_send_byte(DUMMY_BYTE);
		pbuffer++;
	}

	SPI0_CS_HIGH();
}

//函数功能:读Flash的ID
uint32_t spi_flash_read_id(void)
{
	union GD32_UINT32_DATA_TYPE ret_Data;

	ret_Data.Uint32_Data=0;

	SPI0_CS_LOW();

	spi_flash_send_byte(ReadIdentificationCMD);      //发送"读Flash的ID命令"
	ret_Data.b[2]=spi_flash_send_byte(DUMMY_BYTE);   //读取数据的bit16~bit23
	ret_Data.b[1]=spi_flash_send_byte(DUMMY_BYTE);   //读取数据的bit8~bit15
	ret_Data.b[0]=spi_flash_send_byte(DUMMY_BYTE);   //读取数据的bit0~bit7

	SPI0_CS_HIGH();

	return (ret_Data.Uint32_Data);
}

//函数功能:若src[]和dst[]的前length个字节相同,则返回1
uint8_t memory_compare(uint8_t* src, uint8_t* dst, uint16_t length) 
{
	while(length --)
	{
		if(*src++ != *dst++) return 0;
	}

	return 1;
}

void GD25Qxx_Init(void)
{
	uint16_t i;

	flash_id=0;
	SPI0_Init();
	LED2_Off();

	flash_id = spi_flash_read_id();//读Flash的ID
	if(SFLASH_ID == flash_id)
	{
		for(i=0; i<SPI_FLASH_PAGE_SIZE;i++)
		{
			Flash_Write_Buffer[i]=i;
		}

		spi_flash_sector_erase(0x000000);//擦除扇区,其首地址为0x000000

		spi_flash_buffer_write(Flash_Write_Buffer,0x000000,SPI_FLASH_PAGE_SIZE);
		//将Flash_Write_Buffer[SPI_FLASH_PAGE_SIZE]写入Flash,其首地址为0x000000

		spi_flash_buffer_read(Flash_Read_Buffer,0x000000,SPI_FLASH_PAGE_SIZE);
		//从Flash首地址为0x000000开始,读取SPI_FLASH_PAGE_SIZE个字节,保存到Flash_Read_Buffer[]中
	
		i=0;
		i=memory_compare(Flash_Write_Buffer,Flash_Read_Buffer,SPI_FLASH_PAGE_SIZE);
		//若Flash_Write_Buffer[]和Flash_Read_Buffer[]的前SPI_FLASH_PAGE_SIZE个字节相同,则返回1
	  if(i) LED2_On();//读写Flash正确,则LED2灯点亮
	}
}

 

#ifndef __GD25Qxx_H
#define __GD25Qxx_H

#include "sys.h"
//#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t,bool

#define WriteStatusRegister1_CMD   0x01  //写状态寄存器1,Write Status Register-1
#define WriteEnable_CMD            0x06  //写使能命令,Write Enable
#define PageProgram_CMD            0x02  //页编程命令,Page Program
#define SectorErase_CMD            0x20  //扇区擦除命令,Sector Erase
#define ChipErase_CMD              0xC7  //芯片擦除命令,Chip Erase
#define ReadStatusRegister1_CMD    0x05  //读状态寄存器1命令,Read Status Register-1
#define ReadData_CMD               0x03  //读数据命令,Read Data
#define ReadIdentificationCMD      0x9F  //读Flash的ID命令,Read Identification

#define WIP_FLAG         0x01     /* write in progress(wip)flag */
//WIP位置1,表示芯片正处于编程/擦除/写状态
//When WIP bit sets to 1, means the device is busy in program/erase/write status register progress

#define DUMMY_BYTE       0xA5

#define  SFLASH_ID       0xC84015  //Flash的ID为0xC84015
#define SPI_FLASH_PAGE_SIZE    0x100 //GD25Qxx每页有256个字节

union GD32_UINT32_DATA_TYPE
{
	u8 b[4];
	//b[3]和Uint32_Data的高8位值相等;
	//b[0]和Uint32_Data的低8位值相等;
  uint32_t Uint32_Data;
};

#define Flash_Write_Buffer_Size  SPI_FLASH_PAGE_SIZE
#define Flash_Read_Buffer_Size   SPI_FLASH_PAGE_SIZE
extern uint8_t  Flash_Write_Buffer[Flash_Write_Buffer_Size];
extern uint8_t  Flash_Read_Buffer[Flash_Read_Buffer_Size];

extern void GD25Qxx_Init(void);
#endif

 

  • 6
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
gd25q128是一款常见的串行闪存芯片,广泛应用于各种电子设备中。它的主要特点是容量大、读写速度快以及稳定性高。为了能够充分发挥gd25q128的功能,需要安装相应的驱动程序gd25q128的驱动程序可以通过厂家官方网站下载获取。在下载驱动程序之前,首先要确定操作系统的版本和架构(32位或64位),以确保下载的驱动程序与操作系统兼容。一旦确定了正确的驱动程序版本,就可以下载并解压驱动文件。 安装gd25q128驱动程序的步骤如下: 1. 连接gd25q128芯片至电脑。使用串行接口SPI)或者USB适配器连接芯片与电脑。 2. 打开设备管理器。在Windows操作系统中,可以通过控制面板或者右键点击“我的电脑”选择“属性”来打开设备管理器。 3. 找到闪存芯片设备。在设备管理器的列表中,找到与gd25q128相关的闪存芯片设备。 4. 右键点击闪存芯片设备,选择“更新驱动程序”。 5. 选择“浏览计算机以查找驱动程序软件”选项。 6. 在新的窗口中选择驱动程序所在文件夹。 7. 点击“下一步”进行驱动程序安装。 8. 等待驱动程序安装完成,系统将会自动识别并加载gd25q128闪存芯片。 安装完成之后,电脑即可正常使用gd25q128芯片进行读取和写入操作。确保驱动程序的安装和更新可以提高gd25q128的性能和稳定性,并确保电脑与gd25q128芯片之间的通信无误。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值