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

TWIM clock pin is pull low after sending zero bytes data.

Dear Nordic

I found a example using nrfx_twim_rx() to scan slaves, I was just wondering if I can use nrfx_twim_tx() to scan slave devices by send zero byte data?  I use nrfx_twim_tx()  to send zero byte data to MCP23017 device, I don't got error code, but I don't receive TWIM event too. I found the SCL pin is pull low, I removed MCP23017 but the SCL pin is still low. 

I think the hardware not support to send zero byte data, if we send zero byte, SCL clock will be pull down waiting for data to be sent, is it right?

 

uint8_t HAL_I2C_End_Transmission(HAL_I2C_Interface i2c, uint8_t stop,void* reserved)
{
    HAL_I2C_Acquire(i2c, NULL);

    uint32_t err_code;

    m_i2c_map[i2c].transmitting = true;
    err_code = nrfx_twim_tx(m_i2c_map[i2c].instance, m_i2c_map[i2c].address, m_i2c_map[i2c].tx_buf, 
                                    m_i2c_map[i2c].tx_buf_length, true);  // !stop
    if (err_code)
    {
        m_i2c_map[i2c].transmitting = false;
    }

    while (m_i2c_map[i2c].transmitting);

    m_i2c_map[i2c].tx_buf_index = 0;
    m_i2c_map[i2c].tx_buf_length = 0;


    HAL_I2C_Release(i2c, NULL);
    return 0;
}

Best Regards,

Eugene

Parents
  • Hi Martin, thanks for your reply, the background is our user will use our i2c api to send zero byte to scan slave device. In Nordic SDK, if we send zero byte, it won't generate any events, and STOP signal is shorted to LASTTX and LASTRX, so if we send zero byte, LASTTX event will never be triggered, I add a work around in SDK, it works fine now, could you please help review it?

    I add these lines:

    if (start_task == NRF_TWIM_TASK_STARTTX && p_xfer_desc->primary_length==0)
    {
    nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
    }
    

     

     

    To:

     

    __STATIC_INLINE nrfx_err_t twim_xfer(twim_control_block_t        * p_cb,
                                         NRF_TWIM_Type               * p_twim,
                                         nrfx_twim_xfer_desc_t const * p_xfer_desc,
                                         uint32_t                      flags)
    {
        nrfx_err_t err_code = NRFX_SUCCESS;
        nrf_twim_task_t  start_task = NRF_TWIM_TASK_STARTTX;
        nrf_twim_event_t evt_to_wait = NRF_TWIM_EVENT_STOPPED;
    
        if (!nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
        {
            err_code = NRFX_ERROR_INVALID_ADDR;
            NRFX_LOG_WARNING("Function: %s, error code: %s.",
                             __func__,
                             NRFX_LOG_ERROR_STRING_GET(err_code));
            return err_code;
        }
        /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
        nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
        if (p_cb->busy)
        {
            nrf_twim_int_enable(p_twim, p_cb->int_mask);
            err_code = NRFX_ERROR_BUSY;
            NRFX_LOG_WARNING("Function: %s, error code: %s.",
                             __func__,
                             NRFX_LOG_ERROR_STRING_GET(err_code));
            return err_code;
        }
        else
        {
            p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
                          (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false: true;
        }
    
        p_cb->xfer_desc = *p_xfer_desc;
        p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
        nrf_twim_address_set(p_twim, p_xfer_desc->address);
    
        nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
        nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
    
        twim_list_enable_handle(p_twim, flags);
        switch (p_xfer_desc->type)
        {
        case NRFX_TWIM_XFER_TXTX:
            NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
            NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
            NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
            if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
            {
                err_code = NRFX_ERROR_INVALID_ADDR;
                NRFX_LOG_WARNING("Function: %s, error code: %s.",
                                 __func__,
                                 NRFX_LOG_ERROR_STRING_GET(err_code));
                return err_code;
            }
            nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
            while (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
            {}
            NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
            p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
            break;
        case NRFX_TWIM_XFER_TXRX:
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
            {
                err_code = NRFX_ERROR_INVALID_ADDR;
                NRFX_LOG_WARNING("Function: %s, error code: %s.",
                                 __func__,
                                 NRFX_LOG_ERROR_STRING_GET(err_code));
                return err_code;
            }
            nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
            nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
                                        NRF_TWIM_SHORT_LASTRX_STOP_MASK);
            p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
            break;
        case NRFX_TWIM_XFER_TX:
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
            {
                nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
                p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
                nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
                evt_to_wait = NRF_TWIM_EVENT_SUSPENDED;
            }
            else
            {
                nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
                p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
            }
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
            break;
        case NRFX_TWIM_XFER_RX:
            nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
            p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
            start_task = NRF_TWIM_TASK_STARTRX;
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
            break;
        default:
            err_code = NRFX_ERROR_INVALID_PARAM;
            break;
        }
    
        if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
        {
            nrf_twim_task_trigger(p_twim, start_task);
        }
    
        if (start_task == NRF_TWIM_TASK_STARTTX && p_xfer_desc->primary_length == 0)
        {
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
        }
    
        if (p_cb->handler)
        {
            if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
            {
                p_cb->int_mask = NRF_TWIM_INT_ERROR_MASK;
            }
            nrf_twim_int_enable(p_twim, p_cb->int_mask);
    
    #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
            if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && ((p_xfer_desc->type == NRFX_TWIM_XFER_TX) ||
                                                       (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)))
            {
                p_cb->flags = flags;
                twim_list_enable_handle(p_twim, 0);
                p_twim->FREQUENCY = 0;
                nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
                nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
            }
    #endif
        }
        else
        {
            while (!nrf_twim_event_check(p_twim, evt_to_wait))
            {
                if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
                {
                    NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
                    nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
                    nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
                    nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
                    evt_to_wait = NRF_TWIM_EVENT_STOPPED;
                }
            }
    
            uint32_t errorsrc =  nrf_twim_errorsrc_get_and_clear(p_twim);
    
            p_cb->busy = false;
    
            if (errorsrc)
            {
                err_code = twi_process_error(errorsrc);
            }
        }
        return err_code;
    }
    

     

     

    Best regards,

    Eugene

     

Reply
  • Hi Martin, thanks for your reply, the background is our user will use our i2c api to send zero byte to scan slave device. In Nordic SDK, if we send zero byte, it won't generate any events, and STOP signal is shorted to LASTTX and LASTRX, so if we send zero byte, LASTTX event will never be triggered, I add a work around in SDK, it works fine now, could you please help review it?

    I add these lines:

    if (start_task == NRF_TWIM_TASK_STARTTX && p_xfer_desc->primary_length==0)
    {
    nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
    }
    

     

     

    To:

     

    __STATIC_INLINE nrfx_err_t twim_xfer(twim_control_block_t        * p_cb,
                                         NRF_TWIM_Type               * p_twim,
                                         nrfx_twim_xfer_desc_t const * p_xfer_desc,
                                         uint32_t                      flags)
    {
        nrfx_err_t err_code = NRFX_SUCCESS;
        nrf_twim_task_t  start_task = NRF_TWIM_TASK_STARTTX;
        nrf_twim_event_t evt_to_wait = NRF_TWIM_EVENT_STOPPED;
    
        if (!nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
        {
            err_code = NRFX_ERROR_INVALID_ADDR;
            NRFX_LOG_WARNING("Function: %s, error code: %s.",
                             __func__,
                             NRFX_LOG_ERROR_STRING_GET(err_code));
            return err_code;
        }
        /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
        nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
        if (p_cb->busy)
        {
            nrf_twim_int_enable(p_twim, p_cb->int_mask);
            err_code = NRFX_ERROR_BUSY;
            NRFX_LOG_WARNING("Function: %s, error code: %s.",
                             __func__,
                             NRFX_LOG_ERROR_STRING_GET(err_code));
            return err_code;
        }
        else
        {
            p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
                          (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false: true;
        }
    
        p_cb->xfer_desc = *p_xfer_desc;
        p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
        nrf_twim_address_set(p_twim, p_xfer_desc->address);
    
        nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
        nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
    
        twim_list_enable_handle(p_twim, flags);
        switch (p_xfer_desc->type)
        {
        case NRFX_TWIM_XFER_TXTX:
            NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
            NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
            NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
            if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
            {
                err_code = NRFX_ERROR_INVALID_ADDR;
                NRFX_LOG_WARNING("Function: %s, error code: %s.",
                                 __func__,
                                 NRFX_LOG_ERROR_STRING_GET(err_code));
                return err_code;
            }
            nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
            while (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
            {}
            NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
            nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
            p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
            break;
        case NRFX_TWIM_XFER_TXRX:
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
            {
                err_code = NRFX_ERROR_INVALID_ADDR;
                NRFX_LOG_WARNING("Function: %s, error code: %s.",
                                 __func__,
                                 NRFX_LOG_ERROR_STRING_GET(err_code));
                return err_code;
            }
            nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
            nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
                                        NRF_TWIM_SHORT_LASTRX_STOP_MASK);
            p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
            break;
        case NRFX_TWIM_XFER_TX:
            nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
            {
                nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
                p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
                nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
                evt_to_wait = NRF_TWIM_EVENT_SUSPENDED;
            }
            else
            {
                nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
                p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
            }
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
            break;
        case NRFX_TWIM_XFER_RX:
            nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
            nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
            p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
            start_task = NRF_TWIM_TASK_STARTRX;
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
            break;
        default:
            err_code = NRFX_ERROR_INVALID_PARAM;
            break;
        }
    
        if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
        {
            nrf_twim_task_trigger(p_twim, start_task);
        }
    
        if (start_task == NRF_TWIM_TASK_STARTTX && p_xfer_desc->primary_length == 0)
        {
            nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
        }
    
        if (p_cb->handler)
        {
            if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
            {
                p_cb->int_mask = NRF_TWIM_INT_ERROR_MASK;
            }
            nrf_twim_int_enable(p_twim, p_cb->int_mask);
    
    #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
            if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && ((p_xfer_desc->type == NRFX_TWIM_XFER_TX) ||
                                                       (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)))
            {
                p_cb->flags = flags;
                twim_list_enable_handle(p_twim, 0);
                p_twim->FREQUENCY = 0;
                nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
                nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
            }
    #endif
        }
        else
        {
            while (!nrf_twim_event_check(p_twim, evt_to_wait))
            {
                if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
                {
                    NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
                    nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
                    nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
                    nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
                    evt_to_wait = NRF_TWIM_EVENT_STOPPED;
                }
            }
    
            uint32_t errorsrc =  nrf_twim_errorsrc_get_and_clear(p_twim);
    
            p_cb->busy = false;
    
            if (errorsrc)
            {
                err_code = twi_process_error(errorsrc);
            }
        }
        return err_code;
    }
    

     

     

    Best regards,

    Eugene

     

Children
No Data
Related