Extended MaximInterface
Dependents: mbed_DS28EC20_GPIO
Diff: Devices/DS2480B.cpp
- Revision:
- 0:f77ad7f72d04
- Child:
- 3:f818ea5172ed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Devices/DS2480B.cpp Mon Nov 06 14:39:18 2017 -0600 @@ -0,0 +1,687 @@ +/******************************************************************************* +* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#include <MaximInterface/Utilities/Error.hpp> +#include "DS2480B.hpp" + +// Mode Commands +#define MODE_DATA 0xE1 +#define MODE_COMMAND 0xE3 +#define MODE_STOP_PULSE 0xF1 + +// Return byte value +#define RB_CHIPID_MASK 0x1C +#define RB_RESET_MASK 0x03 +#define RB_1WIRESHORT 0x00 +#define RB_PRESENCE 0x01 +#define RB_ALARMPRESENCE 0x02 +#define RB_NOPRESENCE 0x03 + +#define RB_BIT_MASK 0x03 +#define RB_BIT_ONE 0x03 +#define RB_BIT_ZERO 0x00 + +// Masks for all bit ranges +#define CMD_MASK 0x80 +#define FUNCTSEL_MASK 0x60 +#define BITPOL_MASK 0x10 +#define SPEEDSEL_MASK 0x0C +#define MODSEL_MASK 0x02 +#define PARMSEL_MASK 0x70 +#define PARMSET_MASK 0x0E + +// Command or config bit +#define CMD_COMM 0x81 +#define CMD_CONFIG 0x01 + +// Function select bits +#define FUNCTSEL_BIT 0x00 +#define FUNCTSEL_SEARCHON 0x30 +#define FUNCTSEL_SEARCHOFF 0x20 +#define FUNCTSEL_RESET 0x40 +#define FUNCTSEL_CHMOD 0x60 + +// Bit polarity/Pulse voltage bits +#define BITPOL_ONE 0x10 +#define BITPOL_ZERO 0x00 +#define BITPOL_5V 0x00 +#define BITPOL_12V 0x10 + +// One Wire speed bits +#define SPEEDSEL_STD 0x00 +#define SPEEDSEL_FLEX 0x04 +#define SPEEDSEL_OD 0x08 +#define SPEEDSEL_PULSE 0x0C + +// Data/Command mode select bits +#define MODSEL_DATA 0x00 +#define MODSEL_COMMAND 0x02 + +// 5V Follow Pulse select bits +#define PRIME5V_TRUE 0x02 +#define PRIME5V_FALSE 0x00 + +// Parameter select bits +#define PARMSEL_PARMREAD 0x00 +#define PARMSEL_SLEW 0x10 +#define PARMSEL_12VPULSE 0x20 +#define PARMSEL_5VPULSE 0x30 +#define PARMSEL_WRITE1LOW 0x40 +#define PARMSEL_SAMPLEOFFSET 0x50 +#define PARMSEL_ACTIVEPULLUPTIME 0x60 +#define PARMSEL_BAUDRATE 0x70 + +// Pull down slew rate. +#define PARMSET_Slew15Vus 0x00 +#define PARMSET_Slew2p2Vus 0x02 +#define PARMSET_Slew1p65Vus 0x04 +#define PARMSET_Slew1p37Vus 0x06 +#define PARMSET_Slew1p1Vus 0x08 +#define PARMSET_Slew0p83Vus 0x0A +#define PARMSET_Slew0p7Vus 0x0C +#define PARMSET_Slew0p55Vus 0x0E + +// 12V programming pulse time table +#define PARMSET_32us 0x00 +#define PARMSET_64us 0x02 +#define PARMSET_128us 0x04 +#define PARMSET_256us 0x06 +#define PARMSET_512us 0x08 +#define PARMSET_1024us 0x0A +#define PARMSET_2048us 0x0C +#define PARMSET_infinite 0x0E + +// 5V strong pull up pulse time table +#define PARMSET_16p4ms 0x00 +#define PARMSET_65p5ms 0x02 +#define PARMSET_131ms 0x04 +#define PARMSET_262ms 0x06 +#define PARMSET_524ms 0x08 +#define PARMSET_1p05s 0x0A +#define PARMSET_dynamic 0x0C +#define PARMSET_infinite 0x0E + +// Write 1 low time +#define PARMSET_Write8us 0x00 +#define PARMSET_Write9us 0x02 +#define PARMSET_Write10us 0x04 +#define PARMSET_Write11us 0x06 +#define PARMSET_Write12us 0x08 +#define PARMSET_Write13us 0x0A +#define PARMSET_Write14us 0x0C +#define PARMSET_Write15us 0x0E + +// Data sample offset and Write 0 recovery time +#define PARMSET_SampOff3us 0x00 +#define PARMSET_SampOff4us 0x02 +#define PARMSET_SampOff5us 0x04 +#define PARMSET_SampOff6us 0x06 +#define PARMSET_SampOff7us 0x08 +#define PARMSET_SampOff8us 0x0A +#define PARMSET_SampOff9us 0x0C +#define PARMSET_SampOff10us 0x0E + +// Active pull up on time +#define PARMSET_PullUp0p0us 0x00 +#define PARMSET_PullUp0p5us 0x02 +#define PARMSET_PullUp1p0us 0x04 +#define PARMSET_PullUp1p5us 0x06 +#define PARMSET_PullUp2p0us 0x08 +#define PARMSET_PullUp2p5us 0x0A +#define PARMSET_PullUp3p0us 0x0C +#define PARMSET_PullUp3p5us 0x0E + +// DS2480B program voltage available +#define DS2480BPROG_MASK 0x20 + +namespace MaximInterface { + +error_code DS2480B::initialize() { + // reset modes + level = NormalLevel; + baud = Baud9600bps; + mode = MODSEL_COMMAND; + speed = SPEEDSEL_FLEX; + + // set the baud rate to 9600 + error_code result = setComBaud(baud); + if (result) { + return result; + } + + // send a break to reset the DS2480B + result = breakCom(); + if (result) { + return result; + } + + // delay to let line settle + (*sleep)(2); + + // flush the buffers + result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the timing byte + uint_least8_t packet[5]; + packet[0] = 0xC1; + result = uart->writeBlock(packet, 1); + if (result) { + return result; + } + + // delay to let line settle + (*sleep)(2); + + // set the FLEX configuration parameters + // default PDSRC = 1.37Vus + int packetLen = 0; + packet[packetLen++] = CMD_CONFIG | PARMSEL_SLEW | PARMSET_Slew1p37Vus; + // default W1LT = 10us + packet[packetLen++] = CMD_CONFIG | PARMSEL_WRITE1LOW | PARMSET_Write10us; + // default DSO/WORT = 8us + packet[packetLen++] = CMD_CONFIG | PARMSEL_SAMPLEOFFSET | PARMSET_SampOff8us; + + // construct the command to read the baud rate (to test command block) + packet[packetLen++] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3); + + // also do 1 bit operation (to test 1-Wire block) + packet[packetLen++] = CMD_COMM | FUNCTSEL_BIT | baud | BITPOL_ONE; + + // flush the buffers + result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // read back the response + result = uart->readBlock(packet, sizeof(packet) / sizeof(packet[0])); + if (result) { + return result; + } + + // look at the baud rate and bit operation + // to see if the response makes sense + if (!(((packet[3] & 0xF1) == 0x00) && ((packet[3] & 0x0E) == baud) && + ((packet[4] & 0xF0) == 0x90) && ((packet[4] & 0x0C) == baud))) { + result = make_error_code(HardwareError); + } + + return result; +} + +error_code DS2480B::reset() { + uint_least8_t packet[2]; + int packetLen = 0; + + // check for correct mode + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // construct the command + packet[packetLen++] = (CMD_COMM | FUNCTSEL_RESET | speed); + + // flush the buffers + error_code result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // read back the 1 byte response + result = uart->readBlock(packet, 1); + if (result) { + return result; + } + + // make sure this byte looks like a reset byte + if ((packet[0] & RB_RESET_MASK) == RB_1WIRESHORT) { + result = make_error_code(ShortDetectedError); + } + else if ((packet[0] & RB_RESET_MASK) == RB_NOPRESENCE) { + result = make_error_code(NoSlaveError); + } + + return result; +} + +error_code DS2480B::touchBitSetLevel(bool & sendRecvBit, Level afterLevel) { + uint_least8_t packet[2]; + int packetLen = 0; + + // check for correct mode + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // construct the command + packet[packetLen++] = (sendRecvBit ? BITPOL_ONE : BITPOL_ZERO) | CMD_COMM | + FUNCTSEL_BIT | speed; + + // flush the buffers + error_code result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // read back the response + result = uart->readBlock(packet, 1); + if (result) { + return result; + } + + // interpret the response + if ((packet[0] & 0xE0) == 0x80) { + sendRecvBit = ((packet[0] & RB_BIT_MASK) == RB_BIT_ONE); + result = setLevel(afterLevel); + } else { + result = make_error_code(HardwareError); + } + + return result; +} + +error_code DS2480B::writeByteSetLevel(uint_least8_t sendByte, + Level afterLevel) { + uint_least8_t packet[3]; + int packetLen = 0; + + // check for correct mode + if (mode != MODSEL_DATA) { + mode = MODSEL_DATA; + packet[packetLen++] = MODE_DATA; + } + + // add the byte to send + packet[packetLen++] = sendByte; + + // check for duplication of data that looks like COMMAND mode + if (sendByte == MODE_COMMAND) { + packet[packetLen++] = sendByte; + } + + // flush the buffers + error_code result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // read back the 1 byte response + result = uart->readBlock(packet, 1); + if (result) { + return result; + } + + if (packet[0] == sendByte) { + result = setLevel(afterLevel); + } else { + result = make_error_code(HardwareError); + } + + return result; +} + +error_code DS2480B::readByteSetLevel(uint_least8_t & recvByte, + Level afterLevel) { + uint_least8_t packet[2]; + int packetLen = 0; + + // check for correct mode + if (mode != MODSEL_DATA) { + mode = MODSEL_DATA; + packet[packetLen++] = MODE_DATA; + } + + // add the byte to send + packet[packetLen++] = 0xFF; + + // flush the buffers + error_code result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // read back the 1 byte response + result = uart->readBlock(packet, 1); + if (result) { + return result; + } + + recvByte = packet[0]; + result = setLevel(afterLevel); + + return result; +} + +error_code DS2480B::setSpeed(Speed newSpeed) { + error_code result; + bool setSpeed = false; + + // check if supported speed + switch (newSpeed) { + case OverdriveSpeed: + // check if change from current mode + if (speed != SPEEDSEL_OD) { + result = changeBaud(Baud115200bps); + if (!result) { + speed = SPEEDSEL_OD; + setSpeed = true; + } + } + break; + + case StandardSpeed: + // check if change from current mode + if (speed != SPEEDSEL_STD) { + result = changeBaud(Baud9600bps); + if (!result) { + speed = SPEEDSEL_STD; + setSpeed = true; + } + } + break; + + default: + result = make_error_code(InvalidSpeedError); + break; + } + + // if baud rate is set correctly then change DS2480 speed + if (setSpeed) { + uint_least8_t packet[2]; + int packetLen = 0; + + // check if correct mode + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + // proceed to set the DS2480 communication speed + packet[packetLen++] = CMD_COMM | FUNCTSEL_SEARCHOFF | speed; + + // send the packet + result = uart->writeBlock(packet, packetLen); + } + + return result; +} + +error_code DS2480B::setLevel(Level newLevel) { + error_code result; + // check if need to change level + if (newLevel != level) { + uint_least8_t packet[4]; + int packetLen = 0; + + // check for correct mode + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + + switch (newLevel) { + case NormalLevel: + // stop pulse command + packet[packetLen++] = MODE_STOP_PULSE; + + // add the command to begin the pulse WITHOUT prime + packet[packetLen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | + BITPOL_5V | PRIME5V_FALSE; + + // stop pulse command + packet[packetLen++] = MODE_STOP_PULSE; + + // flush the buffers + result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // read back the 1 byte response + result = uart->readBlock(packet, 2); + if (result) { + return result; + } + + // check response byte + if (((packet[0] & 0xE0) == 0xE0) && ((packet[1] & 0xE0) == 0xE0)) { + level = NormalLevel; + } else { + result = make_error_code(HardwareError); + } + break; + + case StrongLevel: + // set the SPUD time value + packet[packetLen++] = CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite; + // add the command to begin the pulse + packet[packetLen++] = + CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V; + + // flush the buffers + result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // read back the 1 byte response from setting time limit + result = uart->readBlock(packet, 1); + if (result) { + return result; + } + + // check response byte + if ((packet[0] & 0x81) == 0) { + level = newLevel; + } else { + result = make_error_code(HardwareError); + } + break; + + default: + result = make_error_code(InvalidLevelError); + break; + } + } + return result; +} + +error_code DS2480B::changeBaud(BaudRate newBaud) { + error_code result; + + //see if different then current baud rate + if (baud != newBaud) { + uint_least8_t packet[2]; + int packetLen = 0; + + // build the command packet + // check for correct mode + if (mode != MODSEL_COMMAND) { + mode = MODSEL_COMMAND; + packet[packetLen++] = MODE_COMMAND; + } + // build the command + const uint_least8_t baudByte = CMD_CONFIG | PARMSEL_BAUDRATE | newBaud; + packet[packetLen++] = baudByte; + + // flush the buffers + result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, packetLen); + if (result) { + return result; + } + + // make sure buffer is flushed + (*sleep)(5); + + // change our baud rate + result = setComBaud(newBaud); + if (result) { + return result; + } + baud = newBaud; + + // wait for things to settle + (*sleep)(5); + + // build a command packet to read back baud rate + packet[0] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3); + + // flush the buffers + result = uart->clearReadBuffer(); + if (result) { + return result; + } + + // send the packet + result = uart->writeBlock(packet, 1); + if (result) { + return result; + } + + // read back the 1 byte response + result = uart->readBlock(packet, 1); + if (result) { + return result; + } + + // verify correct baud + if (!((packet[0] & 0x0E) == (baudByte & 0x0E))) { + result = make_error_code(HardwareError); + } + } + + return result; +} + +error_code DS2480B::setComBaud(BaudRate newBaud) { + switch (newBaud) { + case Baud115200bps: + return uart->setBaud(115200); + + case Baud57600bps: + return uart->setBaud(57600); + + case Baud19200bps: + return uart->setBaud(19200); + + case Baud9600bps: + default: + return uart->setBaud(9600); + } +} + +error_code DS2480B::breakCom() { + // Switch to lower baud rate to ensure break is longer than 2 ms. + error_code result = uart->setBaud(4800); + if (result) { + return result; + } + result = uart->sendBreak(); + if (result) { + return result; + } + result = setComBaud(baud); + return result; +} + +const error_category & DS2480B::errorCategory() { + static class : public error_category { + public: + virtual const char * name() const { return "DS2480B"; } + + virtual std::string message(int condition) const { + switch (condition) { + case HardwareError: + return "Hardware Error"; + + default: + return defaultErrorMessage(condition); + } + } + } instance; + return instance; +} + +} // namespace MaximInterface