EmbDev.net

Forum: ARM programming with GCC/GNU tools problem with global variable


von Abhijeet B. (xmonito)


Rate this post
useful
not useful
Hi All,

 I'm writing a test code trying to send a character using UART. Now that
is running perfectly fine as long as i declare the character in main.

void sendchar(char ch)
{
  U0THR= ch;
  while (!(U0LSR & 0x20));
}

int main()
{
 unsigned char tc= 'a';
....................
....................
    while(1)
    {
  sendchar(tc);
    }
}
This runs like anything but when i make the character global, nothing is
sent. I figure it has something to do wid my ROM.ld which looks like:

ENTRY(_boot)
STACK_SIZE = 0x800;

/* Memory Definitions */
/* lpc2129 mt */
MEMORY
{
  ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x0003E000
  RAM (rw) : ORIGIN = 0x40000000, LENGTH = 0x00004000
}

/* Section Definitions */
SECTIONS
{
  /* first section is .text which is used for code */
   .text :
  {
  KEEP(*(.init))             /* Startup code from .init-section */
  *(.text .text.*)           /* remaining code */
  *(.gnu.linkonce.t.*)
  *(.glue_7)
  *(.glue_7t)
  *(.gcc_except_table)
  *(.rodata)                 /* read-only data (constants) */
  *(.rodata*)
  *(.gnu.linkonce.r.*)
  } > ROM

  /***** old:
  .text :
  {
    *crt0.o (.text)
    *(.text)
    *(.rodata)
    *(.rodata*)
    *(.glue_7)
    *(.glue_7t)
  } > ROM
  *****/

  . = ALIGN(4);

  /* .ctors .dtors are used for c++ constructors/destructors */
  /* added by Martin Thomas 4/2005 based on Anglia Design example */
  .ctors :
  {
    PROVIDE(_ctors_start_ = .);
    KEEP(*(SORT(.ctors.*)))
    KEEP(*(.ctors))
    PROVIDE(_ctors_end_ = .);
  } >ROM

  .dtors :
  {
    PROVIDE(_dtors_start_ = .);
    KEEP(*(SORT(.dtors.*)))
    KEEP(*(.dtors))
    PROVIDE(_dtors_end_ = .);
  } >ROM

    . = ALIGN(4);
  /* mthomas - end */

  _etext = . ;
  PROVIDE (etext = .);

  /* .data section which is used for initialized data */
  .data : AT (_etext)
  {
    _data = .;
    *(.data)
  *(.data.*)
  *(.gnu.linkonce.d*)
  SORT(CONSTRUCTORS) /* mt 4/2005 */
  . = ALIGN(4);
  *(.fastrun)
  } > RAM

  . = ALIGN(4);
  _edata = . ;
  PROVIDE (edata = .);

  /* .bss section which is used for uninitialized data */
  .bss (NOLOAD):
  {
    __bss_start = . ;
    _bss_start_ = . ;
    *(.bss)
  *(.gnu.linkonce.b*)
    *(COMMON)
    . = ALIGN(4);
  } > RAM

  . = ALIGN(4);
  _bss_end_ = . ;
  PROVIDE (__bss_end = .);

  .stack :
  {
    . = ALIGN(256);
    . += STACK_SIZE;
    PROVIDE (_stack = .);
  } > RAM


  _end = . ;
  PROVIDE (end = .);


Is there any problem here or the *(COMMON)? I tried deleting (NOLOAD)
but that caused .stack to fail. Other functions werent being called so i
assumed that.. Can anyone tell wat i'm doing wrong?

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
Also global variables should be in the data section i presume, I have no
idea wats going wrong then!

von Clifford S. (clifford)


Rate this post
useful
not useful
So you posted the code that works but merely described the code that
fails! Now let's think... what could possibly be the flaw in that
approach to asking questions!?

It seems to be if nothing is being sent than sendchar is not being
called. How are you testing this? If the global is not initialised it
may be sending NUL and most terminal emulators will ignore NUL
characters. Make sure you are using a tool that will show all
characters.

If the global is initialised in your code there may be a problem with
your C runtime initialisation (typically in crt0.s). This is responsible
for copying the initialisation data to the DATA segment in RAM.

The simplest way to work out what is wrong is to step the code in the
debugger.

Clifford

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
To Clifford,

Quite interestingly my code runs well with all other compilers that do
not boast of compliance with so called standards, though they do comply,
being proprietary however i cant use them for free. I'm very satisfied
with winarm however, being able to solve the problems myself. I know
you'll like that. Now, upon initialization of a global variable during
declaration itself assigning a value other than null the value still
remains null if not assigned a value during execution before its use.
I'm really new to this compiler, I started only few days back and things
that I've taken for granted with other compilers don't work. Many
changes I've made to crt0.s which are not even relevant to target
machine, to make it work. Thanks to this forum for that. Also, thanks
for your prompt replies you seem to have spent lot of time doing this,
while i spent that time doing something else, still worthwhile. And yes
debugger, it sure is there.


Abhijit

von Clifford S. (clifford)


Rate this post
useful
not useful
Abhijeet Bokil wrote:

> Quite interestingly my code runs well with all other compilers that do
> not boast of compliance with so called standards, though they do comply,
> being proprietary however i cant use them for free.

Code that runs when built with another compiler is not the same as
correct code. The conclusion: "it works in another compiler so it cannot
be the code" is a dangerous and usually flawed conclusion.

A different compiler (or even the same compiler with different options)
will generate different code and allocate memory differently; so for
example a bug that corrupts memory will only cause an observable error
is that corrupt memory is later used - and even then it may not do-so -
it depends on the nature of the corruption and the affect that has on
the code that uses it. Another cause of execution differences is the use
of undefined or implementation defined language behaviour.


Clifford

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
> Code that runs when built with another compiler is not the same as
> correct code. The conclusion: "it works in another compiler so it cannot
> be the code" is a dangerous and usually flawed conclusion.


Aaaah! You get me wrong! I haven't used the word "correct" or
"incorrect" code i've merely remarked upon the tendency, by which know,
that i only mean not working here. From my,

> things that I've taken for granted with other compiler

you can understand that i know c is implemented differently depending on
compiler and that it is the ability of the cross compiler to make
"Whatever" of the code. So correct code may not actually be correct, or
output sub optimal. In this case the corruption as you said is exactly
what i'm pointing at.

von Clifford S. (clifford)


Rate this post
useful
not useful
Abhijeet Bokil wrote:
> So correct code may not actually be correct, ...

No you are still making no sense. You are implying that the compiler is
generating incorrect object code from correct source, when that is
the least likely explanation. Apply Occam's razor to this.

I can only assume that you have either solved this problem or that you
do not wish to solve it as you are not providing the requested
information:

1) Post the non-working code (you only posted code that works, which I
find bizarre!)

2) Use a tool such as portmon
(http://www.microsoft.com/technet/sysinternals/utilities/portmon.mspx)
to determine exactly what is being output if anything.

3) Confirm whether or not the 'global' is being correctly assigned or
initialised. You have not been clear about this. (which is why you ought
to post the code!).

4) I suggested using a debugger and you merely said "it sure is there".
I don't know what that even means! Being 'there' is insufficient - you
have to use it!

If you have modified crt0.s you may have messed up global
initialisation. But no one here reads minds. You have possibly
over-localised your problem. but you did not even posted the code to
which you have localised it that does not help in any case.

If you cannot coherently address these points I doubt I can assist
further.

Clifford

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
>No you are still making no sense. You are implying that the compiler is
>generating incorrect object code from correct source, when that is
>the least likely explanation.

See, by compiler i meant the entire toolchain, linker as well. Lets say
thats my mistake. I'm NOT doubtful about the object code.


Here is the non-working code:

#include <LPC21xx.h>

unsigned char ch='a';

void sendchar(char ch)
{
  U0THR= ch;
  while (!(U0LSR & 0x20));
}


void sys_config()
{
  PINSEL0 = 0x00000005;
  IO0DIR = 0x00000000;

  U1LCR = 0x83;                /* 8 bits, no Parity, 1 Stop bit     */
  U1DLL = 0x034;
    U1DLM = 0x00;                /* 57600 Baud Rate @ 60MHz VPB Clock
*/
    U1LCR = 0x03;                /* DLAB = 0                          */

    PLLCFG  =  0x22;        /* Settings Pclk <-3* XTAL    */
    PLLCON  =  0x01;
    PLLFEED  =  0xAA;
    PLLFEED  =  0x55;
    while(!(PLLSTAT & 0x400));
    PLLCON  =  0x03;
    PLLFEED  =  0xAA;       /* Set the PLL settings    */
    PLLFEED  =  0x55;

    VPBDIV  =  0x00000001;  /* PCLK SET TO 60 MHz    */

    /* Uart0 Serial Port Baud Settings */

  U0FCR  =  0x01;
  U0LCR  =  0x83;
  U0DLL  =  0x41;       /* BAUD RATE UART0 57600  */
  U0DLM  =  0x00;
  U0LCR  =  0x03;
}

int main()
{
  sys_config();

   while(1)
    {
    sendchar(ch);
  }
  return 0;
}




And here is my crt0.S

//////////////////////////////////////////////////////////////////////// 
//

/*
 crt0.S for LPC2xxx
 - based on examples from R O Software
 - based on examples from newlib-lpc
 - based on an example from Anglia Designs

 collected and modified by Martin Thomas
*/

        .global _etext                  // -> .data initial values in
ROM
        .global _data                   // -> .data area in RAM
        .global _edata                  // end of .data area
        .global __bss_start             // -> .bss area in RAM
        .global _bss_end_             // end of .bss area
        .global _stack                  // top of stack

// Stack Sizes
        .set  UND_STACK_SIZE, 0x00000004
        .set  ABT_STACK_SIZE, 0x00000004
        .set  FIQ_STACK_SIZE, 0x00000004
        .set  IRQ_STACK_SIZE, 0X00000080
        .set  SVC_STACK_SIZE, 0x00000004
        .set  USR_STACK_SIZE, 0x00000400  // modified


// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
        .set  MODE_USR, 0x10            // User Mode
        .set  MODE_FIQ, 0x11            // FIQ Mode
        .set  MODE_IRQ, 0x12            // IRQ Mode
        .set  MODE_SVC, 0x13            // Supervisor Mode
        .set  MODE_ABT, 0x17            // Abort Mode
        .set  MODE_UND, 0x1B            // Undefined Mode
        .set  MODE_SYS, 0x1F            // System Mode

        .equ  I_BIT, 0x80               // was 0x80 when I bit is set,
IRQ is disabled
        .equ  F_BIT, 0x40               // when F bit is set, FIQ is
disabled

        .text
    .arm
    .section .init, "ax"

        .code 32
        .align 2

        .global _boot
        .func   _boot
_boot:

// Runtime Interrupt Vectors
// -------------------------
Vectors:
        b     _start                    // reset - _start
        ldr   pc,_undf                  // undefined - _undf
        ldr   pc,_swi                   // SWI - _swi
        ldr   pc,_pabt                  // program abort - _pabt
        ldr   pc,_dabt                  // data abort - _dabt
        nop                             // reserved
        ldr   pc,[pc,#-0xFF0]           // IRQ - read the VIC
        ldr   pc,_fiq                   // FIQ - _fiq

#if 0
// Use this group for production
_undf:  .word _reset                    // undefined - _reset
_swi:   .word _reset                    // SWI - _reset
_pabt:  .word _reset                    // program abort - _reset
_dabt:  .word _reset                    // data abort - _reset
_irq:   .word _reset                    // IRQ - _reset
_fiq:   .word _reset                    // FIQ - _reset

#else
// Use this group for development
_undf:  .word __undf                    // undefined
_swi:   .word __swi                     // SWI
_pabt:  .word __pabt                    // program abort
_dabt:  .word __dabt                    // data abort
_irq:   .word __irq                     // IRQ
_fiq:   .word __fiq                     // FIQ


__undf: b     .                         // undefined
__swi:  b     .                         // SWI
__pabt: b     .                         // program abort
__dabt: b     .                         // data abort
__irq:  b     .                         // IRQ
__fiq:  b     .                         // FIQ



#endif

       .size _boot, . - _boot
        .endfunc


// Setup the operating mode & stack.
// ---------------------------------
        .global _start, start, _mainCRTStartup
        .func   _start

_start:
start:
_mainCRTStartup:

// Initialize Interrupt System
// - Set stack location for each mode
// - Leave in System Mode with Interrupts Disabled
// -----------------------------------------------
        ldr   r0,=_stack
        msr   CPSR_c,#MODE_UND|I_BIT|F_BIT // Undefined Instruction Mode
        mov   sp,r0
        sub   r0,r0,#UND_STACK_SIZE
        msr   CPSR_c,#MODE_ABT|I_BIT|F_BIT // Abort Mode
        mov   sp,r0
        sub   r0,r0,#ABT_STACK_SIZE
        msr   CPSR_c,#MODE_FIQ|I_BIT|F_BIT // FIQ Mode
        mov   sp,r0
        sub   r0,r0,#FIQ_STACK_SIZE
        msr   CPSR_c,#MODE_IRQ|I_BIT|F_BIT // IRQ Mode
        mov   sp,r0
        sub   r0,r0,#IRQ_STACK_SIZE
        msr   CPSR_c,#MODE_SVC|I_BIT|F_BIT // Supervisor Mode
        mov   sp,r0
        sub   r0,r0,#SVC_STACK_SIZE
//        msr   CPSR_c,#MODE_SYS|I_BIT|F_BIT // System Mode   if
commented using modified code for USR mode
//        mov   sp,r0

        msr   CPSR_c,#MODE_USR
        mov   sp, r0

#  Setup a default Stack Limit (when compiled with "-mapcs-stack-check")
        sub   sl, sp, #USR_STACK_SIZE



// Clear .bss
// ----------
        mov   r0,#0                     // get a zero
        ldr   r1,=__bss_start           // -> bss start
        ldr   r2,=__bss_end__           // -> bss end
2:      cmp   r1,r2                     // check if data to clear
        strlo r0,[r1],#4                // clear 4 bytes
        blo   2b                        // loop until done

// Copy initialized data to its execution address in RAM
// -----------------------------------------------------
#ifdef ROM_RUN
        ldr   r1,=_etext                // -> ROM data start
        ldr   r2,=_data                 // -> data start
        ldr   r3,=_edata                // -> end of data
1:      cmp   r2,r3                     // check if data to move
        ldrlo r0,[r1],#4                // copy it
        strlo r0,[r2],#4
        blo   1b                        // loop until done
#endif

/*
   Call C++ constructors (for objects in "global scope")
   ctor loop added by Martin Thomas 4/2005
   based on a Anglia Design example-application for ST ARM
*/

    LDR   r0, =__ctors_start__
    LDR   r1, =__ctors_end__
ctor_loop:
    CMP   r0, r1
    BEQ   ctor_end
    LDR   r2, [r0], #4
    STMFD   sp!, {r0-r1}
    MOV   lr, pc
    MOV   pc, r2
    LDMFD   sp!, {r0-r1}
    B     ctor_loop
ctor_end:

// Call main program: main(0)
// --------------------------
        mov   r0,#0                     // no arguments (argc = 0)
        mov   r1,r0
        mov   r2,r0
        mov   fp,r0                     // null frame pointer
        mov   r7,r0                     // null frame pointer for thumb
        ldr   r10,=main
        mov   lr,pc

/* Enter the C code, use BX instruction so as to never return */
/* use BLX (?) main if you want to use c++ destructors below */

        bx    r10                       // enter main()

/* "global object"-dtors are never called and it should not be
   needed since there is no OS to exit to. */
/* Call destructors */
#    LDR    r0, =__dtors_start__
#    LDR    r1, =__dtors_end__
dtor_loop:
#    CMP    r0, r1
#    BEQ    dtor_end
#    LDR    r2, [r0], #4
#    STMFD  sp!, {r0-r1}
#    MOV    lr, pc
#    MOV    pc, r2
#    LDMFD  sp!, {r0-r1}
#    B    dtor_loop
dtor_end:

        .size   _start, . - _start
        .endfunc

        .global _reset, reset, exit, abort
        .func   _reset
_reset:
reset:
exit:
abort:
#if 0
// Disable interrupts, then force a hardware reset by driving P23 low
// -------------------------------------------------------------------
        mrs   r0,cpsr                   // get PSR
        orr   r0,r0,#I_BIT|F_BIT        // disable IRQ and FIQ
        msr   cpsr,r0                   // set up status register

        ldr   r1,=(PS_BASE)             // PS Base Address
        ldr   r0,=(PS_PIO)              // PIO Module
        str   r0,[r1,#PS_PCER_OFF]      // enable its clock
        ldr   r1,=(PIO_BASE)            // PIO Base Address
        ldr   r0,=(1<<23)               // P23
        str   r0,[r1,#PIO_PER_OFF]      // make sure pin is contolled by
PIO
        str   r0,[r1,#PIO_CODR_OFF]     // set the pin low
        str   r0,[r1,#PIO_OER_OFF]      // make it an output
#endif
        b     .                         // loop until reset

        .size _reset, . - _reset
        .endfunc

        .end


//////////////////////////////////////////////////////////////////////// 
////


I use the commands:

arm-elf-gcc -g -c -O2 -mcpu=arm7tdmi filename.c -o filename.o
arm-elf-ld -g -M -T LPC2119-ROM.ld crt0.o filename.o -o filename.elf -L
"C:\Program Files\WINARM\lib\gcc\arm-elf\4.1.1" -lgcc -lc
arm-elf-objcopy -O ihex filename.elf filename.hex

This hex file when i put in my target LPC2119, sends a
character(garbage) to my computer's serial port that i'm observing on
hyperterminal. While if in main() i assign a value to the variable 'ch'.

Here,

#include <LPC21xx.h>

unsigned char ch='a';

void sendchar(char ch)
{
  U0THR= ch;
  while (!(U0LSR & 0x20));
}


void sys_config()
{
  PINSEL0 = 0x00000005;
  IO0DIR = 0x00000000;

  U1LCR = 0x83;                /* 8 bits, no Parity, 1 Stop bit     */
  U1DLL = 0x034;
    U1DLM = 0x00;                /* 57600 Baud Rate @ 60MHz VPB Clock
*/
    U1LCR = 0x03;                /* DLAB = 0                          */

    PLLCFG  =  0x22;        /* Settings Pclk <-3* XTAL    */
    PLLCON  =  0x01;
    PLLFEED  =  0xAA;
    PLLFEED  =  0x55;
    while(!(PLLSTAT & 0x400));
    PLLCON  =  0x03;
    PLLFEED  =  0xAA;       /* Set the PLL settings    */
    PLLFEED  =  0x55;

    VPBDIV  =  0x00000001;  /* PCLK SET TO 60 MHz    */

    /* Uart0 Serial Port Baud Settings */

  U0FCR  =  0x01;
  U0LCR  =  0x83;
  U0DLL  =  0x41;       /* BAUD RATE UART0 57600  */
  U0DLM  =  0x00;
  U0LCR  =  0x03;
}

int main()
{
  sys_config();

        ch= 'a';                     /*  Assigned value here  */

   while(1)
    {
    sendchar(ch);
  }
  return 0;
}

In this case the correct value 'a' is sent to serial port from UART.
I've also given my ROM.ld above that i have not further modified. The
problem therefore still stands why i dont understand the global
variable's initialized value not copied in memory?

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
You had suggested using a program that could display all characters, so
i used serial port library in linux, i've used it earlier, it works. The
character was 'K' when i building once, the other time it was '\n'.

von Clifford S. (clifford)


Rate this post
useful
not useful
Abhijeet Bokil wrote:
> See, by compiler i meant the entire toolchain, linker as well. Lets say
> thats my mistake. I'm NOT doubtful about the object code.
No you still entirely misunderstand me - the tool-chain being wrong is
the *least likely proposition. Thousands of developers use the GNU tools
every day. Your code or your build settings are at fault.

Abhijeet Bokil wrote:
> // Copy initialized data to its execution address in RAM
> // -----------------------------------------------------
> #ifdef ROM_RUN
>         ldr   r1,=_etext                // -> ROM data start
>         ldr   r2,=_data                 // -> data start
>         ldr   r3,=_edata                // -> end of data
> 1:      cmp   r2,r3                     // check if data to move
>         ldrlo r0,[r1],#4                // copy it
>         strlo r0,[r2],#4
>         blo   1b                        // loop until done
> #endif

> [...]
>
> I use the commands:
>
> arm-elf-gcc -g -c -O2 -mcpu=arm7tdmi filename.c -o filename.o
> arm-elf-ld -g -M -T LPC2119-ROM.ld crt0.o filename.o -o filename.elf -L
> "C:\Program Files\WINARM\lib\gcc\arm-elf\4.1.1" -lgcc -lc
> arm-elf-objcopy -O ihex filename.elf filename.hex
>
Where is ROM_RUN defined? If it is not defined global and static data
will not be initialised.


Abhijeet Bokil wrote:
> You had suggested using a program that could display all characters, so
> i used serial port library in linux, i've used it earlier, it works. The
> character was 'K' when i building once, the other time it was '\n'.

In your original report you wrote:

> ...when i make the character global, nothing is sent.
Which is not what you are saying now. I wonder why you did not report
the change in findings earlier? This is why I asked you to check with a
more appropriate tool. I suspected a global initialisation problem from
the start and teh questions I asked were aimed at confirming this
suspicion. Ultimately had you use a debugger as I suggested, you could
have seen that the global variable had an incorrect value.

I would advise against using the same name for both global and local
variables (including parameters). The local will 'shadow' the global.
This can cause problems in a debugger if for example you set a watch on
the global variable when the local variable is in scope.


Clifford

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
>Where is ROM_RUN defined? If it is not defined global and static data
>will not be initialised.

That should now end the problem. Thanks! Dude! Some kind of
mis-communication between us. Nevermind!

>Thousands of developers use the GNU tools
>every day. Your code or your build settings are at fault.

I completely believe thousands of developers use it which is why i'm
using it and I've just become one of them! :-) Also i wont declare
variable local n global with same name, u can see in main in the
non-working code, it isn't a declaration. Anyway, thanks!

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
I'll post here as the problem's solved. I'll also verify with debugger
bfor putting in target.

von Clifford S. (clifford)


Rate this post
useful
not useful
Abhijeet Bokil wrote:
> Also i wont declare
> variable local n global with same name, u can see in main in the
> non-working code, it isn't a declaration. Anyway, thanks!

Nonsense! Here:

> unsigned char ch='a';
>
> void sendchar(char ch)
> {
>   U0THR= ch;
>   while (!(U0LSR & 0x20));
> }

The parameter ch shadows the global ch.

Clifford

von Clifford S. (clifford)


Rate this post
useful
not useful
Abhijeet Bokil wrote:
> I'll post here as the problem's solved. I'll also verify with debugger
> bfor putting in target.

Eh!? The debugger runs the code on the target! There is a simulator,
but since that will have its own C runtime start-up and it seems that is
where your problem was it may not have helped.

Clifford

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
>Nonsense! Here:

>> unsigned char ch='a';
>>
>> void sendchar(char ch)
>> {
>>   U0THR= ch;
>>   while (!(U0LSR & 0x20));
>> }

>The parameter ch shadows the global ch.


God!! I mean is it about trying to sort out the problem or "see here u
made a mistake"  or "lets test ur C first". If i can understand that i
shd not be declaring a var wid same name in main() which is declared
global, to avoid prbs to monitor it in debugger, rest assure i wont use
it in any other function. That code was tell u the real problem. plz
refer my first post there u can see the name of var diff. But do u think
it is abt tht?

About the debugger: I knew it about the debugger n so dint mention
anything. I've my own means to debug code that don't require the
debugger.  I'm using them and getting by for the last 10 yrs, out of
sarcasm if u wish to know abt them i can tell u.

von Clifford S. (clifford)


Rate this post
useful
not useful
Goodbye.

von Abhijeet B. (xmonito)


Rate this post
useful
not useful
Goodbye!

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.