Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

C18 variables overlapping!

Status
Not open for further replies.

Pommie

Well-Known Member
Most Helpful Member
I wrote some code earlier and couldn't get it to work. It turned out that two of my buffers were overlapping. I've chopped it down to minimal code but can't see what I have done wrong.

Can someone confirm that this code,
Code:
#include <p18f1320.h>

#pragma config WDT = OFF, LVP = OFF, OSC = INTIO2, DEBUG = OFF, MCLRE = ON

unsigned char IDbuffer[]=
        {0x01,0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,0x90};


void StoreID(unsigned char* Data){
unsigned char buff[80];
    while(1);
}

void main(void){
char Count;
    OSCCON=0x70;
    StoreID(&IDbuffer[0]);
    while(1){
    }
}
when run and then paused results in the following variable allocations,
buff = 0x85 to 0xd4
IDbuffer = 0xc4 to 0xcd

Can someone confirm they see the same results and it's not some quirk of my setup?
Can anyone explain why IDbuffer is in the middle of buff?

I've tried using #pragma idata and various other things but I just can't get this initialised ram array to work.

I'm sure there's some simple reason why this doesn't work but I just can't see it at the moment.

Thanks,

Mike.
 
Infact they do overlap ill try to see why. It may be a linker issue.

STACK SIZE=0x40 RAM=gpr0

Code:
// File: 18f1320.lkr
// Sample linker script for the PIC18F1320 processor

LIBPATH .

FILES c018i.o
FILES clib.lib
FILES p18f1320.lib

CODEPAGE   NAME=page       START=0x0               END=0x1FFF
CODEPAGE   NAME=idlocs     START=0x200000          END=0x200007       PROTECTED
CODEPAGE   NAME=config     START=0x300000          END=0x30000D       PROTECTED
CODEPAGE   NAME=devid      START=0x3FFFFE          END=0x3FFFFF       PROTECTED
CODEPAGE   NAME=eedata     START=0xF00000          END=0xF000FF       PROTECTED

ACCESSBANK NAME=accessram  START=0x0            END=0x7F
DATABANK   NAME=gpr0       START=0x80           END=0xFF
ACCESSBANK NAME=accesssfr  START=0xF80          END=0xFFF          PROTECTED

SECTION    NAME=CONFIG     ROM=config

STACK SIZE=0x40 RAM=gpr0

Max memis 0x7F which is less than 0x80 by 1 byte so you are way over board here. Your 1 variable takes up entire access ram. And such the ID Variable takes over or points to the last 10 bytes.

If you rewrite the code like:
Code:
#include <p18f1320.h>

#pragma config WDT = OFF, LVP = OFF, OSC = INTIO2, DEBUG = OFF, MCLRE = ON

unsigned char buff[80];
unsigned char IDbuffer[]=
        {0x01,0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,0x90};


void StoreID(unsigned char* Data){

    while(1);
}

void main(void){
char Count;
    OSCCON=0x70;
    StoreID(&IDbuffer[0]);
    while(1){
    }
}

you will see the error:
Code:
MPLINK 4.20, Linker
Copyright (c) 2008 Microchip Technology Inc.
Error - section '.udata_main.o' can not fit the section. Section '.udata_main.o' length=0x00000050
Errors    : 1
 
Last edited:
hi Mike,
As you know I am not a C person.
Looking at your IDbuffer & char buff[80] the only difference I can see is that you have defined a char_bfr as 80 long static and IBuff as[] undimensioned as dynamic.??


Code:
unsigned char IDbuffer[]=
        {0x01,0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,0x90};


void StoreID(unsigned char* Data){
unsigned char buff[80];
 
if you put:
IDbuffer[10];

you will still get a overlap. (just tried it) I know it has to do with linker but i dont know how to fix. These linker things suck really. Where would one get the information from to make a linker script? The datasheet i suppose... so im off to read it to hopefully modify the link to work with it.
 
hi Mike,
As you know I am not a C person.
Looking at your IDbuffer & char buff[80] the only difference I can see is that you have defined a char_bfr as 80 long static and IBuff as[] undimensioned as dynamic.??


Code:
unsigned char IDbuffer[]=
        {0x01,0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,0x90};


void StoreID(unsigned char* Data){
unsigned char buff[80];


Hi Eric,

Even if I change it to IDbuffer[10] it's still the same. I'm guessing that there is something I don't understand about initialised global ram variables.

Thanks anyway,

Mike.
 
C generally puts local auto variables of a function on the stack. You stack has a max size of 64 (0x40) bytes so your buff[80] is too large to fit on the stack. Don't confuse this with the hardware stack. This stack is managed by the C compiler and uses the FSR registers.
EDIT: You can change the allocation size of the stack by editing the linker script file. You'll see the change in the "memory usage gauge" after you recompile.
 
Last edited:
Hi kcriste,

I was under the (wrong) impression that the stack and variable area were located in the 256 bytes of ram and one would grow up and the other down.

I managed to fix it by changing the linker script to,
Code:
ACCESSBANK NAME=accessram  START=0x0            END=[COLOR="Blue"]0x3F[/COLOR]
DATABANK   NAME=gpr0       START=[COLOR="blue"]0x40[/COLOR]           END=0xF3
DATABANK   NAME=dbgspr     START=0xF4           END=0xFF           PROTECTED
ACCESSBANK NAME=accesssfr  START=0xF80          END=0xFFF          PROTECTED

SECTION    NAME=CONFIG     ROM=config

STACK SIZE=[COLOR="blue"]0x60[/COLOR] RAM=gpr0

I'm still unclear what the accessram area is. Guess it's time to read that linker documentation.

<edit>BTW, I only needed a 64 byte buffer and changed it to 80 to exaggerate the problem.</edit>

Mike.
 
Last edited:
I just downloaded the latest version of the C18 compiler (3.22) and you no longer have to include a linker script. This solved the problem without any changes.

<edit> Make sure you click the option to use the latest MPLINK in MPLAB.</edit>

Mike.
 
Last edited:
I'm still unclear what the accessram area is. Guess it's time to read that linker documentation.
It's the area of RAM that can be accessed by setting the access bit in an 18F instruction. It eliminates any need for bank switching. Variables that are used frequently are put in the access RAM for better code efficiency. The SFRs are also in this area which is split into two parts just to confuse things further.
Pommie said:
I just downloaded the latest version of the C18 compiler (3.22) and you no longer have to include a linker script.
I'll have to update mine too. Thanks for the reminder.
 
Last edited:
It's the area of RAM that can be accessed by setting the access bit in an 18F instruction. It eliminates any need for bank switching. Variables that are used frequently are put in the access RAM for better code efficiency. The SFRs are also in this area which is split into two parts just to confuse things further.

Maybe I should have worded it better. What I meant was, what does the compiler use it for. The map file for the above code shows 2 bytes used out of 128 total and yet I get a stack crash because the compiler is cramming everything into the top 128 bytes. Even on the most complex program I have (using a 1320) there is still only 35 bytes of accessram used.

Mike.
 
To put something in access RAM, you're supposed to use the near qualifier under main, but it doesn't appear to work in the version I have. Now I really have to try the updated version. :D
Otherwise, I think the compiler just uses the access RAM for internal scratch pad use.
 
I moved the IDbuffer into access ram by doing,
Code:
#include <p18f1320.h>

#pragma config WDT = OFF, LVP = OFF, OSC = INTIO2, DEBUG = OFF, MCLRE = ON

#pragma idata access IDbuff
near ram unsigned char IDbuffer[]=
        {0x01,0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,0x90};
#pragma code

void StoreID(near ram unsigned char* Data){
unsigned char buff[80];
    while(1);
}

void main(void){
char Count;
    OSCCON=0x70;
    StoreID(IDbuffer);
    while(1){
    }
}

I must say I'm surprised that when the access area is empty the compiler doesn't "upgrade" variables to optimize the code.

BTW, installing the latest version resets the evaluation period and so all optimizations work for another 60 days.

Mike.
 
Yes, it seems silly that the compiler will just ignore all that extra memory. I guess ANSI C has no definition of banked memory; but you would have thought MicroChip would have broken the rules a bit to make it work better.
#pragma idata access IDbuff
Ahh. That's what I was forgetting. :eek:
 
Excellent thread, helped me start reading about the details of compilers :)

C generally puts local auto variables of a function on the stack. You stack has a max size of 64 (0x40) bytes so your buff[80] is too large to fit on the stack. Don't confuse this with the hardware stack. This stack is managed by the C compiler and uses the FSR registers.

1) Because I am a bit confused, instead of FSR you mean GPRs right?
2) So that stack is used when a function is called so that it can pass around the variable?
3) If so, why is that a problem in Pommie's program since what is passed, it is actually the address of the first array element (i.e. the stack should be enough)?

Thanks!
 
The problem with my code was that the compiler places local variables on the stack and so my 80 byte variable overflowed the 50ish byte stack. You are correct that only the address of the array was passed but the function defined a local variable that had to be placed on the stack as well.

I'll try to answer your questions,
1. The FSR register is actually an indirect memory pointer and is used (by C) to access the software stack.
2. Yes. It's also used to return values.
3. See above.

Mike.
 
You are correct that only the address of the array was passed but the function defined a local variable that had to be placed on the stack as well.
...
2. Yes. It's also used to return values.
...
Hi and thanks for the reply.

Why is buffer placed on the stack if it only used locally? As you said in answer 2 (above) stack is used when data is passed or returned. However, buffer variable is just used locally and it's not passed or returned, so why is it placed in the stack?

Thanks! This is really interesting :)
 
It's placed on the stack because it is temporary and the only safe place to use is the stack area. When a function is called, the passed variables are placed on the stack, the local variables are then allocated (placed on) stack space and finally when the return directive is met the stack is cleared and the return value is added.

Imagine trying to sort out local variables in non stack area.:eek:

Mike.
 
Last edited:
Why is buffer placed on the stack if it only used locally?
To add to Pommie's comments:
Another advantage of placing variables, local to a function, on the stack is that it saves memory. When the function returns, the memory for the local variable is freed, and ready to be used by the next function. ie: You could have 8 different functions, each with 128 bytes of local variables, on a chip with only 256 bytes of RAM. This assumes that only one function is called at a time.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top