STM32-P152 development with Eclipse on Linux

Some time ago I played with Olimex STM32-P152 board and wrote some posts about it:

I wanted to extend this setup by using an IDE, and I chose Eclipse because it seems to have the right plugins and resources. In particular I have been inspired by this post for developing on STM32F3Discovery on Mac OS X using Eclipse and this post for Windows. I suppose there are many alternatives that are probably simpler and lighter (Eclipse is quite large and complicated), but here’s what I did.

I am certain that the steps that I follow here can be modified to work with many other Cortex-M targets and many other JTAG adapters/emulators, so this guide can be useful to people who are developing on something different from the STM32-P152 and have a different cable than the C232HM-EDHSL-0.

Installation

I follow basically the same steps as the post mentioned above, so use that as a reference, but I have a few differences:

OpenOCD: I have a Debian testing (jessie) PC so I simply ran as root “ aptitude install openocd ” and it installed version 0.7.0-2 of the tool. GCC ARM Embedded toolchain: I extracted GCC ARM Embedded 4.8-2013-q4-major (linux version) in /opt Eclipse: I installed Keplero for C/C++ Developers (Linux 32-bit version) in a subfolder of my home directory (once I had problem installing plugins by installing it in system folders) Eclipse plugins: I only installed Eclipse CDT plugin and GCC ARM plugin, I did not need to install Zylin embedded CDT because recently they added OpenOCD debugging to GCC ARM plugin so I had everything I needed.

Create and build the program

Inside Eclipse, click File -> New -> C Project. Choose Project Type -> Executable -> Hello World ARM Cortex-M3 C Project -> Cross ARM GCC and give a name to the project. I gave it the name “ blink-152 ” because I already had a program that blinked a LED and the program runs on STM32-P152 and it has no connection whatsoever with a certain rock band.

In next page, remove Linker semi-hosting options.

Click Next until you reach the Toolchain option, and complete the path to the toolchain, in my case “ /opt/gcc-arm-none-eabi-4_8-2013q4/bin “.

A “Hello world” project will be created. It contains a main C file, the assembly code for startup and the linker scripts.

The STM32L152 has 128KiB of Flash and 16KiB of RAM, so I changed the “ ldscripts/mem.ld ” to reflect it:

MEMORY{ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K }

Then I filled the “ src/main.c ” file with the program that I already created in previous posts:

#include <stdint.h> #define REG32(addr) (*(volatile uint32_t *)(addr)) #define GPIOE_BASE 0x40021000 #define GPIOE_MODER REG32(GPIOE_BASE + 0x00) #define GPIOE_OTYPER REG32(GPIOE_BASE + 0x04) #define GPIOE_ODR REG32(GPIOE_BASE + 0x14) #define STAT4_PIN 11 #define STAT4_PIN_MASK (1UL<<STAT4_PIN) #define RCC_BASE 0x40023800 #define RCC_AHBENR REG32(RCC_BASE + 0x1C) #define RCC_AHBENR_GPIOEEN 0x10 #define RCC_CR REG32(RCC_BASE + 0x00) #define RCC_CR_HSION 0x1 #define RCC_CR_HSIRDY 0x2 #define RCC_CFGR REG32(RCC_BASE + 0x08) #define RCC_CFGR_SW 0x3 #define RCC_CFGR_SW_HSI 0x1 static void delay(int nops) { while(nops > 0) { asm ("nop"); nops--; } } static void set_gpioe_moder(int pin, int mode) { uint32_t moder; uint32_t moder_pin_pos; uint32_t moder_pin_mask; moder_pin_pos = pin*2; // 2 bits per pin moder_pin_mask = 0x3UL << moder_pin_pos; moder = GPIOE_MODER; // read from register moder &= ~moder_pin_mask; // clear moder pin field moder |= (mode << moder_pin_pos); // set moder pin field GPIOE_MODER = moder; // write to register } int main(void) { RCC_AHBENR |= RCC_AHBENR_GPIOEEN; // enable GPIOE clock GPIOE_OTYPER |= STAT4_PIN_MASK; // open-drain set_gpioe_moder(STAT4_PIN, 1); // general purpose output while(1) { GPIOE_ODR |= STAT4_PIN_MASK; // output pin high-z -> LED OFF delay(1000000); GPIOE_ODR &= ~STAT4_PIN_MASK; // output pin low -> LED ON delay(1000000); } } void SystemInit(void) { uint32_t cfgr; RCC_CR |= RCC_CR_HSION; // Enable High Speed Internal clock while(!(RCC_CR & RCC_CR_HSIRDY)) // Wait for HSI ready { delay(10); } cfgr = RCC_CFGR; cfgr &= ~RCC_CFGR_SW; cfgr |= RCC_CFGR_SW_HSI; // Select HSI as system clock RCC_CFGR = cfgr; while((RCC_CFGR & RCC_CFGR_SW) != RCC_CFGR_SW_HSI) // Wait for HSI as system clock { delay(10); } } void _exit(int code) { while(1); }

I can finally run Project -> Build All (Ctrl-B) and the executable “ Debug/blink-152.elf ” is created.

Write in flash

In order to write the program in flash like I did last time, I wanted a raw binary image of the executable. The project by default creates an Intel HEX image in “Debug/blink-152.hex”, so I changed that option by going in Project -> Properties, then choosing C/C++ Build -> Settings, then under Cross ARM GNU Create Flash Image -> General I changed the Output file format to Raw Binary. On next build (Ctrl-B) Eclipse will create “Debug/blink-152.bin”.

This image will be written in flash by OpenOCD, but we need the configuration files for it. I created a new folder “ blink-152/openocd ” in Eclipse to contain them, and then I created inside it the file “ c232hm-edhsl-0.cfg ” containing:

interface ft2232 ft2232_layout usbjtag ft2232_vid_pid 0x0403 0x6014 adapter_khz 1000

I downloaded “ stm32l.cfg ” from Olimex website into “ blink-152/openocd ” folder, and then I created a last file called “ flash_blink.cfg “:

init reset init halt flash write_image erase Debug/blink-152.bin 0x08000000 shutdown

Now I have all the files I need.

A crucial point is to connect the board, and I repeated exactly the same passages as in this post:

TCK: orange wire on pin 9 of the JTAG 20-pin connector

TMS: brown wire on pin 7

TDI: yellow wire on pin 5

TDO: green wire on pin 13

GND: black wire on any one of pins 4,6,8,10,12,14,16,18,20

Then I set the board jumpers to B0_1 and B1_1 positions to make STM32 boot from RAM.

Now I created a new external tool that takes care of flashing by calling OpenOCD:

Click Run -> External Tools -> External Tools Configuration… Click Program -> New Put in Name: Flash Program Put in Location: /usr/bin/openocd Put in Working Directory: ${workspace_loc:/blink-152} Put in Arguments: -f ${workspace_loc:/blink-152/openocd}/c232hm-edhsl-0.cfg -f ${workspace_loc:/blink-152/openocd}/stm32l.cfg -f ${workspace_loc:/blink-152/openocd}/flash_blink.cfg

Clicking Run will launch OpenOCD and in the Console below the log will display the job done, ending with:

... Info : STM32L flash size is 128kb, base address is 0x8000000 wrote 4096 bytes from file Debug/blink-152.bin in 0.526960s (7.591 KiB/s) shutdown command invoked

By re-configuring the jumpers in B0_0 and B1_0 positions and pressing the reset button the board should start to blink STAT4 LED.

Attach debugger

It’s also possible to attach Eclipse debugger to the board and see the program execution and the internal state of the core.

Click Run -> Debug configurations Add new GDB OpenOCD Debugging Go to Debugger tab Put in Executable: /usr/bin/openocd Put in Other options: -f ${workspace_loc:/blink-152/openocd}/c232hm-edhsl-0.cfg -f ${workspace_loc:/blink-152/openocd}/stm32l.cfg Tick option Connect to running target

Be aware that when you debug you have to make sure that the board is flashed with the same executable that you are debugging. Click Debug and the Eclipse Debug Perspective opens. The program is still running so you need to click the “suspend” button to pause the execution and examine the state.

The “Reset target and restart debugging” button can also be used to run the program from the beginning. Be aware that when you disconnect from the target it will remain in a paused state and you need to reset the board to make it run again.

Conclusions

In this post I showed how to use Eclipse to create a simple “blink” program, flash it on a STM32-P152 board and attach to it with a debugger. This has been possible with the help of Eclipse plugins, GCC ARM Embedded toolchain, OpenOCD, C232HM FTDI JTAG cable. This approach can be adapted to many Cortex-M targets and many JTAG adapters mainly by changing access to hardware registers, changing the linker script memory map, and OpenOCD configuration files.