Wednesday, July 17, 2013

Object-Oriented 1-Wire: An Introduction

One of the many interfaces and protocols that Cosa support is Maxim Integrated 1-Wire. The support classes, OWI, OWI::Driver and OWI::Search, allows easy implementation of 1-Wire device drivers. The support classes implement the full 1-Wire specification with support for parasite power devices and alarm search.

In a previous post the DS18B20 driver was used to implement a Virtual Wire Digital Thermometer. In this post more of the design and implementation of the 1-Wire device driver will be presented. A simple DS1990A iButton reader sketch is used to present the basic functionality. The iButton device is often used as an access control key or for equipment identification. It is the simplest of all 1-Wire devices as only the device identity ROM command is used and there is at most a single device connected on the 1-Wire bus.

The Cosa support for 1-Wire is called OWI (One Wire Interface). Below are the OWI class member functions. The class represents the 1-Wire bus and handles data transfer to and from devices on the bus. It also supports basic alarm search and dispatch function according to the 1-Wire specification.

Fig.1: OWI class member functions
1-Wire devices drivers use the OWI class to communicate with the connected device. All bus interaction is delegated to the OWI class instance.

Fig.2: OWI::Driver class member functions
The OWI::Driver class member functions are the 1-Wire ROM commands. The class holds the 1-Wire identity for a specific connected device. This can be given as an EEMEM 8 byte uint8_t vector or through the connect() member function.

Devices driver member functions initiate a device function command with a ROM command (match_rom/skip_rom) followed by the function command and read or write of data.

bool
DS18B20::read_scratchpad()
{
  if (!match_rom()) return (false);
  m_pin->write(READ_SCRATCHPAD);
  return (m_pin->read(&m_scratchpad, sizeof(m_scratchpad)));
}


Above is an example of the structure in the form of an implementation of the DS18B20 Read Scratchpad (BEh) command. Note that m_pin in the example code above is the OWI reference.

Fig.3: Arduino Pro Mini reading iButton
Back to the iButton (DS1990A) device. In the below example sketch iButton devices are read when connected and their identity (key) is check against a simple table with valid keys. The access is logged (i.e. printout to serial output).

Being the simplest of all 1-Wire devices only a single OWI::Driver member function is used; OWI::Driver::read_rom(). No specific device driver is necessary for this version of iButton. The OWI::Driver class already has the required functionality.

Let us start with the loop() function. When an iButton is connected the 1-Wire identity ROM is read and checked. If the key is valid a green LED is switched on otherwise a red LED will blink (for 5 seconds). The valid keys are stored in a table in program memory (PROGMEM). In an application they would be stored in eeprom (EEMEM) and there would also be an update procedure without recompiling the sketch. The procedure could be, for instance, present a master key and then the key to add/remove from the table. 

void loop()
{
  // Take a nap
  SLEEP(1);

  // Check if a key was connected
  OWI::Driver dev(&owi);
  if (!dev.read_rom()) return;

  // Check if it is an authorized key. Turn on led for 5 seconds
  uint8_t* rom = dev.get_rom();
  for (uint8_t i = 0; i < sizeof(KEY); i += OWI::ROM_MAX) {
    if (!memcmp_P(rom, &KEY[i], OWI::ROM_MAX)) {
      trace << dev << PSTR(":AUTHORIZED KEY") << endl;
      greenLed.on();
      SLEEP(5);
      greenLed.off();
      return;
    }
  }

  // Otherwise it is an illegal key. Flash led for 5 seconds
  trace << dev << PSTR(":ILLEGAL KEY") << endl;
  for (uint8_t i = 0; i < 10; i++) {
    redLed.on();
    MSLEEP(250);
    redLed.off();
    MSLEEP(250);
  }
}

The blue marks the 1-Wire code. The orange marks the log printouts. The Cosa 1-Wire support may be used on ATtinyX4/X5. Below the example sketch is run on an ATtiny85 with Soft::UART connected to D0, 1-Wire bus to D1, red LED to pin D2 and green LED to pin D4. A standard cell battery holder is used as the iBattery connector.

Fig.4: ATtiny85 iButton reader setup
The Cosa Soft::UART is used for the log printouts from the sketch. Below is a screenshot.

Fig.5: Screenshot of iButton reader sketch printouts
Last the sketch setup(). Below is the key table in program memory, the OWI bus object and the LED pins. The setup initiates the UART and binds the trace output stream. Cosa uses the Watchdog for low power sleep mode.

// Table with valid keys (64 bit 1-Wire identity, 8 bytes per entry)
uint8_t KEY[] PROGMEM = {
  0x01, 0x23, 0x81, 0xa3, 0x09, 0x00, 0x00, 0x7b,
  0x01, 0x29, 0x01, 0x27, 0x09, 0x00, 0x00, 0xa8,
  0x01, 0x26, 0xd9, 0x3e, 0x09, 0x00, 0x00, 0x47
};

// One-wire pin (D1 on ATtiny, D7 on others)
#if defined(__ARDUINO_TINY__)
OWI owi(Board::D1);
OutputPin redLed(Board::D2);
OutputPin greenLed(Board::D4);
#else
OWI owi(Board::D7);
OutputPin ledPin(Board::LED);
#define redLed ledPin
#define greenLed ledPin
#endif

void setup()
{
  // Initiate UART as trace output
  uart.begin(9600);
  trace.begin(&uart, PSTR("CosaDS1990A: started"));

  // Initiate the watchdog for low-power sleep mode
  Watchdog::begin();
}


Finally two pictures with the iButton reader in action.

Fig.6: Illegal key
Fig.7: Authorized key




1 comment: