Micropython binding fixes and example for SGP30

pull/136/head
ZodiusInfuser 2021-05-05 12:21:57 +01:00 zatwierdzone przez Phil Howard
rodzic 77ca674ac8
commit ded2710f90
9 zmienionych plików z 94 dodań i 43 usunięć

Wyświetl plik

@ -1,10 +1,10 @@
add_subdirectory(esp32spi)
add_subdirectory(ltp305)
add_subdirectory(ltr559)
add_subdirectory(sgp30)
add_subdirectory(st7789)
add_subdirectory(msa301)
add_subdirectory(rv3028)
add_subdirectory(trackball)
add_subdirectory(vl53l1x)
add_subdirectory(is31fl3731)
add_subdirectory(sgp30)

Wyświetl plik

@ -13,8 +13,6 @@ Distributed as-is; no warranty is given.
namespace pimoroni {
/***** Device registers and masks here *****/
bool SGP30::init() {
i2c_init(i2c, 400000);
@ -62,8 +60,7 @@ namespace pimoroni {
// Get the unique ID from the Chip. Will fail if no chip attached
bool SGP30::retrieve_unique_id() {
// return the Chip ID, in three separate 16-bit values
return read_reg_3_words(GET_SERIAL_ID, 10,
serial_number, serial_number+1, serial_number+2);
return read_reg_3_words(GET_SERIAL_ID, 10, serial_number, serial_number + 1, serial_number + 2);
}
// get the previously-retreved Chip ID as the lower 48 bits of a 64-bit uint
@ -87,7 +84,7 @@ namespace pimoroni {
bool rc = write_reg(INIT_AIR_QUALITY, 10);
// Optionally wait up to 20 seconds for the measurement process to initiate
if( wait_for_setup) {
if(wait_for_setup) {
// It takes 15 seconds to start the measurement process but allow 20.
// Ignore the first 2 readings completely.
uint16_t eCO2, TVOC;
@ -138,46 +135,46 @@ namespace pimoroni {
}
// Write a single byte globally (not to a specifc I2c address)
bool SGP30::write_global(uint16_t reg, uint16_t delayms) {
bool SGP30::write_global(uint16_t reg, uint16_t delay_ms) {
uint8_t buffer[1] = { (uint8_t)(reg & 0xFF)};
i2c_write_blocking(i2c, 0, buffer, 1, false);
sleep_ms(delayms);
sleep_ms(delay_ms);
return true;
}
// Write just the register to the i2c address, no parameter
bool SGP30::write_reg(uint16_t reg, uint16_t delayms) {
bool SGP30::write_reg(uint16_t reg, uint16_t delay_ms) {
uint8_t buffer[2] = { (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF)};
i2c_write_blocking(i2c, address, buffer, 2, false);
sleep_ms(delayms);
sleep_ms(delay_ms);
return true;
}
// Write one 16-bit word (+CRC)
bool SGP30::write_reg_1_word(uint16_t reg, uint16_t delayms, uint16_t value) {
bool SGP30::write_reg_1_word(uint16_t reg, uint16_t delay_ms, uint16_t value) {
uint8_t buffer[5] = { (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF),
(uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF), calculate_crc(value)};
i2c_write_blocking(i2c, address, buffer, 5, false);
sleep_ms(delayms);
sleep_ms(delay_ms);
return true;
}
// Write two 16-bit words (+CRC)
bool SGP30::write_reg_2_words(uint16_t reg, uint16_t delayms, uint16_t value1, uint16_t value2) {
bool SGP30::write_reg_2_words(uint16_t reg, uint16_t delay_ms, uint16_t value1, uint16_t value2) {
uint8_t buffer[8] = { (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF),
(uint8_t)((value1 >> 8) & 0xFF), (uint8_t)(value1 & 0xFF), calculate_crc(value1),
(uint8_t)((value2 >> 8) & 0xFF), (uint8_t)(value2 & 0xFF), calculate_crc(value2)};
i2c_write_blocking(i2c, address, buffer, 8, false);
sleep_ms(delayms);
sleep_ms(delay_ms);
return true;
}
// Write register and read one 16-bit word in response
bool SGP30::read_reg_1_word(uint16_t reg, uint16_t delayms, uint16_t * value) {
bool SGP30::read_reg_1_word(uint16_t reg, uint16_t delay_ms, uint16_t *value) {
uint8_t regbuf[2] = { (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
uint8_t buffer[3];
i2c_write_blocking(i2c, address, regbuf, 2, true);
sleep_ms(delayms);
sleep_ms(delay_ms);
i2c_read_blocking(i2c, address, buffer, 3, false);
if(buffer[2] != calculate_crc(buffer[0], buffer[1]))
return false;
@ -186,11 +183,11 @@ namespace pimoroni {
}
// Write register and read two 16-bit words
bool SGP30::read_reg_2_words(uint16_t reg, uint16_t delayms, uint16_t * value1, uint16_t * value2) {
bool SGP30::read_reg_2_words(uint16_t reg, uint16_t delay_ms, uint16_t *value1, uint16_t *value2) {
uint8_t regbuf[2] = { (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
uint8_t buffer[6];
i2c_write_blocking(i2c, address, regbuf, 2, true);
sleep_ms(delayms);
sleep_ms(delay_ms);
i2c_read_blocking(i2c, address, buffer, 6, false);
if((buffer[2] != calculate_crc(buffer[0], buffer[1])) || (buffer[5] != calculate_crc(buffer[3], buffer[4]))) {
return false;
@ -201,11 +198,11 @@ namespace pimoroni {
}
// Write register and read three 16-bit words
bool SGP30::read_reg_3_words(uint16_t reg, uint16_t delayms, uint16_t * value1, uint16_t * value2, uint16_t * value3) {
bool SGP30::read_reg_3_words(uint16_t reg, uint16_t delay_ms, uint16_t *value1, uint16_t *value2, uint16_t *value3) {
uint8_t regbuf[2] = { (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
uint8_t buffer[9];
i2c_write_blocking(i2c, address, regbuf, 2, true);
sleep_ms(delayms);
sleep_ms(delay_ms);
i2c_read_blocking(i2c, address, buffer, 9, false);
if(buffer[2] != calculate_crc(buffer[0], buffer[1])) {
return false;

Wyświetl plik

@ -94,18 +94,18 @@ namespace pimoroni {
private:
/***** Private methods here *****/
bool write_global(uint16_t reg, uint16_t delayms);
bool write_reg(uint16_t reg, uint16_t delayms);
bool write_reg_1_word(uint16_t reg, uint16_t delayms, uint16_t value);
bool write_reg_2_words(uint16_t reg, uint16_t delayms, uint16_t value1, uint16_t value2);
bool read_reg_1_word(uint16_t reg, uint16_t delayms, uint16_t * value);
bool read_reg_2_words(uint16_t reg, uint16_t delayms, uint16_t * value1, uint16_t * value2);
bool read_reg_3_words(uint16_t reg, uint16_t delayms, uint16_t * value1, uint16_t * value2, uint16_t * value3);
bool write_global(uint16_t reg, uint16_t delay_ms);
bool write_reg(uint16_t reg, uint16_t delay_ms);
bool write_reg_1_word(uint16_t reg, uint16_t delay_ms, uint16_t value);
bool write_reg_2_words(uint16_t reg, uint16_t delay_ms, uint16_t value1, uint16_t value2);
bool read_reg_1_word(uint16_t reg, uint16_t delay_ms, uint16_t *value);
bool read_reg_2_words(uint16_t reg, uint16_t delay_ms, uint16_t *value1, uint16_t *value2);
bool read_reg_3_words(uint16_t reg, uint16_t delay_ms, uint16_t *value1, uint16_t *value2, uint16_t *value3);
// bool readWordFromCommand(uint8_t command[], uint8_t commandLength,
// uint16_t delay, uint16_t *readdata = NULL,
// uint8_t readlen = 0);
// uint8_t generateCRC(uint8_t data[], uint8_t datalen);
// bool read_word_from_command(uint8_t command[], uint8_t commandLength,
// uint16_t delay, uint16_t *readdata = NULL,
// uint8_t readlen = 0);
// uint8_t generate_crc(uint8_t data[], uint8_t datalen);
//
uint8_t calculate_crc(uint16_t value);
uint8_t calculate_crc(uint8_t value1, uint8_t value2);

Wyświetl plik

@ -5,6 +5,10 @@ add_executable(
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_sgp30)

Wyświetl plik

@ -26,18 +26,20 @@ int main() {
stdio_init_all();
bool init_ok = sgp30.init();
if (init_ok) {
bool init_ok = sgp30.init();
if(init_ok) {
printf("SGP30 initialised - about to start measuring without waiting\n");
sgp30.start_measurement(false);
printf("Started measuring for id %012llx\n", sgp30.get_unique_id());
if (sgp30.get_air_quality(&eCO2, &TVOC)) {
if(sgp30.get_air_quality(&eCO2, &TVOC)) {
prd = 1;
} else {
}
else {
printf("SGP30 not found when reading air quality\n");
prd = 2;
}
} else {
}
else {
printf("SGP30 not found when initialising\n");
prd = 3;
}
@ -45,18 +47,18 @@ int main() {
uint16_t j = 0;
while(true) {
j++;
for (uint8_t i=0; i<prd; i++) {
for(uint8_t i=0; i<prd; i++) {
gpio_put(PICO_DEFAULT_LED_PIN, true);
sleep_ms(50);
gpio_put(PICO_DEFAULT_LED_PIN, false);
sleep_ms(50);
}
sleep_ms(1000-(100*prd));
if (prd == 1) {
sleep_ms(1000 - (100 * prd));
if(prd == 1) {
sgp30.get_air_quality(&eCO2, &TVOC);
sgp30.get_air_quality_raw(&raweCO2, &rawTVOC);
printf("%3d: CO2 %d TVOC %d, raw %d %d\n", j, eCO2, TVOC, raweCO2, rawTVOC);
if (j == 30) {
if(j == 30) {
printf("Resetting device\n");
sgp30.soft_reset();
sleep_ms(500);

Wyświetl plik

@ -0,0 +1,31 @@
import time
from breakout_sgp30 import BreakoutSGP30
sgp30 = BreakoutSGP30()
print("SGP30 initialised - about to start measuring without waiting");
sgp30.start_measurement(False)
id = sgp30.get_unique_id()
print("Started measuring for id 0x", hex(id[0]), hex(id[1]), hex(id[2]), sep="")
j = 0
while True:
j += 1
air_quality = sgp30.get_air_quality()
eCO2 = air_quality[BreakoutSGP30.ECO2]
TVOC = air_quality[BreakoutSGP30.TVOC]
air_quality_raw = sgp30.get_air_quality_raw()
H2 = air_quality_raw[BreakoutSGP30.H2]
ETHANOL = air_quality_raw[BreakoutSGP30.ETHANOL]
print(j,": CO2 ", eCO2," TVOC ", TVOC,", raw ", H2," ", ETHANOL, sep="");
if j == 30:
print("Resetting device")
sgp30.soft_reset();
time.sleep(0.5)
print("Restarting measurement, waiting 15 secs before returning")
sgp30.start_measurement(True)
print("Measurement restarted, now read every second")
time.sleep(1.0)

Wyświetl plik

@ -26,6 +26,10 @@ STATIC const mp_rom_map_elem_t BreakoutSGP30_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_get_baseline), MP_ROM_PTR(&BreakoutSGP30_get_baseline_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_baseline), MP_ROM_PTR(&BreakoutSGP30_set_baseline_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_humidity), MP_ROM_PTR(&BreakoutSGP30_set_humidity_obj) },
{ MP_ROM_QSTR(MP_QSTR_ECO2), MP_ROM_INT(ECO2) },
{ MP_ROM_QSTR(MP_QSTR_TVOC), MP_ROM_INT(TVOC) },
{ MP_ROM_QSTR(MP_QSTR_H2), MP_ROM_INT(H2) },
{ MP_ROM_QSTR(MP_QSTR_ETHANOL), MP_ROM_INT(ETHANOL) },
};
STATIC MP_DEFINE_CONST_DICT(BreakoutSGP30_locals_dict, BreakoutSGP30_locals_dict_table);

Wyświetl plik

@ -45,7 +45,7 @@ mp_obj_t BreakoutSGP30_make_new(const mp_obj_type_t *type, size_t n_args, size_t
mp_arg_check_num(n_args, n_kw, 0, 0, true);
self = m_new_obj(breakout_sgp30_BreakoutSGP30_obj_t);
self->base.type = &breakout_sgp30_BreakoutSGP30_type;
self->breakout = new BreakoutSGP30();
self->breakout = new BreakoutSGP30();
}
else {
enum { ARG_i2c, ARG_sda, ARG_scl };
@ -73,7 +73,7 @@ mp_obj_t BreakoutSGP30_make_new(const mp_obj_type_t *type, size_t n_args, size_t
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_sgp30_BreakoutSGP30_obj_t);
self->base.type = &breakout_sgp30_BreakoutSGP30_type;
@ -82,7 +82,9 @@ mp_obj_t BreakoutSGP30_make_new(const mp_obj_type_t *type, size_t n_args, size_t
self->breakout = new BreakoutSGP30(i2c, sda, scl);
}
self->breakout->init();
if(!self->breakout->init()) {
mp_raise_msg(&mp_type_RuntimeError, "SGP30 not found when initialising");
}
return MP_OBJ_FROM_PTR(self);
}

Wyświetl plik

@ -1,6 +1,17 @@
// Include MicroPython API.
#include "py/runtime.h"
/***** Constants *****/
enum {
ECO2 = 0,
TVOC,
};
enum {
H2 = 0,
ETHANOL,
};
/***** Extern of Class Definition *****/
extern const mp_obj_type_t breakout_sgp30_BreakoutSGP30_type;