EmbeddedRelated.com
Forums
Memfault Beyond the Launch

How to prevent databse from being overwritten in xmem after a power cycle?

Started by "emb...@gmail.com [rabbit-semi]" August 6, 2015
After allocating +13kB in xmem using _xalloc(&tempsz, 0, XALLOC_BB) and itializing it, how do I prevent reallocating memory with default data(which are out-of-date) after a power cycle? is there something I'm missing?
// begin quasi pseudo-code...

#define BLOCK_START_MEMBER ((long)0x3A8446F7)
#define BLOCK_END_MEMBER ((long)0x7F6448A3)

#define BLOCK_START_NODE ((long)0x3A8446F8)
#define BLOCK_END_NODE ((long)0x7F6448A4)

#define BLOCK_START_DIGITAL ((long)0x3A8446F9)
#define BLOCK_END_DIGITAL ((long)0x7F6448A5)

#define BLOCK_START_ANALOG ((long)0x3A8446FA)
#define BLOCK_END_ANALOG ((long)0x7F6448A6)
void main(void)
{

long tempsz;
far char *pMemBlock_Member, *pMemBlock_Node, *pMemBlock_Digital,*pMemBlock_Analog;
far long *pStartAddrMark_Member, *pStartAddrMark_Node, *pStartAddrMark_Digital, *pStartAddrMark_Analog;
far long *pStopAddrMark_Member, *pStopAddrMark_Node, *pStopAddrMark_Digital, *pStopAddrMark_Analog;

//--------------------------Allocate Memory Block for Members----------------
//_xalloc the data block and calculate marker locations
tempsz = (MAX_MEMBERS * sizeof(Member_t));
tempsz += 2 * sizeof(long); //add room for start/end address
pMemBlock_Member = (far char *) _xalloc(&tempsz, 0, XALLOC_BB);
if(pMemBlock_Member == NULL)
{
printf("\n _xalloc failed for MEMBER \n");
//reboot
}
pStartAddrMark_Member = (far long *)pMemBlock_Member;
pStopAddrMark_Member = (far long *)(pMemBlock_Member + tempsz - sizeof(long) );

//check to see if the block is initialized (look for the beginning & ending marker)
if ((*pStartAddrMark_Member != BLOCK_START_MEMBER) || (*pStopAddrMark_Member != BLOCK_END_MEMBER))
{
// zero the memory block
_f_memset(pMemBlock_Member, 0, tempsz);

Initialize with default data.
InitializeWithDefaultData();
// put markers at start and end of the memory block
*pStartAddrMark_Member = BLOCK_START_MEMBER;
*pStopAddrMark_Member = BLOCK_END_MEMBER;
}
PtrToFamilyMemberFile = (far Member_t *)(pMemBlock_Member + sizeof(long));
while (1)
{

}

}
If you are using Recent versions of DC 10 it may be much easier to use normal arrays and allocate them with "bbram far" to create persistent storage over power cycles. I do that in my product and one of the arrays is about 300KB in length - the DC manual says that the limit is 32KB but if you allocate an array of structs you can reserve a much bigger amount of memory. You then need to use far pointers to access the memory instead of array indexes but it works very well as to be honest the array indexing code produced by DC10 is often quite bad so the pointer based access is often faster and takes up less code.

If you look at the trendlog object code in the BACnet stack at bacrabbit.sourceforge.net, you will see this in action (I didn't make the array bbram in this case as it has to work on several boards and not all of them have BBRAM) - see demo\object\trendlog.c for details..

This approach works very well for me and means that the structures are always in the same place in memory after a power up and don't get wiped. You may need to have some checking in place for some of the variables in BBRAM so that on initial power up you can detect unintialised memory and clear everything down first time the code runs.

Regards,
Peter
Hi Peter,

Thanks for the information. If understand you correctly, are you saying I could allocated array struct in xmem that are back-up battery by simply using 'bbram far'? For example:

bbram far TL_DATA_REC Logs[TL_DEFAULT_LOGS]

assuming that I redefine FAT file system buffer such as:

#define FAT_MAXBUFS 0

And If I want to write values to the struct, I could use:
xsetlong(Logs + sizeof(TL_DATA_REC) * index + offsetof(TL_DATA_REC, long_variable), long_value);
xsetchar(...)
xsetint(...)
To read:
long_variable = xgetlong(Logs + sizeof(TL_DATA_REC) * index + offsetof(TL_DATA_REC, long_value));
char_variable = xgetchar(....)
int_variable = xgetint(...)
float_variable = xgetlong(...)
It looks like you've got the basics. If it's still initializing the data
on every power up, you might want to check the bbram coin battery. They
can sometimes arrive very low or dead.

Hmmm.... I just noticed that you're not setting PtrToFamilyMemberFile
until AFTER you call InitializeWithDefaultData(). How is your
initialization function going to know where to put the data?

.... John S.

PS : You don't need to define separate start block and end block pointers
for testing and initializing each block. Just define a pair and reuse them
for each block. (They shouldn't be needed after the setup.)
On Aug 6, 2015 9:47 AM, "e...@gmail.com [rabbit-semi]
rabbit-semi-at-yahoogroups.com |yahoo/Example Allow|" <
b...@sneakemail.com> wrote:

> After allocating +13kB in xmem using _xalloc(&tempsz, 0, XALLOC_BB) and
> itializing it, how do I prevent reallocating memory with default data(which
> are out-of-date) after a power cycle? is there something I'm missing?
> // begin quasi pseudo-code...
>
> #define BLOCK_START_MEMBER ((long)0x3A8446F7)
> #define BLOCK_END_MEMBER ((long)0x7F6448A3)
>
> #define BLOCK_START_NODE ((long)0x3A8446F8)
> #define BLOCK_END_NODE ((long)0x7F6448A4)
>
> #define BLOCK_START_DIGITAL ((long)0x3A8446F9)
> #define BLOCK_END_DIGITAL ((long)0x7F6448A5)
>
> #define BLOCK_START_ANALOG ((long)0x3A8446FA)
> #define BLOCK_END_ANALOG ((long)0x7F6448A6)
> void main(void)
> {
> long tempsz;
> far char *pMemBlock_Member, *pMemBlock_Node,
> *pMemBlock_Digital,*pMemBlock_Analog;
> far long *pStartAddrMark_Member, *pStartAddrMark_Node,
> *pStartAddrMark_Digital, *pStartAddrMark_Analog;
> far long *pStopAddrMark_Member, *pStopAddrMark_Node,
> *pStopAddrMark_Digital, *pStopAddrMark_Analog;
> //--------------------------Allocate Memory Block for
> Members----------------
> //_xalloc the data block and calculate marker locations
> tempsz = (MAX_MEMBERS * sizeof(Member_t));
> tempsz += 2 * sizeof(long); //add room
> for start/end address
> pMemBlock_Member = (far char *) _xalloc(&tempsz, 0, XALLOC_BB);
> if(pMemBlock_Member == NULL)
> {
> printf("\n _xalloc failed for MEMBER \n");
> //reboot
> }
> pStartAddrMark_Member = (far long *)pMemBlock_Member;
> pStopAddrMark_Member = (far long *)(pMemBlock_Member + tempsz -
> sizeof(long) );
>
> //check to see if the block is initialized (look for the beginning &
> ending marker)
> if ((*pStartAddrMark_Member != BLOCK_START_MEMBER) ||
> (*pStopAddrMark_Member != BLOCK_END_MEMBER))
> {
> // zero the memory block
> _f_memset(pMemBlock_Member, 0, tempsz);
>
> Initialize with default data.
> InitializeWithDefaultData();
> // put markers at start and end of the memory block
> *pStartAddrMark_Member = BLOCK_START_MEMBER;
> *pStopAddrMark_Member = BLOCK_END_MEMBER;
> }
> PtrToFamilyMemberFile = (far Member_t *)(pMemBlock_Member +
> sizeof(long));
> while (1)
> {
>
> }
>
> }
It is even simpler than that. To write to the struct use far pointers and normal access methods i.e.

far TL_DATA_REC *ptr;
ptr = Logs + index;
ptr->x = 0;

or if you are doing a lot of individual alterations to a record it can often produce much smaller code to do the following:

TL_DATA_REC temprec;
far TL_DATA_REC *ptr;
ptr = Logs + index;

temprec = *ptr;

// lots of changes/accesses to temprec

*ptr = temprec;

etc...
Regards,
Peter
typedef struct {
unsigned char name[20];
unsigned int age;
unsigned char address[50];
float loan;
long transaction_time;
}TL_DATA_REC

bbram far TL_DATA_REC Logs[TL_DEFAULT_LOGS]

I can copy Logs[10] to temprec by using:
ptr = Logs + index;
temprec = *ptr;

then modify their values, i.e.
strcpy(temprec.name, "example name");
temprec.age = 34;
strcpy(temprec.address, new_address); //new_address is an array containing the new address
temprec.loan = temprec.loan + 25.32; //add 25.32 to current value
temprec.transaction_time = MS_TIMER;

then store new values in database, simply by:
//ptr = Logs + index;
*ptr = temprec;
Hi John,
You're probably correct, the battery might be low. I will need to check the voltage. Thanks again.
AFTER allocating memory space [ pMemBlock_Member = (far char *) _xalloc(&tempsz, 0, XALLOC_BB); ] , the values are initialized. However, I don't want to allocate memory if I have already done so before power cycle.

How do i check if startAddrMark and StopAddrMark exist? If it doesn't exist I would allocate the xmem space and initialized it. If Start/Stop markers already exist, nothing no allocating is necessary.

My current code doesn't work.
//check to see if the block is initialized (look for the beginning & ending marker)
if ((*pStartAddrMark_Member != BLOCK_START_MEMBER) || (*pStopAddrMark_Member != BLOCK_END_MEMBER))
You'll always allocate the memory on program startup. Allocating just reserves that block of memory for your program's use -- it doesn't general:

1) Allocate memory.
2) If markers aren't set correctly:
a) Initialize data structures in memory.
b) Set markers.

That's it. Each time the device starts up, your program will get the same address from the memory allocation call.

If you make changes to your code, the first time you run a new version of the program it might get a different address, but it will detect that condition since the markers won't be set correctly.

-Tom
On Aug 8, 2015, at 7:13 AM, e...@gmail.com [rabbit-semi] wrote:
> Hi John,
> You're probably correct, the battery might be low. I will need to check the voltage. Thanks again.
> AFTER allocating memory space [ pMemBlock_Member = (far char *) _xalloc(&tempsz, 0, XALLOC_BB); ] , the values are initialized. However, I don't want to allocate memory if I have already done so before power cycle.
>
> How do i check if startAddrMark and StopAddrMark exist? If it doesn't exist I would allocate the xmem space and initialized it. If Start/Stop markers already exist, nothing no allocating is necessary.
>
> My current code doesn't work.
> //check to see if the block is initialized (look for the beginning & ending marker)
> if ((*pStartAddrMark_Member != BLOCK_START_MEMBER) || (*pStopAddrMark_Member != BLOCK_END_MEMBER))
[Oops, accidentally sent that last message too soon.]

You'll always allocate the memory on program startup. Allocating just reserves that block of memory for your program's use -- it doesn't initialize or clear it. In general:

1) Allocate memory.
2) If markers aren't set correctly:
a) Initialize data structures in memory.
b) Set markers.

That's it. Each time the device starts up, your program will get the same address from the memory allocation call.

If you make changes to your code, the first time you run a new version of the program it might get a different address, but it will detect that condition since the markers won't be set correctly.

-Tom
On Aug 8, 2015, at 7:13 AM, e...@gmail.com [rabbit-semi] wrote:
> Hi John,
> You're probably correct, the battery might be low. I will need to check the voltage. Thanks again.
> AFTER allocating memory space [ pMemBlock_Member = (far char *) _xalloc(&tempsz, 0, XALLOC_BB); ] , the values are initialized. However, I don't want to allocate memory if I have already done so before power cycle.
>
> How do i check if startAddrMark and StopAddrMark exist? If it doesn't exist I would allocate the xmem space and initialized it. If Start/Stop markers already exist, nothing no allocating is necessary.
>
> My current code doesn't work.
> //check to see if the block is initialized (look for the beginning & ending marker)
> if ((*pStartAddrMark_Member != BLOCK_START_MEMBER) || (*pStopAddrMark_Member != BLOCK_END_MEMBER))
Thanks for the clarification. Everything is functioning the way I want.

Memfault Beyond the Launch