Electronics & Programming

develissimo

Open Source electronics development and programming

  • You are not logged in.
  • Root
  • » MSPGCC
  • » [Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions [RSS Feed]

#1 Nov. 4, 2005 03:44:27

Kris H.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


Hi all,

I couldn't find an email address for Steve Underwood, who wrote the very good
online manual for mspgcc, so I'm posting
this message on the mspgcc-users forum (even though I'm not a user :-)

In response to the "tips and trick for efficient programming" section. I
agree with most of these recommendations
and thank you for a good quality piece of work. I think some explanations would
be appropriate, rather than just the
guidelines. I have specific comments on a few points:

> 5. Avoid using global variables of small size - it is a waste of RAM.

I don't understand this at all. It's normal for an embedded program to have
lots of global variables, and many of these
will be bytes. If you mean what you wrote, I disagree and I don't see your
point. If you mean something else, perhaps
you could make the wording clearer. By "small size" do you mean smaller than a
byte?

> 6. Avoid using volatiles, unless they are really necessary.

No one would ever declare a variable volatile unless there was a good reason
to. Are you saying that the compiler can
optimise better with variables which aren't volatile? That's normal for any
compiler AFAIK.

> 7. Use int instead of char or unsigned char if you want an 8 bit integer.

What? An unsigned char _is_ 8 bits wide. Do you mean the case where you need
eight bits _plus sign_? That would be a
9-bit integer.

> 18. If you execute
> while ((long) a & 0x80000l);
> the program will hang, unless 'a' is declared volatile. So, do it!

That would be a really weird and pointless thing to write, unless you _know_
that 'a' is volatile and _will_ be changed
elsewhere, e.g. by an interrupt handler. And I think you mean "So, _don't_ do
it!"

> 19. Delay loops are very sophisticated routines.
>

I don't think delay loops are necessarily "poor programming style" in the
context of an embedded system where the MCU
clock frequency is known and the device has a (fairly) predictable number of
cycles per instruction. If you want to
delay by a few microseconds, a loop is the obvious way - you could use a timer
(if you have one spare), with or without
an interrupt, but this would add lots of overhead, and a very short tight delay
would not be achievable. True the
maximum execution time is not defined if interrupts are used and interrupts are
enabled during the loop, but this is
often not the case - it depends on the context in which the code is used. In
any case, it's not always necessary to have
a maximum limit on the delay time - for a safety timeout, for example, it's
just necessary to avoid getting stuck
forever in a loop somewhere due to some hardware failure. Instead of saying
words to the effect of "don't do it", you
could suggest how to trick the compiler into not optimising the loop away into
the ether. For example, adding an
"asm("nop")" (or mspgcc's equivalent) in the body of the loop might be enough;
if there's no recommendable way to do
this, perhaps you should add a feature to the compiler to specifically support
short delays, e.g. it could generate the
loop itself, given a number of CPU cycles for the delay. Short delay loops are
common in embedded systems software; some
conventions that apply to other programming situations apply less or not at all
to an embedded system. Just a
suggestion.

> Do not do anything unless you know what you're doing :)

Very good advice for all embedded systems programmers!

Kris
k***@*bbey.co.nz
Kris Heidenstrom Embedded systems design engineer / programmer
Abbey Systems Ltd Telemetry specialists Wellington New Zealand
Voice +64 -4 -385-6611 Fax +64-4-385-6848

Offline

#2 Nov. 4, 2005 07:57:56

Jonas S.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


Hi,

> 7. Use int instead of char or unsigned char if you want an 8 bit integer.

I think this is just written strange. I think it should be:

7. Use int or unsigned char instead of char if you want an 8 bit integer.

Jonas

Offline

#3 Nov. 4, 2005 07:59:58

David S.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


See my comments added in-line below/

Sincerely,

David Smead
www.amplepower.com
www.amplepower.net


On Fri, 4 Nov 2005, Kris Heidenstrom wrote:Hi all,

I couldn't find an email address for Steve Underwood, who wrote the very good
online manual for mspgcc, so I'm posting
this message on the mspgcc-users forum (even though I'm not a user :-)

In response to the "tips and trick for efficient programming" section. I
agree with most of these recommendations
and thank you for a good quality piece of work. I think some explanations would
be appropriate, rather than just the
guidelines. I have specific comments on a few points:5. Avoid using global variables of small size - it is a waste of RAM.I don't understand this at all. It's normal for an embedded program to have
lots of global variables, and many of these
will be bytes. If you mean what you wrote, I disagree and I don't see your
point. If you mean something else, perhaps
you could make the wording clearer. By "small size" do you mean smaller than a
byte?If you organize variables in structures, or arrays, then access to themcan be done with a pointer, which may stay in a register much of the time.Code will be smaller and faster.6. Avoid using volatiles, unless they are really necessary.No one would ever declare a variable volatile unless there was a good reason
to. Are you saying that the compiler can
optimise better with variables which aren't volatile? That's normal for any
compiler AFAIK.7. Use int instead of char or unsigned char if you want an 8 bit integer.An int is the `native size', whereas signed 8 bit variables force signextension be done.What? An unsigned char _is_ 8 bits wide. Do you mean the case where you need
eight bits _plus sign_? That would be a
9-bit integer.18. If you execute
while ((long) a & 0x80000l);
the program will hang, unless 'a' is declared volatile. So, do it!That would be a really weird and pointless thing to write, unless you _know_
that 'a' is volatile and _will_ be changed
elsewhere, e.g. by an interrupt handler. And I think you mean "So, _don't_ do
it!"19. Delay loops are very sophisticated routines.
I've been programming embedded systems since the mid-1960s, and I don'tuse delay loops, although I have used three nops in a row to stretch apulse. I've also resorted to tricks like using the known time of an A-Dconversion as a way to time some action. I can remember when computerswere slow and wasted cycles meant something wasn't going to work right.I don't think delay loops are necessarily "poor programming style" in the
context of an embedded system where the MCU
clock frequency is known and the device has a (fairly) predictable number of
cycles per instruction. If you want to
delay by a few microseconds, a loop is the obvious way - you could use a timer
(if you have one spare), with or without
an interrupt, but this would add lots of overhead, and a very short tight delay
would not be achievable. True the
maximum execution time is not defined if interrupts are used and interrupts are
enabled during the loop, but this is
often not the case - it depends on the context in which the code is used. In
any case, it's not always necessary to have
a maximum limit on the delay time - for a safety timeout, for example, it's
just necessary to avoid getting stuck
forever in a loop somewhere due to some hardware failure. Instead of saying words to the
effect of "don't do it", you
could suggest how to trick the compiler into not optimising the loop away into
the ether. For example, adding an
"asm("nop")" (or mspgcc's equivalent) in the body of the loop might be enough;
if there's no recommendable way to do
this, perhaps you should add a feature to the compiler to specifically support
short delays, e.g. it could generate the
loop itself, given a number of CPU cycles for the delay. Short delay loops are
common in embedded systems software; some
conventions that apply to other programming situations apply less or not at all
to an embedded system. Just a
suggestion.Do not do anything unless you know what you're doing :)Very good advice for all embedded systems programmers!

Kris
k***@*bbey.co.nz
Kris Heidenstrom Embedded systems design engineer / programmer
Abbey Systems Ltd Telemetry specialists Wellington New Zealand
Voice +64 -4 -385-6611 Fax +64-4-385-6848



-------------------------------------------------------
SF.Net email is sponsored by:
Tame your development challenges with Apache's Geronimo App Server. Download
it for free - -and be entered to win a 42" plasma tv or your very own
Sony(tm)PSP. Click here to play:http://sourceforge.net/geronimo.php_______________________________________________
Mspgcc-users mailing list
Mspgcc-users@lists.sourceforge.nethttps://lists.sourceforge.net/lists/listinfo/mspgcc-users

Offline

#4 Nov. 4, 2005 09:38:35

David B.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


> See my comments added in-line below/
>
> Sincerely,
>
> David Smead

I've snipped a bit, and added new comments below.

mvh.,

David


>
> On Fri, 4 Nov 2005, Kris Heidenstrom wrote:
>
> > Hi all,
> >
> >
> >> 5. Avoid using global variables of small size - it is a waste of RAM.
> >
> > I don't understand this at all. It's normal for an embedded program to
have lots of global variables, and many of these
> > will be bytes. If you mean what you wrote, I disagree and I don't see
your point. If you mean something else, perhaps
> > you could make the wording clearer. By "small size" do you mean smaller
than a byte?
> >
> If you organize variables in structures, or arrays, then access to them
> can be done with a pointer, which may stay in a register much of the time.
> Code will be smaller and faster.
>

As far as I can tell, accessing data directly (in absolute mode) has the
same size and speed as accessing it via a pointer. In fact, absolute mode
is implemented as indexed mode using R2 (which gives 0 in indexed mode).
Occasionally, the optomizer might be able to use auto-increment or
auto-decrement modes for accessing structured data, which might be very
slightly more efficient.

The reason for the tip could be that mixing bytes and words in the global
data section could waste bytes through alignment padding.



> >> 6. Avoid using volatiles, unless they are really necessary.
> >
> > No one would ever declare a variable volatile unless there was a good
reason to. Are you saying that the compiler can
> > optimise better with variables which aren't volatile? That's normal for
any compiler AFAIK.
> >

Not true, and not true. Proper use of "volatile" causes newcomers to
embedded programming a great deal of trouble, and sometimes they do err on
the side of making too much volatile (for example, there is the myth that
all data accessed by interrupt routines must be volatile). Also, there are
plenty of embedded compilers which effectively treat all global data as
volatile - people switching from these to gcc are particularly prone to
confusion.


> >> 7. Use int instead of char or unsigned char if you want an 8 bit
integer.
> An int is the `native size', whereas signed 8 bit variables force sign
> extension be done.
> >
> > What? An unsigned char _is_ 8 bits wide. Do you mean the case where you
need eight bits _plus sign_? That would be a
> > 9-bit integer.
> >

> >> 18. If you execute
> >> while ((long) a & 0x80000l);
> >> the program will hang, unless 'a' is declared volatile. So, do it!
> >
> > That would be a really weird and pointless thing to write, unless you
_know_ that 'a' is volatile and _will_ be changed
> > elsewhere, e.g. by an interrupt handler. And I think you mean "So,
_don't_ do it!"
> >

People do write this sort of thing - while loops that wait on a flag, or a
counter passing a certain value are common. And if you don't know how to
use "volatile" properly, you get in trouble. And he does mean "So, do
it!" - the "it" refers to "declaring a volatile". But I'd have to agree
it's not very clear.


> >> 19. Delay loops are very sophisticated routines.
> >>
> >
> I've been programming embedded systems since the mid-1960s, and I don't
> use delay loops, although I have used three nops in a row to stretch a
> pulse. I've also resorted to tricks like using the known time of an A-D
> conversion as a way to time some action. I can remember when computers
> were slow and wasted cycles meant something wasn't going to work right.
>
> >> Do not do anything unless you know what you're doing :)
> >
> > Very good advice for all embedded systems programmers!
> >

Offline

#5 Nov. 4, 2005 15:16:27

Steve U.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


Kris Heidenstrom wrote:Hi all,

I couldn't find an email address for Steve Underwood, who wrote the very good
online manual for mspgcc, so I'm posting
this message on the mspgcc-users forum (even though I'm not a user :-)

In response to the "tips and trick for efficient programming" section. I
agree with most of these recommendations
and thank you for a good quality piece of work. I think some explanations would
be appropriate, rather than just the
guidelines. I have specific comments on a few points:5. Avoid using global variables of small size - it is a waste of RAM.I don't understand this at all. It's normal for an embedded program to have
lots of global variables, and many of these
will be bytes. If you mean what you wrote, I disagree and I don't see your
point. If you mean something else, perhaps
you could make the wording clearer. By "small size" do you mean smaller than a
byte?Have you looked at the typical embedded programmer's work? 90% of alltheir variable are global. It derives from poor assembly languageprogramming, I guess, and the style is carried over to poor C programming.6. Avoid using volatiles, unless they are really necessary.No one would ever declare a variable volatile unless there was a good reason
to. Are you saying that the compiler can
optimise better with variables which aren't volatile? That's normal for any
compiler AFAIK.Do you have any idea how small a percentage of embedded C programmersunderstand what volatile really means, and where it is needed?Lots of people who have used the IAR tools complain about GCC beingbroken, because changes to a global are not sensed. The IAR compiler istoo dumb to optimise away most things, and you can be sloppy and leaveout all the volatiles. Most programmers do. At the other extreme, somepeople put volatile in front of everything. That looses you a lot ofspace and speed optimisation with GCC.const is another important keyword, especially for embedded systems,that people can't really get the hang of. static is even worse.7. Use int instead of char or unsigned char if you want an 8 bit integer.What? An unsigned char _is_ 8 bits wide. Do you mean the case where you need
eight bits _plus sign_? That would be a
9-bit integer.If you use a char or unsigned char as a simple small integer, like aloop counter, the code will be bigger and slower than using the naturalinteger of the machine - an int. Perhaps I use expand the wording there.18. If you execute
while ((long) a & 0x80000l);
the program will hang, unless 'a' is declared volatile. So, do it!That would be a really weird and pointless thing to write, unless you _know_
that 'a' is volatile and _will_ be changed
elsewhere, e.g. by an interrupt handler. And I think you mean "So, _don't_ do
it!"Maybe the wording could be better. My intention by "do it" is do declarethe thing volatile. I should change the order too, to group this withother volatile related points.19. Delay loops are very sophisticated routines.
I don't think delay loops are necessarily "poor programming style" in the
context of an embedded system where the MCU
clock frequency is known and the device has a (fairly) predictable number of
cycles per instruction. If you want to
delay by a few microseconds, a loop is the obvious way - you could use a timer
(if you have one spare), with or without
an interrupt, but this would add lots of overhead, and a very short tight delay
would not be achievable. True the
maximum execution time is not defined if interrupts are used and interrupts are
enabled during the loop, but this is
often not the case - it depends on the context in which the code is used. In
any case, it's not always necessary to have
a maximum limit on the delay time - for a safety timeout, for example, it's
just necessary to avoid getting stuck
forever in a loop somewhere due to some hardware failure. Instead of saying words to the
effect of "don't do it", you
could suggest how to trick the compiler into not optimising the loop away into
the ether. For example, adding an
"asm("nop")" (or mspgcc's equivalent) in the body of the loop might be enough;
if there's no recommendable way to do
this, perhaps you should add a feature to the compiler to specifically support
short delays, e.g. it could generate the
loop itself, given a number of CPU cycles for the delay. Short delay loops are
common in embedded systems software; some
conventions that apply to other programming situations apply less or not at all
to an embedded system. Just a
suggestion.Delay loops are often the only appropriate way to get a smallpredictable delay. There's nothing wrong with that. There is somethingwrong withfor (i = 0; i < 10; i++);GCC will optimise it clean away, unless i is a global volatile. Even ifi a global volatile, the speed of the loop is totally uncertain. Thebrief_pause routine I show in the manual is what I would call a goodpause routine - compact and basically predictable. Sure, and interruptcould extend it, but these things are usually there to impose a welldefined minimum delay. Adding _NOP() is wasteful - maybe only a little,but still poor style when you are programming a 1k chip.Do not do anything unless you know what you're doing :)Very good advice for all embedded systems programmers!Steve

Offline

#6 Nov. 4, 2005 15:43:24

Russ M.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


I'm willing to admit that I don't fully understand where volatile goes. Not
only would it be very noble of someone to explain this to us, but I'm
certain that he would be rained with fame, women, and money for his efforts.

Russ

On 11/4/05, Steve Underwood <ste***@*oppice.org> wrote:
>
> >>6. Avoid using volatiles, unless they are really necessary.
> >>
> >>
> >
> >No one would ever declare a variable volatile unless there was a good
> reason to. Are you saying that the compiler can
> >optimise better with variables which aren't volatile? That's normal for
> any compiler AFAIK.
> >
> >
> Do you have any idea how small a percentage of embedded C programmers
> understand what volatile really means, and where it is needed?
>

Offline

#7 Nov. 4, 2005 16:31:47

Steve U.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


Russ Meyerriecks wrote:I'm willing to admit that I don't fully understand where volatilegoes. Not only would it be very noble of someone to explain this tous, but I'm certain that he would be rained with fame, women, andmoney for his efforts.I'd help, but I suspect you are not being entirely honest about thepotential rewards.RussOn 11/4/05, *Steve Underwood* <ste***@*oppice.org<mailto:ste***@*oppice.org>> wrote:>>6. Avoid using volatiles, unless they are really necessary.
>>
>>
>
>No one would ever declare a variable volatile unless there was a
good reason to. Are you saying that the compiler can
>optimise better with variables which aren't volatile? That's
normal for any compiler AFAIK.
>
>
Do you have any idea how small a percentage of embedded C programmers
understand what volatile really means, and where it is needed?Oh, OK.

What happens if I do this?

int i;

interrupt (TIMERA0_VECTOR) int_routine(void)
{
i = 42;
}

void func(void)
{

i = 0;
while (i == 0);
}Let's assume here that interrupts are working, and "func" is called. Ifyou are used to poorly optimising compilers you might expect "func" toreturn after a timer A interrupt. With GCC and no optimisation "func"will return (I am not sure if that is certain to happen, but it alwaysseems to work). However, turn on optimisation, and GCC will strip outwhatever it can. For example, it could hold "i" in a register within"func", and never see the change cause within the interrupt routine. Itcould go further, figuring out that nothing is every going to happen inthat loop, and strip out the test of i completely, leaving an infiniteloop. If I want to tell GCC that it must look at the actual memorylocation of i each time it checks or manipulates i, I need to declare ias "volatile int i;". Then, we can be sure "func" will respond asrequired when the interrupt routine alters i.The other side of this is that if we start using "volatile" tooliberally we loose significant efficiency. Instead of doing lots of fastcompact register only work, the compiler is forced to go to the realmemory location for everything it does with variables marked volatile.In most cases that is pure waste, making things bigger and slower thannecessary.volatile is your friend. Use it wisely, and the really smart compilerswill do what you want.Regards,
Steve

Offline

#8 Nov. 5, 2005 03:17:42

m.
Registered: 2009-11-02
Reputation: +  0  -
Profile   Send e-mail  

[Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions


> I'm willing to admit that I don't fully understand where volatile goes. Not
> only would it be very noble of someone to explain this to us, but I'm
> certain that he would be rained with fame, women, and money for his efforts.

It goes like this: the C language is inherently single-threaded.
It does not understand multiple threads or interrupt handlers.

The standard is very clear that the compiler is allowed to assume that
nobody is changing any variables except the executing code. So when
I write

foo = 42;
bar = foo;

If I don't refer to foo again, the compiler is quite free to eliminate
it entirely and just generate
bar = 42;

Further, if the rest of the code ends up using the vale of bar/2 a lot,
the compiler could just let bar = 21 and eliminate all those divisions.

To take a simple example, if you write a standard loop in C:

for (i = 0; i < 10; i++)
foo();

gcc actually generates:
bar:
call #foo
call #foo
call #foo
call #foo
call #foo
call #foo
call #foo
call #foo
call #foo
call #foo
ret

Look ma, no variable i at all!

If I make the loop a little bigger:

unsigned x = 0
for (i = 0; i < 100; i++)
x += foo(x);
return x;

Then I get

bar:
push r11
push r10
mov #0, r10
mov #99, r11
.L6:
mov r10, r15
call #foo
add r15, r10
add #-1, r11
jge .L6
mov r10, r15
pop r10
pop r11
ret

The closest thing to a variable i is r11, which counts from 99 down to 0
rather than 0 up to 99.

The compiler can do this because it knows that nobody, including the
called function foo, is allowed to see or change i, so it can convert
it to a different form.


This sort of thing is harder to do with global variables, because the
compiler can't see the entire program as it's compiling (but there do
exist compilers which do such "interprocedural" optimization at link
time, so it's not impossible), but the compiler can still load
the global variable when it enters a function and store it once when
it leaves and not touch it in memory in the mean time. One thing
it does particularly often is change the order in which it reads from
or writes to such variables.


Now, any form of multithreading, including interrupt handlers or
hardware peripherals that rewrite status registers, breaks this
assumption all over the place. In order to make it possible to write
such code, the ANSI C standard includes the "volatile" keyword.

"volatile" says "someone else may read or write this variable at any
time, so don't get clever. Every time I refer to the variable in my
source code, you have to actually go to the given memory address and
do an actual load or store."

The compiler is still allowed to optimize access to any other variables,
but doesn't assume that the "volatile" variable has the same value
when loaded as was last stored.


If you have a variable that is used by an interrupt handler, you must
declare it volatile in the non-interrupt code that reads or writes it,
or what the interrupt handler sees and when it sees it won't be
well-defined. Likewise, if it's written by the interrupt handler,
it has to be volatile or there's no guarantee the main code will see the
change.

This pessimism, however, comes at a significant performance cost.
*Don't* use voltatile anywhere you don't need it. If a "variable"
never actually varies, or is only accessed from one thread, leaving
volatile off generates smaller and faster code. Local variables,
for example, are almost never volatile.

Hardware registers act like interrupt handlers, too - the "interrupt
handler" just executes on custom hardware rather than in the
main processor.


One possible analogy is like going to the bathroom in the dark. I can get
out of bed and find the bathroom without turning the lights on because I
know where everything is, so I don't have to see the furniture to avoid
tripping on it. The furniture is where I last left it. But if I live
with someone who likes rearranging the furniture, I'd better turn on
the lights or I'm going to get in trouble.


Here's one example of volatile usage that isn't an interrupt handler,
but is an excellent example of its intended use. Sometimes, people like
to include identifcation strings (like the famous RCS $Id: ...$ headers)
in an executable or ROM image. And there are utilities like "rcsid" or
"strings" that search through the executable and pull out those strings.
A lot of source files start with

static char const rcsid = "$Id: file.c,v 1.32 2005/11/04 ...";

It's static so the same name ("rcsid") can be used in each file without
the compiler complaining.

But some compilers are smart enough to notice that nothing inside file.c
actually refers to that array, and since it's static, no other source
files can refer to it, so they leave it out!

But the whole point of the string is that it's read by something *other*
than the program - they're read by something that examines the non-running
program's executable.

This is exactly what volatile is for. You can write

static char const volatile rcsid = "$Id: file.c,v 1.32 2005/11/04 ...";

and the compiler knows it's not allowed to delete it just because it
can't figure out who's reading it.

Offline

  • Root
  • » MSPGCC
  • » [Mspgcc-users] Attn Steve Underwood, mspgcc online manual section 7, "tips and tricks", opinions and questions [RSS Feed]

Board footer

Moderator control

Enjoy the 18th of November
PoweredBy

The Forums are managed by develissimo stuff members, if you find any issues or misplaced content please help us to fix it. Thank you! Tell us via Contact Options
Leave a Message
Welcome to Develissimo Live Support