Ubxlib GNSS Sample

Overview

A sample application demonstrating how to integrate a u-blox GNSS device into a Zephyr application. The example code is rigidly configured to work with an u-blox M10 device [1]. It was tested with the SparkFun MAX-M10S Breakout [2].

Requirements

The u-blox GNSS device must be connected via UART, and a Devicetree alias ubxlib-uart0 must exist that point towards this UART port. Also a single GPIO line for the module reset signal have to define. To fulfil this requirement, this sample application comes with a generic application overlay app.overlay that should be usable with all boards that provies an Arduino UNO R3 edge connector. For ubxlib-uart0 the standard Arduino UART on D0 (RX) and D1 (TX) will be used (&arduino_serial). The reset signal will be controlled by D8 (GPIO) and is mapped to <&arduino_header 14 /*…*/>. To ensure to use the correct GPIO line for the module reset signal, the example provides the only locally usable Devicetree binding reset-switch.yaml. This specifies the Devicetree compatibility string reset-switch.

Default application overlay

Binding for the module reset signal

app.overlay
/ {
	reset_switch: reset_switch {
		compatible = "reset-switch";
		gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>;
	};

	aliases {
		ubxlib-uart0 = &arduino_serial;
	};
};

&arduino_serial {
	status = "okay";
	current-speed = <9600>;
};
reset-switch.yaml
description: GPIO pin to cause a reset on an external device

compatible: "reset-switch"

properties:
  gpios:
    type: phandle-array
    required: true
    description: |
      The GPIO pin connected to a reset switch.

Regardless of this, it is still free and open to use a specific board overlay to adapt these default settings to other hardware conditions.

Building and Running

Build and flash for different boards

Nordic nRF9160 DK (nRF9160)

west build -b nrf9160dk/nrf9160 -p -d build/nrf9160dk_nrf9160-ubx_gnss bridle/samples/ubx_gnss
west flash -d build/nrf9160dk_nrf9160-ubx_gnss

Nordic nRF52840 DK (nRF52840)

west build -b nrf52840dk/nrf52840 -p -d build/nrf52840dk_nrf52840-ubx_gnss bridle/samples/ubx_gnss
west flash -d build/nrf52840dk_nrf52840-ubx_gnss

ST Nucleo L496ZG

west build -b nucleo_l496zg -p -d build/nucleo_l496zg-ubx_gnss bridle/samples/ubx_gnss
west flash -d build/nucleo_l496zg-ubx_gnss

ST Nucleo F413ZH

west build -b nucleo_f413zh -p -d build/nucleo_f413zh-ubx_gnss bridle/samples/ubx_gnss
west flash -d build/nucleo_f413zh-ubx_gnss

ST Nucleo F767ZI

west build -b nucleo_f767zi -p -d build/nucleo_f767zi-ubx_gnss bridle/samples/ubx_gnss
west flash -d build/nucleo_f767zi-ubx_gnss

NXP MIMXRT1170-EVKB (CM7)

west build -b mimxrt1170_evk@B/mimxrt1176/cm7 -p -d build/mimxrt1170_evkb_cm7-ubx_gnss bridle/samples/ubx_gnss
west flash -r pyocd -d build/mimxrt1170_evkb_cm7-ubx_gnss

NXP MIMXRT1060-EVK

west build -b mimxrt1060_evk -p -d build/mimxrt1060_evk-ubx_gnss bridle/samples/ubx_gnss
west flash -r pyocd -d build/mimxrt1060_evk-ubx_gnss

NXP MIMXRT1010-EVK (experimental)

west build -b mimxrt1010_evk -p -S usb-console -d build/mimxrt1010_evk-ubx_gnss bridle/samples/ubx_gnss -- -DCONFIG_LOG=n
west flash -r pyocd -d build/mimxrt1010_evk-ubx_gnss

Warning

This board requires special care when using and maintaining the code base. First of all, there is a lack of sufficient UART interfaces. The user must decide whether he wants to use the one available LPUART1 as a console via the on-board debug adapter (the factory default) or whether he needs it for his own purposes on the Arduino edge connector. For this example, the later is the case and it is extremely important that the two jumpers JP31 for TX and JP32 for RX are removed so that there is no longer an active connection to the on-board debug adapter (isolation). This also removes the channel for the standard console and the on-board USB device at J9 must be used as an alternative. This in turn means that Zephyr needs the USB device software stack with the USB-CDC/ACM class driver for VCOM access to the shell enabled. Note the west build parameter -S usb-console.

It is more luck than sense that this example works on this extremely poorly equipped board. The word “works” should also not be overrated. The ubxlib software stack is extremely memory-intensive and requires at least 16 kB RAM for the memory heap (CONFIG_HEAP_MEM_POOL_SIZE). That alone is already 25% of the available RAM in this system. Together with the necessary USB device software stack and the USB-CDC/ACM class driver, there is hardly anything left for additional functions. This means that the Zephyr shell can only be used in the absolute minimum configuration (CONFIG_SHELL_MINIMAL=y) and the Zephyr logging system must be omitted completely (CONFIG_LOG=n). The CMake parameter -DCONFIG_LOG=n must be considered for this when calling west build.

As a result of the limited memory capacity, important runtime stacks must also be reduced. That are in summary:

Board specific configuration

Context and meaning

boards/mimxrt1010_evk.conf
CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_MAIN_STACK_SIZE=3456
CONFIG_ISR_STACK_SIZE=1024
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512
CONFIG_USB_WORKQUEUE_STACK_SIZE=512
CONFIG_USB_CDC_ACM_RINGBUF_SIZE=512
Dynamic Memory Pool:
left on 16384
Main Context:
from 4096 to 3456
Interrupt Serive Routines:
from 2048 to 1024
System Worker Queue:
USB-CDC/ACM Worker Queue:
from 1024 to 512
USB-CDC/ACM Ring Buffer:
from 1024 to 512

With this heuristically determined memory configuration, the main functions of this “simple” example can be used. One exception is the shell command gnss single. The subsequent function call stack may grow to a point where the reduced ISR or main stack overflows and, in the absence of further Zephyr functionality, the CPU simply stops in a critical exception – with no visible notification to the user. This is a very dynamic effect and difficult to predict, but it happens very often.

Example console session

After power-on or hard reset, the GNSS module will be initialized automatically:

*** Booting Zephyr OS build v3.7.0 ***
[00:00:02.021,000] <inf> main: GNSS Device is ready!
uart:~$ _

There is a simple Shell command for some standard evaluation steps:

uart:~$ gnss -h
gnss - GNSS related commands
Subcommands:
  single  :Get a one-shot position estimate
  stream  :Start or stop streaming of position estimates
  reset   :Reset GNSS module
  ttff    :Measure TTFF
uart:~$ _

Reset GNSS module:

uart:~$ gnss reset
uart:~$ _

The on-module LED for PPS signaling goes off and comes back to blink after TTFF.

Measure TTFF:

uart:~$ gnss ttff
Run 1 of 1: Acquired fix after 32.26s
---------------
Avg. TTFF: 32.26
uart:~$ _

The on-module LED for PPS signaling goes off and comes back to blink after TTFF.

It is also possible to run several TTFF measurements sequentially. If there is also a good receiving range and a reliable position already exists, the TTFF will be correspondingly low:

uart:~$ gnss ttff 10
Run 1 of 10: Acquired fix after 0.23s
Run 2 of 10: Acquired fix after 0.79s
Run 3 of 10: Acquired fix after 1.00s
Run 4 of 10: Acquired fix after 0.59s
Run 5 of 10: Acquired fix after 0.81s
Run 6 of 10: Acquired fix after 0.79s
Run 7 of 10: Acquired fix after 0.80s
Run 8 of 10: Acquired fix after 1.01s
Run 9 of 10: Acquired fix after 0.58s
Run 10 of 10: Acquired fix after 0.81s
---------------
Avg. TTFF: 0.74
uart:~$ _

Get a one-shot position estimate:

uart:~$ gnss single
Found position estimate after 0.8s: (lat, lon): (50.922432, 11.600015), alt: 192.05m, radius: 1.48m (15 SV used)
uart:~$ _

Start or stop streaming of position estimates:

uart:~$ gnss stream start
[00:01:15.687,000] <inf> main: Found position estimate: (lat, lon): (50.922447, 11.600006), alt: 192.64m, radius: 1.45m (17 SV used)
[00:01:16.692,000] <inf> main: Found position estimate: (lat, lon): (50.922451, 11.600005), alt: 192.53m, radius: 1.45m (18 SV used)
[00:01:17.697,000] <inf> main: Found position estimate: (lat, lon): (50.922451, 11.600004), alt: 192.63m, radius: 1.45m (18 SV used)
[00:01:18.904,000] <inf> main: Found position estimate: (lat, lon): (50.922455, 11.600004), alt: 192.71m, radius: 1.46m (17 SV used)
[00:01:19.658,000] <inf> main: Found position estimate: (lat, lon): (50.922455, 11.600004), alt: 192.80m, radius: 1.46m (18 SV used)
[00:01:20.663,000] <inf> main: Found position estimate: (lat, lon): (50.922455, 11.600004), alt: 192.96m, radius: 1.46m (18 SV used)
[00:01:21.667,000] <inf> main: Found position estimate: (lat, lon): (50.922455, 11.600003), alt: 192.89m, radius: 1.46m (18 SV used)
[00:01:22.722,000] <inf> main: Found position estimate: (lat, lon): (50.922459, 11.600002), alt: 192.79m, radius: 1.47m (17 SV used)
[00:01:23.929,000] <inf> main: Found position estimate: (lat, lon): (50.922459, 11.600001), alt: 192.92m, radius: 1.47m (18 SV used)
[00:01:24.683,000] <inf> main: Found position estimate: (lat, lon): (50.922462, 11.600000), alt: 192.89m, radius: 1.48m (17 SV used)
[00:01:25.688,000] <inf> main: Found position estimate: (lat, lon): (50.922462, 11.599999), alt: 192.77m, radius: 1.48m (18 SV used)
[00:01:26.693,000] <inf> main: Found position estimate: (lat, lon): (50.922466, 11.599998), alt: 192.69m, radius: 1.48m (18 SV used)
[00:01:27.697,000] <inf> main: Found position estimate: (lat, lon): (50.922466, 11.599996), alt: 192.49m, radius: 1.50m (18 SV used)
uart:~$ gnss stream stop
[00:01:28.905,000] <inf> main: Found position estimate: (lat, lon): (50.922470, 11.599995), alt: 192.22m, radius: 1.50m (18 SV used)
[00:01:29.709,000] <inf> main: Found position estimate: (lat, lon): (50.922470, 11.599994), alt: 192.12m, radius: 1.50m (18 SV used)
uart:~$ _

References