Table of Contents
Microcontroller Components
Simplified Blue Pill Architecture
CPU
The STM32F103 microcontroller uses an ARM Cortex-M3 CPU. It plays a similar role to the CPU in a PC, but is much smaller, simpler, and more energy-efficient.
By itself, a CPU is inert; it needs some things around it to function.
- a clock signal
- a reset signal
- bus interface(s)
The clock signal is the heartbeat of all stateful digital circuits. State transitions occur at a clock edge, inputs are captured at a clock edge, and outputs are asserted at a clock edge. Most CPUs are designed entirely with synchronous logic today and therefore nothing (at the level of digital logic, anyway) happens between clock cycles.
Circuits as complex as CPUs have many stateful components, and in order to work correctly they have to start at a correct initial state. That is the job of the power-on reset. After powering up, the CPU's state can be put back to that initial state again by asserting a reset signal.
The bus interface is critical because a CPU can do very little without instructions, and when it comes out of reset the CPU has none. The first thing it does is to use its bus interface to fetch the top-of-stack address from address 0x00000000, then the location of its first instruction to execute from the next location, 0x00000004. That location is called the "Reset Vector"; it informs the CPU the address of the instructions it should execute when it comes out of reset.
The CPU itself follows instructions from the ARM Thumb-1 and Thumb-2 instruction sets; these are a more compact encoding of classic ARM instructions. It has relatively fast integer multiply and divide instructions, but no floating point unit!
The CPU has an exception-handling mechanism; when an exception condition arises, the CPU switches to "handler mode" and uses the exception vector table to determine what address it should execute from in order to handle the type of exception it received. It has a separate stack pointer for running in handler mode.
Bus
Most microcontrollers today don't just have a single bus, but a complex hierarchy of different types of buses. But from the CPU's perspective, it appears as a unified address space. Sometimes the details of the bus structure matter, but when starting the simplified view is fine.
The function of the bus is to translate requests from "bus masters" such as the CPU into operations on peripherals that are also connected to the bus. Peripherals are mapped into different regions of the address space, which on a 32-bit addressed bus like the one we are dealing with, is 4GB in size.
In a bus transaction, a master asserts both an address and some information about the request, such as whether it is a read request or write request, and whether it is for the full data width of the bus or some subset of it. If the address corresponds to a region mapped to a peripheral, that peripheral is given an enable signal and reads the details of the request from the bus, performs the operation, and signals completion.
Asserting a transaction to an unmapped address, or a write transaction to a read-only address, may trigger a bus fault exception in the CPU.
Real buses, including the ones on our microcontroller, are far more complex in their protocols, but this description should be good enough to start with.
RAM
Memory is just a peripheral on the bus that responds to a write operation by storing the data from the bus at the address (suitably translated into its internal addressing scheme) that was on the bus. A subsequent read operation with the same address asserted on the bus will cause the memory to write the same data back to the bus.
In other words, the range of addresses mapped to RAM act just like you would expect memory to act.
While the CPU in a PC is typically far faster than the RAM, our microcontroller is equipped with RAM that be accessed at the full processor speed. But there is comparatively very little of it!
Flash
Flash memory is a form of electrically-erasable read-only memory. It is typically used to store your program's instructions and data. The Flash peripheral has two regions mapped into memory; one region acts as read-only memory, and another region presents a set of read/write control registers that you can manipulate to erase, re-program, and adjust the access latency of the peripheral.
In this microcontroller, the CPU generally fetches its instructions directly from Flash rather than RAM. When the CPU is running full-speed, the Flash isn't fast enough to perform a read every cycle, but it includes a prefetch buffer on its instruction fetch interface to keep it from making the CPU wait too often.
Peripherals
Peripherals are pieces of hardware, part of the microcontroller chip, that can be controlled by the CPU (or any bus master on their bus, in fact) by manipulating a set of read/write control regions, called register sets, that are mapped into the bus address space. These can include I/O peripherals, co-processors, or different kinds of memories.
Clock Tree
Just as the CPU needs a clock to function, all of the peripherals need clocks to function as well, and they often need to be running at different clock rates than the CPU or each other.
Clocks can either be generated by oscillating circuits internal to the microcontroller or from external oscillating circuits. There is generally a dedicated peripheral for selecting the source oscillator for core system clocks, controlling clock manipulation circuitry such as dividers, multipliers, or even fancy Phase-Locked-Loop-based clock frequency synthesizers.
Many peripheral register sets will have their own clock logic to pick among several system or external sources for their clocking as well, and may even have their own sets of clock dividers that you can choose from.
Setting up the microcontroller's clock tree properly for the peripherals you need to use and the CPU operating frequency you want can be surprisingly complex!
Power Management
Because many microcontrollers end up running from batteries, power consumption can be very important, and most have fairly fine-grained power control over parts of the chip. The STM32 we are using is fortunately configured out of reset in a useful configuration, so you should only need to investigate these controls if you want to reduce power consumption.
Pin Multiplexing
Most microcontrollers have far more I/O peripheral signals than they have pins. This means that most pins on the external package can serve more than one peripheral depending on how you configure things. Sometimes, a peripheral can choose between multiple pins for a signal, so that you can select different sets of pins depending on which other peripherals are in use.
Like clock trees, getting the right pin multiplexing configuration can be tricky!