quasiyoke

STM32 L152 Discovery kit toolchain setup

ARM microctrollers (MCUs) are cheaper and more powerful than popular Atmel AVR MCUs (source, Russian). I’m familiar with AVR architecture and I have small experience of work with ATMega, but I want to study usage of ARM MCUs in real applications. If you have some experience in programming and working with some electronics this article may help you to start studying ARM platform.

Advanced RISC Machines Ltd. (ARM) is developing their processor designs which are allowed to license by various hardware manufacturers. ARM does not produce any hardware chips at all! One of the last ARM’s processors is Cortex family. It belongs to ARM v7 architecture and has 3 modifications (profiles):

  • The A profile is designed for high-performance open application platforms.
  • The R profile is designed for high-end embedded systems in which real-time performance is needed.
  • The M profile is designed for deeply embedded microcontroller-type systems.

Cortex-M3 processor is based on one profile of the v7 architecture, called ARM v7-M, an architecture specification for microcontroller products. There’s “The Definitive Guide to the ARM Cortex-M3” (PDF, 15 MiB) — it fits perfetly for those who want to study ARM MCUs’ core.

One of ARM’s partners is ST Microelectronics. ST produces a family of 32-bit MCUs. STM32 F2, STM32 F1 and STM32 L1 series are based on Cortex-M3 core. Like other manufacturers ST surrounds Cortex-M core with a bunch of peripheral circuits giving I/O abilities and various features like timers, ADC, temperature measurement and so on. These peripheral devices are specific to each manufacturer. ST has a range of tools for evaluation of their MCUs. They’re not very expensive and give you ability to try some of chip’s features without soldering a single wire.

My friends gave me 32L152CDISCOVERY—STM32 Discovery kit which has on its board:

  • STM32L152RCT6—256 KB Flash memory, 32 KB RAM, 8 KB EEPROM MCU,
  • ST-LINK/V2—in-circuit debugger and programmer connected to USB Mini-B socket (most likely your phone uses another plug),
  • 24-segments LCD,
  • touch sensor,
  • 2 MCU-controlled LEDs,
  • 1 MCU-connected button.

Last few days I’ve spent trying to configure work with my Discovery board on Ubuntu 16.04. In this article I’ve described set up of the following toolchain:

  1. Eclipse CDT,
  2. GNU ARM Eclipse Plug-in,
  3. GNU ARM Embedded toolchain,
  4. OpenOCD.
  5. Open source STLINK tool

I like this setup so much because it has no proprietary tools in it, I have a full control over each step of board programming and such configuration is pretty common and production-ready.

Eclipse CDT

If you still haven’t installed Eclipse CDT, do it right now.

First of all, install Java.

sudo apt install openjdk-8-jre

Download latest Eclipse CDT (Eclipse IDE for C/C++ Developers) from the official website and extract it to /opt/. The specific edition used here is Eclipse IDE for C/C++ Developers v. Mars.2 Release (4.5.2).

cd /opt/ && sudo tar -zxvf ~/Downloads/eclipse-*.tar.gz

To make Eclipse available from launcher we should create shortcut (courtesy to UbuntuHandbook and Ask Ubuntu 1 2).

gksudo gedit /usr/share/applications/eclipse.desktop

Paste the following content to the opened file and save it.

[Desktop Entry]
Name=Eclipse CDT
Type=Application
Exec=env UBUNTU_MENUPROXY=0 SWT_GTK3=0 /opt/eclipse/eclipse
Terminal=false
Icon=/opt/eclipse/icon.xpm
Comment=Integrated Development Environment
NoDisplay=false
Categories=Development;IDE;
Name[en]=Eclipse CDT

Now you should be able to open Eclipse from Unity Dash. I’ll assume that you place your Eclipse workspace here: ~/workspace/

After that we need to install GNU ARM Plug-in using Eclipse’s internal package manager. To do that go to Help > Install new software. We need to add plugin’s repository to “Work with” field. Press “Add…” button and add “GNU ARM Eclipse Plug-in” repository: http://gnuarmeclipse.sourceforge.net/updates

Useful keystrokes

  • Ctrl + B — build project,
  • F11 — start debugging,
  • F8 — resume execution (when program have paused at some breakpoint),
  • Ctrl + F2 — stop debugging,
  • Ctrl + F8 — switch perspective (from Debug to C/C++ and backwards).

How to make Eclipse launch the same debug configuration each time?

You should go to Window > Preferences > Run/Debug > Launching. Select the option “Always launch the previously launched application”. It’s located at the bottom of the dialog. Courtesy to Stack Overflow.

GNU ARM Embedded toolchain

We’re going to compile on our machine MCU’s flash having another processor architecture. This is called cross-compilation. To do that we need special toolchain. Installation is straight-forward for every Ubuntu user.

sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt update
sudo apt install gcc-arm-none-eabi gdb-arm-none-eabi

If installation finished correctly you should be able to test toolchain’s version.

arm-none-eabi-gcc --version

If this command ran correctly, toolchain lays at /usr/bin/. In case when toolchain lays in other place you should specify its location in Eclipse here: Window > Preferences > C/C++ > Build > Global Tools Path.

OpenOCD

OpenOCD is a tool for debugging hardware. Ubuntu has pretty fresh OpenOCD v0.9 in its repos now.

sudo apt install openocd
cd ~/Downloads/
git clone https://github.com/texane/stlink.git
cd ~/Downloads/stlink/
sudo install -m 644 etc/udev/rules.d/49-stlinkv2.rules /etc/udev/rules.d/49-stlinkv2.rules
sudo udevadm control --reload-rules

Create blinking “Hello world”

In this section we’ll make our board blink with its LED. Eclipse GNU ARM Plug-in has a set of STM32 F-series “hello world” example projects. We need to modify one to test our Discovery board equiepped with STM32 L1-series MCU.

In Eclipse open File > New > C Project. Choose some Project name (I’ll use stm32-l1-blink name below) and Project type: “STM32F10x C/C++ Project”. The toolchain should be “Cross ARM GCC”. Press “Next”. On the following wizard’s page choose Flash size: 256 kB, RAM size: 32 kB (that’s our STM32L152RCT6 MCU parameters), all other fields leave without changes. Go through the wizard pressing “Next” to the “Finish”.

Let’s try to build the project to check if toolchain works. Press Project > Build All (Ctrl + B). When compilation finish, you should see Binaries/stm32-l1-blink.elf MCU flash. Compilation works but we should modify the source code.

“Hello world” generated by Eclipse contains library for working with STM32 F10x peripheral devices. You can download such library for STM32 L1 series from official website (you’ll need registration) or my copy (ZIP, 18 MiB, v1.3.1). Unpack it to “home” (assuming you’ve downloaded it to ~/Downloads/):

unzip ~/Downloads/stm32-l1-peripherals-library-v1.3.1.zip -d ~

Peripherals library now unpacked to ~/STM32L1xx_StdPeriph_Lib_V1.3.1/. To merge it with our project you should do the following (assuming your Eclipse workspace is at ~/workspace/):

rm ~/workspace/stm32-l1-blink/include/stm32f10x_conf.h
cp ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Project/STM32L1xx_StdPeriph_Templates/stm32l1xx_conf.h ~/workspace/stm32-l1-blink/include/stm32l1xx_conf.h

rm ~/workspace/stm32-l1-blink/system/include/cmsis/stm32f10x.h
cp ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Libraries/CMSIS/Device/ST/STM32L1xx/Include/stm32l1xx.h ~/workspace/stm32-l1-blink/system/include/cmsis/stm32l1xx.h

rm ~/workspace/stm32-l1-blink/system/include/cmsis/system_stm32f10x.h
cp ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Libraries/CMSIS/Device/ST/STM32L1xx/Include/system_stm32l1xx.h ~/workspace/stm32-l1-blink/system/include/cmsis/system_stm32l1xx.h

rm ~/workspace/stm32-l1-blink/system/src/cmsis/system_stm32f10x.c
cp ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Project/STM32L1xx_StdPeriph_Templates/system_stm32l1xx.c ~/workspace/stm32-l1-blink/system/src/cmsis/system_stm32l1xx.c

rm -rf ~/workspace/stm32-l1-blink/system/include/stm32f1-stdperiph/
cp -r ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Libraries/STM32L1xx_StdPeriph_Driver/inc/ ~/workspace/stm32-l1-blink/system/include/stm32l1-stdperiph/

rm -rf ~/workspace/stm32-l1-blink/system/src/stm32f1-stdperiph/
cp -r ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Libraries/STM32L1xx_StdPeriph_Driver/src/ ~/workspace/stm32-l1-blink/system/src/stm32l1-stdperiph/

cp -rf ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Libraries/CMSIS/Include/ ~/workspace/stm32-l1-blink/system/include/cmsis/

rm ~/workspace/stm32-l1-blink/system/include/cmsis/core_cm4.h
rm ~/workspace/stm32-l1-blink/system/src/cmsis/vectors_stm32f10x.c
cp ~/STM32L1xx_StdPeriph_Lib_V1.3.1/Libraries/CMSIS/Device/ST/STM32L1xx/Source/Templates/TrueSTUDIO/startup_stm32l1xx_md.s ~/workspace/stm32-l1-blink/system/include/cmsis/startup_stm32l1xx_md.S

After that go to Project > Properties > C/C++ Build > Settings and point to fresh peripheral library’s “Includes” for Cross ARM GNU Assembler, Cross ARM C Compiler and Cross ARM C++ Compiler: just change directory path from ../system/include/stm32f1-stdperiph to ../system/include/stm32l1-stdperiph

In the same window replace STM32F10X_MD preprocessor definition with STM32L1XX_MD. Do that in “Preprocessor” tabs of Cross ARM GNU Assembler, Cross ARM C Compiler and Cross ARM C++ Compiler.

We still can’t build the project because of slight differences between STM32 F1 and STM32 L1 peripherals’ libraries.

include/BlinkLed.h

Edit include in the header of BlinkLed.h:

#include "stm32l1xx.h" // Was `stm32f10x.h`

Correct definitions for blue LED on 32L152CDISCOVERY:

#define BLINK_PORT_NUMBER               (1) /* Was 2 */
#define BLINK_PIN_NUMBER (6) /* Was 12 */
#define BLINK_ACTIVE_LOW (0) /* Was 1 */

#define BLINK_GPIOx(_N) ((GPIO_TypeDef *)(GPIOA_BASE + (GPIOB_BASE-GPIOA_BASE)*(_N)))
#define BLINK_PIN_MASK(_N) (1 << (_N))
#define BLINK_RCC_MASKx(_N) (RCC_AHBPeriph_GPIOA << (_N)) /* Used `RCC_APB2Periph_GPIOA` */

src/BlinkLed.c

Edit blink_led_init definition:

void blink_led_init()
{
// Enable GPIO Peripheral clock
RCC_AHBPriphClockCmd(BLINK_RCC_MASKx(BLINK_PORT_NUMBER), ENABLE); // Used `RCC_APB2PeriphClockCmd`

GPIO_InitTypeDef GPIO_InitStructure;

// Configure pin in output mode
GPIO_InitStructure.GPIO_Pin = BLINK_PIN_MASK(BLINK_PIN_NUMBER);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz; // Was `GPIO_Speed_50MHz`
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // Was `GPIO_Mode_Out_PP`
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // New
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // New
GPIO_Init(BLINK_GPIOx(BLINK_PORT_NUMBER), &GPIO_InitStructure);

// Start with led turned off
blink_led_off();
}

To understand what’s going on in this function read article about STM32 F0 GPIO. To understand STM32 L1 GPIO’s peculiarities I encourage you to look at STM32 L1 reference manual. You’re able to download it from official website or use (PDF, 13 MiB, v13).

system/include/cmsis/cmsis_device.h

#ifndef STM32L1_CMSIS_DEVICE_H_
#define STM32L1_CMSIS_DEVICE_H_

#include "stm32l1xx.h"

#endif // STM32L1_CMSIS_DEVICE_H_

After this modifications the project can be built without errors.

Debugging setup

Open Run > Debug Configurations and create new configuration by double-clicking “GDB OpenOCD Debugging”. Rename it as “OpenOCD debug”, choose current project at “Main” tab and configure work with the board in “Config options” field at “Debugger” tab: -f "/usr/share/openocd/scripts/board/stm32ldiscovery.cfg" -f "/usr/share/openocd/scripts/interface/stlink-v2.cfg"

Now, if you press Debug button your board will be flashed and interactive debug session will be started. You’re able to download my stm32-l1-blink project (ZIP, 609 KiB) if any.