VE Programmierhandbuch En
VE Programmierhandbuch En
Programming Manual
Development of VE application software – Manual version 2.1
Contents
1. Introduction ............................................................................................................4
1.1. Requirements for readers ...................................................................................... 4
1.2. Required software................................................................................................. 4
2. Basic information on the development of VE modules ..................................................5
2.1. What is a VE module? .......................................................................................... 5
2.2. Basic concepts ...................................................................................................... 7
2.2.1. Creation of the VE module with VECTOSTUDIO .............................................. 7
2.2.2. System structure of VECTONUM EMBEDDED ................................................ 16
2.2.3. VeCoreInterface runtime system ................................................................... 18
2.2.4. I/Os............................................................................................................ 18
2.2.5. Unit and drive modules ................................................................................ 22
2.2.6. System callbacks.......................................................................................... 25
2.2.7. Start behavior and debugging ...................................................................... 26
3. Advanced VE module development ......................................................................... 27
3.1. Use of dynamic memory areas ............................................................................ 27
3.1.1. Dynamically allocated data is prohibited ....................................................... 27
3.1.2. Stack use..................................................................................................... 27
3.2. Use of libraries ................................................................................................... 27
3.2.1. Mathematical functions ................................................................................ 28
3.2.2. The libVePlc library ...................................................................................... 31
3.3. Callback I/Os .................................................................................................... 34
3.4. Error handling in the VE module ......................................................................... 35
3.4.1. Use of ErrorGroups ..................................................................................... 36
3.5. CAN-BUS programming ..................................................................................... 39
3.5.1. Programming of RAW-CAN applications ....................................................... 39
3.5.2. Use of CANopen ......................................................................................... 43
3.5.3. Porting incompatible CanMatrix implementations .......................................... 52
3.5.4. Use of the serial interface (UART).................................................................. 57
3.6. Position control with P8 polynomials .................................................................... 58
3.7. Implementation of motor models ........................................................................ 63
3.8. Implementation of callback functions ................................................................... 64
1. Introduction
This document describes the development of application-specific software modules (VE modules)
for the ARADEX VECTONUM EMBEDDED (VE) operating system. The VE is used for inverters of
the VECTOPOWER-DM2 and VECTODRIVE-50 series.
The VE modules can easily extend the functionality of the basic firmware with application-specific
functions. These functions are integrated in the I/O concept of the VE system and can use all the
analysis interfaces of the basic firmware (ANALYSER and VE_CONFIG).
In addition, readers should know how to use and parameterize the VE system. It is recommended
to read the VE user manual for this purpose.
VE modules can be provided together with the VE firmware and the appropriate configuration file
in an integrated installation package. This allows the inverter system to be easily commissioned in
series production.
When the device is started, the VE basic firmware searches for VE modules that are present and
initializes them. This mechanism is encapsulated in the framework of the VE modules and does
not have to be implemented when a module is created. This makes it very simple to design your
own modules, and it can also be quickly mastered by beginners.
The preferred programming language for VE modules is C++. Programming can be done offline,
although a target device is necessary to test the application. The target system is connected with
the development computer via USB, serially, or via the CAN interface. The interface to be used
depends on the device configuration. VD50 devices are preferably programmed via the USB
interface and VECTOPOWER devices via the CAN interface. When the CAN interface is used, the
development computer must be equipped with a PEAK CAN USB adapter.
The development cycle can be basically divided into the following steps:
1. Connection of the hardware of the development system with the target device (optional)
2. Starting VECTOSTUDIO
3. Checking whether the VE API package installed in VECTOSTUDIO matches the device. If
not, the right package must be installed.
4. Creation of a new VE module using the ARADEX wizard
We will now create a new workspace in which to store our projects. To do this, we click
In the following dialog box, we select the memory location for our workspace. In the example,
this is “C:\vectostudio\workspace_example”.
To set up the appropriate build environment, the workspace type is then subsequently queried:
After confirmation with “OK”, VECTOSTUDIO automatically closes and opens the newly created
workspace.
VECTOSTUDIO now appears with an empty session, which we will fill with life step by step in the
following.
An Explorer dialog box opens that displays the installed package. If this does not match the target
hardware, a new package can be installed as follows:
Notes:
The API package always contains the appropriate firmware. This can be extracted from the
package using the program 7-zip, for example, and loaded to the target system.
It is also possible to store the API package in the workspace. For this reason, the corresponding
build environment for the project is automatically installed when the workspace is opened. In
addition, the firmware version of the device is checked when it is downloaded from
VECTOSTUDIO. If the firmware version does not match the project, the device is updated.
menu item.
Now select “VECTONUM Embedded PLC Project” in the ARADEX Wizard folder and click the Next
button.
In the following dialog box, we select “HelloWorld” as Project name and “C++” as Programming
language. The check mark next to Use default location must remain set!
The project can now be opened in the Project Explorer window, and the source files
HelloWorld.h, HelloWorld.cpp, and HelloWorld_ios.h can be opened by double-clicking.
is used to compile our project HelloWorld. This should be possible without an error message.
When the “Application Configuration” node is right-clicked in the file editor and “New Child” is
selected in the context menu that opens, the target platform is selected.
Right-clicking the added device and selecting “New Child -> Firmware” adds the Firmware node.
When you open the context menu of the Firmware node, you can open a dialog box via “New
Child -> Module” in which our HelloWorld VE module can be added to the configuration.
Note:
Several VE modules can be added to the device configuration from the workspace in the same
way!
The Connect dialog box opens, in which the device has to be selected.
The VE module can now be installed on the target device via the menu item
Confirm this selection with Yes in the dialog box that appears after the project is compiled.
Note:
VECTOSTUDIO checks the firmware version on the device. If the firmware version does not
match the API package used, the firmware of the device will be automatically adapted to the
version of the API package.
After the downloading is complete, the target system reboots and our module is active. This can
be checked via the I/O System_ModuleManager_ModulesFound. The I/O should contain the value
“1”.
We have now successfully created our first VE module and installed it on the target device.
VE allows the VE module to tap into the cyclic calls of the following four tasks via callback
functions:
source for the VE priority. that can only be thread for lengthy
operating system. interrupted by calculations, for
ControlTask. example
In addition, there are also event-triggered callbacks, which are described in chapter 3.8.1.2.
...
OnUpdateNonRtThread()
VE Idle Task
...
OnUpdateRtComTask()
NonRtThread
OnPostUpdateControlMode()
OnUpdateControlOutput()
...
OnUpdateControlMode()
OnUpdateHwOutput()
OnUpdateHwInput()
OnUpdateMain()
OnCoreTaskUpdate()
...
VE OSTasks
RtComTask
...
ControlTask
...
...
CoreTask
X+1
2.2.4. I/Os
I/Os are global variables in the VE system. They form the interface between modules and the VE
core system.
Parameterization, diagnosis, and debugging also take place via I/Os. They can be done with
VE_CONFIG or VECTOSTUDIO.
For a description of all I/O types and parameters, see chapter 3.10.
The “I/O Number Calculator” integrated in VE_CONFIG allows the I/O number to be quickly
determined via the IDs and vice versa.
When the file is opened in the editor, it shows that there are already templates for the existing I/O
types. These should be used as the basis for one’s own I/Os.
FIELD 32-bit integer, the individual bits of which can be Depending on element
(IS_BITMASK) assigned a Boolean variable. definition
In addition to the four basic types, there are the following special forms:
Name Description
IO_TYPE_CB Callback I/O. A function must be transferred that checks the value before it is set
and if necessary prevents the setting or performs further calculations (e.g., other
parameters depending on the I/O value).
The definition of I/Os will be examined in more detail using the example of IO_UINT
System_Scheduler_Ctrl_ActDutyTime:
The parameters of the IO_FLOAT I/O macro have the following meaning:
In our project, the I/O object has to be declared in the header file HelloWorld.h:
CIoUnsignedIntegerReference m_io_ActCycleCounter;
This declaration creates an I/O object that can reference an I/O of the type IO_UINT. For the
compiler to be able to link our object with the VE I/O, the object must be initialized in the
function bool CHelloWorld::bInitIos() of the file HelloWorld.cpp.
Note:
If several I/Os have to be initialized, the readability of the source code can be improved by
assigning the pointer to the VeCoreInterface of a variable.
In the following, the I/O could be used in the cyclic update callback
void CHelloWorld::OnUpdateMain()
1. Unit I/Os
2. Drive I/Os
Unit I/Os are present in the device once. Examples of this include the configuration of the
Analyser or the statistics I/Os (cycle time, task utilization etc.).
Drive I/Os, on the other hand, exist separately for each axis. Examples include the adjustment of
the position controller or the motor settings.
If you write your own VE module, it must be distinguished whether it is a unit or a drive module.
Depending on this, the framework of the application ensures the right I/O interface and the use of
the correct callback functions (some callback functions are only implemented for drive modules).
To distinguish among the I/Os, VE uses the instance number that is contained in the I/O number.
Unit I/Os and drive I/Os for axis 1 have the instance number “0”. Drive I/Os for axis 2, on the
other hand, have the instance number “1”. For further axes, the instance number would be
correspondingly increased.
///
/// general configuration for all modules
#define APP_USE_UPDATE_MAIN_CB 1 ///< The cyclic real time callback.
#define APP_USE_RESET_ERRORS_CB 1 ///< The reset error callback.
#define APP_USE_NON_RT_THREAD_CB 0 ///< The cyclic non real time callback.
#define APP_USE_RT_COM_TASK_CB 0 ///< The high priority communication
task callback.
#define APP_USE_CYCLE_TIME_CHANGED_CB 0 ///< The notification about changes of
the cycle time.
#define APP_USE_UPDATE_HW_INPUT_CB 0 ///< It's called after the hardware
input signals are updated.
#define APP_USE_CONTROL_OUTPUT_CB 0 ///< It's called before the current
setpoints are written to the current controller.
#define APP_USE_UPDATE_HW_OUTPUT_CB 0 ///< It's called before writing the
process data to the hardware.
#define APP_USE_READ_ABS_POS_CB 0 ///< It's called when the absolute
position is updated.
#define APP_USE_LOAD_DEFAULT_VALUES_CB 0 ///< It's called when all config-I/Os
are reset to their default values.
#define APP_USE_PRE_START_CB 0 ///< It's called before the real time
interrupt is started.
#define APP_USE_LVSUPPLY_READY_OK_CB 0 ///< It's called when the internal low
voltage supply is ready.
The application is configured via the corresponding #define instruction. The corresponding
option can be activated with a “1”. “0” deactivates this option.
An exception is the parameter APP_DRIVE_NUMBER. Here the valid options are USE_DRIVE_0 or
USE_DRIVE_1.
After the configuration of the module has been completed, the line
#warning "Please adapt VENDOR_ID and MODULE_ID and then remove this line!"
can be deleted. It has no functional meaning but merely indicates the necessary adjustment.
• APP_IS_DRIVE_MODULE
• APP_DRIVE_NUMBER
• APP_USE_CONTROL_MODE_CB
• APP_USE_USER_MOTOR_MODEL_CB
• APP_USE_POST_CRITICAL_CB
• APP_USE_PS_ENABLED_CB
• APP_USE_PS_DISABLED_CB
are specifically for drive modules and can be left in the default setting (0).
When I/Os are created in the ios.h file, all the I/Os of a unit module must have the attribute
IO_IS_UNIT. The framework helps us here by using the definition APP_IO_IS_UNIT. Depending
on the module type, this is defined as IO_IS_UNIT for unit modules or as 0 for drive modules.
Example:
bInitSuccess &= CVeCoreInterface::poGetInterface()->bInitIo(&m_io_ActCycleCounter,
System_Scheduler_Ctrl_ActCycleCounter_NUMBER);
It is necessary to enter the instance number to initialize drive I/Os. This can be determined with
the function uiGetDriveNumber(). The first axis has the value “0” and the second axis the value
“1”.
Example:
bInitSuccess &= CVeCoreInterface::poGetInterface()-->bInitIo( &m_io_P0KpD,
Drive_CurrentControl_Config_P0_KpD_NUMBER, uiGetDriveNumber() );
Note:
Cyclic queries (so-called “polling”) of system I/Os in the main part of the application are a poor
alternative to using callback functions. In the case of cyclic queries, it is also impossible to
specifically manipulate particular functions of the VE core, e.g., the motor model.
Since the definition of the callbacks is a complex matter, this task is performed by the framework.
The framework already contains all the definitions and the function bodies of the VE callback
functions. To minimize the module memory usage, the used callbacks first have to be activated in
the configuration section of our VE module (see chapter 2.2.5.1).
virtual bool bInitIos() Initialization of I/Os that are If an I/O cannot be initialized,
provided by the VE system or false must be reported back.
other modules
virtual void OnUpdateMain() Cyclic call of the module Called by the VE system from
the control task; real-time
capable!
The starting point for one’s own programs is normally the function OnUpdateMain(). In chapter
3.8.1 you will find a more detailed description of all callback functions. The ARADEX project team
is also happy to advise you if you have questions regarding the implementation of a specific
application.
If the system does not start, the following points should be checked first in the program code:
such as, e.g., the formatting of strings (e.g., sprintf(…)) lead to greatly larger programs. C++
exceptions are not supported.
For example, the mathematical library should not be integrated via #include<cmath>; instead,
the functions of the VE firmware should be shared via the CVeMath object of VeCoreInterface.
m_sIos.MyApp_IoFloat = CVeCoreInterface::poGetInterface()->poGetVeMath()-
>sin(2.0 * fPi * fFrequency * m_fActTime)
Trigonometric functions
float double
float
double
Exponential functions
float double
float double
Unlike with C/C++, float is assumed as the default data type, since this is supported by the
mathematical coprocessor of the microcontroller. The use of double variables is not
recommended, since this causes the program to have a significantly worse runtime behavior.
The VeMath library also already contains the definitions for frequently used mathematical
constants.
VE_M_3PI_4 ¾π 2.3561944901923448370E0
VE_M_SQRTPI √π 1.77245385090551602792981
VE_M_SQRT2 √2 1.41421356237309504880
VE_M_SQRT3 √3 1.73205080756887719000
#include <libVePlc/Functions.h>
CMove and CAccelerationRamp Complex setpoint generator with configurable starting and
stopping ramps
CFilter This is the abstract basic class of all filters. Use this class to
derive your own filter classes.
CFilterAvMax Filter that limits acceleration and speed; the end position is
always reached.
CFilterPid2 PID filter like CFilterPid but additionally with low-pass filter
for the D component.
A solution to this is provided by so-called callback I/Os. When a callback I/O is defined, a pointer
is transferred to a function that is called before the value changes. This then allows further
calculations to be initiated or the value to be checked for plausibility.
Callback I/Os are available for all I/O types except for arrays. These are identified in the I/O
configuration by the suffix _CB.
Example:
BEGIN_FIELD(MyApp_IoEnum)
ELEMENT ( 1, Enum1, "Testing I/O enum value 1")
ELEMENT ( 2, Enum2, "Testing I/O enum value 2")
ELEMENT ( 3, Enum3, "Testing I/O enum value 3")
ELEMENT (10, PostError, "Post 'MyApp_IoBitmaskError.Error0'")
END_FIELD_CB(MyApp_IoEnum, bCallback_IoEnum, (4), "", "%d", 1, 1,
10, 0, 1, IO_IS_INPUT | IO_IS_OUTPUT | IO_IS_ENUM | APP_IO_IS_UNIT,
"Testing I/O enum with callback");
In the example, the entry bCallback_IoEnum is an indicator for the callback function. For
implementation reasons, this function must be declared before the ios.h file is included. The
function also has to be defined as static.
The instruction BEGIN_FIELD must not be given the suffix _CB!
/**
* Add I/O callback functions here
*/
/**
*
* @param puiValue Pointer to the new value
* @param pIo Pointer to the I/O
* @param pThis Pointer to the module instance
* @return True if new value is valid, otherwise false
*/
static bool bCallback_IoEnum(uint32_t* puiValue, CIoUnsignedInteger* pIo,
void* pThis);
/**
* Begin I/O handling
*/
#define IO_FILE "HelloWorld_ios.h"
#include <libIoInterface/Macros/IoDefinitions.h>
/**
* End I/O handling
*/
The keyword static means that this function can be called even without instantiation of the
object. This has the consequence that the VE module object can no longer be directly accessed
from the callback function.
For this reason, the THIS macro has been introduced, which provides the pointer for our object.
This trick makes it easy to call the member variables and methods of our module. It must only be
noted that this has to be declared as public.
Errors are displayed as Boolean values. They can be mirrored either directly on an I/O of the
IO_BOOL type or on individual bits of an IO_UINT. The I/O name or the name of the bit of an
IO_UINT I/O is used as the error name in the display of VE_CONFIG.
BEGIN_FIELD(IoErrorBitmask)
ELEMENT(0, Error0, "Error 0 comment")
ELEMENT(1, Error1, "Error 1 comment ")
END_FIELD(IoUIntBitmask, (4) /*Number*/, "" /*Unit*/, "%d"
/*Formatstring*/, 0 /*Default*/, 0 /*Min*/, UINT32_MAX /*Max*/, 0
/*Exponent*/, 1 /*Scale*/, IO_IS_OUTPUT | IO_IS_BITMASK | IO_IS_ERROR |
IO_IS_MSG_APPLICATION_USER | APP_IO_IS_UNIT /*Flags*/, "Testing error I/O"
/*Description*/);
For our I/O to become an error I/O, the attribute IO_IS_ERROR must be given. If the attribute
IO_ERROR_IS_CRITICAL is also given, the enabling of the inverter will be automatically switched
off when an error is triggered.
In the case of an error or warning I/O, the corresponding ErrorGroup category should also be
specified. Here you indicate the assignment to the individual collective error groups. A description
of the attributes is found in chapter 3.4.1.1.
CVeCoreInterface::poGetInterface()->PostError(&m_sIos. DemoErrorUInt,
EDemoErrorUInt::MyErrorBit);
For errors that are directly represented by an IO_BOOL, the value 0 is transferred as the
parameter.
Errors are reset globally in the VE system via the OnResetErrors() callback. Errors must not be
reset automatically. The VE module must make sure that internal module errors are only deleted
in the OnResetErrors() method.
Warnings can reset themselves. If the warning is no longer current, the I/O or the bit can be set to
false.
• Device errors and axis errors have identical categories. The same holds true for warnings.
• A device error is also signaled in parallel for each axis.
• However, an axis error is not shown for the device, in order to prevent a further axis from
going into an error state as well).
• The first error that occurs is saved in the ErrorGroup_Drive_ErrorNumber_Id I/O. The
corresponding error bit (0 for IO_BOOL errors) is in the
ErrorGroup_Drive_ErrorNumber_Param I/O.
To check an axis for errors, it is therefore sufficient to evaluate your ErrorGroup.
Note:
A list of all errors can be obtained by exporting the error definition list of the device via the menu
item
in VE_CONFIG. This error list also contains the errors of all loaded VE modules.
Note:
In the VECTOSTUDIO welcome screen,
The RtComTask task is responsible for communication via CAN in the VE system. It runs with a
high priority and can only be interrupted by the ControlTask (control).
VE internally uses two differential prioritized FIFO buffers to send outgoing messages:
1. The PDO FIFO is reserved for real-time messages. It is forwarded by the VE system to the
CAN controller with high priority.
2. The SDO FIFO is intended for service messages. It is larger than the PDO FIFO buffer and
is also used for communication with VE_CONFIG, for example.
The priority of the sending can be influenced via the System_CanBus_RealTimePriority I/O. The
following settings are possible:
System_CanBus_RealTimePriority
If an FIFO does not contain any data, the other respective FIFO is sent as long as the CAN
controller can receive data.
Received messages are picked up by the CAN controller and stored in an input buffer. This takes
place at the beginning of each RtComTask cycle. Each module can read the complete buffer and
process the received CAN messages. The contents of the receive buffer are deleted at the end of
the communication cycle of the RtComTask.
VE Device Message
integrated CAN Receive
Controller List
CAN_bGetNewCanMsg(..)
CAN_bSendCanMsg(Msg,
eCanPrioSDO);
CAN_bSendCanMsg(Msg,
eCanPrioPDO);
PDO-FIFO
SDO-FIFO
VE Device
integrated CAN
Controller
It is necessary to use the so-called owner ID to access the filters and the message functions. This
identifies the module in relation to the VE kernel and can be freely selected in principle.
However, it is recommended to generate this ID based on the vendor ID and the module ID so
that it is the same throughout the entire system.
m_ui2CanOwnerId = Intf->poGetVeIoExtensionCardInterface()->
CAN_uiGetOwnerId(
VE_VID_Development, MY_MODULE_ID);
If you want to parameterize the filters of the internal CAN controller at a later time, the owner ID
is noted and the VE module can selectively delete its own filters as well later on.
Instead of directly programming the filter for an identifier, it is also possible to set a mask. The
function for this is:
bool CAN_bSetFilterIdRange(
uint32_t uiOwnerId,
uint32_t uiCanId,
uint32_t uiMask,
bool bIsExtendedId = false,
bool bIsRtr = false,
uint32_t uiFifo = 0 );
The mask defines which bits have to be set in the CAN identifier. The parameter bIsExtendedId
indicates whether 9-bit or 11-bit identifiers are used.
The bIsRtr and uiFifo parameters can be used to cover special applications. Normally, the
default specifications should be used here (do not enter parameters).
If the function yields the message false, the filter has not been set. This could be because all
available filters have already been used. In this case it is possible to switch off all the filters.
If the filters are to be set so that all messages are received on the CAN bus, the function
CAN_EnableAllIdFilter(uint32_t uiOwnerId)
must be called.
The next step could be the reception of CAN messages within the VE module. In this case, the
following must be observed:
CVeIoExtensionCardInterface::CAN_RX_MSG sCanRxMessage;
if (CVeCoreInterface::poGetInterface()->poGetVeIoExtensionCardInterface()-
> CAN_bGetNewCanMsg(m_u32iCanOwnerId, &sCanRxMessage,
m_ui32CanOpenSdoRxId))
{
… process m_CanRxMessage
}
or
while (CVeCoreInterface::poGetInterface()-
>poGetVeIoExtensionCardInterface()-> CAN_bGetNewCanMsg(m_u32iCanOwnerId,
&m_CanRxMessage, UINT32_MAX))
{
if (m_CanRxMessage.StdId == m_ui32CanOpenSdoRxId )
{
… process m_CanRxMessage
}
}
In this example, the program tries to send the message until VE can save the new telegram in its
output buffer. If this is not possible within 20 ms, an error is reported back.
For a clearly organized program code, it is advisable to manage the send and receive data in a
structure. The structure can then be mapped onto the byte array with the user data via “casting”.
struct MyCanMsg {
uint8_t ui8Cmd;
uint16_t ui16Object;
uint8_t ui8Si;
int32_t i32Value;
} __attribute__((packed));
psMsg->ui8Cmd = 0x23;
…
CANopen can be advantageous in respect to the application as well. In addition to the possibility
of reading and writing the I/Os of the system via SDO access, dynamically configurable transmit
and receive PDOs (TPDO, RPDO) are also integrated. The PDOs can be configured via an
external tool (e.g., the CANopen DeviceExplorer from Emtas) or by directly setting the
configuration I/Os.
Note:
For configuring external CANopen devices, a so-called EDS file is required. This can be created
via VE_CONFIG. For this purpose, the menu item
Tools -> Development -> Export CANopen electronic data sheet (EDS) file...
has to be called.
Sync Event timer Compatibilit Inhibit time Trans- COB-ID used by PDO
coun- (ms) y entry (1/10 ms) missio
ter n type
Transmission type:
Indicates whether the message is to be transferred cyclically or in relation to the SYNC signal.
Examples:
255 -> The timing of the “Event Timer” entry is valid
1 -> Send the TPDO each time that a SYNC telegram is received.
10 -> Send the TPDO at every 10th SYNC signal.
Inhibit time:
Minimum time between two PDO events.
Compatibility entry:
Not used; prescribed in the standard only for reasons of compatibility.
Event timer:
The transmission interval of the transmit PDO in milliseconds
Sync counter:
Number of SYNC events until the TPDO is sent.
Example:
Entry Value
Object number (SDO number) Subindex Number of bits of the data from the SDO object
Important:
A maximum of 8 I/Os with a total length of 64 bits can be parameterized for each PDO.
If, for example, two float variables or integer32’s (bit length 32) are used, the PDO will
already be completely occupied.
Example:
0x2000 + F E D C B A 9 8 7 6 5 4 3 2 1 0
SDO index
VE I/O-ID Number + 1
Note:
The integrated I/O number calculator in VE_CONFIG is a great help for finding the correct ID.
3.5.2.3. Example VE module for implementing the CAN matrix using the
CANopen protocol
The VE module “CANmatrix” implements the ARADEX CAN matrix using the CANopen protocol.
A great advantage of this method is that the data to be transmitted can be easily changed or
expanded compared with the Can_Matrix module.
Note:
In the VECTOSTUDIO welcome screen, under
The CCANmatrix class is the main class of the application and is also responsible for sending the
unit-specific CAN messages. In addition, the drive objects of the CCANmatrixMessage class are
instantiated here. These manage the reception of the control data and transmit the drive-specific
status messages.
To keep the bus load low, the I/Os are scaled and optimally mapped to the CAN messages.
This is done via additional I/O variables that are created by the module.
The file CANmatrixDefinitions.h contains the description of the control word as a structure
declaration
union CANopen_Controla
{
struct
{
//Control Byte 0
struct
{
uint8_t Enable : 1; ///< Enable Drive
uint8_t ControlMode : 3; ///< 0=disabled; 1=speed;
/// 2=torque; 3=current;
/// 4=f/U 7=DCDC;
uint8_t DigiOut : 4; ///< digi out 0..3
//Control Byte1
struct
{
uint8_t SendId : 1; ///< request sending VP_INFO_DEVICE
uint8_t ResetErrors : 1;
uint8_t ExtendedMode: 1;
uint8_t ReservedB1 : 5;
} __attribute__ ((__packed__)) m_sControl_Byte1;
union CANopen_Controlb
{
struct
{
/// Control Byte 4+5
int16_t SetPoint2; ///< setpoint for limp mode /../ current q /
/// output_voltage
CCANmatrixMessage::UpdateControlMode(
CANopen_Controla& sControla,
CANopen_Controlb& sControlb)
with the corresponding I/O values and are assigned to the I/Os CANmatrix_Controla and
CANmatrix_Controlb.
These I/Os can be mapped on a PDO that is automatically sent by the CANopen stack of the VE
device. This is done in the function CCANmatrixMessage::DefineReceivePDOs().
CCANmatrixMessage::DefineReceivePDOs()
{
if (m_i_CANmatrix_DisableDrive2 && uiGetDriveNumber()== 1)
{
return;
}
m_poCANopenHelpers->bSetPdoCfg(
(uiGetDriveNumber()== 0 ?
&System_CanBus_CanOpen_PdoCfg_Obj1400 :
&System_CanBus_CanOpen_PdoCfg_Obj1404),
m_poCANopenHelpers->ui32GetIdentifier(eDataId_VP_Control,
uiGetDriveNumber()),
0, 0, 0, 0 //< not used for RPDOs
);
m_poCANopenHelpers->bSetPdoMappingParameter(
(uiGetDriveNumber()== 0 ?
&System_CanBus_CanOpen_PdoCfg_Obj1600 :
&System_CanBus_CanOpen_PdoCfg_Obj1604),
&m_sIos.CANmatrix_Controla, 0);
m_poCANopenHelpers->bSetPdoMappingParameter(
(uiGetDriveNumber()== 0 ?
&System_CanBus_CanOpen_PdoCfg_Obj1600 :
&System_CanBus_CanOpen_PdoCfg_Obj1604),
&m_sIos.CANmatrix_Controlb, 1);
}
bool CCANopenHelpers::bSetPdoMappingParameter(
CIoDataArrayReference<uint32_t>* pioArray,
CIo* pIo,
uint32_t ui32EntryNumber)
determines to which SDO subindex entry the mapping parameter is to be written (0 ->
subindex1, …, 7 -> subindex 8).
If CAN messages for drive 2 are not needed, they can be deactivated by setting the parameter
CANmatrix_DisableDrive2.
Can_bSetFilterIdOnly
(m_ui32CanOpenOwnerId,
0x7E5, false, false,
1); // Receive
LSS Master ID 0x7E5 -
HW CAN FIFO1
CVeIoExtensionCardInterface::E_CAN_BAUD_RATE eGetBaudrate(uint32_t
uiBaudrate);
m_poExtCardInterface->CAN_Init(eGetBaudrate(m_sIos.CanMatrix_BaudRate));
The function is now the responsibility of the VE kernel. Do not forget to remove the
corresponding I/Os from the file ios.h.
Instead of this, an ID must be obtained for receiving messages and setting filters:
m_uiCanOwnerId = CVeCoreInterface::poGetInterface()
->poGetVeIoExtensionCardInterface()->CAN_uiGetOwnerId(
VE_VID_ARADEX_VeTechnologyModules, VE_MID_TechnologyModule_CanMatrix);
m_poExtCardInterface->CAN_bSendMessage(&CanTxMessage);
becomes
m_poExtCardInterface->CAN_bSendCanMsg(&CanTxMessage,
CVeIoExtensionCardInterface::eCanPrioPDO);
Instead of eCanPrioPDO, you can also use eCanPrioSDO. For SDO messages, the internal buffer
is larger. However, PDO messages have priority for sending.
The enclosing while{} loop should be eliminated. Firstly, the kernel now contains an output
buffer that is independent of the CAN controller, and secondly, this loop would otherwise slow
down the VE operating system as well. It is better to check whether a message has been sent, and
if this is not possible, to try sending it again in the next cycle.
m_poExtCardInterface->CAN_bGetMessage(&CanRxMessage,0x110);
becomes
m_poExtCardInterface->CAN_bGetNewCanMsg(m_uiCanOwnerId, &CanRxMessage,
0x110);
CVeIoExtensionCardInterface::CAN_FILTER CanFilter;
CanFilter.uiStdId = 0x100;
CanFilter.uiExtId = 0;
CanFilter.bIDE = false;
CanFilter.bRTR = false;
m_poExtCardInterface->CAN_SetIdFilter(1, &CanFilter, true);
becomes
m_poExtCardInterface->CAN_bSetFilterIdOnly(0x100);
Note:
The filters may only be set once, or they must be deleted via CAN_ResetFilters(uint32_t
uiOwnerId) before being reset. Without this deletion, the filter would be entered multiple times
and thus waste valuable hardware resources.
ATTENTION:
The member variables
uint32_t m_uiCanOwnerId
bool m_bUseExtendedIdentifier
uint32_t m_ui32CanID
may only be declared in the basic class CCan_Matrix_Base() and must be removed from the
message classes. If this is forgotten, the message could be transmitted with the identifier 0x0, for
example.
The following data structures should be created for accessing the interface:
m_uart_config.eParityBit =
CVeIoExtensionCardInterface::EParityBit::Parity_No ;//no parity
m_uart_config.eStopBits =
CVeIoExtensionCardInterface::EStopBits::StopBits_1;//1 stop bit
m_uart_config.uiBaudrate = 115200;
m_uartExtiface = CVeCoreInterface::poGetInterface()-
>poGetVeIoExtensionCardInterface();
m_uartExtiface -> UART_Init(m_uart_config);
Before the receipt, it first has to be checked whether new data is present. If new data is present, it
is copied to a buffer:
enum { MAX_RX_DATA_SIZE = 32 };
ui8Buffer[MAX_RX_DATA_SIZE];
ui8RxCounter = 0;
while(m_uartExtiface->UART_bDataReceived())
{
m_uartExtiface->UART_bReceiveByte(&ui8Buffer[ui8RxCounter++]);
if (ui8RxCounter >= MAX_RX_DATA_SIZE)
{
break;
}
}
Since this example already has a high complexity, the example “P8Move” in source code should
also be considered parallel to this chapter. This can be installed in the VECTOSTUDIO welcome
screen – Examples category – under “Examples from the VE programmer's manual”. Only
important aspects of the program are explained in the following.
The wizard is used to create the project with the name P8Move.
The header files for the setpoint generator (Move.h) and the PID filter (FilterPid.h) must be added
to the application framework.
#include <libVePlc/FilterPid.h>
#include <libVePlc/Move.h>
The setpoint generator and the control circuit object are defined as member variables as follows:
NMove::CMoveP8 m_oMove;
NFilter::CFilterPid m_oControlPos;
The application framework is configured next. We select the following options (deselected options
are not listed in the example):
Our example is to implement the function for drive 1. Since we are performing calculations for
the control circuit of the drive, it is important to call these in the OnUpdateControlMode()
callback function. This is the only way to make sure that the new setpoints are processed by the
current controller in the same cycle.
The initialization of required I/Os, which has to take place in the bInitIos() function, will not
be discussed here in further detail.
Since the setpoint generator and the control circuit filter depend on the cycle time, we initialize
them in the OnPreStart() callback function. This callback is triggered by the VE kernel once
before the block cycle starts.
void CP8Move::OnPreStart()
{
m_oControlPos.Reset(0.0);
m_oMove.Reset();
SetFilterParameters();
}
void CP8Move::SetFilterParameters()
{
m_fCycleTime = tMax<float>(m_io_fNominalCycleTime.GetValue(),
FLT_MIN);
m_oControlPos.SetCycleTime(m_fCycleTime);
m_oControlPos.SetCoefficients(
m_sIos.PosCtrl_Drv_Kp,
m_sIos.PosCtrl_Drv_Tn,
m_sIos.PosCtrl_Drv_Tv);
m_oMove.SetCycleTime(m_fCycleTime);
}
In addition, our objects have to be initialized and the control circuit parameters must be set. To
ensure that the cycle time and the control parameters are also copied when changes occur during
the running time, we use callback I/Os and the VE callback function. This makes sure that the
event-controlled transfer of information is ensured over the changed cycle time.
P8Move_ios.h:
IO_FLOAT_CB(PosCtrl_Drv_Kp, bCallback_SetPidParams , 4, "", "%.3f"
, 0 , -FLT_MAX , FLT_MAX , 0, 1 , IO_IS_INPUT | IO_IS_CONFIG,
"Proportional factor");
IO_FLOAT_CB(PosCtrl_Drv_Tn, bCallback_SetPidParams , 5, "", "%.3f"
, 0 , -FLT_MAX , FLT_MAX , 0, 1 , IO_IS_INPUT | IO_IS_CONFIG,
"Integral time");
IO_FLOAT_CB(PosCtrl_Drv_Tv, bCallback_SetPidParams , 6, "", "%.3f"
, 0 , -FLT_MAX , FLT_MAX , 0, 1 , IO_IS_INPUT | IO_IS_CONFIG,
"Differential time");
P8Move.cpp
/*static*/ bool CP8Move::bCallback_SetPidParams(float* pfValue, CIoFloat*
pIo, void* pThis)
{
pIo->SetValueInternal(*pfValue);
THIS->poGetControl()->SetCoefficients(
THIS->m_sIos.PosCtrl_Drv_Kp,
THIS->m_sIos.PosCtrl_Drv_Tn,
THIS->m_sIos.PosCtrl_Drv_Tv);
return true;
}
Note:
The THIS macro is used to access member variables of our VE module class from the static
function. It is defined by the wizard as reinterpret_cast<CP8Move*>(pThis)
The position setpoints and the new current setpoint for the output stage are finally calculated in
the OnUpdateControlMode handler. In most cases, it is a good idea to check the set control
mode of the device. This prevents the position control of our VE module from being already
activated during the commutation, for example.
The sequence logic of the program (e.g., start and stop of the movement command) is
implemented in the OnUpdateMain() callback function. This ensures that the control algorithms
are processed as quickly as possible and the time period between the reading of the position
encoder values and the output of a new current setpoint is as short as possible. This also decreases
the idle time of the control path, which leads to a higher control accuracy.
void CP8Move::OnUpdateMain()
{
// start command and motor stands still
if (m_sIos.PosCtrl_Position_MoveRel &&
!m_sIos.PosCtrl_Position_IsMoving
{
if (m_io_Drive_ControlMaster_Act_CtrlMode !=
Drive_ControlMaster_Act_CtrlMode::
EDrive_ControlMaster_Act_CtrlMode_Current)
{
CVeCoreInterface::poGetInterface()->
PostError(&m_sIos.PosCtrl_Drv_Supervision_Error,
EPosCtrl_Drv_Supervision_Error::ControlModeMismatch);
}
else
{
// Optional:
// Reset move generator to minimize floating point
// rounding effects for longer runtime
m_oMove.Reset();
m_oMove.SetCurrentPosition(m_sIos.PosCtrl_Position_NomPos);
m_oMove.Update();
// configure the setpoint generator
m_oMove.SetMaxJerk ( 100000.0);
m_oMove.SetMaxAcceleration ( m_sIos.PosCtrl_Position_MaxAcc);
m_oMove.SetMaxSpeed ( m_sIos.PosCtrl_Position_MaxSpeed);
// start movement
m_oMove.MoveRelative( m_sIos.PosCtrl_Position_SetPos, 1.0 );
m_sIos.PosCtrl_Position_IsMoving = true;
}
}
else if (true == m_sIos.PosCtrl_Position_IsMoving)
{
//the motor is in moving state
if ( !m_sIos.PosCtrl_Position_MoveRel
&& !m_oMove.bIsDecelerating()
&& m_oMove.bIsMoving())
{
// motor is moving but not decelerating -> stop it
m_oMove.CancelMovement();
}
if (!m_oMove.bIsMoving())// end position reached, clear flag
{
m_sIos.PosCtrl_Position_IsMoving = false;
m_sIos.PosCtrl_Position_MoveRel = false;
}
}
}
Finally, the setpoint generator and the control circuit must be reset when the control is switched
off.
void CP8Move::OnPsDisabled()
{
ControlOff();
}
Within this function, it is possible to manipulate the Q and D current setpoints. In our example, a
constant D current is to be output. This example is only for demonstration purposes and is not
relevant for practical application.
#define APP_IS_DRIVE_MODULE 1
#define APP_DRIVE_NUMBER USE_DRIVE_0
#define APP_USE_USER_MOTOR_MODEL_CB 1
The implementation of the motor model could look like the following:
The executable example MotorModel can be installed in VECTOSTUDIO via the welcome screen
under “Examples from the VE programmer's manual”.
class CCreateIoCallbackHandler;
class CInitIoCallbackHandler;
class CInitModuleCallbackHandler;
class CCreateInternalCallbackHandler;
class CLoadDefaultValuesCallbackHandler;
class CResetErrorsCallbackHandler;
class CPreStartCallbackHandler;
class CPostCriticalCallbackHandler;
class CPostCtrlCycleTimeChangedCallbackHandler;
class CPsEnabledCallbackHandler;
class CPsDisabledCallbackHandler;
class CUpdateControlModeCallbackHandler;
class CPostUpdateControlModeCallbackHandler;
class CUpdateNonRtThreadCallbackHandler;
class CUpdateHwInputCallbackHandler;
class CUpdateControlOutputCallbackHandler;
class CUpdateMainCallbackHandler;
class CUpdateHwOutputCallbackHandler;
class CLVSupplyReadyOkCallbackHandler;
class CLVSupplyReadyFailCallbackHandler;
class CUpdateRtComTaskCallbackHandler;
class CReadAbsPosCallbackHandler;
class CCoreTaskUpdateCallbackHandler;
class CUpdateUserMotorModelCallbackHandler;
class CCreateIoCallbackHandler;
class CInitIoCallbackHandler;
class CInitModuleCallbackHandler;
class CCreateInternalCallbackHandler;
class CLoadDefaultValuesCallbackHandler;
class CPreStartCallbackHandler;
• CreateInternalCallbackHandler
This is the first callback function that is called by the system. The call takes place directly after
the FPGA of the device is initialized.
Registration of callback handler: public CCreateInternalCallbackHandler
Declaration: virtual bool OnCreateInternal() override;
• CreateIoCallbackHandler
This is a special callback implementation. CreateIo() is used directly by the VE system, and you
must not use it in your own software modules.
• InitIoCallbackHandler
The InitIo callback is used to initialize present system I/Os (see description in chapter 2.2.4.3).
The call takes place after the system I/Os have been created via CreateIo() (I/Os from*ios.h)
and the firmware default values have been assigned to the I/Os.
Registration of callback handler: public CInitIoCallbackHandler
Declaration: virtual bool bInitIos() override;
Special feature: This callback function expects a Boolean return value. If false is output, the VE
system starts in error mode.
• InitModuleCallbackHandler
This callback handler is called after all I/Os have been initialized (in other words, after the
bInitIos() callback).
A return value is expected for this function as well. If false is output, the VE system goes into
error mode.
• LoadDefaultValuesCallbackHandler
This callback handler is called after the default values have been read from the internal
memory and written to the I/Os. The call is between the CreateIo() and bInitIos()
callback.
Registration of callback handler: public CLoadDefaultValuesCallbackHandler
Declaration: virtual void OnLoadDefaultValues() override;
• PreStartCallbackHandler
This handler is called directly before the cyclic process is started. Final initializations, for
example, can be performed here before the cyclic task starts.
Registration of callback handler: public CPreStartCallbackHandler
Declaration: virtual void OnPreStart() override;
class CResetErrorsCallbackHandler;
class CPostCriticalCallbackHandler;
class CPostCtrlCycleTimeChangedCallbackHandler;
class CPsEnabledCallbackHandler;
class CPsDisabledCallbackHandler;
class CLVSupplyReadyOkCallbackHandler;
class CLVSupplyReadyFailCallbackHandler;
class CReadAbsPosCallbackHandler;
class CUpdateUserMotorModelCallbackHandler ;
• CResetErrorsCallbackHandler
This callback handler is called as soon as the Information_ResetErrors I/O is set. The callback
function must be used to acknowledge any error states of the VE module.
Registration of callback handler: public CResetErrorsCallbackHandler
Declaration: virtual void OnResetErrors() override;
• CPostCriticalCallbackHandler
This callback handler is called as soon as a critical error is triggered. Critical errors are errors
that cause the output stage to switch off immediately.
Registration of callback handler: public CPostCriticalCallbackHandler
Declaration: virtual void OnPostCritical() override;
• CPostCtrlCycleTimeChangedCallbackHandler
This callback function is called after the cycle time is changed. It can be used to reconfigure
filters (low-pass, high-pass ...), for example.
Registration of callback handler: public
CPostCtrlCycleTimeChangedCallbackHandler
Declaration: virtual void OnPostCtrlCycleTimeChanged
(SPostCtrlCycleTimeChangedParams* psParams)
override;
• CPsEnabledCallbackHandler
This callback is called once when the enable of the hardware output stage is issued. In this
case, the hardware enable and the software enable are set.
Registration of callback handler: public CPsEnabledCallbackHandler
Declaration: virtual void OnPsEnabled() override;
• CPsDisabledCallbackHandler
This handler is triggered when the hardware output stage is switched off.
Registration of callback handler: public CPsDisabledCallbackHandler
Declaration: virtual void OnPsDisabled() override;
• CLVSupplyReadyOkCallbackHandler
This callback handler is called as soon as the low-voltage supply of the device is securely
applied. If it should fail in the meantime, the VE system will report when the voltage is stable
again.
Registration of callback handler: public CLVSupplyReadyOkCallbackHandler
Declaration: virtual void OnLVSupplyReadyOk() override;
• CLVSupplyReadyFailCallbackHandler
This callback function is called when the low-voltage supply falls below a defined value.
Registration of callback handler: public CLVSupplyReadyFailCallbackHandler
Declaration: virtual void OnLVSupplyReadyFail() override;
CReadAbsPosCallbackHandler
The callback function is called when the encoder has read a new absolute value. This allows a
setpoint generator to adjust its offset, for example.
Registration of callback handler: public CReadAbsPosCallbackHandler
Declaration: virtual void OnReadAbsPos() override;
CUpdateUserMotorModelCallbackHandler
This callback function is called during the calculation of the motor model. It is for calculating
application-specific motor models.
Registration of callback handler: public CUpdateUserMotorModel
Declaration: virtual void
OnUpdateUserMotorModel(SMotorModel* psModel)
override;
• CUpdateControlModeCallbackHandler
This function is called before the control circuit is calculated. You can implement your own
control circuits here.
Registration of callback handler: public CUpdateControlModeCallbackHandler
Declaration: virtual void OnUpdateControlMode(
SUpdateControlModeParams* psParams) override;
• CPostUpdateControlModeCallbackHandler
After the control circuit has been successfully calculated, this callback function is called. This
makes it possible to manipulate the output of the control circuit at a later time.
Registration of callback handler: public CPostUpdateControlModeCallbackHandler
Declaration: virtual void OnPostUpdateControlMode(
SPostUpdateControlModeParams* psParams)
override;
• CUpdateNonRtThreadCallbackHandler
This callback function is called from the low-priority non-real-time component of the VE
kernel. It is suitable for lengthy, time-uncritical operations.
Registration of callback handler: public CUpdateNonRtThreadCallbackHandler
Declaration: virtual void OnUpdateNonRtThread() override;
• CUpdateHwInputCallbackHandler
This callback is called after the hardware inputs have been read.
Registration of callback handler: public CUpdateHwInputCallbackHandler
Declaration: virtual void OnUpdateHwInput() override;
• CUpdateControlOutputCallbackHandler
This callback function is called before the new current setpoint is transferred to the hardware.
Registration of callback handler: public CUpdateControlOutputCallbackHandler
Declaration: virtual void OnUpdateControlOutput()
override;
• CUpdateMainCallbackHandler
This callback function is intended for real-time-capable program components. A large part of
the application-specific VE module code is usually implemented here.
• CUpdateHwOutputCallbackHandler
This callback function is called as soon as the hardware outputs are written. This allows final
manipulations at the outputs.
Exception: The current setpoint has already been written to the hardware and cannot be
changed there anymore.
Registration of callback handler: public CUpdateHwOutputCallbackHandler
Declaration: virtual void OnUpdateHwOutput() override;
• CUpdateRtComTaskCallbackHandler
This callback function is called by the VE communication task. It is intended for handling the
application-specific process communication of the device. This function can only be
interrupted by the OnUpdateMain() callback; it has a higher priority than the other VE tasks,
however.
Registration of callback handler: public CUpdateRtComTaskCallbackHandler
Declaration: virtual void OnUpdateRtComTask() override;
• CCoreTaskUpdateCallbackHandler
This callback has the highest priority in the VE kernel. It is called in a 250 µs cycle by default
and can even interrupt the main task of the VE system (control). This function is only allowed
to be used for special applications. A minimum processing time must be observed, since the
drive control or the watchdog monitoring of the VE system could be disturbed.
Registration of callback handler: public CCoreTaskUpdateCallbackHandler
Declaration: virtual void OnCoreTaskUpdate() override;
A VE unit module is created via the “Project->New” function in VECTOSTUDIO using the
ARADEX wizard.
#define APP_IS_DRIVE_MODULE 0
must be set in the *.h file as a configuration option in the application framework.
If the ARADEX wizard is used to create a module, the following must be selected in the
configuration options of the VE module to create a VE drive module:
#define APP_IS_DRIVE_MODULE 1
#define APP_DRIVE_NUMBER USE_DRIVE_0
In the example, the VE module is created for axis 1. If the VE module is to address axis 2, use the
following option:
For a VE module for axis 1 and 2 at the same time, the option
is used.
Note:
When I/Os are created in the file *_ios.h, the I/O attribute IO_IS_UNIT is not set.
All I/Os that are declared in the *_ios.h file are created separately for each drive. The I/O numbers
then have a different instance ID.
The different callback functions are used independently of whether the VE module is a drive or a
unit module.
This is illustrated using the OnResetErrors() callback function as an example. There are two
callback functions than can be used:
The behavior of the callback function changes depending on whether the function is used in a
unit or a drive module.
In the case of a global reset error via the Information_ResetErrors I/O, the function is called for
each axis/instance. The call via the axis-specific reset error command (Drive_State_ResetError)
takes place for the callback function of the respective axis.
void CTest::OnResetErrors()
{
m_sIos.Counter++;
}
In the case of a global reset via the Information_ResetErrors I/O, the OnResetErrors() function is
called twice. This function and OnResetErrors(uint32_t uiDriveNo) are also called twice,
once for each axis. The uiDriveNo parameter contains the value 0 at the first call and the value 1
at the second call.
When an error is reset via the Drive_State_ResetError I/O, the OnResetErrors() callback function is
called once and the axis-specific OnResetErrors(uint32_t uiDriveNo) function is also
called once. The uiDriveNo variable contains the value of the axis for which the ResetError
command is carried out.
void CTest::OnResetErrors()
{
m_sIos.Counter2++;
}
The following explanations for this example are to impart the basic knowledge necessary to
develop multi-axis-capable VE modules.
The configuration options in the header file of the project must be adjusted as follows:
#define APP_IS_DRIVE_MODULE 1
#define APP_DRIVE_NUMBER USE_DRIVE_0 | USE_DRIVE_1
This means that a drive module has to be created that is called for axes 1 and 2. The definition of
USE_DRIVE_0|USE_DRIVE_1 causes the module-specific I/Os from the ios.h file to be created
separately for each drive instance.
If I/Os of the device are to be referenced, the desired I/O must be initialized for each axis
instance. For this purpose, the I/O references are declared as fields across the total number of
available axes.
CIoBooleanReference
m_io_Drive_ControlMaster_Act_IsEnabled[MAX_DRIVES_COUNT];
CIoIntegerReference m_io_FPGA_CurCtrl_CtrlOutD [MAX_DRIVES_COUNT];
CIoIntegerReference m_io_FPGA_CurCtrl_CtrlOutQ[MAX_DRIVES_COUNT];
The definition MAX_DRIVES_COUNT is provided by VeCoreInterface and contains the total number
of axes supported by the firmware.
The initialization of the I/Os in the bInitIos() function must be done across the entire
reference variable field.
The FOREACH_DRIVE is defined in VeCoreInterface as a loop via the counting variable uiDrive,
which counts from 0 to MAX_DRIVES_COUNT-1.
Note:
The FOREACH_AVAILABLE_DRIVE macro, which is also available, only counts up to the number
of axes actually present that are determined by the device.
The access to the module I/Os that are defined in the ios.h file takes place transparently. Here the
VE framework automatically selects the corresponding I/O instance.
For reference I/Os, on the other hand, the instance of the axis must be determined using the
uiGetDriveNumber() function. The I/O belonging to the axis is then accessed by accessing the
corresponding element of the reference I/O field.
if(m_io_Drive_ControlMaster_Act_IsEnabled[uiDrive])
{
fControlOutD = static_cast<float>(m_io_FPGA_CurCtrl_CtrlOutD[uiDrive])
/ 5.12; //< scale FPGA integer I/O
fControlOutQ = static_cast<float>(m_io_FPGA_CurCtrl_CtrlOutQ[uiDrive])
/ 5.12;
}
3.10.I/Os
The following subchapters describe the I/O types used in VE and their parameters. They also
explain how the I/Os of a VE module can be initialized from a second VE module.
3.10.1.I/O types
3.10.1.1. INT
In the VE system, the data type INT always has 32 bits. This data type thus has a value range of -
2147483648 (INT32_MIN) … 2147483647 (INT32_MAX).
Parameter Description
3.10.1.2. UINT
Variables of the type IO_UINT are defined identically as variables of the type IO_INT. When
entering the limits (min, max), ensure that they stay within the valid range of the data type
uint32_t.
3.10.1.3. FLOAT
The description of the parameters can also be taken from the data type IO_INT. The limits (min,
max) must be selected so that they are covered by the data type float (FLT_MIN … FLT_MAX).
A floating point number according to the IEEE standard is created with single precision (4 byte
size).
3.10.1.4. ARRAY
The data type Array is created with the macro IO_ARRAY_NEW.
Parameter Description
3.10.1.5. FIELD
In addition to the basic data types that have been described so far, the extension FIELD also exists
in two variants.
BEGIN_FIELD(name)
ELEMENT (value, name, description)
RANGE (start, stop, name, description)
END_FIELD(name, number, unit, printformat, default, min, max, exponent,
scale, flags, description)
Parameter Description
3.10.2.I/O attributes
I/Os must be given corresponding attributes in the definition. These define access rights and
specify special characteristics.
#define _INCLUDE_IO_NUMBERS_
#undef MODULE_ID
#undef VENDOR_ID
#include
"../../../MyOtherVeModule/Source/MyOtherVeModule/MyOtherVeModule_ios.h"
bInitSuccess &= Intf->bInitIo(&m_io_MyOtherVeModuleIO,
MyOtherVeModuleIO_NUMBER);
The initialization of I/Os from other VE modules is thus no longer different from the initialization
of the firmware I/Os. This procedure is also recommended by the wizard (commented in the VE
module template).
VID Vendor ID
MID Module ID
Example:
IO_NUMBER(
VE_VID_ARADEX_VeTechnologyModules,
VE_MID_TechnologyModule_CanMatrix,
0,
47);
Note:
The integrated I/O number calculator in VE_CONFIG is a great help for finding the correct ID.
When a VE module is compiled, a *.module file is created. This is found in the project directory
under
Projectname\Export\bin.
The desired module file must be integrated in the configuration folder of the workspace. The
corresponding node name in the Project Explorer of VECTOSTUDIO is:
configuration/application/firmware
If the binary file has been added to the project, it can be added as a module to the application
configuration in the next step. This step has already been described in detail in chapter 2.2.1.3.
From this time on, the external VE module is taken into account when the software is
downloaded or an installation package is created (see also chapter 4.2).
The target file Modules.vemod is created. The location of the file can be determined as follows:
subdirectory.
The installation package can now be copied via VE_CONFIG for subsequent downloading.
Note:
If this step does not function, check whether a v8configuration.xml file is in the
configuration/application/configuration node of the workspace. VE and V8 can be managed
together. VECTOSTUDIO compiles V8 projects with priority when there is no online connection
to a VE device and the file v8configuration.xml is present.
For preparation, the appropriate parameter set (*.vecfg file) must be saved in the workspace. This
is done in the configuration/application/configuration node. If this node is not present, it must be
created. In the example, the file HelloWorld.vecfg has been added to the project.
Figure 6 - The parameter set added to the VE project for creating a firmware package
The parameter set that we have selected must now be added to the VE module configuration (see
also chapter 2.2.1.3). This is done by opening the file AppConfiguration.appconfig in the
configuration editor of VECTOSTUDIO. When the Firmware node is selected, the attribute “VE
configuration file” appears in the characteristics window. The name of the vecfg file (in the
example, HelloWorld.vecfg) is entered here.
After the configuration has been saved, the installation package can be created via the context
menu of the device node “Create Application Runtime file…”.
The firmware package can be loaded onto the device in the VE_CONFIG program at a later time.
To do this, the
5. VE internals
The following chapter contains details on implementing particular VE functions. It can be
consulted for a deeper understanding of the functionality. This detailed knowledge is not
necessary for VE module development.
The registration with the callback handler takes place by deriving the corresponding callback
method of the basic class of the respective callback handler.
• InitIoCallbackHandler
• InitModuleCallbackHandler
• UpdateMainCallbackHandler
The class CIoInit therefore has to be derived from these three callback handlers:
class CIoInit
: public CVeModuleInterface, //Base class for VE modules
public CInitIoCallbackHandler, //Callback for I/O initialization
public CInitModuleCallbackHandler,//Callback for the InitModule
//function
public CUpdateMainCallbackHandler //Callback for the cyclic
//UpdateMain fct.
After successful registration with the callback handlers, the entry function still has to be set up in
its own source code. In Example 1, three callback handlers have been registered. The following
three methods then have to be registered in the class definition (header file):
Note:
The override addition increases security during programming. This characterizes functions that
are derived from a basic class. If there is no identical function in the basic class, an error would
result when the software module is compiled. This quickly identifies write errors in the names or
parameters of derived functions that would otherwise be difficult to recognize.
The functions naturally also have to be implemented in the *.cpp file; in Example 1 this could
look like the following:
bool CIoInit::bInitIos()
{
bool bInitSuccess = true;
return bInitSuccess;
}
bool CIoInit::bInitModule()
{
bool bInitSuccess = true;
return bInitSuccess;
}
void CIoInit::OnUpdateMain()
{
}
If a fourth callback is to be used in addition to these three callbacks, then this list can be easily
expanded. In the case shown below, the LoadDefaultValues callback handler has been added to
the existing three callback handlers as well.
class CIoInit
: public CVeModuleInterface,
public CInitIoCallbackHandler,
public CInitModuleCallbackHandler,
public CUpdateMainCallbackHandler,
public CLoadDefaultValuesCallbackHandler
Header- file:
*.cpp file:
bool CIoInit::bInitIos()
{
bool bInitSuccess = true;
return bInitSuccess;
}
bool CIoInit::bInitModule()
{
bool bInitSuccess = true;
return bInitSuccess;
}
void CIoInit::OnUpdateMain() {}
void CIoInit::OnLoadDefaultValues() {}
The class definition for a VE unit module looks like the following:
class CTest
: public CVeModuleInterface,
public CInitIoCallbackHandler,
public CInitModuleCallbackHandler,
public CUpdateMainCallbackHandler
class CTest
: public CVeDriveModuleInterface,
public CInitIoCallbackHandler,
public CInitModuleCallbackHandler,
public CUpdateMainCallbackHandler
The macro CREATE_CONTROL_MODULE for VE unit modules must be replaced by the macro
CREATE_CONTROL_MODULE_DRIVE for a VE drive module. The axes for which the VE module will
be called then have to be defined in the second macro.
The following holds true for a VE module that is called for both axes:
For a VE module that is called for axis 1, the following parameter must be set:
CREATE_CONTROL_MODULE_DRIVE(CTest, USE_DRIVE_0);
CREATE_CONTROL_MODULE_DRIVE(CTest, USE_DRIVE_1);
6. Document history
The present document is version 2.1.
2.0 MBartsch Complete revision and expansion of the document. First release version
created.
7. Own notes