📄 ssiflash.c
字号:
//*****************************************************************************
//
// 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 + -