#10 Stack Overflow and Other Pitfalls of Functions

Поделиться
HTML-код
  • Опубликовано: 31 июл 2024
  • This lesson wraps up the subject of functions in C. You will see how your programs can blow up when you use functions incorrectly. You'll also learn about passing pointer arguments and returning pointer values.
    ------
    Resources:
    Companion web page for this video course:
    www.state-machine.com/quickstart
    GitHub repository for projects for this video course:
    github.com/QuantumLeaps/moder...
    Transcript of this lesson:
    www.state-machine.com/course/...
    Music credits:
    The background music comes from:
    www.bensound.com/royalty-free...
  • НаукаНаука

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

  • @leohuang990
    @leohuang990 2 месяца назад +2

    The carefully designed example about stack corruption is a great one. It shows how a C program can go wrong w/o explicit signs. Nice to know that static variables resolve the common bugs of reading out-of-scope local variables.

  • @thecombatengineer7069
    @thecombatengineer7069 5 лет назад +4

    I recall you saying " I love it" while watching the stack overflow in step-by-step mode....I am not complaining, in fact, I am stoked when teachers like you share the emotion. This is what makes you special. I just received my 'Tiva' board and I am working through the entire playlist (for the 1st time). I am sure I will watch this series a few more times to really understand the treasures you've gifted us. Thank you again.

  • @sonuok
    @sonuok 5 лет назад +3

    For the first time you are understanding the hardware ramifications of the various C language constructs. We also read what the different constructs (static, volatile, etc) are but now things are amazingly demystified! Mr. Samek , you have done a great job. You be a professor at an ivy league!

  • @krisjk999
    @krisjk999 4 года назад +11

    Outstanding lecture series. The explanation for static variable made my day. Thank you so much.

  • @dongolahmed
    @dongolahmed 10 лет назад +15

    your lessons are really over the top ... I've learned new stuff by the virtue of them ... hope you decrease the span between the lesson & the one after it ...
    best regards

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

    I listened this lesson for more than 90 minutes for understanding the theme of his lecture. IMO it very deep understanding about stack and function calls in an embedded application.

  • @StateMachineCOM
    @StateMachineCOM  10 лет назад +3

    That's what I said at the end of the lesson 10. CMSIS uses structures to represent hardware registers, so in the next lesson 11 I will introduce C structures and the CMSIS-compliant header file for the LauchPad board. Stay tuned...
    --MMS

  • @StateMachineCOM
    @StateMachineCOM  10 лет назад +2

    This is re-edited version of Lesson 10. The edit was to delete a section, where I have just tested the swap() function. This section got into the final video by mistake.
    --MMS

  • @muxx9992
    @muxx9992 6 лет назад +3

    Modifying the stack and heap size as shown at 10:30 with IAR EW version 8.22 would work only if the project.icf file was already in place. I copied the original TM4C123FH6PMI.icf to Lesson10 directory and renamed it project.icf . By the way the actual MCU type on my Tiva-C board is GH6, not FH6, but the debugger and linker files for both types are identical so this does not matter.
    Dr. Miro - thanks a lot for your dedication! Information density in your videos is challenging the Shannon limit. No doubt it takes hours to prepare one 15 minutes video, and one shouldn't fool himself that learning from it would take 15 minutes either. It is safer to assume each video is a full lesson, 2 academic hours long.

  • @oussamarabhi3262
    @oussamarabhi3262 9 месяцев назад +1

    this is really my first time ever commenting a youtube video, i really wanna thank you for this amazing playlist and for your outstanding explaination skills Miro

  • @mohamadyakteen8710
    @mohamadyakteen8710 5 лет назад +3

    Hello,
    In the final code of this lesson, please move the definitions and initialization of x and y to before the While(1) loop so that the swap function gives different values on each iteration and the result shows correctly on the blinking LED.
    Your lessons are so valuable Dr. Miro, looking forward for new videos...

  • @ilanaizelman3993
    @ilanaizelman3993 6 лет назад +1

    Your videos are amazing! Thank you so much

  • @kapkunal
    @kapkunal 10 лет назад +2

    Waiting for the next tutorials. When will the new tutorials be available?
    Tutorials are very good!!

  • @jfbeltran325
    @jfbeltran325 10 лет назад +1

    hi wanted to know if you can do a tutorial on how to operate the sw1 and sw2 buttons and how to configure the adc (analog digital converter)

  • @xuyan2650
    @xuyan2650 10 лет назад +7

    Thank you for these lessons, they are really helpful.
    I'm wondering when you are going to introduce interrupt later.
    thank you for this again. It make me enjoy embedded systems

    • @StateMachineCOM
      @StateMachineCOM  10 лет назад +1

      Thank you very much for such a nice comment.
      The next lesson 11 is going to be about structures in C, standard integer types and CMSIS. Stay tuned!
      --MMS

  • @rospotrebpozor3873
    @rospotrebpozor3873 9 лет назад +1

    Good C tutorials.

  • @minhvu8893
    @minhvu8893 4 года назад +1

    you should leave int x and y outside of while(1) to see blinking patern interesting

  • @AlexJaja82
    @AlexJaja82 7 лет назад

    Which kind of microcontroller launchpad you would recommend to buy now to follow your course?

  • @andreipopescu6931
    @andreipopescu6931 10 лет назад +3

    Very useful lessons, thumb up from me also!
    As others have suggested interrupts (first the timer) would be a nice addition to the lessons.

    • @StateMachineCOM
      @StateMachineCOM  10 лет назад +3

      Absolutely, interrupts will be covered. But I want to do it right with the CMSIS standard for the interrupt names, etc. So, before getting to interrupts I need to introduce the CMSIS header files. But to do this, I first need to talk about structures in C, as this is how you access the peripherals in CMSIS. So, this will be the subject of the next lesson. Stay tuned...
      --MMS

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

    Amazing series and wonderful work. As a supporter, I would like to point out that in the last demo of the swap function, the declaration of variable x and y must be outside the while loop in order for the led to swapping delay value every time it blinks.

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

      Yes, x and y should be defined and initialized outside the while(1) loop. The corrected project has been updated both in the direct download from state-machine.com/quickstart and on github.com/QuantumLeaps/modern-embedded-programming-course --MMS

  • @GalinaMalakhova
    @GalinaMalakhova 4 года назад +1

    This is my favorite lesson so far. "Sherlock Holmes" hahaha

  • @miguelorrrr
    @miguelorrrr 5 лет назад

    Muchas gracias!!

  • @MohammadHosseinAskariHemmat
    @MohammadHosseinAskariHemmat 10 лет назад +1

    I have worked with LPC1768 before and I found CMSIS very useful. I wonder if you are going to start using CMSIS for the next videos?

  • @nonsense1195
    @nonsense1195 10 лет назад +1

    MMS! I've waited so long for your latest video. thank you for all the lessons they really have been invaluable.
    I wanted to ask if about working with the timers on processor, but first and foremost how to set the clock speed, it is possible with the SysCtlClockSet(....|....|....|....); library function however i am unable to do it from scratch using the RCC registers and initialising the PLL
    no-where the state machine forum a few months back and no one has been able to help!
    please advise!!

  • @nikhileshk7047
    @nikhileshk7047 4 года назад +4

    26:46 To see the LED blinking as expected (activated by the 'swap function'), the x and y variables are to be outside the while (1) endless loop which means they have to be initialized only once. Otherwise it makes no sense. Just saying.

    • @tea-noodle
      @tea-noodle 3 года назад

      I was going to say, that variable placement didn't make any sense. I thought I was rusty and I was wracking my brain to figure out how it could work on his machine.

  • @abdelrahmanelashry7926
    @abdelrahmanelashry7926 5 лет назад +2

    First off, Thank you for the wonderful videos!
    Can you please provide me with a reference so I look more into the whole ( Using the heap causes more harm than good in real time applications ) ?
    I don't seem to understand why does dynamic memory allocation could do harm?
    Thanks!

    • @StateMachineCOM
      @StateMachineCOM  5 лет назад +3

      Using dynamic memory in embedded real-time systems typically creates more problems than it solves. Here is my blog "A Heap of Problems", which explains why: embeddedgurus.com/state-space/2010/01/heap-of-problems/

  • @ThangQTran
    @ThangQTran 4 года назад

    26:23 Could you please explain to me, what is the difference between global and static variable in this lesson? Thank you.

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

      Global variables are typically declared in a .h header file (with the "extern" keyword) and then used in many .c source code files that #include the header files. In contrast, local variables are declared and defined in a single .c source code file (with the "static" keyword) and used exclusively in this file. So, even though both global and static variables have the same lifetime (the whole duration of the program execution), they have different scope and visibility. Globals have global scope. Static variables have local scope. For better programs, it is recommended to use as narrow scope as possible. --MMS

  • @adityakapoor8055
    @adityakapoor8055 8 лет назад

    Based on the first example, we see the maximum top limit of the Stack is at 0x20000000 (i.e. at the beginning of the RAM). However, when we forcefully change the size of the stack, are we changing the location of this top limit or is the top limit always fixed at 0x20000000 and the starting location of the Stack changes based on the size we allocate to the Stack? Also, what happens to variables stored in the 'regular memory' when the Stack expands towards the beginning of the RAM?
    Also, where exactly in memory is the Heap located (when it has non-zero size)?

    • @StateMachineCOM
      @StateMachineCOM  8 лет назад +1

      +Aditya Kapoor I'm not sure when the top limit of the Stack is at 0x20000000 (?) The stack grows towards lower addresses (down), so the beginning of RAM is the bottom limit, not the top limit.
      But perhaps you are confusing the "top stack limit" with the current value of the SP register, which is current top of stack (?)
      The question about stack overflow is easy. The stack corrupts everything in its path, so the content of variables in the "regular" RAM is destroyed. This is obviously not good.
      Finally, the question about the location of the Heap. This you can see when you look into the linker script file "project.icf". Specifically, at the very bottom of this file, you can see that the block HEAP is allocated after (above) the block CSACK.
      --MMS

  • @VTeslaV
    @VTeslaV 10 лет назад +2

    can i use the STM32F4 Discovery in this series?

    • @StateMachineCOM
      @StateMachineCOM  10 лет назад +3

      The IAR EWARM KickStart supports the STM-Link hardware debugger, which is built-into the STM32 Discovery boards. So you can use the STM32 Discovery boards with the IAR toolset. But you need to understand that the project files for the TI LaunchPad board won't work on the STM32 board. That's because the addresses of GPIOs and other peripherals are different.
      --MMS

  • @rolandoaguilera3114
    @rolandoaguilera3114 7 лет назад

    Another approach instead of using static keyword is using the heap right? Both methods have the same result?

    • @StateMachineCOM
      @StateMachineCOM  7 лет назад

      Using heap memory (malloc()/free() in C) is very different than using static variables. In programming embedded systems, using the heap is typically a bad idea. See the blog post "A Heap of Problems" embeddedgurus.com/state-space/2010/01/heap-of-problems/

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

    @Miro, Can you please provide some insight about any pitfalls of using local or global variables, and when to use one over the other? Perhaps point to where I can find reliable information on the topic? In practice I always opt for global variables because it seems to be less complicated to use than local due to restrictions associated with the latter (like the one you mention in this video). For context, I write embedded C code for C2000 family of DSPs from TI using CCS. I am no embedded systems expert by any stretch of the imagination but I am growing increasingly curious about the field.
    Thanks in advance!

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

      Global variables should be used very judiciously. The real problems with them start when you use them in interrupts and/or threads of a Real-Time Operating System (RTOS). I talk about the problems with shared global variables in the later lessons, but specifically in lesson-20 "Race Conditions" and lessons 22-28 about the RTOS. But there is much more to the problem of global variables than to say "don't use them". The real help is to show how to replace global variables with safer mechanisms. And this is exactly the subject of even later lessons in this course, where you learn about object-oriented programming, event-driven programming and the Active Object design pattern. All these lessons are already available, so please watch them. Also, more lessons about the subject of avoiding sharing global variables are on the way. Stay tuned! --MMS

  • @ivanhu
    @ivanhu 5 лет назад +2

    Hi Miro, thank you for this incredible well presented and easy to follow knowledge. This would cost a few thousand dollars at a university and I am very grateful.
    However, I THINK there is an error in the code. You said the purpose of the swap function is to make the blink pattern more interesting. You initialise the x and y variables as 1000000 and 1000000/2 respectively within the blinking loop and then swap the variables, so x and y actually have the same values for every iteration of the loop. Doesn't that kind of defeat the purpose of swap()?
    I apologise if this has been pointed out years ago. I just want to verify that what I have observed and concluded is correct.
    Again, thank you.

    • @StateMachineCOM
      @StateMachineCOM  5 лет назад +2

      Yes, good catch. The variables x and y should be defined and initialized OUTSIDE the while(1) loop. Otherwise, as it is now in the code, the swap() function will always end up setting p[0] to 1000000/2 and p[1] to 1000000, which will obviously not vary the blinking pattern. --MMS

  • @HeliosFire9ll
    @HeliosFire9ll 8 лет назад

    Hey QP, I'm not very sure what you mean when you put static on the tmp array. You said that the tmp array operates outside of the stack when you give it static and place it into memory. But isn't the stack the memory? Also for the concept of what static is, I've interpreted it as a keyword for a local variable not to be erased when the function returns.

    • @StateMachineCOM
      @StateMachineCOM  8 лет назад +1

      +Helios Fire The stack is just a region in memory (RAM). But of course, there is more memory than just the stack. So, the "static" variables also go into the memory, but they are allocated *outside* the stack region.
      The "static" keyword has many (too many) meanings in C. But a "static" variable within a function means that the variable lives on after the function returns (it lives even before the function is called). In other words, such a "static" variable takes space in memory all the time. This is in contrast to the "automatic" (stack-based) variables, which exist on the stack during the function call and they become invalid (possibly overwritten) after the function returns.

  • @ZnSstr
    @ZnSstr 7 лет назад +5

    man this seems so hard, I mean I know programming, but for doing this correctly is a lot of things to understand. how much does it take to learn?

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

      a life time. you just have to start and never stop.

  • @neharay9789
    @neharay9789 6 лет назад +2

    Thank you very much for these awesome videos. The explanation is so clear and precise.
    I have 1 doubt in this video in the following sentence. "But somehow, the CPU executes this data as legit 16-bit instructions, whereas it takes two disassembly steps per each 32-bit data value." How can the cpu recognize the vector table addresses as valid opcodes? why does it not throw an illegal opcode instruction?

    • @StateMachineCOM
      @StateMachineCOM  6 лет назад

      The vector table in this case is very short and contains only either zeros or one address 0x0000010f (please view lesson#14 to see the complete vector table). Viewed as 16-bit instructions, the opcodes are 0x0000 and 0x010f. It turns out that these are somehow legit opcodes that don't cause any CPU exceptions and don't do anything harmful either (as far as I can tell). --MMS

    • @neharay9789
      @neharay9789 6 лет назад

      Thank you very much for the clarification. It is clear now that coincidently the two addresses 0x0000 and 0x010f correspond to legal opcodes.

  • @edwintjoa6099
    @edwintjoa6099 5 лет назад

    When the swap function returns tmp array. How come p[0] is *x and p[1] is *y since *x and *y is never returned? Confused with pointers. Please advise.

    • @StateMachineCOM
      @StateMachineCOM  5 лет назад

      The code of the swap() function at time ruclips.net/video/jmzvued3w3Y/видео.html is intentionally *INCORRECT* to demonstrate why returning pointers to local variables is wrong. A faulty code like that can cause all sorts of unexpected things. For example, the variables x and y are also on the stack (because they are local variables of the main() function), and it just so happens that p[0] holds address of x (&x) and p[1] holds address if y (&y). --MMS

    • @edwintjoa6099
      @edwintjoa6099 5 лет назад

      @@StateMachineCOM Thanks for your prompt reply and explanation!!

  • @sunnychan950
    @sunnychan950 8 лет назад

    at 12:55 when you subtract 0x18 from the SP. was the value of the SP 0xb086? If so 0xB086 - 0x18 = 0xB06E, but we see the next address show a value of 0xA900. Shouldn't the value at memory addres 0x04 be 0xB06E and not 0xA900?

    • @StateMachineCOM
      @StateMachineCOM  8 лет назад +1

      +Sunny Chan It seems to me that you might be confusing the SP register, which points to the top of stack in RAM, with the PC register, which points to the current instruction in ROM. I'm saying this, because you subtract 0x18 from the PC value 0xB086 in ROM (visible in the disassembly view). Instead, you should subtract it from the SP (visible in the register view). The arithmetic for the SP is as follows: 0x200003F0 - 0x18 == 0x200003D8. Please notice that you can always tell ROM addresses, like 0x0000B086, from RAM addresses, like 0x200003D8, because the RAM starts at 0x20000000.

    • @mohamedanas4323
      @mohamedanas4323 4 года назад

      @@StateMachineCOM thanks for clearing my doubt . i was about to ask the same

  • @Denis-di6hc
    @Denis-di6hc 8 месяцев назад

    how about Stellaris LM4F120? Is it suitable for this course? Thx

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

      Yes, the Stellaris EK-LM4F120XL board is equivalent to the TivaC LaunchPad. The Stellaris board has been out of the market for 10 years, but if you still have one of those, you *can* use it in this course. --MMS

  • @HeliosFire9ll
    @HeliosFire9ll 8 лет назад

    Also how did you plan for the return address to be odd? I didn't see you change you're code so it'd specifically return an odd address.

    • @StateMachineCOM
      @StateMachineCOM  8 лет назад +1

      +Helios Fire As a programmer, you don't do anything special to ensure that values loaded to the PC are always odd. This is arranged by the hardware in the CPU and by the compiler. For example, the instruction BL (for calling functions) loads the LR register with the address of the next instruction after BL (to return from the function). This value in LR will be odd, because the CPU will set the bit-0 in LR to 1, so that when the LR will be loaded back to PC (to return from the function), the PC will be also odd.

    • @smaroukis
      @smaroukis 11 месяцев назад

      @@StateMachineCOM I thought previously you said that the return address has to be even, and the POP to PC instruction is set by the CPU by setting the bit-0 to 1. Is that correct?

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

      @@smaroukis No, it doesn't sound correct. I said that POP to PC (or BX) does not change the bit-0 in the PC (which must remain 0). Instead, bit-0 of the source is loaded into the T-bit (Thumb bit-24) in the PSR. --MMS

  • @ahsanbaig74
    @ahsanbaig74 4 года назад +1

    no doubt, I am not from embedded background but at least, THIS video is getting difficult to UNDERSTAND, all previous videos were also difficult for me but at the end, I UNDERSTOOD ALL, but this one I don't know what is happening in it,

  • @HeliosFire9ll
    @HeliosFire9ll 8 лет назад

    I've gone back to lesson 8 but I'm still not sure why the return address needs to be odd. In my computer architecture class a 32 bit system goes to next memory space by 32 bits or 4 bytes. We see 0x1000, 0x1004, 0x1008, 0x100C. As you can see all of them are even. I've tried to find the explanation on lesson 8 but I'm at a loss.

    • @StateMachineCOM
      @StateMachineCOM  8 лет назад +4

      +Helios Fire The return address loaded to the PC is NOT the literal address in the memory. Instead, the ARM Cortex-M CPU loads only the address bits A1-A31 to the PC bits 1-31. (The PC bit 0 is not really used and is always zero). The return address A0 is loaded not to the PC, but to the Status Register T-bit (Thumb instruction set). Since Cortex-M supports only the Thumb instruction set, the A0 bit must be 1. (If A0 is not 1, the CPU will enter an exception, because it will not be able to execute the code.) So, that's why the return address must be odd (A0 bit must be 1). I hope this clarifies this issue a bit.

    • @sunnychan950
      @sunnychan950 8 лет назад

      +Quantum Leaps, LLC
      So the reason why the return address loaded to PC is odd is because it is using bits 1 -31(odd because 31 bits are odd) instead of bits 0 -31(even because 32 bits are even)?

    • @gergelycsontos1435
      @gergelycsontos1435 5 лет назад +2

      @@sunnychan950 I know it's been 2 years, but you never got your answer.
      Parity has not much to do with the number of bits used in the representation. It only depends on the bit 0, if it's 1 -> number is odd, if 0 the number is even. The address saved on the stack must be odd, because the bit 0 is not part of the address actually, but a flag to the core that it shall use Thumb instruction set for execution.

  • @mertaliturk650
    @mertaliturk650 9 месяцев назад

    but lesson-8 you said that return adress must be even , but in this lesson you are saying it must be odd , ı am confused , can you help me please?

    • @StateMachineCOM
      @StateMachineCOM  9 месяцев назад

      In a sense both statements are correct! The return address must be *even* because THUMB-2 instructions are aligned at even addresses. At the same time, the least significant bit (LSB) of the address must be 1 (which makes the address odd) because it indicates the mode of the processor (THUMB mode in this case). Those two contradicting requirements are reconciled by the fact that the LSB is *NOT* used for addressing (it was used for mode changes between ARM and THUMB mode). However, after explaining all this a couple of times, I cannot always repeat that every time I mention the word "address". On a side note, the use of the LSB for the mode changes of the processor is a vestige from the history of the ARM CPU. This anachronism makes no sense in Cortex-M (which supports only THUMB mode) but exists only because of the evolutionary history. --MMS

    • @mertaliturk650
      @mertaliturk650 9 месяцев назад

      @@StateMachineCOM I understand very well , thank you so much for help mr.Samek , you are the best!

  • @EmbeddedSorcery
    @EmbeddedSorcery 5 лет назад

    Of course... if that $7000 IDE from IAR had some basic smarts like many free programming environments..... it would be much harder to make little errors like that. Embedded development is still locked in a hell of cascading costs unfortunately, thanks to some ridiculous big name engineering companies. *cough* Analog Devices

  • @kuriotsportokalis
    @kuriotsportokalis 6 месяцев назад

    On Keil MDK even on -O0 the compiler does not allow any of the interesting stuff to happen.

    • @StateMachineCOM
      @StateMachineCOM  6 месяцев назад

      Yes, that's true that the KEIL-MDK project for lesson #10 fails differently than the IAR-EWARM project. But that doesn't mean that the failure is not "interesting". Please, set a breakpoint at x = fact(9U); and then set the memory view to watch the stack. Then single step at the assembly level and observe that the return address (0x00005F7) *is* corrupted by the parameter n==9. What happens from that point is complicated, but in my debugger, it spins a long time inside the fact() function. Much later, the program fails. This is also an interesting lesson that the failure caused by stack overflow is so unpredictable. Different compiler or even different compiler options change the failure mode completely. Isn't this scary? I hope it is, so that you will NEVER want this to happen in YOUR programs... --MMS

    • @kuriotsportokalis
      @kuriotsportokalis 6 месяцев назад

      For me it seems to stop calculating after fact(5U), the addresses on the stack never get corrupted and the program always returns 0x78 @@StateMachineCOM
      Edit: it seems the board was unable to reset to new state unless a hard reset was first done (this is permanent) . If this was caused by the stack overflow or something else I do not know.

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

    Ich think that the original "crime" was to implement factorial with recursion, instead of a simple loop which does not grow the stack the higher the number is.
    I know, you did this to intentionally provoke a stack overflow for teaching purpose. And you might have mentioned this in your last video. Still, I have seen factorial in so many beginners courses as an "elegant" solution (which it is - from the mathematical point of view), but also I think that beginners should very early be taught that it is not always the best solution in programming, for this very reason (stack overflow). There are cases where recursion can solve a problem very nicely - when the depth is guaranteed to be low and you know what you do, e.g. when parsing known data structures. But they should also be encouraged to consider a linear implementation as well. Just to be aware of the possible pitfall.

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

      Absolutely, recursive factorial is a horrible idea. Also, recursion of any kind is typically a BAD idea in embedded programming, because of the excessive stack use and possibility of stack overflow. As you will see in the later lessons about the RTOS (Real-Time Operating System), you would need multiple stacks for each RTOS thread, which exacerbates the problem even more. But in a short lesson like this, recursion was just an *excuse* to demonstrate stack overflow. --MMS

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

      I see, we are on the same page :-). BTW, your programming course videos are with the best I have seen, because they have a clear curriculum, consider all layers of interest interactively (hardware, UML, C-code, assembler, memory view), to give always a sound understanding of what's going on. They are well explained and give the time to understand. I am coming from rather higher level embedded Linux/C++ where I did not have to care about low level things like stack size and scheduler details. Now I have a project on a cortex M4 with RTOS, and I am very thankful to actually see the mechanisms behind it here. Learned a few things!