BY25Q32的读写(BY AT32F415)

在写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)
    {
    }
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值