Problem with initial operation not working when transmitting TWI after wake-up by GPIOTE

hello,

We are implementing the function of sending/receiving via TWI after wake-up by GPIOTE.

The problem is after wake-up by GPIOTE....

The first TWI transmission/reception does not work. (No specific error is returned... only the waveform cannot be observed from the actual port.)

And in the operating state, TWI transmission/reception works normally from the second GPIOTE signal.

SW configuration is

wake-up by GPIOE -> void bsp_event_handler(bsp_event_t event) ->  app_timer_start(m_eventTWI_timer_id, EVENT_TWI_MEAS_INTERVAL, NULL);

-> static void eventTWI_timeout_handler(void * p_context) ->  read_sensor_data() -> Run nrf_drv_twi_rx

void bsp_event_handler(bsp_event_t event)
{
    uint32_t err_code;
    uint8_t mBLE_Send_check = 0;
    printf("> bsp_EH ");

    switch (event)
    {

        case   BSP_EVENT_ADVERTISING_STOP :
         
            printf("> BSP_EVENT_ADVERTISING_STOP\r\n");
           

            break;

       
        case BSP_EVENT_KEY_0 :

            printf("eTouch\r\n");

            m_eventTWI_timer_cnt = 0;
            err_code = app_timer_start(m_eventTWI_timer_id, EVENT_TWI_MEAS_INTERVAL, NULL);
            APP_ERROR_CHECK(err_code);

            //err_code = nrf_drv_twi_tx(&m_twi, PIC_TOUCH_ADDR, TWI_reg, sizeof(TWI_reg), false);
            //PIC_TOUCH_set_mode();
           

            mBLE_Send_check = 1;
           
             break;
   }
}
 

static void eventTWI_timeout_handler(void * p_context)
{
   
    //PIC_TOUCH_set_mode();
    //nrf_delay_us(500);
   
    m_eventTWI_timer_cnt++;
    printf("> TWI_tEH %d\n\r", m_eventTWI_timer_cnt);
    UNUSED_PARAMETER(p_context);

   
     if( m_eventTWI_timer_cnt <= 1 )
     {
        read_sensor_data();
     }
     else
     {
        //m_eventTWI_timer_cnt = 0;    
        app_timer_stop(m_eventTWI_timer_id);    
     }
}

static void read_sensor_data()
{
    m_xfer_done = false;
    uint8_t temp_key = 0;

    /* Read 1 byte from the specified address - skip 3 bits dedicated for fractional part of temperature. */
    ret_code_t err_code = nrf_drv_twi_rx(&m_twi, PIC_TOUCH_ADDR, &m_PIC_Touch_data[0], sizeof(m_PIC_Touch_data) );
    APP_ERROR_CHECK(err_code);
}

After wake-up, there was no effect even if the Timer delay was greatly increased to 500ms or more.

Please check if the first TWI does not run after wake-up.

-----------------------------------------------------------------------------------------------------------------------------------------------------

Additionally, what was discovered during the experiment was

The role of the PCB that currently runs TWI is peripheral, but the above phenomenon is reproduced when it is not connected to central.

However, when connected to central... the problem of not being able to run TWI the first time above disappears.

It operates normally from the first TWI.

Parents
  • Hello,

    GPITE signal looks too short. You can try to debug the code to see if the handler is actually called and TWI functions are actually called? You are using BSP, which has 50ms detection delay by default for buttons in order to avoid button debounce, signal issues etc.

  • hello, 

    I am receiving debugging messages for the above behavior.

    Therefore, it was confirmed that normal wake-up occurred for the GPITE signal.


    The actual wake-up occurs normally without any omissions.

    The TWI signal is not generated...

    and

    Do you have any idea why it depends on whether you are registered or not?

    thank

  • Hello,

    ''I am receiving debugging messages for the above behavior.''

    Could you please share the debug output?

  • hello,

    The message that determines wake-up, as I mentioned, is in the code below.

            case BSP_EVENT_KEY_0 :

                printf("eTouch\r\n");

                m_eventTWI_timer_cnt = 0;
                err_code = app_timer_start(m_eventTWI_timer_id, EVENT_TWI_MEAS_INTERVAL, NULL);
                APP_ERROR_CHECK(err_code);

    void bsp_event_handler(bsp_event_t event)
    {
        uint32_t err_code;
        uint8_t mBLE_Send_check = 0;
        printf("> bsp_EH ");
    
        switch (event)
        {
    
            case   BSP_EVENT_ADVERTISING_STOP :
             
                printf("> BSP_EVENT_ADVERTISING_STOP\r\n");
               
    
                break;
    
           
            case BSP_EVENT_KEY_0 :
    
                printf("eTouch\r\n");
    
                m_eventTWI_timer_cnt = 0;
                err_code = app_timer_start(m_eventTWI_timer_id, EVENT_TWI_MEAS_INTERVAL, NULL);
                APP_ERROR_CHECK(err_code);

    if,

    The interval between GPIOE signals is approximately 80ms. (Refer to the waveform above)

    Is this time short enough to complete the TWI transfer?

    Normal) GPIOTE 1st -> TWI 1st -> GPIOTE 2nd -> TWI 2nd

    expectation? ) GPIOTE 1st -> GPIOTE 2nd occurs in the middle of TWI 1st processing -> TWI 2nd -> TWI 1st

    We are preparing for mass production, so it is a very urgent situation. Please help.

  • Hello,

    ''The interval between GPIOE signals is approximately 80ms. (Refer to the waveform above)''. The issue is how long the GPIOTE signals are not the length of interval between the signals. Looking at the waveforms we can say that the 'dips' of the GPIOTE signal is very short. The button detect delay if 50 ms (default value), seems like signals are not entirely pulled down long enough to be detected by button library. 

  • hello

    I also said above that GPIOE's time is not 50ms.

    It's an urgent issue, but the answer came after a long time...

    The basic code has been modified as shown below.

    We confirmed that GPIOE is recognized normally through debugging messages.

    /* GPIOTE event is used only to start periodic timer when first button is activated. */
    static void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
    uint8_t cnt ;
    
    app_button_cfg_t const * p_btn = button_get(pin); // pin -> configuartion data = app_button_cfg_t type
    bool is_set = nrf_drv_gpiote_in_is_set(p_btn->pin_no); // INPUT CHECK = nrf_gpio_pin_read
    bool is_active = !((p_btn->active_state == APP_BUTTON_ACTIVE_HIGH) ^ is_set); // acticve check
    
    /* If event indicates that pin is active and no other pin is active start the timer. All
    * action happens in timeout event.
    */
    if (is_active && (m_pin_active == 0)) // Key First check = evt_handle(uint8_t pin, uint8_t value)
    // if (is_active && (mButton_Mask == 0))
    {
    // NRF_LOG_DEBUG("First active button, starting periodic timer");
    mPin = p_btn->pin_no;
    
    if( mPin == 3 ) // touch
    {
    m_pin_active = eKey_Process_PU_touch;
    mPin_active_cnt = 0;
    mPin_timer = 0;
    
    }
    :
    :
    }
    
    
    static void detection_delay_timeout_handler(void * p_context)
    {
    
        :
        :
        
        else if( m_pin_active == eKey_Process_PU_touch)   
        {
    
            usr_event( mPin, APP_BUTTON_PUSH );
    
           m_pin_active = eKey_Process_no;
           mPin_active_cnt = 0;
           mPin_timer = 0;
         }
         
        :
        :
    
    
    }

    Please confirm.

  • Hi!

    Kazi is out of office, so I'm replying instead.

    Do you have a small example that reproduces this issue on a 52832-DK?

    What SDK version are you using ? 

    Are you using the Button handling library here?

Reply Children
  • hello, Sigurd

    I haven't tried running this issue on the nRF52-DK board.

    Because it is an event and TWI communication through GPIOE, I thought it would not be a HW problem.

    Is there any need to try nRF52-DK?


    The SDK in use is nRF5_SDK_17.1.0.

    The Button Handing Library is being used with some modifications.

    static void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
    uint8_t cnt ;
    
    app_button_cfg_t const * p_btn = button_get(pin); // pin -> configuartion data = app_button_cfg_t type
    bool is_set = nrf_drv_gpiote_in_is_set(p_btn->pin_no); // INPUT CHECK = nrf_gpio_pin_read
    bool is_active = !((p_btn->active_state == APP_BUTTON_ACTIVE_HIGH) ^ is_set); // acticve check
    
    /* If event indicates that pin is active and no other pin is active start the timer. All
    * action happens in timeout event.
    */
    if (is_active && (m_pin_active == 0)) // Key First check = evt_handle(uint8_t pin, uint8_t value)
    // if (is_active && (mButton_Mask == 0))
    {
    // NRF_LOG_DEBUG("First active button, starting periodic timer");
    mPin = p_btn->pin_no;
    
    if( mPin == 3 ) // touch
    {
    m_pin_active = eKey_Process_PU_touch;
    mPin_active_cnt = 0;
    mPin_timer = 0;
    
    }
    :
    :
    }

  • Hi!

    Could you show the code where you call app_button_init() ?

  • hello.

    Relevant codes are attached.

    static void buttons_leds_init(bool * p_erase_bonds)

    /**@brief Function for initializing buttons and leds.
    *
    * @param[out] p_erase_bonds Will be true if the clear bonding button was pressed to wake the application up.
    */
    static void buttons_leds_init(bool * p_erase_bonds)
    {
    bsp_event_t startup_event;
    
    uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
    APP_ERROR_CHECK(err_code);
    
    
    err_code = bsp_btn_ble_init(NULL, &startup_event);
    APP_ERROR_CHECK(err_code);
    
    *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
    }

    uint32_t bsp_init(uint32_t type, bsp_event_callback_t callback)

    uint32_t bsp_init(uint32_t type, bsp_event_callback_t callback)
    {
    uint32_t err_code = NRF_SUCCESS;
    
    #if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
    m_indication_type = type;
    #endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
    
    #if (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)
    m_registered_callback = callback;
    
    
    // *********************** BSP will support buttons and generate events ***********************
    
    if (type & BSP_INIT_BUTTONS)
    {
    uint32_t num;
    
    /*** @brief key set ***/
    // button -> BSP_EVENT_KEY_0 matching
    
    for (num = 0; ((num < BUTTONS_NUMBER) && (err_code == NRF_SUCCESS)); num++)
    {
    err_code = bsp_event_to_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT);
    }
    
    /*** @brief key set ***/
    // 1) Pullup / Pulldown, enable / disable , event function
    // 2) call Function : nrf_drv_gpiote_is_init
    
    if (err_code == NRF_SUCCESS)
    {
    err_code = app_button_init((app_button_cfg_t *)app_buttons,
    BUTTONS_NUMBER,
    APP_TIMER_TICKS(5));
    
    // err_code = app_button_init((app_button_cfg_t *)app_buttons,
    // BUTTONS_NUMBER,
    // APP_TIMER_TICKS(50));
    
    }
    
    /*** @brief key enable ***/
    if (err_code == NRF_SUCCESS)
    {
    err_code = app_button_enable();
    }
    
    /*** @brief button_timer_handler => input check ***/
    if (err_code == NRF_SUCCESS)
    {
    err_code = app_timer_create(&m_bsp_button_tmr, // assign Timer => APP_TIMER_DEF( m_bsp_button_tmr )
    APP_TIMER_MODE_SINGLE_SHOT, // timer => one-time operation
    button_timer_handler); // button_timer_handler -> bsp_event_handler
    }
    
    
    /*** @brief Button source initialize ***/
    bsp_board_init(BSP_INIT_BUTTONS);
    
    }
    #elif (BUTTONS_NUMBER > 0) && (defined BSP_SIMPLE)
    bsp_board_init(type);
    #endif // (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)
    
    #if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
    if (type & BSP_INIT_LEDS)
    {
    //handle LEDs only. Buttons are already handled.
    bsp_board_init(BSP_INIT_LEDS);
    
    // timers module must be already initialized!
    if (err_code == NRF_SUCCESS)
    {
    err_code =
    app_timer_create(&m_bsp_leds_tmr, APP_TIMER_MODE_SINGLE_SHOT, leds_timer_handler);
    }
    
    if (err_code == NRF_SUCCESS)
    {
    err_code =
    app_timer_create(&m_bsp_alert_tmr, APP_TIMER_MODE_REPEATED, alert_timer_handler);
    }
    }
    #endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
    
    // FIXME
    bsp_board_init(BSP_INIT_NOUSE_GPIO);
    
    
    return err_code;
    }

    uint32_t bsp_btn_ble_init(bsp_btn_ble_error_handler_t error_handler, bsp_event_t * p_startup_bsp_evt)

    uint32_t bsp_btn_ble_init(bsp_btn_ble_error_handler_t error_handler, bsp_event_t * p_startup_bsp_evt)
    {
    uint32_t err_code = NRF_SUCCESS;
    
    m_error_handler = error_handler;
    
    if (p_startup_bsp_evt != NULL)
    {
    //printf("> bsp_btn_ble_init - startup_event_extract\r\n");
    startup_event_extract(p_startup_bsp_evt);
    }
    
    if (m_num_connections == 0)
    {
    //printf("> bsp_btn_ble_init - advertising_buttons_configure\r\n");
    err_code = advertising_buttons_configure();
    }
    
    
    return err_code;
    }

    uint32_t bsp_event_to_button_action_assign(uint32_t button, bsp_button_action_t action, bsp_event_t event)

    uint32_t bsp_event_to_button_action_assign(uint32_t button, bsp_button_action_t action, bsp_event_t event)
    {
    uint32_t err_code = NRF_SUCCESS;
    
    #if BUTTONS_NUMBER > 0
    if (button < BUTTONS_NUMBER)
    {
    if (event == BSP_EVENT_DEFAULT)
    {
    // Setting default action: BSP_EVENT_KEY_x for PUSH actions, BSP_EVENT_NOTHING for RELEASE and LONG_PUSH actions.
    event = (action == BSP_BUTTON_ACTION_PUSH) ? (bsp_event_t)(BSP_EVENT_KEY_0 + button) : BSP_EVENT_NOTHING;
    }
    switch (action)
    {
    case BSP_BUTTON_ACTION_PUSH:
    m_events_list[button].push_event = event;
    break;
    case BSP_BUTTON_ACTION_LONG_PUSH:
    m_events_list[button].long_push_event = event;
    break;
    case BSP_BUTTON_ACTION_RELEASE:
    m_events_list[button].release_event = event;
    break;
    default:
    err_code = NRF_ERROR_INVALID_PARAM;
    break;
    }
    }
    else
    {
    err_code = NRF_ERROR_INVALID_PARAM;
    }
    #else
    err_code = NRF_ERROR_INVALID_PARAM;
    #endif // BUTTONS_NUMBER > 0
    
    return err_code;
    }

    uint32_t app_button_init(app_button_cfg_t const * p_buttons,
    uint8_t button_count,
    uint32_t detection_delay)

    uint32_t app_button_init(app_button_cfg_t const * p_buttons,
    uint8_t button_count,
    uint32_t detection_delay)
    {
    uint32_t err_code;
    
    if (detection_delay < 2*APP_TIMER_MIN_TIMEOUT_TICKS)
    {
    return NRF_ERROR_INVALID_PARAM;
    }
    
    // @ initialize check
    if (!nrf_drv_gpiote_is_init())
    {
    err_code = nrf_drv_gpiote_init();
    VERIFY_SUCCESS(err_code);
    }
    
    /* Save configuration. */
    mp_buttons = p_buttons;
    m_button_count = button_count;
    m_detection_delay = detection_delay;
    
    memset(m_pin_states, 0, sizeof(m_pin_states));
    m_pin_active = 0;
    
    while (button_count--) // total number of buttons
    {
    app_button_cfg_t const * p_btn = &p_buttons[button_count];
    
    #if defined(BUTTON_HIGH_ACCURACY_ENABLED) && (BUTTON_HIGH_ACCURACY_ENABLED == 1)
    nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(p_btn->hi_accuracy);
    #else
    nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
    #endif
    config.pull = p_btn->pull_cfg;
    
    err_code = nrf_drv_gpiote_in_init(p_btn->pin_no, &config, gpiote_event_handler);
    VERIFY_SUCCESS(err_code);
    }
    
    /* Create polling timer. */
    return app_timer_create(&m_detection_delay_timer_id,
    APP_TIMER_MODE_SINGLE_SHOT,
    detection_delay_timeout_handler);
    }

    uint32_t app_button_enable(void)

    uint32_t app_button_enable(void)
    {
    ASSERT(mp_buttons);
    
    uint32_t i;
    for (i = 0; i < m_button_count; i++) // m_button_count = nRF52832 32EA Port at app_button_init
    {
    nrf_drv_gpiote_in_event_enable(mp_buttons[i].pin_no, true); // mp_buttons = app_button_cfg_t at app_button_init
    }
    
    return NRF_SUCCESS;
    }

    void bsp_board_init(uint32_t init_flags)

    void bsp_board_init(uint32_t init_flags)
    {
    #if defined(BOARDS_WITH_USB_DFU_TRIGGER) && defined(BOARD_PCA10059)
    (void) nrf_dfu_trigger_usb_init();
    #endif
    
    #if LEDS_NUMBER > 0
    if (init_flags & BSP_INIT_LEDS)
    {
    bsp_board_leds_init();
    }
    #endif //LEDS_NUMBER > 0
    
    
    #if BUTTONS_NUMBER > 0
    if (init_flags & BSP_INIT_BUTTONS)
    {
    //bsp_board_buttons_init();
    
    
    // bsp_board_buttons_source_init();
    }
    #endif //BUTTONS_NUMBER > 0
    
    
    if (init_flags & BSP_INIT_NOUSE_GPIO)
    {
    bsp_board_GPIO_noUsed_init();
    }
    }

  • Hi!

    I don't see anything immediately wrong in the code snippets. Is this wake-up from System ON or System OFF sleep?

    Maybe setting BUTTON_HIGH_ACCURACY_ENABLED to 1 in sdk_config.h could help

    If that does not help, then I think we would need as mentioned, a small example that reproduces this issue on a 52832-DK to dig into this further.

  • HI

    I think this issue was a timing issue.

    When the GPIOE signal event occurs, I2C is read almost immediately with the code below...

    /* Read 1 byte from the specified address - skip 3 bits dedicated for fractional part of temperature. */
    ret_code_t err_code = nrf_drv_twi_rx(&m_twi, PIC_TOUCH_ADDR, &m_PIC_Touch_data[0], sizeof(m_PIC_Touch_data) );
    APP_ERROR_CHECK(err_code);

    Currently, when a GPIOE signal event occurs, nrf_drv_twi_rx() is read after a certain time using a timer.
    It operates normally.

    I don't know if this is the exact cause...

    First of all, the operational problem was resolved.

Related