STM32 W25Q64驱动程序


这里使用STM32的LL库,用逻辑分析仪调了贼久,这里注意以下问题

1.查询BUSY位,查询一次后,必须等待2ms左右(1MS我没试过,不需要那么快) ,否则擦除全片,擦除block等,会出现马上返回busy=0x02的情况

2.erase后,不能马上read ,必须有一个小等待 (10ms)左右,不然读出来全0

 

 3.数据写入的时候只能按照Page来写入,最多一次只能写256个字节,也就是一个页的空间,写入的时候可以不从页的开始地址写入,如果一次写入字节数溢出了一个页的空间,那么多出来的会从循环到页的开始地址处覆盖原来的数据,数据手册的10.2.14节说的很明白

 

/********************************** (C) COPYRIGHT *******************************
* File Name          : dev_flash.h
* Author             : XZH
* Version            : V1.00
* Date               : 2020/07/09
* Description        : iap
*                        
*
*******************************************************************************/

#ifndef __DEV_SPI_H
#define __DEV_SPI_H

/*******************************************************************************/    
/* Include */
#include "main.h"
/*******************************************************************************/


/******************************************************************************/
/* Typedef enum */
#define     FLASH_WRITE_ENABLE_CMD          0x06
#define     FLASH_WRITE_DISABLE_CMD         0x04
#define     FLASH_READ_SR_CMD               0x05
#define     FLASH_WRITE_SR_CMD              0x01
#define     FLASH_READ_DATA                 0x03
#define     FLASH_FASTREAD_DATA             0x0b
#define     FLASH_WRITE_PAGE                0x02
#define     FLASH_ERASE_PAGE                0x81
#define     FLASH_ERASE_SECTOR              0x20
#define     FLASH_ERASE_BLOCK               0xd8
#define     FLASH_ERASE_CHIP                0xc7
#define     FLASH_POWER_DOWN                0xb9
#define     FLASH_RELEASE_POWER_DOWN        0xab
#define     FLASH_READ_DEVICE_ID            0x90
#define     FLASH_READ_JEDEC_ID             0x9f

#define     DEV_FLASH_FLASH_SIZE                        (4*1024*1024)    //  4M字节
#define        DEV_FLASH_PAGE_SIZE                            256    // 256 bytes
#define     DEV_FLASH_SECTOR_SIZE                        409// 4-Kbyte
#define        DEV_FLASH_BLOCK_SIZE                        65536    // 64-Kbyte    


#define     FLASH_CS_LOW                    LL_GPIO_ResetOutputPin( GPIOA, LL_GPIO_PIN_4 )
#define     FLASH_CS_HIGH                   LL_GPIO_SetOutputPin( GPIOA, LL_GPIO_PIN_4 )

/******************************************************************************/


/******************************************************************************/
/* Extern Variate */
/******************************************************************************/


/******************************************************************************/
/* Extern Function */
uint16_t dev_flash_read_device_id( void );
uint32_t dev_flash_read_jedec_id( void );
void dev_flash_read_bytes (uint8_t *pdata, uint32_t addr, uint16_t read_length);
void dev_flash_write_page(uint8_t *pdata, uint32_t write_addr, uint16_t write_length);
void dev_flash_write_bytes_nocheck(uint8_t *pdata, uint32_t write_addr, uint16_t write_length);
void dev_flash_erase_page(uint32_t page_num);
void dev_flash_erase_sector(uint32_t sector_num);
void dev_flash_erase_block(uint32_t block_num);
void dev_flash_erase_chip(void);
/******************************************************************************/

#endif

 

 

 

 

 

/********************************** (C) COPYRIGHT *******************************
* File Name          : dev_flash.c
* Author             : XZH
* Version            : V1.00
* Date               : 2020/07/20
* Description        : w25qxx驱动
*                        
*
*******************************************************************************/

/*******************************************************************************/    
/* Include */
#include "dev_flash.h"
/*******************************************************************************/

/*******************************************************************************/
/* Variables */
/*******************************************************************************/

/*******************************************************************************/    
/* Globle Variate */
/******************************************************************************/

/******************************************************************************/
/* Static Function  */

/*******************************************************************************
* Function Name  : dev_flash_delay
* Description    : flash驱动使用的delay 
*                  平台适配
*
* Input          : delay_time 延迟时间 注意最大只能8位这里设置了
*                  
*                
* Output         : None
* Return         : None
*******************************************************************************/ 
static void dev_flash_delay( uint8_t delay_time )
{
    LL_mDelay( delay_time );
}

/*******************************************************************************
* Function Name  : dev_flash_read_write_byte
* Description    : 全双工读写函数 平台适配
*                  平台适配
*
* Input          : tx_data 8位数据 这里注意适配一下retry超时时间,不能太短,否则会直接跳出导致数据错误
*                  
*                 
* Output         : None
* Return         : None
*******************************************************************************/ 
static uint8_t dev_flash_read_write_byte(uint8_t tx_data)
{        
    uint16_t retry=0;
    
    while (LL_SPI_IsActiveFlag_TXE( SPI1 ) == RESET) 
    {
        retry++;
        if(retry>20000)return 0;
    }
    LL_SPI_TransmitData8(SPI1,tx_data);
    retry=0;
    while (LL_SPI_IsActiveFlag_RXNE( SPI1 ) == RESET) 
    {
        retry++;
        if(retry>20000)return 0;
    }
    return (LL_SPI_ReceiveData8(SPI1));
 
}

/*******************************************************************************
* Function Name  : dev_flash_send_bytes
* Description    : 发送多个数据
*                  
*
* Input          : pdata 数据指针
*                  send_length  16位数据长度 
*                  
* Output         : None
* Return         : None
*******************************************************************************/ 
static void dev_flash_send_bytes( uint8_t *pdata, uint16_t send_length )
{
    for (uint16_t i = 0; i < send_length; i++)
    {
        dev_flash_read_write_byte(pdata[i]);
    }
}

/*******************************************************************************
* Function Name  : dev_flash_recv_bytes
* Description    : spi读取多次数据 这里发送没用数据0xff用于给时钟
*                 
*
* Input          : recv_length  16位数据长度
*                 
*                  
* Output         : pdata 读取到buf的数据指针 
* Return         : None
*******************************************************************************/ 
static void dev_flash_recv_bytes( uint8_t *pdata, uint16_t recv_length)
{

    for (uint16_t i = 0; i < recv_length; i++)
    {
         *pdata ++ = dev_flash_read_write_byte( 0xff ); 
    }   
    
}

/*******************************************************************************
* Function Name  : dev_flash_write_enable
* Description    : 写数据之前必须发写使能
*                 
*
* Input          : None
*                 
*                  
* Output         : None
* Return         : None
*******************************************************************************/ 
static void dev_flash_write_enable(void)
{
    FLASH_CS_LOW;
    
    dev_flash_read_write_byte( FLASH_WRITE_ENABLE_CMD );
    
    FLASH_CS_HIGH;
}

/*******************************************************************************
* Function Name  : dev_flash_write_disable
* Description    : 写失能
*                 
*
* Input          : None
*                 
*                  
* Output         : None
* Return         : None
*******************************************************************************/ 
static void dev_flash_write_disable(void)
{
    FLASH_CS_LOW;
    
    dev_flash_read_write_byte(FLASH_WRITE_ENABLE_CMD);
    
    FLASH_CS_HIGH;
}

/*******************************************************************************
* Function Name  : dev_flash_read_sr
* Description    : 读状态寄存器
*                 
*
* Input          : None
*                 
*                  
* Output         : None
* Return         : 8位状态寄存器
*******************************************************************************/ 
static uint8_t dev_flash_read_sr(void)
{
    uint8_t temp;

    FLASH_CS_LOW;
    
    dev_flash_read_write_byte( FLASH_READ_SR_CMD );    
    temp = dev_flash_read_write_byte( 0xff );
    
    FLASH_CS_HIGH;
    
    return temp;
}

/*******************************************************************************
* Function Name  : dev_flash_write_sr
* Description    : 写状态寄存器
*                 
*
* Input          : sr 8位状态寄存器
*                 
*                  
* Output         : None
* Return         : 
*******************************************************************************/ 
static void dev_flash_write_sr(uint8_t sr)
{
    dev_flash_write_enable();    

    FLASH_CS_LOW;

    dev_flash_read_write_byte( FLASH_WRITE_SR_CMD );
    dev_flash_read_write_byte( sr );
    
    FLASH_CS_HIGH;
    
    //dev_flash_write_disable();
}

/*******************************************************************************
* Function Name  : dev_flash_wait_nobusy
* Description    : Flash操作是否处于忙状态,判断之前的工作是否完成
*                 
*
* Input          : None
*                 
*                  
* Output         : None
* Return         : 8位状态寄存器
*******************************************************************************/ 
static void dev_flash_wait_nobusy(void)
{
    while( ( (dev_flash_read_sr() ) & 0x01) == 0x01 ) dev_flash_delay(2); //必须做一下延迟
}


/******************************************************************************/



/******************************************************************************/
/* Extern Function */

/*******************************************************************************
* Function Name  : dev_flash_read_device_id
* Description    : 读取 deviceid
*                 
*
* Input          : None
*                 
*                  
* Output         : None 
* Return         : 16位deviec_id 0xxx13 代表25q80这种8M的 0xxx14代表16M 0xxx15代表 32M 0xxx16代表 64M的 前面1字节看生产厂商
*******************************************************************************/ 
uint16_t dev_flash_read_device_id( void )
{
    uint16_t dat = 0;
  
    FLASH_CS_LOW;
    
    /* Send "RDID " instruction */
    dev_flash_read_write_byte( FLASH_READ_DEVICE_ID );                
    dev_flash_read_write_byte( 0x0 );
    dev_flash_read_write_byte( 0x0 );
    dev_flash_read_write_byte( 0x0 );    

    /* Read a byte from the FLASH */
    dat |= ( uint16_t )dev_flash_read_write_byte( 0xff ) << 8;
    /* Read a byte from the FLASH */
    dat |= dev_flash_read_write_byte( 0xff );
  

    FLASH_CS_HIGH;

    return( dat );
}

/*******************************************************************************
* Function Name  : dev_flash_read_jedec_id
* Description    : 读取 jedec id
*                 
*
* Input          : None
*                 
*                  
* Output         : None 
* Return         : 32位jedec id 前2字节为0x00 
*******************************************************************************/ 
uint32_t dev_flash_read_jedec_id( void )
{
    uint32_t dat = 0;


    FLASH_CS_LOW;                                                    
    
    dev_flash_read_write_byte( FLASH_READ_JEDEC_ID );                                    

    dat = ( uint32_t )dev_flash_read_write_byte( 0xff ) << 16;
    
    dat |= ( uint32_t )dev_flash_read_write_byte( 0xff ) << 8;
    
    dat |= dev_flash_read_write_byte( 0xff );


    FLASH_CS_HIGH;

    return( dat );
}

/*******************************************************************************
* Function Name  : dev_flash_read_bytes
* Description    : 读取数据
*                 
*
* Input          : addr 读取地址
*                  read_length 读取长度
*                  
* Output         : pdata 读取到的buf指针 
* Return         : None
*******************************************************************************/ 
void dev_flash_read_bytes (uint8_t *pdata, uint32_t addr, uint16_t read_length)
{
    uint8_t temp_buff[3] = {0};
    
    temp_buff[0] = (uint8_t)(addr >> 16);
    temp_buff[1] = (uint8_t)(addr >> 8);
    temp_buff[2] = (uint8_t)(addr >> 0);

    FLASH_CS_LOW;
    
    dev_flash_read_write_byte(FLASH_READ_DATA);    
    
    dev_flash_read_write_byte( temp_buff[0] );
    dev_flash_read_write_byte( temp_buff[1] );
    dev_flash_read_write_byte( temp_buff[2] );

    dev_flash_recv_bytes( pdata, read_length );

    FLASH_CS_HIGH;
}

/*******************************************************************************
* Function Name  : dev_flash_write_page
* Description    : 写一页 最多256字节 注意这里别越扇区了!!!不会自己检查
*                 
*
* Input          : pdata 数据
*                  addr  写入地址
*                  write_length 写入长度 

* Output         : None 
* Return         : None
*******************************************************************************/ 
void dev_flash_write_page(uint8_t *pdata, uint32_t write_addr, uint16_t write_length)
{
    
    dev_flash_write_enable();    
    
    FLASH_CS_LOW;
    
    dev_flash_read_write_byte(FLASH_WRITE_PAGE);    
    dev_flash_read_write_byte((uint8_t)(write_addr>>16));    
    dev_flash_read_write_byte((uint8_t)(write_addr>>8));
    dev_flash_read_write_byte((uint8_t)(write_addr>>0));

    dev_flash_send_bytes( pdata, write_length);
    
    FLASH_CS_HIGH;
    
    dev_flash_wait_nobusy();
    
    //dev_flash_write_disable();
    
}

/*******************************************************************************
* Function Name  : dev_flash_write_bytes_nocheck
* Description    : 写数据 自动查询当前地址 自动越扇区写入 注意这里只能写擦除过的
*                 
*
* Input          : pdata 数据
*                  write_addr  写入地址
*                  write_length 写入长度 

* Output         : None 
* Return         : None
*******************************************************************************/ 
void dev_flash_write_bytes_nocheck(uint8_t *pdata, uint32_t write_addr, uint16_t write_length)
{
    uint16_t PageByte = 256 - write_addr % 256;

    if(write_length <= PageByte)    
    {
        PageByte = write_length;
    }
    
    while(1)
    {
        dev_flash_write_page(pdata, write_addr, PageByte);
        if(write_length == PageByte)    
            break;
        else
        {
            pdata += PageByte;    
            write_addr += PageByte;    
            write_length -= PageByte;    
            if(write_length > 256)
            {
                PageByte = 256;
            }
            else
            {
                PageByte = write_length;
            }
        }
    }
}

/*******************************************************************************
* Function Name  : dev_flash_erase_page
* Description    : 擦除一页 256字节
*                 
*
* Input          : page_num 页码 注意填入的是 地址/256 
*                  
*                  

* Output         : None 
* Return         : None
*******************************************************************************/ 
void dev_flash_erase_page(uint32_t page_num)
{
    page_num *= 256;
    
    dev_flash_write_enable();

    FLASH_CS_LOW;
    
    dev_flash_read_write_byte(FLASH_ERASE_PAGE);    
    dev_flash_read_write_byte((uint8_t)(page_num>>16));    
    dev_flash_read_write_byte((uint8_t)(page_num>>8));
    dev_flash_read_write_byte((uint8_t)(page_num>>0));

    FLASH_CS_HIGH;
    
    dev_flash_wait_nobusy();    
    
    //dev_flash_write_disable();
}

/*******************************************************************************
* Function Name  : dev_flash_erase_sector
* Description    : 擦除一扇区 4K字节
*                 
*
* Input          : sector_num 扇区码 注意填入的是 地址/4096 
*                  
*                  

* Output         : None 
* Return         : None
*******************************************************************************/ 
void dev_flash_erase_sector(uint32_t sector_num)
{
    
    sector_num *= 4096;    
    
    dev_flash_write_enable();
    dev_flash_wait_nobusy();
    
    FLASH_CS_LOW;
    dev_flash_read_write_byte( FLASH_ERASE_SECTOR);
    dev_flash_read_write_byte( (uint8_t)( sector_num >> 16) );
    dev_flash_read_write_byte( (uint8_t)( sector_num >> 8)  );
    dev_flash_read_write_byte( (uint8_t) sector_num  );

    FLASH_CS_HIGH;
    
    dev_flash_wait_nobusy();
    
    //dev_flash_write_disable();
}

/*******************************************************************************
* Function Name  : dev_flash_erase_sector
* Description    : 擦除一块  64K字节
*                 
*
* Input          : sector_num 扇区码 注意填入的是 地址/65536 
*                  
*                  

* Output         : None 
* Return         : None
*******************************************************************************/ 
void dev_flash_erase_block(uint32_t block_num)
{

    
    block_num *= 65536;    
    
    dev_flash_write_enable();
    dev_flash_wait_nobusy();
    
    FLASH_CS_LOW;
    dev_flash_read_write_byte( FLASH_ERASE_BLOCK );
    dev_flash_read_write_byte( (uint8_t)(block_num >> 16) );
    dev_flash_read_write_byte( (uint8_t)(block_num >> 8) );
    dev_flash_read_write_byte( (uint8_t)(uint8_t)(block_num >> 0) );

    FLASH_CS_HIGH;
    
    dev_flash_wait_nobusy();
    
    //dev_flash_write_disable();
}

/*******************************************************************************
* Function Name  : dev_flash_erase_chip
* Description    : 整片擦除
*                 
*
* Input          : None
*                  
*                  

* Output         : None 
* Return         : None
*******************************************************************************/ 
void dev_flash_erase_chip(void)
{

    dev_flash_write_enable();    
    
    FLASH_CS_LOW;
    
    dev_flash_read_write_byte(FLASH_ERASE_CHIP);

    FLASH_CS_HIGH;
    
    dev_flash_wait_nobusy();    
    
    //dev_flash_write_disable();
}


/******************************************************************************/

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM