![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
Read User ID memory words |
Posted: Wed Sep 23, 2015 6:29 am |
|
|
I would like to write an serial number in the User ID memory which I would like to transfer through RS232, but unfortunately I can't get it working.
As I read the CCS manual the read_configuration_memory() is only for 18F controllers and with the read_program_memory it will not work for me.
Code: |
#include <16F1824.H>
#FUSES INTRC_IO,NOWDT
#FUSES PUT,NOMCLR,NOPROTECT,NOCPD,BROWNOUT,BORV25
#FUSES NOCLKOUT,NOIESO
#FUSES NOFCMEN,WRT
#FUSES PLL_SW,NOSTVREN,NODEBUG,NOLVP
#Device ADC=8
#use delay(clock=8000000)
#use rs232(baud=9600, xmit = PIN_A0)
#define user_id 0x8000
#rom 0x8000={0x3F01} // maximaal bereik is 3FFF hex
#rom 0x8001={0x3F02} //
#rom 0x8002={0x3F03} //
#rom 0x8003={0x3F04}
int serialnumber1, serialnumber2, serialnumber3, serialnumber4, serialnumber5, serialnumber6, serialnumber7, serialnumber8;
int userid_serialnumber1, userid_serialnumber2, userid_serialnumber3, userid_serialnumber4, userid_serialnumber5, userid_serialnumber6, userid_serialnumber7, userid_serialnumber8;
struct twobytes
{
int8 l;
int8 h;
};
union prog_mem
{
int16 word;
struct twobytes b;
};
void main()
{
struct
{
union prog_mem userid_serialnumber1;
union prog_mem userid_serialnumber2;
union prog_mem userid_serialnumber3;
union prog_mem userid_serialnumber4;
union prog_mem userid_serialnumber5;
union prog_mem userid_serialnumber6;
union prog_mem userid_serialnumber7;
union prog_mem userid_serialnumber8;
} values;
read_program_memory(user_id, &values, 8);
serialnumber1 = values.userid_serialnumber1.b.l;
serialnumber2 = values.userid_serialnumber2.b.l;
serialnumber3 = values.userid_serialnumber3.b.l;
serialnumber4 = values.userid_serialnumber4.b.l;
serialnumber5 = values.userid_serialnumber5.b.l;
serialnumber6 = values.userid_serialnumber6.b.l;
serialnumber7 = values.userid_serialnumber7.b.l;
serialnumber8 = values.userid_serialnumber8.b.l;
printf("%u ", serialnumber1);
printf("%u ", serialnumber2);
printf("%u ", serialnumber3);
printf("%u ", serialnumber4);
printf("%u ", serialnumber5);
printf("%u ", serialnumber6);
printf("%u ", serialnumber7);
printf("%u ", serialnumber8);
}
|
With the HEF this sort of programming worked for me. But why is the address 8000 not working for me?
In CCS-load I can see the values correct in the configuration ID section.
I receive the following numbers: 136 0 0 255 251 255 127 194
Anyone a idea what I do wrong?
CCS version: 5.026 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Wed Sep 23, 2015 8:13 am |
|
|
Read the manual again. You will find the read_configuration memory function, is for PIC18, _and enhanced PIC16_ devices. Yours is such a device.
You only have 4 words of user ID (not the 8 you are trying to access). |
|
![](templates/subSilver/images/spacer.gif) |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Thu Sep 24, 2015 12:56 am |
|
|
I know I have only 4 bytes, but I thought that it doesn't matter if I read 8 bytes. Just to be sure I had more info to debug.
I also tried the read_configuration_memory(); function, but I receive an error 12 (undefined identifier) on that function. Is that because of my CCS version, 5.026? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Thu Sep 24, 2015 1:29 am |
|
|
Probably. It exists in the current releases for your chip.
Shouldn't matter to 'read' the extra, but does matter if you try to write. If you look at the table in the data sheet, there is only write access for the first four words.
The key point is that the CGFS bit has to be set to access these locations, which the read_program_memory function won't do. The EEADR register only holds a 15bit address, so can't access 0x8000.
Simplest answer, just code your own function:
Code: |
#byte EEADRL=getenv("SFR:EEADRL")
#byte EEADRH=getenv("SFR:EEADRH")
#bit CFGS=getenv("BIT:CFGS")
#bit RD=getenv("BIT:RD")
#word EEDAT=getenv("SFR:EEDATL")
#bit EEPGD=getenv("BIT:EEPGD")
int16 read_ID_word(int8 offset)
{
EEADRL=offset; //must be 0 to 8 only
EEADRH=0;
EEPGD=TRUE;
CFGS=TRUE;
disable_interrupts(GLOBAL); //ensure interrupts are disabled for read
RD=TRUE; //initiate read vyte
delay_cycles(1); //NOP
delay_cycles(1);
enable_interrupts(GLOBAL);
return EEDAT;
}
|
Should be close to right (look at example 11-3 in the data sheet).
Last edited by Ttelmah on Thu Sep 24, 2015 7:01 am; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 24, 2015 1:35 am |
|
|
I see that Ttelmah posted while I was typing. I'll post this anyway.
This program compiles with no errors with compiler vs. 5.049:
Code: | #include <16F1824.H>
#fuses INTRC_IO, NOWDT
#use delay(clock=8M)
//===========================
void main()
{
int8 buffer[8];
read_configuration_memory(buffer, 8);
while(TRUE);
}
|
Here is the ASM code, if you wanted to use it as a guide
to write your own routine:
Code: |
@READ_CONFIGURATION_MEMORY:
0003: MOVLB 03
0004: BSF EECON1.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 EECON1.EEPGD
000D: BSF EECON1.RD
000E: NOP
000F: NOP
0010: MOVF EEDATL,W
0011: MOVWF INDF0
0012: ADDFSR 01,FSR0
0013: MOVF EEDATH,W
0014: MOVWF INDF0
0015: ADDFSR 01,FSR0
0016: INCF EEADRL,F
0017: BTFSC STATUS.Z
0018: INCF EEADRH,F
0019: DECFSZ @77,F
001A: GOTO 00D
001B: BCF EECON1.CFGS
001C: MOVLP 00
001D: MOVLB 00
001E: GOTO 035 (RETURN)
....................
.................... void main()
{
.
.
.
.................... read_configuration_memory(buffer, 8);
002A: MOVLB 03
002B: CLRF EEADRH
002C: CLRF EEADRL
002D: MOVLW buffer+-1
002E: MOVWF FSR0H
002F: MOVLW buffer+-32
0030: MOVWF FSR0L
0031: MOVLW 08
0032: MOVLB 00
0033: MOVWF @READ_CONFIGURATION_MEMORY.P2
0034: GOTO @READ_CONFIGURATION_MEMORY
.................... while(TRUE);
0035: GOTO 035 |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Thu Sep 24, 2015 7:19 am |
|
|
Now, we hit the question of whether MPLAB (8.92) correctly simulates this....
The following code:
Code: |
#include <16F1824.H>
#FUSES INTRC_IO,NOWDT
#FUSES PUT,NOMCLR,NOPROTECT,NOCPD,BROWNOUT,BORV25
#FUSES NOCLKOUT,NOIESO
#FUSES NOFCMEN,WRT
#FUSES PLL_SW,STVREN,NODEBUG,NOLVP
#Device ADC=8
#use delay(clock=8000000)
#use rs232(baud=9600, xmit = PIN_A0)
#define user_id 0x8000
#rom user_id={0x0001,0x0002,0x0003,0x0004} // maximaal bereik is 3FFF hex
#byte EEADRL=getenv("SFR:EEADRL")
#byte EEADRH=getenv("SFR:EEADRH")
#bit CFGS=getenv("BIT:CFGS")
#bit RD=getenv("BIT:RD")
#word EEDAT=getenv("SFR:EEDATL")
#bit EEPGD=getenv("BIT:EEPGD")
int16 read_ID_word(int8 offset)
{
EEADRL=offset; //must be 0 to 8 only
EEADRH=0;
CFGS=TRUE;
EEPGD=TRUE; //data sheet does not show this - needed.....
disable_interrupts(GLOBAL); //ensure interrupts are disabled for read
RD=TRUE; //initiate read byte
delay_cycles(1); //NOP
delay_cycles(1);
enable_interrupts(GLOBAL);
return EEDAT;
}
struct twobytes
{
int8 l;
int8 h;
};
union prog_mem
{
int16 word;
struct twobytes b;
};
void main()
{
struct
{
union prog_mem userid_serialnumber[4];
} values;
int ctr;
for (ctr=0;ctr<4;ctr++)
values.userid_serialnumber[ctr].word=read_ID_word(ctr);
for (ctr=0;ctr<4;ctr++)
printf("%u ", values.userid_serialnumber[ctr].b.l);
while(TRUE)
;
}
|
Correctly sets every bit in the EECON1 register and triggers the read. However in MPLAB 8.92 simulator, it returns the bytes from the start of program memory, not the config memory (CFGS is set).
Using the read_configuration_memory function on a current compiler, does exactly the same. So it looks as if MPLAB SIM, does not correctly implement this. So 'beware' if testing this..... |
|
![](templates/subSilver/images/spacer.gif) |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Thu Sep 24, 2015 8:43 am |
|
|
Thanks for your effort Ttelmah and PCM programmer.
It was not my intention to write to the ID section, only read.
I've looked in the compiler update and found this:
5.027 read/write_configuration_memory() now work on the ID area in Enhanced 16 chips
So my version is unfortunately too old for the read_configuration memory function.
I've tried Ttelmah's test program and at this moment I read 3FFF instead of 3F01, this is not the right value, but is a better value then I had before.
Is it correct to write EEDAT to RS232?
I've used the function as follows:
Code: |
read_ID_word(0); //no offset
printf("%Lu ", EEDAT);
|
Do I have to set an address (8000) somewhere? Or is this what you mean in your last post? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Thu Sep 24, 2015 9:11 am |
|
|
The function returns the word it reads.
So:
Code: |
printf("%Lu ",read_ID_word(0));
|
The point I found was that both using the CCS function, and mine, running in the simulator (haven't got that chip at the moment), it returned the value from the bottom of the program memory, rather than the config.... |
|
![](templates/subSilver/images/spacer.gif) |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Fri Sep 25, 2015 6:34 am |
|
|
Yes, it works and I understand it, thanks.
I've also bought the 1 year maintenance renewal again, this is the second problem where the older version of the compiler makes trouble (also with the HEF).
One final question (but it is more a general C question):
If I would like to use your function in a different .c file which is attached to my main.c file, how can I access your function. If I write "printf("%Lu ",read_ID_word(0));" in the other .c file it creates a "error12 Undefined identifier". |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Fri Sep 25, 2015 8:43 am |
|
|
Just #include "different_file.c" before using it. |
|
![](templates/subSilver/images/spacer.gif) |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Mon Oct 19, 2015 7:41 am |
|
|
I think I find another bug in the compiler (5.050).
The getenv from the CFGS bit (EECON1 register) isn't compiled correct.
Code: | #bit CFGS = 195.6
.................... CFGS=TRUE;
0062: MOVLB 01
0063: BSF 43.6 |
Code: | #bit CFGS = getenv("bit:CFGS")
.................... CFGS=TRUE;
0062: BSF 15.6 |
The getenv function doesn't change the bank I think, therefore the getenv doesn't work. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 19, 2015 9:23 am |
|
|
Quote: | I think I find another bug in the compiler (5.050).
The getenv from the CFGS bit (EECON1 register) isn't compiled correct. |
I tried it and it works for me. It changes to Bank 3 correctly below.
This is with compiler vs. 5.050:
Code: |
.................... void main()
0003: MOVLW 6A
0004: MOVLB 01
0005: MOVWF OSCCON
0006: MOVLB 03
0007: CLRF ANSELA
0008: CLRF ANSELC
0009: MOVLB 02
000A: CLRF CM1CON1
000B: CLRF CM1CON0
000C: CLRF CM2CON1
000D: CLRF CM2CON0
.................... {
....................
.................... CFGS=TRUE;
000E: MOVLB 03 // Sets bank 3 correctly
000F: BSF EECON1.CFGS
....................
.................... while(1);
0010: GOTO 010
.................... }
....................
0011: SLEEP |
Test program:
Code: |
#include <16F1824.H>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#bit CFGS = getenv("bit:CFGS")
//===================================
void main()
{
CFGS=TRUE;
while(1);
} |
|
|
![](templates/subSilver/images/spacer.gif) |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Thu Oct 22, 2015 3:06 am |
|
|
Ok, strange that the program act different if I change from the getenv(CFGS) to the 195.6 line. But I've locate the problem a bit more. The problem I have is related to the CFGS bit and the read_eeprom() function.
The read_id_word() function from Ttelmah:
Code: | int16 read_ID_word(int8 offset)
{
EEADRL=offset; //must be 0 to 8 only
EEADRH=0;
CFGS=TRUE;
disable_interrupts(GLOBAL); //ensure interrupts are disabled for read
RD=TRUE; //initiate read vyte
delay_cycles(1); //NOP
delay_cycles(1);
enable_interrupts(GLOBAL);
return EEDAT;
} |
overrules the read_eeprom function in a kind of way so they don't work together, but only seperately. If I disable the CFGS=true line or the read_eeprom() line in my program they act correct, but together they don't. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Thu Oct 22, 2015 3:44 am |
|
|
Simple.
Set CFGS back to FALSE at the end of the function.
Problem is that read_eeprom is _assuming_ that CFGS (which is the flag to say 'I want to talk to the configuration memory'), is set to 'FALSE' already when it is called. Silly programming.
You need CFGS set to TRUE, or the routine won't talk to the configuration memory... |
|
![](templates/subSilver/images/spacer.gif) |
mvanvliet
Joined: 02 Jun 2009 Posts: 123 Location: The Netherlands
|
|
Posted: Thu Oct 22, 2015 4:28 am |
|
|
Good idea to set the CFGS false after the function, I didn't thought about that. ![Rolling Eyes](images/smiles/icon_rolleyes.gif) |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|