Setting up an Embedded Development Environment

Revision as of 14:15, 6 July 2024 by Ayelovic (talk | contribs)

A development environment is a collection of software organized to help streamline writing code, compiling it, and installing it to the correct location to be run.

For writing embedded software, it is important to recall how compilation works.

Note

For the purposes of this page, I will be using the Make naming convention for compiler toolchain programs, namely CC for the compiler, LD for the linker, OBJCOPY for the object file translator. and AS for the assembler.

Compilation

A compiler translates code from a source language to a target language. In our case, C is the source language and Arm assembly is the target language. We don't really care about the generated assembly code though, so when we run the compiler we also have it assemble the generated assembly code into an object file ready for linking.

Linking

A linker takes multiple object files and combines them into a coherent machine code executable, resolving symbols and references in the process. This is how things like functions and function prototypes are correlated and extern variables are resolved.

Architecture

When writing code on a PC intended to be run on a PC, the compilation-into-executable process is really straightforward. There might be some hiccups when it comes to writing software for Windows versus Linux versus macOS for example, but that is just a matter of library usage (when building for Linux your program would link to Linux system libraries, as the exercise in the previous lesson indicates; building for Windows is just a matter of linking a Windows library in its place). It gets a little more complicated when it comes to computer architecture differences however, which has become more evident recently with Apple switching their Macs to Arm processors instead of Intel x86 ones.

Picking the Right Compiler

The compiler is the program is responsible for translating the source code to the correct assembly language, so it's a good idea to start here. Using the GNU compiler toolchain as an example, when you run gcc on a Linux machine with an x86_64, what is actually being run is x86_64-none-linux-gcc (in a sense, that's why it's not in the monospaced font, because this isn't actually what happens). For GNU, compiler toolchains roughly follow this naming convention: target_architecture-vendor-ABI, where target_architecture means the architecture you are compiling for (where the compiled code is going to be executed on), vendor is the distributor of the compiler (this part isn't super important, for our purposes this is almost always "none"), and ABI is the Application Binary Interface of your target.

Downloads for Our Board

As of time of writing, we use two MCUs: an STM32G0B1RE, and an STM32G431CB. Both of them use a 32-bit ARM CPU, so that is our target architecture.