How to Control LTE with the Nordic nRF9160 and Golioth

The Nordic nRF9160 is a fantastic solution for cellular connectivity. All of the Golioth sample code runs on the nRD9160-DK without any changes to configuration so you can test out all of our features. But eventually you’re going to start scratching your head about how the LTE connection works. This is especially true because the device will do nothing while first establishing the connection, which can take over one minute depending on your network. The answer is to use the LTE link controller library.

Using Automatic LTE Control

The Nordic nRF Connect SDK (based on Zephyr) makes it really easy to automatically connect to LTE. Simply put, there’s a Kconfig symbol that causes the modem to connect to the cellular network when the device powers up:


While this takes care of the connection, it does so before main() begins running, and it blocks program execution until the network is connected. That can take more than a minute and depends on things like your distance to your closest tower and the strength of the signal in your office. Since you can’t write log messages, toggle LEDs, or write to a screen, it can look to a user like the device is stuck.

For battery-controlled devices you want to carefully control when the radio is on and when it is off. In this case, automatic control is usually not an option.

Using Manual LTE Control

Nordic’s docs for the LTE link controller are fantastic, you should spend the time to read through them. We’ll discuss the most basic form of link control: manually establishing a connection.

To use the link controller, first select the library using Kconfig:


Then include the library in your c file:

#include <modem/lte_lc.h>

We can now start using the link controller functions. For me, the most interesting ones are the async functions. For instance:

int err;

//Initalize the modem and connect to the network (register a callback)
err = lte_lc_init_and_connect_async(lte_handler);

/* Do some things on the network */

//Place the modem in offline mode
err = lte_lc_offline();

/* Do some offline things */

//Modem already initialized, just reconnect again
err = lte_lc_connect_async(lte_handler);

Notice that lines 4 and 14 register a callback. Nordic has a nice example of what that callback should look like:

/* Semaphore used to block the main thread until the link controller has
 * established an LTE connection.
K_SEM_DEFINE(lte_connected, 0, 1);

static void lte_handler(const struct lte_lc_evt *const evt)
     switch (evt->type) {
             if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) &&
             (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) {

             printk("Connected to: %s network\n",
             evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ? "home" : "roaming");

             /* Callback events carrying LTE link data */

Also notice that they recommend using a semaphore. Because this runs asynchronously, checking this semaphore is a good way for the rest of your code to know if an LTE connection has been established.

Considerations when Using Golioth with Manual Control

Golioth depends on a network connection. When you manually control the network, you should also take Golioth into consideration. You need to wait until LTE has been connected to start the Golioth System Client. A good place to do this is in the callback:

    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. Starting Golioth System Client...");



Before going offline or putting the modem into a sleep mode it is recommended that you stop the Golioth client:


Calls to Golioth services (LightDB State, LightDB Stream, etc.) will cause errors if the client is not connected. You may choose simply to ignore the errors in the serial terminal, however, gating those function calls with a semaphore is another option.

For applications that utilize an intermittent network connection, we like using message queues to cache data. Timestamps may be added to each reading so that the data is properly recorded the next time a connection is available. We have previously discussed using Zephyr message queues for this purpose.


Automatic LTE control is great for trying out demo code. However, we think in most applications you’ll want to decide when and how to use the modem. Luckily, for this particular SIP, Nordic has made the control library really easy to use.

Do you have questions about cellular modem control with your IoT fleets? We’d love to hear from you! Open a new thread on the Golioth Forum, or set up a video call with our Developer Relations crew to discuss your use case.

Talk with an Expert

Implementing an IoT project takes a team of people, and we want to help out as part of your team. If you want to troubleshoot a current problem or talk through a new project idea, we're here for you.

Notable Replies

  1. Hey @arquiteturadecomputa, welcome to the forum!

    In the US (where I’m based), almost all of the 2G/3G has been sunset. This article takes a look at the sunsetting in different regions, but it will depend on your particular carrier.

    The nRF9160 is a CatM1/NB-IOT modem, without 2G fallback. Some modems in the low power CatM1 space do have 2G fallback, but Nordic is clear in their spec that there is no fallback capabiilities.

    Are you targeting a specific region of the world?

  2. Hi, i am Miguel , teacher
    We are writing project where the partner are University a local Company that make with Water Data Collect in Brazil.
    Today they use 2G,3G GPRS to collect data from Remote Cities.
    I see that NRF9160 and Golioth is good choice…but…will work in Remote Cities ? May i can convince them to forget 2G,3G GPRS and going to CATm1/Nbiot and make integration with Golioth
    What do you think about this Brazil ? Have you clients using NF9160 here ?

  3. What do you think about this Brazil ? Have you clients using NF9160 here?

    In fact some of our wonderful developers live in Brazil!

    The key thing will be coverage from a particular SIM provider to make sure they have coverage in the remote cities. The rollout of Cat M1 and NB-IOT is consistently increasing, but there’s no way to know unless you have a coverage map from your local provider.

    Our friend Joao from BP&M has been doing a bunch of work with the nRF9160, I’ll forward this thread to him to see if he has more insight. They are a local support resource in Brazil because I don’t believe Nordic doesn’t have a direct company resource in the country. We have done work with him in the past and he’s a really great engineer.

    There are also 3rd party resources that share coverage maps, like this: 5G coverage map worldwide - nPerf.com

    I would suggest choosing a local data / SIM provider and checking with them, as they will have the most up to date coverage. Then if you find an MNO (such as Claro, TIM, Vivo, Oi, etc) that has coverage you think will work for your application, then you could see if an MVNO (which often has coverage from multiple carriers) supports the MNO that you like. I know this isn’t a great answer to your question, but because it comes down to the providers in a region, it really makes sense to spend the time researching this up front to make sure you get the service you need.

Continue the discussion at forum.golioth.io

5 more replies


Avatar for ChrisGammell Avatar for mike Avatar for joaodullius Avatar for arquiteturadecomputa