Port of FreeModbus to STM32F103

MODBUS was briefly considered for a smart sensor protocol to use with the Data Acquisition project, but has subsequently been abandoned in favour of CANopen. FreeMODBUS was ported to the STM32F103 as an exercise and was tested successfully. It is possible to incorporate FreeRTOS but this hasn't been done. The firmware library used is libopencm3 which, when mature, should allow porting to a number of Cortex M3 or M4 microcontrollers.

The code may be found on GitHub.

The following files are present in the package:

  1. The main file modbus.c contains callback functions to react to requests for Input Register (eMBRegInputCB), Holding Register (eMBRegHoldingCB), Coil Register (eMBRegCoilsCB) and Input Discrete Register (eMBRegDiscreteCB). These form the MODBUS command set and define the data formats. The main program is here and a call to a hardware configuration function is made at the start.

  2. The hardware configuration file stm32.c contains initialization code.

  3. A makefile is provided for use with GNU make, and calls on the gcc ARM bare metal port arm-none-eabi-gcc. This contains references to library locations specific to the installation. These will need to be changed to suit users' implementations. The LDSCRIPT variable refers to a linker script that must be included to define the memory mappings. These scripts are provided in the libopencm3 lib directories for each of the subfamilies of devices. An appropriate one must be selected for the device being used. Examples are given in the package here which define the memory sizes for the STM32F103RBT6 and STM32F103RET6 devices, and include the generic linker script from the library.

  4. The file portother.c has two essential functions vMBPortEnterCritical() and vMBPortExitCritical() needed by FreeMODBUS to ensure that certain code blocks are not interrupted. These require the functions getprimask() and setprimask(), which are defined here although they should appear in libopencm3 eventually. These functions read and enable/disable the global interrupt enable control.

  5. portserial.c has functions that manage the serial link. This includes setup, initialization, get, put and an ISR. In the STM32 series, USART interrupts are mapped to a single interrupt, so a single ISR must determine what caused the interrupt. The Rx and Tx interrupts here are checked and the pxMBFrameCBByteReceived() and pxMBFrameCBTransmitterEmpty() callback functions respectively are invoked.

  6. porttimer.c has code for timer initialization, enable, disable and a single ISR. The STM32 families provide a large range of timers with a rich functionality. Here a basic timer TIM2 is set to interrupt when the counter reaches a preset value. This is used to time the gap between message bits. In MODBUS a gap of more than 3.5 bit periods signals the end of a message. As such the function vMBPortTimersEnable() must not only enable the timer, but also reset its value to the initial count (in this case zero as an up counter is used). This was a point I found unclear in the FreeMODBUS instructions.

  7. portevent.c is taken unchanged from the bare port. This implements the event queue and would need attention if an RTOS were to be used.

FreeMODBUS API documentation is found here. In this page, under Related Pages, a description of the requirements for porting to another archiecture is given, including the incorporation of an RTOS. Many of the examples provided with FreeMODBUS contain ports for FreeRTOS and include ARM Cortex M3 devices. These generally use the proprietary peripheral libraries provided by the manufacturer. There is among the examples a "bare port" that provides a framework for a new port.

First created 14 October 2012
Last Modified 29 June 2015
Ken Sarkies 2012