Embedded - 401: Oil and Water

Episode Date: February 4, 2022

Miro Samek joins us to discuss designing systems, state machines, and teaching courses. Miro’s company is Quantum Leaps (state-machine.com) which provides commercial licensing for QP Real-Time Embed...ded Frameworks.  It is an open source project, the code can be found on github: github.com/QuantumLeaps/qpc  One of the key concepts is an Active Object which aids in real-time system development, especially in the areas of state machines and concurrency.  Miro’s (amazing) Modern Embedded System Programming series can be found on his YouTube channel.  You can also find Miro on Twitter: @mirosamek

Transcript
Discussion (0)
Starting point is 00:00:00 Welcome to Embedded. I am Elysia White, here with Christopher White. We are happy to welcome Miro Zemeck back to the show. Hi, Miro. Hi, thank you for inviting me back. Could you tell us about yourself as if we met at an embedded systems conference? Yeah, thank you for inviting me again to your show. I've been developing embedded real-time software for almost three decades now.
Starting point is 00:00:38 And I started with programming nuclear physics experiments. And later on, I worked for GE Medical Systems, where I worked on diagnostics x-rays machines. Then I moved on to Silicon Valley, where I worked for a couple of companies working in GPS technologies. But around 2005, I founded my own company, which represents my main interest, which is modern embedded programming.
Starting point is 00:01:15 I also wrote a couple of books about it, about practical aspects of using UML state machines, UML state charts, and event-driven active objects in the context of deeply embedded systems such as microcontrollers. So are you ready for a lightning round where we ask you short questions and we want short answers, and if we're behaving ourselves, we won't ask how and why and all of that? Sure, please go ahead. Do you like to complete one project or start a dozen? Complete one project. True or false?
Starting point is 00:01:43 Most embedded systems are either primarily state machines or continuous monitoring devices, or some combination of the two. But usually more one than the other. That's a long question. It really was a lot of hedging there, wasn't it? Yeah, yes, I would agree, by and large. What else is there? What's a favorite course that you took in your academic career?
Starting point is 00:02:07 Well, you know, I studied physics. So they grilled us on math a lot, analysis and geometry. I think maybe quantum mechanics was interesting. Yeah, I took that too. Pretty cool. Do you have a preferred way to learn new technical things? For example, reading the manual, watching videos, or trying it out without reading the docs? Oh, that's difficult.
Starting point is 00:02:32 I certainly read first, but then I experiment on my own. I'm a hands-on person, so I need to experiment. We might have asked you this one last time, in which case I'm interested to know if the answer changed, but I have to go check.
Starting point is 00:02:47 Favorite fictional robot? I think that I watched recently Terminator 2 again. And so T-100, Arnold, I think it's the top of my list now. Do you have a tip everyone should know? Yeah, well, I would say that in embedded systems, nothing works until everything works. Oh, I thought that was going to be a much shorter sentence. You're going to stop with nothing works? After the last couple of weeks, I would stop there, yes.
Starting point is 00:03:21 Actually, could you expand on that? Nothing works until everything works. Well, we need to always start with a working system and only make small incremental steps to keep it working at all times. Very often, for instance, users of my software take the software and immediately want to go
Starting point is 00:03:48 to their own board and their own example that interests them. Instead of starting with a set of tested examples that are provided as well. So I would recommend just buy a very inexpensive board,
Starting point is 00:04:07 even though it's not exactly your target, and try those examples first, as is, without changing anything. You already would be testing many things, the software, the compiler, everything around it, the connectivity, and then you everything around it, the connectivity, and then you can only make very small incremental steps from there. I didn't do quite exactly that thing, but that's what I did kind of starting with a new client this month
Starting point is 00:04:35 is they had a particular target, and I got some dev boards that were similar and got familiar with the IDE, which I'd never used. And I just got the examples from the vendor and tried a bunch of them and made sure everything worked and got familiar with the IDE, which I'd never used. And I just got the examples from the vendor and tried a bunch of them and make sure everything worked and got familiar with things. And it made it a lot easier when I finally did import the client software and start building it.
Starting point is 00:04:55 Yeah, absolutely. It builds the confidence that the stuff works, first of all. And then people take two large steps. And in order to move fast, you have to take baby steps, really small steps. If you take one bigger step, you will waste a lot of time trying to find out why things don't work anymore. And taking smaller steps actually ends up that you will be moving faster. I feel like this relates to when I read recipes online, where you'll read a cookie recipe and they'll say, I replaced the sugar for honey and it didn't work at all. And it's just, yes, I see that a lot with embedded systems as well, that you have to run what they said to run first and then make the changes. Right.
Starting point is 00:05:51 There's a million ways it can go wrong and only a few ways for this to go right. So probability points to the way of doing this. You have a YouTube series teaching embedded systems programming, teaching modern embedded systems programming. What's the modern there for? I call, well, first of all, what I define as modern, everything invented past mid-1980s, I call modern. Because what I observe is that most of the, and the other stuff I call traditional, that the traditional approach is still the dominating, absolutely dominating approach in our field. So we probably didn't really take, learned many lessons past mid-1980s, I would say. Which is a sad state of affairs here. But that's why I call it modern.
Starting point is 00:06:49 I'm trying to point out interesting and important developments that happened in the 90s and maybe early 2000s. But even if you apply more modern techniques, we're still stuck with a lot of old stuff, like I squared C and SPI aren't going anywhere anywhere and they're from pre-Pac-Man era. Right. Pre-Pac-Man era. Thanks. That's a nice line in the sand.
Starting point is 00:07:13 Okay. So, I mean, we've gotten past assembly. Yeah. Yes. So the whole premise of this course is I see it as a missing curriculum because our discipline falls, as you know, somewhere between EE, electrical engineering, and CS, computer science. And yet our field is distinct and different from both of those. And not many universities actually teach this middle ground.
Starting point is 00:07:47 So there is, of course, a need, but also an opportunity to fill the gap and to teach this part. Do you think that we will be seeing more embedded systems curriculum going forward? Or do you think it will always be you learned half of your your education in embedded systems in school and the other half you just have to pick up on the job i i don't really know what's in on the mind of of universities and and schools that teach this um some schools do some schools do and and are probably specializing in producing embedded
Starting point is 00:08:27 engineers but not too many right now I mean it's certainly better than when we went to school because we basically
Starting point is 00:08:34 got C++ and or Java a little bit after us and then if you wanted any embedded there was a microprocessors course in the engineering
Starting point is 00:08:41 department right yes yes of course. And now there are far more robotics teams and other hands-on interdisciplinary clubs. Right. But they often start with Arduino and maker platforms like this. And for instance, in my course,
Starting point is 00:09:01 I deliberately didn't choose Arduino for the reasons that we probably will discuss later. But it is geared towards newcomers to the field and makers and hobbies, but not so much to professional embedded developers that will then later go into the industry and develop production level code. It's not for professional? I would say that Arduino isn't meant for that. Sorry, I thought you were talking about your course and I was like, I think maybe? Yeah, so that's why we have this, I'm talking to what Christopher just said, that there is no easier. Yes, and we have maker platforms like Arduino, which didn't exist a few years back. But they are not necessarily geared towards professionals.
Starting point is 00:09:56 Fair enough. I mean, I wrote a blog post about not using Arduino. I think it was called, don't use Arduino for professional work. So you're right on there. Yeah, so I think we're in strong agreement on that. And now, and I'm teaching a course too, which is totally different from yours, and it's been a little
Starting point is 00:10:16 hard to convince people that you can't take a project that is based in the Arduino IDE into an interview and talk about it and expect, even if you put a lot of work into it, you can't expect them to take it as seriously as if you just used a compiler, GCC, IAR, Kyle, anything other than Arduino IDE.
Starting point is 00:10:43 Right. You end up using, you end up showing a lot of code in your videos. Right. And you're compiling for the Teva platform. Is that right? Actually, maybe I should let you tell. What platform are you compiling with and what tools are you using? Yeah.
Starting point is 00:11:09 So please remember that the video course started back in 2013, right? So it's a while back. And so back then I chose Tiva C launchpad board for quite the, and the choice was quite deliberate. I had the whole list of features that the board should support. First of all, I wanted it to be based on the modern ARM Cortex-N processor, as opposed, for instance, AVR or something older. Second, I wanted to have a debugger, a real debugger interface, built into the board.
Starting point is 00:11:42 I wanted to have a few LEDs and a few switches on the board. I want to have accessible pins because in later lessons I used logic analyzers, so I wanted to easily connect to the board. I wanted to have a virtual COM port.
Starting point is 00:12:00 Right now I don't make much use of it, but in the future I will talk about concepts like software tracing and testing on the target. So this will be very useful. And I wanted this to be available for a long time. And so far, Tiva is still available, can be bought almost everywhere from DigiKey and other vendors. And last but not least, it had to be quite inexpensive. So it retailed for some $12.99 or something like this.
Starting point is 00:12:34 And this is important because many people who participate in the course come not necessarily from the U.S. or the European Union, but from countries like the Middle East, South America, India, China. And for them, it would be a problem if the border would be too expensive. So that's why I chose Tiva. If I had the choice right now, I would probably go with STM32 Nucleo, although Nucleos don't have enough LEDs for me. There are some discovery boards that have rings of LEDs now.
Starting point is 00:13:13 Right. These are nice. But some discoveries didn't have virtual comport. I was quite, you know, this was an important feature for me. What did you choose? Yeah, I ended up, Cortex-M was all I limited it to. Right. So you don't specify beyond that.
Starting point is 00:13:36 I recommend strongly that they use an STM32 and a discovery board. And I gave them a list of things that they could use. And that has worked out well for me because I have cohorts and they go through together and then they talk about their boards and they end up with more information than I could possibly give them. STM is a good choice right now.
Starting point is 00:13:59 So your class has been going on since 2013, you said? And you have, was it 60, 80? It was a lot. You have a lot of courses, a lot of videos. Over 40 now, 43 or something. Have you planned out what you're going to teach when? Yeah, well, I drew a chart, a dependency chart, if you want. So which subject depends on which other subject.
Starting point is 00:14:27 And so I wanted to start from the beginning to kind of establish the terminology and common understanding of things. But then, you know, it took me eight years to get to my favorite subject, which is state machine. So that's why I had to talk about things like RTOS much
Starting point is 00:14:49 earlier than that because, so you see that I see RTOS a little bit lower level than hierarchical state machines and active objects. So yeah, so the dependency, what depends on what, and what I have to talk about
Starting point is 00:15:04 first and can then build upon it. This determines my order of presentation. How did you choose your theory of order? I mean, some things you do have to explain earlier, but did you base it on your book or just how you wish you had been presented the material? I wanted to end up with something like Active Object Framework. And so I worked backwards, so to speak, working which concepts need to be presented to get to that point. And so, for instance, at some point, I had to talk about object-oriented programming because it's a framework based on classes
Starting point is 00:15:49 and instances and inheritance and polymorphism. So I needed to cover those concepts. I needed to talk about real-time and scheduling and real-time issues and something like rate monotonic scheduling analysis had to be, mutual exclusion blocking had to be covered before that. Of course, the interrupts and race conditions have to be covered even earlier than that. So that's why, you know, I worked backwards.
Starting point is 00:16:19 So only now I'm slowly getting where I wanted to end up. It looks like you're finally to state machines, which is one of the things that I think you really enjoy talking about. Yes, I find this subject a little bit hard to explain because I see a lot of misconceptions. And the subject is complex because there are so many kinds of state machines even. And there is no single terminology to even name them. For instance, I talked at some point about input-driven state machines and contrast them with event-driven state machines. Now, input-driven state machines is something that I just found in the literature, but some people call it periodic state machines or even some other names.
Starting point is 00:17:15 But the point is that they are not exactly the same, and they cannot be translated into UOML state charts later on. They are not quite compatible. So that's why surgical state machines take eight lessons, and probably it's not the end of the story yet. It was odd for me to see that you had eight lessons on state machines and four lessons on RTOSs. And to me, those are opposite levels of complexity.
Starting point is 00:17:44 Why, I guess. Yeah, well, exactly because RTOS is maybe more crisply understood concept. You know, of course, you have to start with the definition, what you consider RTOS. Some people consider RTOS the whole software. It's the kernel, it's the file system, it's the communication stacks, and so on and so forth. So I like and I prefer to use as narrow as possible meaning of the word. So for me, RTOSas is the Arthas kernel only. This allows me to be more precise when I talk about things,
Starting point is 00:18:31 not to put too much meaning into one word. So for instance, when I narrow it down that way, Arthas could be explained in about six or seven 30-minute lessons. Of course, I didn't cover in detail the communication mechanisms within the RTOS, but it was precise enough for my purposes. Interestingly, things that many people will consider tricky, like context switch, could be explained within maybe first two lessons. Actually, only second lesson showed how to automate context switch in assembly.
Starting point is 00:19:23 But things like semaphores, mutexes, and other communication mechanisms could not be explained that quickly at all. This is where the complexity of the RTOS is, and many people don't appreciate it. In order to use those mechanisms correctly, you have to be quite versed, and these mechanisms are also very tricky to use correctly. Because of concurrency or other reasons? Yeah, well, I think that the biggest problem with Inartos is the issue of blocking. And this is the root of many problems in Inartos. So, of course, you can have race conditions and there are mechanisms to prevent them, such as mutual exclusion mechanisms, such as mutex, for instance. But then you introduce additional blocking, potentially,
Starting point is 00:20:09 and this, of course, interferes with your real-time response. For instance, I saw on your show, it was an interesting episode, 3.3.5 I have here, patching on the surface of Mars with Joel Sherrill, I guess. He talked about Artem's open source, Arthas. And he talked, among others, he talked about HICAP in the real-time response, where a highest priority task that normally took one millisecond to execute, all of a sudden started to execute in 17 milliseconds or something like this, or of magnitude worse.
Starting point is 00:20:46 And in the same episode, he explained the rate-monotonic scheduling and this method of handling real-time responses. And then the problem is immediately apparent for me that RTOS, even though has been designed specifically to enable real-time monitoring scheduling, for instance, at the same time, because of those interactions and mutual exclusion mechanisms, defeats the purpose right there. Because sometimes you have a completely unresponsive system
Starting point is 00:21:21 that apparently doesn't meet any real-time deadlines. Yeah, I think that's an interesting point, because I think of mutexes and semaphores and all those things as fairly simple concepts, but most of the places I've used them haven't been in places where preserving a real-time response was super critical. They were using mutexes to, you know, keep things from clobbering other things, make sure things were happening in the right order. But adding the additional requirements
Starting point is 00:21:53 of not having those things get in the way of your real-time response just makes things a lot more complex for figuring out how to architect your system. And they're not great tools for that, like you said, because they're blocking. Right. Rate-monitoring scheduling, for instance,
Starting point is 00:22:06 does not take into account mutual exclusion. And if you want to, really, then you would have to take the worst possible case and count this towards the CPU utilization, a central concept
Starting point is 00:22:22 in rate-monotonic scheduling. And then what you will end up doing is that most systems wouldn't be schedulable, meaning that they will have no chance of meeting the deadlines always. This would work for soft real-time systems, but for hard real-time systems, it is unacceptable. So should we ditch all the real-time operating systems and just use state machines? No, no, no. That is exactly the point that I introduced a real-time operating system and had to do this because it's a stepping stone in understanding active objects and hierarchical state machines, the event-driven state machines that work with active objects. So what active objects are, there's actually a design pattern that prescribes how to use an RTOS, if you will, safely.
Starting point is 00:23:16 So there are just simply restrictions on the naked threads on top of the R2 threads, that when those best practices are implemented, you'll have a chance to build a correct system much better than without them. So first of all, you should avoid any sharing of resources among threads. Any sharing of resources among threads, but you can communicate between threads. I could pass something. Right. Now, the second thing is, in order to communicate, you have to designate special objects for that. Gotcha.
Starting point is 00:23:52 And these are called events or messages. And they are specifically designed for communication only. And they are exchanged between those threads in a thread-safe manner. And it is kind of a component that is on top of the RTOS. Some RTOSes, many RTOSes, for instance, provide message queues. So message queues could be used to exchange those events safely between those tasks. And so this means that you should prefer asynchronous communications
Starting point is 00:24:26 by means of those events. By asynchronous, I mean that you just post an event with a queue, but you don't wait for the handling of this event for the processing. And then the third thing is that you should structure all your threads around event loop, meaning that there will be just one single point of blocking within an endless Y1 loop in each thread or each task at the top of the loop. And then when an event arrives,
Starting point is 00:24:59 this blocking call unblocks, and then event is processed in the application-level code. So some application-level code is called to handle this event. The event has to be handled without any further blocking, and then you quickly return back to the event loop. It's funny that you're using the TI board because this is a pattern I see a lot in the TI code, especially their BLE subsystems, that every thread really is its own little kingdom, and it spends most of its time waiting, and then it doesn't do any waiting until it gets back to waiting for whatever happens. So there's no, oh, I received some data, I'm going to print it out the serial port and wait for that to be done. No, no, oh, I received some data, I'm going to print it out the serial
Starting point is 00:25:46 port and wait for that to be done. No, no, no, no. If you receive the data, you can print it out the serial port, but you can't wait. You have to go back to your single point of waiting. Right. It's funny because my first, when I started my career, I started in networking protocols. And this was how all code was written, because networking protocols work this way. You're passing messages between separate devices, and you're receiving messages, and then you see what kind of message it is, and that's an event. And then you have this loop that handles it, and then you handle it, and you get out, and that's how everything was architected. And so when I did other things, that seemed like a natural way to do it, but I don't see a lot of people using this pattern that often, day-to-day anymore. Yeah, so there are, of course, many dangers now with programming.
Starting point is 00:26:36 I mean, many pitfalls that you potentially can fall into when you start doing this. So first of all, Ardus provides a whole assortment of mechanisms, all of them based on blocking. And so it is very tempting, for instance, in your event handler, in the code that is supposed to handle an event very quickly in return, to call something like a small delay or blocking delay.
Starting point is 00:27:03 Or you have a situation where you send some information, for instance, a packet through I2C port, but then you expect some reply. So what you do is you wait in line for the reply. So this obviously holds the whole event loop processing and you are becoming unresponsive to any new events that start accumulating in your event queue and can actually overflow it.
Starting point is 00:27:32 So this would actually derail the whole mechanism. The point is, though, that RTOS provides so many of those mechanisms and when you buy an RTOS, you pay mostly for those mechanisms. And each one of them is actually something that should be avoided. So you're paying for the things you shouldn't use. You shouldn't use. Are you familiar with any of the free RTOSes? Free RTOS or Zephyr or I think there was a MicroCOS one that was out.
Starting point is 00:28:09 Yeah. For instance, the QP frameworks are ported to all of those that you mentioned. To FreeRTOS, to MicroCOS, to ThreadX, to Emboss from Seger. And, of course, to POSIX that QP can run on top of Linux and other POSIX compliant RTOCIF. So yes, I am familiar. The QP framework, that is what your company actually makes and that's what you sell. Right. That's right. And how is that related to active objects?
Starting point is 00:28:40 Well, this is an active object framework. So it provides active objects as first class items in the framework. So there is an active object class from which you can derive your own class and specialize. There is strong support for hierarchical state machines. So the behavior of your active object is specified as a state machine. So there is, of course, support for events and thread-safe event passing. You can pass the events directly from one active object to other active object or from ISR to active object. But there is also the publish-subscribe event delivery
Starting point is 00:29:22 where you can publish an event and all subscribers will receive, the event will be multicast to all those subscribers and delivered in a thread-safe way again. There is support for dynamic events with parameters that can be mutable events that are then allocated from thread-safe and deterministic event pools. And then the whole event recycling is handled automatically in the framework.
Starting point is 00:29:52 And there are many other things that the framework supports also. But to some extent, it's about keeping things, I don't want to say clean, because that's not really the right word, keeping the objects separated as an architectural thing, not as a last-minute, just naked RTOS, just for instance, free RTOS, then you have all those mechanisms, event flags and message queue and so on and so forth, time delay. But they are not very useful, as I said. Maybe they are even harmful. On the other hand, you don't have events. You don't have publish, subscribe, and other thread-safe mechanisms for delivering those events, because the events don't exist in the first place. You don't have any support for state machines, or let alone hierarchical state machines.
Starting point is 00:31:00 So what you end up doing is you have to build all those mechanisms on top of the RTOS. And instead of everyone doing this on their own, I'm just thinking all of those things are completely reusable. And so you can think of this as just the extension of an RTOS. The most important thing that differs between framework and there's a difference between framework and RTOS, is that a framework works by inversion of control. So when you use a framework, you write the code that the framework will call. So you will write, for instance, a state machine code
Starting point is 00:31:39 that it will be called by the framework when the event is available. This is in contrast to writing threads in the real-time operating system where you write the whole body of, so every single time you start with Y1 loop and you choose which blocking mechanism you will use in this particular thread or task. So the inversion of control is just a defining characteristic of the framework versus a library like an RTOS. But you did say that it works on top of an RTOS. Right. Okay.
Starting point is 00:32:15 Because those state machines, they need to be scheduled. course you could you could use very simple mechanisms that would for instance execute everyone every such state machine to completion and then look what is the next active object that has some events in their event queue and maybe choose the highest priority one and then execute this one in such a cooperative non non-preemptive way. This is one way of doing this. But it is also possible to combine the whole approach with a preemptive kernel. And in that case, the active object, for instance, one active object can be running very long run-to-completion step.
Starting point is 00:33:01 For instance, in a GPS receiver, a position fix is a floating point calculation iterative that takes a few hundred milliseconds to complete on a small ARM processor. In the meantime, you have to track the GPS signals every few hundred microseconds, really, that fast. So you need to, in this case, you could use a preemptive kernel to do the signal processing at much higher priority
Starting point is 00:33:27 every single time preempting a very long run-to-completion step. And this run-to-completion step then will eventually complete. And everything is fine because there will be no processing of for instance next event still in the middle of processing the first one. So this will be all fine from the perspective of a state machine but you will be able to meet hard real-time deadline in a high priority thread.
Starting point is 00:34:00 And this system is, by the way, much more compatible with rate-monotony scheduling because exactly you don't have situations where you share something through mutexes or something like that. And you don't extend artificially your CPU utilization. So the whole method works much easier and cleaner. It's much easier to analyze such a system. You don't spend a lot of time talking about your framework on the videos I saw from your YouTube channel on modern embedded systems programming.
Starting point is 00:34:36 Well, that's right, but it is coming more and more, and it's already kind of being used. I smuggle it piece by piece, so to speak. For instance, in the lesson of RTOS, on RTOS, I've used not free RTOS. At the very beginning, maybe I used micro-COS or something like that. But at some point, I switched to the kernel built into the framework because the framework comes with a selection of a few real-time kernels. And one of them is called QXK, has been used in the last few lessons where I exactly demonstrate hard real-time behavior of an RTOS and using illustrations with logic analyzer traces.
Starting point is 00:35:18 I show, for instance, priority inversions and how to remedy them with priority ceiling protocol and so on. So, yes, the framework is being increasingly used. In the lessons for state machines, I used it, for instance, to demonstrate the semantics of hierarchical state machines, how events are, what actions exactly are triggered by events in a hierarchical state machine, in which order the exit actions and entry actions are handled, and so on. And this was already using the framework. Okay. Clearly, I skipped around. But you have more than 40 lessons at like 30 to 40 minutes each that start with interrupts and getting started.
Starting point is 00:36:10 But I didn't get any commercials on YouTube. And I wasn't even using Christopher's account. This is a lot of work. I mean, this is a lot, a lot of work. Yes. This is a lot of work. I mean, this is a lot, a lot of work. Yes, and because you do something similar, I know that you have an idea how much. Well, that is because the revenue of the company is not coming through this. The company survives on the revenue from selling commercial licenses to QP frameworks. So QP frameworks are available under open source license, but this is GPL, so it has the strings attached,
Starting point is 00:36:52 meaning that if you use GPL framework, you are obligated to publish your application level code as well. And it would be very easy for companies to publish the code, create a free GitHub account and put the code out there. But actually, most companies don't want to do this. They prefer to pay money and buy a commercial license which frees them from the obligation of GPL. And so this is how Quantum Leaps makes money.
Starting point is 00:37:29 And the YouTube course is just one of many channels of promoting this to the developer community. I feel it's as good a channel of promoting QP as the Embedded Podcast is a channel for promoting logical elegance, which is to say, you don't do a lot of promotion, do you? That's right. Well, you are doing the exact similar thing, I suppose. You just educate and you teach, in a sense. And that is what small companies can do. We can out-teach the competition, so to speak. For some reason, big companies like Wind River will not teach for free, but we do. It's nice. I mean, I totally agree. And clearly, because we're doing similar things.
Starting point is 00:38:28 But it is weird that it's the smaller companies who tend to want to reach out more. And the larger companies are going to instead make it all about their company or make you pay for lessons. It's odd. Talk about an inversion of how things should be. Right. I never understood, for instance, the policy of microchip, that they were still selling professional or higher optimized versions of compilers for their PIC processors. They make money by selling tons and tons of chipsets,
Starting point is 00:39:07 chips out there. And they should be giving the best possible compiler in the hands of the developers and not charge, you know... For them, these are really pennies. I never understood their policy. But I think that in bigger companies, everything is about return on investment. And they have to have some demonstrated value immediately available.
Starting point is 00:39:32 If they don't see it, they don't do it. I don't really, as a small company, I don't really know what my return on investment will be. I have only sense that it is worth doing. And because I think with the small companies, the return on investment may not be cash. We don't necessarily do everything by revenue. We can have our return on investment be satisfaction and people telling us thank you and that sort of thing. Right. Yeah. And people, for instance, when I mentioned that there is a need to fill the missing curriculum, if you will, for embedded developers, that is also an opportunity to exactly provide this for them.
Starting point is 00:40:18 And if you do, you will earn their trust and that you know something about that, that you helped them, and then they are more likely to use your product. Yes, you too were influenced by, if you build it, they will come. I understand that. Okay, so back to the videos. How much of what you do is pre-written versus how much is done on the fly? Everything is pre-written for me. I actually write down my script. First of all, I start with a code. If I don't have a good idea what kind of code I will present, I don't have a lesson yet.
Starting point is 00:40:58 So I think a lot about the code. I experiment. You'll be surprised how difficult it is, for instance, to show failures. For instance, stack overflow or race condition or some other failure. So I experiment what is possible. Then I write down the script, and then I edit it down. Well, I remember one thing, a story somebody told me that Blaise Pascal,
Starting point is 00:41:29 that was this French mathematician from the day, he started one of his letters like this. I apologize that the letter is so long, but I didn't have the time to make it shorter. So I do take the time to shorten my original script. And so in the end, just so people maybe understand, I figure that is about an hour of my time for every minute of the video. So a 30-minute video will cost me about 30 minutes of time. 30 hours.
Starting point is 00:42:04 30 hours, sorry. Sorry, sorry. Yes. You know, this includes writing the code, preparing the diagrams that I show, the editing, and so on. Does that make it hard for you to go to conferences that won't pay you and be okay with putting together a conference talk, knowing how long it takes you to present things? Well, again, I see it as if it was easy, then anybody could do it. So if it is hard, and I chose to do this the harder way,
Starting point is 00:42:42 people appreciate triple notice. I had some comments that some people wrote to me that this is the only... They watch my videos at 1x speed, and this is probably one of the only few that actually they don't speed up the videos. That is a real compliment. I take it as a compliment, right?
Starting point is 00:43:06 You show a lot of code in your lessons. How much time do you think people spend writing code versus reading other people's code? Well, I think that code is read much more than it is written. So it has to be legible. It has to be nice and elegant. But speaking of writing the code, I don't think... Well, I still, for instance, try to write as much code as I only can. And I take pride in this.
Starting point is 00:43:51 This is an important part of my day. As opposed to many companies now outsource it to the least bidder or somewhere. And the code is not the highest possible quality. So I would just say, pay attention how you write your code and then this will pay off in every possible way. This is the most valuable part that you can contribute to your company. I agree with you. And I must have gotten my question wrong because I wanted to know for people who are learning, they often jump into wanting to write code, which is fun. Writing code is fun, but they often don't want to read other people's code.
Starting point is 00:44:46 And so you put a lot of code on the screen, and I appreciate that because it encourages them to read it. But do you think outside that screen time, people are becoming accustomed to reading code instead of just starting to type? Yeah, well, just like any literature, you have to read a lot before you start writing. So that's why I would say people new to the field should read a lot of good code and choose wisely which one they consider good, elegant code, and then emulate that. Any recommendations for good and elegant code? I somehow think it's not going to be the Linux kernel. Probably not.
Starting point is 00:45:30 You're trying to get emails? Yeah, that's why, for instance, books like Jean Labrosse's MicroCOS, they were a very good source of elegant code. I would, and I might be biased, I would recommend QP, which is also open source and developed on GitHub, to read that. So there is good code, well-explained code out there. I agree.
Starting point is 00:45:58 I usually suggest Adafruit's code as a very nicely put together system where you understand you're implementing a lot of different features. It's still code that maybe isn't quite as optimized as it could be but if you are thinking about a system where you need to implement 10 different sensors
Starting point is 00:46:27 and you want one interface, that's the code to look at. Because they've thought about that. Yeah. Well, someone said, I think that Donald Knuth was, that premature optimization is the source of all evil. So yes, I would agree that overly optimized code is obscure and not as clear as it could be. And we should probably put
Starting point is 00:46:50 clarity of the code above the absolute last byte of memory and absolute last CPU cycle. Especially with our processors now. They're big enough, they're fast enough. We don't need to optimize. And when you do need to optimize, start with what the compiler wants to do.
Starting point is 00:47:09 Unless you're on a pick, in which case you don't want to pay for that. I have some listener questions. One is from Simon, and he asks, What mistakes slash problems can I avoid building into my system by properly using state machines? What are the easiest ways to use state machines improperly, and how can I avoid falling into those traps? So if you start using state machines, and by that I mean event-driven state machines, in which you generate events externally to the state machine, and then you send those events to the state machine for processing.
Starting point is 00:47:52 So if you use, if you mean those state machines, then if you start using them in the context of active objects, and by active object, we talked about it, it is the set of those three best practices that they encapsulate. So if you start using those, you can avoid a lot of problems. You will not have to deal with race conditions, because if you don't share things that can lead to race conditions, you are safe with them. You will be sharing only events that are guaranteed to be delivered thread-safe from the source to the destination. So no race conditions, you are safe with them. You will be sharing only events that are guaranteed to be delivered thread-safe from the source to the destination.
Starting point is 00:48:28 So no race conditions, no mutual exclusions mechanism. You won't need to even know what the mutex is. You will also be able to meet your hard real-time deadlines much easier and
Starting point is 00:48:43 apply RMS, rate monitoring scheduling method, for instance, to mathematically prove that you will meet your hard real-time deadlines always. It will be also easier to reason about your system because every event will be processed to completion as opposed to have some convoluted path through your code. And also, if you start using state machines, you will avoid a lot of spaghetti code. We talked about spaghetti in my last time at this podcast. So now, what are the easiest ways to use state machines improperly?
Starting point is 00:49:29 The improper use of state machine would be if you would start mixing event-driven paradigm with sequential paradigm, by which I mean if you start putting blocking calls inside your state machines. So for instance, if there's an action of your state machine, you will call it delay, time delay function, or you would call a blocking semaphore or something like that.
Starting point is 00:49:56 Don't do that. So you will be better off not to use state machine at all than to put a blocking call inside your state machine. So my point here is that please don't always realize what kind of paradigm you are using in which thread. You can mix those. You should never mix them
Starting point is 00:50:16 within one thread. You can make a hybrid system so one thread could be completely event-driven and the other thread could be sequential. That would be all right. But don't mix them in one thread could be completely event-driven, and the other thread could be sequential. That would be all right. But don't mix them in one thread of execution.
Starting point is 00:50:29 And so always realize which one paradigm you are using and stick to it. Don't mix them. They don't mix. It's like oil and water. This is why we need names for them. And we need agreed, we need shared names for them so that when you look at somebody else's code, you're like, oh, you're mixing the interrupt or event-driven state machines
Starting point is 00:50:54 with the sequential state machines, and you shouldn't do that. So let's separate those things out. Not only this, when you are using state machines, you need to realize that, oh, I am using an event-driven state machine here, or that is a case that I'm using an input-driven state machine. Input-driven state machine would be quite easy. They are quite easy to recognize because each state starts with the if statement, in which you test some global variables.
Starting point is 00:51:29 In UML nomenclature, this would be called a guard condition. It's a fancy name for if and else. So if every case in your state machine starts with an if, this is an input-driven state machine. It is not an event-driven state machine. So it is all fine, but I'm just suggesting that you recognize which type of state machine you are dealing with and then stick with that. Don't mix those either. Okay. Keep separate event driven, interrupt, and sequential. Okay. Doug G. asks about using QP on multi-core, multi-processor systems.
Starting point is 00:52:10 Have you done it? How did it go? And any interesting notes? Well, as I mentioned, QP has been ported to RTOSs and, among others, to POSIX. So if, for instance, you use it on top of embedded Linux and this embedded Linux runs on a multicore, then QP is running on multicore. But that is mostly transparent to the programmer, the symmetric multiprocessing typically, and you don't really do anything special.
Starting point is 00:52:41 I have not used QP yet on a small multi-core. Now we have chips that have for instance a small M0, Cortex-M0 and then M7 or something like this. I have not used them in such systems yet. I have however used QP on distributed systems, meaning that there was two microcontrollers talking to each other over a serial port. And it turns out that the Active Object model is very suitable for this because it is kind of like a thin wire communication through events only and nothing is being shared, which is suitable for just serializing those events and sending them over the network
Starting point is 00:53:31 or over the serial connection in this case, and then deserializing them on the other end. And actually, if you use so-called communication proxy design pattern, then you can have a proxy active object that actually does not do the processing, but just only sends events back and forth between those two processes. However, this active object looks to other active objects
Starting point is 00:53:55 in the same address space as the real thing they don't know, that they are posting events to an active object that actually lives in some other address space in the processor. So what I'm trying to say is that the active object model is very suitable for distributed systems and will be probably also quite suitable for multi-core. But I have not made that experience quite yet. You've mentioned hierarchical state machines. Can you give an example of what that is? It happens often in the state machine design that you have several states that need to handle this given event in the same way.
Starting point is 00:54:46 However, in a normal classical flat state machines without any hierarchy, because they react to some other events in a different way, you will have to put them in a separate state and then replicate the same responses, the same transitions in all those states. So this, of course, inflicts repetition, and that's why normal finite state machines, the traditional ones, tend to explode. In the 1980s, David Harrell came up with a more advanced version, which he called state charts. Later on, they were adopted into UML and sometimes also called hierarchical state machines. And this is the mechanism that you can now put states within states.
Starting point is 00:55:35 And those states that are nested within a bigger state, they inherit, so to speak, the behavior from the super state. So now you can have this common transition or common reaction to events coded only at the level of the higher level state. And all states that nest within, if they don't prescribe how to handle this event, this event will not be forgotten or dropped on the floor. It will be propagated to the high-level state and handled there. And so in that case, you will have a mechanism of overriding this event, if you like, so the substate can prescribe how to handle this event on its own, and it will be the case of overriding a virtual function.
Starting point is 00:56:23 Or if it ignores it, it will be handled in a common way by the super state. And that way you can reuse the behavior. And so you avoid the repetition. And that's why those hierarchical state machines, they don't no longer explode as your problem grows in complexity. I tend to like really hands-on examples. So I'm going to try to give one, and if I'm wrong, you can tell me. So I have a toy, and it talks, blah, blah, blah, play with me. And if I hit the volume button, it has a click, you know,
Starting point is 00:57:00 high click or low click, depending on which way I put the volume. But if I hit a different button, the A button, it goes into a different thing. It starts talking about the letter A. And in the letter A, if I hit the volume button, it still gives me the same clicks. But if I was in an old-timey, traditional finite state machine, the A state would have to point to a volume that then would have to point back to an A state. So it'd be a volume that was in the A state and only belonged to that.
Starting point is 00:57:33 But with hierarchical, I can say, look, if anybody presses the volume, you're going to play the click sound. And if you don't want that to happen, you have to replace it with something else. Yeah, that is a good model here. Yes, that would be a good application of state hierarchy, right? I tend to use toys for all of my state hierarchy because children's toys have so much state in them. And it's easier for me to think about, okay, well, how does that apply here?
Starting point is 00:58:09 Let's see. Oh, I saw a new book from the Raspberry Pi Foundation about teaching computer science called Hello World. Have you seen that? No, no, I haven't. Okay, well, then I won't ask you questions about it. You can. But someday someone is going to say yes, and I'll ask them questions, although it may be somebody I invite from the author list.
Starting point is 00:58:33 Because teaching embedded systems and computer science, it's different than teaching just about everything else. Do you agree with that? Well, I have not taught anything else, so it's difficult to make comparisons. I think that in my course, I focus on fundamental concepts, such as object-oriented programming and event-driven programming and RTOS and real-time and state machines and active objects. So that's why I believe that fundamental concepts, it is always good to understand those deeply.
Starting point is 00:59:16 And if you do go and show people how they work at the lower level, they tend to understand it better and deeper and then use this more efficiently. So this is my approach that I take. In my education as a physicist, we had actually a course for teaching physics, and I taught physics at the level of middle school, and I always tried to show them experiments, and I believe that showing
Starting point is 00:59:45 and demonstrating things to people is very effective to teach them I totally agree I have one more listener question from I don't remember your first name how would you pronounce that, Christopher? Which one?
Starting point is 01:00:09 M-C-N... M-C-E-N... Some kind of a handle. I'm going to go with Kevin, because I don't remember. I should, but I don't. who made a really wonderful joke about, are city machines less complex than state machines? It is Kevin. It is Kevin, okay.
Starting point is 01:00:39 How far can we, or should we, push concurrency on bare metal through state machines before it really makes sense to move to an RTOS? Well, Kevin, probably at this point meant the input-driven state machines that combine event discovery with event processing. So this is, again, the situation that you start every case in your state machine for every state with an if statement, which is supposed to test your inputs
Starting point is 01:01:15 and find out if an interesting change in those inputs has occurred that you need to handle. So you discover your events, and then you try to handle them. The point is that because it's a non-blocking process, so if there is nothing interesting to do, you don't block, you very quickly return or you just pass through that code. You can string such state machines
Starting point is 01:01:40 and put them one after the other in the forever super loop, right, in the foreground-background system. So in this sense, people think of FSMs, of finite state machines, as a mechanism that handles some kind of concurrency before they switch to an RTOS. With event-driven state machines, the situation is different, and they are actually at the higher level of abstraction than RTOS itself. So they build on top of the RTOS. So how far should you go, push concurrency before it makes sense to use Muftun and RTOS? I would say don't use a naked RTOS at all. Use RTOS only with those three best practices of concurrency.
Starting point is 01:02:28 That means use the RTOS only as an active object, as a vehicle to partition your problems into encapsulated threads called active objects. And then you can use event-driven state machines inside each of those threads. So this is kind of like an inversion of the question, because Kevin apparently puts an artist at the higher level than state machines, and I'm saying this is only because he probably thinks of input-driven state machines. Otherwise, I recommend to use active object design patterns with event-driven state machines on top of the RTOS. So go beyond the RTOS with that, not somewhere below the RTOS.
Starting point is 01:03:20 I would add that we've already talked about mixing the types of state machines is bad. And so an RTOS gives you a way to mix the types of state machines without it being bad because it limits their scope between them. So if you have a sequential state machine and an input-driven state machine, you need an RTOS so that they don't fight? Well, actually, RTOS limits your choice because you're no longer typically in an RTOS unless you do a periodic, you know, you sleep for a tick and then you start checking for your inputs. Then you could possibly use an input-driven state machine. Otherwise, RTOS prefers probably event-driven state machine
Starting point is 01:04:08 because the tasks can block on the empty event queues. And RTOS needs blocking because during the blocking time in one thread, progress can be made in other threads. So RTOS necessarily needs blocking to manage the concurrency that way. So I would say that RTOS strongly prefers event-driven state machines. But actually, RTOS can be bad for state machines for some other reason. And that is mixing the sequential blocking programming paradigm with state machines for some other reason, and that is mixing the sequential blocking programming paradigm with state machines.
Starting point is 01:04:47 As I said, it is very bad to put any blocking calls inside the state machine, in the action of the state machine. So that's why... So this is the danger of using RTOS and state machines together, because there are so many temptations, so many mechanisms within an RTOS that would block all of them based on blocking. Okay, I think I understand, Christopher. Nods. One more question for you, I think. think uh your book is practical uml state charts in c and c plus plus event driven programming
Starting point is 01:05:27 for events embedded systems and you have another one uh quantum programming for embedded systems which is practical state charts in c plus plus you really like uml state charts i've never gotten into them. Convince me, please. Well, the state chart title was suggested at some point by my editor, and we stuck with that. Maybe, you know, I should have called this book maybe somewhat differently, and maybe the subtitle would be better, Event-Dri for embedded systems. Yeah, but yes, I was trying to,
Starting point is 01:06:11 in the first part of those, these were two editions of my book, try to explain the state machines and their full potential to actually have them working at their full potential, it turns out that you need a framework around them that works on the principle of inversion of control and provides the run-to-completion execution context
Starting point is 01:06:38 for each state machine, because the state machines need to run to completion and be undisturbed during that time so they are vulnerable if somebody would call for instance you know a state machine from within another state machine and so on so so so people don't really i i came to this realization after reading of course many books that that um event of state machines actually do need a framework. And you see this in all UML tools capable of code generation. For instance, the Rhapsody tool from IBM is based around the framework called OXF,
Starting point is 01:07:20 Object Execution Framework. There are some other frameworks also supported by Rhapsody, for instance, IDF, interrupt-driven framework, and many others. But all of them are frameworks. And there are other tools also based around frameworks. So it turns out that UML state machines do require a framework. And the contribution of QP is actually to provide something very, very lightweight, capable of working with small microcontrollers.
Starting point is 01:07:52 Miro, thank you so much for speaking with us today. Do you have any thoughts you'd like to leave us with? Well, not really big thoughts. I just maybe want to reiterate that you can use different paradigms, and it is all right, but it is always good to realize which one you are currently using.
Starting point is 01:08:17 And then you need to know which one can and cannot be or like to be mixed together. So it's all right to use different paradigms, but sometimes they just don't work well together. Our guest has been Mira Samek, founder and CEO of Quantum Leaps. You can easily find his YouTube series by searching for his name,
Starting point is 01:08:43 but there'll be links in the show notes to that and many other things. Thanks, Mira. It's good stuff. Thank you for having me. Thank you to Christopher for producing and co-hosting. Thank you to our Patreon listener Slack group for questions. And thank you for listening. You can always contact us at show at embedded.fm or hit the contact link on Embedded FM.
Starting point is 01:09:06 And now a quote to leave you with from Immanuel Kant. Space and time are the framework within which the mind is constrained to construct its experience of reality.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.