From ded2710f90e5b5aac2cc208653552d450b9fa846 Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Wed, 5 May 2021 12:21:57 +0100 Subject: [PATCH] Micropython binding fixes and example for SGP30 --- drivers/CMakeLists.txt | 2 +- drivers/sgp30/sgp30.cpp | 35 +++++++++---------- drivers/sgp30/sgp30.hpp | 22 ++++++------ examples/breakout_sgp30/CMakeLists.txt | 4 +++ examples/breakout_sgp30/demo.cpp | 20 ++++++----- micropython/examples/breakout_sgp30/demo.py | 31 ++++++++++++++++ .../modules/breakout_sgp30/breakout_sgp30.c | 4 +++ .../modules/breakout_sgp30/breakout_sgp30.cpp | 8 +++-- .../modules/breakout_sgp30/breakout_sgp30.h | 11 ++++++ 9 files changed, 94 insertions(+), 43 deletions(-) create mode 100644 micropython/examples/breakout_sgp30/demo.py diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 24248ac0..07942027 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -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) diff --git a/drivers/sgp30/sgp30.cpp b/drivers/sgp30/sgp30.cpp index 53182972..f785f8d4 100644 --- a/drivers/sgp30/sgp30.cpp +++ b/drivers/sgp30/sgp30.cpp @@ -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; diff --git a/drivers/sgp30/sgp30.hpp b/drivers/sgp30/sgp30.hpp index 680179a5..07c14add 100644 --- a/drivers/sgp30/sgp30.hpp +++ b/drivers/sgp30/sgp30.hpp @@ -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); diff --git a/examples/breakout_sgp30/CMakeLists.txt b/examples/breakout_sgp30/CMakeLists.txt index 1011b0c3..21fb5b85 100644 --- a/examples/breakout_sgp30/CMakeLists.txt +++ b/examples/breakout_sgp30/CMakeLists.txt @@ -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) diff --git a/examples/breakout_sgp30/demo.cpp b/examples/breakout_sgp30/demo.cpp index 41ce235b..834daa1e 100644 --- a/examples/breakout_sgp30/demo.cpp +++ b/examples/breakout_sgp30/demo.cpp @@ -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; ibase.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); } diff --git a/micropython/modules/breakout_sgp30/breakout_sgp30.h b/micropython/modules/breakout_sgp30/breakout_sgp30.h index 1fc5e1ef..90d18be8 100644 --- a/micropython/modules/breakout_sgp30/breakout_sgp30.h +++ b/micropython/modules/breakout_sgp30/breakout_sgp30.h @@ -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;