diff --git a/ltr329.c b/ltr329.c new file mode 100644 index 0000000..6918d7d --- /dev/null +++ b/ltr329.c @@ -0,0 +1,202 @@ +/* + * ltr329.c + * + * Created on: May 22, 2022 + * Author: david + */ +#include "ltr329.h" +#include "main.h" /* for uart_disable_interrupts() */ + +static int8_t ltr329_read_register (ltr329_cmd_t register_addr, uint8_t *register_data ) +{ + uint8_t tx_buffer[1]; + uint8_t rx_buffer[1]; + int result; + + // start measurement + tx_buffer[0] = register_addr; + /* disable interrupts to prevent modbus/i2c conflict */ + uart_disable_interrupts(); + result = i2c_transmit(LTR329_I2C_ADDRESS<<1, tx_buffer, 1); + uart_enable_interrupts(); + if (result != I2C_OK) { + return LTR329_ERROR; + } + LL_mDelay(10); /* 10 ms should be enough */ + /* read out */ + uart_disable_interrupts(); + result = i2c_receive(LTR329_I2C_ADDRESS<<1, rx_buffer, 1); + uart_enable_interrupts(); + if (result != I2C_OK) { + return LTR329_ERROR; + } + + *register_data = rx_buffer[0]; + return LTR329_OK; +} + +static int8_t ltr329_write_register (ltr329_cmd_t register_addr, uint8_t register_data) +{ + uint8_t tx_buffer[2]; + int result; + + // start measurement + tx_buffer[0] = register_addr; + tx_buffer[1] = register_data; + /* disable interrupts to prevent modbus/i2c conflict */ + uart_disable_interrupts(); + result = i2c_transmit(LTR329_I2C_ADDRESS<<1, tx_buffer, 2); + uart_enable_interrupts(); + if (result != I2C_OK) { + return LTR329_ERROR; + } + return LTR329_OK; +} + +int8_t ltr329_write_settings (ltr329_gain_t gain, ltr329_als_mode_t mode, ltr329_integration_time_t integ_time, ltr329_measurement_rate_t meas_rate) +{ + int8_t result; + /* Write Gain and ALS Mode */ + result = ltr329_write_register(LTR329_ALS_CONTR, (gain | mode)); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + /* Write Integration Time and Measurement Rate */ + + result = ltr329_write_register(LTR329_ALS_MEAS_RATE, (integ_time | meas_rate)); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + return LTR329_OK; +} + +int8_t ltr329_read_settings (ltr329_gain_t *gain, ltr329_als_mode_t *mode, ltr329_integration_time_t *integ_time, ltr329_measurement_rate_t *meas_rate) +{ + int8_t result; + uint8_t control_register_data; + uint8_t rate_register_data; + + result = ltr329_read_register(LTR329_ALS_CONTR, &control_register_data); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + + result = ltr329_read_register(LTR329_ALS_MEAS_RATE, &rate_register_data); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + + uint8_t control_register_gain_mask = 0b00011100; + uint8_t control_register_mode_mask = 0b00000001; + uint8_t rate_register_int_time_mask = 0b00111000; + uint8_t rate_register_rate_mask = 0b00000111; + + /* Return Registers Values */ + /* TODO: This might not be safe */ + *gain = control_register_data & control_register_gain_mask; + *mode = control_register_data & control_register_mode_mask; + *integ_time = rate_register_data & rate_register_int_time_mask; + *meas_rate = rate_register_data & rate_register_rate_mask; + + return LTR329_OK; +} + +int8_t ltr329_sw_reset( void ) +{ + int8_t result; + /* Write Gain and ALS Mode */ + result = ltr329_write_register(LTR329_ALS_CONTR, 0b00000010); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + return LTR329_OK; +} + +int8_t ltr329_measure (uint16_t *data_ch0, uint16_t *data_ch1) +{ + uint8_t ch0_l, ch0_h, ch1_l, ch1_h; + int result; + result = ltr329_read_register(LTR329_ALS_DATA_CH0_0, &ch0_l); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + result = ltr329_read_register(LTR329_ALS_DATA_CH0_1, &ch0_h); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + result = ltr329_read_register(LTR329_ALS_DATA_CH1_0, &ch1_l); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + result = ltr329_read_register(LTR329_ALS_DATA_CH1_1, &ch1_h); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + + *data_ch0 = (ch0_h << 8) + ch0_l; + *data_ch1 = (ch1_h << 8) + ch1_l; + return LTR329_OK; +} + +int8_t ltr329_read_status_register(uint8_t *data_valid, uint8_t *new_data, ltr329_gain_t *gain) +{ + int8_t result; + uint8_t status_register_data; + result = ltr329_read_register(LTR329_ALS_STATUS, &status_register_data); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + + /* Check data valid */ + uint8_t data_invalid_mask = 0b10000000; + if ((status_register_data & data_invalid_mask) == data_invalid_mask) + { + *data_valid = 0; + } else + { + *data_valid = 1; + } + + /* Check if there is new data */ + uint8_t data_status_mask = 0b00000100; + if ((status_register_data & data_status_mask) == data_status_mask) + { + *new_data = 1; + } else + { + *new_data = 0; + } + + /* Check Gain */ + /* TODO: This might not be safe */ + uint8_t gain_mask = 0b01110000; + *gain = status_register_data & gain_mask; + + return LTR329_OK; +} + +int8_t ltr329_read_device_info (uint8_t *manufacturer_id, uint8_t *part_id) +{ + int8_t result; + result = ltr329_read_register(LTR329_MANUFAC_ID, manufacturer_id); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + result = ltr329_read_register(LTR329_PART_ID, part_id); + if (result != LTR329_OK) + { + return LTR329_ERROR; + } + return LTR329_OK; +} diff --git a/ltr329.h b/ltr329.h new file mode 100644 index 0000000..7294a2a --- /dev/null +++ b/ltr329.h @@ -0,0 +1,93 @@ +/* + * ltr329.h + * + * Created on: May 22, 2022 + * Author: david + */ + +#ifndef INC_LTR329_H_ +#define INC_LTR329_H_ + +#include "stdint.h" +#include "stm32l0xx_ll_i2c.h" +#include "stm32l0xx_ll_utils.h" +#include "i2c.h" + +#define LTR329_I2C_ADDRESS 0x29 + +/* + * Return values + */ + +#define LTR329_OK 0 +#define LTR329_ERROR -1 // generic error + +/* LTR-329ALS-01 Registers */ +/* Datasheet: https://optoelectronics.liteon.com/upload/download/DS86-2014-0006/LTR-329ALS-01_DS_V1.pdf */ +typedef enum +{ + LTR329_ALS_CONTR = 0x80, /* RW */ + LTR329_ALS_MEAS_RATE = 0x85, /* RW */ + LTR329_PART_ID = 0x86, /* R */ + LTR329_MANUFAC_ID = 0x87, /* R */ + LTR329_ALS_DATA_CH1_0 = 0x88, /* R */ + LTR329_ALS_DATA_CH1_1 = 0x89, /* R */ + LTR329_ALS_DATA_CH0_0 = 0x8A, /* R */ + LTR329_ALS_DATA_CH0_1 = 0x8B, /* R */ + LTR329_ALS_STATUS = 0x8C /* R */ +} ltr329_cmd_t; + +/* Bit masks for ALS Mode */ +typedef enum +{ + LTR329_MODE_STAND_BY = 0b00000000, /* DEFAULT */ + LTR329_MODE_ACTIVE = 0b00000001 +} ltr329_als_mode_t; + +/* Bit masks for Gain settings */ +typedef enum +{ + LTR329_GAIN_1X = 0b00000000, /* DEFAULT */ + LTR329_GAIN_2X = 0b00000100, + LTR329_GAIN_4X = 0b00001000, + LTR329_GAIN_8X = 0b00001100, + LTR329_GAIN_48X = 0b00011000, + LTR329_GAIN_96X = 0b00011100, + LTR329_GAIN_RESERVED1 = 0b00010000, + LTR329_GAIN_RESERVED2 = 0b00010100 +} ltr329_gain_t; + +/* Bit masks for Integration Time settings */ +typedef enum +{ + LTR329_INTEGRATION_50MS = 0b00001000, + LTR329_INTEGRATION_100MS = 0b00000000, /* DEFAULT */ + LTR329_INTEGRATION_150MS = 0b00100000, + LTR329_INTEGRATION_200MS = 0b00010000, + LTR329_INTEGRATION_250MS = 0b00101000, + LTR329_INTEGRATION_300MS = 0b00110000, + LTR329_INTEGRATION_350MS = 0b00111000, + LTR329_INTEGRATION_400MS = 0b00011000 +} ltr329_integration_time_t; + +/* Bit masks for Measurement Rate settings */ +typedef enum +{ + LTR329_MEAS_RATE_50MS = 0b00000000, + LTR329_MEAS_RATE_100MS = 0b00000001, + LTR329_MEAS_RATE_200MS = 0b00000010, + LTR329_MEAS_RATE_500MS = 0b00000011, /* DEFAULT */ + LTR329_MEAS_RATE_1000MS = 0b00000100, + LTR329_MEAS_RATE_2000MS = 0b00000111 +} ltr329_measurement_rate_t; + +static int8_t ltr329_read_register (ltr329_cmd_t register_addr, uint8_t *register_data ); +static int8_t ltr329_write_register (ltr329_cmd_t register_addr, uint8_t register_data); +int8_t ltr329_write_settings (ltr329_gain_t gain, ltr329_als_mode_t mode, ltr329_integration_time_t integ_time, ltr329_measurement_rate_t meas_rate); +int8_t ltr329_read_settings (ltr329_gain_t *gain, ltr329_als_mode_t *mode, ltr329_integration_time_t *integ_time, ltr329_measurement_rate_t *meas_rate); +int8_t ltr329_sw_reset( void ); +int8_t ltr329_measure (uint16_t *data_ch0, uint16_t *data_ch1); +int8_t ltr329_read_status_register(uint8_t *data_valid, uint8_t *new_data, ltr329_gain_t *gain); +int8_t ltr329_read_device_info (uint8_t *manufacturer_id, uint8_t *part_id); + +#endif /* INC_LTR329_H_ */