Added untested support for erasing a specific portion of the SIMM

(in 256 KB increments). Won't be able to test it until I implement it in
the control software as well, but I think it should work.
This commit is contained in:
Doug Brown 2012-10-15 22:00:29 -07:00
parent d484d126e5
commit 7bbfc23c1a
4 changed files with 197 additions and 2 deletions

View File

@ -256,6 +256,91 @@ void ExternalMem_EraseChips(uint8_t chipsMask)
ExternalMem_WaitCompletion(chipsMask);
}
bool ExternalMem_EraseSectors(uint32_t address, uint32_t length, uint8_t chipsMask)
{
bool result = false;
// Make sure the area requested to be erased is on 64 KB boundaries.
// True, the 2 MB SIMM doesn't require 64 KB boundaries, but I'm going to
// keep it to 2 MB boundaries to simplify everything.
#define ERASABLE_SECTOR_SIZE (64*1024UL*1024UL)
if ((address & ERASABLE_SECTOR_SIZE) ||
(length & ERASABLE_SECTOR_SIZE))
{
return false;
}
// We're good to go. Let's do it.
if (curChipType == ChipType8BitData_4MBitSize)
{
#define SECTOR_SIZE_4MBIT (128)
// This chip sucks because you have to erase each sector with its own
// complete erase unlock command, which can take a while. At least
// individual erase operations are much faster on this chip...
while (length)
{
// Start the erase command
ExternalMem_UnlockChips(chipsMask);
ExternalMem_WriteCycle(0x55555555UL, 0x80808080UL);
ExternalMem_UnlockChips(chipsMask);
// Now provide a sector address, but only one. Then the whole
// unlock sequence has to be done again after this sector is done.
ExternalMem_WriteCycle(address, 0x20202020UL);
address += SECTOR_SIZE_4MBIT;
length -= SECTOR_SIZE_4MBIT;
// Wait for completion of this individual erase operation before
// we can start a new erase operation.
ExternalMem_WaitCompletion(chipsMask);
}
result = true;
}
else if (curChipType == ChipType8Bit16BitData_16MBitSize)
{
#define SECTOR_SIZE_16MBIT (64*1024UL*1024UL)
// This chip is nicer because it can take all the sector addresses at
// once and then do the final erase operation in one fell swoop.
// Start the erase command
ExternalMem_UnlockChips(chipsMask);
ExternalMem_WriteCycle(0xAAAAAAAAUL, 0x80808080UL);
ExternalMem_UnlockChips(chipsMask);
// Now provide as many sector addresses as needed to erase.
// The first address is a bit of a special case because the boot sector
// actually has finer granularity for sector sizes.
if (address == 0)
{
ExternalMem_WriteCycle(0x00000000UL, 0x30303030UL);
ExternalMem_WriteCycle(0x00004000UL, 0x30303030UL);
ExternalMem_WriteCycle(0x00006000UL, 0x30303030UL);
ExternalMem_WriteCycle(0x00008000UL, 0x30303030UL);
address += SECTOR_SIZE_16MBIT;
length -= SECTOR_SIZE_16MBIT;
}
// The remaining sectors can use a more generic algorithm
while (length)
{
ExternalMem_WriteCycle(address, 0x30303030UL);
address += SECTOR_SIZE_16MBIT;
length -= SECTOR_SIZE_16MBIT;
}
// Wait for completion of the entire erase operation
ExternalMem_WaitCompletion(chipsMask);
result = true;
}
return result;
}
void ExternalMem_WaitCompletion(uint8_t chipsMask)
{
// Mark the chips not requested as already completed,
@ -408,3 +493,8 @@ void ExternalMem_SetChipType(ChipType type)
{
curChipType = type;
}
ChipType ExternalMem_GetChipType(void)
{
return curChipType;
}

View File

@ -94,6 +94,7 @@ void ExternalMem_IdentifyChips(struct ChipID *chips);
// Erases the chips requested
void ExternalMem_EraseChips(uint8_t chipsMask);
bool ExternalMem_EraseSectors(uint32_t address, uint32_t length, uint8_t chipsMask);
// Writes a byte to the chips requested at the specified address
void ExternalMem_WriteByteToChips(uint32_t address, uint32_t data, uint8_t chipsMask);
@ -107,5 +108,6 @@ uint8_t ExternalMem_Write(uint32_t startAddress, uint32_t *buf, uint32_t len, ui
// Tells which flash command protocol to use
void ExternalMem_SetChipType(ChipType type);
ChipType ExternalMem_GetChipType(void);
#endif /* EXTERNAL_MEM_H_ */

View File

@ -45,7 +45,8 @@ typedef enum ProgrammerCommand
SetSIMMTypePLCC32_2MB,
SetSIMMTypeLarger,
SetVerifyWhileWriting,
SetNoVerifyWhileWriting
SetNoVerifyWhileWriting,
ErasePortion
} ProgrammerCommand;
// After a command is sent, the programmer will always respond with
@ -166,4 +167,21 @@ typedef enum ComputerBootloaderEraseWriteRequest
ComputerBootloaderCancel
} ComputerBootloaderEraseWriteRequest;
// ------------------------- ERASE PORTION OF CHIP PROTOCOL -------------------------
// If the command is ErasePortion, the programmer will reply CommandReplyOK.
// Next, the program will send the beginning position to erase as a 4-byte little
// endian integer, followed by the length to erase as a 4-byte little endian
// integer. The programmer will reply with ProgrammerErasePortionOK to signify
// that the erase is beginning, followed by ProgrammerErasePortionFinished when
// everything is done.
// The length and position to erase must be on 256 KB boundaries and shouldn't
// go past the end of the selected type of chip. If any error occurs, it will
// reply with ProgrammerErasePortionError instead.
typedef enum ProgrammerErasePortionOfChipReply
{
ProgrammerErasePortionOK = 0,
ProgrammerErasePortionError,
ProgrammerErasePortionFinished
};
#endif /* PROGRAMMER_PROTOCOL_H_ */

View File

@ -34,6 +34,7 @@
#define MAX_CHIP_SIZE (2UL * 1024UL * 1024UL)
#define READ_CHUNK_SIZE_BYTES 1024UL
#define WRITE_CHUNK_SIZE_BYTES 1024UL
#define ERASE_SECTOR_SIZE_BYTES (256UL * 1024UL)
#if ((READ_CHUNK_SIZE_BYTES % 4) != 0)
#error Read chunk size should be a multiple of 4 bytes
#endif
@ -54,7 +55,8 @@ typedef enum ProgrammerCommandState
ReadingChipsReadLength,
ReadingChips,
ReadingChipsUnableSendError,
WritingChips
WritingChips,
ErasePortionReadingPosLength
} ProgrammerCommandState;
static ProgrammerCommandState curCommandState = WaitingForCommand;
@ -66,6 +68,8 @@ static uint8_t readLengthByteIndex;
static int16_t writePosInChunk = -1;
static uint16_t curWriteIndex = 0;
static bool verifyDuringWrite = false;
static uint32_t erasePosition;
static uint32_t eraseLength;
// Private functions
void USBSerial_HandleWaitingForCommandByte(uint8_t byte);
@ -74,6 +78,7 @@ void USBSerial_HandleReadingChipsReadLengthByte(uint8_t byte);
void USBSerial_SendReadDataChunk(void);
void USBSerial_HandleWritingChipsByte(uint8_t byte);
void USBSerial_ElectricalTest_Fail_Handler(uint8_t index1, uint8_t index2);
void USBSerial_HandleErasePortionReadPosLengthByte(uint8_t byte);
// Read/write to USB serial macros -- easier than retyping
// CDC_Device_XXX(&VirtualSerial_CDC_Interface...) every time
@ -107,6 +112,9 @@ void USBSerial_Check(void)
case WritingChips:
USBSerial_HandleWritingChipsByte((uint8_t)recvByte);
break;
case ErasePortionReadingPosLength:
USBSerial_HandleErasePortionReadPosLengthByte((uint8_t)recvByte);
break;
}
}
}
@ -227,6 +235,13 @@ void USBSerial_HandleWaitingForCommandByte(uint8_t byte)
verifyDuringWrite = false;
SendByte(CommandReplyOK);
break;
case ErasePortion:
readLengthByteIndex = 0;
eraseLength = 0;
erasePosition = 0;
curCommandState = ErasePortionReadingPosLength;
SendByte(CommandReplyOK);
break;
// We don't know what this command is, so reply that it was invalid.
default:
SendByte(CommandReplyInvalid);
@ -416,6 +431,76 @@ void USBSerial_ElectricalTest_Fail_Handler(uint8_t index1, uint8_t index2)
SendByte(index2);
}
// If we're figuring out the position/length to erase, parse it here.
void USBSerial_HandleErasePortionReadPosLengthByte(uint8_t byte)
{
// Read in the position and length to erase
if (readLengthByteIndex < 4)
{
erasePosition |= (((uint32_t)byte) << (8*readLengthByteIndex));
}
else
{
eraseLength |= (((uint32_t)byte) << (8*(readLengthByteIndex - 4)));
}
if (++readLengthByteIndex >= 8)
{
ChipType chipType = ExternalMem_GetChipType();
bool eraseSuccess = false;
// Ensure they are both within limits of sector size erasure
if (((erasePosition & ERASE_SECTOR_SIZE_BYTES) == 0) &&
((eraseLength & ERASE_SECTOR_SIZE_BYTES) == 0))
{
uint32_t boundary = eraseLength + erasePosition;
// Ensure they are within the limits of the chip size too
if (chipType == ChipType8BitData_4MBitSize)
{
if (boundary <= (2 * 1024UL * 1024UL))
{
// OK! We're erasing certain sectors of a 2 MB SIMM.
SendByte(ProgrammerErasePortionOK);
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
if (ExternalMem_EraseSectors(erasePosition/NUM_CHIPS,
eraseLength/NUM_CHIPS, ALL_CHIPS))
{
eraseSuccess = true;
}
}
}
else if (chipType == ChipType8Bit16BitData_16MBitSize)
{
if (boundary <= (8 * 1024UL * 1024UL))
{
// OK! We're erasing certain sectors of an 8 MB SIMM.
SendByte(ProgrammerErasePortionOK);
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
if (ExternalMem_EraseSectors(erasePosition/NUM_CHIPS,
eraseLength/NUM_CHIPS, ALL_CHIPS))
{
eraseSuccess = true;
}
}
}
}
if (eraseSuccess)
{
// Not on a sector boundary for erase position and/or length
SendByte(ProgrammerErasePortionFinished);
curCommandState = WaitingForCommand;
}
else
{
// Not on a sector boundary for erase position and/or length
SendByte(ProgrammerErasePortionError);
curCommandState = WaitingForCommand;
}
}
}
// LUFA event handler for when the USB configuration changes.
void EVENT_USB_Device_ConfigurationChanged(void)
{