|
|
View previous topic :: View next topic |
Author |
Message |
matteo
Joined: 31 May 2012 Posts: 5
|
dsPIC33 - Quick question about program memory as EEPROM |
Posted: Thu May 31, 2012 12:42 pm |
|
|
Hi Everyone,
I am having some issues with writing the program memory on a dsPIC33FJ64GS608, others have had the same trouble as I but their fixes have not worked for me.
I'm using PCD 4.121.
Preprocessor
Code: | #ORG 0xA900,0xA9FE {}
int chk = 1300;
int ace = 0; |
Main Code (after initialization of course)
Code: | write_program_memory(0xA900,chk,2);
delay_ms(1);
read_program_memory(0xA900,&ace,2);
printf("%X\n\r",ace); |
I'm rather confused and probably doing something stupid. The same code seems to work for others in the past. I can never seem to change the default FFFF value.
Questions:
Is there any care I need to take in the allocation of my memory? I put it where MPLAB told me I had to contain it within, then subtracted 256 bytes for my start address.
Can I use #ROM for this? When I tried it showed the same symptom.
Have I done something wrong?
Thanks so much guys! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 31, 2012 3:33 pm |
|
|
Quote: | #ORG 0xA900,0xA9FE {}
int chk = 1300;
int ace = 0; |
This code will reserve an address range in Flash memory and
then create two RAM variables and initialize them. That's not
what you want.
Maybe this example will help:
http://www.ccsinfo.com/forum/viewtopic.php?t=880&start=1 |
|
|
matteo
Joined: 31 May 2012 Posts: 5
|
|
Posted: Thu May 31, 2012 4:16 pm |
|
|
I'm missing something....
Code: | #ORG 0xA900,0xA9FE {}
#define ttval 0xA900
#ROM ttval = {1240} |
Then I try to write/read "ttval" again only to see it is unchanged from the ROM declaration of 1240.
Thanks for your help PCM, I'll study the link again and see if I didn't catch something the first time. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Thu May 31, 2012 6:17 pm |
|
|
Some general rules concerning writing to program memory:
1. You have to erase a page before you can write anywhere to it. write_program_memory() will do that for you only if you write to the start of a page. Otherwise, it assumes the erase already happened, which won't be the case at address 0xA900, since that isn't on a page boundary.
2. I don't recall where the fuse page starts on that chip, but be very careful not to erase it as you will erase the fuses. If you want to write to upper memory, write to the page prior to the one with the fuses
3. It's been a while, but I believe the dsPics share the same reqs as PIC24F's in that you are required to write data in chunks of 4 bytes. This is because program memory is word sized (2 bytes) and must be interacted with on even addresses only (so every 2 words or 4bytes). Also, the 4th byte is always 0 since it is a 24bit instruction space.
try something like:
Code: |
#define PM_END (getenv("PROGRAM_MEMORY")-1) //in words
#define PM_PAGE_SIZE (getenv("FLASH_ERASE_SIZE")/2) //in words
#define PM_NUM_PAGES (PM_END/PM_PAGE_SIZE)
#define PM_FUSE_PAGE (PM_NUM_PAGES*PM_PAGE_SIZE)
//use page prior to fuse page:
#define PM_USER_PAGE (PM_FUSE_PAGE-PM_PAGE_SIZE)
//make sure no code gets in this space
#org PM_USER_PAGE, (PM_FUSE_PAGE-1) {}
|
Then try:
Code: |
unsigned int8 read_data[4];
unsigned int8 write_data[] = {0x12,0x34,0x56,0x00};
read_program_memory(PM_USER_PAGE,read_data,4);
printf("%x %x %x %x\n\r",read_data[0],read_data[1],read_data[2],read_data[3]);
delay_ms(1);
write_program_memory(PM_USER_PAGE,write_data,4);
delay_ms(1);
read_program_memory(PM_USER_PAGE,read_data,4);
printf("%x %x %x %x\n\r",read_data[0],read_data[1],read_data[2],read_data[3]);
|
Mind you, those are just for example. I didn't test them for compilability as I don't have the compiler here on hand to do so. |
|
|
matteo
Joined: 31 May 2012 Posts: 5
|
|
Posted: Fri Jun 01, 2012 10:55 am |
|
|
jeremiah,
Thanks very much for your time and assistance.
1. I was unclear about that. The CCS manual is vague, and the things I saw reading threads didn't explicitly describe it. They would say "it erases before write all in one command," but the page boundary thing was assumed known. And I just wasn't sure how the pages were defined even after looking at the datasheets memory chapter or app notes.
2. Roger that.
3. They do indeed.
Your code worked and started me in the right direction! Remember kids, always use proper page management |
|
|
Matt Que
Joined: 16 Nov 2009 Posts: 14
|
|
Posted: Sun Jul 29, 2012 7:03 pm |
|
|
Hey Guys,
I am trying to do the same thing... Write a few bytes of data to ROM. I tried to following your examples and I was wondering if there were any other configurations/fuses required to enable this functionality?
Here is my example code.
CCS PCD C Compiler, Version 4.118
PIC24HJ128GP306
Code: | #include <24HJ128GP306.h>
#build(stack = 256)
#device ICD=TRUE
#define PM_END (getenv("PROGRAM_MEMORY")-1) //in words
#define PM_PAGE_SIZE (getenv("FLASH_ERASE_SIZE")/2) //in words
#define PM_NUM_PAGES (PM_END/PM_PAGE_SIZE)
#define PM_FUSE_PAGE (PM_NUM_PAGES*PM_PAGE_SIZE)
//use page prior to fuse page:
#define PM_USER_PAGE (PM_FUSE_PAGE-PM_PAGE_SIZE)
//make sure no code gets in this space
#org PM_USER_PAGE, (PM_FUSE_PAGE-1) {}
#type FLOAT=32
#fuses HS
#fuses NOWDT
#fuses NOPROTECT
#fuses DEBUG
#fuses PR
#use delay(crystal=20M, clock=40M)
////////////////////////////////////////////////////////////////////////////////
/////////////////UART CONFIGURATION/////////////////////////////////////////////
#use rs232(STREAM=TELEMETRY, UART1, PARITY=N, BITS=8, ERRORS)
#use rs232(STREAM=IMU_SERIAL,UART2, PARITY=N, BITS=8, ERRORS)
#word U1BRG = 0x228
#bit U1BRGH = 0x220.3
#word U2BRG = 0x238
#bit U2BRGH = 0x230.3
void main ()
{
// Setup IRQs
enable_interrupts(INT_RDA);
enable_interrupts(INT_RDA2);
// Set Port IOs
set_tris_B(0b1111111111001011);
set_tris_C(0b1111000000000110);
set_tris_D(0b0000111101111111);
set_tris_F(0b0000000010010100);
set_tris_G(0b1111001111001111);
// Set Serial Baud
U1BRGH = 0;
U1BRG = 10; //sets 115200 Baud, -1.4%
U2BRGH = 0;
U2BRG = 10; // sets 115200 Baud, -1.4%
//////////////////////////////////////////////////////////////////////
//////////////// MAIN ////////////////////////////////////////////////
unsigned int8 IN_ROM[4];
unsigned int8 IN_RAM[4];
IN_RAM[0] = 0x01;
IN_RAM[1] = 0x01;
IN_RAM[2] = 0x00;
IN_RAM[3] = 0x00;
read_program_memory(PM_USER_PAGE,IN_ROM,4);
fprintf(IMU_SERIAL,"IN ROM @ PM_USER_PAGE: %x %x %x %x\n\r",IN_ROM[0],IN_ROM[1],IN_ROM[2],IN_ROM[3]);
fprintf(IMU_SERIAL,"IN RAM: %x %x %x %x\n\r",IN_RAM[0],IN_RAM[1],IN_RAM[2],IN_RAM[3]);
fprintf(IMU_SERIAL," PM_END: %Lu \n\r PM_PAGE_SIZE: %Lu \n\r PM_NUM_PAGES: %Lu \n\r PM_USER_PAGE: %Lu \n\r PM_FUSE_PAGE: %Lu\n\r",PM_END,PM_PAGE_SIZE,PM_NUM_PAGES,PM_USER_PAGE,PM_FUSE_PAGE);
delay_ms(1000);
write_program_memory(PM_USER_PAGE,IN_RAM,4);
delay_ms(1000);
read_program_memory(PM_USER_PAGE,IN_ROM,4);
delay_ms(1000);
fprintf(IMU_SERIAL,"NOW in ROM: %x %x %x %x\n\r",IN_ROM[0],IN_ROM[1],IN_ROM[2],IN_ROM[3]);
delay_ms(2000);
} |
This is what the result of my program.
ROM @ PM_USER_PAGE: ff ff ff 00
IN RAM: 01 01 00 00
PM_END: 88063
PM_PAGE_SIZE: 1024
PM_NUM_PAGES: 85
PM_USER_PAGE: 86016
PM_FUSE_PAGE: 87040
NOW in ROM: ff ff ff 00
What am I missing? Any feedback would be greatly appreciated! |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Sun Jul 29, 2012 8:54 pm |
|
|
I would start with your fuses. Look at your LST file that is generated when you compile. At the bottom it lists the fuses it puts in the hex file. Post those values here.
Also, compare them to the configuration bits section of your PIC's datasheet (starts on page 215 of your PIC's datasheet...I think 217 has a couple of fuses of interest though).
See if any of the protection fuses are being set since you don't specify many of them yourself. |
|
|
Matt Que
Joined: 16 Nov 2009 Posts: 14
|
|
Posted: Sun Jul 29, 2012 11:22 pm |
|
|
Thanks Jeremiah for the direction...
Attached are the fuses.
Code: | Configuration Fuses:
Word 1L: 00CF NOWRTB NORBS
H: 0000
Word 2L: 00CF NOWRTSS NORSS
H: 0000
Word 3L: 0007 NOWRT NOPROTECT
H: 0000
Word 4L: 0083 PR_PLL IESO
H: 0000
Word 5L: 00C6 HS NOOSCIO
H: 0000
Word 6L: 005F WPOSTS16 WPRES128 WINDIS NOWDT
H: 0000
Word 7L: 00E7 PUT128
H: 0000
Word 8L: 00C3 ICSP1 NOJTAG NODEBUG
H: 0000 |
1.00 NOWRTB Boot block not write protected
1.06 NORBS No Boot RAM defined
3.00 NOWRTSS Secure segment not write protected
3.06 NORSS No secure segment RAM
5.00 NOWRT Program memory not write protected
5.00 NOPROTECT Code not protected from reading
7.00 PR_PLL Primary Oscillator with PLL
7.07 IESO Internal External Switch Over mode enabled
9.00 HS High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
9.02 NOOSCIO OSC2 is clock output
11.00 WPOSTS16 Watch Dog Timer PostScalar 1:32768
11.04 WPRES128 Watch Dog Timer PreScalar 1:128
11.06 WINDIS Watch Dog Timer in non-Window mode
11.07 NOWDT No Watch Dog Timer
13.00 PUT128 Power On Reset Timer value 128ms
15.00 ICSP1 ICD uses PGC1/PGD1 pins
15.05 NOJTAG JTAG disabled
15.07 NODEBUG No Debug mode for ICD
Since NOWRT is present... Is that all that is necessary for program memory writes?
By using the CCS function for write_program_memory and read_program_memory... does the SFR's (NVMCON) need any special attention or configuration?
Thank you for your help on this! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Jul 30, 2012 7:42 am |
|
|
One thing to beware of.
The program memory on these chips is 24bit 'words', in a 32bit 'space'. However the program_memory functions normally require _byte_ addresses. So to talk to the memory word 0x1000, you have to use address 0x4000.
May be the problem.
Best Wishes |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Mon Jul 30, 2012 7:59 am |
|
|
There are some things questionable with your code, though I have no idea if they are causing your problems or not:
1. You typically are not supposed to declare variables in the middle of your code. That isn't allowed in C. The compiler won't complain, but I have seen that cause bugs in RAM memory in the past.
2. You don't need to set the tris registers. CCS will do that for you unless you give it a preprocessor directive to let you. Unneeded for this program.
3. You don't need the enable interrupts lines as you have no interrupt service routines defined. This can cause issues too in the long run.
4. use the #use rs232() to set your baud rate if you can.
I don't have your chip to test against, but do have a PIC24FJ series, so I tested the following program which worked (using your fuse settings). I use UART1 and a different clock setting since my board is already fixed.
This is the program I tested:
Code: |
#case
#include <24FJ256GA106.h>
#device ICD=TRUE
#fuses HS
#fuses NOWDT
#fuses NOPROTECT
#fuses DEBUG
#fuses PR
#build(stack = 256)
#pin_select U1TX = PIN_B6
#pin_Select U1RX = PIN_B7
#use delay(clock=22118400)
#use rs232(UART1,baud=9600,bits=8,stop=1,parity=N,errors,stream=IMU_SERIAL)
////////////////////////////////////////////////////////////////////////////////
// PM EEPROM Setup
////////////////////////////////////////////////////////////////////////////////
#define PM_END (getenv("PROGRAM_MEMORY")-1) //in words
#define PM_PAGE_SIZE (getenv("FLASH_ERASE_SIZE")/2) //in words
#define PM_NUM_PAGES (PM_END/PM_PAGE_SIZE)
#define PM_FUSE_PAGE (PM_NUM_PAGES*PM_PAGE_SIZE)
//use page prior to fuse page:
#define PM_USER_PAGE (PM_FUSE_PAGE-PM_PAGE_SIZE)
//make sure no code gets in this space
#org PM_USER_PAGE, (PM_FUSE_PAGE-1) {}
void main() {
unsigned int8 in_rom[4];
unsigned int8 in_ram[4]={0x01,0x01,0x00,0x00};
delay_ms(1000);
printf("\r\n******Starting******\r\n");
read_program_memory(PM_USER_PAGE,in_rom,4);
fprintf(IMU_SERIAL,"IN ROM @ PM_USER_PAGE: %x %x %x %x\n\r",in_rom[0],
in_rom[1],
in_rom[2],
in_rom[3]);
fprintf(IMU_SERIAL,"IN RAM: %x %x %x %x\n\r",in_ram[0],
in_ram[1],
in_ram[2],
in_ram[3]);
fprintf(IMU_SERIAL," PM_NUM_PAGES: %Lu \n\r",PM_NUM_PAGES);
fprintf(IMU_SERIAL," PM_PAGE_SIZE: 0x%Lx \n\r",PM_PAGE_SIZE);
fprintf(IMU_SERIAL," PM_END: 0x%Lx \n\r",PM_END);
fprintf(IMU_SERIAL," PM_USER_PAGE: 0x%Lx \n\r",PM_USER_PAGE);
fprintf(IMU_SERIAL," PM_FUSE_PAGE: 0x%Lx \n\r",PM_FUSE_PAGE);
delay_ms(1000);
write_program_memory(PM_USER_PAGE,in_ram,4);
delay_ms(1000);
read_program_memory(PM_USER_PAGE,in_rom,4);
delay_ms(1000);
fprintf(IMU_SERIAL,"NOW in ROM: %x %x %x %x\n\r",in_rom[0],
in_rom[1],
in_rom[2],
in_rom[3]);
while(TRUE); //loop forever here
}
|
output:
Code: |
******Starting******
IN ROM @ PM_USER_PAGE: ff ff ff 0
IN RAM: 1 1 0 0
PM_NUM_PAGES: 170
PM_PAGE_SIZE: 0x400
PM_END: 0x2abf7
PM_USER_PAGE: 0x2a400
PM_FUSE_PAGE: 0x2a800
NOW in ROM: 1 1 0 0
|
Try this code, but change the chip header file include, the UART settings to match yours, and the clock settings to match yours.
If it works, I highly suggest you go through your code you posted, and take things out one by one until you get to the code that worked to see what messed you up (so it doesn't mess you up again later)
If it doesn't work, try changing the location of the user page to:
Code: |
//use page prior to fuse page:
#define PM_USER_PAGE (PM_FUSE_PAGE-(2*PM_PAGE_SIZE))
|
which moves it to the page before that one. You could possibly have a bad page in memory.
Last edited by jeremiah on Mon Jul 30, 2012 8:06 am; edited 2 times in total |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Mon Jul 30, 2012 8:02 am |
|
|
Ttelmah wrote: | One thing to beware of.
The program memory on these chips is 24bit 'words', in a 32bit 'space'. However the program_memory functions normally require _byte_ addresses. So to talk to the memory word 0x1000, you have to use address 0x4000.
May be the problem.
Best Wishes |
I just tested this on my PIC24FJ and it is interpretting addresses as 16bit word addresses.
Code: |
read_program_memory(PM_USER_PAGE,in_rom,4);
delay_ms(1000);
fprintf(IMU_SERIAL,"NOW in ROM: %x %x %x %x\n\r",in_rom[0],
in_rom[1],
in_rom[2],
in_rom[3]);
read_program_memory(PM_USER_PAGE+1,in_rom,4);
delay_ms(1000);
fprintf(IMU_SERIAL,"NOW in ROM: %x %x %x %x\n\r",in_rom[0],
in_rom[1],
in_rom[2],
in_rom[3]);
|
gives:
Code: |
NOW in ROM: 1 2 3 0
NOW in ROM: 3 0 ff ff
|
|
|
|
Matt Que
Joined: 16 Nov 2009 Posts: 14
|
SOLVED!! |
Posted: Tue Jul 31, 2012 4:32 pm |
|
|
I implemented your test code, changed the required hardware specific items and tested it and it did not work.
It would get as far into the program as the final read_program_memory line and never accomplished the last printf line. I tried it both with the ICD and with DEBUG fuses disabled with the same result...
Frustrated, I updated the compiler version from 4.118 to 4.135 and re-compiled and this time it worked!!!
I read through the update log and of course there is a myriad of loosely described bug fixes that may have addressed the issue.
I appreciate the help and taking time in testing it out! |
|
|
|
|
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
|