Moving ISRs to a file

Go To Last Post
96 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As expected things don't quite work when I try and move all my ISRs to an ISR file so they are out of the way in the main file.

I have (following someone's suggestion :? )

 ISR(PCINT3_vect);

in the header file that gets included in the main file and

#include "dxio-71_definitions.h"

#include 

	extern uint16_t seconds_tick;
	extern uint8_t  timeout_flag;

ISR(PCINT3_vect)
{
	if	(DS3232_int_port & (1<<DS3232_INT_SQW))			//Do nothing if pin is high
		{
		} etc.

in the ISRs service file. But I get 3 warnings which means that not all is well.

So how do I make the ISRs visible to the main file in the header file?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
So how do I make the ISRs visible to the main file in the header file?

You don't.

Nothing in main() (or any of the code it may call) will ever actually call an ISR. The only entry to an ISR is via the vector table that is provided by the C runtime.

So just put your ISRs into a separate .c file and add that to the list of files to be built into the project. It will be compiled completely separately then the linker will arrange that the C runtime providing the vector table will be "fixed up" to make the JMPs to the ISR routines.

The one thing you may want to "share" between the main() code and the ISR are some global variables such as your 'seconds_tick' and 'timeout_flag' above. Just put their definition into ONE of the .c files and then for the others just include those extern declarations you show above either in the .c files themselves or in a .h file.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Removing the header file removes 3 warnings. However I still get 3 warnings in the ISR file :(

Quote:
../Ad_station_mk2_int_s.c:11: warning: return type defaults to 'int'
../Ad_station_mk2_int_s.c: In function 'ISR':
../Ad_station_mk2_int_s.c:11: warning: type of '__vector_7' defaults to 'int'
../Ad_station_mk2_int_s.c:26: warning: control reaches end of non-void function
I only have moved 1 ISR so far and this is the full code:
#include "dxio-71_definitions.h"

#include 

	extern uint16_t seconds_tick;
	extern uint8_t  timeout_flag;

ISR(PCINT3_vect)
{
	if	(DS3232_int_port & (1<<DS3232_INT_SQW))			//Do nothing if pin is high
		{
		}
	else
		{
		if (seconds_tick==0)
			{
			}
		else seconds_tick --;
			if (seconds_tick==0)
				{
				timeout_flag=1;
				}
		}
}

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

#include

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DUH!!! Why is it always the obvious :? interrupt.h was left in the main file where it is no longer needed.

Well gents you have earned your avrfreaks salary today. :-) and I have had enough for today, so off to vegetate for a while.

Nice to have a simple main file with just the main and have the other stuff tucked away elsewhere.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey, John, one other quick word to the wise (and yes, you are wise! :D ):

Cliff wrote:
The one thing you may want to "share" between the main() code and the ISR are some global variables such as your 'seconds_tick' and 'timeout_flag' above. Just put their definition into ONE of the .c files and then for the others just include those extern declarations you show above either in the .c files themselves or in a .h file.
And please read Cliff's FAQ #1 and make the shared variables volatile. Otherwise, you'll be soon asking FAQ #1. :lol:

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ALL my variables are volatile for now to preserve sanity, except for local variables, REALLY local (things that I would use a temp register or 2 in asm).

If something does not work I rename all variables as volatile and it fixes things. :lol:

I'm used at having everything as being globally accessible with asm so don't quite understand something being eaten by the "OPTIMISER" because it is not declared volatile, if I put it there I WANT it there! I'm the human, the master... :lol:

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John,

But the "eating" that usually occurs is where you have defined a variable (which in Asm would be like a .dseg/var: .db 0xFF) and so would have to probably use LDS/STS to access it and the C compiler actually realises that "if I just LDS that into Rnn at the top of the routine I won't need to keep STS and LDS'ing it every time it's changed". When you use 'volatile' you are saying "even if you think you can see a quick way to handle this variable, don't do it, for every time it's read use LDS to read it out of SRAM and for every time it's written use STS to put it back into SRAM"

So using 'volatile' more than necessary is just very similar to building the whole thing with -O0 optimisation (ie no optimisation) anyway and leads to the generation of slow/bloated code where the compiler's optimiser could have spotted some "tricks" to reduce code size and increase execution speed otherwise.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John wrote:
I'm used at having everything as being globally accessible with asm so don't quite understand something being eaten by the "OPTIMISER" because it is not declared volatile, if I put it there I WANT it there! I'm the human, the master... :lol:
Sorry, this particular post turned into a bit of a rant. You won't hurt my feelings if you skip it. Go ahead, I don't mind.

Ah, still here! :wink: Okay! :D

To add to Cliff's comment, when writing Assembly, you are the master. Nothing is there that you didn't put in and everything you specified is there the way you specified it. (Okay, almost always, assuming the code compiles. :lol:) The trick is specifying it correctly.

In C, you hand "the details" off to the compiler. You're trading better productivity (arguable, in John's case :D) by working at a more abstract level against the compiler's ability to discern your intentions from the code.

The problem is that C is a "necessary but insufficient" method of describing all of the programmer's intent. Is that code supposed to run blazingly fast? Is it supposed to run slow? Is it supposed to be small? Should it be placed exactly there? The code, in and of itself, doesn't say. Even with the __attribute__ directive (or #pragma or whatever the compiler writers use), sometimes the exact intent is lost on the compiler.

There's the rub. Each programmer will prioritize Small versus Fast versus Exact Timing differently, for each case. How is the compiler to know? Or the library writers, for that matter. Smaller doesn't necessarily mean faster, nor vice versa.

In Cliff's case, the Assembly writer will, in the back of his head, know that a variable is accessed often and that no one else will mess with it, so loading the variable into a register and leaving it there is okay. How is the C compiler supposed to know that? Or the Assembly writer may know that this variable is changed by an ISR (or reference a hardware register) and is therefore subject to change without notice. Again, how is the compiler supposed to know that unless you tell it?

You tell the compiler that a variable may change from some source outside the scope of the current code by declaring the variable volatile. You're telling the compiler that it should not rely on this variable staying the same just because it doesn't see it being changed. It's a way of stating your intent that this variable can change wildly and unpredictably at any moment from something happening outside the compiler's ken.

This is a basic problem with abstraction. It doesn't happen only in C -- I had it when I was writing Verilog for a custom chip design. The Verilog code was being taken directly and synthesized into logic gates, then auto-routed into a block to be placed on the chip. Some signals had obvious connections. Others drove humongous buses across the chip. And some signals (clocks, enables, etc.) drove enormous loads within the block.

If the compiler (Synopsys, in this case) had all of my intent, it did pretty well. The problem was that Verilog, in and of itself, did not capture it all.

At any rate, I hope you catch the drift. As I said above, this turned into an huge rant My wife keeps saying I should write a book. When I see some of my posts I think, "I already have, kiddo."

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
ALL my variables are volatile for now to preserve sanity, except for local variables, REALLY local (things that I would use a temp register or 2 in asm).
There aren't any good reasons to declare a local variable volatile.
All your local variables should be non-volatile.
Quote:
If something does not work I rename all variables as volatile and it fixes things. :lol:

I'm used at having everything as being globally accessible with asm so don't quite understand something being eaten by the "OPTIMISER" because it is not declared volatile, if I put it there I WANT it there! I'm the human, the master... :lol:

The optimizer isn't allowed to eat globals of any sort.
A function's net effect on globals is required to be the same regardless of optimization.
For volatiles the sequence of effects is required to be the same regardless of optimization.
If making a local variable volatile fixes something,
another mistake is lurking somewhere.

There is one issue with volatile and ISRs that doesn't get mentioned often:
Inside most ISRs, most volatiles really aren't volatile,
because interrupts are turned off.

There are work-arounds that will allow the optimizer to work:

isrsonly.h:
#define VOLATILE /*nothing*/

nonisrsonly.h:
#define VOLATILE volatile

fred.h:
extern VOLATILE char fred;

main.c:
#include "nonisrsonly.h"
#include "fred.h"
...

isrs.c:
#include "isrsonly.h"
#include "fred.h"
...

Another:

fred.h:
extern volatile char fred;

isrs.c:
#include "fred.h"

ISR(hank_vect)
{
char *fred_ptr=(char*)&fred;  // probably eaten
#define fred (*fred_ptr)
...

#undef fred
}

That said, I expect that a lot of ISRs are so simple
that the volatility of globals doesn't matter much.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

...oh my head.....why did I do it... :lol:

Anyway things are running, just over 9K of code now (mostly due to volatile being used?? :? ), main is running fast enough to catch a pin change coming from the RTC every 500ms and flip the system running led, the 1s WDT is not triggering, inputs are being processed without noticeable delay.

8 C source files, with one annoying giant one that will need to be split into 3 at least, as most of the code in it is from a project and I can't get it's functions or buffers working well from outside so I add my own, duplicating things. But that's not a priority for now as it does what is supposed to do.

I'll attack it later on when things become less hazy.

SO volatile IS GOOD!! :-)

And Sydney is nice and warm, usually, in December. So Cliff and anyone else contemplating a holiday think of Sydney as a destination....and you will be able to streamline my code in a few minutes and then off to the beach. :wink:

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
SO volatile IS GOOD!! :-)
I realize that you've had some issues with finding volatile more necessary that folks here have understood. But, as you move forward, I'd encourage you to think as volatile as being absolutely necessary in certain situations and completely unnecessary and wasteful of time and space in all other situations.
Quote:
And Sydney is nice and warm, usually, in December. So Cliff and anyone else contemplating a holiday think of Sydney as a destination....and you will be able to streamline my code in a few minutes and then off to the beach. :wink:
That would be fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Case in point. If I declare these in main ie:

int	main(void)
{
	uint16_t current_time_hm, On_time_hm,Off_time_hm;	//combined hour and minutes variables

they are not seen within a function in main without being declared volatile

			
			if ( (system_flags & (1<<new_minute_flag)) )

				{ 
				system_flags &= ~ (1<<new_minute_flag);						// Clear new minute flag
				current_time_hm = ( ((RTC_Buffer[ 2 ] & 0x3f) <<8) | (RTC_Buffer [1]) );
				On_time_hm = ( ((eeprom_read_byte (& On_time_h)) <<8) | (eeprom_read_byte (&On_time_m)) );
				Off_time_hm = ( ((eeprom_read_byte (&Off_time_h)) <<8) | (eeprom_read_byte (&Off_time_m)) );
					if ( (current_time_hm >= On_time_hm) && (current_time_hm < Off_time_hm) )
					 {

no problem if I declare them outside main

	extern uint8_t RTC_Buffer[ 10 ];

	uint16_t current_time_hm, On_time_hm,Off_time_hm;	//combined hour and minutes variables

int	main(void)
{

Should not everything within main see all 3 variables as they are local to main?? CRAZY minds need to know!! :?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your variables are "auto" to the main function.

Their scope is throughout the main function, but no other functions will know about them.
So if you want to pass them to another function you should pass as parameters to the function.

main() is not a good example because it is never left.

Take atoi() as an example. main may use: number = atoi(decimal_string);
atoi() uses this parameter to perform its function but does not alter it.
atoi() may get called with different_decimal_string next time. The function is written once, called in many ways.

You may decide that some of these auto variables from main() are better placed as globals.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John, I'm not 100% sure of what you mean by "within a function in main". In C parlance, function means a subroutine. David was mentioning how functions called by main will not be aware of auto variables declared in main. But, are you meaning that auto variables declared within main are not seen by "statements" contained within the main function? In this case, all auto variables should sure been seen within all statements in the main function. (Though, if you declare a block within a function by using braces {} and declare another auto variable with the same name, then only the innermost defined auto variable will be accessed by the block.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm just trying to get my head round why 'volatile' on an auto is even considered legal - what meaning could it have? 'volatile' means "this may be changed by something else that you (the C compiler) cannot see right now" but with local variables "something else" could never "see" them to access them anyway?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's a good point, Cliff, with auto variables being stored on the stack, even multithreaded programs would have no need for volatile auto variables.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have wondered this too. The purpose of volatile (IMHO) is to show me (the author) that something may change out of the program's control.

The side-effect is that the compiler learns about this too.

To lie about it purely so that the compiler produces meaningless code is the wrong approach.

Likewise, if you declare everything as autos, then only move them into global space as required. These variables are fairly likely to be needed by other modules, so only then do they join the extern declarations in project.h.

My personal ( rather jaded ) view of how to treat a compiler.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I'm just trying to get my head round why 'volatile' on an auto is even considered legal - what meaning could it have? 'volatile' means "this may be changed by something else that you (the C compiler) cannot see right now" but with local variables "something else" could never "see" them to access them anyway?

Maybe in the case of passing by reference:

void foo(void)
{
   uint16_t myvar:
   dosomething(&myvar);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
Maybe in the case of passing by reference:
I don't think so. I haven't seen a C compiler that doesn't assume the value of a variable may be changed when you pass its address to a function. One advantage of C99/C++ is that you can use the const keyword to tell the compiler that the value of variable will not be changed by the function so it can have more ability to optimize.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kmr wrote:
CirMicro wrote:
Maybe in the case of passing by reference:
I don't think so. I haven't seen a C compiler that doesn't assume the value of a variable may be changed when you pass its address to a function. One advantage of C99/C++ is that you can use the const keyword to tell the compiler that the value of variable will not be changed by the function so it can have more ability to optimize.

Thats funny, gcc for avr seems to :)

void foo(void)
{
   char myvar=0;
   dosomething(&myvar);
   if(myvar == 0)
   dosomethingelse();  // <-- This gets optimized away
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Their scope is throughout the main function, but no other functions will know about them.
So I thought that everything within main, including any subroutines/functions within main, should be able to see those variables. But that is not the case.

I understand that something declared within any subroutine/function would not be visible by other subroutines/functions or even main, unless they are declared volatile.

Anyway...volatile IS GOOD!..volatile IS GOOD!..volatile IS GOOD!! I must not inhale while writing C code. :-)

This project is almost finished, just a bit more code to read a text file off the USB stick and dump it to USARTO, may even try and write a RS485 driver for my electronic signs, but at the moment it can be driven with just a CR terminated string.

Don't know if I will tackle the DST monster for now (or another C project for that matter), everytime I look into it it gets more complicated, with some coutries even changing DST on Thursday and time varying from 00:00 to 03.00.

Talking about derailing a thread for good! :?

The RTC has turned off the system active led on the module at 8pm and all going to plan it shoud become active at 8am. So it is time for me to turn off also after a short, 13 hour day. It's goodnight from me and goodnight from me..good to have a split personality!

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

main() is really no different to any other function. Anything that gets defined within a set of braces is "hidden" within that area whether those braces be:

int main(void) {
 int only_visible_in_main;
}
void function(void) {
 int only_visible_in_function;
}
void another_function(void) {
 int only_visible_in_another_function;
}

or even:

int main(void) {
 int only_visible_in_main;
 { // start a sub-section within main
  int only_visible_in_subsection;
 }
}

The only difference between main() and the other functions is that (like in Hotel California) you can check-out but you can never leave! So 'only_visible_in_function' and 'only_visible_in_another_function' only exist until their closing brace is reached but as the closing brace of main() is never (hopefully!) reached then 'only_visible_in_main' exists for the entire time the program is running. But function() and another_function() still cannot "see" it.

Oh and 'only_visible_in_subsection' will only last until the } so is more like a local in one of those other functions in that sense.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I'm just trying to get my head round why 'volatile' on an auto is even considered legal - what meaning could it have? 'volatile' means "this may be changed by something else that you (the C compiler) cannot see right now" but with local variables "something else" could never "see" them to access them anyway?

If you store a pointer to it in a global variable and then accesses it in an interrupt.

char *pointer;

ISR(TIM0_ovf) {
  ++*pointer;
}

int main() {
  char variable;
  pointer = &variable;
  ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I'm just trying to get my head round why 'volatile' on an auto is even considered legal - what meaning could it have? 'volatile' means "this may be changed by something else that you (the C compiler) cannot see right now" but with local variables "something else" could never "see" them to access them anyway?

If you store a pointer to it in a global variable and then accesses it in an interrupt.

char * volatile pointer;

ISR(TIM0_ovf) {
  ++*pointer;
}

int main() {
  char variable;
  pointer = &variable;
  ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You rarely need volatile, except when a variable can be changed by something asynchronous to the main flow of execution, like shared variables between ISRs and hardware registers.

Quote:

char * volatile pointer;

creates a volatile pointer, the value pointed to is not volatile.

This creates a pointer to a volatile variable:

volatile char *pointer;

And if both pointer and the referenced value are volatile:

volatile char * volatile pointer;

In this case, on each access the compiler is forced to both reload the pointer itself and the referenced value.

We can stir things up by adding const :P

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
Thats funny, gcc for avr seems to :)
It's not too funny, you're just noticing the effects of the optimizer being smart and realizing that you are not changing the value of variable pointed to in dosomething(). Try replacing your test with dosomething() being defined as
void dosomething(char * m) {
  *m = PINB;
}

and you'll see different assembly output. Alternately, try this definition and look at the code

void dosomething(char * m) {
  *m = 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
and you'll see different assembly output. Alternately, try this definition and look at the code

In my test case I used a global variable that is used in several other functions with the same results as assigning a constant.
char myvar[2];

void dosomething(char * m) {
  *m = myvar[0];
}

I guess the point is that to be sure you were to get the correct code volatile probably would be warranted in these cases if you didn't want to play chance with how another version might handle the optimizations.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or, for an easy life, just build everything -O0 perhaps? ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
I guess the point is that to be sure you were to get the correct code volatile probably would be warranted in these cases if you didn't want to play chance with how another version might handle the optimizations.
You only need to use volatile if another code path will be changing the value. Otherwise, let the optimizer get rid of code that it can discern will never be executed. In your test (if you like, post your whole test program), the compiler can discern that myvar will always be zero, so the second function is never called. I'm not how "play chance with how another version" is at all an issue for your example. Some compilers may be smart enough to see that myvar is always zero so don't bother with the conditional and second function invocations, and others won't be so smart, and will execute the conditional and see that myvar is 0 and not call the function. Other than variances in CPU cycles consumed, there is no difference in the behavior of the program across compilers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Or, for an easy life, just build everything -O0 perhaps? ;)

But that would conflict with directive #4 :wink:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
But that would conflict with directive #4 :wink:
I'm glad that you picked up on Cliff's point!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In part I was actually being serious. I can kind of see an argument why a beginner might be more at home with -O0, for one thing there'll be no mysteries in the debugger. But clearly things like:

MCUCR = JTD;
MCUCR = JTD;

and the 's could cause some consternation when what appears to be "valid code" doesn't do what it says on the tin.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
In part I was actually being serious.
I wonder if we'll see a revision in your famous FAQs :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kevin wrote:
You only need to use volatile if another code path will be changing the value.

Yes, I thought that's what this conversation was about. The "smart" compiler being the whole reason for needing volatile in the first place because sometimes it's not as smart as it thinks it is.

I'm not at my other computer but here is another test program.

#include 
#include 

void Dosomething(char *m);


char myvar[2];


int main(void)
{
  char r = 0;
  Dosomething(&r);

  if (r) r++;

  for(;;);
}


void Dosomething(char *m)
{
  *m = myvar[0];
}


ISR(INT0_vect)
{
  static char i=0;
  i++;
  myvar[0] = '0' + i;

}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
Yes, I thought that's what this conversation was about.
Well, now I'm less sure than ever what this conversation is truly about ;) The original point of the thread (as I understood it) was to help John realize when volatile was necessary and when it was not.

Then, you mentioned that avr-gcc violates my observation that C compilers assume the value of a variable that is passed by reference (pointer) can be changed -- unless the optimizer can inspect the code and see that the function doesn't change the value. You posted a fragment of a single threaded example showing how the optimizer has deduced that the the value of the variable is not changed by the function and so it ptimized away a later conditional and function call. I provided examples that showed how the compiler will no longer make that assumption with the functions I provided.

Then, you post a total difference example using interrupts where volatile is clearly required for a correct operation. So, I'm not sure what your original point was to my post. But, I have the feeling that somehow we agree about all this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
But, I have the feeling that somehow we agree about all this.

I'm getting that feeling too.

My only point was that the compiler does still try to optimize even if by reference and it is possible a variable may be altered that the compiler might not pick up on. Admittedly most of these situations probably wouldn't be very good programming practice anyway.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
kmr wrote:
CirMicro wrote:
Maybe in the case of passing by reference:
I don't think so. I haven't seen a C compiler that doesn't assume the value of a variable may be changed when you pass its address to a function. One advantage of C99/C++ is that you can use the const keyword to tell the compiler that the value of variable will not be changed by the function so it can have more ability to optimize.

Thats funny, gcc for avr seems to :)

void foo(void)
{
   char myvar=0;
   dosomething(&myvar);
   if(myvar == 0)
   dosomethingelse();  // <-- This gets optimized away
} 

If dosomethingelse() is being optimized away,
the compiler can tell that myvar is being changed.
Perhaps foo is preceded by
void dosomething(char *tovictim)
{
*tovictim=1;
} // dosomething

Then again, dosomethingelse() might have been optimized
away because it doesn't do anything.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
My only point was that the compiler does still try to optimize even if by reference and it is possible a variable may be altered that the compiler might not pick up on. Admittedly most of these situations probably wouldn't be very good programming practice anyway.
Okay, I understand. Yes, with optimization on, the compiler will try to optimize calls by reference to the extent that it can. And, yes, it can be tripped up by some of the programming issues we've seen in the thread, such as aliased pointers http://en.wikipedia.org/wiki/Ali...(computing) .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
If dosomethingelse() is being optimized away...
Agreed, Michael. After further discussion with CirMicro, he understands this, too. But, sure took a few posts to get to this level of mutual understanding!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My look at this is, that the semantics of C assumes
that there is only a single flow of control.
And the optimizer can do what it wants as long as
the user can not notice it, but it assumes
there is a 'single flow of control'.

But with interrupts the 'single flow of control'
assumption is no longer valid. And so something had to
be invented to prevent the optimizer to do certain things.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just made those 3 variables volatile and the code jumps from 9306 to 9336 bytes, so I can see the value of limiting the number of volatile variables.

So it will be a case of going through and finding out what really needs to be volatile and what does not.

Working with multiple files the need is there to share variables and therefore some need to be volatile.

Does the optimser give warnings of eaten code? I can't remember, I have seen warnings about unused variables when doing test builds with some variables declared but yet unused. I suppose the only reason I got the warnings was because they were volatile?? otherwise they may have been quietly "optimised".

Where is Ian Flemings?? The next James Bond movie MUST include the phrase about someone "being optimised".

Or perhaps Arnie could say in Total Recall II "Consider this an optimazation of our relationship" instead of "Consider it a divorce". :?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1. Since you are > 8192 bytes, you only need to worry about code size as you approach 16384.

2. Seriously go through your functions to eliminate any use of global variables. i.e. use a function return value, and send structure addresses as parameters. There is no problem with sending a buffer address, the function modifies the buffer, the function returns a good or bad boolean result. Your function is documented once, is re-usable, has some clear calling conventions, and effects.

3. You will always end up with a small number of global structures and simple variables.

4. I would guess that your ISRs are relatively simple and compact. Even then, they will seldom do more than set flags or update a buffer pointer. These things are volatile because they can change outside of normal program flow. A variable that is read by an ISR but otherwise not altered is not volatile.

5. It is no different to using ASM. You have to keep track of register and variable usage. I suspect that you already have your own style for register stacking and re-use. You will also have your own documentation style for variable use.

6. With C, you can just accept that the language looks after the registers. But variables are exactly the same. So the fewer global variables and greater re-use of debugged functions apply to both languages.

7. If you have ever used 68000 ASM, you tend to place local variables in temporary storage in a stack frame. They are available throughout that subroutine, at the RTS they disappear, and the space is re-used by the next subroutine. You can argue that 68000 followed C or that C followed the 68000.

8. I believe that you choose not to use a command line, so you are limited in using standard tools. But even with the Studio editor you can find across files ( in a pretty restricted way ). Your current project will be good experience in writing re-usable functions and modularising code.

9. When you are finished I guess that you will have less volatile variables than the number of ISRs.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By re-arranging some code and only making volatile the necessary variables shared by various modules I saved 144 bytes.

With asm everything is "volatile", whatever RAM variables are declared are always there, accessible by any routine from anywhere. Pointers and passing data via the stack is not really my cup of expresso.. :?

Maybe one day, when I grow up, I'll be more proficient with them.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
With asm everything is "volatile", whatever RAM variables are declared are always there, accessible by any routine from anywhere.

Ah but I'll bet if you had a routine that looked something like:

routine:
 LDS R16, RAM_location
 ORI R16, 0x55
 STS RAM_location, R16
...
 LDS R16, RAM_location
 OUT PORTB, R16
 RET

then you'd actually be tempted to:

.def RAM_copy R24

routine:
 LDS RAM_copy, RAM_location
 ORI RAM_copy, 0x55
 STS RAM_location, RAM_copy
...
 OUT PORTB, RAM_copy
 RET

(that is dedicate a register to temporarily holding a copy to save instructions and RAM access) but consider what happens if an interrupt that may update RAM_location occurs during those "..."

If you thought this could happen you would write it the first way, if you didn't think it could happen you'd probably use the second way.

Meanwhile back in C:

void routine(void) {
 RAM_location |= 0x55;
...
 PORTB = RAM_location;
}

there's no obvious way to ask the compiler to use implemenation 1 or 2.

Well, actually there is, 'volatile unsigned char RAM_location' ensures that implementation 1 (or similar) will be used.

So you are making the same choices about RAM variables when you write Asm - it's just it's not as formalised as having a keyword to force a particular behaviour.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Pointers and passing data via the stack is not really my cup of expresso..

There are only a limited number of techniques, but many variations of them.

1. Never use a register. Just use global memory locations.
2. Pass parameters via registers.
3. Pass parameters via the stack.

You must have some sort of strategy for register use. I cannot believe that you have no plan at all.
For example to send a string to the USART, I would guess that you pass the string address in a register pair, and have a sentinel terminator. You probably choose to restore any registers that are used.

I would put money on you using method 2, even if you are loath to admit it.

Incidentally, method 3 in 68000 ASM would normally look like regular memory addressing. You just assign your storage via a stack frame register. With macros, you would never even know.

If you really do re-write each "typical function" using hard-coded values, you must have a nightmare with every new project.

I suspect that you are already organised, and are taking a gentle p*ss. You already manage large ASM projects, so you must have a system. You also know that remembering register / memory / variable use over a large project is no easy task. The principles are exactly the same with any language.

I would suggest that re-arranging your existing style to enable better modularity is a worthwhile task.

David.

Edit. You may well feel more comfortable by just moving to an assembler that produces linkable objects. The trick is to reduce the number of .global or .extern directives. And definitely avoid avr-as that is not strict with .externs

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
So it will be a case of going through and finding out what really needs to be volatile and what does not.
Absent heavy math, the rule is simple:
if it's changed by an interrupt handler and it's
used or changed when an interrupt is possible,
it needs to be volatile.
Otherwise it doesn't.
Quote:
Does the optimser give warnings of eaten code?
No.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
2. Pass parameters via registers.
I understand that because I control which registers do what, I don't really want to know how the compiler does it.

I have r24 as temp, r25 as temp1 and r23 as temp3 usually for macros use. And of course I use the index registers in an organised way. ie printing routines, eeprom read/write use Z.

So summing up the volatile issue for me: with asm I declare a ram or even a register variable (for smaller projects no ram used) "and it stays there, it just lies there"...a feel a song coming up...regardless of how/if used. With C "it ain't necessarily so"..another song popping up...

And I become "volatile" when I try to watch something and I get a "memory location not valid" or other rubbish. Or I try and put a breakpoint somewhere and the breakpoint pops up half a dozen lines down, no matter what :evil: I just know that my code has been "optimised"!

How do I then prevent these vaiables being declared as volatile?

They are declared in the project_name_functions.c where working bit of code end up to clear project_name_main.c

	volatile uint8_t supply_voltage, dB ;
	volatile uint8_t old_minute, new_minute;

supply_voltage, dB are variables worked on in this module and accessed by the project_name_monitor.c with

	extern uint8_t supply_voltage, dB;

and in project_name_main.c with

//External variables
	extern uint8_t RTC_Buffer[ 10 ], old_minute;

new_minute is only used project_name_functions.c so does not have to be volatile, correct?

RTC_Buffer will eventually disappear when I get my head around at accessing the existing RTC buffer, written by others and in another module. Not a priority but I'm duplicating code and ram usage as I know what I'm doing with my own code.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John,

The optimiser is less clever than you. It is just that it does not get tired, emotional, hungry etc like humans.

If you can see that you gave a bone to a dead dog, you know that the bone will still be there. So there is no need to constantly check.
Give a bone to a live dog, and it may be left, eaten buried... You have a volatile situation.
No, stray dogs ae not allowed to go bone-stealing.

So by the variable names that you are using, I would guess that Supply_Voltage is likely to be set by an ISR that reads an ADC. So of course it can change outside of program control, and as such be volatile. Similarly New_Minute is likely to be set by an ISR.

For debugging purposes you may find it handy to copy something to a dummy local variable that you Watch. The dummy must constantly re-read the changing variable. Otherwise it remains unaltered. Try Watching the real variable instead.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
With asm everything is "volatile", whatever RAM variables are declared are always there, accessible by any routine from anywhere.

You are still confusing terms here. What you mean here is that everything in asm is "global". Volatile is a completely different concept.

Quote:
And I become "volatile" when I try to watch something and I get a "memory location not valid" or other rubbish. Or I try and put a breakpoint somewhere and the breakpoint pops up half a dozen lines down, no matter what I just know that my code has been "optimised"!

This part should be easy for you. Just bring up the dissassembly window and watch what is happening there. These situations happen because the code has been optimized enough that it can not be matched up easily to the C code.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
This part should be easy for you. Just bring up the dissassembly window and watch what is happening there. These situations happen because the code has been optimized enough that it can not be matched up easily to the C code.
The .lss file contains a listing of asm roughly
interleaved with the corresponding C.
Sometimes the correspondence is rather rough.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

Pages