Browse Source

Implement solo device optimisations - if there is only one device on the bus, addressing can be simplified.

main
David Antliff 8 years ago
parent
commit
149c6ce4dc
  1. 11
      README.md
  2. 128
      main/ds18b20.c
  3. 17
      main/ds18b20.h
  4. 23
      main/ds18b20_main.c

11
README.md

@ -8,11 +8,15 @@ It supports multiple devices on the same 1-Wire bus.
It is written and tested for the [ESP-IDF](https://github.com/espressif/esp-idf) environment, using the xtensa-esp32-elf toolchain (gcc version 5.2.0). It is written and tested for the [ESP-IDF](https://github.com/espressif/esp-idf) environment, using the xtensa-esp32-elf toolchain (gcc version 5.2.0).
## Supported Features ## Features
This library includes:
* External power supply mode (parasitic mode not yet supported). * External power supply mode (parasitic mode not yet supported).
* Static (stack-based) or dynamic (malloc-based) memory model. * Static (stack-based) or dynamic (malloc-based) memory model.
* No globals - support any number of 1-Wire buses simultaneously.
* 1-Wire device detection and validation, including search for multiple devices on a single bus. * 1-Wire device detection and validation, including search for multiple devices on a single bus.
* Addressing optimisation for a single (solo) device on a bus.
* 1-Wire bus operations including multi-byte read and write operations. * 1-Wire bus operations including multi-byte read and write operations.
* CRC checks on ROM code and temperature data. * CRC checks on ROM code and temperature data.
* Programmable temperature measurement resolution (9, 10, 11 or 12-bit resolution). * Programmable temperature measurement resolution (9, 10, 11 or 12-bit resolution).
@ -47,9 +51,8 @@ Parts of this code are based on references provided to the public domain by Maxi
The following features are anticipated but not yet implemented: The following features are anticipated but not yet implemented:
* Simultaneous temperature conversion from multiple devices. * Simultaneous temperature conversion from multiple devices on the same bus - concurrency.
* Alarm support. * Alarm support.
* EEPROM support. * EEPROM support.
* Single device optimisations - avoid ROM addressing when only one device exists.
* Parasitic power support. * Parasitic power support.
* FreeRTOS event-based example.

128
main/ds18b20.c

@ -92,6 +92,36 @@ static bool _is_init(const DS18B20_Info * ds18b20_info)
return ok; return ok;
} }
static bool _address_device(const DS18B20_Info * ds18b20_info)
{
bool present = false;
if (_is_init(ds18b20_info))
{
present = owb_reset(ds18b20_info->bus);
if (present)
{
if (ds18b20_info->solo)
{
// if there's only one device on the bus, we can skip
// sending the ROM code and instruct it directly
owb_write_byte(ds18b20_info->bus, OWB_ROM_SKIP);
}
else
{
// if there are multiple devices on the bus, a Match ROM command
// must be issued to address a specific slave
owb_write_byte(ds18b20_info->bus, OWB_ROM_MATCH);
owb_write_rom_code(ds18b20_info->bus, ds18b20_info->rom_code);
}
}
else
{
ESP_LOGE(TAG, "ds18b20 device not responding");
}
}
return present;
}
static bool _check_resolution(DS18B20_RESOLUTION resolution) static bool _check_resolution(DS18B20_RESOLUTION resolution)
{ {
return (resolution >= DS18B20_RESOLUTION_9_BIT) && (resolution <= DS18B20_RESOLUTION_12_BIT); return (resolution >= DS18B20_RESOLUTION_9_BIT) && (resolution <= DS18B20_RESOLUTION_12_BIT);
@ -125,12 +155,12 @@ static Scratchpad _read_scratchpad(const DS18B20_Info * ds18b20_info, size_t cou
count = _min(sizeof(Scratchpad), count); // avoid overflow count = _min(sizeof(Scratchpad), count); // avoid overflow
Scratchpad scratchpad = {0}; Scratchpad scratchpad = {0};
ESP_LOGD(TAG, "scratchpad read %d bytes: ", count); ESP_LOGD(TAG, "scratchpad read %d bytes: ", count);
owb_reset(ds18b20_info->bus); if (_address_device(ds18b20_info))
owb_write_byte(ds18b20_info->bus, OWB_ROM_MATCH); {
owb_write_rom_code(ds18b20_info->bus, ds18b20_info->rom_code); owb_write_byte(ds18b20_info->bus, DS18B20_FUNCTION_SCRATCHPAD_READ);
owb_write_byte(ds18b20_info->bus, DS18B20_FUNCTION_SCRATCHPAD_READ); owb_read_bytes(ds18b20_info->bus, (uint8_t *)&scratchpad, count);
owb_read_bytes(ds18b20_info->bus, (uint8_t *)&scratchpad, count); esp_log_buffer_hex(TAG, &scratchpad, count);
esp_log_buffer_hex(TAG, &scratchpad, count); }
return scratchpad; return scratchpad;
} }
@ -141,26 +171,26 @@ static bool _write_scratchpad(const DS18B20_Info * ds18b20_info, const Scratchpa
// All three bytes MUST be written before the next reset to avoid corruption. // All three bytes MUST be written before the next reset to avoid corruption.
if (_is_init(ds18b20_info)) if (_is_init(ds18b20_info))
{ {
owb_reset(ds18b20_info->bus); if (_address_device(ds18b20_info))
owb_write_byte(ds18b20_info->bus, OWB_ROM_MATCH);
owb_write_rom_code(ds18b20_info->bus, ds18b20_info->rom_code);
owb_write_byte(ds18b20_info->bus, DS18B20_FUNCTION_SCRATCHPAD_WRITE);
owb_write_bytes(ds18b20_info->bus, (uint8_t *)&scratchpad->trigger_high, 3);
ESP_LOGD(TAG, "scratchpad write 3 bytes:");
esp_log_buffer_hex(TAG, &scratchpad->trigger_high, 3);
result = true;
if (verify)
{ {
Scratchpad read = _read_scratchpad(ds18b20_info, offsetof(Scratchpad, configuration) + 1); owb_write_byte(ds18b20_info->bus, DS18B20_FUNCTION_SCRATCHPAD_WRITE);
if (memcmp(&scratchpad->trigger_high, &read.trigger_high, 3) != 0) owb_write_bytes(ds18b20_info->bus, (uint8_t *)&scratchpad->trigger_high, 3);
ESP_LOGD(TAG, "scratchpad write 3 bytes:");
esp_log_buffer_hex(TAG, &scratchpad->trigger_high, 3);
result = true;
if (verify)
{ {
ESP_LOGE(TAG, "scratchpad verify failed: " Scratchpad read = _read_scratchpad(ds18b20_info, offsetof(Scratchpad, configuration) + 1);
"wrote {0x%02x, 0x%02x, 0x%02x}, " if (memcmp(&scratchpad->trigger_high, &read.trigger_high, 3) != 0)
"read {0x%02x, 0x%02x, 0x%02x}", {
scratchpad->trigger_high, scratchpad->trigger_low, scratchpad->configuration, ESP_LOGE(TAG, "scratchpad verify failed: "
read.trigger_high, read.trigger_low, read.configuration); "wrote {0x%02x, 0x%02x, 0x%02x}, "
result = false; "read {0x%02x, 0x%02x, 0x%02x}",
scratchpad->trigger_high, scratchpad->trigger_low, scratchpad->configuration,
read.trigger_high, read.trigger_low, read.configuration);
result = false;
}
} }
} }
} }
@ -193,15 +223,45 @@ void ds18b20_free(DS18B20_Info ** ds18b20_info)
} }
} }
void ds18b20_init(DS18B20_Info * ds18b20_info, OneWireBus * bus, OneWireBus_ROMCode rom_code) static void _init(DS18B20_Info * ds18b20_info, OneWireBus * bus)
{ {
if (ds18b20_info != NULL) if (ds18b20_info != NULL)
{ {
ds18b20_info->bus = bus; ds18b20_info->bus = bus;
ds18b20_info->rom_code = rom_code; memset(&ds18b20_info->rom_code, 0, sizeof(ds18b20_info->rom_code));
ds18b20_info->use_crc = false; ds18b20_info->use_crc = false;
ds18b20_info->resolution = DS18B20_RESOLUTION_INVALID; ds18b20_info->resolution = DS18B20_RESOLUTION_INVALID;
ds18b20_info->solo = false; // assume multiple devices unless told otherwise
ds18b20_info->init = true; ds18b20_info->init = true;
}
else
{
ESP_LOGE(TAG, "ds18b20_info is NULL");
}
}
void ds18b20_init(DS18B20_Info * ds18b20_info, OneWireBus * bus, OneWireBus_ROMCode rom_code)
{
if (ds18b20_info != NULL)
{
_init(ds18b20_info, bus);
ds18b20_info->rom_code = rom_code;
// read current resolution from device as it may not be power-on or factory default
ds18b20_info->resolution = ds18b20_read_resolution(ds18b20_info);
}
else
{
ESP_LOGE(TAG, "ds18b20_info is NULL");
}
}
void ds18b20_init_solo(DS18B20_Info * ds18b20_info, OneWireBus * bus)
{
if (ds18b20_info != NULL)
{
_init(ds18b20_info, bus);
ds18b20_info->solo = true;
// read current resolution from device as it may not be power-on or factory default // read current resolution from device as it may not be power-on or factory default
ds18b20_info->resolution = ds18b20_read_resolution(ds18b20_info); ds18b20_info->resolution = ds18b20_read_resolution(ds18b20_info);
@ -297,26 +357,22 @@ static void _wait_for_conversion(DS18B20_RESOLUTION resolution)
} }
} }
float ds18b20_get_temp(DS18B20_Info * ds18b20_info) float ds18b20_get_temp(const DS18B20_Info * ds18b20_info)
{ {
float temp = 0.0f; float temp = 0.0f;
if (_is_init(ds18b20_info)) if (_is_init(ds18b20_info))
{ {
OneWireBus * bus = ds18b20_info->bus; OneWireBus * bus = ds18b20_info->bus;
if (owb_reset(bus)) if (_address_device(ds18b20_info))
{ {
//owb_write_byte(bus, OWB_ROM_SKIP); // initiate a temperature measurement
owb_write_byte(bus, OWB_ROM_MATCH);
owb_write_rom_code(bus, ds18b20_info->rom_code);
owb_write_byte(bus, DS18B20_FUNCTION_TEMP_CONVERT); owb_write_byte(bus, DS18B20_FUNCTION_TEMP_CONVERT);
// wait at least maximum conversion time
_wait_for_conversion(ds18b20_info->resolution); _wait_for_conversion(ds18b20_info->resolution);
// reset // read measurement
owb_reset(bus); _address_device(ds18b20_info);
//owb_write_byte(bus, OWB_ROM_SKIP);
owb_write_byte(bus, OWB_ROM_MATCH);
owb_write_rom_code(bus, ds18b20_info->rom_code);
owb_write_byte(bus, DS18B20_FUNCTION_SCRATCHPAD_READ); owb_write_byte(bus, DS18B20_FUNCTION_SCRATCHPAD_READ);
uint8_t temp_LSB = 0; uint8_t temp_LSB = 0;

17
main/ds18b20.h

@ -59,6 +59,7 @@ typedef enum
typedef struct typedef struct
{ {
bool init; ///< True if struct has been initialised, otherwise false bool init; ///< True if struct has been initialised, otherwise false
bool solo; ///< True if device is intended to be the only one connected to the bus, otherwise false
bool use_crc; ///< True if CRC checks are to be used when retrieving information from a device on the bus bool use_crc; ///< True if CRC checks are to be used when retrieving information from a device on the bus
OneWireBus * bus; ///< Pointer to 1-Wire bus information relevant to this device OneWireBus * bus; ///< Pointer to 1-Wire bus information relevant to this device
OneWireBus_ROMCode rom_code; ///< The ROM code used to address this device on the bus OneWireBus_ROMCode rom_code; ///< The ROM code used to address this device on the bus
@ -87,6 +88,20 @@ void ds18b20_free(DS18B20_Info ** ds18b20_info);
*/ */
void ds18b20_init(DS18B20_Info * ds18b20_info, OneWireBus * bus, OneWireBus_ROMCode rom_code); void ds18b20_init(DS18B20_Info * ds18b20_info, OneWireBus * bus, OneWireBus_ROMCode rom_code);
/**
* @brief Initialise a device info instance with the specified GPIO as a solo device on the bus.
*
* This is subject to the requirement that this device is the ONLY device on the bus.
* This allows for faster commands to be used without ROM code addressing.
*
* NOTE: if additional devices are added to the bus, operation will cease to work correctly.
*
* @param[in] ds18b20_info Pointer to device info instance.
* @param[in] bus Pointer to initialised 1-Wire bus instance.
* @param[in] rom_code Device-specific ROM code to identify a device on the bus.
*/
void ds18b20_init_solo(DS18B20_Info * ds18b20_info, OneWireBus * bus);
/** /**
* @brief Enable or disable use of CRC checks on device communications. * @brief Enable or disable use of CRC checks on device communications.
* @param[in] ds18b20_info Pointer to device info instance. * @param[in] ds18b20_info Pointer to device info instance.
@ -125,7 +140,7 @@ OneWireBus_ROMCode ds18b20_read_rom(DS18B20_Info * ds18b20_info);
* @param[in] ds18b20_info Pointer to device info instance. Must be initialised first. * @param[in] ds18b20_info Pointer to device info instance. Must be initialised first.
* @return The current temperature returned by the device, in degrees Celsius. * @return The current temperature returned by the device, in degrees Celsius.
*/ */
float ds18b20_get_temp(DS18B20_Info * ds18b20_info); float ds18b20_get_temp(const DS18B20_Info * ds18b20_info);
#ifdef __cplusplus #ifdef __cplusplus

23
main/ds18b20_main.c

@ -36,8 +36,9 @@
#include "ds18b20.h" #include "ds18b20.h"
#define GPIO_DS18B20_0 (GPIO_NUM_4) #define GPIO_DS18B20_0 (GPIO_NUM_5)
#define MAX_DEVICES (8) #define MAX_DEVICES (8)
#define DS18B20_RESOLUTION (DS18B20_RESOLUTION_12_BIT)
void app_main() void app_main()
@ -109,16 +110,20 @@ void app_main()
DS18B20_Info * ds18b20_info = ds18b20_malloc(); // heap allocation DS18B20_Info * ds18b20_info = ds18b20_malloc(); // heap allocation
devices[i] = ds18b20_info; devices[i] = ds18b20_info;
#endif #endif
ds18b20_init(ds18b20_info, owb, device_rom_codes[i]); // associate with bus and device if (num_devices == 1)
//ds18b20_init_solo(ds18b20_info, owb); // only one device on bus {
printf("Single device optimisations enabled\n");
ds18b20_init_solo(ds18b20_info, owb); // only one device on bus
}
else
{
ds18b20_init(ds18b20_info, owb, device_rom_codes[i]); // associate with bus and device
}
ds18b20_use_crc(ds18b20_info, true); // enable CRC check for temperature readings ds18b20_use_crc(ds18b20_info, true); // enable CRC check for temperature readings
// ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION_9_BIT); ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION);
// ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION_10_BIT);
// ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION_11_BIT);
ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION_12_BIT);
} }
// read temperatures from all sensors // read temperatures from all sensors sequentially
while (1) while (1)
{ {
printf("\nTemperature readings (degrees C):\n"); printf("\nTemperature readings (degrees C):\n");

Loading…
Cancel
Save