|
|
View previous topic :: View next topic |
Author |
Message |
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
Problem storing variables in program ROM |
Posted: Fri Nov 26, 2010 3:42 pm |
|
|
Hi all,
I'm using PCWH 4.099, compiling for a PIC18F26J50.
Because the chip lacks EEPROM, I need to store application config data in program ROM. I'm running into some problems doing this.
The data is a range of variables consisting of ints, longs, and arrays of around 300 bytes total (though it will get bigger later on).
I can do this with no problem:
Code: |
char msg[3][64];
ROM char s_msg[3][64];
...
write_program_memory(&s_msg,msg,192);
read_program_memory(&s_msg,msg,192);
|
But, with a few dozen variables it gets very cumbersome and inefficient to do this for each one. Also, I found that the compiler is putting the ROM variables in the last page of ROM, and if I erase the page (as is recommended in the data sheet), it corrupts the config words.
What I tried first is this (shortened for readability):
Code: | #org 0xF800, 0xFBFF
ROM unsigned int s_speed, s_hangtime, s_cbeepdelay, s_id_volume;
#org default |
Unfortunately, the compiler seems to ignore the #org and sticks the data just below the config words, in reverse order. That means if I do an erase_program_memory() it whacks my config words. The symbol file shows me this:
Code: | User Memory space:
00FFF6-00FFF6 s_speed
00FFF4-00FFF4 s_hangtime
00FFF2-00FFF2 s_cbeepdelay
00FFF0-00FFF0 s_id_volume |
Ideally I'd like to be able to just copy the variables from RAM (they're all in a nice neat block) into ROM with write_program_memory(). By doing that I can specify the ROM address. However, when I try that it seems to write to areas I'm not expecting. As a test I tried this:
Code: | write_program_memory(0x00C000,&speed,192); |
When i read back the program memory and compare it to the original program, I find that there is nothing around 0xC000:
Code: | :10C00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40
:10C01000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30
:10C02000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20
:10C03000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10
:10C04000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 |
But it does seem to have written to the middle of my program:
Code: | :1022700045004100540045005200200043004F003B
D <! :102280004E00540052004F004C004C0045005200DC
D <! :10229000F76AA00FF66E220EF7220900F550120021
D <! :1022A000E001970233039B03BB039B0333039702B5
D <! :1022B000E00128018C002400050024008C00280186
I !> :10228000000000000000000000000000000000004E
I !> :10229000000000000000000000000000000002003C
I !> :1022A000E000800210000100100290032003900063
I !> :1022B000000008000800000000000000000000000E
:1022C000F2CF0EF0F29EF76ADA0FF66E220EF722C8 |
Of course at that point my device promptly dies, since its program is now corrupted.
I've been hammering away at this for over a day now. I'm stumped. Is write_program_eeprom broken in this compiler version? Am I doing something wrong? I can't possibly be the first person to want to store configuration parameters to ROM on EEPROM-less parts, so I know this has to have been addressed before. I did try searching the forums here, but without much luck.
What am I missing here? |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Sat Nov 27, 2010 7:52 am |
|
|
Hi Dale,
I never used the 26J50, but in order to get a clue to find out this specific problem, I suggest post a short
and compilable code that we can test with differents compiler versions and compare its resulting .hex
Regards,
Humberto |
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Sat Nov 27, 2010 12:46 pm |
|
|
It would be interesting to see the symbols, listing and statistics from a newer compiler version, if it's not too much trouble. I would like to see if the behavior has changed since 4.099.
Code: |
#include <18F26J50.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES INTRC_PLL_IO //Internal RC Osc, no CLKOUT
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOPROTECT //Code not protected from reading
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES IOL1WAY //Allows only one reconfiguration of peripheral pins
#FUSES PRIMARY //Primary clock is system clock when scs=00
#FUSES WPCFG
#FUSES WPEND
#FUSES WPDIS
#FUSES NOCPUDIV
#FUSES LPT1OSC //Timer1 configured for low-power operation
#FUSES T1DIG
#FUSES MSSPMSK7
#FUSES PLLDIV2
#FUSES DSWDT2147483648
#FUSES DSWDT
#FUSES DSBOR
#FUSES RTCOSC_T1
#FUSES DSWDTOSC_INT
#FUSES WPFP0
#FUSES WPFP1
#FUSES WPFP2
#FUSES WPFP3
#FUSES WPFP4
#FUSES WPFP5
#use delay(clock=48mhz,internal)
unsigned int speed, hangtime, cbeepdelay, id_volume, recv_volume, cbeep_speed;
unsigned long int id_time, first_id, beacon_time, cbeep_tone, cwid_tone, watchdog, id_delay;
char msg[3][64];
#org 0xF800, 0xFBFF
ROM unsigned int s_speed, s_hangtime, s_cbeepdelay, s_id_volume, s_recv_volume, s_cbeep_speed;
ROM unsigned long int s_id_time, s_first_id, s_beacon_time, s_cbeep_tone, s_cwid_tone, s_watchdog, s_id_delay;
ROM char s_msg[3][64];
#org default
// This works in the original program. However, it's looking like
// I will have dozens of parameters to store and retrieve.
void read_params_from_flash(void) {
read_program_memory(&s_speed,&speed,1);
read_program_memory(&s_hangtime,&hangtime,1);
read_program_memory(&s_cbeepdelay,&cbeepdelay,1);
read_program_memory(&s_id_volume,&id_volume,1);
read_program_memory(&s_recv_volume,&recv_volume,1);
read_program_memory(&s_cbeep_speed,&cbeep_speed,1);
read_program_memory(&s_id_time,&id_time,2);
read_program_memory(&s_first_id,&first_id,2);
read_program_memory(&s_beacon_time,&beacon_time,2);
read_program_memory(&s_cbeep_tone,&cbeep_tone,2);
read_program_memory(&s_cwid_tone,&cwid_tone,2);
read_program_memory(&s_watchdog,&watchdog,2);
read_program_memory(&s_id_delay,&id_delay,2);
read_program_memory(&s_msg,msg,192);
}
void write_params_to_flash(void) {
// If the ROM parameters were stored in the block
// beginning at F800, the line below would work.
// Since they're not, it will erase the config words
// along with the parameters.
// erase_program_eeprom((&s_speed & 0xFC00));
write_program_memory(&s_speed,&speed,1);
write_program_memory(&s_hangtime,&hangtime,1);
write_program_memory(&s_cbeepdelay,&cbeepdelay,1);
write_program_memory(&s_cbeep_speed,&cbeep_speed,1);
write_program_memory(&s_id_volume,&id_volume,1);
write_program_memory(&s_recv_volume,&recv_volume,1);
write_program_memory(&s_cbeep_speed,&cbeep_speed,1);
write_program_memory(&s_id_time,&id_time,2);
write_program_memory(&s_first_id,&first_id,2);
write_program_memory(&s_beacon_time,&beacon_time,2);
write_program_memory(&s_cbeep_tone,&cbeep_tone,2);
write_program_memory(&s_cwid_tone,&cwid_tone,2);
write_program_memory(&s_watchdog,&watchdog,2);
write_program_memory(&s_id_delay,&id_delay,2);
write_program_memory(&s_msg,msg,192);
}
// These don't work for me because the compiler puts the stuff
// in program ROM in reverse order...
void write_by_block(void) {
write_program_memory(&s_speed,&speed,211);
}
void read_by_block(void) {
read_program_memory(&s_speed,&speed,211);
}
void main(void) {
speed = 20;
hangtime = 25;
cbeepdelay = 5;
id_volume = 75;
recv_volume = 100;
cbeep_speed = 30;
id_time = 600;
first_id = 10;
beacon_time = 3600;
cbeep_tone = 2000;
cwid_tone = 1000;
watchdog = 240;
id_delay = 5;
msg[0] = "This is a test";
msg[1] = "Another test string";
write_params_to_flash();
read_params_from_flash();
write_by_block();
read_by_block();
}
|
Compiling this I get the following from the .SYM file:
Code: | User Memory space:
00FFF6-00FFF6 s_speed
00FFF4-00FFF4 s_hangtime
00FFF2-00FFF2 s_cbeepdelay
00FFF0-00FFF0 s_id_volume
00FFEE-00FFEE s_recv_volume
00FFEC-00FFEC s_cbeep_speed
00FFEA-00FFEB s_id_time
00FFE8-00FFE9 s_first_id
00FFE6-00FFE7 s_beacon_time
00FFE4-00FFE5 s_cbeep_tone
00FFE2-00FFE3 s_cwid_tone
00FFE0-00FFE1 s_watchdog
00FFDE-00FFDF s_id_delay
00FF1E-00FFDD s_msg
|
|
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Sun Nov 28, 2010 6:06 pm |
|
|
You know, after looking at this for quite some time... I decided to just add a bloody I2C EEPROM to the board and be done with it. I could see how to make it work the way I wanted -- more or less -- with program ROM, but it was always going to be messy and inefficient. I could see it causing headaches for a long time to come when it came time to maintain the code. Since I'm already using I2C, I just had to find space for a TSSOP-8 package on the board.
Saved me almost 2K of program space, which I'm sure will come in handy later on. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sun Nov 28, 2010 6:46 pm |
|
|
I just recently did this for the 26j50 (and the 26j11) and it works fine -- but there are some things you have to keep in mind (as stated right in the datasheet):
When you are going to write to a space out there, you have to read the ENTIRE page into an array (like unsigned int buffer[1024])
Then you modify what you want... then erase and write it back.
You can also tell the compiler to put NOTHING out in that zone of memory you want.
I'll have to check, but it doesn't require that much memory (2k??!?!) of code to handle it.. but it does require at least one page's worth of RAM (1024bytes - ouch) to handle it.
So it can be done -- and reasonably "pain free".
-Ben
p.s. Also, consider keeping all your "save stuff" inside a structure.. then it's really easy to rattle the location and length of the structure back and forth to program memory and make it easy for the rest of your program to access. It's what I do anyway. _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
|
|
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
|