Author Topic: MODBUS IP to serial (RTU) gateway  (Read 28117 times)

Offline jezc

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
MODBUS IP to serial (RTU) gateway
« on: April 29, 2012, 08:53:57 PM »
Hi Mark,

I've been asked to look into providing a simple MODBUS gateway to allow serial (RTU) devices (RS232 & RS485 but not necessarily both at the same time) to be connected via Ethernet (MODBUS IP).

Having had a read of the documentation, this looks to be a pretty simple application for the uTasker MODBUS implementation.

I have a pretty wide range of devices to choose from (ColdFire Kirin3/Kinetis, NXP LPC2xxx/LPC17xx, STM32, TI) though the preference for development tools/compiler would be to use IAR (for ARM or ColdFire).

Can you suggest what the relative benefits/drawbacks of the various platforms are for the uTasker/MODBUS combination? I'd imagine that most would be capable of supporting the simple case above but any indication on which dev kits would be suitable for initial prototype development would be a great help.

Initial minimum project features are for MODBUS IP (IP v4 though the option for IP v6 would be good) & either RS232 or RS485 (possibly as two hardware builds) purely as a gateway.

Next phase would be to add in some simple web server applications & possibly support more than one serial connection at once (e.g. RS232 & RS485).

Then we'd be looking to add in USB Host functionality (we have our own flavour of MODBUS over USB bulk transfers we'd like to support)

We may also be wanting to offer a plain (non-MODBUS) Ethernet to serial gateway (but so far the options for providing a virtual serial port on the PC is looking problematic for this)

We'd like to be able to support this within a family of processors (maybe scaling the memory/package sizes as the complexity rises) rather than mixing solutions across the different vendors.

Any thoughts or suggestions (from you or your other MODBUS customers) would help

Cheers,
    Jez

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3238
    • View Profile
    • uTasker
Re: MODBUS IP to serial (RTU) gateway
« Reply #1 on: April 30, 2012, 11:00:25 PM »
Hi Jez

I don't have any real recommendation for device becaause all are supported to work with all MODBUS functionality.
Generally if you are open to processor types, the freescale Kinetis family are very popular at the moment and are optimal for Ethernet and RS485 work since they have TCP/IP checksum offloading - I just updated a benchmak showing its performance benefits here: http://www.utasker.com/docs/uTasker/uTaskerBenchmarks.PDF Its UART has automatic RS485 RTS control, which is nice too. There are a wide range of chips and they have up to 6 UARTs - IAR works well with them too.

The MODBUS TCP interface uses IPv4 but the Kinetic package has IPv6 TCP support so it would be quite simple to adapt it to IPv6 (or dual stack) operation if required.

The uTasker project supports only USB device at the moment and not Host. USB CDC has been used for MODBUS as USB device (there is a define for this) but I don't know how you would like to use host. Kinetis USB device is however also fully implemented.

Since you are looking at a scalable solution the Kinetis is also a good choice since it has good scalability.


Regards

Mark





Offline jezc

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: MODBUS IP to serial (RTU) gateway
« Reply #2 on: May 16, 2012, 12:55:40 PM »
Hi Mark,

Thank you for the response - I've tried to make a start with the simulator for both Kinetis & LPC17xx families but both fail to compile when I include the 'real' MODBUS.c & .h files...

\utasker\modbus\modbus.c(1383): error C2039: 'timer_reference' : is not a member of 'stPIT_SETUP'
\hardware\kinetis\kinetis.h(5857) : see declaration of 'stPIT_SETUP'
\utasker\modbus\modbus.c(1383): error C2065: 'MODBUS0_TIMER_CHANNEL' : undeclared identifier


I've quickly tried the same with the 52259 DEMO board & that seems to build ok for the simulator & run.

Do I need a later version of MODBUS.c & modbus.h fiels to support Kinetis /LPC17xx/2xxx ?
Looking at the comment at the top of MODBUS.c I appear to have v1.06 (2/9/2009)...

Is there any chance to get the updated files to allow me to use Kinetis or LPC targets please?
Or, if it's easier to just let me know what changes I need to add in to support one or other, that would be most helpful.

In the meantime I'll try and get some of the basic functionality/configuration sorted out with the 52259 ssimulation.

Cheers,
    Jez

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3238
    • View Profile
    • uTasker
Re: MODBUS IP to serial (RTU) gateway
« Reply #3 on: May 16, 2012, 03:55:10 PM »
Hi Jez

It looks like your version doesn't support all chips - there are sometimes some special HW related routines to control timers that are a bit chip-dependent.

You can always get the latest version here: http://www.utasker.com/forum/index.php?topic=1424.0 where also the changes are documented.


Regards

Mark


Offline jezc

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: MODBUS IP to serial (RTU) gateway
« Reply #4 on: May 16, 2012, 05:14:27 PM »
Hi Mark,

Ok, thanks for confirming that is the problem. The next problem is for me to find the original password again...

I'll continue proving the ideas with the 52259 build until I can retrieve the password.

Thanks once again for your support!

Cheers,
    Jez

Offline jezc

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: MODBUS IP to serial (RTU) gateway
« Reply #5 on: May 17, 2012, 01:02:04 PM »
Hi Mark,

  Thanks for sending the password (again). ;D

With the latest MODBUS files I've managed to get the Kinetis project compiling ok in the simulator (C++ 2010 Express) - I'm struggling to get the same project working on the 2009 version on a different PC but I'll upgrade to 2010 & see if that sorts it.

Thanks once again for your help with this - it really is appreciated.

I'll let you know when I've sorted it all.

Cheers,
    Jez

PS - I've just tried to get the MODBUS working in the simulator for the LPC1768 (Keil MCB17xx board) target to compare with the Kinetis but that's still reporting compile errors relating to stTIMER_INTERRUPT_SETUP as below

1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1618): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1619): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1622): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1623): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1626): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1627): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1630): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1631): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1635): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1636): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1639): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1640): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1643): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1644): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1648): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'
1>c:\downloads\utasker\utasker_lpc17xx_v1.4-1\utasker\modbus\modbus.c(1649): error C2039: 'timer_us_value' : is not a member of 'stTIMER_INTERRUPT_SETUP'
1>          c:\downloads\utasker\utasker_lpc17xx_v1.4-1\hardware\lpc17xx\lpc17xx.h(3661) : see declaration of 'stTIMER_INTERRUPT_SETUP'

Changing the target back to LPC1788 is still giving me the same errors.

Any ideas?

Cheers,
    Jez
« Last Edit: May 17, 2012, 04:03:18 PM by jezc »

Offline kiryat8

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: MODBUS IP to serial (RTU) gateway
« Reply #6 on: August 26, 2014, 07:26:47 AM »
Did you ever get resolved the lack of the lacking timer_us_value field in TIMER_INTERRUPT_SETUP.
I am implementing the Modbus now using the LPC1768 chip and get the same errors.
Thanks

Offline kiryat8

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: MODBUS IP to serial (RTU) gateway
« Reply #7 on: August 26, 2014, 08:18:30 AM »
I downloaded the latest Modbus code to be used with the latest LPC code base.
As I wrote there is no timer_us_value field in the TIMER_INTERRUPT_SETUP structure.
There is also no "_TCP_SOCKET_MASK" macro defined.
Should I use a different Modbus version or where can I get the new defines?

Thanks

Offline kiryat8

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: MODBUS IP to serial (RTU) gateway
« Reply #8 on: August 26, 2014, 12:32:41 PM »
In the LPC's tcpip.h file I added the following that I found in the kinetis version.
Now

// ?!? added
#if IP_INTERFACE_COUNT > 1 || IP_NETWORK_COUNT > 1                       // {74}
    #define _TCP_SOCKET_MASK_ASSIGN(uSocket)  (uSocket &= (SOCKET_NUMBER_MASK))
    #define _TCP_SOCKET_MASK(uSocket)  (USOCKET)((uSocket) & (SOCKET_NUMBER_MASK))
    #define _UDP_SOCKET_MASK_ASSIGN(uSocket)  (uSocket &= (SOCKET_NUMBER_MASK))
    #define _UDP_SOCKET_MASK(uSocket)  (USOCKET)((uSocket) & (SOCKET_NUMBER_MASK))
#else
    #define _TCP_SOCKET_MASK_ASSIGN(uSocket)                             // does nothing when single interface and single networks
    #define _TCP_SOCKET_MASK(uSocket) (uSocket)
    #define _UDP_SOCKET_MASK_ASSIGN(uSocket)
    #define _UDP_SOCKET_MASK(uSocket) (uSocket)
#endif

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3238
    • View Profile
    • uTasker
Re: MODBUS IP to serial (RTU) gateway
« Reply #9 on: August 26, 2014, 01:25:20 PM »
Hi

The LPC17xx project doesn't use "timer_us_value"but instead uses "timer_value". [this is partly historical due to compatibility with the LPC2xxx code and partly due to its hardware timer capability - usually this detail is not really noticed by users]

This is controlled in the MODBUS code by the conditional expression:
#if defined _LM3SXXXX || defined _STM32 || (defined _HW_TIMER_MODE && (defined _LPC23XX || defined _LPC17XX))

_HW_TIMER_MODE is a fixed define (see lpc17xx.h) so it looks like _LPC17XX is missing when building this file. _LPC17XX is passed as a pre-processor define to all files - eg. in the GCC make file:
-D _GNU -D _LPC17XX

If you are using a different tool chain and you added these files to the project they "may" have been added without these so edit the build property of MODBUS.c (in the IDE's property setting) and then I expect that the problem will be solved.

In the case of _TCP_SOCKET_MASK() the LPC17xx project needs this as an empty macro #define _TCP_SOCKET_MASK(uSocket) (uSocket). This allows the MODBUS module to be used on multiple networks, interfaces and/or VLANs (eg. one socket on the Ethernet, one on a serial interface and multiple IP addresses). Since the LPC17XX project doesn't (presently) include multi-networking code the define needs to be added manually (since quite recently). I have just added a note in the release notes to avoid this difficulty again.

Regards

Mark




Offline kiryat8

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: MODBUS IP to serial (RTU) gateway
« Reply #10 on: August 27, 2014, 05:41:39 AM »
I found that _HW_TIMER_MODE was not defined. It is used only in ADC_Timers.h fnConfigure_Timer() and in debug.c fnTestTCPServer() in the test project.

A few other questions:
1) When I enable the HTTP server demo together with USE_MODBUS , I can not upload ftp files and the web pages are destroyed. I guess that the fnGetMODBUS_parameters() in modbus_app.c needs to be changed somehow.
I use a SPI_FLASH_SST25VF080B external flash chip which works fine.

2) Our application uses a Modbus RTU slave along with a Modbus TCP slave accessing the exact same data.
My defined Modbus registers are in several address ranges so I guess that I set the second parameter in the fnInitialiseMODBUS_port() function to NULL and I will get notified in the fnMODBUSuserFunction callback?
I must manually send a reply with fnMODBUS_transmit and return zero if all is correct?
Do you have a code snippet example. We use mainly Rd/Wr Holding registers.

Thanks

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3238
    • View Profile
    • uTasker
Re: MODBUS IP to serial (RTU) gateway
« Reply #11 on: August 28, 2014, 12:51:32 AM »
Hi

1) I don't understand why enabling the MODBUS module is affecting FTP and the web server. MODBUS adds extra sockets and requires extra memory so it may be an idea to check the memory utilisation (see the command "memory" in command line menu "statistics").
There are extra MODBUS parameters added when the MODBUS operation is enabled but the version number of the parameters is also modified so that a previous unmatching set is reset back to default values, which means that there should be no problems enabling and disabling MODBUS (in that parameter mismatch causes errors).

2) There are several ways to handle MODBUS registers (you could use one address range that is handled automatically and anothers (outside of this) that are handled by the call back (event USER_RECEIVING_MISSED_RANGE). Entering a zero for parameters will mean that all receptions provoke the callback and all handling is also in the user callback (event USER_RECEIVING_ALL_MODBUS_DATA).
fnMODBUSuserFunction() in modbus_app.c shows a few handling cases, such as gatewaying certain register addresses to different ports. It also shows handling the function code MODBUS_READ_COILS and returning a response using the fnMODBUS_transmit() function.
*modbus_rx_function also contains information about the port that the request arrived on so the handing could be made different if there should be certain dependencies (such as one port not having write access rights).
When working with automatic registers multiple ports can access them. Special handling (such as port dependencies) can be performed in fnMODBUSPreFunction() which is a callback just before a register read. The callback fnMODBUSPostFunction() is handled after a MODBUS write has been executed.
If you have various ranges in the registers (rather than a single block of addresses) it may still be possible to define a single (larger) block of registers/memory and use the pre- and post.- callbacks just to signal exceptions if the addresses accessed were not legal addresses (it requires more memory for the complete set of registers but allows the majority of handling to be performed by the function handling in the MODBUS code itself).

Regards

Mark