Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Portability: Harmony between PC and microcontroller

Reply
Thread Tools

Portability: Harmony between PC and microcontroller

 
 
Tomás Ó hÉilidhe
Guest
Posts: n/a
 
      05-05-2008

I'll try to summarise this as best I can, as my last thread wasn't
very to-the-point:

The C Standard says the following two things:

* int is the natural integer type for the system.
* int must be at least 16-Bit.

Now the problem here is that these two criteria conflict if the
natural type for the system is in fact 8-Bit, which is the case with
many microcontrollers today.

As an example, let's take the following code:

char unsigned x, y;
...
x = y;

On my microcontroller compiler, this produces different assembler
depending on whether 'x' is an "unsigned int" or an "unsigned char".
If it's an "unsigned char", then the assembler is:

MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */

However, if 'x' is an "unsigned int", then the assembler is:

MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
MOVF y+1, W /* Copy the next byte of y to the acc */
MOVWF x+1 /* Copy the acc to the next byte of x */

Now quite plainly to see, the "int" version takes twice as many
instructions in this case, and will therefore take exactly twice as
long to execute, and so will be twice as slow. In other situations,
the difference is far worse; let's take for example the following
code:

if (condition) x = y;

Depending on the type of x and y, this produces either:

MOVF y, W /* Copy y to the accumulator */
BTFSC condition /* If condition is false, skip the next
instruction */
MOVWF x /* Copy the accumulator to x */

or:

BTFSS condition /* Skip the next instruction if condition is true
*/
GOTO There
MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
MOVF y+1, W /* Copy the next byte of y to the acc */
MOVWF x+1 /* Copy the acc to the next byte of x */
There:

Not only does the int version consist of more instructions, but it
also involves a goto which will take up even more time. So basically
if your microcontroller is running at 8 MHz, then you may aswell
pretend it's running at 4 MHz or 2 MHz if you're going to be using int
for doing everyday arithmetic.

Now we could go down the road of discussing how C is inadequate in
terms of its accommodation of microcontrollers, but I'd rather discuss
ways of "making it right". The reason I'm so eager to bridge the gap
is that, other than the "int" situation, C is actually great for
programming an embedded system. I used it in my college project this
year to program a portable electronic Connect4 game, and it worked
great!

One way of making things right is to stop using int for arbitrarily
storing numbers, and instead use something like ufast8 (the fastest
integer type that's at least 8-Bit). In this way, neither the
microcontrollers nor the PC's suffer.

Examples of a piece of code that could be brought between PC's and
microcontrollers is something like a look-up table as follows:

ufast8 days_in_month[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

To those people out there who are enthusiastic about writing portable
code, how do you feel about using types such as ufast8 instead of int?

stdint.h is great and all, but I find the type names to be too long
winded. For instance I'd rather write "ufast8" instead of
"uint_fast8_t".
 
Reply With Quote
 
 
 
 
Martin Ambuhl
Guest
Posts: n/a
 
      05-05-2008
CBFalconer wrote:
> Jack Klein wrote:
> .... snip ...
>> One of the things that you might not realize is that the C
>> programming language was developed originally on a 16-bit
>> minicomputer. At the time Dennis was developing C, there was no
>> such thing as an 8-bit microprocessor in existence. Let alone
>> 8-bit microcontrollers which evolved after the microprocessor.

>
> Cough, hack. Remember the PDP8?


Cough, hack. The PDP-8 and PDP-5 were 12 bit machines.
 
Reply With Quote
 
 
 
 
Bartc
Guest
Posts: n/a
 
      05-05-2008

"Tomás Ó hÉilidhe" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
>
> I'll try to summarise this as best I can, as my last thread wasn't
> very to-the-point:
>
> The C Standard says the following two things:
>
> * int is the natural integer type for the system.
> * int must be at least 16-Bit.
>
> Now the problem here is that these two criteria conflict if the
> natural type for the system is in fact 8-Bit, which is the case with
> many microcontrollers today.
>
> As an example, let's take the following code:
>
> char unsigned x, y;
> ...
> x = y;


It doesn't seem an insurmountable problem.

If you want a default int size that is best for your cpu, try something
like:

typedef unsigned char uint; /* Or uint_fast8_t etc. */
typedef signed char sint;

Then use uint and sint everywhere in place of unsigned/signed int.

When moving to a bigger processor, you need to change those two lines or use
some conditional compilation tricks.

--
Bartc


 
Reply With Quote
 
Tomás Ó hÉilidhe
Guest
Posts: n/a
 
      05-05-2008

Thanks for the reply.


On May 5, 3:42*am, Jack Klein <(E-Mail Removed)> wrote:

> Try doing another embedded project, this time with an ARM. *ST just
> announced some ARM parts with up to 2MB of flash and 96KB of RAM.



For my next hobby project, I want to make a very simple two-port
router. When the router receives a packet, it will look up the IP
address in its routing table, and then decide what port to forward it
out on and what destination MAC address to use. That's pretty much all
it will do. Of course I'll have to make it do a few other things, like
send and receive ARP requests, but nothing too complicated.

I started throwing some code together in notepad, just to see how I'd
make it work. Now the thing is, I see no reason why I shouldn't be
able to move this code over to a PC. Here's the beginnings of it:

typedef uint_fast32_t IPv4addr;
typedef uint_fast64_t MACaddr;

typedef struct RoutingTableEntry {
IPv4addr addr;
IPv4addr mask;
IPv4addr router_addr;
uint_fast8_t port; /* Here's a great example of where I'd
normally use "unsigned int" */
} RoutingTableEntry;


typedef struct InfoForForwarding {
uint_fast8_t port;
MACaddr dst_mac;
} InfoForForwarding;

#define LEN_ROUTING_TABLE 16u
RoutingTableEntry routing_table[LEN_ROUTING_TABLE]; /* Hold 16
routes max in the table */
#define pend_routing_table (routing_table + LEN_ROUTING_TABLE)

InfoForForwarding GetInfoForForwarding(IPv4addr const dst_ip)
{
InfoForForwarding iff = { 0 };

RoutingTableEntry const *p = routing_table;

do
{
if ((dst_ip & p->mask) == p->addr)
{
iff.port = p->port;

/* Now consult ARP table to get MAC address of router */
iff.dst_mac = GetMACaddr(iff.port,p->router_addr);

return iff;
}

} while (pend_routing_table != ++p);

return iff;
}

As I hope you'll agree from looking at this code, there's nothing
microcontroller-specific or PC-specific about it. There's no reason
why the code couldn't be used to make a PC program that would
implement a "virtual router" between two network cards.

It appears that quite a few people think that PC programming and
embedded programming are quite separate from each other, but I hope my
code example above shows why there's no reason why code can't migrate
and be portable between the two. Many C programmers already are
enthusiastic about their code being portable, but I just hope they'd
consider microcontrollers too.

Slightly off-topically, I don't know if you've been following my
thread entitled "Ethernet in its most basic form". I've been asking
around to see what microcontroller I should use for making my little
two port router. I've been given many suggestions of microcontrollers
that will work with one sole ethernet port, but obviously I'll need a
microcontroller that will work with two. (Or then again I might need
two microcontrollers that will communicate with each other... ?). I
don't suppose you'd have any idea what I should use for that? I want
to work at 100 MBps full-duplex.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      05-05-2008
"Bartc" <(E-Mail Removed)> writes:
> "Tomás Ó hÉilidhe" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>>
>> I'll try to summarise this as best I can, as my last thread wasn't
>> very to-the-point:
>>
>> The C Standard says the following two things:
>>
>> * int is the natural integer type for the system.
>> * int must be at least 16-Bit.
>>
>> Now the problem here is that these two criteria conflict if the
>> natural type for the system is in fact 8-Bit, which is the case with
>> many microcontrollers today.

[...]
>
> It doesn't seem an insurmountable problem.
>
> If you want a default int size that is best for your cpu, try something
> like:
>
> typedef unsigned char uint; /* Or uint_fast8_t etc. */
> typedef signed char sint;
>
> Then use uint and sint everywhere in place of unsigned/signed int.
>
> When moving to a bigger processor, you need to change those two lines or use
> some conditional compilation tricks.


*Please* don't call them "uint" and "sint".

What the name "uint" says to me is "unsigned int, but I care more
about saving a few keystrokes than writing clear code"; likewise for
"sint". The only thing worse than typedef'ing "unsigned int" to
"uint" is typedef'ing something else to "uint". I understand that
"uint" is intended to convey "unsigned integer" rather than "unsigned
int", but that's not how it comes across.

If you want to call them, say, "small_signed" and "small_unsigned",
that's fine.

--
Keith Thompson (The_Other_Keith) <(E-Mail Removed)>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Chris Dollin
Guest
Posts: n/a
 
      05-06-2008
Tomás Ó hÉilidhe wrote:

>
> I'll try to summarise this as best I can, as my last thread wasn't
> very to-the-point:
>
> The C Standard says the following two things:
>
> * int is the natural integer type for the system.
> * int must be at least 16-Bit.
>
> Now the problem here is that these two criteria conflict if the
> natural type for the system is in fact 8-Bit, which is the case with
> many microcontrollers today.


That just means that those microcontrollers aren't a natural fit
to C, so programmers writing looks-like-C for them need to be
aware that natural-C idioms might not work as nicely.

I don't see a problem here.

--
"It was the first really clever thing the King had /Alice in Wonderland/
said that day."

Hewlett-Packard Limited registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England

 
Reply With Quote
 
Tomás Ó hÉilidhe
Guest
Posts: n/a
 
      05-06-2008
On May 6, 12:33*pm, Chris Dollin <(E-Mail Removed)> wrote:

> That just means that those microcontrollers aren't a natural fit
> to C, so programmers writing looks-like-C for them need to be
> aware that natural-C idioms might not work as nicely.



This is what I'm against. When I first started programming in C for
embedded systems, I was weary of the compiler's compliance to the
Standard. I was hesitant to rely on rules from the Standard when it
came to things like:
* Minimum size of integer types
* Behaviour of overflow
* Existance and usage of a stack

Having written a fully working program though in C for embedded
systems, and also having looked at the assembler produced to check
what it's actually doing, I've seen that my embedded compile is
extremely compliant. I defined an object as "long unsigned", and lo
and behold the assembler produced used four bytes to store it (even
though it can only do arithmetic on 8-Bit numbers).


> I don't see a problem here.



The problem comes with writing portable code. For instance, I'm
currently writing code to implement an internet protocol router. The
code show be able to run on both a microcontroller and on a PC.
However, if the code uses "int" then the code will be less efficient
on a microcontroller. And if it uses "char" then the code will be less
efficient on a PC. Usage of uint_fast8_t would produce optimal
assembler for both systems.

There's no reason why there has to be an "embedded version of C"
distinct from "Standard C".
 
Reply With Quote
 
Chris Dollin
Guest
Posts: n/a
 
      05-06-2008
Tomás Ó hÉilidhe wrote:

> On May 6, 12:33Â*pm, Chris Dollin <(E-Mail Removed)> wrote:
>
>> That just means that those microcontrollers aren't a natural fit
>> to C, so programmers writing looks-like-C for them need to be
>> aware that natural-C idioms might not work as nicely.

>
>
> This is what I'm against. When I first started programming in C for
> embedded systems, I was weary of the compiler's compliance to the
> Standard. I was hesitant to rely on rules from the Standard when it
> came to things like:
> * Minimum size of integer types
> * Behaviour of overflow
> * Existance and usage of a stack
>
> Having written a fully working program though in C for embedded
> systems, and also having looked at the assembler produced to check
> what it's actually doing, I've seen that my embedded compile is
> extremely compliant. I defined an object as "long unsigned", and lo
> and behold the assembler produced used four bytes to store it (even
> though it can only do arithmetic on 8-Bit numbers).
>
>
>> I don't see a problem here.

>
>
> The problem comes with writing portable code.


No, it doesn't. Not if the compiler conforms to the standard.

> For instance, I'm
> currently writing code to implement an internet protocol router. The
> code show be able to run on both a microcontroller and on a PC.
> However, if the code uses "int" then the code will be less efficient
> on a microcontroller.


Your problem is not with portability; it's with performance.
Different platforms can have differing performance profiles
at whim, and portable code may need tweaking for best performance
on /any/ of them. Singling out performance issues on 8-bit
micros and thinking everyone should write code so that it
(by /hypothesis/) performs equally (well, badly) on those
implementations is, I think, obsession over microefficiency.

--
"The one you're playing, I think." /The Lion Game/

Hewlett-Packard Limited Cain Road, Bracknell, registered no:
registered office: Berks RG12 1HN 690597 England

 
Reply With Quote
 
Tomás Ó hÉilidhe
Guest
Posts: n/a
 
      05-06-2008
On May 6, 1:40*pm, Chris Dollin <(E-Mail Removed)> wrote:

> Your problem is not with portability; it's with performance.



They can be one in the same thing if the performance affects the
usability of the product. If I port a web browser to a Nintendo gaming
console, is it really a succesful port if it takes seven minutes to
load a webpage? I don't think it is.


> Different platforms can have differing performance profiles
> at whim, and portable code may need tweaking for best performance
> on /any/ of them.



Yes but there are more fundamental concepts here, that is, the choice
of integer types, whether to use 1, 2, or 4 bytes to store a number.

You say that different platforms have differing performance profiles,
and you're right. What gets better performance on one system might
result in poorer performance on another. But let me draw a crude
analogy:

Let's say you have a farm, and you want to get the best performance
out of all your animals. For the sheep, you might give them a field of
nice thick grass. For the young chicks, you might keep them in a
heated enclosure. For the horses, you might give them a vast open
space to run around. But there'a more fundamental way of getting
better performance out of all your animals -- give them water.

Just as water is a common thing to all animals, integer types are
common to all computers. Before you bother doing specialised things
for each animal such as giving them more grass or more space, do the
universal thing first: water.

And for computers, this universal thing is the choice of integer
types. You can have the best optimiser in the world, but it can only
do so good if you're using sub-optimal integer types.


> on 8-bit
> micros and thinking everyone should write code so that it
> (by /hypothesis/) performs equally (well, badly) on those
> implementations is, I think, obsession over microefficiency.



Firstly, zero effort would go into making it perform equally well on
both systems. It's just a matter of getting into the habit of using
uint_fast8_t instead of unsigned int where possible.

For my current embedded project, if I were to change "uint_fast8_t"
from "unsigned char" to "unsigned int", then I bet I'd see flicker in
my display (because the microcontroller can't flash the display fast
enough so that the human eye can't see the flashing). I've already
submitted my project board to my college to be graded but I should be
getting it back tomorrow. I'll try it out changing the integer types
and see if the display flickers. If it does, then I'll have to reduce
the duration of each flash, which will result in a dimmer display.
 
Reply With Quote
 
soscpd@terra.com.br
Guest
Posts: n/a
 
      05-06-2008
On May 6, 9:06*am, Tomás Ó hÉilidhe <(E-Mail Removed)> wrote:

> They can be one in the same thing if the performance affects the
> usability of the product. If I port a web browser to a Nintendo gaming
> console, is it really a succesful port if it takes seven minutes to
> load a webpage? I don't think it is.


Did it load? Yes? Then, it is. Don't think a nintendo (hey... some
nintendo can work very fine here... hardware was designed to work
as a http daemon (maybe that is not the product!). Performance isn't
100% hardware and, isn't too, 100% code. Run a vanilla 2.4 kernel in a
dual xeon with 1Tb memory, and run the same in a 286 with 1Mb RAM. Do
you really expect code tuning, best practices or hacks to make both
run, at least close to each other?

Did you pick the wrong language or the wrong hardware (haven't you
picked C? haven't you picked the 8 bit platform? Why mix them if you
think that will not work?)? That is the question I think you must
answer before post C standards or limits as the source of your
problems. The right tools Tomás. The right tools.


Regards
Rafael
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
communication between matlab and microcontroller (problem with the C code) abd.hed C Programming 0 04-12-2012 11:45 AM
Review: Logitech Harmony 680 IR Remote Silverstrand Front Page News 0 06-24-2006 02:59 PM
Living with Harmony Joel Rubin Computer Support 1 06-17-2005 10:57 PM
CANON Digital Rebel/300D & Harmony remote JC - Toronto Digital Photography 0 11-13-2004 05:49 AM
Ant-contrib-0.3.jar sample and code does not work in harmony Brian C++ 1 07-29-2003 05:03 AM



Advertisments