Skip to content

Commit

Permalink
Pull CMSIS headers from github
Browse files Browse the repository at this point in the history
cpq committed Jun 16, 2023
1 parent 2a61ea2 commit 785aa2e
Showing 14 changed files with 66 additions and 22,190 deletions.
81 changes: 24 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1315,26 +1315,23 @@ CMSIS is an ARM standard, and since CMSIS headers are supplied by the MCU
vendor, they are the source of authority. Therefore, using vendor
headers is a preferred way, rather than writing definitions manually.
In this section, we will replace our API functions in the `mcu.h` by the
CMSIS vendor header, and leave the rest of the firmware intact.
STM32 CMSIS headers for F4 family can be found at
https://github.com/STMicroelectronics/cmsis_device_f4 repo. From there,
copy the following files into our firmware directory,
[step-5-cmsis](step-5-cmsis):
- [stm32f429xx.h](https://raw.githubusercontent.com/STMicroelectronics/cmsis_device_f4/master/Include/stm32f429xx.h)
- [system_stm32f4xx.h](https://raw.githubusercontent.com/STMicroelectronics/cmsis_device_f4/master/Include/system_stm32f4xx.h)
Those two files depend on a standard ARM CMSIS includes, download them too:
- [core_cm4.h](https://raw.githubusercontent.com/STMicroelectronics/STM32CubeF4/master/Drivers/CMSIS/Core/Include/core_cm4.h)
- [cmsis_gcc.h](https://raw.githubusercontent.com/STMicroelectronics/STM32CubeF4/master/Drivers/CMSIS/Core/Include/cmsis_gcc.h)
- [cmsis_version.h](https://raw.githubusercontent.com/STMicroelectronics/STM32CubeF4/master/Drivers/CMSIS/Core/Include/cmsis_version.h)
- [cmsis_compiler.h](https://raw.githubusercontent.com/STMicroelectronics/STM32CubeF4/master/Drivers/CMSIS/Core/Include/cmsis_compiler.h)
- [mpu_armv7.h](https://raw.githubusercontent.com/STMicroelectronics/STM32CubeF4/master/Drivers/CMSIS/Core/Include/mpu_armv7.h)
From the `mcu.h`, remove all peripheral API and definitions, and leave only
standard C inludes, vendor CMSIS include, defines to PIN, BIT, FREQ, and
`timer_expired()` helper function:
There are two sets of CMSIS headers:
- First, there are ARM Core CMSIS headers. They describe ARM core,
and published by ARM on github: https://github.com/ARM-software/CMSIS_5
- Second, there are MCU vendor CMSIS headers. They describe MCU peripherals,
and published by the MCU vendor. In our case, ST publishes them at
https://github.com/STMicroelectronics/cmsis_device_f4
We can pull those headers by a simple Makefile snippet:
The ST CMSIS package also provides startup files for all their MCUs. We
can use those instead of hand-writing the startup.c. The ST-provided startup
file calls `SystemInit()` function, so we define it in the `main.c`.
Now, let's replace our API functions in the `mcu.h` using CMSIS definitions,
and leave the rest of the firmware intact. From the `mcu.h`, remove all
peripheral API and definitions, and leave only standard C inludes, vendor CMSIS
include, defines to PIN, BIT, FREQ, and `timer_expired()` helper function:
```c
#pragma once
@@ -1366,38 +1363,12 @@ If we try to rebuild the firmware - `make clean build`, then GCC will fail
complaining about missing `systick_init()`, `GPIO_MODE_OUTPUT`, `uart_init()`,
and `UART3`. Let's add those using STM32 CMSIS files.
Let's start from `systick_init()`. The `core_cm4.h` header defines
`SysTick_Type` structure which is identical to our `struct systick`, and has
an appropriate #define for `SysTick` peripheral. Also, `stm32f429xx.h` has
a `RCC_TypeDef` structure and appropriate #define for the `RCC`. Therefore
our `systick_init()` function remains almost unchanged: we only have to replace
`SYSTICK` with `SysTick`:
```c
static inline void systick_init(uint32_t ticks) {
if ((ticks - 1) > 0xffffff) return; // Systick timer is 24 bit
SysTick->LOAD = ticks - 1;
SysTick->VAL = 0;
SysTick->CTRL = BIT(0) | BIT(1) | BIT(2); // Enable systick
RCC->APB2ENR |= BIT(14); // Enable SYSCFG
}
```
Let's start from `systick_init()`. ARM core CMSIS headers provide a
`SysTick_Config()` function that does the same - so we'll use it.
Next goes `gpio_set_mode()` function. The `stm32f429xx.h` header has
`GPIO_TypeDef` structure, identical to our `struct gpio`. Let's use it:
```c
#define GPIO(bank) ((GPIO_TypeDef *) (GPIOA_BASE + 0x400 * (bank)))
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
static inline void gpio_set_mode(uint16_t pin, uint8_t mode) {
GPIO_TypeDef *gpio = GPIO(PINBANK(pin)); // GPIO bank
int n = PINNO(pin); // Pin number
RCC->AHB1ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
gpio->MODER &= ~(3U << (n * 2)); // Clear existing setting
gpio->MODER |= (mode & 3) << (n * 2); // Set new mode
}
```
https://github.com/cpq/bare-metal-programming-guide/blob/2a61ea23e44c4531b66f6508238cfc43ca7c2634/step-5-cmsis/mcu.h#L32-L41
The `gpio_set_af()` and `gpio_write()` functions is also trivial -
simply replace `struct gpio` with `GPIO_TypeDef`, and that's all.
@@ -1419,15 +1390,11 @@ shows the output. Congratulations, we have adopted our firmware code to
use vendor CMSIS header files. Now let's reorganise the repository a bit
by moving all standard files into `include` directory and updating Makefile
to let GCC know about it:
https://github.com/cpq/bare-metal-programming-guide/blob/2a61ea23e44c4531b66f6508238cfc43ca7c2634/step-5-cmsis/Makefile#L3
```make
...
-g3 -Os -ffunction-sections -fdata-sections -I. -Iinclude \
```
We have left with
a project template that can be reused for the future projects.
A complete project source code you can find in [step-5-cmsis](step-5-cmsis)
We have left with a project template that can be reused for the future
projects. A complete project source code you can find in
[step-5-cmsis](step-5-cmsis)
## Setting up clocks
20 changes: 14 additions & 6 deletions step-5-cmsis/Makefile
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \
-Wformat-truncation -fno-common -Wconversion \
-g3 -Os -ffunction-sections -fdata-sections -I. -Iinclude \
-g3 -Os -ffunction-sections -fdata-sections \
-I. -Iinclude -Icmsis_core/CMSIS/Core/Include -Icmsis_f4/Include \
-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(EXTRA_CFLAGS)
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
SOURCES = main.c startup.c syscalls.c
SOURCES = main.c syscalls.c
SOURCES += cmsis_f4/Source/Templates/gcc/startup_stm32f429xx.s # ST startup file. Compiler-dependent!

ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F
else
RM = rm -f
RM = rm -rf
endif

build: firmware.bin

firmware.elf: $(SOURCES)
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
firmware.elf: cmsis_core cmsis_f4 mcu.h link.ld Makefile $(SOURCES)
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@

firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@

flash: firmware.bin
st-flash --reset write $< 0x8000000

cmsis_core:
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@

cmsis_f4:
git clone --depth 1 -b v2.6.8 https://github.com/STMicroelectronics/cmsis_device_f4 $@

clean:
$(RM) firmware.*
$(RM) firmware.* cmsis_*
266 changes: 0 additions & 266 deletions step-5-cmsis/include/cmsis_compiler.h

This file was deleted.

2,085 changes: 0 additions & 2,085 deletions step-5-cmsis/include/cmsis_gcc.h

This file was deleted.

39 changes: 0 additions & 39 deletions step-5-cmsis/include/cmsis_version.h

This file was deleted.

2,129 changes: 0 additions & 2,129 deletions step-5-cmsis/include/core_cm4.h

This file was deleted.

270 changes: 0 additions & 270 deletions step-5-cmsis/include/mpu_armv7.h

This file was deleted.

17,185 changes: 0 additions & 17,185 deletions step-5-cmsis/include/stm32f429xx.h

This file was deleted.

104 changes: 0 additions & 104 deletions step-5-cmsis/include/system_stm32f4xx.h

This file was deleted.

20 changes: 8 additions & 12 deletions step-5-cmsis/link.ld
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
ENTRY(_reset);
ENTRY(Reset_Handler);
MEMORY {
flash(rx) : ORIGIN = 0x08000000, LENGTH = 2048k
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 192k /* remaining 64k in a separate address space */
}
_estack = ORIGIN(sram) + LENGTH(sram); /* stack points to end of SRAM */

SECTIONS {
.vectors : { KEEP(*(.vectors)) } > flash
.text : { *(.text*) } > flash
.rodata : { *(.rodata*) } > flash
.vectors : { KEEP(*(.isr_vector)) } > flash
.text : { *(.text*) } > flash
.rodata : { *(.rodata*) } > flash

.data : {
_sdata = .; /* .data section start */
_sdata = .;
*(.first_data)
*(.data SORT(.data.*))
_edata = .; /* .data section end */
_edata = .;
} > sram AT > flash
_sidata = LOADADDR(.data);

.bss : {
_sbss = .; /* .bss section start */
*(.bss SORT(.bss.*) COMMON)
_ebss = .; /* .bss section end */
} > sram
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram

. = ALIGN(8);
_end = .; /* for cmsis_gcc.h */
_end = .;
}
15 changes: 10 additions & 5 deletions step-5-cmsis/main.c
Original file line number Diff line number Diff line change
@@ -8,12 +8,17 @@ void SysTick_Handler(void) {
s_ticks++;
}

uint32_t SystemCoreClock = FREQ;
void SystemInit(void) {
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // Enable SYSCFG
SysTick_Config(SystemCoreClock / 1000); // Tick every 1 ms
}

int main(void) {
uint16_t led = PIN('B', 7); // Blue LED
systick_init(FREQ / 1000); // Tick every 1 ms
gpio_set_mode(led, GPIO_MODE_OUTPUT); // Set blue LED to output mode
uart_init(UART3, 115200); // Initialise UART
uint32_t timer = 0, period = 500; // Declare timer and 500ms period
uint16_t led = PIN('B', 7); // Blue LED
gpio_set_mode(led, GPIO_MODE_OUTPUT); // Set blue LED to output mode
uart_init(UART_DEBUG, 115200); // Initialise UART
volatile uint32_t timer = 0, period = 500; // Declare timers
for (;;) {
if (timer_expired(&timer, period, s_ticks)) {
static bool on; // This block is executed
15 changes: 6 additions & 9 deletions step-5-cmsis/mcu.h
Original file line number Diff line number Diff line change
@@ -21,14 +21,6 @@ static inline void spin(volatile uint32_t count) {
while (count--) asm("nop");
}

static inline void systick_init(uint32_t ticks) {
if ((ticks - 1) > 0xffffff) return; // Systick timer is 24 bit
SysTick->LOAD = ticks - 1;
SysTick->VAL = 0;
SysTick->CTRL = BIT(0) | BIT(1) | BIT(2); // Enable systick
RCC->APB2ENR |= BIT(14); // Enable SYSCFG
}

#define GPIO(bank) ((GPIO_TypeDef *) (GPIOA_BASE + 0x400U * (bank)))
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };

@@ -56,6 +48,10 @@ static inline void gpio_write(uint16_t pin, bool val) {
#define UART2 USART2
#define UART3 USART3

#ifndef UART_DEBUG
#define UART_DEBUG USART3
#endif

static inline void uart_init(USART_TypeDef *uart, unsigned long baud) {
// https://www.st.com/resource/en/datasheet/stm32f429zi.pdf
uint8_t af = 7; // Alternate function
@@ -95,7 +91,8 @@ static inline uint8_t uart_read_byte(USART_TypeDef *uart) {
return (uint8_t) (uart->DR & 255);
}

static inline bool timer_expired(uint32_t *t, uint32_t prd, uint32_t now) {
static inline bool timer_expired(volatile uint32_t *t, uint32_t prd,
uint32_t now) {
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
if (*t > now) return false; // Not expired yet, return
22 changes: 0 additions & 22 deletions step-5-cmsis/startup.c

This file was deleted.

5 changes: 4 additions & 1 deletion step-5-cmsis/syscalls.c
Original file line number Diff line number Diff line change
@@ -56,7 +56,7 @@ int _getpid(void) {

int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
if (fd == 1) uart_write_buf(UART3, ptr, (size_t) len);
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
return -1;
}

@@ -84,3 +84,6 @@ int mkdir(const char *path, mode_t mode) {
(void) path, (void) mode;
return -1;
}

void _init(void) {
}

0 comments on commit 785aa2e

Please sign in to comment.