|
|
View previous topic :: View next topic |
Author |
Message |
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
Global Int32 Variables... |
Posted: Mon Jul 27, 2020 2:09 pm |
|
|
Hi All,
I'm having an issue where several global Int32 variables are changing after they have been set with no good explanation. I know 'global' variables should be used sparingly, but it there anything uniquely specific to global Int32 variables?
I'm using these Int32 variables to hold the Unix time stamp for the beginning and end of daylight savings in a given year. These variables are calculated and set correctly in one routine, but a short time later when they are used in another routine they have changed to the wrong value. This was working at one time, and then seems to have stopped as the program size has increased, which seems to suggest that something is being overwritten unintentionally?
A possible clue:
Code: |
int32 DST_Start_LCL_Ticks = 0; //Variable to store DST start LCL time ticks
int32 DST_End_LCL_Ticks = 0; //Variable to store DST end LCL time ticks
int8 tDSTStartLCLString[80]; //Variable to store the DST start LCL string
int8 tDSTEndLCLString[80]; //Variable to store the DST end LCL string
|
Code: |
//Here we put the DST start date/time into the time structure for conversion to Ticks.....
MyTMInfo.tm_sec = 0; // seconds after the minute (0-59)
MyTMInfo.tm_min = 0; // minutes after the hour (0-59)
MyTMInfo.tm_hour = 2; // hours since midnight (0-23)
MyTMInfo.tm_mday = DSTStartDay; // day of the month (1-31)
MyTMInfo.tm_mon = 3 - 1; // month of the year (0-11) <- Note: April = 3 NOT 4!!
MyTMInfo.tm_year = MyGPRMCInfo.DT.Year + 100; // years since 1900
MyTMInfo.tm_wday = 0; // day of the week (0-6) (Sunday=0)
MyTMInfo.tm_yday = 0; // day of the year (0-365) - was 98
DST_Start_LCL_Ticks = mktime(&MyTMInfo);
fprintf(Diag, "\r\nDST Start Local Timestamp:<%Lu>\n\r",DST_Start_LCL_Ticks);
ctime(&DST_Start_LCL_Ticks, tDSTStartLCLString);
fprintf(Diag, "DST Start Local Time: %s\n\r", tDSTStartLCLString);
//Here we put the DST end date/time into the time structure for conversion to Ticks.....
MyTMInfo.tm_mday = DSTEndDay; // day of the month (1-31)
MyTMInfo.tm_mon = 11 - 1; // month of the year (0-11) <- Note: April = 3 NOT 4!!
DST_End_LCL_Ticks = mktime(&MyTMInfo);
printf(Diag, "\r\nDST End Local Timestamp:<%Lu>\n\r",DST_End_LCL_Ticks);
ctime(&DST_End_LCL_Ticks, tDSTEndLCLString);
fprintf(Diag, "DST End Local Time: %s\n\r", tDSTEndLCLString);
|
When this code runs, the printout looks like this:
Quote: |
DST Start Local Timestamp:<1583632800>
DST Start Local Time: Sun Mar 8 02:00:00 2020
_<smiley>DST End Local Time: Sun Nov 1 02:00:00 2020
|
The DST_End_LCL_Ticks does not print correctly. Instead, there is an underscore and a smiley face. I assume this is indicative of a memory issue of some kind?
So far, my attempts to condense this issue into a smaller test program have not been successful!
Thoughts?
Jack |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Mon Jul 27, 2020 3:07 pm |
|
|
It's probably some pointer points to the wrong area of RAM, could be a compiler version 'bug'.
philopsophy ?
Since I'm not a C programmer, I've never understood why 'global' variables are 'bad'. Providing the PIC has lots of RAM , 'place for everything and everything in it's place' should be fine....
I know some like to 'reuse' RAM as a space saving thing which only works IF that data is never needed elsewhere.
No program should ever modify any RAM location unless YOU tell it to do so.... |
|
|
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
|
Posted: Mon Jul 27, 2020 4:08 pm |
|
|
Hi Jay,
Yes, I basically agree!
For completeness, my PIC is the 18F46K22, and my compiler is PCH 5.050.
Thanks,
Jack |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Mon Jul 27, 2020 4:20 pm |
|
|
temtronic wrote: |
philopsophy ?
Since I'm not a C programmer, I've never understood why 'global' variables are 'bad'. Providing the PIC has lots of RAM , 'place for everything and everything in it's place' should be fine....
|
It depends on the scale of projects you work on and how many different programmers modify the same code base. Using excessive globals can lead to a lot of bugs when you start putting multiple people on the same large code base. There's definitely a middle ground either way. I've seen code where "every" variable in the code was global. It was so messy I couldn't figure out what it was trying to do. My general mantra is to avoid them unless I actually need them (interrupts for example, global device state for another example). |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
Re: Global Int32 Variables... |
Posted: Mon Jul 27, 2020 4:22 pm |
|
|
JAM2014 wrote: | Hi All,
I'm having an issue where several global Int32 variables are changing after they have been set with no good explanation. I know 'global' variables should be used sparingly, but it there anything uniquely specific to global Int32 variables?
I'm using these Int32 variables to hold the Unix time stamp for the beginning and end of daylight savings in a given year. These variables are calculated and set correctly in one routine, but a short time later when they are used in another routine they have changed to the wrong value. This was working at one time, and then seems to have stopped as the program size has increased, which seems to suggest that something is being overwritten unintentionally?
A possible clue:
|
It's hard to tell from what you posted, but one of the more common issues I see with int32s is when someone tries to use them both in interrupts and in non interrupt code. It leads to data corruption if done incorrectly. They are not atomic variables, so they need to be treated in a special manner if used in both contexts. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Mon Jul 27, 2020 4:39 pm |
|
|
re: Quote: | Using excessive globals can lead to a lot of bugs when you start putting multiple people on the same large code base. |
OK.. where do these 'bugs' come from ? If more than one programmer, I assume someone prints out a 'variables used' list so 3 guys don't use the variable 'temperature' for THEIR chunk of code. If they want to use 'temperature', maybe 'ABC_temperature' for programmer Albert Benny Chandler, 'DEF_temperature' for Doug Edward Fairchild.
I can only blame the guy in the mirror for coding 'issues'.....
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 27, 2020 5:04 pm |
|
|
You could priint out in detail what is in these two variables before they
are used by the ctime() function:
Quote: | ctime(&DST_End_LCL_Ticks, tDSTEndLCLString); |
For the first variable, print out the structure contents.
For the 2nd variable, use a for() loop to print each byte in hex format.
Then you can figure out why ctime() is producing a defective output. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Tue Jul 28, 2020 12:03 am |
|
|
This is where the use of:
CRITICAL_SECTION_ENTER(), and
CRITICAL_SECTION_EXIT() comes in.
For a timer, when you want to read it out in the 'main' (or subroutine)
code, use a local 'copy' of the timer, and have something like:
Code: |
//Near the start of your code:
#include "critical.h"
//then when you want to read the timer
CRITICAL_SECTION_ENTER();
local_timer=sys_timer;
CRITICAL_SECTION_EXIT();
|
There is also a REENTER function for where you have multiple critical
sections in one routine. These are macros, that add the code to disable
the interrupts momentarily around the access to a variable that may
be changed by an interrupt. For anything larger than an int8 (PIC16/18)
or an int16 (PIC24/30/33), these (or you own equivalent) should be used.
As an 'equivalent', that does not involve disabling the interrupt:
Code: |
do {
local_timer=sys_timer;
} while (local_timer!=sys_timer);
|
This copies the value once, then tests that it has not changed. If it has
changed, it copies it again.
Ensuring that accesses to variables are atomic when dealing with things
that can be changed in interrupts, is a vital part of writing reliable code..... |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Tue Jul 28, 2020 6:06 am |
|
|
temtronic wrote: | re: Quote: | Using excessive globals can lead to a lot of bugs when you start putting multiple people on the same large code base. |
OK.. where do these 'bugs' come from ? If more than one programmer, I assume someone prints out a 'variables used' list so 3 guys don't use the variable 'temperature' for THEIR chunk of code. If they want to use 'temperature', maybe 'ABC_temperature' for programmer Albert Benny Chandler, 'DEF_temperature' for Doug Edward Fairchild.
I can only blame the guy in the mirror for coding 'issues'.....
Jay |
Honestly in some businesses, there really isn't time or money for blame. It's more cost effective to have fewer bugs in the first place (not always, some business models are more fluid). It is certainly expensive to try and debug some random edge case bug that doesn't seem related to any of your recent code changes on the surface. Whether that is more expensive that designing your software a different way depends on your business model, the types of products you make, and how much your employees get paid.
On one of our old code baselines, something like 70% of our tracked bugs (both existing and those created as new changes are made) were related to how globals were used. It's not that they were used maliciously, but for a lot of humans, it is sometimes difficult to wrap their head around the logic because the usage is spread out over large programs and you have people with different experience levels all making modifications over long periods of time.
I'm not saying it is impossible to have a good program with a lot of globals, just that statistically for us, designs that rely heavily on globals tend to be more bug prone and we aren't the only ones (There are plenty of people out there who also avoid them). I don't avoid globals like the plague or anything, I just think carefully about if/how I want to use them. ISR variables are obvious ones, but sometimes instead of using a global, I could have used a local static variable instead, so I do that. Sometimes I can just add a return value to a function to get my result back instead of saving it to a global. If I do something like store settings in an EEPROM, I'll keep a global RAM copy of the variables for speed, but I also make sure the global is only exposed to the one C file and not the outside world. |
|
|
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
|
Posted: Tue Jul 28, 2020 2:26 pm |
|
|
Hi All,
Well, the problem is solved!
First, what I thought might have been a clue to what was going on turned out to be a red herring! It seemed like a possible symptom was that the Unix time stamp for the DST end time was not printing correctly. As PCM suggested, I printed out each byte of the string created by the ctime function, and everything looked OK! On further inspection, I noticed that the string was mistakenly being printed by 'printf' vs. 'fprintf', even though a stream was being used. As soon as I fixed that issue, the correct string was printed!
OK, so knowing what was NOT the problem forced me to dig a bit deeper to find the actual problem. This code had been working until I added a new display module, so I started looking at the changes there. I found another global array variable that was being used to hold a string which commands the new display. I realized that the size of this array was smaller than was actually required! After increasing the size of the array, everything is back working as expected!
Thanks,
Jack |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Tue Jul 28, 2020 2:58 pm |
|
|
so it only took 3 pots of coffee and you now have 13 more grey (gray ) hairs..
hay, it WORKS !!!
Jay |
|
|
|
|
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
|