STM32 dev: Difference between revisions

From SGMK-SSAM-WIKI
Jump to navigation Jump to search
Line 506: Line 506:


* Great introduction: [http://www.triplespark.net/elec/pdev/arm/stm32.html Programming STM32 F2, F4 ARMs under Linux: A Tutorial from Scratch]
* Great introduction: [http://www.triplespark.net/elec/pdev/arm/stm32.html Programming STM32 F2, F4 ARMs under Linux: A Tutorial from Scratch]
* Alternative ST programmer tool: [https://github.com/texane/stlink stlink]


== Hardware ==
== Hardware ==

Revision as of 13:57, 29 January 2016

Overview

Notes on STM32 microcontrollers and on how to get them working in DIY projects.

/// this is a work in progress draft ///

Software Tools

All about software tools for STM32 dev. Development environments, compilers, debuggers, IDEs etc.

Prerequisites: ARM toolchain

Install the GCC arm-none-eabi toolchain for your OS. On Arch Linux this can be done with the package manager:

$ sudo pacman -S arm-none-eabi-gcc arm-none-eabi-gdb arm-none-eabi-binutils arm-none-eabi-newlib

Alternatively, it can be built from scratch, to have all tools and their sources of your development environment in place.

$ cp gcc-arm-none-eabi-5_2-2015q4-20151219-src.tar.bz2 ~/toolchain
$ cd ~/toolchain
$ tar -xjf gcc-arm-none-eabi-5_2-2015q4-20151219-src.tar.bz2
$ cd ./gcc-arm-none-eabi-5_2-2015q4-20151219/src
$ find -name '*.tar.*' | xargs -I% tar -xf %
$ cd ..
$ ./build-prerequisites.sh --skip_steps=mingw32
$ ./build-toolchain.sh --skip_steps=mingw32,manual

Note that those skip_steps options were required in my case.


STM32CubeMX on Linux

STM32CubeMX is a code generator for STM32 micros that can come in handy when you start a new project. It generates all the necessary init and HAL code, library and custom pin mux code for your specific MCU.

Unfortunately, it comes as a Windows EXE and ST doesn't mention that it actually is a Java application. Luckily it can be installed on Linux by hand (thanks to 5V Joe's great note there):

  • Download STM32CubeMX.
  • Install the application (tested in January 2016):
$ unzip SetupSTM32CubeMX-4.12.0.exe -d stm32cube
$ cd stm32cube
$ java -cp . com.izforge.izpack.installer.bootstrap.Installer
  • Run:
$ cd <install_dir>
$ java -cp . java -cp . com.st.microxplorer.maingui.STM32CubeMX

Convert STM32CubeMX generated project to GCC/Makefile

For whatever reason, STM32CubeMX does not export plain GCC/Makefiles along with the initialization code. But instead, it supports an unpopular IDE called SW4STM32, which is also based on free GNU tools. So after installing STM32CubeMX, these are the steps to get the GCC/Makefile project running:

  • Get this nice Python script by Baoshi to generate the Makefile for an exported SW4STM32 project:
$ git clone https://github.com/baoshi/CubeMX2Makefile
$ cd CubeMX2Makefile
$ python2 CubeMX2Makefile.py <your_sw4stm32_prject_dir>
$ cd <your_sw4stm32_prject_dir>
  • Fix a tiny bug in the generated Makefile (tested in January 2016). More can be read here.
$ grep __weak Makefile 
C_DEFS = -D__weak="__attribute__\(\(weak\)\)" -D__packed="__attribute__\(\(__packed__\)\)" -DUSE_HAL_DRIVER -DSTM32F072xB
$ sed -i 's/\\(\\(weak\\)\\)/((weak))/g' Makefile 
$ sed -i 's/\\(\\(packed\\)\\)/((packed))/g' Makefile 
$ grep __weak Makefile 
C_DEFS = -D__weak="__attribute__((weak))" -D__packed="__attribute__\(\(__packed__\)\)" -DUSE_HAL_DRIVER -DSTM32F072xB
  • Then build the binary:
$ make
(...)
arm-none-eabi-size build/STM32F072RBT6.elf
   text	   data	    bss	    dec	    hex	filename
   4568	     12	   1572	   6152	   1808	build/STM32F072RBT6.elf
arm-none-eabi-objcopy -O ihex build/STM32F072RBT6.elf build/STM32F072RBT6.hex
arm-none-eabi-objcopy -O binary -S build/STM32F072RBT6.elf build/STM32F072RBT6.bin	

Flash

Install OpenOCD and STLINK. On Arch Linux:

sudo pacman -S stlink openocd

Now OpenOCD and (arm-none-eabi-)gdb can be used to program and debug the MCU. All discovery boards also come with an ST-LINK/V2 programmer right built in speaking over USB to the host and over JTAG/SWD to the target (note: only two pins are actually required for SWD debugging/flashing (SWDIO/SWCLK), but that for later (see also #Hardware)). STM32 Discovery Boards should show up in the lsusb list like that:

$ lsusb
(...)
Bus 003 Device 006: ID 0483:3748 STMicroelectronics ST-LINK/V2
(...)

OpenOCD can now act as a "middleman" between the ST-LINK programmer and the user. As a server on the host, to which you can connect with telnet and GDB.

To configure OpenOCD, put a configuration file called opencd.cfg into the project folder and start OpenOCD. While working on the project, let it run there in the foreground to see all the logs...

For the STM32 F072 Discovery board this should work, for example:

$ cd <project_directory>
$ echo "source [find board/stm32f0discovery.cfg]" > openocd.cfg
$ openocd
Open On-Chip Debugger 0.9.0 (2015-05-19-13:50)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v0 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 2.896454
Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints

(Don't worry about those warnings about the wrong clock speed for now...)


In order to program the flash, connect to OpenOCD via telnet in another terminal:

$ telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Open On-Chip Debugger
> 
> reset halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0xc1000000 pc: 0x080014d0 msp: 0x20004000
> flash probe 0
device id = 0x20016448
flash size = 128kbytes
flash 'stm32f1x' found at 0x08000000
> flash write_image erase build/STM32F072RBT6.elf
auto erase enabled
target state: halted
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20004000
wrote 6144 bytes from file build/STM32F072RBT6.elf in 0.503961s (11.906 KiB/s)
> reset run
> exit
Connection closed by foreign host.
$

This should write the binary to the flash memory and start the program. Of course, all those steps can be automated further and integrated into an IDE, but that's for later...

( To program the STM32F0Discovery board for example, this can be used to just flash the chip:

$ openocd -f board/stm32f0discovery.cfg -c "program build/STM32F072RBT6.elf verify reset exit" 

)


The exported main.c from STM32CubeMX was only slightly modified to let the user LEDs flash and react to the user pushbutton:

******************************************************************************
* main.c *
******************************************************************************

#include "stm32f0xx_hal.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();

  while (1)
  {
    uint32_t delay;
    if( HAL_GPIO_ReadPin( GPIOA, GPIO_PIN_0 ) == GPIO_PIN_SET )
      delay = 50;
    else
      delay = 250;

    HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_9 );
    HAL_Delay( delay );
    HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_8 );
    HAL_Delay( delay );
    HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_7 );
    HAL_Delay( delay );
    HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_6 );
    HAL_Delay( delay );

  }
}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);

  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOA_CLK_ENABLE();
  __GPIOC_CLK_ENABLE();

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PC6 PC7 PC8 PC9 */
  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

}

( Note that pins -- among various other things -- can be customized in the CubeMX editor. Reexporting code to an existing project is straight forward, and can be done easily while the old Makefile keeps valid for minor changes... - However, STM32CubeMX looks still quite unfinished to me. It's a nice concept, but where are all the ST libraries, for example for the touch functionality? It still needs to be downloaded separately... and it comes in a bloody EXE file as well! *arghs*

Unfortunately, things seem to be a bit confusing. If you're using a STM32F0, then probably need to take a look into the STM32CubeF0 software bundle, which contains a more up-to-date TouchSensing Library... Hm.

Also, note that most of the provided code by ST is only documented in the source files themselves... And there are at least two vastly differing versions of the basic functions out there, what makes copy/pasting/sharing a bit difficult. I even don't know if they continue working on this code base, or if they switch over to mbed. That seems to be the focus of those newer Nucleo evaluation boards. )


Debugging: GDB

GDB can be used to debug the code right on the hardware. While OpenOCD is running, you can connect to the target like this and step through the program:

$ arm-none-eabi-gdb -tui build/STM32F072RBT6.elf
(...)
Reading symbols from build/STM32F072RBT6.elf...done.

(gdb) target remote :3333
Remote debugging using :3333
Python Exception <type 'exceptions.NameError'> Installation error: gdb.execute_u
nwinders function is missing:
HAL_GetTick () at Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal.c:298

(gdb) c
Continuing.

Program received signal SIGINT, Interrupt.
0x080002f6 in HAL_Delay (Python Exception <type 'exceptions.NameError'> Installa
tion error: gdb.execute_unwinders function is missing:
Delay=250)
    at Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal.c:317

(gdb) break main.c:91
Breakpoint 1 at 0x8001392: file Src/main.c, line 91.

(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.
Python Exception <type 'exceptions.NameError'> Installation error: gdb.execute_u
nwinders function is missing:

Breakpoint 1, main () at Src/main.c:91

(...)
(gdb) detach
(qdb) quit
$

(Note: the -tui option is really great to inspect the code... see GDB Text User Interface)


IDE: Eclipse

To use Eclipse as an IDE for the STM32s, just install Eclipse and a the GNU ARM Eclipse Plugin.

  • Eclipse IDE for C/C++ (CDT). This can be installed manually or with your package manager.
  • Eclipse Plugin: GNU ARM Eclipse

This can be done in the Eclipse Marketplace (under Help > Eclipse Marketplace (use the default options)).

  • Create a new Eclipse project with the GNU ARM Eclipse (Choose STM32Fxxx C/C++ Project in the Wizard)

With some minor adjustments in the settings (OpenOCD), the basic Blinky example that comes with the plugin should work out of the box, with a STLink v2 programmer. Code completion etc. works fine too.

(/todo: show every step)


But there's quite annoying problem with this workflow!:

http://www.carminenoviello.com/en/2015/06/04/stm32-applications-eclipse-gcc-stcube/:

Unfortunately, the plug-in author has updated just the template for STM32-F4 family to the more recently STM32Cube-F4 HAL framework from ST (which still supports only commercial IDE.....), leaving the other templates still based on the old Standard Peripheral Library, which is no longer supported by ST and STM32CubeMX tool used in my tutorial. This causes my instructions to be wrong for processor families different from STM32-F4.


So, several manual setup steps will be required to get started with your own STM32 project. To goal is to configure the project in STM32CubeMX, and use up-to-date HAL code, and not the deprecated Standard Peripheral Library.

The GNU ARM Eclipse plugin is great, but doesn't create projects with up-to-date code. So we need to modify the manually created GNU ARM Eclipse project. - I used a custom STM32F072C8 board, and all steps below assum this hardware. The steps would be slightly different for other hardware.

This tutorial was helping here: http://www.carminenoviello.com/en/2015/06/04/stm32-applications-eclipse-gcc-stcube/


  • First create a new 'C Project' in your Eclipse workspace.
    • In Wizard slide C Project: Important: Choose Executable > Hello World ARM Cortex-M C/C++ Project and give it a name (e.g. testSTM32_00). This will generate a generic ARM project instead of an STM32Fxxx one. - Then hit Next.
    • In Wizard slide Target processor settings: Configure the target processor: For the STM32F072C8: Change the defaults to Flash size (kB): 64, RAM size (kB): 16, Use system calls: Freestanding (no POSIX system calls), Trace output: None (no trace output). - Then hit Next.
    • In Wizard slide Folders: Change Vendor CMSIS name to stm32f0xx. - Then hit next.
    • In Wizard slide Select Configurations: Leave as is. - Then hit Next.
    • In Wizard slide Cross GNU ARM Toolchain: Select GNU Tools for ARM Embedded Processors (arm-none-eabi-gcc) and either choose the global, system wide toolchain (probably in /usr/bin) or enter the path to your custom one. - Then hit Finish.

This will create a generic ARM project, which should build without errors (hit Ctrl+B).

Next, we need to add the vendor specific HAL code by ST generated with STM32CubeMX and/or downloaded in a more specific firmware package (STM32CubeF0, STM32CubeF4 etc.).

Side note: No idea why ST did not update STM32CubeMX to come with all required sources, examples and libraries for all families of their Cortex-M ARMs. (2016-01) - The STM32CubeFx packages seem to tailored to the specific family of chips, so I guess this is the right place to start. - To configure specific aspects (like pin configuration, interrupts, clocks), the more general STM32CubeMX GUI Tool can be used. - They seem to reduce cost that way...

... So, after configuring a generic Eclipse project, we're ready to modify it.

  • Configure and export an EWARM project in STM32CubeMX (with default settings).

As a starting point, here's a bash script, that modifies the previously created Eclipse project:

#!/usr/bin/env bash

set -e

#echo "Press CTRL+C to proceed."
#trap "pkill -f 'sleep 1h'" INT
#trap "set +x ; sleep 1h ; set -x" DEBUG

# MODIFY THIS!
ECLIPSE_PROJECT=/run/media/rel/prc/code/workspace_testSTM32_01/testSTM32_00
STM32CUBEF0=/home/rel/src/STM32Cube_FW_F0_V1.4.0
STM32CUBEMX=/home/rel/Desktop/test_stm32cubemx_ewarm

echo --------------------------------------------------------------------------------
echo Eclipse Project Initializer for STM32F072 Dev
echo --------------------------------------------------------------------------------

echo
echo The script is using the following paths:
echo
echo Eclipse Project:
echo $ECLIPSE_PROJECT
echo
echo STM32Cube:
echo $STM32CUBEF0
echo
echo STM32CubeMX:
echo $STM32CUBEMX

echo
echo -n "Do you want to proceed? [ENTER]"
read

echo
echo Deleting files from eclipse project:
rm -fv $ECLIPSE_PROJECT/src/main.c
rm -fv $ECLIPSE_PROJECT/src/Timer.c
rm -fv $ECLIPSE_PROJECT/include/Timer.h

rm -fv $ECLIPSE_PROJECT/system/include/cmsis/stm32f0xx.h
rm -fv $ECLIPSE_PROJECT/system/include/cmsis/system_stm32f0xx.h

rm -fv $ECLIPSE_PROJECT/system/src/cmsis/system_stm32f0xx.c
rm -fv $ECLIPSE_PROJECT/system/src/cmsis/vectors_stm32f0xx.c


echo
echo Copying: ST HAL:
cp -rfv $STM32CUBEF0/Drivers/STM32F0xx_HAL_Driver/Src/* \
$ECLIPSE_PROJECT/system/src/stm32f0xx

cp -rfv $STM32CUBEF0/Drivers/STM32F0xx_HAL_Driver/Inc/* \
$ECLIPSE_PROJECT/system/include/stm32f0xx

cp -rfv $STM32CUBEF0/Drivers/CMSIS/Device/ST/STM32F0xx/Include/* \
$ECLIPSE_PROJECT/system/include/cmsis

cp -fv $STM32CUBEF0/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates/gcc/startup_stm32f072xb.s \
$ECLIPSE_PROJECT/system/src/cmsis/startup_stm32f072xb.S

cp -fv $STM32CUBEF0/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates/system_stm32f0xx.c \
$ECLIPSE_PROJECT/system/src/cmsis


# echo Copying: example project from STM32CubeF0:
#cp $STM32CUBEF0/Projects/STM32F072B-Discovery/Examples/GPIO/GPIO_IOToggle/Inc/* \
#$ECLIPSE_PROJECT/include

#cp $STM32CUBEF0/Projects/STM32F072B-Discovery/Examples/GPIO/GPIO_IOToggle/Src/main.c \
#$ECLIPSE_PROJECT/src

#cp $STM32CUBEF0/Projects/STM32F072B-Discovery/Examples/GPIO/GPIO_IOToggle/Src/stm32f0xx_it.c \
#$ECLIPSE_PROJECT/src


echo
echo Copying: example project from STM32CubeMX:
cp $STM32CUBEMX/Src/* $ECLIPSE_PROJECT/src
cp $STM32CUBEMX/Inc/* $ECLIPSE_PROJECT/include

echo
echo Modifiying/fixing the memory map:
echo $ECLIPSE_PROJECT/ldscripts/mem.ld
sed -i 's/FLASH (rx) : ORIGIN = 0x00000000/FLASH (rx) : ORIGIN = 0x08000000/g' $ECLIPSE_PROJECT/ldscripts/mem.ld


echo
echo SUCCESS
echo

echo
echo Now, exclude the following file from the Eclipse project manually:
ls $ECLIPSE_PROJECT/system/src/stm32f0xx/stm32f0xx_hal_msp_template.c

echo
echo And add the following preprocessor constants to the C/C++ compiler settings in Eclipse:
echo USE_HAL_DRIVER
echo STM32F072xB

echo
echo "And add the following config options to the GDB OpenOCD Debugging settings (in Run Configurations):"
echo "-f interface/stlink-v2.cfg -f target/stm32f0x.cfg"

This script needs to be modified according to your needs! (Currently is working for the STM32F072C8, and contains fixed paths!)

Like described in the script above, some minor manual changes need to be made in Eclipse after running the script.

This should now be a good basis to start a new STM32 project.


/todo Show how to use semihosting

ARM Software Ecosystem

  • Compared to today's high level software tools for desktop, mobile, web, most of those ARM tools seem to be back in the early 2000s. - At some point, embedded dev might be much easier and high level too. - See LUA on NodeMCU, micro python and javascript/Espruino.
  • Compared to community driven creativity tools like Arduino: very inaccessible, protective, $$$ driven.

Is it really worth it to learn all the nitty-gritty details? Why can it not be much easier to work with these tiny machines?


mbed and Arduino Zero (Atmel SAM D21) might be worth more investigation.

Links

Hardware

/todo

  • Minimal STM32
  • JTAG
  • Serial

.....


Projects

/todo

  • bare metal hello blink
  • I2C peripherals
  • I2S peripherals
  • SPI peripherals
  • touch
  • usb

.....