If you are having issues with the exercises, please create a ticket on DevZone:
Click or drag files to this area to upload. You can upload up to 2 files.

Exercise 2

In this exercise, let’s use the LTE Link Controller library in nRF Connect SDK to establish the LTE connection. One advantage of using a high-level library instead of direct serial communication commands is that the library lets you asynchronously set up the LTE connection, which is what we will do in this exercise.

Exercise Steps

1. Open the base exercise code for this exercise in VS Code.

1.1 Clone the GitHub repository for this course.

Copy the link to the repository and use VS Code’s Command Palette to clone the repository.

1.2 In the nRF Connect for VS Code extension, select Open an existing application, and open the base code for this exercise, found in cell-fund/<version>/lesson2/cellfund_less2_exer2, of whichever version directory you are using (v2.2.0-v2.3.0 or v2.4.0-v2.x.x).

Due to changes in nRF Connect SDK, make sure to use the correct version folder of the base code, either v2.2.0-v2.3.0 or v2.4.0-v2.x.x, or you will get errors when building.


The nRF9161 DK is only supported with nRF Connect SDK v2.5.0 and higher.

2. Enable the nRF Modem library.

Search for STEP 2 in prj.conf and add the following line:

More on this

The nRF Modem Library is the library that interfaces with the nRF9160 modem and is necessary for the LTE link controller library to run. We will talk more about the nRF Modem Library in lesson 3, but for now we will just enable it in our application.

3. Enable and configure the LTE link controller library.

Search for STEP 3 in prj.conf and add the following lines

v2.4.0 – v2.x.x
v2.2.0 – v2.3.0

CONFIG_LTE_LINK_CONTROL enables the library and CONFIG_LTE_AUTO_INIT_AND_CONNECT disables the auto initialize and connect functionality.

4. Include the relevant header files.

v2.4.0 – v2.x.x

Include the header file for the nRF Modem library and the LTE link controller library.

In the main.c file, search for STEP 4 and add the following line

#include <modem/nrf_modem_lib.h>
#include <modem/lte_lc.h>
v2.2.0 – v2.3.0

Include the header file for the LTE link controller library.

In the main.c file, search for STEP 4 and add the following line

#include <modem/lte_lc.h>

5. Define the semaphore lte_connected.

Define a semaphore using K_SEM_DEFINE, with initial count 0 and max count 1, to be used when connecting.

Search for STEP 5 and add the following line

static K_SEM_DEFINE(lte_connected, 0, 1);

6. Define the function modem_configure().

v2.4.0 – v2.x.x

Define the function modem_configure() to initialize the modem library and the LTE connection.

Search for STEP 6 and add the following lines

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;

	/* lte_lc_init deprecated in >= v2.6.0 */
	#if NCS_VERSION_NUMBER < 0x20600
	err = lte_lc_init();
	if (err) {
		LOG_ERR("Failed to initialize LTE link control library, error: %d", err);
		return err;
	LOG_INF("Connecting to LTE network");
	err = lte_lc_connect_async(lte_handler);
	if (err) {
		LOG_ERR("Error in lte_lc_connect_async, error: %d", err);
		return err;
	return 0;


In nRF Connect SDK v2.6.0 and up, lte_lc_init() is deprecated as the LTE link control library is initialized automatically when included in the application.

v2.2.0 – v2.3.0

Define the function modem_configure() to initialize the LTE connection.

Search for STEP 6 and add the following lines

int err = lte_lc_init_and_connect_async(lte_handler);
if (err) {
	LOG_ERR("Modem could not be configured, error: %d", err);

7. In the event handler for the link controller lte_handler().

In lte_handler(), in the event of changed registration status (LTE_LC_EVT_NEW_REG_STATUS), check if the modems registration status is connected (LTE_LC_NW_REG_REGISTERED_HOME or LTE_LC_NW_REG_REGISTERED_ROAMING), and if so, give the semaphore lte_connected.

Search for STEP 7.1 and add the following lines

	if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) &&
	     (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) {

	LOG_INF("Network registration status: %s",
		evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ?
		"Connected - home network" : "Connected - roaming");

7.2 Upon the event of changed RRC mode (LTE_LC_EVT_RRC_UPDATE), print the RRC mode.

Search for STEP 7.2 and add the following lines

	LOG_INF("RRC mode: %s", evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ? 
			"Connected" : "Idle");

8. In main(), call modem_configure() to initiate the LTE connection.

Search for STEP 8 and add the following lines

err = modem_configure();
if (err) {
	LOG_ERR("Failed to configure the modem");
	return 0;

9. Take the semaphore lte_connected.

Take the semaphore using k_sem_take() with no timeout, which will only be given in the callback function once the modem’s registration status is connected.

Search for STEP 9 and add the following lines

k_sem_take(&lte_connected, K_FOREVER);

After taking the semaphore, the two next lines will only be run when the device is connected to the network at which point the semaphore is given.

10. Turn on the LED status LED

Upon successfully connecting to the network, turn on the status LED.

Search for STEP 10 and add the following line


11. Build and flash the application.

11.1 Add a build configuration and select whichever board you are using:

  • nRF9161 DK: nrf9161dk_nrf9161_ns
  • nRF9160 DK: nrf9160dk_nrf9160_ns
  • Thingy:91: thingy91_nrf9160_ns

Make sure the Build after generating configuration option is enabled to trigger the build process after clicking on the Build Configuration button.


For the nRF9161 DK, you need to have nrfjprog v10.22.1 or higher. You can check this by running nrfjprog -v in a terminal window.

11.2 Flash the application to your device.


If you are using the Thingy:91 without an external debugger, make sure to follow the Thingy:91 flash procedure.

You should see the following log output on your console.

In addition, the connection LED which is the LED that will indicate a connection (LED2 on the nRF9160 DK or green LED on the Thingy:91) should be lit.


Your device can show up as multiple consecutive COM ports. If this is the case, you need to test which COM port is the correct one.

12. For further debugging purposes, let’s enable the AT Host library.

In the prj.conf file, search for STEP 12 and add the following lines to the prj.conf file

CONFIG_AT_HOST_LIBRARY is to enable the AT Host library and CONFIG_UART_INTERRUPT_DRIVEN enables interrupt support for UART so that the AT Host library can print asynchronously to the console.

The AT Host library automatically spawns a thread to print status AT commands.

13. Build and flash the application again.

You should notice intermittent unsolicited AT command notifications +CEREG and +CSCON being printed on the console among the log messages from the application.

14. Enabling the AT Host library also allows us to send AT commands while the application is running.

Let’s read out the IMEI of our device by sending:

Observe the AT command response containing the 15-digit IMEI (censored here).

The solution for this exercise can be found in lesson2/cellfund_less2_exer2_solution of whichever version directory you are using (v2.2.0-v2.3.0 or v2.4.0-v2.x.x).

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.