#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推挽输出,输出速度最大为50MHzgpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);//SPI0_MOSI:配置GPIOA7的工作模式为复用功能IO推挽输出,输出速度最大为50MHzgpio_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=1spi_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时钟预分频器值为8spi_init_struct.endian               = SPI_ENDIAN_MSB;           //先发送最高位spi_init(SPI0, &spi_init_struct);//使用spi_init_struct结构参数初始化SPI0spi_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控制寄存器0reg=(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~bit23spi_flash_send_byte( addr.b[1] );     //发送扇区地址的bit8~bit15spi_flash_send_byte( addr.b[0] );     //发送扇区地址的bit0~bit7SPI0_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~bit23spi_flash_send_byte( addr.b[1] );   //发送页地址的bit8~bit15spi_flash_send_byte( addr.b[0] );   //发送页地址的bit0~bit7while(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_SIZEspi_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~bit23spi_flash_send_byte( addr.b[1] );//发送地址的bit8~bit15spi_flash_send_byte( addr.b[0] );//发送地址的bit0~bit7while(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~bit23ret_Data.b[1]=spi_flash_send_byte(DUMMY_BYTE);   //读取数据的bit8~bit15ret_Data.b[0]=spi_flash_send_byte(DUMMY_BYTE);   //读取数据的bit0~bit7SPI0_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的IDif(SFLASH_ID == flash_id){for(i=0; i<SPI_FLASH_PAGE_SIZE;i++){Flash_Write_Buffer[i]=i;}spi_flash_sector_erase(0x000000);//擦除扇区,其首地址为0x000000spi_flash_buffer_write(Flash_Write_Buffer,0x000000,SPI_FLASH_PAGE_SIZE);//将Flash_Write_Buffer[SPI_FLASH_PAGE_SIZE]写入Flash,其首地址为0x000000spi_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个字节相同,则返回1if(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

使用GD32F10x的SPI0接口读写GD25Q128相关推荐

  1. A40I工控主板(SBC-X40I)USB接口读写测试

    SBC-X40I产品特性 采用Allwinner公司Cortex-A7四核A40i处理器,运行最高速度为1.2GHZ: 支持Mali-400MP2 GPU,支持OpenGL ES 2.0 / Open ...

  2. 仿真通过AXI_lite接口读写寄存器时axi_awready信号无法拉高的一种原因

    本人初次接触AXI接口,在了解了AXI接口读写时序后,计划使用AXI接口对BRAM进行读写,并进行仿真测试,AXI接口有三种类型:AXI4.AXI-lite.AXI-stream,我一开始成功对AXI ...

  3. c8051f c语言编程,C8051F SPI接口读写c程序

    C8051F SPI接口读写c程序 #ifndef SPI_H #define SPI_H #define  WREN   0x06 #define  READ   0x03 #define  WRI ...

  4. STM32 通过USB接口读写挂载的SD卡(支持fatfs文件系统)

    通过USB接口读写挂载的SD卡 HAL库 标准库 本文以STM32F407为例分别用HAL库(STM32CubeMX)和标准库实现SD卡对fatfs支持,以及通过USB接口读写SD卡.首先看电路连接: ...

  5. 100脚的STM32F103VE单片机通过FSMC接口读写DS12C887时钟芯片中的寄存器

    STM32F1系列的单片机本身自带的RTC实时时钟外设只是一个单纯的32位计数器,没有分立为年月日.小时.分钟.秒等寄存器,使用起来不是很方便.这时可以考虑使用外部RTC芯片,比如使用SPI接口的双向 ...

  6. Marvell交换机芯片SMI接口读写协议

    Marvell的88E6XXX系列交换机芯片基本都提供SMI(Serial Management Interface)接口. SMI接口使用2线串行通信,一个MDC提供时钟,一个MDIO为双向数据引脚 ...

  7. C#如何使用REST接口读写数据

    原网站:http://www.codeproject.com/Tips/497123/How-to-make-REST-requests-with-Csharp 一个类,我们拷贝下来直接调用就行: u ...

  8. 用VC++实现USB接口读写数据的程序

    使用一个GUIDguidHID_1查找并打开一个USB设备 extern "C" int PASCAL SearchUSBDevice() {HANDLE hUsb;int nCo ...

  9. sdio接口_单片机基础 —— 使用SDMMC接口读写SD卡数据

    本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件SDMMC外设读取SD卡数据. 1. 准备工作 硬件准备 开发板 首先需要准备一个开发板,这里我准备的是STM32L4 ...

最新文章

  1. web.xml 配置 加载顺序
  2. c语言的语言扩展的数据类型,C语言之数据类型
  3. PAT甲级题目翻译+答案 AcWing(进位制)
  4. Java AIO 编程
  5. 再谈二叉树(二叉树概念,二叉树的性质,二叉树的存储结构)
  6. 苹果七绕过基带激活2020_苹果漏洞,可跳过苹果激活锁
  7. 阿里云发布首个流式存储与播放解决方案
  8. Star Schema完全参考手册读书笔记八
  9. 挑选回文串(二进制枚举)
  10. Java-虚拟机-垃圾收集器/垃圾收集算法/GCROOT根
  11. k8s学习:kubeconfig文件详解
  12. 【WebGIS毕业设计】(一)前言、开题与参考文献
  13. DroidCam连接教程+资源
  14. matlab里面的xlsread函数坏,MATLAB的xlsread坏了
  15. java docx4j 合并word_如何使用docx4j在word中添加合并字段?
  16. 魔金(5)——手雷、爱神锁、牛头扣
  17. Java 字段在内存中存储是大端还是小端
  18. SQL 实验项目5_触发器
  19. Javaweb 快速入门之jsp基本语法表单提交方式request对象
  20. 中国铁建信息化顶层设计项目 ---- 相关后续消息

热门文章

  1. 啃k8s之安全机制与RBAC使用方法
  2. 燃气热水器打不着火水压低的解决方法(zt)
  3. 华为一、二、三面面经
  4. java从ftp上下载图片到客户端本地
  5. RHCE之搭建DNS服务器
  6. 淘宝的ITEST框架
  7. 改word文档格式技巧
  8. 美团技术团队:实例详解机器学习如何解决问题
  9. Python pandas 实现无缝衔接Bokeh
  10. js对JSON的操作