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