nrfx_twim infinite loop waiting for 'transmission_finished'

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!

Parents Reply Children
No Data
Related