Skip to content
Snippets Groups Projects
Commit 8b8790c1 authored by Frits Kuipers's avatar Frits Kuipers Committed by Leandro Lanzieri
Browse files

drivers/ds18: Add Maxim Integrated ds18 driver

tests/driver_ds18: Add test application for DS18B20 sensor.

tests/driver_ds18: Add whitelist of boards
parent 13312ef1
No related branches found
No related tags found
No related merge requests found
......@@ -119,6 +119,11 @@ ifneq (,$(filter dynamixel,$(USEMODULE)))
USEMODULE += uart_half_duplex
endif
ifneq (,$(filter ds18,$(USEMODULE)))
USEMODULE += xtimer
FEATURES_REQUIRED += periph_gpio
endif
ifneq (,$(filter enc28j60,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_gpio_irq
......
......@@ -214,6 +214,10 @@ ifneq (,$(filter si114x,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si114x/include
endif
ifneq (,$(filter ds18,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds18/include
endif
ifneq (,$(filter si70xx,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si70xx/include
endif
......
include $(RIOTBASE)/Makefile.base
/*
* Copyright (C) 2017 Frits Kuipers
* 2018 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ds18
* @{
*
* @file
* @brief Device driver implementation for the Maxim Integrated DS1822 and
* DS18B20 temperature sensors.
*
* @author Frits Kuipers <frits.kuipers@gmail.com>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include "ds18.h"
#include "ds18_internal.h"
#include "log.h"
#include "periph/gpio.h"
#include "xtimer.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static void ds18_low(ds18_t *dev)
{
/* Set gpio as output and clear pin */
gpio_init(dev->pin, GPIO_OUT);
gpio_clear(dev->pin);
}
static void ds18_release(ds18_t *dev)
{
/* Init pin as input */
gpio_init(dev->pin, dev->in_mode);
}
static void ds18_write_bit(ds18_t *dev, uint8_t bit)
{
/* Initiate write slot */
ds18_low(dev);
/* Release pin when bit==1 */
if (bit) {
ds18_release(dev);
}
/* Wait for slot to end */
xtimer_usleep(DS18_DELAY_SLOT);
ds18_release(dev);
xtimer_usleep(1);
}
static int ds18_read_bit(ds18_t *dev, uint8_t *bit)
{
/* Initiate read slot */
ds18_low(dev);
ds18_release(dev);
#if defined(MODULE_DS18_OPTIMIZED)
xtimer_usleep(DS18_SAMPLE_TIME);
*bit = gpio_read(dev->pin);
xtimer_usleep(DS18_DELAY_R_RECOVER);
return DS18_OK;
#else
uint32_t start, measurement = 0;
/* Measure time low of device pin, timeout after slot time*/
start = xtimer_now_usec();
while (!gpio_read(dev->pin) && measurement < DS18_DELAY_SLOT) {
measurement = xtimer_now_usec() - start;
}
/* If there was a timeout return error */
if (measurement >= DS18_DELAY_SLOT) {
return DS18_ERROR;
}
/* When gpio was low for less than the sample time, bit is high*/
*bit = measurement < DS18_SAMPLE_TIME;
/* Wait for slot to end */
xtimer_usleep(DS18_DELAY_SLOT - measurement);
return DS18_OK;
#endif
}
static int ds18_read_byte(ds18_t *dev, uint8_t *byte)
{
uint8_t bit = 0;
*byte = 0;
for (int i = 0; i < 8; i++) {
if (ds18_read_bit(dev, &bit) == DS18_OK) {
*byte |= (bit << i);
}
else {
return DS18_ERROR;
}
}
return DS18_OK;
}
static void ds18_write_byte(ds18_t *dev, uint8_t byte)
{
for (int i = 0; i < 8; i++) {
ds18_write_bit(dev, byte & (0x01 << i));
}
}
static int ds18_reset(ds18_t *dev)
{
int res;
/* Line low and sleep the reset delay */
ds18_low(dev);
xtimer_usleep(DS18_DELAY_RESET);
/* Release and wait for the presence response */
ds18_release(dev);
xtimer_usleep(DS18_DELAY_PRESENCE);
/* Check device presence */
res = gpio_read(dev->pin);
/* Sleep for reset delay */
xtimer_usleep(DS18_DELAY_RESET);
return res;
}
int ds18_trigger(ds18_t *dev)
{
int res;
res = ds18_reset(dev);
if (res) {
return DS18_ERROR;
}
/* Please note that this command triggers a conversion on all devices
* connected to the bus. */
ds18_write_byte(dev, DS18_CMD_SKIPROM);
ds18_write_byte(dev, DS18_CMD_CONVERT);
return DS18_OK;
}
int ds18_read(ds18_t *dev, int16_t *temperature)
{
int res;
uint8_t b1 = 0, b2 = 0;
DEBUG("[DS18] Reset and read scratchpad\n");
res = ds18_reset(dev);
if (res) {
return DS18_ERROR;
}
ds18_write_byte(dev, DS18_CMD_SKIPROM);
ds18_write_byte(dev, DS18_CMD_RSCRATCHPAD);
if (ds18_read_byte(dev, &b1) != DS18_OK) {
DEBUG("[DS18] Error reading temperature byte 1\n");
return DS18_ERROR;
}
DEBUG("[DS18] Received byte: 0x%02x\n", b1);
if (ds18_read_byte(dev, &b2) != DS18_OK) {
DEBUG("[DS18] Error reading temperature byte 2\n");
return DS18_ERROR;
}
DEBUG("[DS18] Received byte: 0x%02x\n", b2);
int32_t measurement = ((int32_t)(b2 << 8 | b1) * 625);
*temperature = (int16_t)(measurement / 100);
return DS18_OK;
}
int ds18_get_temperature(ds18_t *dev, int16_t *temperature)
{
DEBUG("[DS18] Convert T\n");
if (ds18_trigger(dev)) {
return DS18_ERROR;
}
DEBUG("[DS18] Wait for convert T\n");
xtimer_usleep(DS18_DELAY_CONVERT);
return ds18_read(dev, temperature);
}
int ds18_init(ds18_t *dev, const ds18_params_t *params)
{
int res;
/* Deduct the input mode from the output mode. If pull-up resistors are
* used for output then will be used for input as well. */
dev->in_mode = (params->out_mode == GPIO_OD_PU) ? GPIO_IN_PU : GPIO_IN;
/* Initialize the device and the pin */
dev->pin = params->pin;
dev->out_mode = params->out_mode;
res = gpio_init(dev->pin, dev->in_mode) == 0 ? DS18_OK : DS18_ERROR;
return res;
}
/*
* Copyright (C) 2017 Frits Kuipers
* 2018 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sensors
* @{
*
* @file
* @brief Internal addresses, registers, constants for DS1822 and DS18B20 temperature sensors.
*
* @author Frits Kuipers <frits.kuipers@gmail.com>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*/
#ifndef DS18_INTERNAL_H
#define DS18_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ds18 commands
* @{
*/
#define DS18_CMD_CONVERT (0x44)
#define DS18_CMD_RSCRATCHPAD (0xbe)
#define DS18_CMD_WRITESCRATCHPAD (0x4e)
#define DS18_CMD_COPYSCRATCHPAD (0x48)
#define DS18_CMD_RECALLE (0xb8)
#define DS18_CMD_RPWRSPPLY (0xb4)
#define DS18_CMD_SEARCHROM (0xf0)
#define DS18_CMD_READROM (0x33)
#define DS18_CMD_MATCHROM (0x55)
#define DS18_CMD_SEARCHROM (0xf0)
#define DS18_CMD_ALARMSEARCH (0xec)
#define DS18_CMD_SKIPROM (0xcc)
/** @} */
/**
* @name ds18 delays
* @{
*/
#define DS18_DELAY_RESET (480U)
#define DS18_DELAY_PRESENCE (60U)
#define DS18_DELAY_SLOT (60U)
#define DS18_SAMPLE_TIME (10U)
#define DS18_DELAY_CONVERT (750U * US_PER_MS)
#define DS18_DELAY_RW_PULSE (1U)
#define DS18_DELAY_R_RECOVER (DS18_DELAY_SLOT - DS18_SAMPLE_TIME)
/** @} */
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* DS18_INTERNAL_H */
/*
* Copyright (C) 2017 Frits Kuipers
* 2018 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ds18
* @{
*
* @file
* @brief SAUL adaption for Maxim Integrated DS1822 and DS18B20 temperature sensors
*
* @author Frits Kuipers <frits.kuipers@gmail.com>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include <string.h>
#include "saul.h"
#include "ds18.h"
static int read_temperature(const void *dev, phydat_t *res)
{
if (ds18_get_temperature((ds18_t *)dev, &res->val[0]) == DS18_ERROR) {
return -ECANCELED;
}
res->unit = UNIT_TEMP_C;
res->scale = -2;
return 1;
}
const saul_driver_t ds18_temperature_saul_driver = {
.read = read_temperature,
.write = saul_notsup,
.type = SAUL_SENSE_TEMP
};
/*
* Copyright (C) 2017 Frits Kuipers
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ds18
*
* @{
* @file
* @brief Default configuration for DS1822 and DS18B20 temperature sensors
*
* @author Frits Kuipers <frits.kuipers@gmail.com>
*/
#ifndef DS18_PARAMS_H
#define DS18_PARAMS_H
#include "ds18.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set default configuration parameters for the ds18
* @{
*/
#ifndef DS18_PARAM_PIN
#define DS18_PARAM_PIN (GPIO_PIN(0, 0))
#endif
#ifndef DS18_PARAM_PULL
#define DS18_PARAM_PULL (GPIO_OD_PU)
#endif
#define DS18_PARAMS_DEFAULT { .pin = DS18_PARAM_PIN, \
.out_mode = DS18_PARAM_PULL }
/**@}*/
/**
* @brief Configure ds18
*/
static const ds18_params_t ds18_params[] =
{
#ifdef DS18_PARAMS_BOARD
DS18_PARAMS_BOARD,
#else
DS18_PARAMS_DEFAULT,
#endif
};
/**
* @brief Configure SAUL registry entries
*/
static const saul_reg_info_t ds18_saul_reg_info[] =
{
{ .name = "ds18" }
};
#ifdef __cplusplus
}
#endif
#endif /* DS18_PARAMS_H */
/** @} */
/*
* Copyright (C) 2017 Frits Kuipers
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_ds18 DS18 temperature sensor driver
* @ingroup drivers_sensors
* @ingroup drivers_saul
* @brief Driver interface for the DS18 temperature sensors
*
* This driver provides @ref drivers_saul capabilities.
* Currently the driver has the following limitations:
*- Does not allow addressing devices, only supports a single device on the bus.
*- The 1-Wire bus handling is hardcoded to the driver.
*- Does not allow configuration of sampling width.
*
* @note Due to timing issues present on some boards this drivers features two
* ways of reading information from the sensor. The optimized uses accurate
* delays to handle this, while the second way polls the line for changes. If
* you know that your board can handle ~3us resolution with the xtimer module,
* then the optimized way is recommended. To used the optimized way add the
* ds18_optimized module. Also this driver test application has a whitelist of
* the boards this driver has been tested on and known to work.
*
* @{
*
* @file
* @brief Driver for Maxim Integrated DS1822 and DS18B20 temperature
* sensors.
*
* @author Frits Kuipers <frits.kuipers@gmail.com>
*/
#ifndef DS18_H
#define DS18_H
#include "periph/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ds18 status return codes
* @{
*/
#define DS18_OK (0)
#define DS18_ERROR (-1)
/** @} */
/**
* @brief Device descriptor for a ds18 device
*/
typedef struct {
gpio_t pin; /**< Pin the sensor is connected to */
gpio_mode_t out_mode; /**< Pin output mode */
gpio_mode_t in_mode; /**< Pin input mode */
} ds18_t;
/**
* @brief Device initialization parameters
*/
typedef struct {
gpio_t pin; /**< Pin the sensor is connected to */
gpio_mode_t out_mode; /**< Pin output mode */
} ds18_params_t;
/**
* @brief Initialize a ds18 device
*
* @param[out] dev device descriptor
* @param[in] params ds18 initialization struct
*
*
* @return 0 on success
* @return -1 on error
*/
int ds18_init(ds18_t *dev, const ds18_params_t *params);
/**
* @brief Triggers a temperature conversion
* @note This also triggers a conversion on all devices connected to the bus
*
* @param[in] dev device descriptor
*
* @return 0 on success
* @return -1 on error
*/
int ds18_trigger(ds18_t *dev);
/**
* @brief Reads the scratchpad for the last conversion
*
* @param[in] dev device descriptor
* @param[out] temperature buffer to write the temperature in centi-degrees
*
* @return 0 on success
* @return -1 on error
*/
int ds18_read(ds18_t *dev, int16_t *temperature);
/**
* @brief convenience fuction for triggering a conversion and reading the
* value
*
* @note This function will block for the convertion time. The current
* implementation of the driver uses 12-bit resolution, so this time is 750 ms.
*
* @param[in] dev device descriptor
* @param[out] temperature buffer to write the temperature in centi-degrees
*
* @return 0 on success
* @return -1 on error
*/
int ds18_get_temperature(ds18_t *dev, int16_t *temperature);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* DS18_H */
......@@ -123,4 +123,7 @@ PSEUDOMODULES += auto_init_skald
PSEUDOMODULES += skald_ibeacon
PSEUDOMODULES += skald_eddystone
# define optimized read function of DS18 driver as a pseudo module
PSEUDOMODULES += ds18_optimized
# Packages may also add modules to PSEUDOMODULES in their `Makefile.include`.
......@@ -340,6 +340,10 @@ void auto_init(void)
extern void auto_init_dht(void);
auto_init_dht();
#endif
#ifdef MODULE_DS18
extern void auto_init_ds18(void);
auto_init_ds18();
#endif
#ifdef MODULE_FXOS8700
extern void auto_init_fxos8700(void);
auto_init_fxos8700();
......
/*
* Copyright (C) 2017 Frits Kuipers
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup auto_init_saul
* @{
*
* @file
* @brief Auto initialization of ds18 driver.
*
* @author Frits Kuipers <frits.kuipers@gmail.com>
*
* @}
*/
#ifdef MODULE_DS18
#include "log.h"
#include "saul_reg.h"
#include "ds18.h"
#include "ds18_params.h"
/**
* @brief Define the number of configured sensors
*/
#define DS18_NUMOF (sizeof(ds18_params) / sizeof(ds18_params[0]))
/**
* @brief Allocation of memory for device descriptors
*/
static ds18_t ds18_devs[DS18_NUMOF];
/**
* @brief Memory for the SAUL registry entries
*/
static saul_reg_t saul_entries[DS18_NUMOF];
/**
* @brief Reference the driver structs.
* @{
*/
extern const saul_driver_t ds18_temperature_saul_driver;
/** @} */
void auto_init_ds18(void)
{
for (unsigned i = 0; i < DS18_NUMOF; i++) {
const ds18_params_t *p = &ds18_params[i];
LOG_DEBUG("[auto_init_saul] initializing ds18 #%u\n", i);
if (ds18_init(&ds18_devs[i], (ds18_params_t *) p) < 0) {
LOG_ERROR("[auto_init_saul] error initializing ds18 #%u\n", i);
return;
}
/* temperature */
saul_entries[i].dev = &(ds18_devs[i]);
saul_entries[i].name = ds18_saul_reg_info[i].name;
saul_entries[i].driver = &ds18_temperature_saul_driver;
/* register to saul */
saul_reg_add(&(saul_entries[i]));
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_DS18 */
include ../Makefile.tests_common
BOARD_WHITELIST := sensebox_samd21 samr21-xpro nucleo-l152re
USEMODULE += ds18
USEMODULE += xtimer
USEMODULE += printf_float
# Use the module if you have an accurate sleep with xtimer (~3us)
#USEMODULE += ds18_optimized
include $(RIOTBASE)/Makefile.include
## About
This is a test application for the Maxime [DS18B20](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf) 1-Wire temperature
sensor.
## Usage
The application will initialize the DS18B20 sensor and every 2 seconds will read
the temperature and print the measurement to STDOUT.
\ No newline at end of file
/*
* Copyright (C) 2018 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the DS18B20 1-Wire temperature sensor.
*
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <inttypes.h>
#include "board.h"
#include "ds18.h"
#include "ds18_params.h"
#include "xtimer.h"
#define SAMPLING_PERIOD 2
int main(void)
{
ds18_t dev;
int result;
puts("DS18B20 test application\n");
printf("+------------Initializing------------+\n");
result = ds18_init(&dev, &ds18_params[0]);
if (result == DS18_ERROR) {
puts("[Error] The sensor pin could not be initialized");
return 1;
}
printf("\n+--------Starting Measurements--------+\n");
while (1) {
int16_t temperature;
/* Get temperature in centidegrees celsius */
if (ds18_get_temperature(&dev, &temperature) == DS18_OK) {
printf("Temperature [ºC]: %d.%d"
"\n+-------------------------------------+\n",
(temperature / 100), (int)(temperature % 100));
}
else {
puts("[Error] Could not read temperature");
}
xtimer_sleep(SAMPLING_PERIOD);
}
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment