Jump to content

n1ksn

Members
  • Content Count

    38
  • Joined

  • Last visited

  • Days Won

    2

Reputation Activity

  1. Like
    n1ksn got a reaction from tripwire in Warning - don't attempt to solder a ZIF to Launchpad   
    I've built a satellite board for the Launchpad, which has a ZIF socket. I found out the hard way (in spite of warnings in the book I was reading) that this precludes the use of a clock crystal on XIN/XOUT. I suspect that the same could be true even if the ZIF is soldered directly to the Launchpad. Of course, if you always use the internal DCO this is not a problem, but using only the DCO can restrict your low power options. Maybe it would still be OK, but the clock crystal oscillator is easily upset.
     
    My solution was to mount the MSP430 chip on the Launchpad socket when using the clock crystal, and use the satellite board ZIF socket if not using the clock crystal. However, for this to work in my set up, I had to remove the surface mount jumpers (0 ohm resistors) on the Launchpad board that connect the XIN/XOUT port pins to the outer breakout pins.
     
    Andy
  2. Like
    n1ksn got a reaction from woodgrain in A brief state machine implementation tutorial   
    In this part we'll look at a couple of header files that are included in our Led.c module. The first is the file System.h which contains some global defines for our program:

    #ifndef SYSTEM_H #define SYSTEM_H #define FALSE 0 #define TRUE 1 #define NULL 0 // Each tick approximately 15.6 ms with ACLK at 32768 Hz (1 sec = 64 ticks) #define ACLK_FREQ 32768 #define TICK_DIVISOR 512 // In this version, set to match WDT interval #define TICKS_PER_SEC (ACLK_FREQ / TICK_DIVISOR) // Port and I/O pin bitmask definitions #define LEDOUT P1OUT #define LED1_BITMASK BIT0 #define LED2_BITMASK BIT1 #define LED3_BITMASK BIT2 #define BTNIN P1IN #define BTNIE P1IE #define BTNIFG P1IFG #define BTNIES P1IES #define BTNREN P1REN #define BTNOUT P1OUT #define BTN1_BITMASK BIT3 #define BTN2_BITMASK BIT4 #define BTN3_BITMASK BIT5 typedef void( * PFN )(void); // Pointer to function (void) foo(void) void System_InitializeHW(void); #endif
    After some initial defines for boolean values and NULL we have defines associated with the system tick. Our Led.c state machine module will be using the TICKS_PER_SEC value. Note that the module System.c sets up the watchdog timer to provide a ~15.6 ms system tick by putting the WDT in an interval mode, so these defines must coincide with that interval. (If you use a regular timer for the system tick, these defines help set that up.)
     
    The next four defines give aliases for the port(s) to which the LEDs are connected, and the bitmasks for them. This particular demonstration uses a single port, but each LED could be wired to a different port in which case aliases would be need for these. These defines aren't really necessary, as we could use P1OUT, BIT0, etc. in our module, but I like to localize pin assignments in the System.h header and System.c module. Below these are similar defines for the pushbutton module.
     
    Near the bottom of the header is a typedef for a pointer to a function which is of the "void foo(void)" variety, with no arguments and no return value. The name of the defined type is PFN (for "pointer to function") and it is the only function pointer type we will use. This state machine implementation uses a function pointer of this type to indicate the current state of the state machine. If you are not comfortable with function pointers in C, you should get to know them. They are our friends.
     
    Now let's look at the header Led.h:

    #ifndef LED_H #define LED_H // Each system tick approximately 15.6 ms with ACLK at 32768 Hz (64 ticks/sec) #define LED_DEFAULT_TICKS (TICKS_PER_SEC / 2) // Default blink half period #define LED_MAX_TICKS (32 * TICKS_PER_SEC) // Max ~ 1 cycle per minute #define LED_MIN_TICKS 2 // Should be at least 2 // Called by main at start-up void Led_InitializeHW(void); void Led_InitializeApp(void); // This function is called every system tick from main to drive // software timers for the LED state machines void Led_ProcessTimerEvents(void); //------------------------------------------------------------------------------ // Variable type and values to allow client module to specify LED typedef enum { LED_1 = 0, LED_2, LED_3 } Led_Index; #define LED_MAX 3 // Must coincide with typedef above // Functions to control LEDs from client module // Put LED in steady off state void Led_TurnOff(Led_Index index); // Put LED in steady on state void Led_TurnOn(Led_Index index); // Puts LED in last steady state void Led_Steady(Led_Index index); // Puts LED in blink state void Led_Blink(Led_Index index); // Sets LED on and off tick lengths (in system ticks), // restricted to range set by LED_MAX_TICKS and LED_MIN_TICKS. // Does not change current state of LED. void Led_SetBlink(Led_Index index, uint16_t on_ticks, uint16_t off_ticks); // Resets blink period to 2 * LED_DEFAULT_TICKS with 50% duty cycle // without changing LED state. void Led_ResetBlink(Led_Index index); // Retrieves current on_tick value of LED uint16_t Led_OnTicks(Led_Index index); // Retrieves current off_tick value of LED uint16_t Led_OffTicks(Led_Index index); #endif
    Here we first have a few more defines which depend on the TICKS_PER_SEC value. They set the default value for an LED blink period and the minimum and maximum number of system ticks for how long an LED can be off or on when blinking. The minimum value is the most important, as too short an interval could cause trouble with our blink software timer. The other two are arbitrary values.
     
    The next three statements are function prototypes which appear in this header so that the main module can call them. (This header is included in the main module.) The first two prototypes are for initialization of module-specific hardware and software on startup, and the third will be called by main on each system tick to operate the LED software timers used when they are blinking.
     
    The remainder of the function prototypes are the client interface for this module. Whichever modules that need to operate the LEDs will do so through these function calls. Their names are fairly self-explanatory. In order for a client to identify which LED is to be affected, the functions have the parameter "index" which is of type Led_Index. This is a custom type set up by the typedef enum statement just above these function prototypes. It is a combination of typedef and enum that defines a variable which can only take on the values enumerated in the definition. In this case there are three LED index values, LED_1, etc. Why do this typedef instead of using a regular old integer? It is a way to have the compiler flag some programmer mistakes that would set the index to a value outside the valid range for the LED index. (I don't think it will catch runtime errors, however.) In any case, it is a nice way to remember which index value goes with which LED. A companion define sets LED_MAX to the number of LEDs in our module.
     
    That's enough for this part. Next we'll (finally) start to look at the C code in Led.c.
     
    If you have any comments or questions about any of these posts, please don't hesitate to write a reply to this thread. I'll eventually include a zip file will all the program files in it.
     
    Later,
    Andy n1ksn
     
    Added in edit: I've added another client function prototype, namely for Led_Steady. This function returns the state machine to whatever steady substate was last active.
  3. Like
    n1ksn got a reaction from obedelu in A brief state machine implementation tutorial   
    In this thread I would like to go though the pieces of code that implement a state machine to control one or more LEDs (3 in this case). It is written to be a device driver with an interface to a client module. You could argue that it is overkill for controlling LEDs, but this is intended to be an example on translating a two-level hierarchical UML statechart into C code. The complete program includes other modules, but for now I just want to concentrate on the LED state machine.
     
    First, though, why use a state machine? There are different choices for the structure of embedded software, and which one works best depends on factors like program size and complexity and ease of maintenance and modification. From most of the the books I've read on the subject (e.g., Simon's "An Embedded Software Primer"), the structures go from the simplest, a round robin with polling, to a round robin with interrupts (including some sleeping), then a task queue and scheduler, and finally a real-time operating system (RTOS). State machines, which seem to be neglected in many books, offer an alternative to task schedulers and real-time operating systems (or can be used in conjunction with them). They are a good approach when the software activity is primarily responses to stimuli from inputs.
     
    State machines allow for multiple thread operations combined with a fairly straight-forward way to translate a program specification into code. They can be implemented with large, nested switch statements, but this approach can get out of hand and be difficult to maintain. (I know this from personal experience because I took this approach a couple of years ago with a program to control a homebrew shortwave transceiver. It depended on a mess of flags and multiple switch statements and was difficult to debug.) Instead we will associate with each state a couple of C functions that perform the needed actions, parse signals to the state machine, and make the appropriate transitions.
     
    This work is an outgrowth of my study of two books. "MSP430 State Machine Programming with the ES2274" by Tom Baugh shows how to build very low power applications on the MSP430 using flat state machines. It also taught me a lot about C and MSP430 assembly instructions. "Practical UML Statecharts in C/C++" by Miro Samek shows how to use his open-source system to implement hierarchical state machines and its Chapter 2 is a crash course UML statecharts, which are part of the Unified Modeling Language (UML). The approach I will take uses a two-level hierarchical UML statechart for the specification, which I then translate into a flat state machine implemented as per Baugh. (Alternatively, one can use some of Samek's software to implement these state machines.)
     
    Here is the UML statechart specifying the state machine for the LED driver module:

    Each box with rounded corners in the diagram is a state. There are two higher level states representing two different modes of operation. Each of these "superstates" contains two substates which describe the behavior of the LED state machine for that mode of operation. The superstate ledStateSteady represents the LED being either off or on indefinately. The superstate ledStateBink represents the LED being in a blinking mode.
     
    The arrows represent transistions from one state to another caused by a "signal" to the state machine. For example, if the LED is in the steady off state, reception of the signal LED_ON_SIG causes a transition to the steady on state. As another example, if the LED is in either the steady off or steady on states and receives an LED_BLINK_SIG, it will transition to the blinking superstate. Note that some transition arrows start or end on a superstate, while others start or end on a substate.
     
    The black dots represent initial starting points. The dot at the very top shows that at start up the state machine goes to the steady superstate. When going into the steady superstate, the dot inside that state shows that initially the transition is into the off steady state. The dot inside the blink superstate shows that upon entering that superstate the state machine transitions to the blink on state. Inside the steady superstate is a dot with an "H" inside. This represents "history" and means that when there is a transition due to the signal LED_STEADY_SIG, the state machine returns to whichever steady substate was last active. (According to strict UML rules, this H dot should replace the solid dot inside the steady superstate, but I think this is confusing.)
     
    Finally, each state contains Entry and/or Exit actions which are taken upon entry to or exit from that state. For example, when the blink superstate is entered the state machine software timer (driven by the system tick) is activated to allow blinking. When the blink superstate is left the timer is deactivated. As another example, when the blink on substate is entered the LED is turned on and the timer counter is set for the number of system ticks it will be on. When the timer counts down to zero, a LED_TIMEOUT_SIG signal is sent to the state machine and a transition is made to the blink off state, where upon entry the LED is turned off and the timer counter is loaded with the number of system ticks it is to be off. One rule of UML statecharts is that as you transition out of a substate into another substate in a different superstate, you must execute the applicable entry and exit actions of the superstates (as well as the substates) as you progress up and then down the hierarchy. This simple example does not have any transitions to illustrate this.
     
    Well, that's it for this first post. Next time we'll quickly look at the "client interface" (the associated header file) and then begin building the C code to implement the LED state machine.
     
    Cheers,
    Andy n1ksn
  4. Like
    n1ksn reacted to cdch10 in Finite State Machines + code generation tool.   
    Hi every one!
    I was reading n1ksn's post "A brief state machine implementation tutorial"and I remembered that a while ago I came across with an application report from TI about Finite State Machines in the MSP430 and its implementation and also they attached a Microsoft Excel
  5. Like
    n1ksn reacted to bluehash in A brief state machine implementation tutorial   
    Of course. I'm in through the first two. Thanks for writing all this up. You have patience.
  6. Like
    n1ksn got a reaction from cdch10 in A brief state machine implementation tutorial   
    In this thread I would like to go though the pieces of code that implement a state machine to control one or more LEDs (3 in this case). It is written to be a device driver with an interface to a client module. You could argue that it is overkill for controlling LEDs, but this is intended to be an example on translating a two-level hierarchical UML statechart into C code. The complete program includes other modules, but for now I just want to concentrate on the LED state machine.
     
    First, though, why use a state machine? There are different choices for the structure of embedded software, and which one works best depends on factors like program size and complexity and ease of maintenance and modification. From most of the the books I've read on the subject (e.g., Simon's "An Embedded Software Primer"), the structures go from the simplest, a round robin with polling, to a round robin with interrupts (including some sleeping), then a task queue and scheduler, and finally a real-time operating system (RTOS). State machines, which seem to be neglected in many books, offer an alternative to task schedulers and real-time operating systems (or can be used in conjunction with them). They are a good approach when the software activity is primarily responses to stimuli from inputs.
     
    State machines allow for multiple thread operations combined with a fairly straight-forward way to translate a program specification into code. They can be implemented with large, nested switch statements, but this approach can get out of hand and be difficult to maintain. (I know this from personal experience because I took this approach a couple of years ago with a program to control a homebrew shortwave transceiver. It depended on a mess of flags and multiple switch statements and was difficult to debug.) Instead we will associate with each state a couple of C functions that perform the needed actions, parse signals to the state machine, and make the appropriate transitions.
     
    This work is an outgrowth of my study of two books. "MSP430 State Machine Programming with the ES2274" by Tom Baugh shows how to build very low power applications on the MSP430 using flat state machines. It also taught me a lot about C and MSP430 assembly instructions. "Practical UML Statecharts in C/C++" by Miro Samek shows how to use his open-source system to implement hierarchical state machines and its Chapter 2 is a crash course UML statecharts, which are part of the Unified Modeling Language (UML). The approach I will take uses a two-level hierarchical UML statechart for the specification, which I then translate into a flat state machine implemented as per Baugh. (Alternatively, one can use some of Samek's software to implement these state machines.)
     
    Here is the UML statechart specifying the state machine for the LED driver module:

    Each box with rounded corners in the diagram is a state. There are two higher level states representing two different modes of operation. Each of these "superstates" contains two substates which describe the behavior of the LED state machine for that mode of operation. The superstate ledStateSteady represents the LED being either off or on indefinately. The superstate ledStateBink represents the LED being in a blinking mode.
     
    The arrows represent transistions from one state to another caused by a "signal" to the state machine. For example, if the LED is in the steady off state, reception of the signal LED_ON_SIG causes a transition to the steady on state. As another example, if the LED is in either the steady off or steady on states and receives an LED_BLINK_SIG, it will transition to the blinking superstate. Note that some transition arrows start or end on a superstate, while others start or end on a substate.
     
    The black dots represent initial starting points. The dot at the very top shows that at start up the state machine goes to the steady superstate. When going into the steady superstate, the dot inside that state shows that initially the transition is into the off steady state. The dot inside the blink superstate shows that upon entering that superstate the state machine transitions to the blink on state. Inside the steady superstate is a dot with an "H" inside. This represents "history" and means that when there is a transition due to the signal LED_STEADY_SIG, the state machine returns to whichever steady substate was last active. (According to strict UML rules, this H dot should replace the solid dot inside the steady superstate, but I think this is confusing.)
     
    Finally, each state contains Entry and/or Exit actions which are taken upon entry to or exit from that state. For example, when the blink superstate is entered the state machine software timer (driven by the system tick) is activated to allow blinking. When the blink superstate is left the timer is deactivated. As another example, when the blink on substate is entered the LED is turned on and the timer counter is set for the number of system ticks it will be on. When the timer counts down to zero, a LED_TIMEOUT_SIG signal is sent to the state machine and a transition is made to the blink off state, where upon entry the LED is turned off and the timer counter is loaded with the number of system ticks it is to be off. One rule of UML statecharts is that as you transition out of a substate into another substate in a different superstate, you must execute the applicable entry and exit actions of the superstates (as well as the substates) as you progress up and then down the hierarchy. This simple example does not have any transitions to illustrate this.
     
    Well, that's it for this first post. Next time we'll quickly look at the "client interface" (the associated header file) and then begin building the C code to implement the LED state machine.
     
    Cheers,
    Andy n1ksn
  7. Like
    n1ksn got a reaction from bluehash in A brief state machine implementation tutorial   
    Here is the code for the main module in the complete state machine demo program. I'm including it here because the comments contain general descriptions of the the program modules and the main function is rather short.

    //------------------------------------------------------------------------------ // main.c in project StateMachineBlink6 // // The overall structure of this program follows the approach of Tom Baugh // found in "MSP430 State Machine Programming." // // The modules in this program: // // Main: General shell program for initialization and execution of the // system tick loop. Program sleeps in LPM3 when not executing a // tick. This version uses the watchdog timer to generate system // ticks, leaving TimerA free for other modules. // // System: Does general low-level hardware initialization and contains // the WDT ISR. // // MyApp: Demonstration applicaton to control the state of the LEDs // using three pushbuttons. // // Led: Driver that sets up and runs state machines that control three LEDs. // // Button: Driver that sets up and runs state machines that control // pushbutton functions, including debouncing and optional alternate // function or acceleration feature. The functions actually // executed on a push are determined by an event sink registration // function called by the client, which in this case is the // MyApp module. // // See the individual module headers for further descriptions. // // This program is written for the MSP430G2452, but should be easily changed // to other MSP430 devices with 4K or more of flash memory by modifying // the device header file include statements. Note that a clock crystal of // 32768 Hz is used to allow LPM3 sleep between ticks. Also, this program was // compiled and tested using CCS Workbench, with the compiler set to level 4 // optimiazation and minimum size. It should compile under IAR Kickstart with // no modifications. // // Andrew Palm // 2011.10.25 //------------------------------------------------------------------------------ #include #include #include "System.h" #include "Led.h" #include "Button.h" #include "MyApp.h" void InitializeHW(void); void InitializeApps(void); //------------------------------------------------------------------------------ void main(void) { WDTCTL = (WDTPW | WDTHOLD); // Disable WDT InitializeHW(); InitializeApps(); _enable_interrupts(); while(1) { // Event loop _low_power_mode_3(); // Sleep between ticks Led_ProcessTimerEvents(); // Process LED state machine timer events Button_ProcessTimerEvents(); // Process button SM timer events } } //------------------------------------------------------------------------------ void InitializeHW(void) { System_InitializeHW(); Led_InitializeHW(); Button_InitializeHW(); MyApp_InitializeHW(); } //------------------------------------------------------------------------------ void InitializeApps(void) { Led_InitializeApp(); Button_InitializeApp(); MyApp_InitializeApp(); }
    After stopping the watchdog timer the initialization functions for all the modules are called and the program enters an endless loop. The processor goes to sleep in LPM3 and is awakened by the watchdog timer ISR (the system tick). The loop contains the calls to the state machine timer functions for the LEDs and the buttons. After these are executed the processor goes back to sleep. There is also a port pin ISR in the module Button.c, but after this performs a few operations the processor goes immediately back to sleep.
     
    Basically, all the action is driven by three pushbuttons. Each button is managed by a state machine, similar to the state machines for the LEDs. These are contained in the Button module. There are a couple of differences however. First, the button state machine is "flat"--there are no superstates. Second, since for any given state there is only one signal that causes a transition out of that state, signals are not explicitly used in the code (although they appear on the UML statechart). The button state machines handle debouncing and add functionality to the buttons by implementing either an alternate function or an acceleration feature on an extended push and release in addition to the normal push and release function.
     
    Another difference in the button state machines is that the client does not control their transitions through client interface functions as is done for the LEDs. Rather, the client module, named MyApp in this demo, "registers event sinks" with the button state machines. What this comes down to is that the client module passes to the button module the addresses of functions that it wants to be executed when a button is pressed. These registrations can be static, occuring only at program startup, or they can be dynamically changed during program execution in response to different operating modes. The demo shows how this can be done. I'm sure everyone is familiar with applications where a set of panel buttons change their function when the gizmo goes into a different mode of operation.
     
    The comments at the beginning of the module MyApp explain the button functions and how they change. One button when pressed and released normally (under one second) rotates through the three LEDs. A long (over one second) push and release of this same button changes the mode of the selected LED. One mode is the steady on/off mode where the other two buttons turn the LED on and off. The other two modes are blinking modes. In one of these the other two buttons change the LED blink period up or down. In the other blinking mode the other two buttons increase and decrease the blink duty cycle. I won't go further into the demo, as the main point of these posts was to show how to code the state machines in Led.c. But you should at least look at Button.h and Button.c to understand event sink registration. (By the way, this user interface has several deficiencies, not the least of which is that the currently selected LED is not indicated. But making this better would take away from putting state machines to work in my "real" projectcs.)
     
    Attached below is a zip file with all the project code, plus jpg files containing the UML statecharts for the LEDs and the buttons. I've also included the UMLet files for these. If you decide to use this approach and want to draw statecharts, the UMLet program, which is freeware, is a nice way to go. It can be downloaded as a standalone program or an Eclipse plug-in.
     
    Unfortunately, the program compiles under CCS to over 2K, so you will need an MSP430 beyond what comes with the Launchpad. But you should be able to write a simpler demo under 2K that blinks the two Launchpad LEDs and cycles through different LED behaviours with successive pushes of the single Launchpad user pushbutton.
     
    I hope those of you that have read these posts will have found something useful.
     
    Best regards,
    Andy n1ksn
     
    StateMachineDemo.zip
  8. Like
    n1ksn got a reaction from zborgerd in A brief state machine implementation tutorial   
    In this part we'll look at a couple of header files that are included in our Led.c module. The first is the file System.h which contains some global defines for our program:

    #ifndef SYSTEM_H #define SYSTEM_H #define FALSE 0 #define TRUE 1 #define NULL 0 // Each tick approximately 15.6 ms with ACLK at 32768 Hz (1 sec = 64 ticks) #define ACLK_FREQ 32768 #define TICK_DIVISOR 512 // In this version, set to match WDT interval #define TICKS_PER_SEC (ACLK_FREQ / TICK_DIVISOR) // Port and I/O pin bitmask definitions #define LEDOUT P1OUT #define LED1_BITMASK BIT0 #define LED2_BITMASK BIT1 #define LED3_BITMASK BIT2 #define BTNIN P1IN #define BTNIE P1IE #define BTNIFG P1IFG #define BTNIES P1IES #define BTNREN P1REN #define BTNOUT P1OUT #define BTN1_BITMASK BIT3 #define BTN2_BITMASK BIT4 #define BTN3_BITMASK BIT5 typedef void( * PFN )(void); // Pointer to function (void) foo(void) void System_InitializeHW(void); #endif
    After some initial defines for boolean values and NULL we have defines associated with the system tick. Our Led.c state machine module will be using the TICKS_PER_SEC value. Note that the module System.c sets up the watchdog timer to provide a ~15.6 ms system tick by putting the WDT in an interval mode, so these defines must coincide with that interval. (If you use a regular timer for the system tick, these defines help set that up.)
     
    The next four defines give aliases for the port(s) to which the LEDs are connected, and the bitmasks for them. This particular demonstration uses a single port, but each LED could be wired to a different port in which case aliases would be need for these. These defines aren't really necessary, as we could use P1OUT, BIT0, etc. in our module, but I like to localize pin assignments in the System.h header and System.c module. Below these are similar defines for the pushbutton module.
     
    Near the bottom of the header is a typedef for a pointer to a function which is of the "void foo(void)" variety, with no arguments and no return value. The name of the defined type is PFN (for "pointer to function") and it is the only function pointer type we will use. This state machine implementation uses a function pointer of this type to indicate the current state of the state machine. If you are not comfortable with function pointers in C, you should get to know them. They are our friends.
     
    Now let's look at the header Led.h:

    #ifndef LED_H #define LED_H // Each system tick approximately 15.6 ms with ACLK at 32768 Hz (64 ticks/sec) #define LED_DEFAULT_TICKS (TICKS_PER_SEC / 2) // Default blink half period #define LED_MAX_TICKS (32 * TICKS_PER_SEC) // Max ~ 1 cycle per minute #define LED_MIN_TICKS 2 // Should be at least 2 // Called by main at start-up void Led_InitializeHW(void); void Led_InitializeApp(void); // This function is called every system tick from main to drive // software timers for the LED state machines void Led_ProcessTimerEvents(void); //------------------------------------------------------------------------------ // Variable type and values to allow client module to specify LED typedef enum { LED_1 = 0, LED_2, LED_3 } Led_Index; #define LED_MAX 3 // Must coincide with typedef above // Functions to control LEDs from client module // Put LED in steady off state void Led_TurnOff(Led_Index index); // Put LED in steady on state void Led_TurnOn(Led_Index index); // Puts LED in last steady state void Led_Steady(Led_Index index); // Puts LED in blink state void Led_Blink(Led_Index index); // Sets LED on and off tick lengths (in system ticks), // restricted to range set by LED_MAX_TICKS and LED_MIN_TICKS. // Does not change current state of LED. void Led_SetBlink(Led_Index index, uint16_t on_ticks, uint16_t off_ticks); // Resets blink period to 2 * LED_DEFAULT_TICKS with 50% duty cycle // without changing LED state. void Led_ResetBlink(Led_Index index); // Retrieves current on_tick value of LED uint16_t Led_OnTicks(Led_Index index); // Retrieves current off_tick value of LED uint16_t Led_OffTicks(Led_Index index); #endif
    Here we first have a few more defines which depend on the TICKS_PER_SEC value. They set the default value for an LED blink period and the minimum and maximum number of system ticks for how long an LED can be off or on when blinking. The minimum value is the most important, as too short an interval could cause trouble with our blink software timer. The other two are arbitrary values.
     
    The next three statements are function prototypes which appear in this header so that the main module can call them. (This header is included in the main module.) The first two prototypes are for initialization of module-specific hardware and software on startup, and the third will be called by main on each system tick to operate the LED software timers used when they are blinking.
     
    The remainder of the function prototypes are the client interface for this module. Whichever modules that need to operate the LEDs will do so through these function calls. Their names are fairly self-explanatory. In order for a client to identify which LED is to be affected, the functions have the parameter "index" which is of type Led_Index. This is a custom type set up by the typedef enum statement just above these function prototypes. It is a combination of typedef and enum that defines a variable which can only take on the values enumerated in the definition. In this case there are three LED index values, LED_1, etc. Why do this typedef instead of using a regular old integer? It is a way to have the compiler flag some programmer mistakes that would set the index to a value outside the valid range for the LED index. (I don't think it will catch runtime errors, however.) In any case, it is a nice way to remember which index value goes with which LED. A companion define sets LED_MAX to the number of LEDs in our module.
     
    That's enough for this part. Next we'll (finally) start to look at the C code in Led.c.
     
    If you have any comments or questions about any of these posts, please don't hesitate to write a reply to this thread. I'll eventually include a zip file will all the program files in it.
     
    Later,
    Andy n1ksn
     
    Added in edit: I've added another client function prototype, namely for Led_Steady. This function returns the state machine to whatever steady substate was last active.
  9. Like
    n1ksn got a reaction from zborgerd in A brief state machine implementation tutorial   
    In this thread I would like to go though the pieces of code that implement a state machine to control one or more LEDs (3 in this case). It is written to be a device driver with an interface to a client module. You could argue that it is overkill for controlling LEDs, but this is intended to be an example on translating a two-level hierarchical UML statechart into C code. The complete program includes other modules, but for now I just want to concentrate on the LED state machine.
     
    First, though, why use a state machine? There are different choices for the structure of embedded software, and which one works best depends on factors like program size and complexity and ease of maintenance and modification. From most of the the books I've read on the subject (e.g., Simon's "An Embedded Software Primer"), the structures go from the simplest, a round robin with polling, to a round robin with interrupts (including some sleeping), then a task queue and scheduler, and finally a real-time operating system (RTOS). State machines, which seem to be neglected in many books, offer an alternative to task schedulers and real-time operating systems (or can be used in conjunction with them). They are a good approach when the software activity is primarily responses to stimuli from inputs.
     
    State machines allow for multiple thread operations combined with a fairly straight-forward way to translate a program specification into code. They can be implemented with large, nested switch statements, but this approach can get out of hand and be difficult to maintain. (I know this from personal experience because I took this approach a couple of years ago with a program to control a homebrew shortwave transceiver. It depended on a mess of flags and multiple switch statements and was difficult to debug.) Instead we will associate with each state a couple of C functions that perform the needed actions, parse signals to the state machine, and make the appropriate transitions.
     
    This work is an outgrowth of my study of two books. "MSP430 State Machine Programming with the ES2274" by Tom Baugh shows how to build very low power applications on the MSP430 using flat state machines. It also taught me a lot about C and MSP430 assembly instructions. "Practical UML Statecharts in C/C++" by Miro Samek shows how to use his open-source system to implement hierarchical state machines and its Chapter 2 is a crash course UML statecharts, which are part of the Unified Modeling Language (UML). The approach I will take uses a two-level hierarchical UML statechart for the specification, which I then translate into a flat state machine implemented as per Baugh. (Alternatively, one can use some of Samek's software to implement these state machines.)
     
    Here is the UML statechart specifying the state machine for the LED driver module:

    Each box with rounded corners in the diagram is a state. There are two higher level states representing two different modes of operation. Each of these "superstates" contains two substates which describe the behavior of the LED state machine for that mode of operation. The superstate ledStateSteady represents the LED being either off or on indefinately. The superstate ledStateBink represents the LED being in a blinking mode.
     
    The arrows represent transistions from one state to another caused by a "signal" to the state machine. For example, if the LED is in the steady off state, reception of the signal LED_ON_SIG causes a transition to the steady on state. As another example, if the LED is in either the steady off or steady on states and receives an LED_BLINK_SIG, it will transition to the blinking superstate. Note that some transition arrows start or end on a superstate, while others start or end on a substate.
     
    The black dots represent initial starting points. The dot at the very top shows that at start up the state machine goes to the steady superstate. When going into the steady superstate, the dot inside that state shows that initially the transition is into the off steady state. The dot inside the blink superstate shows that upon entering that superstate the state machine transitions to the blink on state. Inside the steady superstate is a dot with an "H" inside. This represents "history" and means that when there is a transition due to the signal LED_STEADY_SIG, the state machine returns to whichever steady substate was last active. (According to strict UML rules, this H dot should replace the solid dot inside the steady superstate, but I think this is confusing.)
     
    Finally, each state contains Entry and/or Exit actions which are taken upon entry to or exit from that state. For example, when the blink superstate is entered the state machine software timer (driven by the system tick) is activated to allow blinking. When the blink superstate is left the timer is deactivated. As another example, when the blink on substate is entered the LED is turned on and the timer counter is set for the number of system ticks it will be on. When the timer counts down to zero, a LED_TIMEOUT_SIG signal is sent to the state machine and a transition is made to the blink off state, where upon entry the LED is turned off and the timer counter is loaded with the number of system ticks it is to be off. One rule of UML statecharts is that as you transition out of a substate into another substate in a different superstate, you must execute the applicable entry and exit actions of the superstates (as well as the substates) as you progress up and then down the hierarchy. This simple example does not have any transitions to illustrate this.
     
    Well, that's it for this first post. Next time we'll quickly look at the "client interface" (the associated header file) and then begin building the C code to implement the LED state machine.
     
    Cheers,
    Andy n1ksn
  10. Like
    n1ksn got a reaction from bluehash in A brief state machine implementation tutorial   
    In this thread I would like to go though the pieces of code that implement a state machine to control one or more LEDs (3 in this case). It is written to be a device driver with an interface to a client module. You could argue that it is overkill for controlling LEDs, but this is intended to be an example on translating a two-level hierarchical UML statechart into C code. The complete program includes other modules, but for now I just want to concentrate on the LED state machine.
     
    First, though, why use a state machine? There are different choices for the structure of embedded software, and which one works best depends on factors like program size and complexity and ease of maintenance and modification. From most of the the books I've read on the subject (e.g., Simon's "An Embedded Software Primer"), the structures go from the simplest, a round robin with polling, to a round robin with interrupts (including some sleeping), then a task queue and scheduler, and finally a real-time operating system (RTOS). State machines, which seem to be neglected in many books, offer an alternative to task schedulers and real-time operating systems (or can be used in conjunction with them). They are a good approach when the software activity is primarily responses to stimuli from inputs.
     
    State machines allow for multiple thread operations combined with a fairly straight-forward way to translate a program specification into code. They can be implemented with large, nested switch statements, but this approach can get out of hand and be difficult to maintain. (I know this from personal experience because I took this approach a couple of years ago with a program to control a homebrew shortwave transceiver. It depended on a mess of flags and multiple switch statements and was difficult to debug.) Instead we will associate with each state a couple of C functions that perform the needed actions, parse signals to the state machine, and make the appropriate transitions.
     
    This work is an outgrowth of my study of two books. "MSP430 State Machine Programming with the ES2274" by Tom Baugh shows how to build very low power applications on the MSP430 using flat state machines. It also taught me a lot about C and MSP430 assembly instructions. "Practical UML Statecharts in C/C++" by Miro Samek shows how to use his open-source system to implement hierarchical state machines and its Chapter 2 is a crash course UML statecharts, which are part of the Unified Modeling Language (UML). The approach I will take uses a two-level hierarchical UML statechart for the specification, which I then translate into a flat state machine implemented as per Baugh. (Alternatively, one can use some of Samek's software to implement these state machines.)
     
    Here is the UML statechart specifying the state machine for the LED driver module:

    Each box with rounded corners in the diagram is a state. There are two higher level states representing two different modes of operation. Each of these "superstates" contains two substates which describe the behavior of the LED state machine for that mode of operation. The superstate ledStateSteady represents the LED being either off or on indefinately. The superstate ledStateBink represents the LED being in a blinking mode.
     
    The arrows represent transistions from one state to another caused by a "signal" to the state machine. For example, if the LED is in the steady off state, reception of the signal LED_ON_SIG causes a transition to the steady on state. As another example, if the LED is in either the steady off or steady on states and receives an LED_BLINK_SIG, it will transition to the blinking superstate. Note that some transition arrows start or end on a superstate, while others start or end on a substate.
     
    The black dots represent initial starting points. The dot at the very top shows that at start up the state machine goes to the steady superstate. When going into the steady superstate, the dot inside that state shows that initially the transition is into the off steady state. The dot inside the blink superstate shows that upon entering that superstate the state machine transitions to the blink on state. Inside the steady superstate is a dot with an "H" inside. This represents "history" and means that when there is a transition due to the signal LED_STEADY_SIG, the state machine returns to whichever steady substate was last active. (According to strict UML rules, this H dot should replace the solid dot inside the steady superstate, but I think this is confusing.)
     
    Finally, each state contains Entry and/or Exit actions which are taken upon entry to or exit from that state. For example, when the blink superstate is entered the state machine software timer (driven by the system tick) is activated to allow blinking. When the blink superstate is left the timer is deactivated. As another example, when the blink on substate is entered the LED is turned on and the timer counter is set for the number of system ticks it will be on. When the timer counts down to zero, a LED_TIMEOUT_SIG signal is sent to the state machine and a transition is made to the blink off state, where upon entry the LED is turned off and the timer counter is loaded with the number of system ticks it is to be off. One rule of UML statecharts is that as you transition out of a substate into another substate in a different superstate, you must execute the applicable entry and exit actions of the superstates (as well as the substates) as you progress up and then down the hierarchy. This simple example does not have any transitions to illustrate this.
     
    Well, that's it for this first post. Next time we'll quickly look at the "client interface" (the associated header file) and then begin building the C code to implement the LED state machine.
     
    Cheers,
    Andy n1ksn
  11. Like
    n1ksn got a reaction from bluehash in Revised state machine demo for AVR   
    Attached is a revision of my recently posted project. I added an alternate function capability to the pushbutton code and cleaned up the state handler functions and pushbutton timer handling.
     
    Sorry for any inconvenience. I thought I was done with this, but I felt compelled to clean up the code.
     
    Andy
     
    cStateMachineBlink3.zip
  12. Like
    n1ksn got a reaction from zborgerd in Revised state machine demo for AVR   
    Attached is a revision of my recently posted project. I added an alternate function capability to the pushbutton code and cleaned up the state handler functions and pushbutton timer handling.
     
    Sorry for any inconvenience. I thought I was done with this, but I felt compelled to clean up the code.
     
    Andy
     
    cStateMachineBlink3.zip
  13. Like
    n1ksn got a reaction from zborgerd in My state machine demo program ported to AVR   
    *** Note: An updated version of this port is posted below on this thread. ***
     
    I've been posting a series of demo programs on state machines in the state machine thread started by zeke in the General forum. Yesterday I ported the latest version StateMachineBlink2 to an Atmel ATmega168 on a small custom demo board (or the STK500). I posted it as a project in AVR Freaks, but the zip file of the code is below for your convenience.
     
    The port was fairly straightforward from the MSP430G2452. There were the usual modifications going from CCS to WinAVR GCC, plus I had to complement the LED outputs since my board uses the AVR pins as sinks for the LEDs. Also, the hardware has external pushbutton pullups rather than using the internal ones. I continued to use the watchdog timer as the system tick generator, and it took a bit of digging in the device datasheet and the libc user's manual to get that set up. Also, this was the first time I used a sleep mode with an AVR, so that took some time to figure out. Finally, the biggest change was understanding how the port pin interrupt registers are organized on an AVR. In my opinion, the MSP430 does it better, or at least more naturally.
     
    The code should be OK for other AVRs with small changes to register, interrupt vector, and pin names. With -Os optimization the code was just about 2K in size, with under 100 bytes of RAM used.
     
    Later,
    Andy
     
    cStateMachineBlink2.zip
  14. Like
    n1ksn got a reaction from bluehash in My state machine demo program ported to AVR   
    *** Note: An updated version of this port is posted below on this thread. ***
     
    I've been posting a series of demo programs on state machines in the state machine thread started by zeke in the General forum. Yesterday I ported the latest version StateMachineBlink2 to an Atmel ATmega168 on a small custom demo board (or the STK500). I posted it as a project in AVR Freaks, but the zip file of the code is below for your convenience.
     
    The port was fairly straightforward from the MSP430G2452. There were the usual modifications going from CCS to WinAVR GCC, plus I had to complement the LED outputs since my board uses the AVR pins as sinks for the LEDs. Also, the hardware has external pushbutton pullups rather than using the internal ones. I continued to use the watchdog timer as the system tick generator, and it took a bit of digging in the device datasheet and the libc user's manual to get that set up. Also, this was the first time I used a sleep mode with an AVR, so that took some time to figure out. Finally, the biggest change was understanding how the port pin interrupt registers are organized on an AVR. In my opinion, the MSP430 does it better, or at least more naturally.
     
    The code should be OK for other AVRs with small changes to register, interrupt vector, and pin names. With -Os optimization the code was just about 2K in size, with under 100 bytes of RAM used.
     
    Later,
    Andy
     
    cStateMachineBlink2.zip
  15. Like
    n1ksn reacted to gordon in [ ENDED ] Aug-Sep 2011 - 43oh Project of the Month Contest   
    I seem to remember Andy (the other one ) having expressed unfamiliarity with the process, so here's a quick one for the iambic keyer, if he accepts.
     
    Supposed to fit in an Altoids tin (though I can't verify this) and mostly through-hole with generic components. Gerber files are included (using Seeed CAM rules).
     
    No warranty .
     
    Ed.: See viewtopic.php?f=32&t=1401&start=40#p11382 for the files.
  16. Like
    n1ksn got a reaction from gordon in State Machine Example Code   
    *** Note: There is an upgraded version of this code in a following post. ***
     
    This is a second state machine implementation based on material in Chapter 3 in Samek. Once again, it blinks three LEDs.
     
    In this version there is no table of state transition functions. Instead there is one "state handler function" for each state. The state handler function contains a switch statement based on the Event/Signal received. There are special switch cases for state entry and exit functions, and these are automatically executed on a state transition by the state machine dispatch function. The state handler functions return status codes, but in this version one of these is actually used (the one for transitions). The others were intended, I believe, to be used in a tracing facility.
     
    As for the previous implementation, the user adds state machine parameters or event parameters by derivation from base structures.
     
    I have made a small change in the applicaton by replacing led_is_off_ticks with led_period_ticks. This was done in anticipation of a future implementation that uses pushbuttons to modify the led blink rates. I also increased the system tick period to about 15.9 ms, since this is small enough for led flashing.
     
    Although this implementation uses a couple of funky macros and is somewhat more difficult to follow (especially the initialization steps), it is nice in that there is one state handler function for each state, and the entry and exit functions are clearly indicated. This makes for a better correspondence between code and the state diagram. Also, there is no storage needed for a state transition table which could get large and sparse in large systems.
     
    On the down side, these handler functions might get long if there are many signal types to be checked in the switch statement, and this might be a problem when things must be accomplished within a single system tick. Fortunately, the switch statement in each handler only needs to include events/signals relevant to that state.
     
    Cheers,
    Andy N1KSN
     
    StateMachineBlink.zip
     
    The C code for the primary module:
     

    //------------------------------------------------------------------------------ // Blink.c in project StateMachineBlink // // This program blinks three LEDs at different rates using state machine // functions based on the QEP FSM processor found in Chapter 3 of "Practical // UML Statecharts in C/C++" by Miro Samek. (Copyright (C) 2002-2007 Miro // Samek. All rights reserved.) // // In this implementation there is no table of state transition functions. // Instead there is one "state handler function" (SHF) for each state. Each SHF // contains a switch statement with cases based on the event signals received. // There are special cases for state entry and state exit functions, which are // automatically invoked by the state machine dispatch function when a state // transition occurs. // // There are two states in this LED blinking state machine, LED_IsOn and // LED_IsOff. // // There is only one type of user event in this state machine, a tick from a // timer interrupt ISR. Blink_ProcessEvents is called by main upon wake-up // from this ISR. // // The state handler functions in this state machine also implement a countdown // timer which determines how long that state is held. On entry the timer // counter is set for the delay interval. The counter is decremented if the // state is active and a tick event occurs. If the delay interval is not over // no state transition occurs. When the counter times out the guard condition // is met and there is a transition to the new state. // // Andrew Palm // 2011.09.30 //------------------------------------------------------------------------------ #include #include #include "System.h" #include "StateMachine.h" #include "Blink.h" // Each tick approximately 15.6 ms with ACLK at 32768 Hz (256 ticks/sec) #define LED1_PERIOD_TICKS 3*(TICKS_PER_SEC) #define LED1_IS_ON_TICKS (LED1_PERIOD_TICKS / 96) // 1/3 Hz, short duty cycle #define LED2_PERIOD_TICKS TICKS_PER_SEC #define LED2_IS_ON_TICKS (LED2_PERIOD_TICKS / 2) // 1 Hz, 50% duty cycle #define LED3_PERIOD_TICKS (TICKS_PER_SEC / 8) #define LED3_IS_ON_TICKS (LED3_PERIOD_TICKS / 4) // 8 Hz, 25% duty cycle //------------------------------------------------------------------------------ // Blink LED finite state machine enum BlinkSignals { // Signals for the Blink FSM TICK_SIG = SM_USER_SIG }; typedef struct TickEvtTag { Event super; // Derived from Event structure } TickEvt; // For this application, no additional user parameters typedef struct BlinkTag { // The Blink FSM StateMachine super; // Derived from StateTable structure uint16_t delay_ticks; // Number of delay ticks remaining uint16_t led_is_on_ticks; // Number of delay ticks for on state uint16_t led_period_ticks; // Number of ticks for flash period volatile uint8_t *led_port; // Pointer to LED port uint8_t led_bitmask; // Bit mask for LED pin uint8_t filler; } Blink; static Blink Blink_1; // Blink FSM for LED1 static Blink Blink_2; // Blink FSM for LED2 static Blink Blink_3; // Blink FSM for LED3 //------------------------------------------------------------------------------ // The "constructor" for Blink state machines void Blink_Ctor(Blink *me, uint16_t led_is_on_ticks, uint16_t led_period_ticks, uint8_t led_bitmask, volatile uint8_t *led_port); static Status Blink_Initial(Blink *me, Event const *e); // Initial trans static Status Blink_LED_IsOff(Blink *me, Event const *e); // State handler fn static Status Blink_LED_IsOn(Blink *me, Event const *e); // State handler fn //------------------------------------------------------------------------------ void Blink_Ctor(Blink *me, uint16_t led_is_on_ticks, uint16_t led_period_ticks, uint8_t led_bitmask, volatile uint8_t *led_port) { StateMachine_Ctor(&me->super, (SHF)&Blink_Initial); // Construct superclass // Set user parameters me->led_is_on_ticks = led_is_on_ticks; me->led_period_ticks = led_period_ticks; me->led_bitmask = led_bitmask; me->led_port = led_port; } //------------------------------------------------------------------------------ Status Blink_Initial(Blink *me, Event const *e) { (void)e; // Avoid unused parameter warning // Insert any additional initialization actions here that are not state // entry actions or initializations done in the constructor. return SM_TRAN(&Blink_LED_IsOn); // Transition to initial state } //------------------------------------------------------------------------------ Status Blink_LED_IsOff(Blink *me, Event const *e) { switch (e->sig) { case TICK_SIG: { me->delay_ticks--; // Decrement timer counter if(0 == me->delay_ticks) // Transition guard condition { return SM_TRAN(Blink_LED_IsOn); // Transistion to new state } return SM_HANDLED(); } // Insert any other user signal type cases here case SM_ENTRY_SIG: { *(me->led_port) &= ~(me->led_bitmask); // Turn off LED // Reload delay timer me->delay_ticks = me->led_period_ticks - me->led_is_on_ticks; return SM_HANDLED(); } case SM_EXIT_SIG: { return SM_HANDLED(); } } return SM_IGNORED(); } //------------------------------------------------------------------------------ Status Blink_LED_IsOn(Blink *me, Event const *e) { switch (e->sig) { case TICK_SIG: { me->delay_ticks--; // Decrement timer counter if(0 == me->delay_ticks) // Transition guard condition { return SM_TRAN(Blink_LED_IsOff); // Transistion to new state } return SM_HANDLED(); } // Insert any other user signal type cases here case SM_ENTRY_SIG: { *(me->led_port) |= me->led_bitmask; // Turn on LED me->delay_ticks = me->led_is_on_ticks; // Reload delay timer return SM_HANDLED(); } case SM_EXIT_SIG: { return SM_HANDLED(); } } return SM_IGNORED(); } //------------------------------------------------------------------------------ void Blink_InitializeHW(void) { TACCR0 = TICK_DIVISOR; // Prepare first interrupt } void Blink_InitializeApp(void) { Blink_Ctor(&Blink_1, LED1_IS_ON_TICKS, LED1_PERIOD_TICKS, LED1, &LEDOUTA); // Make initial transition StateMachine_Init((StateMachine *)&Blink_1, (Event *)0); Blink_Ctor(&Blink_2, LED2_IS_ON_TICKS, LED2_PERIOD_TICKS, LED2, &LEDOUTA); // Make initial transition StateMachine_Init((StateMachine *)&Blink_2, (Event *)0); Blink_Ctor(&Blink_3, LED3_IS_ON_TICKS, LED3_PERIOD_TICKS, LED3, &LEDOUTB); // Make initial transition StateMachine_Init((StateMachine *)&Blink_3, (Event *)0); } //------------------------------------------------------------------------------ void Blink_ProcessEvents(void) // Called from main after wakeup { static TickEvt tick_evt = { TICK_SIG }; // Single event type, a tick // Send tick event to each state machine StateMachine_Dispatch((StateMachine *)&Blink_1, (Event *)&tick_evt); StateMachine_Dispatch((StateMachine *)&Blink_2, (Event *)&tick_evt); StateMachine_Dispatch((StateMachine *)&Blink_3, (Event *)&tick_evt); } //------------------------------------------------------------------------------ #pragma vector=TIMER0_A0_VECTOR __interrupt void TimerA_CCR0_ISR(void) // ISR to generate regular ticks { TACCR0 += TICK_DIVISOR; // Update for next interrupt __low_power_mode_off_on_exit(); // Wake the processor }
  17. Like
    n1ksn got a reaction from bluehash in State Machine Example Code   
    Zeke, a while back we had some exchanges in your MSP430 info thread. There you showed me a link to this thread on state machines and I think you invited me to continue discussion here. So here goes...
     
    I have used the state machine approach to programming in several previous projects using giant switch statements in C or the equivalent in assembly language. (These projects were on AVR chips.)
     
    I few weeks ago I finished going through Baugh's "MSP430 State Machine Programming." This was, in my opinion, a great book to work through. I learned a lot about C and many things like bit-banging a UART, etc. The exercises were done using an MSP430F2274 on an Olimex header board stuck in a breadboard. The one down-side to Baugh's approach for me (and maybe only me) is that the state machine structures were not easy to follow. It was easy to get lost in a maze of interconnected functions.
     
    So I bought "Practical UML Statecharts in C/C++", 2nd. ed., by Miro Samek to learn about a more formal approach. This book is somewhat overwhelming, but written in a way to get you through many, many details. And the accompanying code includes a project for a small MSP430--at the very end of the book. In Chapter 3 Samek gives examples of generic approaches, the switch statement and the state transition table approaches. Before going further in the book I decided to try a programming exercise using the state transition table approach. This is it:
     
    StateTableBlink2.zip
     
    The program is written for an MSP430G2452 on my homebrew Launchpad/expansion board combo. It simply blinks three LEDs at different rates and duty cycles. (It could easily be modified for the G2211 on the Launchpad provided the Launchpad has the clock crystal installed and the third LED is eliminated from the code. One would also have to modify the #include statements for the processor header and the name of the TimerA Channel 0 ISR vector. I wrote it in C using the CCS complier, but it should be OK for the IAR compiler.)
     
    Here is the key module:

    //------------------------------------------------------------------------------ // Blink.c in project StateTableBlink2 // // This program blinks three LEDs at different rates using a common state // table framework. The state transition table contains pointers to transition // functions. The table rows are states, the table columns are events. // // The basic state table structure and functions are code copyrighted by Miro // Samek in StateTable.c and StateTable.h. The overall structure of the // program follows the approach of Tom Baugh. // // When an event occurs, the transition function in the table for that event // and the current state is executed via the StateTable_Dispatch function. // // The transition function performs the following: // - Check any transition guard conditions // - Execute any exit functions of the state being left // - Change the current state to the new state using the macro TRAN // - Execute any entry functions of the new state // // There are two states in this LED blinking state machine, LED_IsOn and // LED_IsOff. // // There is only one type of event in this state machine, a tick from a timer // interrupt ISR. Blink_ProcessEvents is called by main upon wake-up from // this ISR. // // The transition functions in this state machine also implement a countdown // timer for each state which determines how long that state is held. On // initial entry the timer counter is set for the delay interval. The counter // is decremented if the state is active and a tick event occurs. If the // delay interval is not over no state transition occurs. When the counter // times out the guard condition is met and there is a transition to the new // state. // // Alternately, the state delay timers could be decremented and the transition // guard conditions checked in Blink_ProcessEvents. This simplifies the // transition functions and gives somewhat faster execution since the // StateTable_Dispatch function is only called on delay timeouts. This // approach requires Blink_ProcessEvents to directly access state machine // variables, so could be considered less "clean." // // Andrew Palm // 2011.09.28 //------------------------------------------------------------------------------ #include #include #include "System.h" #include "StateTable.h" #include "Blink.h" // Each tick approximately 3.9 ms with ACLK at 32768 Hz (256 ticks/sec) #define LED1_IS_ON_TICKS (TICKS_PER_SEC / 32) // 1/3 Hz, short duty cycle #define LED1_IS_OFF_TICKS (95*(TICKS_PER_SEC / 32)) #define LED2_IS_ON_TICKS (TICKS_PER_SEC / 2) // 1 Hz, 50% duty cycle #define LED2_IS_OFF_TICKS (TICKS_PER_SEC / 2) #define LED3_IS_ON_TICKS (TICKS_PER_SEC / 32) // 16 Hz, 25% duty cycle #define LED3_IS_OFF_TICKS (3*(TICKS_PER_SEC / 32)) //------------------------------------------------------------------------------ // Blink LED finite state machine enum BlinkSignals { // Signals for the Blink FSM TICK_SIG, MAX_SIG // Number of signals }; enum BlinkStates { // States for the Blink FSM LED_IS_OFF_STATE, LED_IS_ON_STATE, MAX_STATE // Number of states }; typedef struct TickEvtTag { Event super; // Derived from Event structure } TickEvt; typedef struct BlinkTag { // The Blink FSM StateTable super; // Derived from StateTable structure uint16_t delay_ticks; // Number of delay ticks remaining uint16_t led_is_on_ticks; // Number of delay ticks for on state uint16_t led_is_off_ticks; // Number of delay ticks for off state volatile uint8_t *led_port; // Pointer to LED port uint8_t led_bitmask; // Bit mask for LED pin uint8_t filler; } Blink; static Blink Blink_1; // Blink FSM for LED1 static Blink Blink_2; // Blink FSM for LED2 static Blink Blink_3; // Blink FSM for LED3 //------------------------------------------------------------------------------ // The "constructor" void Blink_Ctor(Blink *me, uint16_t led_is_on_ticks, uint16_t led_is_off_ticks, uint8_t led_bitmask, volatile uint8_t *led_port); void Blink_Initial(Blink *me, Event const *e); // Initial transition void Blink_LED_IsOff_TICK(Blink *me, Event const *e); // Transition function void Blink_LED_IsOn_TICK(Blink *me, Event const *e); // Transition function // State table for all Blink state machines (moved outside constructor) static const Tran Blink_StateTable[MAX_STATE][MAX_SIG] = { { (Tran)&Blink_LED_IsOff_TICK }, { (Tran)&Blink_LED_IsOn_TICK } }; //------------------------------------------------------------------------------ void Blink_Ctor(Blink *me, uint16_t led_is_on_ticks, uint16_t led_is_off_ticks, uint8_t led_bitmask, volatile uint8_t *led_port) { StateTable_Ctor(&me->super, &Blink_StateTable[0][0], MAX_STATE, MAX_SIG, (Tran)&Blink_Initial); // Construct the superclass me->led_is_on_ticks = led_is_on_ticks; me->led_is_off_ticks = led_is_off_ticks; me->led_bitmask = led_bitmask; me->led_port = led_port; } //------------------------------------------------------------------------------ void Blink_Initial(Blink *me, Event const *e) { (void)e; // Avoid unused parameter warning // Transistion to initial state TRAN(LED_IS_ON_STATE); // New state entry actions *(me->led_port) |= me->led_bitmask; // Turn on LED me->delay_ticks = me->led_is_on_ticks; // Load delay timer } //------------------------------------------------------------------------------ void Blink_LED_IsOff_TICK(Blink *me, Event const *e) { (void)e; // Avoid unused parameter warning // This state re-entry actions me->delay_ticks--; // Decrement timer counter if(0 == me->delay_ticks) // Transition guard condition { // Transistion to new state TRAN(LED_IS_ON_STATE); // New state entry actions *(me->led_port) |= me->led_bitmask; // Turn on LED me->delay_ticks = me->led_is_on_ticks; // Reload delay timer } } //------------------------------------------------------------------------------ void Blink_LED_IsOn_TICK(Blink *me, Event const *e) { (void)e; // Avoid unused parameter warning // This state re-entry actions me->delay_ticks--; // Decrement timer counter if(0 == me->delay_ticks) // Transition guard condition { // Transistion to new state TRAN(LED_IS_OFF_STATE); // New state entry actions *(me->led_port) &= ~(me->led_bitmask); // Turn off LED me->delay_ticks = me->led_is_off_ticks; // Reload delay timer } } //------------------------------------------------------------------------------ void Blink_InitializeHW(void) { TACCR0 = TICK_DIVISOR; // Prepare first interrupt } void Blink_InitializeApp(void) { Blink_Ctor(&Blink_1, LED1_IS_ON_TICKS, LED1_IS_OFF_TICKS, LED1, &LEDOUTA); StateTable_Init((StateTable *)&Blink_1); // Make initial transition Blink_Ctor(&Blink_2, LED2_IS_ON_TICKS, LED2_IS_OFF_TICKS, LED2, &LEDOUTA); StateTable_Init((StateTable *)&Blink_2); // Make initial transition Blink_Ctor(&Blink_3, LED3_IS_ON_TICKS, LED3_IS_OFF_TICKS, LED3, &LEDOUTB); StateTable_Init((StateTable *)&Blink_3); // Make initial transition } //------------------------------------------------------------------------------ void Blink_ProcessEvents(void) // Called from main after wakeup { static TickEvt tick_evt = { TICK_SIG }; // Single event type, a tick // Send tick event to each state machine StateTable_Dispatch((StateTable *)&Blink_1, (Event *)&tick_evt); StateTable_Dispatch((StateTable *)&Blink_2, (Event *)&tick_evt); StateTable_Dispatch((StateTable *)&Blink_3, (Event *)&tick_evt); } //------------------------------------------------------------------------------ #pragma vector=TIMER0_A0_VECTOR __interrupt void TimerA_CCR0_ISR(void) // ISR to generate regular ticks { TACCR0 += TICK_DIVISOR; // Update for next interrupt __low_power_mode_off_on_exit(); // Wake the processor }
     
    The comments at the head of the Blink.c module briefly explain how the thing runs. There are only two states (on and off) and one event (tick from the ISR), but I jazzed things up a tad by making the state table structure generic for blinking an LED and setting the port and pin bit mask in the constructor. I also had the state transition functions implement the delay timers for the states. The generic state table structures and processing are in StateTable.c and StateTable.h (in the zip file with the rest of the modules). These are from Samek's book and are copyrighted.
     
    Why this "simple" exercise? Well, in fact it took some head scratching to get a clear conceptual idea of what is going on here. In this approach the states themselves are represented as rows in Blink_StateTable. The functions pointed to in the table cells are the TRANSITION ACTIONS from one state to the other, not the states. This was a key insight for me. So any particular one of these functions contains code for transition guard conditions, current state exit functions, changing the current state to the new state, and the new state entry functions. This makes the primary model here a Mealy state machine (as opposed to a Moore).
     
    In this particular case I have added code to implement a delay timer for each state within the transition functions, so when a tick event occurs but the delay is not completed, we can conceptually think of this as a loop-back transition to the current state. This requires the state table event dispatch function to be called for every ISR tick, but it is cleaner than having the event processor loop keep tabs of the timer counters internal to each LED state machine.
     
    My next step is to develop state machines for push buttons, formalizing what Baugh did in his book. These will include normal presses and long presses for acceleration. I'll see how much the program size grows with these additions. By the way, I chose the G2452 because (a) I had some on hand, ( they have a complete PORT2, and © they have plenty of code space for this messing around.
     
    Cheers,
    Andy
  18. Like
    n1ksn got a reaction from nuetron in State Machine Example Code   
    Zeke, a while back we had some exchanges in your MSP430 info thread. There you showed me a link to this thread on state machines and I think you invited me to continue discussion here. So here goes...
     
    I have used the state machine approach to programming in several previous projects using giant switch statements in C or the equivalent in assembly language. (These projects were on AVR chips.)
     
    I few weeks ago I finished going through Baugh's "MSP430 State Machine Programming." This was, in my opinion, a great book to work through. I learned a lot about C and many things like bit-banging a UART, etc. The exercises were done using an MSP430F2274 on an Olimex header board stuck in a breadboard. The one down-side to Baugh's approach for me (and maybe only me) is that the state machine structures were not easy to follow. It was easy to get lost in a maze of interconnected functions.
     
    So I bought "Practical UML Statecharts in C/C++", 2nd. ed., by Miro Samek to learn about a more formal approach. This book is somewhat overwhelming, but written in a way to get you through many, many details. And the accompanying code includes a project for a small MSP430--at the very end of the book. In Chapter 3 Samek gives examples of generic approaches, the switch statement and the state transition table approaches. Before going further in the book I decided to try a programming exercise using the state transition table approach. This is it:
     
    StateTableBlink2.zip
     
    The program is written for an MSP430G2452 on my homebrew Launchpad/expansion board combo. It simply blinks three LEDs at different rates and duty cycles. (It could easily be modified for the G2211 on the Launchpad provided the Launchpad has the clock crystal installed and the third LED is eliminated from the code. One would also have to modify the #include statements for the processor header and the name of the TimerA Channel 0 ISR vector. I wrote it in C using the CCS complier, but it should be OK for the IAR compiler.)
     
    Here is the key module:

    //------------------------------------------------------------------------------ // Blink.c in project StateTableBlink2 // // This program blinks three LEDs at different rates using a common state // table framework. The state transition table contains pointers to transition // functions. The table rows are states, the table columns are events. // // The basic state table structure and functions are code copyrighted by Miro // Samek in StateTable.c and StateTable.h. The overall structure of the // program follows the approach of Tom Baugh. // // When an event occurs, the transition function in the table for that event // and the current state is executed via the StateTable_Dispatch function. // // The transition function performs the following: // - Check any transition guard conditions // - Execute any exit functions of the state being left // - Change the current state to the new state using the macro TRAN // - Execute any entry functions of the new state // // There are two states in this LED blinking state machine, LED_IsOn and // LED_IsOff. // // There is only one type of event in this state machine, a tick from a timer // interrupt ISR. Blink_ProcessEvents is called by main upon wake-up from // this ISR. // // The transition functions in this state machine also implement a countdown // timer for each state which determines how long that state is held. On // initial entry the timer counter is set for the delay interval. The counter // is decremented if the state is active and a tick event occurs. If the // delay interval is not over no state transition occurs. When the counter // times out the guard condition is met and there is a transition to the new // state. // // Alternately, the state delay timers could be decremented and the transition // guard conditions checked in Blink_ProcessEvents. This simplifies the // transition functions and gives somewhat faster execution since the // StateTable_Dispatch function is only called on delay timeouts. This // approach requires Blink_ProcessEvents to directly access state machine // variables, so could be considered less "clean." // // Andrew Palm // 2011.09.28 //------------------------------------------------------------------------------ #include #include #include "System.h" #include "StateTable.h" #include "Blink.h" // Each tick approximately 3.9 ms with ACLK at 32768 Hz (256 ticks/sec) #define LED1_IS_ON_TICKS (TICKS_PER_SEC / 32) // 1/3 Hz, short duty cycle #define LED1_IS_OFF_TICKS (95*(TICKS_PER_SEC / 32)) #define LED2_IS_ON_TICKS (TICKS_PER_SEC / 2) // 1 Hz, 50% duty cycle #define LED2_IS_OFF_TICKS (TICKS_PER_SEC / 2) #define LED3_IS_ON_TICKS (TICKS_PER_SEC / 32) // 16 Hz, 25% duty cycle #define LED3_IS_OFF_TICKS (3*(TICKS_PER_SEC / 32)) //------------------------------------------------------------------------------ // Blink LED finite state machine enum BlinkSignals { // Signals for the Blink FSM TICK_SIG, MAX_SIG // Number of signals }; enum BlinkStates { // States for the Blink FSM LED_IS_OFF_STATE, LED_IS_ON_STATE, MAX_STATE // Number of states }; typedef struct TickEvtTag { Event super; // Derived from Event structure } TickEvt; typedef struct BlinkTag { // The Blink FSM StateTable super; // Derived from StateTable structure uint16_t delay_ticks; // Number of delay ticks remaining uint16_t led_is_on_ticks; // Number of delay ticks for on state uint16_t led_is_off_ticks; // Number of delay ticks for off state volatile uint8_t *led_port; // Pointer to LED port uint8_t led_bitmask; // Bit mask for LED pin uint8_t filler; } Blink; static Blink Blink_1; // Blink FSM for LED1 static Blink Blink_2; // Blink FSM for LED2 static Blink Blink_3; // Blink FSM for LED3 //------------------------------------------------------------------------------ // The "constructor" void Blink_Ctor(Blink *me, uint16_t led_is_on_ticks, uint16_t led_is_off_ticks, uint8_t led_bitmask, volatile uint8_t *led_port); void Blink_Initial(Blink *me, Event const *e); // Initial transition void Blink_LED_IsOff_TICK(Blink *me, Event const *e); // Transition function void Blink_LED_IsOn_TICK(Blink *me, Event const *e); // Transition function // State table for all Blink state machines (moved outside constructor) static const Tran Blink_StateTable[MAX_STATE][MAX_SIG] = { { (Tran)&Blink_LED_IsOff_TICK }, { (Tran)&Blink_LED_IsOn_TICK } }; //------------------------------------------------------------------------------ void Blink_Ctor(Blink *me, uint16_t led_is_on_ticks, uint16_t led_is_off_ticks, uint8_t led_bitmask, volatile uint8_t *led_port) { StateTable_Ctor(&me->super, &Blink_StateTable[0][0], MAX_STATE, MAX_SIG, (Tran)&Blink_Initial); // Construct the superclass me->led_is_on_ticks = led_is_on_ticks; me->led_is_off_ticks = led_is_off_ticks; me->led_bitmask = led_bitmask; me->led_port = led_port; } //------------------------------------------------------------------------------ void Blink_Initial(Blink *me, Event const *e) { (void)e; // Avoid unused parameter warning // Transistion to initial state TRAN(LED_IS_ON_STATE); // New state entry actions *(me->led_port) |= me->led_bitmask; // Turn on LED me->delay_ticks = me->led_is_on_ticks; // Load delay timer } //------------------------------------------------------------------------------ void Blink_LED_IsOff_TICK(Blink *me, Event const *e) { (void)e; // Avoid unused parameter warning // This state re-entry actions me->delay_ticks--; // Decrement timer counter if(0 == me->delay_ticks) // Transition guard condition { // Transistion to new state TRAN(LED_IS_ON_STATE); // New state entry actions *(me->led_port) |= me->led_bitmask; // Turn on LED me->delay_ticks = me->led_is_on_ticks; // Reload delay timer } } //------------------------------------------------------------------------------ void Blink_LED_IsOn_TICK(Blink *me, Event const *e) { (void)e; // Avoid unused parameter warning // This state re-entry actions me->delay_ticks--; // Decrement timer counter if(0 == me->delay_ticks) // Transition guard condition { // Transistion to new state TRAN(LED_IS_OFF_STATE); // New state entry actions *(me->led_port) &= ~(me->led_bitmask); // Turn off LED me->delay_ticks = me->led_is_off_ticks; // Reload delay timer } } //------------------------------------------------------------------------------ void Blink_InitializeHW(void) { TACCR0 = TICK_DIVISOR; // Prepare first interrupt } void Blink_InitializeApp(void) { Blink_Ctor(&Blink_1, LED1_IS_ON_TICKS, LED1_IS_OFF_TICKS, LED1, &LEDOUTA); StateTable_Init((StateTable *)&Blink_1); // Make initial transition Blink_Ctor(&Blink_2, LED2_IS_ON_TICKS, LED2_IS_OFF_TICKS, LED2, &LEDOUTA); StateTable_Init((StateTable *)&Blink_2); // Make initial transition Blink_Ctor(&Blink_3, LED3_IS_ON_TICKS, LED3_IS_OFF_TICKS, LED3, &LEDOUTB); StateTable_Init((StateTable *)&Blink_3); // Make initial transition } //------------------------------------------------------------------------------ void Blink_ProcessEvents(void) // Called from main after wakeup { static TickEvt tick_evt = { TICK_SIG }; // Single event type, a tick // Send tick event to each state machine StateTable_Dispatch((StateTable *)&Blink_1, (Event *)&tick_evt); StateTable_Dispatch((StateTable *)&Blink_2, (Event *)&tick_evt); StateTable_Dispatch((StateTable *)&Blink_3, (Event *)&tick_evt); } //------------------------------------------------------------------------------ #pragma vector=TIMER0_A0_VECTOR __interrupt void TimerA_CCR0_ISR(void) // ISR to generate regular ticks { TACCR0 += TICK_DIVISOR; // Update for next interrupt __low_power_mode_off_on_exit(); // Wake the processor }
     
    The comments at the head of the Blink.c module briefly explain how the thing runs. There are only two states (on and off) and one event (tick from the ISR), but I jazzed things up a tad by making the state table structure generic for blinking an LED and setting the port and pin bit mask in the constructor. I also had the state transition functions implement the delay timers for the states. The generic state table structures and processing are in StateTable.c and StateTable.h (in the zip file with the rest of the modules). These are from Samek's book and are copyrighted.
     
    Why this "simple" exercise? Well, in fact it took some head scratching to get a clear conceptual idea of what is going on here. In this approach the states themselves are represented as rows in Blink_StateTable. The functions pointed to in the table cells are the TRANSITION ACTIONS from one state to the other, not the states. This was a key insight for me. So any particular one of these functions contains code for transition guard conditions, current state exit functions, changing the current state to the new state, and the new state entry functions. This makes the primary model here a Mealy state machine (as opposed to a Moore).
     
    In this particular case I have added code to implement a delay timer for each state within the transition functions, so when a tick event occurs but the delay is not completed, we can conceptually think of this as a loop-back transition to the current state. This requires the state table event dispatch function to be called for every ISR tick, but it is cleaner than having the event processor loop keep tabs of the timer counters internal to each LED state machine.
     
    My next step is to develop state machines for push buttons, formalizing what Baugh did in his book. These will include normal presses and long presses for acceleration. I'll see how much the program size grows with these additions. By the way, I chose the G2452 because (a) I had some on hand, ( they have a complete PORT2, and © they have plenty of code space for this messing around.
     
    Cheers,
    Andy
  19. Like
    n1ksn reacted to cde in Why MSP430?   
    Not 50 cents, but 1 dollar each in a 5 pack.
    http://www.ebay.com/itm/5x-SOP28-SO28-S ... 3451wt_822
     
    Dipmicro has some nice ones http://www.dipmicro.com/store/PCB-SSOP-DIP28 but are currently out of stock.
    So maybe not 50 cents, but 1 dollar is cheap enough. And probably cheaper if you go for 10 or 15 at a time. Ebay, cheap crap allday every day.
  20. Like
    n1ksn reacted to zborgerd in Why MSP430?   
    It's always a matter of using the right tool for the job. I like AVR 8 because it is popular in the hobbyist community, and there is a lot of code out there for cool projects. I like MSP430 because development hardware is cheap and practically free in a lot of cases. Software is free if you can get around the size limitations or use GCC (as I do). And it's becoming more popular all the time, especially as TI aggressively offers such ludicrous deals on hardware.
     
    The problem with the CCS size-limited release is that you cannot compile the example programs that come with most of the demo hardware; The MSP-EXP430F5529, for instance, and I even the EZ430-Chronos software is too large (which is why I use OpenChronos with GCC). To be fair though, the F5529 board has a 16K limited demo that allows you to enable / disable features pretty easily.
     
    CCS is fine for LaunchPad, but that's it. If you begin to get more serious about it, and want to use the more powerful chips, you're going to have to bite the bullet at some point and pay in some form or another; Either for CCS or the time involved in switching to GCC.
     
    It's also worth being prepared to at least plan to try GCC. But if you are planning to stick to just the Launchpad, then you will have no issues. No G-Series Value Line chips exceed 16KB anyway.
     
    Regardless, you are right that no hobbyist can stick to just one platform. That's part of being a hacker / maker; Always learning new stuff.
  21. Like
    n1ksn reacted to cde in Why MSP430?   
    TSOP packaged chips are relatively easy to solder and cheap to get adapters for. Like 50 cents a board at most.
  22. Like
    n1ksn reacted to zborgerd in Why MSP430?   
    I use both the AVR and MSP430.
     
    There are a few things to consider:
     
    1. It's been long-rumored that the DIP-based AVRs are in short supply (I don't know if this means that they are being phased-out or not). This is evident by the fact that stock of DIP Arduino boards is often very low, and an SMD variation has become more common. MSP430, on the other hand, has new DIP-based parts (especially the value line) all of the time.
     
    2. GCC isn't really just for Linux / UNIX. It's just most common there because it's largely written on Linux systems and there are few alternatives when it comes to compiling code for a device. If you are serious about avoiding the licensing cost of IAR or CCS, it's certainly worth considering. But I understand that people have difficulty in compiling it from the source. I have found that code written in IAR or CCS can be easily modified for mspgcc (in a lot of cases, it's a matter of just changing interrupt routines and tracking down a handful of small differences). It's my understanding that the header files are pretty much identical, so that's why the code is relatively interchangable between compilers. The ASM is the same regardless of the IDE. At least, I've never worked on a chip where the ASM that was written on a Windows machine with a manufacturers assembler was any different with GNU tools on Linux. But that's just been my experience. The ASM is determined by the manufacturer. A mnemonic is going to do what it's designed to do.
     
    3. Some people get away plugging GCC into Eclipse. I've tried it and didn't really have any issues other than the fact that I don't like large IDEs. But if you need to go the cheap / free route, you can use mspgcc with Eclipse. Even TI has indicated that they are trying to make CCS 5.1 as close to stock-Eclipse as they can get it, so I don't know that there is any substantial advantage in using future versions of CCS. If price is not an issue, just use IAR or CCS. But if you are going with a DIP model, you are more than likely going to use a value-line chip and then the size limits aren't even really much of an issue.
     
    4. Consider the memory limitations of MSP430. If you have a large application that might need external memory, then the AVR might be a better choice due to the external memory bus. But I am generally of the opinion that both an AVR or MSP430 are wrong for any application that really requires this (though some people disagree).
  23. Like
    n1ksn reacted to zeke in Why MSP430?   
    And, if you're concerned about a custom pcb then consider this: there are some eager folks right here that would design you a circuit board in short order ie: me.
     
    You may think you're an old guy but you're not. When you turn 80 then I'll let you call yourself old
  24. Like
    n1ksn reacted to bluehash in Why MSP430?   
    Thats a well detailed post. For a little background, I have programmed Microchips, TI C2000 DSPs, ADI Blackfins, Stellaris LM3S series, the MSP430s and a host of others - so I'm not biased to anyone(although I love the Stellaris :thumbup:). They are all good in their own areas.
     
    I have a few questions first:
    -
    Why would the instruction set(assembly) of the MSP430 be different on IAR and CCS. Are they really that different?
     
    -
    You can now get 10 PCBs for $10 from SEEED Fusion service and Itead. Many of our members here have used them with no problems. If you are worried about footprints or rather even launchpad footprints, they are readily available in this Forum. If not, I understand-DIP packages have their advantages.
     
    - What kind of programs/projects would you be running on these controllers(MSP/AVR). They have their limits.
     
    The following will help in your decision:
    - Controller should have required peripherals that you need( UART/SPI/ADC/CAP)
    - Controller should have enough RAM/Flash. If you need to control something like an OLED(small), you need at least 1kb RAM.
    - Good tools - meaning compilers, debuggers and IDEs
    - Quality of debugger - number of breakpoints, watch views, speed.
    - Good support. Both at the Manufacturer and Online community.
    - Easily upgradable/inexpensive to higher series with current tools.
    - Your current knowledge on the controller.
  25. Like
    n1ksn reacted to zeke in Best information for those new to the MSP430?   
    You are so right about Tom Baugh's MSP430 State Machine Programming. I bought it at the same time as Davies' book.
     
    I used the state machine approach to design and to code on a recent contract. The beauty is that I could complete a paper code design and know at once that it would work. After fixing two cut and paste errors, I had my code running bug free immediately.
     
    So, I'm a big fan of state machine style programming. I even started a thread on how to design a state machine over here. I haven't finished it just yet due to work commitments but I'll get to it eventually.
×
×
  • Create New...