Can I user NRF TWI Manager to write varying lengths from a buffer?

Hello,

I am attempting to use the NRF twi manager based on the "twi master using nrf twi manager" example. I noticed that the example only reads and wrties a single byte and hence the transfer sizes can be defined as constants. However, I am trying to use an I2C uart module, since NRF52832 only has one UART, to output some debug information.

Hence the writes are of variable length and I am struggling to get the code to compile as it requires the transfer[x].length to be a constant. So my question is if I can use the manager to schedule these writes.

I have attempted to use the standard twi master which results in watchdog resets as the "while (m_xfer_done == false)" results in a blocking call even when using an event handler. I understand that I could implement a queuing mechanism however, I am trying to avoid that effort if the twi manager does this already.

Ankit

Parents
  • Hi there,

    I'm not 100% sure I get the problem correct. Is the problem that it seems that the twi manger only transmits one byte per transfer or that the transfer size has to be known at compile time?

    I have attempted to use the standard twi master which results in watchdog resets as the "while (m_xfer_done == false)" results in a blocking call even when using an event handler. I understand that I could implement a queuing mechanism however, I am trying to avoid that effort if the twi manager does this already.

    Also, do you mean that even though you're running the twi module in non-blocking mode it doesn't allow you to feed the watchdog which results in a watchdog timeout? How are you feeding the watchdog?

    regards

    Jared 

  • Hello Jared,

    One of the problems is indeed that the transfer size should be known at compile time. I want them to be variable.

    Regarding watchdog resets, I am feeding the watchdog in a timer. This is our third development project using nRF52. So we are using a stable base code that has been working in the field for about 2 years now and does not lead to watchdog resets. However, the current project uses TWI while the previous ones didn't. I added various log messages throughout to isolate the issue which seem to be the wait for TWI transfer to complete. I would prefer to queue the bytes and let the system clear them when possible. Is there something already available in NRF libraries that would achieve this for TWI?

    Regards

  • I would prefer to queue the bytes and let the system clear them when possible.

    The TWI manager already does this. It puts the messages in a queue and sends them once the bus is free. The example code is a bit simplistic as it just waits for completion using that while loop you quoted.

    One case the library does not handle well is the case when the bus is stuck. Ie something is holding the bus low and the transfers never finish.

Reply Children
  • So is there are workaround for this stuck bus issue? 

    Also can the transfer sizes be variable for the TWI manager? Is there an example?

  • Also can the transfer sizes be variable for the TWI manager? Is there an example?

    I don't think I've ever actually tried varying the transfer size, but it should work. The transfer structs don't need to be const. And you can define them without the helper macros the example uses.

    So is there are workaround for this stuck bus issue? 

    I added a timeout and a uninit/reinit -cycle if the timeout is hit. This is mainly an issue if you use the blocking versions (the twi_manger_perform). I worked with a slave device that had an errata concerning ack timing. That device caused some watchdog timeouts until I figured out what was happening.

  • Hi,

    exsurgo_ankit said:

    One of the problems is indeed that the transfer size should be known at compile time. I want them to be variable.

    The size parameter should be initialized to a constant, are you getting a "initializer element is not constant" error? Exactly what error are you getting?

    Also, note that the log module also supports RTT as backend, which use the SWD interface to output logs instead of the UART interface.

    exsurgo_ankit said:
    Regarding watchdog resets, I am feeding the watchdog in a timer. This is our third development project using nRF52. So we are using a stable base code that has been working in the field for about 2 years now and does not lead to watchdog resets. However, the current project uses TWI while the previous ones didn't. I added various log messages throughout to isolate the issue which seem to be the wait for TWI transfer to complete. I would prefer to queue the bytes and let the system clear them when possible. Is there something already available in NRF libraries that would achieve this for TWI?

    What kind of timer are you using? Are you using a HW Timer + PPI or an app timer and feeding the watchdog in the app timers timeout handler?

    I have attempted to use the standard twi master which results in watchdog resets as the "while (m_xfer_done == false)" results in a blocking call even when using an event handler.

    Can you share the main loop when you're trying to use the standard twi master? The while (m_xfer_done == flase) loop shouldn't block any other task of executing. 

    regards

    Jared

  • Hello Jared,

    1. You are right. I am getting this error "initializer element is not constant"

    2. RTT logger is a workaround but I need a usb uart interface to the device to allow applications on Windows to connect to it.

    3. I am using an app timer and feeding the watchdog in the app timer's timeout handler. Also note that calls to TWI also happen in this timer and the TWI priority is higher than app timer's priority. If I set it the same then the app does watchdog resets from the start.

    4. Here is the code snippet of read reg and write to a fifo of the i2c-uart module.

    static uint8_t readReg(uint8_t reg, void* pBuf, size_t size)
    {
      if(pBuf == NULL)
      {
        DBG("pBuf ERROR!! : null pointer");
        return 0;
      }
      
      uint8_t * _pBuf = (uint8_t *)pBuf;
      
      //set the address to read
      _addr = updateAddr(_addr, _subSerialChannel, OBJECT_REGISTER);
      _addr &= 0xFE;
        m_xfer_done = false;
        nrf_drv_twi_tx(&m_twi, _addr, &reg, 1, false);
        while (m_xfer_done == false); //wait for transfer to complete
        
    
        //read the data
        m_xfer_done = false;
        nrf_drv_twi_rx(&m_twi, _addr, _pBuf, size);
        while (m_xfer_done == false); //wait for transfer to complete
        
      
      return size;  
    }
    
    static void writeFIFO(void *pBuf, size_t size)
    {
      if(pBuf == NULL)
      {
          DBG("pBuf ERROR!! : null pointer");
          return;
      }
      _addr = updateAddr(_addr, _subSerialChannel, OBJECT_FIFO);
      uint8_t *_pBuf = (uint8_t *)pBuf;
      size_t left = size;
      while(left)
      {
          size = (left > IIC_BUFFER_SIZE) ? IIC_BUFFER_SIZE: left;
          
          #if TWI_DRV == 1
          m_xfer_done = false;
          nrf_drv_twi_tx(&m_twi, _addr, _pBuf, size, false); 
          while (m_xfer_done == false); //wait for transfer to complete
          
          left -= size;
          _pBuf = _pBuf + size;
          if(left > 0)
          {
             nrf_delay_us(100);
          }
          else
          {
              break; //done transmitting, no need to wait
          }
      }
    }

    Regards

    Ankit

  • Hello mrono,

    A part of the problem is that I am not sure how to vary the size due to a compile time error expecting the intiialiser element for transfer to be a constant.

    uninit/reinit may be an option but I have to get the twi manager to work first with varying transfer length.

Related