⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssiflash.c

📁 基于TI公司Cortex-M3的uart超级通信开发
💻 C
📖 第 1 页 / 共 3 页
字号:
//*****************************************************************************
//
// ssiflash.c - Driver for the Winbond Serial Flash on the dk-lm3s9b96 board.
//
// Copyright (c) 2009 Luminary Micro, Inc.  All rights reserved.
// Software License Agreement
// 
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
// exclusively on LMI's microcontroller products.
// 
// The software is owned by LMI and/or its suppliers, and is protected under
// applicable copyright laws.  All rights are reserved.  You may not combine
// this software with "viral" open-source software in order to form a larger
// program.  Any use in violation of the foregoing restrictions may subject
// the user to criminal sanctions under applicable laws, as well as to civil
// liability for the breach of the terms and conditions of this license.
// 
// THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 5228 of the DK-LM3S9B96 Firmware Package.
//
//*****************************************************************************

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "ssiflash.h"
#include "ssi_hw.h"

//*****************************************************************************
//
//! \addtogroup ssiflash_api
//! @{
//
//*****************************************************************************

//*****************************************************************************
//
// The rate of the SSI clock and derived values.
//
//*****************************************************************************
#define SSI_CLK_RATE            10000000
#define SSI_CLKS_PER_MS         (SSI_CLK_RATE / 1000)
#define STATUS_READS_PER_MS     (SSI_CLKS_PER_MS / 16)

//*****************************************************************************
//
// Labels for the instructions supported by the Winbond part.
//
//*****************************************************************************
#define INSTR_WRITE_ENABLE      0x06
#define INSTR_WRITE_DISABLE     0x04
#define INSTR_READ_STATUS       0x05
#define INSTR_WRITE_STATUS      0x01
#define INSTR_READ_DATA         0x03
#define INSTR_FAST_READ         0x0B
#define INSTR_PAGE_PROGRAM      0x02
#define INSTR_BLOCK_ERASE       0xD8
#define INSTR_SECTOR_ERASE      0x20
#define INSTR_CHIP_ERASE        0xC7
#define INSTR_POWER_DOWN        0xB9
#define INSTR_POWER_UP          0xAB
#define INSTR_MAN_DEV_ID        0x90
#define INSTR_JEDEC_ID          0x9F

//*****************************************************************************
//
// Status register bit definitions
//
//*****************************************************************************
#define STATUS_BUSY                 0x01
#define STATUS_WRITE_ENABLE_LATCH   0x02
#define STATUS_BLOCK_PROTECT_0      0x04
#define STATUS_BLOCK_PROTECT_1      0x08
#define STATUS_BLOCK_PROTECT_2      0x10
#define STATUS_TOP_BOTTON_WP        0x20
#define STATUS_REGISTER_PROTECT     0x80

//*****************************************************************************
//
// Manufacturer and device IDs that we expect to see.
//
//*****************************************************************************
#define MANUFACTURER_WINBOND    0xEF
#define DEVICE_ID_W25X80A       0x13

//*****************************************************************************
//
// Block, sector, page and chip sizes for the supported device.  Some of the
// code here assumes (reasonably) that these are all powers of two.
//
//*****************************************************************************
#define W25X80A_BLOCK_SIZE      (64 * 1024)
#define W25X80A_SECTOR_SIZE     (4 * 1024)
#define W25X80A_PAGE_SIZE       256
#define W25X80A_CHIP_SIZE       (1024 * 1024)

//*****************************************************************************
//
// The number of times we query the device status waiting for it to be idle
// after various operations have taken place and during initialization.
//
//*****************************************************************************
#define MAX_BUSY_POLL_IDLE              100
#define MAX_BUSY_POLL_ERASE_SECTOR      (STATUS_READS_PER_MS * 250)
#define MAX_BUSY_POLL_ERASE_BLOCK       (STATUS_READS_PER_MS * 1000)
#define MAX_BUSY_POLL_ERASE_CHIP        (STATUS_READS_PER_MS * 10000)
#define MAX_BUSY_POLL_PROGRAM_PAGE      (STATUS_READS_PER_MS * 3)

//*****************************************************************************
//
// Reads the serial flash device status register.
//
// This function reads the serial flash status register and returns the value.
//
// \return Returns the current contents of the serial flash device status
// register.
//
//*****************************************************************************
static unsigned char
SSIFlashStatusGet(void)
{
    unsigned long ulStatus;

    //
    // Assert the chip select for the serial flash.
    //
    GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, 0);

    //
    // Send the status register read instruction and read back a dummy byte.
    //
    SSIDataPut(SFLASH_SSI_BASE, INSTR_READ_STATUS);
    SSIDataGet(SFLASH_SSI_BASE, &ulStatus);

    //
    // Write a dummy byte then read back the actual status.
    //
    SSIDataPut(SFLASH_SSI_BASE, 0xFF);
    SSIDataGet(SFLASH_SSI_BASE, &ulStatus);

    //
    // Deassert the chip select for the serial flash.
    //
    GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, SFLASH_CS_PIN);

    //
    // Return the status read.
    //
    return((unsigned char)(ulStatus & 0xFF));
}

//*****************************************************************************
//
// Empties the SSI receive FIFO of any data it may contain.
//
// \return None.
//
//*****************************************************************************
static void
SSIFlashRxFlush(void)
{
    unsigned long ulDummy;

    while(SSIDataGetNonBlocking(SFLASH_SSI_BASE, &ulDummy))
    {
        //
        // Spin until there is no more data to read.
        //
    }
}

//*****************************************************************************
//
// Write an instruction to the serial flash.
//
// \param ucInstruction is the instruction code that is to be sent.
// \param ucData is a pointer to optional instruction data that will be sent
// following the instruction code provided in \e ucInstruction.  This parameter
// is ignored if \e usLen is 0.
// \param usLen is the length of the optional instruction data.
//
// This function writes an instruction to the serial flash along with any
// provided instruction-specific data.  On return, the flash chip select
// remains asserted allowing an immediate call to SSIFlashInstructionRead().
// To finish an instruction and deassert the chip select, a call must be made
// to SSIFlashInstructionEnd() after this call.
//
// It is assumed that the caller has already determined that the serial flash
// is not busy and is able to accept a new instruction at this point.
//
//*****************************************************************************
static void
SSIFlashInstructionWrite(unsigned char ucInstruction, unsigned char *ucData,
                         unsigned short usLen)
{
    unsigned long ulLoop;
    unsigned long ulDummy;

    //
    // Throw away any data that may be sitting in the receive FIFO.
    //
    SSIFlashRxFlush();

    //
    // Deassert the select for the SD card (in case it was previously asserted).
    //
    GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, SDCARD_CS_PIN);

    //
    // Assert the chip select for the serial flash.
    //
    GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, 0);

    //
    // Send the instruction byte and receive a dummy byte to pace the
    // transaction.
    //
    SSIDataPut(SFLASH_SSI_BASE, ucInstruction);
    SSIDataGet(SFLASH_SSI_BASE, &ulDummy);

    //
    // Send any optional bytes.
    //
    for(ulLoop = 0; ulLoop < (unsigned long)usLen; ulLoop++)
    {
        SSIDataPut(SFLASH_SSI_BASE, ucData[ulLoop]);
        SSIDataGet(SFLASH_SSI_BASE, &ulDummy);
    }
}

//*****************************************************************************
//
// Write additional data following an instruction to the serial flash.
//
// \param ucData is a pointer to data that will be sent to the device.
// \param usLen is the length of the data to send.
//
// This function writes a block of data to the serial flash device.  Typically
// this will be data to be written to a flash page.
//
// It is assumed that SSIFlashInstructionWrite() has previously been called to
// set the device chip select and send the initial instruction to the device.
//
//*****************************************************************************
static void
SSIFlashInstructionDataWrite(unsigned char *ucData, unsigned short usLen)
{
    unsigned long ulLoop;
    unsigned long ulDummy;

    //
    // Send the data to the device.
    //
    for(ulLoop = 0; ulLoop < (unsigned long)usLen; ulLoop++)
    {
        SSIDataPut(SFLASH_SSI_BASE, ucData[ulLoop]);
        SSIDataGet(SFLASH_SSI_BASE, &ulDummy);
    }
}

//*****************************************************************************
//
// Read data from the serial flash following the write portion of an
// instruction.
//
// \param ucData is a pointer to storage for the bytes read from the serial
// flash.
// \param ulLen is the number of bytes to read from the device.
//
// This function read a given number of bytes from the device.  It is assumed
// that the flash chip select is already asserted on entry and that an
// instruction has previously been written using a call to
// SSIFlashInstructionWrite().
//
//*****************************************************************************
static void
SSIFlashInstructionRead(unsigned char *ucData, unsigned long ulLen)
{
    unsigned long ulData;
    unsigned long ulLoop;

    //
    // For each requested byte...
    //
    for(ulLoop = 0; ulLoop < ulLen; ulLoop++)
    {
        //
        // Write dummy data.
        //
        SSIDataPut(SFLASH_SSI_BASE, 0xFF);

        //
        // Get a byte back from the SSI controller.
        //
        SSIDataGet(SFLASH_SSI_BASE, &ulData); /* read data frm rx fifo */

        //
        // Stash it in the caller's buffer.
        //
        ucData[ulLoop] = (unsigned char)(ulData & 0xFF);
    }
}

//*****************************************************************************
//
// Finish an instruction by deasserting the serial flash chip select.
//
// This function must be called following SSIFlashInstructionWrite() and,
// depending upon the instruction, SSIFlashInstructionRead() to complete the
// instruction by deasserting the chip select to the serial flash device.
//
//*****************************************************************************
static void
SSIFlashInstructionEnd(void)
{
    //
    // Pull CS high to deassert it and complete the previous instruction.
    //
    GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, SFLASH_CS_PIN);
}

//*****************************************************************************
//
// Waits for the flash device to report that it is idle.
//
// \param ulMaxRetries is the maximum number of times the serial flash device
// should be polled before we give up and report an error.  If this value is
// 0, the function continues polling indefinitely.
//
// This function polls the serial flash device and returns when either the
// maximum number of polling attempts is reached or the device reports that it
// is no longer busy.
//
// \return Returns \e true if the device reports that it is idle before the
// specified number of polling attempts is exceeded or \e false otherwise.
//
//*****************************************************************************
static tBoolean
SSIFlashIdleWait(unsigned long ulMaxRetries)
{
    unsigned long ulDelay;
    tBoolean bBusy;

    //
    // Wait for the device to be ready to receive an instruction.
    //
    ulDelay = ulMaxRetries;

    do
    {
        bBusy = SSIFlashIsBusy();

        //
        // Increment our counter.  If we have waited too long, assume the
        // device is not present.
        //
        ulDelay--;
    }
    while(bBusy && (ulDelay || !ulMaxRetries));

    //
    // If we get here and we're still busy, we need to return false to indicate
    // a problem.
    //
    return(!bBusy);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -