edb-rat: an app for testing EDB features
This repository contains a "lab rat" test application on which we will demonstrate features of EDB. This repository also contains "links" in the form of git submodules to a frozen version of the EDB firmware and the EDB console repos.
Below is a quick start tutorial for how to use EDB to debug an application. The application runs on a WISP5 energy-harvesting device.
This repository also includes as submodules the EDB firmware and host console
as an external tool dependency (in
ext/) -- this is done to make the
procedure as reproducible as possible, submodules freeze versions of
To start, clone this repository with
git clone --recursive ..., in order
to fetch it along with the submodules.
The app (and most of its dependencies) are built using the
maker repos is also included as a submodule in
Optional: build and flash EDB firmware
If you have a board, chances are the firware has already been flashed onto it, but if needed you can always build and flash the firmware as follows:
cd ext/edb-server make bld/gcc/all make bld/gcc/prog cd ..
The edb-rat application has a separate built configuration for testing each
feature. To select the build variant, set one of the
TEST_* variables to
Build and flash edb-rat app
To build and flash the edb-rat app onto the WISP, run:
make bld/gcc/clean make bld/gcc/all make bld/gcc/prog
NOTE: After changing the build configuration, make sure to clean.
NOTE: After cleaning, it is sufficient to make the
bld/gcc/all is a prerequisite.
Connect the EDB to the WISP by connecting the two ends of the matching 8+3-pin board-to-board headers. Then, separately, connect three additional wires: the Vcap line, RF RX line and RF TX line. On EDBv1.1 board, these connections go to the 5-pin header located near the programming header on the bottom side of the board. On EDBv1.0 board, these connections go to separate test points in the upper region on the board.
Open the EDB console and attach to the debugger, specifying the TTY device that shows up when you plug in the board (see tips below):
cd ext/edb-console ./edb > attach --device /dev/ttyUSB0 >
There should be no need to re-run the attach command as long as the console stays open, even if the EDB board is reset.
To verify that the workstation recognized the EDB board as a USB device, check that a TTY device was created after the cable was plugged in:
If you don't see a
/dev/ttyUSB* device, then check your connections, and check
kernel log (
dmesg) for any hints, also check lsusb output, which should have:
Bus 002 Device 023: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
On Linux, to grant your user permission to access the device, add it to
sudo usermod -a -G dialout $(whoami)
Linux kernel shipps with the drivers, so no need to install anything. On OS X driver installation is likely necessary, as described in this tutorial from SparkFun.
The four LEDs on the top of the board indicate status as follows:
* GREEN (flashing): device powered (from USB or FET) and idle * YELLOW: flashes once when EDB boots * ORANGE: on while in interactive debug mode * RED: error occured, error code encoded as frequency of flashing (see on scope)
A brief help for each console command can be obtained by running the command
ATTENTION: Disconnect WISP from the FET programmer when working with EDB, because the FET leaks power to the WISP, even when the FET is connected in the self-powered configuration. Also, when working with the RFID reader, keep it off while configuring things in the EDB console, and only turn it on once all is ready for the experiment. Otherwise, events will happen in the middle of you trying to set things up (e.g. enable watchpoints, etc.), which is very likely to confuse EDB.
NOTE: Before each of the different tests described below, do reset the EDB board using the on-board reset push-button. This is not always necessary, but eliminates potential problems.
Sense and set energy level on the target device
Sense voltage on the target capacitor
> sense vcap Vcap = 2.0121
The next operation to try is to charge and discharge the WISP capacitor:
> charge 2.2 Vcap = 2.2001 > discharge 0.1 Vcap = 0.1006
The printed Vcap value is the capacitor voltage measured at the completion of the charging/discharging procedure.
If the command never completes, one possible reason is that the wire to the WISP capacitor is not connected.
Discharging to precisely 0.0 might not work (edge-case), so use a small positive value.
Passively monitor energy, program, and I/O events
Stream energy level
Monitor the voltage level on the WISP capacitor using the
Turn on the reader to see the voltage rising up to 2.4V
(turn-on threshold) as the capacitor charges and very quickly falling to 1.8V
(brown-out threshold) as WISP is actively computing.
> stream - - vcap adc_sampling_period_cycles= 3000 timestamp_sec,VCAP 0.001013,2.327659 0.002014,2.332031 0.003014,2.332031 0.004014,2.337861 0.005015,2.342963 0.006015,2.353165 0.007015,2.343691 0.008016,2.331302 0.009016,2.307982
Ctrl-C ends the stream operation. Note: cleanup bugs may exist, if commands not working after having run some commands, reset the debugger board and start fresh.
Build the app with
TEST_WATCHPOINTS = 1 and the rest set to 0.
In the EDB console, enable the watchpoints and start monitoring for them using
> watch --energy 0 E > watch --energy 1 E > stream watchpoints adc_sampling_period_cycles=3000 host_timestamp_sec,timestamp_sec,watchpoint_id,watchpoint_vcap 13.678827,0.018393,0,2.3517 13.678827,0.018469,1,2.3466 13.678827,0.018546,1,2.3408 13.678827,0.018623,0,2.3451 13.678827,0.018699,1,2.3393 13.678827,0.018776,1,2.3313 13.678827,0.018853,0,2.3335
--energy flag tells EDB to collect the energy level when watchpoint hits.
Stream energy-interference-free printf output
The energy-interference-free printf allows a target application to generate output while running on an intermittent power supply. The output can consume an arbitrary amount of energy -- EDB compensates.
Build the app with
TEST_EIF_PRINTF = 1 and the rest set to 0.
The application code contains printf or log statements with values of interest:
In the EDB console, expect the stdout data using the
> wait 20.119: EDB-RAT
Stream RFID messages
For applications that communicate with the reader over RFID protocol, EDB can decode the incoming and (partially) outgoing messages (TODO: add to app).
> attach > stream - - rf_events adc_sampling_period_cycles= 3000 timestamp_sec,rf_event ...
Make sure that the RX and TX lines (not part of the main 8+3 header) are connected.
Watch output of SLLURP tool tool to make sure that communication is actually taking place.
Events are buffered, so it make take quite a few minutes before they show up in the console.
NOTE: This has not been tested in a while, so due to bit-rot it may not work out-of-the-box.
Energy guards for energy-interference-free instrumentation
An energy guard allows the target application to execute (instrumentation) code of an arbitrary energy cost, while running on an intermittent power supply. For example, a costly invariant check can be wrapped into an energy guard:
ENERGY_GUARD_BEGIN(); [ code ] ENERGY_GUARD_END();
While executing energy guarded code, EDB powers the target. At the end of the guard, EDB restores the energy level to its value before the energy guard, masking the effect of the guard on the stored energy level.
Build the app with
TEST_ENERGY_GUARDS = 1 and the rest set to 0.
The test code contains a watchpoint before and after the guard. If all is working, we should see no difference in the energy values at the watchpoints (except for some precision error), despite the lengthy code inside the guard.
> watch --energy 0 E > watch --energy 1 E > stream watchpoints adc_sampling_period_cycles=3000 host_timestamp_sec,timestamp_sec,watchpoint_id,watchpoint_vcap 7.999799,0.016739,0,2.3663 7.999799,0.020505,1,2.3437 7.999799,0.020784,0,2.3422 7.999799,0.002843,1,2.3131
With keep-alive asserts, an application can check invariants while running on an intermittent power supply. When an assert fails, EDB steps in, starts supplying power, and presents the user with an interactive debug prompt.
Build the app with
TEST_ASSERT = 1 and the rest set to 0.
Turn on the RF power source. Then, once the ASSERT is reached in code, the console should indicate which assert failed, and allow further inspection:
Interrupted: 'ASSERT' line: 57 Vcap_saved = 2.3517 *> pc 0x0000473c *>
Interrupt on next boot
Build the app with
TEST_INTERRUPT = 1 and the rest set to 0.
Turn off the reader (to make things
simpler), then charge the WISP and interrupt the execution. The
tells EDB to wait for WISP to boot up, and then to interrupt:
Turn on the RFID reader. After serveral seconds, depending on the RF power, once the WISP boots, the console should drop into the interactive debug mode:
Vcap_saved = 2.3320 *> pc 0x000046ee *> cont Vcap_restored = 2.3284
While in interactive debug mode, the console prompt should be marked with a
*>. Also, the orange LED on the EDB board should be on and the
green LED on the side of the WISP without the MCU should also be on.
Build the app with
TEST_BREAKPOINTS = 1 and the rest set to 0.
The interactive debug mode can also be reached by hitting a breakpoint. In the application code, add
Then, turn on the power source, enable the breakpoint in the EDB console, and wait for it to be hit:
> break e 1 en > wait Interrupted: BREAKPOINT id: 1 Vcap_saved = 2.2336 *>
Sidenote: The first argument to the
break cmd 'e' stands for 'external',
the type of breakpoint. TODO: elaborate.
In interactive mode, we can get the current program counter address:
*> pc 0x00004766
In interactive mode, any address (volatile memory, non-volatile memory,
memory-mapped registers) can be read and written. Currently, EDB cannot resolve
symbols into addresses, so this has to be done manually. For example, get the
address of a global variable from the
.map file, generated by the linker:
grep nv_state_magic bld/gcc/*.map 00004400 nv_state_magic 00004400 nv_state_magic
Inspect and modify the value of that global variable in the EDB console (when in interactive session):
*> read 0x4400 4 0x00004400: 0xef 0xbe 0xad 0xde *> write 0x4400 0xfe 0xca 0x0d 0xf0 0x00004400: 0xfe 0xca 0x0d 0xf0
To continue the execution (and have EDB automatically restore the energy level its value prior to interruption):