Embedded - 224: Interrupts to Interrupt Interrupts

Episode Date: November 22, 2017

Andrei Chichak joins Elecia and Christopher to do a deep dive into the world of interrupts. Andrei writes on our blog: Embedded Wednesdays. He has written specifically about interrupts in mult...iple ways: general introduction, buttons and debouncing, peripheral data transfer via DMA, and so on). The knock-knock joke comes from Chris Svec’s Embedded.fm blog post on interrupts. Jack Ganssle on debouncing buttons

Transcript
Discussion (0)
Starting point is 00:00:00 Welcome to Embedded. I'm Iliasia White, here with Christopher White. I'm quite pleased that Andrei Chichak from the Great White North has joined us today to do a deep dive into a particular topic. Interrupts. Hello, Andrei. Good morning. Now, you've been a guest with us a number of times, but still there may be somebody
Starting point is 00:00:29 out there who hasn't already heard of you. Could you give us an introduction? Okay. My name is Andre Csicak, as you've said. Let's see. I was born at the age of three, lived most of my life at 28,000 feet, and I come from a land of ice and snow from the midnight sun where the hot springs flow. So you and Thor, huh? I guess we can just go on.
Starting point is 00:00:59 The next section, I mean, we're skipping lightning round this week in favor of a joke. What? Yeah. What? I want're skipping lightning round this week uh in favor of a joke what yeah what i want to do lightning round oh all right go ahead what would you like us to ask you uh let's see mountain or beach all right mountain or beach beach uh favorite wave standing cats or ferrets cats did you know that there was an armadillo that was once the size of a car no did you know that the word muskrat has nothing to do with musk or rats. Pass. Are bats a reservoir of rabies or not? No. No. Bats are awesome. Bats are so cool.
Starting point is 00:01:51 Do you know that there is continuous frequency bats and then there are frequency modulated bats? They use echolocation chirps in order... Never mind. Show about interrupts. Oh, but we have a joke first. As though it hasn't already, already all been a joke. Okay, I'm sorry, Andrew.
Starting point is 00:02:08 Go ahead. Please start again. Knock, knock. Who's that? Interrupting cow. Interrupting cow. Boo! Yeah, that's exactly how that just...
Starting point is 00:02:19 That's what the show is about today. Interruptions. And cows. And cows. And bats. And return from interrupt. Our goal is to talk about interrupts, specifically to talk about how to teach new embedded software engineers good habits with respect to interrupts. And the goal here is just to chat about how we talk about interrupts to people and how we make it clear without making
Starting point is 00:02:47 it super boring. So let's try that. Well, the first thing is we have to define interrupts, but also... Can I interrupt you there? No, you may not. I think that we should start at Arduinos. Well, that's what I was going to, that's where i was headed is most people who are starting out with arduinos and such probably don't encounter them or need to and so developing why why they're something interesting would be a good way to start is that where you were headed or yeah pretty much yeah go for it well with an ar, of course, you've got the two sections, init and loop. And the rest of us who don't use Arduinos end up using this structure all the time anyways. We just call it the big loop model or super loop or whatever.
Starting point is 00:03:39 So when your program first starts, you initialize all your hardware, initialize all your variables, and then go into a huge loop where you just repeatedly do stuff until the power gets pulled. And on an Arduino, the background structure that nobody sees, when your program first starts, they call init once and then they were just repeatedly called loop and when you're using that sort of a structure like it works really well i mean we use it for small projects all the time but uh what you end up having to do is if if you need to see if somebody is pushing a button you have to go and ask the digital I.O. port, have you been pushed? If you need to get something from a serial port, you have to go to the serial port and say,
Starting point is 00:04:32 is there anything there for me to deal with? And this is known as? Polling. Polling, good. And if you have enough of those things, that becomes most of your program's time is spent asking questions yeah and and you can basically make no progress because you're mostly just sitting around asking your various subunits do you have anything for me to do do
Starting point is 00:04:58 you have anything for me to do this isn't i mean this is the basic form of Arduino. Arduino completely allows interrupts. So we're not saying you can't use interrupts there. And to some extent, when we talk about this main loop or super loop, or sometimes it's called the event loop, especially when it's called the event loop, usually there is this idea that something is happening. Some event is happening and you may be polling for what that event is at the beginning. Do you have a serial character for me? Do you have this button pressed sort of events? But what if those events came from outside the loop? What if they were asynchronous? What if they didn't go in line with this? And so these events are generated by interrupts, really. That's the secret. Asynchronously. In Arduino, you can hide this asynchronous and event words by calling them events. And, of course, you're on a system that, you know, you've got other things to do as well if if we were just sitting here
Starting point is 00:06:06 uh waiting for characters to come in it wouldn't be a very interesting system like you have to have your characters coming in from your zero port and do something with them whether it's move a motor or uh turn power on and off i mean there's other things for your system to do. And you're not actually taking care of those things while you're polling for events that aren't happening yet. So if your events are very sparse, there's probably a better way to do it. Okay.
Starting point is 00:06:42 So let's say we are implementing just a button press. We don't care which processor it is because most of these terms go from processor to processor. So it could be an Arduino. It could be Cortex M4F, whatever. And we start out and we set up the IO line and we say we want it to be an interrupt. I'm sorry. We want it to be an input and then we hook it to be an interrupt, or I'm sorry, we want it to be an input, and then we hook it to a button.
Starting point is 00:07:11 And so we push the button and the line goes up or down depending on how we've configured everything. And then every time we pass through the loop, we say, so how's the button? How's the button? How's the button? How's the button? And we take action on the button. If we were going to do it in an interrupt, how do we do it?
Starting point is 00:07:29 You don't. You let the hardware take care of it for you. That seems harder. A lot of the processors, eh, not really. A lot of the processors have it all built in. And so it's just a matter of us getting over the hurdle of, oh my God, this is really hard to understand and tricky and horrible? Well, I think it is hard to understand because most programmers don't start with the concept of concurrency, right? You write a program and it goes through a series of steps
Starting point is 00:08:02 and you can see those steps and they're all in line interrupts is the first place where people often encounter things jumping up in the middle of what you're doing and doing something else which leads to all kinds of complexity right yeah okay before we go there i just want to get through the basic interrupt Okay, so now I have read the data sheet, and I understand that I can configure a hardware interrupt. And I have some parameters I don't understand on that, but we're just going to assume that I copied and pasted from some hardware abstraction layer. And now I'm getting an interrupt, and now I'm not. I mean, okay, let's say when I push the button,
Starting point is 00:08:43 I want the light to go on, because that's an easy thing to try. So now I push the button, and interrupt happens, I think. What's that mean? Yeah, but my light never goes on, so this did not improve my system. My system worked before. What needs to happen after I set up the hardware to interrupt? Do something. Yeah, how do I make the interrupt do something?
Starting point is 00:09:10 Well, how about if we hold off for just a second? We'll put that on the stack for a second and explain what an interrupt actually is. Yeah, that's definitely part of it. A good way to see an interrupt is a asynchronous subroutine call. So basically, you know, we've got our big loop. We call subroutines. When you call a subroutine, it takes a bunch of stuff, sticks it on the stack, executes some code. And then when you return from the subroutine, it pops all that stuff off the stack and you continue. With an interrupt, it's basically exactly the same thing, but you don't actually do the subroutine call. Some external event causes the processor to stop, put all your stuff on the stack, and then call a prearranged subroutine.
Starting point is 00:10:08 And then finally, when you're done, you do a return and you go back to where you were in the big loop. So instead of me calling a function, maybe my function is my button pressed. Instead, the hardware is going to call this function for me. Yes. And it's all so simple after that. It's all so simple. Okay, so this thing that it calls, you said prearranged function. This is some sort of contract between my code and the processor itself.
Starting point is 00:10:49 Yes. And it has a name. A vector table name. Depends on the processor. That's true. So what are the common names for this? Well, something like if you're using a microchip PIC, you've got... You should just stop there.
Starting point is 00:11:05 No, no, no. Yeah, I know, but it's... My biases are well known in that area. Your bias is showing. With a PIC, you've got high priority interrupts, low priority interrupt, which we'll get to later. But they all go to exactly the same place you've basically got as soon as that interrupt comes through you start executing code at a known location and then you have to trot through and figure out what caused it and do the appropriate thing on something like an arm they have something called vectored interrupts, where you have a table of pointers to subroutines.
Starting point is 00:11:50 And when your interrupt happens, the processor automagically goes and figures out exactly where it should go. So you don't have to figure out who generated the interrupt. The processor figures that all out for you and executes the subroutine for you. Okay, so just to make sure that we're saying this right, on a PIC and a number of smaller, older chips, you get an interrupt or maybe two different interrupts. And from there, you have to figure out, was it your serial port or a button that caused this? On most of the processors I like, I'm sorry, on most of the ARM processors, we instead have this idea of,
Starting point is 00:12:42 oh, the button interrupt calls this function, the serial interrupt calls that function. And there may still be some unraveling. It may just be one of these eight lines did something, and that causes an interrupt. And you still have to go into the interrupt and figure out which it is. So this idea of what exactly made this interrupt happen is important but you have to know your processor well enough to know whether you're untangling did i get a serial character in did i get a serial character out did i get an error and that's why i got my serial interrupt or
Starting point is 00:13:20 or i have to figure it out from whole cloth. And that thing is usually, if you're looking for this thing, that thing is usually called the Interim Cause Register. Yeah. And this goes back quite a ways. I mean, the way that the ARM does it is exactly the same way as the 68000 does it back in the original Macintosh days. Whereas the IBM PC, the original PC only had eight interrupts in the whole system. And then when the AT came around, they increased that to 15.
Starting point is 00:13:54 And I'm not sure how they do it these days, but you still have to basically deal with those original 15 interrupts and go and figure out who interrupted. So it does work very well, but it's a little bit more baroque. Yeah. And now, I mean, I set up a processor that had, I think, 45 interrupts not too long ago, and it wasn't a big or complicated processor. It just had a lot of peripherals and features. That was 45 of them being used. There were some no-ops, but yeah,
Starting point is 00:14:26 there were 45 in my table. Because something like the ARM Cortex, they have 240 possible interrupts available. Oh, wow. But they do everything from divide by zero to Ethernet package just came in. Yeah. So that's that's taking that cause register and just turning it into you can insert a function here instead of
Starting point is 00:14:52 going and figuring out yourself what what happened right okay so we we we have gotten our button press the hardware so bad at this the hardware has said hardware has interrupted whatever it was I was doing before and has just yanked me over to go into the subroutine. The subroutine that we have previously told that the code knows is a special subroutine. We should talk about how the code knows that later. But right now, we're just going to say the hardware magically put me in this function. What should be in this function? What
Starting point is 00:15:32 should be in that function is as little as you can get away with. One of the tenets of interrupt processing is you spend as little time in there as possible so depending yeah we'll get there but that's important and why is a good question and it is important but okay
Starting point is 00:15:55 we'll come back to it okay um one of the one of the things that you have to do in the interrupt is whatever your application needs to do and another thing that you have to do is clear the interrupt. Because if you don't clear the interrupt and you return, you'll immediately go back into the interrupt. So depending on the processor and your compiler, you might get code to clear the interrupt generated for you. The interrupt might clear all by itself. Or you might have to go and read a register to clear the interrupt.
Starting point is 00:16:32 Which is a weird thing. And then you need the appropriate return sequence. That's usually handled by the compiler. Yes. But it used to be the way that you returned from a function was different from the way you returned from an interrupt. And that's still true if you're writing assembly. But you don't see it very much anymore if you are writing for the Cortex family. Right. Because it's all hidden.
Starting point is 00:17:01 Well, it's a little bit different. The Cortex family, the structure of an interrupt is exactly the same as a subroutine. Yes. The difference between a subroutine and interrupt routine is completely gone. Whereas something like on a PIC or any other number of processors, instead of doing a return from subroutine, you have to do a return from interrupt. And those are assembly instructions. RTS, return from subroutine. RTI, return from interrupt.
Starting point is 00:17:37 And they tell the processor what it has to do to get back to where it thinks it should be to get back to the program counter. And when you're returning from some routine, it just has to unload the stack the way it loaded it, and it knows how it did that. But when you're returning from interrupt, it did special things, because you were in the middle of something before,
Starting point is 00:18:00 it has to put you back in the middle of where you were. It can't just jump to the beginning of main. You might have been doing something important. So right now, I don't think we should focus too much on that because we don't, as programmers, have to deal with it very often anymore. But it's kind of nice to know that there is a difference underneath all of that. But I remember having those bugs, but I haven't had them in the last 10 years.
Starting point is 00:18:29 Thank God. Oh, because when you, when you write a interrupt routine, you have to tell the compiler, by the way, this is an interrupt routine, do the right thing. Whereas you probably just call the subroutine instead of calling an interrupt routine and when it returned it did the wrong thing that was a bug yes is that you can it or you can also have you know an interesting function and so you make that the interrupt it does everything you needed but maybe you're in a special mode where you're polling for a little while so you call the interrupt yourself and then it all goes very badly afterwards if you have that situation but we should skip this because we don't have that situation very often anymore we we enter the interrupt and we
Starting point is 00:19:12 just treat it like a normal function because most of our compilers will let us do that now we don't want to be there for very long for reasons we haven't talked about but let's say we're going with this button press thing. You mentioned we need to clear the interrupt, and depending on your architecture and software and all of that, you may have to set it up so that the interrupt can happen again. That's the housekeeping part of it. But what are we going to actually put in this interrupt? How are we going to tell our main loop that the button got pressed?
Starting point is 00:19:46 Well, you could call a subroutine, but no, that would be a bad idea. You could, but it still doesn't. Okay, well, why would that be a bad idea? Why would that be a bad idea? It's sort of, this gets into why you spend as little time as possible in your interrupt routine as well but um you've got a little bit of a concurrency problem where you could actually be in that subroutine so you're you're in subroutine. You get your interrupt from the push button, and in your interrupt routine, you call subroutine A. So now you've got basically two instances of subroutine A happening, and you're getting into a little bit of God mode here where you have to keep everything nice and straight.
Starting point is 00:20:45 This can be done, but you have to keep it nice and straight to make that all work properly. And then it will return to your interrupt routine and then exit properly. So let's talk about what subroutine A might be. And I'm going to take a case that you should not do, but is a reasonable case that happens. Let's say in my main loop, I was printing out, waiting for a button to happen. And in my interrupt, I decided to print out, button happened. Now, you don't usually want to do prints and interrupts, and we will talk about that, I promise. But this is a good way to talk about this thing that Andrea was mentioning about maybe not calling a lot of subroutines, especially ones. Well, okay, so I'm halfway through waiting for a button to happen.
Starting point is 00:21:34 And I get this interrupt, and I send to my debug, print, button happened. But I was only partway through. And now it was sending those bytes to the output buffer and it was collecting them into its output buffer global so it could send them out later so maybe it said wait so far right and then i want to put in more bytes and it's going to be wait button happened in button happened yes it's just going to come out all garbled because we were halfway through something and now we're going to do it again assuming we started from zero it's it doesn't it doesn't work there's but the reason that happens is because you are using a static or
Starting point is 00:22:19 global variable in order to do that printing. You really have to worry about these calling subroutines that you may already be in if there's some sort of information that is static between calls. And there's a word for when you're thread safe like that. What is the word? Reentrancy. Reentrancy. Yes. You know, the word I was trying to get you all to say was volatile. So can we go back to what would you have in the interrupt? We would not have a call to printf. We shouldn't have many calls to subroutines,
Starting point is 00:22:49 especially ones that have global or static variables. And we should get out of there as soon as possible. But what should we have there? Volatile. Say volatile. Come on. Some way to indicate to your main loop that something happened yay oh wait wait we still haven't said the word um that's not necessarily volatile it will be i don't know what you will be but now you've got a variable that's shared between
Starting point is 00:23:21 the main and your interrupt. Is that safe? Well, it's going to have to be global because they're two different functions. Right. And so as long as my interrupt is writing the variable and my main is only reading it, that's totally safe. Well, not really, because... Depends on how big the variable is. No, no, no.
Starting point is 00:23:48 I'm going to take the point of view of the compiler. I've got this subroutine that all that it does is write this variable. Well, that's not very useful, so I'm going to get rid of that code. And I've got this other subroutine that only reads that variable, and the variable doesn't change. So I'm going to get rid of that. It has the other subroutine that only reads that variable and the variable doesn't change. So I'm going to get rid of that. It has the whole subroutine. It knows the variable never changes.
Starting point is 00:24:11 Yeah, so it can just get rid of that. It never changes. So why would you read it? Why don't I just set it once? So somehow we have to tell the compiler, don't optimize out this variable. It's useful. There's something weird happening in the background that you don't know about. So just trust me. I know what I'm doing. Don't get rid of this variable. How would you do that? And that's where the keyword volatile comes
Starting point is 00:24:36 in. Volatile tells the compiler, look, magic's going to happen to this variable and you can't tell what's in it at any time. So don't ever optimize it out. It may change. It's just magic. Just believe me. There used to be a keyword called register that was very similar, but they got rid of it. So now we only have volatile, which is better.
Starting point is 00:25:09 This is also really important on something like a PIC or some sort of an 8-bit processor where if you're working with 16 or 32-bit values, you could be... So the base data size on the processor is 8 bits, but you're dealing with a 32-bit value. That's where I was headed. You could be halfway through doing an add. So you've updated two bytes and you get an interrupt. Something
Starting point is 00:25:30 changes, like a timer went off or something like that. And when you come back, you do the rest of the calculation but on new values. So now you've got a half-corrupted value.
Starting point is 00:25:46 The volatile won't save you. Will it? Yeah, it will. Oh, really? Will it? I don't think so. I don't think so. Or you might have to put that into...
Starting point is 00:25:57 You have to put protection around that. You have to put protection around that, which we'll get to. Yeah. We have to. Yeah, but we're in deep complicated stuff from our button push example now.
Starting point is 00:26:09 So now we have hooked up the hardware and set up. To have an interrupt, we have used the function that is somehow connected to the vector table, jump table, however we get the subroutine that is the interrupt,
Starting point is 00:26:26 interrupt service routine. And in this interrupt service routine, we know we have to clear the interrupt and set it up so it can go again. And then we have this variable. We set this variable that says button has been pushed or maybe button was pushed at this time. Now we go back to the main loop and instead of asking the GPIO system, has a button been pressed? Has a button been pressed? Now I have a loop that says, did this variable change? Did this variable change? How is this better? Now I'm pulling a
Starting point is 00:27:02 variable instead of hardware. It seems like I'm still sitting around asking useless questions. That's why I get to ask the questions so that other people can answer the hard ones. I hated getting this one because it was so like, gosh, you're right. That is both useless. What do you think, Andrew? I'm masking your interrupt. I have answers. Go on. Go ahead, Chris.
Starting point is 00:27:29 Well, for one thing, looking at one variable or indicator is a lot faster than asking a bunch of separate questions. The structure of your code can be a lot better. And you can go to sleep because you know if something happens, it will awaken the processor. And so you don't need to keep asking the question because somebody will just shout at you and wake you up and then you can look at what happened. And if my goal for this whole thing
Starting point is 00:28:04 was to build something that button press turned on the light, turned off a light when it was released, I can do that in the interrupt. We don't want to do a lot in the interrupt. We don't want to do debug printfs for sure. But I can turn on a GPIO. It's not like you can't do anything in interrupts,
Starting point is 00:28:31 but there are times when your whole code is much simpler. Well, you should do things in interrupts that are extremely time-sensitive. Like if you knew that signaling to your main loop was going to cause you a 20-millisecond variable delay and you needed something to happen in one millisecond, those are the kinds of questions you need to ask should i do something in an interrupt okay christopher's talking about latency we should put that on the list of things we should talk about uh but i was just talking i was trying to get to okay you push the button the interrupt uh turns on the light you release
Starting point is 00:29:02 the button the interrupt happens again you have to configure it specially for this, folks. But you release the button and the light goes off. Now what's in your main loop? You know, chilling. Main loop does nothing. You have your setup. You have your interrupt service routine callback thing. Because your entire program is now the interrupt handler. Your entire program is now the interrupt handler. And this is really hard for a lot of people to see because it is pretty easy to go through the main loop. And even if you aren't polling, you're just using variables to transmit events, it's still a fairly linear thing that's happening.
Starting point is 00:29:44 X happens, and then Y happens. Or maybe they're asynchronous, but when X happens, you do this. When Y happens, you do this. When you push it all into the interrupt service routines or some form of callback system, you really are inverting it so that you don't have this if X, then do this. It just happens. And some software engineers,
Starting point is 00:30:09 this is more how they think because there are languages that this is how it's put together. But for a lot of people, this going from serial one step after another to parallel, oh my God, everything's happening asynchronously, is a pretty big mental shift. But it is pretty useful, because having main be totally empty means the system is doing whatever it needs to do, whenever it needs to do it. Okay, do you want to add to why is polling for a variable any better than polling for the hardware change, Andre? Well, what I tend to do when I write systems like that is my main, instead of being completely empty, will be sitting there monitoring the system.
Starting point is 00:31:00 So, read the ADCs, make sure that the voltages are within reason, make sure the temperatures are within reason. And a lot of the times you can have a variable that is pretty much bit encoded. So, when you get an interrupt and the mainline has to do something, you can just set a bit and uh in your normal processing making sure that the system is running properly you can look at that big word and say is it all zero and if it is you just continue on doing your doing your uh scan of the system making sure that everything is fine if somebody needs me to do something one of those bits will be will get set and then i can say okay i must do something greater than is that on the is that where you're going i wasn't really where i was headed but it's an interesting
Starting point is 00:31:58 uh interesting point you can use you can still use these global variables to communicate with your main loop in order to indicate the status of the system and to indicate additional things that need to happen. If I go back to wanting to print out waiting for a button and button happened, then in my main loop I could put waiting for a button and then signal through this variable that a button happened. Now, my interrupt may have already taken care of turning on and off a light for me, but it's still nice for my logs to have both. And because it's looking at this variable and it's not printing asynchronously, it will format correctly. It will finish the one waiting for button to happen and then button happened. And even if the button happened in the middle of where it was printing that waiting message, it will wait until the very end to do the button happened.
Starting point is 00:32:53 So your debug messages can use these bit masks or global variables to indicate what's happening, even if they aren't handling the actual event they aren't handling the event they aren't taking action on them um although it's often helpful to still have their global variables this whole turning the light thing on is obviously just a toy problem but it's a useful toy problem well a very common thing to do with interrupts is output to, like, as you say, you're going to print out, you know, I got a button press. But you can use interrupts to have to, so basically you fill up the buffer and you say go, and the interrupt routine takes care of shipping all that stuff out the serial port.
Starting point is 00:33:48 Yes. takes care of shipping all that stuff out the serial port yes there are a lot more interrupts than just button presses and the serial interrupt is is really useful very useful but if you so you're in the middle of uh sending something out the serial port and you get an interrupt and you immediately go into your interrupt routine and you say, print out this stuff. So now you're using, you've got an interrupt and you're going to be using interrupts to generate your output. And suddenly you've gotten yourself into a whole bunch of hurt unless you're
Starting point is 00:34:20 a God. Okay. We're going back to don't do printfs and interrupts don't do printfs don't do output logs don't do any of that unless you're willing to accept that it is likely to fail and bite you because in that case you're dealing with nested interrupts as well ah yes okay which that's not good i wasn't ready for that a lot of people aren't um okay i want to let me make sure that we have all the things for the very basics of getting an interrupt we talked about that it's asynchronous it's not in the line of of what you think is
Starting point is 00:35:01 happening we talked about vector tables. We kind of touched on context. Maybe we should define what context is. Go Chris. No. Context is all of the things around where you are in the program. It's your state. It's your state. It's, it's your program state. It's what, what is the program counter? What instruction was it about to run? What was in all of its registers? What was it adding together? What was it multiplying? And what was its next instruction in the pipeline? There are all these things around what the processor is doing right now that when an interrupt comes, it has to save that context. It has to remember everything it can about where you are. Because remember, it is just yanking you out of what you were doing
Starting point is 00:35:59 and sending you over to the interrupt to do something entirely different with no context. You go over the interrupt and the program counter now, because the hardware has set it, forced to set it, it is where this function is. But your register values, they can't be what they were before. You have nothing there. And if you do anything in your interrupt it's going to change those register values those are the the cache things those are the memory you use first and it has to then take those registers and put them back the way they were when you go back to your runtime context so there's the thread or runtime context which is what you're normally running
Starting point is 00:36:44 this is your main loop this is what you've called from your main loop. Interrupt comes, has interrupt context. It only has a small view into the system and that small view into the system needs to be completely erased so you can go back to your main context. And it's important to realize there's these two little worlds and the interrupt has a tiny little world and your main has a big world. And that's not a bad thing. An interrupt can be small and not view everything because we do want it to go fast,
Starting point is 00:37:13 which was the other thing on my list. Why are we keeping interrupts small again? I remember I got to a company and they were running their whole system out of interrupt. Every time the accelerometer interrupt came in they did the whole Kalman filter. Worked fine. It's fine if you don't do anything else.
Starting point is 00:37:30 Because when the interrupt is running, your program isn't. Right. So if your program is doing something mundane, that's its normal course of events, let's say you're doing button presses and interrupts, but that's controlling a video game. If you spend a whole lot of time in your interrupt, logging the button press and thinking about something else, and then you come back to your video game, every time somebody presses a
Starting point is 00:37:56 button, your screen's going to stop for a short period of time while you do all that interrupt stuff. And anybody out there who isn't thinking, wait a minute, I've seen that happen. Yeah, we've seen that happen. It happens because people have crummy interrupts, which is what we're trying to avoid. So if you have a program, your main program, that's doing a great deal of work for your application and your interrupts aren't well written,
Starting point is 00:38:23 you can introduce latency into your main program. You can cause jitter and pauses. You can break it entirely if it's doing something time sensitive. So that's one of the reasons to be very careful. But wait. Assume for the moment that you've pushed your button and you are now doing a Kalman filter calculation and a character comes in on your serial point.
Starting point is 00:38:51 Did you get it? In this system, there was only the interrupt, which was the only way to make that system work. No, but in general, if you're in an interrupt routine. And another interrupt happens. And another interrupt happens. And another interrupt happens. It could get, like in interrupts you have, we'll get there, but you have priorities. So everything of a lower priority waits.
Starting point is 00:39:15 So your character that's just come in off of your terminal waits. The flag has been set. The interrupt will happen, but you have to wait. If another character comes in in the meantime and you still haven't serviced it, you've just lost some data. So your first character just got overwritten.
Starting point is 00:39:37 Now you do a return from interrupt. You say, oh, I got an interrupt from my serial port and you go and get it and you've got the second character rather than the first one. The first one is gone. And you probably have an error because you have overrun your buffer or whatever. Which generates another interrupt. So the main reason to have small interrupts is that you don't know what you're interrupting.
Starting point is 00:40:04 You could be interrupting something very important. File system access. And so you do the smallest you can, you get in, you get out, and that's it. And you try not to do delays or printfs or anything that might take a long time because you might be interrupting something that is very important to finish quickly. And you can build a system where that doesn't have to be true. This whole massive system that was done in one interrupt, it is completely possible, but it's harder in the end because that system we could not add logging to until I fixed it. We could not add additional interrupts. We couldn't monitor the ADCs in a good way because we were so tied to this single interrupt. If you want to have multiple interrupts, if you want to have a good system that can
Starting point is 00:40:55 handle all kinds of facility with debugging, enabling logging or allowing users to do multiple things, to not be stuck waiting for just one button. That's where you need to make it small, because you need to be able to handle lots of things and to do it quickly. Chris said the word latency. We haven't defined that. Somebody want to go? Latency is basically the time between when you get the interrupt and when the button gets pushed and when you're ready to get back to doing work again.
Starting point is 00:41:34 So basically, initiation of the time between you push the button and the light comes on. Okay, so Chris is using the American standard definition of latency and Andrew is using the embedded systems version of latency. Okay, there are two definitions here. Whenever you're talking to somebody who cares about latency, the latter definition is the right definition. I think Chris is right. It's basically the entry preamble to your
Starting point is 00:42:15 interrupt routine. The reason there are two, though, is if you think about a motor system where you have to do something every five milliseconds. Right. And if you don't do it within that time, the motor jams or stops or whatever. Flies off.
Starting point is 00:42:37 Flies off and kills people. Whatever. And if you have an interrupt, you know, you have a debug interrupt that takes seven seconds that's really bad but even if you have an interrupt that takes two milliseconds it is asynchronous to that other one and so where does it happen does it happen at t equals zero okay that's fine we're done two milliseconds we need to service the next one in five milliseconds. But what if it happens at t equals four? Now we have a delay. We've started our debug interrupt handler. It's going to take two milliseconds. We started at t equals four milliseconds. It's going to take till t equals six milliseconds. Don't even get to me about
Starting point is 00:43:21 fence post problem. We're not going to talk about that. But now we have this problem that our good stuff didn't happen because of our long, random, useless, really important debugging, but not useful. Yeah, it didn't happen. The good stuff didn't happen when it needed to. And that's why you keep interrupts short. Now that time between when the interrupt happened, the debug interrupt, and when it came back, that two milliseconds, that can be called latency. We also talk about system latency, which is how long does it take for the processor to get from I'm running in a routine to I am running in my interrupt. That's important when you have a
Starting point is 00:44:15 real-time operating system, an RTOS, because they have a lot of overhead. And so if you need to be able to get an interrupt and be able to service it within some small amount of time, let's say you have a satellite, you have to be able to put your shields up when you detect a micro meteorite coming for you. I just totally made that up. I'm sorry. But you only have a little bit of time in order to take an action. You only have a little bit of time before you can swerve in a car or before you can put the locks on the motor because you noticed somebody's finger was about to get crushed. You only have a little bit of time. If your real-time operating system takes too long, then you may not have
Starting point is 00:45:01 enough. And that real-time operating system latency is a number that has been incredibly important in the past. As we get faster and faster processors, it's not as big a deal if it has to take 100 cycles, because now 100 cycles takes less time. So latency is really an important term, but it's hard to get your head around because it means a lot of things in different situations. In some situations, it's just how long until I handle this. In other situations, it's how long until I can get back to what I was doing before you interrupted me. So be aware that that term is very loaded and means different things in different situations. I got a good example of that. I used to work for a very large chemical company,
Starting point is 00:45:48 and one of the guys in the research and development department decided he wanted to do a nice little file transfer from his brand-new PC to our, at that point, it was a VAX computer. And he basically had the PC power typing at this reasonably large minicomputer. And he was only going at 9600 baud. This is characters being transferred between one computer and another over serial port. Not a problem. Except 9600 baud ends up being 960 interrupts per second.
Starting point is 00:46:33 And that was enough to bring quite a large mini computer absolutely to its knees. He was doing okay because he was running in interrupt time. But all the rest of the people on the computer, which would be basically we are the main loop, we all halted for 15 minutes while he did his file transfer. So this is a big deal that actually happens. Okay, that brings in how many interrupts do you do? And how expensive are they to the processor? I mean, 960 interrupts per second doesn't sound that much to me now. Now.
Starting point is 00:47:09 Now. But there are systems that would take all of the time in the world just to service those interrupts. Now we get to RTOSs, and RTOSs are actually just a little bit of smoke and mirrors. You've got a timer that generates an interrupt so many times per second. And every time that timer ticks, everything gets put on hold because you've just got an interrupt. It stacks all the way your registers and all your context that you were just talking about.
Starting point is 00:47:48 And then the task switcher kicks in, which goes through a series of tables trying to figure out who's got the highest priority, who's ready to run, and then loads up their context and does a return from interrupt. That's all an RTOS is. I'm going to let you finish in a second. Okay.
Starting point is 00:48:12 Yeah, okay. This is not the RTOS show. There will be an RTOS show someday, maybe. I feel compelled to say that that's one kind of scheduler. That's a preemptive scheduler. Many other kinds of RTOSs do not interrupt you to switch context in a round-robin fashion. It waits for your task to say, I'm done. So there's other ways to do that.
Starting point is 00:48:36 This is called preemptive multitasking. So, okay. Basically, there's been a lot of research in the last few years to do the task switching as quickly as possible. Because this is the latency that we're talking about. The time between that timer tick and the next task running. So if you spend too much time doing your task switching, then you could end up gobbling a huge amount of system resources doing absolutely nothing but task switching. So let's see, 10 years ago when I was doing RTOSs on a 16 megahertz system, I was able to get about 100 task switches per second and my system would run reasonably well. 1,000 task switches per second, forget it.
Starting point is 00:49:34 It just wouldn't make any progress. Now with the ARM chips that are running at 160, 216 megahertz, getting 1,000 task switches per second is easy, and you've got lots of cycles left over to get your work done. Okay. But we will talk about RTOSs sometime in the future. Let's go back to just interrupts. Okay, so you can get a lot of interrupts.
Starting point is 00:50:07 We want our interrupts to be short, so we don't want to do anything unnecessary. We do maybe want to signal the main loop through the use of global flags or semaphores if you're in our test land. What? I think you're bringing our tosses back in. I know, I'm sorry. I didn't do it. It was totally me. But let's go back to another situation
Starting point is 00:50:29 where you may generate a lot of spurious or silly interrupts. I like the button again. Button bounce. Andrew, I know that you care a lot about debouncing buttons uh so i'm totally throwing you under the button bus here that's okay i wrote an article about this uh for the blog not that long ago where i actually went and looked at some button bounces on uh an oscilloscope so basically what happens when you hit a button is mechanical things, and mechanical things aren't actually all that predictable. So you've got a spring that is
Starting point is 00:51:16 unloading. So when you push the button, it pushes against a spring and some mechanical leafs sort of open and close. Unfortunately, when you push a button, it doesn't just close. It hits the contacts and the contacts bounce open again and close and open and close. And our computers are fast enough that they can see every single one of those open and close events and they're happening on like the uh less than millisecond range and they can continue like jack gansell had a nice little article where he went through a bunch of buttons and he found buttons that would continue to bounce for like 16 milliseconds. So you're going to see every single one of those bounces, and it's going to continue to call your interrupt routine over and over and over again.
Starting point is 00:52:20 So if you were to have an interrupt where you push the button and it turns something on, push the button and it turns something off, and you figure, oh, this is great. I don't have to have a latching button. I can just have an intermittent button. Well, the bounce is going to make it go on, off, on, off, on, off, on, off, on, off, on, off, rather than just on, off. And you're going to see every single one of those interrupts happen. So I usually throw it over the wall. I usually throw it over the wall and tell my electrical engineer buddy to throw some capacitors on it to get rid of the bounce.
Starting point is 00:52:58 And that is a totally reasonable way to do it, especially as a software engineer. There are ways in software of helping to realize when you're doing bounces. One way is to delay enabling this IO interrupt right away so you can't get a whole bunch of them. There's also level versus edge triggered. Does that matter here? Nope. I don't remember why it's important. You need hysteresis, right? Yeah, you really need hysteresis. On some of the Atmel ARM
Starting point is 00:53:36 processors, they've got hardware debounce. Go through your manual and see if that's built in. But this is just a great example because it's physical and it's easy to understand. There's lots of other kinds of things that might interrupt in a spurious way or get into situations where it's triggering many. Like, if you had an error state from some peripheral that triggered an interrupt, and maybe it just went nuts and starts going hundreds of times per second or thousands of times per second.
Starting point is 00:54:09 This is also a situation that you might not anticipate, right? You might bring your whole system down because some peripheral is saying, help, I'm sick, and then I'm fine, and then I'm sick, and then I'm fine. So interrupts have great power to take over your system. Well, that's a good architecture point. Not necessarily in the basics part of interrupting, but when you're looking at doing a system and figuring out how things go together, be aware that there are ways that things can interrupt way too often, usually in an error state. So how do you, maybe you have an interrupt that you receive that it is in an error state, but you don't do anything about it. You don't tell it, that's fine, quit telling me, because you didn't ever expect to be in an error state.
Starting point is 00:54:58 So there's that side of you do have to handle these things so that you don't get a bunch of spurious interrupts then there's the other side where it is always possible to miss an interrupt oh no and it is uh it is bad to to start any design with the words if we're never going to miss an interrupt and if we do our system will just end up rebooting because your system will end up rebooting a lot. It's just the way of the world. When I talk about making a stoplight system as a good way to talk about state machines, one of the things I always say is to be sure not only to depend on the sensors I give you in the road, but to occasionally use a timer to go around the stoplight because you want to make sure that you're not dependent on a broken sensor. And that's kind of my rant about architecture,
Starting point is 00:55:57 is be tolerant of missing interrupts and extra interrupts because that's totally going to happen. I ripped that off from Elizabeth Brenner. Ah, well. I think it was Elizabeth. Anyway, let's see. Next on my list of things we should talk about includes resource protection do's and don'ts.
Starting point is 00:56:19 Go. You should protect your resources. You should hoard them like dragons. I think you shouldn't. Mostly because I'm not sure where this is going. Well, I think she's talking about the issue. Explain yourself. You're talking about if the interrupt handler modifies something that your main program may also modify.
Starting point is 00:56:40 This is the thing we were talking about. Atomic. It's usually trying to update something in an atomic fashion so it's not half updated by your program and half updated by your interrupt handler, right? And allowing re-entrancy with global variables. This is hard without some mechanism to say, I'm messing with this thing right now. You're not allowed to. And when we say resources, I'm saying global variables, but there's also the idea that maybe I push a button and it sends out a small spy command. Right.
Starting point is 00:57:13 That's a resource too. Right. Or I push a button and it... Writes to a file. Writes to a file. That's, well, that might be long. Or it starts to write to a file. It kicks off the writing to a file, that might be long. Or it starts to write to a file. It kicks off the writing to a file. You have to protect these
Starting point is 00:57:27 resources from other things happening at the same time. So how do we protect these resources? Well, you could say, don't interrupt me right now. Yes, we can turn off other interrupts. We can turn off other related interrupts, which is kind of dicey. Or we can turn off other interrupts. We can turn off other related interrupts, which is kind of dicey. Or we can turn off all interrupts. Anybody want to cover the pros and cons of enabling and disabling interrupts? Well, if your interrupts are disabled, obviously any outstanding interrupts won't come through.
Starting point is 00:58:01 So you've got a little bit of a time delay that you've introduced. Latency. We're going to go back to latency. Yeah, you've put overhead on your latency. And also, if something like back to the serial port, if you have a character come in, it generates an interrupt, but they're disabled,
Starting point is 00:58:23 so nothing happens. And then another character comes in, and it would have generated an interrupt, but they're disabled, so nothing happens. And then another character comes in, and it would have generated an interrupt too, so you've just lost a character. So you've got data loss while your interrupts are disabled. Data loss while interrupts are disabled. Failing to do things on timer ticks. You disable your interrupts for long enough and your RTOS goes kaplooey. And if you're doing something critical.
Starting point is 00:58:50 Oh, this happens in the Nordic chips. Once you start the BLE going, you can't ever stop. It makes it hard to debug them because you can't walk through your code once you have BLE running. But any interrupt that takes too long will trash BLE
Starting point is 00:59:08 because BLE has very strict timing requirements. So you can't just print out something and have interrupts disabled around it. So you'd have approximately the same situation with the, what is it, the NeoPixels, where the timing is very critical so if you have any wobble in your in your timing uh your patterns will just be wrong yeah you end up with different colors you end up with some that don't get uh turned on at all or turned on only to a different color. And it's because their timing requirements are so precise
Starting point is 00:59:47 that any latency in the system that isn't them just causes problems. Using the NeoPixels and the Nordic chip is kind of hard to do together. But there's lots of these things that have timing requirements that are very specific. That's why we do embedded systems. If we could just toss it onto a Linux computer, all right, maybe we should do that. But when you have to deal with strict timing requirements and resource constraints, that's where you start dealing with interrupts that are very close in personal level. Yes.
Starting point is 01:00:24 Okay, but how do we protect the resources? We turn off the interrupts. That's one option. But that's not an option for when we want to share a resource between our main context and our interrupt context. Do I have an RTOS? You can call it a semaphore even if you don't have an RTOS. A mutex. A mutex.
Starting point is 01:00:45 A mutex. Fine. Yes. A mutex. Mutex. It's such a funny word. Which means, it means what? Mutual exclusion.
Starting point is 01:00:54 Not mutant explosion. Or something that comes out of your nose when you're sick. Mutex. Mutual exclusion is the correct ding, ding, ding. Is a thing. Is a thing. That you can attach with meaning to a particular object or resource. So a global variable or a spy resource, whatever resource you want.
Starting point is 01:01:15 It's connected to it. It's connected to it in your mind. Okay. Or in your, well, in your code, but not directly. And when you are about to use that resource or modify it, you say, you grab the mutex. I own this. And I have this thing. And I have the conch.
Starting point is 01:01:35 And you always do this for any shared resource, whether it's an SPI bus or the conversation at a party. Right. And so when you have this thing then you go to modify or do your thing that needs to be protected and then you give it back you release it so what happens is if i have this thing and i get an interrupt and the interrupt comes in and says oh i want to modify that thing it tries to grab the mutex. And however the mutex is implemented, whether it's through an RTOS or some other mechanism, it will try to get it and it will either fail and get an error back and say, you can't do that. And it will have to figure out how to wait. Or it will block until the other thing is done. Now this gets into trouble.
Starting point is 01:02:22 It does. Priority. Now you have your main system, which is sort of slow and not responsive trouble. It does. Priority inversions. Now you have your main system, which is sort of slow and not responsive necessarily. It's not an interrupt, right? But it's holding onto the mutex for something the interrupt handler wants to modify. But now the interrupt handler has to wait. Which we don't like to do in interrupts.
Starting point is 01:02:40 We've just taken something that we want to run in a short amount of time and unbounded how long it can run for because it's sitting there waiting for your main program, which, hey, you could grab that mutex and then go out for coffee. And remember, the only way to get back to the main is to do a return from interrupt. That is the other problem. Yeah. So you can't wait in your interrupt routine because that does nothing other than sit there and spin on something that will never happen so this is not actually one of the best ways to go about this
Starting point is 01:03:11 so basically well this happens assume for the moment that you have to use the spi in your main line and your interrupt routine the only way to do this is to turn off interrupt so that your interrupt routine can't fail or, sorry, your interrupt routine can't fire. Or you can mask just that one interrupt that is going to be sharing the thing so that particular one doesn't happen until you're ready to hand off the SPI.
Starting point is 01:03:46 What does mask mean? I'm not going to answer that. Let's continue. No, it means. No, that's what it means. That's what it means. I'm not going to deal with that right now. Gotcha. It's like going into a kindergarten and ignoring Johnny with his constant.
Starting point is 01:04:10 But only Johnny. Just Johnny. Well, there is a concept of a non-maskable interrupt. Yeah. Some computers used to have a button that said NMI right in the front. Yeah. Okay. So each each interrupt has
Starting point is 01:04:25 an enable bit and a flag that says the interrupt is is happening right now and typically a mask bit that says
Starting point is 01:04:37 look it's it's it's it's enabled but don't don't worry about it right now. So if the interrupt happens, the hardware says, I'm going to ignore you because the mask bit is set or however your processor implements this.
Starting point is 01:04:59 But basically, the interrupt is still active, but it's masked. And when the mask gets removed, the interrupt will fire. And we have non-maskable interrupts, which are things like divide by zero or... Processors on fire. Processors on fire is a good one. Typically, you'll also have an IO bit that is non-maskable. And that... So that's kind of the halt and catch fire button.
Starting point is 01:05:27 Yeah. So have we resolved this problem of sharing a resource between an interrupt handler and your main program? I think we've established that it's much too hard and we should all just go to the beach. Rub it in, rub it in. I would say that there's other better ways to handle it. If you have other things available to you, like an RTOS.
Starting point is 01:05:48 But I don't like turning off interrupts. But if you have an RTOS, there's ways to architect this so that instead of the interrupt handler dealing with this, it signals a high-priority threat, which can service it at high priority, but be within the context of the operating system, so that you can work these sorts of things out in a more reasonable manner. So basically what you're saying is I'm working with my SPI bus, I get an interrupt, the interrupt routine says I got to use the SPI bus, but I can't because somebody's got it. How about if I just leave a little breadcrumb behind and when I do a return from interrupt, the main line will say, is this breadcrumb set?
Starting point is 01:06:24 And then it'll do the work. Yes. Or someone else if you have someone else. But, yeah. Yeah. I mean, the RTOS makes nice bread. It can leave breadcrumbs for you. But you can also do this manually.
Starting point is 01:06:37 You don't need RTOS. This goes back to the thing we were talking about with do as little as possible in the interrupt handler and reduce latency. You probably shouldn't be doing the SPI transfer in the interrupt routine anyways. You should question whether there's something that's happening in your interrupt handler that could cause it to wait for something else and find ways around that. And it is okay to signal the main context, the thread context, with what you want to do. Where I switched out my button pressing because it didn't make sense to pull on a variable instead of pull on a hardware. Now we're starting to see where, oh, well, you can't do everything in the interrupt. You do want to just set a variable and deal with it later because you are in a different context and you may be having multiple things happen.
Starting point is 01:07:29 So it goes back to that. It's not as simple as, oh, well, why am I just pulling on a variable? You're pulling on a variable because now you're at the right priority and you have the resources you need. You can check with your mutexes. You aren't waiting in an interrupt. So there's a lot of good stuff about signaling the main line or the main loop to do what you want. All right. Have we confused everybody?
Starting point is 01:07:59 I don't know. The shortest possible explanation of nested interrupts and then one more thing and then... I ain't know. Let's, let's, let's, the shortest possible explanation of nested interrupts. And then one more thing. And then. I ain't doing it. All right. Well, that is pretty short.
Starting point is 01:08:12 Okay. How about if I just jump in here for a second and then say, this has been great. Thanks. What? Oh, we were supposed to interrupt him as he was talking. And then that would have been nested. No, I interrupted you as you were talking. Oh, I see. You're supposed to interrupt him as he was talking. No, I just interrupted you as you were talking.
Starting point is 01:08:26 Oh, I see. You were supposed to. Okay, so let's say I'm telling a joke. And Christopher interrupts and starts telling a different joke. And Andrea interrupts. Now, if we don't let him interrupt, then there's no nested interrupts. He has to wait until Chris is done with his joke. Even if Andrea's joke is more important.
Starting point is 01:08:47 You can have interrupts that interrupt your interrupt handler. Wait a second now. Isn't this going to cause all sorts of problems with stack smashes and stuff? Well, that's up to the processor to be able to sort itself out and to deal with the contexts appropriately. But it goes back to you can get into some pretty bad resource problems. Because when you're in an interrupt, you often assume you're the only one there. Between when you start and when you end, you are running the whole time. But if you have nested interrupts, that's not always true. This sounds hard.
Starting point is 01:09:23 It's kind of important because you don't want your debug interrupt to interrupt your motor control thing because... or your motor control interrupt. You want to be able to prioritize these. If you're going to have nested interrupts, if you're going to allow interrupts to interrupt interrupts... Sorry. If you're going to allow multiple interrupts to happen at the same time interrupting
Starting point is 01:09:46 each other then they're going to have to be prioritized and that that goes back to what needs to run what is its priority and i you know there are times when i have used nested interrupts but for the most part i try to avoid them because they do mentally make my brain squirm a lot of the times it's it's if you write your interrupts properly it's usually not an issue um some processors don't allow nested interrupts um like the some of the picks that only have one interrupt, you have to go through all sorts of backflips to get another interrupt. Some of the later picks that have two interrupts, they've got priorities so that if you're in a high priority interrupt, the low priority interrupt will wait. If you're in a low priority interrupt and you get a high priority interrupt come through, it will interrupt you. But the idea is stay away from global variables because you're in the middle of altering a global variable and you get an interrupt
Starting point is 01:11:05 and it plays around with the global variables. If everything is done on the stack, so this is the reentrancy that you were talking about. If you do reentrancy properly and use local variables, you don't really have to worry too much about nested interrupts. But if you've got a little bit more sloppy style and like the global variables, then yeah, you're going to cause yourself issues.
Starting point is 01:11:38 All right. Did that make any sense? It made sense to me, but I knew what you were talking about. So maybe we should ask other people if it made sense. Why are you looking at me? No, I wasn't really, because you were in that direction, I was waiting for the audience to answer. Going on, because that's insane. Let's see.
Starting point is 01:12:00 Oh, I wanted to mention about phone screens. And I know that this is, it was kind of a big topic shift, except that my main question that I used to ask people if I was doing a phone call with them to do first interview phone call was, what can you tell me about an ISR? And that was the whole question. There was no... We haven't defined anywhere in this whole show. We've never said that. Well, we're going to have to now, aren't we? But the whole question was, what can you tell me about an ISR? And it was good for hardware engineers, good for software engineers. And I was usually interviewing for embedded software. And then you just let the person talk. And if you want to do this formally or you want to help somebody else do it, you make a little bingo card.
Starting point is 01:12:49 And if they can say things like, ISR is an interrupt service routine, well, good, they've already got one bingo square. And if they say nested interrupts and NMI or masking or... They say early advanced concepts? I mean, there's some basic stuff they should be saying before they talk about any other things. A vector table was definitely a square. Context was a square. ISR, IRQ, interrupt request. So that's the little thing that the hardware has to deal with.
Starting point is 01:13:22 Yeah. So that was one of my favorite interview questions. I guess I didn't really have a point to that story. So, you're going to return from that interrupt? I guess so. I didn't know it was an interrupt when I started. I thought we'd discuss it, but then I realized there wasn't much to discuss. But I'll put the picture of one of them in the show notes because I don't know, it was entertaining. And if you have to work with a recruiter, things like that, where it's sort of vocabulary bingo, is kind of nice. It means that the recruiter doesn't
Starting point is 01:14:00 necessarily have to understand all the concepts. it helps if they understand some of them but it gives you a way to do pre-screens that are reasonably fair no that's good because it also gets back to last week's question about um what you should be doing to get yourself a job in embedded systems and i i think a lot of it comes down to you know treat it like a treat it like a career and you're preparing for a career and sort of dissociate that from treating it as a hobby so rather than just uh writing little things in arduino maybe you should get into advanced things like interrupts in Arduinos and having to deal with what the hell is, why is my button
Starting point is 01:14:50 bouncing and how to get around it. Do it seriously. And in the learning about all this stuff, you'll be able to fill in your bingo card. Yes. Maybe we should well, maybe someday in the blog we'll make bigger bingo card. Yes. Maybe we should, well, maybe someday in the blog
Starting point is 01:15:05 we'll make bigger bingo cards for embedded systems careers. That would be kind of amusing. And that was part of the goal of the show is I had promised last summer that we would have some shows about more moving from hobby to the larger technical concepts.
Starting point is 01:15:23 And I was going to call them basics or something. And they do have the basics tag, and this will get the basics tag. But it's a lot more fun to just talk about the stuff instead of trying to do a formal lesson curriculum. Well, maybe someday, but not this year. All right, well, I think that covers most of interrupts. There's a lot more to it, of course, but those are the basic terms we should be looking for and maybe some ways to discuss them. Chris, do you have anything else you want to?
Starting point is 01:15:56 Oh, God, no. We've lost Christopher and Joe's phone. Andre, any thoughts you'd like to leave us with? Yeah, interrupts, they might seem kind of daunting, but if you go through, I think even in my blog posts, I get into interrupts a little bit. And the after Blinky comes reading the button and then interrupts
Starting point is 01:16:30 go through it it's it's it might seem daunting but it's a very useful tool and it's it's a good thing to have in your quiver of tools. I totally agree. Our guest has been Andrej Cicak of the Great White North, author of the Embedded Wednesdays blog on the Embedded.fm site, and an embedded systems developer at CBF Systems. Thank you for joining us, Andrej. Thanks for having me. Thank you to Christopher for producing and co-hosting.
Starting point is 01:17:06 Thank you to Elizabeth Brenner, Andre Cicek, and Chris Veck for essentially writing my outline this week. And, of course, thank you for listening. And if you have any questions, please give them to us, and we'll put the answers in the doobly-doo down at the bottom. That's true. Did I interrupt? Sorry. You did. But there will be show notes, and we do appreciate questions. Except about RTASs.
Starting point is 01:17:34 Nobody appreciates those. I'll do it. Okay, so I have kind of a long quote to leave you with. This one is from The Velveteen Rabbit. It's one of my favorites. That's why it's so long. You become. It takes a long rabbit. It's one of my favorites. That's why it's so long. You become. It takes a long time. That's why it doesn't happen often to people who break easily or have sharp edges or who have to be carefully kept. Generally, by the time you are real, most of your hair has been loved off
Starting point is 01:17:58 and your eyes drop out and you get loose in the joints and very shabby. But these things don't matter at all, because once you are real, you can't be ugly, except people who don't understand. Embedded is an independently produced radio show that focuses on the many aspects of engineering. It is a production of Logical Elegance, an embedded software consulting company in California. If there are advertisements in the show, we did not put them there and do not receive money from them. At this time, our sponsors are Logical Elegance and listeners like you.

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