nrf5-calendar-example SOFTDEVICE: INVALID MEMORY ACCESS

I try to integrate https://github.com/NordicPlayground/nrf5-calendar-example into Keil project. But the following error messages shown when accessing NRF_CLOCK.

error messages

nrf5-calendar-example SOFTDEVICE: INVALID MEMORY ACCESS

source code

int main(void) {
    _initVariables();
    

    // Initialize.
    log_init(); // Power_saving
    uart_init(); // Power_saving
    //_showInfo();
    fstorageInit();
    batteryVoltageInit();
    timerInit();
    button_events_init();
    scheduler_init();
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    db_discovery_init();
    services_init();
    advertising_init();
    conn_params_init();
    timerPeriodStart();
    timerStart();
    

    //  SOFTDEVICE: INVALID MEMORY ACCESS occurred when running the following code
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    
     nrf_cal_init();
     nrf_cal_set_callback(calendar_updated, 4);

}

  • nrf_calendar.h

    /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
     *
     * The information contained herein is property of Nordic Semiconductor ASA.
     * Terms and conditions of usage are described in detail in NORDIC
     * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
     *
     * Licensees are granted free, non-transferable use of the information. NO
     * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
     * the file.
     *
     */
     
    #include "nrf_calendar.h"
    #include "nrf.h"
    #include "nrf_log.h"
     
    static struct tm time_struct, m_tm_return_time; 
    static time_t m_time, m_last_calibrate_time = 0;
    static float m_calibrate_factor = 0.0f;
    static uint32_t m_rtc_increment = 60;
    static void (*cal_event_callback)(void) = 0;
    
    void nrf_cal_print_current_time(void) {
        NRF_LOG_DEBUG("Uncalibrated time:\t%s\r\n", nrf_cal_get_time_string(false));
        NRF_LOG_DEBUG("Calibrated time:\t%s\r\n", nrf_cal_get_time_string(true));
    }
    
    void nrf_cal_updated(void) {
        nrf_cal_print_current_time();
    }
    
    void nrf_cal_set_callback(void (*callback)(void), uint32_t interval) {
        NRF_LOG_DEBUG("nrf_cal_set_callback() e\n");
        // Set the calendar callback, and set the callback interval in seconds
        cal_event_callback = callback;
        m_rtc_increment = interval;
        m_time += CAL_RTC->COUNTER / 8;
        CAL_RTC->TASKS_CLEAR = 1;
        CAL_RTC->CC[0] = interval * 8;
        NRF_LOG_DEBUG("nrf_cal_set_callback() x\n");
    }
    
    void nrf_cal_init(void) {
        NRF_LOG_DEBUG("nrf_cal_init() e\n");
        // Select the 32 kHz crystal and start the 32 kHz clock
        NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos;
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_LFCLKSTART = 1;
        while(NRF_CLOCK->EVENTS_LFCLKSTARTED == 0);
        NRF_LOG_DEBUG("1\n");
        
        // Configure the RTC for 1 minute wakeup (default)
        CAL_RTC->PRESCALER = 0xFFF;
        CAL_RTC->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
        CAL_RTC->INTENSET = RTC_INTENSET_COMPARE0_Msk;
        CAL_RTC->CC[0] = m_rtc_increment * 8;
        CAL_RTC->TASKS_START = 1;
        NRF_LOG_DEBUG("2\n");
        NVIC_SetPriority(CAL_RTC_IRQn, CAL_RTC_IRQ_Priority);
        NRF_LOG_DEBUG("3\n");
        NVIC_EnableIRQ(CAL_RTC_IRQn);
        NRF_LOG_DEBUG("4\n");
        nrf_cal_set_callback(nrf_cal_updated, 4);
        NRF_LOG_DEBUG("nrf_cal_init() x\n");
    }
     
    void nrf_cal_set_time(uint32_t year, uint32_t month, uint32_t day, uint32_t hour, uint32_t minute, uint32_t second)
    {
        static time_t uncal_difftime, difftime, newtime;
        time_struct.tm_year = year - 1900;
        time_struct.tm_mon = month;
        time_struct.tm_mday = day;
        time_struct.tm_hour = hour;
        time_struct.tm_min = minute;
        time_struct.tm_sec = second;   
        newtime = mktime(&time_struct);
        CAL_RTC->TASKS_CLEAR = 1;  
        
        // Calculate the calibration offset 
        if(m_last_calibrate_time != 0)
        {
            difftime = newtime - m_last_calibrate_time;
            uncal_difftime = m_time - m_last_calibrate_time;
            m_calibrate_factor = (float)difftime / (float)uncal_difftime;
        }
        
        // Assign the new time to the local time variables
        m_time = m_last_calibrate_time = newtime;
    }    
    
    struct tm *nrf_cal_get_time(void)
    {
        time_t return_time;
        return_time = m_time + CAL_RTC->COUNTER / 8;
        m_tm_return_time = *localtime(&return_time);
        return &m_tm_return_time;
    }
    
    struct tm *nrf_cal_get_time_calibrated(void)
    {
        time_t uncalibrated_time, calibrated_time;
        if(m_calibrate_factor != 0.0f)
        {
            uncalibrated_time = m_time + CAL_RTC->COUNTER / 8;
            calibrated_time = m_last_calibrate_time + (time_t)((float)(uncalibrated_time - m_last_calibrate_time) * m_calibrate_factor + 0.5f);
            m_tm_return_time = *localtime(&calibrated_time);
            return &m_tm_return_time;
        }
        else return nrf_cal_get_time();
    }
    
    char *nrf_cal_get_time_string(bool calibrated)
    {
        static char cal_string[80];
        strftime(cal_string, 80, "%x - %H:%M:%S", (calibrated ? nrf_cal_get_time_calibrated() : nrf_cal_get_time()));
        return cal_string;
    }
     
    void CAL_RTC_IRQHandler(void) {
        NRF_LOG_DEBUG("CAL_RTC_IRQHandler()\n");
        if(CAL_RTC->EVENTS_COMPARE[0])
        {
            CAL_RTC->EVENTS_COMPARE[0] = 0;
            
            CAL_RTC->TASKS_CLEAR = 1;
            
            m_time += m_rtc_increment;
            if(cal_event_callback) cal_event_callback();
        }
    }
    

  • Hello,

    The app does not have write access to the CLOCK peripheral when the Softdevice is enabled, hence the assert (See Hardware peripherals). Instead you have to access it via the provided Softdevice APIs such as sd_clock_hfclk_request().

    However, it should not be necessary to start HF crystal oscillator for the calendar library, so my suggestion would be to simply not include this code:

        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART = 1;
        while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);

    Best regards,

    Vidar

  • Thanks for your reply! I have changed above code to the following code.

    const ret_code_t errCode = sd_clock_hfclk_request();
        if (errCode != NRF_SUCCESS) {
            NRF_LOG_WARNING("sd_clock_hfclk_request() failed\n");
        }    

        uint32_t hfclkIsRunning = 0;

        while (!hfclkIsRunning) {
            APP_ERROR_CHECK(sd_clock_hfclk_is_running(&hfclkIsRunning) );
        }

    Now it hangs at nrf_cal_init() as the following error messages.

    <debug> app: nrf_cal_init() e
     0>
     0> <error> app: SOFTDEVICE: INVALID MEMORY ACCESS

    void nrf_cal_init(void) {
        NRF_LOG_DEBUG("nrf_cal_init() e\n");
        // Select the 32 kHz crystal and start the 32 kHz clock
        NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos;
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_LFCLKSTART = 1;
        while(NRF_CLOCK->EVENTS_LFCLKSTARTED == 0);
        NRF_LOG_DEBUG("1\n");
        
        // Configure the RTC for 1 minute wakeup (default)
        CAL_RTC->PRESCALER = 0xFFF;
        CAL_RTC->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
        CAL_RTC->INTENSET = RTC_INTENSET_COMPARE0_Msk;
        CAL_RTC->CC[0] = m_rtc_increment * 8;
        CAL_RTC->TASKS_START = 1;

    }

  • Do you have any suggestion about how to change NRF_CLOCK and CAL_RTC related code to Softdevice APIs?

Related