From 03eaafddfddc5e833ff3ad89feaccaf4a2ef2606 Mon Sep 17 00:00:00 2001 From: Piotr Mienkowski Date: Thu, 20 Dec 2018 09:01:14 +0100 Subject: [PATCH] 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 --- soc/arm/Kconfig | 6 ++ subsys/logging/CMakeLists.txt | 5 ++ subsys/logging/Kconfig | 31 +++++++- subsys/logging/log_backend_swo.c | 119 +++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 subsys/logging/log_backend_swo.c diff --git a/soc/arm/Kconfig b/soc/arm/Kconfig index b58a340124f..9a7c5e2f3d1 100644 --- a/soc/arm/Kconfig +++ b/soc/arm/Kconfig @@ -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 diff --git a/subsys/logging/CMakeLists.txt b/subsys/logging/CMakeLists.txt index 2ee9b69ca4f..552290ff55c 100644 --- a/subsys/logging/CMakeLists.txt +++ b/subsys/logging/CMakeLists.txt @@ -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 +) diff --git a/subsys/logging/Kconfig b/subsys/logging/Kconfig index 507919d9743..22c68b7db7a 100644 --- a/subsys/logging/Kconfig +++ b/subsys/logging/Kconfig @@ -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. diff --git a/subsys/logging/log_backend_swo.c b/subsys/logging/log_backend_swo.c new file mode 100644 index 00000000000..1b66eec18c1 --- /dev/null +++ b/subsys/logging/log_backend_swo.c @@ -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 +#include +#include +#include +#include + +/** 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);