I welcome you to this part of my review about Arduino Nano 33 BLE Sense. My review is split into multiple blog posts. You can find all my thoughts about this Arduino and related parts in chapters with name beginning with "Review" like this one. There are also articles describing test projects which I have done for gathering experiences with board and some tutorials. Main page of review contains summary and final score. Following Table of Contents contains links to other parts of my roadtest review.
Table of Contents
- Review of Development Board
- Review of Onboard Sensors
- Review of Microcontroller and BLE Module
- Review of Software (this article)
- Review of Documentation
- Tutorial 01: Accessing Sensor Values
- Tutorial 02: nRF52840 Application without Arduino IDE
Review of Software
In this part of review I present my thoughts about software related to this Arduino and later in this chapter I will also describe software provided by Nordic for nRF52840 MCU which you may be interested in in case when you want to develop without Arduino IDE and libraries for some reason. In this article I will point mainly IDEs and available libraries in both “ecosystems”.
You probably know Arduino IDE. I am not sure if IDE is correct term, because it offers very few features what users expects from IDE. I have tried beta version 2.0 of Arduino IDE and it is much better than old IDE but there are still some issues. The biggest issue is performance. Everything in both IDEs (old and new one) are very slow. Especially compilation is very slow. Reason for that is probably that Wiring language is preprocessed to C++ which efficiently limits most kinds of incremental builds. There are also some additional long-running tasks discovering libraries. Note that performance on Linux in both IDEs is much better than on Windows. I have no idea about reason for that. Otherwise both IDEs supports building and uploading code to device using bootloader and it works slowly but it works. Lastly serial viewer in newer version of IDE is buffered in a very interesting way and get slower and slower over time. In older IDE it works correctly.
Available Arduino Libraries
This Arduino supports most features known from other Arduinos. You may normally use Serial.print, digitalWrite, and so on. Standard libraries are ported to nRF52840 platform and sometimes brings you new functionality like Serial.printf with formatting support. There are also predefined standard constants. Only pay attention to constants LED_RED, LED_GREEN and LED_BLUE. They probably come from some different Arduino and correct constants on this Arduino are LEDR, LEDG, LEDB.
Arduino provides libraries to read values from sensors and control them. Quality and number of supported features vary. I will describe each library for each sensor.
Only library which I found that does not works on this Arduino is OneWire library. OneWire bus is timing sensitive and because Arduino Nano 33 BLE Sense has not an AVR MCU, but it has nRF52840 timing constraints embedded in this library does not work. Luckily, I found for my sensor another library written by someone else.
Library provides basic access to sensor. It enables you to read humidity and temperature from sensor. Library supports compensation of values using calibration data which read from sensor. Library utilize only single shoot mode and does not support continuous mode at all. Library triggers single shoot conversion and then poll the status which is totally nonefficient but because it is simple sensor, I do not worry about it so much. Because Arduino does not connect interrupt signal (signal is named DRDY – data ready) it does not support any configuration of interrupt in this library. Code quality is good. There are comments. Identifiers are properly named. Code formatting is consistent over whole library. Library contains good example how to use it.
To summarize: library is user friendly but supports very few features of chip.
This library is very similar to . Similarly to , library it utilizes only few features of devices. It allows only start single shoot conversion and then read results. Library do not enable you to use advanced features of sensor. Following features you cannot utilize using this library: FIFO, streaming mode, interrupts (interrupt signal is not connected, so you cannot use it even with different library), some low pass filter, switching between low-noise and low-current mode. Sensor also can provide temperature while it is not originally designed to measure temperature. Sensor probably measure temperature for some internal compensations, but you can also read measured temperature from registers. Similarly, to code quality is good. Library contains good example how to use it.
This library supports more features than previous two mentioned. Library contains some static magic constants but all of them are described in datasheet. Library configures sensor by good known values (magic constants) and do not enable you to provide your own configuration (unless you do it manually by driving I2C bus). This library support continuous mode of operation if you want to use it but there are no interrupts. Library poll status of availability. Library do not support following features of sensor: modes of operation (which can disable some parts of sensor), powering modes, sampling frequency in continuous mode, reading multiple samples from FIFO at once, FIFO modes, values scales, endianness selection, sensor reset and self-tests. Library follows code standard similarly to previous two mentioned libraries. There are good examples how to use this library.
To summarize: Library still support only few features of sensor, but it is sufficient for most users.
This library is more advanced than previously mentioned libraries. Note that APDS9960 is single sensor with connected interrupt line to MCU and library can utilize this. Code follows different pattern, but code quality is still good. Sensor configuration is done using magic values, but lot of features are reconfigurable using functions. You can disable individual parts of sensor, configure sensitivity of sensor and IR LED boost (max current). There are very few features unsupported by library like configuration of gain, some advanced FIFO configuration, and some timing stuff. But in overall this library supports most of features of the sensor and features are sufficient for almost any app based on this library. Library also supports configuration of interrupt on sensor side but does not bind any interrupt handler. You can do that manually. Library uses interrupt pin as basic GPIO and use them to check availability of data when polling for it. This is quite funny, but it is not an issue. You can implement your own interrupt handler and read values without need to poll. Reason for this approach is probably platform compatibility because interrupts on AVR works differently than they work on ARM.
Last note on this library is about efficiency of code. Usually in library is one function to read device register, but this library generates function for every single register using macro. This looks good to have function for each register, but this concept totally wastes flash memory for storing very similar functions. Instead of one function with parameter there are 49 functions for reading registers, and 49 functions for writing it. And guess what? Generated functions internally use generic functions with register index as parameter. This library efficiently generates 98 meaningless functions in flash memory (even they are not used) just because author wanted to write getENABLE() instead of read(ENABLE, &val).
Otherwise code quality is good. Examples are also good.
To summarize: Library is good and supports many sensor features.
Nordic tools and SDKs
As part of review I also tried developing device firmware for MCU using Nordic SDK and IDE recommended by IDE. Developing using this approach you can create MCU firmware directly and bypass all Arduino stuff. In this way you can develop apps similarly to like you can develop software for example for STM32 or other ARM-based platforms.
Nordic support for Segger Embeded studio, which is preferred way of developing apps. They also support IAR Embeded Workbench, Keil MDK and opensource toolset based on GCC. I have tried recommended Segger Embeded Studio (SES) mainly. I also tried GCC and it also works but SES is more interesting for me this time.
Segger embedded studio
SES is proprietary IDE which is not based on Eclipse like many others and it is not developed by MCU manufacturer Nordic, but it is from Segger as name says. Segger is German company you may know from popular J-Link debugging probe. In fact, they also do not developed SES, but they based SES on another (but very similar at the first look) CrossWorks for ARM from Rowley Associates and modified it a little. SES supports many MCUs from many vendors. It is generic IDE for developing apps for any MCU you want. This is different approach in comparison with IDEs provided by vendors which are usually locked to MCUs from that vendor. Proprietary IDE like SES are usually very expensive but in SES case this is true only partially. You can develop applications (including commercial) for Nordic chips completely for free (because Nordic negotiated this benefit) and you can use SES for development only non-commercial apps for free for other platforms. But if you want to develop commercial app for non-Nordic platform like for example STM32, you must buy expensive license.
SES targets embedded applications and has many features for simplifying many common tasks when debugging. Very beautiful is project explorer display which after build contains information about how much space in flash occupy compiled code for every single source file. If you are troubleshooting some memory capacity issues SES may help you very much. Very few IDEs support this at this level of details.
Another feature that I like is registry visualizer. When you are troubleshooting state of peripheral, or you want to check that some library configured peripheral correctly you can use registry viewer. Eclipse based IDEs also support this when vendor provide registry definition file (for example Cypress don’t do that, so when developing using their Eclipse based ModusToolbox, you do not see anything in this window). But SES has this registry window much better. The first good thing is that you can configure which peripherals you want to see. It is annoying to scroll over long list of peripherals in STM32CubeIDE every time you search for peripheral. In SES you can configure that you want to see registers of CPU, UART and DMA and that’s all. You will see only registers of this peripherals.
Second good feature of this tool is that window interprets registers value and show user readable meaning of bits, fields of register value. In case of multiple possible combinations, it also supports combo box with labelled values. I like this window very much. It saved me lot of time.
Code editor is very trivial and do not support many features known from other advanced IDEs like Eclipse or Visual Studio. This is common over all proprietary IDEs. For example, Atmel Studio which is based on Visual Studio IDE is much better in this. If you are experienced from Visual Studio or other IDE designed to write lot of software you can forget about all advanced features like for example advanced editing line operations, code snippets and so on. For example, I was very annoyed that code completion does not trigger on Ctrl + Space which is very common keyboard shortcut for triggering this.
While Segger offers tools for investigating hard faults, it looks like they did not integrated it to SES.
To summarize: SES is good IDE and you can use it with Nordic chips completely for free. It has many useful features but only basic code editor.
Nordic nRF5 SDK
nRF5 SDK is library which contains drivers for MCU peripheral and bindings to soft devices which I will describe later. It is quite high-level library and interfaces for peripherals are abstracted from the peripheral designs. I consider this library as comparable to HALs from other vendors. When you create empty project in SES this library is not integrated to project. It is hard to find where to download library at the first look and how to use them. You must download it manually, extract it and then integrated to your project yourself. There is one template in examples folder which could be used as an empty project, but it still requires some significant amount of work to get started with it. There are examples which you can use as a base for your project but there is anywhere integrated full library into project (template project has most of things included but if you want to develop BLE application, you will still need to many things reconfigure). Benefit of the library is that you can integrate it only partially (for example if you do not use SPI, you do not need to integrate SPI driver and you reduce compiled binary size by this approach). Disadvantage is that you almost always need to integrate it manually. It is very hard to understand this when beginning with library.
Many parts of library are implemented using macros which are usually expressed by other macro. It is hard to troubleshoot anything hidden in macros because when navigating over macros in IDE, you usually stuck at the first very complex macro and evaluating get very complicated. For example, logging logic is implemented using macros which finally ends on some function call, but it is hard to determine which one. There are many macros for concatenating macro parameter to name and this concatenated name is usually passed to another very complicated macro.
Peripheral drivers are usually easy to use and sometimes there are example how to use them. Drivers are documented very briefly, and you must guess some restrictions like order of calling initialization functions, requirements for stopping peripheral when reconfiguring, and so on.
There are two variants of drivers. Older begins with nrf_ and newer which are prefixed by nrfx_. I did not find any new API for some features including GPIO, but most peripherals has new nrfx driver. Lastly many examples are based on older drivers while there is available newer driver.
As part of this library there is cryptography library for controlling ARM CryptoCell 310 peripheral. It is developed by Nordic and not an ARM. Library follows conventions used in other parts of nRF5 SDK.
To summarize: Library is good, but it is very hard to use it, understand it and it is complicated for beginners.
Soft devices are proprietary closes source binary blobs which implements stacks for some wireless protocols like Bluetooth Low Energy, Zigbee or Thread. There are headers provided with them for accessing its features. There are multiple soft devices which differs in supported protocols. Soft devices with support for ANT protocol are paid. Otherwise they are free. Soft devices fit to design of nRF5 SDK. They are integrated to project in the same way as other components of SDK.
In case of nRF52840, soft devices runs on the same core as your code runs. Because wireless protocols are very timing sensitive, soft devices registers interrupts with the highest interrupt priority and you efficiently cannot change them. If you need to develop Bluetooth (or other wireless protocol) application and you need some your timing critical interrupt at the same time, nRF52840 with soft devices is not a good platform for doing this. Better approach is using dual core MCU like nRF5340. In this case BLE (or other wireless protocol) stack runs on separate core and second core is dedicated to your (real-time) application. On second core you can use interrupts on any priority level you want, and you do not need to guarantee highest interrupt for soft device. To be clear nRF5340 is newer MCU which supports only newer approach of development using nRF Connect SDK (described later) and do not support nRF5 SDK with soft devices. Another approach is using outsourcing BLE to different chip and connect to them (usually) using UART. This approach is implemented for example on previously roadtested (my review) PSoC 6 Pioneer Kit. In this case MCU (PSoC62 in this case) is dedicated completely to your program and BLE features are provided by external chip (CYW43012 in this case) over UART. This approach has some advantage like unpredictable BLE operation do not affecting your main program but has some disadvantages like need for two chips instead of one and overhead with UART transfers.
nRF Connect SDK
nRF Connect SDK is newer approach of development for nRF platforms. SDK is based on Zephyr RTOS which is complex RTOS sharing patterns with Linux kernel. For example, there are same device tree definition for HW peripherals, similar menuconfigs and so on. I thought that nRF5 SDK is hard to setup, but nRF connect SDK is even more hard to setup. I failed. There is some integration in SES and beautiful dialog for device trees and menuconfig configuration. There is also dialog for opening example project. In dialog you can choose which board you use. There are also predefined boards from Nordic and there are Arduino Nano 33 BLE, but definition of onboard hardware is very brief. Finally, compilation of project with Arduino Nano 3 BLE selected as board resulted into invalid incomplete binary. For some reason, liner probably linked only zephyr OS to non-zero address and other parts including vector table were not included. Compilation with selected Nordic evaluation board instead of Arduino resulted into valid binary, but it is too much work to reconfigure complicated configs to make this binary working with Arduino hardware and pinout. I spend many time with investigating this but Zephyr is very complex and I did not find any way how to compile using nRf connect SDK and Zephyr RTOS for Arduino Nano 33 BLE. If you want to develop using this way, I recommend start with some Nordic evaluating kit rather than Arduino Nano 33 BLE Sense because Nordic kits are much more supported from Nordic.
nRF Connect SDK use Cmake as building system which is much better approach than configuring manually like in case of older nRF5 SDK.
Arduino environment is very easy to understand and work with it. Libraries are mostly well written but expose only little functionality of sensors. Nordic development environment and libraries are very complicated, it is hard to work with them but can expose almost all features of nRF52840 MCU when you spent appreciate amount of time with it.