LPC2129 - Flash as EEPROM, garbage output

Started by sieg...@gmail.com December 13, 2013
I'm creating a data logger using the LPC2129 and need to store configuration data, even when my SD card might become corrupted.

I'm trying to use code from AN11008, using FLASH as EEPROM, modified to store a single, short text file. I think my read functions work properly, but writing to EEPROM seems to fail. I'm having trouble wrapping my head around all of this, so I would really appreciate any help. All functions return properly, but the output is garbled relative to the data input. I know that the read function works, but I am not sure about the storage.

It had been throwing a few errors re: casting pointers in the SetVariableRecord function, but I think I've solved all of those. In testing, I continue to get garbage output files.

Thank you for your help in advance.

/ **** Main file **** /

// Read SD into EEPROM if not already there
f_open(&SD_file_handle, SD_CONFIG_FILENAME, FA_READ);
size = f_size(&SD_file_handle);
debug_printf("* SD writing to EEPROM\n");
f_read(&SD_file_handle, buffer, size, (UINT *)&bytesWritten);
FLASH_WriteConfig(buffer, size);

If the file is not present, we recreate it and populate it:

// If file not found, read EEPROM, create the file, and populate it
if ( !FLASH_GetConfig(buffer, CONFIG_FILE_SIZE) ) { } // Error
else { // Create file and populate
f_write(&SD_file_handle, buffer, CONFIG_FILE_SIZE, (UINT *) &bytesWritten);

/ **** Modified Flash_NVOL - Refers to methods in iap.c**** /
// No sector addressing, since we only want to store one (long) variable
#define SECTOR_NUM 17 //last sector
#define SECTOR_STARTADDR 0x0003E000
#define SECTOR_SIZE 0x2000 //8KB
#define CONFIG_FILE_SIZE 126
typedef struct _Variable_Record {
uint8_t Flags; // flags indicate variable status
uint8_t Data[CONFIG_FILE_SIZE]; // variable data
uint8_t Checksum; // 2's complement checksum of id and data
}__attribute__((packed)) VARIABLE_RECORD;

// Write configuration record
int FLASH_WriteConfig(uint8_t *pValue, uint8_t Size) {
uint8_t i;
// check if the config size is acceptable
if (Size > CONFIG_FILE_SIZE || Size == 0)
return -1;
// get current value for config and compare with new value
pConfig = FindLastValidConfig();
if (pConfig != NULL) {
for (i = 0; i < Size; i++) {
if (pValue[i] != pConfig->Data[i])
// if new value is the same as the current value then no need to store
// the new value
if (i == Size)
return 0;
// get an empty location to store the new config
pConfig = FindFirstEmptyRecord();
if (pConfig == NULL)
return -2;
// assemble variable record
VarRec.Flags = 0xAA;
for (i = 0; i < Size; i++)
VarRec.Data[i] = pValue[i];
VarRec.Checksum = ComputeChecksum(&VarRec);
// store record in sector
if (SetVariableRecord(&VarRec, pConfig->Data)!=0)
return -3;
return 0;

// Store the record
static int SetVariableRecord(VARIABLE_RECORD *pVarSrc, uint8_t *pDst) {
uint16_t Byte;
uint8_t Buffer[512];
//uint16_t Offset = pDst - SECTOR_STARTADDR;
unsigned long Result, tmp;
uint16_t i;
for (i = 0; i < 512; i++)
Buffer[i] = 0xFF;
// Get offset of destination address in 512 byte segment
pTmpVarRec = (VARIABLE_RECORD *) (Buffer + ((int)pDst % 512));
// copy variable record
*pTmpVarRec = *pVarSrc;
for (Byte = 0; Byte < CONFIG_FILE_SIZE; Byte++)
pTmpVarRec->Data[Byte] = pVarSrc->Data[Byte];
// prepare sector
Result = IAP_PrepareSec(SECTOR_NUM, SECTOR_NUM);
if (Result != IAP_STA_CMD_SUCCESS)
return -1;
// write to sector
Result = IAP_CopyRAMToFlash(*pDst - ((int)*pDst % 512), *Buffer, 512);
if (Result != IAP_STA_CMD_SUCCESS)
return -2;
// verify
Result = IAP_Compare(*pDst, *pVarSrc->Data, sizeof(VARIABLE_RECORD), &tmp);
if (Result != IAP_STA_CMD_SUCCESS)
return -3;
return 0;

// Read the record
int FLASH_GetConfig(uint8_t *pDst, uint8_t Size) {
uint8_t i;
// check if the destination buffer size is acceptable
return -1;
// get current value for config
pConfig = FindLastValidConfig();
if (pConfig == NULL)
return -2;
for (i = 0; i < CONFIG_FILE_SIZE; i++)
pDst[i] = pConfig->Data[i];
return 0;

/ **** Methods in iap.c, tested good with other code **** /
extern unsigned long IAP_PrepareSec(unsigned long StartSecNum, unsigned long EndSecNum);
extern unsigned long IAP_CopyRAMToFlash(unsigned long dst, unsigned long src, unsigned long number);
extern unsigned long IAP_EraseSec(unsigned long StartSecNum, unsigned long EndSecNum);
extern unsigned long IAP_BlankChkSec(unsigned long StartSecNum, unsigned long EndSecNum, unsigned long * pResult);
extern unsigned long IAP_ReadParID(unsigned long * PartID);
extern unsigned long IAP_ReadBootVer(unsigned long * MajorVer, unsigned long * MinorVer);
extern unsigned long IAP_Compare(unsigned long dst, unsigned long src, unsigned long number, unsigned long *offset);
extern void IAP_ReinvokeISP(void);

An Engineer's Guide to the LPC2100 Series