EmbeddedRelated.com
Blogs
Memfault Beyond the Launch

Kind of Buggy! The state machine fantastic//

Richard DorfnerAugust 31, 20112 comments

Over the years, I have had the opportunity to experience a lot of different kinds of coding mistakes. There were many that most programmers are familiar with, counting errors, indexing errors (the infamous 'off by one' bug), memory space sharing errors (A threading issue) as well as numerous others. 

I ran into one recently that I wound up using an old trick to help find.

My current project is a Pan/Tilt camera that was, upon occasion, not homing properly in one axis. The camera is a single threaded process with no kernel or OS of any kind. it boots *VERY* quickly (under a second, a few seconds for the bootloader versions).  However, to remain responsive to serial commands, there are many functions that need to be 'stateful' so that they don't sit and spin on a given command till the command completes and instead are always able to respond to new command that is being given to them via the serial port.  Many of you will recognize this as the basis of cooperative multitasking. 

However, the various state transitions are dependant on different things. Some of which are time based which are kept track of in interrupt service routines, others which are serial port command based in order to start sequences such as a homing operation. This can wind up causing interesting behaviours if things are not carefully synced up and close attention paid to how the state transitions occur and to the ordering of when they occur. 

The problem that I had at hand was understanding, in code I had not myself written, how these states were actually being transitioned through. So I relied on an old friend, a small array and an index that I could use to record the last thirty states along with a debugger that let me set breakpoints.  I already had a location where I knew that when the code was misbehaving, it would go through that location, so I set my breakpoint there, and added the following sort of code everywhere where the state variable was altered.


Firstly, the following defines went into the source file where the majority of the state transitions occured.

#define MAX_STEP_STATE 30
#define START_MOVE_FUNCTION 0x40
char stepStateMem[MAX_STEP_STATE];
char stepIndex=0;

Then, wherever the state variable (in this case, bStepState) was altered with a new state, for example, like this..

bStepState = SLEW;

I would follow it with the following two lines of code, to record not only the state that we were now in.
stepStateMem[stepIndex++]=bStepState;
if(stepIndex >= (char) MAX_STEP_STATE) stepIndex = 0;


This allowed me to see, very clearly, what the state transitions were now that they were recorded. To see them, I would wait until the breakpoint got hit, and then look at the variable 'stepIndex' and use that to look at the array stepStateMem indexed at stepIndex and work my way backwards.  The transitions were clearly showing that the state machine was being told to stop, so now I needed to find out where.  To do this, I used the upper 5 bits to record which function was being run when the state transition occured.

For example....
bStepState = RAMP_UP;
stepStateMem[stepIndex++]=bStepState|START_MOVE_FUNCTION;
if(stepIndex >= (char) MAX_STEP_STATE) stepIndex = 0;

What I found was that the state machine was being told to stop due to a peculiar timing between a flag that was raised every 100ms, and the code that ran when that flag was raised.  The code would think that the system had stalled and so was telling the motor controller state machine to stop running.  Once I knew WHERE the code was broken, finding why, and how to fix it was easy.

Happy hunting!

Richard Dorfner



Memfault Beyond the Launch
[ - ]
Comment by DeekshaJanuary 17, 2012
Hi Richard, Very useful debugging technique!Please explain a little more on how the upper 5 bits are recording the function which is running.
[ - ]
Comment by CryptomanJune 30, 2012
I also use state machines quite often. They provide a great way of debugging and developing a system from ground up. I find that defining a structure that stores all attributes of the state of an application is very useful for debugging as well. That way you know exactly where to look when things do not work as expected.

To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.

Please login (on the right) if you already have an account on this platform.

Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: