OPCUA server on bare metal CPU

144 views
Skip to first unread message

Proxima Centauri

unread,
Feb 11, 2025, 2:38:18 PMFeb 11
to open62541
Hi,  could someone point me to a document that describes the steps needed to write a simple OPCUA server for a bare metal CPU (so NO Linux, no other OS) using open62541? As far as I understand from other posts, the arch folder contains some platform-specific parts of the library code. However, it seems that currently only support for win32 and posix platforms exist. I could try to write it myself, but it would be very helpful to know exactly the interface, ie. what functions and structures need to be provided and how to connect them to the rest (common part) of the library. Is there any interfacing structure (as with system drivers) that holds pointers of necessary functions implementation? Any hint how to start would be very appreciated!

vas...@linutronix.de

unread,
Feb 13, 2025, 2:59:39 AMFeb 13
to open62541
Hi,
I don't know if there is any documentation for bare metal. There might be some useful information if you search for freeRTOS implementation.

I think you will need at least a network stack (TCP/UDP/IP) e.g. lwIP, timer and event handling. Own logging might also be interesting.
/arch folder should actually provide a good overview of the platform-specific API. In addition to Linux and win, there is also a zephyrOS port.

Have you already considered these discussion (incl. the links in there)?

Cheers,
Vasilij

Proxima Centauri

unread,
Feb 13, 2025, 9:17:41 AMFeb 13
to open62541
Hi Vasilij,

thank you for your reply and comments.  Yes, I am aware of the need to get the TCP/IP stack as well as clock and event handling. My question is more about connecting the common part of the library with the platform-dependent part.
For example, in ua_architecture.h you see such a connection attempt - there are definitions that allow you to connect a platform-dependent socket implementation to methods called by the common open62541 part:
#define UA_poll poll
#define UA_send send
....e.t.c....

That's why I'm looking for tips on how to do it in a legal, official way. I don't want to manipulate the code and make modifications directly to some files because I want to be compatible with future releases of the OPCUA open62541 stack.

Cheers,
Proxima

Mathias Obetzhauser

unread,
Feb 13, 2025, 4:17:21 PMFeb 13
to open62541
Hi,

with v1.4 the freeRTOS support was removed cause of the implementation of the eventloop. v1.3 is still maintained, so you have to use the latest v1.3.15 release.
From my experience I can say, it's working perfectly on an ESP32 and ESP32-S3. You just need enough SRAM or PSRAM.

Good luck!


Best regards
Mathias (m-obi)

Julius Pfrommer

unread,
Feb 14, 2025, 2:17:19 AMFeb 14
to open62541
@Proxima
If you develop on bare metal, you will still want to use a mature TCP implementation.
It is common to use lwip for those instances [1].

However .. the 1.3 branch uses the POSIX layer of lwip - which depends on threading.
If you go bare-metal, it is advised to use lwip-raw (and lwip-POSIX) w/o threading requirements.

Using lwip-raw can be done for open62541 >1.4 and was one of the use-cases for which the current "EventLoop" was designed.

We have a prototype for this - but not ready for public release.
Hit me up on a private channel if you want to discuss further.

Regards,
Julius

Julius Pfrommer

unread,
Feb 14, 2025, 2:18:10 AMFeb 14
to open62541
lwip-raw (and *not* lwip-POSIX)

Proxima Centauri

unread,
Feb 17, 2025, 2:38:04 AMFeb 17
to open62541
Hi Mathias,
using freeRTOS (or any other OS) is not an option for me, but thanks for your comment!
Proxima

Proxima Centauri

unread,
Feb 20, 2025, 9:08:02 AMFeb 20
to open62541
Hi Julius,

thank you for your reply. I have already tried to contact you on your private channel - not sure if you got my message. 

I have now the lwip library working on my bare-metal platform and I am very interested in making some progress with open62541. If you have anything done in direction of bare-metal CPU, even not tested and not ready for any release, I would still like very much to have a chance to see it and learn more about interfacing possibility.

Best regards,
Proxima

Proxima Centauri

unread,
Dec 2, 2025, 11:41:08 AM (3 days ago) Dec 2
to open62541

After a longer break I returned to the project, and this time I managed to build a working server on a “bare-metal” STM32H563zi processor. The whole setup runs on the NUCLEO-H563ZI board. My test server accepts up to 10 clients (currently only UAexpert), allowing browsing of nodes, monitoring of several variables, etc.

Everything looks fine, except for the case when multiple clients reconnect simultaneously after the board is reset. As soon as the server obtains its IP from DHCP, the clients resume their connections—and then something puzzling happens: they all connect, but shortly afterwards they start reporting errors: “unexpected sequence number.” Interestingly, this problem seems to be “contagious,” meaning that connections which were initially fine soon begin to suffer from the same issue.

If I stop all clients and reconnect them manually one by one, the problem does not occur. Does anyone have an idea where to look for the root cause of this issue and how to resolve it?

Thanks for any suggestions!

Proxima


nucleo-opcua-reconnect-problem.jpg

Julius Pfrommer

unread,
Dec 2, 2025, 1:34:48 PM (3 days ago) Dec 2
to Proxima Centauri, open62541
Proxima,

good to see you are making progress.
Which version of open62541 is this based on? Any changes you made to the core library?
We can extend the lwip code in our repo with additional debug output to track down the source of this.

Regards, Julius


--
You received this message because you are subscribed to the Google Groups "open62541" group.
To unsubscribe from this group and stop receiving emails from it, send an email to open62541+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/open62541/c197d9c8-ce71-45ec-946d-b3323edfe7c9n%40googlegroups.com.

Proxima Centauri

unread,
Dec 2, 2025, 2:09:15 PM (3 days ago) Dec 2
to open62541
Hi Julius,

the version is 1.14.4. and almost no changes to the core, see below for details.
My impression is that the session remains active for a while after the connection has closed. When the next client connects (using the same “recycled” ID), the session management seems to get confused and, instead of creating a new session, it reactivates the old one. I am going now to verify this hypothesis, by assigning always a new ID for  new client, and not a recycled one from the pool. I will let you know about results.

Regards,
Proxima




in client.h, line 628 I added a conditional-compilation check (otherwise compilation errors, when option  UA_ENABLE_HISTORIZING  is not defined) 

#ifdef UA_ENABLE_HISTORIZING  // added by Proxima, 17.11.2025
/*
 * Historical Access Service Set
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
static UA_INLINE UA_THREADSAFE UA_HistoryReadResponse
UA_Client_Service_historyRead(UA_Client *client,
                              const UA_HistoryReadRequest request) {
    UA_HistoryReadResponse response;
    __UA_Client_Service(
        client, &request, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST],
        &response, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]);
    return response;
}

static UA_INLINE UA_THREADSAFE UA_HistoryUpdateResponse
UA_Client_Service_historyUpdate(UA_Client *client,
                                const UA_HistoryUpdateRequest request) {
    UA_HistoryUpdateResponse response;
    __UA_Client_Service(
        client, &request, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST],
        &response, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]);
    return response;
}


#endif  // added by Proxima, 17.11.2025


Other changes are in plugins, not so relevant I guess.

===IN PLUGINS================================================
in nodesteloader.h line 11 I adedd #ifndef UA_ARCHITECTURE_BAREMETAL:

#ifndef UA_ARCHITECTURE_BAREMETAL  //added by Proxima, 17.11.2025

#include <open62541/util.h>

_UA_BEGIN_DECLS

typedef void UA_NodeSetLoaderOptions;

/* Load the typemodel at runtime, without the need to statically compile the model.
 * This is an alternative to the Python nodeset compiler approach. */
UA_EXPORT UA_StatusCode
UA_Server_loadNodeset(UA_Server *server, const char *nodeset2XmlFilePath,
                      UA_NodeSetLoaderOptions *options);

_UA_END_DECLS

#endif //added by Proxima, 17.11.2025

in ua_confog_default.c I addepted th code to call my ConnectionManagerBAREMETAL, commented-out adding UDP connection manager as well as InterruptManger

Proxima Centauri

unread,
Dec 2, 2025, 2:56:06 PM (3 days ago) Dec 2
to open62541
no, my hypothesis was wrong: always assigning new clients a new ID (ie. not recycled from previous, already closed connections) didn't help...
No idea for now.

Regards,
Proxima
Reply all
Reply to author
Forward
0 new messages