libopencm3

Installation

  • create a new folder and cd it with a terminal

  • load the LibOpenCM3 source code from github with

git clone https://github.com/libopencm3/libopencm3.git (blocks with with git://github.com/libopencm3/libopencm3.git)

or download and extract the zip file libopencm3-master.zip

  • The 3 following files are missing:

./include/libopencm3/stm32/l4/nvic.h
./include/libopencmsis/stm32/l4/irqhandlers.h
./lib/stm32/l4/vector_nvic.c
dir lib L4

Create the missing files with a python script:

irq2nvic_h: generate an nvic.h header from a small JSON file describing the interrupt numbers
$python3 ./scripts/irq2nvic_h ./include/libopencm3/stm32/l4/irq.json

with:

irq_json
{
  "irqs": [
      "wwdg",
      "pvd_pvm",
      "tamp_stamp",
      "rtc_wkup",
      "flash",
      "rcc",
      "exti0",
      ...
      "exti4",
      "dma1_channel1",
      ...
      "dma1_channel7",
      "adc1_2",
      "can1_tx",
      "can1_rx0",
      "can1_rx1",
      "can1_sce",
      "exti9_5",
      "tim1_brk_tim15",
      "tim1_up_tim16",
      "tim1_trg_com_tim17",
      "tim1_cc",
      "tim2",
      "tim3",
      "tim4",
      "i2c1_ev",
      "i2c1_er",
      "i2c2_ev",
      "i2c2_er",
      "spi1",
      "spi2",
      "usart1",
      "usart2",
      "usart3",
      "exti15_10",
      "rtc_alarm",
      "dfsdm3",
      "tim8_brk",
      "tim8_up",
      "tim8_trg_com",
      "tim8_cc",
      "adc3",
      "fmc",
      "sdmmc1",
      "tim5",
      "spi3",
      "uart4",
      "uart5",
      "tim6_dacunder",
      "tim7",
      "dma2_channel1",
      ...
      "dma2_channel5",
      "dfsdm0",
      "dfsdm1",
      "dfsdm2",
      "comp",
      "lptim1",
      "lptim2",
      "otg_fs",
      "dma2_channel6",
      "dma2_channel7",
      "lpuart1",
      "quadspi",
      "i2c3_ev",
      "i2c3_er",
      "sai1",
      "sai2",
      "swpmi1",
      "tsc",
      "lcd",
      "aes",
      "rng",
      "fpu",
      "hash_crs",
      "i2c4_ev",
      "i2c4_er",
      "dcmi",
      "can2_tx",
      "can2_rx0",
      "can2_rx1",
      "can2_sce",
      "dma2d"
  ],
  "partname_humanreadable": "STM32 L4 series",
  "partname_doxygen": "STM32L4",
  "includeguard": "LIBOPENCM3_STM32_L4_NVIC_H"
 }
  • Compile the STM32L4 library with:

$make V=1 TARGETS='stm32/l4 stm32/h7'

The first line is

./scripts/irq2nvic_h ./include/libopencm3/stm32/h7/irq.json;

So, the last command with python seems to be obsolete.

This “make” create all the necessary object files.

$make TARGETS='stm32/l4 stm32/h7'
 BUILD   lib/stm32/l4
 CC      adc.c
 .
 .
 AR      libopencm3_stm32l4.a

 BUILD   lib/stm32/h7
 CC      dac_common_all.c
 .
 .
 CC      dwt.c
 AR      libopencm3_stm32h7.a

It also create the equivalent of zip files for libraries: libopencm3_stm32l4.a and libopencm3_stm32h7.a

The AR program (arm-none-eabi-ar) can create, modify and extract from archives.

Makefile for ‘c’ programs using libopencm3

create, modify, and extract from archives Let’s have a small c program:

#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>

#define LED_PORT    GPIOA
#define LED_RED     GPIO5

// function prototype
int foo (int a);

extern int foo (int a)
{
   a=rcc_system_clock_source();
   rcc_periph_clock_enable(RCC_GPIOA);
   gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_RED);
   gpio_set_output_options(LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_LOW, LED_RED);

   gpio_set(LED_PORT, LED_RED);

   return a;
}

In the Makefile, we need to add the following operations:

  • tell the linker the location and the name of the opencm3 library

  • define the stm32 family

  • specify the floating point method

Location and name of the opencm3 library

OPENCM3_DIR := ../../libopencm3
CFLAGS  = -mcpu=cortex-m4 -Wall -Wextra -Werror -g3  -O0 -fstack-usage
CFLAGS += -Wundef -Wshadow -Wimplicit-function-declaration -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
CFLAGS += -fno-common -ffunction-sections -fdata-sections -MD
CFLAGS += --specs=nosys.specs -save-temps -fverbose-asm -I$(OPENCM3_DIR)/include/
CFLAGS += -v -D STM32L4 -mfloat-abi=hard -mthumb

The I flag shows the header path (.h):

-I$(OPENCM3_DIR)/include/

dir library

To get out of the source c directory to be able to reach the opencm3 library, we need to do 2 cd ..: it explains “../../libopencm3” in OPENCM3_DIR.

Define the stm32 family

The -D STM32L4 flag for the c compiler loader specifies the MCU in use. This flag will prevents an error in a number of header files (gpio.h, rcc.h, …) of the libopencm3 library when the STM32 device is unknown:

#if defined(STM32F0)
#       include <libopencm3/stm32/f0/gpio.h>

...

#elif defined(STM32L4)
#       include <libopencm3/stm32/l4/rcc.h>

...
#elif defined(STM32H7)
#       include <libopencm3/stm32/h7/rcc.h>

...

#else
#       error "stm32 family not defined."
#endif

Specify the floating point method

The ‘-mfloat-abi=hard’ flag prevents the following error:

arm-none-eabi-ld: failed to merge target specific data of file libopencm3_stm32l4.a(gpio_common_f0234.o)
arm-none-eabi-ld: error: libopencm3_stm32l4.a(rcc.o) uses VFP register arguments, gpio.elf does not

The M4 has a hardware floating point unit (FPU) with Virtual Floating Point (VFP) registers.

# Used libraries #LDFLAGS += -L$(OPENCM3_DIR)/lib #LDLIBS += -l$(LIBNAME)

# all: gpio.elf LIBNAME = opencm3_stm32l4

# Used libraries #LDLIBS += -l$(LIBNAME) #LDLIBS := -Wl,–start-group -lc -lgcc -lnosys -Wl,–end-group LDLIBS := -lc -lnosys

# $(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(*).elf

# —————————————————————————- gpio.elf: gpio.o clockGPIO.o config_GPIO.o lab.o

arm-none-eabi-ld -Ttext 0x8000000 -Tdata=0x20000000 $(LDLIBS) gpio.o config_GPIO.o clockGPIO.o lab.o libopencm3_stm32l4.a -g -o gpio.elf

gpio.o: gpio.s

arm-none-eabi-as -mthumb -g gpio.s -o gpio.o

clockGPIO.o: sub1.s

arm-none-eabi-as -mthumb -g sub1.s -o clockGPIO.o

config_GPIO.o: sub2.s

arm-none-eabi-as -mthumb -g sub2.s -o config_GPIO.o

lab.o: lab.c $(OPENCM3_DIR)/lib/libopencm3_stm32l4.a

arm-none-eabi-gcc -c $(CFLAGS) lab.c -o lab.o