Hiring Advice

You should avoid this in the first place.

C programmers are taught to code in:

struct {int a,b} *p, x; p =3D &x; p->a =3D p->b;

regardless of architecture.

Reply to
linnix
Loading thread data ...

We should avoid simple static variables ? Why ?

Reply to
Arlet Ottens

is

as

s
)

I didn't say that. You should access static variables more efficiently.

typedef struct {int a, b} T; T *p =3D &x; do_this(p); or do_that(&x);

Reply to
linnix

A simple 'a = b' is easier to read than

T *p = &x; x->a = x->b;

And if 'a' and 'b' don't belong in the same struct, it's even less readable.

Also, on some architectures, messing with pointers may be less efficient than absolute accesses.

Reply to
Arlet Ottens

st

s

g is

l as

ces

a

rs)

Not for properly educated C programmers. You bring up a good point of lousy educational system.

x->a =3D y->b is just as clear.

The point of pointers is to write efficient codes independent of arch.

Reply to
linnix

Actually, T *p, *q, a, b; and p->a = q->b;

I agree that this is not the best notation in C, but they went out of symbols. I would have use another single character symbol for "->" or p.a as pointer access as well. That would confuse the hell out of beginners, however.

Reply to
linnix

I sympathize with the compiler-writers though. Whether two globals wind up being adjacent can depend on a deal made later on with the linker. It certainly helps simplicity to put adjacent declarations into adjacent addresses -- I'm trying to think of circumstances that might mess up that principle.

Mel.

Reply to
Mel

How often do you know "first step" (my quote) that this is in a small enough section of the code? What's "small"? I target my debugging efforts to give me the biggest bang for the least amount of effort/expense. It's *my* time that's at stake, not my boss's *cash*! :>

Assumptions *literally* are the root of all bugs. "Assuming" some third party code is correct; "assuming" the denominator won't be zero, etc.

There's that "a" word! :>

The number of "published errors" I've come across in my career is embarassing (to those publishers!). Many from "experts" (I've emails from Stroudstrup regarding errors in one of his books; errors in medical texts "edited" by folks at Mayo, etc.).

There's that "a" word, again! :> If my expectations differ from what I am *seeing* (reading, told, etc.), then I make a very deliberate effort to back off and rethink things. "*What* am I failing to recognize in this situation?" This is my way of "catching" oversights on my part.

If that reexamination leaves me *still* with the same disconnect, then I have to drag someone else into the picture to arbitrate between our two differing views of reality. This is almost always unfair to the "conflicting party" as they don't have an advocate in this discussion -- unless, of course, the "third party" dragged in points out the error in *my* assessment.

I then proceed with this "corrected" view -- and slap a post-it note on the document pointing out the problem so I know why I "defied" this "expert".

I don't use any "foreign" code to talk to my hardware. I write wrapper functions for all device accesses, startup code, etc. The author of any such "foreign" code *can't* know the assumptions that are applicable in my environment. So, they write for some *other* set of assumptions -- which they don't usually bother to document (did the code you used have a disclaimer telling you which compiler to use, etc.?).

E.g., I like having a handle called _RESET that I can "call" that is *guaranteed* to bring the system to the same state that a "hardware reset" would. Regardless of how things might be configured when it is invoked (this often involves some creative thinking if, for example, memory or I/O might have been remapped to someplace THAT YOU CAN'T ASCERTAIN easily).

So, my startup code is very verbose -- listing all of the default settings for each register/port/etc. *explicitly*. By contrast, a vendor's startup code often assumes all of those are "at their defaults -- because the processor is coming out of RESET. I, in turn, can force the equivalent of a hardware reset wile preserving whatever I consider important, "contractually".

This has the pleasant side effect of giving me a detailed exposure to the intricacies of the hardware before I am

*forced* to suffer that exposure! :>

Sorry, I didn't think we were preparing a list of things that would be *good* to know to do embedded work. If that was the case, we could make a very long list of skills that are justifiable in almost any situation!

Should the "developer" be competent with analog circuit design so he/she can determine if the power supply is falling out of regulation when the code is "doing some particular thing"?

Should the developer be competent in PCB layout to be able to decide if some high speed signal is "ringing" and double-triggering some external latch? Or, if a ground bounce is causing an input to latch-up?

Should he/she be competent enough to, at least, *suspect* these things?

What about writing skills? Surely code that is poorly documented is of dubious value... wouldn't you want to insist that the individual had good grammatical skills?

Etc. ;-)

The OP's problem was that *his* set of requirements was proving too difficult to satisfy. So, he has two choices: wait for the population of potential candidates to improve (maybe next year's graduating class will present more opportunities?) *or*, change the requirements.

Knowledge of hardware and knowledge of assembly language programming are two that I would quickly remove to widen one's chances of finding someone who will fit this

*revised* set of requirements. If that revised set is unacceptable to the job at hand (assuming the job at hand can't be modified to accommodate), then this option goes away. Change some *other* requirement (maybe turn to Ruby-on-Rails for your next embedded project! :>)

Sure! And when the power supply glitches and resets the processor (or some piece of external hardware), you need to dig deeper to understand why *that* is happening (*if* you even have the knowledge to suspect it!)

I don't trust anything that I haven't written and tested, myself. And, as I said, still subject it to the "did I miss the obvious" test by passing it in front of others (but only folks that I know are *good* at this sort of thing).

I've been fortunate that I can usually select and design the hardware on which my code executes. It eliminates the fingerpointing that would otherwise result when "something" didn't work. No one to blame but myself! In the cases where I've had to *only* "write the code" or *only* "design the hardware", I've too often had to

*prove* my part of the project was working properly BY FINDING THE OTHER PARTY'S PROBLEM FOR THEM ("See? This is why the motor is stalling... you're accelerating it at too high a rate for this particular load...")

As far as the "professional embedded people" in your case... they're goal is to sell parts. They often don't have the same level of familiarity that *you* do with a *particular* part! And, they almost always have "moved on" to some other project... the *new* MCU-du-jour. Many "application engineers" have more pressure put on them to "socialize with customers" than to "become prolific in their knowledge of the devices". :< (you can often "buy" an ally, cheaply, by giving/showing them something technical that they can pass on)

Reply to
D Yuniskis

Nah, sometimes a bug is just a typo. [Unless you want to describe that as "assuming" my finger didn't hit the wrong key.]

--
Grant Edwards               grant.b.edwards        Yow! Uh-oh!!  I forgot
                                  at               to submit to COMPULSORY
 Click to see the full signature
Reply to
Grant Edwards

I'd add to your post here by saying that you need a good understanding of the processor architecture if you are going to write good, efficient code for it. That really means you need to be able to read the assembly, at least roughly. As a skill this is becoming a bit less important as processors get bigger, but for smaller micros it is essential. If you are trying to write small and fast code (which translates to cheap device, small footprint, low power, low EMC - all vital for many embedded products), you need to know whether your processor can do divisions without library calls, or whether you should prefer uint8_t to int, or whether you can use single-precision or double-precision floating point. When code is bigger or slower than you expect, the generated assembly is a good place to look for an explanation.

Your comment about the use of volatile is also relevant here. Sometimes the use of "volatile" can be very subtle, and it is hard to realise where your problems lie. This can happen particularly when someone has written code for a poorer compiler, and then has trouble transferring that code to a better compiler. Looking at the assembly will often give you a clue as to what you are doing wrong.

I also find assembly-level debugging can be a help - when you are stepping through code, sometimes line-stepping is just too rough.

And of course there are always low-level parts of the code that need an understanding of assembly. Interrupt code, startup code, etc., can benefit greatly from an understanding of the cpu (even if it can mostly be written in C).

Reply to
David Brown

No, typos are typos. Htis is a typo. These are a bug! :>

[actually, on a more serious note, if you think about it, assumptions really *are* the underlying problem behind bugs. You *assume* the user won't do _________; or this value will never exceed _________; etc. Whether or not you explicitly *state* those assumptions or even are aware of them, yourself!

If you believe this -- I do -- then a great way to cut down on the number and severity of bugs in your design (hardware or software) is to try to explicitly identify those assumptions before or after the fact. Then, see how realistic they actually are!

Likewise, a great way to find bugs in other people's designs is to think of things that would be "unexpected" -- and try them! Amazing how often a colleague will ask me to test drive something he's written and I'll cause a crash in short order:

"Ack!! What did you *do*??" "This..." "Why would you do *that*? That's ridiculous!" "Then why did you LET ME do it?" "Aw, crap! ..."]

Reply to
D Yuniskis

I agree entirely with you regarding the use of assembly for learning and understanding such issues.

What you won't find in the assembly code, however, is the "-fsection-anchors" flag, which can do exactly what you want here (assuming it is supported for the M3, which I haven't checked). From the gcc manual:

-fsection-anchors Try to reduce the number of symbolic address calculations by using shared ?anchor? symbols to address nearby objects. This transformation can help to reduce the number of GOT entries and GOT accesses on some targets. For example, the implementation of the following function foo:

static int a, b, c; int foo (void) { return a + b + c; }

would usually calculate the addresses of all three variables, but if you compile it with -fsection-anchors, it will access the variables from a common anchor point instead. The effect is similar to the following pseudocode (which isn't valid C):

int foo (void) { register int *xr = &x; return xr[&a - &x] + xr[&b - &x] + xr[&c - &x]; }

Not all targets support this option.

Reply to
David Brown

Engage a contractor who lives someplace cheaper than SF. Like, say -- Oregon City :-).

--
Tim Wescott
Wescott Design Services
 Click to see the full signature
Reply to
Tim Wescott

Or better yet, Damascus. ;) As you should very well know!

Jon

Reply to
Jon Kirwan

.
s
e
t

LA is closer and half the cost.

We can get you good C programmers here.

Or send your students here for training.

I run the best emb/C class here.

Reply to
linnix

There is a website just for you:

Just because it is /possible/ to understand a piece of code, that does not make it "just as clear".

The point of using good compilers is to write clear C code, and let the /compiler/ figure out what is best implementation on a particular architecture.

Premature optimisation is the route of all evil. And manually putting all your static data within a structure and accessing it through a pointer is definitely such an "optimisation". It is /very/ far from being independent of the architecture, and /very/ far from being clear, readable and maintainable code.

Sometimes optimisations like this are a necessary evil - but don't kid yourself that they are a good way to write code.

Reply to
David Brown

I've done that... put /all/ the global and static data in a single giant struct, and have the (ARM) compiler allocate a global register to hold the pointer to this struct. As a result, all variable accesses could be done very efficiently, with indirect pointer+offset mode.

It was ugly, but it cut code size down by a huge amount. Without this method, the program wouldn't have fit in the RAM. Fortunately, the whole firmware was small enough that it didn't become too hard to understand/maintain.

Reply to
Arlet Ottens

Yes, sometimes these sorts of things are the best solution. But they are ugly, and are best avoided if practical.

If you have the opportunity, try the "-fsection-anchors" flag and see if it helps.

Reply to
David Brown

Hello,

I understand what you are saying. I was addressing more your comment about it been the last thing you do. For me, it's generally about the second or third step. OTOH, I like to look at generated code anyway as a matter of routine as I like seeing how the various higher level language constructs have been turned into assembly code.

That's very true and all the code I write, both professional and hobbyist, is filled with internal consistancy checks just to make sure I have not missed anything.

However, while I am a professional programmer in my day job, my embedded work is purely as a hobbyist. Therefore up until now, when I see embedded vendor supplied code, I've just assumed that the vendor is documenting a recommended best practice. Hence, I've trusted that the code serves as viable, working, code and I've assumed that if I see something which hasn't been done the way I would expect then it's been a lack of understanding on my part.

I like to write my own code, but this was such a tiny and trivial routine with a open license that I really didn't see the point of doing anything other than just using it.

I've done far more complicated embedded support routines myself over the years even when public implementations were available because that's what I like to do. I use one silly little routine because it addresses something I didn't think of and I get caught. I will stick with writing it myself in the future when possible.

The software library was packaged for the gcc toolchain BTW. Unlike some other vendors Atmel have a policy of supplying code which builds with the GNU toolchain which is something I have liked about them.

Competent enough to fix a design with such issues: No.

Competent enough to understand that such a thing can happen and hence consider it while debugging some weird problem: Yes.

BTW, although I've been doing embedded hobbyist work for years now, I have not really looked at embedded vendor code until now (I just worked from the datasheets and manuals) and when I started looking at ARM vendor code recently, I just assumed I could trust the code and treat it as something to learn from.

Not anymore. :-)

(Although, to be fair, the vendor code does still serve to highlight things which are not as clear as they could be in the datasheets).

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world
Reply to
Simon Clubley

Ah, OK.

I tend to trust my tools. But, I also try not to "press" them too hard (I *really* dislike having to leave a comment in the code to the effect of: "/* XXX FIXME workaround for bug in v1.2.3 compiler */" -- because it eventually screams "Why haven't you fixed this, yet? The compiler is now at v2.3.4!")

There are some *old* texts that do this with an eye towards illustrating the consequences of various language constructs on the generated code. E.g., _Efficient C_ by Plum et al. While the processors used are *antiques*, it is still a good exposure to what is really going on "under the hood" in a "generic" processor.

The problem I find with reviewing generated code is the compiler (even with optimizations "off") often transforms your original implementation into something that isn't immediately recognizable. I.e., each time I look at such code, I spend a fair bit of time trying to figure out *why* it's doing what it is doing (it's never as straightforward as "load register,variable_1; store variable_2,register", etc.). Some of the simple tricks that it plays (like using funky addressing modes in lieu of arithmetic operations) end up being a distraction to me...

Good! But there are still assumptions. :> I write a prologue of debug assertions for each function effectively enforcing and declaring the contractual requirements of the function -- to whatever extent is practical. Yet, I am always amazed at the number of bizzaro things that I forget (e.g., what if this gets invoked with a pointer to "last_memory_address-3").

Cool!

Ah, gwasshoppa... follow not the butterfly blindly as it often flies over cliff!

That's sort of like believing something just because you read it in a *book* (wow, this guy's an AUTHOR so it must be true!) :>

I come from a hardware background so I always start with a device's datasheet and work "up" when interfacing to the iron. I read what code snippets I may have access to -- but I do so in much the same way that I read the description of the registers, etc. I treat it as a supplement to the technical documentation giving me an *example* of how the registers are set, etc. As an additional explanation or clarification -- the two pieces of information *should* be in agreement, right?

But, often you find that the code has made assumptions about the state of the hardware at the time it is run. I.e., "assume the processor just came out of reset; the default memory map is therefore in effect *so* all we have to do is make the changes that adjust it to our needs..." This isn;t going to work for me (see my _RESET comment) but what I come up with *should* be similar -- possibly a superset of this, in theory.

So, if the values that I use or the order in which I initialize registers differs, I need to have an explanation for that deviation -- what am I doing that is *different* from their example? Have *I* forgot something? Or, have they?

E.g., if the memory map can be altered to (effectively) "move" the addresses at which various control registers are located, then how can I *know* where they are NOW (if I am *not* assuming that the processor just got out of RESET)? If I can't know this, how can I be sure that I *really* am accessing them in this code snippet (e.g., perhaps write all the same values to every possible location at which they could reside?)

Or, said another way, if I violate some assumption that the vendor has made (and may or may not have explicitly stated!), will the code he has provided *work*, always?

More times than not, you're probably safe. Except when you aren't! :> And, if you trusted *it*, then you are more likely to go looking for The Problem in some of *your* code thinking yourself to be the source of the problem (this is one reason why another pair of eyes can come in handy as they can't tell what's *your* code and what's someone else's so they scrutinize everything equally).

The same sort of cynicism can be a win when relying on libraries, etc. from "others". At the very least, look at the API for each function and if you can think of ANY "What if..." questions for which the API doesn't explicitly tell you how the function will behave in those particular circumstances, suspect the author has "forgotten something" (e.g., what happens if I pass a NULL pointer, here? how does this routine indicate that it could NOT perform its duties? etc.)

As I said, *read* what they have written and refer to the other documentation to understand what it is trying to do. Then, think about what *else* might need to be done. Or, why do I have to do it *that* way?

OK. Often code samples don't make these things explicit. I had a compiler vendor publish some startup code that was horribly broken. When he grumbled about my complaint, I said, "It's *your* code and *your* compiler! Who else should I be calling? Why publish something if it is wrong?"

I have found that more than a cursory knowledge of hardware tends to be The Exception rather than The Rule. Software curricula seem not to spend much time on this sort of thing. Sort of like teaching for the desktop instead of for embedded :<

I, myself, leave much of the fancier analog work to friends and colleagues. An example of the "Kelly Bundy" effect ("can only hold so many facts in your head") -- and there are far more interesting things that I'd like to know than, e.g., how to process microvolt signals accurately...

It *is* something to learn from! It *should* act as a concrete example of the material presented in the datasheet. And, often it will make subtle dependencies clearer (i.e., the *actual* relationship of the settings in register A vs. register B or the timing between their updates) than can be expressed verbosely in a textual description.

If you review it in the way I described -- with an eye towards what it *isn't* doing -- then you can often get insights into other capabilities that the code *isn't* exploiting. This can give you "ideas" for other things you might want to take advantage of in your system/design ("Gee, why isn't the code using UART #2?")

Yes! It really is hard to explain -- *without* the benefit of a code sample -- how things interact. E.g., I'm thinking of a document I wrote years ago describing how to apply the "MMU" in the Z180 devices (which was implemented in a bizarre way for the time; i.e., *not* as obvious as something like a '610). With illustrations and code snippets, the operation is "obvious"; with *just* textual descriptions, it's much harder to follow (i.e., coming up with the *right* values for the

3 registers involved "the first time" is less assured).

The point is, use the code as a supplement to the text description/definition. And, don't give it any *more* credibility than you would, that (i.e., expect errors and omissions there, as well)

Reply to
D Yuniskis

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.