home Discussion
CODESYS Forge
home
(Discussion)
Forum for home comments
Last updated: 2018-03-03
code Discussion
CODESYS Forge
code
(Discussion)
Forum for code comments
Last updated: 2018-03-03
tickets Discussion
CODESYS Forge
tickets
(Discussion)
Forum for tickets comments
Last updated: 2018-03-16
android Discussion
CODESYS Forge
android
(Discussion)
Forum for android comments
Last updated: 2019-12-25
xml-pac: ./.drone.yml
Bash
bash
(Bash)
kind: pipeline
name: default
workspace:
base: /working/repo
steps:
- name: compile
image: codesys-ide:local
commands:
- codesys gen-package-manifest
- codesys export-libdoc
- codesys compile-library
- codesys build-package
Last updated: 2019-12-17
CODESYS Forge SVN repository
CODESYS Forge
code
(SVN Repository)
Last updated: 2020-08-11
IndexMain
I/O Drivers
doc
(WikiPage)
Driver Documentation Generic I/O Driver SPI Driver I²C Driver Driver FB Database Driver IDs
Last updated: 2018-11-03
SPI
I/O Drivers
doc
(WikiPage)
Preface Device Description Device Identification Connector Driver Info Host Parameter Set Library Function Block Methods SPI Transfer Project Information Summary Properties [[include IndexMain (already included)] Preface This documentation describes the process of creating an own SPI driver for CODESYS, based on the SPI Template, which can be found in the Code Repository. The driver consists of a "Device Description" as well as a CODESYS Library. All essential settings in the Library or the Device Description are repeated in this documentation. For more detailed informations about the Device Descriptions, please check the general I/O driver documentation. Device Description You can use a copy of the Device Description SPI_Template.devdesc.xml as a starting point. You need to adapt the following sections of the device description for your needs. Device Identification The template of the device description can be downloaded with an ordinary SVN client (like Tortoise SVN) or directly from the repository browser, from the Code Repository. Set the Type to 501 for all SPI devices <DeviceDescription> ... <Device> ... <DeviceIdentification> ... <Type>501</Type> ... </DeviceIdentification> ... </Device> ... </DeviceDescription> The ID consists of the "Vendor ID" (0003 for Open Source) and the "Device ID". As the Device ID needs to be unique, you have to register it in the Device Database. <DeviceDescription> ... <Device> ... <DeviceIdentification> ... <Id>0003 0001</Id> ... </DeviceIdentification> ... </Device> ... </DeviceDescription> The version can be freely defined. Just, the format is fix. And you should take care that you never release two different device descriptions with the same Type, ID and Version. As this might produce conflicts in the repositories of other users. <DeviceDescription> ... <Device> ... <DeviceIdentification> ... <Version>1.0.0.0</Version> ... </DeviceIdentification> ... </Device> ... </DeviceDescription> Connector The connector describes the node in the device tree, which the user sees after he added your device. The I/O driver will search for this connector. The moduleType is very important, that the I/O driver can find the corresponding device in the configuration. For SPI drivers, it has to be 500. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.SPI" ...> ... ... </Connector> ... </Device> ... </DeviceDescription> The interface has to be set to "Raspberry.SPI". Note, that currently only the Raspberry Pi is supported. When this limitation is removed, there will be another interface name. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.SPI" ...> ... ... </Connector> ... </Device> ... </DeviceDescription> Driver Info This section specifies some parameters of the driver, and in our case, also which library should be used. The RequiredLib tag specifies exactly which library has to be inserted to your project, when this driver is added to your device tree. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.SPI" ...> ... <DriverInfo needsBusCycle="false"> ... <RequiredLib libname="SPI Template" vendor="Open Source" version="1.0.0.0" identifier="SPI Template"> ... </RequiredLib> ... </Parameter> ... </Connector> ... </Device> ... </DeviceDescription> The FBInstance as well as its sub-tags defines which Function Block out of this library should be called. For an SPI driver all function calls from the template are important. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.SPI" ...> ... <DriverInfo needsBusCycle="false"> ... <RequiredLib libname="SPI Template" vendor="Open Source" version="1.0.0.0" identifier="SPI Template"> ... <FBInstance basename="$(DeviceName)" fbname="SPITemplate"> ... <Initialize methodName="Initialize" /> <CyclicCall methodname="AfterReadInputs" task="#buscycletask" whentocall="afterReadInputs" /> <CyclicCall methodname="BeforeWriteOutputs" task="#buscycletask" whentocall="beforeWriteOutputs" /> ... </FBInstance> ... </RequiredLib> ... </Parameter> ... </Connector> ... </Device> ... </DeviceDescription> Host Parameter Set The host parameter set defines all your configuration parameters, as well as I/O channels. In the current SPI interface, you can use configuration parameters, but no I/O channels. The configuration parameters can be read in the library within the function "Initialize". <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.SPI" ...> ... <HostParameterSet> ... <Parameter ...> ... </Parameter> ... </Connector> ... </Device> ... </DeviceDescription> For more information about the HostParameterSet and datatypes, please check the general I/O driver documentation. Library The template library can be checked out with CODESYS SVN or alternatively with CODESYS SVN Forge. Both can be obtained from the CODESYS Store. As well as the device description, it is placed in the code repository. It is a standard CODESYS Library, which needs the standard information to behave as expected to the user. We describe all bits, which need to be changed in the following documentation. Function Block The function block can be renamed. But make sure, that you change the "FBInstance" parameter in the device description accordingly. It has to be extended from "SPI", which is part of the "Raspberry Pi Peripherals" library. FUNCTION_BLOCK SPITemplate EXTENDS spi VAR_INPUT END_VAR VAR_OUTPUT dwRaw : DWORD; rValue : REAL; END_VAR In this example, the output of this function block is the output of the SPI driver, and the value which will be used by the user in his application. So the value can be used like this in the application: rMyTemperature := SPITemplate.rValue; Methods All methods, which are overloading in your function block, need to call the super method, so that the method of the base SPI function block is still executed. AfterReadInputs can process any inputs from the SPI device and update the output parameters of the FB. So for example "rValue" should be updated in this function. SUPER^.AfterReadInputs(); IF _iState = 10 THEN FOR usiChannel := 0 TO 0 DO aby[0] := 1; aby[1] := 16#80 + SHL(usiChannel AND 7, 4); aby[2] := 0; aby[3] := 0; IF NOT transfer(pabyTxBuffer:=ADR(aby) , pabyRxBuffer:=ADR(aby) , udiLen:=3 , uiDelayus:=0) THEN _iState := 1000; END_IF CASE usiChannel OF 0: dwRaw := aby[3]; dwRaw := SHL(dwRaw,8) OR aby[2]; dwRaw := SHL(dwRaw,8) OR aby[1]; dwRaw := SHL(dwRaw,8) OR aby[0]; rValue := DWORD_TO_REAL(SHR(dwRaw, usiBitWidth)); rValue := rValue * rResolution; END_CASE END_FOR END_IF BeforeWriteOutputs can be used in a similar way to write the outputs to the SPI device. The output is read from the "input" of the function block. Initialize is a special method which can be used to read configuration parameters. When the application is loaded, this function is called, and the corresponding "Connector" (s. Device Description documentation) is passed to it. You can then use IoStandard.ConfigGetParameter() to access the configuration parameters. SUPER^.Initialize(wModuleType, dwInstance, pConnector); pParam := ConfigGetParameter(_pConnector, 1000); IF pParam <> 0 THEN pusiBitWidth := IoStandard.ConfigGetParameterValuePointer(pParam, ADR(udiResult)); usiBitWidth := pusiBitWidth^; END_IF pParam := ConfigGetParameter(_pConnector, 1001); IF pParam <> 0 THEN prResolution := IoStandard.ConfigGetParameterValuePointer(pParam, ADR(udiResult)); rResolution := prResolution^; END_IF SPI Transfer You might have noticed the few lines above: aby[0] := 1; aby[1] := 16#80 + SHL(usiChannel AND 7, 4); aby[2] := 0; aby[3] := 0; IF NOT transfer(pabyTxBuffer:=ADR(aby) , pabyRxBuffer:=ADR(aby) , udiLen:=3 , uiDelayus:=0) THEN _iState := 1000; END_IF In SPI you always have to write out the same number of bytes, which you plan to receive. The method "transfer" is actually doing the transfer on the SPI bus. The addressing code is stolen from the MCP3008 chip. There you have one start bit (in bytes 0), and then a "command", which defines the ADC we want to read. For more informations about the MCP3008, you may check out these pages from Adafruit. As the data is shifted out on the SPI bus, and then received, you can use the same buffer for transmit and receive (like we did in the example above). Project Information In the "Project Information" you have to enter few names and identifiers: Summary As the Company, you can use "Open Source" if it is a plain open source driver (corresponds to the VendorID 0003 of the Device Description). The Title of the library is the name, which the user selects in the library repository when he adds your library manually. The Version can be freely defined. But it usually makes sense to keep this version in sync with the "Device Description" Properties Now, we switch to the more advanced properties of our library. The property DefaultNamespace defines the namespace prefix, which one has to use to access POUs of your library. We recommend, that you use the same as the library name, but w/o spaces. The property Placeholder is important to set. But deviations from the library name are for more advanced use cases. So just enter the same as you entered in Title The rest of the properties can be usually ignored.
Last updated: 2020-01-03
I2C
I/O Drivers
doc
(WikiPage)
Preface Device Description Device Identification Connector Driver Info Host Parameter Set Library Function Block Methods I2C Read / Write Project Information Summary Properties [[include IndexMain (already included)] In Progress!!! Preface This documentation describes the process of creating an own I2C driver for CODESYS, based on the I2C Template, which can be found in the Code Repository. The driver consists of a "Device Description" as well as a CODESYS Library. All essential settings in the Library or the Device Description are repeated in this documentation. For more detailed informations about the Device Descriptions, please check the general I/O driver documentation. Device Description You can use a copy of the Device Description I2C_Template.devdesc.xml as a starting point. You need to adapt the following sections of the device description for your needs. Device Identification The template of the device description can be downloaded with an ordinary SVN client (like Tortoise SVN) or directly from the repository browser, from the Code Repository. Set the Type to 502 for all I2C devices <DeviceDescription> ... <Device> ... <DeviceIdentification> ... <Type>502</Type> ... </DeviceIdentification> ... </Device> ... </DeviceDescription> The ID consists of the "Vendor ID" (0003 for Open Source) and the "Device ID". As the Device ID needs to be unique, you have to register it in the Device Database. <DeviceDescription> ... <Device> ... <DeviceIdentification> ... <Id>0003 0002</Id> ... </DeviceIdentification> ... </Device> ... </DeviceDescription> The version can be freely defined. Just, the format is fix. And you should take care that you never release two different device descriptions with the same Type, ID and Version. As this might produce conflicts in the repositories of other users. <DeviceDescription> ... <Device> ... <DeviceIdentification> ... <Version>1.0.0.0</Version> ... </DeviceIdentification> ... </Device> ... </DeviceDescription> Connector The connector describes the node in the device tree, which the user sees after he added your device. The I/O driver will search for this connector. The moduleType is very important, that the I/O driver can find the corresponding device in the configuration. For I2C drivers, it has to be 500. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.I2C" ...> ... ... </Connector> ... </Device> ... </DeviceDescription> The interface has to be set to "Raspberry.I2C". Note, that currently only the Raspberry Pi is supported. When this limitation is removed, there will be another interface name. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.I2C" ...> ... ... </Connector> ... </Device> ... </DeviceDescription> Driver Info This section specifies some parameters of the driver, and in our case, also which library should be used. The RequiredLib tag specifies exactly which library has to be inserted to your project, when this driver is added to your device tree. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.I2C" ...> ... <DriverInfo needsBusCycle="false"> ... <RequiredLib libname="I2C Template" vendor="Open Source" version="1.0.0.0" identifier="I2C Template"> ... </RequiredLib> ... </Parameter> ... </Connector> ... </Device> ... </DeviceDescription> The FBInstance as well as its sub-tags defines which Function Block out of this library should be called. For an I2C driver all function calls from the template are important. <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.I2C" ...> ... <DriverInfo needsBusCycle="false"> ... <RequiredLib libname="I2C Template" vendor="Open Source" version="1.0.0.0" identifier="I2C Template"> ... <FBInstance basename="$(DeviceName)" fbname="I2CTemplate"> ... <Initialize methodName="Initialize" /> <CyclicCall methodname="AfterReadInputs" task="#buscycletask" whentocall="afterReadInputs" /> <CyclicCall methodname="BeforeWriteOutputs" task="#buscycletask" whentocall="beforeWriteOutputs" /> ... </FBInstance> ... </RequiredLib> ... </Parameter> ... </Connector> ... </Device> ... </DeviceDescription> Host Parameter Set The host parameter set defines all your configuration parameters, as well as I/O channels. In the current I2C interface, you can use configuration parameters, but no I/O channels. The configuration parameters can be read in the library within the function "Initialize". <DeviceDescription> ... <Device> ... <Connector moduleType="500" interface="Raspberry.I2C" ...> ... <HostParameterSet> ... <Parameter ...> ... </Parameter> ... </Connector> ... </Device> ... </DeviceDescription> For more information about the HostParameterSet and datatypes, please check the general I/O driver documentation. Library The template library can be checked out with CODESYS SVN. It can be obtained from the CODESYS Store. As well as the device description, it is placed in the code repository. It is a standard CODESYS Library, which needs the standard information to behave as expected to the user. We describe all bits, which need to be changed in the following documentation. Function Block The function block can be renamed. But make sure, that you change the "FBInstance" parameter in the device description accordingly. It has to be extended from "I2C", which is part of the "Raspberry Pi Peripherals" library. FUNCTION_BLOCK I2CTemplate EXTENDS i2c VAR_INPUT END_VAR VAR_OUTPUT dwRaw : DWORD; rValue : REAL; END_VAR In this example, the output of this function block is the output of the I2C driver, and the value which will be used by the user in his application. So the value can be used like this in the application: rMyTemperature := I2CITemplate.rValue; Methods All methods, which are overloading in your function block, need to call the super method, so that the method of the base I2C function block is still executed. Body The body of the FB should contain a small state machine. It starts with 0 and has to be set to 10 when you finished your stuff. Here is also a good place to define the I2C Address. This is a member of the base FB and needs to be set here. CASE _iState OF 0: IF usiAddress = 0 THEN usiAddress := 16#70; END_IF IF SUPER^.init() THEN _iState := 5; END_IF 5: Timer.pt := T#70MS; _iState := 10; xValid := FALSE; END_CASE AfterReadInputs can process any inputs from the I2C device and update the output parameters of the FB. So for example "rValue" should be updated in this function. SUPER^.AfterReadInputs(); IF _iState = 10 THEN timer(IN:=TRUE); IF timer.Q THEN len := Read(ADR(Buffer), 4); IF len = 4 THEN lrDistance := BYTE_TO_LREAL(Buffer[2])*0.01 + BYTE_TO_LREAL(Buffer[3]) * 2.56; xValid := (lrDistance >= lrMinDistance AND lrDistance <= lrMaxDistance); xNewMeasurement := TRUE; ELSE xValid := FALSE; END_IF Write8(0, 16#51); //new measurement timer(IN:=FALSE); END_IF END_IF BeforeWriteOutputs can be used in a similar way to write the outputs to the I2C device. The output is read from the "input" of the function block. Initialize is a special method which can be used to read configuration parameters. When the application is loaded, this function is called, and the corresponding "Connector" (s. Device Description documentation) is passed to it. You can then use IoStandard.ConfigGetParameter() to access the configuration parameters. SUPER^.Initialize(wModuleType, dwInstance, pConnector); pParam := ConfigGetParameter(_pConnector, 1000); IF pParam <> 0 THEN pusiBitWidth := IoStandard.ConfigGetParameterValuePointer(pParam, ADR(udiResult)); usiBitWidth := pusiBitWidth^; END_IF pParam := ConfigGetParameter(_pConnector, 1001); IF pParam <> 0 THEN prResolution := IoStandard.ConfigGetParameterValuePointer(pParam, ADR(udiResult)); rResolution := prResolution^; END_IF I2C Read / Write You might have noticed the few lines above: len := Read(ADR(Buffer), 4); IF len = 4 THEN lrDistance := BYTE_TO_LREAL(Buffer[2])*0.01 + BYTE_TO_LREAL(Buffer[3]) * 2.56; xValid := (lrDistance >= lrMinDistance AND lrDistance <= lrMaxDistance); xNewMeasurement := TRUE; ELSE xValid := FALSE; END_IF Write8(0, 16#51); //new measurement Project Information In the "Project Information" you have to enter few names and identifiers: Summary As the Company, you can use "Open Source" if it is a plain open source driver (corresponds to the VendorID 0003 of the Device Description). The Title of the library is the name, which the user selects in the library repository when he adds your library manually. The Version can be freely defined. But it usually makes sense to keep this version in sync with the "Device Description" Properties Now, we switch to the more advanced properties of our library. The property DefaultNamespace defines the namespace prefix, which one has to use to access POUs of your library. We recommend, that you use the same as the library name, but w/o spaces. The property Placeholder is important to set. But deviations from the library name are for more advanced use cases. So just enter the same as you entered in Title The rest of the properties can be usually ignored.
Last updated: 2020-03-12
Driver FB
I/O Drivers
doc
(WikiPage)
I/O driver Function Block I/O driver interface Device Description Install the device description Mapping the I/Os Reading / Writing I/Os Adapting the Template Checkout the Template Add the driver Write a Program Configure Login I/O driver library Change the structures Write Driver Code Change Library Details Save Device Description Change the Types Change the Identification Change the Module Type That's it! [[include IndexMain (already included)] I/O driver An I/O driver in the world of CODESYS is a piece of software, that abstracts the access to a piece of hardware, which usually provides input data (like temperatures, switches, ...) or drives outputs (analog, digital, PWM, ...). The way to use those I/Os is usually, to add the modules to the device tree of your CODESYS project, configure them and map the input and output channels to variables i your application. Function Block When start writing an I/O driver in IEC, the best way is to start with a function block. The reason is, that it is very easy to pass the input and output values of your hardware to the inputs and outputs of your FB. Try to keep the interface of the FB as simple as possible, and do all the work, which is necessary to handle the hardware in the main POU of the FB. So if you for example read a value of a sensor through SPI, name the input of the FB accordingly, and code the SPI access inside of your FB. I/O driver interface When you have such an FB, it becomes very straight forward to write an I/O driver frame around that, so that the user can easily add this driver to his project, like he is used to do it with other fieldbusses in CODESYS. Device Description A device description is an XML file, which describes the I/O module, so that the user can add it to the device tree in CODESYS. It mainly consists of configuration parameters and I/O channels. <!-- Configuration parameter --> <Parameter ...> <Attributes channel="none" ... /> ... </Parameter> <!-- Input channel --> <Parameter ...> <Attributes channel="input" ... /> ... </Parameter> <!-- Output Channel --> <Parameter ...> <Attributes channel="output" ... /> ... </Parameter> The purpose of those kinds of parameters is easily explained: Configuration Parameters can be used to configure things at compile time (e.g. baudrate, frequency, ...). Input Channels can be used to map an input (e.g. position od rotary encoder, temperarure, ...) to a variable of the application. Ourput Channels can be uses to map an output (e.g. relais output, PWM, ...)to a variable of the application. When you hit "add device" in CODESYS, you get only a list of devices, which are allowed under the selected device. To let CODESYS know which devices are allowed, we have to define so called connectors with interfaces. <Connector interface="OpenSource:Internal" ...> The algorithm is simple - you have parent and child connectors, each with 1-n interfaces. Each combination of parent and child, where at least one of the interface names matches is valid, and therefore displayed in the "add device" dialog of CODESYS. Install the device description To make your device known to CODESYS, you need to install it to the device repository (Tools -> Device Repository -> install). During development, you will most likely need to install your device descriptions several times for tests. After you installed a new version, it is important to right click on existing devices in your project and select "update device". Mapping the I/Os If you wrote a correct device description, and installed it, you should now be able to map your I/Os to variables of your application. After you downloaded such a driver, you get a call to the function IoDrvUpdateConfiguration. This is your chance to parse the I/O configuration, initialize the hardware and prepare your internal data structures, so that you can efficiently copy the I/O data from and to the hardware. As we decided to use an FB interface to implement our driver, we keep it simple and store a pointer to the input and output variables of our FB. //Setup I/O area FOR i:=0 TO 7 DO pParameter := IoMgrConfigGetParameter(m_pConnector, 1000 + i); IF (pParameter <> 0) THEN pParameter^.dwDriverSpecific := ADR(FBInst.auiValue[i]); END_IF END_FOR Here we are storing a pointer to the inputs and outputs of our FB in the "driver specific value" of the corresponding parameter. Reading / Writing I/Os When you stored the pointer in the driver specific value of the parameter, it is very easy to copy those values cyclically. There are a few helper functions, which can be used to do that. FOR i:=0 TO nCount - 1 DO IF (pConnectorMapList[i].dwNumOfChannels = 0) THEN CONTINUE; END_IF FOR j:= 0 TO UDINT_TO_UINT(pConnectorMapList[i].dwNumOfChannels) - 1 DO IoMgrCopyInputLE(ADR(pConnectorMapList[i].pChannelMapList[j]), pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific); END_FOR END_FOR Note, that the suffix LE or BE defines the byte order on the hardware or fieldbus. The function automatically swaps to and from this byteorder. Adapting the Template For this kind of driver, you can find a template in the code repository of this project. It is called "IoDrvFB". You can use it as a starting point, as everything is prepared in a way, which makes it easy to get your first I/O driver running. Checkout the Template The template contains already a test-code, which makes it possible to test it on every controller. Add the driver The driver can be attached to the "Common.PCI" interface, which is defined on most PLCs as a member of the main PLC. So right click on the PLC in your project and choose "Add device". You should find IoDrvFB in the "Miscellaneous" section. Write a Program Just write a small test program. The driver provides by default an input and an output DWORD. dwOut := dwOut + 1; dwIn; Configure The configuration parameter is used as a factor, so the formula of the driver looks like: dwIn := dwOut * Config Login When you download this program to your PLC, your PRG should look like this: I/O driver library Change the structures The driver FB is mapping only one input, one output and one configuration parameter. The rest can be defined inside of the structures, named "IoDrvConfigInput", "IoDrvConfigOutput" and "IoDrvConfig". The easiest start is therefore, to change those structures according to your needs. Then you don't need to touch the I/O Driver FB in the folder "Generic". Note: If you don't need one of the structures, it is more simple to leave them in place, but just remove the parameter from the device description. Because you don't need to change the generic I/O driver FB this way. Write Driver Code Write your driver code in the body of "TheFB". This FB is called on every bus cycle, and it contains the structures from the last chapter as inputs and outputs. So the implementation should be pretty much straight forward. Change Library Details Double click on "Project Information". There it is mandatory to adapt "Title" and "Namespace". But obviously it makes sense to rework all settings in the dialog. Add the same information to the "GVL" in the project. There you find some constants, describing the names and module type for the generic I/O driver FB. The module type should follow the rules, described here. Save When you have a library open, there is a small button to save and install it in one turn. Note: I would recommend to open two instances of CODESYS when working with libraries. Device Description Change the Types The Types are defined by default like this: <Types namespace="local"> <StructType name="IoDrvInput"> <Component identifier="dwIn" type="std:DWORD"> <Default /> <VisibleName name="local:Input">Input</VisibleName> </Component> </StructType> <StructType name="IoDrvOutput"> <Component identifier="dwOut" type="std:DWORD"> <Default /> <VisibleName name="local:Output">Output</VisibleName> </Component> </StructType> <StructType name="IoDrvConfig"> <Component identifier="dwConfig" type="std:DWORD"> <Default /> <VisibleName name="local:Config">Config</VisibleName> </Component> </StructType> </Types> They need to define the exactly same structure as you defined the structures in your library. While this double work might be annoying, the actual process is straight forward. For some examples check the type examples in the generic driver documentation. Change the Identification Change the device identification after the rules, defined here. Change the Module Type Change the module type, as described here. That's it! After those steps, you should have already a working I/O driver. The main "magic" is done in the I/O driver FB in the subfolder "Generic". Don't worry to change this FB also. The intention of this generic FB is just to make the initial process as easy as possible.
Last updated: 2019-11-30
Post by aliazzz on Discussion for Generic page
I/O Drivers
doc
(Post)
No, You should declare a BYTE in the PLC Code byBitfield : BYTE; Then you can address each bit as follows; byBitfield.0 := xMyBool0; .. byBitfield.7 := xMyBool7; Try to avoid own DUT's (enums, structs) in the Devdesc.xml and stick to basic primitives like BYTE, DINT, REAL, WORD etc. This will make your life easier in editing the devdesc.xml. Offcourse if you want to use them, no problem, but you have to declare them in your code AND the devdes.xml file, so in two seperate places! Good luck
Last updated: 2019-12-10
Post by briangehrke on Discussion for SPI page
I/O Drivers
doc
(Post)
Thanks for confirming the code. Knowing the code is good forced me to look in a new direction. The python line of code [spi.open(0,1)] was the area I needed to focus on. I read some website that said spi.open(0,1) meant open port 0 in mode 1. Then I found out it meant open port 0 using device 1. I changed the settings in the SPI master on the in the device parameters. I put as spidev0.1 instead of spidev0.0. Then everything started to work. Thanks for the help!
Last updated: 2020-01-03
Post by i-campbell on Discussion for Generic page
I/O Drivers
doc
(Post)
Hi Fabio, you've found the driver section already! Yes you will need to create your own driver. I look forward to seeing it, and or lending pointers where needed.
Last updated: 2020-02-26
Post by briangehrke on Discussion for Generic page
I/O Drivers
doc
(Post)
The led is a bool, all I can do with the LED is turn it on or off. The odd part to me is the ppFrame is a also a bool and it works good, but the output LED does not. I set the LED to true in my program and the value does not pass through into the library. *** Update, after playing with the code for a little bit, I found out I had to add it to my program. I was just trying to force the value to make it work. Once I added a LED coil to my program as a coil it started to work. Thanks again for your help!
Last updated: 2020-01-05
Post by ingo on Discussion for Generic page
I/O Drivers
doc
(Post)
Hi Ian, this is what counts for open source drivers: https://forge.codesys.com/drv/io-drivers/database/ If you use another range, or you don't register your ID, you are not safe against conflicts with deivers from others.
Last updated: 2020-01-22
Post by briangehrke on Discussion for SPI page
I/O Drivers
doc
(Post)
Suggested Edit: SPI Transfer You might have noticed the few lines above: aby[0] := 1; << aby[1] := 16#80 + SHL(usiChannel AND 7, 4); aby[2] := 0; aby[3] := 0; IF NOT transfer(pabyTxBuffer:=ADR(aby) , pabyRxBuffer:=ADR(aby) , udiLen:=3 , uiDelayus:=0) THEN _iState := 1000; END_IF
Last updated: 2019-11-30
Post by ingo on Discussion for Generic page
I/O Drivers
doc
(Post)
Looks good! Which data type is the vqriable LED? You know, that for a boolean channel, just one bit is copied. The line: pParameter^.dwDriverSpecific := ... ... is storing the address of the variable of your driver FB in the structure of the parameter. This address is then used in ReadInputs/WriteOutputs to copy the I/O data quickly there.
Last updated: 2020-01-05
Post by i-campbell on Discussion for Generic page
I/O Drivers
doc
(Post)
Can you please clarify if we should use 0004 or 0003 as the vendor ID? I see in the documentation and some of the projects, these vendor IDs are used interchangeably.
Last updated: 2020-01-21
Post by briangehrke on Discussion for Generic page
I/O Drivers
doc
(Post)
If I want to create a module file for a SPI bus device, what module filter do I use. For example, an ethercat fieldbus module uses a description file like this: <ethercatmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:nonamespaceschemalocation="EtherCATModule.xsd"></ethercatmodule> Is there a SPI module? Since the device I am using has multiple types of devices, I thought plugging modules would be the best.
Last updated: 2019-12-25
Post by i-campbell on #3 Vendor code 0003 should be the vendor ID for open source drivers
I/O Drivers
tickets
(Post)
Task 1 of 4 - Complete I have identified the pages that need changing, and shown who has permission to edit those pages. I have also identified the 5 exisiting drivers that use the 0004 vendor ID currently. So it remains: Decisions: whether there is consensus for this suggested change? whether there is consensus for then updating existing drivers from 0004 to 0003? Pages that suggest using 0004: @ingo : https://forge.codesys.com/forge/wiki/IO%20Drivers/ https://forge.codesys.com/drv/io-drivers/database/Home/ https://forge.codesys.com/drv/io-drivers/doc/Generic/ Existing Drivers: @ingo : https://forge.codesys.com/drv/d-logg/code/HEAD/tree/trunk/d-logg/d-logg.devdesc.xml https://forge.codesys.com/drv/mcp3008/code/HEAD/tree/trunk/mcp3008/Devices/MCP3008.devdesc.xml https://forge.codesys.com/drv/io-drivers/code/HEAD/tree/trunk/IoDrvFB.devdesc.xml @aliazzz : https://forge.codesys.com/drv/mega-io/code/HEAD/tree/tags/v2.0.0.0/devdescr/IoDrvMEGAIO.devdesc.xml https://forge.codesys.com/drv/spi-monarco/svn/HEAD/tree/trunk/IoDrvMonarco/IoDrvMonarco%20v2.0.1.3.devdesc.xml https://forge.codesys.com/drv/spi-monarco/home/Project%20Overview/
Last updated: 2020-02-12
Post by ingo on Discussion for Generic page
I/O Drivers
doc
(Post)
Did you already check the [SPI] page? Additionally you can find an SPI Template driver in the code repository.
Last updated: 2019-12-25
Post by ingo on Discussion for Generic page
I/O Drivers
doc
(Post)
I tried to explain that by reworking parts of this chapter. Hope it helps...
Last updated: 2018-10-06
Post by ingo on Discussion for Generic page
I/O Drivers
doc
(Post)
Hi Brian, I think I understand your situation a bit better now. 1) module file I would recommend to stay with one file. Modules are just additional devices, defined in the same device description file. They share virtually every possible tags with the devices, except those, which are identifying the device in the device repository. So, you can define a module parallel to the device in your device description: ... </Device> <Modules> <Module> <ModuleId>1704</ModuleId> <DeviceInfo> <Name name="localStrings:Name1704>Digital Input</Name> <Description name="localStrings:Desc1704"/> <Vendor name="localStrings:3S">3S-Smart Software Solutions</Vendor> <OrderNumber/> </DeviceInfo> <Connector ConnectorId="2" HostPath="-1" interface="MyCompany.A" moduleType="41101" role="child"> <Slot allowEmpty="false" count="1"/> <HostParameterSet> ... 2) iterating over slots As I don't know your exact connector layout, I can give you only a vague answer. There are functions to iterate over the connectors and parameters, when you write an I/O driver. Those functions are located in the library IoStandard, and called: IoMgrGetFirstConnector IoMgrGetNextConnector IoMgrGetFirstChildConnector IoMgrGetNextChildConnector And you guess it, you can iterate over a connector tree with those functions. So I guess, that independent of your exact connector layout, it should be no rocket science. The only tricky part is, that you need to keep track over the remaining connectors in the list. You get the number of connectors passed to IoDrvUpdateConfiguration, and this count is reduced when you call one of the functions above. But when you return from iterating through the childs, you need the previous count again. So as a design pattern, you should simply use a copy of the connector count variable for iterating over the childs. 3) linking inputs and outputs to function blocks I personally always try to set the driver specific value of the parameters, corresponding to my I/O channels to the pointer of the I/Os of the function block. Then I can use the functions IoMgrCopyInputs/Outputs in IoDrvReadInputs/WriteOutputs. This makes live a bit easier in those higher frequently called functions. Hope I could help a bit
Last updated: 2019-12-29
Post by briangehrke on Discussion for SPI page
I/O Drivers
doc
(Post)
I figured out the problem with communicating over the SPI bus. I though this line of code in Python [spi.open(0,1) ] meant open port 0 in mode 1. I found out that this actually means open port 0, device 1. In the SPI master device I needed to replace the value in the SPI Port parameter from '/dev/spidev0.0' with '/dev/spidev0.1'. Once I did this everything started working. I am moving on to complete the driver. Thanks for your help, confirming the code told me to look in a new direction.
Last updated: 2020-01-02
Post by fabiopd on Discussion for I2C page
I/O Drivers
doc
(Post)
Hello I have read all online documentation , I create the xml file and the library for the AM2315 with an empty project (i don't know how to use SVN in codesys) . I tried this code in my library instance in my project (PLC_PRG) TeH: AM2315FB; TeH.usiAddress:= 0 ; TeH.TimeSchedule:= T#200MS; TeH(); TeH.AfterReadInputs(); and the main code of lib is: SUPER^(); CASE _iState OF 0: IF usiAddress = 0 THEN usiAddress := 16#5C; END_IF IF SUPER^.init() THEN _iState := 5; END_IF 5: Timer.pt := TimeSchedule; _iState := 10; intState:= 10; xTempValid := FALSE; xHumidityValid:=FALSE; END_CASE BUt doesn't _iState is always 0 ...may be SUPER^.init() is not working? Why ? Have I to add something to my I2c bus Device or is enough using the library? Thanks
Last updated: 2020-03-12