drivers/sensors: Adds new driver for ds18b20 sensore module
Signed-off-by: Marco Krahl <ocram.lhark@gmail.com>
This commit is contained in:
parent
624a60f456
commit
9f9d266f68
@ -171,6 +171,35 @@ config SENSORS_DHTXX
|
||||
---help---
|
||||
Enable driver support for the DHTxx humidity/temperature sensor.
|
||||
|
||||
config SENSORS_DS18B20
|
||||
bool "Maxim Integrated DS18B20 Temperature Sensor support"
|
||||
default n
|
||||
select 1WIRE
|
||||
---help---
|
||||
Enable driver support for the DS18B20 temperature sensor.
|
||||
|
||||
config SENSORS_DS18B20_POLL
|
||||
bool "Enables polling sensor data"
|
||||
depends on SENSORS_DS18B20
|
||||
default n
|
||||
---help---
|
||||
Enables polling of sensor.
|
||||
|
||||
config SENSORS_DS18B20_POLL_INTERVAL
|
||||
int "Polling interval in microseconds, default 1 sec"
|
||||
depends on SENSORS_DS18B20 && SENSORS_DS18B20_POLL
|
||||
default 1000000
|
||||
range 0 4294967295
|
||||
---help---
|
||||
The interval until a new sensor measurement will be triggered.
|
||||
|
||||
config SENSORS_DS18B20_THREAD_STACKSIZE
|
||||
int "Worker thread stack size"
|
||||
depends on SENSORS_DS18B20 && SENSORS_DS18B20_POLL
|
||||
default 1024
|
||||
---help---
|
||||
The stack size for the worker thread.
|
||||
|
||||
config SENSORS_FXOS8700CQ
|
||||
bool "NXP FXOS8700CQ Motion Sensor support"
|
||||
default n
|
||||
|
@ -260,6 +260,16 @@ endif
|
||||
|
||||
endif # CONFIG_SPI
|
||||
|
||||
# These drivers depend on 1WIRE support
|
||||
|
||||
ifeq ($(CONFIG_1WIRE),y)
|
||||
|
||||
ifeq ($(CONFIG_SENSORS_DS18B20),y)
|
||||
CSRCS += ds18b20.c
|
||||
endif
|
||||
|
||||
endif # CONFIG_1WIRE
|
||||
|
||||
ifeq ($(CONFIG_SENSORS_MPU60X0),y)
|
||||
CSRCS += mpu60x0.c
|
||||
endif
|
||||
|
987
drivers/sensors/ds18b20.c
Normal file
987
drivers/sensors/ds18b20.c
Normal file
@ -0,0 +1,987 @@
|
||||
/****************************************************************************
|
||||
* drivers/sensors/ds18b20.c
|
||||
* Character driver for DS18B20 Digital Humidity and Temperature Module.
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/kthread.h>
|
||||
#include <nuttx/signal.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/1wire/1wire.h>
|
||||
#include <nuttx/1wire/1wire_master.h>
|
||||
#include <nuttx/1wire/1wire_crc.h>
|
||||
#include <nuttx/sensors/ds18b20.h>
|
||||
#include <nuttx/sensors/sensor.h>
|
||||
|
||||
#if defined(CONFIG_1WIRE) && defined(CONFIG_SENSORS_DS18B20)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_ENDIAN_BIG
|
||||
# define ds18b20_leuint64(x) (x)
|
||||
#endif
|
||||
|
||||
/* Scratchpad data definition for reading */
|
||||
|
||||
#define DS18B20_SPAD_LSB_OFFSET 0
|
||||
#define DS18B20_SPAD_MSB_OFFSET 1
|
||||
#define DS18B20_SPAD_TH_OFFSET 2
|
||||
#define DS18B20_SPAD_TL_OFFSET 3
|
||||
#define DS18B20_SPAD_RES_OFFSET 4
|
||||
#define DS18B20_SPAD_CRC_OFFSET 9
|
||||
#define DS18B20_SPAD_SIZE 9
|
||||
|
||||
/* Scratchpad data definition for writing */
|
||||
|
||||
#define DS18B20_WSPAD_CMD_OFFSET 0
|
||||
#define DS18B20_WSPAD_TH_OFFSET 0
|
||||
#define DS18B20_WSPAD_TL_OFFSET 1
|
||||
#define DS18B20_WSPAD_RES_OFFSET 2
|
||||
#define DS18B20_WSPAD_SIZE 3
|
||||
|
||||
/* Measurement resolution bit definition */
|
||||
|
||||
#define DS18B20_RESMIN 0
|
||||
#define DS18B20_RESMAX 3
|
||||
#define DS18B20_NRES DS18B20_RESMAX - DS18B20_RESMIN + 1
|
||||
|
||||
#define DS18B20_RES_VAL(x) (((x) >> 5) & 0x3)
|
||||
#define DS18B20_RES_CONV(x) (((x) & 0x3) << 5)
|
||||
|
||||
/* Measurement timneout offset */
|
||||
|
||||
#define DS18B20_TIMEOUT_OFFSET(x) (DS18B20_RESMAX - (x))
|
||||
|
||||
/* Default alarm temperature */
|
||||
|
||||
#define DS18B20_TALARM_MIN -55
|
||||
#define DS18B20_TALARM_MAX 125
|
||||
|
||||
/* Helper for getting data from scratchpad memory */
|
||||
|
||||
#define DS18B20_TEMP_PREDEC(lsb, msb) (int8_t)(((msb) << 4) | ((lsb) >> 4))
|
||||
#define DS18B20_TEMP_RES(lsb, res) (DS18B20_RESMAX - DS18B20_RES_VAL(res))
|
||||
#define DS18B20_TEMP_RESMASK(lsb, res) (0x0f << DS18B20_TEMP_RES(lsb, res))
|
||||
#define DS18B20_TEMP_DEC(lsb, res) (((lsb) & 0x0f) & \
|
||||
DS18B20_TEMP_RESMASK(lsb, res))
|
||||
#define DS18B20_TEMP(lsb, msb, res) (DS18B20_TEMP_PREDEC(lsb, msb) + \
|
||||
DS18B20_TEMP_DEC(lsb, res) / 16.0)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Internal sensor data */
|
||||
|
||||
struct ds18b20_sensor_data_s
|
||||
{
|
||||
uint64_t timestamp;
|
||||
uint8_t spad[DS18B20_SPAD_SIZE];
|
||||
};
|
||||
|
||||
/* User configuration register */
|
||||
|
||||
struct ds18b20_config_s
|
||||
{
|
||||
uint8_t res; /* Sensor resolution */
|
||||
struct ds18b20_alarm_s alarm; /* Sensor temperature alarm */
|
||||
};
|
||||
|
||||
/* Callback handling for alarm detection */
|
||||
|
||||
struct ds18b20_cb_alarm_s
|
||||
{
|
||||
bool isalarm;
|
||||
uint64_t romcode;
|
||||
};
|
||||
|
||||
/* Lower sensor */
|
||||
|
||||
struct ds18b20_sensor_s
|
||||
{
|
||||
struct sensor_lowerhalf_s lower; /* Common lower interface */
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
bool enabled; /* Sensor activated */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Internal device */
|
||||
|
||||
struct ds18b20_dev_s
|
||||
{
|
||||
struct ds18b20_sensor_s sensor; /* Sensor */
|
||||
FAR struct onewire_master_s *master; /* 1wire master interface */
|
||||
struct onewire_config_s config; /* 1wire device configuration */
|
||||
struct ds18b20_config_s reg; /* Sensor resolution */
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
unsigned int interval; /* Polling interval */
|
||||
sem_t run; /* Locks sensor thread */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Sensor functions */
|
||||
|
||||
static int ds18b20_active(FAR struct sensor_lowerhalf_s *lower,
|
||||
unsigned char enabled);
|
||||
|
||||
static int ds18b20_fetch(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR char *buffer, size_t buflen);
|
||||
|
||||
static int ds18b20_control(FAR struct sensor_lowerhalf_s *lower,
|
||||
int cmd, unsigned long arg);
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
static int ds18b20_set_interval(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR unsigned int *period_us);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Timeout definitions after measurement according to the data sheet */
|
||||
|
||||
static const uint32_t g_res_timeout[DS18B20_NRES] =
|
||||
{
|
||||
93750,
|
||||
187500,
|
||||
375000,
|
||||
750000
|
||||
};
|
||||
|
||||
static const struct sensor_ops_s g_ds18b20_ops =
|
||||
{
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
.set_interval = ds18b20_set_interval,
|
||||
#endif
|
||||
.activate = ds18b20_active,
|
||||
.fetch = ds18b20_fetch,
|
||||
.control = ds18b20_control
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_rawdata
|
||||
*
|
||||
* Description:
|
||||
* Helper for extract temperature data from scratchpad
|
||||
*
|
||||
* Return:
|
||||
* Raw temperature data
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int16_t ds18b20_rawtemp(FAR const uint8_t *spad)
|
||||
{
|
||||
return (spad[DS18B20_SPAD_LSB_OFFSET] |
|
||||
(spad[DS18B20_SPAD_MSB_OFFSET] << 8));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_tempdata
|
||||
*
|
||||
* Description:
|
||||
* Helper for converting temperatur data from raw sensor data
|
||||
*
|
||||
* Return:
|
||||
* Temperature data
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline float ds18b20_temp(FAR const uint8_t *spad)
|
||||
{
|
||||
int8_t predec = DS18B20_TEMP_PREDEC(spad[DS18B20_SPAD_LSB_OFFSET],
|
||||
spad[DS18B20_SPAD_MSB_OFFSET]);
|
||||
uint8_t dec = DS18B20_TEMP_DEC(spad[DS18B20_SPAD_LSB_OFFSET],
|
||||
spad[DS18B20_SPAD_RES_OFFSET]);
|
||||
|
||||
return predec + dec / 16.0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_alarm_cb
|
||||
*
|
||||
* Description:
|
||||
* Call back function for searching a single alarm device.
|
||||
*
|
||||
* Input Parameters:
|
||||
* romcode - Unique romcode of a device with alarm flag set
|
||||
* arg - Pointer to struct onewire_alarm_s
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
static void ds18b20_alarm_cb(int family, uint64_t romcode, FAR void *arg)
|
||||
{
|
||||
FAR struct ds18b20_cb_alarm_s *priv = (FAR struct ds18b20_cb_alarm_s *)arg;
|
||||
|
||||
if (romcode == priv->romcode)
|
||||
{
|
||||
priv->isalarm = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_isalarm
|
||||
*
|
||||
* Description:
|
||||
* Check if a 1wire device has set the alarm flag in an atomic operation.
|
||||
*
|
||||
* Input Parameters:
|
||||
* master - Pointer to the allocated 1-wire interface
|
||||
* config - Described the 1WIRE configuration
|
||||
*
|
||||
* Return Value:
|
||||
* 0 - no alarm flag is set
|
||||
* 1 - alarm flag is set
|
||||
* < 0 - in case of error
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
static int ds18b20_isalarm(FAR struct onewire_master_s *master,
|
||||
FAR const struct onewire_config_s *config)
|
||||
{
|
||||
int ret;
|
||||
struct ds18b20_cb_alarm_s alarm;
|
||||
alarm.romcode = config->romcode;
|
||||
alarm.isalarm = false;
|
||||
|
||||
ret = onewire_search(master, config->family, true, ds18b20_alarm_cb,
|
||||
&alarm);
|
||||
if (ret > 0)
|
||||
{
|
||||
/* Check if our device is in the alarm list */
|
||||
|
||||
if (alarm.isalarm == true)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Device found, but not our */
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_measure
|
||||
*
|
||||
* Description: Perform a measurement
|
||||
*
|
||||
* Parameter:
|
||||
* dev - Internal private lower half driver instance
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_measure(FAR struct ds18b20_dev_s *dev)
|
||||
{
|
||||
int ret;
|
||||
uint8_t buf = DS18B20_CMD_CONVERTT;
|
||||
|
||||
ret = onewire_write(dev->master, &dev->config, &buf, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
snerr("ERROR: Unable to perform a temperature measurement\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_write_spad
|
||||
*
|
||||
* Description: Write scratchpad data to chip
|
||||
*
|
||||
* Parameter:
|
||||
* dev - Internal private lower half driver instance
|
||||
* th - High alarm temperature
|
||||
* lh - Low alarm temperature
|
||||
* res - Temperature resolution
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_write_spad(FAR struct ds18b20_dev_s *dev, int8_t th,
|
||||
int8_t tl, uint8_t res)
|
||||
{
|
||||
int ret;
|
||||
uint8_t wbuf[DS18B20_WSPAD_SIZE + 1];
|
||||
|
||||
wbuf[DS18B20_WSPAD_CMD_OFFSET] = ONEWIRE_CMD_WRITE_SCRATCHPAD;
|
||||
wbuf[DS18B20_WSPAD_TH_OFFSET + 1] = th;
|
||||
wbuf[DS18B20_WSPAD_TL_OFFSET + 1] = tl;
|
||||
wbuf[DS18B20_WSPAD_RES_OFFSET + 1] = res;
|
||||
|
||||
ret = onewire_write(dev->master, &dev->config, wbuf, sizeof(wbuf));
|
||||
if (ret < 0)
|
||||
{
|
||||
snerr("ERROR: Unable to write scratchpad\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_read_spad
|
||||
*
|
||||
* Description: Read scratchpad data from chip
|
||||
*
|
||||
* Parameter:
|
||||
* dev - Internal private lower half driver instance
|
||||
* spad - Pointer to store the scratchpad data
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_read_spad(FAR struct ds18b20_dev_s *dev,
|
||||
FAR uint8_t *spad)
|
||||
{
|
||||
int ret;
|
||||
uint8_t crc;
|
||||
uint8_t wbuf = ONEWIRE_CMD_READ_SCRATCHPAD;
|
||||
FAR struct ds18b20_config_s *reg = &dev->reg;
|
||||
|
||||
ret = onewire_writeread(dev->master, &dev->config, &wbuf, 1, spad,
|
||||
DS18B20_SPAD_SIZE);
|
||||
if (ret < 0)
|
||||
{
|
||||
snerr("ERROR: Unable to read scratchpad\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
crc = onewire_crc8(spad, DS18B20_SPAD_SIZE - 1);
|
||||
if (crc != spad[DS18B20_SPAD_CRC_OFFSET - 1])
|
||||
{
|
||||
snerr("ERROR: crc mismatch in scratchpad\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Update configurable register state each time reading the scratchpad */
|
||||
|
||||
reg->res = spad[DS18B20_SPAD_RES_OFFSET];
|
||||
|
||||
if (reg->res < DS18B20_RES_CONV(DS18B20_RESMIN) ||
|
||||
reg->res > DS18B20_RES_CONV(reg->res))
|
||||
{
|
||||
/* Usually this should not happen, but be sure that we did not run into
|
||||
* a buffer overflow later.
|
||||
*/
|
||||
|
||||
swarn("WARNING: Sensor responsed unknown resolution: %d\n", reg->res);
|
||||
reg->res = DS18B20_RES_CONV(DS18B20_RESMAX);
|
||||
}
|
||||
|
||||
reg->alarm.thigh = spad[DS18B20_SPAD_TH_OFFSET];
|
||||
reg->alarm.tlow = spad[DS18B20_SPAD_TL_OFFSET];
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_set_res
|
||||
*
|
||||
* Description: Set resolution for temperature measurement
|
||||
*
|
||||
* Parameter:
|
||||
* dev - Internal private lower half driver instance
|
||||
* res - Resolution, can be 9 to 12 bit
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_set_res(FAR struct ds18b20_dev_s *dev, uint8_t res)
|
||||
{
|
||||
int ret;
|
||||
uint8_t spad[DS18B20_SPAD_SIZE];
|
||||
|
||||
/* Read current scratchpad first */
|
||||
|
||||
ret = ds18b20_read_spad(dev, spad);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ds18b20_write_spad(dev, dev->reg.alarm.thigh, dev->reg.alarm.tlow,
|
||||
res);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read current scratchpad again and verify that res is set */
|
||||
|
||||
ret = ds18b20_read_spad(dev, spad);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (DS18B20_RES_VAL(spad[DS18B20_SPAD_RES_OFFSET]) != DS18B20_RES_VAL(res))
|
||||
{
|
||||
snerr("ERROR: Expected resolution not matched, received RES: %d\n",
|
||||
spad[DS18B20_SPAD_RES_OFFSET]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_set_alarm
|
||||
*
|
||||
* Description: Set temperature alarm
|
||||
*
|
||||
* Parameter:
|
||||
* dev - Internal private lower half driver instance
|
||||
* alarm - Pointer to store the alarm temperature
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_set_alarm(FAR struct ds18b20_dev_s *dev,
|
||||
FAR const struct ds18b20_alarm_s *alarm)
|
||||
{
|
||||
int ret;
|
||||
uint8_t spad[DS18B20_SPAD_SIZE];
|
||||
|
||||
/* Read current scratchpad first, to get current resolution */
|
||||
|
||||
ret = ds18b20_read_spad(dev, spad);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ds18b20_write_spad(dev, alarm->thigh, alarm->tlow, dev->reg.res);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
dev->reg.alarm.wakeup = alarm->wakeup;
|
||||
#endif
|
||||
|
||||
/* Read current scratchpad again and verify that alarm is set */
|
||||
|
||||
ret = ds18b20_read_spad(dev, spad);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (spad[DS18B20_SPAD_TH_OFFSET] != alarm->thigh ||
|
||||
spad[DS18B20_SPAD_TL_OFFSET] != alarm->tlow)
|
||||
{
|
||||
snerr("ERROR: Expected alarm trigger does not match, " \
|
||||
"received TH: %d, TL: %d\n",
|
||||
spad[DS18B20_SPAD_TH_OFFSET],
|
||||
spad[DS18B20_SPAD_TL_OFFSET]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_curtime
|
||||
*
|
||||
* Description: Helper to get current timestamp.
|
||||
*
|
||||
* Return:
|
||||
* Timestamp in nsec
|
||||
****************************************************************************/
|
||||
|
||||
static unsigned long ds18b20_curtime(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
#ifdef CONFIG_CLOCK_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
#endif
|
||||
|
||||
return 1000000ull * ts.tv_sec + ts.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_notify
|
||||
*
|
||||
* Description:
|
||||
* Notify upper about data has been changed.
|
||||
*
|
||||
* Parameter:
|
||||
* dev - Internal private lower half driver instance
|
||||
* data - Read sensor data
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
static void ds18b20_notify(FAR struct ds18b20_dev_s *dev,
|
||||
FAR struct ds18b20_sensor_data_s *data)
|
||||
{
|
||||
FAR struct ds18b20_sensor_s *sensor = &dev->sensor;
|
||||
struct sensor_event_temp temp;
|
||||
|
||||
temp.temperature = ds18b20_temp(data->spad);
|
||||
temp.timestamp = data->timestamp;
|
||||
sensor->lower.push_event(sensor->lower.priv, &temp,
|
||||
sizeof(struct sensor_event_temp));
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_measure_read
|
||||
*
|
||||
* Description: Perform a measurement and read last measured temperature
|
||||
*
|
||||
* Parameter:
|
||||
* dev - Internal private lower half driver instance
|
||||
* data - Pointer to store sensor data
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_measure_read(FAR struct ds18b20_dev_s *dev,
|
||||
FAR struct ds18b20_sensor_data_s *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ds18b20_measure(dev);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
nxsig_usleep(g_res_timeout[DS18B20_RES_VAL(dev->reg.res)]);
|
||||
|
||||
ret = ds18b20_read_spad(dev, data->spad);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->timestamp = ds18b20_curtime();
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_fetch
|
||||
*
|
||||
* Description: Performs a measuremnt cylce and data read with data
|
||||
* conversion.
|
||||
*
|
||||
* Parameter:
|
||||
* lower - Pointer to lower half sensor driver instance
|
||||
* buffer - Pointer to the buffer for reading data
|
||||
* buflen - Size of the buffer
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_fetch(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR char *buffer, size_t buflen)
|
||||
{
|
||||
int ret;
|
||||
struct ds18b20_sensor_data_s data;
|
||||
FAR struct ds18b20_dev_s *priv = (FAR struct ds18b20_dev_s *)lower;
|
||||
|
||||
/* Check if the user is reading the right size */
|
||||
|
||||
if (buflen != sizeof(struct sensor_event_temp))
|
||||
{
|
||||
snerr("ERROR: You need to read %d bytes from this sensor!\n",
|
||||
sizeof(struct sensor_event_temp));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ds18b20_measure_read(priv, &data);
|
||||
if (!ret)
|
||||
{
|
||||
FAR struct sensor_event_temp *temp =
|
||||
(FAR struct sensor_event_temp *)buffer;
|
||||
temp->temperature = ds18b20_temp(data.spad);
|
||||
temp->timestamp = data.timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_control
|
||||
*
|
||||
* Description: Interface function of struct sensor_ops_s.
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_control(FAR struct sensor_lowerhalf_s *lower,
|
||||
int cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
struct ds18b20_dev_s *priv = (FAR struct ds18b20_dev_s *)lower;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* Read rom code */
|
||||
|
||||
case SNIOC_READROMCODE:
|
||||
{
|
||||
FAR uint64_t *ptr = (FAR uint64_t *)((uintptr_t)arg);
|
||||
DEBUGASSERT(ptr != NULL);
|
||||
*ptr = priv->config.romcode;
|
||||
sninfo("read romcode: %16llx\n", *ptr);
|
||||
ret = OK;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Set new temperature alarm */
|
||||
|
||||
case SNIOC_SETALARM:
|
||||
{
|
||||
FAR struct ds18b20_alarm_s *ptr =
|
||||
(FAR struct ds18b20_alarm_s *)((uintptr_t)arg);
|
||||
DEBUGASSERT(ptr != NULL);
|
||||
sninfo("set alarm: [TH/TL] = %d/%d °C\n", ptr->thigh, ptr->tlow);
|
||||
ret = ds18b20_set_alarm(priv, ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Set sensor resolution */
|
||||
|
||||
case SNIOC_SETRESOLUTION:
|
||||
{
|
||||
uint8_t res = arg - 9;
|
||||
sninfo("set resolution: %ld\n", arg);
|
||||
if (res >= DS18B20_RESMIN && res <= DS18B20_RESMAX)
|
||||
{
|
||||
ret = ds18b20_set_res(priv, DS18B20_RES_CONV(res));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
snerr("ERROR: Unrecognized cmd: %d\n", cmd);
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_active
|
||||
*
|
||||
* Description: Interface function of struct sensor_ops_s.
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
static int ds18b20_active(FAR struct sensor_lowerhalf_s *lower,
|
||||
unsigned char enabled)
|
||||
{
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
bool start_thread = false;
|
||||
struct ds18b20_dev_s *priv = (FAR struct ds18b20_dev_s *)lower;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (!priv->sensor.enabled)
|
||||
{
|
||||
start_thread = true;
|
||||
}
|
||||
}
|
||||
|
||||
priv->sensor.enabled = enabled;
|
||||
|
||||
if (start_thread == true)
|
||||
{
|
||||
/* Wake up the thread */
|
||||
|
||||
nxsem_post(&priv->run);
|
||||
}
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_set_interval
|
||||
*
|
||||
* Description: Interface function of struct sensor_ops_s.
|
||||
*
|
||||
* Return:
|
||||
* OK - on success
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
static int ds18b20_set_interval(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR unsigned int *period_us)
|
||||
{
|
||||
FAR struct ds18b20_dev_s *priv = (FAR struct ds18b20_dev_s *)lower;
|
||||
priv->interval = *period_us;
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_thread
|
||||
*
|
||||
* Description: Thread for performing interval measurement cycle and data
|
||||
* read.
|
||||
*
|
||||
* Parameter:
|
||||
* argc - Number opf arguments
|
||||
* argv - Pointer to argument list
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
static int ds18b20_thread(int argc, char** argv)
|
||||
{
|
||||
uint16_t orawdata;
|
||||
FAR struct ds18b20_dev_s *priv = (FAR struct ds18b20_dev_s *)
|
||||
((uintptr_t)strtoul(argv[1], NULL, 0));
|
||||
|
||||
/* Set initial value to out of measurement range to ensure that the first
|
||||
* data read leads to an upper notification.
|
||||
*/
|
||||
|
||||
orawdata = 0xffff;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int ret;
|
||||
struct ds18b20_sensor_data_s data;
|
||||
FAR struct ds18b20_sensor_s *sensor = &priv->sensor;
|
||||
FAR struct ds18b20_alarm_s *alarm = &priv->reg.alarm;
|
||||
|
||||
if (!sensor->enabled)
|
||||
{
|
||||
/* Waiting to be woken up */
|
||||
|
||||
nxsem_wait(&priv->run);
|
||||
}
|
||||
|
||||
if (alarm->wakeup == true)
|
||||
{
|
||||
/* Perform a temperature conversion to update the alarm flag */
|
||||
|
||||
ret = ds18b20_measure(priv);
|
||||
if (!ret)
|
||||
{
|
||||
/* Wait until temperature conversion is done and the alarm flag
|
||||
* is up to date.
|
||||
*/
|
||||
|
||||
nxsig_usleep(g_res_timeout[DS18B20_RES_VAL(priv->reg.res)]);
|
||||
|
||||
/* Check for existing temperature alarm */
|
||||
|
||||
ret = ds18b20_isalarm(priv->master, &priv->config);
|
||||
if (ret == 1)
|
||||
{
|
||||
ret = ds18b20_measure_read(priv, &data);
|
||||
if (!ret && sensor->enabled == true)
|
||||
{
|
||||
/* Notify upper */
|
||||
|
||||
ds18b20_notify(priv, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Default nofitication when temperature has been changed */
|
||||
|
||||
ret = ds18b20_measure_read(priv, &data);
|
||||
if (!ret)
|
||||
{
|
||||
uint16_t rawtemp = ds18b20_rawtemp(data.spad);
|
||||
|
||||
if (sensor->enabled == true && orawdata != rawtemp)
|
||||
{
|
||||
ds18b20_notify(priv, &data);
|
||||
}
|
||||
|
||||
/* Store the last sensor data for later comparison */
|
||||
|
||||
orawdata = ds18b20_rawtemp(data.spad);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sleeping thread before fetching the next sensor data */
|
||||
|
||||
nxsig_usleep(priv->interval);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_register
|
||||
*
|
||||
* Description:
|
||||
* Register the DS18B20 character device.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devno - The user specifies device number, from 0.
|
||||
* onewire - An instance of the 1wire interface to communicate with DS18B20
|
||||
* sensor.
|
||||
* romcode - The ROM code of the DS18B20.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
****************************************************************************/
|
||||
|
||||
int ds18b20_register(int devno, FAR struct onewire_master_s *onewire,
|
||||
uint64_t romcode)
|
||||
{
|
||||
int ret;
|
||||
struct ds18b20_sensor_s *tmp;
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
FAR char *argv[2];
|
||||
char arg1[32];
|
||||
#endif
|
||||
|
||||
/* Sanity check */
|
||||
|
||||
if (!onewire)
|
||||
{
|
||||
snerr("Invalid 1wire instance\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize the DS18B20 device structure */
|
||||
|
||||
FAR struct ds18b20_dev_s *priv = (FAR struct ds18b20_dev_s *)
|
||||
kmm_malloc(sizeof(struct ds18b20_dev_s));
|
||||
|
||||
if (priv == NULL)
|
||||
{
|
||||
snerr("ERROR: Failed to allocate instance\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->master = onewire;
|
||||
priv->config.romcode = romcode;
|
||||
priv->config.family = DS18B20_DEVICE_FAMILY;
|
||||
priv->reg.res = DS18B20_RES_CONV(DS18B20_RESMAX);
|
||||
priv->reg.alarm.thigh = DS18B20_TALARM_MAX;
|
||||
priv->reg.alarm.tlow = DS18B20_TALARM_MIN;
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
priv->reg.alarm.wakeup = false;
|
||||
priv->interval = CONFIG_SENSORS_DS18B20_POLL_INTERVAL;
|
||||
|
||||
nxsem_init(&priv->run, 0, 0);
|
||||
nxsem_set_protocol(&priv->run, SEM_PRIO_NONE);
|
||||
#endif
|
||||
|
||||
/* Temperature register */
|
||||
|
||||
tmp = &priv->sensor;
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
tmp->enabled = false;
|
||||
#endif
|
||||
tmp->lower.ops = &g_ds18b20_ops;
|
||||
tmp->lower.type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
|
||||
tmp->lower.uncalibrated = false;
|
||||
tmp->lower.buffer_number = 1;
|
||||
ret = sensor_register(&tmp->lower, devno);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto sensor_err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
|
||||
/* Create thread for polling sensor data */
|
||||
|
||||
snprintf(arg1, 16, "0x%" PRIxPTR, (uintptr_t)priv);
|
||||
argv[0] = arg1;
|
||||
argv[1] = NULL;
|
||||
ret = kthread_create("ds18b20_thread", SCHED_PRIORITY_DEFAULT,
|
||||
CONFIG_SENSORS_DS18B20_THREAD_STACKSIZE,
|
||||
ds18b20_thread, argv);
|
||||
if (ret > 0)
|
||||
#endif
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
sensor_err:
|
||||
sensor_unregister(&priv->sensor.lower, devno);
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_1WIRE && CONFIG_SENSORS_DS18B20 */
|
95
include/nuttx/sensors/ds18b20.h
Normal file
95
include/nuttx/sensors/ds18b20.h
Normal file
@ -0,0 +1,95 @@
|
||||
/****************************************************************************
|
||||
* include/nuttx/sensors/ds18b20.h
|
||||
* Character driver for DS18B20 Digital Temperature Module.
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_SENSORS_DS18B20_H
|
||||
#define __INCLUDE_NUTTX_SENSORS_DS18B20_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#if defined(CONFIG_1WIRE) && defined(CONFIG_SENSORS_DS18B20)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define DS18B20_DEVICE_FAMILY (0x28)
|
||||
|
||||
#define DS18B20_CMD_CONVERTT (0x44)
|
||||
#define DS18B20_CMD_COPYSPAD (0x48)
|
||||
#define DS18B20_CMD_RECALL (0xb8)
|
||||
#define DS18B20_CMD_READPOWS (0xb4)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
struct onewire_master_s;
|
||||
|
||||
struct ds18b20_alarm_s
|
||||
{
|
||||
int8_t thigh; /* Upper alarm temperature */
|
||||
int8_t tlow; /* Lower alarm temperature */
|
||||
# ifdef CONFIG_SENSORS_DS18B20_POLL
|
||||
bool wakeup; /* Wakeup poll requests only when alarm detected */
|
||||
# endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ds18b20_register
|
||||
*
|
||||
* Description:
|
||||
* Register the DS18B20 character device.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devno - The user specifies device number, from 0.
|
||||
* onewire - An instance of the 1wire interface to communicate with DS18B20
|
||||
* sensor.
|
||||
* romcode - The ROM code of the DS18B20.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
****************************************************************************/
|
||||
|
||||
int ds18b20_register(int devno, FAR struct onewire_master_s *dev,
|
||||
uint64_t romcode);
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_1WIRE && CONFIG_SENSORS_DS18B20 */
|
||||
#endif /* __INCLUDE_NUTTX_SENSORS_DS18B20_H */
|
@ -229,26 +229,33 @@
|
||||
|
||||
#define SNIOC_READADDR SNIOC_READID /* Arg: uint8_t* pointer */
|
||||
|
||||
/* IOCTL commands unique to the DS18B20 */
|
||||
|
||||
/* SNIOC_SETRESOLUTION */ /* Arg: uint8_t value */
|
||||
|
||||
#define SNIOC_READROMCODE _SNIOC(0x0067) /* Arg: uint64_t* pointer */
|
||||
#define SNIOC_SETALARM _SNIOC(0x0068) /* Arg: struct ds18b20_alarm_s* */
|
||||
|
||||
/* Command: SNIOC_ACTIVATE
|
||||
* Description: Enable or disable sensor
|
||||
* Argument: true or false.
|
||||
*/
|
||||
|
||||
#define SNIOC_ACTIVATE _SNIOC(0x0067)
|
||||
#define SNIOC_ACTIVATE _SNIOC(0x0080)
|
||||
|
||||
/* Command: SNIOC_SET_INTERVAL
|
||||
* Description: Set interval between samples
|
||||
* Argument: This is the interval pointer, in microseconds
|
||||
*/
|
||||
|
||||
#define SNIOC_SET_INTERVAL _SNIOC(0x0068)
|
||||
#define SNIOC_SET_INTERVAL _SNIOC(0x0081)
|
||||
|
||||
/* Command: SNIOC_BATCH
|
||||
* Description: Set batch latency between batch data.
|
||||
* Argument: This is the latency pointer, in microseconds
|
||||
*/
|
||||
|
||||
#define SNIOC_BATCH _SNIOC(0x0069)
|
||||
#define SNIOC_BATCH _SNIOC(0x0082)
|
||||
|
||||
/* Command: SNIOC_GET_NEVENTBUF
|
||||
* Description: the number of sensor events that sensor buffer of upper half
|
||||
@ -265,7 +272,7 @@
|
||||
* See sensor.h(struct sensor_lower_half_s buffer_bytes).
|
||||
*/
|
||||
|
||||
#define SNIOC_GET_NEVENTBUF _SNIOC(0x0070)
|
||||
#define SNIOC_GET_NEVENTBUF _SNIOC(0x0083)
|
||||
|
||||
/* Command: SNIOC_SET_BUFFER_NUMBER
|
||||
* Description: Set the number of events intermediate circualr buffer can
|
||||
@ -275,6 +282,6 @@
|
||||
* circualr buffer can hold by this ioctl command.
|
||||
*/
|
||||
|
||||
#define SNIOC_SET_BUFFER_NUMBER _SNIOC(0x0071)
|
||||
#define SNIOC_SET_BUFFER_NUMBER _SNIOC(0x0084)
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user