CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

dsPIC33 - Quick question about program memory as EEPROM

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
matteo



Joined: 31 May 2012
Posts: 5

View user's profile Send private message

dsPIC33 - Quick question about program memory as EEPROM
PostPosted: Thu May 31, 2012 12:42 pm     Reply with quote

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! Smile
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu May 31, 2012 3:33 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 31, 2012 4:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 31, 2012 6:17 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Jun 01, 2012 10:55 am     Reply with quote

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 Smile
Matt Que



Joined: 16 Nov 2009
Posts: 14

View user's profile Send private message

PostPosted: Sun Jul 29, 2012 7:03 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jul 29, 2012 8:54 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jul 29, 2012 11:22 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 30, 2012 7:42 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 30, 2012 7:59 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jul 30, 2012 8:02 am     Reply with quote

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

View user's profile Send private message

SOLVED!!
PostPosted: Tue Jul 31, 2012 4:32 pm     Reply with quote

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!!! Very Happy Very Happy Very Happy Very Happy

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!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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