nRF9151 custom board – GNSS sample fails with “Failed to activate GNSS functional mode”

Hi Nordic Team,

I have developed a custom board using the nRF9151 controller.
I am testing the GNSS sample from nRF Connect SDK v3.0.0.
When I flash and run the firmware, I see the following output in RTT Viewer:

Hardware Details:

  • SoC: nRF9151

  • Board: Custom design (based on nRF9151 DK reference)

Software Details:

  • nRF Connect SDK: v3.0.0

  • Toolchain: nRF Connect for VS Code

  • Sample Used: nrf/samples/nrf9160/gnss

  • Build target: nrf9151dk_nrf9151

    How can I solve this issue?


Best regards

Arun

Parents Reply Children
  • Hi Arun,

    RTT logging is not enabled by default in the project configuration. Have you modified GNSS sample in any way?

    Best regards,
    Dejan

  • Hi Dejan,

    Yes, I’ve added the following configurations in the prj.conf file to enable RTT logging:

    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_LOG=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_UART=n
    CONFIG_LOG_MODE_IMMEDIATE=y
    CONFIG_PRINTK=y
    CONFIG_STDOUT_CONSOLE=y

    In the main file, I only added

    #include <zephyr/sys/printk.h>

    Other than that, I haven’t made any modifications to the GNSS sample.

    Best regards,
    Arun

  • Hi Arun,

    Can you try to remove occurrences of printk (from your code and configuration) and leave only logging enabled? What is the result?

    Best regards,
    Dejan

  • Hi Dejan,

    I removed all occurrences of printk from both the project source files and the configuration file, but it’s still showing the same error.

    I’m using the nRF52 DK as a programmer to flash my nRF9151 board.
    I upload the firmware using nRF Connect for Desktop (Programmer tab), and since I can’t see any output in the serial terminal, I’m using J-Link RTT Viewer to monitor the logs.

    I’ve attached my main.c and prj.conf files — could you please check and let me know if anything is missing or needs to be modified?

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <zephyr/kernel.h>
    #include <zephyr/logging/log.h>
    #include <nrf_modem_at.h>
    #include <nrf_modem_gnss.h>
    #include <modem/lte_lc.h>
    #include <modem/nrf_modem_lib.h>
    #include <date_time.h>
    
    
    LOG_MODULE_REGISTER(gnss_sample, CONFIG_GNSS_SAMPLE_LOG_LEVEL);
    
    #define PI 3.14159265358979323846
    #define EARTH_RADIUS_METERS (6371.0 * 1000.0)
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    static struct k_work_q gnss_work_q;
    
    #define GNSS_WORKQ_THREAD_STACK_SIZE 2304
    #define GNSS_WORKQ_THREAD_PRIORITY   5
    
    K_THREAD_STACK_DEFINE(gnss_workq_stack_area, GNSS_WORKQ_THREAD_STACK_SIZE);
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE || CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    #include "assistance.h"
    
    static struct nrf_modem_gnss_agnss_data_frame last_agnss;
    static struct k_work agnss_data_get_work;
    static volatile bool requesting_assistance;
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    static struct k_work_delayable ttff_test_got_fix_work;
    static struct k_work_delayable ttff_test_prepare_work;
    static struct k_work ttff_test_start_work;
    static double time_to_fix;
    #endif
    
    static const char update_indicator[] = {'\\', '|', '/', '-'};
    
    static struct nrf_modem_gnss_pvt_data_frame last_pvt;
    static uint64_t fix_timestamp;
    static uint32_t time_blocked;
    
    /* Reference position. */
    static bool ref_used;
    static double ref_latitude;
    static double ref_longitude;
    
    K_MSGQ_DEFINE(nmea_queue, sizeof(struct nrf_modem_gnss_nmea_data_frame *), 10, 4);
    static K_SEM_DEFINE(pvt_data_sem, 0, 1);
    static K_SEM_DEFINE(time_sem, 0, 1);
    
    static struct k_poll_event events[2] = {
    	K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    					K_POLL_MODE_NOTIFY_ONLY,
    					&pvt_data_sem, 0),
    	K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE,
    					K_POLL_MODE_NOTIFY_ONLY,
    					&nmea_queue, 0),
    };
    
    BUILD_ASSERT(IS_ENABLED(CONFIG_LTE_NETWORK_MODE_LTE_M_GPS) ||
    	     IS_ENABLED(CONFIG_LTE_NETWORK_MODE_NBIOT_GPS) ||
    	     IS_ENABLED(CONFIG_LTE_NETWORK_MODE_LTE_M_NBIOT_GPS),
    	     "CONFIG_LTE_NETWORK_MODE_LTE_M_GPS, "
    	     "CONFIG_LTE_NETWORK_MODE_NBIOT_GPS or "
    	     "CONFIG_LTE_NETWORK_MODE_LTE_M_NBIOT_GPS must be enabled");
    
    BUILD_ASSERT((sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE) == 1 &&
    	      sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE) == 1) ||
    	     (sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE) > 1 &&
    	      sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE) > 1),
    	     "CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE and "
    	     "CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE must be both either set or empty");
    
    /* Returns the distance between two coordinates in meters. The distance is calculated using the
     * haversine formula.
     */
    static double distance_calculate(double lat1, double lon1,
    				 double lat2, double lon2)
    {
    	double d_lat_rad = (lat2 - lat1) * PI / 180.0;
    	double d_lon_rad = (lon2 - lon1) * PI / 180.0;
    
    	double lat1_rad = lat1 * PI / 180.0;
    	double lat2_rad = lat2 * PI / 180.0;
    
    	double a = pow(sin(d_lat_rad / 2), 2) +
    		   pow(sin(d_lon_rad / 2), 2) *
    		   cos(lat1_rad) * cos(lat2_rad);
    
    	double c = 2 * asin(sqrt(a));
    
    	return EARTH_RADIUS_METERS * c;
    }
    
    static void print_distance_from_reference(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	if (!ref_used) {
    		return;
    	}
    
    	double distance = distance_calculate(pvt_data->latitude, pvt_data->longitude,
    					     ref_latitude, ref_longitude);
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)) {
    		LOG_INF("Distance from reference: %.01f", distance);
    	} else {
    		printf("\nDistance from reference: %.01f\n", distance);
    	}
    }
    
    static void gnss_event_handler(int event)
    {
    	int retval;
    	struct nrf_modem_gnss_nmea_data_frame *nmea_data;
    
    	switch (event) {
    	case NRF_MODEM_GNSS_EVT_PVT:
    		retval = nrf_modem_gnss_read(&last_pvt, sizeof(last_pvt), NRF_MODEM_GNSS_DATA_PVT);
    		if (retval == 0) {
    			k_sem_give(&pvt_data_sem);
    		}
    		break;
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	case NRF_MODEM_GNSS_EVT_FIX:
    		/* Time to fix is calculated here, but it's printed from a delayed work to avoid
    		 * messing up the NMEA output.
    		 */
    		time_to_fix = (k_uptime_get() - fix_timestamp) / 1000.0;
    		k_work_schedule_for_queue(&gnss_work_q, &ttff_test_got_fix_work, K_MSEC(100));
    		k_work_schedule_for_queue(&gnss_work_q, &ttff_test_prepare_work,
    					  K_SECONDS(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_INTERVAL));
    		break;
    #endif /* CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    	case NRF_MODEM_GNSS_EVT_NMEA:
    		nmea_data = k_malloc(sizeof(struct nrf_modem_gnss_nmea_data_frame));
    		if (nmea_data == NULL) {
    			LOG_ERR("Failed to allocate memory for NMEA");
    			break;
    		}
    
    		retval = nrf_modem_gnss_read(nmea_data,
    					     sizeof(struct nrf_modem_gnss_nmea_data_frame),
    					     NRF_MODEM_GNSS_DATA_NMEA);
    		if (retval == 0) {
    			retval = k_msgq_put(&nmea_queue, &nmea_data, K_NO_WAIT);
    		}
    
    		if (retval != 0) {
    			k_free(nmea_data);
    		}
    		break;
    
    	case NRF_MODEM_GNSS_EVT_AGNSS_REQ:
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    		retval = nrf_modem_gnss_read(&last_agnss,
    					     sizeof(last_agnss),
    					     NRF_MODEM_GNSS_DATA_AGNSS_REQ);
    		if (retval == 0) {
    			k_work_submit_to_queue(&gnss_work_q, &agnss_data_get_work);
    		}
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    		break;
    
    	default:
    		break;
    	}
    }
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    K_SEM_DEFINE(lte_ready, 0, 1);
    
    static void lte_lc_event_handler(const struct lte_lc_evt *const evt)
    {
    	switch (evt->type) {
    	case LTE_LC_EVT_NW_REG_STATUS:
    		if ((evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME) ||
    		    (evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_ROAMING)) {
    			LOG_INF("Connected to LTE network");
    			k_sem_give(&lte_ready);
    		}
    		break;
    
    	default:
    		break;
    	}
    }
    
    void lte_connect(void)
    {
    	int err;
    
    	LOG_INF("Connecting to LTE network");
    
    	err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_LTE);
    	if (err) {
    		LOG_ERR("Failed to activate LTE, error: %d", err);
    		return;
    	}
    
    	k_sem_take(&lte_ready, K_FOREVER);
    
    	/* Wait for a while, because with IPv4v6 PDN the IPv6 activation takes a bit more time. */
    	k_sleep(K_SECONDS(1));
    }
    
    void lte_disconnect(void)
    {
    	int err;
    
    	err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_DEACTIVATE_LTE);
    	if (err) {
    		LOG_ERR("Failed to deactivate LTE, error: %d", err);
    		return;
    	}
    
    	LOG_INF("LTE disconnected");
    }
    #endif /* CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    static const char *get_system_string(uint8_t system_id)
    {
    	switch (system_id) {
    	case NRF_MODEM_GNSS_SYSTEM_INVALID:
    		return "invalid";
    
    	case NRF_MODEM_GNSS_SYSTEM_GPS:
    		return "GPS";
    
    	case NRF_MODEM_GNSS_SYSTEM_QZSS:
    		return "QZSS";
    
    	default:
    		return "unknown";
    	}
    }
    
    static void agnss_data_get_work_fn(struct k_work *item)
    {
    	ARG_UNUSED(item);
    
    	int err;
    
    	/* GPS data need is always expected to be present and first in list. */
    	__ASSERT(last_agnss.system_count > 0,
    		 "GNSS system data need not found");
    	__ASSERT(last_agnss.system[0].system_id == NRF_MODEM_GNSS_SYSTEM_GPS,
    		 "GPS data need not found");
    
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_SUPL)
    	/* SUPL doesn't usually provide NeQuick ionospheric corrections and satellite real time
    	 * integrity information. If GNSS asks only for those, the request should be ignored.
    	 */
    	if (last_agnss.system[0].sv_mask_ephe == 0 &&
    	    last_agnss.system[0].sv_mask_alm == 0 &&
    	    (last_agnss.data_flags & ~(NRF_MODEM_GNSS_AGNSS_NEQUICK_REQUEST |
    				       NRF_MODEM_GNSS_AGNSS_INTEGRITY_REQUEST)) == 0) {
    		LOG_INF("Ignoring assistance request for only NeQuick and/or integrity");
    		return;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_SUPL */
    
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_MINIMAL)
    	/* With minimal assistance, the request should be ignored if no GPS time or position
    	 * is requested.
    	 */
    	if (!(last_agnss.data_flags & NRF_MODEM_GNSS_AGNSS_GPS_SYS_TIME_AND_SV_TOW_REQUEST) &&
    	    !(last_agnss.data_flags & NRF_MODEM_GNSS_AGNSS_POSITION_REQUEST)) {
    		LOG_INF("Ignoring assistance request because no GPS time or position is requested");
    		return;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_MINIMAL */
    
    	if (last_agnss.data_flags == 0 &&
    	    last_agnss.system[0].sv_mask_ephe == 0 &&
    	    last_agnss.system[0].sv_mask_alm == 0) {
    		LOG_INF("Ignoring assistance request because only QZSS data is requested");
    		return;
    	}
    
    	requesting_assistance = true;
    
    	LOG_INF("Assistance data needed: data_flags: 0x%02x", last_agnss.data_flags);
    	for (int i = 0; i < last_agnss.system_count; i++) {
    		LOG_INF("Assistance data needed: %s ephe: 0x%llx, alm: 0x%llx",
    			get_system_string(last_agnss.system[i].system_id),
    			last_agnss.system[i].sv_mask_ephe,
    			last_agnss.system[i].sv_mask_alm);
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	lte_connect();
    #endif /* CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    	err = assistance_request(&last_agnss);
    	if (err) {
    		LOG_ERR("Failed to request assistance data");
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	lte_disconnect();
    #endif /* CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    	requesting_assistance = false;
    }
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    static void ttff_test_got_fix_work_fn(struct k_work *item)
    {
    	LOG_INF("Time to fix: %.01f s", time_to_fix);
    	if (time_blocked > 0) {
    		LOG_INF("Time GNSS was blocked by LTE: %u s", time_blocked);
    	}
    	print_distance_from_reference(&last_pvt);
    	LOG_INF("Sleeping for %u s", CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_INTERVAL);
    }
    
    static int ttff_test_force_cold_start(void)
    {
    	int err;
    	uint32_t delete_mask;
    
    	LOG_INF("Deleting GNSS data");
    
    	/* Delete everything else except the TCXO offset. */
    	delete_mask = NRF_MODEM_GNSS_DELETE_EPHEMERIDES |
    		      NRF_MODEM_GNSS_DELETE_ALMANACS |
    		      NRF_MODEM_GNSS_DELETE_IONO_CORRECTION_DATA |
    		      NRF_MODEM_GNSS_DELETE_LAST_GOOD_FIX |
    		      NRF_MODEM_GNSS_DELETE_GPS_TOW |
    		      NRF_MODEM_GNSS_DELETE_GPS_WEEK |
    		      NRF_MODEM_GNSS_DELETE_UTC_DATA |
    		      NRF_MODEM_GNSS_DELETE_GPS_TOW_PRECISION;
    
    	/* With minimal assistance, we want to keep the factory almanac. */
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_ASSISTANCE_MINIMAL)) {
    		delete_mask &= ~NRF_MODEM_GNSS_DELETE_ALMANACS;
    	}
    
    	err = nrf_modem_gnss_nv_data_delete(delete_mask);
    	if (err) {
    		LOG_ERR("Failed to delete GNSS data");
    		return -1;
    	}
    
    	return 0;
    }
    
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD)
    static bool qzss_assistance_is_supported(void)
    {
    	char resp[32];
    
    	if (nrf_modem_at_cmd(resp, sizeof(resp), "AT+CGMM") == 0) {
    		/* nRF9160 does not support QZSS assistance, while nRF91x1 do. */
    		if (strstr(resp, "nRF9160") != NULL) {
    			return false;
    		}
    	}
    
    	return true;
    }
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD */
    
    static void ttff_test_prepare_work_fn(struct k_work *item)
    {
    	/* Make sure GNSS is stopped before next start. */
    	nrf_modem_gnss_stop();
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_COLD_START)) {
    		if (ttff_test_force_cold_start() != 0) {
    			return;
    		}
    	}
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST_COLD_START)) {
    		/* All A-GNSS data is always requested before GNSS is started. */
    		last_agnss.data_flags =
    			NRF_MODEM_GNSS_AGNSS_GPS_UTC_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_KLOBUCHAR_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_NEQUICK_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_GPS_SYS_TIME_AND_SV_TOW_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_POSITION_REQUEST |
    			NRF_MODEM_GNSS_AGNSS_INTEGRITY_REQUEST;
    		last_agnss.system_count = 1;
    		last_agnss.system[0].sv_mask_ephe = 0xffffffff;
    		last_agnss.system[0].sv_mask_alm = 0xffffffff;
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD)
    		if (qzss_assistance_is_supported()) {
    			last_agnss.system_count = 2;
    			last_agnss.system[1].sv_mask_ephe = 0x3ff;
    			last_agnss.system[1].sv_mask_alm = 0x3ff;
    		}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD */
    
    		k_work_submit_to_queue(&gnss_work_q, &agnss_data_get_work);
    	} else {
    		/* Start and stop GNSS to trigger possible A-GNSS data request. If new A-GNSS
    		 * data is needed it is fetched before GNSS is started.
    		 */
    		nrf_modem_gnss_start();
    		nrf_modem_gnss_stop();
    	}
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    	k_work_submit_to_queue(&gnss_work_q, &ttff_test_start_work);
    }
    
    static void ttff_test_start_work_fn(struct k_work *item)
    {
    	LOG_INF("Starting GNSS");
    	if (nrf_modem_gnss_start() != 0) {
    		LOG_ERR("Failed to start GNSS");
    		return;
    	}
    
    	fix_timestamp = k_uptime_get();
    	time_blocked = 0;
    }
    #endif /* CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    static void date_time_evt_handler(const struct date_time_evt *evt)
    {
    	k_sem_give(&time_sem);
    }
    
    static int modem_init(void)
    {
    	if (IS_ENABLED(CONFIG_DATE_TIME)) {
    		date_time_register_handler(date_time_evt_handler);
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	lte_lc_register_handler(lte_lc_event_handler);
    #elif !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    	lte_lc_psm_req(true);
    
    	LOG_INF("Connecting to LTE network");
    
    	if (lte_lc_connect() != 0) {
    		LOG_ERR("Failed to connect to LTE network");
    		return -1;
    	}
    
    	LOG_INF("Connected to LTE network");
    
    	if (IS_ENABLED(CONFIG_DATE_TIME)) {
    		LOG_INF("Waiting for current time");
    
    		/* Wait for an event from the Date Time library. */
    		k_sem_take(&time_sem, K_MINUTES(10));
    
    		if (!date_time_is_valid()) {
    			LOG_WRN("Failed to get current time, continuing anyway");
    		}
    	}
    #endif
    
    	return 0;
    }
    
    static int sample_init(void)
    {
    	int err = 0;
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	struct k_work_queue_config cfg = {
    		.name = "gnss_work_q",
    		.no_yield = false
    	};
    
    	k_work_queue_start(
    		&gnss_work_q,
    		gnss_workq_stack_area,
    		K_THREAD_STACK_SIZEOF(gnss_workq_stack_area),
    		GNSS_WORKQ_THREAD_PRIORITY,
    		&cfg);
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE || CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    #if !defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)
    	k_work_init(&agnss_data_get_work, agnss_data_get_work_fn);
    
    	err = assistance_init(&gnss_work_q);
    #endif /* !CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE */
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	k_work_init_delayable(&ttff_test_got_fix_work, ttff_test_got_fix_work_fn);
    	k_work_init_delayable(&ttff_test_prepare_work, ttff_test_prepare_work_fn);
    	k_work_init(&ttff_test_start_work, ttff_test_start_work_fn);
    #endif /* CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    
    	return err;
    }
    
    static int gnss_init_and_start(void)
    {
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND)
    	/* Enable GNSS. */
    	if (lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_GNSS) != 0) {
    		LOG_ERR("Failed to activate GNSS functional mode");
    		return -1;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE || CONFIG_GNSS_SAMPLE_LTE_ON_DEMAND */
    
    	/* Configure GNSS. */
    	if (nrf_modem_gnss_event_handler_set(gnss_event_handler) != 0) {
    		LOG_ERR("Failed to set GNSS event handler");
    		return -1;
    	}
    
    	/* Enable all supported NMEA messages. */
    	uint16_t nmea_mask = NRF_MODEM_GNSS_NMEA_RMC_MASK |
    			     NRF_MODEM_GNSS_NMEA_GGA_MASK |
    			     NRF_MODEM_GNSS_NMEA_GLL_MASK |
    			     NRF_MODEM_GNSS_NMEA_GSA_MASK |
    			     NRF_MODEM_GNSS_NMEA_GSV_MASK;
    
    	if (nrf_modem_gnss_nmea_mask_set(nmea_mask) != 0) {
    		LOG_ERR("Failed to set GNSS NMEA mask");
    		return -1;
    	}
    
    	/* Make QZSS satellites visible in the NMEA output. */
    	if (nrf_modem_gnss_qzss_nmea_mode_set(NRF_MODEM_GNSS_QZSS_NMEA_MODE_CUSTOM) != 0) {
    		LOG_WRN("Failed to enable custom QZSS NMEA mode");
    	}
    
    	/* This use case flag should always be set. */
    	uint8_t use_case = NRF_MODEM_GNSS_USE_CASE_MULTIPLE_HOT_START;
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_PERIODIC) &&
    	    !IS_ENABLED(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE)) {
    		/* Disable GNSS scheduled downloads when assistance is used. */
    		use_case |= NRF_MODEM_GNSS_USE_CASE_SCHED_DOWNLOAD_DISABLE;
    	}
    
    	if (IS_ENABLED(CONFIG_GNSS_SAMPLE_LOW_ACCURACY)) {
    		use_case |= NRF_MODEM_GNSS_USE_CASE_LOW_ACCURACY;
    	}
    
    	if (nrf_modem_gnss_use_case_set(use_case) != 0) {
    		LOG_WRN("Failed to set GNSS use case");
    	}
    
    #if defined(CONFIG_NRF_CLOUD_AGNSS_ELEVATION_MASK)
    	if (nrf_modem_gnss_elevation_threshold_set(CONFIG_NRF_CLOUD_AGNSS_ELEVATION_MASK) != 0) {
    		LOG_ERR("Failed to set elevation threshold");
    		return -1;
    	}
    	LOG_DBG("Set elevation threshold to %u", CONFIG_NRF_CLOUD_AGNSS_ELEVATION_MASK);
    #endif
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_CONTINUOUS)
    	/* Default to no power saving. */
    	uint8_t power_mode = NRF_MODEM_GNSS_PSM_DISABLED;
    
    #if defined(CONFIG_GNSS_SAMPLE_POWER_SAVING_MODERATE)
    	power_mode = NRF_MODEM_GNSS_PSM_DUTY_CYCLING_PERFORMANCE;
    #elif defined(CONFIG_GNSS_SAMPLE_POWER_SAVING_HIGH)
    	power_mode = NRF_MODEM_GNSS_PSM_DUTY_CYCLING_POWER;
    #endif
    
    	if (nrf_modem_gnss_power_mode_set(power_mode) != 0) {
    		LOG_ERR("Failed to set GNSS power saving mode");
    		return -1;
    	}
    #endif /* CONFIG_GNSS_SAMPLE_MODE_CONTINUOUS */
    
    	/* Default to continuous tracking. */
    	uint16_t fix_retry = 0;
    	uint16_t fix_interval = 1;
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_PERIODIC)
    	fix_retry = CONFIG_GNSS_SAMPLE_PERIODIC_TIMEOUT;
    	fix_interval = CONFIG_GNSS_SAMPLE_PERIODIC_INTERVAL;
    #elif defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	/* Single fix for TTFF test mode. */
    	fix_retry = 0;
    	fix_interval = 0;
    #endif
    
    	if (nrf_modem_gnss_fix_retry_set(fix_retry) != 0) {
    		LOG_ERR("Failed to set GNSS fix retry");
    		return -1;
    	}
    
    	if (nrf_modem_gnss_fix_interval_set(fix_interval) != 0) {
    		LOG_ERR("Failed to set GNSS fix interval");
    		return -1;
    	}
    
    #if defined(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)
    	k_work_schedule_for_queue(&gnss_work_q, &ttff_test_prepare_work, K_NO_WAIT);
    #else /* !CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST */
    	if (nrf_modem_gnss_start() != 0) {
    		LOG_ERR("Failed to start GNSS");
    		return -1;
    	}
    #endif
    
    	return 0;
    }
    
    static bool output_paused(void)
    {
    #if defined(CONFIG_GNSS_SAMPLE_ASSISTANCE_NONE) || defined(CONFIG_GNSS_SAMPLE_LOG_LEVEL_OFF)
    	return false;
    #else
    	return (requesting_assistance || assistance_is_active()) ? true : false;
    #endif
    }
    
    static void print_satellite_stats(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	uint8_t tracked   = 0;
    	uint8_t in_fix    = 0;
    	uint8_t unhealthy = 0;
    
    	for (int i = 0; i < NRF_MODEM_GNSS_MAX_SATELLITES; ++i) {
    		if (pvt_data->sv[i].sv > 0) {
    			tracked++;
    
    			if (pvt_data->sv[i].flags & NRF_MODEM_GNSS_SV_FLAG_USED_IN_FIX) {
    				in_fix++;
    			}
    
    			if (pvt_data->sv[i].flags & NRF_MODEM_GNSS_SV_FLAG_UNHEALTHY) {
    				unhealthy++;
    			}
    		}
    	}
    
    	printf("Tracking: %2d Using: %2d Unhealthy: %d\n", tracked, in_fix, unhealthy);
    }
    
    static void print_flags(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_DEADLINE_MISSED) {
    		printf("GNSS operation blocked by LTE\n");
    	}
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_NOT_ENOUGH_WINDOW_TIME) {
    		printf("Insufficient GNSS time windows\n");
    	}
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_SLEEP_BETWEEN_PVT) {
    		printf("Sleep period(s) between PVT notifications\n");
    	}
    	if (pvt_data->flags & NRF_MODEM_GNSS_PVT_FLAG_SCHED_DOWNLOAD) {
    		printf("Scheduled navigation data download\n");
    	}
    }
    
    static void print_fix_data(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	printf("Latitude:          %.06f\n", pvt_data->latitude);
    	printf("Longitude:         %.06f\n", pvt_data->longitude);
    	printf("Accuracy:          %.01f m\n", (double)pvt_data->accuracy);
    	printf("Altitude:          %.01f m\n", (double)pvt_data->altitude);
    	printf("Altitude accuracy: %.01f m\n", (double)pvt_data->altitude_accuracy);
    	printf("Speed:             %.01f m/s\n", (double)pvt_data->speed);
    	printf("Speed accuracy:    %.01f m/s\n", (double)pvt_data->speed_accuracy);
    	printf("V. speed:          %.01f m/s\n", (double)pvt_data->vertical_speed);
    	printf("V. speed accuracy: %.01f m/s\n", (double)pvt_data->vertical_speed_accuracy);
    	printf("Heading:           %.01f deg\n", (double)pvt_data->heading);
    	printf("Heading accuracy:  %.01f deg\n", (double)pvt_data->heading_accuracy);
    	printf("Date:              %04u-%02u-%02u\n",
    	       pvt_data->datetime.year,
    	       pvt_data->datetime.month,
    	       pvt_data->datetime.day);
    	printf("Time (UTC):        %02u:%02u:%02u.%03u\n",
    	       pvt_data->datetime.hour,
    	       pvt_data->datetime.minute,
    	       pvt_data->datetime.seconds,
    	       pvt_data->datetime.ms);
    // 	printf("PDOP:              %.01f\n", (double)pvt_data->pdop);
    // 	printf("HDOP:              %.01f\n", (double)pvt_data->hdop);
    // 	printf("VDOP:              %.01f\n", (double)pvt_data->vdop);
    // 	printf("TDOP:              %.01f\n", (double)pvt_data->tdop);
     }
    
    int main(void)
    {
    	int err;
    	uint8_t cnt = 0;
    	struct nrf_modem_gnss_nmea_data_frame *nmea_data;
    
    	LOG_INF("Starting GNSS sample");
    
    	err = nrf_modem_lib_init();
    	if (err) {
    		LOG_ERR("Modem library initialization failed, error: %d", err);
    		return err;
    	}
    
    	/* Initialize reference coordinates (if used). */
    	if (sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE) > 1 &&
    	    sizeof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE) > 1) {
    		ref_used = true;
    		ref_latitude = atof(CONFIG_GNSS_SAMPLE_REFERENCE_LATITUDE);
    		ref_longitude = atof(CONFIG_GNSS_SAMPLE_REFERENCE_LONGITUDE);
    	}
    
    	if (modem_init() != 0) {
    		LOG_ERR("Failed to initialize modem");
    		return -1;
    	}
    
    	if (sample_init() != 0) {
    		LOG_ERR("Failed to initialize sample");
    		return -1;
    	}
    
    	if (gnss_init_and_start() != 0) {
    		LOG_ERR("Failed to initialize and start GNSS");
    		return -1;
    	}
    
    	fix_timestamp = k_uptime_get();
    
    	for (;;) {
    		(void)k_poll(events, 2, K_FOREVER);
    
    		if (events[0].state == K_POLL_STATE_SEM_AVAILABLE &&
    		    k_sem_take(events[0].sem, K_NO_WAIT) == 0) {
    			/* New PVT data available */
    
    			if (IS_ENABLED(CONFIG_GNSS_SAMPLE_MODE_TTFF_TEST)) {
    				/* TTFF test mode. */
    
    				/* Calculate the time GNSS has been blocked by LTE. */
    				if (last_pvt.flags & NRF_MODEM_GNSS_PVT_FLAG_DEADLINE_MISSED) {
    					time_blocked++;
    				}
    			} else if (IS_ENABLED(CONFIG_GNSS_SAMPLE_NMEA_ONLY)) {
    				/* NMEA-only output mode. */
    
    				if (output_paused()) {
    					goto handle_nmea;
    				}
    
    				if (last_pvt.flags & NRF_MODEM_GNSS_PVT_FLAG_FIX_VALID) {
    					print_distance_from_reference(&last_pvt);
    				}
    			} else {
    				/* PVT and NMEA output mode. */
    
    				if (output_paused()) {
    					goto handle_nmea;
    				}
    
    				printf("\033[1;1H");
    				printf("\033[2J");
    				print_satellite_stats(&last_pvt);
    				print_flags(&last_pvt);
    				printf("-----------------------------------\n");
    
    				if (last_pvt.flags & NRF_MODEM_GNSS_PVT_FLAG_FIX_VALID) {
    					fix_timestamp = k_uptime_get();
    					print_fix_data(&last_pvt);
    					print_distance_from_reference(&last_pvt);
    				} else {
    					printf("Seconds since last fix: %d\n",
    					       (uint32_t)((k_uptime_get() - fix_timestamp) / 1000));
    					cnt++;
    					printf("Searching [%c]\n", update_indicator[cnt%4]);
    				}
    
    				printf("\nNMEA strings:\n\n");
    			}
    		}
    
    handle_nmea:
    		if (events[1].state == K_POLL_STATE_MSGQ_DATA_AVAILABLE &&
    		    k_msgq_get(events[1].msgq, &nmea_data, K_NO_WAIT) == 0) {
    			/* New NMEA data available */
    
    			if (!output_paused()) {
    				printf("%s", nmea_data->nmea_str);
    			}
    			k_free(nmea_data);
    		}
    
    		events[0].state = K_POLL_STATE_NOT_READY;
    		events[1].state = K_POLL_STATE_NOT_READY;
    	}
    
    	return 0;
    }
    

    #
    # Copyright (c) 2019 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    # Enable RTT Console and Logging
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_UART=n
    
    # General
    CONFIG_FPU=y
    CONFIG_NRF_MODEM_LIB=y
    CONFIG_STDOUT_CONSOLE=y
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_PICOLIBC_IO_FLOAT=y
    CONFIG_LOG=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    
    # GNSS sample
    # Enable to use nRF Cloud A-GNSS
    CONFIG_NRF_CLOUD=y
    CONFIG_GNSS_SAMPLE_ASSISTANCE_NRF_CLOUD=n
    
    # LTE Link Control
    CONFIG_LTE_LINK_CONTROL=y
    # Request eDRX from the network
    CONFIG_LTE_LC_EDRX_MODULE=y
    CONFIG_LTE_EDRX_REQ=y
    # PSM requested periodic TAU 8 hours
    CONFIG_LTE_LC_PSM_MODULE=y
    CONFIG_LTE_PSM_REQ_RPTAU="00101000"
    # PSM requested active time 6 seconds
    CONFIG_LTE_PSM_REQ_RAT="00000011"
    
    # AT Host library - Used to send AT commands directy from an UART terminal and to allow
    #		    integration with nRF Connect for Desktop LTE Link monitor application.
    CONFIG_AT_HOST_LIBRARY=y
    
    # Networking
    CONFIG_NETWORKING=y
    CONFIG_NET_SOCKETS_OFFLOAD=y
    CONFIG_NET_SOCKETS=y
    CONFIG_POSIX_API=y
    # Disable native network stack to save some memory
    CONFIG_NET_NATIVE=n
    
    # Memory and stack configuration
    CONFIG_HEAP_MEM_POOL_SIZE=2048
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1536
    

    Best regards,
    Arun

  • Hi Arun,

    I am testing the GNSS sample from nRF Connect SDK v3.0.0.
    When I flash and run the firmware, I see the following output in RTT Viewer:
    Arun538 said:
    I’ve attached my main.c and prj.conf files — could you please check and let me know if anything is missing or needs to be modified?

    I have tested GNSS application with your main.c file in NCS v3.0.0. I got build error when using your main.c file but building worked fine when using main.c from GNSS sample. You could try to look for any changes between unmodified sample and your application.

    Arun538 said:
    I uploaded the firmware to my custom board using the nRF9151 DK as a programmer.
    Arun538 said:
    I’m using the nRF52 DK as a programmer to flash my nRF9151 board.

    Which device did you use for programming?

    Best regards,
    Dejan

Related