This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Stream data over TWI with start signal only in the beginning of the frame, and one stop at the end of the frame

Hello,

I am working on a sensor which requires data transfer over with data length over 255 bytes. I am using nRF52832 uC and and from what I see from nordic infocenter by using the following portion of code:

ret_code_t nrf_drv_twi_tx(nrf_drv_twi_t const * p_instance,
                          uint8_t               address,
                          uint8_t const *       p_data,
                          uint8_t               length,
                          bool                  no_stop);

I can send up to 255 bytes and it is possible to set no_stop to true to not send a stop signal. However as you know, the simple write burst operation has a message similar to this message,  , but that case isn't true, when Data Frame xxx is bigger than 255, since after each data frame, no start signal is resent.

  • I have also noticed this function in nrfx_twi.c:

    typedef struct
    {
        nrfx_twi_evt_handler_t  handler;
        void *                  p_context;
        volatile uint32_t       int_mask;
        nrfx_twi_xfer_desc_t    xfer_desc;
        uint32_t                flags;
        uint8_t *               p_curr_buf;
        size_t                  curr_length;
        bool                    curr_tx_no_stop;
        twi_suspend_t           prev_suspend;
        nrfx_drv_state_t        state;
        bool                    error;
        volatile bool           busy;
        bool                    repeated;
        size_t                  bytes_transferred;
        bool                    hold_bus_uninit;
    } twi_control_block_t;
    
    static bool twi_transfer(NRF_TWI_Type           * p_twi,
                             twi_control_block_t    * p_cb)
    {
        bool stopped = false;
        if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_STOPPED))
        {
            nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
            NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_STOPPED));
    
            // Delay handling of STOPPED event till the end of events processing procedure.
            // If penultimate byte is received and function gets interrupted for long enough
            // after enabling BB_STOP shortcut, RXDREADY for last byte as well as STOPPED
            // may be active at the same time. Therefore RXREADY has to be processed before STOPPED to
            // acquire last byte before finishing transmission by returning 'false'.
            stopped = true;
        }
    
        if (p_cb->error)
        {
            nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
            nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
            nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
        }
        else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
        {
            nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
            NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
            nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
            p_cb->error = true;
        }
        else
        {
            if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_TXDSENT))
            {
                nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
                ++(p_cb->bytes_transferred);
                NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_TXDSENT));
                if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
                {
                    nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
                    NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
                    nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
                    p_cb->error = true;
                }
                else
                {
                    if (!twi_send_byte(p_twi, p_cb))
                    {
                        return false;
                    }
                }
            }
            else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_RXDREADY))
            {
                nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
                NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_RXDREADY));
                if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
                {
                    NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
                    nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
                    nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
                    p_cb->error = true;
                }
                else
                {
                    if (!twi_receive_byte(p_twi, p_cb))
                    {
                        return false;
                    }
                }
            }
        }
    
        if (stopped)
        {
            p_cb->prev_suspend = TWI_NO_SUSPEND;
            if (!p_cb->error)
            {
                p_cb->error = !xfer_completeness_check(p_twi, p_cb);
            }
            return false;
        }
    
        return true;
    }

    Is it possible to solve my issue? Is there any documentation to read for this function? I would appreciate any example as well.

    Thanks!

  • Hello Bakry,

    Which SDK version are you using? I see from your initial post that you reference nrf_drv_twi_tx from the legacy TWI driver, and you later in your comment reference a function from nrfx_twi.c
    I would recommend that you do not use these drivers interchangeably, even though the legacy driver is just forwarding macros to the nrfx implementation in later SDK's.

    I am not sure I have understood your issue correctly, but if you are trying to send data over 255 bytes you may do so if you are using the TWIM driver rather than the TWI one. The TWIM driver uses easyDMA by default, which then does not suffer from the 255 byte limitation.
    I would recommend that you use the nrfx_twim driver for this, and that you use the nrfx_twim_xfer function for the purpose you describe.

    Please let me know if anything still should be unclear, or if you should encounter any other issues or questions!

    Best regards,
    Karl

  • Thanks for your reply, I have eventually used:  

    nrfx_err_t nrfx_twi_tx(nrfx_twi_t const * p_instance,
                           uint8_t            address,
                           uint8_t    const * p_data,
                           size_t             length,
                           bool               no_stop)
    {
        nrfx_twi_xfer_desc_t xfer = NRFX_TWI_XFER_DESC_TX(address, (uint8_t*)p_data, length);
        return nrfx_twi_xfer(p_instance, &xfer, no_stop ? NRFX_TWI_FLAG_TX_NO_STOP : 0);
    }
    
    nrfx_err_t nrfx_twi_rx(nrfx_twi_t const * p_instance,
                           uint8_t            address,
                           uint8_t *          p_data,
                           size_t             length)
    {
        nrfx_twi_xfer_desc_t xfer = NRFX_TWI_XFER_DESC_RX(address, p_data, length);
        return nrfx_twi_xfer(p_instance, &xfer, 0);
    }

    I will try to verify if it works this week. In the meantime, may I know what is the difference between TWIM library and nrfx_twi? 

    I am using 17.02 SDK. Also, if size_t length can cover bytes over 255, why don't I use it instead?

  • Bakry said:
    I am using 17.02 SDK. Also, if size_t length can cover bytes over 255, why don't I use it instead?

    Actually, I must rectify a mistake in my previous comment, my apologies.
    It appears that the nRF52832 is still limited to a 255 byte TWI transfer limit, despite using TWIM with easyDMA.
    This is due to the size of the peripheral's TXD.MAXCNT register.
    I discussed this with a colleague, who informed me that even though if you were to use the ArrayList easyDMA feature for the TXD.MAXCNT register, it would still happen in two transfers.
    My thought here was the same as you - that if you suspended with a NO_STOP at the end of the first buffer, you could continue into the next - but here you should instead get a repeated start.
    My apologies for any confusion this might have caused.
    Is this what you were referring to in your initial post?

    Bakry said:
    Thanks for your reply

    No problem at all, I am happy to help!

    Bakry said:
    I will try to verify if it works this week.

    Great, I look forward to hearing any updates.

    Bakry said:
    may I know what is the difference between TWIM library and nrfx_twi? 

    The main difference between the two is that the TWIM driver uses easyDMA by default, while the nrfx_twi driver does not(but still can be configured to do so). This is not the only difference, but it is the most significant one. Please also see the reply by my colleague Einar in this ticket for some more details.

    Best regards,
    Karl

  • Thanks for letting me know. In that case, how to avoid the repeated start?

Related