FreeMODBUS

FreeMODBUS is a free implementation of the popular Modbus protocol specially targeted for embedded systems. Modbus is a popular network protocol in the industrial manufacturing environment. A Modbus communication stack requires two layers. The Modbus Application Protocol which defines the data model and functions and a Network layer. In its current version FreeMODBUS provides an implementation of the Modbus Application Protocol v1.1a and supports RTU/ASCII transmission modes defined in the Modbus over serial line specification 1.0. Since version 0.7 FreeModbus also supports Modbus TCP defined in Modbus Messaging on TCP/IP Implementation Guide v1.0a. It is licensed under the LGPL[1] which permits its usage in commercial environments. The following Modbus functions are currently supported:

  • Read Input Register (0x04)
  • Read Holding Registers (0x03)
  • Write Single Register (0x06)
  • Write Multiple Registers (0x10)
  • Read/Write Multiple Registers (0x17)
  • Read Coils (0x01)
  • Write Single Coil (0x05)
  • Write Multiple Coils (0x0F)
  • Read Discrete Inputs (0x02)
  • Report Slave ID (0x11)

The implementation is based upon the most recent standards and should be fully standard compliant. Receiving and transmitting of Modbus RTU/ASCII frames is implemented as a state machines which is driven by callbacks from the hardware abstraction layer. This makes porting to new platforms easy. If a frame is complete it is passed to the Modbus Application Layer where its content is inspected. Hooks are available in the Application Layer to add new Modbus functions.
If Modbus TCP is used the porting layer must send an event to the protocol stack if a new frame is ready for processing. The protocol stack then calls a function which returns the received Modbus TCP frame and processes it. If valid a response is created and the porting layer is supplied with the Modbus response. It should then send the response back to the client.

[1]:This excludes the demo applications which are licensed under the GPL.

This is a simple example showing how to use the Modbus protocol stack. It is nearly the same as the example simple2.c for the FreeRTOS/STR71x demo application with some parts removed for presentation purposes. In this example we map four 16bit input registers at the register address 1000. The first register counts the number of times the main polling loop was cycled. The second and third registers hold the current RTOS ticks counter and the fourth register holds a constant.

/* ------Defines ------*/

#define REG_INPUT_START 1000

#define REG_INPUT_NREGS 4

/* ------Static variables ------*/

static unsigned short usRegInputStart = REG_INPUT_START;

static unsigned short usRegInputBuf[REG_INPUT_NREGS];

...

static void

vModbusTask( void *pvParameters )

{

portTickType xLastWakeTime;

/* Select either ASCII or RTU Mode. */

( void )eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );

/* Enable the Modbus Protocol Stack. */

( void )eMBEnable( );

for( ;; )

{

/* Call the main polling loop of the Modbus protocol stack. */

( void )eMBPoll( );

/* Application specific actions. Count the number of poll cycles. */

usRegInputBuf[0]++;

/* Hold the current FreeRTOS ticks. */

xLastWakeTime = xTaskGetTickCount( );

usRegInputBuf[1] = ( unsigned portSHORT )( xLastWakeTime > 16UL );

usRegInputBuf[2] = ( unsigned portSHORT )( xLastWakeTime & 0xFFFFUL );

/* The constant value. */

usRegInputBuf[3] = 33;

}

}

Most of the work is done in the main polling loop. Internally it works by waiting for an event posted to a queue (See footnote [1]). Such a event is for example the reception of a Modbus frame. These events are posted to the event queue by the interrupt driven receiver and transmitter state machines. After a frame is received the FRAME_RECEIVED event is posted and one loop iteration is executed. Following the receive event an EXECUTION event is created internally. Because there is such a special event for the time after frame reception and before the response is sent the current register values can be updated. After execution the resulting frame is transmitted and a FRAME_SENT event is raised.
But where does the Modbus stack hold the actual register values? In this case the actual buffer is provided by the callback function eMBRegInputCB. Again the implementation of such a function is quite simple.

eMBErrorCode

eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )

{

eMBErrorCode eStatus = MB_ENOERR;

int iRegIndex;

if( ( usAddress >= REG_INPUT_START )

& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )

{

iRegIndex = ( int )( usAddress - usRegInputStart );

while( usNRegs > 0 )

{

*pucRegBuffer++ =

( unsigned char )( usRegInputBuf[iRegIndex] > 8 );

*pucRegBuffer++ =

( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );

iRegIndex++;

usNRegs--;

}

}

else

{

eStatus = MB_ENOREG;

}

return eStatus;

}

Using this code and a Modbus test utility we get the following output in a console window:

Z:\home\wolti\devel\privat\arm\freemodbus\tools>modpoll.exe -m rtu -a 10 -r 10

00 -c 4 -t 3 -b 38400 -d 8 -p even COM4

modpoll - FieldTalk(tm) Modbus(R) Polling Utility

Copyright (c) 2002-2004 FOCUS Software Engineering Pty Ltd

Getopt Library Copyright (C) 1987-1997 Free Software Foundation, Inc.

Protocol configuration: Modbus ASCII

Slave configuration: Address = 10, start reference = 1000, count = 4

Serial port configuration: COM4, 9600, 7, 1, even

Data type: 16-bit register, input register table

Protocol opened successfully.

Polling slave (Ctrl-C to stop) ...

[1000]: 467

[1001]: 3

[1002]: 18547

[1003]: 33

Polling slave (Ctrl-C to stop) ...

[1000]: 470

[1001]: 3

[1002]: 19544

[1003]: 33

Polling slave (Ctrl-C to stop) ...

[1]: Without an operating systems there are normally no queues available. In this case the application would look like our example and the queue receiving and sending functions would be implemented by simple global variables which are set if events are posted to the queue. The queue receive function would check the state of the variables and would return TRUE if a event was posted. The return value would then be checked by the main loop and if TRUE eMBPool would be called. Otherwise other functions can be executed.

The hardware requirements are minimal - Any reasonable microcontroller with a serial interface, at least some RAM to hold the modbus frames should suffice.

  • A UART which support and interrupts and has at least an receiver buffer full and transmit buffer empty interrupt.
  • A timer capable of creating the t3.5 character timeout timer for Modbus RTU.

For the software part a simple event queue is necessary. The STR71X/FreeRTOS port uses FreeRTOS queues for this purpose to reduce the time spent in the Modbus task. Smaller microcontrollers will most likely come without an operating system. In that case a simple implementation with a global variable is possible (The Atmel AVR port uses such an implementation).

The actual memory requirements depend on the used modules. The first table shows the required memory with all supported functions compiled in. Values for the ARM where obtained using the GNUARM compiler collection 3.4.4 with -O1 in ARM mode. The AVR values where obtained using the WinAVR compiler collection 3.4.5 with -Os.

Module / ARM Code / ARM RAM (static) / AVR Code / AVR RAM (static)
Modbus RTU (Required) / 1132Byte / 272Byte / 1456Byte / 266Byte
Modbus ASCII (Optional) / 1612Byte / 28Byte / 1222Byte / 16Byte
Modbus Functions [1] / 1180Byte / 34Byte / 1602Byte / 34Byte
Modbus Core (Required) / 924Byte / 180Byte / 608Byte / 75Byte
Porting Layer (Required [2]) / 1756Byte / 16Byte / 704Byte / 7Byte
Totals / 7304Byte / 530Byte / 5592Byte / 398Byte

[1]: Actual size depends on the available Modbus functions. They are configurable in the header file mbconfig.h.
[2]: Depends on the hardware.

This port was done with the STR-P711 evaluation port from Olimex. It features a STR711FR2T6 16/32 bit ARM7TDMI with 256K Bytes Program Flash, 64K Bytes RAM. Two ports are supplied - One using Rowley Crossworks which provides a complete IDE. The other one uses the GNU ARM toolchain, GDB and OpenOCD and therefore provides a zero cost option. The files for this port can be found in demo/STR71X and demo/STR71XGCC.

The initial port was done with the Mega168 Mini Module from Embedit Mikrocontrollertechnik. It features a 8Bit AVR ATMega168 controller with 16KByte Flash, 1KByte SRAM and 512Byte EEPROM. The development toolchain used is WinAVR. Since version 1.0 Freemodbus also supports the ATMega8, ATMega32, ATMega128(CVS), ATMega168 and ATMega169 microcontrollers. In addition it includes support for the RS485 driver DS75176. The files for this port can be found in /demo/AVR

Depending upon the selected functions and transmission modes (ASCII/RTU) the following resources are used:

Module / Code / RAM (static)
Modbus RTU (Required [1]) / 1456Byte / 266Byte
Modbus ASCII (Optional) / 1222Byte / 16Byte
Modbus Functions [2] / 1602Byte / 34Byte
Modbus Core (Required) / 608Byte / 75Byte
Porting Layer (Required) / 704Byte / 7Byte

[1]: Includes a special implementation of the CRC16 calculation algorithm to use values from the flash memory.
[2]: All supported Modbus functions compiled in.

The Motorola Coldfire port was done with the M5235BCC kit from Freescale. It features a Freescale MCF5235 processors with 2Mb Flash and 16Mb SDRAM. The development toolchain used is the GNU C compiler 3.4.6 with the Insight debugger [1] and the P&E micro debuggers [2]. The files for this port can be found in demo/MCF5235

[1]: Needs the Insight debugger from and the m68k-bdm patches for development available at
[2]: A free 64k limited version ICDCF is available at P&E Microcomputer Systems

The port was done using the MSP430-P169[1] from Olimex. It includes a TI MSP430F169 MCU with 60Kb Flash and 2Kb RAM. Two ports are supplied - One using Rowley Crossworks[1] for the MSP430 and the other one uses GCC[2]. The files port this port can be found in demo/MSP430.

Depending upon the selected functions and transmission modes (ASCII/RTU) the following resources are used:

Module / Code / RAM (static)
Modbus RTU (Required [1]) / 1248Byte / 266Byte
Modbus ASCII (Optional) / 986Byte / 16Byte
Modbus Functions [2] / 2066Byte / 34Byte
Modbus Core (Required) / 768Byte / 79Byte
Porting Layer (Required) / 596Byte / 9Byte

[1]:The MSP430-P169 development board can be purchased from Olimex
[2]:Rowley Crossworks for MSP430
[3]:The GNU tools are available at the MSPGCC website.

The Win32 port can be used to implement a Windows Modbus Slave. It was the first port which supports the new Modbus/TCP functionallity added in release 0.7.

The basic operation of the protocol stack is the same as for embedded platforms. One typically wants to create a thread in which the main Modbus polling loop function is called. For a Modbus RTU/ASCII example see demo.c. A Modbus TCP example is available in demo.c. Embedding this protocol stack in a DLL should be fairly easy so usage from LabView or other tools should be possible.

Since version 0.9 FreeModbus supports an lwIP [1] port. The port is pretty generic and the FreeModbus port should be portable to another lwIP platform by simply recompiling it.

In addition this port includes a complete FreeRTOS port for the Motorola Coldfire targets and an ethernet driver for the MCF523x FEC controllers. The M5235x platform is a very powerful targets and features a Freescale MCF5235 processor with 2Mb Flash and 16Mb SDRAM. The development toolchain used is the GNU C compiler 3.4.6 with the Insight debuggers [2]. The files for this port can be found in demo/MCF5235TCP. The figure below shows a frame captured with the Ethereal network analyzer.

[1]: lwIP - A Lightweight TCP/IP stack is available from
[2]: Needs the Insight debugger from and the m68k-bdm patches for development available at

This port was based on the original STR71X port of FreeModbus. It adds PPP support to lwIP and includes an advanced serial driver which uses the FIFOs of the UART. It supports PPP connection up to 115200baud and include a working Modbus/TCP example application. The files for this port can be found in demo/STR71XTCP.

The next figure shows an example of the debug console from the embedded target. First a PPP connection was established with a Linux host system with a Null-Modem cable. The a new Modbus/TCP client connected with IP address 10.0.10.1 and sent two Modbus commands. After that the client has disconnected.

INFO: PPP: new PPP connection established

INFO: PPP: our IP address = 10.0.10.2

INFO: PPP: his IP address = 10.0.10.1

INFO: PPP: netmask = 255.255.255.0

DEBUG: MBTCP-ACCEPT: Accepted new client 10.0.10.1

DEBUG: MBTCP-RECV: | TID = 0000 | PID = 0000 | LEN = 0006 | UID = 01|| FUNC = 04 | DATA = 03E70002 |

DEBUG: MBTCP-SENT: | TID = 0000 | PID = 0000 | LEN = 0007 | UID = 01|| FUNC = 04 | DATA = 04AC610001 |

DEBUG: MBTCP-RECV: | TID = 0000 | PID = 0000 | LEN = 0006 | UID = 01|| FUNC = 04 | DATA = 03E70002 |

DEBUG: MBTCP-SENT: | TID = 0000 | PID = 0000 | LEN = 0007 | UID = 01|| FUNC = 04 | DATA = 04B0420001 |

DEBUG: MBTCP-CLOSE: Closed connection to 10.0.10.1.

Again we can use the modpoll utility to test the port. An example is shown below. Note the TCP/IP configuration.

[root@pcno-4 STR71XTCP]# ./simple.sh

modpoll - FieldTalk(tm) Modbus(R) Polling Utility

Copyright (c) 2002-2004 FOCUS Software Engineering Pty Ltd

Protocol configuration: MODBUS/TCP

Slave configuration: Address = 1, start reference = 1000, count = 1

TCP/IP configuration: Host = 10.0.10.2, port = 502

Data type: 32-bit integer, input register table

Protocol opened successfully.

Polling slave (Ctrl-C to stop) ...

[1000]: 87913

Polling slave (Ctrl-C to stop) ...

[1000]: 88914

Polling slave (Ctrl-C to stop) ...

[1000]: 89914

Polling slave (Ctrl-C to stop) ...

Downloading

You can get the current version of FreeModbus at freemodbus-v1.1.0.zip. This versions includes a lot of functions like Modbus RTU/ASCII, Modbus TCP, input/holding register access, discrete registers and more. In addition it has been ported to the following platforms: FreeRTOS/ARM STR71X, lwIP/PPP/STR71X, Freescale MCF5235, lwIP/MCF5235, Atmel AVR ATMega168, TI-MSP430, Win32 and Linux.

Donations

Donations are appreciated and gratefully received! I am looking for HCS12 and Renesas development platforms for porting purposes. If available the kit should include a programmer/debugger interface as well as a target system. In addition money is also accepted and will be used for supporting FreeModbus development. Note that donations are not required in order to use or download FreeModbus. They are completely voluntarily

Donate $10 / 窗体顶部

窗体底部
Donate any other amount / 窗体顶部

窗体底部

Source

If you want to take a look at the source you can find information on how to access the CVS repository at FreeModbus CVS repository. In case you only want to take a look at the code WebCVS access is also available