EmbDev.net

Forum: ARM programming with GCC/GNU tools Strange behavior using functions


von Bruno A. (bvadorno)


Attached files:

Rate this post
useful
not useful
Hi everybody,

   I'm using UART3 to get data and everything goes fine. I wrote a state
machine to get the data and the current state is sent to the computer.
But when I use a very simple function in the main function, the state
sent to the computer is wrong.
   This is a very strange behavior, since the function simply does
nothing! Obviously this is a very simplified situation and other
functions doesn't work properly either.
   Does anybody knows the reason for that behavior? The functional
minimal code is attached.

INLINE u8 test(void)
{
  return 1;
}

int main (void)
{

  initSystemFrequency();
  initComputer();
  initGps();


  EIC_IRQConfig(ENABLE);

  while(!flagSend2Computer);
  flagSend2Computer = 0;

  while(1)
  {
    test(); //if commented everything goes fine
  }
}

Thanks in advance,
Bruno

von Clifford S. (clifford)


Rate this post
useful
not useful
Slow down! The description of your problem, and the code don't seem to
tie up.

There is no sending data to a 'computer' or state-machine here. And the
code is not complete - critically you have not shown a declaration of
flagSend2 or the code that sets it. If this flag is not declared
volatile, and you have used optimisation, the loop is unlikely to ever
exit.

You have described one problem, then posted different code. You may be
looking at a different problem in each case. You have not fully
described the problem (or rather problems). For example how is the data
wrong? Tell us what you send, and what is actually received? Have you
considered byte ordering or structure packing differences for example?

Much of your code in your example is likely to be optimised out if you
switched on optimisation.

You have a comment "//if commented everything goes fine" - what does
that mean? You have commented this line - it won't affect the
generated code. Do you  mean "if commented-out (or removed)"? What does
'fine' mean, what do you expect to happen and what actually happens?

I think you will have to explain more carefully. Give a concrete
example, and say what you are observing and what you expected to
observe. "fine", "wrong", and "strange behaviour" are not adequate
descriptions of your observations.

Clifford

von Bruno A. (bvadorno)


Rate this post
useful
not useful
Clifford Slocombe wrote:
> Slow down! The description of your problem, and the code don't seem to
> tie up.
>
> There is no sending data to a 'computer' or state-machine here. And the
> code is not complete - critically you have not shown a declaration of
> flagSend2 or the code that sets it. If this flag is not declared
> volatile, and you have used optimisation, the loop is unlikely to ever
> exit.

Like I said just before the little piece of code, "the functional
minimal code is attached" (it's the bug_function.tar.gz file). So,
flagSend2computer is in the file "Computer.h". Furthermore, I'm not
using optimisation.

> You have described one problem, then posted different code. You may be
> looking at a different problem in each case. You have not fully
> described the problem (or rather problems). For example how is the data
> wrong? Tell us what you send, and what is actually received? Have you
> considered byte ordering or structure packing differences for example?

I think you are right in some points. I poorly described my problem. The
data that is received by UART3. This is the piece of code of UART3
(remember, the minimal functional code is attached -
bug_function.tar.gz):

void UART3_IRQHandler(void)
{
  static vu8 stateGps = 0;
  static vu16 checksum = 0;
  static vu8 i = 0;
  vu8 id, packetSize;
  vu8 data;

  //UART_ItConfig(gps,UART_RxBufFull, DISABLE);

  data = (u8)gps->RxBUFR;


  stateGps+=48;
  UART_ByteSend(computer,&stateGps);
  stateGps-=48;

  switch (stateGps)
  {
    case 0:
    if (data == 1)
    {
      stateGps = 1;
      checksum=0;
      checksum += data;
    }
    break;
  case 1:
    id = data;
    stateGps = 2;
    checksum += data;
    break;
  case 2:
    if (data == (255-id))
    {
      stateGps = 3;
      checksum += data;
    }
    else
      stateGps=0;
    break;
  case 3:
    packetSize = data;
    i = 0;
    stateGps = 4;
    checksum += data;
    break;
  case 4:
    i++;
    checksum += data;
    if (i == packetSize)
      stateGps = 5;
    break;
  case 5:
    if (data == (u8)checksum)
      stateGps = 6;
    else
      stateGps = 0;
    break;
  case 6:
    stateGps=0;
    break;
  }
  //UART_ItConfig(gps,UART_RxBufFull, ENABLE);
}

You can note the function call UART_ByteSend(computer,&stateGps). So,
the state of data received is sent to my computer and I can trace all
the states of data received.

> Much of your code in your example is likely to be optimised out if you
> switched on optimisation.

You are completely right, but now I'm a little bit more worried about
the problem that I'm trying to explain below =).


> You have a comment "//if commented everything goes fine" - what does
> that mean? You have commented this line - it won't affect the
> generated code. Do you  mean "if commented-out (or removed)"? What does
> 'fine' mean, what do you expect to happen and what actually happens?

Sorry, I made a bad use of the language. When I said //if commented
everything goes fine, I tried to say:

When I call test() (or any other function. It doesn't matter what it
does), the state machine on UART3 doesn't reaches level 6.
while(1)
{
    test(); //if commented everything goes fine
}

When I remove test() the state machine on UART3 reaches level 6.
while(1)
{
    //test();
}

As you can see, test doesn't anything, so it couldn't affect the data
received on UART3. I can say more:

suppose that test was:

u8 a = 0, b = 0; //both global variables

INLINE void test()
{
   a = b;
}

If I call test() inside while(1), the state machine on UART3 *doesn't*
reaches level 6, but if I put

while(1)
{
   a = b;
}

the state machine on UART3 reaches level 6! So, I use functions inside
while(1) everything goes wrong. Note that I'm not using any
optimisations... You can note too that global variables used both inside
and out of interrupt are declared as volatiles.

> I think you will have to explain more carefully. Give a concrete
> example, and say what you are observing and what you expected to
> observe. "fine", "wrong", and "strange behaviour" are not adequate
> descriptions of your observations.
>
> Clifford

Now I think that the problem is better explained =).

Thanks,
Bruno

von Clifford S. (clifford)


Rate this post
useful
not useful
Sorry I did not notice the attachment. Not that I would wade through all
of that in any case.

Sounds line a stack overflow or buffer oveverun to me. Perhaps the
normal stack running interrupt stack or vice versa. This would be easier
for you to determine using the debugger that for someone to analyse
without your set-up.

Clifford

von Bruno A. (bvadorno)


Rate this post
useful
not useful
> Sounds line a stack overflow or buffer oveverun to me. Perhaps the
> normal stack running interrupt stack or vice versa. This would be easier
> for you to determine using the debugger that for someone to analyse
> without your set-up.
>
> Clifford

Clifford,
   which (easy to use) debugger tool do you suggest? I don't have the
habit of using debugging tools (yes, I know that's a shame...).

Thanks,
Bruno

von Clifford S. (clifford)


Rate this post
useful
not useful
Bruno Adorno wrote:
>> Sounds line a stack overflow or buffer oveverun to me. Perhaps the
>> normal stack running interrupt stack or vice versa. This would be easier
>> for you to determine using the debugger that for someone to analyse
>> without your set-up.
>>
>> Clifford
>
> Clifford,
>    which (easy to use) debugger tool do you suggest? I don't have the
> habit of using debugging tools (yes, I know that's a shame...).
>
> Thanks,
> Bruno

Well since you are using GCC the defacto choice is GDB. The command line
tool is a bit painful. The Insight GUI makes it easier. Insight is
included with the WinARM tools in the Utilities folder. Your zip file
included an openocd/wiggler configuration file so I assumed that you
already had the necessary JTAG hardware.

von Bruno A. (bvadorno)


Rate this post
useful
not useful
> Well since you are using GCC the defacto choice is GDB. The command line
> tool is a bit painful. The Insight GUI makes it easier. Insight is
> included with the WinARM tools in the Utilities folder. Your zip file
> included an openocd/wiggler configuration file so I assumed that you
> already had the necessary JTAG hardware.

Now I'm using Insight/GDB am I am able to connect to my STR711 board.
But how can I see if the problem is stack overflow or buffer overrun?
Indeed, I don't think that the problem is buffer overrun because I am
not using any buffer in my program. Maybe the problem is stack overflow,
but how can I see it?

Thanks,
Bruno

von Clifford S. (clifford)


Rate this post
useful
not useful
Bruno Adorno wrote:
> Maybe the problem is stack overflow, but how can I see it?
>
Observe the stack pointer register in the register window. It starts
high and grows downward. If your build generated a map file, then that
will tell you the address of stack (which will be the stack 'top' since
it grows downward). If the SP is lower that this address you have
exhausted the stack.

The exceeding of bounds of any array is referred to as a "buffer
overrun".

Clifford

von Bruno A. (bvadorno)


Rate this post
useful
not useful
Clifford Slocombe wrote:

> Observe the stack pointer register in the register window. It starts
> high and grows downward. If your build generated a map file, then that
> will tell you the address of stack (which will be the stack 'top' since
> it grows downward). If the SP is lower that this address you have
> exhausted the stack.

This was the piece of map file that refers to the stack:

.stack          0x20000814      0x400
                0x20000814                _stack_start_ = .
 *(.stack)
                0x20000c14                . = ((_stack_start_ +
_STACKSIZE) MAX_K .)
 fill         0x20000814      0x400 00
                0x20000c14                _stack_end_ =
(_stack_start_ + SIZEOF (.stack))

So, the address of stack is 0x20000c14 and it grows downward to
0x20000814, right?
The SP register is 0x20000c04 and then is lower that 0x20000c14. So, I
believe that I exhausted the stack. But something is strange. If I
increase the size of stack, SP still points to an address lower than
address of stack:

.stack          0x20000414      0x800
                0x20000414                _stack_start_ = .
 *(.stack)
                0x20000c14                . = ((_stack_start_ +
_STACKSIZE) MAX_K .)
 fill         0x20000414      0x800 00
                0x20000c14                _stack_end_ =
(_stack_start_ + SIZEOF (.stack))

And the SP value is 0x20000c04. It means thas SP is always pointing to
an address 40 bytes lower than stack beginning. This is correct or I
understood all wrong?

Thanks,
Bruno

von Clifford S. (clifford)


Rate this post
useful
not useful
Bruno Adorno wrote:
> The SP register is 0x20000c04 and then is lower that 0x20000c14. So, I
> believe that I exhausted the stack.
No, the stack pointer starts at _stack_end_ and is moved as the stack
grows and shrinks. It must not be less than _stack_start_. The SP
address changes as your code runs. Observe the stack at the start (on
entry to main) and throughout your code.

A good way to check the actual peak stack usage is to fill the stack
with 0xee and then do a memory dump of the stack segment. The highest
address from _stack_start_ still containing 0xee is the high-tide mark
of your stack. If there are no 0xee values, you can be fairly sure you
blew the stack.

Clifford

von Bruno A. (bvadorno)


Rate this post
useful
not useful
Clifford Slocombe wrote:
> Bruno Adorno wrote:
>> The SP register is 0x20000c04 and then is lower that 0x20000c14. So, I
>> believe that I exhausted the stack.
> No, the stack pointer starts at _stack_end_ and is moved as the stack
> grows and shrinks. It must not be less than _stack_start_. The SP
> address changes as your code runs. Observe the stack at the start (on
> entry to main) and throughout your code.
>
> A good way to check the actual peak stack usage is to fill the stack
> with 0xee and then do a memory dump of the stack segment. The highest
> address from _stack_start_ still containing 0xee is the high-tide mark
> of your stack. If there are no 0xee values, you can be fairly sure you
> blew the stack.
>
> Clifford

I did it and I am not blewing the stack. Any other suggestions?

Thanks,
Bruno

von Bruno A. (bvadorno)


Rate this post
useful
not useful
I discovered the bug. There was two variables in UART3 (and that
were related to the state of state machine) that were supposed to be
static, but they were not (and they were not initialized).

    So, when I didn't use a function inside main(), the local variable
in UART3 luckily was always allocated in same place and the program
worked fine. But when I used a function inside main(), all became messed
up and the local variable was allocated in another memory region.

    Anyway, now I am able to use a debugger and I'm happy with that.
Thanks.


    Bruno

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.