industrialNETworXnetx

M T

M T

Hilscher Gesellschaft für Systemautomation mbH

| 04.02.2011 | 07:50 | 2 replies

Guide: How to port the cifX Toolkit

As some problems seems to exist (basically because the included sample is a Windows example) on how to use the cifX Toolkit.

Basics:

There are two different types of devices being handled:

  1. Flash-based devices (like a comX) which have their firmware running out of flash
  2. RAM-based devices (like a cifX) which get their firmware loaded by the driver / toolkit.

 

Here is a short step-by-step guide, what needs to be done:

  • Copy the Source Folder (which contains the whole Toolkit) to your project
  • Implement the OS Abstraction layer (according to the toolkit documentation) in a own / seperate C-file.
    You may take a look at "OSAbstraction\OS_Win32.c" to see how this is done under Windows. You don't need to implement all functions, depending on you use case:

    Options:
    1)
    When not using cifX PCI cards, or any other RAM-based device with the netX directly connected to the PCI bus, you can stub out the functions OS_ReadPCIConfig / OS_WritePCIConfig

    2)
    When not using Interrupts you can stub out the OS_CreateEvent, OS_SetEvent, OS_ResetEvent, OS_DeleteEvent, OS_WaitEvent functions

    3)
    If you don't have a multitasking environment you can stub out the Mutex functions (OS_CreateMutex, OS_WaitMutex, OS_ReleaseMutex, OS_DeleteMutex), as the mutexes are only used to prevent reentrant function calls.
    Note:
    As the Mutexes are expected to work as the toolkit does not know about your O/S you will need to return a value != 0 out of OS_CreateMutex and OS_WaitMutex.
    Attention:
    Doing this in a multitasking environment will result in undefined behaviour as function reentrancy cannot be controlled.

    4)
    If you only have a comX or another netX with flashed firmware you may stub out the file functions (OS_FileOpen, OS_FileRead, OS_FileClose) too, if you don't want to use the automatic update feature of the toolkit, which checks and updates the Firmware during startup.
    Attention: When using RAM-based devices these functions must be implemented.

  • Implement the USER functions in an own / seperate C-file
    You may take a look at "User\TKitUser.c" to see how this is done under Windows.

    Options:
    1)
    If you only have a comX or another netX with flashed firmware you may
    stub out the firmware / bootloader functions (USER_GetFirmwareFileCount, USER_GetFirmwareFile, USER_GetConfigurationFileCount, USER_GetConfigurationFile, USER_GetOSFile, USER_GetBootloaderFile), if you don't want to use the automatic update feature of the
    toolkit, which checks and updates the Firmware during startup.
    Attention: When using RAM-based devices these functions must be implemented.

  • Only needed if any of your devices are using polling mode: Implement a cyclic timer (e.g. 500ms) which calls the function cifXTKitCyclicTimer()
  • Call the Toolkit initialization (cifXTKitInit()) from your driver framework
  • Add all your netX / cifX / comX devices under Toolkit control by:

    1. allocating a DEVICE_INSTANCE structure
    2. Filling in all needed parameters into this structure.
        Note1: You can use the element pvOSDependent to store any non-toolkit parameters for this device.
        Note2: You can override the type of the device by adjusting the element "eDeviceType" if it is not correctly auto-detected by the toolkit.

      COMX Example:

    OS_Memset(ptDevInstance, 0, sizeof(*ptDevInstance));
    ptDevInstance->fPCICard      = 0;
    ptDevInstance->pbDPM         = <Insert pointer to DPM here>;
    ptDevInstance->ulDPMSize     = <Insert accessible size of DPM here>;
    OS_Strncpy(ptDevInstance->szName, "cifX0", sizeof(ptDevInstance->szName));
    ptDevInstance->pvOSDependent = MyDeviceData;

       cifX Example:

    OS_Memset(ptDevInstance, 0, sizeof(*ptDevInstance));
    ptDevInstance->fPCICard      = 1;
    ptDevInstance->pbDPM         = <Insert pointer to DPM here>;
    ptDevInstance->ulDPMSize     = <Insert accessible size of DPM here>;
    OS_Strncpy(ptDevInstance->szName, "cifX0", sizeof(ptDevInstance->szName));
    ptDevInstance->pvOSDependent = MyDeviceData;

    3. Call cifXTKitAddDevice() to add them under Toolkit control

  • On big-endian CPUs:
    You will need to enable big endian support in the toolkit by setting the preprocessor definition "CIFX_TOOLKIT_BIGENDIAN", which instructs the toolkit to convert DPM access endianess.
    Attention: The toolkit will not swap Packet contents or I/O data as it does not know the structured data behind these data areas. So the user has to do the endianess conversion before calling xChannelPutPacket / xChannelIOWrite and after xChannelGetPacket / xChannelIORead calls. Same is valid for system device and some other block access functions (e.g. extended status block).
  • Optional: Use DMA on PCI devices
    Attention: This is only supported if the netX is directly connected to the PCI Bus (e.g. cifX). It does not work with NXPCA-PCI boards (or any other PCI<-->DPM Bridge)

    To use DMA you will need to do the following
     - Insert the preprocessor define "CIFX_TOOLKIT_DMA"
     - pass 8 DMA buffers which need to be aligned on a 256 byte boundary. These buffers must be a multiple of 256 Bytes in size with a maximum size of 63.75kB

    Example:

    ptDevInstance->ulDMABufferCount = 8;
    ptDevInstance->atDmaBuffers[0].ulSize             = 8192;
    ptDevInstance->atDmaBuffers[0].ulPhysicalAddress  = <Insert phys. address here>;
    ptDevInstance->atDmaBuffers[0].pvBuffer           = <Insert virtual / cpu accessible pointer here>;
    ptDevInstance->atDmaBuffers[0].pvUser             = MyDMAData;
    ...
    ptDevInstance->atDmaBuffers[7].ulSize             = 8192;
    ptDevInstance->atDmaBuffers[7].ulPhysicalAddress  = <Insert phys. address here>;
    ptDevInstance->atDmaBuffers[7].pvBuffer           = <Insert virtual / cpu accessible pointer here>;
    ptDevInstance->atDmaBuffers[7].pvUser             = MyDMAData;
  • Now you can use any of the cifX API functions to access your devices

Hope this clears up some misunderstandings a little.

Regards,

MT

chrbuss

chrbuss

| 06.07.2011 | 10:28

Hi MT,

thank you for these instructions on how to port the toolkit.

I have a realtime application (part of a control system) running in kernel mode. This application works as an EtherCAT slave and exchanges data with an EtherCAT master. Currently I have to use the cifX32dll.dll to exchange data with the master, but this dll resides in the user space. Hence I am using the toolkit to write the necessary functions that will work in kernel mode.

Do you have some code that shows how to get a pointer to the DPM? In the toolkit you still rely on the cifx32dll.dll to get the DPM pointer?

Another possibility to solve the user space issue: Is there a possibility to install a (kernel) callback function for channel events without going through the user space dll?

Thank you very much in advance.

Regards, Christian

M T

M T

Hilscher Gesellschaft für Systemautomation mbH

| 07.07.2011 | 07:20

First of all I think I need to clarify some misunderstandings of using the Toolkit. The Windows Sample included with the Toolkit is NOT meant for productional environment and is only included for showing how the toolkit works to write own drivers. Under Windows the Toolkit is already included in the Kernel-Mode Driver "cifxdrv.sys". The dll "cifx32dll.dll" just wraps the interface to this kernel mode driver.

Using the Toolkit in an application by passing the DPM pointer AND having the cifXDrv.Sys active at the same time may cause inpredictable results.

chrbuss wrote:

I have a realtime application (part of a control system) running in kernel mode. This application works as an EtherCAT slave and exchanges data with an EtherCAT master. Currently I have to use the cifX32dll.dll to exchange data with the master, but this dll resides in the user space. Hence I am using the toolkit to write the necessary functions that will work in kernel mode.

As written above this will cause problems as there will be two instances (cifXdrv.sys AND your application) accessing the DPM AND the handshake flags.

chrbuss wrote:

Do you have some code that shows how to get a pointer to the DPM? In the toolkit you still rely on the cifx32dll.dll to get the DPM pointer?

If you want to handle the card yourself you will need to either write a dummy driver to make Windows happy and install that (instead of cifxdrv.sys) which does not do anything with the card, but offers an interface for your application, so you can use the whole toolkit inside your application, or you will need to provide a complete kernel mode driver containing the toolkit which offers a parallel interface to your application in kernel space.

cifXDrv.sys does not offer an internal IOCTL handler, thus it is not possible to do driver<-->driver communication in kernel space.

chrbuss wrote:

Another possibility to solve the user space issue: Is there a possibility to install a (kernel) callback function for channel events without going through the user space dll?

As the driver does not offer an inter-driver-IOCTL handler it is not possible to interface it in kernel mode.

 

Regards,

MT

Login