Porting your Embox project to a new STM32 board

Anton Bondarev
12 min readNov 27, 2023

In this article, I want to tell you how Embox makes easy to port your system to a new platform. We’ll take, as a basis, the previous demo project with ModBus described in the article and tell you what it needs to run the project on a new NUCLEO-F2207ZG board.

In the article about ModBus it was already shown how software portability and ease of development are important for reducing “time-to-market”. Now let’s assume that we want to make a new version of our device on a new hardware platform that is cheaper, less power consuming, or simply available on the market.

Porting Embox to a new STM32 board

We want to release a new version of our device on the NUCLEO-F207ZG board, which is not supported in Embox. Moreover, Embox even does not support F2 series. We use STM32Cube to simplify support for various peripherals. Therefore, we are starting with adding STM32Cube support for F2 series. In fact, we can show the whole process of porting Embox to a new STM32 board. You can see It in the Pull Request on github.

The process porting to a new STM32 board can be described in the following steps:

  • Adding STM32Cube support
  • Adding Board specific part
  • Adding Basic template
  • Adding Peripherals description (“device tree”)
  • Adding drivers support (UART, GPIO, I2C, SPI, FLASH (In-chip), Ethernet)
  • Extending the template with drivers and others

STM32Cube support

Today most drivers for STM32 in Embox use STM32Cube therefore we had to add SMT32Cube support for the ‘F2’ series

You can see the code in the folder ‘third-party/bsp/stm32f2cube’. There are only a few files there:

./Mybuild — declares abstract module (interface) for different boards implementation on it

package third_party.bsp.stmf2cube

abstract module stm32f2_conf {
}

./cube/stm32cube hal.h is the header in oder to independent on STM32Cube series

#ifndef THIRD_PARTY_BSP_STMF2CUBE_CUBE_STM32CUBE_HAL_H_
#define THIRD_PARTY_BSP_STMF2CUBE_CUBE_STM32CUBE_HAL_H_

#include "stm32f2xx_hal.h"

#endif /* THIRD_PARTY_BSP_STMF2CUBE_CUBE_STM32CUBE_HAL_H_ */

./cube/Makefile — makefile for downloading external projects

PKG_NAME := stm32cubef2
PKG_VER := v1.9.4

PKG_SOURCES := https://www.github.com/STMicroelectronics/STM32CubeF2/archive/$(PKG_VER).zip

PKG_MD5 := 741de186164780de6e15314b79a72f9e

include $(EXTBLD_LIB)

./cube/Mybuild describes Embox modules

module ‘third_party.bsp.stmf2cube.cpp_flags’ is required for adding cpp flags including search paths/ It is used for modules which depends on our ‘Cube’

package third_party.bsp.stmf2cube

@BuildArtifactPath(cppflags="-DUSE_HAL_DRIVER -DSTM32F2_CUBE")
@BuildArtifactPath(cppflags="$(addprefix -I$(EXTERNAL_BUILD_DIR)/third_party/bsp/stmf2cube/cube/STM32CubeF2-1.9.4/, Drivers/STM32F2xx_HAL_Driver/Inc Drivers/CMSIS/Device/ST/STM32F2xx/Include Drivers/CMSIS/Include)")
module cube_cppflags {

}

Module ‘third_party.bsp.stmf2cube.cube’

@Build(stage=1,script="$(EXTERNAL_MAKE) download extract patch")
@BuildDepends(cube_cppflags)
@BuildDepends(third_party.bsp.stmf2cube.stm32f2_conf)
static module cube {
option number eth_rx_packet_count = 4
option number eth_tx_packet_count = 2

@IncludeExport(path="bsp")
source "stm32cube_hal.h"
@AddPrefix("^BUILD/extbld/^MOD_PATH/STM32CubeF2-1.9.4/Drivers/STM32F2xx_HAL_Driver/Src")
source
"stm32f2xx_hal.c",
"stm32f2xx_hal_cortex.c",
"stm32f2xx_hal_adc.c",


@NoRuntime depends third_party.bsp.stmf2cube.stm32f2_conf
@NoRuntime depends cube_cppflags
}

The ‘@Build’ annotation declares that the module is built on the ‘first stage’ of the building; there are also zero stage (for building basic embox modules) and second stage (after first stage building). Except this it declares that Makefile is used for external project building.

The ‘@BuildDepends’ annotation inserts additional compilation flags for example recently described ‘cube_cppflags’

The ‘@IncludePath’ annotation points that our series independent header must be placed into the accessible for every module ‘bsp’ folder

The ‘@AddPrefix’ annotation inserts the path as prefix to source files following the command ‘source’

Board specific part support

To support the new board, you need to configure some board-specific features, for example, set clock frequencies. The code responsible for this part can be found in the folder ‘platform/stm32/f2/nucleo_f207zg’

./stm32cube_compat.c auxiliary file contains the function HAL_GetTick() necessary for the correct operation of STM32Cube

uint32_t HAL_GetTick(void) {
return clock_sys_ticks();
}

./stm32f2xx_hal_conf.h configuration file for STM32Cube

This is a file with settings for the board from the original Cube, but it has been modified to allow you to control the number of buffers for the network card using the Mybuild options

/* Definition of the Ethernet driver buffers size and count */   
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#if defined(__EMBOX__)
#include <framework/mod/options.h>
#include <module/third_party/bsp/stmf2cube/cube.h>

#define ETH_RXBUFNB \
OPTION_MODULE_GET(third_party__bsp__stmf2cube__cube, NUMBER, eth_rx_packet_count)
#define ETH_TXBUFNB \
OPTION_MODULE_GET(third_party__bsp__stmf2cube__cube, NUMBER, eth_tx_packet_count)
#else

#define ETH_RXBUFNB 5U /* 5 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB 5U /* 5 Tx buffers of size ETH_TX_BUF_SIZE */
#endif /*__EMBOX__*/

./arch.c file implementing the arch interface in Embox

void arch_init(void) {
ipl_t ipl = ipl_save();

SystemInit();
HAL_Init();

SystemClock_Config();

ipl_restore(ipl);
}

void arch_idle(void) {

}

void arch_shutdown(arch_shutdown_mode_t mode) {
switch (mode) {
case ARCH_SHUTDOWN_MODE_HALT:
case ARCH_SHUTDOWN_MODE_REBOOT:
case ARCH_SHUTDOWN_MODE_ABORT:
default:
HAL_NVIC_SystemReset();
break;
}

/* NOTREACHED */
while(1) {

}
}

The system clock configuration (SystemClock_Config) was also taken from Cube

./Mybuild — the file describes the modules required for this board

package platform.stm32.f2.nucleo_f207zg

@Build(stage=1)
@BuildArtifactPath(cppflags="-DSTM32F207xx -DUSE_STM32F2XX_NUCLEO_144")
static module nucleo_f207zg_conf extends third_party.bsp.stmf2cube.stm32f2_conf {
@IncludeExport(path="")
source "stm32f2xx_hal_conf.h"
}

modules nucleo_f207zg_conf is inherited from the abstract module stm32f2_conf described above in “STM32Cube support” support and will be used during Cube building. It contains the flags with which STM32Cube is built and also the necessary header file stm32f2xx_hal_conf.h

@BuildDepends(nucleo_f207zg_conf)
@BuildDepends(third_party.bsp.stmf2cube.cube)
module arch extends embox.arch.arch {
source "arch.c"
source "stm32cube_compat.c"

@AddPrefix("^BUILD/extbld/third_party/bsp/stmf2cube/cube/STM32CubeF2-1.9.4/")
source "Projects/NUCLEO-F207ZG/Templates/Src/system_stm32f2xx.c"
}

The ‘arch’ module is required to build Embox. Its sources must implement three functions (arch_init(). arch_idle(), arch_shutdown()), which are located in the arch.c file. The file from STM32Cube system_stm32f2xx.c containing the SystemInit() function is also used. And the auxiliary file stm32cube_compat.c containing the HAL_GetTick() function necessary for STM32Cube working

@Build(stage=1)
@BuildDepends(nucleo_f207zg_conf)
@BuildDepends(third_party.bsp.stmf2cube.cube)
@BuildArtifactPath(cppflags="-I$(EXTERNAL_BUILD_DIR)/third_party/bsp/stmf2cube/cube/STM32CubeF2-1.9.4/Drivers/BSP/STM32F2xx_Nucleo_144")
static module bsp extends third_party.bsp.st_bsp_api {

@NoRuntime depends third_party.bsp.stmf2cube.cube
@NoRuntime depends nucleo_f207zg_conf
@NoRuntime depends arch
}

The target module describing the BSP to support a given board will be required for various drivers and contain all the necessary compilation flags.

Basic template

After we have added board support, we can build and run Embox, although till without peripherals, even without a UART, so, we can only check the operation using gdb.

To build Embox, you need at least three configuration files. You can see an example of a minimal configuration in the templates/arm/minimal folder. In our case, we will add settings for our board.

Let’s put our template in the board folder ‘platfrom/stm32/templates/f2/nucleo_f207zg’.

./lds.conf contains memory map for linker script

/* region (origin, length) */
ROM (0x08000000, 1024K)
RAM (0x20000000, 128K)

/* section (region[, lma_region]) */
text (ROM)
rodata (ROM)
data (RAM, ROM)
bss (RAM)

./build.conf contains compiler settings

TARGET = embox

PLATFORM = nucleo_f207zg

ARCH = arm

CROSS_COMPILE = arm-none-eabi-

CFLAGS += -O0 -g
CFLAGS += -mthumb -mlittle-endian
CFLAGS += -march=armv7-m -mtune=cortex-m3
CFLAGS += -ffreestanding

./mods.conf contains system description (requirements for the target system).

package genconfig

configuration conf {
include embox.arch.system(core_freq=120000000)
@Runlevel(0) include embox.arch.arm.cortexm3.bundle
include embox.arch.arm.armmlib.locore
include embox.arch.arm.libarch
include embox.arch.arm.vfork
include platform.stm32.f2.nucleo_f207zg.bsp

@Runlevel(1) include embox.driver.interrupt.cortexm_nvic
@Runlevel(1) include embox.driver.clock.cortexm_systick
include embox.kernel.time.jiffies(cs_name="cortexm_systick")


}

As you can see, we have set the system frequency, our new BSP for the board, as well as the timer and interrupt controller since they are platform independent.

Peripheral devices description (device tree)

Not long ago we added an analogue of device tree (Linux or ZephyrOS). This technology allows you to conveniently describe the configuration of devices available on a hardware platform. Unlike Linux, we need a static representation.

Description files are placed in the ‘board_config’ folder. Let’s add the file nucleo_f207zg.conf.h with a description of the peripherals

#include <gen_board_conf.h>
#include <stm32.h>

struct uart_conf uarts[] = {
[1] = {
.status = DISABLED,
.name = "USART1",
.dev = {
.irqs = {
VAL("", 37),
},
.pins = {
PIN("TX", PB, PIN_9, AF7),
PIN("RX", PB, PIN_10, AF7),
},
.clocks = {
VAL("TX", CLK_GPIOA),
VAL("RX", CLK_GPIOA),
VAL("UART", CLK_USART1),
}
},
.baudrate = 115200,
},

};

struct spi_conf spis[] = {
[1] = {
.status = DISABLED,
.name = "SPI1",
.dev = {
.pins = {
PIN("SCK", PA, PIN_5, AF5),
PIN("MISO", PA, PIN_6, AF5),
PIN("MOSI", PA, PIN_7, AF5),
PIN("CS", PD, PIN_14, NOAF),
},
.clocks = {
VAL("SCK", CLK_GPIOA),
VAL("MISO", CLK_GPIOA),
VAL("MOSI", CLK_GPIOA),
VAL("CS", CLK_GPIOD),
VAL("SPI", CLK_SPI1),
}
},
},

};

struct i2c_conf i2cs[] = {
[1] = {
.status = ENABLED,
.name = "I2C1",
.dev = {
.irqs = {
VAL("EVENT_IRQ", 31),
VAL("ERROR_IRQ", 32),
},
.pins = {
PIN("SCL", GPIO_PORT_B, PIN_6, AF4),
PIN("SDA", GPIO_PORT_B, PIN_9, AF4),
},
.clocks = {
VAL("SCL", CLK_GPIOB),
VAL("SDA", CLK_GPIOB),
VAL("I2C", CLK_I2C1),
}
},
},


};

EXPORT_CONFIG(UART(uarts), LED(leds), SPI(spis), I2C(i2cs))

Drivers support

Embox already had basic STM drivers, but it was necessary to add the F2 series support

UART

The driver is located in the ‘./src/drivers/serial/stm32cube_usart’ folder. It uses the device descriptions from board_config which we’ve added earlie. To add support, you must add a header file containing series-specific features and a description to the Mybuild file

@BuildDepends(third_party.bsp.st_bsp_api)
module stm_usart_f2 extends stm32_usart_ops {

@IncludeExport(path="drivers/serial", target_name="stm_usart.h")
source "stm32_usart_conf_f2.h"

source "stm_hal_msp.c"
source "stm_usart.c"

depends embox.driver.serial.core

depends third_party.bsp.st_bsp_api
}

It depends on our BSP and implements the ‘stm32_usart_ops’ interface,

‘./stm32_usart_conf_f2.h’

#include <bsp/stm32cube_hal.h>

#define STM32_USART_FLAGS(uart) uart->SR
#define STM32_USART_RXDATA(uart) uart->DR
#define STM32_USART_TXDATA(uart) uart->DR

#define STM32_USART_CLEAR_ORE(uart) \
do { \
} while (0)

GPIO

The driver is located in the ./src/drivers/gpio/stm32cube folder. The driver independents on the series (there are differences for the f1 series, which doesn’t have any alternative functions for GPIO)

I2C

The driver is located in the folder ‘./src/drivers/i2c/adapters/stm32cube_i2c’ and also did not require modifications for the new series.

SPI

The driver is located in the folder ‘./src/drivers/spi/stm32cube_spi’ and also did not require modifications for the new series.

FLASH (In-chip)

By this device I mean a block device, which we create using several blocks of in-chip flash. You can use this device to organize a simple file system for storing settings logs, and some other information known in advance. This is described in the article.

The driver is located in the folder ‘./src/drivers/flash/stm32cube_flash’.

The driver required the following modifications:

Add the header file describing the specifics of this series, for example, the size of the in-chip flash block.

#include <framework/mod/options.h>

#define STM32_FLASH_FLASH_SIZE OPTION_GET(NUMBER,flash_size)
#define STM32_ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000)
/* First 4 sectors of STM32F4-Discovery flash are 16Kb */
#define STM32_FLASH_SECTOR_SIZE (16 * 1024)
/* We use only first 4 16Kb sectors */
#define STM32_FLASH_SECTORS_COUNT 4

#define STM32_FLASH_WORD (4)

#ifndef __ASSEMBLER__
#include <stm32f2xx_hal.h>
#include <string.h>

static inline void stm32_fill_flash_erase_struct(
FLASH_EraseInitTypeDef *erase_struct,
unsigned int block) {
memset(erase_struct, 0, sizeof *erase_struct);
erase_struct->TypeErase = FLASH_TYPEERASE_SECTORS;
erase_struct->Sector = block;
erase_struct->NbSectors = 1;
}
#endif

And add the module description for this series

@BuildDepends(third_party.bsp.st_bsp_api)
module stm32f2cube {
option number log_level = 1
option number flash_size=0xc000

source "stm32_flash.c"
source "stm32_flash.lds.S"

@IncludeExport(path="drivers/block_dev/flash",target_name="stm32flash.h")
source "stm32f2flash.h"

depends third_party.bsp.st_bsp_api
depends core
}

Ethernet

The driver is located in the folder ‘./src/drivers/net/stm32cube’

To support the new board it was required:

First, set the HAL_MSP_Init function in the stm32f2cube_eth_msp.c file, which configures the correct contacts to work with PHY

void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIOs clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();

/* Ethernet pins configuration ************************************************/
/*
RMII_REF_CLK ----------------------> PA1
RMII_MDIO -------------------------> PA2
RMII_MDC --------------------------> PC1
RMII_MII_CRS_DV -------------------> PA7
RMII_MII_RXD0 ---------------------> PC4
RMII_MII_RXD1 ---------------------> PC5
RMII_MII_RXER ---------------------> PG2
RMII_MII_TX_EN --------------------> PG11
RMII_MII_TXD0 ---------------------> PG13
RMII_MII_TXD1 ---------------------> PB13
*/

/* Configure PA1, PA2 and PA7 */
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure PB13 */
GPIO_InitStructure.Pin = GPIO_PIN_13;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);

/* Configure PC1, PC4 and PC5 */
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);

/* Configure PG2, PG11, PG13 and PG14 */
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13;
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);



/* Enable ETHERNET clock */
__HAL_RCC_ETH_CLK_ENABLE();
}

Second, add a header file stm32f2cube_eth.h in which only the PHY address is defined.

#include <bsp/stm32cube_hal.h>

#define PHY_ADDRESS LAN8742A_PHY_ADDRESS

And third, add a module description to Mybuild

@BuildDepends(third_party.bsp.st_bsp_api)
module stm32f2cube_eth {
option number irq = 61

source "stm32cube_eth.c"
source "stm32f2cube_eth_msp.c"
@IncludeExport(path="drivers/net", target_name="stm32cube_eth.h")
source "stm32f2cube_eth.h"

option number log_level=1

}

Extending the template

After adding the drivers, expanding our basic template to check that the drivers work

First of all, we need a file with the settings of our peripherals, which additionally configures what is specified in the file describing the devices (board.conf.h)

#include <nucleo_f207zg.conf.h>

CONFIG {
uarts[1].status = ENABLED;
uarts[2].status = DISABLED;
uarts[3].status = ENABLED;

spis[1].status = ENABLED;
}

Let’s add our peripherals to the ‘mods.conf’ file

    @Runlevel(1) include embox.driver.serial.stm_usart_f2
@Runlevel(1) include embox.driver.serial.stm_diag(baud_rate=115200, usartx=3)
@Runlevel(1) include embox.driver.diag(impl="embox__driver__serial__stm_diag")
@Runlevel(1) include embox.driver.serial.stm_ttyS0(baud_rate=115200, usartx=3)

include embox.driver.gpio.stm32cube_gpio
@Runlevel(1) include embox.driver.input.button.stm32cube_button(pin_port=2, pin_num=13)

include embox.driver.spi.core
include embox.driver.spi.stm32cube_spi(log_level=0)
include embox.driver.spi.stm32cube_spi1(log_level=0)

include embox.driver.i2c.stm32cube_i2c
include embox.driver.i2c.stm32cube_i2c1

include embox.driver.flash.flash_cache_block
include embox.driver.flash.stm32f2cube
include embox.driver.flash.flash_fs

@Runlevel(2) include embox.driver.net.stm32f2cube_eth

Let’s add a command interpreter and several useful utilities, for example

    @Runlevel(3) include embox.init.system_start_service(log_level=3, tty_dev="ttyS0")

include embox.cmd.sh.tish(
builtin_commands = "exit logout service"
)
include embox.cmd.service(services_count=2)
include embox.cmd.sys.version
include embox.cmd.help

include embox.cmd.fs.dd
include embox.cmd.fs.cat
include embox.cmd.fs.ls
include embox.cmd.fs.rm
include embox.cmd.fs.mount
include embox.cmd.fs.umount
include embox.cmd.fs.stat
include embox.cmd.fs.echo
include embox.cmd.fs.touch
include embox.cmd.fs.mkdir

include embox.cmd.net.ifconfig
include embox.cmd.net.route
include embox.cmd.net.ping
include embox.cmd.net.bootpc
include embox.cmd.net.telnetd
include embox.cmd.net.netmanager

include embox.cmd.testing.ticker
include embox.cmd.testing.block_dev_test
include embox.cmd.testing.input.input_test
include embox.cmd.testing.input.button_test

include embox.cmd.hardware.pin
include embox.cmd.hardware.spi
include embox.cmd.hw.lsblk
include embox.cmd.hw.input

include embox.cmd.i2c_tools.i2cdetect
include embox.cmd.i2c_tools.i2cdump
include embox.cmd.i2c_tools.i2cget
include embox.cmd.i2c_tools.i2cset

include embox.cmd.net.httpd

Of course, you still need to expand the configuration with such things as kernel settings (multitasking, time, etc.) and other system things. But they will not dwell on this in this article.

I note that since we used system_start_service, we also need to add the file ‘system_start.inc’ to the template. For example, with the following content:

"mkdir -v /conf",
"mount -t DumbFS /dev/stm32flash0 /conf",
"conf_setup",
"netmanager",
"service httpd /http_admin",
"service telnetd",
"tish",

And since we use netmanager to configure the network, we need to add the ‘network’ file with the necessary settings to the root file system. Let’s just create a ‘rootfs’ folder in our template and put our file there (‘ rootfs/network’ )

iface eth0 inet static
address 192.168.2.128
netmask 255.255.255.0
gateway 192.168.2.1
hwaddress aa:bb:cc:dd:ee:02

#iface eth0 inet dhcp

Checking the demo template

After these steps, let’s build our template (“make confload-platform/stm32/f2/nucleo_f207zg; make”), flash the image to the board as described on the wiki page and make sure that everything works.

/dev/ttyACM0 console

As you can see, by default, telnetd and httpd start

Enter with telnet

Enter with a browser

Everything works, and the porting process took me less than two days. Yes, some of our drivers still require improvement, and we are going to do this in the future :)

Starting the project on the new board

Let me remind you that our project is external and is located at github ( https://github.com/embox/embox_project_modbus_iocontrol )

After adding board support, let’s try to run the demo project on the new board, specifying that we have two LEDs that we want to control using a line in ‘mods.conf’.

include iocontrol.modbus.lib.libleddrv(leds_quantity=2)

I just show the diff, from which it is clear that the changes I made concern only some hardware details of the platforms

diff stm32f4_discovery_demo/mods.conf nucleo_f207zg_demo/mods.conf
4c4
< include embox.arch.system(core_freq=144000000)
---
> include embox.arch.system(core_freq=120000000)
6c6
< include platform.stm32.f4.stm32f4_discovery.bsp
---
> include platform.stm32.f2.nucleo_f207zg.bsp
13,14c13,14
< @Runlevel(0) include embox.arch.arm.fpu.cortex_m4_fp
< @Runlevel(0) include embox.arch.arm.fpu.fpv5(log_level=3)
---
> //@Runlevel(0) include embox.arch.arm.fpu.cortex_m4_fp
> //@Runlevel(0) include embox.arch.arm.fpu.fpv5(log_level=3)
20,21c20,21
< @Runlevel(1) include embox.driver.serial.stm_usart_f4
< @Runlevel(1) include embox.driver.serial.stm_diag(baud_rate=115200, usartx=6)
---
> @Runlevel(1) include embox.driver.serial.stm_usart_f2
> @Runlevel(1) include embox.driver.serial.stm_diag(baud_rate=115200, usartx=3)
23,24c23
< @Runlevel(1) include embox.driver.serial.stm_ttyS1(baud_rate=57600, usartx=2)
< @Runlevel(1) include embox.driver.serial.stm_ttyS0(baud_rate=115200, usartx=6)
---
> @Runlevel(1) include embox.driver.serial.stm_ttyS0(baud_rate=115200, usartx=3)
27c26
< @Runlevel(2) include embox.driver.flash.stm32f4cube
---
> @Runlevel(2) include embox.driver.flash.stm32f2cube
32c31
< @Runlevel(2) include embox.driver.net.stm32f4cube_eth
---
> @Runlevel(2) include embox.driver.net.stm32f2cube_eth
133c132
< include iocontrol.modbus.lib.libleddrv(leds_quantity=4)
---
> include iocontrol.modbus.lib.libleddrv(leds_quantity=2)

Now let’s just build and run the project on the new board. Just in case, I provide all the instructions; they are short enough so that anyone can reproduce the situation in yourself.

Preparing the board:

  1. setting up our project as external in embox:
    make ext_conf EXT_PROJECT_PATH=<your projects path>
  2. configure the project for our board:
    make confload-ext_project/modbus/nucleo_f207zg_demo
  3. Configure the necessary network settings in the file ‘conf/rootfs/network’
  4. Building:
    make
  5. Burning the image with openocd as described on the wiki (https://github.com/embox/embox/wiki/NUCLEO-F207ZG )

Preparing the modbus client:

Enter into the folder ‘./modbus/host_cmds’ in the external project and build the client with ‘make’

Running and testing

Connect with an ethernet cable and run the board

Manage the LEDs with the modbus client:

To turn on RED (0) led:
./led-client -a 192.168.2.128 set 0

To turn off RED (0) led:
./led-client -a 192.168.2.128 clr 0

where 192.168.2.128 is my board IP address

You can also control BLUE (1) led with the modbus client.

Open a browser with our IP address (192.168.2.128

And by pressing the corresponding button, we turn on or off the desired LED. The state can be saved, it will be restored upon reboot

You can se how it works in this video:

Conclusion

As shown in the article “Developing SIP Phone with GUI on STM32 MCU” it is very convenient to develop and debug application tasks using Embox. And, as can you see from this article, adding a new platform and transferring an existing project to is not difficult. These facts allow you to make the life cycle of a device under Embox high quality significantly simplify support and maintenance of the device, and of course, minimize time-to-market.Embox high quality and allows you to significantly simplify support and maintenance of the device, and of course minimizes time-to-market.

--

--