Introduction
The System Workbench for STM32 (SW4STM32) aka. OpenSTM32 aka. AC6 Tools is a set of plugins for the popular Eclipse IDE. There are two ways to install OpenSTM32. The first is to add the plugins to an existing installation of Eclipse, the other is to download a flavor of the Eclipse IDE from the ST homepage which has all the plugins preinstalled. This article explains what my experience was installing the preconfigured Eclipse on a MAC including debugging the program on a bluepill with openocd, the arm-none-eabi-gdb and a ST Link v2 programmer.
I used this article as a foundation for my article.
Prerequisits
A word of advice to everybody wanting to use OpenSTM32 on a mac. Make absolutly sure that you are using the latest software packages available. It will not work with outdated software! There is absolutely no backwards compatibility. If your versions are off, the tools just do not work together. They just fail without usefull error messages!
Use the latest version of
- GNU ARM embedded toolchain (ARM none EABI) from https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
- libusb (brew install libusb)
- openocd (brew install open-ocd)
Download and Install OpenSTM32
wget --no-check-certificate http://www.ac6-tools.com/downloads/SW4STM32/install_sw4stm32_macos_64bits-v2.9.run chmod +x install_sw4stm32_macos_64bits-v2.9.run ./install_sw4stm32_macos_64bits-v2.9.run
Error: Unrecognized option: -d64
If you get this error:
Unrecognized option: -d64 Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.
The solution is to run the installer with root priviledges.
sudo ./install_sw4stm32_macos_64bits-v2.9.run -m -f
Opening the OpenSTM32
open -a /Applications/Ac6/SystemWorkbench.app
Creating a Project
Create a C project as outlined here.
In Eclipse, select File > New > Project > C Project
As Project Type: Empty Project
As Toolchain: Ac6 STM32 MCU GCC
Keep Debug and Release builds checked.
In the wizard step “Target Configuration” switch to the MCU Tab, select
Series: STM32F1
Mcu: STM32F103C8Tx
In the Firmware Configuration Dialog, choose Hardware Abstraction Layer (Cube HAL). The Standard Peripheral Library (StdPeriph) is discontinued and I was not able to get the StdPeriph working.
Error: The Project Importer fails to install
If you get this error:
'tar' failed to extract /Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.ide_2.9.0.201904120827/resources/project_importer/macosx/ProjectImporter.app.tar.bz2 to /Applications/Ac6/SystemWorkbench.app/Contents/Applications
the solution is to manually untar the file:
cd /Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.ide_2.9.0.201904120827/resources/project_importer/macosx sudo bzip2 -d ProjectImporter.app.tar.bz2 sudo tar xopf ProjectImporter.app.tar sudo cp -R ProjectImporter.app /Applications/Ac6/SystemWorkbench.app/Contents/Applications
Error: The compiler fails to install
Failed to extract '/Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.externaltools.arm-none.macos64_1.17.0.201812190825/tools/st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3-mac.tar.bz2' to '/Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.externaltools.arm-none.macos64_1.17.0.201812190825/tools/compiler' (tar returned '1') java.lang.Throwable
The solution is to install the compiler manually:
cd /Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.externaltools.arm-none.macos64_1.17.0.201812190825/tools sudo bzip2 -d st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3-mac.tar.bz2 sudo tar xopf st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3-mac.tar sudo ln -s ./st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3-mac ./compiler
Write a small C Program
In order to test debugging you need a small application which is large enough to place some breakpoints in for testing. My example does not make any sense at all so do not question the application too much.
int main(void) { int i = 0; while (1) { i++; if (i == 100) { i = 0; } } return 0; }
The application should now compile in Eclipse without errors.
There are two error messages that are apparently caused by the Eclipse code scanner as explained here.
Program “arm-none-eabi-g++” not found in PATH testf7 Project Properties, C++ Preprocessor Include.../Providers, Ac6 SW4 STM32 MCU Built-in Compiler Settings options C/C++ Scanner Discovery Problem Program “arm-none-eabi-gcc” not found in PATH testf7 Project Properties, C++ Preprocessor Include.../Providers, Ac6 SW4 STM32 MCU Built-in Compiler Settings options C/C++ Scanner Discovery Problem
If you get these two errors, you can just select and delete them as they are bogus messages more or less and they do not cause your build to fail.
Install gcc-arm-none-eabi on macos
download and unzip the latest version of gdb
sudo cp -R /Users/<username>/Downloads/gcc-arm-none-eabi-9-2019-q4-major /usr/local/gcc_arm
In eclipse in the debug configuration change the gdb command path
Debugger-Tab > GDB command >
Install OpenOCD
brew install open-ocd
OpenOCD Configuration Script
OpenOCD is used in the OpenSTM32 build sequence to establish a connection to the bluepill. gdb will then be used to debug the application over the connection that openocd has established.
To configure how openocd establishes the connection, you have to write a configuration script. In Eclipse, debugging or running an application is done using so called run configurations.
You will create a debug run configuration and specify the path to openocd and the configuration script in the run configuration.
According to this post, there is a bug in OpenSTM32 were the openocd configuration script is not allowed to be located within the Eclipse project but in some other folder. Because of this bug, create the configuration script in some folder but not in the project folder.
I keep my configuration scripts in the folder:
/Users/<username>/Documents/board_config_files/bluepill_debug.cfg
Here is the script that works for me:
source [find interface/stlink-v2.cfg] set WORKAREASIZE 0x5000 transport select "hla_swd" set CHIPNAME STM32F103C8Tx # added set BOARDNAME genericBoard # added # CHIPNAMES state set CHIPNAME_CPU0_ACTIVATED 1 # Enable debug when in low power modes set ENABLE_LOW_POWER 1 # Stop Watchdog counters when halt set STOP_WATCHDOG 1 # STlink Debug clock frequency #set CLOCK_FREQ 4000 #set CLOCK_FREQ 1000 set CLOCK_FREQ 950 # We do not connect RESET line to stlink, that's why reset is disabled. #reset_config none reset_config none separate source [find target/stm32f1x.cfg]
Create a Run Configuration for Debugging
Open the pull down menu on the Debug button (Button with a green bug on it) in the toolbar. Select “Debug Configurations…”. A dialog opens. Select Ac6 STM32 Debugging and then click the Document button with the small golder plus symbol on it to create a new Debug Run Configuration of the type Ac6 STM32 Debugging.
Here are the settings to make on the Debugger-Tab:
Start Debugging
A breakpoint causes the debugger to pause the microcontroller as soon as it executes the code the breakpoint was set on. You can set breakpoints everywhere which is a bit misleading as for example you can place a breakpoint on an empty line. Obviously there is no code generated for empty lines and the debugger cannot stop on an empty line. It will only stop on lines that actually translate to code that can be executed by the microcontroller. Eclipse will move breakpoints around before starting the application. If a breakpoint is not on a sensical location, Eclipse will move it to the next sensical location.
To set a breakpoint, double click left of a line number. A small blue dot appears. To get rid of a breakpoint, double click the blue dot and it disapears.
In this example, there is a breakpoint on line 25 of our example application:
Whenever i has been incremented to the value 100, the breakpoint will be hit.
Now that you have an application to debug and a breakpoint that makes sense, you can start the debugging session. To start the session, Select your Run Configuration from the Debugging drop down on the toolbar.
Eclipse will compile your application with debug symbols. It will connect to the board using openocd. It will upload the code via the openocd connection and it will start the gnu debugger gdb and connect it to the openocd server which allows gdb to debug the application on the hardware. Eclipse will switch to the debug perspective and it will break on the breakpoint.
The output during application start should be something similar to this:
Open On-Chip Debugger 0.10.0 Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html none separate 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 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 v29 API v2 SWIM v7 VID 0x0483 PID 0x3748 Info : using stlink api v2 Info : Target voltage: 3.132308 Info : STM32F103C8Tx.cpu: hardware has 6 breakpoints, 4 watchpoints
In the debugger you can look at variable values and you can single step through the code. If there are errors and you cannot figure out what the issue is by solely thinking about the issue, you can use a debugger to see what decision your code makes and you can figure out what decision making is happening and where the incorrect decisions are made. You can then fix the issues.
Do not forget to write unit tests for your code! Do not get into bad code-and-fix habits! Maybe, if the problem lends itself to it, give test-driven development a shot.
Error: error in final launch sequence
If you get the “error in final launch sequence” – error, make sure you are using the latest gcc-arm-none-eabi. If the versions of the tools do not match, errors such as this one arise.
Error: dyld: Library not loaded: requires version 3.0.0 or later, but
If you get this error message:
dyld: Library not loaded: /usr/local/opt/libusb/lib/libusb-1.0.0.dylib Referenced from: /usr/local/opt/libftdi/lib/libftdi1.2.dylib Reason: Incompatible library version: libftdi1.2.dylib requires version 3.0.0 or later, but libusb-1.0.0.dylib provides version 2.0.0
then your libusb versions are out-dated.
For me the libusb files in
/Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/Drivers/FirmwareUpgrade/native/mac_x64/libusb-1.0.0.dylib /Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/bin/libusb-1.0.0.dylib /Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.externaltools.openocd.macos64_1.23.0.201904120827/tools/openocd/lib/libusb-1.0.dylib /Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.externaltools.openocd.macos64_1.23.0.201904120827/tools/openocd/lib/libusb-1.0.0.dylib
are all outdated.
You can check this using the otool command:
otool -L /usr/local/opt/libusb/lib/libusb-1.0.0.dylib /usr/local/opt/libusb/lib/libusb-1.0.0.dylib: /usr/local/opt/libusb/lib/libusb-1.0.0.dylib (compatibility version 3.0.0, current version 3.0.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1575.17.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
For a correct libusb as outlined above, the output says that the libusb library has a compatibility version of 3.0.0 and a current version of 3.0.0. If your libusb versions deviate, install libusb using brew (brew install libusb) then check where the brew files are (brew list libusb) and then replace the outdated libs with the current libs from brew.
Install a new version of libusb using brew (brew install libusb) then create backups of the four outdated files and copy the new libusb files over
cd /Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/Drivers/FirmwareUpgrade/native/mac_x64 sudo mv libusb-1.0.0.dylib libusb-1.0.0.dylib.backup sudo cp /usr/local/lib/libusb-1.0.0.dylib . cd /Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app/Contents/MacOs/bin sudo mv libusb-1.0.0.dylib libusb-1.0.0.dylib.backup sudo cp /usr/local/lib/libusb-1.0.0.dylib . cd /Applications/Ac6/SystemWorkbench.app/Contents/Eclipse/plugins/fr.ac6.mcu.externaltools.openocd.macos64_1.23.0.201904120827/tools/openocd/lib/libusb-1.0.dylib sudo mv libusb-1.0.0.dylib libusb-1.0.0.dylib.backup sudo mv libusb-1.0.dylib libusb-1.0.dylib.backup sudo cp /usr/local/lib/libusb-1.0.0.dylib . sudo cp /usr/local/lib/libusb-1.0.dylib .
Make an LED Blink
Making an LED Blink is described here.
For those coming from a high-level application programming background, a word of advice:
The fact that there is a function called HAL_Delay(500); or osDelay(1000); does not automatically mean that this function will work without setup code! In microcontroller programming, you have to first set up the hardware clock before you can make use of it via waiting functions such as the delay functions!
Same goes for LEDs. You have to first setup the LEDs before you can toggle them. The example given in this article shows how to perform the initial setup which is necessary to periodically make an LED blink. I will duplicate the code here for reference.
#include "stm32f1xx.h" void SystemClock_Config(void) { RCC_ClkInitTypeDef clkinitstruct = { 0 }; RCC_OscInitTypeDef oscinitstruct = { 0 }; oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; oscinitstruct.HSEState = RCC_HSE_ON; oscinitstruct.HSIState = RCC_HSI_OFF; oscinitstruct.PLL.PLLState = RCC_PLL_ON; oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&oscinitstruct) != HAL_OK) { while (1) ; } clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1; clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1; clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2) != HAL_OK) { while (1) ; } } // https://www.onetransistor.eu/2017/12/program-stm32-bluepill-hal-eclipse.html int main(void) { HAL_Init(); SystemClock_Config(); __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitTypeDef gpio; gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Speed = GPIO_SPEED_FREQ_MEDIUM; gpio.Pin = GPIO_PIN_13; gpio.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &gpio); while (1) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); HAL_Delay(500); } }
In order for this code to compile correctly, you have to add the FreeRTOS utility.
Output an Assembler Listing of the Binary
As outlined here, you can add a command to the post build step to call arm-none-eabi-objdump on your binary to disassemble it and output a listing file.
Open the preferences of your project > C / C++ Build > Settings > Tab: Build Steps > PostBuild Steps > Command.
Append to the command:
; arm-none-eabi-objdump -D "${BuildArtifactFileBaseName}.elf" > "${BuildArtifactFileBaseName}.lst"
Do not forget to prefix the semicolon! The semicolon will append a new command to the post build step.
The result is a .lst file in the debug folder that contains the assembly listing.