Micropython binding fixes and example for SGP30
This commit is contained in:
parent
77ca674ac8
commit
ded2710f90
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue