Flash编程导致意外复位

Flash programming causes unexpectedly reset

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

为了让我的软件持久存在,我试图在辅助闪存中存储一​​些变量,以便从意外关机中恢复。

有时,当我测试关闭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);

    }

}

谁能看出我做错了什么?为什么我关闭电源测试持久性时,我的微处理器会不断重置?有一种方法可以捕获导致我的微控制器重置的致命异常?

首先我认为这可能是由于在关机期间写入任何闪存地址时出错,之后无法正确读取但我尝试使用 "magic word" 写入已知位置我的闪存写入结束以检查闪存写入是否已经完成并且似乎不是问题所在。

编辑:MCF51EM256 Reference Manual

编辑 2:这是我的 micro 的内存映射:

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

现在,这个函数在初始化值后调用,LED 永远不会亮起。

注:(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;
    }

}
  • 您不能从当前正在编程的同一闪存阵列执行闪存编程代码。根据这个特定设备的手册,它包含双闪存控制器,目的只是为了让您在编程一个闪存阵列的同时编程另一个闪存阵列。

    所以你必须确保闪存编程代码分配在一个单独的数组中。您甚至可能需要两份完整的闪存编程代码。

    不这样做将导致任何随机行为。

  • 您必须通过写入 FxCDIV 寄存器来配置闪存预分频器时钟。错误配置的闪存时钟通常会导致程序挂起或 CPU 重置等问题。时钟需要在 150-200kHz 范围内。 重要:你需要边距,所以必须考虑你的时钟不准确,以及你的总线时钟的不准确不能被你选择的任何常数整除。

  • 不用说,在闪存编程期间你不能有任何中断运行,以防它们驻留在正在编程的闪存阵列中,或者它们试图访问constants/call 闪存阵列中的代码。

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

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