ARM Cortex-M3 and STM32 Basics
All the datasheets and reference manuals which describe a processor architecture in detail, taken together, may run into thousands of pages. Very often, the systems programmer who wishes to write / port something like a real time OS will need only a core set of information regarding the:
- The processor memory map
- Reset behaviour
- System clock
- Basic instruction set
This wiki page is an experiment in gathering just the amount of information about an ARM Cortex-M3 based processor which will help us understand the working of a simple RTOS (in this case, FreeRTOS).
About ARM Cortex-M3
- A new Thumb-2 instruction set with 16 bit and 32 bit instructions.
- Hardware stack manipulation - registers are pushed/popped automatically during ISR entry/exit
- A SysTick timer integrated into the processor core - useful for writing RTOS code.
Luminary Micro was the first company to bring out Cortex-M3 based processors. This was followed by STMicro bringing out STM32. Cortex-M3 based processors have been announced by NXP, but they are not yet available in the market.
The Cortex-M3 has a linear 32 bit address space. The first 1Gb is split evenly between
code and data; code (flash) is from
0x1fffffff and data (SRAM) is from
0x3fffffff. Peripherals are mapped to locations
Note: The STM32F10xxx processor's flash is mapped to location 0x08000000; but it
can also be accessed from location 0x0.
There is a special
System control space from
region holds, among other things, registers related to the Nested Vectored
Interrupt controller and the SysTick timer.
Cortex-M3 processors are little endian.
The interrupt vector table starts at address
0x4 (the cortex processor uses
the 4 byte value at address
0x0 to initialize the stack pointer).
Each entry is 4 bytes long and should contain the address of the routine
to be executed. The table starts with the reset vector at location
For the cortex core to start executing code, the only requirement is initializing the first two locations properly. The stack pointer can be made to point to the top of available SRAM and the reset vector should point to the code which is to be executed.
GPIO ports are configured as
input floating upon reset and alternate functions are
not enabled. Each port will have upto 16 pins.
Each GPIO port has two 32 bit configuration registers -
two 32 bit data registers,
GPIOx_ODR, a 32 bit set-reset register,
GPIO_xBSRR, a 16 bit reset register,
GPIOx_BRR and a 32 bit locking register,
Each GPIO pin can be configured as one of:
- Input floating
- Input pull-up
- Input pull-down
- Analog input
- Output open-drain
- Output push-pull
- Alternate function push-pull
- Alternate function open-drain
Configuring the GPIO ports
Each I/O pin of a GPIO port has four configuration bits -
GPIOx_CRL holds configuration
bits for 8 pins and
GPIOx_CRH holds the configuration bits for the remaining 8 pins.
The four configuration bits are divided into two MODE bits and two CNF bits -
with MODE bits occupying lower bit positions. For example, in the case GPIO port B,
bits 0 and 1 of
are the MODE bits and bits 2 and 3 are the CNF bits for pin 0.
The MODE bits can have the following values:
00- Input mode (reset state)
01- Output mode (max 10MHz speed)
10- Output mode (max 2MHz speed)
11- Output mode (max 50MHz speed)
The CNF bit values are inte
rpreted differently according to the MODE. If MODE is input,
the CNF bit values are interpreted as:
00- Analog input
01- Floating input
10- Input with pull-up/pull-down
`If MODE is output, the CNF bit values are interpreted as:
00- General purpose output push-pull
01- General purpose output open-drain
10- Alternate function output push-pull
11- Alternate function output open-drain
Here is a link which explains difference between push-pull and open-drain configurations. Normally, to drive LED’s, we will configure the output pins as push-pull.
The Bit Set/Reset register
Bits 0 to 15 of
GPIOx_BSRR are used to “set” the corresponding port pin - writing a
0 to these bits have no effect while writing a 1 will set the port pin.
Bits 16 to 31 are used to “reset” the corresponding port pin - writing a
0 to these bits have no effect while writing a 1 will reset the port pin.
Upon reset, an internal RC oscillator of 8MHz frequency is used as the system clock. For better precision, an external crystal can be used as the clock source. An internal PLL can be used to multiply the base clock (either internal or external) to the maximum system clock frequency of 72MHz.
Clocks to all peripherals (except SRAM and flash) are disabled on reset - so
if we wish to use say the GPIO ports, it’s corresponding
peripheral clock has to be enabled.
Enabling GPIO Clock
No peripheral unit will work without its clock being enabled. Lighting up an LED on a GPIO port requires that the corresponding peripheral clock is enabled.
Bits 2 to 8 of the RCC_APB2ENR register (address
0x40021018) control the clocks
to IO ports A to G.
The STM32F10xxx has 3 different boot modes - mode selection is done using two pins BOOT0 and BOOT1.
| BOOT 1 | BOOT 0 | Boot Mode |
| x | 0 | Main Flash memory |
| 0 | 1 | System memory |
| 1 | 1 | Embedded SRAM |
A timer which generates interrupts periodically is at the heart of most real-time
operating systems. The Cortex-M3 core has a very interesting feature -
it provides a
SysTick timer integrated into the CPU core which can be used for
providing the RTOS
tick. Because this timer is part of the processor core,
all Cortex-M3 devices, irrespective of the vendor, will have this feature.
Note: the SysTick timer may not be properly documented in the vendor's processor
reference manual - it is better to check out the official ARM documentation.
The SysTick timer’s operation is very simple. The counter starts counting down from
the value specified in the
reload register (address
0xe000e014) - when the value
reaches 0, it optionally generates an interrupt and once again starts counting down
from the initial value specified in the
The SysTick interrupt is by default enabled in the NVIC (nested vectored interrupt
controller) - we only have to enable it in the timer by setting the SysTick control
and status register’s (address
0xe000e010) D1’th bit to 1. Setting the D0’th bit
of the same register enables the timer. Setting the D2’th bit to 1 chooses the CPU
clock as the clock source of the timer.
Note: A bit of confusion here - is it the cpu clock or the AHB clock?
What if the bit is zero?