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

"read_program_memory()" problem
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kmp84



Joined: 02 Feb 2010
Posts: 361

View user's profile Send private message

"read_program_memory()" problem
PostPosted: Mon Jan 05, 2015 9:13 am     Reply with quote

Hi all,

I try to store some bytes in program memory, but have this problem:
Code:

   #include <16F1459.h>
   //#device *=16
   #use delay(int=8MHz, clock=48MHz, USB_FULL, act=USB)
   //#USE RS232(DEBUGGER,rcv=PIN_C2,xmit=PIN_C2,stream=STREAM_MONITOR)
   #use rs232(baud=115200, xmit=PIN_B7, rcv=PIN_B5, errors)
   
   #fuses PROTECT
   #fuses MCLR
   #fuses PUT
   #fuses NOWDT
   #fuses BROWNOUT
   
#define BUFFER_SERNUM_SIZE   16                             // in bytes

#define PROGRAM_MEMORY_SIZE   getenv("PROGRAM_MEMORY")
#define BUFFER_SERNUM_END     (PROGRAM_MEMORY_SIZE-1)                  //0x1FFF
#define BUFFER_SERNUM_START   (PROGRAM_MEMORY_SIZE-BUFFER_SERNUM_SIZE) //0x1FEE

//#org BUFFER_SERNUM_START, BUFFER_SERNUM_END {}              //Serial_number 

#rom BUFFER_SERNUM_START = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}

byte ram_buff[16]={255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};

void main (void){
 
   int8 i;
   
   printf("\n\rPROGRAM_MEMORY_SIZE:%Lx",PROGRAM_MEMORY_SIZE);
   printf("\n\rBUFFER_START:%Lx",BUFFER_SERNUM_START);
   printf("\n\rBUFFER_END:%Lx",BUFFER_SERNUM_END);
   printf("\n\n");
   
   read_program_memory(BUFFER_SERNUM_START, ram_buff, BUFFER_SERNUM_SIZE);


   for(i=0;i<16;i++)
   {
      printf("\n\r ram_buff[%u]:%Lx",i,ram_buff[i]);
   }

   for(;;)
   {
      // ...
   }
}


and get this result :


    PROGRAM_MEMORY_SIZE:2000
    BUFFER_START:1ff0
    BUFFER_END:1fff

    ram_buff[0]:00
    ram_buff[1]:00
    ram_buff[2]:01
    ram_buff[3]:00
    ram_buff[4]:02
    ram_buff[5]:00
    ram_buff[6]:03
    ram_buff[7]:00
    ram_buff[8]:04
    ram_buff[9]:00
    ram_buff[10]:05
    ram_buff[11]:00
    ram_buff[12]:06
    ram_buff[13]:00
    ram_buff[14]:07
    ram_buff[15]:00



CCS Compiller v.5.019
Any Idea?
Ttelmah



Joined: 11 Mar 2010
Posts: 19563

View user's profile Send private message

PostPosted: Mon Jan 05, 2015 9:48 am     Reply with quote

The ROM is organised in words. Each is 14bits long (so can't hold two 8bit values), but is accessed by the read/write functions as bytes.
The #ROM statement, writes to the _words_. So when you write '1' to the second location, and then look at this in bytes, you get:

00 //low byte of first word
00 //high 6bits of first word
01 //low byte of second word
00 //high 6 bits of second word

etc..
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Jan 05, 2015 10:54 am     Reply with quote

Some other related issues to think about:

Put #delay and #use rs232 AFTER the fuses. Note that some delay configurations will override some fuses, and some fuses are required to get some clock settings to work.

Your comment on the value of buffer end is wrong. The code is giving you the correct value, 0x1FF0, when it runs.

Your buffer is not compatible with the ICSP debugger. When debugging live hardware, the top of memory is used for debugging code and this will give you wrong data in debug, or worse still, debug won't work at all.

EEPROM is generally a much better storage medium for settable things like serial numbers. Its writeable and erasable byte by byte whereas program memory requires blocks to be erased. Also any program memory checksum/CRC code (I have this on some/many of my projects) will need to take any data storage regions into account. Program memory has much more limited erase cycles than EEPROM, so cannot be changed as often (though a serial number isn't likely to need changing all that often...). EEPROM can also be excluded from programming on many programmers and even bootloaders if required, for example to update code while leaving calibration data/setpoints/serial numbers/identification etc. intact.

While EEPROM is my default persistent/non-volatile data storage medium, I have used program memory, but only for fault data dumps in an "black box recorder" type thing. I write a largish (1K) block from RAM to program memory on the rare occasions (hopefully never, but you never know...) when a fault is detected.
kmp84



Joined: 02 Feb 2010
Posts: 361

View user's profile Send private message

PostPosted: Tue Jan 06, 2015 2:33 am     Reply with quote

Thank you for help Smile

I've trouble with storing only one Byte in program memory . Any suggestion how to do it ?
Thanks ,
Ttelmah



Joined: 11 Mar 2010
Posts: 19563

View user's profile Send private message

PostPosted: Tue Jan 06, 2015 2:48 am     Reply with quote

You always have to store a word. However you can just read the low bytes of the words.
So you start by having to allow a word for each byte you want to store, in your space allocation. Then read as you do, but only look at the even numbered bytes.

I have to ask what you actually want to do?. Are you wanting to update these values later?. If not, then just let the compiler do it for you and use const:

const int8 ser_num[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};


Stores this for you in the program memory.

Or look at the UserID locations in the program memory. These are four locations at 0x8000, reserved for a user ID number. They are part of the config memory.
kmp84



Joined: 02 Feb 2010
Posts: 361

View user's profile Send private message

PostPosted: Tue Jan 06, 2015 2:57 am     Reply with quote

Ttelmah wrote:
You always have to store a word. However you can just read the low bytes of the words.
So you start by having to allow a word for each byte you want to store, in your space allocation. Then read as you do, but only look at the even numbered bytes.

I have to ask what you actually want to do?. Are you wanting to update these values later?. If not, then just let the compiler do it for you and use const:

const int8 ser_num[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};


Stores this for you in the program memory.

Or look at the UserID locations in the program memory. These are four locations at 0x8000, reserved for a user ID number. They are part of the config memory.


Hi "Ttelmah",

Because my chip (16F1459) have not EEPROM data memory , i want to sore 16 byte max ser.num + 1 byte length of ser.num changed at runtime over rs or usb interface.

Thanks,
Ttelmah



Joined: 11 Mar 2010
Posts: 19563

View user's profile Send private message

PostPosted: Tue Jan 06, 2015 3:29 am     Reply with quote

OK. So look at what I said. You have almost done it. It is just that you have to read 32 _bytes_ to access the 16 bytes you want.
But there are some big difficulties raised by what you say. Remember that you can only erase a whole page. So you need to use 32 words of storage as a minimum, and this needs to be on a page boundary.
The +1 makes things much more difficult. Why have this?. Why not just have (for example), leading zeros in the number?. Having a fixed size makes everything easier.
So, use getenv("FLASH_ERASE_SIZE"), to get the page size that is needed for an erase. Subtract this from the PROGRAM_MEMORY_SIZE to get the start address where the data must be stored, and use this to specify the buffer size as well as int16, not byte.
So:
Code:

#define PROGRAM_MEMORY_SIZE   getenv("PROGRAM_MEMORY")
#define PAGE_SIZE getenv("FLASH_ERASE_SIZE")
#define BUFFER_SERNUM_START   (PROGRAM_MEMORY_SIZE-PAGE_SIZE)

#rom BUFFER_SERNUM_START = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}

int16 ram_buff[PAGE_SIZE]; //now you have a buffer for the _words_ the minimum
//size that can be erased

//The read becomes:
read_program_memory(BUFFER_SERNUM_START, ram_buff, sizeof(ram_buff));

Now the data will read as written, and if you write the buffer to this address, a page erase will occur, and the data can be written.

As a comment, don't enable protection while debugging. Doing so, means you won't be able to read the memory in the programmer and see if writes have worked, and will use up extra lives on the chip, since a full erase has to occur every time anything is changed.
kmp84



Joined: 02 Feb 2010
Posts: 361

View user's profile Send private message

PostPosted: Wed Jan 14, 2015 1:52 pm     Reply with quote

Strange problem : My first test board with 16f1459 in DIP socket works good. Second board with same pic (16f1459) in SO20 socket , same software and same schematics is not possible to write to program memory. Confused
Ttelmah



Joined: 11 Mar 2010
Posts: 19563

View user's profile Send private message

PostPosted: Wed Jan 14, 2015 3:42 pm     Reply with quote

Read the errata.
Looks like you have an old (revision A2) chip in the SO20 version.
You can do the write if you switch your clock down to a slower rate, and back up after the write has completed.....
kmp84



Joined: 02 Feb 2010
Posts: 361

View user's profile Send private message

PostPosted: Wed Jan 14, 2015 11:43 pm     Reply with quote

Ttelmah wrote:
Read the errata.
Looks like you have an old (revision A2) chip in the SO20 version.
You can do the write if you switch your clock down to a slower rate, and back up after the write has completed.....

When I test two boards with ICD U64 show the same :
Device ID : 3023
Revision : 00
Ttelmah



Joined: 11 Mar 2010
Posts: 19563

View user's profile Send private message

PostPosted: Thu Jan 15, 2015 1:20 am     Reply with quote

It's not reading the revision properly.
The revision bytes will be 1003, 1005 or 1006.
1003, is the A2 revision. 1005, is A5, and 1006 is A6.

Look at address 8005 in the chip's configuration memory. This is where the revision word is held. 3023, is correct as the device ID (held at 8006).

Look at the erratum, and you will see the problem. On Rev A2 chips, self timed writes won't work with the internal clock at 8MHz or 16MHz (or with external clocks above 4MHz....).
kmp84



Joined: 02 Feb 2010
Posts: 361

View user's profile Send private message

PostPosted: Thu Jan 15, 2015 9:12 am     Reply with quote

Ttelmah wrote:
It's not reading the revision properly.
The revision bytes will be 1003, 1005 or 1006.
1003, is the A2 revision. 1005, is A5, and 1006 is A6.

Look at address 8005 in the chip's configuration memory. This is where the revision word is held. 3023, is correct as the device ID (held at 8006).

Look at the erratum, and you will see the problem. On Rev A2 chips, self timed writes won't work with the internal clock at 8MHz or 16MHz (or with external clocks above 4MHz....).

How to read memory location 8005h and 8006h and print on uart?
Ttelmah



Joined: 11 Mar 2010
Posts: 19563

View user's profile Send private message

PostPosted: Thu Jan 15, 2015 9:15 am     Reply with quote

read_configuration_memory
kmp84



Joined: 02 Feb 2010
Posts: 361

View user's profile Send private message

PostPosted: Thu Jan 15, 2015 9:42 am     Reply with quote

Ttelmah wrote:
read_configuration_memory

Thanks, but CCS Compiler v.5.019 says : "Undefined identifier-- read_configuration_memory"
In "16F1459.h " missing "_bif void read_configuration_memory".
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jan 15, 2015 12:39 pm     Reply with quote

I compiled this program with vs. 5.036:
Code:

#include <16F1459.h>   
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)

//===============================
void main()
{
char buffer[16];

read_configuration_memory(buffer, 16);

while(TRUE);
}

It created the following ASM code for read_configuration_memory():
Code:

.................... read_configuration_memory(buffer, 16);
002B:  MOVLB  03
002C:  CLRF   PMADRH
002D:  CLRF   PMADRL
002E:  MOVLW  buffer+-1
002F:  MOVWF  FSR0H
0030:  MOVLW  buffer+-32
0031:  MOVWF  FSR0L
0032:  MOVLW  10
0033:  MOVLB  00
0034:  MOVWF  @READ_CONFIGURATION_MEMORY.P2  // Number of bytes
0035:  GOTO   @READ_CONFIGURATION_MEMORY


Code:

READ_CONFIGURATION_MEMORY:
0003:  MOVLB  03
0004:  BSF    PMCON1.CFGS
0005:  MOVLB  00
0006:  MOVF   @READ_CONFIGURATION_MEMORY.P2,W
0007:  MOVWF  @77
0008:  BCF    STATUS.C
0009:  INCF   @77,F
000A:  RRF    @77,F
000B:  MOVLB  03
000C:  BSF    PMCON1.RD
000D:  NOP
000E:  NOP
000F:  MOVF   PMDATL,W
0010:  MOVWF  INDF0
0011:  ADDFSR 01,FSR0
0012:  MOVF   PMDATH,W
0013:  MOVWF  INDF0
0014:  ADDFSR 01,FSR0
0015:  INCF   PMADRL,F
0016:  BTFSC  STATUS.Z
0017:  INCF   PMADRH,F
0018:  DECFSZ @77,F
0019:  GOTO   00C
001A:  BCF    PMCON1.CFGS
001B:  MOVLP  00
001C:  MOVLB  00
001D:  GOTO   036 (RETURN)

You could use this as a guide to make your own routine.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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