Flash编程导致意外重置

时间:2016-05-09 08:29:17

标签: c embedded microcontroller flash-memory

我正在使用MCF51EM256飞思卡尔微控制器,我在闪存编程方面遇到了一些问题。

为了使我的软件保持持久性,我试图将一些变量存储在辅助闪存中,以便从意外停机中恢复。

有时,当我测试关闭MCU的工作时,它会不断重置。

我必须存储这个结构:

//  kWh or kVARh Energy accumulator type 
typedef struct {
    uint32 Ea_ps;   // Energy must be stored in kWh or kVARh
    uint32 Ea_ng;   // All fields must contain POSITIVE values!
    uint32 Er_q1;
    uint32 Er_q2;
    uint32 Er_q3;
    uint32 Er_q4;
}kWh_EnergyAcc32;

这些是我的职能:

// This function stores in Flash a 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));

}

*

// This functions erase a 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);
}

*

// This function initializes a given Ws_EnergyAcc64 structure with the
// 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;

}

*

flash编程功能:

#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 to call the function using the 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 to see if FACCERR or PVIOL is set */
  if (FSTAT &0x30)  
  {         
      /* Clear Flags if set*/
      FSTAT = 0x30;  
  }

  if (FlashDataCounter)
  {
    do
    {
        /* Wait for the Last Busrt Command to complete */
        while(!(FSTAT&FSTAT_FCBEF_MASK)){};/*wait until termination*/

        /* Write Data into Flash*/
        (*((volatile unsigned long *)(FlashAddress))) = *pFlashDataPtr;
        FlashAddress += 4;
        pFlashDataPtr++;

        /* Write Command */
        FCMD = FlashCommand;

        /* Put FCBEF at 1 */
        FSTAT = FSTAT_FCBEF_MASK;

        asm (NOP);
        asm (NOP);
        asm (NOP);

         /* Check if Flash Access Error or Protection Violation Error are Set */
        if (FSTAT&0x30)
        {     
          /* If so, finish the function returning 1 to indicate error */
          return (1);
        }

    }while (--FlashDataCounter);
  }
  /* wait for the last command to complete */
  while ((FSTAT&FSTAT_FCCF_MASK)==0){};/*wait until termination*/

  /* Return zero to indicate that the function executed OK */
  return (0);
}

我的主程序如下:

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 all addresses of the 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 to show a 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);

    }

}

谁能看到我做错了什么?当我关闭电源以测试持续性时,为什么我的micro-sometines会不断重置?有一种方法可以捕获这个导致我微观重置的致命异常吗?

首先我认为这可能是由于在关机期间写入任何闪存地址时出错,后者无法正常读取但我尝试使用写在我末尾的已知位置的“魔术字” flash写入以检查闪存写入是否已经完成,似乎不是问题。

修改:MCF51EM256 Reference Manual

编辑2:这是我的micro的记忆图:

enter image description here

编辑3:

我在 Flash编程功能

中包含了FLASH_CLOCK定义

我还包含了这个函数来检查不一致的值:

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;
}

现在,在初始化值之后调用此函数,并且leds永远不会打开。

注意:(Acc-> Ea_ps == -1)与(Acc-> Ea_ps == 0xffffffff)

相同

编辑4:

我的功能代码 SetFlashSectorToZero

void SetFlashSectorToZero(long addr){

    uint32 resetValue = 0x00000000;
    int endSector = addr + 1024;

    while (addr <= endSector) {

        Flash_Burst(addr, 1, &resetValue);
        addr = addr + 4;
    }

}

2 个答案:

答案 0 :(得分:2)

  • 您无法从当前正在编程的同一闪存阵列中执行闪存编程代码。根据该特定设备的手册,它包含双闪存控制器,只是为了允许您编程一个闪存阵列,同时编程另一个闪存阵列。

    因此,您必须确保在单独的数组中分配闪存编程代码。您甚至可能需要两个完整的闪存编程代码副本。

    如果不这样做会导致任何随机行为。

  • 您必须通过写入FxCDIV寄存器来配置闪存预分频器时钟。错误配置的闪存时钟通常会导致程序挂起或CPU重置等问题。时钟需要在150-200kHz之内。 重要:你需要保证金,所以必须考虑到你的时钟不准确,以及你的公共汽车时钟产生的不准确性不能被你选择的任何常数整除。

  • 毋庸置疑,在闪存编程期间,如果它们驻留在正在编程的闪存阵列中,或者它们试图访问闪存阵列中的常量/调用代码,则不能运行任何中断。

答案 1 :(得分:1)

我不知道您是否通过我们的建议解决了您的问题,但我认为您的代码可以通过以下方式缩小:

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 all addresses of the 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 to show a 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);

    }

}

//  kWh or kVARh Energy accumulator type
typedef struct {
    uint32 Ea_ps;   // Energy must be stored in kWh or kVARh
    uint32 Ea_ng;   // All 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 all addresses of the 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 to show a 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);
    }
}