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 edit: aliazzz 2019-12-09
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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 edit: BG_Automation 2019-12-25
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes, I did locate the SPI template titled SPI_Template.devdesc.xml, I probably did not explain myself well enough based on your response. I am looking for a template to create a plug in SPI module to plug into a connector slot. I did not see a template for a SPI_Modules_V1.0.xml file. I have successfully created 8 slots, now I want to create a module to plug into one of the slots. I also would like to see how to iterate through each module and and perform an action based on the module type.
For example, I have a relay card and a DAC card on a SPI bus with addresses 0 and 1 respectively. I plug the modules into my device slots. I have 8 slots available for devices. I put the device type as host parameter and use this parameter as a key to process the information. As I go through a loop in the FB, I will send data in a format to turn relays on, the change the data to send to the DAC module. The data will be formated for the module type and sent through the SPI bus.
1.) How do I create a module file?
2.) How do I iterate through each slot and read the host parameters?
3.) How do I link the inputs and outputs to the function blocks?
While I am researching this, I am working on interfacing a relay module using SPI. I have this somewhat working but needs more work.
BG
Last edit: BG_Automation 2019-12-29
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Your comments above helped out a lot but I am a bit confused on how to create the methods for IoDrvReadInputs/WriteOutputs. I added these two methods to my library and they don't seem to be called.
So lets say I have my Output to Relay1. I added this to my host parameter section as with an attribute of being an output. It shows up in my IO Map channel list in my project and I map a value to Relay1. All of this works for me so far, but I am lost on how the data moves from my project to the library and how to link the data in the library. I have tried getting the pointer to this object using pParameter := IoMgrConfigGetParameter(m_pConnector, 1000 + i); and the pointer does not seem to do anything.
Is there a good driver project that illustrates this method to us? I think the last two sections of preparing I/O channels is vague and needs a little more explanation. This page has been an excellent guide on how to develop drivers.
Thanks for the help!
BG
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have this partially working, but I seem to be missing something. My driver copies the first Channel Output which is a BYTE, but does not copy the boolean. It looks like the channel map stops at the first byte. I have read through the xml file over and over again, it pretty much matches what you have in the
Can you please explain how this line works?
pParameter^.dwDriverSpecific := ADR(_MCP3008.auiValue[i]);
I don't understand how the channel map number of channels increments, looking at the line of code above, it looks like the dwDriverSpecific value keeps getting overwritten by the 8 addresses of the auiValue and just the last address is in the pParameter^.dwDriverSpecific.
So this is what I have:
I can see the value in the first byte named Relays, but the LED value never changes.
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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 edit: BG_Automation 2020-01-05
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Today I learned that vendor ID 0003 is for Open Source, and vendor ID 0004 is for CODESYS Configs. Not 100% sure what Configs are, but it is clear we should be using 0003 for Forge Open Source drivers.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello can I create a driver for the I2C AM2315 (https://learn.adafruit.com/am2315-encased-i2c-temperature-humidity-sensor/arduino-code) ?
or there are some packages to download? Thanks a lot!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
no moderation necessary. Just create your own driver project by clicking on "register project" in driver neighborhood. Then describe your work in the wiki of the project, upload all code and devdescs to SVN, and you are done.
To register your driver ID, just go to database and add it there.
Last edit: Ingo 2020-02-28
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello Ingo I can't undestand how to merge the io-drivers-code-r13-trunk folder in my codesys project.... Have I to use SVN and install CODESYS SVN or I can do without? The process how to build a driver is not clear!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
<attributes download="true" offlineaccess="write" functional="false" channel="input" onlineaccess="readwrite"></attributes>
=> Please explain these meta tags, as they are important ;-)
I tried to explain that by reworking parts of this chapter. Hope it helps...
Last edit: aliazzz 2019-01-18
...
Last edit: aliazzz 2018-10-20
I have a question about the structures. I will start with the BIT structure. It looks
Should the code read
TYPE Bitfield :
STRUCT
Bit0 : Bit;
Bit1 : Bit;
Bit2 : Bit;
Bit3 : Bit;
END_STRUCT
END_TYPE
Device Description
No,
You should declare a BYTE in the PLC Code
Then you can address each bit as follows;
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 edit: aliazzz 2019-12-09
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 edit: BG_Automation 2019-12-25
Did you already check the [SPI] page?
Additionally you can find an SPI Template driver in the code repository.
Related
Documentation: SPI
Yes, I did locate the SPI template titled SPI_Template.devdesc.xml, I probably did not explain myself well enough based on your response. I am looking for a template to create a plug in SPI module to plug into a connector slot. I did not see a template for a SPI_Modules_V1.0.xml file. I have successfully created 8 slots, now I want to create a module to plug into one of the slots. I also would like to see how to iterate through each module and and perform an action based on the module type.
For example, I have a relay card and a DAC card on a SPI bus with addresses 0 and 1 respectively. I plug the modules into my device slots. I have 8 slots available for devices. I put the device type as host parameter and use this parameter as a key to process the information. As I go through a loop in the FB, I will send data in a format to turn relays on, the change the data to send to the DAC module. The data will be formated for the module type and sent through the SPI bus.
1.) How do I create a module file?
2.) How do I iterate through each slot and read the host parameters?
3.) How do I link the inputs and outputs to the function blocks?
While I am researching this, I am working on interfacing a relay module using SPI. I have this somewhat working but needs more work.
BG
Last edit: BG_Automation 2019-12-29
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:
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:
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
Your comments above helped out a lot but I am a bit confused on how to create the methods for IoDrvReadInputs/WriteOutputs. I added these two methods to my library and they don't seem to be called.
So lets say I have my Output to Relay1. I added this to my host parameter section as with an attribute of being an output. It shows up in my IO Map channel list in my project and I map a value to Relay1. All of this works for me so far, but I am lost on how the data moves from my project to the library and how to link the data in the library. I have tried getting the pointer to this object using pParameter := IoMgrConfigGetParameter(m_pConnector, 1000 + i); and the pointer does not seem to do anything.
Is there a good driver project that illustrates this method to us? I think the last two sections of preparing I/O channels is vague and needs a little more explanation. This page has been an excellent guide on how to develop drivers.
Thanks for the help!
BG
The MCP3008 driver is doing it this way.
Step 1) Implement the I/O Driver Interface.
For this, the driver defines a new FB, implenting this interface:
Step 2) Instantiate the driver FB in your devdesc:
Step 3) instantiate your SPI FB inside of the drivrt FB:
Step 4) Map the I/O channels to the inputs and outputs of your SPI FB
Step 5) Call IoMgrCopyXXX in ReadInputs / WriteOutputs
I have this partially working, but I seem to be missing something. My driver copies the first Channel Output which is a BYTE, but does not copy the boolean. It looks like the channel map stops at the first byte. I have read through the xml file over and over again, it pretty much matches what you have in the
Can you please explain how this line works?
pParameter^.dwDriverSpecific := ADR(_MCP3008.auiValue[i]);
I don't understand how the channel map number of channels increments, looking at the line of code above, it looks like the dwDriverSpecific value keeps getting overwritten by the 8 addresses of the auiValue and just the last address is in the pParameter^.dwDriverSpecific.
So this is what I have:
I can see the value in the first byte named Relays, but the LED value never changes.
Looks good!
Which data type is the vqriable LED? You know, that for a boolean channel, just one bit is copied.
The line:
... 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.
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 edit: BG_Automation 2020-01-05
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.
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.
The page you linked suggests using "<id>0004 ....</id>"
https://forge.codesys.com/drv/io-drivers/doc/Generic/?limit=25#device-identification suggests 0004 as well
https://forge.codesys.com/drv/io-drivers/doc/I2C/ suggests 0003
For a new I2C device, I can't decide.
Today I learned that vendor ID 0003 is for Open Source, and vendor ID 0004 is for CODESYS Configs. Not 100% sure what Configs are, but it is clear we should be using 0003 for Forge Open Source drivers.
Hello can I create a driver for the I2C AM2315 (https://learn.adafruit.com/am2315-encased-i2c-temperature-humidity-sensor/arduino-code) ?
or there are some packages to download? Thanks a lot!
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.
If I create it with this tutorial , after that can the moderator add the driver in the list?
Last edit: FabioPD 2020-02-28
Hi Fabio,
no moderation necessary. Just create your own driver project by clicking on "register project" in driver neighborhood. Then describe your work in the wiki of the project, upload all code and devdescs to SVN, and you are done.
To register your driver ID, just go to database and add it there.
Last edit: Ingo 2020-02-28
Hello Ingo I can't undestand how to merge the io-drivers-code-r13-trunk folder in my codesys project.... Have I to use SVN and install CODESYS SVN or I can do without? The process how to build a driver is not clear!
Yes, you need to use CODESYS SVN. But don't worry about the license.
Whenyou use it with CODESYS Forge, you can use it w/o a license.
Indeed you are right. The workflow with CODESYS SVN is not well known, yet.
So a tutorial might be good.