1-Wire® library for mbed. Complete 1-Wire library that supports our silicon masters along with a bit-bang master on the MAX32600MBED platform with one common interface for mbed. Slave support has also been included and more slaves will be added as time permits.
Dependents: MAXREFDES131_Qt_Demo MAX32630FTHR_iButton_uSD_Logger MAX32630FTHR_DS18B20_uSD_Logger MAXREFDES130_131_Demo ... more
Superseded by MaximInterface.
OneWire_Masters/DS2465/DS2465.cpp
- Committer:
- IanBenzMaxim
- Date:
- 2016-03-22
- Revision:
- 24:8942d8478d68
- Parent:
- 22:686273e55cdc
- Child:
- 26:a361e3f42ba5
File content as of revision 24:8942d8478d68:
#include "DS2465.hpp" #define I2C_WRITE 0 #define I2C_READ 1 // DS2465 commands #define CMD_1WMR 0xF0 #define CMD_WCFG 0xD2 #define CMD_CHSL 0xC3 #define CMD_SRP 0xE1 #define CMD_1WRS 0xB4 #define CMD_1WWB 0xA5 #define CMD_1WRB 0x96 #define CMD_1WSB 0x87 #define CMD_1WT 0x78 #define CMD_1WTB 0x69 #define CMD_1WRF 0xE1 #define CMD_CPS 0x5A #define CMD_CSS 0x4B #define CMD_CSAM 0x3C #define CMD_CSWM 0x2D #define CMD_CNMS 0x1E #define CMD_SPR 0x0F // DS2465 status bits #define STATUS_1WB 0x01 #define STATUS_PPD 0x02 #define STATUS_SD 0x04 #define STATUS_LL 0x08 #define STATUS_RST 0x10 #define STATUS_SBR 0x20 #define STATUS_TSB 0x40 #define STATUS_DIR 0x80 // delays (if not polling for complete) #define EEPROM_WRITE_DELAY 30 #define LOAD_SECRET_DELAY 90 #define SHA_COMPUTATION_DELAY 5 static const int I2C_WRITE_OK = 0; std::uint8_t DS2465::Config::readByte() const { std::uint8_t config = 0; if (c1WS) config |= 0x08; if (cSPU) config |= 0x04; if (cPDN) config |= 0x02; if (cAPU) config |= 0x01; return config; } std::uint8_t DS2465::Config::writeByte() const { std::uint8_t config = readByte(); return ((~config << 4) | config); } void DS2465::Config::reset() { c1WS = cSPU = cPDN = false; cAPU = true; } DS2465::DS2465(I2C & I2C_interface, unsigned char I2C_address) : m_I2C_interface(I2C_interface), m_I2C_address(I2C_address) { } OneWireMaster::CmdResult DS2465::OWInitMaster() { return Detect(); } //-------------------------------------------------------------------------- // Compute Next Master Secret DS2465 // // 'swap' - 1 if swapping a page into the computation // 'page' - page number to swap in // 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page // // Returns: true write successful // false failure to complete read // OneWireMaster::CmdResult DS2465::Compute_NextMasterSecret(bool swap, unsigned int pageNum, PageRegion region) { uint8_t command[2] = { CMD_CNMS, (swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) }; return WriteMemory(ADDR_CMD_REG, command, 2); } //-------------------------------------------------------------------------- // Compute Write MAC DS2465 // // 'regwrite' - true if writing to a register, false if regular memory // 'swap' - true if swapping a page into the computation // 'page' - page number to swap in // 'segment' - segment number if swaping // // Returns: true write successful // false failure to complete read // OneWireMaster::CmdResult DS2465::Compute_WriteMAC(bool regwrite, bool swap, unsigned int pageNum, unsigned int segmentNum) const { uint8_t command[2] = { CMD_CSWM, ((regwrite << 7) | (swap << 6) | (pageNum << 4) | segmentNum) }; return CWriteMemory(ADDR_CMD_REG, command, 2); } //-------------------------------------------------------------------------- // Compute Slave Authentication MAC DS2465 // // 'swap' - true if swapping a page into the computation // 'page' - page number to swap in // 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page // // Returns: true write successful // false failure to complete read // OneWireMaster::CmdResult DS2465::Compute_AuthMAC(bool swap, unsigned int pageNum, PageRegion region) const { uint8_t command[2] = { CMD_CSAM, (swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) }; return CWriteMemory(ADDR_CMD_REG, command, 2); } //-------------------------------------------------------------------------- // Compute S-Secret on DS2465 // // 'swap' - true if swapping a page into the computation // 'page' - page number to swap in // 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page // // Returns: true write successful // false failure to complete read // OneWireMaster::CmdResult DS2465::Compute_SSecret(bool swap, unsigned int pageNum, PageRegion region) { uint8_t command[2] = { CMD_CSS, (swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) }; return WriteMemory(ADDR_CMD_REG, command, 2); } ISha256MacCoprocessor::CmdResult DS2465::setMasterSecret(const std::uint8_t (&secret)[secret_len]) { OneWireMaster::CmdResult result; result = WriteMemory(ADDR_SPAD, secret, secret_len); if (result == OneWireMaster::Success) result = CopyScratchpad(1, 0, 1, 0); if (result == OneWireMaster::Success) wait_ms(8 * EEPROM_WRITE_DELAY); return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } ISha256MacCoprocessor::CmdResult DS2465::ComputeAndRead_WriteMAC(const std::uint8_t (&WriteMAC_data)[WriteMAC_data_len], std::uint8_t (&mac)[mac_len]) const { OneWireMaster::CmdResult result; // Write input data to scratchpad result = WriteScratchpad(WriteMAC_data, WriteMAC_data_len); // Compute MAC if (result == OneWireMaster::Success) result = Compute_WriteMAC(false, false, 0, 0); if (result == OneWireMaster::Success) { wait_ms(SHA_COMPUTATION_DELAY); // Read MAC from register result = ReadMemory(ADDR_MAC_READ, mac, mac_len, true); } return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } ISha256MacCoprocessor::CmdResult DS2465::ComputeAndRead_AuthMAC(const std::uint8_t (&devicePage)[devicePage_len], const std::uint8_t (&challenge)[deviceScratchpad_len], const std::uint8_t (&AuthMAC_data)[AuthMAC_data_len], std::uint8_t (&mac)[mac_len]) const { OneWireMaster::CmdResult result; int addr = ADDR_SPAD; // Write input data to scratchpad result = CWriteMemory(addr, devicePage, devicePage_len); if (result == OneWireMaster::Success) { addr += devicePage_len; result = CWriteMemory(addr, challenge, deviceScratchpad_len); } if (result == OneWireMaster::Success) { addr += deviceScratchpad_len; result = CWriteMemory(addr, AuthMAC_data, AuthMAC_data_len); } // Compute MAC if (result == OneWireMaster::Success) result = Compute_AuthMAC(false, 0, REGION_FULL_PAGE); if (result == OneWireMaster::Success) { wait_ms(SHA_COMPUTATION_DELAY * 2); // Read MAC from register result = ReadMemory(ADDR_MAC_READ, mac, mac_len, true); } return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } ISha256MacCoprocessor::CmdResult DS2465::Compute_SSecret(const unsigned char (&devicePage)[devicePage_len], const unsigned char (&deviceScratchpad)[deviceScratchpad_len], const unsigned char (&SSecret_data)[SSecret_data_len]) { OneWireMaster::CmdResult result; int addr = ADDR_SPAD; // Write input data to scratchpad result = WriteMemory(addr, devicePage, devicePage_len); if (result == OneWireMaster::Success) { addr += devicePage_len; result = WriteMemory(addr, deviceScratchpad, deviceScratchpad_len); } if (result == OneWireMaster::Success) { addr += deviceScratchpad_len; result = WriteMemory(addr, SSecret_data, SSecret_data_len); } // Compute secret if (result == OneWireMaster::Success) result = Compute_SSecret(false, 0, REGION_FULL_PAGE); if (result == OneWireMaster::Success) wait_ms(SHA_COMPUTATION_DELAY * 2); return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure); } //-------------------------------------------------------------------------- // Copy Scratchpad on DS2465 to either secret or memory page // // 'dest_secret' - 1 if destination is secret, 0 if memory page // 'page' - page number if dest_secret=0 // 'notfull' - 0 if only 4 byte segment, 1 if writing to full page, // 'seg' - Segment number if full=0. // // Returns: true write successful // false failure to complete read // OneWireMaster::CmdResult DS2465::CopyScratchpad(bool dest_secret, unsigned int pageNum, bool notFull, unsigned int segmentNum) { uint8_t command[2] = { CMD_CPS, (dest_secret ? 0 : (0x80 | (pageNum << 4) | (notFull << 3) | segmentNum)) }; return WriteMemory(ADDR_CMD_REG, command, 2); } //-------------------------------------------------------------------------- // APU enable or disable // // 'readflag' - 1 if reading current configuration // 'apu_enable' - 1 to enable // // Returns: true if write successful, or return configuration value if reading // OneWireMaster::CmdResult DS2465::ConfigureAPU(bool apu_enable) { // clear power down bit in the global config state m_curConfig.cAPU = apu_enable; // write the new config return WriteConfig(m_curConfig); } //-------------------------------------------------------------------------- // Power up 1-Wire using extended function // // Returns: true successful // false failure during communication // OneWireMaster::CmdResult DS2465::OWPowerUp(void) { OneWireMaster::CmdResult rt; // clear power down bit in the global config state m_curConfig.cPDN = false; // write the new config rt = WriteConfig(m_curConfig); // delay 2ms to allow units to power up wait_ms(2); return rt; } //-------------------------------------------------------------------------- // Power down 1-Wire using extended function // // Returns: true successful // false program voltage not available // OneWireMaster::CmdResult DS2465::OWPowerDown(void) { // set power down bit in the global config state m_curConfig.cPDN = true; // write the new config return WriteConfig(m_curConfig); } //-------------------------------------------------------------------------- // Send 1 bit of communication to the 1-Wire Net and verify that the // response matches the 'applyPowerResponse' bit and apply power delivery // to the 1-Wire net. Note that some implementations may apply the power // first and then turn it off if the response is incorrect. // // 'applyPowerResponse' - 1 bit response to check, if correct then start // power delivery // // Returns: true: bit written and response correct, strong pullup now on // false: response incorrect // OneWireMaster::CmdResult DS2465::OWReadBitPower(uint8_t applyPowerResponse) { OneWireMaster::CmdResult result; uint8_t rdbit; // set strong pull-up enable m_curConfig.cSPU = true; // write the new config result = WriteConfig(m_curConfig); if (result != OneWireMaster::Success) return result; // perform read bit result = OWReadBit(rdbit); if (result != OneWireMaster::Success) return result; // check if response was correct, if not then turn off strong pull-up if (rdbit != applyPowerResponse) { OWLevel(LEVEL_NORMAL); return OneWireMaster::OperationFailure; } return OneWireMaster::Success; } //-------------------------------------------------------------------------- // Read 8 bits of communication from the 1-Wire Net. After the // 8 bits are read then change the level of the 1-Wire net. // // Returns: 8 bits read from 1-Wire Net // OneWireMaster::CmdResult DS2465::OWReadBytePower(uint8_t & recvbyte) { OneWireMaster::CmdResult result; // set strong pull-up enable m_curConfig.cSPU = true; // write the new config result = WriteConfig(m_curConfig); if (result != OneWireMaster::Success) return result; // do the read byte result = OWReadByte(recvbyte); return result; } //-------------------------------------------------------------------------- // Send 8 bits of communication to the 1-Wire Net and verify that the // 8 bits read from the 1-Wire Net is the same (write operation). // The parameter 'sendbyte' least significant 8 bits are used. After the // 8 bits are sent change the level of the 1-Wire net. // // 'sendbyte' - 8 bits to send (least significant bit) // OneWireMaster::CmdResult DS2465::OWWriteBytePower(uint8_t sendbyte) { OneWireMaster::CmdResult result; // set strong pull-up enable m_curConfig.cSPU = true; // write the new config result = WriteConfig(m_curConfig); if (result != OneWireMaster::Success) return result; // perform write byte return OWWriteByte(sendbyte); } //-------------------------------------------------------------------------- // Set the 1-Wire Net line level pull-up to normal. The DS2465 does only // allows enabling strong pull-up on a bit or byte event. Consequently this // function only allows the MODE_STANDARD argument. To enable strong pull-up // use OWWriteBytePower or OWReadBitPower. // // 'new_level' - new level defined as // MODE_STANDARD 0x00 // // Returns: current 1-Wire Net level // OneWireMaster::CmdResult DS2465::OWLevel(OW_LEVEL new_level) { // function only will turn back to non-strong pull-up if (new_level != LEVEL_NORMAL) return OneWireMaster::OperationFailure; // clear the strong pull-up bit in the global config state m_curConfig.cSPU = false; // write the new config return WriteConfig(m_curConfig); } //-------------------------------------------------------------------------- // Set the 1-Wire Net communication speed. // // 'new_speed' - new speed defined as // MODE_STANDARD 0x00 // MODE_OVERDRIVE 0x01 // // Returns: current 1-Wire Net speed // OneWireMaster::CmdResult DS2465::OWSpeed(OW_SPEED new_speed) { // set the speed m_curConfig.c1WS = (new_speed == SPEED_OVERDRIVE); // write the new config return WriteConfig(m_curConfig); } //-------------------------------------------------------------------------- // Use the DS2465 help command '1-Wire triplet' to perform one bit of a 1-Wire // search. This command does two read bits and one write bit. The write bit // is either the default direction (all device have same bit) or in case of // a discripancy, the 'search_direction' parameter is used. // // Returns � The DS2465 status byte result from the triplet command // OneWireMaster::CmdResult DS2465::Triplet(Direction search_direction, uint8_t & status) { // 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 OneWireMaster::CmdResult result; uint8_t command[2] = { CMD_1WT, ((search_direction == DIRECTION_WRITE_ONE) ? 0x80 : 0x00) }; result = WriteMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = PollBusy(&status); return result; } //-------------------------------------------------------------------------- // The 'OWSearch' function does a general search. This function // continues from the previos search state. The search state // can be reset by using the 'OWFirst' function. // This function contains one parameter 'alarm_only'. // When 'alarm_only' is true (1) the find alarm command // 0xEC is sent instead of the normal search command 0xF0. // Using the find alarm command 0xEC will limit the search to only // 1-Wire devices that are in an 'alarm' state. // // Returns: true (1) : when a 1-Wire device was found and it's // Serial Number placed in the global ROM // false (0): when no new device was found. Either the // last search was the last device or there // are no devices on the 1-Wire Net. // OneWireMaster::CmdResult DS2465::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; 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 OneWireMaster::CmdResult result = OWReset(); if (result != OneWireMaster::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 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 ? OneWireMaster::Success : OneWireMaster::OperationFailure; } //-------------------------------------------------------------------------- // The 'OWReadBlock' receives a block of data from the // 1-Wire Net. The destination is the mac buffer (rx_mac=1) or // the scratchpad (rx_mac=0). The result is buffer is returned. // // 'rx_buf' - pointer to a block to receive bytes // of length 'rx_len' from 1-Wire Net // 'rx_len' - length in bytes to read. Only valid numbers are 8,16,20,32; // OneWireMaster::CmdResult DS2465::OWReadBlock(uint8_t *rx_buf, uint8_t rx_len) { // 1-Wire Receive Block (Case A) // S AD,0 [A] ADDR_CMD_REG [A] 1WRF [A] PR [A] P // [] indicates from slave // PR indicates byte containing parameter OneWireMaster::CmdResult result; uint8_t command[2] = { CMD_1WRF, rx_len }; result = WriteMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = PollBusy(); if (result == OneWireMaster::Success) result = ReadMemory(ADDR_SPAD, rx_buf, rx_len, false); return result; } OneWireMaster::CmdResult DS2465::OWWriteBlock(const uint8_t *tran_buf, uint8_t tran_len) { return OWWriteBlock(false, tran_buf, tran_len); } //-------------------------------------------------------------------------- // The 'OWWriteBlock' transfers a block of data to the // 1-Wire Net. The mac buffer can be sent (tx_mac=1) or a // portion of the scratchpad can be sent. // // 'tx_mac' - flag to indicate if the MAC buffer is to be sent (1) or // the data provided in teh tran_buf is to be sent (0) // 'tran_buf' - pointer to a block of bytes // of length 'tran_len' that will be sent // to the 1-Wire Net // 'tran_len' - length in bytes to transfer. Only valid numbers are 8,16,20,32; // OneWireMaster::CmdResult DS2465::OWWriteBlock(bool tx_mac, const uint8_t *tran_buf, uint8_t tran_len) { OneWireMaster::CmdResult result; uint8_t command[2] = { CMD_1WTB, (tx_mac ? 0xFF : tran_len) }; if (!tx_mac) { // prefill scratchpad with required data result = WriteMemory(ADDR_SPAD, tran_buf, tran_len); if (result != OneWireMaster::Success) return result; } // 1-Wire Transmit Block (Case A) // S AD,0 [A] ADDR_CMD_REG [A] 1WTB [A] PR [A] P // [] indicates from slave // PR indicates byte containing parameter result = WriteMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = PollBusy(); return result; } //-------------------------------------------------------------------------- // The 'OWBlock' transfers a block of data to and from the // 1-Wire Net. The result is returned in the same buffer. // // 'tran_buf' - pointer to a block of unsigned // chars of length 'tran_len' that will be sent // to the 1-Wire Net // 'tran_len' - length in bytes to transfer // OneWireMaster::CmdResult DS2465::OWBlock(uint8_t *tran_buf, uint8_t tran_len) { OneWireMaster::CmdResult result; for (uint8_t i = 0; i < tran_len; i++) { result = OWTouchByte(tran_buf[i]); if (result != OneWireMaster::Success) break; } return result; } //-------------------------------------------------------------------------- // Send 8 bits of read communication to the 1-Wire Net and return the // result 8 bits read from the 1-Wire Net. // // Returns: 8 bits read from 1-Wire Net // OneWireMaster::CmdResult DS2465::OWReadByte(uint8_t & recvbyte) { OneWireMaster::CmdResult result; uint8_t buf; // 1-Wire Read Bytes (Case C) // S AD,0 [A] ADDR_CMD_REG [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 buf = CMD_1WRB; result = WriteMemory(ADDR_CMD_REG, &buf, 1); if (result == OneWireMaster::Success) result = PollBusy(); if (result == OneWireMaster::Success) result = ReadMemory(ADDR_DATA_REG, &buf, 1); if (result == OneWireMaster::Success) recvbyte = buf; return result; } //-------------------------------------------------------------------------- // Send 8 bits of communication to the 1-Wire Net and verify that the // 8 bits read from the 1-Wire Net is the same (write operation). // The parameter 'sendbyte' least significant 8 bits are used. // // 'sendbyte' - 8 bits to send (least significant byte) // // Returns: true: bytes written and echo was the same // false: echo was not the same // OneWireMaster::CmdResult DS2465::OWWriteByte(uint8_t sendbyte) { // 1-Wire Write Byte (Case B) // S AD,0 [A] ADDR_CMD_REG [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 OneWireMaster::CmdResult result; uint8_t command[2] = { CMD_1WWB, sendbyte }; result = WriteMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = PollBusy(); return result; } //-------------------------------------------------------------------------- // Send 1 bit of communication to the 1-Wire Net and return the // result 1 bit read from the 1-Wire Net. The parameter 'sendbit' // least significant bit is used and the least significant bit // of the result is the return bit. // // 'sendbit' - the least significant bit is the bit to send // // Returns: 0: 0 bit read from sendbit // 1: 1 bit read from sendbit // OneWireMaster::CmdResult DS2465::OWTouchBit(uint8_t & sendrecvbit) { // 1-Wire bit (Case B) // S AD,0 [A] ADDR_CMD_REG [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 OneWireMaster::CmdResult result; uint8_t command[2] = { CMD_1WSB, (sendrecvbit ? 0x80 : 0x00) }; uint8_t status; result = WriteMemory(ADDR_CMD_REG, command, 2); if (result == OneWireMaster::Success) result = PollBusy(&status); if (result == OneWireMaster::Success) sendrecvbit = (status & STATUS_SBR); return result; } //-------------------------------------------------------------------------- // Write to Scratchpad (SRAM) memory on the DS2465 // // 'addr' - address to start writing (must be in SRAM) // 'buf' - buffer of data to write // 'len' - length to write // // Returns: true write successful // false failure to complete write // OneWireMaster::CmdResult DS2465::CWriteMemory(std::uint8_t addr, const std::uint8_t * buf, size_t bufLen) const { int i; // Write SRAM (Case A) // S AD,0 [A] VSA [A] DD [A] P // \-----/ // Repeat for each data byte // [] indicates from slave // VSA valid SRAM memory address // DD memory data to write m_I2C_interface.start(); if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } if (m_I2C_interface.write((unsigned char)addr) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } // loop to write each byte for (i = 0; i < bufLen; i++) { if (m_I2C_interface.write(buf[i]) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } } m_I2C_interface.stop(); return OneWireMaster::Success; } //-------------------------------------------------------------------------- // Read memory from the DS2465 // // 'addr' - address to start reading // 'buf' - buffer to hold memory read // 'len' - length to read // 'skip_set_pointer' - flag to indicate to skip setting address pointer // // Returns: true read successful // false failure to complete read // OneWireMaster::CmdResult DS2465::ReadMemory(std::uint8_t addr, std::uint8_t * buf, size_t bufLen, bool skip_set_pointer) const { int i; // Read (Case A) // S AD,0 [A] MA [A] Sr AD,1 [A] [DD] A [DD] A\ P // \-----/ // Repeat for each data byte, NAK last byte // [] indicates from slave // MA memory address // DD memory data read m_I2C_interface.start(); if (!skip_set_pointer) { if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } if (m_I2C_interface.write((unsigned char)addr) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } m_I2C_interface.start(); } if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK) { m_I2C_interface.stop(); return OneWireMaster::CommunicationWriteError; } // loop to read each byte, NAK last byte for (i = 0; i < bufLen; i++) { buf[i] = m_I2C_interface.read((i == (bufLen - 1)) ? m_I2C_interface.NoACK : m_I2C_interface.ACK); } m_I2C_interface.stop(); return OneWireMaster::Success; } //-------------------------------------------------------------------------- // Write the configuration register in the DS2465. The configuration // options are provided in the lower nibble of the provided config byte. // The uppper nibble in bitwise inverted when written to the DS2465. // // Returns: true: config written and response correct // false: response incorrect // OneWireMaster::CmdResult DS2465::WriteConfig(const Config & config) { std::uint8_t configBuf; OneWireMaster::CmdResult result; configBuf = config.writeByte(); result = WriteMemory(ADDR_WCFG_REG, &configBuf, 1); if (result == OneWireMaster::Success) { result = ReadMemory(ADDR_WCFG_REG, &configBuf, 1); } if (result == OneWireMaster::Success) { if (configBuf != config.readByte()) result = OneWireMaster::OperationFailure; } return result; } OneWireMaster::CmdResult DS2465::PollBusy(uint8_t * pStatus) { const unsigned int pollLimit = 200; OneWireMaster::CmdResult result; uint8_t status; unsigned int pollCount = 0; // loop checking 1WB bit for completion of 1-Wire operation // abort if poll limit reached do { result = ReadMemory(ADDR_STATUS_REG, &status, 1, true); if (result != OneWireMaster::Success) return result; if (pStatus != NULL) *pStatus = status; if (pollCount++ >= pollLimit) return OneWireMaster::TimeoutError; } while (status & STATUS_1WB); return OneWireMaster::Success; } //-------------------------------------------------------------------------- // Reset all of the devices on the 1-Wire Net and return the result. // // Returns: true(1): presense pulse(s) detected, device(s) reset // false(0): no presense pulses detected // OneWireMaster::CmdResult DS2465::OWReset(void) { // 1-Wire reset (Case B) // S AD,0 [A] ADDR_CMD_REG [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P // \--------/ // Repeat until 1WB bit has changed to 0 // [] indicates from slave OneWireMaster::CmdResult result; uint8_t buf; buf = CMD_1WRS; result = WriteMemory(ADDR_CMD_REG, &buf, 1); if (result == OneWireMaster::Success) result = PollBusy(&buf); if (result == OneWireMaster::Success) { // check for presence detect if ((buf & STATUS_PPD) != STATUS_PPD) result = OneWireMaster::OperationFailure; } return result; } OneWireMaster::CmdResult DS2465::Reset(void) { // Device Reset // S AD,0 [A] ADDR_CMD_REG [A] 1WMR [A] Sr AD,1 [A] [SS] A\ P // [] indicates from slave // SS status byte to read to verify state OneWireMaster::CmdResult result; uint8_t buf; buf = CMD_1WMR; result = WriteMemory(ADDR_CMD_REG, &buf, 1); if (result == OneWireMaster::Success) result = ReadMemory(ADDR_STATUS_REG, &buf, 1, true); if (result == OneWireMaster::Success) { if ((buf & 0xF7) != 0x10) result = OneWireMaster::OperationFailure; } if (result == OneWireMaster::Success) OWReset(); // do a command to get 1-Wire master reset out of holding state return result; } OneWireMaster::CmdResult DS2465::Detect(void) { OneWireMaster::CmdResult result; // reset DS2465 result = Reset(); if (result != OneWireMaster::Success) return result; // default configuration m_curConfig.reset(); // write the default configuration setup result = WriteConfig(m_curConfig); return result; }