Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

FreeRTOS power consumption and idle hook

Hi,

I'm developing a custom application starting from ble_hrm_freertos application. When NRF_LOG is enabled there is no way let the chip in low power consumption. I found the problem related to the following code in logger_thread function

#if NRF_LOG_ENABLED

/** **************************************************************************
 ** @brief    Logger task
 **
 ** This thread is responsible for processing log entries if logs are deferred.
 ** Thread flushes all log entries and suspends. It is resumed by idle task hook.
 **
 ** @param    arg   Task arguments (unused)
 ** *************************************************************************/

void TASK_Logger(void * arg)
{
    UNUSED_PARAMETER(arg);

    NRF_LOG_INFO("Logger task started");
    while (1)
    {
        NRF_LOG_FLUSH();
        vTaskSuspend(NULL);
    }
}

#endif
and the vApplicationIdleHook function
/** **************************************************************************
 ** @brief    Idle task hook
 **
 ** @note Idle hook must be enabled in FreeRTOS configuration (configUSE_IDLE_HOOK).
 ** *************************************************************************/

void TASK_Idle( void )
{
#if NRF_LOG_ENABLED

    vTaskResume(m_logger_task);

#endif
}

The following behavior is what happens:
  • When no other thread is scheduled the idle hook is called
  • The idle hook resumes the logger thread
  • After logger suspends, the idle hook is called again

This loop clearly prevents the device from going into low power. My question is the following: is there any other way to implement NRF_LOG flush without the side effect of increasing power consumption that much.

Best regards,

Andrea

Parents Reply Children
  • I think this is fixed in the master branch but never got released as the nRF5 SDK is not frozen.

    In short you should apply this patch I showed in the link. Which do not need you to use ApplicationIdleHook for logger threads but instead have a new function that needs to be overridden by the application in main.c

    #if NRF_LOG_ENABLED && NRF_LOG_DEFERRED
     void log_pending_hook( void )
     {
         BaseType_t result = pdFAIL;
    
        if ( __get_IPSR() != 0 )
        {
            BaseType_t higherPriorityTaskWoken = pdFALSE;
            result = xTaskNotifyFromISR( m_logger_thread, 0, eSetValueWithoutOverwrite, &higherPriorityTaskWoken );
    
            if ( pdFAIL != result )
            {
            portYIELD_FROM_ISR( higherPriorityTaskWoken );
            }
        }
        else
        {
            UNUSED_RETURN_VALUE(xTaskNotify( m_logger_thread, 0, eSetValueWithoutOverwrite ));
        }
     }
    #endif

  • Thanks, it works correcly and the power consumption is reduced when detached from RTT Viewer.

    I also added the hook in the nrf_log_frontend.c as mentioned in the previous post

    /**
     * @brief Log pending hook
     *
     */
    __WEAK void log_pending_hook( void )
    {
        // Nothing to do
    }
    
    /**
     * @brief Allocates chunk in a buffer for one entry and injects overflow if
     * there is no room for requested entry.
     *
     * @param content_len   Number of 32bit arguments. In case of allocating for hex dump it
     *                      is the size of the buffer in 32bit words (ceiled).
     * @param p_wr_idx      Pointer to write index.
     *
     * @return True if successful allocation, false otherwise.
     *
     */
    static inline bool buf_prealloc(uint32_t content_len, uint32_t * p_wr_idx, bool std)
    {
        uint32_t req_len = content_len + HEADER_SIZE;
        bool     ret            = true;
        CRITICAL_REGION_ENTER();
        *p_wr_idx = m_log_data.wr_idx;
        uint32_t available_words = (m_buffer_mask + 1) - (m_log_data.wr_idx - m_log_data.rd_idx);
        while (req_len > available_words)
        {
            UNUSED_RETURN_VALUE(nrf_atomic_u32_add(&m_log_data.log_dropped_cnt, 1));
            if (NRF_LOG_ALLOW_OVERFLOW)
            {
                uint32_t dropped_in_skip = log_skip();
                UNUSED_RETURN_VALUE(nrf_atomic_u32_add(&m_log_data.log_dropped_cnt, dropped_in_skip));
                available_words = (m_buffer_mask + 1) - (m_log_data.wr_idx - m_log_data.rd_idx);
            }
            else
            {
                ret = false;
                break;
            }
        }
    
        if (ret)
        {
            nrf_log_main_header_t invalid_header;
            invalid_header.raw = 0;
    
            if (std)
            {
                invalid_header.std.type        = HEADER_TYPE_STD;
                invalid_header.std.in_progress = 1;
                invalid_header.std.nargs       = content_len;
            }
            else
            {
                invalid_header.hexdump.type = HEADER_TYPE_HEXDUMP;
                invalid_header.hexdump.in_progress = 1;
                invalid_header.hexdump.len = content_len;
            }
    
            nrf_log_main_header_t * p_header =
                       (nrf_log_main_header_t *)&m_log_data.buffer[m_log_data.wr_idx & m_buffer_mask];
    
            p_header->raw = invalid_header.raw;
    
            m_log_data.wr_idx += req_len;
        }
    
        CRITICAL_REGION_EXIT();
        log_pending_hook();
        return ret;
    }
    
    

    I will suggest your reply as the answer.

    Andrea

Related