logger: add a SWO backend

This commit adds Serial Wire Output (SWO) logger backend. SWO is an
extension of Serial Wire Debug (SWD) port developed by ARM.

Signed-off-by: Piotr Mienkowski <piotr.mienkowski@gmail.com>
This commit is contained in:
Piotr Mienkowski 2018-12-20 09:01:14 +01:00 committed by Carles Cufí
commit 03eaafddfd
4 changed files with 159 additions and 2 deletions

View file

@ -20,3 +20,9 @@ config CPU_HAS_ARM_SAU
select CPU_HAS_TEE
help
MCU implements the ARM Security Attribution Unit (SAU).
config HAS_SWO
bool
# Omit prompt to signify "hidden" option
help
When enabled, indicates that SoC has an SWO output

View file

@ -33,3 +33,8 @@ zephyr_sources_ifdef(
CONFIG_LOG_BACKEND_RTT
log_backend_rtt.c
)
zephyr_sources_ifdef(
CONFIG_LOG_BACKEND_SWO
log_backend_swo.c
)

View file

@ -302,6 +302,31 @@ config LOG_BACKEND_UART
help
When enabled backend is using UART to output logs.
config LOG_BACKEND_SWO
bool "Enable Serial Wire Output (SWO) backend"
depends on HAS_SWO
help
When enabled, backend will use SWO for logging.
if LOG_BACKEND_SWO
config LOG_BACKEND_SWO_FREQ_HZ
int "Set SWO output frequency"
default 0
help
Set SWO output frequency. Value 0 will select maximum frequency
supported by the given MCU. Not all debug probes support high
frequency SWO operation. In this case the frequency has to be set
manually.
SWO value defined by this option will be configured at boot. Most SWO
viewer programs will configure SWO frequency when attached to the
debug probe. Such configuration will persist only until the device
reset. To ensure flawless operation the frequency configured here and
by the SWO viewer program has to match.
endif # LOG_BACKEND_SWO
config LOG_BACKEND_RTT
bool "Enable Segger J-Link RTT backend"
depends on USE_SEGGER_RTT
@ -448,14 +473,16 @@ endif # LOG_BACKEND_NET
config LOG_BACKEND_SHOW_COLOR
bool "Enable colors in the backend"
depends on LOG_BACKEND_UART || LOG_BACKEND_NATIVE_POSIX || LOG_BACKEND_RTT
depends on LOG_BACKEND_UART || LOG_BACKEND_NATIVE_POSIX || LOG_BACKEND_RTT \
|| LOG_BACKEND_SWO
default y
help
When enabled selected backend prints errors in red and warning in yellow.
config LOG_BACKEND_FORMAT_TIMESTAMP
bool "Enable timestamp formatting in the backend"
depends on LOG_BACKEND_UART || LOG_BACKEND_NATIVE_POSIX || LOG_BACKEND_RTT
depends on LOG_BACKEND_UART || LOG_BACKEND_NATIVE_POSIX || LOG_BACKEND_RTT \
|| LOG_BACKEND_SWO
default y
help
When enabled timestamp is formatted to hh:mm:ss:ms,us.

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2018 Piotr Mienkowski
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file
* @brief Serial Wire Output (SWO) backend implementation.
*
* SWO/SWV has been developed by ARM. The following code works only on ARM
* architecture.
*
* An SWO viewer program will typically set-up the SWO port including its
* frequency when connected to the debug probe. Such configuration can persist
* only until the MCU reset. The SWO backend initialization function will
* re-configure the SWO port upon boot and set the frequency as specified by
* the LOG_BACKEND_SWO_FREQ_HZ Kconfig option. To ensure flawless operation
* this frequency should much the one set by the SWO viewer program.
*
* The initialization code assumes that SWO core frequency is equal to HCLK
* as defined by SYS_CLOCK_HW_CYCLES_PER_SEC Kconfig option. This may require
* additional, vendor specific configuration.
*/
#include <logging/log_backend.h>
#include <logging/log_core.h>
#include <logging/log_msg.h>
#include <logging/log_output.h>
#include <soc.h>
/** The stimulus port from which SWO data is received and displayed */
#define ITM_PORT_LOGGER 0
/* Set TPIU prescaler for the current debug trace clock frequency. */
#if CONFIG_LOG_BACKEND_SWO_FREQ_HZ == 0
#define SWO_FREQ_DIV 1
#else
#define SWO_FREQ (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC \
+ (CONFIG_LOG_BACKEND_SWO_FREQ_HZ / 2))
#define SWO_FREQ_DIV (SWO_FREQ / CONFIG_LOG_BACKEND_SWO_FREQ_HZ)
#if SWO_FREQ_DIV > 0xFFFF
#error CONFIG_LOG_BACKEND_SWO_FREQ_HZ is too low. SWO clock divider is 16-bit. \
Minimum supported SWO clock frequency is \
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC/2^16.
#endif
#endif
static u8_t buf[1];
static int char_out(u8_t *data, size_t length, void *ctx)
{
ARG_UNUSED(ctx);
for (size_t i = 0; i < length; i++) {
ITM_SendChar(data[i]);
}
return length;
}
LOG_OUTPUT_DEFINE(log_output, char_out, buf, sizeof(buf));
static void log_backend_swo_put(const struct log_backend *const backend,
struct log_msg *msg)
{
log_msg_get(msg);
u32_t flags = LOG_OUTPUT_FLAG_LEVEL | LOG_OUTPUT_FLAG_TIMESTAMP;
if (IS_ENABLED(CONFIG_LOG_BACKEND_SHOW_COLOR)) {
flags |= LOG_OUTPUT_FLAG_COLORS;
}
if (IS_ENABLED(CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP)) {
flags |= LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
}
log_output_msg_process(&log_output, msg, flags);
log_msg_put(msg);
}
static void log_backend_swo_init(void)
{
/* Enable DWT and ITM units */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* Enable access to ITM registers */
ITM->LAR = 0xC5ACCE55;
/* Disable stimulus ports ITM_STIM0-ITM_STIM31 */
ITM->TER = 0x0;
/* Disable ITM */
ITM->TCR = 0x0;
/* Select NRZ (UART) encoding protocol */
TPI->SPPR = 2;
/* Set SWO baud rate prescaler value: SWO_clk = ref_clock/(ACPR + 1) */
TPI->ACPR = SWO_FREQ_DIV - 1;
/* Enable unprivileged access to ITM stimulus ports */
ITM->TPR = 0x0;
/* Configure Debug Watchpoint and Trace */
DWT->CTRL = 0x400003FE;
/* Configure Formatter and Flush Control Register */
TPI->FFCR = 0x00000100;
/* Enable ITM, set TraceBusID=1, no local timestamp generation */
ITM->TCR = 0x0001000D;
/* Enable stimulus port used by the logger */
ITM->TER = 1 << ITM_PORT_LOGGER;
}
static void log_backend_swo_panic(struct log_backend const *const backend)
{
}
const struct log_backend_api log_backend_swo_api = {
.put = log_backend_swo_put,
.panic = log_backend_swo_panic,
.init = log_backend_swo_init,
};
LOG_BACKEND_DEFINE(log_backend_swo, log_backend_swo_api, true);