|
Radix-2 up counter modulo 1572 plan Y |
Solving FSM in C (large number of states)
1. Specifications | Planning | Dev. & test | Prototype | report |
Implement a FSM using C language (plan Y, large number of states)
How can we save a large number of states in a FSM? If there are too many states or too many state transitions, the FSM cannot be enumerated or it is impractical to do it, thus, let us organise the architecture as in chapter 2 plan Y, where var_current_state is defined as std_logic_vector signal. The equivalent this time is to use a RAM variable type int (short, long, etc. depending on the number of bits required). A char or uint8_t variable can hold up to 256 states. An int or uint16_t variable can hold up to 65536 states. A 32-bit double int or or uint32_t variable can hold 4.294.967.296 states (this is for instance counting seconds for 135 years!). Therefore, try to imagine how a real-time calendar chip such as DS1307 may be organised and build using a mC considering concepts from L7.3 chaining counters.
To demonstrate how a sequential circuit can be implemented using a microcontroller PIC18F46K22 and IDE tools (Microchip MPLABX, XC8), let us implement a large counter such as Counter_mod_1572 using plan Y. Fig. 1 represents the symbol and functional table using our naming conventions, which are the same one studied in Counter_mod1572. Full rec.
In a first design step the basic counter can be implemented as shown in Fig.1.
![]() |
|
Fig. 1. Symbol (Visio) of the chip functionality. As usual, we can click a button to input CLK edges or instead, connect an oscillator. Let us this time to drive the counter with CLK's falling edges. |
Additionally, because you know now that this is only the beginning, in a second design step, parallel inputs or reversibility can be added as a new feature for this binary counter.
On the other hand, as an additional complementary exercise, you can even imagine the circuit using plan C2 and counter_mod16 as components adapted to mC and C language.
Your great advantage now: FSM foundations are already studied in P7, and thus, solving it using a different technology based n microcontrollers, is not going to change its conceptualisation in any way. Indeed, from the point of view of engineering, we will have the chance to compare circuit realisations for the same entity (power consumption, speed, component list, flexibility to implement modifications, etc.).
Draw an example of timing diagram as in Fig. 2. Deduce how many states the system may include.
![]() |
Fig. 2. Example of timing diagram directly inherited from Counter_mod1572 and adapted to μC using interrupts to detect falling CLK edges. The polling function read_inputs() for capturing the CE_L level can be executed continuously in the main loop or only when there is an INT0 detection. Which option would be better? |
Specifications | 2. Planning | Dev. & test | Prototype | report |
Let us organise the plan as usual taking large counters from P7 plan Y as reference.
Draw the circuit's state diagram as proposed in Fig. 3.
![]() |
Fig. 3. Example of state diagram adaptation. Every state transition depends on the detection of the CLK active edge by means of the interrupt service routine. Signals are transformed into RAM variables. As in the previous project, all state transitions are effective only when var_CLK_flag is asserted, thus INT0 interrupts must be enabled all the time (INT0IE = 1, GIE = 1) from init_system(). When there is no interrupt detection (var_CLK_flag = 0), the system is doing nothing but wasting time looping the main program. |
The electronic circuit is represented in Fig. 4. Port pins like RA4 and RB0 are connected to inputs. Other 12 pins are outputs to show the counter's current value and terminal count. We can make this pin assignment compatible with the CSD_PICstick board.
![]() |
Fig. 4. Hardware used in this application. The idea is to connect the CLK signal to an external interrupt pin (INT0) that has the specific circuitry to detect an active edge (configured falling) and set the hardware interrupt flag (INT0IF). |
This unit explains the key concept of external interrupt for detecting edges.
The general idea is represented in Fig. 5. The concepts of CC1 and CC2 combinational circuits inherited from Chapter 2 are the same, however this time, we will implement these logics using software routines.
![]() |
Fig. 5. Software organisation used in this application. Because var_current_state is saved in a memory position and updated every main loop cycle, there is no need of var_next_state variable as it was the case in Chapter 2 to drive the FSM's state register. |
The idea of designing a chapter 2 synchronous circuit is not so clear now. On the one hand, the microcontroller (a general purpose processor) is a synchronous device where the external OSC generates the necessary signals to synchronise all the architecture operations; on the other hand, the application, this time an 11-bit binary sequential counter, requires the detection of an external interrupt to be updated (CLK), and, to attend an interrupt there is an overhead of some OSC periods (in the range of some μs). Therefore, think and discuss about it.
Furthermore, when polling (why not sampling?) CE_L values there is also a problem related to the general loop: the more assembly instructions to execute the larger the loop and slower is going to be the polling frequency to read inputs. A higher OSC frequency implies shorter instruction execution times, and thus, a larger polling frequency.
Fig. 6 below shows a clearer flowchart representation of the software organization. What signals to read? what signals to be connected to external interrupts? While running in the infinite loop, any time that an INT0IF is detected the system jumps to attend the interrupt routine for a few μs. In this way, state diagram transitions can be reassessed.
![]() |
|
Fig. 6. General interrupt-driven FSM-style program organisation. |
In Fig. 7 there is an example of software-hardware diagram. Another advantage of this organisation is that software functions output_logic() and state_logic() are completely compatible among platforms and programming languages. Only hardware-dependent functions (drivers) have to be rewritten when changing microcontrollers or programming environments.
![]() |
Fig. 7. Hardware-software diagram. Hardware interface functions are drawn in blue and software functions based on RAM memory in black. The picture also shows the circuit and the associated configuration bits for allowing the external interrupt INT0 to detect CLK's falling edges. |
All the main RAM variables to handle the FSM are represented in Fig. 8. Pay attention that var_Q (and this time also var_current_state) is 11-bit wide, thus a convenient type is int or uint16_t (16-bit wide). All the other variables are kept char or uint8_t type to be able to watch them easily in our simulation and debugging tools.
![]() |
Fig. 8. RAM variables list. |
Draw the main ideas of init_system(). Configure input and output pins. Consider as well interrupt configuration bits to allow INT0.
![]() |
Fig. 9. TRIS configuration bits. |
Draw the flowchart of read_inputs(). Basic function to poll input voltages as in L9.3.
Draw the flowchart of write_outputs(). Basic function write pins voltages as in L9.4.
Infer how to organise the interrupt service routine ISR() to handle CLK's falling edge detections.
![]() |
Fig. 10. Interrupt service routine for setting var_CLK_flag. |
Draw state_logic() truth table. And now, it is necessary to discuss how to transfer all the state transitions into a truth table. This time a convenient behavioural interpretation using the "+" arithmetic operator makes it very easy.
![]() |
Fig. 11. Truth table for state_logic() function and its equivalent behavioural flowchart using arithmetic operators that are included in C language by default. |
Draw output_logic() truth table. This plan Y has the advantage that sequential binary code outputs are simply a copy of the internal state. And the var_TC1572 is deduced with the same logic expressed in Fig. 1.
![]() |
Fig. 12. Truth table output_logic() and its behavioural interpretation. |
Project location:
C:\CSD\P10\Counter_mod1572\(files)
|
Optional. When the project is complete and running make the counter reversible using the control signal UD_L.
Optional. When the project is complete and running, add the parallel load (LD) feature as another design step. Consider the number of port pins required. What to do when an application requires a large number of pins?
Specifications | Planning | 3. Dev. & 4. test | Prototype | report |
The following Fig. 13 is an example on how to capture the schematic in Fig .4 in Proteus. A single pole double throw (SPDT) switch is used for selecting between to types of CLK signals.
![]() |
Fig. 13. Capturing the schematic in Proteus. |
Example circuit: "Counter_mod1572.pdsprj". In Fig. 14 there is an example of I/O ports connections.
![]() |
Fig. 14. Example of I/O. To assign mC pins we can use the CSD_PICstick LED and buttons, and add more LED using the 40-bin extension cable. |
Run the IDE and start a new project in the corresponding folder for the target microcontroller PIC18F46K22. The C source file "Counter_mod1572.c". Add the "config.h" header to your project to fix the mC configuration bits.
Compile, generate COF and HEX output configuration files. Attach the COF file to Microchip PIC18F46K22 Proteus microcontroller.
Check the number of resources used: the size of the program, the number of memory bytes (RAM).
Run Proteus and test the circuit using step by step, break points and the watch window tools. Remember that the key strategy is to write a few lines of code at a time, compile, run and test. And only whet it works, add some more code after having translated truth tables and algorithms into flow charts.
![]() |
Fig. 15. System running and watching variables for debugging purposes. |
Measure the main loop execution speed using breakpoints considering (a) 4 MHz and (b) 16 MHz crystal main oscillator.
![]() |
Fig. 16. Measuring how long does it take to execute the main loop using time elapsed between breakpoints. |
As shown in Fig. 17, try to capture and represent circuit waveforms using the Proteus logic analyser, a similar instrument to the VB8012 to be used in the next prototyping section in the laboratory with the CSD_PICstick board.
![]() a) ![]() b) |
Fig. 17. a) Example on how to capture the TC1572 pulsed signal using the logic analyser. b) The printed and commented waveform for your report customising printer colours. Bus probes are convenient for capturing long vector signals like Q(10..0). |
This is the full project "Counter_mod1572.zip".
Specifications | Planning | Dev. & Test | 5. Prototype | Report |
Board CSD_PICstick. Target microcontroller: PIC18F46K22. Tools: MPLAB X + XC8 + Proteus MPLAB SNAP in-circuit debugger/programmer.
Experiment #1: Run the application and visualise results using the board resources. This is for checking the installation of the tools and programming environment.
Modify the circuit to count up to 133 (TC134) to use visualise only Q(7..0) on the LED bar. Download and program the target chip (*.hex). Play and verify that it works as expected and in the same way it did in Proteus.
When experimenting with the CLK push-button, is there a problem of signal bouncing when clicking and releasing? What may be the cause? How to solve it?
Experiment #2: Download and program the target chip (*.elf) to use the in-circuit debugger. Watch RAM variables in MPLABX IDE. Add breakpoints and follow the program execution as we did in Proteus.
Experiment #3: Drive and visualise digital signals using instruments. The VB8012 (or Analog Discovery 2) waveforms generator may be used to drive the CLK (INT0) signal. Outputs can be visualised using the logic analyser channels.
![]() ![]() |
Fig. 18. Connecting the logic analyser probes to to the CSD_PICstick. The application Waveforms allows controlling the logic analyser and the Wavegen to drive the CLK signal. |
![]() |
Fig. 18. Measured waveforms using the VB8012 compact instrument. We trigger the capture using the TC1572 pulse. |
We can as well measure the propagation delay from the CLK's falling edge to the slowest output to be set.
![]() |
Fig. 19. Circuit propagation delay from CLK to output. |
- How to reduce such delay? Which may be the maximum frequency of operation?
- How this mC realisation compares with to the same circuit Counter_mod1572 as a Chapter 2 P7 counter application?
Specifications | Planning | Dev. & Test | Prototype | 6. Report |
Project report: sheets of paper, scanned figures, file listings, notes or any other resources. Follow this rubric for writing reports. The main idea here is to explain correctly that you have developed and tested the circuit step by step running concurrently the MPLABX IDE and Proteus watching variables and step mode.