STM32 family of microcontrollers are based on
ARM Cortex-M cores.
Cortex-M0 and Cortex-M1 use ARMv6-M architecture, Cortex-M3 uses ARMv7-M, and Cortex-M4 and Cortex-M7 use ARMv7E-M architecture. STM32 family has all of these. The instruction set and certain details are specified by ARM, but the peripherals vary from microcontroller to microcontroller.
To target STM32 microcontrollers, you therefore need a compiler that can target ARMv6-M, ARMv7-M, and/or ARMv7E-M architecture, depending on the STM32 microcontroller. The most commonly used C and C++ ones are GCC, Clang, Keil, and IAR; for a more complete list, see
here (includes other programming languages as well).
GCC is a family of compilers, with each language translated to an internal abstract syntax tree data structure, which the common backend then converts to machine code. Each language is a separate frontend, which converts that language to the internal abstract syntax tree. Clang works in a very similar manner, being the C and C++ frontend, using LLVM as the backend. Some of the others are forks of GCC or Clang, or use LLVM backend.
The object file format used is
ELF. There are two variants, 32-bit and 64-bit, but only 32-bit is used with Cortex-M cores. Compilers and linkers produce ELF files. As firmware update utilities tend to support some variant of
Intel HEX file formats, linkers generate either those directly, or a binary memory image (or images, in case of Harvard architectures, but Cortex-M has a single unified memory addressing scheme) which is then converted to hex or similar format.
The final linkage is controlled by a linker file, which determines how sections are mapped to the memory, and so on. The section model used by ELF files is reflected there, and some features – like collecting information from different object files into a single consecutive array – are either necessary or at least extremely useful for microcontroller firmware development. Even things like interrupt vector arrays can be exposed by the linker, not the compiler (that is, linker determines the memory location, with the compiler only being told what symbol and type to use for it).
ARM also provides an abstraction layer for Cortex-M microcontrollers, called
CMSIS (also at
github.com/ARM-software/CMSIS_5). Vendors tend to provide compatible additions or variants to CMSIS, describing the peripherals provided by each microcontroller.
Often, vendors also provide a Hardware Abstraction Layer (HAL), but their quality and usefulness varies and is up for debate.
Many microcontrollers with native USB interfaces split their firmware into two parts: a bootloader, and the user firmware. The bootloader exposes an interface for easily replacing the user firmware, sometimes even in cases where the user firmware would normally lock up. The easiest of these is USB mass storage, which looks like a USB memory stick with just one file (the user firmware) in it. When one copies a new firmware file to the USB stick, the bootloader first saves it in RAM, calculates and verifies the checksum, and if acceptable, uploads the firmware.
I personally like to use Teensies (based on various NXP microcontrollers; Teensy LC is Cortex-M0+, Teensy 3.2 is Cortex-M4, Teensy 4.x are Cortex-M7F), and they use a proprietary bootloader, which exposes the Teensy as a HID device, so that the upload program does not need administrator privileges, but it does limit the upload speed a bit. On the other hand, it is much smaller than a USB mass storage driver, so more of the total Flash is available for user firmware.
Without a bootloader, or to upload/update the bootloader, you use a separate programmer with a suitable
JTAG adapter for your Cortex-M microcontroller. This also allows you to debug code running on the microcontroller. For STM32s, ST-LINK (/V2 or V3-*) are probably the most commonly used. Mouser sells ST-LINK V3-MINIE for less than 15 USD/EUR, so these do not tend to be expensive, and many are compatible across several manufacturers.
There are also Arduino add-ons and cores for several different Cortex-M microcontrollers, if you want to experiment with that toolchain first. For STM32s, see
STM32duino.com,
its Wiki, and
GitHub sources (C++). It is
licensed under permissive licenses.