|
|
View previous topic :: View next topic |
Author |
Message |
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
ROM & CONST confusing? |
Posted: Wed May 04, 2011 2:32 pm |
|
|
I have made a _small_ test program to explain the problem. It will run perfect in hardware. it is compiled with 4.121.
The problem is I still don't understand why the function there handle the Data as CONST wont send the right data. The function using ROM working 100%.
I confused when using CONST and try to pass it to a function there will use it.
Is this a compiler problem or the programmer?
Code: |
#include "18f4550.h"
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTHS //Internal RC Osc, no CLKOUT
#Fuses PLL1 //No PLL
#Fuses CPUDIV1 //No System PostScaler
#fuses ICSP1 //ICD uses PGC1/PGD1 pins
#Device PASS_STRINGS=IN_RAM
#use delay(clock=8M)
#use RS232(Baud=9600,UART1,ERRORS)
//Data
rom int8 keyR[14] = {0x65,0x51,0x90,0x00,0x72,0x05,0x00,0x01,0x00,0x00,0x00,0x01,0x78,0xa2};
const int8 keyC[14] = {0x65,0x51,0x90,0x00,0x72,0x05,0x00,0x01,0x00,0x00,0x00,0x01,0x78,0xa2};
//This use ROM to handle the data | Working
void SendKeyRom(int16 ptr){
int8 i;
int8 Buf[14];
read_program_memory(ptr,&Buf,14);
printf("ROM:");
for (i=0;i<14;i++)
printf("%x,",Buf[i]);
printf("\r\n");
}
//This use CONST to handle the data | This is not sending the data right!!!!!
void SendKeyConst(int16 *ptr){
int8 i;
printf("CONST:");
for (i=0;i<14;i++)
printf("%x,",ptr[i]);
printf("\r\n");
}
void CpuInit(){
setup_oscillator(OSC_8MHZ);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
SETUP_ADC(ADC_OFF);
SETUP_ADC_PORTS(NO_ANALOGS);
enable_interrupts(Global);
}
void main(){
CpuInit();
printf("Start\r\n");
while (1){
SendKeyRom(KeyR);//Send ROM Data
SendKeyConst(KeyC);//Send CONST Data
delay_ms(1500);
}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 04, 2011 11:10 pm |
|
|
In the code below, you're telling the compiler that you're passing a
pointer to 16-bit values. But in fact, the array is composed of 'int8' values.
So that's bug. It should be 'int8' below:
Quote: |
void SendKeyConst(int16 *ptr){
int8 i;
printf("CONST:");
for (i=0;i<14;i++)
printf("%x,",ptr[i]);
printf("\r\n");
} |
Also, the #device statement and the array below are causing problems.
Quote: | #Device PASS_STRINGS=IN_RAM
const int8 keyC[14] = {0x65,0x51,0x90,0x00,0x72,0x05,0x00,0x01,0x00,0x00,0x00,0x01,0x78,0xa2};
|
The #device statement is expecting a string, which is a sequential array
of ASCII characters with a final byte of 0x00 to indicate the end of the
string. But your keyC array is not a string. It's an array of random bytes
with some embedded nulls (0x00) in it. So the compiler looks at that
array at compile-time and notices how long it is, in terms of a string.
And as string, it's only 4 bytes long. Look at the .SYM file. The compiler
has only allocated 4 bytes to the temporary array that it uses to "pass
strings in ram":
Code: |
006-009 MAIN.@STRPARAM
|
Then look at what comes right after that. It's the address of your ROM
array data.
Code: | 00A-00B SendKeyRom.ptr
|
If you go to View / Program Memory in MPLAB, and scroll all the way to end, you'll see the ROM array data has been placed at address 0x7FF2.
So now, finally, we can explain the bad data:
Quote: | CONST:65 51 90 00 f2 7f 06 00 08 08 00 72 05 00 |
The first 4 bytes are from the expected array data. But because the
@STRPARAM buffer is only 4 bytes long, we're now reading data from
RAM locations that occur after that point. And the first thing we read
is the Rom ptr, which is the address of the ROM data, which is 0x7FF2.
The printed bytes are "f2 7F" because the compiler stores words in
"low-high" byte format.
This is a very long discussion on a simple thing, which is don't use
#device PASS_STRINGS=IN_RAM with non-string data. Instead, you
should use the "rom ptr" method, which you are doing in the other half
of your test program. |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Thu May 05, 2011 2:37 am |
|
|
Thanks for your big job on this.
I now understand some of my problem before when using #Device PASS_STRINGS=IN_RAM
But if I not using "#Device PASS_STRINGS=IN_RAM " I have problem with all my string handed over to functions.
Will the conclusion then be: It is not possible to use CONST array of byte with CCS compiler?
Will the _only_ solution the be to us ROM? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Thu May 05, 2011 4:23 am |
|
|
Key here is the design of the PIC, and history.
Historically, PIC's had no direct ability to read from their ROM. Constants were handled, by generating a subroutine of RETLW instructions, with an offset jump, so if you wanted 'element 20', the code jumped to the 20th RETLW instruction, and returned the value from this. Now this was a _hardware limitation of the chips_. For this mode of operation, CCS used the 'const' name.
Then separately, when latter chips began to appear that offered software abilities to read from a location in ROM, you have to remember that the RAM, and ROM address spaces are distinct. So you can have an element '100', in the ROM space, and also an element '100', in the RAM space. This differs from processors like those on the PC, which have a linear address space. This brings with it a problem, that if you define an address '100', how do you know which 'space' it refers to?. You need to add an extension to the addressing.
So, CCS _by default_ (you can change this behaviour), kept the 'const' name for a read only access, _without the ability to construct a pointer_. The ROM name, also builds a constant table, stored in the ROM,_but adds the code to support pointer construction_.
CCS added a 'trick', to the const form, so that for example, you could build a function to print a single character, and then call it with:
single_char_func("constant string");
and the compiler will automatically call the function multiple times, with each successive character from the string. A useful 'workround' for the inability to construct a pointer, on the older chips.
Then there was a third complication. On ANSI C, the defaults, assume you are working with a system like a PC. On this, though there is 'ROM', this is not accessible to the normal 'runtime' programmer. However there are occasions where you want to have 'variables' declared containing values that are not changeable from the runtime code. This is the ANSI 'const'. To simulate this on the PIC, the 'PASS_STRINGS_IN_RAM' control came about, declaring a constant string, which is then automatically copied to RAM, before use, allowing a normal RAM pointer to be constructed.
Why are you 'against' just using the ROM keyword?. This builds a constant table in ROM, and allows pointer accesses so an address can be passed to a function. It is what it is 'there for'....
If you want _const_ to default to behaving this way, just use the compiler switch:
#device CONST=ROM
This then makes const support pointer construction _but has a slight code overhead when using 'const' values for which a pointer is not needed_.
Best Wishes |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Thu May 05, 2011 2:58 pm |
|
|
Thanks for this.
This explain my confusing.
So, CCS _by default_ (you can change this behaviour), kept the 'const' name for a read only access, _without the ability to construct a pointer_
Thanks to both of you. |
|
|
|
|
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
|