Vai al contenuto

I2CBusManager, Gestione periferiche su bus I2C

Vai all indice del manuale di programmazione
Tipo: Blocco Funzione
Libreria LogicLab: eLLabI2CDevsLib
Libreria Codesys: Non disponibile

Questo blocco funzione gestisce periferiche con interfaccia su bus I2C, in base alla definizione di I2CMode è possibile selezionare il bus da utilizzare.

Eseguendo il FB se WrBytes e WrBuffer sono definiti, viene eseguita la scrittura di WrBytes bytes dal buffer indirizzato da WrBuffer sul dispositivo I2C indirizzato in I2CAddress. Terminata la scrittura se RdBytes e RdBuffer sono definiti viene eseguita la lettura di RdBytes bytes dal dispositivo I2C indirizzato in I2CAddress nel buffer indirizzato da RdBuffer.

Se I2CMode=1 sugli ingressi IClock ed IData vanno connessi i relativi segnali di ingresso, e sulle uscite OClock ed OData i relativi segnali di uscita del bus I2C.

Approfondimenti
  • In questo topic acquisizione di sensore pirometrico MEMS Thermal Sensors D6T della Omron.
Upgrade list

I2CBusManager_v1

Eliminato ingresso SpyOn e gestione spionaggio. E’ possibile definire parametro BFrequency=0 per avere gestione con tempi di loop (Massima velocità).

Aggiunto uscita Ready per abilitazione gestione uscite logiche.

Descrizione

I2CMode (DINT) Definisce il modo di gestione del bus I2C.
0:Viene utilizzato il bus di espansione del sistema gestito in hardware.
1:Si utilizza un bus simulato su I/O discreti. La gestione dei segnali Clock e Data del bus è eseguita interamente da software permettendo di utilizzare qualsiasi I/O discreto, occorre appoggiare i segnali sui rispettivi I/O.
I2CAddress (USINT) Indirizzo dispositivo I2C range da 16#00 a 16#7F.
WrBytes (UDINT) Numero di bytes dati da scrivere. 0 se solo lettura.
WrBuffer (PVOID) Indirizzo buffer memoria che contiene i dati da scrivere, NULL se solo lettura.
RdBytes (UDINT) Numero di bytes dati da leggere. 0 se solo scrittura.
RdBuffer (PVOID) Indirizzo buffer memorizzazione dati letti, NULL se solo scrittura.
Done (BOOL) Si attiva per un loop al termine dell’esecuzione comando.
Fault (BOOL) Si attiva per un loop contemporaneamente al Done se errore esecuzione.
Ok (BOOL) Si attiva per un loop contemporaneamente al Done se il comando terminato correttamente.

I segnali seguenti sono gestiti solo se I2CMode<>0.

Ready (BOOL) Si attiva su FB pronta alla gestione del bus I2C. Se ICMode=0 è sempre attiva.
IClock (BOOL) Collegare il segnale hardware di lettura Clock da bus I2C. Se non è necessario gestire lo stretching si può lasciare scollegato.
IData (BOOL) Collegare il segnale hardware di lettura Data da bus I2C.
OClock (BOOL) Occorre collegare il segnale hardware di gestione Clock su bus I2C.
OData (BOOL) Occorre collegare il segnale hardware di gestione Data su bus I2C.
BFrequency (REAL) Frequenza di Clock bus I2C (Hz). Se 0 la frequenza dipende dal tempo di esecuzione FB, si ha la massima velocità di gestione.
AckTrigger (BOOL) Attivata su acquisizione acknowledge dal dispositivo I2C. Si utilizza per gestire segnali senza feedbak.
BLockup (UDINT) Contatore errori di bus lockup. Si incrementa ad ogni invio di clock per liberare il bus.
Errors (UDINT) Contatore errori, si incrementa ad ogni errore riscontrato nella gestione.

Immagine FB I2CBusManager_v1
Bus simulato su I/O discreti senza feedback

Quando si utilizza il blocco per la gestione di un bus I2C simulato su I/O discreti per facilitare il cablaggio è possibile evitare la lettura sia del segnale di clock che di dato. Non acquisendo il seganle di clock non potrà essere gestito lo stretching (Ma essendo il bus simulato già molto lento non è necessario).

Non acquisendo il dato sarà possibile gestire solo dispositivi di output non potendo gestirne le lettura e non sarà possibile controllare il segnale di acnowledge del dato scritto. Ecco nell’esempio come gestire i due segnali.

    // -------------------------------------------------------------------------
    // OBJECT EXECUTION
    // -------------------------------------------------------------------------
    // Manage the I2C bus on CPU module logic I/Os.
    // The Di00 is used as Clock, Di01 is used as Data.

    DInp(); //Dgital inputs acquisition
    I2CBus.IClock:=TRUE; //Clock in signal
    I2CBus.IData:=NOT(I2CBus.AckTrigger); //Data in signal

    // The Do00 is used as Clock, Do01 is used as Data.

    DOut.Value.0:=NOT(I2CBus.OClock); //Clock out signal
    DOut.Value.1:=NOT(I2CBus.OData); //Data out signal
    DOut(); //Digital output management

Esempi

Come utilizzare gli esempi.
Negli esempi vengono utilizzati gli I/O digitali del modulo CPU per gestire un bus I2C software, in questo modo il bus è completamente isolato dal sistema. Di fianco lo schema di cablaggio utilizzato, la tensione di alimentazione del bus +5Vcc deve essere fornita da un alimentatore esterno.

ST_I2CBusManager: Viene acquisito un sensore di temperatura ed umidità (Come questo) collegato al bus I2C simulato con gli I/O logici.

ST_I2CIOExpander: Viene gestito un PCA9670 I2C I/O expander connesso ad un bus I2C simulato su I/O logici.

ST_ScanI2CDevicesOnIOs: Collegandosi in telnet alla porta indicata viene eseguito la scansione di tutti i possibili indirizzi I2C e ritornato l’elenco dei dispositivi connessi al bus I2C emulato con gli I/O del modulo.

Schema connessioni bus I2C su I/O
LogicLab (Ptp176, ST_I2CBusManager)
PROGRAM ST_I2CBusManager
VAR
    CaseNr : USINT; (* Program case *)
    Errors : UDINT; (* Error counter *)
    TimeBf : UDINT; (* Time buffer (mS) *)
    Temperature : REAL; (* Temperature value (°C) *)
    Humidity : REAL; (* Humidity value (%) *)
    I2CWrite : ARRAY[0..1] OF BYTE; (* I2C write buffer *)
    I2CRead : ARRAY[0..5] OF BYTE; (* I2C read buffer *)
    DInp : SysGetPhrDI; (* Digital input acquisistion *)
    DOut : SysSetPhrDO; (* Digital output management *)
    I2CBus : I2CBusManager_v1; (* I2C bus management *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_I2CBusManager"
// *****************************************************************************
// Temperature and humidity acquisition from a Sensirion SHT30-DIS connected
// to a I2C bus emulated by logic I/Os
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------
    // First program loop initialization.

    IF (SysFirstLoop) THEN

        // Initialize the logic I/O management.

        DInp.Address:=255; //Module address
        DInp.Mode:=DI_I_8_LL; //Input mode

        DOut.Address:=255; //Module address
        DOut.Mode:=DO_8_LL; //Output mode
        DOut.Mask:=16#00000003; //Output mask

        // Initialize the software I2C management.

        I2CBus.I2CMode:=1; //I2C mode selection
        I2CBus.I2CAddress:=16#44; //I2C Address
        I2CBus.BFrequency:=1000.0; //Bus frequency (Hz)
    END_IF;

    // -------------------------------------------------------------------------
    // OBJECT EXECUTION
    // -------------------------------------------------------------------------
    // Manage the I2C bus on CPU module logic I/Os.
    // The Di00 is used as Clock, Di01 is used as Data.

    DInp(); //Dgital inputs acquisition
    I2CBus.IClock:=NOT(DInp.Value.0); //Clock in signal
    I2CBus.IData:=NOT(DInp.Value.1); //Data in signal

    // The Do00 is used as Clock, Do01 is used as Data.

    IF (I2CBus.Ready) THEN
        DOut.Value.0:=NOT(I2CBus.OClock); //Clock out signal
        DOut.Value.1:=NOT(I2CBus.OData); //Data out signal
        DOut(); //Digital output management
    END_IF;

    // -------------------------------------------------------------------------
    // PROGRAM CASES
    // -------------------------------------------------------------------------
    // Program cases management.

    CASE (CaseNr) OF

        // ---------------------------------------------------------------------
        // Conversion command "Single Shot Mode high repeatability" clock
        // streching disabled.

        0:
        I2CWrite[0]:=16#24; //MSB
        I2CWrite[1]:=16#00; //LSB
        I2CBus(WrBuffer:=ADR(I2CWrite), WrBytes:=2, RdBuffer:=eNULL, RdBytes:=0);
        IF NOT(I2CBus.Done) THEN RETURN; END_IF;
        IF (I2CBus.Fault) THEN Errors:=Errors+1; CaseNr:=0; RETURN; END_IF;

        // Save time to wait.

        TimeBf:=SysTimeGetMs(); //Time buffer (mS)
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // Wait conversion complete (Max time oh high repeatability 15 mS).

        1:
        IF ((SysTimeGetMs()-TimeBf) < TO_UDINT(T#15ms)) THEN RETURN; END_IF;

        // Read the conversion results.

        I2CBus(WrBuffer:=eNULL, WrBytes:=0, RdBuffer:=ADR(I2CRead), RdBytes:=6);
        IF NOT(I2CBus.Done) THEN RETURN; END_IF;
        IF (I2CBus.Fault) THEN Errors:=Errors+1; CaseNr:=0; RETURN; END_IF;

        // Convert the acquired values.

        Temperature:=-45.0+(175.0*(TO_REAL((I2CRead[0]*256)+I2CRead[1])/65535.0));
        Humidity:=100.0*(TO_REAL((I2CRead[3]*256)+I2CRead[4])/65535.0);
        CaseNr:=0; //Program case
    END_CASE;

// [End of file]
LogicLab (Ptp176, ST_I2CIOExpander)

Di fianco è riportato lo schema di realizzazione di un semplice I/O expander connesso al bus di espansione di un nostro modulo CPU.

Il PCA9670 ha 3 ingressi di impostazione dell’indirizzo I2C, in questo modo è possibile avere fino a 8 moduli connessi allo stesso bus. Senza ponticelli l’indirizzo I2C è 16#38.

Riportiamo un programma di esempio per la gestione del I/O expander connesso ad un bus simulato sugli I/O di un modulo CPU.

Schema elettrico I/O expander su bus I2C
PROGRAM ST_I2CIOExpander
VAR
    I2CWrite : BYTE; (* I2C write buffer *)
    I2CRead : BYTE; (* I2C read buffer *)
    Errors : UDINT; (* Error counter *)
    LEDs : ARRAY[0..3] OF BOOL; (* LEDs command *)
    PBs : ARRAY[0..3] OF BOOL; (* PBs status *)
    DInp : SysGetPhrDI; (* Digital input acquisistion *)
    DOut : SysSetPhrDO; (* Digital output management *)
    I2CBus : I2CBusManager_v1; (* I2C bus management *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_I2CIOExpander"
// *****************************************************************************
// Manages a PCA9670 I/O expander connected to a I2C simulated bus.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------
    // First program loop initialization.

    IF (SysFirstLoop) THEN

        // Initialize the logic I/O management.

        DInp.Address:=255; //Module address
        DInp.Mode:=DI_I_8_LL; //Input mode

        DOut.Address:=255; //Module address
        DOut.Mode:=DO_8_LL; //Output mode
        DOut.Mask:=16#00000003; //Output mask

        // Initialize the software I2C management.

        I2CBus.I2CMode:=1; //I2C mode selection
        I2CBus.I2CAddress:=16#38; //I2C Address
        I2CBus.BFrequency:=500.0; //Bus frequency (Hz)
    END_IF;

    // -------------------------------------------------------------------------
    // DIGITAL I/O MANAGEMENT
    // -------------------------------------------------------------------------
    // Manage the I2C bus on CPU module logic I/Os.
    // The Di00 is used as Clock, Di01 is used as Data.

    DInp(); //Dgital inputs acquisition
    I2CBus.IClock:=NOT(DInp.Value.0); //Clock in signal
    I2CBus.IData:=NOT(DInp.Value.1); //Data in signal

    // The Do00 is used as Clock, Do01 is used as Data.

    IF (I2CBus.Ready) THEN
        DOut.Value.0:=NOT(I2CBus.OClock); //Clock out signal
        DOut.Value.1:=NOT(I2CBus.OData); //Data out signal
        DOut(); //Digital output management
    END_IF;

    // -------------------------------------------------------------------------
    // I2C BUS MANAGEMENT
    // -------------------------------------------------------------------------
    // Set the LEDs command. The 4 pins used as inputs must be set TRUE.

    LEDs[0]:=SysClock1000; //LEDs command
    LEDs[3]:=PBs[3]; //LEDs command
    I2CWrite.0:=NOT(LEDs[0]); //I2C write buffer
    I2CWrite.1:=NOT(LEDs[1]); //I2C write buffer
    I2CWrite.2:=NOT(LEDs[2]); //I2C write buffer
    I2CWrite.3:=NOT(LEDs[3]); //I2C write buffer
    I2CWrite:=I2CWrite OR 16#F0; //I2C write buffer

    // Manage the I2C bus

    I2CBus(WrBuffer:=ADR(I2CWrite), WrBytes:=1, RdBuffer:=ADR(I2CRead), RdBytes:=1);
    IF NOT(I2CBus.Done) THEN RETURN; END_IF;
    IF (I2CBus.Fault) THEN Errors:=Errors+1; RETURN; END_IF;

    // Copy the PBs status.

    PBs[0]:=NOT(I2CRead.4); //PBs status    
    PBs[1]:=NOT(I2CRead.5); //PBs status    
    PBs[2]:=NOT(I2CRead.6); //PBs status    
    PBs[3]:=NOT(I2CRead.7); //PBs status    

// [End of file]
LogicLab (Ptp176, ST_ScanI2CDevicesOnIOs)
PROGRAM ST_ScanI2CDevicesOnIOs
VAR
    CaseNr : USINT; (* Program case *)
    Fp : eFILEP; (* File pointer array *)
    SOut : STRING[ 128 ]; (* String output *)
    DInp : SysGetPhrDI; (* Digital input acquisistion *)
    DOut : SysSetPhrDO; (* Digital output management *)
    TCPServer : SysTCPServer; (* TCP server *)
    I2CBus : I2CBusManager_v1; (* I2C bus management *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_ScanI2CDevicesOnIOs"
// *****************************************************************************
// Opens a TCP server and when a client connects to it a I2C Bus emulated by
// logic I/Os is scanned.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------
    // TCPServer initialization.

    IF (SysFirstLoop) THEN

        // Initialize the logic I/O management.

        DInp.Address:=255; //Module address
        DInp.Mode:=DI_I_8_LL; //Input mode

        DOut.Address:=255; //Module address
        DOut.Mode:=DO_8_LL; //Output mode
        DOut.Mask:=16#00000003; //Output mask

        // Initialize the software I2C management.

        I2CBus.I2CMode:=1; //I2C mode selection
        I2CBus.WrBytes:=0; //Data to write
        I2CBus.WrBuffer:=eNULL; //Data to write buffer
        I2CBus.RdBytes:=0; //Data to read
        I2CBus.RdBuffer:=eNULL; //Data readed buffer
        I2CBus.BFrequency:=1000.0; //Bus frequency (Hz)

        // Initialize TCP server.
    
        TCPServer.FilesArr:=ADR(Fp); //Files array
        TCPServer.LocalAdd:=ADR('0.0.0.0'); //Local address
        TCPServer.LocalPort:=1110; //Local port 
        TCPServer.MaxConn:=1; //Accepted connections
        TCPServer.FlushTm:=50; //Flush time (mS)
        TCPServer.LifeTm:=15; //Life time (S)
        TCPServer.RxSize:=128; //Rx buffer size
        TCPServer.TxSize:=128; //Tx buffer size
    END_IF;

    // -------------------------------------------------------------------------
    // OBJECT EXECUTION
    // -------------------------------------------------------------------------
    // Manage the I2C bus on CPU module logic I/Os.
    // The Di00 is used as Clock, Di01 is used as Data.

    DInp(); //Dgital inputs acquisition
    I2CBus.IClock:=NOT(DInp.Value.0); //Clock in signal
    I2CBus.IData:=NOT(DInp.Value.1); //Data in signal

    // The Do00 is used as Clock, Do01 is used as Data.

    IF (I2CBus.Ready) THEN
        DOut.Value.0:=NOT(I2CBus.OClock); //Clock out signal
        DOut.Value.1:=NOT(I2CBus.OData); //Data out signal
        DOut(); //Digital output management
    END_IF;

    // Manage the TCP server and check if a client has been connected.

    TCPServer(); //TCPServer management
    TCPServer.Enable:=TRUE; //TCPServer enable
    IF NOT(SysFIsOpen(Fp)) THEN CaseNr:=0; RETURN; END_IF;

    // -------------------------------------------------------------------------
    // PROGRAM CASES
    // -------------------------------------------------------------------------
    // Program cases management.

    CASE (CaseNr) OF

        // ---------------------------------------------------------------------
        // Init check.

        0:
        eTO_JUNK(SysVsnprintf(ADR(SOut), SIZEOF(SOut), ADR('Scan I2C Bus devices%s'), STRING_TYPE, ADR('$r$n')));
        I2CBus.I2CAddress:=16#00; //I2C address
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // Check if the I2C device is present.

        1:
        I2CBus();
        IF NOT(I2CBus.Done) THEN RETURN; END_IF;

        IF NOT(I2CBus.Ok) THEN
            eTO_JUNK(SysCVsnprintf(ADR(SOut), SIZEOF(SOut), ADR('%s '), STRING_TYPE, ADR('--')));
        ELSE
            eTO_JUNK(SysCVsnprintf(ADR(SOut), SIZEOF(SOut), ADR('%02X '), USINT_TYPE, ADR(I2CBus.I2CAddress)));
        END_IF;

        // Increase the I2C address to check.

        I2CBus.I2CAddress:=I2CBus.I2CAddress+1; //I2C address

        // Every 16 addresses return the result.

        IF (MOD(I2CBus.I2CAddress, 16) = 0) THEN    
            eTO_JUNK(SysCVsnprintf(ADR(SOut), SIZEOF(SOut), ADR('%s'), STRING_TYPE, ADR('$r$n')));
            eTO_JUNK(Sysfwrite(ADR(SOut), TO_INT(LEN(SOut)), 1, Fp));
            eTO_JUNK(Sysmemset(ADR(SOut), 0, SIZEOF(SOut)));
            CaseNr:=CaseNr+1; //Program case
            RETURN;
        END_IF;

        // ---------------------------------------------------------------------
        // Waits the output buffer empty.

        2:
        IF (SysFGetOSpace(Fp) <> TO_INT(SysFGetOBfSize(Fp))) THEN RETURN; END_IF;
        eTO_JUNK(Sysmemset(ADR(SOut), 0, SIZEOF(SOut)));

        // Check if all possible addresses has  been tested.

        IF (I2CBus.I2CAddress < 16#80) THEN CaseNr:=CaseNr-1; RETURN; END_IF;
        eTO_JUNK(SysFOBfFlush(Fp)); //Flush the socket data
        TCPServer.Enable:=FALSE; //TCPServer enable
        CaseNr:=0; //Program case
    END_CASE;

// [End of file]
Was this article helpful?