summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Sliwa <dominik.sliwa@toradex.com>2018-09-11 15:35:14 +0200
committerDominik Sliwa <dominik.sliwa@toradex.com>2018-09-11 15:35:14 +0200
commitf3f54d37d7888235bccac1c0cddda1dd9b2323f4 (patch)
treebd68068e0b7889a09779973e0e494f5d73acd2ac
parent4d7f3aebc85ff3928a25bd1567f94f2789d6437b (diff)
implement SWO debugging
Signed-off-by: Dominik Sliwa <dominik.sliwa@toradex.com>
-rw-r--r--board/board.c19
-rw-r--r--source/gpio_ext.h2
-rw-r--r--utilities/fsl_debug_console.c803
-rw-r--r--utilities/fsl_debug_console.h15
4 files changed, 837 insertions, 2 deletions
diff --git a/board/board.c b/board/board.c
index 726870b..ba853ad 100644
--- a/board/board.c
+++ b/board/board.c
@@ -38,8 +38,23 @@
* @brief initialize debug console to enable printf for this demo/example
*/
void BOARD_InitDebugConsole(void) {
- uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ;
+ uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ;
- DbgConsole_Init(BOARD_DEBUG_UART_BASEADDR, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq);
+#ifdef USE_SWO
+ uint32_t SWOSpeed = 1000000; /* default 64k baud rate */
+ uint32_t SWOPrescaler = (uartClkSrcFreq / SWOSpeed) - 1; /* SWOSpeed in Hz, note that cpuCoreFreqHz is expected to be match the CPU core clock */
+ CoreDebug->DEMCR = CoreDebug_DEMCR_TRCENA_Msk; /* enable trace in core debug */
+ *((volatile unsigned *)(ITM_BASE + 0x400F0)) = 0x00000002; /* "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO NRZ, 1: SWO Manchester encoding) */
+ *((volatile unsigned *)(ITM_BASE + 0x40010)) = SWOPrescaler; /* "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output */
+ *((volatile unsigned *)(ITM_BASE + 0x00FB0)) = 0xC5ACCE55; /* ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC */
+ ITM->TCR = ITM_TCR_TraceBusID_Msk | ITM_TCR_SWOENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_ITMENA_Msk; /* ITM Trace Control Register */
+ ITM->TPR = ITM_TPR_PRIVMASK_Msk; /* ITM Trace Privilege Register */
+ ITM->TER = 0x01; /* ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port. */
+ *((volatile unsigned *)(ITM_BASE + 0x01000)) = 0x400003FE; /* DWT_CTRL */
+ *((volatile unsigned *)(ITM_BASE + 0x40304)) = 0x00000100; /* Formatter and Flush Control Register */
+
+#endif
+
+DbgConsole_Init(BOARD_DEBUG_UART_BASEADDR, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq);
}
diff --git a/source/gpio_ext.h b/source/gpio_ext.h
index 39a9183..7d87f4f 100644
--- a/source/gpio_ext.h
+++ b/source/gpio_ext.h
@@ -18,7 +18,9 @@ struct gpio_id{
};
struct gpio_id gpio_list [] = {
+#ifndef USE_SWO
{PORTA, GPIOA, 3},
+#endif
{PORTA, GPIOA, 5},
#ifdef TESTER_BUILD
{PORTA, GPIOA, 12},
diff --git a/utilities/fsl_debug_console.c b/utilities/fsl_debug_console.c
index bd0b241..1620572 100644
--- a/utilities/fsl_debug_console.c
+++ b/utilities/fsl_debug_console.c
@@ -1957,3 +1957,806 @@ int fgetc(FILE *f)
return ch;
}
#endif /* __ICCARM__ */
+
+
+#ifdef USE_SWO
+
+#define ITM_STIM_U32 (*(volatile unsigned int*)0xE0000000) // Stimulus Port Register word acces
+#define ITM_STIM_U8 (*(volatile char*)0xE0000000) // Stimulus Port Register byte acces
+#define ITM_ENA (*(volatile unsigned int*)0xE0000E00) // Trace Enable Ports Register
+#define ITM_TCR (*(volatile unsigned int*)0xE0000E80) // Trace control register
+
+static int32_t DbgConsole_ConvertRadixNumToString(char *numstr, void *nump, int32_t neg, int32_t radix, bool use_caps)
+{
+#if PRINTF_ADVANCED_ENABLE
+ int64_t a;
+ int64_t b;
+ int64_t c;
+
+ uint64_t ua;
+ uint64_t ub;
+ uint64_t uc;
+#else
+ int32_t a;
+ int32_t b;
+ int32_t c;
+
+ uint32_t ua;
+ uint32_t ub;
+ uint32_t uc;
+#endif /* PRINTF_ADVANCED_ENABLE */
+
+ int32_t nlen;
+ char *nstrp;
+
+ nlen = 0;
+ nstrp = numstr;
+ *nstrp++ = '\0';
+
+ if (neg)
+ {
+#if PRINTF_ADVANCED_ENABLE
+ a = *(int64_t *)nump;
+#else
+ a = *(int32_t *)nump;
+#endif /* PRINTF_ADVANCED_ENABLE */
+ if (a == 0)
+ {
+ *nstrp = '0';
+ ++nlen;
+ return nlen;
+ }
+ while (a != 0)
+ {
+#if PRINTF_ADVANCED_ENABLE
+ b = (int64_t)a / (int64_t)radix;
+ c = (int64_t)a - ((int64_t)b * (int64_t)radix);
+ if (c < 0)
+ {
+ uc = (uint64_t)c;
+ c = (int64_t)(~uc) + 1 + '0';
+ }
+#else
+ b = a / radix;
+ c = a - (b * radix);
+ if (c < 0)
+ {
+ uc = (uint32_t)c;
+ c = (uint32_t)(~uc) + 1 + '0';
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ else
+ {
+ c = c + '0';
+ }
+ a = b;
+ *nstrp++ = (char)c;
+ ++nlen;
+ }
+ }
+ else
+ {
+#if PRINTF_ADVANCED_ENABLE
+ ua = *(uint64_t *)nump;
+#else
+ ua = *(uint32_t *)nump;
+#endif /* PRINTF_ADVANCED_ENABLE */
+ if (ua == 0)
+ {
+ *nstrp = '0';
+ ++nlen;
+ return nlen;
+ }
+ while (ua != 0)
+ {
+#if PRINTF_ADVANCED_ENABLE
+ ub = (uint64_t)ua / (uint64_t)radix;
+ uc = (uint64_t)ua - ((uint64_t)ub * (uint64_t)radix);
+#else
+ ub = ua / (uint32_t)radix;
+ uc = ua - (ub * (uint32_t)radix);
+#endif /* PRINTF_ADVANCED_ENABLE */
+
+ if (uc < 10)
+ {
+ uc = uc + '0';
+ }
+ else
+ {
+ uc = uc - 10 + (use_caps ? 'A' : 'a');
+ }
+ ua = ub;
+ *nstrp++ = (char)uc;
+ ++nlen;
+ }
+ }
+ return nlen;
+}
+
+#if PRINTF_FLOAT_ENABLE
+/*!
+ * @brief Converts a floating radix number to a string and return its length.
+ *
+ * @param[in] numstr Converted string of the number.
+ * @param[in] nump Pointer to the number.
+ * @param[in] radix The radix to be converted to.
+ * @param[in] precision_width Specify the precision width.
+
+ * @return Length of the converted string.
+ */
+static int32_t DbgConsole_ConvertFloatRadixNumToString(char *numstr,
+ void *nump,
+ int32_t radix,
+ uint32_t precision_width)
+{
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t i;
+ uint32_t uc;
+ double fa;
+ double dc;
+ double fb;
+ double r;
+ double fractpart;
+ double intpart;
+
+ int32_t nlen;
+ char *nstrp;
+ nlen = 0;
+ nstrp = numstr;
+ *nstrp++ = '\0';
+ r = *(double *)nump;
+ if (!r)
+ {
+ *nstrp = '0';
+ ++nlen;
+ return nlen;
+ }
+ fractpart = modf((double)r, (double *)&intpart);
+ /* Process fractional part. */
+ for (i = 0; i < precision_width; i++)
+ {
+ fractpart *= radix;
+ }
+ if (r >= 0)
+ {
+ fa = fractpart + (double)0.5;
+ if (fa >= pow(10, precision_width))
+ {
+ intpart++;
+ }
+ }
+ else
+ {
+ fa = fractpart - (double)0.5;
+ if (fa <= -pow(10, precision_width))
+ {
+ intpart--;
+ }
+ }
+ for (i = 0; i < precision_width; i++)
+ {
+ fb = fa / (int32_t)radix;
+ dc = (fa - (int64_t)fb * (int32_t)radix);
+ c = (int32_t)dc;
+ if (c < 0)
+ {
+ uc = (uint32_t)c;
+ c = (int32_t)(~uc) + 1 + '0';
+ }
+ else
+ {
+ c = c + '0';
+ }
+ fa = fb;
+ *nstrp++ = (char)c;
+ ++nlen;
+ }
+ *nstrp++ = (char)'.';
+ ++nlen;
+ a = (int32_t)intpart;
+ if (a == 0)
+ {
+ *nstrp++ = '0';
+ ++nlen;
+ }
+ else
+ {
+ while (a != 0)
+ {
+ b = (int32_t)a / (int32_t)radix;
+ c = (int32_t)a - ((int32_t)b * (int32_t)radix);
+ if (c < 0)
+ {
+ uc = (uint32_t)c;
+ c = (int32_t)(~uc) + 1 + '0';
+ }
+ else
+ {
+ c = c + '0';
+ }
+ a = b;
+ *nstrp++ = (char)c;
+ ++nlen;
+ }
+ }
+ return nlen;
+}
+#endif /* PRINTF_FLOAT_ENABLE */
+
+static void DbgConsole_PrintfPaddingCharacter(
+ char c, int32_t curlen, int32_t width, int32_t *count, PUTCHAR_FUNC func_ptr)
+{
+ int32_t i;
+
+ for (i = curlen; i < width; i++)
+ {
+ func_ptr(c);
+ (*count)++;
+ }
+}
+
+static int SWO_PrintfFormattedData(PUTCHAR_FUNC func_ptr, const char *fmt, va_list ap)
+{
+ /* va_list ap; */
+ char *p;
+ int32_t c;
+
+ char vstr[33];
+ char *vstrp = NULL;
+ int32_t vlen = 0;
+
+ int32_t done;
+ int32_t count = 0;
+
+ uint32_t field_width;
+ uint32_t precision_width;
+ char *sval;
+ int32_t cval;
+ bool use_caps;
+ uint8_t radix = 0;
+
+#if PRINTF_ADVANCED_ENABLE
+ uint32_t flags_used;
+ int32_t schar, dschar;
+ int64_t ival;
+ uint64_t uval = 0;
+ bool valid_precision_width;
+#else
+ int32_t ival;
+ uint32_t uval = 0;
+#endif /* PRINTF_ADVANCED_ENABLE */
+
+#if PRINTF_FLOAT_ENABLE
+ double fval;
+#endif /* PRINTF_FLOAT_ENABLE */
+
+ /* Start parsing apart the format string and display appropriate formats and data. */
+ for (p = (char *)fmt; (c = *p) != 0; p++)
+ {
+ /*
+ * All formats begin with a '%' marker. Special chars like
+ * '\n' or '\t' are normally converted to the appropriate
+ * character by the __compiler__. Thus, no need for this
+ * routine to account for the '\' character.
+ */
+ if (c != '%')
+ {
+ func_ptr(c);
+ count++;
+ /* By using 'continue', the next iteration of the loop is used, skipping the code that follows. */
+ continue;
+ }
+
+ use_caps = true;
+
+#if PRINTF_ADVANCED_ENABLE
+ /* First check for specification modifier flags. */
+ flags_used = 0;
+ done = false;
+ while (!done)
+ {
+ switch (*++p)
+ {
+ case '-':
+ flags_used |= kPRINTF_Minus;
+ break;
+ case '+':
+ flags_used |= kPRINTF_Plus;
+ break;
+ case ' ':
+ flags_used |= kPRINTF_Space;
+ break;
+ case '0':
+ flags_used |= kPRINTF_Zero;
+ break;
+ case '#':
+ flags_used |= kPRINTF_Pound;
+ break;
+ default:
+ /* We've gone one char too far. */
+ --p;
+ done = true;
+ break;
+ }
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+
+ /* Next check for minimum field width. */
+ field_width = 0;
+ done = false;
+ while (!done)
+ {
+ c = *++p;
+ if ((c >= '0') && (c <= '9'))
+ {
+ field_width = (field_width * 10) + (c - '0');
+ }
+#if PRINTF_ADVANCED_ENABLE
+ else if (c == '*')
+ {
+ field_width = (uint32_t)va_arg(ap, uint32_t);
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ else
+ {
+ /* We've gone one char too far. */
+ --p;
+ done = true;
+ }
+ }
+ /* Next check for the width and precision field separator. */
+ precision_width = 6;
+#if PRINTF_ADVANCED_ENABLE
+ valid_precision_width = false;
+#endif /* PRINTF_ADVANCED_ENABLE */
+ if (*++p == '.')
+ {
+ /* Must get precision field width, if present. */
+ precision_width = 0;
+ done = false;
+ while (!done)
+ {
+ c = *++p;
+ if ((c >= '0') && (c <= '9'))
+ {
+ precision_width = (precision_width * 10) + (c - '0');
+#if PRINTF_ADVANCED_ENABLE
+ valid_precision_width = true;
+#endif /* PRINTF_ADVANCED_ENABLE */
+ }
+#if PRINTF_ADVANCED_ENABLE
+ else if (c == '*')
+ {
+ precision_width = (uint32_t)va_arg(ap, uint32_t);
+ valid_precision_width = true;
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ else
+ {
+ /* We've gone one char too far. */
+ --p;
+ done = true;
+ }
+ }
+ }
+ else
+ {
+ /* We've gone one char too far. */
+ --p;
+ }
+#if PRINTF_ADVANCED_ENABLE
+ /*
+ * Check for the length modifier.
+ */
+ switch (/* c = */ *++p)
+ {
+ case 'h':
+ if (*++p != 'h')
+ {
+ flags_used |= kPRINTF_LengthShortInt;
+ --p;
+ }
+ else
+ {
+ flags_used |= kPRINTF_LengthChar;
+ }
+ break;
+ case 'l':
+ if (*++p != 'l')
+ {
+ flags_used |= kPRINTF_LengthLongInt;
+ --p;
+ }
+ else
+ {
+ flags_used |= kPRINTF_LengthLongLongInt;
+ }
+ break;
+ default:
+ /* we've gone one char too far */
+ --p;
+ break;
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ /* Now we're ready to examine the format. */
+ c = *++p;
+ {
+ if ((c == 'd') || (c == 'i') || (c == 'f') || (c == 'F') || (c == 'x') || (c == 'X') || (c == 'o') ||
+ (c == 'b') || (c == 'p') || (c == 'u'))
+ {
+ if ((c == 'd') || (c == 'i'))
+ {
+#if PRINTF_ADVANCED_ENABLE
+ if (flags_used & kPRINTF_LengthLongLongInt)
+ {
+ ival = (int64_t)va_arg(ap, int64_t);
+ }
+ else
+#endif /* PRINTF_ADVANCED_ENABLE */
+ {
+ ival = (int32_t)va_arg(ap, int32_t);
+ }
+ vlen = DbgConsole_ConvertRadixNumToString(vstr, &ival, true, 10, use_caps);
+ vstrp = &vstr[vlen];
+#if PRINTF_ADVANCED_ENABLE
+ if (ival < 0)
+ {
+ schar = '-';
+ ++vlen;
+ }
+ else
+ {
+ if (flags_used & kPRINTF_Plus)
+ {
+ schar = '+';
+ ++vlen;
+ }
+ else
+ {
+ if (flags_used & kPRINTF_Space)
+ {
+ schar = ' ';
+ ++vlen;
+ }
+ else
+ {
+ schar = 0;
+ }
+ }
+ }
+ dschar = false;
+ /* Do the ZERO pad. */
+ if (flags_used & kPRINTF_Zero)
+ {
+ if (schar)
+ {
+ func_ptr(schar);
+ count++;
+ }
+ dschar = true;
+
+ DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr);
+ vlen = field_width;
+ }
+ else
+ {
+ if (!(flags_used & kPRINTF_Minus))
+ {
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+ if (schar)
+ {
+ func_ptr(schar);
+ count++;
+ }
+ dschar = true;
+ }
+ }
+ /* The string was built in reverse order, now display in correct order. */
+ if ((!dschar) && schar)
+ {
+ func_ptr(schar);
+ count++;
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ }
+
+#if PRINTF_FLOAT_ENABLE
+ if ((c == 'f') || (c == 'F'))
+ {
+ fval = (double)va_arg(ap, double);
+ vlen = DbgConsole_ConvertFloatRadixNumToString(vstr, &fval, 10, precision_width);
+ vstrp = &vstr[vlen];
+
+#if PRINTF_ADVANCED_ENABLE
+ if (fval < 0)
+ {
+ schar = '-';
+ ++vlen;
+ }
+ else
+ {
+ if (flags_used & kPRINTF_Plus)
+ {
+ schar = '+';
+ ++vlen;
+ }
+ else
+ {
+ if (flags_used & kPRINTF_Space)
+ {
+ schar = ' ';
+ ++vlen;
+ }
+ else
+ {
+ schar = 0;
+ }
+ }
+ }
+ dschar = false;
+ if (flags_used & kPRINTF_Zero)
+ {
+ if (schar)
+ {
+ func_ptr(schar);
+ count++;
+ }
+ dschar = true;
+ DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr);
+ vlen = field_width;
+ }
+ else
+ {
+ if (!(flags_used & kPRINTF_Minus))
+ {
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+ if (schar)
+ {
+ func_ptr(schar);
+ count++;
+ }
+ dschar = true;
+ }
+ }
+ if ((!dschar) && schar)
+ {
+ func_ptr(schar);
+ count++;
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ }
+#endif /* PRINTF_FLOAT_ENABLE */
+ if ((c == 'X') || (c == 'x'))
+ {
+ if (c == 'x')
+ {
+ use_caps = false;
+ }
+#if PRINTF_ADVANCED_ENABLE
+ if (flags_used & kPRINTF_LengthLongLongInt)
+ {
+ uval = (uint64_t)va_arg(ap, uint64_t);
+ }
+ else
+#endif /* PRINTF_ADVANCED_ENABLE */
+ {
+ uval = (uint32_t)va_arg(ap, uint32_t);
+ }
+ vlen = DbgConsole_ConvertRadixNumToString(vstr, &uval, false, 16, use_caps);
+ vstrp = &vstr[vlen];
+
+#if PRINTF_ADVANCED_ENABLE
+ dschar = false;
+ if (flags_used & kPRINTF_Zero)
+ {
+ if (flags_used & kPRINTF_Pound)
+ {
+ func_ptr('0');
+ func_ptr((use_caps ? 'X' : 'x'));
+ count += 2;
+ /*vlen += 2;*/
+ dschar = true;
+ }
+ DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr);
+ vlen = field_width;
+ }
+ else
+ {
+ if (!(flags_used & kPRINTF_Minus))
+ {
+ if (flags_used & kPRINTF_Pound)
+ {
+ vlen += 2;
+ }
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+ if (flags_used & kPRINTF_Pound)
+ {
+ func_ptr('0');
+ func_ptr(use_caps ? 'X' : 'x');
+ count += 2;
+
+ dschar = true;
+ }
+ }
+ }
+
+ if ((flags_used & kPRINTF_Pound) && (!dschar))
+ {
+ func_ptr('0');
+ func_ptr(use_caps ? 'X' : 'x');
+ count += 2;
+ vlen += 2;
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ }
+ if ((c == 'o') || (c == 'b') || (c == 'p') || (c == 'u'))
+ {
+#if PRINTF_ADVANCED_ENABLE
+ if (flags_used & kPRINTF_LengthLongLongInt)
+ {
+ uval = (uint64_t)va_arg(ap, uint64_t);
+ }
+ else
+#endif /* PRINTF_ADVANCED_ENABLE */
+ {
+ uval = (uint32_t)va_arg(ap, uint32_t);
+ }
+ switch (c)
+ {
+ case 'o':
+ radix = 8;
+ break;
+ case 'b':
+ radix = 2;
+ break;
+ case 'p':
+ radix = 16;
+ break;
+ case 'u':
+ radix = 10;
+ break;
+ default:
+ break;
+ }
+ vlen = DbgConsole_ConvertRadixNumToString(vstr, &uval, false, radix, use_caps);
+ vstrp = &vstr[vlen];
+#if PRINTF_ADVANCED_ENABLE
+ if (flags_used & kPRINTF_Zero)
+ {
+ DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr);
+ vlen = field_width;
+ }
+ else
+ {
+ if (!(flags_used & kPRINTF_Minus))
+ {
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+ }
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ }
+#if !PRINTF_ADVANCED_ENABLE
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+#endif /* !PRINTF_ADVANCED_ENABLE */
+ if (vstrp != NULL)
+ {
+ while (*vstrp)
+ {
+ func_ptr(*vstrp--);
+ count++;
+ }
+ }
+#if PRINTF_ADVANCED_ENABLE
+ if (flags_used & kPRINTF_Minus)
+ {
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ }
+ else if (c == 'c')
+ {
+ cval = (char)va_arg(ap, uint32_t);
+ func_ptr(cval);
+ count++;
+ }
+ else if (c == 's')
+ {
+ sval = (char *)va_arg(ap, char *);
+ if (sval)
+ {
+#if PRINTF_ADVANCED_ENABLE
+ if (valid_precision_width)
+ {
+ vlen = precision_width;
+ }
+ else
+ {
+ vlen = strlen(sval);
+ }
+#else
+ vlen = strlen(sval);
+#endif /* PRINTF_ADVANCED_ENABLE */
+#if PRINTF_ADVANCED_ENABLE
+ if (!(flags_used & kPRINTF_Minus))
+#endif /* PRINTF_ADVANCED_ENABLE */
+ {
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+ }
+
+#if PRINTF_ADVANCED_ENABLE
+ if (valid_precision_width)
+ {
+ while ((*sval) && (vlen > 0))
+ {
+ func_ptr(*sval++);
+ count++;
+ vlen--;
+ }
+ /* In case that vlen sval is shorter than vlen */
+ vlen = precision_width - vlen;
+ }
+ else
+ {
+#endif /* PRINTF_ADVANCED_ENABLE */
+ while (*sval)
+ {
+ func_ptr(*sval++);
+ count++;
+ }
+#if PRINTF_ADVANCED_ENABLE
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+
+#if PRINTF_ADVANCED_ENABLE
+ if (flags_used & kPRINTF_Minus)
+ {
+ DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr);
+ }
+#endif /* PRINTF_ADVANCED_ENABLE */
+ }
+ }
+ else
+ {
+ func_ptr(c);
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+int SWO_Printf(const char *fmt_s, ...){
+ va_list ap;
+ int result;
+
+ va_start(ap, fmt_s);
+ result = SWO_PrintfFormattedData(SWO_Putchar, fmt_s, ap);
+ va_end(ap);
+
+ return result;
+}
+
+int SWO_Putchar(int c){
+ volatile int timeout;
+ /* Check if Trace Control Register (ITM->TCR at 0xE0000E80) is set */
+ if ((ITM->TCR&ITM_TCR_ITMENA_Msk) == 0) { /* check Trace Control Register if ITM trace is enabled*/
+ return -1; /* not enabled? */
+ }
+ /* Check if the requested channel stimulus port (ITM->TER at 0xE0000E00) is enabled */
+ if ((ITM->TER & (1ul<<0x00))==0) { /* check Trace Enable Register if requested port is enabled */
+ return -1; /* requested port not enabled? */
+ }
+ timeout = 5000; /* arbitrary timeout value */
+ while (ITM->PORT[0].u32 == 0) {
+ /* Wait until STIMx is ready, then send data */
+ timeout--;
+ if (timeout==0) {
+ return -1; /* not able to send */
+ }
+ }
+ ITM->PORT[0].u8 = c;
+ return 1;
+}
+#endif
diff --git a/utilities/fsl_debug_console.h b/utilities/fsl_debug_console.h
index eb716d8..d617979 100644
--- a/utilities/fsl_debug_console.h
+++ b/utilities/fsl_debug_console.h
@@ -60,6 +60,8 @@
//#define SDK_DEBUGCONSOLE 1U
#endif
+//#define USE_SWO
+
#ifdef TESTER_BUILD
#undef SDK_DEBUGCONSOLE
#endif
@@ -93,10 +95,17 @@
#define PUTCHAR DbgConsole_Putchar
#define GETCHAR DbgConsole_Getchar
#else /* Select printf, scanf, putchar, getchar of toolchain. */
+#ifdef USE_SWO
+#define PRINTF SWO_Printf
+#define SCANF(x...)
+#define PUTCHAR SWO_Putchar
+#define GETCHAR
+#else
#define PRINTF(x...)
#define SCANF(x...)
#define PUTCHAR
#define GETCHAR
+#endif
#endif /* SDK_DEBUGCONSOLE */
/*******************************************************************************
@@ -143,6 +152,12 @@ status_t DbgConsole_Init(uint32_t baseAddr, uint32_t baudRate, uint8_t device, u
*/
status_t DbgConsole_Deinit(void);
+#ifdef USE_SWO
+int SWO_Printf(const char *fmt_s, ...);
+
+int SWO_Putchar(int c);
+#endif
+
#if SDK_DEBUGCONSOLE
/*!
* @brief Writes formatted output to the standard output stream.