基于stm32 hal库实现驱动flash w25q16

w25qxx.h:

#ifndef __W25QXX_H
#define __W25QXX_H

#include "spi.h"
#include "stdint.h"
#define W25QXX_SPI hspi1
#define CS_GPIO_Port  GPIOA
#define CS_Pin        GPIO_PIN_4
// Configuration
typedef struct W25QxObject{
        SPI_HandleTypeDef spi;         
        uint32_t timeout;
}W25QxObjectType;

// 仅支持 128Mbits 及以下,因为 256Mbits 及以上的是 4字节地址

// 1 Block = 16 sectors;1 sector = 16 pages = 4KB

#define W25Q64_BLOCK_COUNT 128
#define W25Q128_BLOCK_COUNT 256

#define W25QXX_FLASH_SIZE 0x1000000 /* 64 MBits => 8MBytes */
#define W25QXX_BLOCK_SIZE 0x10000   /* 64K Bytes */
#define W25QXX_SECTOR_SIZE 0x1000   /* 4k Bytes */
#define W25QXX_PAGE_SIZE 0x100      /* 256 bytes */

#define W25QXX_DUMMY_CYCLES_READ 4
#define W25QXX_DUMMY_CYCLES_READ_QUAD 10

#define W25QXX_BULK_ERASE_MAX_TIME 250000
#define W25QXX_SECTOR_ERASE_MAX_TIME 3000
#define W25QXX_SUBSECTOR_ERASE_MAX_TIME 800
#define W25Qx_TIMEOUT_VALUE 1000

// Commands

/* Reset Operations */
#define RESET_ENABLE_CMD 0x66
#define RESET_MEMORY_CMD 0x99

#define ENTER_QPI_MODE_CMD 0x38
#define EXIT_QPI_MODE_CMD 0xFF

/* Identification Operations */
#define READ_ID_CMD 0x90
#define DUAL_READ_ID_CMD 0x92
#define QUAD_READ_ID_CMD 0x94
#define READ_JEDEC_ID_CMD 0x9F

/* Read Operations */
#define READ_CMD 0x03
#define FAST_READ_CMD 0x0B
#define DUAL_OUT_FAST_READ_CMD 0x3B
#define DUAL_INOUT_FAST_READ_CMD 0xBB
#define QUAD_OUT_FAST_READ_CMD 0x6B
#define QUAD_INOUT_FAST_READ_CMD 0xEB

/* Write Operations */
#define WRITE_ENABLE_CMD 0x06
#define WRITE_DISABLE_CMD 0x04

/* Register Operations */
#define READ_STATUS_REG1_CMD 0x05
#define READ_STATUS_REG2_CMD 0x35
#define READ_STATUS_REG3_CMD 0x15

#define WRITE_STATUS_REG1_CMD 0x01
#define WRITE_STATUS_REG2_CMD 0x31
#define WRITE_STATUS_REG3_CMD 0x11

/* Program Operations */
#define PAGE_PROG_CMD 0x02
#define QUAD_INPUT_PAGE_PROG_CMD 0x32

/* Erase Operations */
#define SECTOR_ERASE_CMD 0x20
#define CHIP_ERASE_CMD 0xC7

#define PROG_ERASE_RESUME_CMD 0x7A
#define PROG_ERASE_SUSPEND_CMD 0x75

/* Flag Status Register */
#define W25QXX_FSR_BUSY 0x01 /*!< busy */
#define W25QXX_FSR_WREN 0x02 /*!< write enable */
#define W25QXX_FSR_QE 0x02   /*!< quad enable */

#define w25qxx_enable()  HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET)
#define w25qxx_disable() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET)

#define W25Qx_OK 0x00
#define W25Qx_ERROR 0x01
#define W25Qx_BUSY 0x02
#define W25Qx_TIMEOUT 0x03

uint8_t         w25qxx_init(W25QxObjectType *w25qx,SPI_HandleTypeDef spi,uint32_t timeout);
static void     w25qxx_reset(W25QxObjectType *w25qx);
static uint8_t  w25qxx_getstatus(W25QxObjectType *w25qx);
uint8_t         w25qxx_write_enable(W25QxObjectType *w25qx);
void            w25qxx_read_id(W25QxObjectType *w25qx,uint8_t* ID);
uint8_t         w25qxx_read(W25QxObjectType *w25qx,uint8_t* pData, uint32_t ReadAddr, uint32_t Size);
uint8_t         w25qxx_write(W25QxObjectType *w25qx,uint8_t* pData, uint32_t WriteAddr, uint32_t Size);
uint8_t         w25qxx_erase_block(W25QxObjectType *w25qx,uint32_t Address);
uint8_t         w25qxx_erase_chip(W25QxObjectType *w25qx);

#endif /* __W25QXX_H */

w25qxx.c:

#include "w25qxx.h"

HAL_StatusTypeDef w25qxx_transmit(W25QxObjectType *w25qx,uint16_t data,uint16_t len){
        return HAL_SPI_Transmit(
                &w25qx->spi, data, len, w25qx->timeout);
}

HAL_StatusTypeDef w25qxx_receive(W25QxObjectType *w25qx,uint8_t* buff,uint16_t len){

        return HAL_SPI_Receive(
                &w25qx->spi, buff, len, w25qx->timeout);
}
/**
 * @brief
 *
 *
 *@retval None*/
uint8_t w25qxx_init(W25QxObjectType *w25qx,SPI_HandleTypeDef spi,uint32_t timeout){

        w25qx->spi     = spi;         
        w25qx->timeout = timeout;

        /* Reset W25Qxxx */
        w25qxx_reset(w25qx);

        return w25qxx_getstatus(w25qx);
}

/**
 * @brief  This function reset the W25Qx.
 * @retval None
 */
static void w25qxx_reset(W25QxObjectType *w25qx){
        uint8_t cmd[2] = {RESET_ENABLE_CMD, RESET_MEMORY_CMD};

        w25qxx_enable();
        /* Send the reset command */
        w25qxx_transmit(w25qx,cmd,2);   
        w25qxx_disable();
}

/**
 * @brief  Reads current status of the W25QXX.
 * @retval W25QXX memory status
 */
static uint8_t w25qxx_getstatus(W25QxObjectType *w25qx){
        uint8_t cmd[] = {READ_STATUS_REG1_CMD};
        uint8_t status;

        w25qxx_enable();
        /* Send the read status command */
        w25qxx_transmit(w25qx,cmd,1);                 
        /* Reception of the data */
        w25qxx_receive(w25qx,&status,1);
        w25qxx_disable();

        /* Check the value of the register */
        if ((status & W25QXX_FSR_BUSY) != 0)
                return W25Qx_BUSY;
        else 
                return W25Qx_OK;
    
}

/**
 * @brief  This function send a Write Enable and wait it is effective.
 * @retval None
 */
uint8_t w25qxx_write_enable(W25QxObjectType *w25qx){
        uint8_t  cmd[]     = {WRITE_ENABLE_CMD};
        uint32_t tickstart = HAL_GetTick();

        /*Select the FLASH: Chip Select low */
        w25qxx_enable();
        /* Send the read ID command */
        w25qxx_transmit(w25qx,cmd,1);
        /*Deselect the FLASH: Chip Select high */
        w25qxx_disable();

        /* Wait the end of Flash writing */
        while (w25qxx_getstatus(w25qx) == W25Qx_BUSY)
                ;
        {
                /* Check for the Timeout */
                if ((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE) {
                        return W25Qx_TIMEOUT;
                }
        }

        return W25Qx_OK;
}

/**
 * @brief  Read Manufacture/Device ID.
 * @param  return value address
 * @retval None
 */
void w25qxx_read_id(W25QxObjectType *w25qx,uint8_t* ID){

        uint8_t cmd[4] = {READ_ID_CMD, 0x00, 0x00, 0x00};

        w25qxx_enable();
        /* Send the read ID command */
        w25qxx_transmit(w25qx,cmd,4);
        /* Reception of the data */
        w25qxx_receive(w25qx,ID,2);

        w25qxx_disable();
}

/**
 * @brief  Reads an amount of data from the QSPI memory.
 * @param  pData: Pointer to data to be read
 * @param  ReadAddr: Read start address
 * @param  Size: Size of data to read
 * @retval QSPI memory status
 */
uint8_t w25qxx_read(W25QxObjectType *w25qx,uint8_t* pData, uint32_t ReadAddr, uint32_t Size){

        uint8_t cmd[4];

        /* Configure the command */
        cmd[0] = READ_CMD;
        cmd[1] = (uint8_t)(ReadAddr >> 16);
        cmd[2] = (uint8_t)(ReadAddr >> 8);
        cmd[3] = (uint8_t)(ReadAddr);

        w25qxx_enable();
        /* Send the read ID command */
        w25qxx_transmit(w25qx,cmd,4);
        /* Reception of the data */
        if (w25qxx_receive(w25qx, pData, Size) != HAL_OK) 
        return W25Qx_ERROR;

        w25qxx_disable();
        return W25Qx_OK;
}

/**
 * @brief  Writes an amount of data to the QSPI memory.
 * @param  pData: Pointer to data to be written
 * @param  WriteAddr: Write start address
 * @param  Size: Size of data to write,No more than 256byte.
 * @retval QSPI memory status
 */
uint8_t w25qxx_write(W25QxObjectType *w25qx,uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{
        uint8_t  cmd[4];
        uint32_t end_addr, current_size, current_addr;
        uint32_t tickstart = HAL_GetTick();

        /* Calculation of the size between the write address and the end of the page */
        current_addr = 0;

        while (current_addr <= WriteAddr) {
        current_addr += W25QXX_PAGE_SIZE;
        }
        current_size = current_addr - WriteAddr;

        /* Check if the size of the data is less than the remaining place in the page */
        if (current_size > Size) {
        current_size = Size;
        }

        /* Initialize the adress variables */
        current_addr = WriteAddr;
        end_addr     = WriteAddr + Size;

        /* Perform the write page by page */
        do {
                /* Configure the command */
                cmd[0] = PAGE_PROG_CMD;
                cmd[1] = (uint8_t)(current_addr >> 16);
                cmd[2] = (uint8_t)(current_addr >> 8);
                cmd[3] = (uint8_t)(current_addr);

                /* Enable write operations */
                w25qxx_write_enable(w25qx);

                w25qxx_enable();
                /* Send the command */
                if (w25qxx_transmit(w25qx, cmd, 4) != HAL_OK)
                        return W25Qx_ERROR;
                

                /* Transmission of the data */
                if (w25qxx_transmit(w25qx, pData, current_size) != HAL_OK)
                        return W25Qx_ERROR;
                
                w25qxx_disable();
                /* Wait the end of Flash writing */
                while (w25qxx_getstatus(w25qx) == W25Qx_BUSY)
                        ;
                {
                        /* Check for the Timeout */
                        if ((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE)
                                return W25Qx_TIMEOUT;
                        
                }

                /* Update the address and size variables for next page programming */
                current_addr += current_size;
                pData += current_size;
                current_size = ((current_addr + W25QXX_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25QXX_PAGE_SIZE;
        } while (current_addr < end_addr);

        return W25Qx_OK;
}

/**
 * @brief  Erases the specified block of the QSPI memory.
 * @param  BlockAddress: Block address to erase
 * @retval QSPI memory status
 */
uint8_t w25qxx_erase_block(W25QxObjectType *w25qx,uint32_t Address)
{
    uint8_t  cmd[4];
    uint32_t tickstart = HAL_GetTick();
    cmd[0]             = SECTOR_ERASE_CMD;
    cmd[1]             = (uint8_t)(Address >> 16);
    cmd[2]             = (uint8_t)(Address >> 8);
    cmd[3]             = (uint8_t)(Address);

    /* Enable write operations */
    w25qxx_write_enable(w25qx);

    /*Select the FLASH: Chip Select low */
    w25qxx_enable();
    /* Send the read ID command */
    w25qxx_transmit(w25qx, cmd, 4);
    /*Deselect the FLASH: Chip Select high */
    w25qxx_disable();

    /* Wait the end of Flash writing */
    while (w25qxx_getstatus(w25qx) == W25Qx_BUSY)
        ;
    {
        /* Check for the Timeout */
        if ((HAL_GetTick() - tickstart) > W25QXX_SECTOR_ERASE_MAX_TIME) {
            return W25Qx_TIMEOUT;
        }
    }
    return W25Qx_OK;
}

/**
 * @brief  Erases the entire QSPI memory.This function will take a very long time.
 * @retval QSPI memory status
 */
uint8_t w25qxx_erase_chip(W25QxObjectType *w25qx)
{
    uint8_t  cmd[4];
    uint32_t tickstart = HAL_GetTick();
    cmd[0]             = SECTOR_ERASE_CMD;

    /* Enable write operations */
    w25qxx_write_enable(w25qx);

    /*Select the FLASH: Chip Select low */
    w25qxx_enable();
    /* Send the read ID command */
    w25qxx_transmit(w25qx, cmd, 1);
    /*Deselect the FLASH: Chip Select high */
    w25qxx_disable();

    /* Wait the end of Flash writing */
    while (w25qxx_getstatus(w25qx) != W25Qx_BUSY)
        ;
    {
        /* Check for the Timeout */
        if ((HAL_GetTick() - tickstart) > W25QXX_BULK_ERASE_MAX_TIME) {
            return W25Qx_TIMEOUT;
        }
    }
    return W25Qx_OK;
}

test.c:

void spi_flash_test(W25QxObjectType *w25qx)
{
        uint8_t  ID[4];
        uint8_t  i;
        uint8_t  wData[0x100];
        uint8_t  rData[0x100];
	printf("SPI-W25Qxxx Example \n");

        /*1- Read the device ID */
        w25qxx_init(w25qx,hspi1,W25Qx_TIMEOUT_VALUE);

        w25qxx_read_id(w25qx,ID);

        printf("W25Qxxx ID is : ");
        for (i = 0; i < 2; i++) {
                printf("0x%02X ", ID[i]);
        }
        printf("\n");

        /* 2- Erase */
        if (w25qxx_erase_block(w25qx,0) == W25Qx_OK)
                printf(" SPI Erase Block ok\n");
        else
                Error_Handler();

        /*-2- Written to the flash */
        /* fill buffer */
        for (i = 0; i < 0x100; i++) {
                wData[i] = i;
                rData[i] = 0;
        }

        if (w25qxx_write(w25qx,wData, 0x00, 0x100) == W25Qx_OK)
                printf(" SPI Write ok\n");
        else
                Error_Handler();

        /* 3- Read the flash */
        if (w25qxx_read(w25qx,rData, 0x00, 0x100) == W25Qx_OK)
                printf(" SPI Read ok\n");
        else
                Error_Handler();

        printf("SPI Read Data : \n");

        for (i = 0; i < 0x100; i++)
                printf("0x%02X  ", rData[i]);
        printf("\n");

        /* 4- check date */
        if (memcmp(wData, rData, 0x100) == 0){
                printf(" W25Q64FV SPI Test OK\n");
        }
        else{
                printf(" W25Q64FV SPI Test False\n");
        }

        return ;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值