Store multi-byte variable in EE with XC8 - Page 1
Forum section: electronics / general

author: David_AVD
author_rank: Super Contributor
timestamp: June 23, 2014, 10:42:10 pm
content: Does XC8 have simple syntax for storing and retrieving multi-byte variables to/from the EE ?I do not want to associate a variable directly with the EE space. I simply want to store a 16-bit value at an address (uses 2 locations) and get it back.I know I can do break it up, store high and low byte separately and do the reverse to get it back, but surely there is a multi-byte function already built in?For Atmel programming I use ee_write_block and ee_read_block for uint16t values (and structures, etc), but can't see anything like that in XC8.

author: dannyf
author_rank: Super Contributor
timestamp: June 23, 2014, 11:22:54 pm
content: 1) use a pointer to convert any data type to char;2) use size of to store / retrieve successive chars.

author: David_AVD
author_rank: Super Contributor
timestamp: June 23, 2014, 11:34:02 pm
content: Yeah, I could do that but thought that there would be something inbuilt.

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 12:05:10 am
content: Just roll your own: infinitely better than what Atmel can offer.

author: zapta
author_rank: Super Contributor
timestamp: June 24, 2014, 12:08:49 am
content: Check section 2.5.9 herehttp://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB_XC8_C_Compiler_User_Guide.pdf. Seems you can define variables of arbitrary type to reside in the eeprom space. Then I guess you just read/write them as standard C variables.If you want to have it in a specific address use a pointer as suggested earlier.typedef __eeprom int eeprom_int;typedef eeprom_int* eeprom_int_ptr;*((eeprom_int_ptr) 1234) = 2233; // assignment, reading in a similar way.(I am not a Microchip user so the above are all guesses).

author: David_AVD
author_rank: Super Contributor
timestamp: June 24, 2014, 12:11:48 am
content: I've written a pair of routines for 16 bit values, but haven't got the hang of how to do the pointer / loop method yet.

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 12:32:52 am
content: Fairly simple:1) write a routine that saves the char value pointed to by a pointer to EEPROM - the built-in routines or macros work here.2) write a loop controlled by size of that invokes the routine you wrote in 1).3) done.Do the same with the retrive side as well.It can deal with any type of data (assuming sufficient eeprom space) and is endian independent.

author: AndyC_772
author_rank: Super Contributor
timestamp: June 24, 2014, 08:00:57 am
content: Code:void eewrite_long (unsigned char ee_addr, unsigned long eedata){unsigned char i, ie;unsigned char * cptr;unsigned char eeptr;cptr = (unsigned char *) &eedata;ie = interrupt_enable;interrupt_enable = 0;for (i = 0; i < 4; i++)eewrite_byte (ee_addr++, *cptr++);interrupt_enable = ie;}signed long eeread_long (unsigned char ee_addr){unsigned char i;unsigned char * cptr;signed long eeresult;cptr = (unsigned char *) &eeresult;for (i = 0; i < 4; i++)*cptr++ = eeread_byte (ee_addr++);return eeresult;}

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: June 24, 2014, 08:24:27 am
content: All you need to do is define the variable with an __eeprom qualifierCode:__eeprom unsigned long var;I think you may be able to use the @ qualifier to specify a fixed addressCode:__eeprom unsigned long var @0x10;

author: David_AVD
author_rank: Super Contributor
timestamp: June 24, 2014, 09:39:53 am
content: I didn't really want to use the __eeprom qualifier as there's not a direct relationship between the EE data location and where I'm using it.

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 11:14:31 am
content: Code:void eewrite_long (unsigned char ee_addr, unsigned long eedata)When you want to save a float type, you have to rewrite it; when you want to save 100 different struct types, you have to write 100 of such nearly identical functions...You need something more generic than what you have here.

author: David_AVD
author_rank: Super Contributor
timestamp: June 24, 2014, 12:22:02 pm
content: I've written something along the lines of what you wrote earlier Danny. It compiled (at work) , but I've not tested it yet.My working knowledge of pointers and other things in C is somewhat lacking.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: June 24, 2014, 12:40:25 pm
content: Quote from: dannyf on June 24, 2014, 11:14:31 amYou can write a macro that takes a pointer to the variable and uses sizeof to get its length, then you can just do ee_write(addr, varname) and it will automatically handle the typeSomething like#define writeeeprom(adr,targ) for(i=adr;i!=adr+sizeof(targ);writebyte(i++, (char*)&targ++));(not sure if that pointer increment syntax is right, but you get the idea)If you're writing to something like I2C ee, you'd want your bottom-level read/write code to write multiple bytes in one operation for efficiency, so it would simplify to just passing the address and size of the variable.

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 03:56:31 pm
content: QuoteThat isn't a good way to use a macro; and potentially dangerous, depending on how writebyte() is implemented.You probably want the function to have three parameters:unsigned int eeprom_addr -> starting address of the eeprom.void * data_ptr -> pointer to data to be written to / read from eeprom.unsigned int block_size -> the amount of data to be written to / read from eeprom.Implementing that would be fairly simple and platform dependent.

author: David_AVD
author_rank: Super Contributor
timestamp: June 25, 2014, 06:04:59 am
content: Can you access (read/write) individual bytes of multi-byte variables (and structures) in C ?Does something like this work to operate on the high and low bytes for example?Code:uint16_t variable;variable = 1;variable = 2;

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: June 25, 2014, 07:33:57 am
content: Quote from: David_AVD on June 25, 2014, 06:04:59 amYes - define a union comprising an array of char plus whatever structure you need.

author: David_AVD
author_rank: Super Contributor
timestamp: June 25, 2014, 08:06:37 am
content: I was more thinking of variable[ x ] where x is the byte I want. I take it there's no way to treat the variable like an array of bytes?I guess what I'm asking is how to I specify the individual byte of a multi-byte variable given a pointer to it?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: June 25, 2014, 09:11:49 am
content: Quote from: David_AVD on June 25, 2014, 08:06:37 amYes, use a union e.g.union { unsigned long l;char c;} longchar;longchar.c gives byte n of longchar.lYou can use #defines to hide the union stuff#define my_long longvar.l#define my_chars longval.cIf my_long=0x12345678, my_chars would be 0x67

author: dannyf
author_rank: Super Contributor
timestamp: June 25, 2014, 11:22:28 am
content: It is so much easier to use pointers.

author: ecat
author_rank: Frequent Contributor
timestamp: June 25, 2014, 11:41:03 am
content: Quote from: dannyf on June 25, 2014, 11:22:28 amAssuming...Quote from: mikeselectricstuff on June 25, 2014, 09:11:49 amlongchar.c is a pointer, and the address assignment is done for you. It's more safe than using a separate pointer and does not require the extra RAM space, though it is perhaps not as flexible.Quote from: mikeselectricstuff on June 25, 2014, 09:11:49 am56 in old moneymy_chars would be 78 if my pic endien-ness is correct.