Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modified driver and example usage of opt3001 interrupt mechanism #3

Open
wants to merge 1 commit into
base: mirea
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 77 additions & 4 deletions drivers/include/opt3001.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* @file opt3001.h
* @brief driver for OPT3001 sensor
* @author Oleg Artamonov [[email protected]]
* @author Dmitriy Faychuk [[email protected]]
*/
#ifndef OPT3001_H_
#define OPT3001_H_
Expand All @@ -40,7 +41,9 @@
#define OPT3001_CFG_FC_4 0x0200
#define OPT3001_CFG_FC_8 0x0300
#define OPT3001_CFG_MASK 0x0400
#define OPT3001_CFG_POLNEG 0x0000
#define OPT3001_CFG_POLPOS 0x0800
#define OPT3001_CFG_HYSTER 0x0000
#define OPT3001_CFG_LATCH 0x1000
#define OPT3001_CFG_FLAGL 0x2000
#define OPT3001_CFG_FLAGH 0x4000
Expand All @@ -54,17 +57,57 @@
#define OPT3001_CFG_RNAUTO 0x00C0

#define OPT3001_CFG (OPT3001_CFG_FC_1 | OPT3001_CFG_SHOT | OPT3001_CFG_100MS | OPT3001_CFG_RNAUTO )
#define OPT3001_CFG_INT (OPT3001_CFG_CONT | OPT3001_CFG_800MS | OPT3001_CFG_RNAUTO)
#define OPT3001_CFG_DEFAULT 0x10C8

/**
* @brief OPT3001 registers
*/
#define OPT3001_REG_RESULT 0x00
#define OPT3001_REG_CONFIG 0x01
#define OPT3001_REG_LOW 0x02
#define OPT3001_REG_HIGH 0x03
#define OPT3001_REG_ID 0x7E
#define OPT3001_CHIP_ID 0x4954
#define OPT3001_REG_CONFIG_MASK 0xFE1F


/**
* @brief Enum that defines the OPT3001 fault counter states
*/
typedef enum {
OPT3001_FC_1 = (OPT3001_CFG_FC_1), /**< Threshold of faults is 1 */
OPT3001_FC_2 = (OPT3001_CFG_FC_2), /**< Threshold of faults is 2 */
OPT3001_FC_4 = (OPT3001_CFG_FC_4), /**< Threshold of faults is 4 */
OPT3001_FC_8 = (OPT3001_CFG_FC_8) /**< Threshold of faults is 8 */
} opt3001_fault_counter_t;

/**
* @brief Enum that defines the comparison modes of the OPT3001 Interrupt Reporting Mechanism
*/
typedef enum {
OPT3001_LATCHED = (OPT3001_CFG_LATCH), /**< Latched Window-Style Comparison Mode, requires manual clearing of the INT pin */
OPT3001_TRANSPARENT = (OPT3001_CFG_HYSTER) /**< Transparent Hysteresis-Style Comparison Mode */
} opt3001_cmp_mode_t;


/**
* @brief Enum that defines the OPT3001 end of conversion mode, which allow INT pin going active on every measurement completion
*/
typedef enum {
OPT3001_NO_EOC, /**< Disabled */
OPT3001_EOC /**< Enabled */
} opt3001_eoc_mode_t;

/**
* @brief Enum that defines the OPT3001 polarity or active state of the INT pin
*/
typedef enum {
OPT3001_IRQ_ON_LOW = (OPT3001_CFG_POLNEG), /**< Active state will be LOW */
OPT3001_IRQ_ON_HIGH = (OPT3001_CFG_POLPOS) /**< Active state will be HIGH */
} opt3001_pol_t;


/**
* @brief Structure that holds the OPT3001 driver internal state and parameters
*/
Expand All @@ -82,8 +125,8 @@ typedef struct {
* @brief OPT3001 driver initialization routine
* @note Corresponding I2C peripheral MUST be initialized before
*
* @param[out] dev device structure pointer
* @param[in] param OPT3001 driver parameters, data will be copied into device parameters
* @param[out] dev device structure pointer
* @param[in] param OPT3001 driver parameters, data will be copied into device parameters
*
* @return 0 if initialization succeeded
* @return <0 in case of error
Expand All @@ -93,8 +136,8 @@ int opt3001_init(opt3001_t *dev);
/**
* @brief Get OPT3001 measure
*
* @param[in] dev pointer to the initialized OPT3001 device
* @param[in] measure pointer to the allocated memory
* @param[in] dev pointer to the initialized OPT3001 device
* @param[in] measure pointer to the allocated memory
*
* @retval 0 for success
*
Expand All @@ -108,4 +151,34 @@ int opt3001_init(opt3001_t *dev);
*/
uint32_t opt3001_measure(opt3001_t *dev, opt3001_measure_t *measure);

/**
* @brief Init opt3001 Interrupt Reporting Mechanism
*
* @param[in] dev pointer to the initialized OPT3001 device
* @param[in] cmp comparison modes of the IRM
* @param[in] eoc end of conversion mode of the IRM
* @param[in] pol polarity of the INT pin
* @param[in] flt fault counter threshold
* @param[in] high HIGH limit value [0.01 - 83865.6], obviously should be higher than LOW
* @param[in] low LOW limit value [0.01 - 83865.6], obviously should be lower than HIGH
*
* @return 0 if succeeded
*
*/
int opt3001_init_int(opt3001_t *dev, opt3001_cmp_mode_t cmp, opt3001_eoc_mode_t eoc,
opt3001_pol_t pol, opt3001_fault_counter_t flt,
uint32_t high, uint32_t low);

/**
* @brief OPT3001 INTpin/FlagH/FlagL clearing routine
* @note Only works with Latched Window-style comparison mode
*
* @param[in] dev pointer to the initialized OPT3001 device
*
* @return 0 if succeeded
*
*/
int opt3001_clear_int(opt3001_t *dev);


#endif /* OPT3001_H_ */
86 changes: 85 additions & 1 deletion drivers/opt3001/opt3001.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
* @{
* @file opt3001.c
* @brief basic driver for OPT3001 sensor
* @authoh Oleg Artamonov [[email protected]]
* @author Oleg Artamonov [[email protected]]
* @author Dmitriy Faychuk [[email protected]]
*/


Expand Down Expand Up @@ -145,6 +146,89 @@ uint32_t opt3001_measure(opt3001_t *dev, opt3001_measure_t *measure)
}


uint8_t get_exp(uint32_t lum)
{
uint8_t exp = 0;
while(lum > 41) {
lum /= 2.0;
exp++;
}
return exp;
}

uint16_t convert(uint32_t lum)
{
uint8_t exp = get_exp(lum);
uint16_t lsb_size_x100 = (1 << exp);
uint16_t binary_mantissa = (lum * 100) / lsb_size_x100;
uint16_t binary_exp = exp << 12;
uint16_t binary_limit = binary_exp | binary_mantissa;
return binary_limit;
}


/**
* @brief Init opt3001 Interrupt Reporting Mechanism
*
* @param[in] dev pointer to the initialized OPT3001 device
* @param[in] cmp comparison mode of the IRM
* @param[in] eoc end of conversion mode of the IRM
* @param[in] pol polarity of the INT pin
* @param[in] flt fault counter threshold
* @param[in] high HIGH limit value [0.01 - 83865.6], obviously should be higher than LOW
* @param[in] low LOW limit value [0.01 - 83865.6], obviously should be lower than HIGH
*
* @return 0 if succeeded
*
*/
int opt3001_init_int(opt3001_t *dev, opt3001_cmp_mode_t cmp, opt3001_eoc_mode_t eoc,
opt3001_pol_t pol, opt3001_fault_counter_t flt,
uint32_t high, uint32_t low)
{
assert(dev != NULL);
i2c_acquire(dev->i2c);

uint16_t cfg = OPT3001_CFG_INT | cmp | pol | flt;
i2c_write_regs(dev->i2c, OPT3001_ADDRESS, OPT3001_REG_CONFIG, (char *)&cfg, 2);

uint16_t high_limit = convert(high);
/* swap bytes, as OPT3001 expects MSB first and I2C driver sends LSB first */
high_limit = ((high_limit >> 8) | (high_limit << 8));
i2c_write_regs(dev->i2c, OPT3001_ADDRESS, OPT3001_REG_HIGH, (char *)&high_limit, 2);

uint16_t low_limit = convert(low);
if(eoc == OPT3001_EOC)
low_limit = (low_limit & 0x3FFF) | 0xC000; // Clear two most significant bits and set them to 11b.
/* swap bytes, as OPT3001 expects MSB first and I2C driver sends LSB first */
low_limit = ((low_limit >> 8) | (low_limit << 8));
i2c_write_regs(dev->i2c, OPT3001_ADDRESS, OPT3001_REG_LOW, (char *)&low_limit, 2);

i2c_release(dev->i2c);
return 0;
}


/**
* @brief OPT3001 INTpin/FlagH/FlagL clearing routine
* @note Only works with Latched Window-style comparison mode
*
* @param[in] dev pointer to the initialized OPT3001 device
*
* @return 0 if succeeded
*
*/
int opt3001_clear_int(opt3001_t *dev)
{
assert(dev != NULL);

i2c_acquire(dev->i2c);
uint16_t cfg = i2c_read_regs(dev->i2c, OPT3001_ADDRESS, OPT3001_REG_CONFIG, (char *)&cfg, 2);
i2c_release(dev->i2c);

return 0;
}


#ifdef __cplusplus
}
#endif
25 changes: 25 additions & 0 deletions examples/irq_limit_opt/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# name of your application
APPLICATION = irq_limit_opt

# If no BOARD is found in the environment, use this default:
BOARD ?= unwd-range-l1-r3

# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1

USEMODULE += opt3001
USEMODULE += xtimer

FEATURES_REQUIRED += periph_i2c
FEATURES_REQUIRED += periph_rtc
FEATURES_REQUIRED += periph_gpio

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

include $(RIOTBASE)/Makefile.include
63 changes: 63 additions & 0 deletions examples/irq_limit_opt/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <stdio.h>
#include "periph/gpio.h"
#include "periph/pm.h"
#include "thread.h"
#include "opt3001.h"
#include "xtimer.h"

#define ENABLE_DEBUG (1)
#include "debug.h"

#define LED_CONTROL_STACK_SIZE (1024)

static kernel_pid_t led_control_pid;
static msg_t led_control_msg;

static void* led_control(void * arg) {
(void)arg;
msg_t message;
while(1) {
msg_receive(&message);
gpio_toggle(GPIO_PIN(PORT_B, 0));
DEBUG("%s\n", "Irq spotted!" );
}
return NULL;
}

static opt3001_t opt3001;

static void interrupt_handler(void* arg) {
(void)arg;
msg_send(&led_control_msg, led_control_pid);
opt3001_clear_int(&opt3001);
}


int main(void)
{
xtimer_init();

pm_init();
pm_prevent_sleep = 1;

puts("Led toggling program. Control the led by irq's sended from opt3001");

printf("You are running RIOT on a(n) %s board.\n", RIOT_BOARD);
printf("This board features a(n) %s MCU.\n", RIOT_MCU);

gpio_init(GPIO_PIN(PORT_B, 0), GPIO_OUT);
gpio_set(GPIO_PIN(PORT_B, 0));

opt3001.i2c = 1;
opt3001_init(&opt3001);
opt3001_init_int(&opt3001, OPT3001_LATCHED, OPT3001_NO_EOC, OPT3001_IRQ_ON_LOW, OPT3001_FC_1, 10000, 100);
gpio_init_int(GPIO_PIN(PORT_A,7), GPIO_IN_PU, GPIO_FALLING, interrupt_handler, NULL);

char stack[LED_CONTROL_STACK_SIZE];
led_control_pid = thread_create(stack, LED_CONTROL_STACK_SIZE,
THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST,
led_control, NULL, "Toggling the led");

return 0;
}
//