Monday, May 2, 2011

Offering Advice

I spend an inordinate amount of my free time on a site called Chiphacker. It's a Stack Overflow for electronics, embedded software and general EE nerdiness. Sometimes you get wonderful questions like this one:

Hey guys, I'm trying to properly bias the LM34476U chip (datasheet here) for operation in the saturated MODE. However, I want to be able to dynamically change the bias to on mode when my signal source changes. I've sketched out a design using the MAX4640AB 4:1 multiplexer that will switch out bias resistors but I'm getting a split second where both resistors are conducting and the feedback causes ringing in my output that I can't get rid of. Can anyone recommend methods to reduce the bandwidth of the LM3447 to eliminate the ringing? I've checked the app notes but the method they suggest there doesn't apply directly to my circuit topology and I don't know where to connect the feedback capacitor with my setup.


Wow, just wow. It's questions like that that I open up my circuits text book for.
Literally - check out this question here. I was even nice!

But sometimes there are questions asked that... spawn blog posts. That spawn stand up comedy routines ('Hey guys did you hear about the guy that asked a stupid question on the internet?'). Questions asked by people with obviously little knowledge of engineering, analog design, programming, digital logic, etc. Out of respect for the guilty I will not post one of the questions here but instead show you a creation of my own twisted mind that makes me approximately as angry as the real thing:
Hey guys, I've just had a great idea that I'd like to follow up on but I don't know where to start so I was hoping you could give me some pointers.
It seems to me that a lot of disabled people have problems with picking things up, so I want to build a robot that will roll around and pick up the things that they need picked up and you can control it with voice commands.
I've got a lot of software experience with VB6 and I've been reading up on the PIC so I think I can write the code for it when I find an implementation of the .NET framework for the PIC.
What I don't know about is the motors and stuff and the voice control maybe. I need the robot to roll around with wheels and its hand has to be just like a persons hand so it can pick everything up.
It also needs to know what the words for things are and it should probably understand if you point at something too.

My cousin is disabled and he has such a hard time... I really want to help him and think this is a good idea. Do any of you guys know a website or book that can help me figure this stuff out?

Thanks guys, I know together we can work this out!


This just makes me angry. Doesn't it make you angry? The first thing that pops up in my head is that this isn't really a question. If you had to distill it it wouldn't end up as 'Is this possible?' or 'What will be involved in doing this?' but instead 'Tell me how to do this'. It's like saying 'I want to get into Heaven - tell me how to do this.' Man, you'd be in for quite a discussion let me tell you....

But what are the specific ways I hate this question: Oh, let me count them:

Hey guys, I've just had a great idea that I'd like to follow up on but I don't know where to start so I was hoping you could give me some pointers.


First off, I hate it when you use any honorifics ('Dear sirs, I am many problems with this software having! For much to help please!') or really, any form of address. Don't call me 'guys', don't pretend like you know me unless you post regularly. Yes, I do check. Secondly the phrases 'I don't know where to start' and 'give me some pointers' indicate this person has no idea how to do what he wants to do. At all. Not even close. When the last time you had a great idea didn't you at least have some clue how it might be done? You think 'I want to know when I should stop pulling my car into the garage' and then immediately assume that this is a question you shouldn't even consider - that you should go consult a professional? Even if you start thinking about it and conclude you don't have enough specific knowledge to formulate a final solution that at least leaves you with some specific questions to ask. If for some reason you decided it needed to be electronic you'll quickly reach the question 'How can I measure distance electronically?' Then you ask THAT question to the professionals. Saying 'I don't know where to start' means you didn't bother to think through it even a little or you honestly don't understand what you want.

It seems to me that a lot of disabled people have problems with picking things up, so I want to build a robot that will roll around and pick up the things that they need picked up and you can control it with voice commands.


This boggles my mind. Do I want to help disabled people? Yes. Do I understand some of the issues that may be affecting them? Yes - apparently they 'have problems with picking things up'. Could I design an apparatus that might help disabled people pick things up - via voice commands? Perhaps - but it would take years. You see, I'm a simple embedded software engineer (before this I was a controls engineer - before that an electrical engineer and before that? Farmer) and the request you just made involves at least four different fields of study (Mechanical engineering, embedded software development, computer science with a specialty in artificial intelligence, digital signal processing, analog design - all of the top of my head) and would require someone with a college education in each. I'd probably need one PhD as well - just for good measure. It's not as if I could do wonderful things to help the disabled but I just get drunk instead. This is HARD.

I've got a lot of software experience with VB6 and I've been reading up on the PIC so I think I can write the code for it when I find an implementation of the .NET framework for the PIC.


Okay... this means you don't understand any of the potential tools you might be working with. Do you guys know what the PIC is? An 8-bit microcontroller that can't find its ass with both hands. Actually, scratch that - the PIC only implements one hand in hardware and requires you to emulate the other hand in software if you want to access it. This thing is dumb as sin. It most certainly doesn't have an implementation of .NET and even if it did the first thing he'd probably try to do is make 'Hello World' using console.writeline or whatever prissy function they use because they're not man enough to call it printf. You have to work with bits when you use this thing. Software people don't even know what bits are anymore - this guy is way out of his league.


What I don't know about is the motors and stuff and the voice control maybe. I need the robot to roll around with wheels and its hand has to be just like a persons hand so it can pick everything up.
It also needs to know what the words for things are and it should probably understand if you point at something too.


Oh okay, what you'll admit you don't know about is maybe 3/4's of the entire thing? So at the very least it's only ten years of school? Do people seriously think that these matters are trivial? Many legitimate college graduates are simply lost as far as practical skills in their first job and even then a mechanical engineer (for instance) isn't a machinist - he may be able to design the mechanical parts but he can't make them. You need someone who works with his hands and hopefully still has all of his fingers - that means he's good! And I'm not even going to get into how difficult it is to 'make it understand words'. Suffice it to say the most advanced processing hardware in the world takes years to learn a language and usually doesn't learn it correctly anyhow.



My cousin is disabled and he has such a hard time... I really want to help him and think this is a good idea. Do any of you guys know a website or book that can help me figure this stuff out?

Thanks guys, I know together we can work this out!


Oh of course - a book! Or website! All he needs is a website - one that tells him EXACTLY WHAT TO DO. Every step from A to Z to make this magical device that barely exists in his mind because he hasn't thought it through very much. Yes, I wrote that webpage - it's on Geocities. I dare you to find it. Face it - even if such a thing exists someone's selling it and they're not going to tell you how to make it. They're not going to document it completely and put it on the web for you to reproduce so you can not pay them anything. People like their effort to be rewarded - and this is effort

People will try to defend this person. 'But Angry', they'll start, 'he just wants to know if it's possible!' Screw that - everything is possible. Period. It all depends how much you want to pay. And I can't tell you how much it will cost. Do you realize that real companies have people who are paid - full time, real money - to estimate how much jobs will cost? And (call me cynical) when you tell him that the price for development of this miracle is in the millions he'll say 'I don't understand why it needs to cost so much!!! You can't be for real!' You see, he has already demonstrated that he lacks the ability and knowledge necessary to judge the difficulty of the ideas he presents. Remember that as far as he's concerned he simply hasn't found the right website to tell him how to do it. After that it's easy.

'He just wants to know what it will take!'

Seriously? Remember how he can't tell whether he's asking for something reasonable or something insane? When I tell him it's something insane guess what? That's not the answer he's looking for. He has every reason to ignore me and perhaps ridicule me. I can't say for sure whether he has a rigid mindset that won't listen to reason but I am saying for certain he has no facility to judge whether something is reasonable or not. So why even ask? Why not ask 'Am I way off base here?' instead of 'Show me how to do this'.

'You should at least be nice to him'

Well... I could. It's true. I don't have to do anything - so many questions simply remain unanswered, bereft and eventually die in obscurity. It feels so fulfilling to see no answers, no comments, no nothing on a question months after it's been asked. But I have my limits. I am the Angry EE for a reason. And that reason is that some things I just can't let go. On the internet anyhow - where all I have to do is type. Otherwise? Waaaay too lazy. But I will not refrain from essentially answering his question in the only way one paragraph can. I am not on retainer for more than one paragraph - no one on stackexchange sites should be. It will be pithy, it will be a little acerbic, but it will be right. If you choose not to believe it, I will follow up with comments that make fun of you more and more.

The moral of the story is to do work for yourself. Do some, any! Then you can ask more specific questions - questions which I will be less hesitant to answer than blanket questions about topics you obviously don't understand and haven't thought about. I answer lots of questions on this site and there's plenty of good ones which means that plenty of people don't expect me to do their homework for them. I like those people. Yeah, don't expect me to do your homework. Homey don't play dat.

(Does anyone get that reference?)

Saturday, April 23, 2011

THE FUTURE

For me, this weekend I realized that I was living in the future.

I've always been bullish on the future. I read a lot of science fiction and science fiction loves the future Time travelers from our time go into the future for some reason and they see all of this cool technology: warp drives, transporters, ray guns, nanoconstructors - you name it. Science fiction writers love science but most of the time they skimp on the social aspects of the future. Do we have racism? Is there free love? Are drugs legal? Is religion abolished?

Sci-fi writers are often less eloquent on these matters. Roddenberry wasn't. He showed us a world in stark contrast to the one that was developing around him. Racism: gone. Freedom: for everyone in every way. No one is sick because we all decided that wasn't going to happen in our world. No one is hungry because not a single person on Earth could bear to see a person starve. There's no war because we're way too grown up for that. There's no money because we're all so rich we don't feel the need to measure it anymore.

But the uniforms he put his characters in were absurd.

Seriously, go-go boots? Miniskirts? Captain Kirk is pretty much wearing pajamas. I mean take a look at military uniforms in our time. They've changed only somewhat in the past 300 years. They're full of creases, corners, polish, buckles and complication. Uniform maintenance is the primary method of making grown men cry in the military. I don't foresee a general relaxing of military culture to the point that you can chill in pajamas on the bridge of the flagship within Star Trek's timeline.

Specific predictions about the future can get tricky. Very few people predicted even really obvious stuff like computers and cell phones. And clothes are worse. Fashion is unrecognizable year to year. The best rule I've figured out is the 20-year rule: whatever you're wearing now will be stylish again in 20 years (assuming it is currently stylish). It works well enough in a general sense, but I'm also quickly losing sense of what is fashionable right now anyhow.

Which is why I was blindsided this weekend. We went to the beach (note to everyone in the frozen north: it is simply gorgeous out here and the water is plenty warm). I saw a bunch of surfers - many of them much much younger than I. And they were ripping up the waves and...

Wearing war paint.

Yeah, streaks of red, blue and yellow all over their faces, arms, chests, you name it. They looked like they belonged in Braveheart. I don't normally attempt to fathom the culture of kids these days but this one left me curious. The only explanation I could think of turned out to be the right one: it's sunblock.

And of course it's sunblock. Let's do the math: you need to wear if you're going to be out in this sun and it pays to be generous with it. When I was bailing hay in summers on the farm I used pure zinc oxide - creamy, greasy and great at picking up dust and dirt. But you had to use it - normal stuff wouldn't get the job done and even with the zinc oxide you had to slather so much on that it was opaque. I looked like one of those nerds you see in movies who never goes outside - pure white nose peeping out from behind a wide-brimmed hat and long sleeves in the middle of summer.

Oh if only I could have looked cool AND gotten sun protection....

Oh, and now in THE FUTURE you can. You can cover yourself in sunblock and look like a warrior instead of a nerd. This is the sort of great idea that I never had or even considered, but seems so foreign when you suggest it:

"In the future," the traveler started, "the kids wear war paint!" The pitch of his voice raised on the last half of his sentence as if he had made a particularly incisive statement. "They go to their sports games all painted up with their team colors, fancy designs on their faces to intimidate the other team - who of course have their own paint. Some wear it for every day pursuits too - go to the store and you might see some of them there."


How odd! How interesting! How different! THE FUTURE! Of course, in this case the future isn't foreign or odd. If you start from certain suppositions (you need sun block, sometimes you need it really thick, but it looks dumb) then it's not a far leap to the conclusion (non-dumb-looking sun block should be invented).

Yes, THE FUTURE has arrived for me and it's a good thing: someone had an idea that seemed foreign and senseless to me but is in actuality insanely great (and it's making the world a better place). Kids are wearing more sunblock, protecting their skin and stopping cancer - but they don't look like idiots. Yes, in THE FUTURE the right thing to do is also the cool thing. I want more future please.

Wednesday, March 16, 2011

Overflow Overflow Overflow

For the second time in the past few weeks it turns out I'm my own worst enemy. I work for days to track down a bug in my latest embedded application only to find out that (surprise) the jerk who put the bug there is none other than me.

Some background: the ARM Cortex M3 has this nice interrupt vector called FAULT. When something bad happens (divide by zero, memory protection error, etc) the program packs up the current processor state and vectors directly to the fault interrupt handler. This is a very good thing - you can put a fault handler in that interrupt, resolve the problem and continue on your merry way. Perhaps. The thing about faults is that they tend to be somewhat hard to recover from. For instance, let's look at my two most recent faults I've had to deal with.

The first fault was a stack overflow. I know that some of you have probably heard of a stack, and some of you have heard of a stack overflow but if you're anything like me you had no idea what this actually meant and simply assumed it would never be a problem for you. Well, it most likely will be for you at some point. It's like the fraternity hazing of the embedded world: you can't consider yourself an embedded programmer until you've had your first stack overflow. Let's have some background: A stack is a Last-in-First-Out memory structure that is essentially scratch space for your program. Whenever you call a function the return address is pushed on the stack as well as function arguments. Inside the function the arguments are popped off and used, and when the function is done the return address is popped off and jumped to. You can use the stack directly but it's not typical to do so if you're programming in a high-level language like C - just let the compiler do the dirty work. Now the stack is stored in memory just like everything else (you'll see in a second why this is at the root of the problem) and it has a specific length. So it may start at memory address 0x20001E0 and if it's 16 bytes long then something else starts at location 0x20001F0. So you've only got 16 bytes to play with for all of your function arguments and return addresses and such. In a VERY simple system maybe this would be enough but it's very doubtful. For instance, if you call a function within a function you have to push a lot more stuff onto the stack. If you call a function within that it gets worse.

Now here's the tricky part - even though the stack is special and unique and essential to calling functions and making your program work correctly your processor doesn't care. It can't really tell what memory is stack and what isn't. So if your stack is 16 bytes long and you push 17 bytes on to it your processor will happily obliterate whatever data was residing just after your stack and replace it with what you just pushed onto the stack. This is stack overflow.

What happened to me the first time is that I didn't allocate enough stack space and it wiped out some important information residing just beyond the stack. Now if what is just beyond the stack is data, then overwriting it is bad, but not fatal for the program. After all, data is data. If I'm adding two numbers and one of them is overwritten by the stack then I can still add it, but the result is unimportant and nonsensical. What's worse is when pointers get overwritten. If you don't know pointers... then you probably have lots of company nowadays. But it's simple: pointers are memory locations. You interpret the value in a pointer as pointing to a memory location. So to load data from a pointer is a two step process: read the memory address stored in the pointer, then look at that memory address and grab the data there. However, if your stack has overwritten this pointer then it might point to the wrong memory address or (more likely) not point to memory at all. You see, RAM on the Cortex M3 (the one I'm working with) starts at 0x20000000. So if a pointer tells you to look at 0x1FFFFFFF then it's not just telling you to look at the wrong memory address - it's telling you to look at something that's not even memory. If it tries to do that it triggers a hard fault and you get to figure out why. If it's your first stack overflow then this process lasts days. Enjoy!

So that's one type of overflow that can hurt you. The second is buffer overflow. There's no magic here either - a buffer is basically an array. Arrays are bounded - they have a definite size. But even if you declare your array to have a size of 512 your compiler won't stop you from requesting the 513th element - it picks out the memory just beyond the end of your array and reads it. And you can write to it just as easily. And of course, there's usually something important there that you really shouldn't overwrite.

Arrays can be difficult to work with, so people create circular buffers. Normal arrays would be linear buffers: start at zero and go to the end. Circular buffers wrap around so that if you try to go outside the array you loop back around to the beginning instead of trailing off the end. That is, they loop back around to the beginning if you code them correctly. Tell me what you think the result of this code is:

head_pointer = (head_pointer + increment_value % buffer_size)

If you said the modulus (this thing: % ) operation would be evaluated first - you're right! And you're smarter than me! That code doesn't do what I wanted it to do: increment the value then wrap it around if it was greater than the buffer size. Instead it wrapped increment_value around if it was bigger than buffer_size and then added it to head_pointer. The net effect of this is that the pointer never loops around to the beginning of the buffer - it just keeps growing and growing and growing and gobbling up memory as you write to it. If you let it go on long enough it will overwrite a pointer with gibberish and trigger a hard fault.

Yes, I did this. At least this sort of stupidity on my part gains me valuable experience. Lesson learned: I am very foolish sometimes.

Thursday, February 17, 2011

C Gotchas

Holy crap, two updates in one day? Yeah... I decided that if I find myself sitting at my computer thinking 'I wonder what's on Slashdot' or 'Do I have any more street cred over at Chiphacker?' I decided I should do something potentially useful and update my blog. Doesn't have to be long, doesn't have to be good, dosen't ahve to ahve correct spellign - just do it. After all, the first step to making money with a blog is to update it every day. Second step? Have people actually read it. Step three profit baby!

But I'm sure you're all here for the real meat of this post and that is going to be the answer to the question 'What stupid thing did Steve do today that cost him hours of time?' It didn't take me hours, but here's a snippet of code that caused me trouble. By the way - you win $10,000 if you spot the bug and submit it before I hit 'Publish' for this post.

#define VALUE 0xF01FUL

short i = 0xF01F;

if( VALUE == i)
{
print("They are equal\r\n");
}
else
{
printf("They are not equal fool\r\n");
}


Ok hotshot, what prints?

If you said 'They are equal' you are in fact wrong. I hope that feels good. But do you know why you are wrong? Here comes the science.

We have two things being compared here: i is a short int. On most processors/architectures that is a 16-bit signed integer. The #defined value is in hex (obviously) and supposedly the same value as the variable but has a little 'UL' on the end of it. That signifies that it is to be treated as an Unsigned Long variable. This corresponds to the unsigned int (32 bit) type on most processors/architectures.

That might already give you the first inkling of why these two aren't equal: one is 32 bit but the other is 16. But you veterans out there (if you consider having taken an introductory C class in college being a veteran) will think 'Ah, but those bottom 16 bits are the same, so it shouldn't matter!'. You would be right, but C doesn't follow your rules. In C all integer comparisons are done on a 32-bit basis. Basically, C expands every integer used in a comparison to 32 bits to determine if they're the same.

'Aha!' you say with a sly smile, 'I was right then! Even if you expand them both to 32 bits they're padded with 0's in the upper unused portions (obviously!) so they come out to the same thing!'

But once again you're incorrect in your assumptions. Why oh why do you assume that they're padded with 0's? Because the only other option is to pad them with one's and that would change the value? You obviously forgot how signed data is represented on a computer! In signed integer types in C the most significant bit is the sign bit - if it's 1 then it's negative. Seems simple enough. So let's follow your line of thinking and expand our (signed) variable to 32 bits:

16-bit value: 0xF01F
Expanded to 32 bits: 0x0000F01F

Wait a darn tootin' second! This was a negative number (the most significant byte was F which means all 1's which means the most significant bit was 1 - which means negative). Now that we've expanded it it's suddenly.... not negative. Well that can't be. It's not the same value then - positive vs. negative. Kind of a big change. So to preserve the value we'd have to expand it and pad with 1's - like this:

16 bit value: 0xF01F
32 bit value: 0xFFFFF01F

Let's check my math with a signed integer calculator that you can find online (via the Google: http://planetcalc.com/747/):

0xF01F: -4,065
0xFFFF01F: -4065
0x0000F01F: 61471

Yep... padding with 0's doesn't produce the same result if the integer is defined as signed. So where you see

if(0xF01F == 0xF01F)


C sees:

if(0x0000F01F == 0xFFFFF01F)


And then it looks at you funny for thinking they're the same.

But I don't look at you funny. I'm only so dismissive and rude because I just made this mistake today and the pain is still fresh. Someday we'll laugh about this.

But for now if you mention it I will end you.

Quick Debug Tip!

You've probably been told you should always read returned error code from functions - especially if you're working with a new API. It's too easy to assume you have everything working because it compiles and then it all falls flat when you try to run it. But the question is what do you DO with the status? It's not always clear. There usually a lot of them and often you won't be handling most of them in a release configuration (hopefully you will have learned how to avoid most of them by the time you release). Some are potentially ill-defined (how many times have you seen a code like ERR_UNKNOWN returned three or four different places in one function?). But what you should always do is read the code and check it - like this:

status = api_function(args);
if(status != ERR_OK)
{
//Apocalypse?
ERROR();
}


This is good practice - always do this. Even if the if statement is blank, still do it. Just get your hands into the habit of reading returned error codes and checking them.

But you may have noticed I put something called ERROR() in there. That's a placeholder for a real error handling strategy. Just start by defining it as a macro (Note, this may not be correct, it's early and I'm not in my right mind):

#define ERROR()


Now it exists but it doesn't DO anything. This is a fancy way of putting nothing inside the brackets but still reminding yourself that you have to do something later. If you do this for every returned error code then you will have a hook in place to do something if a proper status code isn't returned.

Now depending on what point in development you're at and what kind of system you're running you have several options. While still debugging I find it easiest to just define the macro to be something like this:

#define ERROR() disable_ints();for(;;){wdt_pet();}

This will entirely block the program (including interrupts) while simultaneously petting the watchdog timer so it doesn't restart the processor (just in case the watchdog interrupt isn't maskable on your processor). If you don't have a watchdog timer you can ignore that part. This approach works best when you have some sort of debugger. You start the program, wait a second and then pause execution to see if it's stuck in any of these loops. This approach also works in a multi-threaded system assuming that your scheduler runs in a maskable interrupt. When you release this code you should remove that macro so that your system doesn't hang out in the field for an ignorable error.

For a more advanced approach that you might actually want to use in a release environment you can potentially define different levels of error such as ERROR and FAULT. FAULTS would obviously be more important and warrant more attention while ERRORs might simply be counted and then ignored. Most of the time dire errors can't be handled locally, so your only option is to report it to the operator (if there is one) and usually his/her only option is to hit reset and hope everything goes back to normal. But at least there's a process!

There are other interesting wrinkles in this error handling game. The ARM Cortex M3 for instance has a fault interrupt that is called whenever something bad happens (try to access memory outside of RAM, divide by 0, wear white after labor day, etc). It pushes the state of its registers, stack pointer, program counter, etc on to the stack and then visits the interrupt. You can use the information it saves to create a report (because sadly most faults that force a visit to the interrupt cannot be recovered from without a reset). The processor you're using may have similar error-handling features. Take a look.

To summarize - always check returned error codes. Even if most of the time you can't DO anything with them you can at least hang the program so you know you have a problem to fix. You might be able to get fancier later but as my favorite super-national paramilitary group used to say - Knowing is half the battle!

(Actually that's crap - they were all-American when I was growing up and I'm too old to change now! Get off my lawn! GO JOE!)

Tuesday, February 15, 2011

What are you doing?

Stop! Right now. What. Are. You. Doing?

Wow, let's stop that, I felt like a telegraph there for a minute (STOP). But the question stands: just what do you think you're doing? I intend this post mainly for people who have stopped developing software/hardware and have taken a break to absorb my acerbic wit. If I stopped you in the middle of enjoying a bowl of ice cream please believe me when I say I did not intend that you should question why you're putting it in your mouth. There's a good reason for that: it's ice cream. Duh.

But to all those coming for some witty banter - fresh from a break from developing the latest microcontroller-inspired widget - let me ask the question again. Just what do you think you're doing?

Probably your answer is going to be 'coding' or something similar. Good. Microcontrollers need code - that's obvious. But let me ask you this: how certain are you that the code you're writing right now is the code that's going to end up inside of that microcontroller when all is said and done? Uh, analysis? Maybe 15% certain I'd say - depending on what point you're at in the design. If you're early on in the design your chances are closer to 1%.

This is not your fault - well, that's a lie. It probably is your fault - but I'm trying not to scare you off. After all, this happens literally to everyone. Everyone. No one goes through a project and doesn't have one of those moments where they realize they have seriously miscalculated the scope of their project, or the simplicity or realized that they forgot about some other major hurdle. Then they end up decimating their code - and not in the literal sense where 90% of it is left after. No, more like 1% is left - and that's probably a header.

I typically see this problem because people don't consider whether their code actually works. They read specs, requirements and other documentation and then write a lot of C code. Or Java, or Python or whatever. It's all the same - almost literally because as I said 99% of it will typically be gone by the end of the project (so it makes little difference what language it's in anyway). Sure, it probably compiles - with only a few dozen warnings (It's all small stuff - it doesn't affect how the program works. Some casting will fix it, it's fine!) but there's no telling whether it actually does what is expected of it because you didn't set up benchmarks, tests or sanity checks on anything. Your development process goes something like this:

Read
Code
Code
Code
Code
Code
Delete 'old' code
Wish that you had used source control because that wasn't old code at all
Code
Code
Cod (not a misprint - you're enjoying fish at this point)
Ode (poetry break)
Code
Code
Code
Integration
Blank stare
Blank stare
Disbelief
Delete 99% of code
Recode
Recode
Etc

And let's be honest - if at any point in the design process you stop to think about it you're going to think 'Man, integration is going to be a bitch.' There's no project for which that isn't the case - integration is always difficult. But there's a way to make it easier - don't save integration for last.

Why is it that when you work on something for some reason project management always seems to think that it's their job to keep developers apart for as long as possible? It's probably because the Waterfall Model says that development and integration are two separate phases and one (development) is a prerequisite for the other (integration). So no skipping ahead to integration! What will project management do if not enforce the flawed and ultimately unhelpful vanilla implementation of the Waterfall Model on the poor helpless engineers under its command?

Of course not everyone blindly follows the Waterfall Model, or eXtreme Programming (seriously, the initialism is XP, not EP, so I capitalized the right letter there) - it certainly isn't the case where I work. No, what you need to do is integrate as soon as possible.

A project typically consists of several independent parts which can be integrated and tested without bothering the other parts. Projects usually also consist of several pieces of hardware, code or technology you've never worked with before. Let's be honest - when was the last time the new chip you used followed its own datasheet exactly? And for that matter, when was the last time two engineers working on opposite sides of a communication channel, attending the same meetings, reading the same documentation and potentially being in the same love triangle decided to implement their portions of a project in a compatible fashion? These aren't signs of immature engineers or bad project management or difficult documentation - it's just life. These things happen. The difference between an inexperienced engineer and an experienced one is basically how jaded he/she is. Optimism is not a useful trait when everything is contractually obligated to go wrong.

Given these problems it makes no sense to write literally everything and then go back and make sure it actually works. Here are several suggestions:

Use unit test for complex algorithms to catch rookie mistakes such as off by one errors (we all make them).

Walk over to the other engineers office/cubicle and ask copious amounts of questions. Nine times out of ten on a project the arbiters of what actually gets made are the engineers themselves. Just to get everyone on the same page it helps to ask of your fellows 'So what CRC method are we actually using and how does it work?' Then document it.

If two chips have to talk to each other chances are they will hate each other and refuse to speak. Start early with actual chips and force them to get along as soon as possible.

Abstract away interfaces so you don't have to worry about specifics in unrelated parts of code. You don't have to know whether your serial interface actually works if your application's only method of accessing it is a ring buffer.

Verify all assumptions as soon as possible. Chances are you're wrong (life just hates you like that).

This is hardly an exhaustive list but I think you get the idea. In case you don't get the idea I'll state it as plainly as possible:

Code isn't useful unless it works! Don't sit there with questions, concerns and unverified assumptions but pop out 1K lines of code a day. In a month you'll be left with 500 lines of good code and a looming deadline. Be pragmatic, be wary and be prepared.

Note to anyone who is reading this who may actually know me and/or work with me: I am not vindictive, frustrated or lacking empathy for this situation. Believe me I have been stuck in it plenty of times and it was all my fault. But I will be the last person to berate you and the first person to stick up for you in a meeting or directly to your/our boss. Sure, this may be a rookie mistake but we're certainly all allowed them. If we're not then we have no opportunity to become better engineers.

Thursday, February 3, 2011

Terminology Galore

If you're anything like me you hate terminology. You know, those special, magical technical words that people use that you don't know the definition of. Terminology. It'd be great if it weren't so imprecise. You'd think (well, hope) that a word has one definition. This is not even close to the case with regular English (and even worse with British English) but can't one hope for a more direct mapping from technically-minded people. A word should just mean one thing, right?

Take the word 'driver'. On your desktop PC you have drivers - all kinds of them. On an embedded system you have drivers - all kinds of them! But they're not the same kind of drivers - not exactly the same anyway. If you wanted to fill a job writing Windows drivers you might not want to fill it with someone who write embedded systems drivers or even Linux drivers. So if you saw such a job advertised you'd want to make sure what kind of job you were getting into.

So some recruiter calls you and asks 'Do you have driver writing experience?' And you really want to ask what he means but you know he doesn't know. The best answer you're going to get is "What kind of experience do you have?" I would respond with something like "I've written multiple device drivers for bare-metal microcontrollers and real-time operating systems, is that what you're looking for?" And if you're lucky the notes he writes about your experience will be something like "bear-metal.. big iron? Iron Man? multiple operati.. operation systems. Operation - I loved that game...." And what he tells you is "Absolutely absolutely, I'll get in touch with them and let them know. That's great that's great!"

And that's only the answer I would give now - because now I have some idea what a driver is and how it isn't a board-support package or hardware abstraction layer (I think). But if you're anything like me a month ago you're a bit lost. You see I had developed drivers before (I think), and just didn't know it. So let's define some terms!

I consider a driver (in an embedded system) something that hides registers for you. For instance, here's some code that configures a timer on on MSP430 for creating a servo control pulse:

//Clear timer A config

TACTL = 0x04; //TACLR = 1


TACTL = (0x02 << tassel =" 10">
(0x00 << id0 =" 00">


TACCTL0 = 0x0000;


//Configure compare and capture unit 1 for output compare mode 3
TACCTL1 = 0x0000;


TACCTL1 = (0x00 << cap =" 0">

(0x03 << outmod0 =" 011">



//Set CC1 to generate 1.5ms pulse - neutral

//MSP430 user's manual page 11-14

//?? what's going on here?

TACCR1 = 0x0000; //SET output line HI at 0x0000


TACCR0 = PULSE_1MS; //RESET output line (LO) at 1.5ms



//Set timer A period to 2ms

TAR = TIMERA_PERIOD;



//Start timer

TACTL |= (0x02 << mc0 =" 0x01">

(0x01 << taie =" 0x01">



Thats... a lot. A lot of bits. A lot of hex, a lot of OR'ing. A lot of bad formatting. Oh my, I can't handle this.

I'd rather do something like this:

timera_conf(SRC_SMCLK,DIV_1);
timera_cc_conf(FUNC_COMP,COMP_MODE_3);
timera_cc_setpw(1500 /*us*/);
timera_interrupt_enable();
timera_run();

See? No bits. That's a driver.

Now, this is an internal peripheral. Those are easy. Well, easier. We know that drivers basically set registers. When it's an internal peripheral then accessing those registers is just as easy as saying 'register = value'. But it's harder if you have (for instance) a peripheral connected over SPI. You still have to set registers but that requires you writing data over SPI - usually commands like 'I WANT TO WRITE TO THIS MEMORY LOCATION. IT'S A CONFIGURATION REGISTER YO' and then the peripheral responds 'YO DAWG THAT'S COOL WHERE THE DATA AT?' and then with another SPI transfer you say 'HERE DA DATA AT!'. So basically you'll have a peripheral driver utilizing the SPI driver. It's a whole bunch of driver on driver goodiness.

So what about all the other crap? Like a Board Support Package. Well a BSP... supports a board. For instance the ez430-USB development kit has one LED on it (this is the extent of its on-board peripherals). It's located on P1.0 which is on physical pin 3 which can be accessed on port (yadayadayadayada). You don't want to know all of that - you just want a heartbeat LED. You want it to flash. So you have a smart guy write a function for you - a BOARD SUPPORT FUNCTION!

void bsp_led_toggle( void )
{
P1 ^=0X01;
}


This is great - I don't have to know where the LED is, I can just say 'toggle that please!' and it gets done. That's board support - it supports the board. Whatever's on the board needs functions so I don't have to know all about it.

And what about the dreaded HARDWARE ABSTRACTION LAYER?!?
The HAL just makes sure you don't actually need to know what your hardware looks like to use it. For example, you can turn a general-purpose I/O port into a TTL serial interface - you just have to be careful with timing and such but it's certainly possible. Now imagine on your Arduino you have the regular UART and a software-based UART. You want the same interface to both: get a byte, put a byte, turn it on, turn it off. So you write up a bunch of functions and then you just say something like:

byte = uart_get(fake_uart);
byte = uart_get(real_uart);

Same interface, same bytes, different underlying hardware. That's what a hardware abstraction layer does.

Hopefully with some of these definitions you'll be a little more educated about what all these weird definitions are. Good luck!