字幕列表 影片播放 列印英文字幕 Welcome to the Modern Embedded Systems Programming course. My name is Miro Samek and in this lesson I have decided to finally give in to the popular demand and switch the development toolset from IAR to the free and unlimited GNU-ARM compiler and the Eclipse-based Integrated Development Environment. The switch of the toolset is actually a good opportunity to review the code and to see what "code portability" means in practice. As you will see, much of the code you've written so far will work with GNU-ARM without any changes, mostly due to the compliance with the Cortex Microcontroller Software Interface Standard (CMSIS). However, a few IAR-specific extensions in the startup code as well as board-support package will have to be replaced with the GNU compiler equivalents. So, today let's start with downloading and installing a development toolset for GNU-ARM. Actually, there are many choices of such toolsets, but you need to look for a toolset that supports your board. Here, the most important factor is the support for the specific debugger interface, which in case of the TivaC LaunchPad board is the Stellaris-ICDI. Since the board comes from Texas Instruments, the logical place to look is the TI.com website, where indeed you can find the toolset called Code Composer Studio (CCS). As usual these days, instead of giving you a specific fixed URL for downloading CCS, which most likely won't work in a few weeks from now, I recommend using the search box. So, when you search for CCS, you quickly find the right web-page. In the download section, you can read that the CCS tool can be used for free with no limits with the GNU-GCC toolset. Click on the Windows download, which will lead you to the registration page and some more forms to fill to comply with the export control regulations. Eventually, however, you should be able to download the CCS setup program for windows. You need to launch it and agree to the licensing terms. In the next step you can choose the installation directory. You can leave the default, or choose your own destination, but I would strongly recommend against using directory names with spaces or any non-standard characters. The following step allows you to choose the CCS components. Here you need to expand the 32-bit ARM MCUs and select the Tiva-C Series support. Also, you need to explicitly select the GCC ARM Compiler. You don't need to make any more choices, so finally click Finish to start the installation, which can take a couple of minutes. When you launch Code Composer Studio, it will ask you for the location of the "workspace". The concept of a "workspace" is common in all toolsets based on Eclipse and is intended to group together related projects. From what I see, most people tend to use one default workspace for everything they do, but I recommend that you use separate workspaces for your different project groups. Specifically, I recommend that you use a dedicated workspace for this Embedded Programming Course. Since I keep all the projects for this course in the directory "embedded_programming", I also create the CCS workspace there, in the "ccs" subdirectory. So finally you are ready to create your first project. This part is specific to this particular re-packaging of Eclipse as Code Composer Studio, but the general process is similar in all Eclipse based Integrated Development Environments. The first selection you make for a new project is the embedded target. Here you need to choose the Tiva-C family and the specific TM4C MCU within the family that is soldered on your TivaC LaunchPad board. Next, you choose the connection to the target, which in case of your LanchPad is the Stellaris-ICDI. Please note that the support for this particular debugger interface was the primary reason you selected the CCS toolset in the first place. In the next step, you need to name the project. Here, I suggest a generic name "lesson" for projects belonging to this Embedded Programming Course. This name will be fitting for all upcoming lessons, because you will simply clone this original project instead of creating a new project from scratch each time. For the same reason, you also cannot create the project in the default location inside the workspace directory. Instead, you create the project in the directory where you keep all previous lessons. On my machine this is "embedded_programming", but it can be different on your computer. To finish with the project location, you need to add the lesson19 sub-directory for this particular project The next and final step is critical. Here, you need to select the GNU toolset instead of the default TI compiler for ARM. When you click Finish, CCS will create your "lesson" project in the workspace and in the "lesson19" directory on disk. You can build the project by clicking on the hammer button at the top. As you can see, the build process succeeds with 0 problems. So, let's take a quick look at the code that CCS has generated for this project. First, you get the main.c file with the empty main() function. Second, is the startup code, which is very typical for code supplied by silicon vendors. Unfortunately, it has all the shortcomings that I've covered in lessons 13, 14, and 15. For starters, this startup code uses proprietary exception names that are not compliant with CMSIS. Also, the vector table requires editing every time you start or stop using a given interrupt handler. For example, to use the SysTick_Handler interrupt, you would need to modify the appropriate entry in the vector table, and you would also need to declare a prototype of the handler at the top of the file. And finally, the provided implementation of the exception handlers contains endless loops that tie up the CPU. In other words, if any of such exception handler is ever executed, the system will freeze, which the user will perceive as denial of service. This is not acceptable in any production-grade code. The generated code also contains the file with the extension .lds, which is the linker script. The purpose of this file is to tell the linker where ROM and RAM are located in the address space and where to place various program sections. You saw an example of a linker script for the IAR toolset in lesson 14. Here you have a linker script for the GNU toolset. This is again a beaten-path linker script, which matches the startup code. Among others, it allocates the stack as the last section in RAM. In my opinion this is a mistake, because stack grows toward the lower addresses on ARM, and so a stack overflow could damage the RAM sections above it. In fact, this seems the likely cause of failure in the infamous Toyota unintended acceleration cases, as I have described in the article "Are we shooting ourselves in the foot with stack overflow?". I provide a link to this article in the comment section for this video. So, it seems that the code generated by CCS is not terribly usable, but the good news is that you can fix all the issues in it by applying the lessons you've learned so far. The first thing then is to copy all the relevant code from the previous lesson18 to the lesson19 folder. The usable files are: bsp.h, bsp.c, main.c, startup_tm4c.c, and the master header file for your TM4C MCU. Interestingly, the files copied to the lesson19 folder immediately show up inside your project. This is how all Eclipse projects behave. All source files in the project directory are automatically included in the project and you don't need to explicitly add them as it was the case in the IAR Embedded Workbench IDE. This Eclipse policy has its disadvantages too, however. For example, now you have two startup files in the project, so you need to delete one of them. So let's try to build this project. This time you get some errors. The first error is that the compiler cannot find the include file "core_cm4.h". This file is part of the CMSIS, which is not directly available in Code Composer Studio, as it was in IAR Embedded Workbench. This is not a big problem, as you can easily provide CMSIS yourself. Here, I have prepared for you a directory CMSIS, which contains the core header files in the sub-directory Include. You should copy the CMIS directory into the folder where you keep the lessons of this video course. That way you can re-use CMSIS in all upcoming lessons. Of course copying a directory is not enough, because you also need to tell the compiler to look for include files in this new directory CMSIS/Include. You accomplish this by means of the project Properties dialog box, which you open by right-clicking on the project and selecting the Properties pop-up menu. Specifically, you need to choose the Directories property in the GNU Compiler group, where you find the "include paths" pane. To add a new include directory, click on the plus button. The first, easy way is to simply browse your file system for the CMSIS/Include directory. But the big drawback of doing this is that you add an *absolute* include path, which will only work on your computer with this specific C:\\embedded_programming\\CMSIS directory. A much better approach is to create a *relative* include path, which will work on any computer. The Eclipse IDE allows you to create relative paths by means of system variables. Specifically, in the list of these variables, you can choose PROJECT_LOC, which will create paths relative to the project location. From the project location, you need to go one level up, and then you append CMSIS/Include. Regarding the use of directory separators, on Windows you can use either back-slashes or forward-slashes. I use forward-slashes, because they seem more universal. When you build again, you see that the previous include error is gone, but you got a bunch of new errors. As it turns out, most of these new errors come from the startup code. This should not be actually that surprising, because this code was written with IAR-specific extensions to the C language, which the GNU compiler does not recognize. So, here I have prepared for you the startup code, which was re-written with the GNU-specific extensions to the C language. As you will see in a minute, the startup code must closely match the linker script, so I included a matching linker script as well. To include these files in the project is simply copy them over to the lesson19 directory. I need to allow overwriting the previous linker script and I also need to remove the previous startup code. When you switch over to the Eclipse IDE, you can see that the project is immediately updated with the new files. Let's quickly review the code, so that you know how it works. First, in contrast to the old file, the new GNU-specific startup code is compliant with the latest CMSIS 4.3.0. When you scroll down to the vector table, you can see that it has a special attribute section(.isr_vector). This is a GNU-specific extension, which tells the compiler to place the following symbol--the vector table in this case--in the specified section. To see where this section is, you can open the new GNU linker script, where you can see that .isr_vector is the first section in ROM. The ROM section, in turn, is located at address 0, so the vector table at the beginning of ROM is also at zero, which is exactly what the ARM CPU needs. As you hopefully remember from lesson-15, the first element of the ARM vector table is the initial top of stack. So, here you see an ampersand, meaning address of, __stack_end__ cast on an int. The symbol __stack_end__ comes again from the linker script. Indeed, when you scroll a bit down, you can see the .stack section as the first section in RAM. Contrary to the beaten-path approach of putting the stack at the last section in RAM, I recommend placing it at the first section. That way, a stack overflow won't be able to damage any other RAM sections. As an additional bonus, a stack overflowing into the un-mapped memory below RAM will be detected automatically by executing the HardFault exception, so you will know about it. Speaking of the stack, you can change its size by adjusting the symbol STACK_SIZE at the top of the linker script. Going back to the startup code, the symbol __stack_end__ is provided by the linker, but the compiler does not know about it. To tell the compiler, you need to declare __stack_end__ as an external variable at the top of the startup file. The other elements of the vector table are addresses of handler functions for Cortex-M exceptions and interrupts. As you can see, the table already contains all the specific handlers, with names compliant with CMSIS, so you don't need to edit the code at all to use any of these exceptions or interrupts. At the same time, if you don't use a given exception or interrupt, it will be automatically replaced by the Default_Handler implementation. This is accomplished by means of a pair of GNU-specific attributes weak and alias. The weak attribute means that such a symbol definition can be overridden by another definition and the linker will quietly discard the weak definition without reporting that the symbol was defined twice. The alias attribute means that if the symbol is not defined, the alias symbol should be used instead. So, for example, if you define the SysTick_Handler in your application, the linker will take your non-weak definition. If you don't define SysTick_Hanler, the linker will take the Default_Handler alias for it and will not report any errors. Notice though that not all handlers are aliased. This is because the standard fault handlers are actually defined in this startup code so that you don't need to define them in your application. But these handlers are not the primitive endless loops with denial of service. The provided implementations use inline assembly to carefully avoid any use of the stack, which might be corrupted at this point. The assembly code stores the information about the fault in r0 and r1 registers and then branches to assert_handler, where you can perform your last damage control. Here you encounter another GNU-specific attribute "naked", which instructs the compiler not do any stack operations for this function. When you try to build again, you still have an error, this time in bsp.c. By now you should know what's the problem. The extended keyword __stackless was an IAR extension for stackless functions. In GNU, you need to replace it with attribute("naked"). Another build. This time, the compiler complains about __enable_interrupts(), which was an IAR intrinsic function. In GNU this operation needs to be replaced with __enable_irq(). Another build, and..., Hallelujah! No errors at all. Congratulations, you have just finished your first port of deeply embedded code from one toolset to another. Time to plug in your Tiva LaunchPad board and test the code. To download the code to the flash memory of the board and start debugging, you press the bug button at the top. The debugger is setup to stop at the beginning of main and indeed it does. Press the Go button to run the code and watch the LED change color once a second. Click on the Pause button to break into the code and watch it stop in the background loop. By the way, the different screen layout that you see now is called in Eclipse the "Debug Perspective". This is to differentiate this view from the "Edit Perspective" that you saw during editing the code. The Debug Perspective provides all the debugger views that you encountered in IAR, such as the disassembly view. You can also single-step through the code and watch the LED being turned on and off. You can set breakpoints, like for example inside the SysTick_Handler to see how frequently this interrupt is called. To stop the debug session and return to the "Edit Perspective", press the Stop button at the top. As the final step of this lesson, let's modify the behavior of the code copied from your previous IAR project to change the color of the toggled LED from red to blue, for example. Build the project and start debugging as before... Watch the LED blink in a new color. This concludes this lesson about switching the toolset to GNU-ARM and Eclipse-based Code Composer Studio (CCS). The startup code and linker script from this lesson are much closer to production-quality than the typical code distributed by silicon vendors. The code is compliant with CMSIS and will work with any toolset based on GNU-ARM, not just with CCS. You can easily adapt it for any ARM Cortex-M microcontroller. If you'd like to learn more about using the free GNU-ARM toolset, I would recommend my 10-part article "Building Bare Metal ARM Systems with GNU", which in 2007 was the most popular article on Embedded.com. This article talks about the classic ARM7/ARM9 cores, but much of the information still applies to Cortex-M as well. I provide a link to this article in the description of this video on YouTube. The project download for this lesson will come in two parts: the usual lesson19.zip archive with the CCS project and code for the lesson and the CMSIS.zip archive with the CMSIS code. In the next lesson I will finally talk about race conditions, which is a concept that you absolutely need to understand to effectively work with interrupts. If you like this channel, please subscribe to stay tuned. You can also visit state-machine.com/quickstart for the class notes and project file downloads.
B1 中級 嵌入式編程第19課:GNU-ARM和Eclipse (Embedded Programming Lesson 19: GNU-ARM and Eclipse) 64 5 Ed 發佈於 2021 年 01 月 14 日 更多分享 分享 收藏 回報 影片單字