c - Flash programming causes unexpectedly reset -
i'm working mcf51em256 freescale microcontroller , i've problems flash programming.
in order make software persistant i'm trying store variables in secondary flash memory recover unexpected shutdowns.
sometimes, when test work shutting down mcu, reset.
i have store struct:
// kwh or kvarh energy accumulator type typedef struct { uint32 ea_ps; // energy must stored in kwh or kvarh uint32 ea_ng; // fields must contain positive values! uint32 er_q1; uint32 er_q2; uint32 er_q3; uint32 er_q4; }kwh_energyacc32;
and these functions:
// function stores in flash given kwh_energyacc64 structure. void save_flash_kwhenergyacc(long addr, kwh_energyacc32* acc) { // kwhenergyacc struct needs 32 bytes in flash flash_burst(addr, 1, &(acc->ea_ps)); flash_burst(addr + 4, 1, &(acc->ea_ng)); flash_burst(addr + 8, 1, &(acc->er_q1)); flash_burst(addr + 12, 1, &(acc->er_q2)); flash_burst(addr + 16, 1, &(acc->er_q3)); flash_burst(addr + 20, 1, &(acc->er_q4)); }
*
// functions erase flash sector in external flash void eraseflashsector(long startaddr) { // sector size: 1 kb uint32 erasedata = 0xffffffff; flash_cmd((uint32)startaddr, (uint16)1, (uint32*)&erasedata, 0x40); }
*
// function initializes given ws_energyacc64 structure // stored values in flash. void init_flash_kwhenergyacc(long addr, kwh_energyacc32* acc) { acc->ea_ps = *(uint32*)addr; addr = addr + 4; acc->ea_ng = *(uint32*)addr; addr = addr + 4; acc->er_q1 = *(uint32*)addr; addr = addr + 4; acc->er_q2 = *(uint32*)addr; addr = addr + 4; acc->er_q3 = *(uint32*)addr; addr = addr + 4; acc->er_q4 = *(uint32*)addr; addr = addr + 4; }
*
and flash programming functions:
#define flash_mass_erase_cmd 0x41 #define flash_erase_cmd 0x40 #define flash_program_cmd 0x20 #define flash_burst_cmd 0x25 #if (system_clock/2) > 12800000 /* 12.8 mhz */ #define flash_clock (uint8)(( (system_clock/3200000) -1) | 0x40) #else #define flash_clock (unsigned char)( (system_clock/400000) -1)//<200khz #endif /* macros call function using different features */ #define flash_burst(address, size, dataptr) \ flash_cmd((uint32)address, (uint16)size, (uint32*)dataptr, flash_burst_cmd) uint8 /*far*/ flash_cmd(uint32 flashaddress, uint16 flashdatacounter, uint32 *pflashdataptr, uint8 flashcommand) { /* check see if faccerr or pviol set */ if (fstat &0x30) { /* clear flags if set*/ fstat = 0x30; } if (flashdatacounter) { { /* wait last busrt command complete */ while(!(fstat&fstat_fcbef_mask)){};/*wait until termination*/ /* write data flash*/ (*((volatile unsigned long *)(flashaddress))) = *pflashdataptr; flashaddress += 4; pflashdataptr++; /* write command */ fcmd = flashcommand; /* put fcbef @ 1 */ fstat = fstat_fcbef_mask; asm (nop); asm (nop); asm (nop); /* check if flash access error or protection violation error set */ if (fstat&0x30) { /* if so, finish function returning 1 indicate error */ return (1); } }while (--flashdatacounter); } /* wait last command complete */ while ((fstat&fstat_fccf_mask)==0){};/*wait until termination*/ /* return 0 indicate function executed ok */ return (0); }
my main program looks like:
static kwh_energyacc32 phr_abs_kwh_accstr; static long phr_abs_kwh_addr = 0x20000; static long magic_word_addr = 0x20800; main() { uint32 bad_magic_word = 0x12345678; uint32 ok_magic_word = 0x87654321; magic_word = *(uint32*)magic_word_addr; if (isfirstexecution() || (magic_word == bad_magic_word) || (magic_word == -1) { eraseflashsector(phr_abs_kwh_addr); // writes 0's in addresses of flash sector (1024 bytes) setflashsectortozero(phr_abs_kwh_addr); } init_flash_kwhenergyacc(phr_abs_kwh_addr, &phr_abs_kwh_accstr); if (testintegrity(phr_abs_kwh_accstr) == 0) { // turn on leds show message showmsgled(255, 0, 0); } while (1) { getvaluesfromsensors(&phr_abs_kwh_accstr); processvalues(&phr_abs_kwh_accstr); eraseflashsector(magic_word_addr); flash_burst(magic_word_addr, 1, &bad_magic_word); eraseflashsector(phr_abs_kwh_addr); save_flash_kwhenergyacc(phr_abs_kwh_addr, &phr_abs_kwh_accstr); eraseflashsector(magic_word_addr); flash_burst(magic_word_addr, 1, &ok_magic_word); } }
can see i'm doing wrong? why micro sometines reset when turn off de power supply test persistance? there way catch fatal exception causes reset in micro?
first thought might caused error writing flash address, during shutdown, after not able read tried use "magic word" written known location @ end of flash write check if flash write had finished , seems not problem.
edit: mcf51em256 reference manual
edit 2: memory map of micro:
edit 3:
i've included flash_clock definition in flash programming functions
i've included function check inconsistent values:
int testintegrity(kwh_energyacc32 acc) { if (acc.ea_ps == -1 || acc.ea_ng == -1 || acc.er_q1 == -1 || acc.er_q2 == -1 || acc.er_q3 == -1 || acc.er_q4 == -1) return 0; else return 1; }
now, function called after initializing values , leds never turn on.
note: (acc->ea_ps == -1) same (acc->ea_ps == 0xffffffff)
edit 4:
the code function setflashsectortozero:
void setflashsectortozero(long addr){ uint32 resetvalue = 0x00000000; int endsector = addr + 1024; while (addr <= endsector) { flash_burst(addr, 1, &resetvalue); addr = addr + 4; } }
i don't know if solved problem our suggestions, think code smaller in following way:
static kwh_energyacc32 phr_abs_kwh_accstr; static long phr_abs_kwh_addr = 0x20000; static long magic_word_addr = 0x203fc; main() { uint32 ok_magic_word = 0x87654321; magic_word = *(uint32*)magic_word_addr; if (isfirstexecution() || (magic_word != ok_magic_word)) { eraseflashsector(phr_abs_kwh_addr); // writes 0's in addresses of flash sector (1024 bytes) setflashsectortozero(phr_abs_kwh_addr); } init_flash_kwhenergyacc(phr_abs_kwh_addr, &phr_abs_kwh_accstr); if (testintegrity(phr_abs_kwh_accstr) == 0) { // turn on leds show message showmsgled(255, 0, 0); } while (1) { getvaluesfromsensors(&phr_abs_kwh_accstr); processvalues(&phr_abs_kwh_accstr); eraseflashsector(phr_abs_kwh_addr); save_flash_kwhenergyacc(phr_abs_kwh_addr, &phr_abs_kwh_accstr); flash_burst(magic_word_addr, 1, &ok_magic_word); } }
or
// kwh or kvarh energy accumulator type typedef struct { uint32 ea_ps; // energy must stored in kwh or kvarh uint32 ea_ng; // fields must contain positive values! uint32 er_q1; uint32 er_q2; uint32 er_q3; uint32 er_q4; uint32 magic_word; }kwh_energyacc32; static kwh_energyacc32 phr_abs_kwh_accstr; static long phr_abs_kwh_addr = 0x20000; static long *magic_word_addr = (uint32 *)(phr_abs_kwh_addr-sizeof(uint32)); #define ok_magic_word 0x87654321 main() { if (isfirstexecution() || (*magic_word != ok_magic_word)) { eraseflashsector(phr_abs_kwh_addr); // writes 0's in addresses of flash sector (1024 bytes) setflashsectortozero(phr_abs_kwh_addr); } init_flash_kwhenergyacc(phr_abs_kwh_addr, &phr_abs_kwh_accstr); if (testintegrity(phr_abs_kwh_accstr) == 0) { // turn on leds show message showmsgled(255, 0, 0); } while (1) { getvaluesfromsensors(&phr_abs_kwh_accstr); processvalues(&phr_abs_kwh_accstr); phr_abs_kwh_accstr.magic_word = ok_magic_word; eraseflashsector(phr_abs_kwh_addr); flash_burst(phr_abs_kwh_addr, sizeof(kwh_energyacc32)/4, &phr_abs_kwh_accstr); } }
Comments
Post a Comment