And -- pow! My memory was gone.

I'm shaking the box, trying to get the software to settle enough to fit into a 64kB memory space. This is made difficult by the fact that it's a human-interface rich environment with a bit of extra fat contributed by the fact that I'm writing in C++.

This is for an application that worked just peachy-keen on a captive vendor's tool set, but which is too big using gnu tools. It's to be expected, I suppose.

As soon as I saw all of the I/O junk in the map file I realized that maybe I shouldn't be using sprintf (even if it _did_ fit before). So I took it out, and rather than contort my code, I'm writing a replacement for just the formats that I'm using (yes, I know, bomb in the code).

As I usually do, I started easy -- which, in my case, means locating the decimal point with log10, and moving it around using pow(10.0, n).

'pow' is over 1kB!! And it pulls in something called __pow_754, which is HUGE -- like, 5kB or something! Eeek! I mean -- the code worked, but without much room in the end.

So I'm un-powing my sprintf, shaking my head at the vicissitudes of free software, and (since it's a hobby project) thinking about processors with more memory space.

--

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com

Do you need to implement control loops in software?
"Applied Control Theory for Embedded Systems" was written for you.
See details at http://www.wescottdesign.com/actfes/actfes.html
Reply to
Tim Wescott
Loading thread data ...

Use the Forth, Tim, use the Forth! (only 80% kidding.)

-- Roberto Waltman

[ Please reply to the group, return address is invalid ]
Reply to
Roberto Waltman

And I thought this thread was going to be about Alzheimer's or CRS disease or something.

Eric Jacobsen

formatting link
formatting link

Reply to
Eric Jacobsen

C++ doesn't necessarily add fat - it depends on how you use it. If you've got exceptions and RTTI enabled, expect code to be bigger and slower. If you use the STL, expect code to be a /lot/ bigger. If you use a lot of virtual stuff, it may be a lot bigger (depending on the processor) - but it may be smaller than alternative C-style solutions to the same issues (such as with explicit function pointers).

But generally speaking, beware libraries - whether C or C++ - they are often the cause of extra code space (and wasted run time).

You /expect/ that the gnu tools should make your code much bigger? There are some targets for which there are proprietary tools that are much better than open source alternatives. But on most major gcc targets, the compiler is on a par with the commercial tools in terms of code size and space. Sure, there will be some variation - but not as large as you are implying here.

So what is the target?

And what are the libraries? From your post, it looks like the libraries are your main issue - and here there can be a lot bigger differences.

And what about tool versions? Where did you get them? There a lot of websites offering downloads of embedded gcc toolchains that are many years out of date.

And how are you using the tools? Are you using appropriate compiler flags? (The manual has lots of information there, but you can also ask here on c.a.e. or in mailing lists.) For example, for bigger targets, the floating point code will often be IEEE standard - because that's the C standard behaviour. But it means much bigger and slower code than if you ignore the possibility of NaNs and allow slightly loser rules about rounding, etc. You have to use the "-ffast-math" switch to get faster but non-IEEE behaviour - many commercial compilers work like that by default.

Are you trying to display floating point data with decimals? There are /much/ more efficient ways to do that than using log10! Let us know your real problem, rather than the issues you are having with your solution, and you can get better help.

This is a library issue. What you are seeing is a large general-purpose routine, rather than smaller and more specialised functions. By the name, it is probably the IEEE-754 version of the code and will work correctly even when given awkward data (i.e., it will generate the specified NaNs, etc.). It is probably also a double precision version, which might not be what you need. The can probably be mitigated to some extent by using -ffast-math, and by using float instead of double (if appropriate). But in the end, it might just be a design choice of the library - larger but more general functions are more efficient for larger programs but are less efficient for smaller code.

A vast amount of embedded development is done using free software, but it is not always the best choice. /Exactly/ the same applies to commercial tools. You have to pick appropriate tools for the task in hand, and know how to use them effectively.

And you have to have tools that suit you, and the way you work. For some people, they like the way particular commercial tools work, and can't get their heads round gcc - they see it as some sort of refugee from the DOS days. Other people find most commercial tools awkward and inconvenient compared to the streamlined ease and consistency of gcc - they see commercial IDEs as too much lipstick on a pig. It's a matter of viewpoint, habit, experience and personal preference.

But no matter what tools you are using, you'll get on a lot better if you ask for help with your problems, and give specifics, rather than whining that a toolchain you got for free doesn't work in exactly the same way as a toolchain that costs a lot of money.

mvh.,

David

Reply to
David Brown

One I used, I forget whether it was for AVR or ARM, used pow to do bit shifts. And somebody's delay routine brought in the floating-point package so they could take their parameter in seconds. Faced with that, one writes one's own, and one's problems go away.

Mel.

Reply to
Mel

This sort of behavior is to be expected. pow() is a double-precision floating-point arbitrary power function. Such a feat doesn't come easy on an integer-only RISC processor (which I'm assuming you have). If you have plenty of free time to blow, try writing a better version (i.e. one that is more compact without destroying its performance). Then, you can contribute it back to the community!

In all seriousness though, this is a common issue when writing embedded code. This is the reason why many toolset vendors will offer two stdio implementations: one that supports floating-point types and one that does not. The code required to handle all of the printf() features with floating-point types can be pretty large (I've seen printf() take > 20 KB of code space on an embedded processor), and many applications can get by without it. Are you actually using floats/ doubles in your program?

Jason

Reply to
Jason

Is one of the libraries you are using a vendor support library for the I/O? I have seen cases of libraries which are poorly structured project modules that bring in all modules and functions assuming you have the biggest device in the range.

In one case setting a GPIO pin type on the smaller footprint devices loaded GPIO configuration routines for Ethernet, Can, USB, I2S and other things not present on that device.

The support response was use "-g sections" linker option to remove uncalled functions. A using a linker trick to fudge the bad software structure.

If you must support floating point and display floating point for any arbitrary range you will have issues with any form of [s}printf.

My personal suggestion is consider if this range is ALWAYS limited or can be determined to have a floor and ceiling limit before doing the output conversion. This can greatly reduce the complexity of floating point representation.

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
 Timing Diagram Font
  GNU H8 - compiler & Renesas H8/H8S/H8 Tiny
 For those web sites you hate
Reply to
Paul

One of the reasons I never use standard c lib functions much is the amount of crud they tend to pull in, and much of it seems to use signed types where unsigned would be more appropriate. Memories of printf() that pulls in over 100k, just to print a formatted string. Fine if it's running on a desktop machine, but useless for most embedded work. Same applies to the lib. Organising the data appropriately so you can do scaled integer math does help, or designing your own simplified format and limited range floating point functions to suit the application, where that needs to be externalised.

It's not too difficult to roll your own as needed and build libraries over a few projects, with the added advantage that you always have full visibility of all the code in the system...

Regards,

Chris

Reply to
ChrisQ

^^^ Sorry, should say math lib...

Reply to
ChrisQ

That sounds /very/ strange. Bit shifts are integer operations, while pow is a floating point function - they should not be mixed unless your source code says they must be mixed. I'm not going to claim that gcc for the AVR and the ARM are bug-free, or that they always generates optimal code. But this sounds so weird that I'd want to see details before accepting it.

Yes, there is lots of poor or inefficient code out there - I've seen floating point code used in delay routines like that. Done properly, you arrange for the floating point calculations to be done for accuracy and convenience, but evaluated at compile-time rather than run-time. However, that requires that both the programmer and the compiler do the right thing...

Reply to
David Brown

Just looked at my e^X, 2^x etc. FPU code which is part of DPS. For power (PPC), written in VPA, it is $1a0 (416 dec) bytes - double precision FP. Uses the FPU on the chip though (which has fmul, fadd, fsub, fdiv).

On a CPU32 - done in 68k assembly - the code size is $232 (562 dec) bytes (no FPU to help, just the integer unit).

I wonder if one is not using the HLL libraries and has to write his own ones, what good is the HLL for at all then... (other than staying with the trend, that is).

Dimiter

------------------------------------------------------ Dimiter Popoff Transgalactic Instruments

formatting link

------------------------------------------------------

formatting link

Reply to
Didi

It was there, in a couple of functions dedicated to a built-in device. I could hunt it down again, I suppose. My impression was that one particular coder must have thought it was cool.

Mel.

Reply to
Mel

Absolutely, this is exactly what I do. -nostartfiles -nostdlib then write whats missing yourself, For my embedded work this turns out to be a few trivial things like memset, strlen etc.

A typical example is a colour VGA touchscreen UI with proportional fonts and "application" program, runs in ~32-50k of ARM/thumb code. (Depending on fonts and whether ARM or thumb mode). With gcc tools.

Tim: Re sprintf. One useful thing was a public domain integer-only stripped down printf. I modified it to add extra formatting codes for fixed-point numbers. Let me know if you want a copy. I have d = tenths, c=hundredths, m=thousandths. So I get efficient handling of numbers with decimal points too. E.g. temperature stored in hundredths of a degree C might be:

gdiPrintf(lcd, "Temperature %5.2c degrees C\n", status.temperature);

With an output like

Temperature 37.12 degrees C

Actually my library accepts UTF8 and so does GCC in source code, So that could be:

gdiPrintf(lcd, "Temperature %5.2c °C\n", status.temperature);

John

--

John Devereux
Reply to
John Devereux

For many reasons - primarily to have full visibility and confidence in the code you include in projects. Even where sources are available to lib code, it's often to no particular coding standard, can be badly laid out and often has a lack of commentary. Do you really want to include this in client projects without verification of all the corner cases ?. Other reasons include code efficiency and greater granularity in terms of what gets dragged in at link time.

Looking at your web site, it seems like you write most of your own code anyway. Who would want to write all project code in (probably) non portable assembler now...

Regards,

Chris

Reply to
ChrisQ

When doing embedded stuff, I almost never use *printf routines from libc. There are some very nicely done, small-footprint replacements floating around out there that can be configured to support only the features you need.

--
Grant Edwards               grant.b.edwards        Yow! When this load is
                                  at               DONE I think I'll wash it
                              gmail.com            AGAIN ...
Reply to
Grant Edwards

Make that "most" "all" (all tools included) and you'll still be correct :-).

But the assembly language is portable allright, the code which had been written for CPU32 (68k assembly) got beautifully ported to power (PPC) some 10 years ago. Porting this down (to a smaller core, say, like ARM) will be less beautiful but still doable. Yet I pray I do not have to... Hopefully all that QorIQ vaporware materializes in the not so distant future, that is :D .

Anyway, I do not claim what I do is typically done by many other people, I suppose this must be said.

Dimiter

------------------------------------------------------ Dimiter Popoff Transgalactic Instruments

formatting link

------------------------------------------------------

formatting link

Reply to
Didi

Are you talking about some sort of application code or example code? I thought you were talking about the compiler itself generating pow() calls to implement something like (1

Reply to
David Brown

For embedded programming, you use /some/ HLL libraries - but not others. For example, it is common to use the libm libraries directly if you need them - but you do so only if you need it, and you do so appropriately. So if you are using an 8-bit AVR, it is very rare that you would use floats rather than integers - and even rarer that you would use doubles rather than floats. But if you /do/ need to use them, then you do so using the libraries.

Other libraries are less useful in embedded systems - there is little in stdio.h that makes sense in most cases, and the *printf family is always very expensive in size and time. Many libraries for embedded toolchains come with a variety of *printf functions to give a better compromise between functionality and size.

In the end, however, it comes down to a balance between the size and speed of the embedded system, and the cost and speed of the development. Sometimes it makes sense to use inefficient libraries that are easily available, rather than finding or writing something better. But you should only do so when you know what you are doing - this thread started with someone who appears to have thrown code at the toolchain without understanding the compiler or the library.

Reply to
David Brown

I meant to mean library code.

Mel.

Reply to
Mel

I remember that from end-1980's MS BASIC which didn't have a shift operator. This was also the only compiler I've seen which produces the result 3 for INT(SQR(4**2)).

Stefan

Reply to
Stefan Reuther

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.