Up to now, we have transferred all programs using the “Force reboot” setting.
We now intend to use “Installation during task operation” instead.
To support this, all MappLink assignments were moved into the cyclic program task.
However, we are now experiencing intermittent page faults from MappMotion (MC_Reset) after downloading the program.
When using mapp Motion or ACP10/ARNC0, transferring task changes to a running system is only possible without a restart if option “Keep PV values” is selected and user process variables that have been made known to a mapp Motion component (e.g. via a configuration or via address input on a function block) have been declared globally.
What exactly is meant by this requirement?
Is it necessary to define an additional global variable where the MappLink is stored?
Some erly versions of mappMotion had some issues while Transfer. But i think you will have used a rather up to date version. But you might give some updates about this.
This Section means that if a Functionblock has an Input for an Address the Variable which is behind the Adress shall be Global to prevent that this Value is moved in Memory due to a transfer.
One of the rather examples i would think of is the MC_BR_InitCyclicRead function from ARNC0 where you initialise a Parameter Transfer and the Data-Adress is given to the Motion-Manager. This Function could not be updated or deleted, so it was mandatory that the Data-Adresse stays valid at all time.
The most typical issue i could think of is that Global Variables must be considerd as Local if they are only used in one Task. If a Task gets deleted and the global Variable is not used any more, it will be reinitialised with the install of the new Task.
In this case the Setting “Keep PV Values” should prevent issues, as the old values should be keep.
At some time i have started to use a Dummy Task to prevent the Global Variables from beeing only used one time in an Axis Task. This is just my way to try to harden Transfer, and so far i have no known issues today.
About your code, i think there can be made a Test, but i do not know if it makes a huge difference, because it moves the Adress seen for the Mapp-Link but not for the Parameter-Structure. But i think in General for the Mp-Link this is considered more correct. And it is the way i have used it in my applications so far.
Adapt the Functionblock Interface to provide a Adresse instead of a local Copy.
Provide MpLink Adress to the MpAxisBasic. This time it is the Adress of the Global Variable. In your case it was a local Copy of the MpLink which was the Input of the Functionblock.
I’ll add onto Michael’s good recommendations with some additional information.
When you move your address assignments to the cyclic portion of the code, make sure that any address assignments (pointers) are unconditional. What I mean by unconditional, is that the address assignment isn’t executed only based on a state/input condition (ex. IF statement or within a CASE state machine). The address should be updated every execution of the program/function block.
During transfer, a program/task must be stopped, uninstalled, installed, then started. If the new code requires a different amount of memory, based on memory allocation/free space, the locations of variables can change. This can cause issues for pointers referencing those variable addresses. See the example below.
PROGRAM _CYCLIC
mappFunctionBlock.pUnconditional := ADR(myDataBlock);
IF (machineState = INITIALIZE) THEN
mappFunctionBlock.pConditional := ADR(myDataBlock);
END_IF
mappFunctionBlock();
END_PROGRAM
The unconditional pointer (pUnconditional) will automatically update so the mappFunctionBlock always uses the pointer to the correct address.
The conditional pointer saves a tiny bit of processing time by not assigning the address cyclically but is vulnerable to memory errors. When the machine is not in the initialize state, the address is not updated. After a transfer, the next execution of this code (assuming the IF statement is false) will execute against the old memory address of myDataBlock. This can cause a page fault, or unintended behavior.
There are programmatic ways to detect/update the addresses (execute Init/Exit, set flags to update addresses in Exit), but I personally find they add more complexity than the few extra address assignments take in processing time.
I moved the question to the subcategory Programming. @simon.buschor I think your question is answered, or? If so, please mark the respective reply as a solution. Thanks
But I think you will have used a rather up-to-date version. But you might give some updates about this.
Exactly—I’m using the latest versions.
I initially implemented the solution using the DummyTask, but that did not lead to success.
However, once I passed the MpLinks as addresses, it worked!
How do you handle functions where the MapLink itself, rather than the address, is passed? For example: MpAlarmXCheckReaction
This is just my way to try to harden Transfer, and so far I have no known issues today.
Which other global variables are accessed in this task besides Motion? All MapLinks?
@austin.carpenter: Thank you for your suggestions. I’ve reviewed them accordingly.
One more point from my side:
To get the MpRecipeXml working, I had to move the assignments to the cyclic part of the program, as they also change when the tasks are installed.
The Call of the Function MpAlarmXCheckReaction does not apply an Pointer Access so it should make less issues. You just have to make sure that the content of the global valid mpLink is passed to the function. I see no issues if this involves local Variables in between, as far as they are updated every cycle, so even after a Transfer the valid data is provided.
Glad to hear you got it working!
These assignments require you to provide the address of what is essentially a hidden, constant that holds the string characters. Even these hidden constants are part of the task and therefore are subject to moving locations when a task is reinstalled.
The general rule I’d follow is anytime you use the ADR() or & (ANSI C) function to provide an input to a function block, update that input cyclically.