![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
Global memory initialization |
Posted: Tue Feb 18, 2014 5:33 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Tue Feb 18, 2014 5:41 pm |
|
|
I have found in manual that "static" keyword forces the value of specified global variable to 0. I wasn't expecting that... |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Tue Feb 18, 2014 6:41 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed Feb 19, 2014 2:03 am |
|
|
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](images/smiles/icon_confused.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Wed Feb 19, 2014 3:22 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Wed Feb 19, 2014 3:41 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed Feb 19, 2014 8:19 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Wed Feb 19, 2014 8:57 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed Feb 19, 2014 10:14 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1329
|
|
Posted: Wed Feb 19, 2014 11:27 am |
|
|
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? |
|
![](templates/subSilver/images/spacer.gif) |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed Feb 19, 2014 12:34 pm |
|
|
That's exactly my point. It doesn't. The main purpose of static keyword is not working. |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1329
|
|
Posted: Wed Feb 19, 2014 2:58 pm |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Wed Feb 19, 2014 3:16 pm |
|
|
CCS supports what you want, with 'EXCEPT' in the EXPORT options.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Thu Feb 20, 2014 8:43 am |
|
|
Well yeah, but it's far from being elegant... |
|
![](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
|