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

Strange behavior of function return value
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Guest123
Guest







Strange behavior of function return value
PostPosted: Wed Oct 15, 2008 4:47 pm     Reply with quote

Hello

I encountered a very strange behavior of a function return value. For my overall program structure I coded a Timer Module which allows me to generate programmable timeouts. For this reason i have defined the following structure which holds all information for one timer.
Code:

typedef struct timref_t
{
   int1 signal_flag;      ///< Holds the timer flag
   unsigned int16 cnt;      ///< Current counter value for the timer
   unsigned int16 cmp;      ///< Compare value for the timer
};


In order to have an encapsulated module I have coded a function which returns me the value of the signal_flag:

Code:

int1 getTimeout(struct timref_t* ref)
{
   return ref->signal_flag;
}


In the main function I use the Timer module like this:
Code:

void main(void)
{
   struct timref_t myTimRef;

   setTimer(100, &myTimRef);
   
   while(1)
   {
      if(getTimeout(&myTimRef))
      {
         // some code
      }
      // some code
   }
}


However the problem is, that the if condition will sporadically be true even if the signal_flag of myTimRef is still 0. I used an ICD debugger to find out what is wrong. However I found out that it sometimes returns the correct result and sometimes not. It seems like the pointer (struct timref_t* ref) in the getTimeout function is corrupted sometimes but I couldn't reconstruct when this happens and due to what reason it happens. Has anybody encountered a problem like this before (or can someone see the stupid fault I made :-))?

Compiler Version PCH V4.079
Compiling for a PIC18F2620

I hope that anyone can help me I'm really annoyed by this misbehavior...

Thanks in advance
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Oct 15, 2008 4:52 pm     Reply with quote

The first thing I would do to test this, is to get rid of the 'int1'.
Change it to 'int8'.
Guest123
Guest







PostPosted: Thu Oct 16, 2008 1:06 am     Reply with quote

I quickly changed the function from returning int1 to int8. However the behavior remains the same.
I think I will have to analyze what happens during the call of the function. Is it possible that the parameter gets corrupted if an interrupt occurs during the call of the function?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Oct 16, 2008 2:20 am     Reply with quote

Quote:
Is it possible that the parameter gets corrupted if an interrupt occurs during the call of the function?


This should never happen, but is possible due to errors in your code or compiler bugs. If the error is in your code, it should be searched at the interrupt functions rather than the main level.

Regards,
Frank
Guest








PostPosted: Thu Oct 16, 2008 2:34 am     Reply with quote

Code:

79:                int1 getTimeout(struct timref_t* ref)
80:                {
81:                   return ref->signal_flag;
  03C4    0108     MOVLB 0x8
  03C6    C8C7     MOVFF 0x8c7, 0xfe9
  03CA    C8C8     MOVFF 0x8c8, 0xfea
  03CE    0E00     MOVLW 0
  03D0    B0EF     BTFSC 0xfef, 0, ACCESS
  03D2    0E01     MOVLW 0x1
  03D4    6E01     MOVWF 0x1, ACCESS
82:                }
  03D6    0100     MOVLB 0
  03D8    0C00     RETLW 0


This is what the Compiler does with the code of the getTimeout function. I reinvestigated the problem with the ICD and when the function fails there is a wrong address in the 0x8c7 and 0x8c8 memory locations. Any suggestions?
Meanwhile I will have another look at my Interrupt Handlers.
Ttelmah
Guest







PostPosted: Thu Oct 16, 2008 3:08 am     Reply with quote

Look in particular at what is stored immediately in front of these locations in memory.
The 'common' cause of this type of problem, is a buffer or memory area overflowing, and corrupting something beyond. If you are using strings, triple check you are leaving space for the teminating character. If you are using arrays, triple check that you are applying 'bounds checking' in your own code, and indexes can never go outside the legal range. remember in particular that C uses zero-referenced arrays, so for 'array[10]', 9 is the highest legal address.
As a simple 'test', declare two extra 'dummy' variables. One in front, and one behind the problem value. So something like:
[code]
int32 dummy1=0;
struct timref_t myTimRef;
int32 dummy2=0;
[code]
Check in the symbol file that these are actually placed around the problem variable, then see if either of these changes.

Best Wishes
Guest








PostPosted: Thu Oct 16, 2008 3:59 am     Reply with quote

Firstly, thanks for all your support I greatly appreciate it.

However the problem still persists. The memory area the data corruption occurs is not used by my variables it is managed by the compiler. Therefore it is very complicated to see if I overwrite the location by myself.
The problem seems to be that the timing is problematic. The function is used for several references (lets say myTimRef is located at 0x0792 and myTimRef2 is located at 0x0305). In this case as soon as the problem occurs the memory locations which corrupt (0x08x7 and 0x08c8) hold either 0x0305 or 0x0392 instead of 0x0792.
Guest








PostPosted: Thu Oct 16, 2008 5:29 am     Reply with quote

I think that I have found the problem. The disassembly shows it. I have a function (unsetTimer) which is called during an Interrupt. The disassembly is the following:
Code:

56:                timstat_t unsetTimer(struct timref_t* ref)
57:                {
58:                   unsigned int8 i = 0;
  01F0    0108     MOVLB 0x8
  01F2    6BC8     CLRF 0xc8, BANKED
59:               
60:                   // --- Search the corresponding timer ---
61:                   while(timers[i]!=ref && i<NUM_TIMERS)
62:                   {
  01F4    90D8     BCF 0xfd8, 0, ACCESS
  01F6    35C8     RLCF 0xc8, W, BANKED
  01F8    6A03     CLRF 0x3, ACCESS
  01FA    0FCD     ADDLW 0xcd
  01FC    6EE9     MOVWF 0xfe9, ACCESS
  01FE    0E00     MOVLW 0
  0200    2003     ADDWFC 0x3, W, ACCESS
  0202    6EEA     MOVWF 0xfea, ACCESS
  0204    CFEC     MOVFF 0xfec, 0x8ca
  0208    52ED     MOVF 0xfed, F, ACCESS
  020A    CFEF     MOVFF 0xfef, 0x8c9
  020E    51C6     MOVF 0xc6, W, BANKED
  0210    5DC9     SUBWF 0xc9, W, BANKED
  0212    E103     BNZ 0x21a
  0214    51C7     MOVF 0xc7, W, BANKED
  0216    5DCA     SUBWF 0xca, W, BANKED
  0218    E005     BZ 0x224
  021A    51C8     MOVF 0xc8, W, BANKED
  021C    0809     SUBLW 0x9
  021E    E302     BNC 0x224
63:                      i++;
  0220    2BC8     INCF 0xc8, F, BANKED
64:                   }
  0222    D7E8     BRA 0x1f4
65:               
66:                   if(i<NUM_TIMERS)
  0224    51C8     MOVF 0xc8, W, BANKED
  0226    0809     SUBLW 0x9
  0228    E30F     BNC 0x248
67:                   {
68:                      // --- Unset the timer ---
69:                      timers[i] = 0;
  022A    90D8     BCF 0xfd8, 0, ACCESS
  022C    35C8     RLCF 0xc8, W, BANKED
  022E    6A03     CLRF 0x3, ACCESS
  0230    0FCD     ADDLW 0xcd
  0232    6EE9     MOVWF 0xfe9, ACCESS
  0234    0E00     MOVLW 0
  0236    2003     ADDWFC 0x3, W, ACCESS
  0238    6EEA     MOVWF 0xfea, ACCESS
  023A    6AEC     CLRF 0xfec, ACCESS
  023C    52ED     MOVF 0xfed, F, ACCESS
  023E    6AEF     CLRF 0xfef, ACCESS
70:                      return TIMER_OK;
  0240    0E00     MOVLW 0
  0242    6E01     MOVWF 0x1, ACCESS
  0244    D004     BRA 0x24e
71:                   }
72:                   else
  0246    D003     BRA 0x24e
73:                   {
74:                      // --- The given Timer reference has not been found ---
75:                      return WRONG_TIMER_REF;
  0248    0E02     MOVLW 0x2
  024A    6E01     MOVWF 0x1, ACCESS
  024C    D000     BRA 0x24e
76:                   }
77:                }
  024E    0100     MOVLB 0
  0250    0C00     RETLW 0


For reference here again the disassembly of the getTimeout function:
Code:

79:                int1 getTimeout(struct timref_t* ref)
80:                {
81:                   return ref->signal_flag;
  03C4    0108     MOVLB 0x8
  03C6    C8C6     MOVFF 0x8c6, 0xfe9
  03CA    C8C7     MOVFF 0x8c7, 0xfea
  03CE    0E00     MOVLW 0
  03D0    B0EF     BTFSC 0xfef, 0, ACCESS
  03D2    0E01     MOVLW 0x1
  03D4    6E01     MOVWF 0x1, ACCESS
82:                }
  03D6    0100     MOVLB 0
  03D8    0C00     RETLW 0


As one can see the function unsetTimer accesses memory location 0x08c6 (@program location 020E) via a banked access. Therefore if the Interrupt (where unsetTimer is called) arises the passing parameter of getTimeout will get corrupted.

- Can anyone (who has a better understanding of assembly language) please confirm this?
- Where can such bugs (if it is really one) be reported and how can I work around this issue?
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Thu Oct 16, 2008 5:44 am     Reply with quote

If this is the case it is not a compiler bug but an error in your implimentation.

Your easiest option is to disable interrupts at the start of your getTimeout routine and re-enable them at the end.

this will also test your theory Smile
Guest








PostPosted: Thu Oct 16, 2008 6:01 am     Reply with quote

Well I do not agree in all terms with you. It is true that I can do a work around by disabling Interrupts while calling getTimeout. But in my eyes it is a Compiler Bug because I can't control which memory locations the compiler uses to pass the parameter (or whatever it does with these memory locations). A function which is called during an Interrupt (like unsetTimer is) should only use memory locations which exclusive to that function. Please let me know if I am completly wrong with my opinion.
Guest








PostPosted: Thu Oct 16, 2008 6:04 am     Reply with quote

Additionally I dug a little deeper and this is what the symbol map of CCS-C says:

Code:

8C7-8C8 strstr.s1
8C7-8C8 unsetTimer.ref
8C7-8C8 strlen.s
8C7-8C8 getTimeout.ref
8C7-8C8 strncmp.s1
8C7     app_processData.len
8C7     rm_runService.@SCRATCH1
8C7     pdata_read.@SCRATCH3


As one can see CCS-C allocates the passing parameter of unsetTimer and the passing parameter of getTimeout at the same memory location which leads to the data corruption.
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Thu Oct 16, 2008 7:20 am     Reply with quote

There seems to be alot of information missing from this problem.

Is it possible that the time ref passed to getTimeout is unset during the interupt routine.

The timer could interrupt at any time, during the interrupt you proberbly check and remove timers based on their timeout value. If the interrupt occured during the getTimeout routine then the timer you are checking could be unset.

Rather than me (and yes I do understand assembler) go through the assembler, please post the C code including the interrupt routine without the asm code, so we can have a look at that.
Guest








PostPosted: Thu Oct 16, 2008 7:36 am     Reply with quote

Well what you say is possible that the timer gets unset during the call to the getTimeout function. But the information of the signal_flag is stored in the timref_t Variable and this one is still around and valid (it is declared in main from where the getTimeout function is called). Hereunder I post the complete code of my timer module.

Header File (timer.h):
Code:

#ifndef _TIMER_H_
#define _TIMER_H_

/// Timer Reference structure
typedef struct timref_t
{
   int1 signal_flag;      ///< Holds the timer flag
   unsigned int16 cnt;      ///< Current counter value for the timer
   unsigned int16 cmp;      ///< Compare value for the timer
};

/// The status values returned by the timer functions
typedef enum timstat_t
{
   TIMER_OK,            ///< Last operation was ok
   NO_FREE_TIMER,         ///< There are no free timers available
   WRONG_TIMER_REF         ///< The timer reference provided could be found
};

/**
   @brief      Initializes the timer module
   @return      The result of the initialisation process
*/
timstat_t initTimer(void);

/**
   @brief      Initializes a new timer
   @param[in]   timeout      Timer value in miliseconds
   @param[in]   ref         Timer reference to be used
   @return      Result of the timer initialisation process
*/
timstat_t setTimer(unsigned int16 timeout, struct timref_t* ref);

/**
   @brief      Deletes a timer
   @param[in]   ref         Timer reference which shall be deleted
   @return      Result of the timer deletion process
*/
timstat_t unsetTimer(struct timref_t* ref);

/**
   @brief      Checks if the Timeout flag of the provided reference has been risen
   @param[in]   ref         Timer reference
   @return      Timeout flag value
*/
int1 getTimeout(struct timref_t*);

#endif

Code of the implementation file (timer.c):
Code:

#include "timer.h"

#define NUM_TIMERS 10

struct timref_t* timers[NUM_TIMERS];

timstat_t initTimer(void)
{
   unsigned int8 i;

   for(i=0; i<NUM_TIMERS; i++)
    {
      timers[i] = 0;
   }

#ifdef _PIC18F2620_
   // --- Setup Timer2 to fire an Interrupt every milisecond @ Fosc = 32Mhz ---
   T2CON = 0x0F;
   PR2 = 249;
   PIE1 |= 0x02;
#endif

   return TIMER_OK;
}

timstat_t setTimer(unsigned int16 timeout, struct timref_t *ref)
{
   unsigned int8 i=0;

   // --- search unused timer ---
   while(timers[i]!=0 && i<NUM_TIMERS)
   {
      i++;
   }

   // --- There is no timer left to be assigned ---
   if(i >= NUM_TIMERS)
   {
      return NO_FREE_TIMER;
   }

   // --- Reset the timer reference values ---
   ref->cnt = 0;
   ref->cmp = timeout;
   ref->signal_flag = 0;
   timers[i] = ref;

   return TIMER_OK;
}

timstat_t unsetTimer(struct timref_t* ref)
{
   unsigned int8 i = 0;

   // --- Search the corresponding timer ---
   while(timers[i]!=ref && i<NUM_TIMERS)
   {
      i++;
   }

   if(i<NUM_TIMERS)
   {
      // --- Unset the timer ---
      timers[i] = 0;
      return TIMER_OK;
   }
   else
   {
      // --- The given Timer reference has not been found ---
      return WRONG_TIMER_REF;
   }
}

int1 getTimeout(struct timref_t* ref)
{
   return ref->signal_flag;
}

/**
   @brief Interrupt handler for the Timer 2 Compare interrupt

   This interrupt handler is called every milisecond. As soon as one of the registered
   timers reaches its timeout value the corresponding flag is being set.
*/
#INT_TIMER2
void timer2_int_handler(void)
{
   int8 i;

   // --- Execute for every timer ---
   for(i=0; i<NUM_TIMERS; i++)
   {
      // --- Check if a timer is registered for this memory space ---
      if(timers[i] != 0)
      {
         (*(timers[i])).cnt++;

         // --- Has the timer reached its timeout value ---
         if((*(timers[i])).cnt >= (*(timers[i])).cmp)
         {
            (*(timers[i])).signal_flag = 1;      // Set Flag
            timers[i] = 0;
         }
      }
   }
}

I really hope that we can find the mistake. The work around (disabling interrupts during call to getTimeout) is not really an option because you can not do it inside the function. This means that you have to disable the interrupts then call getTimeout and finally reenable the interrupts...
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Thu Oct 16, 2008 7:53 am     Reply with quote

I cannot see where unsetTimer is called. It is not in the Timer2 interrupt!
I cannot see where getTimeout is called. Or where the parameter passed to getTimeout is defined and set.

I have no way of knowing from this if TIMER2 interrupt will affect your code.
Just that it could set a timer to 0 (null) which could well be the one you passed to getTimeout.
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Thu Oct 16, 2008 8:04 am     Reply with quote

I assume you are allocating memory at some point for your timers which you pass to setTimer ?
Where are you deallocating it ?

No need to set the flag if you are then going to set the pointer to 0.
This does not free the memory! It just clears the pointer.

Code:

            (*(timers[i])).signal_flag = 1;      // Set Flag
            timers[i] = 0;


Last edited by Wayne_ on Thu Oct 16, 2008 8:06 am; edited 1 time in total
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
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