kopia lustrzana https://github.com/pimoroni/pimoroni-pico
AS7262 driver
Co-authored-by: ZodiusInfuser <christopher.parrott2@gmail.com>pull/142/head
rodzic
cf8f2dfac2
commit
6afbc2e64c
|
@ -11,3 +11,4 @@ add_subdirectory(vl53l1x)
|
|||
add_subdirectory(is31fl3731)
|
||||
add_subdirectory(fatfs)
|
||||
add_subdirectory(sdcard)
|
||||
add_subdirectory(as7262)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(as7262.cmake)
|
|
@ -0,0 +1,10 @@
|
|||
set(DRIVER_NAME as7262)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
target_sources(${DRIVER_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
|
||||
|
||||
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c)
|
|
@ -0,0 +1,190 @@
|
|||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "as7262.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
/***** Device registers and masks here *****/
|
||||
|
||||
enum reg {
|
||||
DEVICE = 0x00,
|
||||
HW_VERSION = 0x01,
|
||||
FW_VERSION = 0x02, // + 0x03
|
||||
CONTROL = 0x04,
|
||||
INT_T = 0x05,
|
||||
TEMP = 0x06,
|
||||
LED_CONTROL = 0x07,
|
||||
V_HIGH = 0x08, // Violet
|
||||
V_LOW = 0x09,
|
||||
B_HIGH = 0x0A, // Blue
|
||||
B_LOW = 0x0B,
|
||||
G_HIGH = 0x0C, // Green
|
||||
G_LOW = 0x0D,
|
||||
Y_HIGH = 0x0E, // Yellow
|
||||
Y_LOW = 0x0F,
|
||||
O_HIGH = 0x10, // Orange
|
||||
O_LOW = 0x11,
|
||||
R_HIGH = 0x12, // Red
|
||||
R_LOW = 0x13,
|
||||
V_CAL_F = 0x14, // -> 0x17 Float (Violet)
|
||||
B_CAL_F = 0x18, // -> 0x1B Float (Blue)
|
||||
G_CAL_F = 0x1C, // -> 0x1F Float (Green)
|
||||
Y_CAL_F = 0x20, // -> 0x23 Float (Yellow)
|
||||
O_CAL_F = 0x24, // -> 0x27 Float (Orange)
|
||||
R_CAL_F = 0x28, // -> 0x27 Float (Red)
|
||||
};
|
||||
|
||||
|
||||
bool AS7262::init() {
|
||||
bool succeeded = false;
|
||||
|
||||
i2c_init(i2c, 400000);
|
||||
|
||||
gpio_set_function(sda, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(sda);
|
||||
gpio_set_function(scl, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(scl);
|
||||
|
||||
if(interrupt != PIN_UNUSED) {
|
||||
gpio_set_function(interrupt, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(interrupt, GPIO_IN);
|
||||
gpio_pull_up(interrupt);
|
||||
}
|
||||
|
||||
reset();
|
||||
|
||||
/***** Replace if(true) with any operations needed to initialise the device *****/
|
||||
if(true) {
|
||||
succeeded = true;
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void AS7262::reset() {
|
||||
i2c_reg_write_uint8(reg::CONTROL, 0b10000000);
|
||||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
void AS7262::set_gain(gain gain) {
|
||||
uint8_t temp = i2c_reg_read_uint8(reg::CONTROL) & ~0b00110000;
|
||||
temp |= (uint8_t)gain << 4;
|
||||
i2c_reg_write_uint8(reg::CONTROL, temp);
|
||||
}
|
||||
|
||||
void AS7262::set_measurement_mode(measurement_mode mode) {
|
||||
uint8_t temp = i2c_reg_read_uint8(reg::CONTROL) & ~0b00001100;
|
||||
temp |= (uint8_t)mode << 2;
|
||||
i2c_reg_write_uint8(reg::CONTROL, temp);
|
||||
}
|
||||
|
||||
void AS7262::set_indicator_current(indicator_current current) {
|
||||
uint8_t temp = i2c_reg_read_uint8(reg::LED_CONTROL) & ~0b00000110;
|
||||
temp |= (uint8_t)current << 1;
|
||||
i2c_reg_write_uint8(reg::LED_CONTROL, temp);
|
||||
}
|
||||
|
||||
void AS7262::set_illumination_current(illumination_current current) {
|
||||
uint8_t temp = i2c_reg_read_uint8(reg::LED_CONTROL) & ~0b00110000;
|
||||
temp |= (uint8_t)current << 4;
|
||||
i2c_reg_write_uint8(reg::LED_CONTROL, temp);
|
||||
}
|
||||
|
||||
void AS7262::set_leds(bool illumination, bool indicator) {
|
||||
uint8_t temp = i2c_reg_read_uint8(reg::LED_CONTROL) & ~0b00001001;
|
||||
temp |= indicator ? 1 : 0;
|
||||
temp |= (illumination ? 1 : 0) << 3;
|
||||
i2c_reg_write_uint8(reg::LED_CONTROL, temp);
|
||||
}
|
||||
|
||||
std::string AS7262::firmware_version() {
|
||||
std::string buf;
|
||||
uint16_t fw_version = i2c_reg_read_uint16(reg::FW_VERSION);
|
||||
buf += std::to_string(fw_version);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool AS7262::data_ready() {
|
||||
return i2c_reg_read_uint8(reg::CONTROL) & 0b00000010;
|
||||
}
|
||||
|
||||
AS7262::reading AS7262::read() {
|
||||
while(!data_ready()) {}
|
||||
return AS7262::reading {
|
||||
i2c_reg_read_float(reg::R_CAL_F),
|
||||
i2c_reg_read_float(reg::O_CAL_F),
|
||||
i2c_reg_read_float(reg::Y_CAL_F),
|
||||
i2c_reg_read_float(reg::G_CAL_F),
|
||||
i2c_reg_read_float(reg::B_CAL_F),
|
||||
i2c_reg_read_float(reg::V_CAL_F)
|
||||
};
|
||||
}
|
||||
|
||||
uint8_t AS7262::temperature() {
|
||||
return i2c_reg_read_uint8(reg::TEMP);
|
||||
}
|
||||
|
||||
// i2c IO wrappers around the weird virtual i2c nonsense
|
||||
|
||||
void AS7262::i2c_reg_write_uint8(uint8_t reg, uint8_t value) {
|
||||
_i2c_write(reg, &value, 1);
|
||||
}
|
||||
|
||||
float AS7262::i2c_reg_read_float(uint8_t reg) {
|
||||
float value;
|
||||
_i2c_read(reg, (uint8_t *)&value, 4);
|
||||
return __builtin_bswap32(value);
|
||||
}
|
||||
|
||||
uint8_t AS7262::i2c_reg_read_uint8(uint8_t reg) {
|
||||
uint8_t value;
|
||||
_i2c_read(reg, &value, 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint16_t AS7262::i2c_reg_read_uint16(uint8_t reg) {
|
||||
uint16_t value;
|
||||
_i2c_read(reg, (uint8_t *)&value, 2);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Plumbing for virtual i2c
|
||||
void AS7262::_i2c_reg_write_uint8(uint8_t reg, uint8_t value) {
|
||||
uint8_t buffer[2] = {reg, value};
|
||||
i2c_write_blocking(i2c, address, buffer, 2, false);
|
||||
}
|
||||
|
||||
uint8_t AS7262::_i2c_reg_read_uint8(uint8_t reg) {
|
||||
uint8_t value;
|
||||
i2c_write_blocking(i2c, address, ®, 1, false);
|
||||
i2c_read_blocking(i2c, address, (uint8_t *)&value, 1, false);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t AS7262::_i2c_status() {
|
||||
return _i2c_reg_read_uint8(0x00);
|
||||
}
|
||||
|
||||
int AS7262::_i2c_read(uint8_t reg, uint8_t *values, int len) {
|
||||
for (auto i = 0u; i < len; i++){
|
||||
while((_i2c_status() & 0b10) != 0) {}; // Wait for write-ready
|
||||
_i2c_reg_write_uint8(0x01, reg + i); // Set address pointer
|
||||
while((_i2c_status() & 0b01) != 1) {}; // Wait for read-ready
|
||||
values[i] = _i2c_reg_read_uint8(0x02); // Read *one* byte :|
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AS7262::_i2c_write(uint8_t reg, uint8_t *values, int len) {
|
||||
for (auto i = 0u; i < len; i++){
|
||||
while((_i2c_status() & 0b10) != 0) {}; // Wait for write-ready
|
||||
_i2c_reg_write_uint8(0x01, reg | 0x80); // Set address pointer
|
||||
while ((_i2c_status() & 0b10) != 0) {}; // Wait for write-ready
|
||||
_i2c_reg_write_uint8(0x01, values[i]); // Write *one* byte :|
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
class AS7262 {
|
||||
//--------------------------------------------------
|
||||
// Constants
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
static const uint8_t DEFAULT_I2C_ADDRESS = 0x49;
|
||||
static const uint8_t DEFAULT_SDA_PIN = 20;
|
||||
static const uint8_t DEFAULT_SCL_PIN = 21;
|
||||
static const uint8_t DEFAULT_INT_PIN = 22;
|
||||
static const uint8_t PIN_UNUSED = UINT8_MAX;
|
||||
|
||||
/***** More public constants here *****/
|
||||
|
||||
private:
|
||||
/***** Private constants here *****/
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Enums
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
enum class gain : uint8_t {
|
||||
X1 = 0b00,
|
||||
X3_7 = 0b01,
|
||||
X16 = 0b10,
|
||||
X64 = 0b11
|
||||
};
|
||||
|
||||
enum class illumination_current : uint8_t {
|
||||
ma12 = 0b00,
|
||||
ma25 = 0b01,
|
||||
ma50 = 0b10,
|
||||
ma100 = 0b11
|
||||
};
|
||||
|
||||
enum class indicator_current : uint8_t {
|
||||
ma1 = 0b00,
|
||||
ma2 = 0b01,
|
||||
ma4 = 0b10,
|
||||
ma8 = 0b11,
|
||||
};
|
||||
|
||||
enum class measurement_mode : uint8_t {
|
||||
cont_ygnv = 0b00, // yellow, green, blue, violet - continuous
|
||||
cont_royg = 0b01, // red, orange, yellow, green - continuous
|
||||
cont_roygbr = 0b10, // red, orange, yellow, green, violet - continuous
|
||||
oneshot = 0b11 // everything - one-shot
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Substructures
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
struct reading {
|
||||
float red;
|
||||
float orange;
|
||||
float yellow;
|
||||
float green;
|
||||
float blue;
|
||||
float violet;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Variables
|
||||
//--------------------------------------------------
|
||||
private:
|
||||
i2c_inst_t *i2c = i2c0;
|
||||
|
||||
// interface pins with our standard defaults where appropriate
|
||||
int8_t address = DEFAULT_I2C_ADDRESS;
|
||||
int8_t sda = DEFAULT_SDA_PIN;
|
||||
int8_t scl = DEFAULT_SCL_PIN;
|
||||
int8_t interrupt = DEFAULT_INT_PIN;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Constructors/Destructor
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
AS7262() {}
|
||||
|
||||
AS7262(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED) :
|
||||
i2c(i2c), sda(sda), scl(scl), interrupt(interrupt) {}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
bool init();
|
||||
void reset();
|
||||
|
||||
uint8_t device_type();
|
||||
uint8_t hardware_version();
|
||||
std::string firmware_version();
|
||||
reading read();
|
||||
uint8_t temperature();
|
||||
|
||||
void set_gain(gain gain);
|
||||
void set_measurement_mode(measurement_mode mode);
|
||||
void set_indicator_current(indicator_current current);
|
||||
void set_illumination_current(illumination_current current);
|
||||
void set_leds(bool illumination, bool indicator);
|
||||
|
||||
// Virtual i2c transfers, routed through read/write/status regs
|
||||
uint8_t i2c_reg_read_uint8(uint8_t reg);
|
||||
void i2c_reg_write_uint8(uint8_t reg, uint8_t value);
|
||||
uint16_t i2c_reg_read_uint16(uint8_t reg);
|
||||
float i2c_reg_read_float(uint8_t reg);
|
||||
|
||||
private:
|
||||
bool data_ready();
|
||||
uint8_t _i2c_status();
|
||||
int _i2c_read(uint8_t reg, uint8_t *values, int len);
|
||||
int _i2c_write(uint8_t reg, uint8_t *values, int len);
|
||||
|
||||
// *Real* single-byte i2c transfers
|
||||
uint8_t _i2c_reg_read_uint8(uint8_t reg);
|
||||
void _i2c_reg_write_uint8(uint8_t reg, uint8_t value);
|
||||
};
|
||||
|
||||
}
|
|
@ -19,3 +19,4 @@ add_subdirectory(pico_tof_display)
|
|||
add_subdirectory(pico_trackball_display)
|
||||
add_subdirectory(pico_audio)
|
||||
add_subdirectory(pico_wireless)
|
||||
add_subdirectory(breakout_as7262)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
set(OUTPUT_NAME as7262_demo)
|
||||
|
||||
add_executable(
|
||||
${OUTPUT_NAME}
|
||||
demo.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME} pico_stdlib hardware_i2c breakout_as7262)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,43 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "breakout_as7262.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
BreakoutAS7262 as7262;
|
||||
|
||||
int main() {
|
||||
setup_default_uart();
|
||||
|
||||
as7262.init();
|
||||
|
||||
int16_t hw_version = as7262.i2c_reg_read_uint16(0x00);
|
||||
int16_t fw_version = as7262.i2c_reg_read_uint16(0x02);
|
||||
printf("%04x %04x \n", hw_version, fw_version);
|
||||
|
||||
as7262.set_gain(AS7262::gain::X16);
|
||||
as7262.set_measurement_mode(AS7262::measurement_mode::cont_roygbr);
|
||||
as7262.set_illumination_current(AS7262::illumination_current::ma12);
|
||||
as7262.set_indicator_current(AS7262::indicator_current::ma4);
|
||||
//as7262.set_leds(false, false);
|
||||
|
||||
while(true) {
|
||||
|
||||
AS7262::reading reading = as7262.read();
|
||||
printf("R: %f O: %f Y: %f G: %f B: %f V: %f \n",
|
||||
reading.red,
|
||||
reading.orange,
|
||||
reading.yellow,
|
||||
reading.green,
|
||||
reading.blue,
|
||||
reading.violet
|
||||
);
|
||||
|
||||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -7,6 +7,7 @@ add_subdirectory(breakout_rgbmatrix5x5)
|
|||
add_subdirectory(breakout_matrix11x7)
|
||||
add_subdirectory(breakout_trackball)
|
||||
add_subdirectory(breakout_sgp30)
|
||||
add_subdirectory(breakout_as7262)
|
||||
add_subdirectory(pico_graphics)
|
||||
add_subdirectory(pico_display)
|
||||
add_subdirectory(pico_unicorn)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(breakout_as7262.cmake)
|
|
@ -0,0 +1,11 @@
|
|||
set(LIB_NAME breakout_as7262)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
target_sources(${LIB_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_i2c as7262)
|
|
@ -0,0 +1,5 @@
|
|||
#include "breakout_as7262.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../drivers/as7262/as7262.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
typedef AS7262 BreakoutAS7262;
|
||||
}
|
Ładowanie…
Reference in New Issue