Skip to content

Commit

Permalink
Support MAX44009 i2c sensor (#47)
Browse files Browse the repository at this point in the history
* Support MAX44009 i2c sensor

* Fix conversion factor

---------

Co-authored-by: wosk <nikita.vostokov@auriga.com>
Co-authored-by: Oleksii Kutuzov <oleksii.kutuzov@icloud.com>
  • Loading branch information
3 people authored Jul 11, 2023
1 parent f64b084 commit 5de076e
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Lightmeter for Flipper Zero

Lightmeter app for photography based on BH1750 sensor
Lightmeter app for photography based on BH1750/MAX44009 sensor

## Support

Expand Down
9 changes: 8 additions & 1 deletion application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,15 @@ App(
"BH1750.c",
],
),
Lib(
name="MAX44009",
cincludes=["."],
sources=[
"MAX44009.c",
],
),
],
fap_description="Lightmeter app for photography based on BH1750 sensor",
fap_description="Lightmeter app for photography based on BH1750/MAX44009 sensor",
fap_author="Oleksii Kutuzov",
fap_weburl="https://github.com/oleksiikutuzov/flipperzero-lightmeter",
fap_icon_assets="icons",
Expand Down
22 changes: 22 additions & 0 deletions gui/scenes/lightmeter_scene_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,18 @@ static const char* lux_only[] = {
[LUX_ONLY_ON] = "On",
};

static const char* sensor_type[] = {
[SENSOR_BH1750] = "BH1750",
[SENSOR_MAX44009] = "MAX44009",
};

enum LightMeterSubmenuIndex {
LightMeterSubmenuIndexISO,
LightMeterSubmenuIndexND,
LightMeterSubmenuIndexDome,
LightMeterSubmenuIndexBacklight,
LightMeterSubmenuIndexLuxMeter,
LightMeterSubmenuIndexSensorType,
LightMeterSubmenuIndexHelp,
LightMeterSubmenuIndexAbout,
};
Expand Down Expand Up @@ -127,6 +133,17 @@ static void lux_only_cb(VariableItem* item) {
lightmeter_app_set_config(app, config);
}

static void sensor_type_cb(VariableItem* item) {
LightMeterApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);

variable_item_set_current_value_text(item, sensor_type[index]);

LightMeterConfig* config = app->config;
config->sensor_type = index;
lightmeter_app_set_config(app, config);
}

static void ok_cb(void* context, uint32_t index) {
LightMeterApp* app = context;
UNUSED(app);
Expand Down Expand Up @@ -173,6 +190,11 @@ void lightmeter_scene_config_on_enter(void* context) {
variable_item_set_current_value_index(item, config->lux_only);
variable_item_set_current_value_text(item, lux_only[config->lux_only]);

item = variable_item_list_add(
var_item_list, "Sensor", COUNT_OF(sensor_type), sensor_type_cb, app);
variable_item_set_current_value_index(item, config->sensor_type);
variable_item_set_current_value_text(item, sensor_type[config->sensor_type]);

item = variable_item_list_add(var_item_list, "Help and Pinout", 0, NULL, NULL);
item = variable_item_list_add(var_item_list, "About", 0, NULL, NULL);

Expand Down
3 changes: 2 additions & 1 deletion gui/scenes/lightmeter_scene_help.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ void lightmeter_scene_help_on_enter(void* context) {
FuriString* temp_str;
temp_str = furi_string_alloc();
furi_string_printf(
temp_str, "App works with BH1750\nambient light sensor\nconnected via I2C interface\n\n");
temp_str,
"App works with BH1750 and MAX44409 ambient light sensor connected via I2C interface\n\n");
furi_string_cat(temp_str, "\e#Pinout:\r\n");
furi_string_cat(
temp_str,
Expand Down
3 changes: 2 additions & 1 deletion gui/scenes/lightmeter_scene_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ static void lightmeter_scene_main_on_left(void* context) {
void lightmeter_scene_main_on_enter(void* context) {
LightMeterApp* app = context;

lightmeter_app_i2c_init_sensor(context);
lightmeter_main_view_set_left_callback(app->main_view, lightmeter_scene_main_on_left, app);
view_dispatcher_switch_to_view(app->view_dispatcher, LightMeterAppViewMainView);
}
Expand Down Expand Up @@ -39,5 +40,5 @@ bool lightmeter_scene_main_on_event(void* context, SceneManagerEvent event) {
}

void lightmeter_scene_main_on_exit(void* context) {
UNUSED(context);
lightmeter_app_i2c_deinit_sensor(context);
}
27 changes: 27 additions & 0 deletions lib/MAX44009/MAX44009.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <MAX44009.h>
#include <math.h>
#include <furi.h>

void max44009_init() {
furi_hal_i2c_acquire(I2C_BUS);
furi_hal_i2c_write_reg_8(I2C_BUS, MAX44009_ADDR,
MAX44009_REG_CONFIG, MAX44009_REG_CONFIG_CONT_MODE, I2C_TIMEOUT);
furi_hal_i2c_release(I2C_BUS);
}

int max44009_read_light(float* result) {
uint8_t data_one = 0;
uint8_t exp, mantissa;
int status;

furi_hal_i2c_acquire(I2C_BUS);
furi_hal_i2c_read_reg_8(I2C_BUS, MAX44009_ADDR, MAX44009_REG_LUX_HI, &data_one, I2C_TIMEOUT);
exp = (data_one & MAX44009_REG_LUX_HI_EXP_MASK) >> 4;
mantissa = (data_one & MAX44009_REG_LUX_HI_MANT_HI_MASK) << 4;
status = furi_hal_i2c_read_reg_8(I2C_BUS, MAX44009_ADDR, MAX44009_REG_LUX_LO, &data_one, I2C_TIMEOUT);
mantissa |= (data_one & MAX44009_REG_LUX_LO_MANT_LO_MASK);
furi_hal_i2c_release(I2C_BUS);
*result = (float)pow(2, exp) * mantissa * 0.045;
FURI_LOG_D("MAX44009", "exp %d, mant %d, lux %f", exp, mantissa, (double)*result);
return status;
}
26 changes: 26 additions & 0 deletions lib/MAX44009/MAX44009.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <furi.h>
#include <furi_hal.h>

#pragma once

// I2C BUS
#define I2C_BUS &furi_hal_i2c_handle_external
#define I2C_TIMEOUT 10

#define MAX44009_ADDR (0x4A << 1)

#define MAX44009_REG_INT_STATUS 0x00
#define MAX44009_REG_INT_EN 0x01
#define MAX44009_REG_CONFIG 0x02
#define MAX44009_REG_CONFIG_CONT_MODE (1 << 7)
#define MAX44009_REG_LUX_HI 0x03
#define MAX44009_REG_LUX_HI_EXP_MASK 0xF0
#define MAX44009_REG_LUX_HI_MANT_HI_MASK 0x0F
#define MAX44009_REG_LUX_LO 0x04
#define MAX44009_REG_LUX_LO_MANT_LO_MASK 0x0F
#define MAX44009_REG_THRESH_HI 0x05
#define MAX44009_REG_THRESH_LO 0x06
#define MAX44009_REG_INT_TIME 0x07

void max44009_init();
int max44009_read_light(float* result);
57 changes: 42 additions & 15 deletions lightmeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ static void lightmeter_tick_event_callback(void* context) {
LightMeterApp* lightmeter_app_alloc(uint32_t first_scene) {
LightMeterApp* app = malloc(sizeof(LightMeterApp));

// Sensor
bh1750_set_power_state(1);
bh1750_init();
bh1750_set_mode(ONETIME_HIGH_RES_MODE);

// Set default values to config
app->config = malloc(sizeof(LightMeterConfig));
app->config->iso = DEFAULT_ISO;
Expand Down Expand Up @@ -117,8 +112,6 @@ void lightmeter_app_free(LightMeterApp* app) {
}
furi_record_close(RECORD_NOTIFICATION);

bh1750_set_power_state(0);

free(app->config);
free(app);
}
Expand All @@ -138,23 +131,57 @@ void lightmeter_app_set_config(LightMeterApp* context, LightMeterConfig* config)
app->config = config;
}

void lightmeter_app_i2c_init_sensor(LightMeterApp* context) {
LightMeterApp* app = context;
switch(app->config->sensor_type) {
case SENSOR_BH1750:
bh1750_set_power_state(1);
bh1750_init();
bh1750_set_mode(ONETIME_HIGH_RES_MODE);
break;
case SENSOR_MAX44009:
max44009_init();
break;
default:
FURI_LOG_E(TAG, "Invalid sensor type %d", app->config->sensor_type);
return;
}
}

void lightmeter_app_i2c_deinit_sensor(LightMeterApp* context) {
LightMeterApp* app = context;
switch(app->config->sensor_type) {
case SENSOR_BH1750:
bh1750_set_power_state(0);
break;
case SENSOR_MAX44009:
// nothing
break;
default:
FURI_LOG_E(TAG, "Invalid sensor type %d", app->config->sensor_type);
return;
}
}

void lightmeter_app_i2c_callback(LightMeterApp* context) {
LightMeterApp* app = context;

float EV = 0;
float lux = 0;
bool response = 0;

if(bh1750_trigger_manual_conversion() == BH1750_OK) response = 1;

if(response) {
bh1750_read_light(&lux);

if(main_view_get_dome(app->main_view)) lux *= DOME_COEFFICIENT;

EV = lux2ev(lux);
if(app->config->sensor_type == SENSOR_BH1750) {
if(bh1750_trigger_manual_conversion() == BH1750_OK) {
bh1750_read_light(&lux);
response = 1;
}
} else if(app->config->sensor_type == SENSOR_MAX44009) {
if(max44009_read_light(&lux)) response = 1;
}

if(main_view_get_dome(app->main_view)) lux *= DOME_COEFFICIENT;
EV = lux2ev(lux);

main_view_set_lux(app->main_view, lux);
main_view_set_EV(app->main_view, EV);
main_view_set_response(app->main_view, response);
Expand Down
4 changes: 4 additions & 0 deletions lightmeter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "lightmeter_config.h"
#include <BH1750.h>
#include <MAX44009.h>

typedef struct {
int iso;
Expand All @@ -26,6 +27,7 @@ typedef struct {
int dome;
int backlight;
int lux_only;
int sensor_type;
} LightMeterConfig;

typedef struct {
Expand Down Expand Up @@ -55,4 +57,6 @@ typedef enum {

void lightmeter_app_set_config(LightMeterApp* context, LightMeterConfig* config);

void lightmeter_app_i2c_init_sensor(LightMeterApp* context);
void lightmeter_app_i2c_deinit_sensor(LightMeterApp* context);
void lightmeter_app_i2c_callback(LightMeterApp* context);
5 changes: 5 additions & 0 deletions lightmeter_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,9 @@ typedef enum {
LUX_ONLY_ON,
} LightMeterLuxOnlyMode;

typedef enum {
SENSOR_BH1750,
SENSOR_MAX44009,
} LightMeterSensorType;

typedef enum { BACKLIGHT_AUTO, BACKLIGHT_ON } LightMeterBacklight;

0 comments on commit 5de076e

Please sign in to comment.