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

  • Hi,
    See  reply, that seems like a good suggestion for you.


    exsurgo_ankit said:
    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.

    Seems like the TWI is blocking the feeding of the watchdog somehow. Preferably time spent in interrupt context should be as short as possible. Could you try to move the TWI call to main context by replacing the calls to the TWI module in the callback handler by setting a flag that is checked in the main loop. That way you would also avoid the app timer callback handler being blocked by the TWI.

    Something like this:

    void app_timer_handler()
    
    {
        feed_watchdog();
        flag = 1;
    
    }
    
    int flag = 0;
    
    int main(void)
    {
        twi_init()
        watchdog_init()
        while(true)
        {
            if(flag)
            {
                nrf_drv_twi_tx();
                flag = 0;
            }
        }
    
    }

    regards

    Jared

  •   thank you for the suggestion, I will try that. 

     I think the issue with resets has something to do with the app_timer. I have set it up in repeated mode to trigger every 1000 ms, however it always triggers every 1024 ms. Why would that be? I profiled the calls inside the timer and they barely take 2 ms. I also moved the twi tx to the main loop as you suggested and still noticed watchdog resets. I have added many debugging messages and the issue points to the timer not starting at all. 

    Which process could stop the timer from starting? I am using the nrf52 ble uart profile with SD enabled. Do note that this base code with SD enabled is working reliably in the field for over 2 years now, built against the same nRF SDK.

  • Hi,

    exsurgo_ankit said:
    I have set it up in repeated mode to trigger every 1000 ms, however it always triggers every 1024 ms

    How are you measuring this? I tried setting a repeated app timer timeout to 1000ms and toggled a GPIO in the callback handler and measured something much closer to 1000ms then 1024 ms. 

    exsurgo_ankit said:
    I have added many debugging messages and the issue points to the timer not starting at all. 
    exsurgo_ankit said:
    Which process could stop the timer from starting? I am using the nrf52 ble uart profile with SD enabled

    Is this another timer or that triggers the feeding of the watchdog? I'm a bit confused, above you mentioned that the app timer is triggered every 1024, can you elaborate.

    Also, it would be great if you could share a minimal example that reproduces this issue or at least share some relevant code in regards to the app timer. 

    regards

    Jared 

  • Hello Jared,


    I have RTC configured to trigger every 1 ms and that keeps track on milliseconds since startup. I use that variable to log(using RTT) when the timer is triggered.

    There is only one app timer which refreshes watchdog. The timer does various tasks. I log the ticks since startup at various points in the timer and it takes about 2 ms to complete.

    Here is some source code that show rtc and app timer. using RTT logger for some debug messages. There are more in the other files which tell me what happened last before a watchdog reset. Also the watchdog event handler is never triggered. I was hoping I could log the call stack in the watchdog handler and get to the root of the problem. Reason I know the timer is not triggered is because the RTT log at the start is never written. However the timer does end the operation every time based on the last RTT log statement.

    /** @brief: Function for handling the RTC0 interrupts.
     * Triggered on TICK and COMPARE0 match.
     */
    static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
    {    
        (void) int_type;
        
        //increment 1m tick ctr
        g_ticks_since_startup++;    
    }
    
    /**
     * @brief Handler for timer events.
     * 
     * @param p_context 
     */
    static void timer_handler(void * p_context)
    {
        (void) p_context;
        NRF_LOG_RAW_INFO("Timer %d\n", g_ticks_since_startup);
        
        //feed the watchdog
        nrf_drv_wdt_channel_feed(m_channel_id);    
        
        
        //do more stuff
        
        //get uart sensor data 
        sensor_poll(&m_nus);
        NRF_LOG_RAW_INFO("Timer end %d,", g_ticks_since_startup);
       
        
        //set flush logs flag
        flush_pending_logs = true;
    }
    
    
    /**@brief Function for initializing the timer module.
     */
    static void timers_init(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = app_timer_create(&m_timer, APP_TIMER_MODE_REPEATED, timer_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**
     * @brief WDT events handler.
     */
    void wdt_event_handler(void)
    {
        NRF_LOG_RAW_INFO("WDT trig\r\n");
        //NOTE: The max amount of time we can spend in WDT interrupt is two cycles of 32768[Hz] clock - after that, reset occurs
    }
    
    int main(void)
    {
        /* Init systick driver */
        nrf_drv_systick_init();
    
        
        log_init();
        
        
        timers_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();   
    
        //RTC Init
        lfclk_config();
        rtc_config();
        
        //feed the watchdog
        nrf_drv_wdt_channel_feed(m_channel_id);
          
        gpio_init();      
        
        //uart sensor init
        sensor_init();
    
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
        
        //set the ble tx power
        sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_SCAN_INIT, BLE_CONN_HANDLE_INVALID, BLE_TX_POWER); 
        APP_ERROR_CHECK(err_code);
        
        // Start advertising.        
        advertising_start();
    
        //initalise the local adc for battery voltage monitoring   
        saadc_init();
        
        //init the temperature sensor
        g_mc_termperature = 0;
            
        // Enter main loop.
        for (;;)
        {
            // Clear the event register.
            __SEV();
            __WFE();
            // Wait for an event.
            __WFE();
            
            if(flush_pending_logs)
            {
                //flush logs
                flush_pending_logs = false;
            }
    
            idle_state_handle();    
        }
    }

  • Hi,

    Could you share your sdk_config.h file as well?

    regards

    Jared 

Reply Children
Related