TWI interface with flow sensor works incorrectly

Hello!

I have been trying to read a flow sensor with the nRF52840 DK, but the output is unexpected.

It has been proven that the flow sensor is functional, by connecting it with another MCU.

When I used a logic analyzer, the output I received was completely normal, meaning that the flow sensor is actually sending some values, and the DK receives them correctly. The thing is that the values that the flow sensor sends are incorrect. So, the flow sensor gives off incorrect values, but there is no problem with the DK.

After that, I tried to find what was wrong, and for the life of me, I could not see anything wrong with my code. As a result, I started all over from the TWI sensor example. Nothing changed. Even at the most basic level of TWI code, the registers I am reading are giving me the wrong info. What is curious is that when I use the same sensor with a BBB board, where I do not know and cannot change the code that is being executed, the flow sensor gives correct values. So it is not a sensor problem.

I am attaching you the twi code and the sensor's datasheet, where I have highlighted some lines on page 6, so you can understand a bit about the register I am trying to read. Chapter 2.4 is also quite useful. The sensor, by default, jumps into reading the flow register, and so I do not change the register read in my code. In the code, I am just shooting the sensor's flow registers values in the Terminal, every time a twi event occurs. I do not try to translate the data into real values, since I see that the raw register values are incorrect. The output of the code is shown in the figure. The red square contains the 7F-FF registers that denote the full-scale positive flow, which is totally incorrect, since I cannot produce such a flow (500LPM).

Do you have any idea what I am doing wrong?

I am truly pissed, because I know that it is a very simple application, but I cannot get it to work.

Thank you in advance,

Kostas

7723.twi_sensor_mine.zip4571.ESF Series I2C Interface_v2.pdf

Parents
  • Hi,

    I'd agree your code looks fine and it should be working. I didn't see any voltages mentioned on that data sheet - are you sure the logic levels on both MCUs are 3.3V like the Nordic?

    Other than that I would check the status register of the flow meter. If it seems to make sense and it reports an error, then you could try the reset command (0xFE). If signal decoding is actually being goofed then the status register shouldn't make sense and I'd still try that reset command.

  • Hello again!

    Turns out, that I possessed an earlier version of the datasheet of the sensor and I worked with it on the 3.3V level.

    Now, I see that the updated version works at 5V of supply and gives an output of 0.5-4.5V. That means that the logic low is 0.5V and the logic high is 4.5V, right?

    Up till now, I had connected the flow sensor to the VDD pin, and it produced the output you saw in my last post. Is that logical? Moreover, now that I connected it to the 5V pin, the TWI does not generate any events and the communication is lost.

    If that is the case, and the sensor should work at the 5V level, how can I read the sensor at the different logic level?

    Thank you,

    Kostas

    P.S. I am attaching the other datasheet I found, if you would like to take anything from it.ESRF-ESF_V1.2.pdf

  • Hi,

    You need to wait for the m_xfer_done flag to be set in the callback when the transfer completes, before starting a new transfer. Add this after line 104, line 141 and line 152 in your main.c file:

    while(m_xfer_done == false)
    {
        // Do nothing or sleep
    }

    The TWI driver can only handle one transfer at a time, and the APIs are asynchronous when a event handler is provided. When you build the application in Debug configuration, optimization level is set lower, which will typically make the application run a bit slower, which is likely why the transfer manages to complete before a new transfer is started, compared to the Release build.

    Best regards,
    Jørgen

  • Hello Jorgen! Thanks for the prompt reply!

    I added the lines you suggested after the APP_ERROR_CHECK lines you suggested, but nothing changed. The TWI performs the register change successfully, enters the twi_event handler and accurately executes it. But in the first call of the read_sensor_data, the same error is presented on line 104.

    Do you have any idea what I should try after that?

    FYI, line 104 is the APP_ERROR_CHECK line.

    Thank you,

    Kostas

  • Do your main.c look like this after the changes?

    //File includes
    #include <stdio.h>
    #include "boards.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 "nrf_gpio.h"
    
    //Define the TWI instance
    #define TWI_INSTANCE_ID     0
    
    //Slave address and flow register address
    #define SLAVE_ADDRESS       0x45U
    #define FLOW_REG_ADDR       0x00U
    #define TEMP_REG_ADDR       0x01U
    
    //Flag to indicate if operation on TWI has ended
    static volatile bool m_xfer_done = true;
    
    //Define the TWI instance
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
    
    //Buffer for samples
    static uint8_t m_sample[2] = {0x0U, 0x0U};
    
    //Function to handle the data that are produced at the TWI event
    __STATIC_INLINE void data_handler(void)
    {
      //Create a float variable to hold the compensated temperature value
      float temp_reading = 0.0f;
    
      //Create a variable to concatenate the two raw temperature bytes
      uint16_t raw_rdg = 0x0U;
    
      //Log the register values in the terminal
      raw_rdg = ((uint16_t)m_sample[0] << 8) | ((uint16_t)m_sample[1] & 0xFF);
    
      //Calculate the compensated temperature value by using the scaling function
      temp_reading = (float)raw_rdg * 50 / 65535;
        
      //Log the temperature measurement
      NRF_LOG_INFO("Temperature = " NRF_LOG_FLOAT_MARKER, NRF_LOG_FLOAT(temp_reading));
    
      //NRF_LOG_INFO("Register 0: %X ", m_sample[0]);
      //NRF_LOG_INFO("Register 1: %X ", m_sample[1]);
    }
    
    //Function to handle the TWI events
    void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
    {
      switch (p_event->type)
      {
        case NRF_DRV_TWI_EVT_DONE:
          //In case the TWI event is the completion of the transfer
          if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
          {
            //Log the registers on the terminal
            data_handler();
          }
          //Clear the transfer flag
          m_xfer_done = true;
          break;
    
        default:
          break;
      }
    }
    
    //Initialize the TWI module
    void twi_init (void)
    {
      //Declare an error code
      ret_code_t err_code;
    
      //Initialize the configuration structure of the TWI
      const nrf_drv_twi_config_t twi_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = true
      };
    
      //Initialize the TWI module
      err_code = nrf_drv_twi_init(&m_twi, &twi_config, twi_handler, NULL);
      APP_ERROR_CHECK(err_code);
    
      //Enable the TWI module
      nrf_drv_twi_enable(&m_twi);
    }
    
    //Function to read data from the sensor
    static void read_sensor_data()
    {
      //Set flag to false, before the data transmission
      m_xfer_done = false;
    
      //Read two bytes from the sensor
      ret_code_t err_code = nrf_drv_twi_rx(&m_twi, SLAVE_ADDRESS, &m_sample, sizeof(m_sample));
      APP_ERROR_CHECK(err_code);
      while(m_xfer_done == false)
      {
        // Do nothing or sleep
      }
    }
    
    //Main function
    int main(void)
    {
      ret_code_t err_code=NRF_SUCCESS;
    
      //Initialize the nrf-log module
      APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
      NRF_LOG_DEFAULT_BACKENDS_INIT();
    
      //Log a message to denote the beginning of the example
      NRF_LOG_INFO("\r\nTWI sensor example started.");
      NRF_LOG_FLUSH();
    
      nrf_delay_ms(100);
      //Initialize the TWI module
      twi_init();
    
      uint8_t temp_register[1] = {TEMP_REG_ADDR};
      uint8_t flow_register[1] = {FLOW_REG_ADDR};
    
      while (true)
      {
        //Repeat every 10ms
        nrf_delay_ms(10);
        do
        {
          __WFE();
        }while (m_xfer_done == false);
    
        //Set the twi transfer flag to false before a new transfer (write)
        m_xfer_done = false;
    
        //Change the register to read the temperature register
        err_code = nrf_drv_twi_tx(&m_twi, SLAVE_ADDRESS, temp_register, sizeof(temp_register), false);
        APP_ERROR_CHECK(err_code);
        while(m_xfer_done == false)
        {
          // Do nothing or sleep
        }
    
        //Read the temperature measurement
        read_sensor_data();
        NRF_LOG_FLUSH();
    
        //Set the twi transfer flag to false before a new transfer (write)
        m_xfer_done == false;
    
        //Change the register to read the flow register
        err_code = nrf_drv_twi_tx(&m_twi, SLAVE_ADDRESS, flow_register, sizeof(flow_register), false);
        APP_ERROR_CHECK(err_code);
        while(m_xfer_done == false)
        {
          // Do nothing or sleep
        }
    
        //Read the flow measurement
        read_sensor_data();
        NRF_LOG_FLUSH();
    
      }
    }

    I can't see anything else that should cause this error code.

  • Yes, that is exactly the code I am running. I even copied it to my main.c file.

    That's why I am flabbergasted.

    Thank you,

    Kostas

  • Any other ideas on what could be wrong Jorgen?

    Thank you,

    Kostas

Reply Children
  • Unfortunately, it is hard to say what could be wrong. You should not get this error with the current code, unless something has been changed in the drivers, etc.

    I do not have the same sensor available, so I can't test out your code.

    Can you try to add log messages whenever m_xfer_done flag gets set/cleared, and whenever nrf_drv_twi_rx/nrf_drv_twi_rtx gets called? The flag should always get cleared and set once per call to these functions.

Related