Almost all firmware is written in C, with C++ growing on larger projects, and the language is where hardware knowledge turns into working code. Embedded C is ordinary C used with a few extra habits: you think in terms of memory addresses, you care about every byte, and you talk to hardware directly.
You'll begin with variables and pointers, because a pointer is how C names a memory address. You'll then use pointers to reach the hardware registers of a real board, learn why the volatile keyword matters when the compiler is allowed to optimize, and practice the bit-wise operators that let you change one bit of a register without disturbing the rest.
The lessons use a C workflow on an ARM Cortex-M board, and the same ideas apply to C++ firmware. Once you've finished, move on to Toolchains & Version Control to set up the tools you need to build, flash, and debug your code.
How variables live in memory, what the load and store instructions do, and how C represents addresses with pointers: declaring one, taking an address with &, and dereferencing with *.
Reading a board schematic and the data sheet, finding the memory map, and using pointers in C to reach the GPIO registers that turn an LED on and off.
Naming hardware registers with macros and vendor headers, and why the volatile keyword stops the compiler from optimizing away code that talks to hardware.
Setting, clearing, toggling, and shifting individual bits with OR, AND, XOR, NOT, and the shift operators, applied to control a single LED without disturbing the others.