├── .DS_Store ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE.md ├── README.md ├── _config.yml ├── _includes └── incomplete.md ├── docs ├── .DS_Store ├── 1-zephyr-setup │ ├── index.md │ ├── install │ │ ├── index.md │ │ ├── linux.md │ │ ├── mac-os.md │ │ └── windows.md │ └── setup │ │ ├── index.md │ │ ├── linux.md │ │ ├── mac-os.md │ │ └── windows.md ├── 10-mutexes │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── 2-introduction │ ├── index.md │ ├── rtos-basics.md │ ├── tutorial-structure.md │ └── zephyr-structure.md ├── 3-threads │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── 4-gpio │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── 5-scheduling │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── 6-logging │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── 7-debugging │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── 8-interrupts │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── 9-timers │ ├── commands.md │ ├── exercise.md │ ├── index.md │ ├── introduction.md │ └── kconfig.md ├── Contributions.md ├── Introduction.md └── Prerequisites.md ├── exercises ├── basic-sample │ ├── CMakeLists.txt │ ├── prj.conf │ └── src │ │ └── main.c ├── debugging │ ├── multi-thread-debug │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── STM32F756.svd │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ └── runtime-statistics │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ └── main.c ├── gpio │ ├── blinky │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ ├── button │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ └── two-leds │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ └── main.c ├── interrupts │ └── button-interrupt │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ └── main.c ├── networking │ ├── dhcpv4_client │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── overlay-e1000.conf │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ ├── echo │ │ ├── CMakeLists.txt │ │ ├── Makefile.posix │ │ ├── README.rst │ │ ├── boards │ │ │ ├── cc3220sf_launchxl.conf │ │ │ └── cc3235sf_launchxl.conf │ │ ├── overlay-e1000.conf │ │ ├── overlay-log.conf │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── socket_echo.c │ ├── echo_server │ │ ├── CMakeLists.txt │ │ ├── Kconfig │ │ ├── prj.conf │ │ └── src │ │ │ ├── common.h │ │ │ ├── echo-server.c │ │ │ ├── tcp.c │ │ │ └── udp.c │ ├── echo_server_dhcp │ │ ├── CMakeLists.txt │ │ ├── Kconfig │ │ ├── prj.conf │ │ └── src │ │ │ ├── common.h │ │ │ ├── echo-server.c │ │ │ ├── tcp.c │ │ │ └── udp.c │ └── python-networking │ │ ├── client.py │ │ └── server.py ├── scheduling │ ├── cooperative-time-slicing │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ ├── preemptive-time-slicing │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ └── time-slicing │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ └── main.c ├── threads │ ├── thread-abort │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ ├── thread-join │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ ├── thread-sleep │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ ├── thread-start-define │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ ├── thread-start │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ │ └── main.c │ └── thread-suspend │ │ ├── CMakeLists.txt │ │ ├── README.rst │ │ ├── prj.conf │ │ ├── sample.yaml │ │ └── src │ │ └── main.c └── timers │ └── basic-timer │ ├── CMakeLists.txt │ ├── README.rst │ ├── prj.conf │ ├── sample.yaml │ └── src │ └── main.c ├── images ├── .DS_Store ├── 1-zephyr-setup │ ├── blinky_build_errors.png │ ├── coolterm-1.png │ ├── coolterm-2.png │ ├── coolterm-3.png │ ├── coolterm-connect.png │ ├── coolterm-settings.png │ ├── env-var-check.png │ ├── final-setup.png │ ├── hello_world_build_success.png │ ├── hello_world_output.png │ ├── pyocd-error.png │ ├── success-build.png │ └── success-flash.png ├── 2-introduction │ ├── basic-sample.png │ ├── guiconfig.png │ ├── k-config.png │ ├── rtos_basic_execution.gif │ └── sample-folder.png ├── build-system │ └── boilerplate.png ├── debugging │ ├── debug-breakpoint-1.png │ ├── debug-starting.png │ ├── openocd-threads-support.png │ └── runtime-statistics.png ├── donate │ ├── bitcoin-donations.png │ ├── dogecoin-donations.png │ └── ethereum-donations.png ├── gpio │ └── devicetree-binding.png ├── interrupts │ ├── button-interrupt-alias.png │ └── button-interrupt-output.png ├── introduction │ ├── azure-rtos-github.png │ ├── freertos-github.png │ └── zephyr-github.png ├── logo-readme.svg ├── logo.png ├── logo_no_bg.png ├── old │ └── guiconfig.png ├── scheduling │ ├── cooperative.png │ ├── preemptive.png │ ├── serial-coop-time-slicing.png │ ├── serial-preemptive-time-slicing.png │ ├── serial-time-slicing.png │ └── timeslicing.png └── threads │ ├── thread-abort.png │ ├── thread-control-block.png │ ├── thread-entry-point.png │ ├── thread-join.png │ ├── thread-sleep.png │ ├── thread-stack-size.png │ ├── thread-start.png │ ├── thread-states.png │ └── thread-suspend.png ├── index.md ├── svg-files ├── threads-template.svg └── threads │ ├── thread-abort.svg │ ├── thread-join.svg │ ├── thread-sleep.svg │ ├── thread-start.svg │ └── thread-suspend.svg └── svg-images └── threads ├── thread-abort.png ├── thread-join.png ├── thread-sleep.png ├── thread-start.png └── thread-suspend.png /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.d 4 | *.cmd 5 | *.log 6 | *.pyc 7 | *.swp 8 | *.swo 9 | *~ 10 | build/ 11 | !doc/guides/build 12 | !tests/drivers/build_all 13 | cscope.* 14 | .dir 15 | 16 | /*.patch 17 | 18 | # The .cache directory will be used to cache toolchain capabilities if 19 | # no suitable out-of-tree directory is found. 20 | .cache 21 | 22 | outdir 23 | outdir-* 24 | scripts/basic/fixdep 25 | scripts/gen_idt/gen_idt 26 | doc/_build 27 | doc/doxygen 28 | doc/xml 29 | doc/html 30 | doc/boards 31 | doc/samples 32 | doc/latex 33 | doc/themes/zephyr-docs-theme 34 | sanity-out* 35 | twister-out* 36 | bsim_bt_out 37 | scripts/grub 38 | doc/reference/kconfig/*.rst 39 | doc/doc.warnings 40 | .*project 41 | .settings 42 | .envrc 43 | .vscode 44 | hide-defaults-note 45 | venv 46 | .venv 47 | 48 | # Tag files 49 | GPATH 50 | GRTAGS 51 | GTAGS 52 | TAGS 53 | tags 54 | 55 | .idea 56 | 57 | _site 58 | .jekyll-cache 59 | vendor -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'jekyll' 4 | gem 'rake' 5 | gem 'webrick' 6 | gem 'jekyll-relative-links' 7 | gem 'jekyll-remote-theme' 8 | gem 'jekyll-seo-tag' -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.8.0) 5 | public_suffix (>= 2.0.2, < 5.0) 6 | colorator (1.1.0) 7 | concurrent-ruby (1.1.10) 8 | em-websocket (0.5.3) 9 | eventmachine (>= 0.12.9) 10 | http_parser.rb (~> 0) 11 | eventmachine (1.2.7) 12 | ffi (1.15.5) 13 | forwardable-extended (2.6.0) 14 | http_parser.rb (0.8.0) 15 | i18n (1.12.0) 16 | concurrent-ruby (~> 1.0) 17 | jekyll (4.2.2) 18 | addressable (~> 2.4) 19 | colorator (~> 1.0) 20 | em-websocket (~> 0.5) 21 | i18n (~> 1.0) 22 | jekyll-sass-converter (~> 2.0) 23 | jekyll-watch (~> 2.0) 24 | kramdown (~> 2.3) 25 | kramdown-parser-gfm (~> 1.0) 26 | liquid (~> 4.0) 27 | mercenary (~> 0.4.0) 28 | pathutil (~> 0.9) 29 | rouge (~> 3.0) 30 | safe_yaml (~> 1.0) 31 | terminal-table (~> 2.0) 32 | jekyll-relative-links (0.6.1) 33 | jekyll (>= 3.3, < 5.0) 34 | jekyll-remote-theme (0.4.3) 35 | addressable (~> 2.0) 36 | jekyll (>= 3.5, < 5.0) 37 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) 38 | rubyzip (>= 1.3.0, < 3.0) 39 | jekyll-sass-converter (2.2.0) 40 | sassc (> 2.0.1, < 3.0) 41 | jekyll-seo-tag (2.8.0) 42 | jekyll (>= 3.8, < 5.0) 43 | jekyll-watch (2.2.1) 44 | listen (~> 3.0) 45 | kramdown (2.4.0) 46 | rexml 47 | kramdown-parser-gfm (1.1.0) 48 | kramdown (~> 2.0) 49 | liquid (4.0.3) 50 | listen (3.7.1) 51 | rb-fsevent (~> 0.10, >= 0.10.3) 52 | rb-inotify (~> 0.9, >= 0.9.10) 53 | mercenary (0.4.0) 54 | pathutil (0.16.2) 55 | forwardable-extended (~> 2.6) 56 | public_suffix (4.0.7) 57 | rake (13.0.6) 58 | rb-fsevent (0.11.1) 59 | rb-inotify (0.10.1) 60 | ffi (~> 1.0) 61 | rexml (3.2.5) 62 | rouge (3.30.0) 63 | rubyzip (2.3.2) 64 | safe_yaml (1.0.5) 65 | sassc (2.4.0) 66 | ffi (~> 1.9) 67 | terminal-table (2.0.0) 68 | unicode-display_width (~> 1.1, >= 1.1.1) 69 | unicode-display_width (1.8.0) 70 | webrick (1.7.0) 71 | 72 | PLATFORMS 73 | x86_64-darwin-19 74 | 75 | DEPENDENCIES 76 | jekyll 77 | jekyll-relative-links 78 | jekyll-remote-theme 79 | jekyll-seo-tag 80 | rake 81 | webrick 82 | 83 | BUNDLED WITH 84 | 2.3.7 85 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Maksim Drachov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: Zephyr Tutorial 2 | remote_theme: bedroesb/just-the-docs 3 | 4 | plugins: 5 | - jekyll-relative-links 6 | - jekyll-remote-theme 7 | - jekyll-seo-tag 8 | 9 | callouts: 10 | note: 11 | title: Note 12 | color: green 13 | warning: 14 | title: Warning 15 | color: yellow 16 | error: 17 | title: Error 18 | color: red 19 | -------------------------------------------------------------------------------- /_includes/incomplete.md: -------------------------------------------------------------------------------- 1 | {: .warning} 2 | This section is incomplete. You can help by [contributing](https://github.com/maksimdrachov/zephyr-rtos-tutorial). -------------------------------------------------------------------------------- /docs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/docs/.DS_Store -------------------------------------------------------------------------------- /docs/1-zephyr-setup/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '1. Zephyr Setup' 4 | has_children: true 5 | nav_order: 3 6 | --- -------------------------------------------------------------------------------- /docs/1-zephyr-setup/install/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '1.1 Installation' 4 | parent: '1. Zephyr Setup' 5 | has_children: true 6 | nav_order: 1 7 | --- 8 | -------------------------------------------------------------------------------- /docs/1-zephyr-setup/install/linux.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 'Linux' 4 | parent: '1.1 Installation' 5 | grand_parent: '1. Zephyr Setup' 6 | nav_order: 2 7 | --- 8 | 9 | # Install 10 | 11 | ## 1) Install dependencies 12 | I am going to setup for Arch Linux but the steps are similar for all the other Linux distributions. You can find the official getting started guide with steps for Ubuntu [here](https://docs.zephyrproject.org/latest/develop/getting_started/index.html). 13 | - Upgrade the OS 14 | ``` 15 | $ sudo pacman -Syyu 16 | ``` 17 | - Installing the packages 18 | ``` 19 | $ sudo pacman -S base-devel git cmake ninja gperf ccache dfu-util dtc wget python python-pip python-setuptools xz file make gcc multilib-devel sdl2 tk 20 | ``` 21 | Verify the versions of main dependencies 22 | ``` 23 | $ cmake --version 24 | $ python3 --version 25 | $ dtc --version 26 | ``` 27 | 28 | ## 2) Clone Zephyr 29 | - Install `west` tool via pip 30 | ``` 31 | $ pip3 install west 32 | ``` 33 | - Get Zephyr source code 34 | ``` 35 | $ mkdir ~/zephyrproject 36 | $ west init ~/zephyrproject 37 | $ cd ~/zephyrproject 38 | $ west update 39 | ``` 40 | - Export Zephyr Cmake package 41 | ``` 42 | $ west zephyr-export 43 | ``` 44 | - Install Zephyr python dependencies 45 | ``` 46 | $ pip3 install -r zephyr/scripts/requirements.txt 47 | ``` 48 | 49 | ## 3) Cloning the Zephyr SDK 50 | I will be using the `/opt` folder to store the Zephyr SDK. I already have write access. If you get any errors of permission denied. I suggest you to `chown` the `/opt` folder. 51 | 52 | - Download and Verify SDK 53 | ``` 54 | $ cd /opt 55 | $ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.15.2/zephyr-sdk-0.15.2_linux-x86_64.tar.gz 56 | $ wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.15.2/sha256.sum | shasum --check --ignore-missing 57 | ``` 58 | 59 | - Extract the SDK 60 | ``` 61 | $ tar xvf zephyr-sdk-0.15.2_linux-x86_64.tar.gz 62 | ``` 63 | - Run setup script 64 | ``` 65 | $ cd zephyr-sdk-0.15.2 66 | $ ./setup.sh 67 | ``` 68 | {:.note} 69 | > This setup script needs to be run only once or whenever you change the location of the SDK folder. 70 | 71 | - Install `udev` rules 72 | ``` 73 | $ sudo cp ~/zephyr-sdk-0.15.2/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d 74 | $ sudo udevadm control --reload 75 | ``` 76 | 77 | ## 3) Building the Hello, World 78 | {:.note} 79 | > The list of supported boards can be found [here](https://docs.zephyrproject.org/latest/boards/index.html#boards). I am going to use ESP32 for this example. 80 | ``` 81 | cd ~/zephyrproject/zephyr 82 | $ west build -p always -b esp32 samples/hello_world/ 83 | ``` 84 | The `-p` option does a pristine build. It is used to build when there is any changes done to the CMake. 85 | 86 | A successful build looks like this 87 | ![success_build_hello_world](/images/1-zephyr-setup/hello_world_build_success.png) 88 | Now flash the board with 89 | ``` 90 | $ west flash 91 | ``` 92 | To open the serial monitor 93 | ``` 94 | $ west espressif monitor 95 | ``` 96 | You should see the similar output 97 | ![hello_world_success_output](/images/1-zephyr-setup/hello_world_output.png) 98 | 99 | ## 4) Building the blinky 100 | Now, let's try to blink the builtin LED on ESP32. The sample is in `zephyr/samples/basic/blinky` 101 | ``` 102 | $ west build -p -b esp32 samples/basic/blinky 103 | ``` 104 | If you encounter build errors like this 105 | ![blinky_build_error](/images/1-zephyr-setup/blinky_build_errors.png) 106 | It means that we need to add an overlay file with the board support. This file can be added for any unsupported board with the `.overlay`.
107 | Create an `esp32.overlay` file in `zephyr/samples/basic/blinky/` and add the following contents 108 | ```dtc 109 | / { 110 | aliases { 111 | led0 = &myled0; 112 | }; 113 | 114 | leds { 115 | compatible = "gpio-leds"; 116 | myled0: led_0 { 117 | gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; 118 | }; 119 | }; 120 | }; 121 | ``` 122 | It will blink the LED connected to GPIO 0 (BUILTIN_LED). Now try to build 123 | ``` 124 | $ west build -p -b esp32 samples/basic/blinky 125 | ``` 126 | And flash it with 127 | ``` 128 | $ west flash 129 | ``` 130 | 131 | The board will start to blink
132 | ![](https://www.electronicshub.org/wp-content/uploads/2021/02/ESP32-LED-Blink-GIF.gif) -------------------------------------------------------------------------------- /docs/1-zephyr-setup/install/mac-os.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 'MacOS' 4 | parent: '1.1 Installation' 5 | grand_parent: '1. Zephyr Setup' 6 | nav_order: 1 7 | --- 8 | 9 | # Install 10 | 11 | ## 1) Install dependencies 12 | 13 | - Install Homebrew 14 | 15 | ``` 16 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 17 | ``` 18 | 19 | - Use `brew` to install the required dependencies 20 | 21 | ``` 22 | brew install cmake ninja gperf python3 ccache qemu dtc textmate 23 | ``` 24 | 25 | ## 2) Clone Zephyr 26 | ``` 27 | cd ~ 28 | mkdir zephyrproject 29 | cd zephyrproject 30 | git clone https://github.com/zephyrproject-rtos/zephyr 31 | ``` 32 | 33 | ## 3) Install `west` 34 | - Install `west` 35 | 36 | ``` 37 | pip3 install -U west 38 | ``` 39 | 40 | - Add `west` to path 41 | 42 | ``` 43 | mate etc/paths 44 | #Add /Users//Library/Python//bin 45 | ``` 46 | 47 | (running `pip3 show -f west` shows where the binary is installed) 48 | 49 | - Get the Zephyr source code 50 | 51 | ``` 52 | west init ~/zephyrproject 53 | cd ~/zephyrproject 54 | west update 55 | ``` 56 | 57 | - Export Zephyr CMake package: 58 | 59 | ``` 60 | west zephyr-export 61 | ``` 62 | 63 | (this allows CMake to automatically load boilerplate required for building Zephyr applications) 64 | 65 | - Install additional dependencies using `pip3` 66 | 67 | ``` 68 | pip3 install -r ~/zephyrproject/zephyr/scripts/requirements.txt 69 | ``` 70 | 71 | ## 4) Install GNU ARM Embedded toolchain 72 | 73 | - Download and install [GNU ARM Embedded build](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads) (`.pkg`) 74 | 75 | - Set environment variables in `~/.zshenv` 76 | 77 | ``` 78 | mate .zshenv 79 | ``` 80 | 81 | Add the following lines: 82 | 83 | ``` 84 | export ZEPHYR_TOOLCHAIN_VARIANT=GNUARMEMB 85 | export GNUARMEMB_TOOLCHAIN_PATH=/Applications/ARM 86 | ``` 87 | 88 | - Restart terminal and check if environment variables are set up correctly 89 | 90 | ``` 91 | echo $ZEPHYR_TOOLCHAIN_VARIANT 92 | echo $GNUARMEMB_TOOLCHAIN_PATH 93 | ``` 94 | 95 | ![env_var_check](/images/1-zephyr-setup/env-var-check.png) 96 | 97 | ## 5) Build the Blinky sample 98 | 99 | The board name can be found under `~/zephyrproject/zephyr/boards` 100 | 101 | ``` 102 | cd ~/zephyrproject/zephyr/samples/basic/blinky 103 | west build -b # for example: nucleo_l552ze_q 104 | ``` 105 | A successful build looks like this: 106 | ![succes_build](/images/1-zephyr-setup/success-build.png) 107 | 108 | {: .note } 109 | > If you get a CMake error, this can usually be resolved by clearing the previous build: `rm -rf build` 110 | 111 | ## 6) Flash the sample 112 | ``` 113 | cd ~/zephyrproject/zephyr/samples/basic/blinky 114 | west flash 115 | ``` 116 | A successful flash looks like this: 117 | 118 | ![succes_flash](/images/1-zephyr-setup/success-flash.png) 119 | 120 | {: .warning} 121 | > Some boards will require installing an additional `pyocd` package! 122 | > ![pyocd-error](../../../images/zephyr-setup/pyocd-error.png) 123 | > For Nucleo L552ZE-Q: `pyocd pack install stm32l552zetxq` (see [pyocd/target_support](https://pyocd.io/docs/target_support.html#managed-packs)) -------------------------------------------------------------------------------- /docs/1-zephyr-setup/install/windows.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 'Windows' 4 | parent: '1.1 Installation' 5 | grand_parent: '1. Zephyr Setup' 6 | nav_order: 3 7 | --- 8 | 9 | {% include incomplete.md %} -------------------------------------------------------------------------------- /docs/1-zephyr-setup/setup/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '1.2 Workspace Setup' 4 | parent: '1. Zephyr Setup' 5 | has_children: true 6 | nav_order: 2 7 | --- -------------------------------------------------------------------------------- /docs/1-zephyr-setup/setup/linux.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 'Linux' 4 | parent: '1.2 Workspace Setup' 5 | grand_parent: '1. Zephyr Setup' 6 | nav_order: 2 7 | --- 8 | 9 | {% include incomplete.md %} -------------------------------------------------------------------------------- /docs/1-zephyr-setup/setup/mac-os.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 'MacOS' 4 | parent: '1.2 Workspace Setup' 5 | grand_parent: '1. Zephyr Setup' 6 | nav_order: 1 7 | --- 8 | 9 | # Setup 10 | 11 | ## 1) Coolterm 12 | 13 | - Download and install [Coolterm](https://freeware.the-meiers.org/) 14 | 15 | - Connect your board to your computer 16 | 17 | - `Options`: Set up serial connection with Nucleo 18 | - Port: `usbmodemxxxxx` 19 | - Baudrate: `115200` 20 | 21 | ![coolterm-1](/images/1-zephyr-setup/coolterm-1.png) 22 | 23 | - `Terminal`: check "Filter ASCII Escape Sequences" and press `Ok` 24 | 25 | ![coolterm-2](/images/1-zephyr-setup/coolterm-2.png) 26 | 27 | - `File -> Save`: Save this configuration under `~/zephyrproject` 28 | 29 | ![coolterm-settings](/images/1-zephyr-setup/coolterm-settings.png) 30 | 31 | - `Connect` 32 | 33 | ![coolterm-connect](/images/1-zephyr-setup/coolterm-connect.png) 34 | 35 | ## 2) VSCode 36 | 37 | - Install [VSCode](https://code.visualstudio.com/) 38 | 39 | - Add the following extensions to VSCode: 40 | - [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) 41 | - [Cortex-Debug](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) 42 | - [DeviceTree](https://marketplace.visualstudio.com/items?itemName=plorefice.devicetree) 43 | 44 | - Clone tutorial repository into `~/zephyrproject` and open VSCode 45 | 46 | ``` 47 | cd ~/zephyrproject 48 | git clone https://github.com/maksimdrachov/zephyr-rtos-tutorial 49 | cd zephyr-rtos-tutorial 50 | code . 51 | ``` 52 | 53 | - VSCode: `Terminal -> New Terminal` 54 | 55 | ``` 56 | cd exercises/basic-sample 57 | west build -b nucleo_l552ze_q 58 | west flash 59 | ``` 60 | 61 | {: .note } 62 | > If you've previously made a build for a different board, remove the old build first: `rm -rf build` 63 | 64 | - Verify the serial output: 65 | 66 | ![coolterm-3](/images/1-zephyr-setup/coolterm-3.png) 67 | 68 | Your final setup should look something like this: 69 | 70 | ![final-setup](/images/1-zephyr-setup/final-setup.png) -------------------------------------------------------------------------------- /docs/1-zephyr-setup/setup/windows.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: 'Windows' 4 | parent: '1.2 Workspace Setup' 5 | grand_parent: '1. Zephyr Setup' 6 | nav_order: 3 7 | --- 8 | 9 | {% include incomplete.md %} -------------------------------------------------------------------------------- /docs/10-mutexes/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '10.2 Commands' 4 | parent: '10. Mutexes' 5 | --- 6 | 7 | | Command | Description | 8 | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 9 | | K_MUTEX_DEFINE | Statically define and initialize a mutex. | 10 | | k_mutex_init | Initialize a mutex. | 11 | | k_mutex_lock | Lock a mutex. This routine locks mutex. If the mutex is locked by another thread, the calling thread waits until the mutex becomes available or until a timeout occurs. | 12 | | k_mutex_unlock | Unlock a mutex. This routine unlocks mutex. The mutex must already be locked by the calling thread. | 13 | -------------------------------------------------------------------------------- /docs/10-mutexes/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '10.4 Exercise' 4 | parent: '10. Mutexes' 5 | --- 6 | 7 | 2 preemptive threads 8 | 9 | 1 integer value, we want to in one thread add 1 and in the other subtract one. 10 | If we don't use mutex then unpredictable results 11 | If we do it should stay at same value 12 | even though 2 different priorities threads (and they are preemptive) -------------------------------------------------------------------------------- /docs/10-mutexes/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '10. Mutexes' 4 | has_children: true 5 | nav_order: 12 6 | --- -------------------------------------------------------------------------------- /docs/10-mutexes/kconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '10.3 Kconfig' 4 | parent: '10. Mutexes' 5 | --- 6 | 7 | | Kconfig | Description | 8 | | ----------------------- | ---------------------------- | 9 | | CONFIG_PRIORITY_CEILING | Priority inheritance ceiling | 10 | -------------------------------------------------------------------------------- /docs/2-introduction/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '2. Introduction' 4 | has_children: true 5 | nav_order: 4 6 | --- -------------------------------------------------------------------------------- /docs/2-introduction/rtos-basics.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '2.1 RTOS basics' 4 | parent: '2. Introduction' 5 | nav_order: 10 6 | --- 7 | 8 | # RTOS basics 9 | 10 | ## Why do I need an RTOS? 11 | 12 | An RTOS is rarely a requirement; however, as you start to increase the functionality of your embedded applications, it becomes increasingly harder to do everything within one single main loop and some interrupt routines. Usually the next level of complexity is some kind of state machine, where the output of your electronic device changes depending on this (internal) state. This however only gets you so far. For example, what if you need to be able to operate multiple complex inputs and outputs simultaneously? A good example could be an TCP/IP connection, over which you'll be receiving some kind of data which then has to be used to operate a robotic arm, control an electric motor, send out a signal... It quickly becomes clear that a new level of abstraction is required to not drown in the complexity that would be required to implement something like that. This is where an RTOS steps in. 13 | 14 | ## What makes Zephyr different from other RTOS's? 15 | 16 | As I haven't had the time to study other RTOS'es as in-depth I might be biased here. However from my point of view, studying Zephyr has the following benefits: 17 | - Zephyr is supported by the Linux Foundation 18 | - By learning Zephyr you'll automatically get a taste for the Linux kernel. Both show some overlap in the way they are implemented, for example: Kconfig and devicetrees are concepts borrowed by Zephyr from Linux. 19 | - Zephyr is flexible: you can trade off footprint versus extra functionality (through Kconfig). If you don't know how this works: don't worry, I'll explain this later. 20 | - Zephyr supports a wide variety of different dev boards/SoCs. 21 | - A more extensive lists of reasons can be found [here](https://docs.zephyrproject.org/latest/introduction/index.html) 22 | 23 | ## How does an RTOS work and what are some key concepts? 24 | 25 | Ok, so now that I've hopefully convinced you of the *use* of an RTOS, let's start by taking a look at *how* this all works. The first and most fundamental part of an RTOS is the **kernel**. The kernel is responsible for scheduling CPU time for each particular task so that they *appear* to be happening simultaneously. The particulars of how this scheduling algorithm (or also called: **scheduler**) works is not important for now. 26 | 27 | Each **thread** (or task) will use registers and memory as it executes. The whole of these processor registers and stack (memory) compromise the **context** of that particular thread. Once the RTOS decides to switch the thread and run something else, it will need to first *store* context away and then *load* in the context for the thread it wants to run next. This process is called **context switching**. 28 | 29 | Along with threads, you'll be using primitives such as **queues**, **mutexes** and **semaphores** for inter-thread communication. Then each RTOS provides varying levels of support for different protocols such as **TCP/IP**, **Bluetooth**, **LoRaWan**,... This makes your life easier, since now you don't need to study these protocols as in-depth. You'll get a series of API calls which should increase speed of development. 30 | 31 | ![rtos-basic-execution](../../images/2-introduction/rtos_basic_execution.gif) -------------------------------------------------------------------------------- /docs/2-introduction/tutorial-structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '2.3 Tutorial structure' 4 | parent: '2. Introduction' 5 | nav_order: 10 6 | --- 7 | 8 | # Tutorial structure 9 | 10 | ## How is the tutorial structured? 11 | 12 | Each lesson covers 1 aspect of Zephyr. The order of lessons is chosen deliberately, unless you already know a thing or two, it is recommended to not skip ahead. 13 | 14 | Each lesson consist of 4 parts: 15 | - **Introduction**: introduce each new topic/concept, explain why it is useful. 16 | - **Commands**: go over all the commands/api calls that are relevant to that particular topic. 17 | - **Kconfig**: here we take a look at the different Kconfig settings that might be interesting. 18 | - **Examples**: some examples to show how to apply the discussed concepts. 19 | -------------------------------------------------------------------------------- /docs/2-introduction/zephyr-structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '2.2 Zephyr structure' 4 | parent: '2. Introduction' 5 | nav_order: 10 6 | --- 7 | 8 | # Zephyr structure 9 | 10 | ## How to work with Zephyr? 11 | 12 | Before we start writing our first applications in Zephyr, it might be a good step to take a look at the folder structure that Zephyr provides us. 13 | 14 | ![sample-folder](/images/2-introduction/sample-folder.png) 15 | 16 | Let's go one-by-one: 17 | 18 | ### build 19 | This folder appears only once you have build your application and contains the files that are used to flash your microcontroller. 20 | 21 | The following files are sometimes interesting to take a look at: 22 | - **build/zephyr/zephyr.dts**: CMake uses a devicetree to tailor the build towards your specific architecture/board. This is the final version of that file. Here you'll be able to find all the different functionality (GPIO, Timers, PWM, DMA, UART, SPI, I2C, DAC, USB,...) that is present on your MCU (that can then be called upon in your application). 23 | - **build/zephyr/.config**: The final Kconfig used for your built. This can be useful to verify if a setting has been set correctly. 24 | 25 | ### CMakeLists.txt 26 | This file will be used by [CMake](https://en.wikipedia.org/wiki/CMake) to set up your build, during this tutorial you won't need to change this one. 27 | 28 | ### prj.conf 29 | This is you Kconfig file. **Important!** This file will contain any *additional* settings you want set for your particular Zephyr build. Depending on your particular application, you might want to (for example) include a TCP/IP stack or make some changes to the scheduler. We'll explore some of these options throughout the tutorial. 30 | 31 | ![k-config](/images/2-introduction/k-config.png) 32 | 33 | Right now it's pretty empty, since for `basic-sample` we don't require any "fancy" functionality, just the basic Zephyr kernel. The only additional functionality we set is `CONFIG_PRINTK`, which allows us to use the `printk` function to output to the serial port (which is then displayed on your computer screen using Coolterm). 34 | 35 | If you're ever unsure about what a particular config setting does, you have 2 options: 36 | - Use [google](https://www.google.com/search?client=firefox-b-d&q=zephyr+CONFIG_PRINTK): usually Zephyr Documentation is one of the first links 37 | - Use the `guiconfig`: in your `basic-sample` folder execute `west build -t guiconfig`. This will show you a menu of all the possible configuration settings and a small description of what each one does. (Use `Jump to` to find a particular config) 38 | 39 | ![guiconfig](/images/2-introduction/guiconfig.png) 40 | 41 | ### src 42 | Where the magic happens! This folder should contain all of your custom application code. For now it contains one file: `main.c`, which prints out a message to the serial port and then sleeps for 1 second. 43 | 44 | ![basic-sample](/images/2-introduction/basic-sample.png) -------------------------------------------------------------------------------- /docs/3-threads/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '3.2 Commands' 4 | parent: '3. Threads' 5 | --- 6 | 7 | ## How do I define threads in Zephyr? 8 | 9 | A thread is spawned by defining its stack area and its thread control block, and then calling k_thread_create(). 10 | 11 | The stack area must be defined using K_THREAD_STACK_DEFINE or K_KERNEL_STACK_DEFINE to ensure it is properly set up in memory. 12 | 13 | The thread spawning function returns its thread id, which can be used to reference the thread. 14 | 15 | ```c 16 | #define MY_STACK_SIZE 500 17 | #define MY_PRIORITY 5 18 | 19 | extern void my_entry_point(void *, void *, void *); 20 | 21 | K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE); 22 | struct k_thread my_thread_data; 23 | 24 | k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area, 25 | K_THREAD_STACK_SIZEOF(my_stack_area), 26 | my_entry_point, 27 | NULL, NULL, NULL, 28 | MY_PRIORITY, 0, K_NO_WAIT); 29 | ``` 30 | 31 | In order to define a thread you'll need to initiate some parameters: 32 | 33 | ```c 34 | k_tid_t k_thread_create(struct k_thread *new_thread, k_thread_stack_t *stack, size_t stack_size, k_thread_entry_t entry, void *p1, void *p2, void *p3, int prio, uint32_t options, k_timeout_t delay) 35 | 36 | ``` 37 | Parameters: 38 | - `new_thread` – Pointer to uninitialized struct k_thread 39 | - `stack` – Pointer to the stack space. 40 | - `stack_size` – Stack size in bytes. 41 | - `entry` – Thread entry function. 42 | - `p1` – 1st entry point parameter. 43 | - `p2` – 2nd entry point parameter. 44 | - `p3` – 3rd entry point parameter. 45 | - `prio` – Thread priority. 46 | - `options` – Thread options. 47 | - `delay` – Scheduling delay, or K_NO_WAIT (for no delay). 48 | 49 | Returns: 50 | - ID of new thread. 51 | 52 | Alternatively, a thread can be declared at compile time by calling K_THREAD_DEFINE. Observe that the macro defines the stack area, control block, and thread id variables automatically. 53 | 54 | The following code has the same effect as the code segment above. 55 | ```c 56 | #define MY_STACK_SIZE 500 57 | #define MY_PRIORITY 5 58 | 59 | extern void my_entry_point(void *, void *, void *); 60 | 61 | K_THREAD_DEFINE(my_tid, MY_STACK_SIZE, 62 | my_entry_point, NULL, NULL, NULL, 63 | MY_PRIORITY, 0, 0); 64 | ``` 65 | 66 | ## Thread commands 67 | ### k_thread_start() 68 | A thread must be created before it can be used. 69 | 70 | ![k_thread_im](/svg-images/threads/thread-start.png) 71 | 72 | ### k_thread_abort() 73 | Abort a thread. Thread is taken off all kernel queues. 74 | 75 | ![k_thread_im](/svg-images/threads/thread-abort.png) 76 | 77 | ### k_sleep() 78 | A thread can prevent itself from executing for a specified amount of time. A sleeping thread becomes executable automatically once the time limit is reached. 79 | 80 | ![k_thread_im](/svg-images/threads/thread-sleep.png) 81 | 82 | ### k_thread_suspend() 83 | Prevent a thread from executing for an indefinite period of time. Once suspended, use k_thread_resume() to re-start. 84 | 85 | ![k_thread_im](/svg-images/threads/thread-suspend.png) 86 | 87 | ### k_thread_join() 88 | Sleep until a thread exits. 89 | 90 | For example: 91 | - thread_b is responsible for setting up a hardware interface 92 | - thread_a is responsible for processing data from this interface 93 | - As long as thread_b has not exited, thread_a can't start, so we'll use k_thread_join(thread_b, timeout) in this case. 94 | 95 | ![k_thread_im](/svg-images/threads/thread-join.png) 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/3-threads/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '3.4 Exercises' 4 | parent: '3. Threads' 5 | --- 6 | 7 | # Exercises 8 | 9 | For solving the exercises I recommend you create your own folder inside `zephyr-rtos-tutorial` which contains the following filetree. 10 | 11 | ``` 12 | . 13 | └── my-exercises 14 | ├── threads 15 | │ ├── thread-start 16 | │ ├── thread-start-define 17 | │ ├── thread-abort 18 | │ ├── thread-sleep 19 | │ ├── thread-suspend 20 | │ └── thread-join 21 | ├── gpio 22 | ├── scheduling 23 | ├── debugging 24 | ├── interrupts 25 | ├── timers 26 | ├── mutexes 27 | ├── semaphores 28 | ├── logging 29 | └── networking 30 | ``` 31 | 32 | 33 | 34 | ## thread creation: main 35 | 36 | - Use `k_thread_create()` to create a thread 37 | - Implement the following 38 | 39 | ![thread-start](/svg-images/threads/thread-start.png) 40 | 41 | - Output the following serial using `printk()` 42 | 43 | ![thread-start](/images/threads/thread-start.png) 44 | 45 | solution: `exercises/threads/thread-start` 46 | 47 | ## thread creation: define 48 | 49 | - Same as previous, but this time using `K_THREAD_DEFINE` to create thread 50 | 51 | solution: `exercises/threads/thread-start-define` 52 | 53 | ## thread abort 54 | 55 | - Implement the following 56 | 57 | ![thread-abort](/svg-images/threads/thread-abort.png) 58 | 59 | - Output the following serial using `printk()` 60 | 61 | ![thread-abort](/images/threads/thread-abort.png) 62 | 63 | solution: `exercises/threads/thread-abort` 64 | 65 | ## thread sleep 66 | 67 | - Implement the following 68 | 69 | ![thread-sleep](/svg-images/threads/thread-sleep.png) 70 | 71 | - Output the following serial using `printk()` 72 | 73 | ![thread-sleep](/images/threads/thread-sleep.png) 74 | 75 | solution: `exercises/threads/thread-sleep` 76 | 77 | ## thread suspend 78 | 79 | - Implement the following 80 | 81 | ![thread-sleep](/svg-images/threads/thread-suspend.png) 82 | 83 | - Output the following serial using `printk()` 84 | 85 | ![thread-sleep](/images/threads/thread-suspend.png) 86 | 87 | solution: `exercises/threads/thread-suspend` 88 | 89 | ## thread join 90 | 91 | - Implement the following 92 | 93 | ![thread-join](/svg-images/threads/thread-join.png) 94 | 95 | - Output the following serial using `printk()` 96 | 97 | ![thread-join](/images/threads/thread-join.png) 98 | 99 | solution: `exercises/threads/thread-join` -------------------------------------------------------------------------------- /docs/3-threads/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '3. Threads' 4 | has_children: true 5 | nav_order: 5 6 | --- -------------------------------------------------------------------------------- /docs/3-threads/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '3.1 Introduction' 4 | parent: '3. Threads' 5 | --- 6 | 7 | ## What are threads? 8 | 9 | A thread is an isolated instance that is responsible for the execution of some task. While a microcontroller usually only has 1 CPU, the RTOS is able to have multiple tasks execute (seemingly) simultaneously by exchanging the thread that gets run on the CPU as dictated by the scheduler. 10 | 11 | Some key concepts: 12 | - **Stack area**: a region of memory used for the thread's stack. The size can be adjusted as required by the thread's processing. 13 | 14 | ![thread-stack-size](/images/threads/thread-stack-size.png) 15 | 16 | - **Thread control block**: for internal bookkeeping of the thread's metadata. An instance of the type `k_thread`. 17 | 18 | ![thread-control-block](/images/threads/thread-control-block.png) 19 | 20 | - **Entry point function**: invoked when the thread is started. Up to 3 argument values can be passed to this function. 21 | 22 | ![thread-entry-point](/images/threads/thread-entry-point.png) 23 | 24 | _ARG_UNUSED is needed to indicate that the 3 arguments are not used in our thread function._ 25 | 26 | - **Scheduling policy**: intstructs the kernel's scheduler how to allocate CPU time to the thread. (This will be covered in `Scheduling`) 27 | - **Execution mode**: can be supervisor or user mode. By default, threads run in supervisor mode and allow access to privileged CPU instructions, the entire memory address space, and peripherals. User mode threads have a reduced set of privileges. 28 | 29 | The specifics of how to define a thread will be discussed in the next section 30 | 31 | ## How does Zephyr choose which thread to run? 32 | 33 | "Thread is ready" = eligible to be selected as the next running thread. 34 | 35 | Following factors can make a thread unready: 36 | - Thread has not been started 37 | - Waiting for a kernel object to complete an operation (for example, the thread is taking semaphore that is unavailable) 38 | - Waiting for a timeout to occur 39 | - Thread has been suspended 40 | - Thread has terminated or aborted 41 | 42 | The following diagram shows all the possible states a thread can find itself: 43 | 44 | ![thread_states](/images/threads/thread-states.png) -------------------------------------------------------------------------------- /docs/4-gpio/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '4.4 Exercise' 4 | parent: '4. GPIO' 5 | --- 6 | 7 | ## Blinky 8 | GPIO-output 9 | 10 | Make a 1 Hz blinky program. 11 | 12 | solution: `exercises/gpio/blinky` 13 | 14 | ## Button 15 | GPIO-input 16 | 17 | Use button to turn LED on or off. 18 | 19 | solution: `exercises/gpio/button` 20 | 21 | ## 2 LEDs 22 | Threads + GPIO 23 | 24 | Blinky for 2 LED at different frequencies, using different threads. 25 | 26 | solution: `exercises/gpio/two-leds` -------------------------------------------------------------------------------- /docs/4-gpio/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '4. GPIO' 4 | has_children: true 5 | nav_order: 6 6 | --- -------------------------------------------------------------------------------- /docs/4-gpio/kconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '4.3 Kconfig' 4 | parent: '4. GPIO' 5 | --- 6 | 7 | ## Required Kconfig 8 | ``` 9 | CONFIG_GPIO=y 10 | ``` 11 | Includes GPIO drivers in system configuration -------------------------------------------------------------------------------- /docs/5-scheduling/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '5.2 Commands' 4 | parent: '5. Scheduling' 5 | --- 6 | 7 | ## Commands 8 | 9 | A couple of commands we haven't discussed in threads: 10 | 11 | - k_yield: Yield the current thread. This routine causes the current thread to yield execution to another thread of the same or higher priority. If there are no other ready threads of the same or higher priority, the routine returns immediately. 12 | - k_wakeup: Wake up a sleeping thread. This routine prematurely wakes up thread from sleeping. 13 | - k_current_get: Get thread ID of the current thread. 14 | - k_sched_lock: A preemptible thread that does not wish to be preempted while performing a critical operation can instruct the scheduler to temporarily treat it as a cooperative thread by calling k_sched_lock(). This prevents other threads from interfering while the critical operation is being performed. 15 | - k_sched_unlock: Once the critical operation is complete the preemptible thread must call k_sched_unlock() to restore its normal, preemptible status. 16 | - k_busy_wait: A thread can call k_busy_wait() to perform a busy wait that delays its processing for a specified time period without relinquishing the CPU to another ready thread. -------------------------------------------------------------------------------- /docs/5-scheduling/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '5.4 Exercise' 4 | parent: '5. Scheduling' 5 | --- 6 | 7 | # Exercises 8 | 9 | ## Cooperative Time Slicing 10 | 11 | Implement cooperative time slicing that puts out the following serial output (using `printk()`) 12 | 13 | *figure showing that thread_1, even though lower priority, doesn't yield to thread_2 (until finished)* 14 | 15 | ![serial-coop-time-slicing](/images/scheduling/serial-coop-time-slicing.png) 16 | 17 | 18 | ## Preemptive Time Slicing 19 | 20 | Implement Preemptive time slicing that puts out the serial (using `printk()`) 21 | 22 | *figure showing the increase in thread priority and preemption and completion of each thread* 23 | 24 | ![serial-preemptive-time-slicing](/images/scheduling/serial-preemptive-time-slicing.png) 25 | 26 | ## Time Slicing (with 3 threads) 27 | 28 | Implement time slicing with three threads (of equal priority) 29 | 30 | *figure showing the equal priority threads preempting each other* 31 | 32 | ![serial-time-slicing](/images/scheduling/serial-time-slicing.png) 33 | -------------------------------------------------------------------------------- /docs/5-scheduling/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '5. Scheduling' 4 | has_children: true 5 | nav_order: 7 6 | --- -------------------------------------------------------------------------------- /docs/6-logging/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '6.2 Commands' 4 | parent: '6. Logging' 5 | --- 6 | 7 | X: ERR, WRN, INF or DGB 8 | 9 | | Command | Description | 10 | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 11 | | LOG_X | Writes an X level message to the log | 12 | | LOG_PRINTK | Unconditionally print raw log message | 13 | | LOG_INST_X | Writes an X level message associated with the instance to the log | 14 | | LOG_HEXDUMP_X | Writes an X level hexdump message to the log | 15 | | LOG_INST_HEXDUMP_X | Writes an X level hexdump message associated with the instance to the log | 16 | | LOG_MODULE_REGISTER | Create module-specific state and register the module with Logger. This macro normally must be used after including to complete the initialization of the module. | 17 | | LOG_MODULE_DECLARE | Macro for declaring a log module (not registering it). | 18 | | LOG_LEVEL_SET | Macro for setting log level in the file or function where instance logging API is used. | 19 | | | | 20 | | | | 21 | | | | 22 | | | | 23 | -------------------------------------------------------------------------------- /docs/6-logging/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '6.4 Exercise' 4 | parent: '6. Logging' 5 | --- -------------------------------------------------------------------------------- /docs/6-logging/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '6. Logging' 4 | has_children: true 5 | nav_order: 8 6 | --- -------------------------------------------------------------------------------- /docs/6-logging/kconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '6.3 Kconfig' 4 | parent: '6. Logging' 5 | --- 6 | 7 | Mode of operations: 8 | 9 | | Kconfig | Description | 10 | | -------------------------- | ------------------------------- | 11 | | CONFIG_LOG | Deferred mode | 12 | | CONFIG_LOG_MODE_DEFERRED | Deferred mode | 13 | | CONFIG_LOG2_MODE_DEFERRED | Deferred mode v2 | 14 | | CONFIG_LOG_MODE_IMMEDIATE | Immediate (synchronous) mode | 15 | | CONFIG_LOG2_MODE_IMMEDIATE | Immediate (synchronous) mode v2 | 16 | | CONFIG_LOG_MODE_MINIMAL | Minimal footprint mode | 17 | 18 | Filtering options: 19 | 20 | | Kconfig | Description | 21 | | ---------------------------- | --------------------------------------------------------------------------------------------------- | 22 | | CONFIG_LOG_RUNTIME_FILTERING | Enables runtime reconfiguration of the filtering. | 23 | | CONFIG_LOG_DEFAULT_LEVEL | Default level, sets the logging level used by modules that are not setting their own logging level. | 24 | | CONFIG_LOG_OVERRIDE_LEVEL | It overrides module logging level when it is not set or set lower than the override value. | 25 | | CONFIG_LOG_MAX_LEVEL | Maximal (lowest severity) level which is compiled in. | 26 | 27 | Processing options: 28 | 29 | | Kconfig | Description | 30 | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 31 | | CONFIG_LOG_PRINTK | Redirect printk calls to the logging | 32 | | CONFIG_LOG_BUFFER_SIZE | Number of bytes dedicated for the message pool. Single message capable of storing standard log with up to 3 arguments or hexdump message with 12 bytes of data take 32 bytes. In v2 it indicates buffer size dedicated for circular packet buffer. | 33 | 34 | Formatting options: 35 | 36 | | Kconfig | Description | 37 | | ----------------------------------- | --------------------------------------------------------------------------------------------- | 38 | | CONFIG_LOG_FUNC_NAME_PREFIX_ERR | Prepend standard ERROR log messages with function name. Hexdump messages are not prepended. | 39 | | CONFIG_LOG_FUNC_NAME_PREFIX_WRN | Prepend standard WARNING log messages with function name. Hexdump messages are not prepended. | 40 | | CONFIG_LOG_FUNC_NAME_PREFIX_INF | Prepend standard INFO log messages with function name. Hexdump messages are not prepended. | 41 | | CONFIG_LOG_FUNC_NAME_PREFIX_DBG | Prepend standard DEBUG log messages with function name. Hexdump messages are not prepended. | 42 | | CONFIG_LOG_BACKEND_SHOW_COLOR | Enables coloring of errors (red) and warnings (yellow). | 43 | | CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP | If enabled timestamp is formatted to hh:mm:ss:mmm,uuu. Otherwise is printed in raw format. | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/7-debugging/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '7.2 Commands' 4 | parent: '7. Debugging' 5 | --- 6 | 7 | ## Runtime statistics 8 | The analysis is performed on demand when the application calls one of the following functions: 9 | - thread_analyzer_run 10 | - thread_analyzer_print 11 | -------------------------------------------------------------------------------- /docs/7-debugging/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '7.4 Exercise' 4 | parent: '7. Debugging' 5 | --- 6 | 7 | ## Exercise 1: Multiple threads debugging 8 | 9 | Using the code from the previous section (time-slicing), we'll try to see how debugging works in VSCode. 10 | 11 | 1) in `multi-thread-debug` create folder `.vscode` 12 | 2) in `.vscode` create file `launch.json` 13 | 3) setup your debug config as follows inside `launch.json` (change as applicable) 14 | 15 | ```json 16 | { 17 | "version": "0.2.0", 18 | "configurations": [ 19 | { 20 | "type": "cortex-debug", 21 | "request": "launch", 22 | "servertype": "openocd", 23 | "cwd": "${workspaceRoot}", 24 | "executable": "build/zephyr/zephyr.elf", 25 | "name": "zephyr STM32F756ZG", 26 | "configFiles": [ 27 | "/Users/maksim/zephyrproject/zephyr/boards/arm/nucleo_f756zg/support/openocd.cfg" 28 | ], 29 | "svdFile": "STM32F756.svd" 30 | } 31 | ] 32 | } 33 | ``` 34 | 35 | The svd file can be found on the [STM](https://www.st.com/en/microcontrollers-microprocessors/stm32f756zg.html#cad-resources) website. Add this file to your folder and mention it in `launch.json`, this way you'll be able to easily read out the different registers/peripherals/memory once you're in debug mode. 36 | 37 | 4) the svd file is necessary to be able to read registers from that specific stm processor 38 | 39 | 5) Now go to Run->Start debugging 40 | 41 | *The first screen should look like this:* 42 | 43 | ![debug-starting](/images/debugging/debug-starting.png) 44 | 45 | *If you put an interrupt in the first interrupt, the execution will again be stopped at this point* 46 | 47 | ![debug-breakpoint](/images/debugging/debug-breakpoint-1.png) 48 | 49 | Notice the "Cortex Peripherals" and "Cortex Registers" on the left-hand side. 50 | 51 | ## Exercise 2: Print runtime statistics 52 | 53 | 1) Go to `exercises/debugging/runtime-statistics` 54 | 55 | 2) Build & Flash 56 | 57 | ``` 58 | west build -b nucleo_f756zg 59 | west flash 60 | ``` 61 | 62 | 3) Observe the output in the serial monitor: 63 | 64 | ![runtime-statistics](/images/debugging/runtime-statistics.png) 65 | 66 | ## Exercise 3: Core dump 67 | 68 | _Come back to this when I understand GDB better_ 69 | 70 | {% include incomplete.md %} 71 | -------------------------------------------------------------------------------- /docs/7-debugging/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '7. Debugging' 4 | has_children: true 5 | nav_order: 9 6 | --- -------------------------------------------------------------------------------- /docs/7-debugging/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '7.1 Introduction' 4 | parent: '7. Debugging' 5 | --- 6 | 7 | # Introduction 8 | 9 | ## What are some common debugging techniques and when to use them? 10 | 11 | The three most common debugging techniques we'll be discussing here are: 12 | - thread aware debugging (debug probe) 13 | - thread analysis 14 | - core dump 15 | 16 | ## How does thread aware debugging work? 17 | 18 | To enable thread-aware debugging you'll need to add the line shown below to `zephyr/boards/arm/nucleo_f756zg/support/openocd.cfg` 19 | 20 | ``` 21 | # Enable Zephyr thread awareness 22 | $_TARGETNAME configure -rtos Zephyr 23 | ``` 24 | 25 | ![openocd-threads-support](/images/debugging/openocd-threads-support.png) 26 | 27 | A debug probe is special hardware which allows you to control execution of a Zephyr application running on a separate board. Debug probes usually allow reading and writing registers and memory, and support breakpoint debugging of the Zephyr application on your host workstation using tools like GDB. 28 | 29 | ST-LINK is a serial and debug adapter built into all Nucleo and Discovery boards. It provides a bridge between your computer (or other SUB host) and the embedded target processor, which can be used for debugging, flash programming, and serial communication, all over a simple USB cable. 30 | 31 | It is compatible with the following host debug tools: 32 | - OpenOCD Debug Host Tools 33 | - J-Link Debug Host Tools 34 | 35 | In this tutorial we'll be using OpenOCD. 36 | 37 | ## How to use OpenOCD? 38 | 39 | OpenOCD is available by default on ST-Link and configured as the default flash and debug tool. Flash and debug can be done as follows: 40 | ``` 41 | west build -b nucleo_f756zg 42 | west flash 43 | ``` 44 | ``` 45 | west build -b nucleo_f756zg 46 | west debug 47 | ``` 48 | 49 | ## How does thread analysis work? 50 | 51 | The thread analyzer module enables all the Zephyr options required to track the thread information, e.g. thread stack size usage and other runtime thread statistics. 52 | 53 | The analysis is performed on demand when the application calls thread_analyzer_run() or thread_analyzer_print(). 54 | 55 | The output is put on the serial connection. 56 | 57 | ## How does core dump work? 58 | 59 | The core dump module enables dumping the CPU registers and memory content for offline debugging. This module is called when a fatal error is encountered, and the data is printed or stored to which backends are enabled. This core dump data can be fed into a custom made GDB server as a remote target for GDB. CPU registers, memory content and stack can be examined in the debugger. 60 | 61 | This usually involves the following steps: 62 | 1) Get the core dump log from the device depending on enabled backends. 63 | 2) Convert the core dump log into a binary format that can be parsed by the GDB server. For example, scripts/coredump/coredump_serial_log_parser.py can be used to convert the serial console log into a binary file. 64 | 3) Start the custom GDB server using the script scripts/coredump/coredump_gdbserver.py with the core dump binary log file, and the Zephyr ELF file as parameters. 65 | 4) Start the debugger corresponding to the target architecture. 66 | -------------------------------------------------------------------------------- /docs/7-debugging/kconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '7.3 Kconfig' 4 | parent: '7. Debugging' 5 | --- 6 | 7 | ## OpenOCD 8 | 9 | ### Thread analyzer 10 | 11 | | CONFIG | Description | 12 | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | 13 | | THREAD_ANALYZER | enable the module | 14 | | THREAD_ANALYZER_USE_PRINTK | use printk for thread statistics | 15 | | THREAD_ANALYZER_USE_LOG | use the logger for thread statistics | 16 | | THREAD_ANALYZER_AUTO | run the thread analyzer automatically. You do not need to add any code to the application when using this option | 17 | | THREAD_ANALYZER_AUTO_INTERVAL | the time for which the module sleeps between consecutive printing of thread analysis in automatic mode | 18 | | THREAD_ANALYZER_AUTO_STACK_SIZE | the stack for thread analyzer automatic thread | 19 | | THREAD_NAME | enable this option in the kernel to print the name of the thread instead of its ID | 20 | | THREAD_RUNTIME_STATS | enable this option to print thread runtime data such as utilization (This options is automatically selected by THREAD_ANALYZER) | 21 | 22 | ### Core dump 23 | 24 | | CONFIG | Description | 25 | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 26 | | DEBUG_COREDUMP | enable the module | 27 | | DEBUG_COREDUMP_BACKEND_LOGGING | use log module for core dump output | 28 | | DEBUG_COREDUMP_BACKEND_NULL | fallback core dump backend if other backends cannot be enabled. All output is sent to null. | 29 | | DEBUG_COREDUMP_MEMORY_DUMP_MIN | only dumps the stack of the exception thread, its thread struct, and some other bare minimal data to support walking the stack in debugger. Use this only if absolute minimum of data dump is desired. | -------------------------------------------------------------------------------- /docs/8-interrupts/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '8.2 Commands' 4 | parent: '8. Interrupts' 5 | --- 6 | 7 | The following interrupt-related APIs are provided by irq.h: 8 | 9 | | Command | Description | 10 | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 11 | | IRQ_CONNECT | Initialize an interrupt handler. This routine initializes an interrupt handler for an IRQ. The IRQ must be subsequently enabled before the interrupt handler begins servicing interrupts. | 12 | | IRQ_DIRECT_CONNECT | Initialize a ‘direct’ interrupt handler. This routine initializes an interrupt handler for an IRQ. The IRQ must be subsequently enabled via irq_enable() before the interrupt handler begins servicing interrupts. | 13 | | ISR_DIRECT_HEADER | Common tasks before executing the body of an ISR. This macro must be at the beginning of all direct interrupts and performs minimal architecture-specific tasks before the ISR itself can run. It takes no arguments and has no return value. | 14 | | ISR_DIRECT_FOOTER | Common tasks before exiting the body of an ISR. This macro must be at the end of all direct interrupts and performs minimal architecture-specific tasks like EOI. It has no return value. | 15 | | ISR_DIRECT_PM | Perform power management idle exit logic. | 16 | | ISR_DIRECT_DECLARE | Helper macro to declare a direct interrupt service routine. | 17 | | irq_lock() | Lock interrupts. This routine disables all interrupts on the CPU. | 18 | | irq_unlock() | Unlock interrupts. | 19 | | irq_enable() | Enable an IRQ. | 20 | | irq_disable() | Disable an IRQ. | 21 | | irq_is_enabled() | Get IRQ enable state. | 22 | 23 | 24 | The following interrupt-related APIs are provided by kernel.h: 25 | 26 | | Command | Description | 27 | | --------------------- | ----------------------------------------------------- | 28 | | k_is_in_isr() | Determine if code is running at interrupt level. | 29 | | k_is_preempt_thread() | Determine if code is running in a preemptible thread. | 30 | 31 | -------------------------------------------------------------------------------- /docs/8-interrupts/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '8.4 Exercise' 4 | parent: '8. Interrupts' 5 | --- 6 | 7 | ## Button-interrupt 8 | GPIO-input-interrupt 9 | 10 | Configure an interrupt on a button press. 11 | 12 | 1 thread running continuously putting out "loop message" every second 13 | 14 | on button press: print out "isr message" 15 | 16 | 17 | 18 | [Zephyr docs](https://docs.zephyrproject.org/1.9.0/kernel/other/interrupts.html) 19 | [Example 1](https://github.com/zephyrproject-rtos/zephyr/issues/13514) 20 | [Example 2](https://github.com/zephyrproject-rtos/zephyr/issues/9630) 21 | 22 | User button and LED aliases can be found in the devicetree file `build/zephyr/zephyr.dts`. 23 | 24 | ![button-interrupt-alias](/images/interrupts/button-interrupt-alias.png) 25 | 26 | Expected output: 27 | 28 | ![button-interrupt-output](/images/interrupts/button-interrupt-output.png) -------------------------------------------------------------------------------- /docs/8-interrupts/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '8. Interrupts' 4 | has_children: true 5 | nav_order: 10 6 | --- -------------------------------------------------------------------------------- /docs/8-interrupts/kconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '8.3 Kconfig' 4 | parent: '8. Interrupts' 5 | --- 6 | -------------------------------------------------------------------------------- /docs/9-timers/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '9.2 Commands' 4 | parent: '9. Timers' 5 | --- 6 | 7 | | Command | Description | 8 | | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 9 | | k_timer_init | Initialize a timer. This routine initializes a timer, prior to its first use. | 10 | | k_timer_start | Start a timer. This routine starts a timer, and resets its status to zero. The timer begins counting down using the specified duration and period values. | 11 | | k_timer_stop | Stop a timer. This routine stops a running timer prematurely. The timer’s stop function, if one exists, is invoked by the caller. | 12 | | k_timer_status_get | Read timer status. This routine reads the timer’s status, which indicates the number of times it has expired since its status was last read. | 13 | | k_timer_status_sync | Synchronize thread to timer expiration. This routine blocks the calling thread until the timer’s status is non-zero (indicating that it has expired at least once since it was last examined) or the timer is stopped. If the timer status is already non-zero, or the timer is already stopped, the caller continues without waiting. | 14 | | k_timer_expires_ticks | Get next expiration time of a timer, in system ticks. | 15 | | k_timer_remaining_ticks | Get time remaining before a timer next expires, in system ticks. | 16 | | k_timer_remaining_get | Get time remaining before a timer next expires. | 17 | -------------------------------------------------------------------------------- /docs/9-timers/exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '9.4 Exercise' 4 | parent: '9. Timers' 5 | --- 6 | 7 | Define a timer that will print a message after 2 s and then every second. -------------------------------------------------------------------------------- /docs/9-timers/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '9. Timers' 4 | has_children: true 5 | nav_order: 11 6 | --- -------------------------------------------------------------------------------- /docs/9-timers/kconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: '9.3 Kconfig' 4 | parent: '9. Timers' 5 | --- 6 | 7 | None -------------------------------------------------------------------------------- /docs/Contributions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Contributing 4 | nav_order: 13 5 | --- 6 | 7 | ## Contributing to the Zephyr RTOS Tutorial 8 | 9 | The general workflow is the following: 10 | 11 | 1. Find an [issue](https://github.com/maksimdrachov/zephyr-rtos-tutorial/issues) you want to start working on or create a new one. 12 | 1. In comments claim that you want to take over the issue. The first person who does this will be assigned to the issue. 13 | 1. [Fork the repository](https://help.github.com/articles/fork-a-repo/). 14 | 1. Make all necessary changes. 15 | 1. [Send a pull request](https://help.github.com/articles/about-pull-requests/). 16 | 1. After a review, your changes will be merged. 17 | 18 | The following types of contributions are particularly useful for the project. 19 | 20 | 1. Validating the source code and text of the lessons, fixing bugs and errors. 21 | 1. Help in making lessons content more accurate and easier to understand. 22 | 1. Working on the source code and content for new lessons. 23 | 1. Sharing source code of completed exercises. 24 | 1. Suggesting new exercises. 25 | 1. Providing feedback, requesting new features and content. 26 | 1. Anything else that can help the project. 27 | -------------------------------------------------------------------------------- /docs/Introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Introduction 4 | nav_order: 1 5 | --- 6 | 7 | # Introduction 8 | 9 | In this tutorial we'll be taking a closer look at the Zephyr real-time operating system (RTOS). Before we dive in, it might be useful to understand why RTOS has become a foundational building block for modern embedded systems. 10 | 11 | As embedded systems have become increasingly complex with more devices becoming connected to the Internet, the difficulty of writing software for such systems has increased as well. Modern applications often require a delicate balance: between executing multiple tasks simultaneously (with tight timing constraints), as well as managing complex protocols such as WiFi, Bluetooth, USB, encryption,... To deal with this increased complexity, programming purely on the bare metal is no longer a feasible proposition. An RTOS provides an abstraction layer for certain commonly used functionality allowing the developer to focus on the actual application itself, without having to re-implement everything from scratch. 12 | 13 | In this tutorial we won't necessarily be digging 'under the hood' of the workings of a modern RTOS, there have already been written many [books](https://www.amazon.com/Embedded-RTOS-Design-Insights-Implementation/dp/0128228512/) that cover this topic quite extensively. Instead we'll be mainly focusing on learning how to *use* the functionality provided by Zephyr. 14 | 15 | ## Why Zephyr? 16 | 17 | Zephyr RTOS is a relatively new real-time operating system that offers support for a wide variety of MCU architectures. You get all the common kernel features such as threads, semaphores, mutexes, etc. that other RTOSes provide (with FreeRTOS being another popular option). A complete in-depth technical comparison between the different RTOSes is beyond the scope this tutorial, but suffice it to say I think Zephyr does a good job in making it easy to work with these "kernel objects". 18 | 19 | ### Open source 20 | 21 | Another major benefit of Zephyr RTOS is that it is completely open source and backed by the Linux Foundation. Other RTOSes are often backed by industry giants such as Amazon (FreeRTOS), Azure RTOS (Microsoft) and MbedOS (ARM); resulting in possible vendor lock-in down the line. 22 | 23 | Perhaps unsurprisingly this open nature has heavily accelereated Zephyr's adoption, this can be seen when comparing the number of contributions between the different RTOS projects: 24 | 25 | [Contributions to the Zephyr RTOS GitHub repository](https://github.com/zephyrproject-rtos/zephyr/graphs/contributors) 26 | 27 | ![zephyr-github](../images/introduction/zephyr-github.png) 28 | 29 | [Contributions to the FreeRTOS GitHub repository](https://github.com/FreeRTOS/FreeRTOS-Kernel/graphs/contributors) 30 | 31 | ![freertos-github](../images/introduction/freertos-github.png) 32 | 33 | [Contributions to the Azure RTOS GitHub repository](https://github.com/azure-rtos/threadx/graphs/contributors) 34 | 35 | ![azure-rtos-github](../images/introduction/azure-rtos-github.png) 36 | 37 | ### Kconfig 38 | 39 | Another distinctive feature of Zephyr is its unique build and configuration system. For those coming from the embedded Linux world, Kconfig is a familiar feature that allows developers to adjust the build process of the kernel, and include only those features that are used (hereby reducing the memory footprint). 40 | 41 | There's many more features that can be discussed, if you're interested [this](https://medium.com/geekculture/the-zephyr-rtos-is-awesome-931bce3a695f) article covers some additional benefits of using Zephyr. 42 | 43 | ## Examples 44 | 45 | And last but not least here are some companies that are already using Zephyr in their products: 46 | 47 | - teenage engineering ([video](https://twitter.com/ZephyrIoT/status/1366674644145737730)) 48 | - byte lab ([blog](https://www.byte-lab.com/why-developers-should-choose-zephyr-rtos/)) 49 | - Golioth ([blog](https://zephyrproject.org/connectig-conexio-stratus-to-golioth/)) 50 | - Antmicro ([blog](https://www.zephyrproject.org/antmicro-doubles-down-on-commitment-to-zephyr-rtos-as-community-grows-to-more-than-1000-contributors/)) 51 | 52 | -------------------------------------------------------------------------------- /docs/Prerequisites.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Prerequisites 4 | nav_order: 2 5 | --- 6 | 7 | # Prerequisites 8 | 9 | ## 1. [Nucleo L552ZE-Q](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html) 10 | 11 | This is the board that I'll be using for the tutorial, since Zephyr is platform-agnostic you can also use whatever you have laying around, but the build commands will look slightly different for you. I can recommend picking an STM32 or Nordic board as those usually are the best supported (full RPI Pico support is still [pending](https://github.com/zephyrproject-rtos/zephyr/pull/34835)). 12 | 13 | [Zephyr supported boards](https://docs.zephyrproject.org/latest/boards/index.html#boards) 14 | 15 | ## 2. [USB to Micro-USB Cable](https://www.google.com/search?q=micro+usb) 16 | 17 | To connect you board to your computer. 18 | 19 | ## 3. Optional 20 | 21 | To play with some of the more advanced features, you'll need a board that supports this. 22 | 23 | - Ethernet: [Nucleo F756ZG](https://www.st.com/en/evaluation-tools/nucleo-f756zg.html) 24 | - Bluetooth: [Nordic nRF52-DK](https://www.nordicsemi.com/Products/Development-hardware/nrf52-dk) 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /exercises/basic-sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(basic-sample) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/basic-sample/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | 3 | -------------------------------------------------------------------------------- /exercises/basic-sample/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | /* 1000 msec = 1 sec */ 12 | #define SLEEP_TIME_MS 1000 13 | 14 | void main(void) 15 | { 16 | printk("main: basic sample started \n"); 17 | 18 | while (1) { 19 | printk("main: basic sample loop \n"); 20 | k_msleep(SLEEP_TIME_MS); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /exercises/debugging/multi-thread-debug/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(threads) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/debugging/multi-thread-debug/README.rst: -------------------------------------------------------------------------------- 1 | .. _96b_carbon_multi_thread_blinky: 2 | 3 | Basic Thread Example 4 | #################### 5 | 6 | Overview 7 | ******** 8 | 9 | This example demonstrates spawning multiple threads using 10 | :c:func:`K_THREAD_DEFINE`. It spawns three threads. Each thread is then defined 11 | at compile time using K_THREAD_DEFINE. 12 | 13 | The first two each control an LED. These LEDs, ``led0`` and ``led1``, have 14 | loop control and timing logic controlled by separate functions. 15 | 16 | - ``blink0()`` controls ``led0`` and has a 100ms sleep cycle 17 | - ``blink1()`` controls ``led1`` and has a 1000ms sleep cycle 18 | 19 | When either of these threads toggles its LED, it also pushes information into a 20 | :ref:`FIFO ` identifying the thread/LED and how many times it has 21 | been toggled. 22 | 23 | The third thread uses :c:func:`printk` to print the information added to the 24 | FIFO to the device console. 25 | 26 | Requirements 27 | ************ 28 | 29 | The board must have two LEDs connected via GPIO pins. These are called "User 30 | LEDs" on many of Zephyr's :ref:`boards`. The LEDs must be configured using the 31 | ``led0`` and ``led1`` :ref:`devicetree ` aliases, usually in the 32 | :ref:`BOARD.dts file `. 33 | 34 | You will see one of these errors if you try to build this sample for an 35 | unsupported board: 36 | 37 | .. code-block:: none 38 | 39 | Unsupported board: led0 devicetree alias is not defined 40 | Unsupported board: led1 devicetree alias is not defined 41 | 42 | Building 43 | ******** 44 | 45 | For example, to build this sample for :ref:`96b_carbon_board`: 46 | 47 | .. zephyr-app-commands:: 48 | :zephyr-app: samples/basic/threads 49 | :board: 96b_carbon 50 | :goals: build flash 51 | :compact: 52 | 53 | Change ``96b_carbon`` appropriately for other supported boards. 54 | -------------------------------------------------------------------------------- /exercises/debugging/multi-thread-debug/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | CONFIG_TIMESLICING=y 5 | CONFIG_TIMESLICE_SIZE=10 6 | 7 | -------------------------------------------------------------------------------- /exercises/debugging/multi-thread-debug/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A basic demo to showcase multi-threading 3 | using K_THREAD_DEFINE 4 | name: Basic Thread Demo 5 | tests: 6 | sample.basic.threads: 7 | tags: kernel threads gpio 8 | filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and 9 | dt_enabled_alias_with_parent_compat("led1", "gpio-leds") 10 | depends_on: gpio 11 | harness: console 12 | harness_config: 13 | type: multi_line 14 | ordered: false 15 | regex: 16 | - "Toggled led0; counter=(.*)" 17 | - "Toggled led1; counter=(.*)" 18 | -------------------------------------------------------------------------------- /exercises/debugging/multi-thread-debug/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | /* size of stack area used by each thread */ 11 | #define STACKSIZE 1024 12 | 13 | #define PRIORITY_THREAD_1 (1) 14 | #define PRIORITY_THREAD_2 (1) 15 | #define PRIORITY_THREAD_3 (1) 16 | 17 | 18 | K_THREAD_STACK_DEFINE(thread_1_stack_area, STACKSIZE); 19 | static struct k_thread thread_1_data; 20 | 21 | K_THREAD_STACK_DEFINE(thread_2_stack_area, STACKSIZE); 22 | static struct k_thread thread_2_data; 23 | 24 | K_THREAD_STACK_DEFINE(thread_3_stack_area, STACKSIZE); 25 | static struct k_thread thread_3_data; 26 | 27 | void thread_1(void *dummy1, void *dummy2, void *dummy3) 28 | { 29 | ARG_UNUSED(dummy1); 30 | ARG_UNUSED(dummy2); 31 | ARG_UNUSED(dummy3); 32 | 33 | printk("thread_1: thread started \n"); 34 | 35 | 36 | while (1) 37 | { 38 | printk("thread_1: thread loop \n"); 39 | } 40 | 41 | } 42 | 43 | void thread_2(void *dummy1, void *dummy2, void *dummy3) 44 | { 45 | ARG_UNUSED(dummy1); 46 | ARG_UNUSED(dummy2); 47 | ARG_UNUSED(dummy3); 48 | 49 | printk("thread_2: thread started \n"); 50 | 51 | while (1) 52 | { 53 | printk("thread_2: thread loop \n"); 54 | } 55 | 56 | } 57 | 58 | void thread_3(void *dummy1, void *dummy2, void *dummy3) 59 | { 60 | ARG_UNUSED(dummy1); 61 | ARG_UNUSED(dummy2); 62 | ARG_UNUSED(dummy3); 63 | 64 | printk("thread_3: thread started \n"); 65 | 66 | while (1) 67 | { 68 | printk("thread_3: thread loop \n"); 69 | } 70 | 71 | } 72 | 73 | void main(void) 74 | { 75 | k_thread_create(&thread_1_data, thread_1_stack_area, 76 | K_THREAD_STACK_SIZEOF(thread_1_stack_area), 77 | thread_1, NULL, NULL, NULL, 78 | PRIORITY_THREAD_1, 0, K_FOREVER); 79 | k_thread_name_set(&thread_1_data, "thread_1"); 80 | 81 | k_thread_create(&thread_2_data, thread_2_stack_area, 82 | K_THREAD_STACK_SIZEOF(thread_2_stack_area), 83 | thread_2, NULL, NULL, NULL, 84 | PRIORITY_THREAD_2, 0, K_FOREVER); 85 | k_thread_name_set(&thread_2_data, "thread_2"); 86 | 87 | k_thread_create(&thread_3_data, thread_3_stack_area, 88 | K_THREAD_STACK_SIZEOF(thread_3_stack_area), 89 | thread_3, NULL, NULL, NULL, 90 | PRIORITY_THREAD_3, 0, K_FOREVER); 91 | k_thread_name_set(&thread_3_data, "thread_3"); 92 | 93 | k_thread_start(&thread_1_data); 94 | k_thread_start(&thread_2_data); 95 | k_thread_start(&thread_3_data); 96 | } 97 | -------------------------------------------------------------------------------- /exercises/debugging/runtime-statistics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(threads) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/debugging/runtime-statistics/README.rst: -------------------------------------------------------------------------------- 1 | .. _96b_carbon_multi_thread_blinky: 2 | 3 | Basic Thread Example 4 | #################### 5 | 6 | Overview 7 | ******** 8 | 9 | This example demonstrates spawning multiple threads using 10 | :c:func:`K_THREAD_DEFINE`. It spawns three threads. Each thread is then defined 11 | at compile time using K_THREAD_DEFINE. 12 | 13 | The first two each control an LED. These LEDs, ``led0`` and ``led1``, have 14 | loop control and timing logic controlled by separate functions. 15 | 16 | - ``blink0()`` controls ``led0`` and has a 100ms sleep cycle 17 | - ``blink1()`` controls ``led1`` and has a 1000ms sleep cycle 18 | 19 | When either of these threads toggles its LED, it also pushes information into a 20 | :ref:`FIFO ` identifying the thread/LED and how many times it has 21 | been toggled. 22 | 23 | The third thread uses :c:func:`printk` to print the information added to the 24 | FIFO to the device console. 25 | 26 | Requirements 27 | ************ 28 | 29 | The board must have two LEDs connected via GPIO pins. These are called "User 30 | LEDs" on many of Zephyr's :ref:`boards`. The LEDs must be configured using the 31 | ``led0`` and ``led1`` :ref:`devicetree ` aliases, usually in the 32 | :ref:`BOARD.dts file `. 33 | 34 | You will see one of these errors if you try to build this sample for an 35 | unsupported board: 36 | 37 | .. code-block:: none 38 | 39 | Unsupported board: led0 devicetree alias is not defined 40 | Unsupported board: led1 devicetree alias is not defined 41 | 42 | Building 43 | ******** 44 | 45 | For example, to build this sample for :ref:`96b_carbon_board`: 46 | 47 | .. zephyr-app-commands:: 48 | :zephyr-app: samples/basic/threads 49 | :board: 96b_carbon 50 | :goals: build flash 51 | :compact: 52 | 53 | Change ``96b_carbon`` appropriately for other supported boards. 54 | -------------------------------------------------------------------------------- /exercises/debugging/runtime-statistics/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | CONFIG_TIMESLICING=y 5 | CONFIG_TIMESLICE_SIZE=50 6 | CONFIG_THREAD_ANALYZER=y 7 | CONFIG_THREAD_ANALYZER_USE_PRINTK=y 8 | 9 | 10 | -------------------------------------------------------------------------------- /exercises/debugging/runtime-statistics/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A basic demo to showcase multi-threading 3 | using K_THREAD_DEFINE 4 | name: Basic Thread Demo 5 | tests: 6 | sample.basic.threads: 7 | tags: kernel threads gpio 8 | filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and 9 | dt_enabled_alias_with_parent_compat("led1", "gpio-leds") 10 | depends_on: gpio 11 | harness: console 12 | harness_config: 13 | type: multi_line 14 | ordered: false 15 | regex: 16 | - "Toggled led0; counter=(.*)" 17 | - "Toggled led1; counter=(.*)" 18 | -------------------------------------------------------------------------------- /exercises/debugging/runtime-statistics/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | #define PRIORITY_THREAD_1 (1) 16 | #define PRIORITY_THREAD_2 (1) 17 | #define PRIORITY_THREAD_3 (1) 18 | 19 | 20 | K_THREAD_STACK_DEFINE(thread_1_stack_area, STACKSIZE); 21 | static struct k_thread thread_1_data; 22 | 23 | K_THREAD_STACK_DEFINE(thread_2_stack_area, STACKSIZE); 24 | static struct k_thread thread_2_data; 25 | 26 | K_THREAD_STACK_DEFINE(thread_3_stack_area, STACKSIZE); 27 | static struct k_thread thread_3_data; 28 | 29 | void thread_1(void *dummy1, void *dummy2, void *dummy3) 30 | { 31 | ARG_UNUSED(dummy1); 32 | ARG_UNUSED(dummy2); 33 | ARG_UNUSED(dummy3); 34 | 35 | printk("thread_1: thread started \n"); 36 | 37 | 38 | while (1) 39 | { 40 | printk("thread_1: thread loop \n"); 41 | } 42 | 43 | } 44 | 45 | void thread_2(void *dummy1, void *dummy2, void *dummy3) 46 | { 47 | ARG_UNUSED(dummy1); 48 | ARG_UNUSED(dummy2); 49 | ARG_UNUSED(dummy3); 50 | 51 | printk("thread_2: thread started \n"); 52 | 53 | while (1) 54 | { 55 | printk("thread_2: thread loop \n"); 56 | } 57 | 58 | } 59 | 60 | void thread_3(void *dummy1, void *dummy2, void *dummy3) 61 | { 62 | ARG_UNUSED(dummy1); 63 | ARG_UNUSED(dummy2); 64 | ARG_UNUSED(dummy3); 65 | 66 | printk("thread_3: thread started \n"); 67 | 68 | while (1) 69 | { 70 | printk("thread_3: thread loop \n"); 71 | thread_analyzer_print(); 72 | } 73 | 74 | } 75 | 76 | void main(void) 77 | { 78 | k_thread_create(&thread_1_data, thread_1_stack_area, 79 | K_THREAD_STACK_SIZEOF(thread_1_stack_area), 80 | thread_1, NULL, NULL, NULL, 81 | PRIORITY_THREAD_1, 0, K_FOREVER); 82 | k_thread_name_set(&thread_1_data, "thread_1"); 83 | 84 | k_thread_create(&thread_2_data, thread_2_stack_area, 85 | K_THREAD_STACK_SIZEOF(thread_2_stack_area), 86 | thread_2, NULL, NULL, NULL, 87 | PRIORITY_THREAD_2, 0, K_FOREVER); 88 | k_thread_name_set(&thread_2_data, "thread_2"); 89 | 90 | k_thread_create(&thread_3_data, thread_3_stack_area, 91 | K_THREAD_STACK_SIZEOF(thread_3_stack_area), 92 | thread_3, NULL, NULL, NULL, 93 | PRIORITY_THREAD_3, 0, K_FOREVER); 94 | k_thread_name_set(&thread_3_data, "thread_3"); 95 | 96 | k_thread_start(&thread_1_data); 97 | k_thread_start(&thread_2_data); 98 | k_thread_start(&thread_3_data); 99 | } 100 | -------------------------------------------------------------------------------- /exercises/gpio/blinky/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(blinky) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/gpio/blinky/README.rst: -------------------------------------------------------------------------------- 1 | .. _blinky-sample: 2 | 3 | Blinky 4 | ###### 5 | 6 | Overview 7 | ******** 8 | 9 | Blinky is a simple application which blinks an LED forever using the :ref:`GPIO 10 | API `. The source code shows how to configure GPIO pins as outputs, 11 | then turn them on and off. 12 | 13 | See :ref:`pwm-blinky-sample` for a sample which uses the PWM API to blink an 14 | LED. 15 | 16 | .. _blinky-sample-requirements: 17 | 18 | Requirements 19 | ************ 20 | 21 | You will see this error if you try to build Blinky for an unsupported board: 22 | 23 | .. code-block:: none 24 | 25 | Unsupported board: led0 devicetree alias is not defined 26 | 27 | The board must have an LED connected via a GPIO pin. These are called "User 28 | LEDs" on many of Zephyr's :ref:`boards`. The LED must be configured using the 29 | ``led0`` :ref:`devicetree ` alias. This is usually done in the 30 | :ref:`BOARD.dts file ` or a :ref:`devicetree overlay 31 | `. 32 | 33 | Building and Running 34 | ******************** 35 | 36 | Build and flash Blinky as follows, changing ``reel_board`` for your board: 37 | 38 | .. zephyr-app-commands:: 39 | :zephyr-app: samples/basic/blinky 40 | :board: reel_board 41 | :goals: build flash 42 | :compact: 43 | 44 | After flashing, the LED starts to blink. Blinky does not print to the console. 45 | -------------------------------------------------------------------------------- /exercises/gpio/blinky/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_GPIO=y 2 | -------------------------------------------------------------------------------- /exercises/gpio/blinky/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | name: Blinky Sample 3 | tests: 4 | sample.basic.blinky: 5 | tags: LED gpio 6 | filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") 7 | depends_on: gpio 8 | harness: led 9 | integration_platforms: 10 | - frdm_k64f 11 | -------------------------------------------------------------------------------- /exercises/gpio/blinky/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /* 1000 msec = 1 sec */ 13 | #define SLEEP_TIME_MS 1000 14 | 15 | /* The devicetree node identifier for the "led0" alias. */ 16 | #define LED0_NODE DT_ALIAS(led0) 17 | 18 | #if DT_NODE_HAS_STATUS(LED0_NODE, okay) 19 | #define LED0 DT_GPIO_LABEL(LED0_NODE, gpios) 20 | #define PIN DT_GPIO_PIN(LED0_NODE, gpios) 21 | #define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios) 22 | #else 23 | /* A build error here means your board isn't set up to blink an LED. */ 24 | #error "Unsupported board: led0 devicetree alias is not defined" 25 | #define LED0 "" 26 | #define PIN 0 27 | #define FLAGS 0 28 | #endif 29 | 30 | void main(void) 31 | { 32 | const struct device *dev; 33 | bool led_is_on = true; 34 | int ret; 35 | 36 | dev = device_get_binding(LED0); 37 | if (dev == NULL) { 38 | return; 39 | } 40 | 41 | ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS); 42 | if (ret < 0) { 43 | return; 44 | } 45 | 46 | while (1) { 47 | 48 | gpio_pin_set(dev, PIN, (int)led_is_on); 49 | led_is_on = !led_is_on; 50 | k_msleep(SLEEP_TIME_MS); 51 | 52 | 53 | /* Or using toggle: 54 | gpio_pin_toggle(dev, PIN); 55 | k_msleep(SLEEP_TIME_MS); 56 | */ 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /exercises/gpio/button/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(button) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/gpio/button/README.rst: -------------------------------------------------------------------------------- 1 | .. _button-sample: 2 | 3 | Button 4 | ###### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple button demo showcasing the use of GPIO input with interrupts. 10 | The sample prints a message to the console each time a button is pressed. 11 | 12 | Requirements 13 | ************ 14 | 15 | The board hardware must have a push button connected via a GPIO pin. These are 16 | called "User buttons" on many of Zephyr's :ref:`boards`. 17 | 18 | The button must be configured using the ``sw0`` :ref:`devicetree ` 19 | alias, usually in the :ref:`BOARD.dts file `. You will 20 | see this error if you try to build this sample for an unsupported board: 21 | 22 | .. code-block:: none 23 | 24 | Unsupported board: sw0 devicetree alias is not defined 25 | 26 | You may see additional build errors if the ``sw0`` alias exists, but is not 27 | properly defined. 28 | 29 | The sample additionally supports an optional ``led0`` devicetree alias. This is 30 | the same alias used by the :ref:`blinky-sample`. If this is provided, the LED 31 | will be turned on when the button is pressed, and turned off off when it is 32 | released. 33 | 34 | Devicetree details 35 | ================== 36 | 37 | This section provides more details on devicetree configuration. 38 | 39 | Here is a minimal devicetree fragment which supports this sample. This only 40 | includes a ``sw0`` alias; the optional ``led0`` alias is left out for 41 | simplicity. 42 | 43 | .. code-block:: devicetree 44 | 45 | / { 46 | aliases { 47 | sw0 = &button0; 48 | }; 49 | 50 | soc { 51 | gpio0: gpio@0 { 52 | status = "okay"; 53 | gpio-controller; 54 | #gpio-cells = <2>; 55 | /* ... */ 56 | }; 57 | }; 58 | 59 | buttons { 60 | compatible = "gpio-keys"; 61 | button0: button_0 { 62 | gpios = < &gpio0 PIN FLAGS >; 63 | label = "User button"; 64 | }; 65 | /* ... other buttons ... */ 66 | }; 67 | }; 68 | 69 | As shown, the ``sw0`` devicetree alias must point to a child node of a node 70 | with a "gpio-keys" :ref:`compatible `. 71 | 72 | The above situation is for the common case where: 73 | 74 | - ``gpio0`` is an example node label referring to a GPIO controller 75 | - ``PIN`` should be a pin number, like ``8`` or ``0`` 76 | - ``FLAGS`` should be a logical OR of :ref:`GPIO configuration flags ` 77 | meant to apply to the button, such as ``(GPIO_PULL_UP | GPIO_ACTIVE_LOW)`` 78 | 79 | This assumes the common case, where ``#gpio-cells = <2>`` in the ``gpio0`` 80 | node, and that the GPIO controller's devicetree binding names those two cells 81 | "pin" and "flags" like so: 82 | 83 | .. code-block:: yaml 84 | 85 | gpio-cells: 86 | - pin 87 | - flags 88 | 89 | This sample requires a ``pin`` cell in the ``gpios`` property. The ``flags`` 90 | cell is optional, however, and the sample still works if the GPIO cells 91 | do not contain ``flags``. 92 | 93 | Building and Running 94 | ******************** 95 | 96 | This sample can be built for multiple boards, in this example we will build it 97 | for the nucleo_f103rb board: 98 | 99 | .. zephyr-app-commands:: 100 | :zephyr-app: samples/basic/button 101 | :board: nucleo_f103rb 102 | :goals: build 103 | :compact: 104 | 105 | After startup, the program looks up a predefined GPIO device, and configures the 106 | pin in input mode, enabling interrupt generation on falling edge. During each 107 | iteration of the main loop, the state of GPIO line is monitored and printed to 108 | the serial console. When the input button gets pressed, the interrupt handler 109 | will print an information about this event along with its timestamp. 110 | -------------------------------------------------------------------------------- /exercises/gpio/button/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_GPIO=y 2 | -------------------------------------------------------------------------------- /exercises/gpio/button/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | name: Button Sample 3 | tests: 4 | sample.basic.button: 5 | tags: button gpio 6 | filter: dt_enabled_alias_with_parent_compat("sw0", "gpio-keys") 7 | depends_on: gpio 8 | harness: button 9 | -------------------------------------------------------------------------------- /exercises/gpio/button/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Open-RnD Sp. z o.o. 3 | * Copyright (c) 2020 Nordic Semiconductor ASA 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define SLEEP_TIME_MS 1 16 | 17 | /* 18 | * Get button configuration from the devicetree sw0 alias. This is mandatory. 19 | */ 20 | #define SW0_NODE DT_ALIAS(sw0) 21 | #if !DT_NODE_HAS_STATUS(SW0_NODE, okay) 22 | #error "Unsupported board: sw0 devicetree alias is not defined" 23 | #endif 24 | static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, 25 | {0}); 26 | 27 | 28 | /* 29 | * The led0 devicetree alias is optional. If present, we'll use it 30 | * to turn on the LED whenever the button is pressed. 31 | */ 32 | static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, 33 | {0}); 34 | 35 | void main(void) 36 | { 37 | int ret; 38 | 39 | /* Make sure button is ready */ 40 | if (!device_is_ready(button.port)) { 41 | printk("Error: button device %s is not ready\n", 42 | button.port->name); 43 | return; 44 | } 45 | 46 | /* Configure button as input */ 47 | ret = gpio_pin_configure_dt(&button, GPIO_INPUT); 48 | if (ret != 0) { 49 | printk("Error %d: failed to configure %s pin %d\n", 50 | ret, button.port->name, button.pin); 51 | return; 52 | } 53 | 54 | /* Configure LED port as output */ 55 | if (led.port) { 56 | ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT); 57 | if (ret != 0) { 58 | printk("Error %d: failed to configure LED device %s pin %d\n", 59 | ret, led.port->name, led.pin); 60 | led.port = NULL; 61 | } else { 62 | printk("Set up LED at %s pin %d\n", led.port->name, led.pin); 63 | } 64 | } 65 | 66 | if (led.port) { 67 | while (1) { 68 | /* If we have an LED, match its state to the button's. */ 69 | int val = gpio_pin_get_dt(&button); 70 | 71 | if (val >= 0) { 72 | gpio_pin_set_dt(&led, val); 73 | } 74 | k_msleep(SLEEP_TIME_MS); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /exercises/gpio/two-leds/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(threads) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/gpio/two-leds/README.rst: -------------------------------------------------------------------------------- 1 | .. _96b_carbon_multi_thread_blinky: 2 | 3 | Basic Thread Example 4 | #################### 5 | 6 | Overview 7 | ******** 8 | 9 | This example demonstrates spawning multiple threads using 10 | :c:func:`K_THREAD_DEFINE`. It spawns three threads. Each thread is then defined 11 | at compile time using K_THREAD_DEFINE. 12 | 13 | The first two each control an LED. These LEDs, ``led0`` and ``led1``, have 14 | loop control and timing logic controlled by separate functions. 15 | 16 | - ``blink0()`` controls ``led0`` and has a 100ms sleep cycle 17 | - ``blink1()`` controls ``led1`` and has a 1000ms sleep cycle 18 | 19 | When either of these threads toggles its LED, it also pushes information into a 20 | :ref:`FIFO ` identifying the thread/LED and how many times it has 21 | been toggled. 22 | 23 | The third thread uses :c:func:`printk` to print the information added to the 24 | FIFO to the device console. 25 | 26 | Requirements 27 | ************ 28 | 29 | The board must have two LEDs connected via GPIO pins. These are called "User 30 | LEDs" on many of Zephyr's :ref:`boards`. The LEDs must be configured using the 31 | ``led0`` and ``led1`` :ref:`devicetree ` aliases, usually in the 32 | :ref:`BOARD.dts file `. 33 | 34 | You will see one of these errors if you try to build this sample for an 35 | unsupported board: 36 | 37 | .. code-block:: none 38 | 39 | Unsupported board: led0 devicetree alias is not defined 40 | Unsupported board: led1 devicetree alias is not defined 41 | 42 | Building 43 | ******** 44 | 45 | For example, to build this sample for :ref:`96b_carbon_board`: 46 | 47 | .. zephyr-app-commands:: 48 | :zephyr-app: samples/basic/threads 49 | :board: 96b_carbon 50 | :goals: build flash 51 | :compact: 52 | 53 | Change ``96b_carbon`` appropriately for other supported boards. 54 | -------------------------------------------------------------------------------- /exercises/gpio/two-leds/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | CONFIG_HEAP_MEM_POOL_SIZE=256 3 | CONFIG_ASSERT=y 4 | CONFIG_GPIO=y 5 | -------------------------------------------------------------------------------- /exercises/gpio/two-leds/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A basic demo to showcase multi-threading 3 | using K_THREAD_DEFINE 4 | name: Basic Thread Demo 5 | tests: 6 | sample.basic.threads: 7 | tags: kernel threads gpio 8 | filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and 9 | dt_enabled_alias_with_parent_compat("led1", "gpio-leds") 10 | depends_on: gpio 11 | harness: console 12 | harness_config: 13 | type: multi_line 14 | ordered: false 15 | regex: 16 | - "Toggled led0; counter=(.*)" 17 | - "Toggled led1; counter=(.*)" 18 | -------------------------------------------------------------------------------- /exercises/gpio/two-leds/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Linaro Limited 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /* size of stack area used by each thread */ 15 | #define STACKSIZE 1024 16 | 17 | /* scheduling priority used by each thread */ 18 | #define PRIORITY 7 19 | 20 | #define LED0_NODE DT_ALIAS(led0) 21 | #define LED1_NODE DT_ALIAS(led1) 22 | 23 | #if !DT_NODE_HAS_STATUS(LED0_NODE, okay) 24 | #error "Unsupported board: led0 devicetree alias is not defined" 25 | #endif 26 | 27 | #if !DT_NODE_HAS_STATUS(LED1_NODE, okay) 28 | #error "Unsupported board: led1 devicetree alias is not defined" 29 | #endif 30 | 31 | struct printk_data_t { 32 | void *fifo_reserved; /* 1st word reserved for use by fifo */ 33 | uint32_t led; 34 | uint32_t cnt; 35 | }; 36 | 37 | K_FIFO_DEFINE(printk_fifo); 38 | 39 | struct led { 40 | struct gpio_dt_spec spec; 41 | const char *gpio_pin_name; 42 | }; 43 | 44 | static const struct led led0 = { 45 | .spec = GPIO_DT_SPEC_GET_OR(LED0_NODE, gpios, {0}), 46 | .gpio_pin_name = DT_PROP_OR(LED0_NODE, label, ""), 47 | }; 48 | 49 | static const struct led led1 = { 50 | .spec = GPIO_DT_SPEC_GET_OR(LED1_NODE, gpios, {0}), 51 | .gpio_pin_name = DT_PROP_OR(LED1_NODE, label, ""), 52 | }; 53 | 54 | void blink(const struct led *led, uint32_t sleep_ms, uint32_t id) 55 | { 56 | const struct gpio_dt_spec *spec = &led->spec; 57 | int cnt = 0; 58 | int ret; 59 | 60 | if (!device_is_ready(spec->port)) { 61 | printk("Error: %s device is not ready\n", spec->port->name); 62 | return; 63 | } 64 | 65 | ret = gpio_pin_configure_dt(spec, GPIO_OUTPUT); 66 | if (ret != 0) { 67 | printk("Error %d: failed to configure pin %d (LED '%s')\n", 68 | ret, spec->pin, led->gpio_pin_name); 69 | return; 70 | } 71 | 72 | while (1) { 73 | gpio_pin_set(spec->port, spec->pin, cnt % 2); 74 | 75 | struct printk_data_t tx_data = { .led = id, .cnt = cnt }; 76 | 77 | size_t size = sizeof(struct printk_data_t); 78 | char *mem_ptr = k_malloc(size); 79 | __ASSERT_NO_MSG(mem_ptr != 0); 80 | 81 | memcpy(mem_ptr, &tx_data, size); 82 | 83 | k_fifo_put(&printk_fifo, mem_ptr); 84 | 85 | k_msleep(sleep_ms); 86 | cnt++; 87 | } 88 | } 89 | 90 | void blink0(void) 91 | { 92 | blink(&led0, 100, 0); 93 | } 94 | 95 | void blink1(void) 96 | { 97 | blink(&led1, 1000, 1); 98 | } 99 | 100 | void uart_out(void) 101 | { 102 | while (1) { 103 | struct printk_data_t *rx_data = k_fifo_get(&printk_fifo, 104 | K_FOREVER); 105 | printk("Toggled led%d; counter=%d\n", 106 | rx_data->led, rx_data->cnt); 107 | k_free(rx_data); 108 | } 109 | } 110 | 111 | K_THREAD_DEFINE(blink0_id, STACKSIZE, blink0, NULL, NULL, NULL, 112 | PRIORITY, 0, 0); 113 | K_THREAD_DEFINE(blink1_id, STACKSIZE, blink1, NULL, NULL, NULL, 114 | PRIORITY, 0, 0); 115 | K_THREAD_DEFINE(uart_out_id, STACKSIZE, uart_out, NULL, NULL, NULL, 116 | PRIORITY, 0, 0); 117 | -------------------------------------------------------------------------------- /exercises/interrupts/button-interrupt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(button) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/interrupts/button-interrupt/README.rst: -------------------------------------------------------------------------------- 1 | .. _button-sample: 2 | 3 | Button 4 | ###### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple button demo showcasing the use of GPIO input with interrupts. 10 | The sample prints a message to the console each time a button is pressed. 11 | 12 | Requirements 13 | ************ 14 | 15 | The board hardware must have a push button connected via a GPIO pin. These are 16 | called "User buttons" on many of Zephyr's :ref:`boards`. 17 | 18 | The button must be configured using the ``sw0`` :ref:`devicetree ` 19 | alias, usually in the :ref:`BOARD.dts file `. You will 20 | see this error if you try to build this sample for an unsupported board: 21 | 22 | .. code-block:: none 23 | 24 | Unsupported board: sw0 devicetree alias is not defined 25 | 26 | You may see additional build errors if the ``sw0`` alias exists, but is not 27 | properly defined. 28 | 29 | The sample additionally supports an optional ``led0`` devicetree alias. This is 30 | the same alias used by the :ref:`blinky-sample`. If this is provided, the LED 31 | will be turned on when the button is pressed, and turned off off when it is 32 | released. 33 | 34 | Devicetree details 35 | ================== 36 | 37 | This section provides more details on devicetree configuration. 38 | 39 | Here is a minimal devicetree fragment which supports this sample. This only 40 | includes a ``sw0`` alias; the optional ``led0`` alias is left out for 41 | simplicity. 42 | 43 | .. code-block:: devicetree 44 | 45 | / { 46 | aliases { 47 | sw0 = &button0; 48 | }; 49 | 50 | soc { 51 | gpio0: gpio@0 { 52 | status = "okay"; 53 | gpio-controller; 54 | #gpio-cells = <2>; 55 | /* ... */ 56 | }; 57 | }; 58 | 59 | buttons { 60 | compatible = "gpio-keys"; 61 | button0: button_0 { 62 | gpios = < &gpio0 PIN FLAGS >; 63 | label = "User button"; 64 | }; 65 | /* ... other buttons ... */ 66 | }; 67 | }; 68 | 69 | As shown, the ``sw0`` devicetree alias must point to a child node of a node 70 | with a "gpio-keys" :ref:`compatible `. 71 | 72 | The above situation is for the common case where: 73 | 74 | - ``gpio0`` is an example node label referring to a GPIO controller 75 | - ``PIN`` should be a pin number, like ``8`` or ``0`` 76 | - ``FLAGS`` should be a logical OR of :ref:`GPIO configuration flags ` 77 | meant to apply to the button, such as ``(GPIO_PULL_UP | GPIO_ACTIVE_LOW)`` 78 | 79 | This assumes the common case, where ``#gpio-cells = <2>`` in the ``gpio0`` 80 | node, and that the GPIO controller's devicetree binding names those two cells 81 | "pin" and "flags" like so: 82 | 83 | .. code-block:: yaml 84 | 85 | gpio-cells: 86 | - pin 87 | - flags 88 | 89 | This sample requires a ``pin`` cell in the ``gpios`` property. The ``flags`` 90 | cell is optional, however, and the sample still works if the GPIO cells 91 | do not contain ``flags``. 92 | 93 | Building and Running 94 | ******************** 95 | 96 | This sample can be built for multiple boards, in this example we will build it 97 | for the nucleo_f103rb board: 98 | 99 | .. zephyr-app-commands:: 100 | :zephyr-app: samples/basic/button 101 | :board: nucleo_f103rb 102 | :goals: build 103 | :compact: 104 | 105 | After startup, the program looks up a predefined GPIO device, and configures the 106 | pin in input mode, enabling interrupt generation on falling edge. During each 107 | iteration of the main loop, the state of GPIO line is monitored and printed to 108 | the serial console. When the input button gets pressed, the interrupt handler 109 | will print an information about this event along with its timestamp. 110 | -------------------------------------------------------------------------------- /exercises/interrupts/button-interrupt/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_GPIO=y 2 | -------------------------------------------------------------------------------- /exercises/interrupts/button-interrupt/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | name: Button Sample 3 | tests: 4 | sample.basic.button: 5 | tags: button gpio 6 | filter: dt_enabled_alias_with_parent_compat("sw0", "gpio-keys") 7 | depends_on: gpio 8 | harness: button 9 | -------------------------------------------------------------------------------- /exercises/interrupts/button-interrupt/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Open-RnD Sp. z o.o. 3 | * Copyright (c) 2020 Nordic Semiconductor ASA 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define SLEEP_TIME_MS 1 16 | 17 | /* 18 | * Get button configuration from the devicetree sw0 alias. This is mandatory. 19 | */ 20 | #define SW0_NODE DT_ALIAS(sw0) 21 | #if !DT_NODE_HAS_STATUS(SW0_NODE, okay) 22 | #error "Unsupported board: sw0 devicetree alias is not defined" 23 | #endif 24 | static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, 25 | {0}); 26 | static struct gpio_callback button_cb_data; 27 | 28 | /* 29 | * The led0 devicetree alias is optional. If present, we'll use it 30 | * to turn on the LED whenever the button is pressed. 31 | */ 32 | static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, 33 | {0}); 34 | 35 | void button_pressed(const struct device *dev, struct gpio_callback *cb, 36 | uint32_t pins) 37 | { 38 | printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32()); 39 | } 40 | 41 | void main(void) 42 | { 43 | int ret; 44 | 45 | if (!device_is_ready(button.port)) { 46 | printk("Error: button device %s is not ready\n", 47 | button.port->name); 48 | return; 49 | } 50 | 51 | ret = gpio_pin_configure_dt(&button, GPIO_INPUT); 52 | if (ret != 0) { 53 | printk("Error %d: failed to configure %s pin %d\n", 54 | ret, button.port->name, button.pin); 55 | return; 56 | } 57 | 58 | ret = gpio_pin_interrupt_configure_dt(&button, 59 | GPIO_INT_EDGE_TO_ACTIVE); 60 | if (ret != 0) { 61 | printk("Error %d: failed to configure interrupt on %s pin %d\n", 62 | ret, button.port->name, button.pin); 63 | return; 64 | } 65 | 66 | gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); 67 | gpio_add_callback(button.port, &button_cb_data); 68 | printk("Set up button at %s pin %d\n", button.port->name, button.pin); 69 | 70 | if (led.port && !device_is_ready(led.port)) { 71 | printk("Error %d: LED device %s is not ready; ignoring it\n", 72 | ret, led.port->name); 73 | led.port = NULL; 74 | } 75 | if (led.port) { 76 | ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT); 77 | if (ret != 0) { 78 | printk("Error %d: failed to configure LED device %s pin %d\n", 79 | ret, led.port->name, led.pin); 80 | led.port = NULL; 81 | } else { 82 | printk("Set up LED at %s pin %d\n", led.port->name, led.pin); 83 | } 84 | } 85 | 86 | printk("Press the button\n"); 87 | if (led.port) { 88 | while (1) { 89 | /* If we have an LED, match its state to the button's. */ 90 | int val = gpio_pin_get_dt(&button); 91 | 92 | if (val >= 0) { 93 | gpio_pin_set_dt(&led, val); 94 | } 95 | k_msleep(SLEEP_TIME_MS); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /exercises/networking/dhcpv4_client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(dhcpv4_client) 6 | 7 | FILE(GLOB app_sources src/*.c) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /exercises/networking/dhcpv4_client/overlay-e1000.conf: -------------------------------------------------------------------------------- 1 | CONFIG_NET_L2_ETHERNET=y 2 | CONFIG_NET_QEMU_ETHERNET=y 3 | 4 | CONFIG_ETH_E1000=y 5 | 6 | CONFIG_PCIE=y 7 | 8 | #CONFIG_ETHERNET_LOG_LEVEL_DBG=y 9 | -------------------------------------------------------------------------------- /exercises/networking/dhcpv4_client/prj.conf: -------------------------------------------------------------------------------- 1 | # This option enables generic link layer and IP networking support 2 | CONFIG_NETWORKING=y 3 | 4 | # Disable IPv6 support 5 | CONFIG_NET_IPV6=n 6 | 7 | # Enable IPv4 support 8 | CONFIG_NET_IPV4=y 9 | 10 | # Enable ARP support. This is necessary on hardware that requires it to get IPv4 working (like Ethernet devices) 11 | CONFIG_NET_ARP=y 12 | 13 | # Enable UDP 14 | CONFIG_NET_UDP=y 15 | 16 | # Enable DHCPV4 client 17 | CONFIG_NET_DHCPV4=y 18 | 19 | # Non-random number generator 20 | CONFIG_TEST_RANDOM_GENERATOR=y 21 | 22 | # Initialize stack areas. 23 | # This option instructs the kernel to initialize stack areas with a 24 | # known value (0xaa) before they are first used, so that the high 25 | # water mark can be easily determined. This applies to the stack areas 26 | # for threads, as well as to the interrupt stack. 27 | CONFIG_INIT_STACKS=y 28 | 29 | # Network Management API 30 | # Add support for NM API that enables managing different aspects 31 | # of the network stack as well as receiving notification on network 32 | # events (ip address change, iface up and running ...). 33 | CONFIG_NET_MGMT=y 34 | 35 | # Add support for runtime network event notifications 36 | # This adds support for the stack to notify events towards any 37 | # relevant listener. This can be necessary when application 38 | # (or else) needs to be notified on a specific network event 39 | # (ip address change for instance) to trigger some related work. 40 | CONFIG_NET_MGMT_EVENT=y 41 | 42 | # Enable network stack logging and debugging 43 | # Enable logging in various parts of the network stack. 44 | # Specific debugging options to other sub-menus will be unlocked 45 | # as well (IPv6, IPv4, ...). 46 | CONFIG_NET_LOG=y 47 | 48 | # Logging 49 | CONFIG_LOG=y 50 | 51 | # SLIP network connection statistics 52 | CONFIG_SLIP_STATISTICS=n 53 | 54 | # Enable network shell utilities 55 | # Activate shell module that provides network commands like 56 | # ping to the console. 57 | CONFIG_NET_SHELL=y 58 | -------------------------------------------------------------------------------- /exercises/networking/dhcpv4_client/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | name: DHCP Client 3 | tests: 4 | sample.net.dhcpv4_client: 5 | harness: net 6 | depends_on: netif 7 | tags: net http 8 | -------------------------------------------------------------------------------- /exercises/networking/dhcpv4_client/src/main.c: -------------------------------------------------------------------------------- 1 | /* Networking DHCPv4 client */ 2 | 3 | /* 4 | * Copyright (c) 2017 ARM Ltd. 5 | * Copyright (c) 2016 Intel Corporation. 6 | * 7 | * SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | #include 11 | LOG_MODULE_REGISTER(net_dhcpv4_client_sample, LOG_LEVEL_DBG); 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | static struct net_mgmt_event_callback mgmt_cb; 24 | 25 | static void handler(struct net_mgmt_event_callback *cb, 26 | uint32_t mgmt_event, 27 | struct net_if *iface) 28 | { 29 | int i = 0; 30 | 31 | if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { 32 | return; 33 | } 34 | 35 | for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { 36 | char buf[NET_IPV4_ADDR_LEN]; 37 | 38 | if (iface->config.ip.ipv4->unicast[i].addr_type != 39 | NET_ADDR_DHCP) { 40 | continue; 41 | } 42 | 43 | LOG_INF("Your address: %s", 44 | log_strdup(net_addr_ntop(AF_INET, 45 | &iface->config.ip.ipv4->unicast[i].address.in_addr, 46 | buf, sizeof(buf)))); 47 | LOG_INF("Lease time: %u seconds", 48 | iface->config.dhcpv4.lease_time); 49 | LOG_INF("Subnet: %s", 50 | log_strdup(net_addr_ntop(AF_INET, 51 | &iface->config.ip.ipv4->netmask, 52 | buf, sizeof(buf)))); 53 | LOG_INF("Router: %s", 54 | log_strdup(net_addr_ntop(AF_INET, 55 | &iface->config.ip.ipv4->gw, 56 | buf, sizeof(buf)))); 57 | } 58 | } 59 | 60 | void main(void) 61 | { 62 | struct net_if *iface; 63 | 64 | LOG_INF("Run dhcpv4 client"); 65 | 66 | net_mgmt_init_event_callback(&mgmt_cb, handler, 67 | NET_EVENT_IPV4_ADDR_ADD); 68 | net_mgmt_add_event_callback(&mgmt_cb); 69 | 70 | iface = net_if_get_default(); 71 | 72 | net_dhcpv4_start(iface); 73 | } 74 | -------------------------------------------------------------------------------- /exercises/networking/echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(sockets_echo) 7 | 8 | FILE(GLOB app_sources src/*.c) 9 | target_sources(app PRIVATE ${app_sources}) 10 | 11 | include(${ZEPHYR_BASE}/samples/net/common/common.cmake) 12 | -------------------------------------------------------------------------------- /exercises/networking/echo/Makefile.posix: -------------------------------------------------------------------------------- 1 | # This makefile builds socket_echo sample for POSIX system, like Linux 2 | 3 | socket_echo: src/socket_echo.c 4 | $(CC) $^ -o $@ 5 | -------------------------------------------------------------------------------- /exercises/networking/echo/README.rst: -------------------------------------------------------------------------------- 1 | .. _sockets-echo-sample: 2 | 3 | Socket Echo Server 4 | ################## 5 | 6 | Overview 7 | ******** 8 | 9 | The sockets/echo sample application for Zephyr implements an IPv4 TCP echo 10 | server using a BSD Sockets compatible API. The purpose of this sample is to 11 | show how it's possible to develop a sockets application portable to both 12 | POSIX and Zephyr. As such, it is kept minimal and supports only IPv4 and TCP. 13 | 14 | The source code for this sample application can be found at: 15 | :zephyr_file:`samples/net/sockets/echo`. 16 | 17 | Requirements 18 | ************ 19 | 20 | - :ref:`networking_with_host` 21 | - or, a board with hardware networking 22 | 23 | Building and Running 24 | ******************** 25 | 26 | Build the Zephyr version of the sockets/echo application like this: 27 | 28 | .. zephyr-app-commands:: 29 | :zephyr-app: samples/net/sockets/echo 30 | :board: 31 | :goals: build 32 | :compact: 33 | 34 | After the sample starts, it expects connections at 192.0.2.1, port 4242. 35 | The easiest way to connect is: 36 | 37 | .. code-block:: console 38 | 39 | $ telnet 192.0.2.1 4242 40 | 41 | After a connection is made, the application will echo back any line sent 42 | to it. The application implements a single-threaded server using blocking 43 | sockets, and thus can serve only one client connection at time. After the 44 | current client disconnects, the next connection can proceed. 45 | 46 | Running application on POSIX Host 47 | ================================= 48 | 49 | The same application source code can be built for a POSIX system, e.g. 50 | Linux. (Note: if you look at the source, you will see that the code is 51 | the same except the header files are different for Zephyr vs POSIX.) 52 | 53 | To build for a host POSIX OS: 54 | 55 | .. code-block:: console 56 | 57 | $ make -f Makefile.posix 58 | 59 | To run: 60 | 61 | .. code-block:: console 62 | 63 | $ ./socket_echo 64 | 65 | To test: 66 | 67 | .. code-block:: console 68 | 69 | $ telnet 127.0.0.1 4242 70 | 71 | As can be seen, the behavior of the application is the same as the Zephyr 72 | version. 73 | 74 | Running on cc3220sf_launchxl 75 | ============================ 76 | 77 | See the note on Provisioning and Fast Connect in :ref:`cc3220sf_launchxl`. 78 | 79 | After having connected to an Access Point using the sample Wi-Fi shell, 80 | the IP address will be printed to the console upon running this echo 81 | application. 82 | 83 | Proceed to test as above. 84 | -------------------------------------------------------------------------------- /exercises/networking/echo/boards/cc3220sf_launchxl.conf: -------------------------------------------------------------------------------- 1 | # Networking Config: 2 | CONFIG_NETWORKING=y 3 | CONFIG_NET_NATIVE=n 4 | CONFIG_NET_IPV4=y 5 | CONFIG_NET_IPV6=n 6 | CONFIG_NET_SOCKETS=y 7 | 8 | # Enable SimpleLink WiFi Driver and Socket Offload 9 | CONFIG_WIFI=y 10 | CONFIG_WIFI_SIMPLELINK=y 11 | CONFIG_NET_SOCKETS_OFFLOAD=y 12 | 13 | # Disable unneeded settings from the base prj.conf: 14 | CONFIG_TEST_RANDOM_GENERATOR=n 15 | CONFIG_NET_CONFIG_SETTINGS=n 16 | CONFIG_NET_CONFIG_MY_IPV4_ADDR="" 17 | CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" 18 | 19 | # Debugging 20 | CONFIG_NET_LOG=y 21 | CONFIG_WIFI_LOG_LEVEL_DBG=y 22 | CONFIG_DEBUG=y 23 | #CONFIG_ASSERT=y 24 | -------------------------------------------------------------------------------- /exercises/networking/echo/boards/cc3235sf_launchxl.conf: -------------------------------------------------------------------------------- 1 | # Networking Config: 2 | CONFIG_NETWORKING=y 3 | CONFIG_NET_NATIVE=n 4 | CONFIG_NET_IPV4=y 5 | CONFIG_NET_IPV6=n 6 | CONFIG_NET_SOCKETS=y 7 | 8 | # Enable SimpleLink WiFi Driver and Socket Offload 9 | CONFIG_WIFI=y 10 | CONFIG_WIFI_SIMPLELINK=y 11 | CONFIG_NET_SOCKETS_OFFLOAD=y 12 | 13 | # Disable unneeded settings from the base prj.conf: 14 | CONFIG_TEST_RANDOM_GENERATOR=n 15 | CONFIG_NET_CONFIG_SETTINGS=n 16 | CONFIG_NET_CONFIG_MY_IPV4_ADDR="" 17 | CONFIG_NET_CONFIG_PEER_IPV4_ADDR="" 18 | 19 | # Debugging 20 | CONFIG_NET_LOG=y 21 | CONFIG_WIFI_LOG_LEVEL_DBG=y 22 | CONFIG_DEBUG=y 23 | CONFIG_CC3235SF_DEBUG=y 24 | #CONFIG_ASSERT=y 25 | -------------------------------------------------------------------------------- /exercises/networking/echo/overlay-e1000.conf: -------------------------------------------------------------------------------- 1 | # Overlay for experimental TCP as qemu_x86 with E1000 2 | 3 | CONFIG_PCIE=y 4 | CONFIG_ETH_E1000=y 5 | 6 | CONFIG_NET_L2_ETHERNET=y 7 | CONFIG_NET_QEMU_ETHERNET=y 8 | -------------------------------------------------------------------------------- /exercises/networking/echo/overlay-log.conf: -------------------------------------------------------------------------------- 1 | CONFIG_LOG=y 2 | CONFIG_LOG_MODE_IMMEDIATE=y 3 | CONFIG_LOG_BACKEND_SHOW_COLOR=n 4 | 5 | CONFIG_NET_LOG=y 6 | 7 | #CONFIG_NET_IF_LOG_LEVEL_DBG=y 8 | #CONFIG_NET_L2_ETHERNET_LOG_LEVEL_DBG=y 9 | 10 | CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=y 11 | CONFIG_NET_CONN_LOG_LEVEL_DBG=y 12 | CONFIG_NET_CONTEXT_LOG_LEVEL_DBG=y 13 | 14 | CONFIG_NET_TCP_LOG_LEVEL_DBG=y 15 | -------------------------------------------------------------------------------- /exercises/networking/echo/prj.conf: -------------------------------------------------------------------------------- 1 | # General config 2 | 3 | # Newlib C library 4 | # Build with newlib library. The newlib library is expected to be 5 | # part of the SDK in this case. 6 | # Newlib is a C standard library implementation intended for use on embedded systems. 7 | CONFIG_NEWLIB_LIBC=y 8 | 9 | # Main stack 10 | CONFIG_MAIN_STACK_SIZE=1200 11 | 12 | # Networking config 13 | CONFIG_NETWORKING=y 14 | CONFIG_NET_IPV4=y 15 | CONFIG_NET_IPV6=n 16 | CONFIG_NET_TCP=y 17 | CONFIG_NET_SOCKETS=y 18 | CONFIG_NET_SOCKETS_POSIX_NAMES=y 19 | 20 | # Network driver config 21 | CONFIG_TEST_RANDOM_GENERATOR=y 22 | 23 | # Network address config 24 | 25 | # Set network settings for applications 26 | # Allow IP addresses to be set in config file for 27 | # networking client/server sample applications, or 28 | # some link-layer dedicated settings like the channel. 29 | # Beware this is not meant to be used for proper 30 | # provisioning but quick sampling/testing. 31 | CONFIG_NET_CONFIG_SETTINGS=y 32 | 33 | # This application wants IPv4 support 34 | # The network application needs IPv4 support to function properly. 35 | # This option makes sure the network application is initialized properly 36 | # in order to use IPv4. 37 | CONFIG_NET_CONFIG_NEED_IPV4=y 38 | 39 | # My IPv4 address 40 | CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.0.246" 41 | 42 | # Peer IPv4 address 43 | # This is only applicable in client side applications that try 44 | # to establish a connection to peer host. 45 | # Use 192.0.2.2 here if uncertain. 46 | # CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.168.0.239" 47 | 48 | CONFIG_NET_ARP=y -------------------------------------------------------------------------------- /exercises/networking/echo/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: BSD Sockets API TCP echo server sample 3 | name: socket_echo 4 | common: 5 | harness: net 6 | depends_on: netif 7 | filter: TOOLCHAIN_HAS_NEWLIB == 1 8 | tests: 9 | sample.net.sockets.echo: 10 | tags: net socket 11 | sample.net.sockets.echo.offload.simplelink: 12 | platform_allow: cc3220sf_launchxl 13 | tags: net socket offload simplelink 14 | -------------------------------------------------------------------------------- /exercises/networking/echo/src/socket_echo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Linaro Limited 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef __ZEPHYR__ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #else 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #endif 25 | 26 | #define MY_IPV4_ADDR 1 27 | #define BIND_PORT 4242 28 | 29 | void print_ip(unsigned int ip) 30 | { 31 | unsigned char bytes[4]; 32 | bytes[0] = ip & 0xFF; 33 | bytes[1] = (ip >> 8) & 0xFF; 34 | bytes[2] = (ip >> 16) & 0xFF; 35 | bytes[3] = (ip >> 24) & 0xFF; 36 | printf("%d.%d.%d.%d\n", bytes[3], bytes[2], bytes[1], bytes[0]); 37 | } 38 | 39 | void main(void) 40 | { 41 | int serv; 42 | struct sockaddr_in bind_addr; 43 | static int counter; 44 | int bind_addr_len; 45 | char my_addr_str[32]; 46 | 47 | volatile struct sockaddr_ll dst = { 0 }; 48 | 49 | serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 50 | 51 | if (serv < 0) { 52 | printf("error: socket: %d\n", errno); 53 | exit(1); 54 | } 55 | 56 | bind_addr.sin_family = AF_INET; 57 | bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); 58 | bind_addr.sin_port = htons(BIND_PORT); 59 | 60 | if (bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) { 61 | printf("error: bind: %d\n", errno); 62 | exit(1); 63 | } 64 | 65 | if (listen(serv, 5) < 0) { 66 | printf("error: listen: %d\n", errno); 67 | exit(1); 68 | } 69 | 70 | printf("Single-threaded TCP echo server waits for a connection on " 71 | "port %d...\n", BIND_PORT); 72 | 73 | bind_addr_len = sizeof(bind_addr); 74 | if (getsockname(serv, (struct sockaddr *)&bind_addr, &bind_addr_len) < 0) 75 | { 76 | printf("error: getsockname"); 77 | exit(1); 78 | } 79 | inet_ntop(bind_addr.sin_family, &bind_addr.sin_addr, my_addr_str, sizeof(my_addr_str)); 80 | printf("Local IP address is: %s\n", my_addr_str); 81 | // printf("Local port is: %d\n", (int) ntohs(bind_addr.sin_port)); 82 | 83 | dst.sll_ifindex = net_if_get_by_iface(net_if_get_default()); 84 | 85 | while (1) { 86 | struct sockaddr_in client_addr; 87 | socklen_t client_addr_len = sizeof(client_addr); 88 | char addr_str[32]; 89 | int client = accept(serv, (struct sockaddr *)&client_addr, 90 | &client_addr_len); 91 | 92 | if (client < 0) { 93 | printf("error: accept: %d\n", errno); 94 | continue; 95 | } 96 | 97 | inet_ntop(client_addr.sin_family, &client_addr.sin_addr, 98 | addr_str, sizeof(addr_str)); 99 | printf("Connection #%d from %s\n", counter++, addr_str); 100 | 101 | while (1) { 102 | char buf[128], *p; 103 | int len = recv(client, buf, sizeof(buf), 0); 104 | int out_len; 105 | 106 | if (len <= 0) { 107 | if (len < 0) { 108 | printf("error: recv: %d\n", errno); 109 | } 110 | break; 111 | } 112 | 113 | p = buf; 114 | do { 115 | out_len = send(client, p, len, 0); 116 | if (out_len < 0) { 117 | printf("error: send: %d\n", errno); 118 | goto error; 119 | } 120 | p += out_len; 121 | len -= out_len; 122 | } while (len); 123 | } 124 | 125 | error: 126 | close(client); 127 | printf("Connection from %s closed\n", addr_str); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /exercises/networking/echo_server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(sockets_echo_server) 7 | 8 | if(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND 9 | (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) 10 | add_custom_target(development_psk 11 | COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" 12 | COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" 13 | COMMAND ${CMAKE_COMMAND} -E echo "--- development. Set NET_SAMPLE_PSK_HEADER_FILE to use ---" 14 | COMMAND ${CMAKE_COMMAND} -E echo "--- own pre-shared key. ---" 15 | COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" 16 | ) 17 | add_dependencies(app development_psk) 18 | endif() 19 | 20 | target_sources( app PRIVATE src/echo-server.c) 21 | target_sources_ifdef(CONFIG_NET_UDP app PRIVATE src/udp.c) 22 | target_sources_ifdef(CONFIG_NET_TCP app PRIVATE src/tcp.c) 23 | #target_sources_ifdef(CONFIG_NET_VLAN app PRIVATE src/vlan.c) 24 | #target_sources_ifdef(CONFIG_NET_L2_IPIP app PRIVATE src/tunnel.c) 25 | 26 | include(${ZEPHYR_BASE}/samples/net/common/common.cmake) 27 | 28 | #set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) 29 | 30 | # foreach(inc_file 31 | # ca.der 32 | # server.der 33 | # server_privkey.der 34 | # echo-apps-cert.der 35 | # echo-apps-key.der 36 | # ) 37 | # generate_inc_file_for_target( 38 | # app 39 | # src/${inc_file} 40 | # ${gen_dir}/${inc_file}.inc 41 | # ) 42 | # endforeach() 43 | -------------------------------------------------------------------------------- /exercises/networking/echo_server/Kconfig: -------------------------------------------------------------------------------- 1 | # Private config options for echo-server sample app 2 | 3 | # Copyright (c) 2018 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | mainmenu "Networking echo-server sample application" 7 | 8 | config NET_SAMPLE_NUM_HANDLERS 9 | int "How many connections to serve at the same time" 10 | default 1 11 | help 12 | Each connection is served by a thread which needs 13 | memory. Only increase the value here if really needed. 14 | 15 | config NET_SAMPLE_IFACE2_MY_IPV6_ADDR 16 | string "My IPv6 address for second interface" 17 | help 18 | The value depends on your network setup. 19 | 20 | config NET_SAMPLE_IFACE2_MY_IPV4_ADDR 21 | string "My IPv4 address for second interface" 22 | help 23 | The value depends on your network setup. 24 | 25 | config NET_SAMPLE_IFACE2_MY_IPV4_NETMASK 26 | string "My IPv4 netmask for second interface" 27 | help 28 | The value depends on your network setup. 29 | 30 | config NET_SAMPLE_IFACE2_VLAN_TAG 31 | int "VLAN tag for second interface" 32 | default 100 33 | range 0 4094 34 | depends on NET_VLAN 35 | help 36 | Set VLAN (virtual LAN) tag (id) that is used in the sample 37 | application. 38 | 39 | config NET_SAMPLE_IFACE3_MY_IPV6_ADDR 40 | string "My IPv6 address for third interface" 41 | help 42 | The value depends on your network setup. 43 | 44 | config NET_SAMPLE_IFACE3_MY_IPV4_ADDR 45 | string "My IPv4 address for third interface" 46 | help 47 | The value depends on your network setup. 48 | 49 | config NET_SAMPLE_IFACE3_MY_IPV4_NETMASK 50 | string "My IPv4 netmask for third interface" 51 | help 52 | The value depends on your network setup. 53 | 54 | config NET_SAMPLE_IFACE3_VLAN_TAG 55 | int "VLAN tag for third interface" 56 | default 200 57 | range 0 4094 58 | depends on NET_VLAN 59 | help 60 | Set VLAN (virtual LAN) tag (id) that is used in the sample 61 | application. 62 | 63 | config NET_SAMPLE_TUNNEL_PEER_ADDR 64 | string "Remote IP address of the tunnel interface" 65 | depends on NET_L2_IPIP 66 | help 67 | Use overlay-tunnel.conf to setup the tunnel support. 68 | 69 | config NET_SAMPLE_TUNNEL_MY_ADDR 70 | string "My address for tunnel interface" 71 | depends on NET_L2_IPIP 72 | help 73 | The value depends on your network setup. 74 | 75 | config NET_SAMPLE_PSK_HEADER_FILE 76 | string "Header file containing PSK" 77 | default "dummy_psk.h" 78 | depends on MBEDTLS_KEY_EXCHANGE_PSK_ENABLED 79 | help 80 | Name of a header file containing a 81 | pre-shared key. 82 | 83 | config NET_SAMPLE_CERTS_WITH_SC 84 | bool "Signed certificates" 85 | depends on NET_SOCKETS_SOCKOPT_TLS 86 | help 87 | Enable this flag, if you are interested to run this 88 | application with signed certificates and keys. 89 | 90 | source "Kconfig.zephyr" 91 | -------------------------------------------------------------------------------- /exercises/networking/echo_server/prj.conf: -------------------------------------------------------------------------------- 1 | # Generic networking options 2 | CONFIG_NETWORKING=y 3 | CONFIG_NET_UDP=y 4 | CONFIG_NET_TCP=y 5 | CONFIG_NET_IPV6=n 6 | CONFIG_NET_IPV4=y 7 | CONFIG_NET_SOCKETS=y 8 | CONFIG_NET_SOCKETS_POSIX_NAMES=y 9 | CONFIG_POSIX_MAX_FDS=6 10 | CONFIG_NET_CONNECTION_MANAGER=y 11 | 12 | # Kernel options 13 | CONFIG_MAIN_STACK_SIZE=2048 14 | CONFIG_ENTROPY_GENERATOR=y 15 | CONFIG_TEST_RANDOM_GENERATOR=y 16 | CONFIG_INIT_STACKS=y 17 | 18 | # Logging 19 | CONFIG_NET_LOG=y 20 | CONFIG_LOG=y 21 | CONFIG_NET_STATISTICS=y 22 | CONFIG_PRINTK=y 23 | 24 | # Network buffers 25 | CONFIG_NET_PKT_RX_COUNT=16 26 | CONFIG_NET_PKT_TX_COUNT=16 27 | CONFIG_NET_BUF_RX_COUNT=64 28 | CONFIG_NET_BUF_TX_COUNT=64 29 | CONFIG_NET_CONTEXT_NET_PKT_POOL=y 30 | 31 | # IP address options 32 | CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 33 | CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 34 | CONFIG_NET_MAX_CONTEXTS=10 35 | 36 | # Network shell 37 | CONFIG_NET_SHELL=y 38 | CONFIG_SHELL=y 39 | 40 | # Network application options and configuration 41 | CONFIG_NET_CONFIG_SETTINGS=y 42 | CONFIG_NET_CONFIG_NEED_IPV6=n 43 | #CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" 44 | #CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" 45 | CONFIG_NET_CONFIG_NEED_IPV4=y 46 | CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.0.200" 47 | CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.168.0.239" 48 | 49 | # Number of socket descriptors might need adjusting 50 | # if there are more than 1 handlers defined. 51 | CONFIG_POSIX_MAX_FDS=12 52 | 53 | # How many client can connect to echo-server simultaneously 54 | CONFIG_NET_SAMPLE_NUM_HANDLERS=2 55 | 56 | # DHCP configuration. Until DHCP address is assigned, 57 | # static configuration above is used instead. 58 | CONFIG_NET_DHCPV4=y 59 | -------------------------------------------------------------------------------- /exercises/networking/echo_server/src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2019 Intel Corporation. 3 | * Copyright (c) 2018 Nordic Semiconductor ASA. 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | 9 | #define MY_PORT 4242 10 | #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) || defined(CONFIG_NET_TCP2) || \ 11 | defined(CONFIG_COVERAGE) 12 | #define STACK_SIZE 4096 13 | #else 14 | #define STACK_SIZE 2048 15 | #endif 16 | 17 | #if IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) 18 | #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1) 19 | #else 20 | #define THREAD_PRIORITY K_PRIO_PREEMPT(8) 21 | #endif 22 | 23 | #define RECV_BUFFER_SIZE 1280 24 | #define STATS_TIMER 60 /* How often to print statistics (in seconds) */ 25 | 26 | #if defined(CONFIG_USERSPACE) 27 | #include 28 | extern struct k_mem_partition app_partition; 29 | extern struct k_mem_domain app_domain; 30 | #define APP_BMEM K_APP_BMEM(app_partition) 31 | #define APP_DMEM K_APP_DMEM(app_partition) 32 | #else 33 | #define APP_BMEM 34 | #define APP_DMEM 35 | #endif 36 | 37 | struct data { 38 | const char *proto; 39 | 40 | struct { 41 | int sock; 42 | char recv_buffer[RECV_BUFFER_SIZE]; 43 | uint32_t counter; 44 | atomic_t bytes_received; 45 | struct k_work_delayable stats_print; 46 | } udp; 47 | 48 | struct { 49 | int sock; 50 | atomic_t bytes_received; 51 | struct k_work_delayable stats_print; 52 | 53 | struct { 54 | int sock; 55 | char recv_buffer[RECV_BUFFER_SIZE]; 56 | uint32_t counter; 57 | } accepted[CONFIG_NET_SAMPLE_NUM_HANDLERS]; 58 | } tcp; 59 | }; 60 | 61 | struct configs { 62 | struct data ipv4; 63 | struct data ipv6; 64 | }; 65 | 66 | extern struct configs conf; 67 | 68 | void start_udp(void); 69 | void stop_udp(void); 70 | 71 | void start_tcp(void); 72 | void stop_tcp(void); 73 | 74 | void quit(void); 75 | 76 | #if defined(CONFIG_NET_VLAN) 77 | int init_vlan(void); 78 | #else 79 | static inline int init_vlan(void) 80 | { 81 | return 0; 82 | } 83 | #endif /* CONFIG_NET_VLAN */ 84 | 85 | #if defined(CONFIG_NET_L2_IPIP) 86 | int init_tunnel(void); 87 | bool is_tunnel(struct net_if *iface); 88 | #else 89 | static inline int init_tunnel(void) 90 | { 91 | return 0; 92 | } 93 | 94 | static inline bool is_tunnel(struct net_if *iface) 95 | { 96 | ARG_UNUSED(iface); 97 | return false; 98 | } 99 | #endif /* CONFIG_NET_L2_IPIP */ 100 | -------------------------------------------------------------------------------- /exercises/networking/echo_server/src/echo-server.c: -------------------------------------------------------------------------------- 1 | /* echo-server.c - Networking echo server */ 2 | 3 | /* 4 | * Copyright (c) 2016 Intel Corporation. 5 | * Copyright (c) 2018 Nordic Semiconductor ASA. 6 | * 7 | * SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | #include 11 | LOG_MODULE_REGISTER(net_echo_server_sample, LOG_LEVEL_DBG); 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "common.h" 26 | //#include "certificate.h" 27 | 28 | #define APP_BANNER "Run echo server" 29 | 30 | static struct k_sem quit_lock; 31 | static struct net_mgmt_event_callback mgmt_cb; 32 | static bool connected; 33 | K_SEM_DEFINE(run_app, 0, 1); 34 | static bool want_to_quit; 35 | 36 | #if defined(CONFIG_USERSPACE) 37 | K_APPMEM_PARTITION_DEFINE(app_partition); 38 | struct k_mem_domain app_domain; 39 | #endif 40 | 41 | #define EVENT_MASK (NET_EVENT_L4_CONNECTED | \ 42 | NET_EVENT_L4_DISCONNECTED) 43 | 44 | APP_DMEM struct configs conf = { 45 | .ipv4 = { 46 | .proto = "IPv4", 47 | }, 48 | .ipv6 = { 49 | .proto = "IPv6", 50 | }, 51 | }; 52 | 53 | void quit(void) 54 | { 55 | k_sem_give(&quit_lock); 56 | } 57 | 58 | static void start_udp_and_tcp(void) 59 | { 60 | LOG_INF("Starting..."); 61 | 62 | if (IS_ENABLED(CONFIG_NET_TCP)) { 63 | start_tcp(); 64 | } 65 | 66 | if (IS_ENABLED(CONFIG_NET_UDP)) { 67 | start_udp(); 68 | } 69 | } 70 | 71 | static void stop_udp_and_tcp(void) 72 | { 73 | LOG_INF("Stopping..."); 74 | 75 | if (IS_ENABLED(CONFIG_NET_UDP)) { 76 | stop_udp(); 77 | } 78 | 79 | if (IS_ENABLED(CONFIG_NET_TCP)) { 80 | stop_tcp(); 81 | } 82 | } 83 | 84 | static void event_handler(struct net_mgmt_event_callback *cb, 85 | uint32_t mgmt_event, struct net_if *iface) 86 | { 87 | if ((mgmt_event & EVENT_MASK) != mgmt_event) { 88 | return; 89 | } 90 | 91 | if (want_to_quit) { 92 | k_sem_give(&run_app); 93 | want_to_quit = false; 94 | } 95 | 96 | if (mgmt_event == NET_EVENT_L4_CONNECTED) { 97 | LOG_INF("Network connected"); 98 | 99 | connected = true; 100 | k_sem_give(&run_app); 101 | 102 | return; 103 | } 104 | 105 | if (mgmt_event == NET_EVENT_L4_DISCONNECTED) { 106 | if (connected == false) { 107 | LOG_INF("Waiting network to be connected"); 108 | } else { 109 | LOG_INF("Network disconnected"); 110 | connected = false; 111 | } 112 | 113 | k_sem_reset(&run_app); 114 | 115 | return; 116 | } 117 | } 118 | 119 | static void init_app(void) 120 | { 121 | k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); 122 | 123 | LOG_INF(APP_BANNER); 124 | 125 | if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { 126 | net_mgmt_init_event_callback(&mgmt_cb, 127 | event_handler, EVENT_MASK); 128 | net_mgmt_add_event_callback(&mgmt_cb); 129 | 130 | net_conn_mgr_resend_status(); 131 | } 132 | 133 | } 134 | 135 | static int cmd_sample_quit(const struct shell *shell, 136 | size_t argc, char *argv[]) 137 | { 138 | want_to_quit = true; 139 | 140 | net_conn_mgr_resend_status(); 141 | 142 | quit(); 143 | 144 | return 0; 145 | } 146 | 147 | SHELL_STATIC_SUBCMD_SET_CREATE(sample_commands, 148 | SHELL_CMD(quit, NULL, 149 | "Quit the sample application\n", 150 | cmd_sample_quit), 151 | SHELL_SUBCMD_SET_END 152 | ); 153 | 154 | SHELL_CMD_REGISTER(sample, &sample_commands, 155 | "Sample application commands", NULL); 156 | 157 | void main(void) 158 | { 159 | init_app(); 160 | 161 | if (!IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { 162 | /* If the config library has not been configured to start the 163 | * app only after we have a connection, then we can start 164 | * it right away. 165 | */ 166 | k_sem_give(&run_app); 167 | } 168 | 169 | /* Wait for the connection. */ 170 | k_sem_take(&run_app, K_FOREVER); 171 | 172 | start_udp_and_tcp(); 173 | 174 | k_sem_take(&quit_lock, K_FOREVER); 175 | 176 | if (connected) { 177 | stop_udp_and_tcp(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /exercises/networking/echo_server_dhcp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(sockets_echo_server) 7 | 8 | if(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND 9 | (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) 10 | add_custom_target(development_psk 11 | COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" 12 | COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" 13 | COMMAND ${CMAKE_COMMAND} -E echo "--- development. Set NET_SAMPLE_PSK_HEADER_FILE to use ---" 14 | COMMAND ${CMAKE_COMMAND} -E echo "--- own pre-shared key. ---" 15 | COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" 16 | ) 17 | add_dependencies(app development_psk) 18 | endif() 19 | 20 | target_sources( app PRIVATE src/echo-server.c) 21 | target_sources_ifdef(CONFIG_NET_UDP app PRIVATE src/udp.c) 22 | target_sources_ifdef(CONFIG_NET_TCP app PRIVATE src/tcp.c) 23 | #target_sources_ifdef(CONFIG_NET_VLAN app PRIVATE src/vlan.c) 24 | #target_sources_ifdef(CONFIG_NET_L2_IPIP app PRIVATE src/tunnel.c) 25 | 26 | include(${ZEPHYR_BASE}/samples/net/common/common.cmake) 27 | 28 | #set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) 29 | 30 | # foreach(inc_file 31 | # ca.der 32 | # server.der 33 | # server_privkey.der 34 | # echo-apps-cert.der 35 | # echo-apps-key.der 36 | # ) 37 | # generate_inc_file_for_target( 38 | # app 39 | # src/${inc_file} 40 | # ${gen_dir}/${inc_file}.inc 41 | # ) 42 | # endforeach() 43 | -------------------------------------------------------------------------------- /exercises/networking/echo_server_dhcp/Kconfig: -------------------------------------------------------------------------------- 1 | # Private config options for echo-server sample app 2 | 3 | # Copyright (c) 2018 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | mainmenu "Networking echo-server sample application" 7 | 8 | config NET_SAMPLE_NUM_HANDLERS 9 | int "How many connections to serve at the same time" 10 | default 1 11 | help 12 | Each connection is served by a thread which needs 13 | memory. Only increase the value here if really needed. 14 | 15 | config NET_SAMPLE_IFACE2_MY_IPV6_ADDR 16 | string "My IPv6 address for second interface" 17 | help 18 | The value depends on your network setup. 19 | 20 | config NET_SAMPLE_IFACE2_MY_IPV4_ADDR 21 | string "My IPv4 address for second interface" 22 | help 23 | The value depends on your network setup. 24 | 25 | config NET_SAMPLE_IFACE2_MY_IPV4_NETMASK 26 | string "My IPv4 netmask for second interface" 27 | help 28 | The value depends on your network setup. 29 | 30 | config NET_SAMPLE_IFACE2_VLAN_TAG 31 | int "VLAN tag for second interface" 32 | default 100 33 | range 0 4094 34 | depends on NET_VLAN 35 | help 36 | Set VLAN (virtual LAN) tag (id) that is used in the sample 37 | application. 38 | 39 | config NET_SAMPLE_IFACE3_MY_IPV6_ADDR 40 | string "My IPv6 address for third interface" 41 | help 42 | The value depends on your network setup. 43 | 44 | config NET_SAMPLE_IFACE3_MY_IPV4_ADDR 45 | string "My IPv4 address for third interface" 46 | help 47 | The value depends on your network setup. 48 | 49 | config NET_SAMPLE_IFACE3_MY_IPV4_NETMASK 50 | string "My IPv4 netmask for third interface" 51 | help 52 | The value depends on your network setup. 53 | 54 | config NET_SAMPLE_IFACE3_VLAN_TAG 55 | int "VLAN tag for third interface" 56 | default 200 57 | range 0 4094 58 | depends on NET_VLAN 59 | help 60 | Set VLAN (virtual LAN) tag (id) that is used in the sample 61 | application. 62 | 63 | config NET_SAMPLE_TUNNEL_PEER_ADDR 64 | string "Remote IP address of the tunnel interface" 65 | depends on NET_L2_IPIP 66 | help 67 | Use overlay-tunnel.conf to setup the tunnel support. 68 | 69 | config NET_SAMPLE_TUNNEL_MY_ADDR 70 | string "My address for tunnel interface" 71 | depends on NET_L2_IPIP 72 | help 73 | The value depends on your network setup. 74 | 75 | config NET_SAMPLE_PSK_HEADER_FILE 76 | string "Header file containing PSK" 77 | default "dummy_psk.h" 78 | depends on MBEDTLS_KEY_EXCHANGE_PSK_ENABLED 79 | help 80 | Name of a header file containing a 81 | pre-shared key. 82 | 83 | config NET_SAMPLE_CERTS_WITH_SC 84 | bool "Signed certificates" 85 | depends on NET_SOCKETS_SOCKOPT_TLS 86 | help 87 | Enable this flag, if you are interested to run this 88 | application with signed certificates and keys. 89 | 90 | source "Kconfig.zephyr" 91 | -------------------------------------------------------------------------------- /exercises/networking/echo_server_dhcp/prj.conf: -------------------------------------------------------------------------------- 1 | # Generic networking options 2 | CONFIG_NETWORKING=y 3 | CONFIG_NET_UDP=y 4 | CONFIG_NET_TCP=y 5 | CONFIG_NET_IPV6=n 6 | CONFIG_NET_IPV4=y 7 | CONFIG_NET_SOCKETS=y 8 | CONFIG_NET_SOCKETS_POSIX_NAMES=y 9 | CONFIG_POSIX_MAX_FDS=6 10 | CONFIG_NET_CONNECTION_MANAGER=y 11 | 12 | # Kernel options 13 | CONFIG_MAIN_STACK_SIZE=2048 14 | CONFIG_ENTROPY_GENERATOR=y 15 | CONFIG_TEST_RANDOM_GENERATOR=y 16 | CONFIG_INIT_STACKS=y 17 | 18 | # Logging 19 | CONFIG_NET_LOG=y 20 | CONFIG_LOG=y 21 | CONFIG_NET_STATISTICS=y 22 | CONFIG_PRINTK=y 23 | 24 | # Network buffers 25 | CONFIG_NET_PKT_RX_COUNT=16 26 | CONFIG_NET_PKT_TX_COUNT=16 27 | CONFIG_NET_BUF_RX_COUNT=64 28 | CONFIG_NET_BUF_TX_COUNT=64 29 | CONFIG_NET_CONTEXT_NET_PKT_POOL=y 30 | 31 | # IP address options 32 | CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 33 | CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4 34 | CONFIG_NET_MAX_CONTEXTS=10 35 | 36 | # Network shell 37 | CONFIG_NET_SHELL=y 38 | CONFIG_SHELL=y 39 | 40 | # Network application options and configuration 41 | CONFIG_NET_CONFIG_SETTINGS=y 42 | CONFIG_NET_CONFIG_NEED_IPV6=n 43 | #CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" 44 | #CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" 45 | CONFIG_NET_CONFIG_NEED_IPV4=y 46 | CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.0.247" 47 | CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.168.0.239" 48 | 49 | # Number of socket descriptors might need adjusting 50 | # if there are more than 1 handlers defined. 51 | CONFIG_POSIX_MAX_FDS=12 52 | 53 | # How many client can connect to echo-server simultaneously 54 | CONFIG_NET_SAMPLE_NUM_HANDLERS=2 55 | -------------------------------------------------------------------------------- /exercises/networking/echo_server_dhcp/src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2019 Intel Corporation. 3 | * Copyright (c) 2018 Nordic Semiconductor ASA. 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | 9 | #define MY_PORT 4242 10 | #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) || defined(CONFIG_NET_TCP2) || \ 11 | defined(CONFIG_COVERAGE) 12 | #define STACK_SIZE 4096 13 | #else 14 | #define STACK_SIZE 2048 15 | #endif 16 | 17 | #if IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE) 18 | #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1) 19 | #else 20 | #define THREAD_PRIORITY K_PRIO_PREEMPT(8) 21 | #endif 22 | 23 | #define RECV_BUFFER_SIZE 1280 24 | #define STATS_TIMER 60 /* How often to print statistics (in seconds) */ 25 | 26 | #if defined(CONFIG_USERSPACE) 27 | #include 28 | extern struct k_mem_partition app_partition; 29 | extern struct k_mem_domain app_domain; 30 | #define APP_BMEM K_APP_BMEM(app_partition) 31 | #define APP_DMEM K_APP_DMEM(app_partition) 32 | #else 33 | #define APP_BMEM 34 | #define APP_DMEM 35 | #endif 36 | 37 | struct data { 38 | const char *proto; 39 | 40 | struct { 41 | int sock; 42 | char recv_buffer[RECV_BUFFER_SIZE]; 43 | uint32_t counter; 44 | atomic_t bytes_received; 45 | struct k_work_delayable stats_print; 46 | } udp; 47 | 48 | struct { 49 | int sock; 50 | atomic_t bytes_received; 51 | struct k_work_delayable stats_print; 52 | 53 | struct { 54 | int sock; 55 | char recv_buffer[RECV_BUFFER_SIZE]; 56 | uint32_t counter; 57 | } accepted[CONFIG_NET_SAMPLE_NUM_HANDLERS]; 58 | } tcp; 59 | }; 60 | 61 | struct configs { 62 | struct data ipv4; 63 | struct data ipv6; 64 | }; 65 | 66 | extern struct configs conf; 67 | 68 | void start_udp(void); 69 | void stop_udp(void); 70 | 71 | void start_tcp(void); 72 | void stop_tcp(void); 73 | 74 | void quit(void); 75 | 76 | #if defined(CONFIG_NET_VLAN) 77 | int init_vlan(void); 78 | #else 79 | static inline int init_vlan(void) 80 | { 81 | return 0; 82 | } 83 | #endif /* CONFIG_NET_VLAN */ 84 | 85 | #if defined(CONFIG_NET_L2_IPIP) 86 | int init_tunnel(void); 87 | bool is_tunnel(struct net_if *iface); 88 | #else 89 | static inline int init_tunnel(void) 90 | { 91 | return 0; 92 | } 93 | 94 | static inline bool is_tunnel(struct net_if *iface) 95 | { 96 | ARG_UNUSED(iface); 97 | return false; 98 | } 99 | #endif /* CONFIG_NET_L2_IPIP */ 100 | -------------------------------------------------------------------------------- /exercises/networking/echo_server_dhcp/src/echo-server.c: -------------------------------------------------------------------------------- 1 | /* echo-server.c - Networking echo server */ 2 | 3 | /* 4 | * Copyright (c) 2016 Intel Corporation. 5 | * Copyright (c) 2018 Nordic Semiconductor ASA. 6 | * 7 | * SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | #include 11 | LOG_MODULE_REGISTER(net_echo_server_sample, LOG_LEVEL_DBG); 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "common.h" 26 | //#include "certificate.h" 27 | 28 | #define APP_BANNER "Run echo server" 29 | 30 | static struct k_sem quit_lock; 31 | static struct net_mgmt_event_callback mgmt_cb; 32 | static bool connected; 33 | K_SEM_DEFINE(run_app, 0, 1); 34 | static bool want_to_quit; 35 | 36 | #if defined(CONFIG_USERSPACE) 37 | K_APPMEM_PARTITION_DEFINE(app_partition); 38 | struct k_mem_domain app_domain; 39 | #endif 40 | 41 | #define EVENT_MASK (NET_EVENT_L4_CONNECTED | \ 42 | NET_EVENT_L4_DISCONNECTED) 43 | 44 | APP_DMEM struct configs conf = { 45 | .ipv4 = { 46 | .proto = "IPv4", 47 | }, 48 | .ipv6 = { 49 | .proto = "IPv6", 50 | }, 51 | }; 52 | 53 | void quit(void) 54 | { 55 | k_sem_give(&quit_lock); 56 | } 57 | 58 | static void start_udp_and_tcp(void) 59 | { 60 | LOG_INF("Starting..."); 61 | 62 | if (IS_ENABLED(CONFIG_NET_TCP)) { 63 | start_tcp(); 64 | } 65 | 66 | if (IS_ENABLED(CONFIG_NET_UDP)) { 67 | start_udp(); 68 | } 69 | } 70 | 71 | static void stop_udp_and_tcp(void) 72 | { 73 | LOG_INF("Stopping..."); 74 | 75 | if (IS_ENABLED(CONFIG_NET_UDP)) { 76 | stop_udp(); 77 | } 78 | 79 | if (IS_ENABLED(CONFIG_NET_TCP)) { 80 | stop_tcp(); 81 | } 82 | } 83 | 84 | static void event_handler(struct net_mgmt_event_callback *cb, 85 | uint32_t mgmt_event, struct net_if *iface) 86 | { 87 | if ((mgmt_event & EVENT_MASK) != mgmt_event) { 88 | return; 89 | } 90 | 91 | if (want_to_quit) { 92 | k_sem_give(&run_app); 93 | want_to_quit = false; 94 | } 95 | 96 | if (mgmt_event == NET_EVENT_L4_CONNECTED) { 97 | LOG_INF("Network connected"); 98 | 99 | connected = true; 100 | k_sem_give(&run_app); 101 | 102 | return; 103 | } 104 | 105 | if (mgmt_event == NET_EVENT_L4_DISCONNECTED) { 106 | if (connected == false) { 107 | LOG_INF("Waiting network to be connected"); 108 | } else { 109 | LOG_INF("Network disconnected"); 110 | connected = false; 111 | } 112 | 113 | k_sem_reset(&run_app); 114 | 115 | return; 116 | } 117 | } 118 | 119 | static void init_app(void) 120 | { 121 | k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); 122 | 123 | LOG_INF(APP_BANNER); 124 | 125 | if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { 126 | net_mgmt_init_event_callback(&mgmt_cb, 127 | event_handler, EVENT_MASK); 128 | net_mgmt_add_event_callback(&mgmt_cb); 129 | 130 | net_conn_mgr_resend_status(); 131 | } 132 | 133 | } 134 | 135 | static int cmd_sample_quit(const struct shell *shell, 136 | size_t argc, char *argv[]) 137 | { 138 | want_to_quit = true; 139 | 140 | net_conn_mgr_resend_status(); 141 | 142 | quit(); 143 | 144 | return 0; 145 | } 146 | 147 | SHELL_STATIC_SUBCMD_SET_CREATE(sample_commands, 148 | SHELL_CMD(quit, NULL, 149 | "Quit the sample application\n", 150 | cmd_sample_quit), 151 | SHELL_SUBCMD_SET_END 152 | ); 153 | 154 | SHELL_CMD_REGISTER(sample, &sample_commands, 155 | "Sample application commands", NULL); 156 | 157 | void main(void) 158 | { 159 | init_app(); 160 | 161 | if (!IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { 162 | /* If the config library has not been configured to start the 163 | * app only after we have a connection, then we can start 164 | * it right away. 165 | */ 166 | k_sem_give(&run_app); 167 | } 168 | 169 | /* Wait for the connection. */ 170 | k_sem_take(&run_app, K_FOREVER); 171 | 172 | start_udp_and_tcp(); 173 | 174 | k_sem_take(&quit_lock, K_FOREVER); 175 | 176 | if (connected) { 177 | stop_udp_and_tcp(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /exercises/networking/python-networking/client.py: -------------------------------------------------------------------------------- 1 | # based on https://www.youtube.com/watch?v=3QiPPX-KeSc 2 | 3 | import socket 4 | 5 | HEADER = 64 6 | PORT = 4242 7 | FORMAT = 'utf-8' 8 | DISCONNECT_MESSAGE = "!DISCONNECT" 9 | SERVER = "192.168.0.240" 10 | ADDR = (SERVER, PORT) 11 | 12 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 13 | client.connect(ADDR) 14 | 15 | def send(msg): 16 | message = msg.encode(FORMAT) 17 | msg_length = len(message) 18 | send_length = str(msg_length).encode(FORMAT) 19 | send_length += b' ' * ( HEADER - len(send_length) ) 20 | client.send(send_length) 21 | client.send(message) 22 | 23 | send("Hello World!") 24 | #send("Hello Everyone!") 25 | 26 | #send(DISCONNECT_MESSAGE) -------------------------------------------------------------------------------- /exercises/networking/python-networking/server.py: -------------------------------------------------------------------------------- 1 | # based on https://www.youtube.com/watch?v=3QiPPX-KeSc 2 | 3 | import socket 4 | import threading 5 | 6 | HEADER = 64 7 | PORT = 5050 8 | # local IP address 9 | SERVER = socket.gethostbyname(socket.gethostname()) 10 | print("Local IP address: ",SERVER) 11 | print("host name: ",socket.gethostname()) 12 | ADDR = (SERVER, PORT) 13 | FORMAT = 'utf-8' 14 | DISCONNECT_MESSAGE = "!DISCONNECT" 15 | 16 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 17 | server.bind(ADDR) 18 | 19 | def handle_client(conn, addr): 20 | print(f"[NEW CONNECTION] {addr} connected.") 21 | 22 | connected = True 23 | while connected: 24 | msg_length = conn.recv(HEADER).decode(FORMAT) 25 | if msg_length: 26 | msg_length = int(msg_length) 27 | msg = conn.recv(msg_length).decode(FORMAT) 28 | if msg == DISCONNECT_MESSAGE: 29 | connected = False 30 | 31 | print(f"[{addr}] {msg}") 32 | conn.close() 33 | 34 | 35 | def start(): 36 | server.listen() 37 | while True: 38 | conn, addr = server.accept() 39 | thread = threading.Thread(target=handle_client, args=(conn,addr)) 40 | thread.start() 41 | print(f"[ACTIVE CONNECTIONS] {threading.activeCount()-1}") 42 | 43 | 44 | print("[STARTING] server is starting...") 45 | start() 46 | -------------------------------------------------------------------------------- /exercises/scheduling/cooperative-time-slicing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(threads) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/scheduling/cooperative-time-slicing/README.rst: -------------------------------------------------------------------------------- 1 | .. _96b_carbon_multi_thread_blinky: 2 | 3 | Basic Thread Example 4 | #################### 5 | 6 | Overview 7 | ******** 8 | 9 | This example demonstrates spawning multiple threads using 10 | :c:func:`K_THREAD_DEFINE`. It spawns three threads. Each thread is then defined 11 | at compile time using K_THREAD_DEFINE. 12 | 13 | The first two each control an LED. These LEDs, ``led0`` and ``led1``, have 14 | loop control and timing logic controlled by separate functions. 15 | 16 | - ``blink0()`` controls ``led0`` and has a 100ms sleep cycle 17 | - ``blink1()`` controls ``led1`` and has a 1000ms sleep cycle 18 | 19 | When either of these threads toggles its LED, it also pushes information into a 20 | :ref:`FIFO ` identifying the thread/LED and how many times it has 21 | been toggled. 22 | 23 | The third thread uses :c:func:`printk` to print the information added to the 24 | FIFO to the device console. 25 | 26 | Requirements 27 | ************ 28 | 29 | The board must have two LEDs connected via GPIO pins. These are called "User 30 | LEDs" on many of Zephyr's :ref:`boards`. The LEDs must be configured using the 31 | ``led0`` and ``led1`` :ref:`devicetree ` aliases, usually in the 32 | :ref:`BOARD.dts file `. 33 | 34 | You will see one of these errors if you try to build this sample for an 35 | unsupported board: 36 | 37 | .. code-block:: none 38 | 39 | Unsupported board: led0 devicetree alias is not defined 40 | Unsupported board: led1 devicetree alias is not defined 41 | 42 | Building 43 | ******** 44 | 45 | For example, to build this sample for :ref:`96b_carbon_board`: 46 | 47 | .. zephyr-app-commands:: 48 | :zephyr-app: samples/basic/threads 49 | :board: 96b_carbon 50 | :goals: build flash 51 | :compact: 52 | 53 | Change ``96b_carbon`` appropriately for other supported boards. 54 | -------------------------------------------------------------------------------- /exercises/scheduling/cooperative-time-slicing/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | 5 | -------------------------------------------------------------------------------- /exercises/scheduling/cooperative-time-slicing/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A basic demo to showcase multi-threading 3 | using K_THREAD_DEFINE 4 | name: Basic Thread Demo 5 | tests: 6 | sample.basic.threads: 7 | tags: kernel threads gpio 8 | filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and 9 | dt_enabled_alias_with_parent_compat("led1", "gpio-leds") 10 | depends_on: gpio 11 | harness: console 12 | harness_config: 13 | type: multi_line 14 | ordered: false 15 | regex: 16 | - "Toggled led0; counter=(.*)" 17 | - "Toggled led1; counter=(.*)" 18 | -------------------------------------------------------------------------------- /exercises/scheduling/cooperative-time-slicing/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | /* size of stack area used by each thread */ 11 | #define STACKSIZE 1024 12 | 13 | #define PRIORITY_THREAD_1 (-1) 14 | #define PRIORITY_THREAD_2 (-2) 15 | 16 | 17 | K_THREAD_STACK_DEFINE(thread_1_stack_area, STACKSIZE); 18 | static struct k_thread thread_1_data; 19 | 20 | K_THREAD_STACK_DEFINE(thread_2_stack_area, STACKSIZE); 21 | static struct k_thread thread_2_data; 22 | 23 | void thread_1(void *dummy1, void *dummy2, void *dummy3) 24 | { 25 | ARG_UNUSED(dummy1); 26 | ARG_UNUSED(dummy2); 27 | ARG_UNUSED(dummy3); 28 | 29 | int i = 0; 30 | 31 | printk("thread_1: thread started \n"); 32 | k_thread_start(&thread_2_data); 33 | printk("thread_1: thead_2 started \n"); 34 | 35 | while (1) 36 | { 37 | i++; 38 | printk("thread_1: thread loop %d\n", i); 39 | if (i == 3) 40 | { 41 | printk("thread_1: thread abort\n"); 42 | k_thread_abort(&thread_1_data); 43 | } 44 | } 45 | 46 | } 47 | 48 | void thread_2(void *dummy1, void *dummy2, void *dummy3) 49 | { 50 | ARG_UNUSED(dummy1); 51 | ARG_UNUSED(dummy2); 52 | ARG_UNUSED(dummy3); 53 | 54 | int i = 0; 55 | 56 | printk("thread_2: thread started \n"); 57 | 58 | while (1) 59 | { 60 | i++; 61 | printk("thread_2: thread loop %d\n", i); 62 | if (i == 3) 63 | { 64 | printk("thread_2: thread abort\n"); 65 | k_thread_abort(&thread_2_data); 66 | } 67 | } 68 | 69 | } 70 | 71 | void main(void) 72 | { 73 | k_thread_create(&thread_1_data, thread_1_stack_area, 74 | K_THREAD_STACK_SIZEOF(thread_1_stack_area), 75 | thread_1, NULL, NULL, NULL, 76 | PRIORITY_THREAD_1, 0, K_FOREVER); 77 | k_thread_name_set(&thread_1_data, "thread_1"); 78 | 79 | k_thread_create(&thread_2_data, thread_2_stack_area, 80 | K_THREAD_STACK_SIZEOF(thread_2_stack_area), 81 | thread_2, NULL, NULL, NULL, 82 | PRIORITY_THREAD_2, 0, K_FOREVER); 83 | k_thread_name_set(&thread_2_data, "thread_2"); 84 | 85 | k_thread_start(&thread_1_data); 86 | } 87 | -------------------------------------------------------------------------------- /exercises/scheduling/preemptive-time-slicing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(threads) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/scheduling/preemptive-time-slicing/README.rst: -------------------------------------------------------------------------------- 1 | .. _96b_carbon_multi_thread_blinky: 2 | 3 | Basic Thread Example 4 | #################### 5 | 6 | Overview 7 | ******** 8 | 9 | This example demonstrates spawning multiple threads using 10 | :c:func:`K_THREAD_DEFINE`. It spawns three threads. Each thread is then defined 11 | at compile time using K_THREAD_DEFINE. 12 | 13 | The first two each control an LED. These LEDs, ``led0`` and ``led1``, have 14 | loop control and timing logic controlled by separate functions. 15 | 16 | - ``blink0()`` controls ``led0`` and has a 100ms sleep cycle 17 | - ``blink1()`` controls ``led1`` and has a 1000ms sleep cycle 18 | 19 | When either of these threads toggles its LED, it also pushes information into a 20 | :ref:`FIFO ` identifying the thread/LED and how many times it has 21 | been toggled. 22 | 23 | The third thread uses :c:func:`printk` to print the information added to the 24 | FIFO to the device console. 25 | 26 | Requirements 27 | ************ 28 | 29 | The board must have two LEDs connected via GPIO pins. These are called "User 30 | LEDs" on many of Zephyr's :ref:`boards`. The LEDs must be configured using the 31 | ``led0`` and ``led1`` :ref:`devicetree ` aliases, usually in the 32 | :ref:`BOARD.dts file `. 33 | 34 | You will see one of these errors if you try to build this sample for an 35 | unsupported board: 36 | 37 | .. code-block:: none 38 | 39 | Unsupported board: led0 devicetree alias is not defined 40 | Unsupported board: led1 devicetree alias is not defined 41 | 42 | Building 43 | ******** 44 | 45 | For example, to build this sample for :ref:`96b_carbon_board`: 46 | 47 | .. zephyr-app-commands:: 48 | :zephyr-app: samples/basic/threads 49 | :board: 96b_carbon 50 | :goals: build flash 51 | :compact: 52 | 53 | Change ``96b_carbon`` appropriately for other supported boards. 54 | -------------------------------------------------------------------------------- /exercises/scheduling/preemptive-time-slicing/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | 5 | -------------------------------------------------------------------------------- /exercises/scheduling/preemptive-time-slicing/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A basic demo to showcase multi-threading 3 | using K_THREAD_DEFINE 4 | name: Basic Thread Demo 5 | tests: 6 | sample.basic.threads: 7 | tags: kernel threads gpio 8 | filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and 9 | dt_enabled_alias_with_parent_compat("led1", "gpio-leds") 10 | depends_on: gpio 11 | harness: console 12 | harness_config: 13 | type: multi_line 14 | ordered: false 15 | regex: 16 | - "Toggled led0; counter=(.*)" 17 | - "Toggled led1; counter=(.*)" 18 | -------------------------------------------------------------------------------- /exercises/scheduling/preemptive-time-slicing/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | /* size of stack area used by each thread */ 11 | #define STACKSIZE 1024 12 | 13 | #define PRIORITY_THREAD_1 (3) 14 | #define PRIORITY_THREAD_2 (2) 15 | #define PRIORITY_THREAD_3 (1) 16 | 17 | 18 | K_THREAD_STACK_DEFINE(thread_1_stack_area, STACKSIZE); 19 | static struct k_thread thread_1_data; 20 | 21 | K_THREAD_STACK_DEFINE(thread_2_stack_area, STACKSIZE); 22 | static struct k_thread thread_2_data; 23 | 24 | K_THREAD_STACK_DEFINE(thread_3_stack_area, STACKSIZE); 25 | static struct k_thread thread_3_data; 26 | 27 | void thread_1(void *dummy1, void *dummy2, void *dummy3) 28 | { 29 | ARG_UNUSED(dummy1); 30 | ARG_UNUSED(dummy2); 31 | ARG_UNUSED(dummy3); 32 | 33 | int i = 0; 34 | 35 | printk("thread_1: thread started \n"); 36 | k_thread_start(&thread_2_data); 37 | 38 | while (1) 39 | { 40 | i++; 41 | printk("thread_1: thread loop %d\n", i); 42 | if (i == 3) 43 | { 44 | printk("thread_1: thread abort\n"); 45 | k_thread_abort(&thread_1_data); 46 | } 47 | } 48 | 49 | } 50 | 51 | void thread_2(void *dummy1, void *dummy2, void *dummy3) 52 | { 53 | ARG_UNUSED(dummy1); 54 | ARG_UNUSED(dummy2); 55 | ARG_UNUSED(dummy3); 56 | 57 | int i = 0; 58 | 59 | printk("thread_2: thread started \n"); 60 | k_thread_start(&thread_3_data); 61 | 62 | while (1) 63 | { 64 | i++; 65 | printk("thread_2: thread loop %d\n", i); 66 | if (i == 3) 67 | { 68 | printk("thread_2: thread abort\n"); 69 | k_thread_abort(&thread_2_data); 70 | } 71 | } 72 | 73 | } 74 | 75 | void thread_3(void *dummy1, void *dummy2, void *dummy3) 76 | { 77 | ARG_UNUSED(dummy1); 78 | ARG_UNUSED(dummy2); 79 | ARG_UNUSED(dummy3); 80 | 81 | int i = 0; 82 | 83 | printk("thread_3: thread started \n"); 84 | 85 | while (1) 86 | { 87 | i++; 88 | printk("thread_3: thread loop %d\n", i); 89 | if (i == 3) 90 | { 91 | printk("thread_3: thread abort\n"); 92 | k_thread_abort(&thread_3_data); 93 | } 94 | } 95 | 96 | } 97 | 98 | void main(void) 99 | { 100 | k_thread_create(&thread_1_data, thread_1_stack_area, 101 | K_THREAD_STACK_SIZEOF(thread_1_stack_area), 102 | thread_1, NULL, NULL, NULL, 103 | PRIORITY_THREAD_1, 0, K_FOREVER); 104 | k_thread_name_set(&thread_1_data, "thread_1"); 105 | 106 | k_thread_create(&thread_2_data, thread_2_stack_area, 107 | K_THREAD_STACK_SIZEOF(thread_2_stack_area), 108 | thread_2, NULL, NULL, NULL, 109 | PRIORITY_THREAD_2, 0, K_FOREVER); 110 | k_thread_name_set(&thread_2_data, "thread_2"); 111 | 112 | k_thread_create(&thread_3_data, thread_3_stack_area, 113 | K_THREAD_STACK_SIZEOF(thread_3_stack_area), 114 | thread_3, NULL, NULL, NULL, 115 | PRIORITY_THREAD_3, 0, K_FOREVER); 116 | k_thread_name_set(&thread_3_data, "thread_3"); 117 | 118 | k_thread_start(&thread_1_data); 119 | } 120 | -------------------------------------------------------------------------------- /exercises/scheduling/time-slicing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(threads) 6 | 7 | target_sources(app PRIVATE src/main.c) 8 | -------------------------------------------------------------------------------- /exercises/scheduling/time-slicing/README.rst: -------------------------------------------------------------------------------- 1 | .. _96b_carbon_multi_thread_blinky: 2 | 3 | Basic Thread Example 4 | #################### 5 | 6 | Overview 7 | ******** 8 | 9 | This example demonstrates spawning multiple threads using 10 | :c:func:`K_THREAD_DEFINE`. It spawns three threads. Each thread is then defined 11 | at compile time using K_THREAD_DEFINE. 12 | 13 | The first two each control an LED. These LEDs, ``led0`` and ``led1``, have 14 | loop control and timing logic controlled by separate functions. 15 | 16 | - ``blink0()`` controls ``led0`` and has a 100ms sleep cycle 17 | - ``blink1()`` controls ``led1`` and has a 1000ms sleep cycle 18 | 19 | When either of these threads toggles its LED, it also pushes information into a 20 | :ref:`FIFO ` identifying the thread/LED and how many times it has 21 | been toggled. 22 | 23 | The third thread uses :c:func:`printk` to print the information added to the 24 | FIFO to the device console. 25 | 26 | Requirements 27 | ************ 28 | 29 | The board must have two LEDs connected via GPIO pins. These are called "User 30 | LEDs" on many of Zephyr's :ref:`boards`. The LEDs must be configured using the 31 | ``led0`` and ``led1`` :ref:`devicetree ` aliases, usually in the 32 | :ref:`BOARD.dts file `. 33 | 34 | You will see one of these errors if you try to build this sample for an 35 | unsupported board: 36 | 37 | .. code-block:: none 38 | 39 | Unsupported board: led0 devicetree alias is not defined 40 | Unsupported board: led1 devicetree alias is not defined 41 | 42 | Building 43 | ******** 44 | 45 | For example, to build this sample for :ref:`96b_carbon_board`: 46 | 47 | .. zephyr-app-commands:: 48 | :zephyr-app: samples/basic/threads 49 | :board: 96b_carbon 50 | :goals: build flash 51 | :compact: 52 | 53 | Change ``96b_carbon`` appropriately for other supported boards. 54 | -------------------------------------------------------------------------------- /exercises/scheduling/time-slicing/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | CONFIG_TIMESLICING=y 5 | CONFIG_TIMESLICE_SIZE=10 6 | 7 | -------------------------------------------------------------------------------- /exercises/scheduling/time-slicing/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A basic demo to showcase multi-threading 3 | using K_THREAD_DEFINE 4 | name: Basic Thread Demo 5 | tests: 6 | sample.basic.threads: 7 | tags: kernel threads gpio 8 | filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and 9 | dt_enabled_alias_with_parent_compat("led1", "gpio-leds") 10 | depends_on: gpio 11 | harness: console 12 | harness_config: 13 | type: multi_line 14 | ordered: false 15 | regex: 16 | - "Toggled led0; counter=(.*)" 17 | - "Toggled led1; counter=(.*)" 18 | -------------------------------------------------------------------------------- /exercises/scheduling/time-slicing/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | /* size of stack area used by each thread */ 11 | #define STACKSIZE 1024 12 | 13 | #define PRIORITY_THREAD_1 (1) 14 | #define PRIORITY_THREAD_2 (1) 15 | #define PRIORITY_THREAD_3 (1) 16 | 17 | 18 | K_THREAD_STACK_DEFINE(thread_1_stack_area, STACKSIZE); 19 | static struct k_thread thread_1_data; 20 | 21 | K_THREAD_STACK_DEFINE(thread_2_stack_area, STACKSIZE); 22 | static struct k_thread thread_2_data; 23 | 24 | K_THREAD_STACK_DEFINE(thread_3_stack_area, STACKSIZE); 25 | static struct k_thread thread_3_data; 26 | 27 | void thread_1(void *dummy1, void *dummy2, void *dummy3) 28 | { 29 | ARG_UNUSED(dummy1); 30 | ARG_UNUSED(dummy2); 31 | ARG_UNUSED(dummy3); 32 | 33 | printk("thread_1: thread started \n"); 34 | 35 | 36 | while (1) 37 | { 38 | printk("thread_1: thread loop \n"); 39 | } 40 | 41 | } 42 | 43 | void thread_2(void *dummy1, void *dummy2, void *dummy3) 44 | { 45 | ARG_UNUSED(dummy1); 46 | ARG_UNUSED(dummy2); 47 | ARG_UNUSED(dummy3); 48 | 49 | printk("thread_2: thread started \n"); 50 | 51 | while (1) 52 | { 53 | printk("thread_2: thread loop \n"); 54 | } 55 | 56 | } 57 | 58 | void thread_3(void *dummy1, void *dummy2, void *dummy3) 59 | { 60 | ARG_UNUSED(dummy1); 61 | ARG_UNUSED(dummy2); 62 | ARG_UNUSED(dummy3); 63 | 64 | printk("thread_3: thread started \n"); 65 | 66 | while (1) 67 | { 68 | printk("thread_3: thread loop \n"); 69 | } 70 | 71 | } 72 | 73 | void main(void) 74 | { 75 | k_thread_create(&thread_1_data, thread_1_stack_area, 76 | K_THREAD_STACK_SIZEOF(thread_1_stack_area), 77 | thread_1, NULL, NULL, NULL, 78 | PRIORITY_THREAD_1, 0, K_FOREVER); 79 | k_thread_name_set(&thread_1_data, "thread_1"); 80 | 81 | k_thread_create(&thread_2_data, thread_2_stack_area, 82 | K_THREAD_STACK_SIZEOF(thread_2_stack_area), 83 | thread_2, NULL, NULL, NULL, 84 | PRIORITY_THREAD_2, 0, K_FOREVER); 85 | k_thread_name_set(&thread_2_data, "thread_2"); 86 | 87 | k_thread_create(&thread_3_data, thread_3_stack_area, 88 | K_THREAD_STACK_SIZEOF(thread_3_stack_area), 89 | thread_3, NULL, NULL, NULL, 90 | PRIORITY_THREAD_3, 0, K_FOREVER); 91 | k_thread_name_set(&thread_3_data, "thread_3"); 92 | 93 | k_thread_start(&thread_1_data); 94 | k_thread_start(&thread_2_data); 95 | k_thread_start(&thread_3_data); 96 | } 97 | -------------------------------------------------------------------------------- /exercises/threads/thread-abort/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(k_thread_start) 7 | 8 | target_sources(app PRIVATE src/main.c) 9 | -------------------------------------------------------------------------------- /exercises/threads/thread-abort/README.rst: -------------------------------------------------------------------------------- 1 | .. _synchronization_sample: 2 | 3 | Synchronization Sample 4 | ###################### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple application that demonstrates basic sanity of the kernel. 10 | Two threads (A and B) take turns printing a greeting message to the console, 11 | and use sleep requests and semaphores to control the rate at which messages 12 | are generated. This demonstrates that kernel scheduling, communication, 13 | and timing are operating correctly. 14 | 15 | Building and Running 16 | ******************** 17 | 18 | This project outputs to the console. It can be built and executed 19 | on QEMU as follows: 20 | 21 | .. zephyr-app-commands:: 22 | :zephyr-app: samples/synchronization 23 | :host-os: unix 24 | :board: qemu_x86 25 | :goals: run 26 | :compact: 27 | 28 | Sample Output 29 | ============= 30 | 31 | .. code-block:: console 32 | 33 | threadA: Hello World! 34 | threadB: Hello World! 35 | threadA: Hello World! 36 | threadB: Hello World! 37 | threadA: Hello World! 38 | threadB: Hello World! 39 | threadA: Hello World! 40 | threadB: Hello World! 41 | threadA: Hello World! 42 | threadB: Hello World! 43 | 44 | 45 | 46 | Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. 47 | -------------------------------------------------------------------------------- /exercises/threads/thread-abort/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_STDOUT_CONSOLE=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | CONFIG_SCHED_CPU_MASK=y 5 | -------------------------------------------------------------------------------- /exercises/threads/thread-abort/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A simple application that demonstrates 3 | basic sanity of the kernel. 4 | name: Synchronization Sample 5 | tests: 6 | sample.kernel.synchronization: 7 | build_on_all: true 8 | tags: synchronization 9 | harness: console 10 | harness_config: 11 | type: multi_line 12 | regex: 13 | - "thread_a: Hello World from (.*)!" 14 | - "thread_b: Hello World from (.*)!" 15 | -------------------------------------------------------------------------------- /exercises/threads/thread-abort/src/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - Hello World demo */ 2 | 3 | /* 4 | * Copyright (c) 2012-2014 Wind River Systems, Inc. 5 | * 6 | * SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | /* scheduling priority used by each thread */ 16 | #define PRIORITY 7 17 | 18 | /* delay between greetings (in ms) */ 19 | #define SLEEPTIME 500 20 | 21 | 22 | K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); 23 | static struct k_thread threadA_data; 24 | 25 | /* threadA is a static thread that is spawned automatically */ 26 | 27 | void threadA(void *dummy1, void *dummy2, void *dummy3) 28 | { 29 | ARG_UNUSED(dummy1); 30 | ARG_UNUSED(dummy2); 31 | ARG_UNUSED(dummy3); 32 | 33 | int i = 10; // Amount of times to execute while loop 34 | 35 | printk("thread_a: thread started \n"); 36 | 37 | while (1) 38 | { 39 | printk("thread_a: thread loop \n"); 40 | k_msleep(SLEEPTIME); 41 | i -= 1; 42 | if (i == 0) 43 | { 44 | printk("thread_a: thread abort \n"); 45 | k_thread_abort(&threadA_data); 46 | } 47 | } 48 | 49 | } 50 | 51 | void main(void) 52 | { 53 | k_thread_create(&threadA_data, threadA_stack_area, 54 | K_THREAD_STACK_SIZEOF(threadA_stack_area), 55 | threadA, NULL, NULL, NULL, 56 | PRIORITY, 0, K_FOREVER); 57 | k_thread_name_set(&threadA_data, "thread_a"); 58 | 59 | k_thread_start(&threadA_data); 60 | } 61 | -------------------------------------------------------------------------------- /exercises/threads/thread-join/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(k_thread_start) 7 | 8 | target_sources(app PRIVATE src/main.c) 9 | -------------------------------------------------------------------------------- /exercises/threads/thread-join/README.rst: -------------------------------------------------------------------------------- 1 | .. _synchronization_sample: 2 | 3 | Synchronization Sample 4 | ###################### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple application that demonstrates basic sanity of the kernel. 10 | Two threads (A and B) take turns printing a greeting message to the console, 11 | and use sleep requests and semaphores to control the rate at which messages 12 | are generated. This demonstrates that kernel scheduling, communication, 13 | and timing are operating correctly. 14 | 15 | Building and Running 16 | ******************** 17 | 18 | This project outputs to the console. It can be built and executed 19 | on QEMU as follows: 20 | 21 | .. zephyr-app-commands:: 22 | :zephyr-app: samples/synchronization 23 | :host-os: unix 24 | :board: qemu_x86 25 | :goals: run 26 | :compact: 27 | 28 | Sample Output 29 | ============= 30 | 31 | .. code-block:: console 32 | 33 | threadA: Hello World! 34 | threadB: Hello World! 35 | threadA: Hello World! 36 | threadB: Hello World! 37 | threadA: Hello World! 38 | threadB: Hello World! 39 | threadA: Hello World! 40 | threadB: Hello World! 41 | threadA: Hello World! 42 | threadB: Hello World! 43 | 44 | 45 | 46 | Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. 47 | -------------------------------------------------------------------------------- /exercises/threads/thread-join/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_STDOUT_CONSOLE=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | CONFIG_SCHED_CPU_MASK=y 5 | -------------------------------------------------------------------------------- /exercises/threads/thread-join/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A simple application that demonstrates 3 | basic sanity of the kernel. 4 | name: Synchronization Sample 5 | tests: 6 | sample.kernel.synchronization: 7 | build_on_all: true 8 | tags: synchronization 9 | harness: console 10 | harness_config: 11 | type: multi_line 12 | regex: 13 | - "thread_a: Hello World from (.*)!" 14 | - "thread_b: Hello World from (.*)!" 15 | -------------------------------------------------------------------------------- /exercises/threads/thread-join/src/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - Hello World demo */ 2 | 3 | /* 4 | * Copyright (c) 2012-2014 Wind River Systems, Inc. 5 | * 6 | * SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | /* scheduling priority used by each thread */ 16 | #define PRIORITY 7 17 | 18 | /* delay between greetings (in ms) */ 19 | #define SLEEPTIME 500 20 | 21 | 22 | K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); 23 | static struct k_thread threadA_data; 24 | 25 | K_THREAD_STACK_DEFINE(threadB_stack_area, STACKSIZE); 26 | static struct k_thread threadB_data; 27 | 28 | void threadA(void *dummy1, void *dummy2, void *dummy3) 29 | { 30 | ARG_UNUSED(dummy1); 31 | ARG_UNUSED(dummy2); 32 | ARG_UNUSED(dummy3); 33 | 34 | printk("thread_a: thread started \n"); 35 | 36 | printk("thread_a: waiting for thread_b to complete \n"); 37 | k_thread_join(&threadB_data, K_FOREVER); // wait forever until thread_b returns 38 | 39 | while (1) 40 | { 41 | printk("thread_a: thread loop \n"); 42 | k_msleep(SLEEPTIME); 43 | 44 | } 45 | 46 | } 47 | 48 | void threadB(void *dummy1, void *dummy2, void *dummy3) 49 | { 50 | ARG_UNUSED(dummy1); 51 | ARG_UNUSED(dummy2); 52 | ARG_UNUSED(dummy3); 53 | 54 | printk("thread_b: thread started \n"); 55 | 56 | k_msleep(SLEEPTIME); 57 | 58 | printk("thread_b: returning to thread_a \n"); 59 | 60 | 61 | } 62 | 63 | void main(void) 64 | { 65 | k_thread_create(&threadA_data, threadA_stack_area, 66 | K_THREAD_STACK_SIZEOF(threadA_stack_area), 67 | threadA, NULL, NULL, NULL, 68 | PRIORITY, 0, K_FOREVER); 69 | k_thread_name_set(&threadA_data, "thread_a"); 70 | 71 | k_thread_create(&threadB_data, threadB_stack_area, 72 | K_THREAD_STACK_SIZEOF(threadB_stack_area), 73 | threadB, NULL, NULL, NULL, 74 | PRIORITY+1, 0, K_FOREVER); // priority of thread_b is lower than thread_b 75 | k_thread_name_set(&threadB_data, "thread_b"); 76 | 77 | k_thread_start(&threadA_data); 78 | k_thread_start(&threadB_data); 79 | } 80 | -------------------------------------------------------------------------------- /exercises/threads/thread-sleep/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(k_thread_start) 7 | 8 | target_sources(app PRIVATE src/main.c) 9 | -------------------------------------------------------------------------------- /exercises/threads/thread-sleep/README.rst: -------------------------------------------------------------------------------- 1 | .. _synchronization_sample: 2 | 3 | Synchronization Sample 4 | ###################### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple application that demonstrates basic sanity of the kernel. 10 | Two threads (A and B) take turns printing a greeting message to the console, 11 | and use sleep requests and semaphores to control the rate at which messages 12 | are generated. This demonstrates that kernel scheduling, communication, 13 | and timing are operating correctly. 14 | 15 | Building and Running 16 | ******************** 17 | 18 | This project outputs to the console. It can be built and executed 19 | on QEMU as follows: 20 | 21 | .. zephyr-app-commands:: 22 | :zephyr-app: samples/synchronization 23 | :host-os: unix 24 | :board: qemu_x86 25 | :goals: run 26 | :compact: 27 | 28 | Sample Output 29 | ============= 30 | 31 | .. code-block:: console 32 | 33 | threadA: Hello World! 34 | threadB: Hello World! 35 | threadA: Hello World! 36 | threadB: Hello World! 37 | threadA: Hello World! 38 | threadB: Hello World! 39 | threadA: Hello World! 40 | threadB: Hello World! 41 | threadA: Hello World! 42 | threadB: Hello World! 43 | 44 | 45 | 46 | Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. 47 | -------------------------------------------------------------------------------- /exercises/threads/thread-sleep/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_STDOUT_CONSOLE=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | CONFIG_SCHED_CPU_MASK=y 5 | -------------------------------------------------------------------------------- /exercises/threads/thread-sleep/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A simple application that demonstrates 3 | basic sanity of the kernel. 4 | name: Synchronization Sample 5 | tests: 6 | sample.kernel.synchronization: 7 | build_on_all: true 8 | tags: synchronization 9 | harness: console 10 | harness_config: 11 | type: multi_line 12 | regex: 13 | - "thread_a: Hello World from (.*)!" 14 | - "thread_b: Hello World from (.*)!" 15 | -------------------------------------------------------------------------------- /exercises/threads/thread-sleep/src/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - Hello World demo */ 2 | 3 | /* 4 | * Copyright (c) 2012-2014 Wind River Systems, Inc. 5 | * 6 | * SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | /* scheduling priority used by each thread */ 16 | #define PRIORITY 7 17 | 18 | /* delay between greetings (in ms) */ 19 | #define SLEEPTIME 500 20 | 21 | 22 | K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); 23 | static struct k_thread threadA_data; 24 | 25 | /* threadA is a static thread that is spawned automatically */ 26 | 27 | void threadA(void *dummy1, void *dummy2, void *dummy3) 28 | { 29 | ARG_UNUSED(dummy1); 30 | ARG_UNUSED(dummy2); 31 | ARG_UNUSED(dummy3); 32 | 33 | int i = 2; // Amount of times to execute while loop 34 | k_timeout_t sleep_time = K_MSEC(5000); // length of sleep 35 | 36 | 37 | printk("thread_a: thread started \n"); 38 | 39 | while (1) 40 | { 41 | printk("thread_a: thread loop \n"); 42 | k_msleep(SLEEPTIME); 43 | i -= 1; 44 | if (i == 0) 45 | { 46 | printk("thread_a: sleeping for 5000 ms \n"); 47 | k_sleep(sleep_time); 48 | i = 2; 49 | } 50 | } 51 | 52 | } 53 | 54 | void main(void) 55 | { 56 | k_thread_create(&threadA_data, threadA_stack_area, 57 | K_THREAD_STACK_SIZEOF(threadA_stack_area), 58 | threadA, NULL, NULL, NULL, 59 | PRIORITY, 0, K_FOREVER); 60 | k_thread_name_set(&threadA_data, "thread_a"); 61 | 62 | k_thread_start(&threadA_data); 63 | } 64 | -------------------------------------------------------------------------------- /exercises/threads/thread-start-define/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(k_thread_start) 7 | 8 | target_sources(app PRIVATE src/main.c) 9 | -------------------------------------------------------------------------------- /exercises/threads/thread-start-define/README.rst: -------------------------------------------------------------------------------- 1 | .. _synchronization_sample: 2 | 3 | Synchronization Sample 4 | ###################### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple application that demonstrates basic sanity of the kernel. 10 | Two threads (A and B) take turns printing a greeting message to the console, 11 | and use sleep requests and semaphores to control the rate at which messages 12 | are generated. This demonstrates that kernel scheduling, communication, 13 | and timing are operating correctly. 14 | 15 | Building and Running 16 | ******************** 17 | 18 | This project outputs to the console. It can be built and executed 19 | on QEMU as follows: 20 | 21 | .. zephyr-app-commands:: 22 | :zephyr-app: samples/synchronization 23 | :host-os: unix 24 | :board: qemu_x86 25 | :goals: run 26 | :compact: 27 | 28 | Sample Output 29 | ============= 30 | 31 | .. code-block:: console 32 | 33 | threadA: Hello World! 34 | threadB: Hello World! 35 | threadA: Hello World! 36 | threadB: Hello World! 37 | threadA: Hello World! 38 | threadB: Hello World! 39 | threadA: Hello World! 40 | threadB: Hello World! 41 | threadA: Hello World! 42 | threadB: Hello World! 43 | 44 | 45 | 46 | Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. 47 | -------------------------------------------------------------------------------- /exercises/threads/thread-start-define/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | 5 | -------------------------------------------------------------------------------- /exercises/threads/thread-start-define/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A simple application that demonstrates 3 | basic sanity of the kernel. 4 | name: Synchronization Sample 5 | tests: 6 | sample.kernel.synchronization: 7 | build_on_all: true 8 | tags: synchronization 9 | harness: console 10 | harness_config: 11 | type: multi_line 12 | regex: 13 | - "thread_a: Hello World from (.*)!" 14 | - "thread_b: Hello World from (.*)!" 15 | -------------------------------------------------------------------------------- /exercises/threads/thread-start-define/src/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - Hello World demo */ 2 | 3 | /* 4 | * Copyright (c) 2012-2014 Wind River Systems, Inc. 5 | * 6 | * SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | /* scheduling priority used by each thread */ 16 | #define PRIORITY 7 17 | 18 | /* delay between greetings (in ms) */ 19 | #define SLEEPTIME 500 20 | 21 | 22 | K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); 23 | static struct k_thread threadA_data; 24 | k_tid_t my_tid; 25 | 26 | /* threadA is a static thread that is spawned automatically */ 27 | 28 | void threadA(void *dummy1, void *dummy2, void *dummy3) 29 | { 30 | ARG_UNUSED(dummy1); 31 | ARG_UNUSED(dummy2); 32 | ARG_UNUSED(dummy3); 33 | 34 | printk("thread_a: thread started \n"); 35 | 36 | while (1) 37 | { 38 | printk("thread_a: thread loop \n"); 39 | k_msleep(SLEEPTIME); 40 | } 41 | 42 | } 43 | 44 | K_THREAD_DEFINE(my_tid, STACKSIZE, 45 | threadA, NULL, NULL, NULL, 46 | PRIORITY, 0, 0); 47 | -------------------------------------------------------------------------------- /exercises/threads/thread-start/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(k_thread_start) 7 | 8 | target_sources(app PRIVATE src/main.c) 9 | -------------------------------------------------------------------------------- /exercises/threads/thread-start/README.rst: -------------------------------------------------------------------------------- 1 | .. _synchronization_sample: 2 | 3 | Synchronization Sample 4 | ###################### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple application that demonstrates basic sanity of the kernel. 10 | Two threads (A and B) take turns printing a greeting message to the console, 11 | and use sleep requests and semaphores to control the rate at which messages 12 | are generated. This demonstrates that kernel scheduling, communication, 13 | and timing are operating correctly. 14 | 15 | Building and Running 16 | ******************** 17 | 18 | This project outputs to the console. It can be built and executed 19 | on QEMU as follows: 20 | 21 | .. zephyr-app-commands:: 22 | :zephyr-app: samples/synchronization 23 | :host-os: unix 24 | :board: qemu_x86 25 | :goals: run 26 | :compact: 27 | 28 | Sample Output 29 | ============= 30 | 31 | .. code-block:: console 32 | 33 | threadA: Hello World! 34 | threadB: Hello World! 35 | threadA: Hello World! 36 | threadB: Hello World! 37 | threadA: Hello World! 38 | threadB: Hello World! 39 | threadA: Hello World! 40 | threadB: Hello World! 41 | threadA: Hello World! 42 | threadB: Hello World! 43 | 44 | 45 | 46 | Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. 47 | -------------------------------------------------------------------------------- /exercises/threads/thread-start/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | 5 | -------------------------------------------------------------------------------- /exercises/threads/thread-start/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A simple application that demonstrates 3 | basic sanity of the kernel. 4 | name: Synchronization Sample 5 | tests: 6 | sample.kernel.synchronization: 7 | build_on_all: true 8 | tags: synchronization 9 | harness: console 10 | harness_config: 11 | type: multi_line 12 | regex: 13 | - "thread_a: Hello World from (.*)!" 14 | - "thread_b: Hello World from (.*)!" 15 | -------------------------------------------------------------------------------- /exercises/threads/thread-start/src/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - Hello World demo */ 2 | 3 | /* 4 | * Copyright (c) 2012-2014 Wind River Systems, Inc. 5 | * 6 | * SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | /* scheduling priority used by each thread */ 16 | #define PRIORITY 7 17 | 18 | /* delay between greetings (in ms) */ 19 | #define SLEEPTIME 500 20 | 21 | 22 | K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); 23 | static struct k_thread threadA_data; 24 | 25 | /* threadA is a static thread that is spawned automatically */ 26 | 27 | void threadA(void *dummy1, void *dummy2, void *dummy3) 28 | { 29 | ARG_UNUSED(dummy1); 30 | ARG_UNUSED(dummy2); 31 | ARG_UNUSED(dummy3); 32 | 33 | printk("thread_a: thread started \n"); 34 | 35 | while (1) 36 | { 37 | printk("thread_a: thread loop \n"); 38 | k_msleep(SLEEPTIME); 39 | } 40 | 41 | } 42 | 43 | void main(void) 44 | { 45 | k_thread_create(&threadA_data, threadA_stack_area, 46 | K_THREAD_STACK_SIZEOF(threadA_stack_area), 47 | threadA, NULL, NULL, NULL, 48 | PRIORITY, 0, K_FOREVER); 49 | k_thread_name_set(&threadA_data, "thread_a"); 50 | 51 | k_thread_start(&threadA_data); 52 | } 53 | -------------------------------------------------------------------------------- /exercises/threads/thread-suspend/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(k_thread_start) 7 | 8 | target_sources(app PRIVATE src/main.c) 9 | -------------------------------------------------------------------------------- /exercises/threads/thread-suspend/README.rst: -------------------------------------------------------------------------------- 1 | .. _synchronization_sample: 2 | 3 | Synchronization Sample 4 | ###################### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple application that demonstrates basic sanity of the kernel. 10 | Two threads (A and B) take turns printing a greeting message to the console, 11 | and use sleep requests and semaphores to control the rate at which messages 12 | are generated. This demonstrates that kernel scheduling, communication, 13 | and timing are operating correctly. 14 | 15 | Building and Running 16 | ******************** 17 | 18 | This project outputs to the console. It can be built and executed 19 | on QEMU as follows: 20 | 21 | .. zephyr-app-commands:: 22 | :zephyr-app: samples/synchronization 23 | :host-os: unix 24 | :board: qemu_x86 25 | :goals: run 26 | :compact: 27 | 28 | Sample Output 29 | ============= 30 | 31 | .. code-block:: console 32 | 33 | threadA: Hello World! 34 | threadB: Hello World! 35 | threadA: Hello World! 36 | threadB: Hello World! 37 | threadA: Hello World! 38 | threadB: Hello World! 39 | threadA: Hello World! 40 | threadB: Hello World! 41 | threadA: Hello World! 42 | threadB: Hello World! 43 | 44 | 45 | 46 | Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. 47 | -------------------------------------------------------------------------------- /exercises/threads/thread-suspend/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_STDOUT_CONSOLE=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | CONFIG_SCHED_CPU_MASK=y 5 | -------------------------------------------------------------------------------- /exercises/threads/thread-suspend/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A simple application that demonstrates 3 | basic sanity of the kernel. 4 | name: Synchronization Sample 5 | tests: 6 | sample.kernel.synchronization: 7 | build_on_all: true 8 | tags: synchronization 9 | harness: console 10 | harness_config: 11 | type: multi_line 12 | regex: 13 | - "thread_a: Hello World from (.*)!" 14 | - "thread_b: Hello World from (.*)!" 15 | -------------------------------------------------------------------------------- /exercises/threads/thread-suspend/src/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - Hello World demo */ 2 | 3 | /* 4 | * Copyright (c) 2012-2014 Wind River Systems, Inc. 5 | * 6 | * SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | /* scheduling priority used by each thread */ 16 | #define PRIORITY 7 17 | 18 | /* delay between greetings (in ms) */ 19 | #define SLEEPTIME 500 20 | 21 | 22 | K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); 23 | static struct k_thread threadA_data; 24 | 25 | K_THREAD_STACK_DEFINE(threadB_stack_area, STACKSIZE); 26 | static struct k_thread threadB_data; 27 | 28 | void threadA(void *dummy1, void *dummy2, void *dummy3) 29 | { 30 | ARG_UNUSED(dummy1); 31 | ARG_UNUSED(dummy2); 32 | ARG_UNUSED(dummy3); 33 | 34 | int i = 3; //amount of times to loop before suspend 35 | 36 | printk("thread_a: thread started \n"); 37 | 38 | while (1) 39 | { 40 | printk("thread_a: thread loop \n"); 41 | i -= 1; 42 | if (i == 0) 43 | { 44 | printk("thread_a: thread suspended \n"); 45 | k_thread_suspend(&threadA_data); 46 | i = 3; 47 | } 48 | 49 | } 50 | 51 | } 52 | 53 | void threadB(void *dummy1, void *dummy2, void *dummy3) 54 | { 55 | ARG_UNUSED(dummy1); 56 | ARG_UNUSED(dummy2); 57 | ARG_UNUSED(dummy3); 58 | 59 | printk("thread_b: thread started \n"); 60 | 61 | while (1) 62 | { 63 | k_msleep(SLEEPTIME); 64 | printk("thread_b: resuming thread_a \n"); 65 | k_thread_resume(&threadA_data); 66 | } 67 | 68 | } 69 | 70 | void main(void) 71 | { 72 | k_thread_create(&threadA_data, threadA_stack_area, 73 | K_THREAD_STACK_SIZEOF(threadA_stack_area), 74 | threadA, NULL, NULL, NULL, 75 | PRIORITY, 0, K_FOREVER); 76 | k_thread_name_set(&threadA_data, "thread_a"); 77 | 78 | k_thread_create(&threadB_data, threadB_stack_area, 79 | K_THREAD_STACK_SIZEOF(threadB_stack_area), 80 | threadB, NULL, NULL, NULL, 81 | PRIORITY+1, 0, K_FOREVER); // priority of thread_b is lower than thread_b 82 | k_thread_name_set(&threadB_data, "thread_b"); 83 | 84 | k_thread_start(&threadA_data); 85 | k_thread_start(&threadB_data); 86 | } 87 | -------------------------------------------------------------------------------- /exercises/timers/basic-timer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.13.1) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(k_thread_start) 7 | 8 | target_sources(app PRIVATE src/main.c) 9 | -------------------------------------------------------------------------------- /exercises/timers/basic-timer/README.rst: -------------------------------------------------------------------------------- 1 | .. _synchronization_sample: 2 | 3 | Synchronization Sample 4 | ###################### 5 | 6 | Overview 7 | ******** 8 | 9 | A simple application that demonstrates basic sanity of the kernel. 10 | Two threads (A and B) take turns printing a greeting message to the console, 11 | and use sleep requests and semaphores to control the rate at which messages 12 | are generated. This demonstrates that kernel scheduling, communication, 13 | and timing are operating correctly. 14 | 15 | Building and Running 16 | ******************** 17 | 18 | This project outputs to the console. It can be built and executed 19 | on QEMU as follows: 20 | 21 | .. zephyr-app-commands:: 22 | :zephyr-app: samples/synchronization 23 | :host-os: unix 24 | :board: qemu_x86 25 | :goals: run 26 | :compact: 27 | 28 | Sample Output 29 | ============= 30 | 31 | .. code-block:: console 32 | 33 | threadA: Hello World! 34 | threadB: Hello World! 35 | threadA: Hello World! 36 | threadB: Hello World! 37 | threadA: Hello World! 38 | threadB: Hello World! 39 | threadA: Hello World! 40 | threadB: Hello World! 41 | threadA: Hello World! 42 | threadB: Hello World! 43 | 44 | 45 | 46 | Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. 47 | -------------------------------------------------------------------------------- /exercises/timers/basic-timer/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PRINTK=y 2 | # enable to use thread names 3 | CONFIG_THREAD_NAME=y 4 | 5 | -------------------------------------------------------------------------------- /exercises/timers/basic-timer/sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: A simple application that demonstrates 3 | basic sanity of the kernel. 4 | name: Synchronization Sample 5 | tests: 6 | sample.kernel.synchronization: 7 | build_on_all: true 8 | tags: synchronization 9 | harness: console 10 | harness_config: 11 | type: multi_line 12 | regex: 13 | - "thread_a: Hello World from (.*)!" 14 | - "thread_b: Hello World from (.*)!" 15 | -------------------------------------------------------------------------------- /exercises/timers/basic-timer/src/main.c: -------------------------------------------------------------------------------- 1 | /* main.c - Hello World demo */ 2 | 3 | /* 4 | * Copyright (c) 2012-2014 Wind River Systems, Inc. 5 | * 6 | * SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* size of stack area used by each thread */ 13 | #define STACKSIZE 1024 14 | 15 | /* scheduling priority used by each thread */ 16 | #define PRIORITY 7 17 | 18 | /* delay between greetings (in ms) */ 19 | #define SLEEPTIME 500 20 | 21 | 22 | K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE); 23 | static struct k_thread threadA_data; 24 | 25 | /* Defining a timer */ 26 | struct k_timer my_timer; 27 | extern void my_expiry_function(struct k_timer *timer_id); 28 | 29 | /* threadA is a static thread that is spawned automatically */ 30 | 31 | void threadA(void *dummy1, void *dummy2, void *dummy3) 32 | { 33 | ARG_UNUSED(dummy1); 34 | ARG_UNUSED(dummy2); 35 | ARG_UNUSED(dummy3); 36 | 37 | printk("thread_a: thread started \n"); 38 | 39 | while (1) 40 | { 41 | printk("thread_a: thread loop \n"); 42 | k_msleep(SLEEPTIME); 43 | } 44 | 45 | } 46 | 47 | void my_expiry_function(struct k_timer *timer_id) 48 | { 49 | printk("timer: expiry function \n"); 50 | } 51 | 52 | void main(void) 53 | { 54 | k_thread_create(&threadA_data, threadA_stack_area, 55 | K_THREAD_STACK_SIZEOF(threadA_stack_area), 56 | threadA, NULL, NULL, NULL, 57 | PRIORITY, 0, K_FOREVER); 58 | k_thread_name_set(&threadA_data, "thread_a"); 59 | 60 | k_timer_init(&my_timer, my_expiry_function, NULL); 61 | 62 | k_timer_start(&my_timer, K_MSEC(5000), K_MSEC(1000)); 63 | 64 | k_thread_start(&threadA_data); 65 | } 66 | -------------------------------------------------------------------------------- /images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/.DS_Store -------------------------------------------------------------------------------- /images/1-zephyr-setup/blinky_build_errors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/blinky_build_errors.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/coolterm-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/coolterm-1.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/coolterm-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/coolterm-2.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/coolterm-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/coolterm-3.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/coolterm-connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/coolterm-connect.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/coolterm-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/coolterm-settings.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/env-var-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/env-var-check.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/final-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/final-setup.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/hello_world_build_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/hello_world_build_success.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/hello_world_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/hello_world_output.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/pyocd-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/pyocd-error.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/success-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/success-build.png -------------------------------------------------------------------------------- /images/1-zephyr-setup/success-flash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/1-zephyr-setup/success-flash.png -------------------------------------------------------------------------------- /images/2-introduction/basic-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/2-introduction/basic-sample.png -------------------------------------------------------------------------------- /images/2-introduction/guiconfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/2-introduction/guiconfig.png -------------------------------------------------------------------------------- /images/2-introduction/k-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/2-introduction/k-config.png -------------------------------------------------------------------------------- /images/2-introduction/rtos_basic_execution.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/2-introduction/rtos_basic_execution.gif -------------------------------------------------------------------------------- /images/2-introduction/sample-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/2-introduction/sample-folder.png -------------------------------------------------------------------------------- /images/build-system/boilerplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/build-system/boilerplate.png -------------------------------------------------------------------------------- /images/debugging/debug-breakpoint-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/debugging/debug-breakpoint-1.png -------------------------------------------------------------------------------- /images/debugging/debug-starting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/debugging/debug-starting.png -------------------------------------------------------------------------------- /images/debugging/openocd-threads-support.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/debugging/openocd-threads-support.png -------------------------------------------------------------------------------- /images/debugging/runtime-statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/debugging/runtime-statistics.png -------------------------------------------------------------------------------- /images/donate/bitcoin-donations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/donate/bitcoin-donations.png -------------------------------------------------------------------------------- /images/donate/dogecoin-donations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/donate/dogecoin-donations.png -------------------------------------------------------------------------------- /images/donate/ethereum-donations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/donate/ethereum-donations.png -------------------------------------------------------------------------------- /images/gpio/devicetree-binding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/gpio/devicetree-binding.png -------------------------------------------------------------------------------- /images/interrupts/button-interrupt-alias.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/interrupts/button-interrupt-alias.png -------------------------------------------------------------------------------- /images/interrupts/button-interrupt-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/interrupts/button-interrupt-output.png -------------------------------------------------------------------------------- /images/introduction/azure-rtos-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/introduction/azure-rtos-github.png -------------------------------------------------------------------------------- /images/introduction/freertos-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/introduction/freertos-github.png -------------------------------------------------------------------------------- /images/introduction/zephyr-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/introduction/zephyr-github.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/logo.png -------------------------------------------------------------------------------- /images/logo_no_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/logo_no_bg.png -------------------------------------------------------------------------------- /images/old/guiconfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/old/guiconfig.png -------------------------------------------------------------------------------- /images/scheduling/cooperative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/scheduling/cooperative.png -------------------------------------------------------------------------------- /images/scheduling/preemptive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/scheduling/preemptive.png -------------------------------------------------------------------------------- /images/scheduling/serial-coop-time-slicing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/scheduling/serial-coop-time-slicing.png -------------------------------------------------------------------------------- /images/scheduling/serial-preemptive-time-slicing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/scheduling/serial-preemptive-time-slicing.png -------------------------------------------------------------------------------- /images/scheduling/serial-time-slicing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/scheduling/serial-time-slicing.png -------------------------------------------------------------------------------- /images/scheduling/timeslicing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/scheduling/timeslicing.png -------------------------------------------------------------------------------- /images/threads/thread-abort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-abort.png -------------------------------------------------------------------------------- /images/threads/thread-control-block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-control-block.png -------------------------------------------------------------------------------- /images/threads/thread-entry-point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-entry-point.png -------------------------------------------------------------------------------- /images/threads/thread-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-join.png -------------------------------------------------------------------------------- /images/threads/thread-sleep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-sleep.png -------------------------------------------------------------------------------- /images/threads/thread-stack-size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-stack-size.png -------------------------------------------------------------------------------- /images/threads/thread-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-start.png -------------------------------------------------------------------------------- /images/threads/thread-states.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-states.png -------------------------------------------------------------------------------- /images/threads/thread-suspend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/images/threads/thread-suspend.png -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | title: Home 4 | nav_order: 0 5 | --- 6 | 7 | # Zephyr: Tutorial for Beginners 8 | 9 | A step-by-step guide that teaches you how to use Zephyr RTOS. It assumes: 10 | - knowledge of C 11 | - no previous experience with RTOS 12 | - basic embedded electronics knowledge (GPIO, Timers, Interrupt,...) 13 | 14 | Each lesson builds on the previous one. Most lessons end with exercises (with solutions!) that show how the covered concepts can be used in a practical application. 15 | 16 | {: .warning} 17 | This tutorial is under active development, if you want to participate - please read the [Contribution guide](docs/Contributions.md). -------------------------------------------------------------------------------- /svg-images/threads/thread-abort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/svg-images/threads/thread-abort.png -------------------------------------------------------------------------------- /svg-images/threads/thread-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/svg-images/threads/thread-join.png -------------------------------------------------------------------------------- /svg-images/threads/thread-sleep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/svg-images/threads/thread-sleep.png -------------------------------------------------------------------------------- /svg-images/threads/thread-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/svg-images/threads/thread-start.png -------------------------------------------------------------------------------- /svg-images/threads/thread-suspend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maksimdrachov/zephyr-rtos-tutorial/bbfac4a660485aa86a410c9ca8158350a98640e5/svg-images/threads/thread-suspend.png --------------------------------------------------------------------------------