Implementation of 1-Wire with added Alarm Search Functionality
Dependents: Max32630_One_Wire_Interface
Diff: OneWire_Masters/DS248x/ds248x.cpp
- Revision:
- 2:02d228c25fd4
- Parent:
- 1:91e52f8ab8bf
- Child:
- 3:644fc630f958
--- a/OneWire_Masters/DS248x/ds248x.cpp Sat Jan 30 23:00:57 2016 +0000 +++ b/OneWire_Masters/DS248x/ds248x.cpp Sun Jan 31 06:15:24 2016 +0000 @@ -46,6 +46,62 @@ #include "ds248x.h" +//OW ROM Commands +#define READ_ROM 0x33 +#define MATCH_ROM 0x55 +#define SEARCH_ROM 0xF0 +#define SKIP_ROM 0xCC + +// ds248x commands +#define CMD_DRST 0xF0 +#define CMD_WCFG 0xD2 +#define CMD_A1WP 0xC3 //DS2484 only +#define CMD_CHSL 0xC3 //DS2482-800 only +#define CMD_SRP 0xE1 +#define CMD_1WRS 0xB4 +#define CMD_1WWB 0xA5 +#define CMD_1WRB 0x96 +#define CMD_1WSB 0x87 +#define CMD_1WT 0x78 + +// ds248x config bits +#define CONFIG_APU 0x01 +#define CONFIG_PDN 0x02 +#define CONFIG_SPU 0x04 +#define CONFIG_1WS 0x08 + +// ds248x 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 + +// ds2484 adjustable parameters +#define TRSTL 0 +#define TRSTL_OD 1 +#define TMSP 2 +#define TMSP_OD 3 +#define TW0L 4 +#define TW0L_OD 5 +#define TREC0 6 //OD NA +#define RWPU 8 //OD NA + + +// misc constants +#define POLL_LIMIT 200 +#define TRUE 1 +#define FALSE 0 + +// API mode bit flags +#define MODE_STANDARD 0x00 +#define MODE_OVERDRIVE 0x01 +#define MODE_STRONG 0x02 + + //********************************************************************* Ds248x::Ds248x(I2C *p_i2c_bus, ds248x_i2c_adrs_t adrs) { @@ -77,36 +133,250 @@ //********************************************************************* -uint8_t Ds248x::detect(void) +bool Ds248x::detect(void) +{ + bool rtn_val = false; + + // reset the ds2484 ON selected address + if (!reset()) + { + rtn_val = false; + } + else + { + // default configuration + _c1WS = FALSE; + _cSPU = FALSE; + _cPDN = FALSE; + _cAPU = FALSE; + + // write the default configuration setup + if (!write_config(_c1WS | _cSPU | _cPDN | _cAPU)) + { + rtn_val = false; + } + else + { + rtn_val = true; + } + } + + return(rtn_val); +} + + +//********************************************************************* +bool Ds248x::reset(void) { - uint8_t rtn_val; + 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 + + _p_i2c_bus->write(_w_adrs, packet, 1); + _p_i2c_bus->read(_r_adrs, &status, 1); + + return((status & 0xF7) == 0x10); +} + + +//********************************************************************* +bool Ds248x::write_config(uint8_t config) +{ + bool rtn_val = false; + char read_config; + char packet [] = {CMD_WCFG, (config | (~config << 4))}; + + _p_i2c_bus->write(_w_adrs, packet, 2); + _p_i2c_bus->read(_r_adrs, &read_config, 1); + + // check for failure due to incorrect read back + if (config != read_config) + { + // handle error + // ... + reset(); + rtn_val = false; + } + else + { + rtn_val = true; + } + return(rtn_val); } //********************************************************************* -uint8_t Ds248x::reset(void) +bool Ds248x::channel_select(uint8_t channel) { - uint8_t rtn_val; - return(rtn_val); + + 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; + + _p_i2c_bus->write(_w_adrs, packet, 2); + _p_i2c_bus->read(_r_adrs, &check, 1); + + // check for failure due to incorrect read back of channel + return (check == ch_read); +} + + +//********************************************************************* +bool Ds248x::adjust_timing(uint8_t param, uint8_t val) +{ + bool rtn_val = false; + char read_port_config; + char control_byte; + + control_byte = (((param & 0x0F) << 4) | (val & 0x0F)); + + char packet [] = {CMD_A1WP, control_byte}; + + _p_i2c_bus->write(_w_adrs, packet, 2); + _p_i2c_bus->read(_r_adrs, &read_port_config, 1); + + // check for failure due to incorrect read back + if ((control_byte & 0x0F) != read_port_config) + { + // handle error + // ... + reset(); + + rtn_val = false; + } + else + { + rtn_val = true; + } + + return(rtn_val); } //********************************************************************* -uint8_t Ds248x::write_config(uint8_t config) +uint8_t Ds248x::search_triplet(uint8_t search_direction) { - uint8_t rtn_val; - return(rtn_val); + uint8_t rtn_val = 0; + uint8_t poll_count = 0; + char status; + char packet [] = {CMD_1WT, search_direction ? 0x80 : 0x00}; + + // 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 + + _p_i2c_bus->write(_w_adrs, packet, 2); + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + do + { + _p_i2c_bus->read(_r_adrs, &status, 1); + } + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + reset(); + rtn_val = FALSE; + } + else + { + rtn_val = status; + } + + return(rtn_val); } //********************************************************************* +bool Ds248x::OWReset() +{ + bool rtn_val = false; + + 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 + + _p_i2c_bus->write(_w_adrs, packet, 1); + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + do + { + _p_i2c_bus->read(_r_adrs, &status, 1); + } + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)); -//********************************************************************* -uint8_t Ds248x::OWReset() -{ - uint8_t rtn_val; + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + reset(); + rtn_val = false; + } + else + { + // check for short condition + if (status & STATUS_SD) + { + _short_detected = TRUE; + } + else + { + _short_detected = FALSE; + } + + // check for presence detect + if (status & STATUS_PPD) + { + rtn_val = true; + } + else + { + rtn_val = false; + } + } + return(rtn_val); } @@ -114,15 +384,14 @@ //********************************************************************* void Ds248x::OWWriteBit(uint8_t sendbit) { - + OWTouchBit(sendbit); } //********************************************************************* uint8_t Ds248x::OWReadBit() { - uint8_t rtn_val; - return(rtn_val); + return(OWTouchBit(0x01)); } @@ -130,14 +399,92 @@ uint8_t Ds248x::OWTouchBit(uint8_t sendbit) { uint8_t rtn_val; - return(rtn_val); + uint8_t poll_count = 0; + char status; + char packet[] = {CMD_1WSB, sendbit ? 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 + + _p_i2c_bus->write(_w_adrs, packet, 2); + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + do + { + _p_i2c_bus->read(_r_adrs, &status, 1); + } + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + reset(); + rtn_val = 0; + } + else + { + // return bit state + if (status & STATUS_SBR) + { + rtn_val = 1; + } + else + { + rtn_val = 0; + } + } + + return(rtn_val); } //********************************************************************* -void Ds248x::OWWRiteByte(uint8_t sendbyte) +bool Ds248x::OWWriteByte(uint8_t sendbyte) { + bool rtn_val = false; + 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 + + _p_i2c_bus->write(_w_adrs, packet, 2); + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + do + { + _p_i2c_bus->read(_r_adrs, &status, 1); + } + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + reset(); + rtn_val = false; + } + else + { + rtn_val = true; + } + + return(rtn_val); } @@ -145,6 +492,49 @@ uint8_t Ds248x::OWReadByte(void) { uint8_t rtn_val; + + 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 + + _p_i2c_bus->write(_w_adrs, packet, 1); + + // loop checking 1WB bit for completion of 1-Wire operation + // abort if poll limit reached + do + { + _p_i2c_bus->read(_r_adrs, &status, 1); + } + while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT)); + + // check for failure due to poll limit reached + if (poll_count >= POLL_LIMIT) + { + // handle error + // ... + reset(); + rtn_val = 0; + } + else + { + packet[0] = CMD_SRP; + packet[1] = 0xE1; + + _p_i2c_bus->write(_w_adrs, packet, 2); + _p_i2c_bus->read(_r_adrs, &data, 1); + + rtn_val = data; + } + return(rtn_val); } @@ -153,6 +543,17 @@ uint8_t Ds248x::OWTouchByte(uint8_t sendbyte) { uint8_t rtn_val; + + if (sendbyte == 0xFF) + { + rtn_val = OWReadByte(); + } + else + { + OWWriteByte(sendbyte); + rtn_val = sendbyte; + } + return(rtn_val); } @@ -160,29 +561,88 @@ //********************************************************************* void Ds248x::OWBlock(uint8_t *tran_buf, uint8_t tran_len) { - + uint8_t i; + + for (i = 0; i < tran_len; i++) + { + tran_buf[i] = OWTouchByte(tran_buf[i]); + } } //********************************************************************* -void Ds248x::OWFirst(void) +bool Ds248x::OWFirst(void) { - + // reset the search state + _last_discrepancy = 0; + _last_device_flag = FALSE; + _last_family_discrepancy = 0; + + return OWSearch(); +} + + +//********************************************************************* +bool Ds248x::OWNext(void) +{ + // leave the search state alone + return OWSearch(); } //********************************************************************* -uint8_t Ds248x::OWNext(void) +bool Ds248x::OWVerify(void) { - uint8_t rtn_val; - return(rtn_val); -} + bool rtn_val = false; + + uint8_t rom_backup[8]; + uint8_t i,rslt,ld_backup,ldf_backup,lfd_backup; + + // keep a backup copy of the current state + for (i = 0; i < 8; i++) + { + rom_backup[i] = _rom_number[i]; + } + + ld_backup = _last_discrepancy; + ldf_backup = _last_device_flag; + lfd_backup = _last_family_discrepancy; + + // set search to find the same device + _last_discrepancy = 64; + _last_device_flag = FALSE; + if (OWSearch()) + { + // check if same device found + rslt = TRUE; + for (i = 0; i < 8; i++) + { + if (rom_backup[i] != _rom_number[i]) + { + rslt = FALSE; + break; + } + } + } + else + { + rslt = FALSE; + } -//********************************************************************* -uint8_t Ds248x::OWVerify(void) -{ - uint8_t rtn_val; + // restore the search state + for (i = 0; i < 8; i++) + { + _rom_number[i] = rom_backup[i]; + } + + _last_discrepancy = ld_backup; + _last_device_flag = ldf_backup; + _last_family_discrepancy = lfd_backup; + + // return the result of the verify + rtn_val = rslt; + return(rtn_val); } @@ -190,30 +650,180 @@ //********************************************************************* void Ds248x::OWTargetSetup(uint8_t family_code) { + uint8_t i; + + // set the search state to find SearchFamily type devices + _rom_number[0] = family_code; + for (i = 1; i < 8; i++) + { + _rom_number[i] = 0; + } + _last_discrepancy = 64; + _last_family_discrepancy = 0; + _last_device_flag = FALSE; } //********************************************************************* void Ds248x::OWFamilySkipSetup(void) { + // set the Last discrepancy to last family discrepancy + _last_discrepancy = _last_family_discrepancy; + // clear the last family discrpepancy + _last_family_discrepancy = 0; + + // check for end of list + if (_last_discrepancy == 0) + { + _last_device_flag = TRUE; + } } //********************************************************************* -uint8_t Ds248x::OWSearch(void) +bool Ds248x::OWSearch(void) { - uint8_t rtn_val; - return(rtn_val); + uint8_t id_bit_number; + uint8_t last_zero, rom_byte_number, search_result; + uint8_t id_bit, cmp_id_bit; + uint8_t rom_byte_mask, search_direction, status; + + // initialize for search + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = FALSE; + _crc8 = 0; + + // if the last call was not the last one + if (!_last_device_flag) + { + // 1-Wire reset + if (!OWReset()) + { + // reset the search + _last_discrepancy = 0; + _last_device_flag = FALSE; + _last_family_discrepancy = 0; + return FALSE; + } + + // issue the search command + OWWriteByte(SEARCH_ROM); + + // 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 ((_rom_number[rom_byte_number] & rom_byte_mask) > 0) + search_direction = 1; + else + search_direction = 0; + } + else + { + // if equal to last pick 1, if not then pick 0 + if (id_bit_number == _last_discrepancy) + search_direction = 1; + else + search_direction = 0; + } + + // Perform a triple operation on the ds2484 which will perform 2 read bits and 1 write bit + status = search_triplet(search_direction); + + // 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) ? (unsigned char)1 : (unsigned char)0; + + // check for no devices on 1-Wire + if ((id_bit) && (cmp_id_bit)) + break; + else + { + if ((!id_bit) && (!cmp_id_bit) && (search_direction == 0)) + { + 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 == 1) + _rom_number[rom_byte_number] |= rom_byte_mask; + else + _rom_number[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) + { + calc_crc8(_rom_number[rom_byte_number]); // accumulate the CRC + rom_byte_number++; + rom_byte_mask = 1; + } + } + } + while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 + + // if the search was successful then + if (!((id_bit_number < 65) || (_crc8 != 0))) + { + // search successful so set LastDiscrepancy,LastDeviceFlag,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 || (_rom_number[0] == 0)) + { + _last_discrepancy = 0; + _last_device_flag = FALSE; + _last_family_discrepancy = 0; + search_result = FALSE; + } + + return search_result; } //********************************************************************* uint8_t Ds248x::OWSpeed(uint8_t new_speed) { - uint8_t rtn_val; - return(rtn_val); + // set the speed + if (new_speed == MODE_OVERDRIVE) + { + _c1WS = CONFIG_1WS; + } + else + { + _c1WS = FALSE; + } + + // write the new config + write_config(_c1WS | _cSPU | _cPDN | _cAPU); + + return(new_speed); } @@ -221,22 +831,79 @@ uint8_t Ds248x::OWLevel(uint8_t new_level) { uint8_t rtn_val; + + // function only will turn back to non-strong pull-up + if (new_level != MODE_STANDARD) + { + rtn_val = MODE_STRONG; + } + else + { + // clear the strong pull-up bit in the global config state + _cSPU = FALSE; + // write the new config + write_config(_c1WS | _cSPU | _cPDN | _cAPU); + rtn_val = MODE_STANDARD; + } + return(rtn_val); } //********************************************************************* -uint8_t Ds248x::OWWriteBytePower(uint8_t sendbyte) +bool Ds248x::OWWriteBytePower(uint8_t sendbyte) { - uint8_t rtn_val; + bool rtn_val = false; + + // set strong pull-up enable + _cSPU = CONFIG_SPU; + + // write the new config + if (!write_config(_c1WS | _cSPU | _cPDN | _cAPU)) + { + rtn_val = false; + } + else + { + // perform write byte + OWWriteByte(sendbyte); + rtn_val = true; + } + return(rtn_val); } //********************************************************************* -uint8_t Ds248x::OWReadBitPower(uint8_t applyPowerResponse) +bool Ds248x::OWReadBitPower(uint8_t applyPowerResponse) { - uint8_t rtn_val; + bool rtn_val = false; + + uint8_t rdbit; + + // set strong pull-up enable + _cSPU = CONFIG_SPU; + + // write the new config + if (!write_config(_c1WS | _cSPU | _cPDN | _cAPU)) + { + rtn_val = false; + } + else + { + // perform read bit + rdbit = OWReadBit(); + + // check if response was correct, if not then turn off strong pull-up + if (rdbit != applyPowerResponse) + { + OWLevel(MODE_STANDARD); + rtn_val = false; + } + + rtn_val = true; + } + return(rtn_val); } @@ -244,6 +911,31 @@ //********************************************************************* uint8_t Ds248x::calc_crc8(uint8_t data) { - uint8_t rtn_val; - return(rtn_val); + unsigned char i; + + // See Application Note 27 + _crc8 = _crc8 ^ data; + for (i = 0; i < 8; ++i) + { + if (_crc8 & 1) + { + _crc8 = (_crc8 >> 1) ^ 0x8c; + } + else + { + _crc8 = (_crc8 >> 1); + } + } + + return _crc8; +} + + +//********************************************************************* +void Ds248x::get_rom_number(uint8_t *p_rom_buff) +{ + for(uint8_t idx = 0; idx < 8; idx++) + { + *(p_rom_buff + idx) = _rom_number[idx]; + } } \ No newline at end of file