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 support@ccsinfo.com

Global memory initialization

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



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

Global memory initialization
PostPosted: Tue Feb 18, 2014 5:33 pm     Reply with quote

Hi there,

As we all know, global variables are being set to 0 right before main() occurs. But how can I disable this?

The problem that I have is inside a bootloader, where, if I want to use 1k bytes of RAM, the compiler adds 2k bytes of ROM just to clear it with "CLRF" for each byte. That's rather ridiculous for a bootloader. Any idea how can I disable this and use my own clear loop?

Thanks,
Cezane.
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Tue Feb 18, 2014 5:41 pm     Reply with quote

I have found in manual that "static" keyword forces the value of specified global variable to 0. I wasn't expecting that...
temtronic



Joined: 01 Jul 2010
Posts: 9177
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Feb 18, 2014 6:41 pm     Reply with quote

curious...I just did a small program for the 18F46K22 and it's 397 words long.When I insert the #zero_ram directive, the program is only 13 words longer, no where near the 2K you've seen. I'd like to see your code(small program) that shows this 2K.

btw I've always been under the impression that unless _you_ , the programmer, specifically place values in RAM variables, that they can be anything, random in fact, based upon powerup time, static charge, whatever. I know there's nothing inside a PIC to force RAM to a known state upon powerup.


hth
jay
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 2:03 am     Reply with quote

Hi temtronic, try using this:
Code:
#define SE_RX_BUFF_SIZE      1024

static struct
{
   uint8 rx_buff[SE_RX_BUFF_SIZE];
   uint8 rx_last_byte;
   uint16 rx_count;
}se_data;

I'm using the same 18F46K22 with 4.138, and I'm not specifying #zero_ram. Surprisingly, the "static" keyword not only sticks with the module (which I don't think it really works), but also clears to 0. Confused
Ttelmah



Joined: 11 Mar 2010
Posts: 19382

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 3:22 am     Reply with quote

Static for a global, clearing to zero, is in the CCS manual:
"Variable is globally active and initialized to 0".
This is actually always the case in C. Look at:
<http://stackoverflow.com/questions/3373108/why-are-static-variables-auto-initialized-to-zero>
It is now part of the ANSI standard, which is why CCS does this...

In CCS, global variables, are not zeroed. Global variables are inherently 'static', without being declared as such (since the code always runs). Variables declared in main are also inherently 'static' without being declared as such. However they are only initialised, if they are declared as static, or if there is a value allocated to them.

ZERO_RAM, forces all of RAM to be zeroed (fairly obvious...).
Adds a tiny block of code to zero them. Size varies with the processor (PIC16's with bank switching, may take up to perhaps 30 bytes, while on processors with simpler memory maps, this is much smaller). Certainly not 2K. Declaring the variable as static, requires initialisation of a single defined area of memory. Not quite so efficient to do, but still not 2K.

So one solution if you want the variable to not be initialised, is to declare it externally (so global), not static. It is then not initialised. Use zero_ram, so it is initialised to zero.

Demo:
Code:

#include <18F46K22.h>
#device ADC=10

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(crystal=20000000)
#use rs232(baud=9600,parity=N,UART1,bits=8,stream=PORT1,errors)

#include <stdint.h>
#define uint8 uint8_t
#define uint16 uint16_t

#define SE_RX_BUFF_SIZE      1024

struct
{
   uint8 rx_buff[SE_RX_BUFF_SIZE];
   uint8 rx_last_byte;
   uint16 rx_count;
}se_data;

void main()
{
   while(TRUE)
   {
      delay_us(1);
   }
}
/*
               ROM used:   68 bytes (0%)
                           Largest free fragment is 65468
               RAM used:   1032 (26%) at main() level
                           1032 (26%) worst case
*/
//With no initialisation.
//Now add #zero_ram
/*
               ROM used:   94 bytes (0%)
                           Largest free fragment is 65442
               RAM used:   1032 (26%) at main() level
                           1032 (26%) worst case
*/
//So 26 bytes used to initialise.
//Now remove zero_ram, and instead make the variable static
/*
               ROM used:   150 bytes (0%)
                           Largest free fragment is 65386
               RAM used:   1032 (26%) at main() level
                           1032 (26%) worst case
*/
//So 82 bytes used to initialise
//declare the variable inside main as static, and it still only uses 82 bytes
//to initialise.


So the reason it is done, is to be standard.

To avoid your problem, declare it outside the function (so global), without using static, and if you want it cleared, use #zero_ram. Most efficient solution. However it should not be using 2K to clear the variable, unless there is some reason it cannot do the initialisation using a TBLRD operation. Even declared as static, it only uses 82 bytes to initialise it for me....

Best Wishes
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 3:41 am     Reply with quote

Pret wrote:
I have found in manual that "static" keyword forces the value of specified global variable to 0. I wasn't expecting that...


You should, it's standard C behaviour: statics that are not user initialised are nulled, which in the case of integers means zero. Globals and non-static locals are NOT set to any specific value unless the user does it explicitly in code. Statics in C are essentially global variables with local scope. Global statics are local in scope to the entire program.

That means that on a restart, whether warm or cold, you a) cannot assume what a non-static variable contains until its assigned a value and b) you can assume that, unless the hardware does something special, that a non-static variable will have the same value at start-up as it last had while running, allowing global variables to be held over a restart. Bear in mind that locals are not in an exclusive place in data memory; they, in one way or another, share memory temporally. Local variables may contain anything at every time they are instantiated and therefore should always be initialised or assigned a value before use. Other languages work differently, and many do initialise global and/or local variables in some way (in some cases to a special "not initialised" value, e.g. NaN for floats) but C, probably due to its systems programming/small footprint origins, does not.

CCS C, and some other compilers/runtime environments, has facilities for presetting variables at start of runtime. This is done by simply running through all non-user initialised RAM byte by byte (in the case of PICs, word by word on other architectures) and setting everything to 0. Floats which have all zero bytes are interpreted as 0.0, the null character for strings is \0, so all strings appear empty, all chars are \0 and all pointers are null. its not done variable by variable, but by contiguous data memory region.

User initialised variables are set differently, and probably take more effort in start up code, particularly is the values are not the equivalent of 0.

This means that the simplest and fastest initialisation is when #zero ram is not used, or if it is, then all user specified global variables are in one contiguous data memory region, and all unspecified variables in another contiguous region, allowing one simple zeroing loop. That's often difficult to arrange, or at least difficult to be sure of because the programmer doesn't normally have full control of the data memory map.
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 8:19 am     Reply with quote

Thanks guys.

As a personal programming tactic, I'm always initializing variables before using them, regardless of their location (global or local). In this specific case, in main() I'm calling mem_set(&se_data, 0, sizeof(se_data)), which has the obvious effect. Additionally, I wanted to limit the scope of my se_data to my .c file. And here we are...

Ttelmah, Here is a sample code:
Code:
#define SE_RX_BUFF_SIZE   1024

static struct
{
   uint8 rx_buff[SE_RX_BUFF_SIZE];
   uint8 rx_last_byte;
   uint16 rx_count;
}se_data;


void main()
{
   sleep();
}


And the output:
Code:

CCS PCH C Compiler, Version 4.138, 5967               19-feb.-14 16:09

               Filename:   D:\Programe\Pic\Electra\DAC\v1.1\tmp\boot.lst

               ROM used:   2130 bytes (3%)
                           Largest free fragment is 63406
               RAM used:   1035 (27%) at main() level
                           1035 (27%) worst case
               Stack:     0 locations

*
00000:  GOTO   main
.................... #define BOOTL_MAIN
.................... #include <boot.h>
.................... #include <18F46K22.h>
[...]
.................... ///////////////////////////////////////   Implementation  ////////////////////////
.................... 
.................... #define SE_RX_BUFF_SIZE   1024
.................... 
.................... static struct
.................... {
....................    uint8 rx_buff[SE_RX_BUFF_SIZE];
....................    uint8 rx_last_byte;
....................    uint16 rx_count;
.................... }se_data;
.................... 
.................... 
.................... void main()
.................... {
00004:  CLRF   TBLPTRU
00006:  BCF    RCON.IPEN
00008:  CLRF   FSR0H
0000A:  CLRF   FSR0L
0000C:  CLRF   cs_recurse
0000E:  MOVLW  70
00010:  MOVWF  OSCCON
00012:  BSF    OSCTUNE.PLLEN
00014:  BCF    OSCTUNE.INTSRC
00016:  MOVF   ADCON1,W
00018:  ANDLW  F0
0001A:  MOVWF  ADCON1
0001C:  MOVLW  00
0001E:  MOVLB  F
00020:  MOVWF  x38
00022:  MOVWF  x3C
00024:  MOVWF  x39
00026:  MOVWF  x3A
00028:  MOVWF  x3B
0002A:  MOVLB  1
0002C:  CLRF   x88
0002E:  CLRF   CM2CON1
00030:  CLRF   CM2CON0
00032:  CLRF   CM1CON0
00034:  MOVLB  0
00036:  CLRF   se_data
00038:  CLRF   se_data+1
0003A:  CLRF   se_data+2
0003C:  CLRF   se_data+3
0003E:  CLRF   se_data+4
00040:  CLRF   se_data+5
00042:  CLRF   se_data+6
00044:  CLRF   se_data+7
00046:  CLRF   se_data+8
00048:  CLRF   se_data+9
0004A:  CLRF   se_data+10
0004C:  CLRF   se_data+11
0004E:  CLRF   se_data+12
00050:  CLRF   se_data+13
00052:  CLRF   se_data+14
00054:  CLRF   se_data+15
00056:  CLRF   se_data+16
00058:  CLRF   se_data+17
0005A:  CLRF   se_data+18
0005C:  CLRF   se_data+19
0005E:  CLRF   se_data+20
00060:  CLRF   se_data+21
00062:  CLRF   se_data+22
00064:  CLRF   se_data+23
00066:  CLRF   se_data+24
00068:  CLRF   se_data+25
0006A:  CLRF   se_data+26
0006C:  CLRF   se_data+27
0006E:  CLRF   se_data+28
00070:  CLRF   se_data+29
[...]    // --------------------------------- skip
0082E:  CLRF   se_data+1016
00830:  CLRF   se_data+1017
00832:  CLRF   se_data+1018
00834:  CLRF   se_data+1019
00836:  CLRF   se_data+1020
00838:  CLRF   se_data+1021
0083A:  CLRF   se_data+1022
0083C:  CLRF   se_data+1023
0083E:  CLRF   se_data
00840:  CLRF   se_data+1025
00842:  CLRF   se_data+1026
....................    sleep();
00844:  MOVFF  OSCCON,00
00848:  BCF    OSCCON.IDLEN
0084A:  SLEEP
0084C:  MOVFF  00,OSCCON
.................... }
.................... 
.................... 
00850:  SLEEP

Configuration Fuses:
   Word  1: 2800   INTRC_IO NOPLLEN PRIMARY_ON NOFCMEN NOIESO
   Word  2: 3E18   PUT NOBROWNOUT BORV19 WDT_SW WDT32768
   Word  3: 1D00   CCP2C1 NOPBADEN CCP3B5 HFOFST TIMER3C0 CCP2C0 NOMCLR
   Word  4: 0080   NOSTVREN NOLVP NOXINST NODEBUG
   Word  5: 0000   PROTECT CPB CPD
   Word  6: A00F   NOWRT NOWRTC WRTB NOWRTD
   Word  7: 000F   NOEBTR EBTRB

If I simply remove the static, the code size is 66 bytes.
Ttelmah



Joined: 11 Mar 2010
Posts: 19382

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 8:57 am     Reply with quote

It's a 'late V4 compiler bug'.....

I don't see why you want to declare the variable as static.
No point at all. A global variable is always static in CCS, with the one difference that it is not initialised.
You gain nothing by declaring it as static.
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 10:14 am     Reply with quote

What I was hoping with static is to limit the visibility of that variable to that particular module. I wanted to give access to the module (driver) only through its routines, and deny access to any internal variables. Some kind of encapsulation.
jeremiah



Joined: 20 Jul 2010
Posts: 1329

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 11:27 am     Reply with quote

To be honest, I've never tried, but I'm not sure if CCS supports that feature of static or not. Have you tested to see if it actually provides that?
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 12:34 pm     Reply with quote

That's exactly my point. It doesn't. The main purpose of static keyword is not working.
jeremiah



Joined: 20 Jul 2010
Posts: 1329

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 2:58 pm     Reply with quote

My apologies then. I only saw the discussion on the initialization part. I missed the scoping discussion.
#module might be something to play with. I haven't used it, but it might help with what you want.
Ttelmah



Joined: 11 Mar 2010
Posts: 19382

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 3:16 pm     Reply with quote

CCS supports what you want, with 'EXCEPT' in the EXPORT options.

Best Wishes
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

PostPosted: Thu Feb 20, 2014 8:43 am     Reply with quote

Well yeah, but it's far from being elegant...
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