BY25Q32的读写(BY AT32F415)

本文介绍BY25Q32 SPI闪存芯片的初始化配置、读写操作及扇区擦除等核心功能实现。通过具体C语言代码示例,展示了如何利用SPI接口进行数据交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

### STM32 MicroSD Card Read Write Example Code Tutorial For implementing read/write operations on a microSD card using an STM32 microcontroller, one can utilize the FatFS file system library which is widely supported by STM32CubeMX. This approach simplifies handling files and directories stored on FAT-formatted media like SD cards. #### Preparing Hardware Connections Ensure that hardware connections between the STM32 board and the microSD module are correct. Typically this involves SPI communication lines such as MOSI, MISO, SCK, along with CS (Chip Select). The specific pin assignments depend upon the chosen STM32 model and its available peripherals[^1]. #### Initializing Project Using STM32CubeMX To streamline configuration tasks including clock settings, peripheral initialization, interrupt setup etc., use STM32CubeMX to generate initial project code. During generation select support for external storage devices through FatFs middleware option provided within CubeMX interface. #### Sample Initialization Functionality Below demonstrates how to initialize necessary components before performing any I/O operation: ```c #include "ff.h" FATFS fs; /* File system object */ FIL fil; /* File object */ void MX_FatFs_Init(void){ FRESULT res; // Register & mount volume. res = f_mount(&fs, "", 0); } ``` This snippet registers and mounts the filesystem onto your application context allowing further access commands against mounted volumes. #### Writing Data To A File On MicroSD Card Here's an example of writing data into a text file located at root directory level: ```c UINT byteswritten; res = f_open(&fil, "test.txt", FA_CREATE_ALWAYS | FA_WRITE); if(res == FR_OK){ const char *text_to_write = "Hello from STM32!"; res = f_write(&fil, text_to_write , strlen(text_to_write), &byteswritten); if(byteswritten != strlen(text_to_write)){ // Handle error here... } } else { // Error opening file... } // Close after done. f_close(&fil); ``` In case where `FR_OK` isn't returned during open call or written byte count doesn't match expected length then appropriate errors should be handled accordingly. #### Reading From An Existing Text File Reading back content previously saved works similarly but uses different flags when calling `f_open()` function alongside reading functions instead: ```c char buffer[50]; UINT bytesread; res = f_open(&fil,"test.txt",FA_READ); if(res==FR_OK){ UINT br; while(1){ res=f_read(&fil,&buffer,sizeof(buffer)-1,&br); if(res!=FR_OK || br==0) break; buffer[br]='\0'; // Null terminate string HAL_UART_Transmit(&huart2,(uint8_t*)buffer,strlen(buffer),HAL_MAX_DELAY); } }else{ // Deal with failure to open existing file... } f_close(&fil); ``` After successfully opening target file in read mode loop until end-of-file reached sending received chunks over UART port for demonstration purposes only. --related questions-- 1. What considerations must be taken regarding power supply requirements for stable operation of microSD modules? 2. How does changing SPI frequency impact performance characteristics related to speed versus reliability tradeoffs? 3. Can you explain methods used to ensure integrity checks on files being transferred across unreliable mediums? 4. Are there alternative libraries besides FatFS suitable for embedded systems targeting resource-constrained environments?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值