Hi,
I'm attempting to modify the basic firmware, and I'm progressing quite well however there are a couple of sneaky scenarios which require a lower level debugging capability.
Can you please advise how you debug the firmware, on the device?
I've modified the firmware to call 'AudioMoth_setupSWOForPrint' at the end of AudioMoth_initialise() and added a couple of debug statements such as printf("Debugging enabled"); Throughout the code, being executed. These changes, along with my other alterations were then successfully flashed to the AudioMoth device.
I've then connected my J-Link debug probe https://www.segger.com/products/debug-probes/j-link/, which appears to support the EFM32WG980F256 chip. https://www.segger.com/downloads/supported-devices.php
1. PC -> USB -> AudioMoth USB plug (normal USB connection for an AudioMoth)
2. PC -> USB -> JLink Debug Probe -> SWD via Dupont Connectors -> AudioMoth Debug pads
Here's a couple of photos to highlight what I'm doing. Sure, those connections are soldered a little rough but have been verified to be fine.
As a simple dump, here's what I'm using. I'm expecting you're doing something similar when modifying the firmware.
JLinkExe
SEGGER J-Link Commander V6.52c (Compiled Oct 11 2019 15:44:58)
DLL version V6.52c, compiled Oct 11 2019 15:44:50
....
Type "connect" to establish a target connection, '?' for help
J-Link>connect
Please specify device / core. <Default>: EFM32WG980F256
Type '?' for selection dialog
Device>
Please specify target interface:
J) JTAG (Default)
S) SWD
T) cJTAG
TIF>S
Specify target interface speed [kHz]. <Default>: 4000 kHz
Speed>
Device "EFM32WG980F256" selected.
Connecting to target via SWD
Found SW-DP with ID 0x2BA01477
Scanning AP map to find all available APs
AP[1]: Stopped AP scan as end of AP map has been reached
AP[0]: AHB-AP (IDR: 0x24770011)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0xE00FF000
CPUID register: 0x410FC241. Implementer code: 0x41 (ARM)
Found Cortex-M4 r0p1, Little endian.
FPUnit: 6 code (BP) slots and 2 literal slots
CoreSight components:
ROMTbl[0] @ E00FF000
ROMTbl[0][0]: E000E000, CID: B105E00D, PID: 000BB00C SCS-M7
ROMTbl[0][1]: E0001000, CID: B105E00D, PID: 003BB002 DWT
ROMTbl[0][2]: E0002000, CID: B105E00D, PID: 002BB003 FPB
ROMTbl[0][3]: E0000000, CID: B105E00D, PID: 003BB001 ITM
ROMTbl[0][4]: E0040000, CID: B105900D, PID: 003BB923 TPIU-Lite
ROMTbl[0][5]: E0041000, CID: B105900D, PID: 000BB925 ETM
Cortex-M4 identified.
J-Link>SWORead
0 bytes read (0 bytes in host buffer)
J-Link>SWOView
Receiving SWO data @ 4000 kHz.
Data from stimulus port 0:
-----------------------------------------------
Occasionally I'll get SWO output, but its all garbled and meaningless. On other hardware I would think this was a mismatch of the receiving clock (4000 kHz), but maybe I'm attacking this incorrectly.
I appreciate this is getting down into the lower levels of core programming on the device but I suspect other users may wish to also understand these debugging aspects when modifying the firmware to suit their needs also. Without a device level debugging capability the only way to check out changes is to flash the device with extra LED flashes to highlight state changes, or log to the microSD via the AudioMoth_appendFile operation.
Which SWO debug probe do you use to validate changes to the base firmware?
What code changes do you make to enable debugging?
Are there Simplicity Studio changes which you utilise to support debugging on the device?
Are you debugging the code off the device instead, on a PC using a 32-bit ARM emulator or 32-bit x86 target toolchain?
Are you implementing Unit Testing on your version of the firmware?
Hi, We typically debug directly on the hardware except when experimenting with digital signal processing where we can test initial versions offline, and to test functions such as -
scheduleRecording(uint32_t currentTime, uint32_t *timeOfNextRecording, uint32_t *durationOfNextRecording)
- which don't involve any actual hardware interaction.
One really useful thing to develop would be an AudioMoth simulator which would simulate the library calls and generate the appropriate interrupts such that all of the application code could be tested offline. We haven't done that but it would be an interesting project.
We typically use one of the EFM32 starter kits as an external debugger as they are cheap and are well integrated with the Simplicity Studio environment. All this requires is the addition of the AudioMoth_setupSWOForPrint function to the setup routine (as you have in your example) and then the SWO outputs appear in the console output when running the debugger within Simplicity Studio. You can then also set breakpoints and explore the SRAM and flash contents.
The one challenge with this approach is that the standard AudioMoth code goes into EM4 mode and is woken by the BURTC every couple of seconds and doing so will cause the debugger to lose connection.
Writing the activity of the device to the SD card is also really useful and is what we typically do for custom versions of firmware so we can log anything we like over extended periods of time. We generally add a macro:
#define RETURN_ON_FALSE(fn) { \
bool success = (fn); \
if (!success) return; \
}
and then use a logging function:
void writeLog(uint32_t currentTime, char *message) {
if (!fileSystemEnabled) fileSystemEnabled = AudioMoth_enableFileSystem();
if (!fileSystemEnabled) return;
RETURN_ON_FALSE(AudioMoth_appendFile(logFilename));
struct tm *time = gmtime((time_t*)¤tTime);
sprintf(logBuffer, "%02d/%02d/%04d %02d:%02d:%02d: ", time->tm_mday, time->tm_mon + 1, time->tm_year + 1900, time->tm_hour, time->tm_min, time->tm_sec);
RETURN_ON_FALSE(AudioMoth_writeToFile(logBuffer, strnlen(logBuffer, LOG_BUFFER_LENGTH)));
RETURN_ON_FALSE(AudioMoth_writeToFile(message, strlen(message)));
RETURN_ON_FALSE(AudioMoth_writeToFile("\n", 1));
RETURN_ON_FALSE(AudioMoth_closeFile());
}