Skip to main content

NRD Module Enables ESDK to Detect Nuclear Radiation

ESDK Nuclear Radiation Detector (NRD) board

ESDK Nuclear Radiation Detector (NRD) board allows for detection of beta, gamma and X-ray radiation.

In this article, we’ll take a look at the new ESDK Nuclear Radiation Detector board features and the design process.

The NRD Module

The ESDK-NRD board features the standard set of connectors for integration with the existing ESDK ecosystem, plus a nuclear radiation detector and a Raspberry Pi RP2040 microcontroller to keep track of total radiation events, counts-per-second and counts-per-minute.

Teviso BG51 beta, gamma and X-ray sensor

We opted to use the Teviso BG51 beta, gamma and X-ray sensor that utilises a PIN diode array to detect radiation. The sensor provides the necessary analogue front-end required to interface with the PIN diodes, and provides a TTL pulse output when a detection event occurs. Supply voltage for the sensor is between 2.5V to 12V enabling us to directly connect the sensor to the 3.3V power supply rail.

RC filter circuit

Teviso recommends an RC filter circuit consisting of two series filters in the sensor supply rail, to help eliminate power supply noise. We implemented this as a belt-and-braces approach to ensure that noise is reduced as much as possible — and given the cost of the required components, it was a no-brainer.

Raspberry Pi RP2040

As the board needed a microcontroller to interface with the I2C bus we started searching for a suitable part, and given the ongoing component supply chain issues, we found our choice was severely limited.

The Raspberry Pi RP2040 seemed to be well-stocked and has an impressive feature set given the low cost; including a dual-core ARM Cortex M0+ processor clocking at 133MHz, 264kB SRAM, up to 16MB QSPI off-chip Flash, eight PIO state machines — somewhat akin to the BeagleBone Black SoC “Programmable Realtime Units” — and thirty GPIO pins that can be mapped to a number of different peripherals.

MicroPython support has also been provided for the RP2040, further influencing our decision to use the part, since writing our firmware in Python makes the code more accessible to a wider audience, who may understand Python but not necessarily the nitty-gritty details of C. Another advantage of using MicroPython is that the development environment is easier to set up and can be as simple as installing the Thonny IDE (which has out-of-the-box support for the RP2040).

Hardware design for the RP2040 - circuit diagram

Hardware design for the RP2040 requires only a number of passives, an external Flash chip, crystal resonator and a button/jumper to enter bootloader mode. We opted to include a USB-C connector for ease of programming rather than using SWD from an external programmer. As we wanted to use at least 0603 sized components the power rail decoupling capacitors have to be spaced away from the edges of the IC slightly.

The Flash chip that is present on the board is one recommended in the RP2040 hardware design manual: the Winbond W25Q128JVS, which provides 16MB of storage. Given the low cost for the 16MB flash chip, having excess free space is not an issue and provides room for future firmware expansion.

A small tactile switch is included to be able to put the board into “BOOTSEL” mode, which presents the RP2040 as a USB mass storage device, allowing code to be directly copied to the device.

a small 3.3V regulator has been included

Additionally, to provide the option of running the board standalone (as in the case of programming) a small 3.3V regulator has been included, with a pin header to select between the 3.3V supply from the ESDK ecosystem connector or the on-board regulator. Moving the jumper to the position closest to the USB port connects the regulator.

A GPIO line from the RP2040 is connected through a 1K resistor to the GPIO1 signal present on the ESDK connector, which allows for signalling between the NRD board and Main board that does not rely on the I2C bus.

MOSFET and red LED connected to a GPIO pin on the RP2040

The final inclusion is a MOSFET and red LED connected to a GPIO pin on the RP2040 that serves as an event indicator. On every detection event, the LED is toggled on for five milliseconds, but this feature can be turned off by writing to a register over the I2C bus.

The Firmware

Firmware for the NRD board is written in MicroPython, which is a slimmed-down variant of Python designed to fit into the memory and storage constraints of a microcontroller, whilst still keeping major features of a conventional Python install.

We settled on a main list of features that the firmware should have and this includes count-per-second reporting, count-per-minute reporting, accumulated counts, event LED control and GPIO output control.

We started firmware development by finding an I2C responder library to use, as MicroPython does not have a responder yet — this enables us to treat the RP2040 as an I2C device. A library from Github user “epmoyer” was used as this offered us all the functionality we needed. This library was tested on a Raspberry Pi Pico before we started hardware design,  to ensure that it would work as required.

With the library verified and our board designed, we moved on to ensure that we could capture events from the sensor. Our initial approach was to use an interrupt alongside two timers to calculate CPS and CPM values, but this quickly stopped working once a second thread (running on the second processor core) was introduced.

To work around this issue the timers and interrupts were removed, and two threads that run as quickly as possible were introduced. One thread solely handles the I2C responder as this is polled and needs to be able to watch for bus traffic all the time. The second thread handles capturing the sensor pin change, toggling the event LED and GPIO, and keeping track of counts.

# Turn on LED if event detected
if(event and led_enabled and led.value() == False):
    ledOnTime = time.ticks_ms()
    event = False

# Turn off LED after 5ms timeout (to make a blink)
if(led.value() and time.ticks_diff(time.ticks_ms(), ledOnTime) > 5):

Instead of using delays in the sensor loop, which would block execution of the thread, a series of if statements are used that compare timestamps — a system timer is provided that can be read to get either microseconds or milliseconds since boot. For example, the LED code stores a timestamp in a variable when the LED is turned on, and then another if statement checks the current time is 5ms later then turns the LED off.

By using timestamps and a series of if statements this also allows the thread to execute as quickly as possible, reducing the chance of any missed count events when the sensor output toggles. The pulse width on the sensor output is quite small, ranging from 50μS to 200μS, so having the loop run as quickly as possible is paramount.

The I2C thread again runs in a loop without any delays, so as to ensure that no request from the bus is missed. A series of if statements again adjust variables appropriately, and send the correct data back to the bus.

During testing, we observed an occasional I2C bus crash, where the thread that handles the I2C responder would crash and leave the SCL line pulled low. This then causes issues as other devices on the same bus cannot be communicated with. 

To work around this, we implemented a software watchdog that by default is disabled, but can be enabled by writing to a register over I2C. Once enabled, I2C traffic has to be sent more frequently than once every ten seconds, otherwise, the microcontroller is reset which restarts program execution.

A number of registers are available over the I2C bus:

  • 0x01 reads one byte which is the current counts-per-second rate
  • 0x02 reads two bytes which is the current counts-per-minute rate
  • 0x03 reads four bytes which is the accumulated counts
  • 0x04 reads one byte which is the event LED enabled state, and writing one byte of either 0x01 or 0x00 to enable & disable the LED respectively
  • 0x05 writes one byte which resets all the counters, including CPS, CPM and the accumulated counts
  • 0x06 reads one byte of the event GPIO enabled status, and writing one byte of either 0x01 or 0x00 enables and disables the event GPIO respectively
  • 0x07 reads one byte of the I2C watchdog timer status, and writing one byte of either 0x01 or 0x00 enables and disables the watchdog respectively

Firmware Flashing

Before flashing the firmware to the board, MicroPython must be installed and this is documented on the Raspberry Pi website. The procedure is simple and involves putting the board into bootloader mode, then dropping the supplied UF2 firmware file onto the USB flash drive that appears. The board can then be unplugged and plugged back into re-enumerate as a USB serial port that gives access to the MicroPython REPL.

The board can then be connected using your programming tool of choice (in our case, the Thonny IDE), following which both “” and “” (from the I2CResponder GitHub repository) can be uploaded to the board. Another power cycle should start running the code!

Software Support

DesignSpark.ESDK library software support will be included in an upcoming release, along with a number of other updates to the “aq-device” software. The NRD sensor software module will behave the same as any other ESDK sensor software module, easing integration into existing applications.

Demonstration Video

To Finish

The ESDK-NRD board expands the ESDK ecosystem to provide support for detecting beta, gamma and X-ray radiation and provides functionality to calculate counts-per-second, counts-per-minute and total counts detected.

Design files and firmware for the NRD board are available on GitHub.

Engineer of mechanical and electronic things by day, and a designer of rather amusing, rather terrible electric "vehicles" by night.
DesignSpark Electrical Logolinkedin