View previous topic :: View next topic |
Author |
Message |
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
Reading/Writing Pointers to EEPROM |
Posted: Mon Jun 11, 2012 10:27 am |
|
|
I am attempting to replace a switch(case) system with function pointers.
My previous code relied on a variable stored in EEPROM so that each time the micro (16LF819) is powered up it would read the EEPROM and know which "setting" it was last used in.
Example:
Code: |
mode = eeprom_read(0x00);
switch(mode)
case1:
whatev();
break;
|
I had hoped that I would be able to do the same with the pointer but I'm unable to compile because of my #ROM 0x2100 {}; line of code.
I attempted to write a pointer to the function I want called when the micro powers up.
Code: | #ROM 0x2100 = {*test}
|
Gives me compile error: Expression must evaluate to a constant
test(); is the function I want it to run when it powers up.
How I do I write the location of this function (pointer) to eeprom?
I have a sneaking suspicion I'm about to find out about a built in
function that I was unaware of.
Thanks everyone |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 11, 2012 12:30 pm |
|
|
You can #org the function, and then since you know the address, you can
just put it into eeprom:
Code: |
#include <16F877.H>
#fuses XT, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=4M)
#rom getenv("EEPROM_ADDRESS") = {0x00, 0x05}
#org 0x500,0x51F
int8 my_func(void)
{
char c;
c = 0x55;
return(c);
}
//==========================================
void main()
{
while(1);
} |
|
|
|
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Mon Jun 11, 2012 1:47 pm |
|
|
Both the 16F819 and 16F877 datasheets say that ON-Chip Program Memory starts at 0005h. In your #org example you used the starting location as 0x500.
-Are those both referencing the same location in memory?
Also, I can not make sense of what the manual is telling me about the getenv() function. What does this line do:
#rom getenv("EEPROM_ADDRESS") = {0x00, 0x05}
OH wait! It just clicked! It's finding the start address of the
EEPROM so you don't have to look that up for individual devices. Nice!
So whats the best way to determine what my memory end point should be?
Count lines in my .lst file? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 11, 2012 2:01 pm |
|
|
Actually, that is the Intel Lo-Hi storage format for the 16-bit value of
0x0500, which is the function's starting address.
http://people.cs.umass.edu/~verts/cs32/endian.html
Quote: |
So whats the best way to determine what my memory end point should
be? Count lines in my .lst file?
|
I think so. I just round it up to the end of the next 16-byte boundary. |
|
|
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Mon Jun 11, 2012 2:12 pm |
|
|
Well I have some more reading to do.
And re: setting space for a function. The compiler was nice enough to tell me that I didn't give it enough space and how much more it needed!
Thanks for your help PCMprogrammer. I'm knee deep in that link you sent me. |
|
|
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Mon Jun 11, 2012 3:03 pm |
|
|
You know what, I've still got an issue.
Code: |
void test(void){
whatev;
}
void main(void){
eeprom_write(0x00, &test);
}
|
I want to write the location of function test() to eeprom location 0x00.
Am I missing something? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Jun 11, 2012 3:24 pm |
|
|
stinky wrote: | Am I missing something? | Yes.
CCS Manual wrote: | write_eeprom( )
Syntax: write_eeprom (address, value)
Parameters:
address is a (8 bit or 16 bit depending on the part) int, the range is device dependent
value is an 8 bit int | How many bits is a memory address and how many bits are you writing? |
|
|
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Mon Jun 11, 2012 4:10 pm |
|
|
Up until you asked that I question I thought the answer to both of those questions was 8.
I do still believe that I'm writing 8 bits to EEPROM but perhaps my assumption on address length is incorrect.
So in the memory map I see addresses listed in 4 byte sections implying a maximum 16 bit value there. And table 1-1 lists the program flash as 2k x 14 so perhaps the correct answer is that I'm trying to write a 14 bit address into an 8 bit location.
Where I come from we refer to that as "too much junk in the trunk" |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 11, 2012 4:18 pm |
|
|
Here's an example. I couldn't get it to work with function return values,
so I gave up on that part, but at least it calls the function OK:
Code: |
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
#include "internal_eeprom.c"
void test(void)
{
putc('A');
}
// Typedef a function pointer.
typedef int8 (*_fptr)(void);
//==========================================
void main()
{
_fptr my_fptr, new_fptr;
my_fptr = test; // Set function ptr to address of test()
printf("fptr = %lx\r", my_fptr); // Display function ptr
write_int16_eeprom(0, my_fptr); // Write it to eeprom
new_fptr = read_int16_eeprom(0); // Read it back from eeprom
printf("new_fptr = %lx\r", new_fptr); // Display value read
*new_fptr(); // Call it
while(1);
} |
|
|
|
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Mon Jun 11, 2012 5:50 pm |
|
|
Aha!
And due to the functions inside internal_eeprom.c it will split my 16 bit integer into two 8 bit integers and write one into the eeprom address I specify, and then it will write one into the eeprom address one location greater than the first....yes? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 11, 2012 6:01 pm |
|
|
Yes. |
|
|
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Tue Jun 12, 2012 8:54 am |
|
|
OK I think I might be running into a syntax issue with CCS V 4.132.
The compiler doesn't like the following:
Code: |
void test(void);
int16 *testPtr = &test;
if(testPtr == &test)
{
;
}
|
This produces an error of "Expecting a ( "
But it's ok if I do the following:
Code: |
void test(void);
int16 *testPtr = &test;
int16 *retestPtr = &test;
if(testPtr == retestPtr)
{
;
}
|
Has anyone had any experience with this? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Tue Jun 12, 2012 1:33 pm |
|
|
There are several syntax errors, and problems in what you post:
1)
void test(void);
This has now declared a function called 'test' that does nothing. No '{' to show the function code follows...
2)
int16 *testPtr=&test;
First problem here is that the compiler never likes initialising variables with anything except constants. This is listed as a limitation in the manual. You have to declare the variable, then initialise it separately.
3) Your pointer declaration, is wrong. The C syntax for a function pointer, to a function accepting and returning a void, is:
void (*testPtr)(void);
You are declaring a pointer to an int16.
4) Remember that in the PIC, the RAM, is not the same memory space as the ROM. '&' attempts to return the address of a RAM variable. The name of the function, _is_ it's address, with no '&' needed.
5) However you can't use a function name in a direct comparison, the compiler only supports the name as the source of an assignment.
So:
Code: |
void test(void) {
void (*testPtr)(void);
void (*TP2)(void);
testPtr=test;
TP2=test;
if(testPtr == TP2) {
;
}
}
|
You have to be 'squeaky clean' when working with function pointers, particularly because of the twin memory spaces in the PIC.
As a 'comment', beware of storing the function address in the EEPROM. What happens to the code, if the write does not complete both bytes?.
Why not just declare an array of function pointers, initialise these at boot, and just store the array index?.
Best Wishes |
|
|
|