– August 2, 2018 RA
You can put the SAMD51 into a bricked state. The only option is to use an SWD adapter and send a erase flash to wipe the chip. I use Segger JLink over SWD to flash and debug ARM processors. SWD is a two wire protocol, SWDIO bidirectional data and SWCLK clock. Unlike previous processors, the processor will recognize that the SWD interface is in use without pulling on a special pin on reset. The JLink is not cheap but with support you get from Segger makes it a bargain.
You can use the JLink flash utility to write the flash without a bootloader. When it is bricked, go into JLink commander, and send the following erase chip command to the processor DSU.
w1 0x41002000, 0x10This will erase all of flash with the exception of a protected bootloader.
The SDO does go to the JLink or other SWD interface although it isn't considered an actual part of the SWD interface. I was curious about using it with the SWO viewer provided by Segger. Running through the recommended initialization from ARM, from Segger and others didn't work. CMSIS provides routines which put a character over SDO but do not have initialization code. Usually processors run the trace units off the CPU clock and so clocking setup is not required. This is not true of the SAMD51.
So a conversation with Microchip was worthwhile. There is a undocumented and uncoded clock ID path for the trace module.
#define CM4_TRACE_GCLK_ID 47
This is part of my initmaker and I added a file cm4.h to the instance lib.
#define SWO_PRINT_PORT 0 #define SWO_FREQUENCY 6000000UL #define SWOPRESCALE (((CPU_FREQUENCY)/(SWO_FREQUENCY)) - 1) #define ITM_ID ((1UL << ITM_TCR_TraceBusID_Pos) & ITM_TCR_TraceBusID_Msk)
/* SDO can be used for printf messages without the expense of aUART */ /* This file is included as an extended file to initialize ITM */ gclk_write_PCHCTRL(CM4_TRACE_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN); while(gclk_get_PCHCTRL(CM4_TRACE_GCLK_ID, GCLK_PCHCTRL_CHEN) == 0) {}; CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; /* enable access to the trace component registers. */ TPI->SPPR = 0x2UL; /* Selected Pin Protocol Register -> Serial Wire Viewer, UART Non-Return to Zero encoding */ TPI->ACPR = SWOPRESCALE; ITM->LAR = 0xC5ACCE55UL; /* unlock the ITM */ ITM->TCR = ITM_TCR_ITMENA_Msk | ITM_TCR_TSENA_Msk | (1UL << ITM_TCR_TraceBusID_Pos) | ITM_TCR_DWTENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_SWOENA_Msk; /* Enable ITM. This must be before ITM Stimulus and Trace Enable registers are written. */ ITM->TER = 0xFFFFFFFF; /* ITM Trace Enable Register - enable port */ ITM->TPR = 0;
The CMSIS function ITM_SendChar() will send characters to channel 0 and received and logged by SWOViewer. SWO has 32 channels that can be filtered along with sending messages without the use of a UART or USB.
You can wrap puts and putchar in the linker so printf doesn't use the default libc functions.
-Wl,-wrap=puts -Wl,-wrap=putchar
and then compile in the following functions
/* * puts is not so easy to override as printf * __wrap_puts overrides the puts in libc * it requires link option -Wl,-wrap=puts, -Wl, -wrap=putc * this prevents printf("str"); from using puts from libc */ int __wrap_puts (const char* str) { while(*str != '\0') { ITM_SendChar(*str++); } ITM_SendChar('\r'); ITM_SendChar('\n'); return 1; } int __wrap_putchar(int c) { ITM_SendChar(c); return 1; }
I also use the printf-stdarg.c from freeRTOS instead of libc printf.