Hello everyone,
using Segger Embedded Studio, I encountered an issue with the TWI libraries. My device consists of a custom PCB controlled by the nRF52840 (programmed with the PCA10056), to which various sensors are connected using the I2C protocol. Some sensors require a 3.3V power supply while one requires 5V. To obtain these two voltages, I use a 3.9V battery connected to a 3.3V regulator, followed by a power booster circuit to increase it to 5V. The I2C line used is shown in the photo.
The 5V sensor is the SPS30 from Sensirion, and it is the one causing issues. I am programming it with a simple code that activates and reads only its values.
/** * Copyright (c) 2016 - 2021, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <stdio.h> #include <stdint.h> #include "boards.h" #include "nrf.h" #include "nordic_common.h" #include "app_util_platform.h" #include "app_error.h" #include "nrf_drv_twi.h" #include "nrf_delay.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "sps30.h" #define CONTINUOUS_MEASUREMENT 1 // 0 = no, 1 = si #define MEASURE_INTERVAL 2 // seconds #define LED_G 43 #define LED_R 45 #define START_TIME 1 // seconds // TWI instance ID #if TWI0_ENABLED #define TWI_INSTANCE_ID 0 #elif TWI1_ENABLED #define TWI_INSTANCE_ID 1 #endif // Number of possible TWI addresses #define TWI_ADDRESSES 127 // TWI instance static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID); // TWI initialization void twi_init (void) { ret_code_t err_code; const nrf_drv_twi_config_t twi_config = { .scl = 6, // viola .sda = 8, // bianco .frequency = NRF_DRV_TWI_FREQ_100K, .interrupt_priority = APP_IRQ_PRIORITY_HIGH, .clear_bus_init = false }; err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL); APP_ERROR_CHECK(err_code); nrf_drv_twi_enable(&m_twi); } // Funzione per scansione e stampa di tutti i dispositivi su linea I2C void twi_scan (void) { ret_code_t err_code; uint8_t address; uint8_t sample_data; bool detected_device = false; twi_init(); for (address = 1; address <= TWI_ADDRESSES; address++) { nrf_delay_ms(1); err_code = nrf_drv_twi_rx(&m_twi, address, &sample_data, sizeof(sample_data)); if (err_code == NRF_SUCCESS) { detected_device = true; printf("TWI device detected at address 0x%x.\n", address); } //printf("%d. ", address); //printf("0x%x.\n", address); } } void sps30_init(void) { int16_t err; char serial[SPS30_MAX_SERIAL_LEN]; uint8_t major, minor; // checks the sensor functionality while(sps30_probe() != 0) { printf("Probe failed\n\n"); nrf_delay_ms(1000); } printf("Probe succeded\n\n"); // gets the sensor serial number err = sps30_get_serial(serial); if(err == 0) printf("SPS30 serial number: %s\n", serial); else printf("Error getting serial number, error code = %d\n", err); // gets the sensor firmware version err = sps30_read_firmware_version(&major, &minor); if(err == 0) printf("SPS30 firmware version: %d.%d\n", major, minor); else printf("Error getting firmware version, error code = %d\n", err); } int main(void) { int16_t err; uint16_t data_ready; struct sps30_measurement measurement; nrf_gpio_cfg_output(LED_G); nrf_gpio_cfg_output(LED_R); nrf_gpio_pin_set(LED_G); printf("Power up time, wait 5 seconds\n\n"); nrf_delay_ms(5000); twi_scan(); printf("SPS30 INITALIZATION\n\n"); sps30_init(); printf("START MEASURING\n\n"); if(CONTINUOUS_MEASUREMENT) { printf("CONTINUOUS_MEASUREMENT\n\n"); // wake up (go into idle mode) err = sps30_wake_up(); if(err) printf("Error in wake up, error code = %d\n", err); // entering in measurement mode (go into measurement mode) err = sps30_start_measurement(); if(err) printf("Error in start measurement, error code = %d\n", err); else printf("Starting measurement mode, wait %d seconds\n\n", START_TIME); nrf_delay_ms(START_TIME*1000); while (true) { // wait if i dont have new data (new data every 1s) while(!data_ready) { err = sps30_read_data_ready(&data_ready); if(err) printf("Error in read data ready, error code = %d\n", err); } // read measures err = sps30_read_measurement(&measurement); if(err) printf("Error in read measurement, error code = %d\n", err); else { printf("Mass_conc PM1.0 [ug/m^3] = %f\n", measurement.mc_1p0); printf("Mass_conc PM2.5 [ug/m^3] = %f\n", measurement.mc_2p5); printf("Mass_conc PM4.0 [ug/m^3] = %f\n", measurement.mc_4p0); printf("Mass_conc PM10.0 [ug/m^3] = %f\n", measurement.mc_10p0); printf("Num_conc PM0.5 [#/cm^3] = %f\n", measurement.nc_0p5); printf("Num_conc PM1.0 [#/cm^3] = %f\n", measurement.nc_1p0); printf("Num_conc PM2.5 [#/cm^3] = %f\n", measurement.nc_2p5); printf("Num_conc PM4.0 [#/cm^3] = %f\n", measurement.nc_4p0); printf("Num_conc PM10.0 [#/cm^3] = %f\n", measurement.nc_10p0); printf("Size [um] = %f\n\n", measurement.typical_particle_size); } nrf_gpio_pin_toggle(LED_R); nrf_delay_ms(MEASURE_INTERVAL*1000); } } }
For an initial variable time interval (approximately 30 seconds), the code works correctly, initializing the sensor and reading its values. I am reading these results from the SES Debug terminal and printing them with printf.
TWI device detected at address 0x68. TWI device detected at address 0x69. SPS30 INITALIZATION Probe succeded SPS30 serial number: 7BEBC883A41E47E4 SPS30 firmware version: 2.3 START MEASURING Mass_conc PM1.0 [ug/m^3] = 15.410099 Mass_conc PM2.5 [ug/m^3] = 19.336349 Mass_conc PM4.0 [ug/m^3] = 21.849613 Mass_conc PM10.0 [ug/m^3] = 23.103143 Num_conc PM0.5 [#/cm^3] = 95.856666 Num_conc PM1.0 [#/cm^3] = 118.646446 Num_conc PM2.5 [#/cm^3] = 122.495880 Num_conc PM4.0 [#/cm^3] = 123.189979 Num_conc PM10.0 [#/cm^3] = 123.363677 Size [um] = 0.516945 Mass_conc PM1.0 [ug/m^3] = 18.200382 Mass_conc PM2.5 [ug/m^3] = 19.246212 Mass_conc PM4.0 [ug/m^3] = 19.246215 Mass_conc PM10.0 [ug/m^3] = 19.246200 Num_conc PM0.5 [#/cm^3] = 122.828605 Num_conc PM1.0 [#/cm^3] = 144.672042 Num_conc PM2.5 [#/cm^3] = 145.254455 Num_conc PM4.0 [#/cm^3] = 145.300537 Num_conc PM10.0 [#/cm^3] = 145.333267 Size [um] = 0.453337 Mass_conc PM1.0 [ug/m^3] = 12.457713 Mass_conc PM2.5 [ug/m^3] = 15.536768 Mass_conc PM4.0 [ug/m^3] = 17.490024 Mass_conc PM10.0 [ug/m^3] = 18.464246 Num_conc PM0.5 [#/cm^3] = 77.745971 Num_conc PM1.0 [#/cm^3] = 96.035362 Num_conc PM2.5 [#/cm^3] = 99.042457 Num_conc PM4.0 [#/cm^3] = 99.583114 Num_conc PM10.0 [#/cm^3] = 99.718978 Size [um] = 0.516211 Mass_conc PM1.0 [ug/m^3] = 4.853436 Mass_conc PM2.5 [ug/m^3] = 5.132323 Mass_conc PM4.0 [ug/m^3] = 5.132324 Mass_conc PM10.0 [ug/m^3] = 5.132320 Num_conc PM0.5 [#/cm^3] = 32.754295 Num_conc PM1.0 [#/cm^3] = 38.579212 Num_conc PM2.5 [#/cm^3] = 38.734519 Num_conc PM4.0 [#/cm^3] = 38.746810 Num_conc PM10.0 [#/cm^3] = 38.755538 Size [um] = 0.422523 Mass_conc PM1.0 [ug/m^3] = 14.064829 Mass_conc PM2.5 [ug/m^3] = 24.091142 Mass_conc PM4.0 [ug/m^3] = 31.710147 Mass_conc PM10.0 [ug/m^3] = 35.510295 Num_conc PM0.5 [#/cm^3] = 70.238800 Num_conc PM1.0 [#/cm^3] = 100.139724 Num_conc PM2.5 [#/cm^3] = 110.764526 Num_conc PM4.0 [#/cm^3] = 112.786033 Num_conc PM10.0 [#/cm^3] = 113.253890 Size [um] = 0.689805 Mass_conc PM1.0 [ug/m^3] = 18.654300 Mass_conc PM2.5 [ug/m^3] = 21.003868 Mass_conc PM4.0 [ug/m^3] = 22.059883 Mass_conc PM10.0 [ug/m^3] = 22.586586 Num_conc PM0.5 [#/cm^3] = 122.471214 Num_conc PM1.0 [#/cm^3] = 146.664154 Num_conc PM2.5 [#/cm^3] = 148.671310 Num_conc PM4.0 [#/cm^3] = 148.993804 Num_conc PM10.0 [#/cm^3] = 149.088684 Size [um] = 0.529599
The problem is that after this period, the code gets stuck in "nrfx_twim.c" in the loop at line 591, waiting for "transmission_finished" (I observed this using the debugging mode of SES).
I would like to highlight that I have an older device that uses an nRF52832 with the same connections to the SPS30. The only difference is that it is powered at 3.9V, and it works without errors using the same code.
I am unable to identify the issue, as everything works correctly for the first few seconds.
Thank you all for any help and suggestions!