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
To search for an exact phrase, put it in quotes. Example: "getting started docs"
To exclude a word or phrase, put a dash in front of it. Example: docs -help
To search on specific fields, use these field names instead of a general text search. You can group with AND
or OR
.
You can use the 'Search comments?' checkbox to include comments in the search results.
You can use the 'Search history?' checkbox to include previous revisions of items in the search results.