Merge pull request #142 from pimoroni/driver/as7262

C++ and MP support and example for AS7262 breakout
pull/148/head
Philip Howard 2021-05-12 16:16:25 +01:00 zatwierdzone przez GitHub
commit 15b85d1ee2
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
24 zmienionych plików z 1105 dodań i 0 usunięć

Wyświetl plik

@ -11,3 +11,4 @@ add_subdirectory(vl53l1x)
add_subdirectory(is31fl3731)
add_subdirectory(fatfs)
add_subdirectory(sdcard)
add_subdirectory(as7262)

Wyświetl plik

@ -0,0 +1 @@
include(as7262.cmake)

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1,228 @@
#include <cstdlib>
#include <math.h>
#include <map>
#include <vector>
#include <cstring>
#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);
}
i2c_inst_t* AS7262::get_i2c() const {
return i2c;
}
int AS7262::get_sda() const {
return sda;
}
int AS7262::get_scl() const {
return scl;
}
int AS7262::get_int() const {
return interrupt;
}
uint8_t AS7262::device_type() {
return i2c_reg_read_uint8(reg::DEVICE);
}
uint8_t AS7262::hardware_version() {
return i2c_reg_read_uint8(reg::HW_VERSION);
}
void AS7262::firmware_version(uint8_t &major_out, uint8_t &minor_out, uint8_t &sub_out) {
uint16_t fw_version = i2c_reg_read_uint16(reg::FW_VERSION);
major_out = (fw_version & 0x00F0) >> 4;
minor_out = ((fw_version & 0x000F) << 2) | ((fw_version & 0xC000) >> 14);
sub_out = (fw_version & 0x3F00) >> 8;
}
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);
}
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);
}
void AS7262::set_integration_time(float integration_time_ms) {
uint8_t integration_time = uint8_t(integration_time_ms * 2.88);
i2c_reg_write_uint8(reg::INT_T, integration_time);
}
bool AS7262::data_ready() {
return i2c_reg_read_uint8(reg::CONTROL) & 0b00000010;
}
// 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);
}
// convert the AS7262s 4-byte big-endian float value into a native float
float AS7262::i2c_reg_read_float(uint8_t reg) {
uint32_t value;
i2c_read(reg, (uint8_t *)&value, 4);
value = __builtin_bswap32(value);
// Fails due to -Werror=strict-aliasing in MicroPython build
// return reinterpret_cast<float &>(value);
// Assumes sizeof(uint32_t) == sizeof(float)
float result;
memcpy(&result, &value, sizeof(float));
return result;
}
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;
}
uint8_t AS7262::i2c_status() {
return _i2c_reg_read_uint8(0x00);
}
uint8_t AS7262::i2c_read(uint8_t reg, uint8_t *values, uint8_t len) {
for(uint8_t i = 0; 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;
}
uint8_t AS7262::i2c_write(uint8_t reg, uint8_t *values, uint8_t len) {
for(uint8_t i = 0; 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;
}
// 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, &reg, 1, false);
i2c_read_blocking(i2c, address, (uint8_t *)&value, 1, false);
return value;
}
}

Wyświetl plik

@ -0,0 +1,136 @@
#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;
//--------------------------------------------------
// 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();
// For print access in micropython
i2c_inst_t* get_i2c() const;
int get_sda() const;
int get_scl() const;
int get_int() const;
uint8_t device_type();
uint8_t hardware_version();
void firmware_version(uint8_t &major_out, uint8_t &minor_out, uint8_t &sub_out);
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_integration_time(float integration_time_ms);
void set_leds(bool illumination, bool indicator);
private:
bool data_ready();
// 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);
uint8_t i2c_status();
uint8_t i2c_read(uint8_t reg, uint8_t *values, uint8_t len);
uint8_t i2c_write(uint8_t reg, uint8_t *values, uint8_t 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);
};
}

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1,2 @@
include("${CMAKE_CURRENT_LIST_DIR}/basic_demo.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/explorer_bargraph.cmake")

Wyświetl plik

@ -0,0 +1,16 @@
set(OUTPUT_NAME as7262_basic_demo)
add_executable(
${OUTPUT_NAME}
basic_demo.cpp
)
# enable usb output, disable uart output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_enable_stdio_uart(${OUTPUT_NAME} 0)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_as7262)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,44 @@
#include "pico/stdlib.h"
#include "breakout_as7262.hpp"
using namespace pimoroni;
BreakoutAS7262 as7262;
int main() {
stdio_init_all();
as7262.init();
uint8_t dev_type = as7262.device_type();
uint8_t hw_version = as7262.hardware_version();
uint8_t major, minor, sub;
as7262.firmware_version(major, minor, sub);
printf("Device: %d, HW: %d, FW: %d.%d.%d\n", dev_type, hw_version, major, minor, sub);
as7262.set_gain(AS7262::gain::X64);
as7262.set_integration_time(17.857);
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(true, true);
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;
}

Wyświetl plik

@ -0,0 +1,16 @@
set(OUTPUT_NAME as7262_explorer_bargraph)
add_executable(
${OUTPUT_NAME}
explorer_bargraph.cpp
)
# enable usb output, disable uart output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_enable_stdio_uart(${OUTPUT_NAME} 0)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_as7262 pico_explorer)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,98 @@
#include "pico/stdlib.h"
#include "breakout_as7262.hpp"
#include "pico_explorer.hpp"
using namespace pimoroni;
constexpr float INTEGRATION_TIME = 10.0f;
BreakoutAS7262 as7262;
uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT];
PicoExplorer pico_explorer(buffer);
uint8_t bar_width = PicoExplorer::WIDTH / 6;
uint8_t bar_height = PicoExplorer::HEIGHT;
void draw_bar(float scale, uint16_t channel) {
int16_t bar_top = bar_height - (bar_height * scale);
bar_top = std::max((int16_t)0, bar_top);
int16_t current_bar_height = bar_height - bar_top;
pico_explorer.rectangle(Rect(channel * bar_width, bar_top, bar_width, current_bar_height - 1));
}
int main() {
stdio_init_all();
pico_explorer.init();
as7262.init();
uint8_t dev_type = as7262.device_type();
uint8_t hw_version = as7262.hardware_version();
uint8_t major, minor, sub;
as7262.firmware_version(major, minor, sub);
printf("Device: %d, HW: %d, FW: %d.%d.%d\n", dev_type, hw_version, major, minor, sub);
as7262.set_gain(AS7262::gain::X64);
as7262.set_integration_time(INTEGRATION_TIME);
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(true, true);
while(true) {
pico_explorer.set_pen(0, 0, 0);
pico_explorer.clear();
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
);
float m = reading.red;
if(reading.orange > m) m = reading.orange;
if(reading.yellow > m) m = reading.yellow;
if(reading.green > m) m = reading.green;
if(reading.blue > m) m = reading.blue;
if(reading.violet > m) m = reading.violet;
pico_explorer.set_pen(0, 0, 0);
pico_explorer.clear();
// Red
pico_explorer.set_pen(255, 0, 0);
draw_bar(reading.red / m, 0);
// Orange
pico_explorer.set_pen(255, 128, 0);
draw_bar(reading.orange / m, 1);
// Yellow
pico_explorer.set_pen(255, 255, 0);
draw_bar(reading.yellow / m, 2);
// Green
pico_explorer.set_pen(0, 255, 0);
draw_bar(reading.green / m, 3);
// Blue
pico_explorer.set_pen(0, 0, 255);
draw_bar(reading.blue / m, 4);
// Violet
pico_explorer.set_pen(255, 0, 255);
draw_bar(reading.violet / m, 5);
pico_explorer.update();
sleep_ms(INTEGRATION_TIME);
}
return 0;
}

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1 @@
include(breakout_as7262.cmake)

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1,5 @@
#include "breakout_as7262.hpp"
namespace pimoroni {
}

Wyświetl plik

@ -0,0 +1,8 @@
#pragma once
#include "../../drivers/as7262/as7262.hpp"
namespace pimoroni {
typedef AS7262 BreakoutAS7262;
}

Wyświetl plik

@ -0,0 +1,27 @@
import time
from breakout_as7262 import BreakoutAS7262
as7262 = BreakoutAS7262()
dev_type = as7262.device_type()
hw_version = as7262.hardware_version()
fw_version = as7262.firmware_version()
print("Device: ", dev_type, "HW: ", hw_version, sep="", end=", ")
print("FW: ", fw_version[0], ".", fw_version[1], ".", fw_version[2])
as7262.set_gain(BreakoutAS7262.X16)
as7262.set_measurement_mode(BreakoutAS7262.CONT_ROYGBR)
as7262.set_illumination_current(BreakoutAS7262.MA12)
as7262.set_indicator_current(BreakoutAS7262.MA4)
# as7262.set_leds(False, False)
while True:
reading = as7262.read()
print("R:", reading[0], end=" ")
print("O:", reading[1], end=" ")
print("Y:", reading[2], end=" ")
print("G:", reading[3], end=" ")
print("B:", reading[4], end=" ")
print("V:", reading[5])
time.sleep(1.0)

Wyświetl plik

@ -0,0 +1,65 @@
from breakout_as7262 import BreakoutAS7262
import picoexplorer as display
import time
width = display.get_width()
height = display.get_height()
bar_width = width // 6
bar_height = height
display_buffer = bytearray(width * height * 2) # 2-bytes per pixel (RGB565)
display.init(display_buffer)
as7 = BreakoutAS7262()
integration_time = 10 # integration time in milliseconds, max ~90ms
as7.set_gain(as7.X64)
as7.set_integration_time(integration_time)
as7.set_measurement_mode(as7.CONT_ROYGBR)
as7.set_leds(True, True)
def draw_bar(v, i):
current_bar_top = int(bar_height - (bar_height * v))
# Drawing outside of the display region will cause horrible, horrible crashes
current_bar_top = max(0, current_bar_top)
current_bar_height = bar_height - current_bar_top
display.rectangle(i * bar_width, current_bar_top, bar_width, current_bar_height - 1)
while True:
r, o, y, g, b, v = as7.read()
m = max(r, o, y, g, b, v)
display.set_pen(0, 0, 0)
display.clear()
# Red
display.set_pen(255, 0, 0)
draw_bar(r / m, 0)
# Orange
display.set_pen(255, 128, 0)
draw_bar(o / m, 1)
# Yellow
display.set_pen(255, 255, 0)
draw_bar(y / m, 2)
# Green
display.set_pen(0, 255, 0)
draw_bar(g / m, 3)
# Blue
display.set_pen(0, 0, 255)
draw_bar(b / m, 4)
# Violet
display.set_pen(255, 0, 255)
draw_bar(v / m, 5)
display.update()
time.sleep(integration_time / 1000.0)

Wyświetl plik

@ -0,0 +1,84 @@
#include "breakout_as7262.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// BreakoutAS7262 Class
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Methods *****/
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutAS7262_reset_obj, BreakoutAS7262_reset);
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutAS7262_device_type_obj, BreakoutAS7262_device_type);
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutAS7262_hardware_version_obj, BreakoutAS7262_hardware_version);
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutAS7262_firmware_version_obj, BreakoutAS7262_firmware_version);
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutAS7262_read_obj, BreakoutAS7262_read);
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutAS7262_temperature_obj, BreakoutAS7262_temperature);
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutAS7262_set_gain_obj, 1, BreakoutAS7262_set_gain);
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutAS7262_set_measurement_mode_obj, 1, BreakoutAS7262_set_measurement_mode);
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutAS7262_set_indicator_current_obj, 1, BreakoutAS7262_set_indicator_current);
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutAS7262_set_illumination_current_obj, 1, BreakoutAS7262_set_illumination_current);
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutAS7262_set_integration_time_obj, 1, BreakoutAS7262_set_integration_time);
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutAS7262_set_leds_obj, 1, BreakoutAS7262_set_leds);
/***** Binding of Methods *****/
STATIC const mp_rom_map_elem_t BreakoutAS7262_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&BreakoutAS7262_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_device_type), MP_ROM_PTR(&BreakoutAS7262_device_type_obj) },
{ MP_ROM_QSTR(MP_QSTR_hardware_version), MP_ROM_PTR(&BreakoutAS7262_hardware_version_obj) },
{ MP_ROM_QSTR(MP_QSTR_firmware_version), MP_ROM_PTR(&BreakoutAS7262_firmware_version_obj) },
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutAS7262_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_temperature), MP_ROM_PTR(&BreakoutAS7262_temperature_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_gain), MP_ROM_PTR(&BreakoutAS7262_set_gain_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_measurement_mode), MP_ROM_PTR(&BreakoutAS7262_set_measurement_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_indicator_current), MP_ROM_PTR(&BreakoutAS7262_set_indicator_current_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_illumination_current), MP_ROM_PTR(&BreakoutAS7262_set_illumination_current_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_integration_time), MP_ROM_PTR(&BreakoutAS7262_set_integration_time_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_leds), MP_ROM_PTR(&BreakoutAS7262_set_leds_obj) },
{ MP_ROM_QSTR(MP_QSTR_X1), MP_ROM_INT(MP_X1) },
{ MP_ROM_QSTR(MP_QSTR_X3_7), MP_ROM_INT(MP_X3_7) },
{ MP_ROM_QSTR(MP_QSTR_X16), MP_ROM_INT(MP_X16) },
{ MP_ROM_QSTR(MP_QSTR_X64), MP_ROM_INT(MP_X64) },
{ MP_ROM_QSTR(MP_QSTR_MA12), MP_ROM_INT(MP_MA12) },
{ MP_ROM_QSTR(MP_QSTR_MA25), MP_ROM_INT(MP_MA25) },
{ MP_ROM_QSTR(MP_QSTR_MA50), MP_ROM_INT(MP_MA50) },
{ MP_ROM_QSTR(MP_QSTR_MA100), MP_ROM_INT(MP_MA100) },
{ MP_ROM_QSTR(MP_QSTR_MA1), MP_ROM_INT(MP_MA1) },
{ MP_ROM_QSTR(MP_QSTR_MA2), MP_ROM_INT(MP_MA2) },
{ MP_ROM_QSTR(MP_QSTR_MA4), MP_ROM_INT(MP_MA4) },
{ MP_ROM_QSTR(MP_QSTR_MA8), MP_ROM_INT(MP_MA8) },
{ MP_ROM_QSTR(MP_QSTR_CONT_YGNV), MP_ROM_INT(MP_CONT_YGNV) },
{ MP_ROM_QSTR(MP_QSTR_CONT_ROYG), MP_ROM_INT(MP_CONT_ROYG) },
{ MP_ROM_QSTR(MP_QSTR_CONT_ROYGBR), MP_ROM_INT(MP_CONT_ROYGBR) },
{ MP_ROM_QSTR(MP_QSTR_ONESHOT), MP_ROM_INT(MP_ONESHOT) },
};
STATIC MP_DEFINE_CONST_DICT(BreakoutAS7262_locals_dict, BreakoutAS7262_locals_dict_table);
/***** Class Definition *****/
const mp_obj_type_t breakout_as7262_BreakoutAS7262_type = {
{ &mp_type_type },
.name = MP_QSTR_breakout_as7262,
.print = BreakoutAS7262_print,
.make_new = BreakoutAS7262_make_new,
.locals_dict = (mp_obj_dict_t*)&BreakoutAS7262_locals_dict,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// breakout_as7262 Module
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Globals Table *****/
STATIC const mp_map_elem_t breakout_as7262_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_as7262) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutAS7262), (mp_obj_t)&breakout_as7262_BreakoutAS7262_type },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_as7262_globals, breakout_as7262_globals_table);
/***** Module Definition *****/
const mp_obj_module_t breakout_as7262_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_breakout_as7262_globals,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
MP_REGISTER_MODULE(MP_QSTR_breakout_as7262, breakout_as7262_user_cmodule, MODULE_BREAKOUT_AS7262_ENABLED);
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

Wyświetl plik

@ -0,0 +1,266 @@
#include "../../../libraries/breakout_as7262/breakout_as7262.hpp"
#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o))
// SDA/SCL on even/odd pins, I2C0/I2C1 on even/odd pairs of pins.
#define IS_VALID_SCL(i2c, pin) (((pin) & 1) == 1 && (((pin) & 2) >> 1) == (i2c))
#define IS_VALID_SDA(i2c, pin) (((pin) & 1) == 0 && (((pin) & 2) >> 1) == (i2c))
using namespace pimoroni;
extern "C" {
#include "breakout_as7262.h"
/***** Variables Struct *****/
typedef struct _breakout_as7262_BreakoutAS7262_obj_t {
mp_obj_base_t base;
BreakoutAS7262 *breakout;
} breakout_as7262_BreakoutAS7262_obj_t;
/***** Print *****/
void BreakoutAS7262_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind; //Unused input parameter
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_as7262_BreakoutAS7262_obj_t);
BreakoutAS7262* breakout = self->breakout;
mp_print_str(print, "BreakoutAS7262(");
mp_print_str(print, "i2c = ");
mp_obj_print_helper(print, mp_obj_new_int((breakout->get_i2c() == i2c0) ? 0 : 1), PRINT_REPR);
mp_print_str(print, ", sda = ");
mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sda()), PRINT_REPR);
mp_print_str(print, ", scl = ");
mp_obj_print_helper(print, mp_obj_new_int(breakout->get_scl()), PRINT_REPR);
mp_print_str(print, ", int = ");
mp_obj_print_helper(print, mp_obj_new_int(breakout->get_int()), PRINT_REPR);
mp_print_str(print, ")");
}
/***** Constructor *****/
mp_obj_t BreakoutAS7262_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
breakout_as7262_BreakoutAS7262_obj_t *self = nullptr;
if(n_args == 0) {
mp_arg_check_num(n_args, n_kw, 0, 0, true);
self = m_new_obj(breakout_as7262_BreakoutAS7262_obj_t);
self->base.type = &breakout_as7262_BreakoutAS7262_type;
self->breakout = new BreakoutAS7262();
}
else {
enum { ARG_i2c, ARG_sda, ARG_scl, ARG_int };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_int, MP_ARG_INT, {.u_int = BreakoutAS7262::PIN_UNUSED} },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Get I2C bus.
int i2c_id = args[ARG_i2c].u_int;
if(i2c_id < 0 || i2c_id > 1) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id);
}
int sda = args[ARG_sda].u_int;
if(!IS_VALID_SDA(i2c_id, sda)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SDA pin"));
}
int scl = args[ARG_scl].u_int;
if(!IS_VALID_SCL(i2c_id, scl)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin"));
}
self = m_new_obj(breakout_as7262_BreakoutAS7262_obj_t);
self->base.type = &breakout_as7262_BreakoutAS7262_type;
i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1;
self->breakout = new BreakoutAS7262(i2c, sda, scl, args[ARG_int].u_int);
}
self->breakout->init();
return MP_OBJ_FROM_PTR(self);
}
/***** Methods *****/
mp_obj_t BreakoutAS7262_reset(mp_obj_t self_in) {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_as7262_BreakoutAS7262_obj_t);
self->breakout->reset();
return mp_const_none;
}
mp_obj_t BreakoutAS7262_device_type(mp_obj_t self_in) {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_as7262_BreakoutAS7262_obj_t);
return mp_obj_new_int(self->breakout->device_type());
}
mp_obj_t BreakoutAS7262_hardware_version(mp_obj_t self_in) {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_as7262_BreakoutAS7262_obj_t);
return mp_obj_new_int(self->breakout->hardware_version());
}
mp_obj_t BreakoutAS7262_firmware_version(mp_obj_t self_in) {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_as7262_BreakoutAS7262_obj_t);
uint8_t major, minor, sub;
self->breakout->firmware_version(major, minor, sub);
mp_obj_t tuple[3];
tuple[0] = mp_obj_new_int(major);
tuple[1] = mp_obj_new_float(minor);
tuple[2] = mp_obj_new_float(sub);
return mp_obj_new_tuple(3, tuple);
}
mp_obj_t BreakoutAS7262_read(mp_obj_t self_in) {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_as7262_BreakoutAS7262_obj_t);
BreakoutAS7262::reading reading = self->breakout->read();
mp_obj_t tuple[6];
tuple[0] = mp_obj_new_float(reading.red);
tuple[1] = mp_obj_new_float(reading.orange);
tuple[2] = mp_obj_new_float(reading.yellow);
tuple[3] = mp_obj_new_float(reading.green);
tuple[4] = mp_obj_new_float(reading.blue);
tuple[5] = mp_obj_new_float(reading.violet);
return mp_obj_new_tuple(6, tuple);
}
mp_obj_t BreakoutAS7262_temperature(mp_obj_t self_in) {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_as7262_BreakoutAS7262_obj_t);
return mp_obj_new_int(self->breakout->temperature());
}
mp_obj_t BreakoutAS7262_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_gain };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_gain, MP_ARG_REQUIRED | MP_ARG_INT },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int gain = args[ARG_gain].u_int;
if(gain < 0 || gain > 3) {
mp_raise_ValueError("mode not a valid value. Expected 0 to 3 (X1, X3_7, X16, X64)");
}
else {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_as7262_BreakoutAS7262_obj_t);
self->breakout->set_gain((BreakoutAS7262::gain)gain);
}
return mp_const_none;
}
mp_obj_t BreakoutAS7262_set_measurement_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_mode };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int mode = args[ARG_mode].u_int;
if(mode < 0 || mode > 3) {
mp_raise_ValueError("mode not a valid value. Expected 0 to 3 (CONT_YGNV, CONT_ROYG, CONT_ROYGBR, ONESHOT)");
}
else {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_as7262_BreakoutAS7262_obj_t);
self->breakout->set_measurement_mode((BreakoutAS7262::measurement_mode)mode);
}
return mp_const_none;
}
mp_obj_t BreakoutAS7262_set_indicator_current(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_current };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_current, MP_ARG_REQUIRED | MP_ARG_INT },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int current = args[ARG_current].u_int;
if(current < 0 || current > 3) {
mp_raise_ValueError("current not a valid value. Expected 0 to 3 (MA1, MA2, MA4, MA8)");
}
else {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_as7262_BreakoutAS7262_obj_t);
self->breakout->set_indicator_current((BreakoutAS7262::indicator_current)current);
}
return mp_const_none;
}
mp_obj_t BreakoutAS7262_set_illumination_current(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_current };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_current, MP_ARG_REQUIRED | MP_ARG_INT },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
int current = args[ARG_current].u_int;
if(current < 0 || current > 3) {
mp_raise_ValueError("current not a valid value. Expected 0 to 3 (MA12, MA25, MA50, MA100)");
}
else {
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_as7262_BreakoutAS7262_obj_t);
self->breakout->set_illumination_current((BreakoutAS7262::illumination_current)current);
}
return mp_const_none;
}
mp_obj_t BreakoutAS7262_set_integration_time(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_integration_time };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_integration_time, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
float integration_time = mp_obj_get_float(args[ARG_integration_time].u_obj);
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_as7262_BreakoutAS7262_obj_t);
self->breakout->set_integration_time(integration_time);
return mp_const_none;
}
mp_obj_t BreakoutAS7262_set_leds(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_illumination, ARG_indicator };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_illumination, MP_ARG_REQUIRED | MP_ARG_BOOL },
{ MP_QSTR_indicator, MP_ARG_REQUIRED | MP_ARG_BOOL },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
breakout_as7262_BreakoutAS7262_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_as7262_BreakoutAS7262_obj_t);
self->breakout->set_leds(args[ARG_illumination].u_bool, args[ARG_indicator].u_bool);
return mp_const_none;
}
}

Wyświetl plik

@ -0,0 +1,50 @@
// Include MicroPython API.
#include "py/runtime.h"
/***** Constants *****/
enum {
MP_X1 = 0b00,
MP_X3_7 = 0b01,
MP_X16 = 0b10,
MP_X64 = 0b11
};
enum {
MP_MA12 = 0b00,
MP_MA25 = 0b01,
MP_MA50 = 0b10,
MP_MA100 = 0b11
};
enum {
MP_MA1 = 0b00,
MP_MA2 = 0b01,
MP_MA4 = 0b10,
MP_MA8 = 0b11
};
enum {
MP_CONT_YGNV = 0b00, // yellow, green, blue, violet - continuous
MP_CONT_ROYG = 0b01, // red, orange, yellow, green - continuous
MP_CONT_ROYGBR = 0b10, // red, orange, yellow, green, violet - continuous
MP_ONESHOT = 0b11 // everything - one-shot
};
/***** Extern of Class Definition *****/
extern const mp_obj_type_t breakout_as7262_BreakoutAS7262_type;
/***** Extern of Class Methods *****/
extern void BreakoutAS7262_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
extern mp_obj_t BreakoutAS7262_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t BreakoutAS7262_reset(mp_obj_t self_in);
extern mp_obj_t BreakoutAS7262_device_type(mp_obj_t self_in);
extern mp_obj_t BreakoutAS7262_hardware_version(mp_obj_t self_in);
extern mp_obj_t BreakoutAS7262_firmware_version(mp_obj_t self_in);
extern mp_obj_t BreakoutAS7262_read(mp_obj_t self_in);
extern mp_obj_t BreakoutAS7262_temperature(mp_obj_t self_in);
extern mp_obj_t BreakoutAS7262_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t BreakoutAS7262_set_measurement_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t BreakoutAS7262_set_indicator_current(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t BreakoutAS7262_set_illumination_current(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t BreakoutAS7262_set_integration_time(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t BreakoutAS7262_set_leds(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);

Wyświetl plik

@ -0,0 +1,20 @@
set(MOD_NAME breakout_as7262)
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
add_library(usermod_${MOD_NAME} INTERFACE)
target_sources(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/as7262/as7262.cpp
)
target_include_directories(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
-DMODULE_${MOD_NAME_UPPER}_ENABLED=1
)
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})

Wyświetl plik

@ -0,0 +1,13 @@
set(MOD_NAME breakout_as7262)
BREAKOUT_MOD_DIR := $(USERMOD_DIR)
# Add our source files to the respective variables.
SRC_USERMOD += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.c
SRC_USERMOD_CXX += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.cpp
# Add our module directory to the include path.
CFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR)
CXXFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR)
# We use C++ features so have to link against the standard library.
LDFLAGS_USERMOD += -lstdc++

Wyświetl plik

@ -1,6 +1,7 @@
include(${CMAKE_CURRENT_LIST_DIR}/breakout_dotmatrix/micropython.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/breakout_ltr559/micropython.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/breakout_colourlcd160x80/micropython.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/breakout_as7262/micropython.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/breakout_roundlcd/micropython.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/breakout_rgbmatrix5x5/micropython.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/breakout_matrix11x7/micropython.cmake)