#39 State Machines Part-5: Optimal Implementation in C

Поделиться
HTML-код
  • Опубликовано: 4 окт 2024
  • This lesson continues the subject of STATE MACHINES. Today you will learn the "optimal" state machine implementation in C. You will start with designing a simple "domain-specific language" (DSL) for specifying state machines and then you will turn it into a C program. You will then generalize the implementation into a reusable "event processor" to include this optimal state machine implementation strategy directly in the Micro-C-AO active object framework that you've been building in this segment of lessons.
    This lesson includes quite a bit of coding with the intent to give you some "pair programming" experience as you witness the gradual transformation of the design into C.
    Also, you will see and compare other state machine DSL based on the SMC (State Machine Compiler).
    Finally, you will see a technique for measuring code execution speed on ARM Cortex-M CPUs by means of the Cycle Counter register in the DWT (Data Watchpoint and Trace) hardware block.
    This lesson comes with two projects:
    the "optimal" implementation of the TimeBomb state machine and the updated uC/AO active object framework.
    the implementation of the TimeBomb state machine based on the SMC (State Machine Compiler)
    -------
    Resources:
    Companion web page for this video course:
    www.state-mach...
    GitHub repository for projects for this video course:
    github.com/Qua...
    Transcript of this lesson:
    www.state-mach...
    Music credits:
    --------------
    The background music comes from:
    www.bensound.c...

Комментарии • 36

  • @StateMachineCOM
    @StateMachineCOM  2 года назад +3

    NOTE: The source code, as presented in the video, might cause compilation errors with the newer MDK-ARM / uVision toolsets. This is because the underlying compiler in MDK-ARM has been changed to "Compiler-6", while the older "Compiler-5" is considered now obsolete. The updated code that compiles cleanly with "Compiler-6" is available from the companion website at:
    www.state-machine.com/video-course
    and from GitHub:
    github.com/QuantumLeaps/modern-embedded-programming-course

  • @ManikantaRaju
    @ManikantaRaju 3 года назад +4

    Yesss! My favorite channel is back with a new video 😁

  • @zhitailiu3876
    @zhitailiu3876 3 года назад +3

    Can't wait for the next lesson!
    It's so great that we can watch how an implementation is evolved, modified and then optimized.

    • @StateMachineCOM
      @StateMachineCOM  3 года назад +11

      Thank you for noting this aspect. I put quite a bit of thought into the *way* the code evolves before your eyes. This is important, because it illustrates the way of *thinking* in programming. It is generally very difficult to convey the thought process. Big literature and poetry can do this. But in programming, we have another way: we can show the unfolding *evolution* of the code. To me, this is a new art form. That's why I enjoy to teach programming this new way. --MMS

    • @zhitailiu3876
      @zhitailiu3876 3 года назад +2

      I am so grateful for what you've done for these educational videos.
      My colleague and I usually take 2 to 3 hours to fully appreciate the content of each lesson, also make some hands-on exercises.
      And we simply can't imagine how much effort and determination it takes to fulfill this series of videos!

    • @StateMachineCOM
      @StateMachineCOM  3 года назад +6

      @@zhitailiu3876 Yes, I'm also surprised how much time it costs to make a video lesson like that. It's a lot of trial and error and iteration before the lesson flows as intended. That's why I can come up with a new lesson only so often. But, new lessons are coming and they are getting more interesting (even though more advanced). Stay tuned!

    • @ManikantaRaju
      @ManikantaRaju 3 года назад

      @@StateMachineCOM can't just wait for the hierarchical state machines lecture. 😁

    • @mauricioribeiro7630
      @mauricioribeiro7630 15 дней назад

      @@StateMachineCOM You've not just proved that this is a form of art, but also shown that you're THE Master at it. This is definitly one of the best educational series available. It has a modern (because of the contents) but still a similar fashion of teaching as the old vhs courses such as 'The Art Of Mixing (A Arte da Mixagem) - David Gibson' (ruclips.net/video/TEjOdqZFvhY/видео.html). Thank you.

  • @cwgreenley
    @cwgreenley 3 года назад +2

    Excellent as always. I'm very much looking forward to the next one about hierarchical state machines! I've dabbled with them a bit and I they seem promising.

  • @t.p.2305
    @t.p.2305 3 года назад +2

    Thanks a lot for this episode (and of course those before)!

  • @MahmoudAli-sv7fj
    @MahmoudAli-sv7fj 2 года назад +1

    Excellent as always.

  • @claudiustirbei5214
    @claudiustirbei5214 3 года назад +1

    nice and clean. very good series!

  • @mixguru9669
    @mixguru9669 3 года назад +1

    Awesome content

  • @dominicvalentino6377
    @dominicvalentino6377 3 года назад +3

    Awesome, I don't understand why so many so called "embedded engineers" use a collection of global flags for handling state.

    • @StateMachineCOM
      @StateMachineCOM  3 года назад +1

      That question is, of course, the whole motivation for state machines. But, going beyond that, I don't understand why so many "embedded engineers" still use so many inferior state machine implementations. Go figure... --MMS

  • @ramadhanafif
    @ramadhanafif 2 года назад +3

    I tried to implement the fsm object in C++ as its own class that used later as base class. Turns out it was very difficult because of pointer-to-function and pointer-to-member-function was different.
    Tried to make the state functions static so the function pointer can be independent from its class, but it prevents me to access other variable, which makes the OOP pointless...
    Any advice Mr Miro?

    • @StateMachineCOM
      @StateMachineCOM  2 года назад +2

      Yes, it's a very good observation: pointers-to-member-functions in C++ are inappropriate for an "optimal" state machine implementation because they are very different from pointers-to-functions. A good workaround is to represent a sate-handler as two functions: a static function of the class taking the "me" pointer and a regular member function. The static function calls the regular member function (via the "me->" pointer). This regular member function uses the "this" calling convention, so has natural access to all class members. It turns out that the overhead of the static function indirection layer is just one branch instruction on ARM Cortex-M. All of this is described in the QP/C++ framework documentation at: www.state-machine.com/qpcpp/group__sds__sm.html . --MMS

  • @vidaljuanp
    @vidaljuanp Год назад +1

    I'm trying to create a state machine using your example, where after the initial state uses TRAN() to move to the next state, makes a validation(if, else) in the ENTRY_SIG and uses the TRAN() to move to another state. But it doesn't work. The SM needs to receive a signal once it enters a state in order to move to another state. It seems to me that TRAN() macro cannot be used in the begining of entering a state on ENTRY_SIG. am I'm missing something here.? Thanks for this great video.

    • @StateMachineCOM
      @StateMachineCOM  Год назад

      Transitions are NOT allowed in state entry or exit actions (actions are actions, not transitions). Also, just try to *draw* your creation in a state diagram, and then you'll see that you can't. Please watch other videos in the state-machine playlist. Specifically, please see lesson-42 "Semantics Hierarchical State Machines" ruclips.net/video/NxV7JlU0-F4/видео.html ). --MMS

  • @jorgis123
    @jorgis123 7 месяцев назад

    Hello Miro,
    I was wondering if you know a good resource about using floating point variables on embedded platforms.
    In the previous lessons, I've seen the FPU appear here and there in the periphery. To me this hints that somehow using floating points or doing more serious numerical work on embedded platforms might have some quirks and pitfalls compared to "regular" systems, especially on the performance front.
    Right now it seems a bit mysterious that no floats were used in the lessons yet, and I was wondering if there was a reason for that.
    Kind regards,
    Jorgis
    P.S.: It's amazing how great the content is. I'm sooo ready to apply all the 39 lessons so far to my own project, but I am learning so much from your lessons that I'd rather finish this course instead! :)

    • @StateMachineCOM
      @StateMachineCOM  7 месяцев назад +1

      Indeed, floating point is still tricky in embedded CPUs even in this day and age. This is because to be efficient floating point computations need hardware acceleration (FPU). Without such special hardware, floating point computations are CPU intensive and slow. But even when FPU is available, it often offers only "sinble-precision" 32-bit floating point numbers (type 'float' in C). This is the FPU in Cortex-M4 and even many Cortex-M7. With a "single-precision" FPU, the usual 64-bit "double-precision" computations are still releaviely slow (although faster than without the FPU). Additionally, Cortex-M FPU comes with its own register file (32 registers), which is more complex than the Cortex-M CPU. These registers must be carefully saved and restored during interrupt procesing and, of course, inside an RTOS, if it is used. For all these resons, the use of floating point must be carefully considered, if it is even advantageous. For occasional computation requiring some fractional numbers, it is often better to use "fixed point math" (e.g., see www.embedded.com/fixed-point-math). --MMS

    • @jorgis123
      @jorgis123 7 месяцев назад

      @@StateMachineCOMI am afraid I will not be able to side-step the slow computations, as I intend to work with physical sensors and models with lots of matrix computations, such as Kalman filters and control algorithms. I guess all your lessons on how to work with time-critical systems will be very useful then!

  • @isokemisoke
    @isokemisoke 3 года назад

    Sir Samek thank you for everything firstly, we will be happy, if we have more info about code generation in QM and integrating QF into the our self BSP Files.

    • @StateMachineCOM
      @StateMachineCOM  3 года назад +4

      Automatic code generation will be discussed and QM will be used as a tool example for that. Stay tuned! --MMS

  • @zoenagy9458
    @zoenagy9458 7 месяцев назад

    What happens when states go missing (e.g. overload), how timeouts handled, what if events backing up and try to execute faster than mechanical components allow? T.T architecture is much safer, even if not most efficient.

    • @StateMachineCOM
      @StateMachineCOM  7 месяцев назад +2

      I obviously cannot provide a full and fair comparison between the event-driven and time-triggered (TT) approaches in this RUclips comment, so here are just a few remarks.
      First, in the event-driven approach, *you* control which events are posted and *you* also control how they are all handled. In particular, if you choose to post only periodic timeout events, you effectively make a TT system. In other words, the TT architecture is already included (as a special case) in the method covered by these videos. In fact, most projects discussed in the later lessons (especially lessons #43 and #44) are based on periodic timeout events, so they *are* mostly TT. Just take a look!
      And second, the problems you describe (e.g., events backing up or trying execute code faster than mechanical components allow) are the same in any system. If the TT system can handle them, so can event-driven system. Again, *you* choose which events get posted and how frequently. If your system detects that the hardware cannot keep up, you slow down posting events or do something else.
      And finally, in a TT system *you* must provide the "task lists" to the TT scheduler. This puts a lot of burden on the developers because it really is manually doing what other types of schedulers do automatically. From what I've seen, people constantly fiddle with the "task lists" to torture the system to submission. Been there, done that!
      In contrast, an event-driven system with a scheduler complying with the RMS/RMA method (see lesson #26) can be mathematically proven to meet all hard real-time deadlines. Such a scheduler does not require any additional work from the developers.

  • @arthurchow-h8t
    @arthurchow-h8t 2 года назад

    感谢作者, 用着非常好, 能否和ucos的线程同时运行. ????

  • @alex12I3
    @alex12I3 2 года назад

    Can I use this on a Raspberry Pi. I see you use systick interrupt to able to do this. Do I have to enable a timer interrupt on the raspberry pi in order to apply this state-machine concept?

    • @StateMachineCOM
      @StateMachineCOM  2 года назад

      Yes, the implementation presented in this video can be used on Raspberry PI and any other Linux computer (embedded or not). In Linux (POSIX), you don't program with interrupts directly. Instead, you can dedicate a separate p-thread (POSIX-thread) to call the TimeEvent_tick() function, sleep for a while and loop back. All of this and more is demonstrated in the video "Running QP Real-Time Frameworks and QP/Spy Software Tracing on Embedded Linux" ruclips.net/video/0AaPRMSt2jg/видео.html . --MMS

  • @patrykojewski298
    @patrykojewski298 2 года назад

    Hi,
    Could You please a bit explain me pointer function ?
    What is the difference when we call
    me->state() vs. *me->state()
    or when we assign not function address but function:
    me->state = TimeBomb_init
    not: me->state = &TimeBomb_init
    Is there any difference ?

    • @StateMachineCOM
      @StateMachineCOM  2 года назад +2

      As you notice, the C language accepts two ways of assigning and calling a function via a pointer-to-function. The two ways of assigning a pointer-to-function are: fun_ptr = my_fun; and fun_ptr = &my_fun; The two ways of calling a function via a pointer-to-function are: fun_ptr() , and: (*fun_ptr)(); All of these versions are legal and all would work. But, the syntax: fun_ptr = &my_fun; for assigning and (*fun_ptr)() for calling are much clearer as to what is going on. My recommendation is to always choose the syntax that most clearly communicates your intent, which makes it absolutely clear that I prefer the second version. I hope this makes sense. --MMS

    • @patrykojewski298
      @patrykojewski298 2 года назад

      @@StateMachineCOM Thank You for explanation. Of course clean and intuitive code is very important. That is right it is much clearer, programmer does not have to go and search in whole code, because he exactly know what is going on in that one line of code.
      Thanks a lot again for Your time and Your work !

  • @BinGanzLieb
    @BinGanzLieb Год назад

    I read that in Misra C is using function pointers not allowed. is this true and is there an implementation of state machines without function pointers?

    • @StateMachineCOM
      @StateMachineCOM  Год назад +2

      Actually, MISRA-C does not disallow function pointers (see stackoverflow.com/questions/34736006/2-out-of-3-voting-using-function-pointer-approach-for-state-machine-design ). Regarding a state machine implementation without function pointers, please see : stackoverflow.com/questions/34939379/state-machine-with-no-function-pointer . --MMS

    • @BinGanzLieb
      @BinGanzLieb Год назад

      @@StateMachineCOM Thanks for your reply. That read promising.
      I am practice your videos about state machines to apply it at my next job. It seems that I did a lot of mistakes in applying state machines

  • @ardenuf7586
    @ardenuf7586 3 года назад +1

    For those like me who are just starting to play along, you may need to download an addon pack for uVision that installs the needed Stellaris ICDI debug driver. Just google "Stellaris ICDI Debug Adapter Support".