Skip to content

cl2hang/fw_challenge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

FW-Challenge

My take-home interview project. It's a small, production-flavored Zephyr application that samples a “battery voltage” channel on a Nordic DK, exposes readings over BLE, persists a counter across reboots, and is configurable at runtime and at build time.

Deliverables

Here are a list of deliverables as required:

  • source code: see the app folder.
  • DTS overlays: see the app\boards folder.
  • Kconfig: see Kconfig, prj.conf and overlay_ble.conf in the app folder.
  • __Kconfig (app menu): see docs folder.
  • ztests: see folders tests\ztest_app_config and tests\ztest_ble_codec.
  • screen captures: a video of system running boot logs showning notification toggling with button click; a video of running with native-sim in the commandline environment; Kconfig app menu screenshot. See docs folder for detail.

Correction: due to the file size, the video of firmware running on native_sim is available on here on Google Drive.

Build & Run Steps

This project has been tested during development on both boards Ezurio BL652 DVK, Seeed XIAO nRF52840, and the POSIX simulator Native Sim. The boards supported (but not yet tested) are Nordic nRF52840 DK NRF52840 and Nordic NRF5340 DK NRF5340 Application.

The IDE for development is VS Code, and the toolchain and SDK are both NCS3.1.0. Please follow the instuctions here to set up the IDE, as well as the corrrect toolchain and SDK.

Once the IDE environment is ready, we can open the project folder as an existed NCS application, the add a build configuration according to the supported board chosen. To support BLE, an overlay config named overlay_ble.conf should be included as the Extra Kconfig fragment.

To build and run the application, the app sub-folder should be used. To run the ztest suites, choose either tests\ztest_app_config or tests\ztest_ble_codec as the top folder.

Notably, we can only build and run the code on native_sim on an Linux system. Also, not all features are supported when the firmware is running on Native Sim. The features not supported (or configured) include BLE, button, PWM LED, WDT, etc.

Key Implementation Features

1. Device Tree Choices

An device tree overlay is presented in the app\boards sub-folder for all the boards supported. For each overlay, the peripheral components are chosen at a preference of availability. The includes ADC (&adc for most boards), button (&button_0 mostly), PWM LED (mostly &pwm_led0), etc.

For ADC (or ADC Emul), an only channel named channel@0 is created. For some boards, the missing components are added, such as pwm_led0 for bl652_dvk, a button (using GPIO0.28) for xiao_ble, etc.

What's more, a custom node named app is introduced in each overlay, with 3 properties as sample-interval-ms, voltage-threshold-mv, and enable-ble.

2. Kconfig Symbols and Precedence Policy

A few custom Kconfig symbols are introduced in app\Kconfig. Some of them contradict with the properties defined in the device tree overlay.

Implemented in the header file app\include\app_cinfig.c, here is the precedence policy we are using once such conflicts exist. The device tree definition will have a higher precedence than Kconfig given that the latter is more application oriented but the former is more board specified. That is to say, the Kconfig definition is for a more general purpose, but the device tree definition is more specific according to the chosen hardware platform.

3. BLE GATT Service & Characteristics Design

The custom service is named as FCS (abbr of Fw-Challenge Service).

As implemented in app\src\ble.c, and UUIDs defined in app\include\app_uuids.h, the GATT service and characteristics are designed as follows.

  • GATT Service: FCS (uuid: 56435452-0000-0001-435A-46774368616E)
  • Characterisitc #1: voltage_mv (uuid: 56435452-0001-0001-435A-46774368616E), readable, notifiable.
  • Atrribute Profile (CCC): readable, writable.
  • Characterisitc #2: voltage_mv (uuid: 56435452-0001-0001-435A-46774368616E), readable, notifiable.

Here, the UUIDs are kind of designed randomly, but with the 2nd section for the index of characteristcs, and the 3rd section for service index.

The CCC profile above is writable, it is used (e.g., through a client app nRFConnect) for enabling / disabling the notification of voltage_mv on the client's side. On the device side, Clicking the device button will have a similar effect.

4. Persistent Settings in NVS

A variable named sample_count is kept in NVS. It is loaded into memory once the system is restarted, and will be updated are persisted for each round of data sampling.

See app\src\nvs_persist.c for the implementation detail.

5. Power Saving Consideration & Measures

Try to avoid using a busy-loop, so that the system can have more chance entering the different level of lower power consumption modes automatically.

For this reason, we choose to use PWM LED instead of a thread controlling the different patterns of LED blink, and schedule a delayable work for the periodic data sampling.

Also, PM device suspend/resume of ADC are implemented so that the ADC is in a suspended state whenever it's not used.

6. Watchdog

Watchdog is implemented (see app\src\watchdog.c) to guard the system running. So far, the only issue that needs watchdog's help is the continuous BLE advertising. It is restarted each time after a BLE connection session.

In case BLE advertising fails to start, the system will not be accessible through BLE anymore. This is when the watchdog is needed to trigger a system reset.

Discussion

Some other topics during the firmware development also deserves discussion.

1. PWM LED vs LED

I did consider which one to use for some time, but eventually chose PWM LED. In this way, I don't need an extra thread to control the LED state. But, a shortcoming of PWM LED is that, it seems the blinking frequency has to be quite high for both boards I have, as low as about 4Hz. So I have to use a PWM calibration process to determine the best blinking frequency for both slow pattern and fast pattern. Unfortunately, the LED still blinks too fast.

I don't have time to reimplement this function with normal LED (using GPIO pin to control the LED state). But, the idea will be as follows. First, I will need a dedicated thread for the LED control. Some events should be introduced to notify the thread to launch different LED patterns (slow, fast, double blink). The events should be triggered in the delayable works of data sampling.

2. Button Debounce

It looks unnessary to do any button debounce for the development boards I have. But, I still added a similar approach in app\user_btn.c to prevent a continuous clicking of the button. Any such continuous pressing will be treated as only a single button click.

3. BLE Codec

Both characteristics are not writable, so that it seems unnecessary to decode a byte array to uint32_t, as well as the interval range check (100~60000ms) for BLE. But, the Little Endian codec and sample interval check functions are still implemented in app\app_util.c. Their test cases are presented in tests\ztest_ble_codec\src\main.

4. DTS Bindings

DTS bindings are needed for detecting DT_PROPs for DT_NODE. Such a binding can be found at dts\bindings\app,config.yaml. Such a binding is duplicated in tests\ztest_app_config since it seems the DTS_ROOT option in the CMakeLists.txt of the test folder does not work.

5. overlay-ble.conf

Instead of the suggested overlay_no_ble.conf, I chose to use overlay_ble.conf as the overlay config. Once this config is not used, a firmware without BLE support should be built. And the BLE library, as well as the code in app\src\ble.c, will be ignored.

6. NCS 3.1.0 vs NCS 3.1.1

When starting the development, NCS 3.1.1 (the latest toolchain / SDK) was my choice. Until I met some strange issues with BLE advertising, I then started to downgrade it to NCS 3.1.0.

Maybe this issue is not for all boards, but BLE advertising cannot be started successfully (error code: -22) for the bl652_dvk board I have. This cost me quite some time to figure out the reason.

7. Native-sim

This is the 1st time that I am using native-sim. My previous work experience are all on the target boards directly. So the first challenge for me is that I don't have a Linux system and cannot run native-sim directly in VS Code. I have to install a WSL subsystem on my PC, so that I can at least run native-sim in a commandline environment.

8. My Time Management

I started my work on Friday, implemented most of the functions that day. On Saturday, I got all the code refactored and improved, and all functions were implemented. On Sunday, I devoted all my efforts on native-sim and ztests. In Monday morning, my work is on documentation and the various delivarables.

9. Regard the Plagiarism & AI policy

I referred a lot open documents. Most are the Zephyr documentation, samples, source code, and a few Youtube videos. I did not use the AI assistance intentionally. Of course, there's always an "AI Overview" after a Google search. I did have a look at the content for a few times, especially when I want to quickly understand native-sim but could not get enough open resouces promptly. If it counts, this is the only chance that I have an access to AI.

Acknowledgement

Great gratitude for the interview opportunity and your time and effort in reviewing my work! Please feel free to contact me if you have any question about the project or encounter any issue when building and running the firmware.

About

A take-home interview project on Zephyr.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published