This describes the firmware provided for the emonTH3 temperature, humidity, and pulse counting system.
This firmware is intended to be used with the OpenEnergyMonitor platform. Hardware systems are available directly from them.
Issues can be reported:
- As a GitHub issue
- On the OpenEnergyMonitor forums
Please include as much information as possible, including at least:
- The emonTH3 hardware that you using and the emonTH3 firmware version (run the 'v' command on the serial link)
- All settings (run the
lcommand on the serial link) - A full description, including a reproduction if possible, of the issue
The firmware version numbering follows semantic versioning. That is, for version X.Y.Z:
X: major version with no guaranteed backward compatibility with previous major versionsY: minor version where any added functionality has backward compatibilityZ: improvements and bug fixes
Any firmware with X == 0 is considered unstable and subject to change without notice.
Note
Build information, including compiler version and commit, is generated during the build process and included in the binary.
A UART is provided for configuration and, optionally, data transmission. It has the following configuration:
- 115200 baud
- 8N1
When the emonTH3 is powered on or reset, the STATUS indicator will slowly pulse for 5 seconds. If any character is received over the UART connection in this time, the emonTH3 will enter configuration mode. It is not possible to configure the emonTH3 outside this period.
Note
All options can be listed by entering ?.
The following options are available through the serial configuration interface.
| Command | Description | Arguments |
|---|---|---|
? |
Show help text | None |
a<n> <m> |
Configure the SCD4x CO2 sensor | n: sample interval (s)m: altitude above sea level (m) |
c<n> |
Enable UART output | 0: off, 1: on |
d<n> |
Set the data acquisition period | n: period value |
e<n> |
Set the number of external temperature sensors | 0, 1, or 4 |
f |
Exit configuration mode and continue boot | None |
j<n> |
Enable JSON serial format | 0: off, 1: on |
l |
List settings as key/value pairs | None |
lh |
List settings in human readable form | None |
m <x> <y> <z> |
Configure pulse counting | x: 0 off, 1 ony: n no pull, d pull down, u pull upz: minimum pulse period (ms) |
n<n> |
Set node ID | [1..60] |
p<n> |
Set RF power level | n: RF power level |
r |
Restore defaults | None |
s |
Save settings to NVM | None |
t<x> <yy> <yy> <yy> <yy> <yy> <yy> <yy> <yy> |
Change an external sensor's position | x: sensor position in the list (1-based)yy: hexadecimal address bytes, e.g. 28 81 43 31 07 00 00 D9 |
v |
Print firmware and board information | None |
w<n> |
Enable wireless | 0: off, 1: on |
x<n> |
Set 433 MHz compatibility | 0: 433.92 MHz, 1: 433.00 MHz |
Compiling the firmware requires the the Arm gcc toolchain (may be available as a package in your distribution). The Makefile is for a Cortex-M23 based microcontroller, specifically the Microchip ATSAML10E15 (datasheet, errata).
Note
To find which version, if any, of the toolchain is on your path, enter arm-none-eabi-gcc --version. You can set the path to a compiler off your path by setting the TC_PATH variable in Makefile.
To build the firmware:
> make -j
In bin/, the following binary files will be generated:
emonTH-vX.Y.Z-(commit[-dirty]).binemonTH-vX.Y.Z-(commit[-dirty]).elfemonTH-vX.Y.Z-(commit[-dirty]).hex
The -dirty tag (if present) indicates that there are uncommitted changes when the binaries are built.
The emonTH3 is supplied with a serial bootloader installed. To enter the bootloader, press the BOOT button while powering on the emonTH3. The LED will blink to indicate it has entered the bootloader.
Note
A Python virtual environment should be setup by running python3 -m venv venv && source venv/bin/activate && pip3 install -r requirements.txt in ./scripts/.
build_info.py: generatessrc/emonTH_build_info.cduring the build with the git revision, compiler version, build time, machine, and release metadata embedded in the firmware.version_info.py: derives the versioned output filename from the firmware version insrc/emonTH.hand the current git revision.elf_size.sh: runself-size-analyzeonbuild/emonTH.elfto break the image down by function size.led_pulse.py: generates theledIntensity[]lookup table used for the startup LED pulse effect.
There are no compile time configuration options.
Assertions are implemented by the EMONTH_ASSERT(condition) macro. The microcontroller will enter a breakpoint when an assertion fails and the PC is stored in the g_assert_info variable. The PC is used to find the file and line where the assertion failed using arm-none-eabi-addr2line.
The following table lists the peripherals used in the SAML10.
| Peripheral | Alias | Description | Usage |
|---|---|---|---|
| ADC | Analog-to-digital converter | Acquire battery voltage | |
| DMAC | DMA Controller | UART transmission | |
| EIC | External interrupt controller | External device sense | |
| PORT | GPIO handling | ||
| SERCOM0 | SERCOM_I2CM | I2C | I2C for internal peripherals |
| SERCOM1 | SERCOM_SPI | SPI | Drives RFM module |
| SERCOM2 | SERCOM_UART | UART | Configuration and data UART |
| TC0 | TIMER_LP | Timer/Counter (16bit) | Low power timing |
| TC1 | TIMER_PULSE | Timer/Counter (16bit) | Pulse timing / mask window |
| TC2 | TIMER_DELAY | Timer/Counter (16bit) | Delay counter, 8 us resolution |
The files ./src/board_def.h and ./src/board_def.c contain options for configuring the microcontroller for a given board. Pin mappings and peripheral usage will need to be adjusted to your design.
Within the top level loop, there are no direct calls to low level hardware. You must provide functions that handle the hardware specific to the microcontroller you are using.
All peripheral drivers are in header/source pairs named driver_<PERIPHERAL>. For example, the ADC driver is in driver_ADC.*. If you are porting to a new microcontroller, you will need to provide implementations of all the functions exposed in driver_<PERIPHERAL>.h and any internal functions within driver_<PERIPHERAL>.c. If your microcontroller does not support a particular function (for example, it doesn't have a DMA), then either no operation or an alternative must be provided.
You will also need to ensure that the vendor's headers are included and visible to the compiler.
Contributions are welcome! Small PRs can be accepted at any time. Please get in touch before making large changes to see if it's going to fit before spending too much time on things.
Tip
A clang-format autoformat pattern is included in the repository. Run the install-hooks.sh script to install the pre-commit hook to the autoformatter. You may need to install clang-format using your OS's package manager.
Note
Please bear in mind that this is an open source project and PRs and enhancements may not be addressed quickly, or at all. This is no comment on the quality of the contribution, and please feel free to fork as you like!
- mcu-starter-projects - good starting point for build chains for microcontrollers.
- RFM69 - RFM69 driver from Low Power Labs used as reference.
- Using Asserts in Embedded Systems - custom assertions from Interrupt by Memfault.
- Wintertools - various build and linker scripts from Winterbloom.
- Glyn Hudson @ OpenEnergyMonitor
- Trystan Lea @ OpenEnergyMonitor