Generic OneWire

Top  Previous  Next

//------------------------------------------------------------------------------
// DS2408.vpl, created 2012-05-09 10:19
// 
// Demonstrate communication with Maxim DS2408 1-Wire device, using the generic
// 1-Wire interface. 
//
// DESCRIPTION of the DS2408
//    The DS2408 is an 8-channel, programmable I/O 1-Wire chip. PIO outputs are
//    configured as open-drain and provide an on resistance of 100? max.
//    A robust PIO channel-access communication protocol ensures that PIO 
//    output-setting changes occur error-free. A data-valid strobe output can
//    be used to latch PIO logic states into external circuitry such as a D/A
//    converter (DAC) or microcontroller data bus.
//
//
// HARDWARE configuration
//    The hardware used to communicate with is based on the reference design 
//    found in the datasheet of the DS2408 (version 19-5702; 12/10), and a
//    RTCU device.
//
//                         DS2408            External
//
//    1-Wire      -->   IO         P0  -->   SW1    
//    SGND        -->   GND        P1  -->   SW2
//    3.3V        -->   VCC        P2  -->   SW3
//                                 P3  -->   SW4
//                                 P4  -->   LED1
//                                 P5  -->   LED2
//                                 P6  -->   LED3
//                                 P7  -->   LED4
//    
//------------------------------------------------------------------------------
INCLUDE rtcu.inc
 
//  Output variables that can be configured via the configuration dialog
VAR_OUTPUT
   Connected      : BOOL; | Connected to the DS2408
   NotConnected   : BOOL; | NOT connected to the DS2408
END_VAR;
 
//------------------------------------------------------------------------------
// Special 1-Wire function to read the registers of a 
// Maxim DS2408 - 1-Wire 8-Channel Addressable Switch
//
// INPUT
//    device   : INT (default 1 (1st.))
//       device number withing the family is handling multiple DS2408 on same net
//
// OUTPUT
//    P     : ARRAY[0..7] OF BOOL
//             PIO Logic State
//    PL    : ARRAY[0..7] OF BOOL
//             PIO Output Latch State Register
//    AL    : ARRAY[0..7] OF BOOL
//             PIO Activity Latch State Register
//    SM    : ARRAY[0..7] OF BOOL
//             Conditional Search Channel Selection Mask
//    SP    : ARRAY[0..7] OF BOOL
//             Conditional Search Channel Polarity Selection
//    PLS   : BOOL   
//             Pin or Activity Latch Select
//    CT    : BOOL 
//             Conditional Search Logical Term
//    ROS   : BOOL    
//             RSTZ Pin Mode Control
//    PORL  : BOOL    
//             Power-On Reset Latch
//    VCCP  : BOOL 
//             VCC Power Status
//    ready : BOOL   
//             Last update successful
//
//------------------------------------------------------------------------------
FUNCTION_BLOCK owDS2408;
VAR_INPUT
   device   : INT    := 1;       // use device found with owSearchX()
END_VAR;
VAR_OUTPUT
   P        : ARRAY[0..7] OF BOOL; // PIO Logic State
   PL       : ARRAY[0..7] OF BOOL; // PIO Output Latch State Register
   AL       : ARRAY[0..7] OF BOOL; // PIO Activity Latch State Register
   SM       : ARRAY[0..7] OF BOOL; // Conditional Search Channel Selection Mask
   SP       : ARRAY[0..7] OF BOOL; // Conditional Search Channel Polarity Selection
   PLS      : BOOL   := FALSE;     // Pin or Activity Latch Select
   CT       : BOOL   := FALSE;     // Conditional Search Logical Term
   ROS      : BOOL   := FALSE;     // RSTZ Pin Mode Control
   PORL     : BOOL   := FALSE;     // Power-On Reset Latch
   VCCP     : BOOL   := FALSE;     // VCC Power Status
   ready    : BOOL   := FALSE;     // Last update successful
END_VAR;
VAR
   regs     : ARRAY[16#88..16#8F] OF SINT; // Register map
   crc      : INT;                // inverted crc16 all data send and received.
   rc       : INT;
   i        : SINT;
END_VAR;
ready := FALSE;
 
// RST -> PD -> Select
rc := owAccess(family := 16#29, device := device);
IF rc <> 0 THEN
   DebugFmt(message := "owDS2408 : Failed to access device (\1)", v1 := rc);
   RETURN;
END_IF;
 
// RPR - Command "Read PIO Registers"
owWrite(data := 16#F0);
// TA - Target address
owWrite(data := 16#88); // TA1 (T7:T0)
owWrite(data := 16#00); // TA2 (T15:T8)
owReadData(data := ADDR(regs), size := SIZEOF(regs));
owReadData(data := ADDR(crc),  size := SIZEOF(crc));
owRelease();
 
// Validate received data against received CRC16                              
IF NOT (crcCalculate(
      buffer      := ADDR(regs),
      length      := SIZEOF(regs),
      order       := 16,
      polynom     := 16#0000_8005,  // X^16+X^15+X^2+1
      preset      := 16#0000_66CC,  // the CRC16 of RPR + TA using same polynom
      direct      := TRUE,  
      finalxor    := NOT (crc),     // check against received inverted crc
      reverseData := TRUE,  
      reverseCRC  := TRUE  
   ) = 0) THEN
   DebugMsg(message := "owDS2408 : Failed to read register (CRC error)");
   RETURN;
END_IF;
 
// Map register values to output values
FOR i := 0 TO 7 DO
   P[i] := (regs[16#88] AND shl8(in := 1, n := i))  <> 0;
END_FOR;
FOR i := 0 TO 7 DO
   PL[i] := (regs[16#89] AND shl8(in := 1, n := i)) <> 0;
END_FOR;
FOR i := 0 TO 7 DO
   AL[i] := (regs[16#8A] AND shl8(in := 1, n := i)) <> 0;
END_FOR;
FOR i := 0 TO 7 DO
   SM[i] := (regs[16#8B] AND shl8(in := 1, n := i)) <> 0;
END_FOR;
FOR i := 0 TO 7 DO
   SP[i] := (regs[16#8C] AND shl8(in := 1, n := i)) <> 0;
END_FOR;
 
PLS   := (regs[16#8D] AND 16#01) <> 0;
CT    := (regs[16#8D] AND 16#02) <> 0;
ROS   := (regs[16#8D] AND 16#04) <> 0;
PORL  := (regs[16#8D] AND 16#08) <> 0;
VCCP  := (regs[16#8D] AND 16#80) <> 0;
 
ready := TRUE; // all data received successful
END_FUNCTION_BLOCK;
 
//------------------------------------------------------------------------------
// Special 1-Wire function to set the Control/Status Register.
// This will also clear the power-on reset latch (PORL) status.
//
// INPUTS
//    device   : INT (default 1 (1st.))
//       device number withing the family is handling multiple DS2408 on same net
//    PLS   : BOOL   
//             Pin or Activity Latch Select configuration
//    CT    : BOOL 
//             Conditional Search Logical Term configuration
//    ROS   : BOOL    
//             RSTZ Pin Mode Control configuration
//------------------------------------------------------------------------------
FUNCTION owDS2408Cfg;
VAR_INPUT
   device   : INT    := 1;
   PLS      : BOOL   := FALSE;   // Pin or Activity Latch Select
   CT       : BOOL   := FALSE;   // Conditional Search Logical Term
   ROS      : BOOL   := FALSE;   // RSTZ Pin Mode Control
END_VAR;
 
VAR
   reg      : SINT   := 16#00;
   val      : SINT   := 16#00;
   rc       : INT;
END_VAR;
 
IF PLS THEN reg := reg OR 16#01; END_IF;
IF CT  THEN reg := reg OR 16#02; END_IF;
IF ROS THEN reg := reg OR 16#04; END_IF;
 
// RST -> PD -> Select
rc := owAccess(family := 16#29, device := device);
IF rc <> 0 THEN
   DebugFmt(message := "owDS2408Cfg : Failed to access device (\1)", v1 := rc);
   RETURN;
END_IF;
 
owWrite(data := 16#CC);
owWrite(data := 16#8D);
owWrite(data := 16#00);
owWrite(data := reg);
owRelease(); 
 
rc := owAccess(family := 16#29, device := device);
IF rc <> 0 THEN
   DebugFmt(message := "owDS2408Cfg (verify) : Failed to access device (\1)",
            v1 := rc);
   RETURN;
END_IF;
 
owWrite(data := 16#F0); // read reg
owWrite(data := 16#8D);
owWrite(data := 16#00);
owRead(data := val);
owRelease(); 
 
IF (val AND 16#0007) <> reg THEN
   DebugFmt(message := "owDS2408Cfg (validate) : Failed (\1 <> \2)",
            v1 := (val AND 16#0007), v2 := (reg AND 16#00FF));
END_IF;
END_FUNCTION;
 
//------------------------------------------------------------------------------
// Special 1-Wire function to reset the PIO Activity Latch State Register
//
// INPUTS
//    device   : INT (default 1 (1st.))
//       device number withing the family is handling multiple DS2408 on same net
//------------------------------------------------------------------------------
FUNCTION owDS2408ResetAL : BOOL;
VAR_INPUT
   device   : INT := 1;
END_VAR;
 
VAR
   ack      : SINT;
   rc       : INT;
END_VAR;
 
rc := owAccess(family := 16#29, device := device);
IF rc <> 0 THEN
   DebugFmt(message := "owDS2408ResetAL : Failed to access device (\1)",
            v1 := rc);
   RETURN;
END_IF;
 
owWrite(data := 16#C3);
owRead(data := ack);
owRelease();
 
IF (ack AND 16#00FF) <> 16#00AA THEN
   DebugFmt(message := "owDS2408ResetAL : Failed to reset latch (ack = \1)",
            v1 := (ack AND 16#00FF));
   RETURN;
END_IF;
owDS2408ResetAL := TRUE;
END_FUNCTION;
 
//------------------------------------------------------------------------------
// Special 1-Wire function to set the PIO pins state.
//
// output pin status will be ignored when using pins as inputs.
//
// INPUTS
//    device   : INT (default 1 (1st.))
//       device number withing the family is handling multiple DS2408 on same net
//
//    p0       : BOOL (default OFF)
//       pin 0 ON/OFF
//    p1       : BOOL (default OFF)
//       pin 1 ON/OFF
//    p2       : BOOL (default OFF)
//       pin 2 ON/OFF
//    p3       : BOOL (default OFF)
//       pin 3 ON/OFF
//    p4       : BOOL (default OFF)
//       pin 4 ON/OFF
//    p5       : BOOL (default OFF)
//       pin 5 ON/OFF
//    p6       : BOOL (default OFF)
//       pin 6 ON/OFF
//    p7       : BOOL (default OFF)  
//       pin 7 ON/OFF
//------------------------------------------------------------------------------
FUNCTION owDS2408SetOutput;
VAR_INPUT
   device   : INT    := 1;
   p0       : BOOL   := OFF;
   p1       : BOOL   := OFF;
   p2       : BOOL   := OFF;
   p3       : BOOL   := OFF;
   p4       : BOOL   := OFF;
   p5       : BOOL   := OFF;
   p6       : BOOL   := OFF;
   p7       : BOOL   := OFF;  
END_VAR;
 
VAR
   mask     : SINT := 0; // the pin stat after the update
   ack      : SINT;
   rc       : INT;
   i        : SINT;
   status   : SINT;
END_VAR;
 
IF p0 THEN mask := mask OR 16#01; END_IF;
IF p1 THEN mask := mask OR 16#02; END_IF;
IF p2 THEN mask := mask OR 16#04; END_IF;
IF p3 THEN mask := mask OR 16#08; END_IF;
IF p4 THEN mask := mask OR 16#10; END_IF;
IF p5 THEN mask := mask OR 16#20; END_IF;
IF p6 THEN mask := mask OR 16#40; END_IF;
IF p7 THEN mask := mask OR 16#80; END_IF;
 
rc := owAccess(family := 16#29, device := device);
IF rc <> 0 THEN
   DebugFmt(message := "owDS2408SetOutput : Failed to access device (\1)", v1 := rc);
   RETURN;
END_IF;
 
owWrite(data := 16#5A);
owWrite(data := mask);
owWrite(data := NOT(mask));
owRead(data := ack);
owRead(data := status);
owRelease();
 
IF (ack AND 16#00FF) <> 16#00AA THEN
   DebugFmt(message := "owDS2408SetOutput : Failed to set new pin state (reply \1)",
            v1 := (ack AND 16#00FF));
END_IF;
END_FUNCTION;
 
 
//-----------------------------------------------------------------------------
// Application to run
//    Monitor the state of the DS2408 inputs (pin 0-3), and maps it to
//    the outputs (pin 4-7).
//-----------------------------------------------------------------------------
PROGRAM DS2408;
VAR
   DS2408   : owDS2408;
   id       : STRING;   
   cnt      : INT;
   i        : INT;
   upd      : BOOL;
END_VAR;
 
// Enable/Disable 3.3VDC output to supply external LEDs
boardDCOut(enable:=ON);
 
BEGIN
   IF connected THEN
      Sleep(delay := 500); // allow DS2408 to detect changes on inputs
      DS2408(device := 1);
   END_IF;
   IF DS2408.ready THEN
      owDS2408ResetAL(device := 1); // reset the latches as we got them
      upd := FALSE;
      IF DS2408.porl THEN
         DebugMsg(Message := "Power-On Reset detected.");
         owDS2408Cfg(device := 1, ros := ON);
         upd := TRUE;
      ELSE
         FOR i := 0 TO 3 DO
            IF DS2408.al[i] THEN
               DebugFmt(message := "DS2408 : PIN \1 = \2",
                        v1 := i, v2 := SINT(DS2408.p[i]));
               upd := TRUE;
            END_IF;
         END_FOR;
      END_IF;
      IF upd THEN
         owDS2408SetOutput(
            device := 1,
            p4 := DS2408.p[0], 
            p5 := DS2408.p[1],
            p6 := DS2408.p[2], 
            p7 := DS2408.p[3]);
      END_IF;
   ELSE
      IF NOT (id = "") THEN
         DebugMsg(message := "Lost connection to DS2408 device 1 '" + id +"'");
         id := "";
      END_IF;
      cnt := owSearchX(first := 16#29, last := 16#29); // only search for DS2408 devices
      IF cnt > 0 THEN
         DebugFmt(message := "Found \1 DS2408 1-Wire devices.", v1 := cnt);
         id := owGetID(device := 1, family := 16#29);
         DebugFmt(message := "Using DS2408 1-Wire device = " + id);         
      ELSIF cnt < 0 THEN
         DebugMsg(message := "Failed to search for DS2408 1-Wire devices.");
      END_IF;
   END_IF;
   Connected    := (id <> "");
   NotConnected := NOT Connected;
END;
END_PROGRAM;