|
|
View previous topic :: View next topic |
Author |
Message |
JacquesB
Joined: 22 Aug 2008 Posts: 21
|
Addresses of parameters in internal EEPROM |
Posted: Fri Nov 14, 2014 10:43 am |
|
|
Hi,
I want to place some parameters in the pic's internal EEPROM and have them programmed during device programming.
Presently I have a working code but I'm wondering if there would be a better way to do it.
I need to have individual parameter addresses in order to be able to read them with read_eeprom(addr).
Since parameters have different types, I have to manually change the addresses if I add parameters or change types.
In the example below, if I want to change data2 type from int8 to int32 I must change all the #define to update the addresses.
The final program have more than 30 different parameters of mix types. Risk of errors is important.
I need a way to have data1_EEADR to data5_EEADR defined automatically and also have the initialization part updated.
I'm not sure if I could use a structure in EEPROM and how to initialize it.
Code: | #include "18F26K80.h"
#fuses INTRC_IO,NOWDT,MCLR,SOSC_DIG,NOPROTECT,NOPUT,BROWNOUT,NOCPD,STVREN,NOWRT,NOWRTD,NOWRTC,NOWRTB,NOEBTR,NOEBTRB,NOCPB
#define EE_MAP_ADR getenv("EEPROM_ADDRESS")
// parameter addresses in EEPRom
#define data1_EEADR 0x00
#define data2_EEADR 0x01 // previous 1 byte
#define data3_EEADR 0x02 // previous 1 byte
#define data4_EEADR 0x04 // previous 2 bytes
#define data5_EEADR 0x08 // previous 4 bytes
// default parameter values
#define data1_DEFAULT= {0x01}
#define data2_DEFAULT= {0x05}
#define data3_DEFAULT= {0x1122}
#define data4_DEFAULT= {0xAABBCCDD}
#define data5_DEFAULT= {0x13}
int i,j;
long k;
int32 l;
void main(void){
i= read_eeprom(data1_EEADR);
j= read_eeprom(data1_EEADR);
k= read_eeprom(data1_EEADR);
l= read_eeprom(data1_EEADR);
while(1);
}
// Initialisation of EEProm
#rom int EE_MAP_ADR + data1_EEADR= {data1_DEFAULT}
#rom int EE_MAP_ADR + data2_EEADR= {data2_DEFAULT}
#rom long EE_MAP_ADR + data3_EEADR= {data3_DEFAULT}
#rom int32 EE_MAP_ADR + data4_EEADR= {data4_DEFAULT}
#rom int EE_MAP_ADR + data5_EEADR= {data5_DEFAULT} |
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Nov 15, 2014 7:08 am |
|
|
Quote: |
if I want to change data2 type from int8 to int32 I must change all the #define to update the addresses. |
the code you present makes no sense to me.
you have totally stumped this chump.
From what you wrote, i can not tell if you are confused about how
to use the CCS compiler directives
OR
by the address scheme of your PIC
OR
about using 'C in general.
this much is certain:
read_eeprom() only returns one byte - no matter what the var type
where you try to stuff it. Examining the .LST file will show you what is going on in your main() |
|
|
JacquesB
Joined: 22 Aug 2008 Posts: 21
|
|
Posted: Mon Nov 17, 2014 8:06 am |
|
|
Hi asmboy
Your're right. that's stupid.
the original program is much more complex and I wanted emphasize the definition part and I screwed the main(). (copy paste!)
the main() should have been :
Code: |
i= read_eeprom(data1_EEADR);
j= read_eeprom(data2_EEADR);
k= L_int_from_eeprom(data3_EEADR); // read a long int
l= LL_in_from_eeprom(data4_EEADR); // read a int32
|
Anyway, the code is working OK but I just wanted to know if there is a better way to reserve the adresses in the EEPROM based on the parameter's type.
i,j,k,l are variables that are initialized from parameter values in EEPROM.
The parameter addresses depends on the variable types.
Defining the parameter's addresses the way I did requires manual calculation, thus possible errors.
Another way could be:
Code: |
// parameter addresses in EEPRom
#define data1_EEADR 0x00 // address where content of i is taken
#define data2_EEADR data1_EEADR+ sizeof(i) // address where content of j is taken
#define data3_EEADR data1_EEADR+ sizeof(j) // address where content of k is taken
#define data4_EEADR data1_EEADR+ sizeof(k) // address where content of l is taken
#define data5_EEADR data1_EEADR+ sizeof(l) // address where content of _ is taken
|
Does it make more sense now?
If not let me know. I may not be using the proper words since english is not my native language.
Thanks |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Nov 17, 2014 9:38 am |
|
|
the basic facts are these:
1- all core EEPROM operations are one byte at a time for READ and WRITE
( and they are relatively SLOW to execute on WRITE )
2- its up to YOU to reserve appropriate base addresses and number of bytes of "extent" to hold all the data you wish to store.
3- your code needs to disassemble any numeric type greater than an int8 or byte for storage ( and reassemble it on READ)
4- YOU decide if the bytes that make up a two or more byte numeric type are desired to be in BIG endian format or not . Or any order you choose. The compiler has no tools that control write order.
the details are up to you. The compiler has the tools to turn higher order numeric types into bytes , so there you go. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Mon Nov 17, 2014 10:16 am |
|
|
I'd suggest blocking your configurations together. Do some thought, and if (for instance), there is a config for one part of the code, that is always loaded together, then 'keep it together'. Use a structure to hold the whole config. Then put the entries per line to match the element in the structure (see what I show below), and use the sizes automatically to generate the addresses. So:
Code: |
typedef struct
{
int8 light;
int16 factor1;
int8 factor2;
int16 another; //dummy layout
} config;
typedef struct
{
int16 another;
int8 more; //and more
} second_config;
#define CONFIG_ADDR getenv("EEPROM_ADDRESS")
#ROM int8 CONFIG_ADDR = { 0x01,
0x04,0x08,
0x12,
0x02,0x12 } //each line matches a line in the struct
#define SECOND_CONFIG_ADDR CONFIG_ADDR+sizeof(config)
//Address is automatically calculated for the next element.
#ROM int8 SECOND_CONFIG_ADDR = { 0x14, 0x12,
0x12 }
//routine to read any size element - int16 if ROM is over 256bytes needed.
void read_struct(char * data, int8 size, int8 address)
{
int8 count;
for (count=0;count<size;count++)
data[count]=read_eeprom(count);
}
void main()
{
config eeprom_data;
second_config eeprom_data2; //generate variables to hold data
read_struct(&eeprom_data,sizeof(config),CONFIG_ADDR);
read_struct(&eeprom_data2,sizeof(second_config),SECOND_CONFIG_ADDR);
//and read
while(TRUE)
{
}
}
|
|
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Nov 17, 2014 10:27 am |
|
|
I keep things simple. I try to make all my EEPROM data two types: sixteen bit signed or unsigned and read/write them all as sixteen bit entities. Bytes are too restrictive, though addressing what are effectively byte pairs can get confusing.
I split strings up into two byte substrings and store them in my sixteen bit locations. I don't store as floats, but as scaled integers, sixteen bit naturally.
Its all to make my life simpler, or at least make it possible for me to have a consistent approach to EEPROM storage. I also have some common code that does CRC checking on EEPROM data, ensuring that I can detect corruption of configurations and settings. For the record, so far, my code hasn't detected any, which is a good thing.
One point, V4.xxx compilers defaulted to 16 bit words when using #rom, and you only had to specify the type when using bytes. All V5.xxx compilers default to bytes, and you must specify when you're using 16 bit words. This can make for frustrating incompatibilities between EEPROM code that worked in V4 but doesn't in V5. I now ensure I ALWAYS specify the type and don't rely on the default. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 17, 2014 10:47 am |
|
|
I think he would like to:
1. typedef a packed structure in eeprom.
2. Initialize an instance of it.
But I don't think you can do this in CCS.
Failing that, he wants the easiest alternate method. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Nov 18, 2014 2:51 am |
|
|
That's the sort of situation addressmod() would be useful for. Addressmod allows variables, including complex structures to be mapped on to non-internal RAM memories, such as internal and external EEPROM, using simple access, i.e. read and write, routines. Pity it doesn't work too well....
I fight shy of trying to be too "clever" with sort of thing. I like to keep things simple, rather than impose my will on the hardware - e.g. saying this "should" work and I'll move mountains to make it work, and its not "my fault" if it won't - I try to work within its limitations. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|