diff --git a/DS2482_HAL.c b/DS2482_HAL.c new file mode 100644 index 0000000..10710e5 --- /dev/null +++ b/DS2482_HAL.c @@ -0,0 +1,472 @@ +#include "DS2482_HAL.h" +#include "errors.h" +#include <stdint.h> + +static I2C_HandleTypeDef* hi2c; + +HAL_StatusTypeDef ds2482_init(I2C_HandleTypeDef* handle) { + hi2c = handle; + + HAL_StatusTypeDef status = ds2482_reset(); + if (status != HAL_OK) { + return status; + } + + status = ds2482_write_config(DS2482_CONFIG_APU); + if (status != HAL_OK) { + return status; + } + + uint8_t config; + status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, &config, 1, DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } else if (config != DS2482_CONFIG_APU) { + return HAL_ERROR; + } + + return HAL_OK; +} + +HAL_StatusTypeDef ds2482_reset() { + uint8_t data[1] = {DS2482_CMD_RESET}; + return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); +} + +HAL_StatusTypeDef ds2482_write_config(uint8_t config) { + uint8_t data[2] = {DS2482_CMD_WRITE_CONFIG, config | (~config << 4)}; + return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); +} + +HAL_StatusTypeDef ds2482_set_read_ptr(uint8_t read_ptr) { + uint8_t data[2] = {DS2482_CMD_SET_READ_PTR, read_ptr}; + return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); +} + +HAL_StatusTypeDef ds2482_1w_reset() { + uint8_t data[1] = {DS2482_CMD_1W_RESET}; + HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + DS2482_Status status_reg = {.BUSY = 1}; + uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W; + do { + status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + if (HAL_GetTick() > timeout) { + return HAL_TIMEOUT; + } + } while (status_reg.BUSY); + + if (status_reg.SHORT) { + return HAL_ERROR; + } + + return HAL_OK; +} + +HAL_StatusTypeDef ds2482_1w_write_byte(uint8_t byte) { + uint8_t data[2] = {DS2482_CMD_1W_WRITE_BYTE, byte}; + HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + + DS2482_Status status_reg = {.BUSY = 1}; + uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W; + do { + status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + if (HAL_GetTick() > timeout) { + return HAL_TIMEOUT; + } + } while (status_reg.BUSY); + + return HAL_OK; +} + +HAL_StatusTypeDef ds2482_1w_read_byte(uint8_t* byte) { + uint8_t data[1] = {DS2482_CMD_1W_READ_BYTE}; + HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + + DS2482_Status status_reg = {.BUSY = 1}; + uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W; + do { + status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + if (HAL_GetTick() > timeout) { + return HAL_TIMEOUT; + } + } while (status_reg.BUSY); + + status = ds2482_set_read_ptr(DS2482_READ_DATA); + if (status != HAL_OK) { + return status; + } + + return HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, byte, 1, DS2482_TIMEOUT_I2C); +} + +HAL_StatusTypeDef ds2482_1w_triplet(uint8_t dir) { + uint8_t data[2] = {DS2482_CMD_1W_TRIPLET, dir ? 0xFF : 0x00}; + return HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); +} + +static HAL_StatusTypeDef ds2482_1w_write_bit(bool bit) { + uint8_t data[2] = {DS2482_CMD_1W_SINGLE_BIT, bit ? 0xFF : 0x00}; + HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + + DS2482_Status status_reg = {.BUSY = 1}; + uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W; + do { + status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + if (HAL_GetTick() > timeout) { + return HAL_TIMEOUT; + } + } while (status_reg.BUSY); + + return HAL_OK; +} + +static HAL_StatusTypeDef ds2482_1w_read_bit(bool* bit) { + uint8_t data[2] = {DS2482_CMD_1W_SINGLE_BIT, 0xFF}; + HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, DS2482_I2C_ADDR, data, sizeof(data), DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + + DS2482_Status status_reg = {.BUSY = 1}; + uint16_t timeout = HAL_GetTick() + DS2482_TIMEOUT_1W; + do { + status = HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C); + if (status != HAL_OK) { + return status; + } + if (HAL_GetTick() > timeout) { + return HAL_TIMEOUT; + } + } while (status_reg.BUSY); + + *bit = status_reg.SBR; + return HAL_OK; +} + + + +// +// From https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/187.html +// + + + +// global search state +static uint8_t ROM_NO[8]; +static int LastDiscrepancy; +static int LastFamilyDiscrepancy; +static bool LastDeviceFlag; +static uint8_t crc8; + +//-------------------------------------------------------------------------- +// Setup the search to find the device type 'family_code' on the next call +// to OWNext() if it is present. +// +static void OWTargetSetup(uint8_t family_code) { + int i; + + // set the search state to find SearchFamily type devices + ROM_NO[0] = family_code; + for (i = 1; i < 8; i++) + ROM_NO[i] = 0; + LastDiscrepancy = 64; + LastFamilyDiscrepancy = 0; + LastDeviceFlag = false; +} + +//-------------------------------------------------------------------------- +// Setup the search to skip the current device type on the next call +// to OWNext(). +// +static void OWFamilySkipSetup() { + // set the Last discrepancy to last family discrepancy + LastDiscrepancy = LastFamilyDiscrepancy; + LastFamilyDiscrepancy = 0; + + // check for end of list + if (LastDiscrepancy == 0) + LastDeviceFlag = true; +} + +//-------------------------------------------------------------------------- +// 1-Wire Functions to be implemented for a particular platform +//-------------------------------------------------------------------------- + +//-------------------------------------------------------------------------- +// Reset the 1-Wire bus and return the presence of any device +// Return true : device present +// false : no device present +// +static bool OWReset() { + ds2482_1w_reset(); + DS2482_Status status_reg = {}; + HAL_I2C_Master_Receive(hi2c, DS2482_I2C_ADDR, (uint8_t*)&status_reg, 1, DS2482_TIMEOUT_I2C); + return status_reg.PPD; +} + +//-------------------------------------------------------------------------- +// Send 8 bits of data to the 1-Wire bus +// +static inline void OWWriteByte(uint8_t byte_value) { ds2482_1w_write_byte(byte_value); } + +//-------------------------------------------------------------------------- +// Send 1 bit of data to teh 1-Wire bus +// +static inline void OWWriteBit(uint8_t bit_value) { ds2482_1w_write_bit(bit_value); } + +//-------------------------------------------------------------------------- +// Read 1 bit of data from the 1-Wire bus +// Return 1 : bit read is 1 +// 0 : bit read is 0 +// +static inline uint8_t OWReadBit() { + bool bit; + ds2482_1w_read_bit(&bit); + return bit; +} + +// TEST BUILD +static uint8_t dscrc_table[] = { + 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, 157, 195, 33, 127, 252, 162, + 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, + 128, 222, 60, 98, 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, 70, 24, + 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, 219, 133, 103, 57, 186, 228, 6, 88, + 25, 71, 165, 251, 120, 38, 196, 154, 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, + 122, 36, 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, 140, 210, 48, 110, + 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205, 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, + 111, 49, 178, 236, 14, 80, 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, + 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, 202, 148, 118, 40, 171, 245, + 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, + 244, 170, 72, 22, 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, 116, 42, + 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53}; + +//-------------------------------------------------------------------------- +// Calculate the CRC8 of the byte value provided with the current +// global 'crc8' value. +// Returns current global crc8 value +// +static uint8_t docrc8(uint8_t value) { + crc8 = dscrc_table[crc8 ^ value]; + return crc8; +} + +//-------------------------------------------------------------------------- +// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing +// search state. +// Return true : device found, ROM number in ROM_NO buffer +// false : device not found, end of search +// +static bool OWSearch() { + int id_bit_number; + int last_zero, rom_byte_number, search_result; + int id_bit, cmp_id_bit; + uint8_t rom_byte_mask, search_direction; + + // initialize for search + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = 0; + crc8 = 0; + + // if the last call was not the last one + if (!LastDeviceFlag) { + // 1-Wire reset + if (!OWReset()) { + // reset the search + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + return false; + } + + // issue the search command + OWWriteByte(0xF0); + + // loop to do the search + do { + // read a bit and its complement + id_bit = OWReadBit(); + cmp_id_bit = OWReadBit(); + + // check for no devices on 1-wire + if ((id_bit == 1) && (cmp_id_bit == 1)) + break; + else { + // all devices coupled have 0 or 1 + if (id_bit != cmp_id_bit) + search_direction = id_bit; // bit write value for search + else { + // if this discrepancy if before the Last Discrepancy + // on a previous next then pick the same as last time + if (id_bit_number < LastDiscrepancy) + search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); + else + // if equal to last pick 1, if not then pick 0 + search_direction = (id_bit_number == LastDiscrepancy); + + // if 0 was picked then record its position in LastZero + if (search_direction == 0) { + last_zero = id_bit_number; + + // check for Last discrepancy in family + if (last_zero < 9) + LastFamilyDiscrepancy = last_zero; + } + } + + // set or clear the bit in the ROM byte rom_byte_number + // with mask rom_byte_mask + if (search_direction == 1) + ROM_NO[rom_byte_number] |= rom_byte_mask; + else + ROM_NO[rom_byte_number] &= ~rom_byte_mask; + + // serial number search direction write bit + OWWriteBit(search_direction); + + // 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) { + docrc8(ROM_NO[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 + LastDiscrepancy = last_zero; + + // check for last device + if (LastDiscrepancy == 0) + LastDeviceFlag = true; + + search_result = true; + } + } + + // if no device found then reset counters so next 'search' will be like a first + if (!search_result || !ROM_NO[0]) { + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + search_result = false; + } + + return search_result; +} + +//-------------------------------------------------------------------------- +// Find the 'first' devices on the 1-Wire bus +// Return true : device found, ROM number in ROM_NO buffer +// false : no device present +// +static bool OWFirst() { + // reset the search state + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + + return OWSearch(); +} + +//-------------------------------------------------------------------------- +// Find the 'next' devices on the 1-Wire bus +// Return true : device found, ROM number in ROM_NO buffer +// false : device not found, end of search +// +static inline bool OWNext() { + // leave the search state alone + return OWSearch(); +} + +//-------------------------------------------------------------------------- +// Verify the device with the ROM number in ROM_NO buffer is present. +// Return true : device verified present +// false : device not present +// +static bool OWVerify() { + uint8_t rom_backup[8]; + int 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_NO[i]; + ld_backup = LastDiscrepancy; + ldf_backup = LastDeviceFlag; + lfd_backup = LastFamilyDiscrepancy; + + // set search to find the same device + LastDiscrepancy = 64; + LastDeviceFlag = false; + + if (OWSearch()) { + // check if same device found + rslt = true; + for (i = 0; i < 8; i++) { + if (rom_backup[i] != ROM_NO[i]) { + rslt = false; + break; + } + } + } else + rslt = false; + + // restore the search state + for (i = 0; i < 8; i++) + ROM_NO[i] = rom_backup[i]; + LastDiscrepancy = ld_backup; + LastDeviceFlag = ldf_backup; + LastFamilyDiscrepancy = lfd_backup; + + // return the result of the verify + return rslt; +} + + + +HAL_StatusTypeDef ds2482_1w_search(uint16_t max_devices, uint64_t devices[static max_devices]) { + OWFirst(); + uint16_t count = 0; + do { + uint64_t device = 0; + for (int i = 0; i < 8; i++) { + device |= (uint64_t)ROM_NO[i] << (i * 8); + } + devices[count++] = device; + } while (OWNext() && count < max_devices); + + return HAL_OK; +} diff --git a/DS2482_HAL.h b/DS2482_HAL.h new file mode 100644 index 0000000..13410c8 --- /dev/null +++ b/DS2482_HAL.h @@ -0,0 +1,51 @@ +#pragma once + +#ifndef DS2482_HAL_H +#define DS2482_HAL_H +#include "stm32f3xx_hal.h" + +#define DS2482_I2C_ADDR 0x30 // TODO: change to actual address + +#define DS2482_CMD_RESET 0xF0 +#define DS2482_CMD_SET_READ_PTR 0xE1 +#define DS2482_CMD_WRITE_CONFIG 0xD2 +#define DS2482_CMD_1W_RESET 0xB4 +#define DS2482_CMD_1W_SINGLE_BIT 0x87 +#define DS2482_CMD_1W_WRITE_BYTE 0xA5 +#define DS2482_CMD_1W_READ_BYTE 0x96 +#define DS2482_CMD_1W_TRIPLET 0x78 + +#define DS2482_STATUS 0xF0 +#define DS2482_READ_DATA 0xE1 +#define DS2482_CONFIG 0xC3 + +#define DS2482_CONFIG_APU 1 << 0 +#define DS2482_CONFIG_SPU 1 << 2 +#define DS2482_CONFIG_1WS 1 << 3 + +#define DS2482_TIMEOUT_1W 100 +#define DS2482_TIMEOUT_I2C 100 + +typedef struct { + uint8_t BUSY : 1; + uint8_t PPD : 1; + uint8_t SHORT : 1; + uint8_t LL : 1; + uint8_t RST : 1; + uint8_t SBR : 1; + uint8_t TSB : 1; + uint8_t DIR : 1; +} DS2482_Status; + +HAL_StatusTypeDef ds2482_init(I2C_HandleTypeDef* handle); +HAL_StatusTypeDef ds2482_reset(); +HAL_StatusTypeDef ds2482_write_config(uint8_t config); +HAL_StatusTypeDef ds2482_set_read_ptr(uint8_t read_ptr); +HAL_StatusTypeDef ds2482_1w_reset(); +HAL_StatusTypeDef ds2482_1w_write_byte(uint8_t byte); +HAL_StatusTypeDef ds2482_1w_read_byte(uint8_t* byte); +HAL_StatusTypeDef ds2482_1w_triplet(uint8_t dir); + +HAL_StatusTypeDef ds2482_1w_search(uint16_t max_devices, uint64_t devices[static max_devices]); + +#endif // DS2482_HAL_H \ No newline at end of file