mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
222 lines
5.0 KiB
C
222 lines
5.0 KiB
C
/*
|
|
* 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(const ds18_t *dev)
|
|
{
|
|
/* Set gpio as output and clear pin */
|
|
gpio_init(dev->params.pin, GPIO_OUT);
|
|
gpio_clear(dev->params.pin);
|
|
}
|
|
|
|
static void ds18_release(const ds18_t *dev)
|
|
{
|
|
/* Init pin as input */
|
|
gpio_init(dev->params.pin, dev->params.in_mode);
|
|
}
|
|
|
|
static void ds18_write_bit(const 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(const 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->params.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->params.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(const 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(const ds18_t *dev, uint8_t byte)
|
|
{
|
|
for (int i = 0; i < 8; i++) {
|
|
ds18_write_bit(dev, byte & (0x01 << i));
|
|
}
|
|
}
|
|
|
|
static int ds18_reset(const 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->params.pin);
|
|
|
|
/* Sleep for reset delay */
|
|
xtimer_usleep(DS18_DELAY_RESET);
|
|
|
|
return res;
|
|
}
|
|
|
|
int ds18_trigger(const 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(const 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 = (int16_t)(b2 << 8 | b1);
|
|
*temperature = (int16_t)((100 * measurement) >> 4);
|
|
|
|
return DS18_OK;
|
|
}
|
|
|
|
int ds18_get_temperature(const 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;
|
|
|
|
dev->params = *params;
|
|
|
|
/* 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->params.in_mode = (dev->params.out_mode == GPIO_OD_PU) ? GPIO_IN_PU : GPIO_IN;
|
|
|
|
/* Initialize the device and the pin */
|
|
res = gpio_init(dev->params.pin, dev->params.in_mode) == 0 ? DS18_OK : DS18_ERROR;
|
|
|
|
return res;
|
|
}
|