#23 RTOS Part-2: Automating the context switch

Поделиться
HTML-код
  • Опубликовано: 14 апр 2018
  • In this second lesson on RTOS, you will see how to automate the context switch process. Specifically, in this lesson, you will start building your own minimal RTOS that will implement the manual context switch procedure that you worked out in the previous lesson-22.
    --------
    Resources:
    Find MiROS on GitHub:
    github.com/QuantumLeaps/MiROS
    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/...
    ARM Community blog post: "Cutting Through the Confusion with ARM Cortex-M Interrupt Priorities":
    community.arm.com/iot/embedde...
    Music credits:
    The background music comes from:
    www.bensound.com/royalty-free...
  • НаукаНаука

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

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

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

  • @isahilliogluu
    @isahilliogluu 3 года назад +9

    Vow! This is just awesome! An RTOS from scrach, step by step, by debugging, trials and errors. Appreciated so much.

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

    This series continues to get better and better. Thanks for the effort!

  • @tzacks_
    @tzacks_ 6 лет назад +5

    one of the best tutorial series on yt, keep it up miro.

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

    Thank you Dr. Samek - impressive material.

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

    Hey, glad to see your update. really like "MIROS" name! Thank you.

  • @qwertybrain
    @qwertybrain 4 года назад +2

    Wow. An incredible tutorial. Thank you.

  • @rijoabraham0205
    @rijoabraham0205 6 месяцев назад +1

    Thanks Miro for this great course…
    For the fellow learners, in Keli uVision, it’s possible to trigger the interrupts manually using the Peripherals -> Core Peripherals -> NVIC window… Just a different way to trigger the interrupts using the IDE… 12:02

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

    Awesome stuff Miro.. looking fwd to the next lesson.

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

    MiROS! I see what you did there! Great series!

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

    Thank you so much Miro! Looking forward to OOP in C!

  • @piotrjaga6929
    @piotrjaga6929 5 месяцев назад

    This is EXACTLY what i was looking for

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

    Hi Dr, this is totally amazing and wild. Thank you so much.

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

    Excellent tutorial series! I've binge-watched and liked all of them over the course of a week. But now we are left at a cliff-hanger! (automating scheduling). When will you upload part 3? :D

  • @04mfjoyce
    @04mfjoyce 2 года назад

    Fantastic videos...thank you again!

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

    you are a great teacher

  • @zDoubleE23
    @zDoubleE23 3 месяца назад

    So far, this series reminds me of a song where tension keeps building and building with every video but without a release. Just when I think the release is there, something pops up where the previous code is flawed and more tension is built. Very informative series but it appears the viewer digs deeper on what not to do.

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

      Your impression is correct. I strive to present the RTOS fairly by discussing its benefits, but also its flaws. In the end, however, I don't believe that the traditional blocking RTOS invented in the 1980's is still the best solution in the 21st century. In my opinion, the event-driven, non-blocking approach is superior. --MMS

  • @Ne3M1
    @Ne3M1 5 лет назад +1

    This unfolds like a crime thriller!

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

    I've gained so much confidence as an embedded systems developer by watching your videos. Now I just need advice on how to land my dream job as embedded systems engineer at SpaceX. 😁

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

      Keep it up!, any update on the job?

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

      @@jamate living the dream now programming machines that won't go to space any time soon but it's a step forward.

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

      @@rjgonzalez8108 congrats man!

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

    Great Teaching

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

    Sin duda el mejor curso que he estado siguiendo respecto a programación embebida. Compré el Tiva-c por casualidad y esta serie de videos me vino como anillo al dedo.
    Saludos desde México!

  • @StateMachineCOM
    @StateMachineCOM  9 дней назад

    The code uploads for this lesson #23 as well as #24, #25, and #26 have been updated for the STM32 NUCLEO-C031. The updates were necessary because the STM32C031 is a Cortex-M0+ CPU, for which the provided assembly didn't compile (ARMv6-M architecture is limited compared to ARMv7-M like in Cortex-M4). The provided code now should compile for both ARMv6-M and ARMv7-M architectures. --MMS

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

    Thank you!

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

    Thank you sir

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

    Awesome!!!!!

  • @ManishSharma-qs3sv
    @ManishSharma-qs3sv 5 лет назад

    I am obliged and highly thankful to the author of this video who gave the best in class insight about the scheduling mechanism.
    Regards,
    Manish

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

    Hi Miro. I see that you separated BSP code and data from OS code and data, is the goal to make the OS package arch-independent?

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

    Damn it gets a bit harder!
    Nice lessons!

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

    So easy to understand that I actually watched it at double speed; when will RUclips give us quadruple speed.

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

    Hi, at first thank You for Your great work.
    I cannot understand why we need to prefill this stackpointer / stack by register addresses. Do we not need only the PC (function address) and the compiler has this information to fill the stack when preemption starts and finishes ? What the compiler / proccessor do with this prefill values ?

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

      You're right that the only values needed on the stack are the entries corresponding to the SPSR and PC. And the context switch will work just fine if we left the other entries at 0, or whatever. But pre-filling the stack with some easy-to-recognize values helps a bit in debugging. Just set a breakpoint at the beginning of any thread function and, after the breakpoint is hit, see what's in the CPU registers (the Register view). I hope you'll immediately appreciate the pre-filled values because it will reassure you that the initial context was "restored" correctly. --MMS

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

    Hello Sir,
    Could you please elaborate why we do OS_curr->sp = sp in the PendSV handler if body, because it will always be overwritten by OS_curr = OS_next without being used in between.
    Thank you

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

      First, you need to distinguish between OS_curr->sp, which is the stack pointer of the current thread, and OS_curr, which is a pointer to the current thread. I hope you can see that these are different things. And second, the order of instructions matter, so OS_curr->sp is set *before* OS_curr is changed. --MMS

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

      Thanks sir, I will have to calmy rethink it myself, I did it in practice and works well.

  • @PawanKumarYouTube
    @PawanKumarYouTube 6 лет назад +7

    Sir, we also notice the name of the OS, MIROS carries your name : ) Great Teacher......

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

      He did that on purpose!

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

    @Quantum Leaps, LLC
    34:03
    lool ...yeaaah I can see it apparently!
    BTW : in the first minutes in this video when you were writing the code I was crazy and pulled my hair ...why did he left the (&) before that pointer !? .... now I won

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

    Hi Miro, thanks for the nice courses. I am just wondering if you have tried to test your code in Microsoft Visual Studio?

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

      If you mean Visual Studio Code, this is just a code editor. Perhaps you could use it to build projects originally produced with KEIL uVision, but it's some work. If you mean the full-fledged Visual Studio, this is for Windows development, and I don't see how it applies to embedded software, especially when it comes to debugging on target. --MMS

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

    Great presentation, i just have one question, why can we not Implement PendSv handler in C, why we need to implement it in assembly. the compiler seems to be doing a great job dissambling, and as for the stack pointer, we can access a global variable pointing to it i think it is __stack, something like that. thanks

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

      The context switch coded in PendSV_Handler performs things that are outside the standard C, such as pushing very specific registers to the stack. It is also obviously CPU-specific (ARM Cortex-M4 in this case). For these reasons you cannot code it in C, even with some extensions. (BTW, the __stack "variable" typically contains the address of the top of the C-stack. This is not what you need here.) --MMS

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

    I have two doubts
    1)Context switching is happening at the end of any interrupt but if itself interrupt is changing those registers then it may create problems
    What is the solution then?
    2)is pendsv interrupt is get triggered automatically after each systick interrupt or we need to do manually in systick interrupt handler?

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

      The interrupt code (ISR) is generated by the compiler, which *knows* which registers are preserved and which are not in hardware (the calling convention). Therefore, the compiler will *not* clobber any registers that are not preserved by the callee.
      The PendSV interrupt is triggered in the OS_sched() function, but only if context switch is needed (see the statement `if (OS_next != OS_curr)...`.
      --MMS

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

    can you suggest us a book for this material?

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

      I'm reading "The Definitive Guide to Arm Cortex M3 & M4" as I watch these videos. I think the book and the course complement each other well on this subject.

  • @MohamedAhmed-wr9mf
    @MohamedAhmed-wr9mf 5 лет назад +2

    Hello Sir ,
    Thanks for this nice and helpful description of RTOS , I've question regarding systick interrupt 9:40
    why if we write context switch code in systick handler we need to add it in every ISR implemented in the system.

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

      I also did not get it.

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

      I think I understand it now.
      It is described fairly good at page 194
      books.google.ru/books?id=5OZblBzjsJ0C&pg=PA194&lpg=PA194&dq=why+to+use+lowest+priority+interrupt+for+task+switching&source=bl&ots=m3gOboMkMl&sig=ACfU3U1br7y-WYhRDMoutWoe-PvzLCJp2A&hl=ru&sa=X&ved=2ahUKEwiinvbdwovpAhUJzaYKHT14BxIQ6AEwC3oECAoQAQ#v=onepage&q=why%20to%20use%20lowest%20priority%20interrupt%20for%20task%20switching&f=false
      The core idea is that we should do context swithcing only if we are NOT in nested interrupts, so we do in in the lowest proirity interruprt

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

    Thanks for the video. I am trying to better understand the concept at point 7:45 in the video. What does integer division by 8 followed by integer multiplication by 8 actually do? I understand we are talking about the concept of alignment, but why these numbers in the math?

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

      Perhaps the best way to understand the stack alignment method used in the video is to apply the arithmetic to a number that is aligned at 4-byte boundary, but is NOT aligned at the 8-byte boundary. (The end of array of uint32_t numbers is going to be aligned at 4-byte boundary, but not necessary at 8-byte boundary). So, for example take the number 52. Now calculate (52/8)*8 using *integer* division. The result is 48, which is both 8-byte aligned and does not exceed 52 (exceeding 52 would go beyond the end of the allocated array).
      I hope that it starts to make more sense now... --MMS

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

    Why is it that in the assembly code for PendSV_Handler, first the address of OS_curr is loaded to r1, and then in the next instruction the value of OS_curr is loaded to r1. Why not just execute the code that loads the value?

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

      ARM CPU is the so called "load-store" architecture (see en.wikipedia.org/wiki/Load%E2%80%93store_architecture ). This is part of being a RISC (Reduced Instruction Set Computer) architecture. This means that the CPU must always go through its registers to get or put anything to/from the memory. More specifically, to get any value from the memory, the CPU must first prepare the memory *address* in one of its registers, and only then it can load (LDR) the value in another or the same register. Most commonly an *address* of a variable is prepared in a register by means of the "PC-relative" LDR Rx,[PC,...] instruction, where Rx is the destination register. The PC (Program Counter) points to the program (code) memory in ROM. So, a PC-relative address is grabbing the data from ROM, which is exactly what you need because the address of your variable is a constant, so it can be placed in ROM. --MMS

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

    Hi Miro,
    Some questions:
    1. should there be a check on the stack size argument in OSThread_start to ensure it's at least bigger than the set of registers to be pushed?
    2. to round up/down the stack pointer, would the use of mod (%) be more obvious?
    Thanks! I can't wait for new videos on more advanced topics!
    (perhaps say, a real OS and/or RTOS with BSP and bootloader, networking, code optimization, and maybe even DSP stuff).
    E

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

      (1) Yes, a check for the minimum stack size could be added to OSThread_start(). Better yet, I would actually put there an assertion. (2) I'm not sure the the modulus (%) operator is more "obvious" to round the stack. (3) As to explaining the other components of a "full-blown" RTOS, it requires a specific MCU with networking, DSP extensions, etc., which TivaC does not have. This would also go into minutia of a specific chip. Generally, I have a bigger fish to fry in this course. I still need to explain blocking, priority-based scheduling and RMA. After this, I would like to finally leave the 1970's and move on to more modern stuff, like object-oriented programming, event-driven programming, state machines, active objects, etc. Stay tuned... --MMS

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

      Quantum Leaps, LLC thanks for the reply Miro!
      2. By using mod I meant this: (to round down, cast stack pointer to uint32_t, and do this: stack_top_p -= stack_top_p%8; To round up: stack_btm_limit_p += 7 , and then round down!). Do you think this will work?
      3. That's awesome, please touch on *some modern embedded hardware and hardware architecture topics too (NAND/NOR/eMMC, ethernet, wi-fi, bluetooth, DMA, etc.).
      4. Please also introduce useful debug constructs like asserts and modern debuggers like JTAG and ARM ETM.. a dedicated session on debug with intro to debugger HW and writing debug-able code would be great!
      E

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

    IAR
    Error[Ta147]: Unknown symbol "OS_Curr" referenced from inline assembler
    Error[Ta147]: Unknown symbol "OS_Nex" referenced from inline assembler
    i cannot find a solution to this issue, in KEIL you used the IMPORT directive but that doesnt work for IAR

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

      The IAR project for lesson 23 has been added to the project downloads on the companion web-page www.state-machine.com/quickstart/ . Please download lesson23_iar and try it. --MMS

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

    Hi Miro, I am using MDK-ARM Version 5.37 with V6.18 compiler. When PendSV_Handler temporary C code was replaced with assembly code and modified exactly as in the lesson, after I ran BUILD, I got the following errors - 1) in __asm line: "expected ';' after top level asm block __asm" 2) in void PendSV_Handler (void) line: "expected '(' after asm" 3) in IMPORT OS_curr line: "use of undeclared identifier 'IMPORT'". I debugged this issue by building simple inline assembler code from ARM documentation - line 1: int qadd(int i, int j) { line2 int res; line 3 __asm lines 4, 5 and 6 { QADD res, i, j } lines 7 and 8 return res; } The build of this code produced the error on line 4 - "expected 'volatile', 'inline', 'goto' or '('. The line 4 was '{'. What could be an issue? I had not seen such errors before. Could it be configuration issue, tool bug or corrupted tool? Have anybody seen such behavior?

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

      As I explained in the pinned comment to this video, the compilation errors are caused by the new "Compiler-6" shipping with the newer versions of MDK-ARM. This "Compiler-6" uses a different syntax for the inline assembly than the previous, now obsolete "Compiler-5". To compile the code with "Compiler-6" you need to update it to the new syntax. But all of this is already done for you in the project downloads for this lesson. Please simply visit the companion web-page to this video course at state-machine.com/quickstart and download the file lesson23.zip . Of course, you can compare the new code updated for "Compiler-6" with your code. When you do this, I'm sure you will notice that this is exactly the same assembly, merely written using a different syntax. --MMS

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

    could someone re-explain to me, why it is necessary to push the r4-11? Why and what is the consequence of not doing so.

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

      First of all, the what really needs explaining is that regular ISRs on ARM Cortex-M can get away *without* saving r4-r11. And this is possible because of the AAPCS convention. But AAPCS requires a function (such as ISR) to return to exactly the same place where it was "called from". So, as long as an ISR returns to exactly the place of preemption, AAPCS is not violated. But in an RTOS, an ISR does *not* return to the point of preemption, but rather to a *different* thread (context switch). And this violates the AAPCS bargain. Therefore, *all* registers must be saved, and this included r4-r11.

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

    while compiling I am getting below errors:
    1) STR sp,[r1,#0x00]; LDR sp,[r1,#0x00]; on these lines I am getting ERROR "A1875E: Register Rt must be from R0 to R7 in this instruction".
    2) PUSH {r4-r11}; POP {r4-r11}; on these lines I am getting ERROR "A1874E: Specified register list cannot be loaded or stored in target instruction set"
    I am using Cortex M0 target. May you please able to give me some hints ? what could be the problem ?

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

      Hi , may you please help to solve above errors ?

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

      Even I get same error. I use cortex-M0+ target. Read on the internet that in THUMB mode we couldn't SP register in LDR instruction.
      But cortexM0+ works only on thumb mode. How can it be solved ?

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

    hi , found this line in a vendors startup script.
    /* Flush instruction and data pipelines to insure assertion of new settings. */
    __ISB();
    __DSB();
    so why are they used??

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

      These are intrinsic functions for inserting Instruction Synchronization Barrier (ISB) and Data Synchronization Barrier (DSB), respectively. These instructions are described online at: infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0802b/CIHGHHIE.html . The ISB, DSB, and DMB instructions are important for high-performace cores, such as Cortex-M7. --MMS

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

      Quantum Leaps, LLC Thanks, that was useful.can you please explain a case where without these instructions the code fails....

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

      I would have to send you to the ARM website that explains when to use data and instruction synchronization barriers: infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/CHDGACJD.html and infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka14041.html . --MMS

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

      Quantum Leaps, LLC thanks that cleared my doubt👍

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

    Hi Miro,
    At 6:57,
    1. Why did you cast the void typed stack pointer to unit32_t? Is it because arithmetic is not allowed on void*?
    2. Why did you cast the threadhandler pointer to uint32_t as well? There is no arithmetic involved for that pointer. Why can't it stay with type OSThreadHandler?
    Thanks.
    E

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

      (1) The initial cast (uint32_t)stkSto converts a pointer to a number. This is because I don't want to perform pointer arithmetic. I want to perform number arithmetic. Please also note that the stkSize parameter is size in bytes, not size in (void *). (2) The case (uint32_t)threadHandler is needed to store that pointer on the stack, which is an array of uint32_t. Note that the sp is of type uint32_t. Finally, all such casts are rather dangerous and are disallowed by safety-standards such as MISRA-C. They are needed in system-level software, but you should not take a habit of doing something like this in your "vanilla" application-level code. I hope this makes sense. --MMS

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

      Thanks for the clarification! I can understand it now. It's because those register values you saved are of type uint32_t, not void*. But for the function pointer, you could have temporarily cast the sp to type OSThreadHandler rather than casting the threadHandler to uint32_t, right? Would this work:
      line 41 at 6:57: *--((OSThreadHandler)sp) = threadHandler;
      line 42 *--((uint32_t*)sp) = 0x12345678U;

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

      I just realized that there is a uint23_t requirement for all register values, so even though we are storing a function pointer onto the stack, it has to fit into uint32_t to be able to popped to PC. Am I right?

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

      Casting the left-hand side of assignment operator is always tricky and if you can only avoid it by casting the right-hand side, you should prefer it. Your suggested left-hand side cast is wrong. To work, it would need to look something like this: *(OSThreadHandler *)sp = threadHandler; But, as I said, this is ugly and avoidable by a right-hand side cast. --MMS

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

      Yes, for the 32-bit ARM CPU, the stack consists of 32-bit words (uint32_t). Please note that all this casting is specific to this CPU and is not portable to other processors. --MMS

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

    Hello Sir I am following your Series but i am stuck here in the Arm compiler 5 You used the word IMPRT OS_curr while in the ARM compiler 6 example from your github you did not include the IMPORT OS_curr what's the reason behind this?

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

      The file miros.c contains mixed C and inline assembly, and the rules for inline assembly are compiler-dependent (they are not prescribed by the C Standard). This includes the rules for exporting global variables (so that they are visible to the assembler). Apparently, Compiler-6 (LLVM) does not need to explicitly import OS_curr because it is already declared at the C level at the top of the miros.c file. But you don't need to worry about this. The compiler and linker will tell you if they have trouble locating such a symbol. --MMS

  • @raviranjankishor8960
    @raviranjankishor8960 5 лет назад +1

    Hello Mr. Samek, I want to understand why for the stk_limit did you first subtract 1 from start address of stack before dividing it by 8?

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

      So the inner operation (going to call this x later) (stksto-1)/8 will do nothing if the stack buffer is not 8 byte aligned, but if it is 8 byte aligned it will round down. Then the outer operation (x+1)*8 will add 8 bytes to the result. This means that if the stack was already aligned then nothing will happen, but if it wasn't aligned then the result will be rounded UP to 8 byte alignment.
      Rounding up the pointer to the stack limit actually shortens the loop because the stack actually grows in the downward direction. This way you don't partially write into memory not allocated for you.

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

      And if you want to know why you did the opposite in the beginning, with rounding down, it's because it's happening at the other end, so you're actually bringing the two sides closer together on each end. It was a head scratcher for me too till I sketched it out.

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

    i am still using the IAR IDE, what is the keyword to tell the compiler we are coding PendSV in assembly language?

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

      In IAR you can also code an entire function in inline-assembly. You do this by specifying:
      __stackless
      void PendSV_Handler(void) {
      __asm volatile (
      " CPSID I
      "
      " LDR r1,=OS_curr
      "
      . . .
      );
      }
      For an example of a PendSV_Handler coded in inline-assembly you can take a look inside the qpc framework (used started with lesson 21 and all the following lessons). Specifically, you can examine the file qpc\ports\arm-cm\qk\iar\qk_port.c. This is a file for a different real-time kernel (QK), but the syntax is exactly what you need for the MiROS RTOS.

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

      @@StateMachineCOM thank you very much for the time and effort you put I to these lessons. Also thank you for your swift response to my question.

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

      @@StateMachineCOM it doesn't like the assembly label PendSV_restore. I haven't found a solution on the web as yet

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

      @@StateMachineCOM I think I got it! I placed a : at the end of PendSV_restore at the point where execution should jump to.

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

      @@StateMachineCOMthe
      IMPORT OS_curr
      statement doesn't work and I've been stuck on it for at least 3hrs. I found this on iar help but it still doesn't work.
      IMPORT symbol [,symbol]
      Please help me understand what I'm missing. Thank you!

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

    Dr. Samek - As a beginner when it comes to embedded systems (as well as assembly), I want to thank you for your commitment for these awesome videos.
    As a beginner, I have refactored the `PendSV_Handler` function and welcome suggestions and constructive criticism (from yourself and/or other fans)
    If others want to try it out, just remove the `PendSV_Handler()` function defined in “miros.c”, add a new file called “miros.s” (remember to add it to the project….) and paste the following:
    AREA |.text|, CODE, READONLY, ALIGN=2
    THUMB ; is this needed?
    EXPORT PendSV_Handler
    IMPORT OS_curr
    IMPORT OS_next
    ;******************************************************************************
    ;
    ; Changes:
    ; - removed duplicate 's used to obtain the addr that `OS_curr` points to
    ; - removed duplicate 's used to obtain the addr that `OS_next` points to
    ; - removed 3rd instruction that was used to reobtain `OS_curr` address
    ; and used to change the value at `OS_next` (around `OS_curr = OS_next;')
    ;
    ; Questions:
    ; - Should the `EXPORT` and `IMPORT` directives be before OR inside
    ; the `PendSV_Handler`?
    ; - should `PendSV_Handler` be marked with `PROC` and end with `ENDP`?
    ; (examples of this are in the "startup_TM1C123GH6PM.s" in the project
    ; - is the `THUMB` directives at the start of the section needed?
    ;
    ;******************************************************************************
    PendSV_Handler
    CPSID I ; Disable Interrupts (I=1)
    LDR r2, =OS_curr ; Load address of OS_curr -> R2
    LDR r1, [r2,#0x00] ; Load value from addr held in R2 -> R1
    CBZ r1, PendSV_restore ; IF R1==0; jump to `PendSV_restore`
    PUSH {r4-r11} ; PUSH reg's (R4)-(R11) on the stack
    ; OS_curr->sp = sp;
    STR sp, [r1,#0x00] ; Store value in SP -> addr held in R1
    PendSV_restore
    LDR r1, =OS_next ; Load addr of OS_next -> R1
    LDR r1, [r1,#0x00] ; Load value from addr held in R1 -> R1
    ; sp = OS_next->sp;
    LDR sp, [r1,#0x00] ; Load value from addr held in R1 -> SP
    ; OS_curr = OS_next;
    STR r1, [r2,#0x00] ; Store value in R1 -> addr held in R2
    POP {r4-r11} ; POP reg's (R4)-(R11) off the stack
    CPSIE I ; Enable Interrupts (I=0)
    BX lr
    ALIGN ; Ensure the end of this section is aligned
    END ; End of module

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

      Hi Brandon! I'm glad to see that you delved a bit into assembly programming. At this point, I would recommend that you fork the MiROS project on GitHub (see github.com/QuantumLeaps/MiROS ) and add your changes there. Learning to work with Git and GitHub is a valuable skill in itself. --MMS

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

    In PendSV we can see the assembly does not use registers r4-r11, so why bother pushing and popping them?

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

      The PendSV exception handler is *not* concerned about the registers that it uses. The concern is about the registers that are used by the *interrupted* code, because the interrupted code does not "know" where it will be interrupted. Therefore, the PendSV handler must very carefully save and restore all the registers that the interrupted code *might* have used. --MMS

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

      @@StateMachineCOM right. Thanks for answering. Great video, as always.

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

    Excellent video. I am using ARM compiler version 6.18 and it does not like the inline assembly in miros.c : miros.c(90): error: expected '(' after 'asm'. Anyone has this problem?

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

      This problem is caused by the change of the compiler in the new uVision. Specifically, now only the Compiler-6 (a.k.a. ARM-CLANG) is installed and the old and obsolete Compiler-5 is not. But all projects for this video course have been updated to the new Compiler-6. Please download the projects again, either from state-machine.com/video-course or from GitHub (github.com/QuantumLeaps/modern-embedded-programming-course ). --MMS

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

      @@StateMachineCOM , thank you so much!

  • @ovais217
    @ovais217 2 года назад +1

    For beginners (like me) having problems compiling the assembly code, you need to install arm-compiler version-5.
    Specifically you can download the version from here : developer.arm.com/downloads/-/legacy-compilers#arm-compiler-5
    Make sure to install it inside the Keil folder to avoid issues,
    for e.g: C:\Keil_v5\ARM\ARM_Compiler_5.06u7\
    Then follow the instructions on this page:
    developer.arm.com/documentation/101407/0537/Creating-Applications/Tips-and-Tricks/Manage-Arm-Compiler-Versions

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

      I got this error still : .\dbg\lesson.sct(7): error: L6236E: No section matches selector - no section to be FIRST/LAST.

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

    IMPORT OS_curr doesn't work with IAR, any solutions please

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

      Inline assembly is a non-standard extension, so every compiler implements it differently. So, what works for ARM-KEIL apparently does not work for IAR. But I've created a working version for IAR. Please visit www.state-machine.com/quickstart/, scroll down to lesson23 and download lesson23_iar.zip. --MMS

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

      Thank you very much for the time you put into this to pass on your expert knowledge! YOU ARE AWESOME!

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

      @@StateMachineCOM it appears this example you created has the same error with os_curr and os_next

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

      @@StateMachineCOM I think I've tried every resource available online to find the a fix to the problem. I even tried moving on using keil mdk but having issues transporting the code😔

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

    Hi, Can you explain it for me about :
    1. Why do we need use PendSV exception (or other exception) to use for context switch without using context switch directly in System Tick Handler?
    2. Can you explain more about: PendSV need to code by assembly language?

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

      First: why PendSV is used? This is because interrupts in ARM Cortex-M can nest (the NVIC is called "Nested" Interrupt Controller for a reason!). This means that while you service an interrupt *another* interrupt (such as SysTick) might preempt. In that case, the SysTick will return back to the preempted interrupt and NOT back to a thread context! This means that it would be *WRONG* to perform a context switch right in SysTick! The trick is to perform the context switch in an interrupt/exception that is guaranteed to be the *last* in the chain of nested exceptions. The PendSV exception has been specifically designed for that, but you must be *careful* to assign it the lowest interrupt priority of all (0xFF for the reversed interrupt priority scheme used in the NVIC).

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

      And the second question: why PendSV cannot be coded in C and has to be coded in assembly? This is because PendSV needs to mess with the SP (Stack Pointer) and other CPU registers. All this is obviously very specific to the CPU and cannot be done in standard C, which is a CPU agnostic language.

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

      @@StateMachineCOM Hi, thanks for the explanation! Is my understanding correct? 1, If the SysTick prempt other interrupt, and we do context switch in SysTick, then we will switch to other thread instead of the preemptd interrupt, this will cause problem since we did want to back to the preempted interrupt in this case. My question is, what if we make SysTick lowest priority? Then the SysTick will not preempt other interrupt... Is it because of the timing issue? Maybe in this case the context switch will be the lowest priority so it need to wait for other higher priority interrupt to finish?

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

      ​@@StateMachineCOM Because what we want to switch are those threads (tasks, like turn on/off those LED, inplemented in blink1, blink2 and blink3 functions ), but not those interrupts, which will be nested and executed one by one according to their priority level and the context switching for them will be automatically done by function call/return mechanism. So, we can not do the context switching for our threads(tasks) in anyother interrupt handler except PendSV_Handler, cause this is the last interrupt in the nested interrupts chain and we set its priority as the lowest for this purpose. PendSV stands for pendable service vector interrupt.

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

      @@wondererasl I'm not quite sure if I understand the question, but it seems to be about PendSV and its role in handling the context switch. So, consider the following scenario: one task is running (e.g., Blinky1). An interrupt occurs (e.g., SysTick) and immediately preempts Blinky1. The interrupt calls the scheduler at the end, which schedules a new task to run (e.g., Blinky2), so it also pends the PendSV. But before SysTick ISR returns, another higher-prio interrupt occurs and preempts SysTick. That interrupt would also call the scheduler at the end. Now the high-prio interrupt returns, but it should return to SysTick and NOT to PendSV. Luckily this is exactly what happens because PendSV has the lowest priority. Only after SysTick ISR returns, PendSV is entered and only then context is switched. This is because PendSV is guaranteed to be the last exception exited and it returns to the *task* level. I hope this starts to make sense to you... --MMS

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

    I find this error error: expected '(' after 'asm') when I compiled in keil v5 error: expected '(' after 'asm')
    and there is another error about import error: invalid instruction

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

      Keil uVision supports two different compilers. One is called "compiler version 5" and the other "compiler version 6". These two compilers accept different syntax for inline assembly and the code for this lesson assumes "compiler version 6". Please check which one you're using. The place to check is (starting from the top menu) "Project | Options for target..." dialog box, Target tab, Code Generation/Arm Compiler section. --MMS

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

      @@StateMachineCOMFYI to future readers - I received the same error using Keil V5.37 with only default installed Compiler 6, so maybe something has changed in the default Keil_V5 installation? What worked for me was to download/install ARM Compiler V5.06 along side Compiler 6. Prior to downloading Compiler 5, I also tried using the Miros_gnu.c, because the ARM documentation states Compiler 6 only supports GNU style inline assembler statements; However, the (optimize("-fno-stack-protector")) threw an error. What is interesting, now that I have Compiler 5 installed, I no longer get this error even if I choose to compile with Compiler 6. TLDR: Code won't compile with only Keil ARM Compiler 6, must also have Compiler 5 installed, even if only using Compiler 6.

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

      @@brettolson2605 Yes, the ARM/KEIL Compiler 5 is now obsolete and the newer versions of KEIL uVision no longer install that compiler. Instead, they come with the new Compiler 6 (a.k.a. armclang). To match these changes, I will update the projects for all affected lessons to use the new Compiler 6 and I will put them on the state-machine.com/video-course website as well as on GitHub (github.com/QuantumLeaps/modern-embedded-programming-course ). I'm sorry for the problems with the current versions, but this is the cost of progress. --MMS

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

      @@StateMachineCOM
      thx
      I tried your new version and it works , I have no errors now

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

    I'm using CORTEX-M0+ target , getting these errors
    (71) PUSH {r4-r11}
    (78) STR sp,[r1,#0x00]
    (85) LDR sp,[r1,#0x00]
    (96) POP {r4-r11}
    RTOS.c(71): error: A1874E: Specified register list cannot be loaded or stored in target instruction set
    RTOS.c(78): error: A1875E: Register Rt must be from R0 to R7 in this instruction
    RTOS.c(85): error: A1875E: Register Rt must be from R0 to R7 in this instruction
    RTOS.c(96): error: A1874E: Specified register list cannot be loaded or stored in target instruction set
    Read on the internet that in THUMB mode we couldn't use SP register as Rt in LDR instruction.
    But cortexM0+ works only on thumb mode. How can it be solved ?

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

      Cortex-M0/M0+ uses a reduced subset of THUMB2 instructions with limitations. The instruction set distinguishes between the "low" registers (R0-R7) and "high" registers (R8-R15). The "high" registers are restricted and cannot perform LDR/STR or PUSH operations. So, to LDR/STR/PUSH any of the "high" registers you need to first MOV them to "low" registers. --MMS

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

    DEBUG Mode not working on Keil: I was running into a problem where I could not debug the controller anymore. I found this solution online that I am leaving here just in case some else out there runs into the same. : users.ece.utexas.edu/~valvano/Volume1/Window8KeilDebuggerFix.htm

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

      Thanks for sharing, but this has been documented and explained a long time ago in the "Troubleshooting TivaC LaunchPad" application note specially posted on the companion web-page to this video course at: state-machine.com/quickstart. Please just *visit* this web-page and see what's available, because there are many things that you might need. --MMS

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

      @@StateMachineCOM You've really thought this through and through haven't you? Just want to take this opportunity to say that this is an excellent course. Thank you for your work.

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

    If anyone interested to know why systick handler can't execute context switching, watch this video: ruclips.net/video/vlmi7XFY1v0/видео.html

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

    bro this music is hideous, please just let the timelapse of code play without any music, its so annoying