📄 ssiflash.c
字号:
}
//*****************************************************************************
//
// Sends a command to the flash to enable program and erase operations.
//
// This function sends a write enable instruction to the serial flash device
// in preparation for an erase or program operation.
//
// \return Returns \b true if the instruction was accepted or \b false if
// write operations could not be enabled.
//
//*****************************************************************************
static tBoolean
SSIFlashWriteEnable(void)
{
tBoolean bRetcode;
unsigned char ucStatus;
//
// Issue the instruction we need to write-enable the chip.
//
SSIFlashInstructionWrite(INSTR_WRITE_ENABLE, (unsigned char *)0, 0);
SSIFlashInstructionEnd();
//
// Wait for the instruction to complete.
//
bRetcode = SSIFlashIdleWait(MAX_BUSY_POLL_IDLE);
//
// Is the flash idle?
//
if(bRetcode)
{
//
// Read the status and make sure that the Write Enable Latch bit is
// set (indicating that a write may proceed).
//
ucStatus = SSIFlashStatusGet();
bRetcode = (ucStatus & STATUS_WRITE_ENABLE_LATCH) ? true : false;
}
//
// Tell the caller how we got on.
//
return(bRetcode);
}
//*****************************************************************************
//
//! Initializes the SSI port and determines if the serial flash is available.
//!
//! This function must be called prior to any other function offered by the
//! serial flash driver. It configures the SSI port to run in mode 0 at 10MHz
//! and queries the ID of the serial flash device to ensure that it is
//! available.
//!
//! \note SSI0 is shared between the serial flash and the SDCard on the
//! dk-lm3s9b96 boards. Two independent GPIOs are used to provide chip selects
//! for these two devices but care must be taken when using both in a single
//! application, especially during initialization of the SDCard when the SSI
//! clock rate must initially be set to 400KHz and later increased. Since both
//! the SSI flash and SDCard drivers initialize the SSI peripheral, application
//! writers must be aware of the possible contention and ensure that they do
//! not allow the possibility of two different interrupt handlers or execution
//! threads from attempting to access both peripherals simultaneously.
//!
//! This driver assumes that the application is aware of the possibility of
//! contention and has been designed with this in mind. Other than disabling
//! the SDCard when an attempt is made to access the serial flash, no code is
//! included here to arbitrate for ownership of the SSI peripheral.
//!
//! \return Returns \b true on success or \b false if an error is reported or
//! the expected serial flash device is not present.
//!
//*****************************************************************************
tBoolean
SSIFlashInit(void)
{
tBoolean bRetcode;
unsigned char ucManufacturer, ucDevice;
//
// Enable the peripherals used to drive the SDC on SSI.
//
SysCtlPeripheralEnable(SFLASH_SSI_PERIPH);
SysCtlPeripheralEnable(SFLASH_SSI_GPIO_PERIPH);
//
// Configure the appropriate pins to be SSI instead of GPIO. The CS
// is configured as GPIO since this board has 2 devices connected to
// SSI0 and each uses a separate CS.
//
GPIOPinTypeSSI(SFLASH_SSI_GPIO_BASE, SFLASH_SSI_PINS);
GPIOPinTypeGPIOOutput(SFLASH_CS_BASE, SFLASH_CS_PIN);
GPIOPinTypeGPIOOutput(SDCARD_CS_BASE, SDCARD_CS_PIN);
GPIOPadConfigSet(SFLASH_SSI_GPIO_BASE, SFLASH_SSI_PINS, GPIO_STRENGTH_4MA,
GPIO_PIN_TYPE_STD_WPU);
//
// Deassert the SSI0 chip selects for both the SD card and serial flash
//
GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, SDCARD_CS_PIN);
GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, SFLASH_CS_PIN);
//
// Configure the SSI0 port for 10MHz operation
//
SSIConfigSetExpClk(SFLASH_SSI_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, 10000000, 8);
SSIEnable(SFLASH_SSI_BASE);
//
// Wait for the device to be ready to receive an instruction.
//
bRetcode = SSIFlashIdleWait(MAX_BUSY_POLL_IDLE);
//
// If the device didn't report that it was idle, assume it isn't there
// and return an error.
//
if(!bRetcode)
{
return(bRetcode);
}
//
// Read the device ID and check to see that it is one we recognize.
//
bRetcode = SSIFlashIDGet(&ucManufacturer, &ucDevice);
if(!bRetcode || (ucManufacturer != MANUFACTURER_WINBOND) ||
(ucDevice != DEVICE_ID_W25X80A))
{
//
// This is not a device we recognize so return an error.
//
return(false);
}
else
{
//
// All is well.
//
return(true);
}
}
//*****************************************************************************
//
//! Determines if the serial flash is able to accept a new instruction.
//!
//! This function reads the serial flash status register and determines whether
//! or not the device is currently busy. No new instruction may be issued to
//! the device if it is busy.
//!
//! \return Returns \b true if the device is busy and unable to receive a new
//! instruction or \b false if it is idle.
//
//*****************************************************************************
tBoolean
SSIFlashIsBusy(void)
{
unsigned char ucStatus;
//
// Get the flash status.
//
ucStatus = SSIFlashStatusGet();
//
// Is the busy bit set?
//
return((ucStatus & STATUS_BUSY) ? true : false);
}
//*****************************************************************************
//
//! Returns the manufacturer and device IDs for the attached serial flash.
//!
//! \param pucManufacturer points to storage which will be written with the
//! manufacturer ID of the attached serial flash device.
//! \param pucDevice points to storage which will be written with the device
//! ID of the attached serial flash device.
//!
//! This function may be used to determine the manufacturer and device IDs
//! of the attached serial flash device.
//!
//! \return Returns \b true on success or \b false on failure.
//
//*****************************************************************************
tBoolean
SSIFlashIDGet(unsigned char *pucManufacturer, unsigned char *pucDevice)
{
tBoolean bRetcode;
unsigned char pucBuffer[3];
//
// Wait for the flash to be idle.
//
bRetcode = SSIFlashIdleWait(MAX_BUSY_POLL_IDLE);
//
// If the device is not idle, return an error.
//
if(!bRetcode)
{
return(bRetcode);
}
//
// Now perform the instruction we need to read the IDs.
//
pucBuffer[0] = 0;
pucBuffer[1] = 0;
pucBuffer[2] = 0;
SSIFlashInstructionWrite(INSTR_MAN_DEV_ID, pucBuffer, 3);
SSIFlashInstructionRead(pucBuffer, 2);
SSIFlashInstructionEnd();
//
// Copy the returned IDs into the caller's storage.
//
*pucManufacturer = pucBuffer[0];
*pucDevice = pucBuffer[1];
//
// Tell the caller everything went well.
//
return(true);
}
//*****************************************************************************
//
//! Returns the size of a sector for this device.
//!
//! This function returns the size of an erasable sector for the serial flash
//! device. All addresses passed to SSIFlashSectorErase() must be aligned on
//! a sector boundary.
//!
//! \return Returns the number of bytes in a sector.
//
//*****************************************************************************
unsigned long
SSIFlashSectorSizeGet(void)
{
//
// This device supports 4KB sectors.
//
return(W25X80A_SECTOR_SIZE);
}
//*****************************************************************************
//
//! Returns the size of a block for this device.
//!
//! This function returns the size of an erasable block for the serial flash
//! device. All addresses passed to SSIFlashBlockErase() must be aligned on
//! a block boundary.
//!
//! \return Returns the number of bytes in a block.
//
//*****************************************************************************
unsigned long
SSIFlashBlockSizeGet(void)
{
//
// This device support 64KB blocks.
//
return(W25X80A_BLOCK_SIZE);
}
//*****************************************************************************
//
//! Returns the total amount of storage offered by this device.
//!
//! This function returns the size of the programmable area provided by the
//! attached SSI flash device.
//!
//! \return Returns the number of bytes in the device.
//
//*****************************************************************************
unsigned long
SSIFlashChipSizeGet(void)
{
//
// This device is 1MB in size.
//
return(W25X80A_CHIP_SIZE);
}
//*****************************************************************************
//
//! Erases the contents of a single serial flash sector.
//!
//! \param ulAddress is the start address of the sector which is to be erased.
//! This value must be an integer multiple of the sector size returned
//! by SSIFlashSectorSizeGet().
//! \param bSync should be set to \b true if the function is to block until
//! the erase operation is complete or \b false to return immediately after
//! the operation is started.
//!
//! This function erases a single sector of the serial flash, returning all
//! bytes in that sector to their erased value of 0xFF. The sector size and,
//! hence, start address granularity can be determined by calling
//! SSIFlashSectorSizeGet().
//!
//! The function may be synchronous (\e bSync set to \b true) or asynchronous
//! (\e bSync set to \b false). If asynchronous, the caller is responsible for
//! ensuring that no further serial flash operations are requested until the
//! erase operation has completed. The state of the device may be queried by
//! calling SSIFlashIsBusy().
//!
//! Three options for erasing are provided. Sectors provide the smallest
//! erase granularity, blocks provide the option of erasing a larger section of
//! the device in one operation and, finally, the whole device may be erased
//! in a single operation via SSIFlashChipErase().
//!
//! \note This operation will take between 120mS and 250mS to complete. If the
//! \e bSync parameter is set to \b true, this function will, therefore, not
//! not return for a significant period of time.
//!
//! \return Returns \b true on success or \b false on failure.
//
//*****************************************************************************
tBoolean
SSIFlashSectorErase(unsigned long ulAddress, tBoolean bSync)
{
tBoolean bRetcode;
unsigned char pucBuffer[3];
//
// Make sure the address passed is aligned correctly.
//
if(ulAddress & (W25X80A_SECTOR_SIZE - 1))
{
//
// Oops - it's not on a sector boundary so fail the call.
//
return(false);
}
//
// Wait for the flash to be idle.
//
bRetcode = SSIFlashIdleWait(0);
//
// If the device is not idle, return an error.
//
if(!bRetcode)
{
return(bRetcode);
}
//
// Enable write operations.
//
bRetcode = SSIFlashWriteEnable();
//
// If write operations could not be enabled, return the error.
//
if(!bRetcode)
{
return(bRetcode);
}
//
// Now perform the instruction we need to erase the sector.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -