Dear Dr. Samek, I couldn't be more grateful for this incredible course. You explain complex Embedded Systems concepts in the most simplified way I've ever seen. I hope you will release other content in the same way.
Cant emphasise how good this course is. I am completely new to embedded programming but have learnt so much and I am not even half way through. You are doing an amazing job for which we are grateful. Thank you.
The best embedded programming course I've ever found. Highly recommended to all those who want to have a deep understanding of how a microcontroller operates. Thanks Dr. Samek.
Frankly Dr.Samek, I dont know what we have done to get this quality of lectures free of cost on youtube. I feel super lucky that I have access to these lectures. Uptil now, I sort of knew what happens before main, today I actually witnessed (and executed) the magic !! Thank you so much. !!
OK, I definitely had the "Ah ha!" moment of understanding why a device stops responding. Such a good explanation. Now I have to watch it 5 times and about 3 energy drinks to make sure I understand it.
awesome, one of the best tutorials on yt, no kidding. I have a picky correction @18:22: "the LSB of any value loaded into the PC register must be zero" (instead of one)
Thanks for a great lecture! When I disassemble ARM Cortex-M firmware, they often have "Reset_Handler" in the IVT entry of "__iar_program_start" in this lecture. I guess it's due to different vendors or development kits.
thank you - frankly your video is of very high quality - challenging and dense and all the important points. many other video is just a waste of time.....so much time wasters.
When I step through in the disassembly window, it skips over assembly statements. I think it is stepping through each C statement and jumps over all the assembly associated with that C statement. Is there any way to change the settings so that I can step through each assembly statement in the disassembly window?
To step one machine instruction at a time, first click inside the disassebmly window. To go back to stepping one C line at a time, click in the code window. --MMS
@@StateMachineCOM, Wow I really appreciate the quick response! Unfortunately, that's not working. When I click in the disassembly window, it still steps through the C code.
It's time for stupid questions. Why does linker has to copy data from ROM to the .data section that's in RAM instead of put it in RAM immediately What's the benefit of it's been saved in ROM?
It all goes back to the physical properties of RAM and ROM. RAM is *volatile* which means that it loses its content when power is removed. Therefore, when the system first powers up, the RAM has *random* content and it needs to be initialized to some known values. In contrast, ROM is non-volatile and preserves its content even when power is removed. So, upon the power-up, you can trust the content of the ROM and use it to initialize the RAM. I hope this makes sense. --MMS
Good point about verifying the initialization of .bss using the debugger. If I remember correctly Keil's C51 for 8051 required that you manually enter the bss size in some dialog box or config file for STARTUP.A51 to work correctly. For a certain chip this manual step was skipped, and a patch had to be written to take care of it. But of course only after it was finally tracked down after inconsistent behavior was observed.
Hi, I have a question and want to make sure of something regarding to linker and stack. From the video, I saw that in the map file the room for stack (1024) was the linker responsibility. And you have briefly explained it. So, am I right by saying that beside linking the .o from several modules, shared/static/dyamic libs, etc, linker also the one, which reserved or responsible to create room for stack ? And also, I didn't quite understand at 12:44. About "reordered so It could be initiaiized in s single block" and why It's needed. Could you please give a more detailed explanation, Sir ? Thank you before. Warm regards.
First, regarding the stack allocation: While it is possible to allocate the stack as a variable (an array) in the startup code, or even in the application-level code, it is better to leave the stack allocation to the linker. This makes it easier to place the stack in a specific section and to place this section in the most appropriate memory (some MCUs have more than one RAM block to choose from). Second, regarding the "reordering and consolidating the data section": You define the various global or static variables throughout the code, so you might have hundreds or even thousands of pieces of data scattered around. The linker consolidates all these pieces into one contiguous .data section. This section then can be initialized in a single block-copy, which is faster and requires far less code than initializing each individual variable separately. I hope this makes sense.
Ah, I see .. Your second answer makes sense for me. But, regarding to your first answer, I'm still struggling to understand, what you're trying to convey. As far as I know from your previous lectures, stack used for local variables and for saving return address. And the range of the memory will be then decided by the option from IAR toolset, which you could type in the text field (From your example is 1024), then linker will be the one, which allocated the stack in RAM. So, I took a conclusion that It doesn't matter where or when we declare a variables (an array) in the startup code or application-level code. as long as the size is smaller than the stack memory range we already inputted before, the variables will live in that stack memory range.. But then, you said "it is possible to allocate the stack as a variable (an array) in the startup code, or in the application-level code, it is better to leave the stack allocation to the linker." Which means, my conclusion before is wrong. Because from that sentence of yours, I assumes that if I allocate the stack as an array in startup code/application-level, and at the same time I also make the linker allocated some memory for stack, then the array in startup code/application-level, will live "outside" the stack memory range allocated by the linker ? Is that so ? Please correct me if I'm wrong. Thank you.
There are many different approaches to startup code out there. So, you might find startup code and linker scripts that don't allocate the stack at all. Instead, the startup code simply allocates stack as a global array, which from the linker perspective is just like any other variable. The CPU does not really care one way or another. All the CPU needs is the initial value of the stack pointer (SP), which the ARM Cortex-M CPU loads from address zero the beginning of the vector table.
I see what you mean by now. Before, I thought that the linker which allocate the stack is generic and It happened in all processors. So, there are many different methods how startup code works. That's explained everything. Thank you very much for your response Dr. Samek. I really appreciated it.
Dear Dr.Miro Samek. I really wanted to thank you for your precious videos. They are really awesome and They helped me to greatly understand the interaction between software and hardware in embedded systems. Now, regarding this video, I am having a very different .map file other than the one shown in your lesson. Moreover, the vector table in this lesson is very different than the one I have generated. my IAR version is 8.32.1. So, how can I get the same .map and the same assembly files as you do in this lesson ? Please help
I've noticed that someone in quite an old comment was asking about the packbits_init_single.o present in the map file. I have also stumbled upon this problem and it took me quite a while to figure out, so I thought I would share it. The short answer is that the linker just chose a compression algorithm to store the data (used for initalization of RAM variables) in ROM. PackBits is just one of the available compression algorithms. You can change which and if any algorithm is used. The developement guide for IAR (link at the bottom of the comment, page 527-528) says that if not otherwise stated IAR will compress the bits stored in ROM and include the instructions to 'unpack' them during initialization ->"ILINK estimates the resulting size using each packing method (except for auto), and then chooses the packing method that produces the smallest estimated size. Note that the size of the decompressor is also included. This is the default method for initialize by copy". As this line was in my .icf file - 'initialize by copy { readwrite };' - the default rule was implemented and it seems like the PackBits compression algorithm was just deemed the most worthiest of the worthy in this case and applied. So I changed this line to 'initialize by copy with packing=none { readwrite };' to force the linker to keep the data 'raw'. After this modification, the end of "P1" section in .map file looks like: .text ro code 0x1c8 0xa cexit.o [4] .text ro code 0x1d4 0x14 exit.o [5] .text ro code 0x1e8 0x1c cstartup_M.o [4] .rodata const 0x204 0x0 copy_init3.o [4] Initializer bytes const 0x204 0x24 - 0x228 0x1e8 So there is is no zero_init (like in the video) but the behaviour is somewhat similar. iar_copy_init just stores from a chosen register into a RAM adress word-by-word. With packbit the values were initlialized byte- by-byte by the 'decoder' - decoder was included in 'packbits_init_single.o' I presume. However, now this is not optimal in the sense that all the global variables, initialized or not take up ROM space. Also funny thing happens to P2 : "P2", part 1 of 2: 0x24 P2 s0 0x2000'0000 0x24 .bss inited 0x2000'0000 0xc main.o [1] .data inited 0x2000'000c 0x8 main.o [1] .bss inited 0x2000'0014 0x8 main.o [1] .data inited 0x2000'001c 0x4 main.o [1] .bss inited 0x2000'0020 0x4 main.o [1] - 0x2000'0024 0x24 As .bss is mixed with .data. To be honest I don't know what influences the order of these elements. In main.c global variables are declared and defined like: Point p2; Window w2; Triangle t; Point p1 = { 1u, 2u}; Window w1 = { {123u, 1234u}, {234u, 6789u}}; I have no idea whatsoever how would you optimize this in ROM, while keeping the word-by-word copy behaviour, perhaps something just eludes me. I am not sure why this different default behaviour when you compare it with the video. Perhaps a newer version of IAR (mine is 9.32.2) or perhaps I just forked something up with configuration :D. I hope this elaboration will help somebody and if someone knows something more about the topic they could also share :D Developement Guide - www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwiH1abXy-7_AhXVrIsKHfzuCoEQFnoECA8QAQ&url=https%3A%2F%2Fwwwfiles.iar.com%2Farm%2Fwebic%2Fdoc%2FEWARM_DevelopmentGuide.ENU.pdf&usg=AOvVaw1ymg-Bf97xtcHsk7wrvx45&opi=89978449 - for version 9.40.
Hello Mr Samek, I am running this example on my computer, but the code don't seem to execute code in section __iar_zero_init3 (described at 13:42), is there a special setting that you had to enable to execute this section of the code?
+dogintwater I am running IAR embedded workbench for ARM v 7.40.3 Is there an option to explicitly ask the compiler to clear .bss sections? If not how would I go about writing zeros into the .data sections? Thanks for your time.
+dogintwater Clearing of the .bss section must happen inside the target (you MUC) at runtime. This is way after the compiler has compiled the code, so no compiler option can do it for you. Instead, clearing of .bss must be accomplished by executing special startup code, which either comes from a standard library, or you need to write it yourself. I hope this makes sense to you. --MMS
Miro - I wonder if there wasn't enough bss and the linker(?) decided it was better handled with __iar_packbits_init_single3? e.g. maybe some of the statics weren't referenced and were optimized away? It all depends on exactly what was compiled and what project options were selected.
@@keithevans6450 Hello, did you get an answer for your question??? My code also goes through __iar_packbits_init_single3 and I can't understand if this is ok or not ...
he got a PhD in an ultra difficult domain and now he's a top expert in a totally different extremely complex domain.Genius!I'm guessing photographic memory,otherwise it's impossible
Thank you for the nudge to do the next lesson. This one will show how to implement the real vector table (as opposed as the generic one). Stay tuned...
Quantum Leaps, LLC Looking forward to the next episode; I've been checking the channel everyday to see whether there's a new video.. When do you think it will be up?
I have a question about the effect of compiler optimization level here. I started this lesson with only the code related to led blinking (hence, no Point, Window or Triangle structure, not even the definitions). I then added the declarations of those structs and of declarations+initializations of the global Point and Window variables, but DIDN't use them in main(). At this point I checked the map file, and saw no Initializer Bytes or .data section. Compiler optimization was set at Low. I thought setting the compiler optimization to None would make the sections appear, but they didn't. The only way to make them appear was to actually use one of those global variables in main(). Is there another setting that controls this? Or maybe the compiler deems completely unused variable as totally useless, even if i dont have any optimization? Thanks, and ... awesome material as usual!
For anyone still wondering (like I was), I found an article on the IAR website under *Technical Note 51348* titled *Linker removes functions and variables or external not found* that states: "If functions and variables are not refered to in the main() call-tree or in any interrupt call-tree the linker will remove them by default." It goes on to say that this can be prevented. For example, to keep some unused variable `i`, use either the: 1) *__root* extended keyword before your declaration, such as `__root int i;`, 2) *--keep* (or *-g* for older EWARM versions) linker option, such as `--keep i` under "Project -> Options... -> Linker -> Extra Options", or 3) *REQUIRE* assembler directive, used in manually-written assembly code or possibly in inline C code such as `asm ("REQUIRE i");`. See the article on the IAR website for more details.
StateMachineCOM Could you please re explain the rule of copying value from address 0x04 to the PC register (how it becomes -1), you said that you have explained that in a previous lesson, but I think that I haven't previously understood this point as well. And could you please remind me in the vector table (error handler) why is the address in 1db, but actually in 1da?
ARM processor has what it called a "Thump mode" that required every address copied to the PC must has a '1' at the least significant bit. The address at 0x04 was 0x219 and its binary value will be 0010 0001 1000, here the least significant bit is '0'. But when copy it to PC the processor change it into 0x218 which its binary value is 0010 0001 0111, as we see the least significant bit is '1' which is acceptable. Also the same answer applied for your second question.
There is no "Thump mode" or "Trump mode" for that matter. The mode of the processor is called Thumb, like the short, thick first digit of the human hand.
Hi firstly thank you for your videos, you are a great teacher. Im running IAR Arm 8.42.1 version and when I select the FPU my check box is a little different to yours. it says FPVv4 single precision, when i try to debug i get a fatal error, compiler generates FPU instructions for a device without an FPU on line 117 if i choose the option none for the floating point settings it then compiles? do you know what the problem is? i have downloaded lesson 12 and have followed the lesson 13 also tried downloading the lesson 13 file from quantum leaps ? i notice my tiva c micro is ... tm4c123gh6pm instead of the tm4c123fh6pm that shows on your video could the absence of an f mean absence of floating point hardware? just a guess as im learning ?? i have just purchased my tiva c its an ek-tm4c123gxl rev b any help would be amazing , thank you sir
All TivaC MCUs are based on ARM Corterx-M4F (with hardware FPU). I need to check, but the run-time failure with FPU is most likely caused by not enabling the FPU in software (a bit needs to be set in some register). Without the FPU enabled, the CPU cannot execute the FPU instructions, hence the HardFault. -MMS
Was wondering if this issue was ever resolved as I am having a very similar issue. When I try to compile the code the following error message is received: Fatal Error[Pe035]: #error directive: "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" C:\Embedded_Programming_Samek\Lesson13\core_cm4.h 117 Checking core_cm4.h around line 117 shows the following preprocessor statements: #elif defined ( __ICCARM__ ) #if defined __ARMVFP__ #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) #define __FPU_USED 1U #else #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" #define __FPU_USED 0U #endif #else #define __FPU_USED 0U #endif Thanks for any help.
@@richardchristie9794 I was getting the same error when building for the TM4C123GH6PM with VFPv4 selected. Using your comment as a clue I added __FPU_PRESENT flag to the build and I no longer get the build error. I added __FPU_PRESENT=1 to the build configuration Project>Options>C/C++ Compiler>Preprocessor>Defined symbols. See www.iar.com/support/tech-notes/general/iarbuild.exe-and-preprocessor-defines/ for more info.
@@mashruralam5795 Thanks for the information Mashrur. I had checked all the header files looking for __FPU_PRESENT to be defined somewhere. When I had no luck it dawned on me that it was up to the programmer to set it. I simply put #define __FPU_PRESENT 1U at the beginning of the code and then it complied with no errors. Looks like setting it using the Project>Options works as well.
after initializing the data and recompiling, the map file shows only two parts in the RAM section (.bss and .data are combined in the same part and all are initialized) also the size of the two .data combined is 0xc but the size of the initializer byte in ROM is 0xf can't see why.. or is it software version dependant (currently using IAR V 8.40.1)
Hello, I am not fairly getting the concept that why the instruction address must be at odd address while actual code is at even address? What is this concept called?
My initialiser bytes section size is equal .bss section + .data section, not just data section. So the apparently IAR compailer views the unintialised .bss as actually initialised but to zero. Have I missed something?
I got different map file than this lesson one with initialized data. I am using IAR IDE 8.11 32kb code size limited free version. If i tried to initialized one data then the rest all also initialized on MAP file. Please give me some suggestion for this.
Thank you, for uninitialized variables (.bss) will be deleted, without having to write to ROM. is it recommended to not initialize the data that will be erased and save rom space?
Yes, absolutely, this situation is called a "reset loop". There are several possible scenarios, which need to be carefully considered. One class of scenarios is that a fault handler can cause another fault handler, for example when the stack overflows a fault handler that tries to call a function can cause another fault handler. This is preventable (e.g., a fault handler should re-set the stack pointer before calling a fault handler function.) But there are other scenarios, more difficult to prevent. In the end, in production code, you might want to count the number of resets (e.g., in some kind of non-volatile memory that survives resets) and stop when the maximum number of resets is reached. Fault handling is a complex subject and very strongly depends on the specific device being built. But one sure thing is that the default behavior of silently entering an endless loop, as it is coded in most vendor-supplied fault handlers, is certainly WRONG. --MMS
An exception vector in ARM Cortex-M is a 32-bit address of a handler routine stored in the vector table. Out of reset, this vector table must be at address 0, but can be relocated to a different address by writing to a special register. But assuming no relocation, an exception vector is a 32-bit address at a specific memory location, which will be loaded to the PC when the CPU recognizes the exception.
IAR provides one of the best compilers and reliable debugger. The toolset by itself is not more difficult to learn than any other comparable tool. Regarding the startup code, IAR is a bit more complex than others, because a lot is happening in the __iar_program_start function. For that, however, there is good documentation, which you can read in the online Help. --MMS
There will be any video dealing with the Cortex M interrupts? The technical references are badly written (ST for example) and is almost impossible to put the info together. Thanks.
Quantum Leaps, LLC Dear Dr. Samek, thank you for such a comprehensive series of tutorials! I am also eager to see the new lessons on the topics you've mentioned! I was not able to subscribe to the newsletter as your form (www.state-machine.com/about/contact.php) rejected a few addresses of mine as invalid. I am also curious if you plan on making such in-depth lessons on QP frameworks as well?
Quantum Leaps, LLC Also, have you though about creating paid courses, e.g. on Udemy with reasonable prices so that students can still pay for them but you can cover at least part of your costs?
This lesson #13 uses the standard startup code generated by KEIL uVision. To get this code, you need to open the provided project in KEIL uVision. The act of opening the project will cause the generation of additional directories in your project folder. Among others, you will get the RTE folder (Run-Time Environment). Inside this directory, you need to go to RTE\Device\STM32C031C6Tx. Deep inside there, KEIL has generated the startup file startup_stm32c031xx.s, which is in assembly (not in C), but you can study this file. In the subsequent lessons (#14 and higher), you will use the customized startup code written in C. Please watch the subsequent lessons. --MMS
This one was rather difficult. Had to watch 2 times and repeatedly rewind some parts to get the idea. I feel the .map file is both very important and difficult to understand. I guess if one want to write his own bootloader, the map file is the central place to refer to.
when i did the same steps as you did i found out the intializer bytes is = 0xf while the 2 data section i have creat is = 0xc so why this happened to me unlike the video
I noticed something similar. For example, if I have three uninitialized variables they appear in the .bss section. If I then initialize two of them, those two switch from .bss to .data, but the initializer bytes section that is created still matches the size of the three variables. Is the linker combining them for the sake of efficiency.
At __iar_program_start, there are 2 instruction: MOV R8, R8 ?? It doesn't make any sense to me. I know the instruction is to put the content of R8 into R8, which again make no sense. Can anyone help explain?
Instructions like MOV R8,R8 are used as NOP (No-OPeration) instructions. Such NOP instructions are used for various purposes: as a very short delay, to make a previous instruction take effect before executing some other instructions (due to pipeline instructions are sometimes "glued together"), or to make room for a breakpoint instruction. I'm not sure which one of these uses is meant in the IAR startup code. --MMS
__iar_program_start: MOV R8, R8 MOV R8, R8 It looks like any garbage, doesn't make sense. That was unexplained. Myguess it is any template for exchange if exist any other path to going for ARM.
I'm not sure why in this older version of IAR EWARM (from 2014) the standard IAR startup code had the do-nothing instructions "MOV R8,R8" at the beginning of __iar_program_start. But at least these instructions are *harmless*. The newer versions of IAR don't have such wasteful instructions anymore. --MMS
@@StateMachineCOM Thanks for your answer. Absolute *BRILLANT* channel, course, teacher and content. Thanks for share your huge knowledge. btw. my painfull ARM C production: ua-cam.com/video/n3DCP5vWiIU/v-deo.html
You might need to install the USB driver for the on-board JTAG of your TivaC LauchPad. The USB drivers for the board are provided on the companion website to the course at state-machine.com/quickstart. Alternatively, you might simply wait a bit after plugging in the board to your USB ports. On Windows 10 it might take several seconds before the board is recognized. You should see the board in the Windows Device Manager as "Stellaris ICDI JTAG/SWD Interface" and in "Ports (COM&LPT)" section as "Stellaris Virtual Serial Port (COMx)". --MMS
Hi, I've written a wrong reset vector address into the vector table (trying to be stupid I guess..) and now I can't program my board anymore.. How can I solve this?? Thanks!
+Luca Davidian Yes, you can unlock your board, but you will need the LMFlash utility for it. You can get LMFlash from Texas Instruments (just google for "LMFlash") . Once you install LMFlash, run it in GUI mode and go to the tab "Other Utilities". Make sure that the TM4C123 radio-button is selected and press Unlock. Follow the instructions from there.
+Quantum Leaps, LLC yeah thanks a lot! it worked.. I was afraid there was no easy way to do it (I'm just learning to program this board) And many thanks for your tutorials, they're a goldmine of knowledge for starting to delve into embedded programming. Do you plan to add more videos? For example to get started with simple peripherals (UART,I2C,SPI) (I would like to get where I was with AVR programming, interfacing to EEPROM and GLCDs). THANKS!!
I'm totally confused as to why the interrupt vector table has to be replaced. IAR doesn't support processor specific interrupts? Really? As a novice, I'm completely blown away by this. Replacement of the vector table seems like an extremely advanced operation. But aren't interrupts fundamental to microcontroller programming? Why would a programmer at this advanced level even be watching these videos? You lost me here.
Each MCU for ARM Cortex-M has potentially a different interrupt vector table. The beginning of the table is defined by ARM and contains the standard exception handlers. But the rest is specific to the MCU and contains the IRQ handlers (interrupt handlers). Tool vendors like IAR typically don't provide the interrupt vector table for each of the thousands of MCUs they support. This is typically a part of the MCU-specific startup code. However, the vendors provide the MCU-specific linker scripts and flash programming algorithms.
Thanks for the response. Your video's are great and up to this point very clear, even to a beginning micro controller programmer like me. I assumed that TI provides a specific and complete vector table for Tiva, so it's not clear to me why a developer would need to create his/her own. For someone like me that's simply trying to move up from the AVR world replacing the vector table seems like jumping into the deep end of computer science. Hopefully this is only required by people that need to squeeze the absolute ultimate performance possible out of the hardware.
TI provides startup code examples for their TivaC MCUs (e.g., in the "TivaWare" software suite). The tool vendors also provide startup code examples for specific MCUs. But as an aspiring embedded software engineer you need to understand the startup code, not merely use it as a black box. And another issue is the standard implementation of the exception handlers that is provided in the example startup code. This implementation is unacceptable for actual deployment of the code in real-life products. This is because the exception handler hang the CPU in an endless loop, which really represents "denial of service". I hope you can agree that this is not acceptable.
Very generous of you to ask my agreement since you are obviously a maestro and I can barely whistle. I'd like to go deeper than the "Tivaware" level of programming but this may be too far. As you mentioned, your target audience is professional developers of real-life products. That's not me. I'm a hobbyist. I've been following along with your video's using TI's CCS since I started with TI's tutorials. So far it's worked pretty well. But I had no idea that fundamental things like the vector table and startup code change drastically with each IDE. So it looks I may be departing the ARM train. It's too much to learn a different IDE for every tutorial. I suspect that's why Arduino has become so popular. It may not be a very powerful programming environment, but at least it's consistent. Average programmers can find plenty of tutorials and examples of useful things without having to learn a new IDE each time. I might jump to the end of your videos to see what you say about using open source tools. Perhaps there's some consistency there and hopefully a base of hobbyists like me somewhere to share ideas.
The endless variety of MCUs, toolchains and IDEs, real-time operating systems, other software components etc. is the unfortunate reality of embedded software development. I agree that this is completely unnecessary, but at least the industry seems to coalesce around the ARM Cortex-M cores for the embedded MCUs. This is already a BIG improvement to the Tower of Babel that we had up to this point.... --MMS
Dear Dr. Samek, I couldn't be more grateful for this incredible course. You explain complex Embedded Systems concepts in the most simplified way I've ever seen. I hope you will release other content in the same way.
Cant emphasise how good this course is. I am completely new to embedded programming but have learnt so much and I am not even half way through. You are doing an amazing job for which we are grateful. Thank you.
The best embedded programming course I've ever found. Highly recommended to all those who want to have a deep understanding of how a microcontroller operates. Thanks Dr. Samek.
Frankly Dr.Samek, I dont know what we have done to get this quality of lectures free of cost on youtube. I feel super lucky that I have access to these lectures.
Uptil now, I sort of knew what happens before main, today I actually witnessed (and executed) the magic !! Thank you so much. !!
Best tutorial in embeded world please continue to teaching.. regards..
Thumbs up for making complicated stuff seem like a piece of cake!
OK, I definitely had the "Ah ha!" moment of understanding why a device stops responding. Such a good explanation. Now I have to watch it 5 times and about 3 energy drinks to make sure I understand it.
better that 1000 C books!
Thank you, Quantum Leaps, LLC! :)
awesome, one of the best tutorials on yt, no kidding. I have a picky correction @18:22: "the LSB of any value loaded into the PC register must be zero" (instead of one)
Amazing amazing amazing thank you so much Dr.Samek
Thanks for a great lecture! When I disassemble ARM Cortex-M firmware, they often have "Reset_Handler" in the IVT entry of "__iar_program_start" in this lecture. I guess it's due to different vendors or development kits.
Very great work! I am waiting the interruption courses! Best regards
thank you - frankly your video is of very high quality - challenging and dense and all the important points. many other video is just a waste of time.....so much time wasters.
When I step through in the disassembly window, it skips over assembly statements. I think it is stepping through each C statement and jumps over all the assembly associated with that C statement. Is there any way to change the settings so that I can step through each assembly statement in the disassembly window?
To step one machine instruction at a time, first click inside the disassebmly window. To go back to stepping one C line at a time, click in the code window. --MMS
@@StateMachineCOM, Wow I really appreciate the quick response! Unfortunately, that's not working. When I click in the disassembly window, it still steps through the C code.
It's time for stupid questions. Why does linker has to copy data from ROM to the .data section that's in RAM instead of put it in RAM immediately What's the benefit of it's been saved in ROM?
It all goes back to the physical properties of RAM and ROM. RAM is *volatile* which means that it loses its content when power is removed. Therefore, when the system first powers up, the RAM has *random* content and it needs to be initialized to some known values. In contrast, ROM is non-volatile and preserves its content even when power is removed. So, upon the power-up, you can trust the content of the ROM and use it to initialize the RAM. I hope this makes sense. --MMS
Good point about verifying the initialization of .bss using the debugger. If I remember correctly Keil's C51 for 8051 required that you manually enter the bss size in some dialog box or config file for STARTUP.A51 to work correctly. For a certain chip this manual step was skipped, and a patch had to be written to take care of it. But of course only after it was finally tracked down after inconsistent behavior was observed.
Hi, I have a question and want to make sure of something regarding to linker and stack.
From the video, I saw that in the map file the room for stack (1024) was the linker responsibility.
And you have briefly explained it.
So, am I right by saying that beside linking the .o from several modules, shared/static/dyamic libs, etc,
linker also the one, which reserved or responsible to create room for stack ?
And also, I didn't quite understand at 12:44. About "reordered so It could be initiaiized in s single block" and why It's needed. Could you please give a more detailed explanation, Sir ?
Thank you before. Warm regards.
First, regarding the stack allocation: While it is possible to allocate the stack as a variable (an array) in the startup code, or even in the application-level code, it is better to leave the stack allocation to the linker. This makes it easier to place the stack in a specific section and to place this section in the most appropriate memory (some MCUs have more than one RAM block to choose from).
Second, regarding the "reordering and consolidating the data section": You define the various global or static variables throughout the code, so you might have hundreds or even thousands of pieces of data scattered around. The linker consolidates all these pieces into one contiguous .data section. This section then can be initialized in a single block-copy, which is faster and requires far less code than initializing each individual variable separately. I hope this makes sense.
Ah, I see ..
Your second answer makes sense for me.
But, regarding to your first answer, I'm still struggling to understand, what you're trying to convey. As far as I know from your previous lectures, stack used for local variables and for saving return address.
And the range of the memory will be then decided by the option from IAR toolset, which you could type in the text field (From your example is 1024), then linker will be the one, which allocated the stack in RAM.
So, I took a conclusion that It doesn't matter where or when we declare a variables (an array) in the startup code or application-level code. as long as the size is smaller than the stack memory range we already inputted before, the variables will live in that stack memory range..
But then, you said "it is possible to allocate the stack as a variable (an array) in the
startup code, or in the application-level code, it is better to leave the stack allocation to the linker."
Which means, my conclusion before is wrong. Because from that sentence of yours, I assumes that if I allocate the stack as an array in startup code/application-level, and at the same time I also make the linker allocated some memory for stack, then the array in startup code/application-level, will live "outside" the stack memory range allocated by the linker ? Is that so ?
Please correct me if I'm wrong.
Thank you.
There are many different approaches to startup code out there. So, you might find startup code and linker scripts that don't allocate the stack at all. Instead, the startup code simply allocates stack as a global array, which from the linker perspective is just like any other variable. The CPU does not really care one way or another. All the CPU needs is the initial value of the stack pointer (SP), which the ARM Cortex-M CPU loads from address zero the beginning of the vector table.
I see what you mean by now. Before, I thought that the linker which allocate the stack is generic and It happened in all processors.
So, there are many different methods how startup code works. That's explained everything.
Thank you very much for your response Dr. Samek.
I really appreciated it.
awesome to the point teaching..please upload the rest too..
:O Wow! Thanks for explaining how .map files work!
hola
Dear Dr.Miro Samek. I really wanted to thank you for your precious videos. They are really awesome and They helped me to greatly understand the interaction between software and hardware in embedded systems.
Now, regarding this video, I am having a very different .map file other than the one shown in your lesson. Moreover, the vector table in this lesson is very different than the one I have generated. my IAR version is 8.32.1. So, how can I get the same .map and the same assembly files as you do in this lesson ?
Please help
Eagerly waiting for the upcoming parts in the series.....
I've noticed that someone in quite an old comment was asking about the packbits_init_single.o present in the map file. I have also stumbled upon this problem and it took me quite a while to figure out, so I thought I would share it. The short answer is that the linker just chose a compression algorithm to store the data (used for initalization of RAM variables) in ROM. PackBits is just one of the available compression algorithms. You can change which and if any algorithm is used.
The developement guide for IAR (link at the bottom of the comment, page 527-528) says that if not otherwise stated IAR will compress the bits stored in ROM and include the instructions to 'unpack' them during initialization ->"ILINK estimates the resulting size using each packing method (except for auto), and then chooses the packing method that produces the smallest estimated size. Note that the size of the decompressor is also included. This is the default method for initialize by copy".
As this line was in my .icf file - 'initialize by copy { readwrite };' - the default rule was implemented and it seems like the PackBits compression algorithm was just deemed the most worthiest of the worthy in this case and applied. So I changed this line to 'initialize by copy with packing=none { readwrite };' to force the linker to keep the data 'raw'.
After this modification, the end of "P1" section in .map file looks like:
.text ro code 0x1c8 0xa cexit.o [4]
.text ro code 0x1d4 0x14 exit.o [5]
.text ro code 0x1e8 0x1c cstartup_M.o [4]
.rodata const 0x204 0x0 copy_init3.o [4]
Initializer bytes const 0x204 0x24
- 0x228 0x1e8
So there is is no zero_init (like in the video) but the behaviour is somewhat similar. iar_copy_init just stores from a chosen register into a RAM adress word-by-word. With packbit the values were initlialized byte- by-byte by the 'decoder' - decoder was included in 'packbits_init_single.o' I presume.
However, now this is not optimal in the sense that all the global variables, initialized or not take up ROM space. Also funny thing happens to P2 :
"P2", part 1 of 2: 0x24
P2 s0 0x2000'0000 0x24
.bss inited 0x2000'0000 0xc main.o [1]
.data inited 0x2000'000c 0x8 main.o [1]
.bss inited 0x2000'0014 0x8 main.o [1]
.data inited 0x2000'001c 0x4 main.o [1]
.bss inited 0x2000'0020 0x4 main.o [1]
- 0x2000'0024 0x24
As .bss is mixed with .data. To be honest I don't know what influences the order of these elements. In main.c global variables are declared and defined like:
Point p2;
Window w2;
Triangle t;
Point p1 = { 1u, 2u};
Window w1 = { {123u, 1234u}, {234u, 6789u}};
I have no idea whatsoever how would you optimize this in ROM, while keeping the word-by-word copy behaviour, perhaps something just eludes me.
I am not sure why this different default behaviour when you compare it with the video. Perhaps a newer version of IAR (mine is 9.32.2) or perhaps I just forked something up with configuration :D. I hope this elaboration will help somebody and if someone knows something more about the topic they could also share :D
Developement Guide - www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwiH1abXy-7_AhXVrIsKHfzuCoEQFnoECA8QAQ&url=https%3A%2F%2Fwwwfiles.iar.com%2Farm%2Fwebic%2Fdoc%2FEWARM_DevelopmentGuide.ENU.pdf&usg=AOvVaw1ymg-Bf97xtcHsk7wrvx45&opi=89978449 - for version 9.40.
Hello Mr Samek,
I am running this example on my computer, but the code don't seem to execute code in section __iar_zero_init3 (described at 13:42), is there a special setting that you had to enable to execute this section of the code?
+dogintwater
I am running IAR embedded workbench for ARM v 7.40.3
Is there an option to explicitly ask the compiler to clear .bss sections? If not how would I go about writing zeros into the .data sections?
Thanks for your time.
+dogintwater Clearing of the .bss section must happen inside the target (you MUC) at runtime. This is way after the compiler has compiled the code, so no compiler option can do it for you. Instead, clearing of .bss must be accomplished by executing special startup code, which either comes from a standard library, or you need to write it yourself. I hope this makes sense to you.
--MMS
Miro - I wonder if there wasn't enough bss and the linker(?) decided it was better handled with __iar_packbits_init_single3? e.g. maybe some of the statics weren't referenced and were optimized away? It all depends on exactly what was compiled and what project options were selected.
@@keithevans6450 Hello, did you get an answer for your question??? My code also goes through __iar_packbits_init_single3 and I can't understand if this is ok or not ...
if i may ask what type of degree and in what subject do you have? because you are very knowledgable .
Eddie Amaya " Dr. Samek earned his Ph.D. in nuclear physics at GSI (Darmstadt, Germany). " WOW! Teach me your ways!
Eddie Amaya
Here is my LinkedIn profile: www.linkedin.com/in/samek
--MMS
he got a PhD in an ultra difficult domain and now he's a top expert in a totally different extremely complex domain.Genius!I'm guessing photographic memory,otherwise it's impossible
Great tutorial! Wating for more lessons....
Great work and very informative. Can you please post more lectures.
Thank you for the nudge to do the next lesson. This one will show how to implement the real vector table (as opposed as the generic one). Stay tuned...
StateMachineCOM Thank you sir...
Quantum Leaps, LLC
Looking forward to the next episode; I've been checking the channel everyday to see whether there's a new video.. When do you think it will be up?
Thanks for your excellent tutorial..
Waiting for next parts..
Nice :) Please try to release the next one quickly, I am very interested in your brilliant course :)
Great, Please upload more
I have a question about the effect of compiler optimization level here.
I started this lesson with only the code related to led blinking (hence, no Point, Window or Triangle structure, not even the definitions).
I then added the declarations of those structs and of declarations+initializations of the global Point and Window variables, but DIDN't use them in main().
At this point I checked the map file, and saw no Initializer Bytes or .data section. Compiler optimization was set at Low.
I thought setting the compiler optimization to None would make the sections appear, but they didn't.
The only way to make them appear was to actually use one of those global variables in main().
Is there another setting that controls this? Or maybe the compiler deems completely unused variable as totally useless, even if i dont have any optimization?
Thanks, and ... awesome material as usual!
Just to note, the first time I forgot to "Make" the program before I run it, it could be the reason!!!
I curious about this, too. Already any answer available ?
For anyone still wondering (like I was), I found an article on the IAR website under *Technical Note 51348* titled *Linker removes functions and variables or external not found* that states:
"If functions and variables are not refered to in the main() call-tree or in any interrupt call-tree the linker will remove them by default."
It goes on to say that this can be prevented. For example, to keep some unused variable `i`, use either the:
1) *__root* extended keyword before your declaration, such as `__root int i;`,
2) *--keep* (or *-g* for older EWARM versions) linker option, such as `--keep i` under "Project -> Options... -> Linker -> Extra Options", or
3) *REQUIRE* assembler directive, used in manually-written assembly code or possibly in inline C code such as `asm ("REQUIRE i");`.
See the article on the IAR website for more details.
Great Teacher!!!! Thanks a ton...
StateMachineCOM Could you please re explain the rule of copying value from address 0x04 to the PC register (how it becomes -1), you said that you have explained that in a previous lesson, but I think that I haven't previously understood this point as well.
And could you please remind me in the vector table (error handler) why is the address in 1db, but actually in 1da?
ARM processor has what it called a "Thump mode" that required every address copied to the PC must has a '1' at the least significant bit. The address at 0x04 was 0x219 and its binary value will be 0010 0001 1000, here the least significant bit is '0'. But when copy it to PC the processor change it into 0x218 which its binary value is 0010 0001 0111, as we see the least significant bit is '1' which is acceptable.
Also the same answer applied for your second question.
There is no "Thump mode" or "Trump mode" for that matter. The mode of the processor is called Thumb, like the short, thick first digit of the human hand.
Quantum Leaps, LLC
Yea sure, it was a typo. Thanks for the correction
Hi firstly thank you for your videos, you are a great teacher.
Im running IAR Arm 8.42.1 version and when I select the FPU my check box is a little different to yours. it says FPVv4 single precision, when i try to debug i get a fatal error, compiler generates FPU instructions for a device without an FPU on line 117
if i choose the option none for the floating point settings it then compiles? do you know what the problem is? i have downloaded lesson 12 and have followed the lesson 13 also tried downloading the lesson 13 file from quantum leaps ? i notice my tiva c micro is ... tm4c123gh6pm instead of the tm4c123fh6pm that shows on your video could the absence of an f mean absence of floating point hardware? just a guess as im learning ?? i have just purchased my tiva c its an ek-tm4c123gxl rev b any help would be amazing , thank you sir
All TivaC MCUs are based on ARM Corterx-M4F (with hardware FPU). I need to check, but the run-time failure with FPU is most likely caused by not enabling the FPU in software (a bit needs to be set in some register). Without the FPU enabled, the CPU cannot execute the FPU instructions, hence the HardFault. -MMS
Was wondering if this issue was ever resolved as I am having a very similar issue. When I try to compile the code the following error message is received:
Fatal Error[Pe035]: #error directive: "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
C:\Embedded_Programming_Samek\Lesson13\core_cm4.h 117
Checking core_cm4.h around line 117 shows the following preprocessor statements:
#elif defined ( __ICCARM__ )
#if defined __ARMVFP__
#if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)
#define __FPU_USED 1U
#else
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#define __FPU_USED 0U
#endif
#else
#define __FPU_USED 0U
#endif
Thanks for any help.
@@richardchristie9794 I was getting the same error when building for the TM4C123GH6PM with VFPv4 selected. Using your comment as a clue I added __FPU_PRESENT flag to the build and I no longer get the build error. I added __FPU_PRESENT=1 to the build configuration Project>Options>C/C++ Compiler>Preprocessor>Defined symbols. See www.iar.com/support/tech-notes/general/iarbuild.exe-and-preprocessor-defines/ for more info.
@@mashruralam5795 Thanks for the information Mashrur. I had checked all the header files looking for __FPU_PRESENT to be defined somewhere. When I had no luck it dawned on me that it was up to the programmer to set it. I simply put #define __FPU_PRESENT 1U at the beginning of the code and then it complied with no errors. Looks like setting it using the Project>Options works as well.
Thanks alot for the tutorial, waitimg for the nextt part :)
after initializing the data and recompiling, the map file shows only two parts in the RAM section (.bss and .data are combined in the same part and all are initialized) also the size of the two .data combined is 0xc but the size of the initializer byte in ROM is 0xf
can't see why.. or is it software version dependant (currently using IAR V 8.40.1)
Hello, I am not fairly getting the concept that why the instruction address must be at odd address while actual code is at even address? What is this concept called?
A statue to this man..
My initialiser bytes section size is equal .bss section + .data section, not just data section. So the apparently IAR compailer views the unintialised .bss as actually initialised but to zero. Have I missed something?
Sir your class is really helpful...but where i can get serial communications
I got different map file than this lesson one with initialized data. I am using IAR IDE 8.11 32kb code size limited free version. If i tried to initialized one data then the rest all also initialized on MAP file. Please give me some suggestion for this.
Thank you,
for uninitialized variables (.bss) will be deleted, without having to write to ROM. is it recommended to
not initialize the data that will be erased and save rom space?
How does it ends up in endless loop when an exception happen? I mean I am talking about denial of service.
Yes, absolutely, this situation is called a "reset loop". There are several possible scenarios, which need to be carefully considered. One class of scenarios is that a fault handler can cause another fault handler, for example when the stack overflows a fault handler that tries to call a function can cause another fault handler. This is preventable (e.g., a fault handler should re-set the stack pointer before calling a fault handler function.) But there are other scenarios, more difficult to prevent. In the end, in production code, you might want to count the number of resets (e.g., in some kind of non-volatile memory that survives resets) and stop when the maximum number of resets is reached. Fault handling is a complex subject and very strongly depends on the specific device being built. But one sure thing is that the default behavior of silently entering an endless loop, as it is coded in most vendor-supplied fault handlers, is certainly WRONG. --MMS
@StateMachineCOM thank you sir. I am just starting my journey in embedded systems, and your course is sure a good start.
How would you define an exception vector? How is defined in a microcontroller point of view...
An exception vector in ARM Cortex-M is a 32-bit address of a handler routine stored in the vector table. Out of reset, this vector table must be at address 0, but can be relocated to a different address by writing to a special register. But assuming no relocation, an exception vector is a 32-bit address at a specific memory location, which will be loaded to the PC when the CPU recognizes the exception.
I would like to know if it's difficult to learn iar because I find it very complicated to learn. Your advice for me
IAR provides one of the best compilers and reliable debugger. The toolset by itself is not more difficult to learn than any other comparable tool. Regarding the startup code, IAR is a bit more complex than others, because a lot is happening in the __iar_program_start function. For that, however, there is good documentation, which you can read in the online Help. --MMS
@@StateMachineCOM okay I got it . I will document myself. Thank you so much 👍
There will be any video dealing with the Cortex M interrupts? The technical references are badly written (ST for example) and is almost impossible to put the info together. Thanks.
Yes, interrupts will be discussed along with other related issues, such as: context switch, race conditions, disabling interrupts, etc. Stay tuned.
Quantum Leaps, LLC
Thanks, also for the excellent videos.
Quantum Leaps, LLC Dear Dr. Samek, thank you for such a comprehensive series of tutorials! I am also eager to see the new lessons on the topics you've mentioned! I was not able to subscribe to the newsletter as your form (www.state-machine.com/about/contact.php) rejected a few addresses of mine as invalid. I am also curious if you plan on making such in-depth lessons on QP frameworks as well?
Quantum Leaps, LLC Also, have you though about creating paid courses, e.g. on Udemy with reasonable prices so that students can still pay for them but you can cover at least part of your costs?
How could we see the startup code on the STM32?
This lesson #13 uses the standard startup code generated by KEIL uVision. To get this code, you need to open the provided project in KEIL uVision. The act of opening the project will cause the generation of additional directories in your project folder. Among others, you will get the RTE folder (Run-Time Environment). Inside this directory, you need to go to RTE\Device\STM32C031C6Tx. Deep inside there, KEIL has generated the startup file startup_stm32c031xx.s, which is in assembly (not in C), but you can study this file. In the subsequent lessons (#14 and higher), you will use the customized startup code written in C. Please watch the subsequent lessons. --MMS
@@StateMachineCOM Thank you for the quick reply.
This one was rather difficult. Had to watch 2 times and repeatedly rewind some parts to get the idea. I feel the .map file is both very important and difficult to understand. I guess if one want to write his own bootloader, the map file is the central place to refer to.
very helpfull
when i did the same steps as you did i found out the intializer bytes is = 0xf while the 2 data section i have creat is = 0xc so why this happened to me unlike the video
I noticed something similar. For example, if I have three uninitialized variables they appear in the .bss section. If I then initialize two of them, those two switch from .bss to .data, but the initializer bytes section that is created still matches the size of the three variables. Is the linker combining them for the sake of efficiency.
At __iar_program_start, there are 2 instruction: MOV R8, R8 ?? It doesn't make any sense to me. I know the instruction is to put the content of R8 into R8, which again make no sense. Can anyone help explain?
Instructions like MOV R8,R8 are used as NOP (No-OPeration) instructions. Such NOP instructions are used for various purposes: as a very short delay, to make a previous instruction take effect before executing some other instructions (due to pipeline instructions are sometimes "glued together"), or to make room for a breakpoint instruction. I'm not sure which one of these uses is meant in the IAR startup code. --MMS
Quantum Leaps, LLC Thank you sir. I am so happy I found this channel, worth more than gold.
__iar_program_start:
MOV R8, R8
MOV R8, R8
It looks like any garbage, doesn't make sense. That was unexplained. Myguess it is any template for exchange if exist any other path to going for ARM.
I'm not sure why in this older version of IAR EWARM (from 2014) the standard IAR startup code had the do-nothing instructions "MOV R8,R8" at the beginning of __iar_program_start. But at least these instructions are *harmless*. The newer versions of IAR don't have such wasteful instructions anymore. --MMS
@@StateMachineCOM Thanks for your answer. Absolute *BRILLANT* channel, course, teacher and content. Thanks for share your huge knowledge.
btw. my painfull ARM C production:
ua-cam.com/video/n3DCP5vWiIU/v-deo.html
when i downloaded my code error : JTAG initialization failed 0x00000001 Session aborted!
how to fix it?
You might need to install the USB driver for the on-board JTAG of your TivaC LauchPad. The USB drivers for the board are provided on the companion website to the course at state-machine.com/quickstart. Alternatively, you might simply wait a bit after plugging in the board to your USB ports. On Windows 10 it might take several seconds before the board is recognized. You should see the board in the Windows Device Manager as "Stellaris ICDI JTAG/SWD Interface" and in "Ports (COM&LPT)" section as "Stellaris Virtual Serial Port (COMx)". --MMS
it doesn't work too
Hi, I've written a wrong reset vector address into the vector table (trying to be stupid I guess..) and now I can't program my board anymore..
How can I solve this?? Thanks!
+Luca Davidian Yes, you can unlock your board, but you will need the LMFlash utility for it. You can get LMFlash from Texas Instruments (just google for "LMFlash") . Once you install LMFlash, run it in GUI mode and go to the tab "Other Utilities". Make sure that the TM4C123 radio-button is selected and press Unlock. Follow the instructions from there.
+Quantum Leaps, LLC
yeah thanks a lot! it worked.. I was afraid there was no easy way to do it (I'm just learning to program this board)
And many thanks for your tutorials, they're a goldmine of knowledge for starting to delve into embedded programming.
Do you plan to add more videos? For example to get started with simple peripherals (UART,I2C,SPI)
(I would like to get where I was with AVR programming, interfacing to EEPROM and GLCDs).
THANKS!!
I'm totally confused as to why the interrupt vector table has to be replaced. IAR doesn't support processor specific interrupts? Really? As a novice, I'm completely blown away by this. Replacement of the vector table seems like an extremely advanced operation. But aren't interrupts fundamental to microcontroller programming? Why would a programmer at this advanced level even be watching these videos? You lost me here.
Each MCU for ARM Cortex-M has potentially a different interrupt vector table. The beginning of the table is defined by ARM and contains the standard exception handlers. But the rest is specific to the MCU and contains the IRQ handlers (interrupt handlers). Tool vendors like IAR typically don't provide the interrupt vector table for each of the thousands of MCUs they support. This is typically a part of the MCU-specific startup code. However, the vendors provide the MCU-specific linker scripts and flash programming algorithms.
Thanks for the response. Your video's are great and up to this point very clear, even to a beginning micro controller programmer like me. I assumed that TI provides a specific and complete vector table for Tiva, so it's not clear to me why a developer would need to create his/her own. For someone like me that's simply trying to move up from the AVR world replacing the vector table seems like jumping into the deep end of computer science. Hopefully this is only required by people that need to squeeze the absolute ultimate performance possible out of the hardware.
TI provides startup code examples for their TivaC MCUs (e.g., in the "TivaWare" software suite). The tool vendors also provide startup code examples for specific MCUs. But as an aspiring embedded software engineer you need to understand the startup code, not merely use it as a black box. And another issue is the standard implementation of the exception handlers that is provided in the example startup code. This implementation is unacceptable for actual deployment of the code in real-life products. This is because the exception handler hang the CPU in an endless loop, which really represents "denial of service". I hope you can agree that this is not acceptable.
Very generous of you to ask my agreement since you are obviously a maestro and I can barely whistle. I'd like to go deeper than the "Tivaware" level of programming but this may be too far. As you mentioned, your target audience is professional developers of real-life products. That's not me. I'm a hobbyist. I've been following along with your video's using TI's CCS since I started with TI's tutorials. So far it's worked pretty well. But I had no idea that fundamental things like the vector table and startup code change drastically with each IDE. So it looks I may be departing the ARM train. It's too much to learn a different IDE for every tutorial. I suspect that's why Arduino has become so popular. It may not be a very powerful programming environment, but at least it's consistent. Average programmers can find plenty of tutorials and examples of useful things without having to learn a new IDE each time. I might jump to the end of your videos to see what you say about using open source tools. Perhaps there's some consistency there and hopefully a base of hobbyists like me somewhere to share ideas.
The endless variety of MCUs, toolchains and IDEs, real-time operating systems, other software components etc. is the unfortunate reality of embedded software development. I agree that this is completely unnecessary, but at least the industry seems to coalesce around the ARM Cortex-M cores for the embedded MCUs. This is already a BIG improvement to the Tower of Babel that we had up to this point.... --MMS
thx
Best tutorial in embeded world please continue to teaching.. regards..