ERROR 4 [NRF_ERROR_NO_MEM] at app_timer2.c

The following error occurred after BLE APP connects to nRF52832 device. How can debug this issue?

<error> app: ERROR 4 [NRF_ERROR_NO_MEM] at ..\..\..\..\..\..\components\libraries\timer\app_timer2.c:184

Log messages of nRF52832 device:

SEGGER J-Link RTT Viewer V7.66a Terminal Log File
# Compiled: 15:21:19 on May 19 2022
# Logging started @ 08 Aug 2022 09:27:38
00> <debug> nrf_ble_gatt: Requesting to update ATT MTU to 185 bytes on connection 0x0.
00>
00> <info> app: BLE_GAP_EVT_CONNECTED
00>
00>
00> <debug> app: state=1
00>
00>
00> <debug> nrf_ble_gatt: Peer on connection 0x0 requested a data length of 251 bytes.
00>
00> <debug> nrf_ble_gatt: Updating data length to 27 on connection 0x0.
00>
00> <debug> nrf_ble_gatt: Data length updated to 27 on connection 0x0.
00>
00> <debug> nrf_ble_gatt: max_rx_octets: 27
00>
00> <debug> nrf_ble_gatt: max_tx_octets: 27
00>
00> <debug> nrf_ble_gatt: max_rx_time: 2120
00>
00> <debug> nrf_ble_gatt: max_tx_time: 2120
00>
00> <debug> nrf_ble_gatt: Peer on connection 0x0 requested an ATT MTU of 527 bytes.
00>
00> <debug> nrf_ble_gatt: Updating ATT MTU to 185 bytes (desired: 185) on connection 0x0.
00>
00> <debug> nrf_ble_gatt: ATT MTU updated to 185 bytes on connection 0x0 (response).
00>
00> <debug> app: _securityRequestHandler
00>
00>
00> <info> app: BLE_GAP_EVT_SEC_PARAMS_REQUEST
00>
00>
00> <info> app: Received data from BLE NUS. Writing data on UART.
00>
00> <debug> app:  54 49 4D 45 32 30 32 32|TIME2022
00>
00> <debug> app:  30 38 30 38 30 39 32 37|08080927
00>
00> <debug> app:  35 36                  |56      
00>
00> <debug> app: length=18
00>
00> <debug> app: data[0]=0x54 T
00>
00> <debug> app: data[1]=0x49 I
00>
00> <debug> app: data[2]=0x4D M
00>
00> <debug> app: data[3]=0x45 E
00>
00> <debug> app: data[4]=0x32 2
00>
00> <debug> app: data[5]=0x30 0
00>
00> <debug> app: data[6]=0x32 2
00>
00> <debug> app: data[7]=0x32 2
00>
00> <debug> app: data[8]=0x30 0
00>
00> <debug> app: data[9]=0x38 8
00>
00> <debug> app: data[10]=0x30 0
00>
00> <debug> app: data[11]=0x38 8
00>
00> <debug> app: data[12]=0x30 0
00>
00> <debug> app: data[13]=0x39 9
00>
00> <debug> app: data[14]=0x32 2
00>
00> <debug> app: data[15]=0x37 7
00>
00> <debug> app: data[16]=0x35 5
00>
00> <debug> app: data[17]=0x36 6
00>
00> <debug> app: state=2
00>
00>
00> <debug> app: 2 2
00>
00>
00> <debug> app: 0 0
00>
00>
00> <debug> app: 2 2
00>
00>
00> <debug> app: 2 2
00>
00>
00> <debug> app: 8 8
00>
00>
00> <debug> app: 0 0
00>
00>
00> <debug> app: 8 8
00>
00>
00> <debug> app: 0 0
00>
00>
00> <debug> app: 9 9
00>
00>
00> <debug> app: 0 0
00>
00>
00> <debug> app: 7 7
00>
00>
00> <debug> app: 2 2
00>
00>
00> <debug> app: 6 6
00>
00>
00> <debug> app: 5 5
00>
00>
00> <debug> app: datetime sync
00>
00> <debug> app: 2022-8-8 9:27:56
00>
00> <info> app:
00>
00>
00>
00> <info> app: Received data from BLE NUS. Writing data on UART.
00>
00> <debug> app:  4D 45 41 53 55 52 45   |MEASURE
00>
00> <debug> app: length=7
00>
00> <debug> app: data[0]=0x4D M
00>
00> <debug> app: data[1]=0x45 E
00>
00> <debug> app: data[2]=0x41 A
00>
00> <debug> app: data[3]=0x53 S
00>
00> <debug> app: data[4]=0x55 U
00>
00> <debug> app: data[5]=0x52 R
00>
00> <debug> app: data[6]=0x45 E
00>
00> <debug> app: state=4
00>
00>
00> <info> app:
00>
00>
00>
00> <debug> app: record measure begin
00>
00>
00> <debug> app: offsetStart=0x0
00>
00>
00> <debug> app: offsetEnd=0x0
00>
00>
00> <debug> app: timeStart
00>
00> <debug> app: 2022-8-8 9:28:0
00>
00> <debug> app: timeEnd
00>
00> <debug> app: 2022-8-8 9:28:0
00>
00> <debug> app: endAddr=0x7FFFF
00>
00> <debug> app: startAddr=0x7F000
00>
00> <debug> app: type=0, addr=0x7F000
00>
00>
00> <debug> app: START E, state=0
00>
00>
00> <warning> app: nrf_fstorage_erase() e
00>
00>
00> <warning> app: nrf_fstorage_erase() x
00>
00>
00> <debug> app: START x, state=1
00>
00>
00> <debug> app: fstate=1
00>
00>
00> <debug> app: Evt e
00>
00>
00> <debug> app: Evt er
00>
00>
00> <debug> app: NRF_FSTORAGE_EVT_ERASE_RESULT ok
00>
00> <debug> app: Evt x
00>
00>
00> <debug> app: record measure begin
00>
00>
00> <debug> app: offsetStart=0x0
00>
00>
00> <debug> app: offsetEnd=0x0
00>
00>
00> <debug> app: timeStart
00>
00> <debug> app: 2022-8-8 9:28:0
00>
00> <debug> app: timeEnd
00>
00> <debug> app: 2022-8-8 9:28:0
00>
00> <debug> app: endAddr=0x7FFFF
00>
00> <debug> app: startAddr=0x7F000
00>
00> <debug> app: type=0, addr=0x7F000
00>
00>
00> <debug> app: START E, state=2
00>
00>
00> <debug> app: record
00>
00>
00> <debug> app: offsetStart=0x0
00>
00>
00> <debug> app: offsetEnd=0x0
00>
00>
00> <debug> app: timeStart
00>
00> <debug> app: 2022-8-8 9:28:0
00>
00> <debug> app: timeEnd
00>
00> <debug> app: 2022-8-8 9:28:0
00>
00> <debug> app: nrf_fstorage_write() e
00>
00>
00> <debug> app: nrf_fstorage_write() x
00>
00>
00> <debug> app: START x, state=3
00>
00>
00> <debug> app: fstate=3
00>
00>
00> <debug> app: Evt e
00>
00>
00> <debug> app: Evt w
00>
00>
00> <debug> app: NRF_FSTORAGE_EVT_WRITE_RESULT ok
00>
00> <debug> app: Evt x
00>
00>
00> <debug> app: record measure begin
00>
00>
00> <debug> app: offsetStart=0x0
00>
00>
00> <debug> app: offsetEnd=0x0
00>
00>
00> <debug> app: timeStart
00>
00> <debug> app: 2022-8-8 9:28:1
00>
00> <debug> app: timeEnd
00>
00> <debug> app: 2022-8-8 9:28:1
00>
00> <debug> app: endAddr=0x7FFFF
00>
00> <debug> app: startAddr=0x7F000
00>
00> <debug> app: type=0, addr=0x7F000
00>
00>
00> <debug> app: START E, state=4
00>
00>
00> <debug> app: START x, state=4
00>
00>
00> <debug> app: fstate=4
00>
00>
00> <debug> app: state=5
00>
00>
00> <debug> app: _extFlashWriteData(0x0, 182)
00>
00>
00> <debug> app: buf
00>
00>
00> <debug> app: pData[0]=0xEE
00>
00>
00> <debug> app: pData[1]=0xED
00>
00>
00> <debug> app: pData[2]=0x23
00>
00>
00> <debug> app: pData[3]=0xFA
00>
00>
00> <debug> app: pData[4]=0x0
00>
00>
00> <debug> app: pData[5]=0x4
00>
00>
00> <debug> app: pData[6]=0x33
00>
00>
00> <debug> app: pData[7]=0x40
00>
00>
00> <debug> app: pData[8]=0x6
00>
00>
00> <debug> app: pData[9]=0x87
00>
00>
00> <error> app: ERROR 4 [NRF_ERROR_NO_MEM] at ..\..\..\..\..\..\components\libraries\timer\app_timer2.c:184
00>
00> PC at: 0x00039F33
00>
00> <error> app: End of error report
00>

Parents
  • Hello again,

    00> <error> app: ERROR 4 [NRF_ERROR_NO_MEM] at ..\..\..\..\..\..\components\libraries\timer\app_timer2.c:184

    This error message indicates that the APP_ERROR_CHECK on line 184 of app_timer2.c returned with the NRF_ERROR_NO_MEM error code. Which function returned the error code that was checked on line 184 of app_timer2.c in your project?

    Best regards,
    Karl

  • line 184 of app_timer2.c is

    APP_ERROR_CHECK(err_code);

  • /**
     * Copyright (c) 2018 - 2019, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    #include "app_timer.h"
    #include "nrf_atfifo.h"
    #include "nrf_sortlist.h"
    #include "nrf_delay.h"
    #if APP_TIMER_WITH_PROFILER
    #include "app_util_platform.h"
    #endif
    #if APP_TIMER_CONFIG_USE_SCHEDULER
    #include "app_scheduler.h"
    #endif
    #include <stddef.h>
    #define NRF_LOG_MODULE_NAME APP_TIMER_LOG_NAME
    #if APP_TIMER_CONFIG_LOG_ENABLED
    #define NRF_LOG_LEVEL       APP_TIMER_CONFIG_LOG_LEVEL
    #define NRF_LOG_INFO_COLOR  APP_TIMER_CONFIG_INFO_COLOR
    #define NRF_LOG_DEBUG_COLOR APP_TIMER_CONFIG_DEBUG_COLOR
    #else //APP_TIMER_CONFIG_LOG_ENABLED
    #define NRF_LOG_LEVEL       0
    #endif //APP_TIMER_CONFIG_LOG_ENABLED
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    #include "drv_rtc.h"
    
    /**
     * Maximum possible relative value is limited by safe window to detect cases when requested
     * compare event has already occured.
     */
    #define APP_TIMER_SAFE_WINDOW APP_TIMER_TICKS(APP_TIMER_SAFE_WINDOW_MS)
    
    #define APP_TIMER_RTC_MAX_VALUE   (DRV_RTC_MAX_CNT - APP_TIMER_SAFE_WINDOW)
    
    static drv_rtc_t m_rtc_inst = DRV_RTC_INSTANCE(1);
    
    #if APP_TIMER_WITH_PROFILER
    static uint8_t m_max_user_op_queue_utilization;     /**< Maximum observed timer user operations queue utilization. */
    static uint8_t m_current_user_op_queue_utilization; /**< Currently observed timer user operations queue utilization. */
    #endif /* APP_TIMER_WITH_PROFILER */
    
    /**
     * @brief Timer requests types.
     */
    typedef enum
    {
        TIMER_REQ_START,
        TIMER_REQ_STOP,
        TIMER_REQ_STOP_ALL
    } app_timer_req_type_t;
    
    /**
     * @brief Operation request structure.
     */
    typedef struct
    {
        app_timer_req_type_t type;    /**< Request type. */
        app_timer_t *        p_timer; /**< Timer instance. */
    } timer_req_t;
    
    static app_timer_t * volatile mp_active_timer; /**< Timer currently handled by RTC driver. */
    static bool                   m_global_active; /**< Flag used to globally disable all timers. */
    static uint64_t m_base_counter;
    static uint64_t m_stamp64;
    
    /* Request FIFO instance. */
    NRF_ATFIFO_DEF(m_req_fifo, timer_req_t, APP_TIMER_CONFIG_OP_QUEUE_SIZE);
    
    /* Sortlist instance. */
    static bool compare_func(nrf_sortlist_item_t * p_item0, nrf_sortlist_item_t *p_item1);
    NRF_SORTLIST_DEF(m_app_timer_sortlist, compare_func); /**< Sortlist used for storing queued timers. */
    
    /**
     * @brief Return current 64 bit timestamp
     */
    static uint64_t get_now(void)
    {
        uint64_t now = m_base_counter + drv_rtc_counter_get(&m_rtc_inst);
    
        /* it is possible that base was not updated and overflow occured, in that case 'now' will be
         * 24bit value behind. Additional timestamp updated on every 24 bit period is used to detect
         * that case. Apart from that 'now' should never be behind previously read timestamp.
         */
        if (now < m_stamp64) {
            now += (DRV_RTC_MAX_CNT + 1);
        }
    
        return now;
    }
    /**
     * @brief Function used for comparing items in sorted list.
     */
    static inline bool compare_func(nrf_sortlist_item_t * p_item0, nrf_sortlist_item_t *p_item1)
    {
        app_timer_t * p0 = CONTAINER_OF(p_item0, app_timer_t, list_item);
        app_timer_t * p1 = CONTAINER_OF(p_item1, app_timer_t, list_item);
    
        uint64_t p0_end = p0->end_val;
        uint64_t p1_end = p1->end_val;
        return (p0_end <= p1_end) ? true : false;
    }
    
    #if APP_TIMER_CONFIG_USE_SCHEDULER
    static void scheduled_timeout_handler(void * p_event_data, uint16_t event_size)
    {
        ASSERT(event_size == sizeof(app_timer_event_t));
        app_timer_event_t const * p_timer_event = (app_timer_event_t *)p_event_data;
    
        p_timer_event->timeout_handler(p_timer_event->p_context);
    }
    #endif
    
    /**
     * @brief Function called on timer expiration
     * If end value is not reached it is assumed that it was partial expiration and time is put back
     * into the list. Otherwise function calls user handler if timer was not stopped before. If timer
     * is in repeated mode then timer is rescheduled.
     *
     * @param p_timer Timer instance.
     *
     * @return True if reevaluation of sortlist needed (becasue it was updated).
     */
    static bool timer_expire(app_timer_t * p_timer)
    {
        ASSERT(p_timer->handler);
        bool ret = false;
    
        if ((m_global_active == true) && (p_timer != NULL) && (p_timer->active))
        {
            if (get_now() >= p_timer->end_val) {
                /* timer expired */
                if (p_timer->repeat_period == 0)
                {
                    p_timer->active = false;
                }
        #if APP_TIMER_CONFIG_USE_SCHEDULER
                app_timer_event_t timer_event;
    
                timer_event.timeout_handler = p_timer->handler;
                timer_event.p_context       = p_timer->p_context;
                uint32_t err_code = app_sched_event_put(&timer_event,
                                                        sizeof(timer_event),
                                                        scheduled_timeout_handler);
                if (err_code != NRF_SUCCESS) {
                    NRF_LOG_WARNING("app_sched_event_put() failed 0x%x\n", err_code);
                }    
                APP_ERROR_CHECK(err_code);
        #else
                NRF_LOG_DEBUG("Timer expired (context: %d)", (uint32_t)p_timer->p_context)
                p_timer->handler(p_timer->p_context);
        #endif
                /* check active flag as it may have been stopped in the user handler */
                if ((p_timer->repeat_period) && (p_timer->active))
                {
                    p_timer->end_val += p_timer->repeat_period;
                    nrf_sortlist_add(&m_app_timer_sortlist, &p_timer->list_item);
                    ret = true;
                }
            }
            else
            {
                nrf_sortlist_add(&m_app_timer_sortlist, &p_timer->list_item);
                ret = true;
            }
        }
        return ret;
    }
    
    /**
     * @brief Function is configuring RTC driver to trigger timeout interrupt for given timer.
     *
     * It is possible that RTC driver will indicate that timeout already occured. In that case timer
     * expires and function indicates that RTC was not configured.
     *
     * @param          p_timer Timer instance.
     * @param [in,out] p_rerun Flag indicating that sortlist reevaluation is required.
     *
     * @return True if RTC was successfully configured, false if timer already expired and RTC was not
     *         configured.
     *
     */
    static bool rtc_schedule(app_timer_t * p_timer, bool * p_rerun)
    {
        ret_code_t ret = NRF_ERROR_TIMEOUT;
        *p_rerun = false;
        int64_t remaining = (int64_t)(p_timer->end_val - get_now());
    
        if (remaining > 0) {
            uint32_t cc_val = ((uint32_t)remaining > APP_TIMER_RTC_MAX_VALUE) ?
                    (app_timer_cnt_get() + APP_TIMER_RTC_MAX_VALUE) : p_timer->end_val;
    
            ret = drv_rtc_windowed_compare_set(&m_rtc_inst, 0, cc_val, APP_TIMER_SAFE_WINDOW);
            NRF_LOG_DEBUG("Setting CC to 0x%08x (err: %d)", cc_val & DRV_RTC_MAX_CNT, ret);
            if (ret == NRF_SUCCESS)
            {
                return true;
            }
        }
        else
        {
            drv_rtc_compare_disable(&m_rtc_inst, 0);
        }
    
        if (ret == NRF_ERROR_TIMEOUT)
        {
            *p_rerun = timer_expire(p_timer);
        }
        else
        {
            NRF_LOG_ERROR("Unexpected error: %d", ret);
            ASSERT(0);
        }
    
        return false;
    }
    
    static inline app_timer_t * sortlist_pop(void)
    {
        nrf_sortlist_item_t * p_next_item = nrf_sortlist_pop(&m_app_timer_sortlist);
        return p_next_item ? CONTAINER_OF(p_next_item, app_timer_t, list_item) : NULL;
    }
    
    static inline app_timer_t * sortlist_peek(void)
    {
        nrf_sortlist_item_t const * p_next_item = nrf_sortlist_peek(&m_app_timer_sortlist);
        return p_next_item ? CONTAINER_OF(p_next_item, app_timer_t, list_item) : NULL;
    }
    
    /**
     * @brief Function for deactivating all timers which are in the sorted list (active timers).
     */
    static void sorted_list_stop_all(void)
    {
        app_timer_t * p_next;
        do
        {
            p_next = sortlist_pop();
            if (p_next)
            {
                p_next->active = false;
            }
        } while (p_next);
    }
    
    /**
     * @brief Function for handling RTC counter overflow.
     *
     * Increment base counter used to calculate 64 bit timestamp.
     */
    static void on_overflow_evt(void)
    {
        NRF_LOG_DEBUG("Overflow EVT");
        m_base_counter += (DRV_RTC_MAX_CNT + 1);
    }
    
    /**
     * #brief Function for handling RTC compare event - active timer expiration.
     */
    static void on_compare_evt(drv_rtc_t const * const  p_instance)
    {
        if (mp_active_timer)
        {
            /* If assert fails it suggests that safe window should be increased. */
            ASSERT(app_timer_cnt_diff_compute(drv_rtc_counter_get(p_instance),
                                              mp_active_timer->end_val & RTC_COUNTER_COUNTER_Msk) < APP_TIMER_SAFE_WINDOW);
    
            NRF_LOG_INST_DEBUG(mp_active_timer->p_log, "Compare EVT");
            UNUSED_RETURN_VALUE(timer_expire(mp_active_timer));
            mp_active_timer = NULL;
        }
        else
        {
            NRF_LOG_WARNING("Compare event but no active timer (already stopped?)");
        }
    }
    
    /**
     * @brief Channel 1 is triggered in the middle of 24 bit period to updated control timestamp in
     * place where there is no risk of overflow.
     */
    static void on_compare1_evt(drv_rtc_t const * const  p_instance)
    {
        m_stamp64 = get_now();
    }
    
    /**
     * @brief Function updates RTC.
     *
     * Function is called at the end of RTC interrupt when all new user request and/or timer expiration
     * occured. It configures RTC if there is any pending timer, reconfigures if the are timers with
     * shorted timeout than active one or stops RTC if there is no active timers.
     */
    static void rtc_update(drv_rtc_t const * const  p_instance)
    {
        while(1)
        {
            app_timer_t * p_next = sortlist_peek();
            bool rtc_reconf = false;
            if (p_next) //Candidate for active timer
            {
                if (mp_active_timer == NULL)
                {
                    //There is no active timer so candidate will become active timer.
                    rtc_reconf = true;
                }
                else if (p_next->end_val < mp_active_timer->end_val)
                {
                    //Candidate has shorter timeout than current active timer. Candidate will replace active timer.
                    //Active timer is put back into sorted list.
                    rtc_reconf = true;
                    if (mp_active_timer->active)
                    {
                        NRF_LOG_INST_DEBUG(mp_active_timer->p_log, "Timer preempted.");
                        nrf_sortlist_add(&m_app_timer_sortlist, &mp_active_timer->list_item);
                    }
                }
    
                if (rtc_reconf)
                {
                    bool rerun;
                    p_next = sortlist_pop();
                    NRF_LOG_INST_DEBUG(p_next->p_log, "Activating timer (CC:%d/%08x).", p_next->end_val, p_next->end_val);
                    if (rtc_schedule(p_next, &rerun))
                    {
                        if (!APP_TIMER_KEEPS_RTC_ACTIVE && (mp_active_timer == NULL))
                        {
                            drv_rtc_start(p_instance);
                        }
                        mp_active_timer = p_next;
    
                        if (rerun == false)
                        {
                            //RTC was successfully updated and sortlist was not updated. Function can be terminated.
                            break;
                        }
                    }
                    else
                    {
                        //If RTC driver indicated that timeout already occured a new candidate will be taken from sorted list.
                        NRF_LOG_INST_DEBUG(p_next->p_log,"Timer expired before scheduled to RTC.");
                        mp_active_timer = NULL;
                    }
                }
                else
                {
                    //RTC will not be updated. Function can terminate.
                    break;
                }
            }
            else //No candidate for active timer.
            {
                if (!APP_TIMER_KEEPS_RTC_ACTIVE && (mp_active_timer == NULL))
                {
                    drv_rtc_stop(p_instance);
                }
                break;
            }
        }
    }
    
    /**
     * @brief Function for processing user requests.
     *
     * Function is called only in the context of RTC interrupt.
     */
    static void timer_req_process(drv_rtc_t const * const  p_instance)
    {
        nrf_atfifo_item_get_t fifo_ctx;
        timer_req_t *         p_req = nrf_atfifo_item_get(m_req_fifo, &fifo_ctx);
    
        while (p_req)
        {
            switch (p_req->type)
            {
                case TIMER_REQ_START:
                    if (!p_req->p_timer->active)
                    {
                        p_req->p_timer->active = true;
                        nrf_sortlist_add(&m_app_timer_sortlist, &(p_req->p_timer->list_item));
                        NRF_LOG_INST_DEBUG(p_req->p_timer->p_log,"Start request (expiring at %d/0x%08x).",
                                                      p_req->p_timer->end_val, p_req->p_timer->end_val);
                    }
                    break;
                case TIMER_REQ_STOP:
                    if (p_req->p_timer == mp_active_timer)
                    {
                        mp_active_timer = NULL;
                    }
                    else
                    {
                        bool found = nrf_sortlist_remove(&m_app_timer_sortlist, &(p_req->p_timer->list_item));
                        if (!found)
                        {
                             NRF_LOG_INFO("Timer not found on sortlist (stopping expired timer).");
                        }
                    }
                    NRF_LOG_INST_DEBUG(p_req->p_timer->p_log,"Stop request.");
                    break;
                case TIMER_REQ_STOP_ALL:
                    sorted_list_stop_all();
                    m_global_active = true;
                    NRF_LOG_INFO("Stop all request.");
                    break;
                default:
                    break;
            }
    #if APP_TIMER_WITH_PROFILER
            CRITICAL_REGION_ENTER();
    #endif
            UNUSED_RETURN_VALUE(nrf_atfifo_item_free(m_req_fifo, &fifo_ctx));
    #if APP_TIMER_WITH_PROFILER
            if (m_max_user_op_queue_utilization < m_current_user_op_queue_utilization)
            {
                m_max_user_op_queue_utilization = m_current_user_op_queue_utilization;
            }
            --m_current_user_op_queue_utilization;
            CRITICAL_REGION_EXIT();
    #endif /* APP_TIMER_WITH_PROFILER */
            p_req = nrf_atfifo_item_get(m_req_fifo, &fifo_ctx);
        }
    }
    
    static void rtc_irq(drv_rtc_t const * const  p_instance)
    {
        if (drv_rtc_overflow_pending(p_instance))
        {
            on_overflow_evt();
        }
        if (drv_rtc_compare_pending(p_instance, 0))
        {
            on_compare_evt(p_instance);
        }
        if (drv_rtc_compare_pending(p_instance, 1))
        {
            on_compare1_evt(p_instance);
        }
    
        timer_req_process(p_instance);
        rtc_update(p_instance);
    }
    
    /**
     * @brief Function for triggering processing user requests.
     *
     * @note All user requests are processed in a single context - RTC interrupt.
     */
    static inline void timer_request_proc_trigger(void)
    {
        drv_rtc_irq_trigger(&m_rtc_inst);
    }
    
    /**
     * @brief Function for putting user request into the request queue
     */
    static ret_code_t timer_req_schedule(app_timer_req_type_t type, app_timer_t * p_timer)
    {
        nrf_atfifo_item_put_t fifo_ctx;
        timer_req_t * p_req;
    #if APP_TIMER_WITH_PROFILER
        CRITICAL_REGION_ENTER();
    #endif
        p_req = nrf_atfifo_item_alloc(m_req_fifo, &fifo_ctx);
    #if APP_TIMER_WITH_PROFILER
        if (p_req)
        {
            ++m_current_user_op_queue_utilization;
        }
        CRITICAL_REGION_EXIT();
    #endif /* APP_TIMER_WITH_PROFILER */
        if (p_req)
        {
            p_req->type    = type;
            p_req->p_timer = p_timer;
            if (nrf_atfifo_item_put(m_req_fifo, &fifo_ctx))
            {
                timer_request_proc_trigger();
            }
            else
            {
                NRF_LOG_WARNING("Scheduling interrupted another scheduling.");
            }
            return NRF_SUCCESS;
        }
        else
        {
            return NRF_ERROR_NO_MEM;
        }
    }
    
    ret_code_t app_timer_init(void)
    {
        ret_code_t err_code;
        drv_rtc_config_t config = {
            .prescaler          = APP_TIMER_CONFIG_RTC_FREQUENCY,
            .interrupt_priority = APP_TIMER_CONFIG_IRQ_PRIORITY
        };
    
        err_code = NRF_ATFIFO_INIT(m_req_fifo);
        if (err_code != NRFX_SUCCESS)
        {
            return err_code;
        }
    
        err_code = drv_rtc_init(&m_rtc_inst, &config, rtc_irq);
        if (err_code != NRFX_SUCCESS)
        {
            return err_code;
        }
        drv_rtc_overflow_enable(&m_rtc_inst, true);
        drv_rtc_compare_set(&m_rtc_inst, 1, DRV_RTC_MAX_CNT >> 1, true);
        if (APP_TIMER_KEEPS_RTC_ACTIVE)
        {
            drv_rtc_start(&m_rtc_inst);
        }
    
        m_global_active = true;
        return err_code;
    }
    
    ret_code_t app_timer_create(app_timer_id_t const *      p_timer_id,
                                app_timer_mode_t            mode,
                                app_timer_timeout_handler_t timeout_handler)
    {
        ASSERT(p_timer_id);
        ASSERT(timeout_handler);
    
        if (timeout_handler == NULL)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        app_timer_t * p_t = (app_timer_t *) *p_timer_id;
        p_t->handler = timeout_handler;
        p_t->repeat_period = (mode == APP_TIMER_MODE_REPEATED) ? 1 : 0;
        return NRF_SUCCESS;
    }
    
    ret_code_t app_timer_start(app_timer_t * p_timer, uint32_t timeout_ticks, void * p_context)
    {
        ASSERT(p_timer);
        app_timer_t * p_t = (app_timer_t *) p_timer;
    
        if (p_t->active)
        {
            return NRF_SUCCESS;
        }
    
        p_t->p_context = p_context;
        p_t->end_val = get_now() + timeout_ticks;
    
        if (p_t->repeat_period)
        {
            p_t->repeat_period = timeout_ticks;
        }
    
        return timer_req_schedule(TIMER_REQ_START, p_t);
    }
    
    
    ret_code_t app_timer_stop(app_timer_t * p_timer)
    {
        ASSERT(p_timer);
        app_timer_t * p_t = (app_timer_t *) p_timer;
        p_t->active = false;
    
        return timer_req_schedule(TIMER_REQ_STOP, p_t);
    }
    
    ret_code_t app_timer_stop_all(void)
    {
        //block timer globally
        m_global_active = false;
    
        return timer_req_schedule(TIMER_REQ_STOP_ALL, NULL);
    }
    
    #if APP_TIMER_WITH_PROFILER
    uint8_t app_timer_op_queue_utilization_get(void)
    {
        return m_max_user_op_queue_utilization;
    }
    #endif /* APP_TIMER_WITH_PROFILER */
    
    uint32_t app_timer_cnt_diff_compute(uint32_t   ticks_to,
                                        uint32_t   ticks_from)
    {
        return ((ticks_to - ticks_from) & RTC_COUNTER_COUNTER_Msk);
    }
    
    uint32_t app_timer_cnt_get(void)
    {
        return drv_rtc_counter_get(&m_rtc_inst);
    }
    
    void app_timer_pause(void)
    {
        drv_rtc_stop(&m_rtc_inst);
    }
    
    void app_timer_resume(void)
    {
        drv_rtc_start(&m_rtc_inst);
    }
    

  • snowuyl said:

    line 184 of app_timer2.c is

    APP_ERROR_CHECK(err_code);

    Yes, which is why you will need to look at which function that returned the error code that was checked on this line.
    In your case, this error code is returned by app_sched_event_put.

    You can then either check the functions API reference documentation to see why it would return this value, or you could open up the source code for the function to see why it would return the error. In your case, I am guessing that you are attempting to schedule things faster than they are being processed and removed from the scheduler.
    Could this be the case?

    Best regards,
    Karl

  • Thanks for your reply! Since NRF_ERROR_NO_MEM  error code is returned if the internal timer operations queue was full. Is it possible to increase size of internal timer operations queue?

Reply Children
Related