Feedback
Feedback

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

Exercise 2

Customizing the application

During application development, it can be useful to customize aspects of the nRF Connect SDK for your specific application, without modifying the SDK files themselves.

In this exercise, we will customize our application by adding custom files, configurations, and modifying the devicetree.

Exercise steps

Use the previous exercises as your starting point. Copy the previous completed exercise to a new directory and name it l3_e2.

Adding custom files

1. Create a .c file and a .h file in the same location as the main.c file, and call them myfunction.c and myfunction.h.

2.1 Define the function sum() in the myfunction.c file and make sure to include the header file.

#include "myfunction.h"

int sum(int a, int b){
    return a+b;
}
C

2.2 Then declare the function in the myfunction.h header file.

#ifndef MY_FUNCTION_H
#define MY_FUNCTION_H

int sum(int a, int b);

#endif
C

The first two lines and the last lines are called include guards.

Definition

Include guards: A construct, in this case, a macro, that is used to avoid the problem of double inclusion, which happens if the header file is included twice, thereby rendering the contents invalid.

3. Include the custom files in the build.

To include the custom files in the build, we use the CMake function target_sources(). Add the following line to CMakeLists.txt

target_sources(app PRIVATE src/myfunction.c)
CMake

4. Include the header file for the custom function.

Now that the files are included in the build, we just need to include the header file in main.c to run the function.

#include "myfunction.h"
C

5. Replace main() to run the custom function.

Alter main() to run the function sum() that we have defined.

int main(void)
{
	int a = 3, b = 4;
	while(1){
		printk("The sum of %d and %d is %d\n", a, b, sum(a,b));
		k_msleep(1000);
	}
}
C

6. Build and flash the application to your board.

Open a terminal output and you should see the following output.

*** Booting nRF Connect SDK v2.8.0-preview1-11645184a54d ***
*** Using Zephyr OS v3.7.99-adcffa835a8e ***
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
Terminal

The issue with including source code through target_sources() is that we will include this file in our build regardless of whether we will use it. In the next paragraph, we will learn how to control the inclusion of source code using Kconfig symbols and target_sources_ifdef().

Adding custom configurations

6. Define a custom Kconfig for enabling myfunction.

Now, let’s define our own config that will determine if our custom files get included in the build or not. To do this, create a file called Kconfig in the application directory (the same location as CMakeLists.txt and prj.conf).

Make sure the file does not have a file extension. Depending on your editor, an extension may be added by default and has to be removed manually.

source "Kconfig.zephyr"

config MYFUNCTION
	bool "Enable my function"
	default n
Kconfig

The first line sources Kconfig.zephyr, which is necessary when defining a new Kconfig file to source Zephyr RTOS configurations. The next three lines define the configuration CONFIG_MYFUNCTION as a boolean variable and sets its default value to n.

If you are interested in learning more about creating menus in Kconfig, here is a link to documentation with more details.

7. Make the addition of custom files conditional on the Kconfig.

In CMakeLists.txt, we want the addition of the custom files to be conditional. Comment out the line from step 3 and add the following line using the function target_sources_ifdef(), like this:

target_sources_ifdef(CONFIG_MYFUNCTION app PRIVATE src/myfunction.c)
CMake

The build will now only include the custom file myfunction.c if CONFIG_MYFUNCTION is enabled.

Note

This strategy is used intensively in nRF Connect SDK to only include the source code of libraries that you plan to use in your project.

This is to limit the size of your application. Modules and subsystems are only included in the build when you enable the relevant configuration, allowing you to keep the application as small as you wish.

8. Enable the Kconfig for myfunction.

Enable the config by adding the following line to prj.conf:

CONFIG_MYFUNCTION=y
Kconfig

9. Update your main.c file so that it can check if the Kconfig symbol is enabled/disabled

9.1 Check CONFIG_MYFUNCTION before including the header file.

#ifdef CONFIG_MYFUNCTION
#include "myfunction.h"
#endif
C

9.2 Check CONFIG_MYFUNCTION before calling sum().

int main(void)
{

	while (1) {
#ifdef CONFIG_MYFUNCTION
		int a = 3, b = 4;
		printk("The sum of %d and %d is %d\n", a, b, sum(a, b));
#else
		printk("MYFUNCTION not enabled\n");
		return 0;
#endif
		k_msleep(1000);
	}
	return 0;
}
C

10. Build and flash the application to your board and you should see the following output.

*** Booting nRF Connect SDK v2.8.0-preview1-11645184a54d ***
*** Using Zephyr OS v3.7.99-adcffa835a8e ***
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
The sum of 3 and 4 is 7
Terminal

11. Try disabling the Kconfig symbol in prj.conf.

11.1 In the prj.conf file, change the first line to CONFIG_MYFUNCTION=n

11.2 Build and flash the application as you have done previously.

You should see the following log output.

*** Booting nRF Connect SDK v2.8.0-preview1-11645184a54d ***
*** Using Zephyr OS v3.7.99-adcffa835a8e ***
MYFUNCTION not enabled
Terminal

11.3 Reenable the CONFIG_MYFUNCTION symbol (CONFIG_MYFUNCTION=y) as we need it for the next section, “Modifying the devicetree”.

Modifying the devicetree

In this section, we will modify the devicetree of the device’ only for this application by changing the baud rate (seed) at which information is sent to the console. Changing the hardware description (devicetree) for a specific application is done using devicetree overlay files.

12. Create an overlay file in the application directory with the name of the board you’re using.

In the application directory (the same location as CMakeLists.txt and prj.conf), create a directory named boards. In the boards directory, create an overlay file with the name of the board you’re using, in our case nrf52833dk_nrf52833.overlay. The main rule is that the file name must be the same name as the target board, and the file must end with .overlay, e.g <board_target>.overlay. There are other ways to define overlays explained in nRF Connect SDK documentation.

Note that if you are using a device with multiple targets (e.g nRF54L15 DK, nRF9151 DK), make sure you use the board target, not the board name. For example nrf54l15dk_nrf54l15_cpuapp.overlay, not nrf54l15dk_nrf54l15dk.overlay (which will not work).

Note

In nRF Connect for VS Code, there is an option to create an overlay file with the same board name used for the build as shown in the image below. Make sure to select the application context first (1). Then open Config files -> Devicetree to reveal the option to + Create overlay file (2).

This GUI also lets you view all the nodes in the devicetree and will help you with tips on the correct syntax to use.

13. Change the baud rate for the UART node.

We want to change the baud rate for the UART instance used when printing to console, which is UART0 (UART20 for the nRF54L15). The baud rate is the property current-speed in the nrf-uart binding, which is defined and specified in nrf-uart-common.yaml. Add the following to the overlay file, which can be found in the root directory of the application, to change this property:

uart0 is used for all Nordic DKs except the nRF54L15 DK.

&uart0 {
	current-speed = <9600>;
};
Devicetree

uart20 is used for the nRF54L15 DK.

&uart20 {
	current-speed = <9600>;
};
Devicetree

Other common things to change in the devicetree are the pins used by peripherals (rx, tx, cts, etc.), and the status (okay, disabled).

There are different methods to set devicetree overlay files. More details can be found here: Set devicetree overlays.

14. Do a pristine build and flash the application to the board.

In the Actions window, select this icon to the right of the Build action to do a pristine build.

If this icon does not appear for you, you can alternatively invoking the command palette of VS Code (Ctrl + Shift + P in Windows) and search for Pristine Build to trigger it.

Definition

Pristine build: Creates a new build directory. All byproducts from previous builds have been removed.

To confirm that the devicetree was changed, we can view the compiled devicetree output.

This can be done by invoking the command palette of VS Code (Ctrl + Shift + P in Windows) and typing the command nRF DeviceTree: Open Compiled Output. Inside the Compiled devicetree file, search for the node-name uart0 (1) and find the node in the devicetree (2). Here we can see that the current-speed has been changed to the value set in the overlay file (3).

This file can also be found at the path l3_e2/build/l3_e2/zephyr/zephyr.dts

You could also open the DeviceTree Visual Editor and navigate to soc-> uart0 to examine this node’s properties. For a multi-core SoC, it will be soc->peripheral->uart0. The Devietree Visual Editor needs a compiled application to process the project’s devicetree structure.

Note

If the DeviceTree window is not visible in VS Code, it means you don’t have the nRF DeviceTree extension installed in VS Code. Make sure you install it by going, to Extensions, and searching for nRF Devicetree. The nRF DeviceTree is also part of the nRF Connect for VS Code Extension Pack.

15. Observe that the serial terminal doesn’t show any output.

This is because we changed the baud rate in the application to 9600 baud/sec while the terminal is still using the default baud rate of 115200 baud/sec. Which means, the serial terminal is trying to read the log output at the wrong speed.

16. Change the baud rate in the serial terminal.

1. Close and open a new terminal.

  1. Close the current terminal
  2. Open a new one for the same COM port

2. Change the baud rate to 9600.

  1. In the menu that appears at the top of the window, select the cogwheel to the right to Change port settings.
  2. Select [Other]
  3. Select 9600 to change the baud rate

For the remaining settings:

  • Enter data bits: 8
  • Enter stop bits: 1
  • Choose parity: None
  • Choose flow control: RTSCTS

3. Observe the log output.

Output as seen in nRF Serial Terminal

1. Change the baud rate to 9600.

  1. Select Serial Settings to get a drop down all configurable options
  2. You must Disconnect from port to be able to configure the terminal
  3. Select the drown down menu under Baud rate
  4. Select 9600 to change the speed.

2. Connect to the device.

Select Connect to port to connect to the device using the current settings

3. Observe the log output.

Output as seen in Serial Terminal app

17. Devicetree Visual Editor (further reading).

Once we have a devicetree overlay for an application and a build application, we can now use the Devicetree Visual Editor, which allows us to edit devicetree structure using an intuitive GUI.

Through the DeviceTree visual editor, we can also explore the available properties in each node and modify entries directly using the visual editor. It is important to know that the Devicetree visual editor and devicetree text editor methods are interchangeable. Therefore, it is a great tool for learning Devicetree syntax.

We can access the Devicetree visual editor from the Actions view:

See the illustration below showing how the Devicetree Visual Editor is used to set the following UART configurations:

  • Hardware Flow Control: Enabled (rtscts: on)
  • baud rate: 115200
  • data bits: 8
  • stop bits: 1
  • parity: none

Note that the Devicetree visual editor is populating the Devicetree overlay file for you instead of having to remember the syntax of Devicetree.

The solution for this exercise can be found in the GitHub repository, l3/l3_e2_sol of whichever version directory you are using.

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.