From 667c2c5a2de26a92ee1c2360565203e48a371ea6 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Sun, 30 Sep 2012 14:41:22 -0700 Subject: [PATCH] Added verify during write. It seems to mostly work except when the chip is completely removed from the SIMM -- in that case, the verification still passes for some reason. I'm still debugging this one. Maybe the data I had just written is still essentially on the bus because of the floating pins and it reads it too fast? Maybe turning on pull-ups would help with that? --- external_mem.c | 61 +++++++++++++++++++++++++++++++++++++++-- external_mem.h | 4 ++- programmer_protocol.h | 12 ++++++-- usb_serial/usb_serial.c | 35 +++++++++++++++++++---- 4 files changed, 101 insertions(+), 11 deletions(-) diff --git a/external_mem.c b/external_mem.c index 15ce360..56a749c 100644 --- a/external_mem.c +++ b/external_mem.c @@ -336,12 +336,69 @@ void ExternalMem_WriteByteToChips(uint32_t address, uint32_t data, uint8_t chips ExternalMem_WaitCompletion(chipsMask); } -void ExternalMem_Write(uint32_t startAddress, uint32_t *buf, uint32_t len, uint8_t chipsMask) +uint8_t ExternalMem_Write(uint32_t startAddress, uint32_t *buf, uint32_t len, uint8_t chipsMask, bool doVerify) { + // Use a mask so we don't worry about chips we don't want to talk with + uint32_t mask = ExternalMem_MaskForChips(chipsMask); + while (len--) { - ExternalMem_WriteByteToChips(startAddress++, *buf++, chipsMask); + ExternalMem_WriteByteToChips(startAddress, *buf, chipsMask); + if (doVerify) + { + #define VERIFY_EXTRA_READ_TRIES 2 + + // Read back the word we just wrote to make sure it's OK... + uint32_t readback = ExternalMem_ReadCycle(startAddress) & mask; + if (readback != (*buf & mask)) + { + // We found a failure, but don't despair yet. Let's try reading + // two more times in case it a fluke of the data toggle polling + // algorithm. + bool secondFailureFound = false; + int try = 0; + + while ((try < VERIFY_EXTRA_READ_TRIES) && !secondFailureFound) + { + try++; + readback = ExternalMem_ReadCycle(startAddress) & mask; + if (readback != (*buf & mask)) + { + secondFailureFound = true; + } + } + + // If we re-read it a few times and it failed again, the write + // failed. Otherwise, it was probably just the data toggle + // polling algorithm giving us fits. + if (secondFailureFound) + { + uint8_t failMask = 0; + // Figure out the mask of chip(s) acting up + int x; + for (x = 0; x < NUM_CHIPS; x++) + { + // Is this a chip we're working with? + if (chipsMask & (1 << x)) + { + if ((readback & (0xFFUL << (8*x))) != (*buf & (0xFFUL << (8*x)))) + { + // Save the failMask in reverse order + // (so bit 0 refers to IC1 rather than IC4) + failMask |= (1 << ((NUM_CHIPS - 1) - x)); + } + } + } + return failMask; + } + } + } + + startAddress++; + buf++; } + + return 0; } void ExternalMem_SetChipType(ChipType type) diff --git a/external_mem.h b/external_mem.h index 4eda3ac..ba19daa 100644 --- a/external_mem.h +++ b/external_mem.h @@ -101,7 +101,9 @@ void ExternalMem_WriteByteToChips(uint32_t address, uint32_t data, uint8_t chips // Writes a buffer to the requested chips simultaneously // (each uint32_t contains an 8-bit portion for each chip, // which is masked away if the chip is not requested) -void ExternalMem_Write(uint32_t startAddress, uint32_t *buf, uint32_t len, uint8_t chipsMask); +// returns a mask representing the chips acting up (if requested with doVerify) +// or 0 on success (or if verification was not requested) +uint8_t ExternalMem_Write(uint32_t startAddress, uint32_t *buf, uint32_t len, uint8_t chipsMask, bool doVerify); // Tells which flash command protocol to use void ExternalMem_SetChipType(ChipType type); diff --git a/programmer_protocol.h b/programmer_protocol.h index f357101..4dd6fb0 100644 --- a/programmer_protocol.h +++ b/programmer_protocol.h @@ -43,7 +43,9 @@ typedef enum ProgrammerCommand EnterProgrammer, BootloaderEraseAndWriteProgram, SetSIMMTypePLCC32_2MB, - SetSIMMTypeLarger + SetSIMMTypeLarger, + SetVerifyWhileWriting, + SetNoVerifyWhileWriting } ProgrammerCommand; // After a command is sent, the programmer will always respond with @@ -115,6 +117,11 @@ typedef enum ComputerReadReply // this one, and then the computer can send a 1024-byte chunk of data. // The programmer will reply with ProgrammerWriteOK, and then the cycle can // continue (the computer sends another request in this enum) +// +// If the programmer was asked to verify while writing and a verification error +// occurs, it will respond with ProgrammerWriteVerificationError ORed with a bit +// mask of chips that are acting up (so it could be 0x81 if IC1 is acting up, +// for example) typedef enum ComputerWriteRequest { ComputerWriteMore = 0, @@ -126,7 +133,8 @@ typedef enum ProgrammerWriteReply { ProgrammerWriteOK = 0, ProgrammerWriteError, - ProgrammerWriteConfirmCancel + ProgrammerWriteConfirmCancel, + ProgrammerWriteVerificationError = 0x80 /* high bit signifies verify error, low bits signify which chips are bad */ } ProgrammerWriteReply; // ------------------------- BOOTLOADER STATE PROTOCOL ------------------------- diff --git a/usb_serial/usb_serial.c b/usb_serial/usb_serial.c index a294eb5..57e11af 100644 --- a/usb_serial/usb_serial.c +++ b/usb_serial/usb_serial.c @@ -29,6 +29,7 @@ #include "../tests/simm_electrical_test.h" #include "../programmer_protocol.h" #include "../led.h" +#include #define MAX_CHIP_SIZE (2UL * 1024UL * 1024UL) #define READ_CHUNK_SIZE_BYTES 1024UL @@ -64,6 +65,7 @@ static uint32_t readLength; static uint8_t readLengthByteIndex; static int16_t writePosInChunk = -1; static uint16_t curWriteIndex = 0; +static bool verifyDuringWrite = false; // Private functions void USBSerial_HandleWaitingForCommandByte(uint8_t byte); @@ -217,6 +219,14 @@ void USBSerial_HandleWaitingForCommandByte(uint8_t byte) ExternalMem_SetChipType(ChipType8Bit16BitData_16MBitSize); SendByte(CommandReplyOK); break; + case SetVerifyWhileWriting: + verifyDuringWrite = true; + SendByte(CommandReplyOK); + break; + case SetNoVerifyWhileWriting: + verifyDuringWrite = false; + SendByte(CommandReplyOK); + break; // We don't know what this command is, so reply that it was invalid. default: SendByte(CommandReplyInvalid); @@ -373,12 +383,25 @@ void USBSerial_HandleWritingChipsByte(uint8_t byte) { // We filled up the chunk, write it out and confirm it, then wait // for the next command from the computer! - ExternalMem_Write(curWriteIndex * (WRITE_CHUNK_SIZE_BYTES/4), - chunks.writeChunks, WRITE_CHUNK_SIZE_BYTES/4, ALL_CHIPS); - SendByte(ProgrammerWriteOK); - curWriteIndex++; - writePosInChunk = -1; - LED_Toggle(); + uint8_t writeResult = ExternalMem_Write(curWriteIndex * (WRITE_CHUNK_SIZE_BYTES/4), + chunks.writeChunks, WRITE_CHUNK_SIZE_BYTES/4, ALL_CHIPS, verifyDuringWrite); + + // But if we asked to verify, make sure it came out OK. + if (verifyDuringWrite && (writeResult != 0)) + { + // Uh oh -- verification failure. + LED_Off(); + // Send the fail bit along with a mask of failed chips. + SendByte(ProgrammerWriteVerificationError | writeResult); + curCommandState = WaitingForCommand; + } + else + { + SendByte(ProgrammerWriteOK); + curWriteIndex++; + writePosInChunk = -1; + LED_Toggle(); + } } } }