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.

Adding custom files

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

2. 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

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. 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. 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

Alter main() to run the function 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

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

*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
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. 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. In CMakeLists.txt, we want the addition of the custom files to be conditional. Change the last line to use 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. This strategy is used intensively in nRF Connect SDK only to include the source code of libraries that you plan to use in your project.

The reason for 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. Lastly, 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

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

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

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;
#endif
		k_msleep(1000);
	}
}
C

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

*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
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, then build and flash the application. You should see the following output:

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

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

*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
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 exercise, we will customize our device’s devicetree only for this application by changing the baud rate at which information is sent to the console. Changing the hardware description for a specific application is done through devicetree overlay files.

12. Create an overlay file in the application directory (the same location as CMakeLists.txt and prj.conf) 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 : <board_name>.overlay . There are other ways to define overlays explained in nRF Connect SDK documentation.

Note

In nRF Connect for VS Code, in the Details View, there is an option to create an overlay file with the same board name used for the build as show in the image below. 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. We want to change the baud rate for the UART instance used when printing to console, which is UART0. The baud rate is the property current-speed in the nrf-uart binding, which is defined and specified in nrf-uart-common.yaml lines 16-38. Add the following to the overlay file, which can be found in the root directory of the application, to change this property:

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

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

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

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

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 fund_less3_exer2/build/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 serial terminal is launched with 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. Close the window and open another session where you use the correct speed that was set in the overlay file, see images below. Now observe that the log is being printed like normal.

Changing speed in PuTTY
Changing the baud rate in the nRF Terminal
Output as seen in nRF Serial Terminal

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, lesson3/fund_less3_exer2_solution of whichever version directory you are using (v2.x.x or v1.6.0-v1.9.1)

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.