Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: MAXREFDES131_Qt_Demo MAX32630FTHR_iButton_uSD_Logger MAX32630FTHR_DS18B20_uSD_Logger MAXREFDES130_131_Demo ... more
OneWire_Masters/DS248x/ds248x.cpp
- Committer:
- IanBenzMaxim
- Date:
- 2016-03-21
- Revision:
- 21:00c94aeb533e
- Parent:
- 17:b646b1e3970b
- Child:
- 23:e8e403d61359
File content as of revision 21:00c94aeb533e:
/******************************************************************//**
* Copyright (C) 2016 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 "ds248x.h"
//*********************************************************************
Ds248x::Ds248x(I2C &i2c_bus, DS248X_I2C_ADRS adrs)
:_p_i2c_bus(&i2c_bus), _i2c_owner(false)
{
set_i2c_adrs(adrs);
}
//*********************************************************************
Ds248x::Ds248x(PinName sda, PinName scl, DS248X_I2C_ADRS adrs)
:_p_i2c_bus(new I2C(sda, scl)), _i2c_owner(true)
{
set_i2c_adrs(adrs);
}
//*********************************************************************
Ds248x::~Ds248x()
{
if(_i2c_owner)
{
delete _p_i2c_bus;
}
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWInitMaster(void)
{
return(detect());
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::detect(void)
{
OneWireInterface::CmdResult result;
// reset the ds2484 ON selected address
result = reset();
if(result == OneWireInterface::Success)
{
// default configuration
_c1WS = 0;
_cSPU = 0;
_cPDN = 0;
_cAPU = 0;
result = write_config(_c1WS | _cSPU | _cPDN | _cAPU);
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::reset(void)
{
OneWireInterface::CmdResult result;
char status;
char packet[] = {CMD_DRST};
// Device Reset
// S AD,0 [A] DRST [A] Sr AD,1 [A] [SS] A\ P
// [] indicates from slave
// SS status byte to read to verify state
if(_p_i2c_bus->write(_w_adrs, packet, 1) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
if(_p_i2c_bus->read(_r_adrs, &status, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
else
{
if((status & 0xF7) == 0x10)
{
result = OneWireInterface::Success;
}
else
{
result = OneWireInterface::OperationFailure;
}
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::write_config(uint8_t config)
{
OneWireInterface::CmdResult result;
char read_config;
char packet [] = {CMD_WCFG, (config | (~config << 4))};
if(_p_i2c_bus->write(_w_adrs, packet, 2) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
if(_p_i2c_bus->read(_r_adrs, &read_config, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
else
{
// check for failure due to incorrect read back
if (config != read_config)
{
reset();
result = OneWireInterface::OperationFailure;
}
else
{
result = OneWireInterface::Success;
}
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::channel_select(uint8_t channel)
{
OneWireInterface::CmdResult result;
char ch, ch_read, check;
char packet [2];
packet[0] = CMD_CHSL;
// Channel Select (Case A)
// S AD,0 [A] CHSL [A] CC [A] Sr AD,1 [A] [RR] A\ P
// [] indicates from slave
// CC channel value
// RR channel read back
switch (channel)
{
default: case 0: ch = 0xF0; ch_read = 0xB8; break;
case 1: ch = 0xE1; ch_read = 0xB1; break;
case 2: ch = 0xD2; ch_read = 0xAA; break;
case 3: ch = 0xC3; ch_read = 0xA3; break;
case 4: ch = 0xB4; ch_read = 0x9C; break;
case 5: ch = 0xA5; ch_read = 0x95; break;
case 6: ch = 0x96; ch_read = 0x8E; break;
case 7: ch = 0x87; ch_read = 0x87; break;
};
packet[1] = ch;
if(_p_i2c_bus->write(_w_adrs, packet, 2) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
if(_p_i2c_bus->read(_r_adrs, &check, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
else
{
// check for failure due to incorrect read back of channel
if (check == ch_read)
{
result = OneWireInterface::Success;
}
else
{
result = OneWireInterface::OperationFailure;
}
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::adjust_timing(uint8_t param, uint8_t val)
{
OneWireInterface::CmdResult result;
char read_port_config;
char control_byte;
control_byte = (((param & 0x0F) << 4) | (val & 0x0F));
char packet [] = {CMD_A1WP, control_byte};
if(_p_i2c_bus->write(_w_adrs, packet, 2) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
if(_p_i2c_bus->read(_r_adrs, &read_port_config, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
else
{
// check for failure due to incorrect read back
if ((control_byte & 0x0F) != read_port_config)
{
result = OneWireInterface::OperationFailure;
reset();
}
else
{
result = OneWireInterface::Success;
}
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::search_triplet(uint8_t search_direction, uint8_t & status)
{
OneWireInterface::CmdResult result;
uint8_t poll_count = 0;
char packet [] = {CMD_1WT, search_direction ? 0x80 : 0x00};
char read_data;
// 1-Wire Triplet (Case B)
// S AD,0 [A] 1WT [A] SS [A] Sr AD,1 [A] [Status] A [Status] A\ P
// \--------/
// Repeat until 1WB bit has changed to 0
// [] indicates from slave
// SS indicates byte containing search direction bit value in msbit
if(_p_i2c_bus->write(_w_adrs, packet, 2) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
// loop checking 1WB bit for completion of 1-Wire operation
// abort if poll limit reached
//dummy write for loop
result = OneWireInterface::Success; //so far
do
{
if(_p_i2c_bus->read(_r_adrs, &read_data, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
}
while ((read_data & STATUS_1WB) && (poll_count++ < POLL_LIMIT) && (result != OneWireInterface::CommunicationReadError));
if((result == OneWireInterface::CommunicationReadError) || (poll_count >= POLL_LIMIT))
{
// check for failure due to poll limit reached
if(poll_count >= POLL_LIMIT)
{
// handle error
// ...
reset();
result = OneWireInterface::TimeoutError;
}
}
else
{
status = read_data;
result = OneWireInterface::Success;
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWReset(void)
{
OneWireInterface::CmdResult result;
uint8_t poll_count = 0;
char status;
char packet [] = {CMD_1WRS};
// 1-Wire reset (Case B)
// S AD,0 [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P
// \--------/
// Repeat until 1WB bit has changed to 0
// [] indicates from slave
if(_p_i2c_bus->write(_w_adrs, packet, 1) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
// loop checking 1WB bit for completion of 1-Wire operation
// abort if poll limit reached
//dummy write for loop
result = OneWireInterface::Success; //so far
do
{
if(_p_i2c_bus->read(_r_adrs, &status, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
}
while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT) && (result != OneWireInterface::CommunicationReadError));
if((result == OneWireInterface::CommunicationReadError) || (poll_count >= POLL_LIMIT))
{
// check for failure due to poll limit reached
if(poll_count >= POLL_LIMIT)
{
// handle error
// ...
reset();
result = OneWireInterface::TimeoutError;
}
}
else
{
// check for short condition
if (status & STATUS_SD)
{
_short_detected = true;
}
else
{
_short_detected = false;
}
// check for presence detect
if (status & STATUS_PPD)
{
result = OneWireInterface::Success;
}
else
{
result = OneWireInterface::OperationFailure;
}
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWTouchBit(uint8_t & sendrecvbit)
{
OneWireInterface::CmdResult result;
uint8_t poll_count = 0;
char status;
char packet[] = {CMD_1WSB, sendrecvbit ? 0x80 : 0x00};
// 1-Wire bit (Case B)
// S AD,0 [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] A\ P
// \--------/
// Repeat until 1WB bit has changed to 0
// [] indicates from slave
// BB indicates byte containing bit value in msbit
if(_p_i2c_bus->write(_w_adrs, packet, 2) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
// loop checking 1WB bit for completion of 1-Wire operation
// abort if poll limit reached
//dummy write for loop
result = OneWireInterface::Success; //so far
do
{
if(_p_i2c_bus->read(_r_adrs, &status, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
}
while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT) && (result != OneWireInterface::CommunicationReadError));
if((result == OneWireInterface::CommunicationReadError) || (poll_count >= POLL_LIMIT))
{
// check for failure due to poll limit reached
if (poll_count >= POLL_LIMIT)
{
// handle error
// ...
reset();
result = OneWireInterface::TimeoutError;
}
}
else
{
// return bit state through out param
if (status & STATUS_SBR)
{
sendrecvbit = 1;
}
else
{
sendrecvbit = 0;
}
result = OneWireInterface::Success;
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWWriteByte(uint8_t sendbyte)
{
OneWireInterface::CmdResult result;
uint8_t poll_count = 0;
char status;
char packet [] = {CMD_1WWB, sendbyte};
// 1-Wire Write Byte (Case B)
// S AD,0 [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] A\ P
// \--------/
// Repeat until 1WB bit has changed to 0
// [] indicates from slave
// DD data to write
if(_p_i2c_bus->write(_w_adrs, packet, 2) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
// loop checking 1WB bit for completion of 1-Wire operation
// abort if poll limit reached
//dummy write for loop
result = OneWireInterface::Success; //so far
do
{
if(_p_i2c_bus->read(_r_adrs, &status, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
}
while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT) && (result != OneWireInterface::CommunicationReadError));
if((result == OneWireInterface::CommunicationReadError) || (poll_count >= POLL_LIMIT))
{
// check for failure due to poll limit reached
if (poll_count >= POLL_LIMIT)
{
// handle error
// ...
reset();
result = OneWireInterface::TimeoutError;
}
}
else
{
result = OneWireInterface::Success;
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWReadByte(uint8_t & recvbyte)
{
OneWireInterface::CmdResult result;
uint8_t poll_count = 0;
char data, status;
char packet[2] = {CMD_1WRB, 0};
// 1-Wire Read Bytes (Case C)
// S AD,0 [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A\
// \--------/
// Repeat until 1WB bit has changed to 0
// Sr AD,0 [A] SRP [A] E1 [A] Sr AD,1 [A] DD A\ P
//
// [] indicates from slave
// DD data read
if(_p_i2c_bus->write(_w_adrs, packet, 1) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
// loop checking 1WB bit for completion of 1-Wire operation
// abort if poll limit reached
//dummy write for loop
result = OneWireInterface::Success; //so far
do
{
if(_p_i2c_bus->read(_r_adrs, &status, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
}
while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT) && (result != OneWireInterface::CommunicationReadError));
if((result == OneWireInterface::CommunicationReadError) || (poll_count >= POLL_LIMIT))
{
// check for failure due to poll limit reached
if (poll_count >= POLL_LIMIT)
{
// handle error
// ...
reset();
result = OneWireInterface::TimeoutError;
}
}
else
{
packet[0] = CMD_SRP;
packet[1] = 0xE1;
if(_p_i2c_bus->write(_w_adrs, packet, 2) != I2C_WRITE_OK)
{
result = OneWireInterface::CommunicationWriteError;
}
else
{
if(_p_i2c_bus->read(_r_adrs, &data, 1) != I2C_READ_OK)
{
result = OneWireInterface::CommunicationReadError;
}
else
{
recvbyte = data;
result = OneWireInterface::Success;
}
}
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWWriteBlock(const uint8_t *tran_buf, uint8_t tran_len)
{
OneWireInterface::CmdResult result;
for(uint8_t idx = 0; idx < tran_len; idx++)
{
result = OWWriteByte(tran_buf[idx]);
if(result != OneWireInterface::Success)
{
break;
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWReadBlock(uint8_t *rx_buf, uint8_t rx_len)
{
OneWireInterface::CmdResult result;
for(uint8_t idx = 0; idx < rx_len; idx++)
{
//OwReadByte() uses pass by reference
result = OWReadByte(rx_buf[idx]);
if(result != OneWireInterface::Success)
{
break;
}
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWSearch(RomId & romId)
{
int id_bit_number;
int last_zero, rom_byte_number;
int id_bit, cmp_id_bit;
unsigned char rom_byte_mask, status;
bool search_result;
unsigned char crc8 = 0;
SEARCH_DIRECTION search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = false;
// if the last call was not the last one
if (!_last_device_flag)
{
// 1-Wire reset
OneWireInterface::CmdResult result = OWReset();
if (result != OneWireInterface::Success)
{
// reset the search
_last_discrepancy = 0;
_last_device_flag = false;
_last_family_discrepancy = 0;
return result;
}
// issue the search command
OWWriteByte(0xF0);
// loop to do the search
do
{
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < _last_discrepancy)
{
if ((romId[rom_byte_number] & rom_byte_mask) > 0)
search_direction = DIRECTION_WRITE_ONE;
else
search_direction = DIRECTION_WRITE_ZERO;
}
else
{
// if equal to last pick 1, if not then pick 0
if (id_bit_number == _last_discrepancy)
search_direction = DIRECTION_WRITE_ONE;
else
search_direction = DIRECTION_WRITE_ZERO;
}
// Peform a triple operation on the DS2465 which will perform 2 read bits and 1 write bit
search_triplet(search_direction, status);
// check bit results in status byte
id_bit = ((status & STATUS_SBR) == STATUS_SBR);
cmp_id_bit = ((status & STATUS_TSB) == STATUS_TSB);
search_direction = ((status & STATUS_DIR) == STATUS_DIR) ? DIRECTION_WRITE_ONE : DIRECTION_WRITE_ZERO;
// check for no devices on 1-wire
if ((id_bit) && (cmp_id_bit))
break;
else
{
if ((!id_bit) && (!cmp_id_bit) && (search_direction == DIRECTION_WRITE_ZERO))
{
last_zero = id_bit_number;
// check for Last discrepancy in family
if (last_zero < 9)
_last_family_discrepancy = last_zero;
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction == DIRECTION_WRITE_ONE)
romId[rom_byte_number] |= rom_byte_mask;
else
romId[rom_byte_number] &= (unsigned char)~rom_byte_mask;
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0)
{
crc8 = romId.calculateCRC8(crc8, romId[rom_byte_number]); // accumulate the CRC
rom_byte_number++;
rom_byte_mask = 1;
}
}
}
while(rom_byte_number < RomId::byteLen); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!((id_bit_number <= (RomId::byteLen * 8)) || (crc8 != 0)))
{
// search successful so set m_last_discrepancy,m_last_device_flag,search_result
_last_discrepancy = last_zero;
// check for last device
if (_last_discrepancy == 0)
_last_device_flag = true;
search_result = true;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || (romId.familyCode() == 0))
{
_last_discrepancy = 0;
_last_device_flag = false;
_last_family_discrepancy = 0;
search_result = false;
}
return search_result ? OneWireInterface::Success : OneWireInterface::OperationFailure;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWSpeed(OW_SPEED new_speed)
{
// set the speed
if (new_speed == SPEED_OVERDRIVE)
{
_c1WS = CONFIG_1WS;
}
else
{
_c1WS = 0;
}
// write the new config, and return result of op
return write_config(_c1WS | _cSPU | _cPDN | _cAPU);
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWLevel(OW_LEVEL new_level)
{
OneWireInterface::CmdResult result;
// function only will turn back to non-strong pull-up
if (new_level != LEVEL_NORMAL)
{
result = OneWireInterface::OperationFailure;
}
else
{
// clear the strong pull-up bit in the global config state
_cSPU = 0;
result = write_config(_c1WS | _cSPU | _cPDN | _cAPU);
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWWriteBytePower(uint8_t sendbyte)
{
OneWireInterface::CmdResult result;
// set strong pull-up enable
_cSPU = CONFIG_SPU;
// write the new config
result = write_config(_c1WS | _cSPU | _cPDN | _cAPU);
if (result == OneWireInterface::Success)
{
// perform write byte
result = OWWriteByte(sendbyte);
}
return result;
}
//*********************************************************************
OneWireInterface::CmdResult Ds248x::OWReadBitPower(uint8_t applyPowerResponse)
{
OneWireInterface::CmdResult result;
uint8_t rdbit;
// set strong pull-up enable
_cSPU = CONFIG_SPU;
// write the new config
result = write_config(_c1WS | _cSPU | _cPDN | _cAPU);
if (result == OneWireInterface::Success)
{
// perform read bit
result = OWReadBit(rdbit);
if(result == OneWireInterface::Success)
{
// check if response was correct, if not then turn off strong pull-up
if (rdbit != applyPowerResponse)
{
OWLevel(LEVEL_NORMAL);
result = OneWireInterface::OperationFailure;
}
}
}
return result;
}
OneWireInterface::CmdResult Ds248x::OWReadBytePower(uint8_t & recvbyte)
{
OneWireInterface::CmdResult result = Success;
uint8_t recvbit;
recvbyte = 0;
for (unsigned int i = 1; i <= 8; i++)
{
// Set strong pull-up on last bit
if (i == 8)
{
// set strong pull-up enable
_cSPU = CONFIG_SPU;
// write the new config
result = write_config(_c1WS | _cSPU | _cPDN | _cAPU);
if (result != Success)
break;
}
result = OWReadBit(recvbit);
if (result != Success)
break;
recvbyte = (recvbyte << 1) | recvbit;
}
return result;
}
//*********************************************************************
void Ds248x::set_i2c_adrs(DS248X_I2C_ADRS adrs)
{
_w_adrs = (adrs << 1);
_r_adrs = (_w_adrs | 1);
}