1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Add support for Adafruit Seesaw Soil moisture sensor (#14835)

drivers/seesaw_soil: Add support for Adafruit Seesaw Soil moisture sensor
This commit is contained in:
Viktor Gal 2020-09-23 17:35:33 +02:00 committed by GitHub
parent e719eaf97c
commit 7ea8f738fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 584 additions and 0 deletions

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2020 Viktor Gal
*
* 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_seesaw_soil Adafruit Seesaw Soil Moisture and Temperature Sensor
* @ingroup drivers_sensors
* @ingroup drivers_saul
* @brief Driver for the Adafruit Seesaw Soil Moisture and Temperature Sensor
*
*
* This driver provides @ref drivers_saul capabilities.
*
* @{
*
* @file
* @brief Interface definition for the Adafruit Seesaw Soil sensor.
*
* @author Viktor Gal <viktor.gal@maeth.com>
*/
#ifndef SEESAW_SOIL_H
#define SEESAW_SOIL_H
#include <stdint.h>
#include "periph/i2c.h"
#include "seesaw_soil_regs.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @defgroup drivers_seesaw_soil_config Adafruit Seesaw Soil Moisture and Temperature Sensor driver compile configuration
* @ingroup config_drivers_sensors
* @{
*/
/**
* @brief Default I2C bus address of Adafruit Seesaw Soil devices
*
* The address value depends on the state of AD0 and AD1 Pins
*/
#ifndef CONFIG_SEESAW_SOIL_I2C_ADDRESS
#define CONFIG_SEESAW_SOIL_I2C_ADDRESS (0x36)
#endif
/** @} */
/**
* @brief Seesaw Soil specific return values
*/
enum {
SEESAW_SOIL_OK = 0, /**< everything went as expected */
SEESAW_SOIL_NODEV = -1, /**< no SEESAW_SOIL device found on the bus */
SEESAW_SOIL_NOBUS = -2, /**< errors while initializing the I2C bus */
SEESAW_SOIL_BUSERR = -3 /**< error during I2C communication */
};
/**
* @brief Parameters needed for device initialization
*/
typedef struct {
i2c_t i2c; /**< bus the device is connected to */
uint8_t addr; /**< address on that bus */
} seesaw_soil_params_t;
/**
* @brief Device descriptor for Seesaw Soil sensors
*/
typedef struct {
seesaw_soil_params_t params; /**< Configuration parameters */
} seesaw_soil_t;
/**
* @brief Initialize the given Seesaw Soil device
*
* @param[out] dev device descriptor of sensor to initialize
* @param[in] params configuration parameters
*
* @return SEESAW_SOIL_OK on success
* @return SEESAW_SOIL_NOBUS if initialization of I2C bus fails
* @return SEESAW_SOIL_NODEV if no Seesaw Soil device found on bus
*/
int seesaw_soil_init(seesaw_soil_t *dev, const seesaw_soil_params_t *params);
/**
* @brief Convenience function for reading temperature
*
* @param[in] dev device descriptor of sensor
* @param[out] temp temperature [in 100 * degree centigrade]
*
* @return SEESAW_SOIL_OK on success
* @return SEESAW_SOIL_BUSERR on I2C communication failures
*/
int seesaw_soil_temperature(const seesaw_soil_t *dev, int16_t *temp);
/**
* @brief Convenience function for reading ca
*
* @param[in] dev device descriptor of sensor
* @param[out] moist moisture using capacitive measurement.
* Value is ranging from 200 (very dry) to 2000 (very wet).
*
* @return SEESAW_SOIL_OK on success
* @return SEESAW_SOIL_BUSERR on I2C communication failures
*/
int seesaw_soil_moisture(const seesaw_soil_t *dev, uint16_t *moist);
#ifdef __cplusplus
}
#endif
#endif /* SEESAW_SOIL_H */
/** @} */

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2020 Viktor Gal
*
* 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 sys_auto_init_saul
* @{
*
* @file
* @brief Auto initialization for Adafruit Seesaw Soil devices
*
* @author Viktor Gal <viktor.gal@maeth.com>
*
* @}
*/
#include "assert.h"
#include "log.h"
#include "saul_reg.h"
#include "seesaw_soil.h"
#include "seesaw_soil_params.h"
/**
* @brief Define the number of configured sensors
*/
#define SEESAW_SOIL_NUM ARRAY_SIZE(seesaw_soil_params)
/**
* @brief Allocate memory for the device descriptors
*/
static seesaw_soil_t seesaw_soil_devs[SEESAW_SOIL_NUM];
/**
* @brief Memory for the SAUL registry entries
*/
static saul_reg_t saul_entries[SEESAW_SOIL_NUM];
/**
* @brief Define the number of saul info
*/
#define SEESAW_SOIL_INFO_NUM ARRAY_SIZE(seesaw_soil_saul_info)
/**
* @name Reference the driver struct
* @{
*/
extern saul_driver_t seesaw_soil_saul_temp_driver;
/** @} */
void auto_init_seesaw_soil(void)
{
assert(SEESAW_SOIL_NUM == SEESAW_SOIL_INFO_NUM);
for (unsigned i = 0; i < SEESAW_SOIL_NUM; i++) {
LOG_DEBUG("[auto_init_saul] initializing seesaw_soil #%u\n", i);
int res = seesaw_soil_init(&seesaw_soil_devs[i], &seesaw_soil_params[i]);
if (res < 0) {
LOG_ERROR("[auto_init_saul] error initializing seesaw_soil #%u\n", i);
continue;
}
saul_entries[i].dev = &(seesaw_soil_devs[i]);
saul_entries[i].name = seesaw_soil_saul_info[i].name;
saul_entries[i].driver = &seesaw_soil_saul_temp_driver;
saul_reg_add(&(saul_entries[i]));
}
}

View File

@ -227,6 +227,10 @@ void saul_init_devs(void)
extern void auto_init_sdp3x(void);
auto_init_sdp3x();
}
if (IS_USED(MODULE_SEESAW_SOIL)) {
extern void auto_init_seesaw_soil(void);
auto_init_seesaw_soil();
}
if (IS_USED(MODULE_SHT3X)) {
extern void auto_init_sht3x(void);
auto_init_sht3x();

View File

@ -0,0 +1,23 @@
# Copyright (c) 2020 Viktor Gal
#
# 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.
#
menuconfig KCONFIG_MODULE_SEESAW_SOIL
bool "Configure SEESAW_SOIL driver"
depends on MODULE_SEESAW_SOIL
help
Configure the SEESAW_SOIL driver using Kconfig.
if KCONFIG_MODULE_SEESAW_SOIL
config SEESAW_SOIL_I2C_ADDRESS
hex "I2C default address"
range 0x36 0x39
default 0x36
help
SEESAW_SOIL allows for up to 4 devices on single bus. The value depends on
the state of AD1 and AD0 pins.
endif # KCONFIG_MODULE_SEESAW_SOIL

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,2 @@
USEMODULE += xtimer
FEATURES_REQUIRED += periph_i2c

View File

@ -0,0 +1,2 @@
USEMODULE_INCLUDES_seesaw_soil := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_seesaw_soil)

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2020 Viktor Gal
*
* 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_seesaw_soil
*
* @{
* @file
* @brief Default configuration for Seesaw Soil devices
*
* @author Viktor Gal <viktor.gal@maeth.com>
*/
#ifndef SEESAW_SOIL_PARAMS_H
#define SEESAW_SOIL_PARAMS_H
#include "board.h"
#include "seesaw_soil.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters for the SEESAW_SOIL driver
* @{
*/
#ifndef SEESAW_SOIL_PARAM_I2C
#define SEESAW_SOIL_PARAM_I2C I2C_DEV(0)
#endif
#ifndef SEESAW_SOIL_PARAM_ADDR
#define SEESAW_SOIL_PARAM_ADDR (CONFIG_SEESAW_SOIL_I2C_ADDRESS)
#endif
#ifndef SEESAW_SOIL_PARAMS
#define SEESAW_SOIL_PARAMS { .i2c = SEESAW_SOIL_PARAM_I2C, \
.addr = SEESAW_SOIL_PARAM_ADDR }
#endif
#ifndef SEESAW_SOIL_SAUL_INFO
#define SEESAW_SOIL_SAUL_INFO { .name = "seesaw_soil" }
#endif
/**@}*/
/**
* @brief Seesaw Soil configuration
*/
static const seesaw_soil_params_t seesaw_soil_params[] =
{
SEESAW_SOIL_PARAMS
};
/**
* @brief Additional meta information to keep in the SAUL registry
*/
static const saul_reg_info_t seesaw_soil_saul_info[] =
{
SEESAW_SOIL_SAUL_INFO
};
#ifdef __cplusplus
}
#endif
#endif /* SEESAW_SOIL_PARAMS_H */
/** @} */

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2020 Viktor Gal
*
* 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_seesaw_soil
* @{
*
* @file
* @brief Register definitions for Seesaw Soil devices
*
* @author Viktor Gal <viktor.gal@maeth.com>
*/
#ifndef SEESAW_SOIL_REGS_H
#define SEESAW_SOIL_REGS_H
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @name Manufacturer ID
* @{
*/
#define SEESAW_SOIL_MID_VALUE 0x55
/** @} */
/**
* @name Register Map
* @{
*/
#define SEESAW_SOIL_MANUFACTURER_ID (0x01)
#define SEESAW_SOIL_TEMPERATURE (0x04)
#define SEESAW_SOIL_MOISTURE (0x0F10)
#define SEESAW_SOIL_RST (0x7F)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* SEESAW_SOIL_REGS_H */
/** @} */

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2020 Viktor Gal
*
* 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_seesaw_soil
* @{
*
* @file
* @brief Driver for the Adafruit Seesaw Soil Moisture and Temperature Sensor.
*
* @author Viktor Gal <viktor.gal@maeth.com>
*
* @}
*/
#include <string.h>
#include "assert.h"
#include "byteorder.h"
#include "xtimer.h"
#include "periph/i2c.h"
#include "seesaw_soil.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static int _seesaw_read_regs(const seesaw_soil_t *dev, uint16_t reg_addr, void* data, size_t len) {
int r;
reg_addr = htons(reg_addr);
/* send the 16bit register address we want to read with STOP bit */
if ((r = i2c_write_bytes(dev->params.i2c, dev->params.addr,
&reg_addr, 2, 0)) < 0) {
return r;
}
/* wait for the answer */
xtimer_usleep(5000);
/* and now we read the register value */
if ((r = i2c_read_bytes(dev->params.i2c, dev->params.addr,
data, len, 0)) < 0) {
return r;
}
return r;
}
static int _seesaw_read_reg(seesaw_soil_t *dev, uint16_t reg_addr, void* data) {
return _seesaw_read_regs(dev, reg_addr, data, 1);
}
int seesaw_soil_init(seesaw_soil_t *dev, const seesaw_soil_params_t *params)
{
uint8_t reg;
/* write device descriptor */
dev->params = *params;
DEBUG("[SEESAW SOIL] Initializing seesaw soil device.\n");
/* try if we can interact with the device by reading its manufacturer ID */
i2c_acquire(dev->params.i2c);
if (_seesaw_read_reg(dev, SEESAW_SOIL_MANUFACTURER_ID, &reg) < 0) {
DEBUG("[SEESAW SOIL] Could not read manufacture id.\n");
i2c_release(dev->params.i2c);
return SEESAW_SOIL_NOBUS;
}
if (reg != SEESAW_SOIL_MID_VALUE) {
DEBUG("[SEESAW SOIL] Wrong manufacture id: %x\n", reg);
i2c_release(dev->params.i2c);
return SEESAW_SOIL_NODEV;
}
i2c_release(dev->params.i2c);
/* all set */
return SEESAW_SOIL_OK;
}
int seesaw_soil_temperature(const seesaw_soil_t *dev, int16_t *temp)
{
int status = SEESAW_SOIL_OK;
uint32_t raw_temp;
i2c_acquire(dev->params.i2c);
if (_seesaw_read_regs(dev, SEESAW_SOIL_TEMPERATURE, &raw_temp, sizeof(raw_temp)) < 0) {
status = SEESAW_SOIL_BUSERR;
}
i2c_release(dev->params.i2c);
if (temp && (status == SEESAW_SOIL_OK)) {
*temp = (ntohl(raw_temp) * 100) >> 16;
}
return status;
}
int seesaw_soil_moisture(const seesaw_soil_t *dev, uint16_t *moist)
{
int status = SEESAW_SOIL_OK;
uint16_t raw_moist;
i2c_acquire(dev->params.i2c);
if (_seesaw_read_regs(dev, SEESAW_SOIL_MOISTURE, &raw_moist, 2) < 0) {
status = SEESAW_SOIL_BUSERR;
}
i2c_release(dev->params.i2c);
if (moist && (status == SEESAW_SOIL_OK)) {
*moist = ntohs(raw_moist);
}
return status;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2020 Viktor Gal
*
* 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_seesaw_soil
* @{
*
* @file
* @brief Seesaw Soil adaption to the RIOT actuator/sensor interface
*
* @author Viktor Gal <viktor.gal@maeth.com>
*
* @}
*/
#include <string.h>
#include "saul.h"
#include "seesaw_soil.h"
static int read_temp(const void *dev, phydat_t *res)
{
if (seesaw_soil_temperature((const seesaw_soil_t *)dev, &(res->val[0])) != SEESAW_SOIL_OK) {
return -ECANCELED;
}
res->val[1] = 0;
res->val[2] = 0;
res->unit = UNIT_TEMP_C;
res->scale = -2;
return 1;
}
const saul_driver_t seesaw_soil_saul_temp_driver = {
.read = read_temp,
.write = saul_notsup,
.type = SAUL_SENSE_TEMP,
};

View File

@ -0,0 +1,7 @@
include ../Makefile.tests_common
USEMODULE += seesaw_soil
USEMODULE += xtimer
USEMODULE += fmt
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,6 @@
# About
This is a manual test application for the Adafruit Seesaw Soil driver.
# Usage
After initialization, the sensor reads the temperature and moisture values every
second and prints them to STDOUT.

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2020 Viktor Gal
*
* 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 Adafruit Seesaw Soil sensor driver
*
* @author Viktor Gal <viktor.gal@maeth.com>
*
* @}
*/
#include <stdio.h>
#include "fmt.h"
#include "xtimer.h"
#include "seesaw_soil.h"
#include "seesaw_soil_params.h"
#define SLEEP_USEC (1000 * 1000U)
int main(void)
{
seesaw_soil_t dev;
int16_t temp;
uint16_t moist;
char tstr[8];
char mstr[8];
puts("Seesaw Soil Temperature and Moisture Sensor driver test application\n");
printf("Initializing Seesaw Soil sensor at I2C_DEV(%i)... ",
(int)seesaw_soil_params[0].i2c);
if (seesaw_soil_init(&dev, &seesaw_soil_params[0]) == SEESAW_SOIL_OK) {
puts("[OK]\n");
}
else {
puts("[Failed]");
return 1;
}
while (1) {
size_t len;
seesaw_soil_temperature(&dev, &temp);
seesaw_soil_moisture(&dev, &moist);
len = fmt_s16_dfp(tstr, temp, -2);
tstr[len] = '\0';
len = fmt_u16_dec(mstr, moist);
mstr[len] = '\0';
printf("Reading: T: %s °C Moist: %s\n", tstr, mstr);
xtimer_usleep(SLEEP_USEC);
}
return 0;
}