在写BY25Q32之前,我们需要了解一些基本知识,包括一些配置与状态指令,这些在芯片手册中都有,我也分别上传过该芯片的中文和英文版的数据手册,有需要可以下载看看(中文版是机翻,有很多错误)。当然也可以去这儿,这篇文章里详细地给出了各项指令。
然后需要注意的是,BY25Q32使用SPI进行通讯,支持模式3和另外一个我不大记得的模式,这里用到的是模式3.
代码如下:
SPI_FLASH.C
#include 'spi_flash.h'
void spiflash_init(void) //gpio及spi初始化
{
gpio_init_type gpio_initstructure;
spi_init_type spi_initstruct;
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK,TRUE);
/* software cs, pa4 as a general io to control flash cs */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pins = GPIO_PINS_4;
gpio_init(GPIOA, &gpio_initstructure);
/* sck */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pins = GPIO_PINS_5;
gpio_init(GPIOA, &gpio_initstructure);
/* miso */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
gpio_initstructure.gpio_pins = GPIO_PINS_6;
gpio_init(GPIOA, &gpio_initstructure);
/* mosi */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_pull = GPIO_PULL_UP;
gpio_initstructure.gpio_mode = GPIO_MODE_MUX;
gpio_initstructure.gpio_pins = GPIO_PINS_7;
gpio_init(GPIOA, &gpio_initstructure);
FLASH_CS_HIGH();
crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK,TRUE);
spi_default_para_init(&spi_initstruct);
spi_initstruct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
spi_initstruct.master_slave_mode = SPI_MODE_MASTER;
spi_initstruct.mclk_freq_division = SPI_MCLK_DIV_8;
spi_initstruct.first_bit_transmission = SPI_FIRST_BIT_MSB;
spi_initstruct.frame_bit_num = SPI_FRAME_8BIT;
spi_initstruct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
spi_initstruct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
spi_initstruct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
spi_init(SPI1, &spi_initstruct);
spi_enable(SPI1, TRUE);
}
void spiflash_sector_erase(uint32_t erase_adder) //擦除扇区
{
erase_adder *= SPIF_SECTOR_SIZE; /* translate sector address to byte address */
spiflash_write_enable();
spiflash_wait_busy();
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_SECTORERASE);
spiflash_bytewrite((erase_adder&0xFF0000)>>16);
spiflash_bytewrite((erase_adder&0x00FF00)>>8);
spiflash_bytewrite(erase_adder&0x0000FF);
FLASH_CS_HIGH();
spiflash_wait_busy();
}
/*操作完成后发送一个无用字节,以此判断flash内部时序是否操作完成*/
void spiflash_wait_busy(void) //等待FLASH内部时序操作完成
{
uint8_t flag = 0;
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_READSTATUSREG1);
do
{
flag = (uint8_t)spiflash_bytewrite(0xFF);
}while((flag&0x01)==1);
FLASH_CS_HIGH();
}
void spiflash_write_enable(void) //flash写入使能
{
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_WRITEENABLE);
FLASH_CS_HIGH();
}
void spiflash_write_disable(void) //flash写入失能
{
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_WRITEDISABLE);
FLASH_CS_HIGH();
}
u8 spiflash_bytewrite(u8 byte) //发送或接收一个字节
{
while(spi_i2s_flag_get(SPI1, SPI_I2S_TDBE_FLAG) == RESET);
spi_i2s_data_transmit(SPI1,byte);
while(spi_i2s_flag_get(SPI1, SPI_I2S_RDBF_FLAG) == RESET);
return spi_i2s_data_receive(SPI1);
}
void spiflash_read_data(uint32_t adder,uint8_t *pbuff,uint32_t numberbyte)
{
uint16_t i;
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_READDATA);
spiflash_bytewrite((adder&0xFF0000)>>16);
spiflash_bytewrite((adder&0x00FF00)>>8);
spiflash_bytewrite(adder&0x0000FF);
for(i=0;i<numberbyte;i++)
{
pbuff[i] = spiflash_bytewrite(0xFF);
}
FLASH_CS_HIGH();
}
/*按地址与字节长度写入一个数据*/
void spiflash_write_data(uint32_t adder,u8 *pbuffWrite,uint32_t NumByteToWrite)
{
uint16_t i;
spiflash_write_enable();
spiflash_wait_busy();
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_WRITEDATA);
spiflash_bytewrite((adder&0xFF0000)>>16);
spiflash_bytewrite((adder&0x00FF00)>>8);
spiflash_bytewrite(adder&0x0000FF);
if(NumByteToWrite > 256)
{
NumByteToWrite = 256;
}
for(i=0;i<NumByteToWrite;i++) //循环写数
spiflash_bytewrite(pbuffWrite[i]);
FLASH_CS_HIGH();
spiflash_wait_busy();
}
void spiflash_powerdown(void) //低功耗休眠
{
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_POWERDOWN);
FLASH_CS_HIGH();
}
void spiflash_wakeup(void) //休眠唤醒
{
FLASH_CS_LOW();
spiflash_bytewrite(SPIF_WAKEUP);
FLASH_CS_LOW();
}
void flash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
secpos=WriteAddr/4096; //扇区地址
secoff=WriteAddr%4096; //在扇区内的偏移
secremain=4096-secoff; //扇区剩余空间大小
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
while(1)
{
u8 BY25Q32_BUF[4096];
spiflash_read_data(secpos*4096,BY25Q32_BUF,4096);//读出整个扇区的内容
for(i=0;i<secremain;i++)//校验数据
{
if(BY25Q32_BUF[secoff+i]!=0XFF)break;//需要擦除
}
if(i<secremain)//需要擦除
{
spiflash_sector_erase(secpos*4096); //擦除这个扇区
for(i=0;i<secremain;i++) //复制
{
BY25Q32_BUF[i+secoff]=pBuffer[i];
}
spiflash_write_nocheck(BY25Q32_BUF,secpos*4096,4096);//写入整个扇区
}else spiflash_write_nocheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.
if(NumByteToWrite==secremain)break;//写入结束了
else//写入未结束
{
secpos++; //扇区地址增1
secoff=0; //偏移位置为0
pBuffer+=secremain; //指针偏移
WriteAddr+=secremain; //写地址偏移
NumByteToWrite-=secremain; //字节数递减
if(NumByteToWrite>4096)secremain=4096; //下一个扇区还是写不完
else secremain=NumByteToWrite; //下一个扇区可以写完了
}
};
}
void spiflash_write_nocheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint16_t pageremain;
pageremain=256-WriteAddr%256; //单页剩余的字节数
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
while(1)
{
spiflash_write_data(WriteAddr,pBuffer,pageremain);
if(NumByteToWrite==pageremain) break; //写入结束了
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //减去已经写入了的字节数
if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
else pageremain=NumByteToWrite; //不够256个字节了
}
};
}
spi_flash.h
#ifndef __SPI_FLASH_H
#define __SPI_FLASH_H
#include "at32f415.h"
#define FLASH_CS_HIGH() gpio_bits_set(GPIOA, GPIO_PINS_4)
#define FLASH_CS_LOW() gpio_bits_reset(GPIOA, GPIO_PINS_4)
#define SPIF_SECTOR_SIZE 4096 //扇区大小
#define SPIF_PAGE_SIZE 256 //页大小
#define SPIF_READDATA 0x03 //读取数据
#define SPIF_SECTORERASE 0x20 //扇区擦除
#define FLASH_SPI_DUMMY_BYTE 0xAB //自定义大小的dummy byte
#define SPIF_READSTATUSREG1 0x05 //读状态寄存器1
#define SPIF_WRITEENABLE 0x06 //写使能
#define SPIF_MANUFACTDEVICEID 0x9F //读设备商ID
#define SPIF_WRITEDISABLE 0x04
#define SPIF_WRITEDATA 0x02
#define SPIF_POWERDOWN 0XB9
#define SPIF_WAKEUP 0xAB
extern void spiflash_init(void);
extern void spiflash_sector_erase(uint32_t erase_addr);
extern void spiflash_wait_busy(void);
extern void spiflash_write_enable(void);
extern u8 spiflash_bytewrite(u8 byte);
extern void spiflash_write_enable(void); //写入flash使能
extern uint8_t spiflash_read_sr1(void);
extern void spiflash_read_data(uint32_t adder,uint8_t *pbuff,uint32_t numberbyte);
extern void spiflash_write_data(uint32_t adder,u8 *pbuffWrite,uint32_t numberbyte);
extern void spiflash_powerdown(void);
extern void spiflash_wakeup(void);
extern void spiflash_write_nocheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
extern void flash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
#endif
/*有一些宏定义实际并未用到*/
main.c
#include "at32f415_board.h"
#include "at32f415_clock.h"
#include "spi_flash.h"
u8 textcount[6] = {0xf1,0x01,0x01,0x45,0x23,0x39};
u8 readcount[6];
/*以上两数组仅做测试使用*/
int main()
{
system_clock_config();
at32_board_init();
spiflash_init();
spiflash_sector_erase(0x0000);
delay_ms(50);
spiflash_write_data(0,textcount,6);
delay_ms(50);
spiflash_read_data(0,readdata,6);
delay_ms(50);
/****************************************
spiflash_write_nocheck()函数可以进行跨页写入
flash_Write()一个函数即可搞定擦除写入
****************************************8*/
while(1)
{
}
}