Sunday, January 16, 2011

Desk Update

I mostly finished my desk/workspace. I think it looks good. You can see pictures of it here: http://picasaweb.google.com/sfriederichs/DeskPics?feat=directlink

I totaled up the cost for the materials. Not tools or time, just materials. The new things I bought came out to about $340, but I also used some wood from my old desk. I'll figure about $60 for that and put the materials cost about around $400, plus about a full week of time spent on it. Don't even ask about the tools and miscellaneous consumables (staining pads, etc). Tools are worth it, but consumables are just something you have to live with.

Saturday, January 8, 2011

A Proper Workspace

When it comes to work surfaces I am no fan of store-bought desks - I'm very angry at them. I need to do real work and to do that I need a solid dependable work surface. Sadly, you won't find that in most stores. Or, if you do, you'll pay $1000 for an 'Executive' desk that does its job well (and usually that job is much different than the one you want it to do). If you buy from a store, you're likely to find something like this in your price range: http://www.officemax.com:80/catalog/sku.jsp?productId=prod1811868

This monstrosity is a disaster. I mean, even the picture alone signifies that they just didn't care. Look at the CRT and circa 1996 inkjet printer. They didn't even update the picture for the new millennium. I'll start picking this thing apart in no particular order:

3) Teak Laminate Top. Teak Laminate Top. When you're just not important enough for real wood, we'll mix sawdust and glue together to give you particle board and plaster it with just enough real wood to make you think we spent money on you. This is low low low LOW quality. And sadly, if you're anything like me you've seen plenty of laminate (and hated it).

6) Penumatic work surface adjustment - how likely is it that the pneumatic parts are similar to the ones you see in office chairs? You know, the office chairs that fail working particularly well after a few years? Yes, for now it's an adjustable work surface, but come three years along you'll have to drill holes through the supports and stick bolts through them to make sure that it doesn't keep dropping on you overnight.

2) Keyboard trays - these are universally awful. For me anyhow. Yes, I'm sure they work for some people but how likely is it that this keyboard tray will work for you? You'll either end up disconnecting the thing (painfully) or developing carpal tunnel. I have not had a single work desk (that I didn't make myself) be 'ergonomic' in any fashion and the keyboard trays were some of the worst offenders. Just look at the wrist rest - bunched up right against the keyboard. That looks painful. Look at the odd angle. Yes, I'm sure it works for some people, and I'm sure it can be altered, but let's face it - they use cheap hardware on these things and they never stay altered. They wear down and flop back to the worst possible position.

7) CD storage on the desk - since when did this ever work at all? Do you own 12 CDs? Then this is the desk for you! Pathetic. You need a real storage solution for CDs and DVDs - not the pathetic attempt seen on this desk.

9) No monitor stand. Really, this is a necessity. Your neck is just as important as your wrists.

4) No cable management. It will look ugly.

1) No front legs. Just try to lean on it and see what happens. And I don't hold out much hope for those metal support parts. They're probably hollow and will bend/break eventually. This is not how you make stable work surfaces.

5) Leg room - nil. Seriously, where do my legs go? Can I stretch them? No I'm going to hit the wall or one of those supports.

8) Too small - it's 29" deep which is good, but only three and a half foot wide. Not nearly enough room to spread out several documents.

But hey, what can you expect for a desk that's only $80? Oh, wait, what's this:

Top component of the Balt Ergo Sit/Stand Workstation - ORDER BOTH TOP AND BASE
Oh, this only half of it, so it's $170 or so right? No? Nearly $400? Oh, well that's a great price....

This will not do. I cannot work on those thin
gs. I don't just need a computer desk - I need a real workstation - computer desk, writing desk, solder station, filing system, parts storage, tools storage and sever closet all in one. I need it to be solid. I need it to not hurt me. I need it to look nice. And I don't want to spend $1000 on it.

So I make them myself.

Now, this may surprise some of you, but I did not start out as an electron pusher. I grew up on a farm and learned about many many things. I can spot weld, cut metal with a torch, help pour concrete, drive a tractor, be a human gate, give a pig a shot, stack hay and shoot guns. I am also not to shabby with woodworking. Wood is my preferred material. It's light, strong and pleasing to the eye. It's also phenomenally cheap and the tools to work it are similarly inexpensive. And when you mess up it's easy to hide (as my dad always said 'A little putty and a little paint makes a carpenter what he ain't').

I started making my own desks with very simple construction. Here's an example of something I hacked together with 2x4's and wood screws that is very similar to my first desks:


Such a table is not difficult to put together. Most of the pieces you'll buy pre-made from places like Lowes. The top is a single 2 ft x 4 ft sheet of 3/4" plywood screwed into the frame. The frame and legs are 2x4's all around - butted up against each other and screwed with cheap wood screws. Everything was cut to length right in the store then brought home for assembly. The only touches of flair are counter-sunk holes for the screws (keeps the screw heads from sticking out) and paint, along with a coat of spar varnish to protect it from the elements.

It's not pretty, but it has its benefits. It is exactly the table I wanted - no more no less. It is solid, very solid. I can stand on it no problem. It won't tip or jostle and the legs stay in place. And it is cheap. Materials were at most $50 and my labor is free (I'm a slave driver).

That's all well and good, but it's still not really a piece of furniture - I wouldn't hand that down to my grandchildren. And it's not very shall we say... featureful. It's four legs and a top. No drawers, no shelves, nada. For a workstation I need something a lot more complicated. I need this:


This is my workstation. I just made it over Christmas with the help of my dad. It's just shy of 8 foot long, 30" deep with a 12" deep monitor shelf along the back - all pine. It has four stylish legs all the way at the corners of the desk for maximum stability, and the part in the middle is also weight-bearing. I sanded the hell out of it and applied two coats of a stain/polyurethane combo. Half of it (on the left) is meant for electronics and the other half is for the computer. There are cable holes on the computer end for easy cable routing. My laptop there is sitting on an Ergotron laptop arm. There are spaces for drawers on both the electronics and computer end. The part in the middle is slide out storage for printers (both my inkjet and laser). Take a look at one of them in action:

Underneath, there's power strips running all along the back of the desk, as well as a piece of pegboard that holds my wireless router, NAS, print server, power adapters and other IT-related paraphernalia. This is temporary at this point and everything is going to go in the drawer when it gets put in later:

There is a second piece that is still waiting to get put in that will support rails for plenty of shelving storage and a bookshelf on top as well as extra lighting. Here's what it looks like right now:



(Oh and don't complain that it's covered in papers. This is what a desk is supposed to look like. If your desk is clean it means you're not doing any work.)

And what did this wonder cost me? Less than $500 at this point, and three solid days of work. Well, the tools cost a fair bit by themselves, but I think it's worth it when you consider what you can make with them.

I'll post pictures of the completed project when it's done.

Saturday, September 25, 2010

Something I'm Proud Of

Engineers are supposed to make things, right? You'll cruise the hobby blogs and read about all these cool projects that light up and/or tweet things - everyone seems to be making something nowadays. I'm not so great in that respect. I really haven't made anything apart from my job. It's a little embarrassing, but I don't really get off my butt unless someone orders me to do something. But then I'm great - I make scripts. PCBs, code, you name it.

Well it turns out that lately I've actually accomplished something - and it all started with a problem. While working on a microcontroller design at work I was readily infuriated by breadboards. You just can't get away from them and you shouldn't try. Everything really out to be breadboarded before it's finalized - otherwise you'll have loads of incorrect PCBs laying around and lots of wasted money. But breadboards are hard to work with: wires pop out, you can't put surface mount components on them, they don't have nice modular connectors and you can't always stick a probe in the holes to see what's going on. So I made something to fix that problem for me.


This little doohicky is a breadboard test point/connector adapter. It has a row of 8 pins that plugs into your breadboard and then connectors for the power bus (there's two different configurations of power busses that i've seen - .1" pitch and .15". It has holes for both). First, it has 8 surface mount LEDs for each of the pins making it very useful for status displays. Second, it has a 2x5 connector that will fit a standard IDC cable plug. I have plans to make an IDC to male pin cable that plugs into it. Third, it has two sets of test points - there are male headers for logic analyzer female plugs to fit onto (along with the obligatory 9th connection - ground) and then there are high profile test points that work great with scope probes. And also for the scope probes there are four high-profile test point ground connections. No more silly jumper wires to the ground bus on the breadboard. All of the test points are isolated from the breadboard by 10K resistors. That way, if you accidentally short two test points together (perhaps one that is connected to ground and another to +5V) you won't break whatever is connected to those pins. If, for instance, you do have the worst case scenario and +5V shorts to ground, you have an equivalent 20K of resistance between them and nothing short circuits - just 2.5mA flows through the connection. Lastly, there is a 1.5A resettable fuse between the breadboard VCC and the VCC on the IDC connector, so if something you accidentally connect the +5V from the IDC connector to ground the fuse will trip and not hurt your power supply on the breadboard.

I plan to sell these at... well, wherever will take them. Sparkfun, Ladyada, etc But not yet. There are several design problems that need to be ironed out. A bit more parts selection, maybe a few more components and this board will be ready to sell. I hope everyone else is as excited as me.

Anyone?

Anyone? Bueller?

Oh well.

Thursday, September 16, 2010

Don't Save Bad Code

As coders we're often asked to do things we don't know how to. Use a new library, use a new microcontroller, try a new compiler. So we start to experiment - make something 'just to see' if you can program your microcontroller or figure out how a library works or do simple socket communication. Then you think 'Wow! That worked! Let's try more things! I'll just start coding everything here in main()....' And then you get eaten by raptors.

You've made a mistake. You weren't thinking about organizing this mess or even making sure it was robust - you were just seeing what you could do. Your main() is 1000 lines and you're not sure what all of this code is supposed to. You didn't comment because it was all so obvious earlier, but now all you know about this line is that if you comment it out the program crashes. Whoa boy.

But still you feel the compulsion to try to work with this mess. You want to massage it, start breaking things off into functions, add a few defines, rename the variables and make it work again. But step back - is this what you're supposed to be doing? After all, you started this to learn the library or a framework and, well, haven't you? Isn't that information tucked in your head by now? Is this code even remotely close to your final product? Could it be? Does it work? Is it well-organized and robust? Didn't you have a real development plan somewhere here? Complete with projections and unit tests? And haven't you learned enough to start on the real work, rather than just trying to save this one .c file out of sentimentality?

You shouldn't try to save old code just because it's already written. Old code has no particular value over newly-written code for several reasons.

First, there is no cost to writing new code in place of old code. When working with physical objects if you make a mistake with a material you have to pay to replace the material. If I were whittling wood and I shaved off a little too much I would try to work with it. But with software we have source control, so if I make a mistake I can revert it or even start over without losing anything. I still have access to the important things: my old code and the knowledge I've gained from writing that code.

Second, new code presents an opportunity for a more correct solution. So you've sat down and written a lot of bad code. You feel like deleting it would mean deleting the progress you've made towards a correct solution. But surely you haven't been asleep this whole time? Your mind has been watching the code you're writing and doing its own work - pondering the patterns behind the madness, taking note of vulnerabilities, seeing patterns that could become functions, etc. You've gained a lot of experience just by doing it wrong and at the very least you have a better idea of what NOT to do once you start over. A fresh start allows for a more pure expression of the solution that can't be shoehorned into your ill-conceived beginning.

Third, you will improve your tests by trying things different ways. If you use a FOR loop then you won't encounter errors that you might if you used a WHILE loop. If you're using dynamic memory allocation instead of static you have more things to worry about. Each new method of solving the problem before you opens up new areas for failure. Will this sub-function I just started using return 0x00 for any reason? Because I return its value without checking it and zero would not work well for a return value. So write a unit test to ensure that the return value is never 0. That's one more level of certainty that you're writing correct code, not just code.

Fourth, writing new code allows you to follow best practices more closely. So after a few hours of hacking together your test program-turned release candidate you decide to see what happens when you run splint on it. Turns out it produces so many warnings that your ego crawls into a hole and hides. What's the right course of action? Fix the warnings one by one until the splint output is clean. What do most people do? Turn off splint and wait for it all to be caught in integration. It's much easier to run splint on a 5-line function than 1000. Starting over gives you the chance to comment, run analysis tools, develop unit tests and format your masterpiece when it's a much more manageable size. This will only help you in the long run by front-loading much of the work that leads to clean, well-running and tested code at integration time.

Whenever you are writing - be it code, a short story, a joke, a play, a manual on annoying your cat remember this: the measure of how well you have written isn't the number of words - it's whether you accomplished what you wanted with those words. Eliminating incorrect code instead of massaging it back to life costs you nothing, lets you write more correct code, expands the range of your unit tests and helps you follow process more closely. So don't save that crufty old code, replace it and move on.

Friday, June 25, 2010

Just How Awesome is Batman?

Unlike my usual practice of the title of the blog post having nothing to do with the content I have posted a relevant title today. And also, there's nothing about electrical engineering or computers or code or controls or math in this post (except insofar as Batman can do any/all of those things awesomely) - just Batman.

Truly, Batman is amazing - he's crazy prepared at all times. (Note: I reference the Justice League cartoon when I'm talking here - haven't done much comics reading). When AMAZO stole Superman's powers, Batman nonchalantly whips out kryptonite from his belt and fends him off - prompting Wonder Woman to ask "You carry kryptonite around with you all the time?" Of course he does - he's the Goddamn Batman. If Supes suddenly went rogue (as opposed to going rouge which involves cross-dressing) then Batman would be on it. His utility belt is like Schroedinger's cat. While the cat is both alive and dead at the same time, his belt does and does not contain every single item in the universe - particularly the one that would be most useful. He's just lucky enough that when he opens a specific compartment the probability waves collapse into the exact item he needs. Or not - he'll just MacGuyver up something from whatever he finds in there. I mean, it might be pocket lint and somehow he'll defuse a nuclear bomb and give everyone ice cream cones (with sprinkles).

It's a well-known fact that Batman has a way to defeat every single Justice League member if they turn evil. But this brings us into the barber paradox of the day: Can Batman defeat himself? The logic of the situation is similar to the barber paradox but instead of shaving it involves death served cold. We start from several assumptions:

1) Batman is always prepared. Always.
2) Batman doesn't want to die
3) Batman has plans to kill every member of the Justice League himself
4) Batman is in the Justice League
5) Batman is the Goddamn Batman

So, some conclusions. From 1 and 2 we surmise that Batman will always have a plan ready to prevent his demise. This only makes sense - who wants to die? And by adding in 5 we can assume that this plan will always work. It always has in the past. In the 80+ years of his comics I don't think he's ever died. I mean, Bane broke his back but he didn't die - he healed up again and went on being Batman. That's about as close as it gets. Maybe in some alternate timeline or something he dies. I hear the Joker got reality-warping powers once somehow and might have killed him but that didn't work out for the Joker because the whole mess was cleaned up by the end of the comic and Batman was alive again. Yes you heard that right - when Batman and reality itself are in conflict Batman wins. That's tough.

From 2 and 3 we surmise that Batman must have a plan to kill himself if he goes rogue and by adding in 1 we can surmise that he's ready to follow it through. It makes sense. I'm sure he's been under mind control or something often enough to want to have a backup plan in case he starts acting all evil. Most likely if he really needed to die he'd just have Supes or WW pummel him to death or slice him in half with heat vision (or lasso him to death somehow - not effective, but kinky and I think he'd like to go like that. Plus he can't lie when the lasso is around him so he'd probably admit it turned him on).

So this gives us two contradictory conclusions: Batman can't be killed and Batman has a plan to kill himself that will succeed. Both of these can't be true. I'll throw out a few examples:

Batman knows that he needs to go down if he turns evil, so he tells Supes to beat him to death under a very specific set of circumstances - maybe some kind of mind control that can only be broken by blending his brain into a milkshake or something. But! We know that Batman really doesn't want to die AND he has a plan to kill Supes. What stops him from just going through with that plan? Not much - he's Batman. So Supes is dead, and then Wonder Woman, Green Lantern - pretty much anyone who gets in his way. That's not a very effective plan. Maybe the ENTIRE Justice League could jump him at once but hell I just thought of that in ten seconds - Batman probably considered that one when he was still in the womb. I'm sure he has a plan for the whole Justice League turning evil at once. In fact I'm sure there's a precedent for that somewhere in comics history. And I'm sure Batman resolved it with ice cream again. So scratch that.

Okay, so maybe Batman can just kill himself. If he was evil he wouldn't consciously want to do it but maybe he implanted some post-hypnotic suggestion triggered by a code word that would force his heart to stop or something. And then he makes himself forget about it somehow and only lets certain people know. People like... Superman again? No, because if he really fears Supes going evil (enough such that he keeps kryptonite on his person) then he's not going to give him a kill switch. And even if he did do that whole hypnotic kill switch thing and forced himself to forget about it what stops him from one day discovering that someone implanted a hypnotic suggestion in his mind somehow and rooting it out? He doesn't know that he put it there - it could have been Grodd or someone else's insurance policy. Just yell 'Steeplejack!' in their next battle and Batman makes tea for him instead of delivering a beatdown. Can't take that chance.

I wouldn't even put it past Batman to install a tiny computer with a tiny AI in his suit somehow prevents him from stabbing himself in the chest, or replacing his heart with a nuclear bomb (the Goddamn Batman needs no capacity to love, or circulate blood. The blood moves on its own because it fears what will happen if it doesn't) that goes off as a last resort and his consciousness transferring through the ether to a clone tank on the moon that he put there and made himself forget about so no one could sabotage it. HE'S FREAKING BATMAN PEOPLE! He put a space station with a fusion laser in orbit a week after Martians attacked Earth. The buses weren't even running but apparently Wayne Enterprises had orbital capacity. Fusion technology didn't even exist! He invented it and then did it and surprised the hell out of the rest of the league and was all like 'Oh you like this space station? Yeah of course I can afford it. I'm the Goddamn Batman. Go to your quarters - the mattresses are stuffed with money and I can flood your rooms with poison gas if you get out of line. I mean, strike that last part. I'm Batman.'

Does anyone have a logical resolution to this mess?

Quick question: In a fight between Batman and Chuck Norris who wins? Answer: No one wins - there are only losers. Specifically, you and everyone you love.

Tuesday, March 9, 2010

New Unoriginal Idea

I don't think that I learn much at my job, but I was surprised the other day to learn something new about microcontrollers. Well, coding in general anyhow. You see, when working with microcontrollers I use a finite state machine to control program execution. No, wait, what does that mean? That's technical gobbledy gook. It means that I have a variable and I define a bunch of different values it can take. When my program starts it goes into INITIALIZE mode and it initializes stuff. Then when its done I usually put it into IDLE where it doesn't do much of anything and usually waits for user input like a button press or something. Then depending on what happens I put it into other modes like DO_STUFF_1 or DO_STUFF_2. Different events can change the mode it's in and that produces different behaviors. The idea is that it will be a nice and orderly flow from one mode to the next and that depending on what mode you're in you won't handle certain inputs, or you'll handle them differently. The goal is predictable behavior.

But microcontrollers are anything but predictable. You see, there's these awful things called interrupts. They are what they sound like - they interrupt your program and do something else. They happen usually when hardware has done something - say a button has been pressed. When that happens, whatever you were doing previously stops and this new code executes. That's not usually so bad, but you almost always want to change the mode you're in based on what happens in that interrupt. Okay, so change the mode. Fine, whatever. I don't care.

Except I obviously do. This might happen:

CODE ALERT! CODE ALERT!

do_special_stuff_for_different(modes)
{
mode1:
easy_command();
easy_command();
---OOOOPS INTERRUPT HAPPENED HERE!----
change_mode_to(mode2)
---INTERRUPT OVER BYE BYE NOW!--------
command_that_checks_mode(); //Oops, doesn't run, wrong mode!
command_that_depends_on_the_above(); //fails, above didnt' run!
...
} //Always close your braces!

You see what happens there. Ideally, you want all the commands for a mode to run regardless of whether the mode changes halfway through.

This can be done. Just use a queue data structure to change the mode. A queue is a list of things. I can put things into the back end and take things out of the front. So when I want the mode to change, I can just put the new value for mode into the queue and then handle it in one and only one place in the program:

is(empty(mode_queue))
{
no:
mode =new_mode_from_the(mode_queue);
yes:
//Do nothing!
}
do_special_stuff_for_different(modes)
{
mode1:
easy_command();
...
}

So you only change the mode before you handle events for that mode, and never while you're handling them. This eliminates confusion for the poor code.

But, my unoriginal idea improves this - I think. Say that you're in MODE1 and you have an interrupt that wants to change the mode to MODE2. Ok, it puts the new mode into the queue and we'll handle it when the time comes. But now, before it can be handled you get another interrupt that tries to change the mode to MODE3. Well, put it in the queue and we'll handle it. When everything is said and done, you have the mode change from MODE1 to MODE2 to MODE3 right after one another. It seems OK, but wait! When we designed the system, we never intended to move from MODE2 to MODE3 because in MODE2, we set things up to get ready for MODE4 which we intend to follow MODE2 directly. But that doesn't happen. When you're in MODE2 you try to put MODE4 on the queue, but it gets in line behind MODE3. And meanwhile, if MODE3 attempts to put MODE5 next, it also fails. So you've got two different things trying to happen in sequence at the same time.

It might work, but it might not. We intended in our design to move right from MODE2 to MODE4 but we didn't do anything to ensure that it actually would. That's where my unoriginal idea comes in. These modes are stored on a microcontroller. That means they're stored with bytes, and bytes are made of bits - eight of them to be precise. Eight bits can store 256 different modes if you encode it that way, or it can store eight if you use something called one-hot encoding. One-hot encoding means that only one bit is ever a '1' at a time - the rest are zeros. Wherever the '1' is determines what the value is.

So, when we want to change modes we don't put the next mode we want to move to into the queue, we XOR the current mode with the next mode and put that into the queue. The XOR operation works on bits and it says if two bits are the same, the outcome is zero. If they're different, the outcome is 1. Since all of our modes are encoded with one-hot encoding, there shouldn't be any same bits. Wherever there was a one in either of the modes' bytes, there will be a one in the resulted XOR'd byte. Using this method we don't only record the next mode we want to go to, but we record the mode the program was in when it wanted to go there. It says 'I want to go from MODE2 to MODE4' instead of 'I want to go to MODE4'. Then, when it comes time to look at the queue and change the mode, we can make a better decision. If the request is 'I want to go from MODE2 to MODE4' but we're in MODE3 right now, it doesn't happen. It goes on to the next request which was 'I want to go from MODE3 to MODE5' and that one happens.

Now, there's an obvious flaw in this: the request to go to MODE4 is lost totally. The upshot is that if I press two buttons at the same time only one thing happens. For buttons that's good enough, but for other inputs it's not. For some inputs what you really mean to say is 'No matter what mode I'm in now, I want to go to MODE8'. How do you do that? Simple, it's.. No, wait, how DO you do that?

Oh, wait, I know how. Assuming you followed all of the above steps, then when you XOR the information in the queue with the current mode you get out a valid new mode and just switch to that. If you don't, then you can assume that you want to perform one of these unequivocal mode changes. You just have to figure out what mode you want to change to. So, in order to handle that, you can do this: instead of putting the XOR'd mode into the queue, just put the next mode you want to go to. When the program attempts to XOR it again with the current mode it WON'T get a valid mode out of it. So, it will XOR the data again with the current mode and if you meant to do one of those unequivocal jumps, it will produce a valid mode from THAT XOR operation. If you didn't mean to do an unequivocal jump, then it will produce an invalid mode. Tada!

Monday, March 8, 2010

Debugging

This post isn't for me. I never have to debug. I follow a strict development process in which all of the documentation I read is perfectly accurate and describes all edge case behavior. I also follow code writing procedures so well that every exception is handled, every input is sanitized completely (even to the point of predicting accurately what the user meant to enter instead of what the user did) and every return value is checked. All reported errors (which are entirely due to... well, not me anyhow) have expository messages bordering on small novels that not only tell you what caused the error but actually fix it themselves in all known copies of the program, including those in the past. Yeah, that's right - my code is so awesome that it goes back in time and fixes itself before you even see an error message.

Well, I doubt you believe that. I'm not sure what to believe anymore - the full truth of the situation is caught somewhere in an unstable time loop that will someday tear reality apart. So in the meantime, I actually debug things. Yes, things that I created. This is because you can never get away from debugging. Because documentation is Just. Plain. Wrong. Because the user put international unicode characters that you didn't even know existed into your text box. Because every library you rely on has bugs and undefined behavior. And it's only worse with circuits: the EM spectrum is effectively infinite. Wavelengths you only see in your nightmares can ruin your life in an instant. It happened with the earliest digital computers - freaking cosmic rays would cause a single bit in memory to be changed and trash your machine state. Yes, the very fabric of nature hates you and wants to give you blue screens.

The best, the very best that you can hope for is that your code or circuit does what you designed it to do. Put all your effort into meeting the spec first - later, after you're almost done debugging and trying to figure out why the slave device won't respond to a perfectly valid message, well, that's when they'll tell you that the specs they gave you were wrong and you have to wipe out some code and start over.

In any case, when all you have is a spec, all you can do is implement it. Let's imagine a scenario that involves both hardware and software. I'll imagine a small embedded sensor that has to relay data to its gateway - probably an AVR based 8-bit microcontroller with firmware that I've made, communicating with a host system over TTL-level serial (8-N-1, 115200 bps) and it collects 0-5V data with the ADC. It uses a packet-based serial communication scheme (START, MSG ID, LENGTH, DATA, END sort of deal) to transmit data every second to the host.

Ideally, you code everything, solder everything, hook up power and communication and it works. Then you go home to your supermodel wife/husband/plaything and sports car and sip scotch while listening to death metal. But the reality is that 99.9999% of the time it won't work. The questions you have to keep asking yourself:

'What might be wrong if it doesn't work?'
'What's the quickest way to test that?'


Before I begin, let me note that I said 'quickest' way to test things. When you think you're done and you're testing your code or hardware the actual system it's meant to interface and work with, then chances are your time is limited. You'll probably be close to delivery of the final product, or you'll have another group that needs to use the actual system to test. In either case, quickest is best - you want to front-load as much of this integration phase as possible into design as possible. Don't ever assume it's going to work and then attempt to throw debug capability into your design after you amazingly find that it doesn't 'just work'.

So, look at the host computer and see what it says. No communication with slave?

'What might be wrong if that doesn't work?'


You should know why specifically it shows that message - in this case let's say that it shows it because it didn't receive an answer to an initialization message. Maybe it's just not getting the message

'What is the quickest way to test that?'

I think the easiest way is to put an LED on my slave device and light it if it finds the message. So we'll create the light and lo and behold it doesn't light.

'What might be wrong if it doesn't light?'

If it doesn't light, then the serial port may not be working correctly.

'What's the quickest way to test that?'


I would create a wrap-around self-test mode. Just loop the TX lines of your slave to RX and send a test message, then light an LED if it receives what it sent out.

'What might be wrong if THAT light doesn't light up?'

At this point, if it can't communicate with itself then it's just not sending anything out (for one reason or another) or what it's sending out is gibberish and can't be read back.

'What's the quickest way to test that?'

Monitor the signal to see if it looks like a legitimate serial transmission. To do that, you'll need test points to hook up your logic analyzer or oscilloscope. So you'll either see a valid waveform, an invalid waveform, or no waveform.

So ask yourself again: 'What might be wrong if I see valid waveform or no waveform?'

If you see a valid or no waveform waveform then it's probably software: the receive or transmit buffer isn't being filled perhaps.

And then: 'What's the quickest way of testing that?'

What *I* would do is use a secondary serial port as a debug terminal so you can view the contents of the RX and TX serial buffers. Then you can see if they're being filled or not, and go on from there.

So look back at all that. Just by considering what might not work we added several things to our system: test points, a wrap-around self-test functionality and a debug terminal. If you have all of those things ready and you've tackled some of the other 'Why might this not work and what can I do to quickly test it?' scenarios then you're poised to quickly find the root of the problems you're seeing in minutes and hours instead of days and weeks. Integration (that is, combining what YOU make with what OTHER people make) is the most difficult part of any project. Specs aren't going to help you because no spec is ever complete enough to define a system. Everyone makes assumptions and doesn't tell anyone and that makes testing a pain. So save yourself some pain and plan ahead. You'll thank yourself later.