GPS 1PPS on nRF9151 DK

Hello, my application requires very precise timing to trigger an action on the edge of the GPS time. I just need to get this time once in a while to synchronize the system, and afterwards, I can trigger a timer interrupt every 1s following the event of the GPS time trigger. After some time searching in the documentation, I found that the nRF9151 DK has a COEX1 interface, quoting from these 2 sources (source 1 and source 2):

COEX1 – Output from the LTE modem to the external device. When internal GPS is used, COEX1 delivers the GPS 1PPS (one pulse per second) time mark pulse. The 1PPS feature must not be used when LTE is enabled.

I'm trying to find a way to access GPS PPS signal, but unsure how. The closest forum post I found is this: https://devzone.nordicsemi.com/f/nordic-q-a/75137/getting-access-to-the-gps-pps-signal-on-the-nrf9160, but the question is about nRF9160 and it's over 2 years old, so I'm not sure if this is still relevant for the new nRF9151 DK. From this document, it seems that I can configure 1PPS, but I don't know how to get this. Is it via an interrupt? Do I need to make any hardware wiring? I'd appreciate it if there is a sample application or general guidance on how to approach it. Thank you.

  • Hello,

    it should be possible to enable this on the nrf9151. Check out this part of the documentation.

    1PPS can be accessed on the COEX1 pin on the nrf9151, P24 pin2 on the DK. You should read the details about the COEX interface. Also, importantly make sure that LTE is disabled during 1PPS operation on COEX1.

    I was unfortunately not able to find a proper sample for this.

  • Hi Hakon, thank you for your response. These are the sources I linked in my original question as well. My confusion is how to use the COEX1 pin? Since the document said this is an output pin, I can wire it back to the GPIO and treat it as an interrupt? Is there a way for the DK to automatically know this without any additional wiring (such as enabling some Kconfig option)?

  • Yun531 said:
    Since the document said this is an output pin, I can wire it back to the GPIO and treat it as an interrupt? Is there a way for the DK to automatically know this without any additional wiring (such as enabling some Kconfig option)?

    Yes, you can use GPIO pin on your host MCU and configure an interrupt to know when activity occurs. That seems like the best option as far as I am concerned.

    Yun531 said:
    Is there a way for the DK to automatically know this without any additional wiring (such as enabling some Kconfig option)?

    I don't know how that would be possible.

  • Hi,

    If there is no sample for using the COEX1, is there any sample or general guide on how to enable and disable LTE manually?

    I'm currently working through the Cellular IoT Fundamentals course and so far, the exercises for LTE and GNSS to be active at the same time is enable GNSS when the LTE is in power saving mode (Lesson 6 exercise 2). My SIM does not support PSM or eDRX, and here's a note from the lesson:

    If your network operator and/or SIM card does not support either PSM nor eDRX, you will have to manually deactivate and activate the modem when wanting to use the GNSS in your application. There is a workaround, by giving the GNSS priority over LTE events to help get a fix. This is not recommended, as it interferes with LTE operations.

    Could you help me with this? Especially, there is a "keep alive" while true loop in main, I'm unsure on how to manually deactivate/activate the modem in conjunction with this loop.

    If helpful, here are the links that I refered to:

    GNSS Lesson 6 Exercise

  • I tried to enable 1PPS but I have no luck so far. 

    I followed one of the sample from Nordic Cellular IoT Course (Lesson 6 Exercise 1) to enable GPS only. I use the same code as this exercise, and I added 1 PPS:

    /* 1PPS pulse on COEX1 */
    struct nrf_modem_gnss_1pps_config config = {
        .pulse_interval = 120,
        .pulse_width = 500,
        .apply_start_time = false
    };
    
    /* In main right before nrf_modem_gnss_start */
    err = nrf_modem_gnss_1pps_enable(&config);
    if (err != 0) {
        LOG_ERR("Failed to enable 1 PPS, error %d", err);
        return -1;
    }
    
    

    I attached the main.c file here as well.

    /*
     * Copyright (c) 2022 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <stdio.h>
    #include <ncs_version.h>
    #include <zephyr/kernel.h>
    
    #include <zephyr/logging/log.h>
    #include <modem/nrf_modem_lib.h>
    #include <modem/lte_lc.h>
    #include <dk_buttons_and_leds.h>
    
    /* STEP 4 - Include the header file for the GNSS interface */
    #include <nrf_modem_gnss.h>
    
    /* 1PPS pulse on COEX1 */
    struct nrf_modem_gnss_1pps_config config = {
        .pulse_interval = 120,
        .pulse_width = 500,
        .apply_start_time = false
    };
    
    /* STEP 5 - Define the PVT data frame variable */
    static struct nrf_modem_gnss_pvt_data_frame pvt_data;
    
    /* STEP 12.1 - Declare helper variables to find the TTFF */
    static int64_t gnss_start_time;
    static bool first_fix = false;
    
    static K_SEM_DEFINE(lte_connected, 0, 1);
    
    LOG_MODULE_REGISTER(Lesson6_Exercise1, LOG_LEVEL_INF);
    
    
    static int modem_configure(void)
    {
    	int err;
    
    	LOG_INF("Initializing modem library");
    
    	err = nrf_modem_lib_init();
    	if (err) {
    		LOG_ERR("Failed to initialize the modem library, error: %d", err);
    		return err;
    	}
    
    	return 0;
    }
    
    /* STEP 6 - Define a function to log fix data in a readable format */
    static void print_fix_data(struct nrf_modem_gnss_pvt_data_frame *pvt_data)
    {
    	LOG_INF("Latitude:       %.06f", pvt_data->latitude);
    	LOG_INF("Longitude:      %.06f", pvt_data->longitude);
    	LOG_INF("Altitude:       %.01f m", (double)pvt_data->altitude);
    	LOG_INF("Time (UTC):     %02u:%02u:%02u.%03u",
    	       pvt_data->datetime.hour,
    	       pvt_data->datetime.minute,
    	       pvt_data->datetime.seconds,
    	       pvt_data->datetime.ms);
    }
    
    
    static void gnss_event_handler(int event)
    {
    	int err;
    
    	switch (event) {
    	/* STEP 7 - On a PVT event, confirm if PVT data is a valid fix */
    	case NRF_MODEM_GNSS_EVT_PVT:
    		LOG_INF("Searching...");
    		/* STEP 15 - Print satellite information */
    		int num_satellites = 0;
    		for (int i = 0; i < 12 ; i++) {
    			if (pvt_data.sv[i].signal != 0) {
    				LOG_INF("sv: %d, cn0: %d, signal: %d", pvt_data.sv[i].sv, pvt_data.sv[i].cn0, pvt_data.sv[i].signal);
    				num_satellites++;
    			}
    		}
    		LOG_INF("Number of current satellites: %d", num_satellites);
    		err = nrf_modem_gnss_read(&pvt_data, sizeof(pvt_data), NRF_MODEM_GNSS_DATA_PVT);
    		if (err) {
    			LOG_ERR("nrf_modem_gnss_read failed, err %d", err);
    			return;
    		}
    		if (pvt_data.flags & NRF_MODEM_GNSS_PVT_FLAG_FIX_VALID) {
    			dk_set_led_on(DK_LED1);
    			print_fix_data(&pvt_data);
    			/* STEP 12.3 - Print the time to first fix */
    			if (!first_fix) {
    				LOG_INF("Time to first fix: %2.1lld s", (k_uptime_get() - gnss_start_time)/1000);
    				first_fix = true;
    			}
    			return;
    		}
    		break;
    	/* STEP 7.2 - Log when the GNSS sleeps and wakes up */
    	case NRF_MODEM_GNSS_EVT_PERIODIC_WAKEUP:
    		LOG_INF("GNSS has woken up");
    		break;
    	case NRF_MODEM_GNSS_EVT_SLEEP_AFTER_FIX:
    		LOG_INF("GNSS enter sleep after fix");
    		break;
    	default:
    		break;
    	}
    }
    
    int main(void)
    {
    	int err;
    
    	if (dk_leds_init() != 0) {
    		LOG_ERR("Failed to initialize the LEDs Library");
    	}
    
    	err = modem_configure();
    	if (err) {
    		LOG_ERR("Failed to configure the modem");
    		return 0;
    	}
    
    	/* STEP 8 - Activate only the GNSS stack */
    	if (lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_GNSS) != 0) {
    		LOG_ERR("Failed to activate GNSS functional mode");
    		return 0;
    	}
    
    	/* STEP 9 - Register the GNSS event handler */
    	if (nrf_modem_gnss_event_handler_set(gnss_event_handler) != 0) {
    		LOG_ERR("Failed to set GNSS event handler");
    		return 0;
    	}
    
    	/* STEP 10 - Set the GNSS fix interval and GNSS fix retry period */
    	if (nrf_modem_gnss_fix_interval_set(CONFIG_GNSS_PERIODIC_INTERVAL) != 0) {
    		LOG_ERR("Failed to set GNSS fix interval");
    		return 0;
    	}
    
    	if (nrf_modem_gnss_fix_retry_set(CONFIG_GNSS_PERIODIC_TIMEOUT) != 0) {
    		LOG_ERR("Failed to set GNSS fix retry");
    		return 0;
    	}
    
        err = nrf_modem_gnss_1pps_enable(&config);
        if (err != 0) {
            LOG_ERR("Failed to enable 1 PPS, error %d", err);
            return -1;
        }
    
    	/* STEP 11 - Start the GNSS receiver*/
    	LOG_INF("Starting GNSS");
    	if (nrf_modem_gnss_start() != 0) {
    		LOG_ERR("Failed to start GNSS");
    		return 0;
    	}
    
    	/* STEP 12.2 - Log the current system uptime */
    	gnss_start_time = k_uptime_get();
    
    	return 0;
    }

    I'm able to get a fix from GPS, but the COEX1 pin is not pulsing. I open the board configurator and enable this option:

    Then I connect the COEX1 pin from the nRF9151 DK to the oscilloscope, and there is no pulse. I don't know what I'm supposed to do to make the COEX1 pin to start pulsing. Any suggestions or help would be greatly appreciated. Thank you.

Related