Author Topic: Handling short power failures  (Read 16008 times)

Offline Richard

  • Newbie
  • *
  • Posts: 44
    • View Profile
Handling short power failures
« on: April 21, 2009, 11:39:22 PM »
Hi, all.
    In previous projects, I've found that many power outages are so short that RAM values are reliably maintained, even though prudence dictated stopping the CPU when power dropped below a certain level.  If power was again restored within seconds, a surprisingly frequent situation, a quick check of RAM -- e.g., a checksum of a specific area --  if successful, can allow the program to resume as though nothing had happened.  This is the desired result, since going through a full restart may have unpleasant side-effects, including annoying the user.
    Unfortunately, the M5223X CW project startup code zeroes RAM before allowing any user-defined procedures to run.  This is one way to guarantee that external C variables are initialized to zero by default, as required by C semantics.  However, it prevents using my old assembly-language based technique for a silent restart after a very brief outage.
    So I've got three questions:
1) Is it possible to protect a specified part of RAM from being zeroed on power up?  And, of course, it has to be possible to specify which variables are to be put into this part of RAM.
2) Is there some other reasonable way during power up to tell that power has been down for a very short time, at most a few seconds?  If this were possible, I could simply save critical data in FLASH as power went down and restore it after short outages.
3) Is there some other way to respond to failing power that prevents erratic behavior but does not cause a full reset if power comes back quickly?

Thanks for any suggestions.
    - Richard
« Last Edit: April 22, 2009, 12:23:51 AM by Richard »

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3240
    • View Profile
    • uTasker
Re: Handling short power failures
« Reply #1 on: April 23, 2009, 01:51:28 PM »
Hi Richard

This is quite a complicated topic so there is no simple answer, but rather lots of possibilities to achieve parts of such a solution.

Here are a few notes:

In the uTasker project the variable initialisation is in mcf52235_init(), in M5223X.c. This can be modified to not zero data if required:

    if (__DATA_ROM != __DATA_RAM) {                                      // move initialized data from ROM to RAM.
      dp = (unsigned char *)__DATA_RAM;
      sp = (unsigned char *)__DATA_ROM;
      n = (unsigned long)(__DATA_END - __DATA_RAM);
        while (n--) {
         *dp++ = *sp++;
        }
   }

    if (__BSS_START != __BSS_END) {                                      // zero uninitialised data
      sp = (unsigned char *)__BSS_START;
      n = (unsigned long)(__BSS_END - __BSS_START);
        while (n--) {
         *sp++ = 0;
        }
   }


I don't think that the debugger zeroes RAM, or at least not when it doesn't known that the RAM is being used by the project (that is when the variables are in an area not declared as being available in the linker script. I did some tests of randomness of RAM variables after power loss and also randomness here: http://forums.freescale.com/freescale/board/message?board.id=CFCOMM&thread.id=6321
This showed that the test location was not being initialised by the debugger and also has a highly random value after power loss.

For applications with hard requirements for variable data retention after short power losses I would also consider a device with battery backed up RAM (like the M52259). Also MRAM (see http://www.utasker.com/forum/index.php?topic=504.0 ) which allows variable to be permanently maintained over also long power loss periods.

Regards

Mark



Offline Richard

  • Newbie
  • *
  • Posts: 44
    • View Profile
Re: Handling short power failures
« Reply #2 on: June 07, 2009, 07:29:29 PM »
Hi, Mark.

To preserve key variables, I do as you suggested: I monitor the raw voltage being supplied to the microprocessor.  When it drops below a threshold, I store the active parameters in the RAM parameter block into FLASH.  To handle short outages, I have to be careful to preserve the RAM copies of the parameter blocks during startup.  To do this, I've created a global variable
Code: [Select]
struct tParamStorage {
    char parameterBlock[PAR_BLOCK_SIZE/2];
    char tempParameterBlock[PAR_BLOCK_SIZE/2];
} ramParameterBlocks;
and replaced
Code: [Select]
parameters = uMalloc(sizeof(PARS));                             // get RAM for a local copy of device parameters
temp_pars  = uMalloc(sizeof(TEMPPARS));                      // get space for a backup of all modifiable parameters
with
Code: [Select]
parameters = (PARS *)&ramParameterBlocks.parameterBlock;
temp_pars = (TEMPPARS *)&ramParameterBlocks.tempParameterBlock;

I modified mcf52235_init() to leave ramParameterBlocks uninitialized when it zeroes out the BSS area.
Code: [Select]
    // Make sure that ramParameterBlocks lies in the BSS area (as it certainly should!)
    // and then initialize all the BSS except the ramParameterBlocks area.
    if ((unsigned char *)__BSS_START <= (unsigned char *)&ramParameterBlocks &&
        (unsigned char *)&ramParameterBlocks + PAR_BLOCK_SIZE <= (unsigned char *)__BSS_END) {
    for (sp = (unsigned char *)__BSS_START; sp < (unsigned char *)&ramParameterBlocks; sp++)
    *sp = 0;
    for (sp = (unsigned char *)&ramParameterBlocks + PAR_BLOCK_SIZE; sp < (unsigned char *)__BSS_END; sp++)
    *sp = 0;
    }
    else
        while (1) {}; // hang here to make the problem obvious while debugging.

I check that it has survived a power failure using a 16-bit checksum (based on an old *nix sum algorithm).  The only issue here is to be sure that the checksum, which is stored in the parameter block, is set to a known value, e.g., 0xffff, before the checksum algorithm runs.

If the checksum test fails, I reload the parameters from FLASH or initialize them to default values, based on your original code.

Cheers,
    Richard