This builds on the example Blinky and adds printf like output via the SWO pin. Download the example BlinkySWO.zip which contains a readme describing each file in the package.
Code
Source code for outputting via the SWO pin
#include <nrf.h>
#include "nrf_delay.h"
#include "sdk_errors.h"
#include "main.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
//
// The BLE652 has an external 32Mhz crystal that is converted internally
// in the nrf52832 to a 64Mhz clock.
//
// Try 64000000 but if its unstable slow down to 32000000
//
#define CPU_CORE_FREQUENCY_HZ 32000000 /* CPU core frequency in Hz */
//
// Use port 0 of the ITM
//
#define ITM_PORT_NUMBER 0
//
// Initialise the SWO trace port
//
// Must compile the whole project with the define ENABLE_SWO set
// (-DENABLE_SWO)
//
void SWOInit()
{
//
// CPU_CORE_FREQUENCY_HZ is expected to
// match the CPU core clock
//
uint32_t portBits = 1<<ITM_PORT_NUMBER;
uint32_t SWORequestedBaudRate = 57600; // default 64k baud rate
uint32_t SWOPrescaler = (CPU_CORE_FREQUENCY_HZ/SWORequestedBaudRate)+1;
//
// On Nordic devices, CoreDebug is defined in core_cm*.h
// (where * is the version of processor so for a Cortex M4
// the file would be core_cm4.h) Just replace with addresses
// of the registers on non Nordic devices:
//
// CoreDebug->DEMCR is just the address of the DEMCR register
// on the ARM core (0xE000EDFC)
// Same for DWT (0xE0001000), ITM (0xE0000000) and TPI
// (0xE0040000). These are the base addresses
// for the respective registers.
//
// Enable tracing
//
CoreDebug->DEMCR = CoreDebug_DEMCR_TRCENA_Msk;
//
// TPI
// Set the baud rate. This is a function of
// core frequency / desired baud rate
// Output in format suitable for a UART.
// 0x01: Manchester. 0x02 UART/NRZ.
//
TPI->ACPR = SWOPrescaler;
TPI->SPPR = 0x2;
TPI->FFCR = 0x00000100;
//
// ITM
// Via the LAR, enable write access to the ITM registers
// and set the TCR,TPR and TER
//
ITM->LAR = 0xC5ACCE55;
ITM->TCR = ITM_TCR_TraceBusID_Msk | ITM_TCR_SWOENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_ITMENA_Msk;
ITM->TPR = ITM_TPR_PRIVMASK_Msk;
ITM->TER = portBits;
//
// DWT register
//
DWT->CTRL = 0x400003FE;
}
//
// Checks if tracing is enabled on the supplied port
//
bool CheckTraceEnabled()
{
//
// Check if tracing is enabled:
// Check tracing enabled in the TCR and also for the supplied port
//
bool traceEnabled = (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0) && ((ITM->TER & (0x1 << ITM_PORT_NUMBER)) != 0)) ? true : false;
return traceEnabled;
}
//
// Output a character over the SWO pin
//
bool SWOPrintChar(char currentChar)
{
//
// Spin wait waiting for the port to have emptied.
// 5000 is an arbitrary timeout value
//
bool printChar = true;
const int maxTimeoutValue = 5000;
volatile int timeout = maxTimeoutValue;
while (ITM->PORT[ITM_PORT_NUMBER].u32 == 0)
{
if (timeout == 0)
{
//
// Timeout, unable to send
//
printChar = false;
break;
}
timeout--;
}
if(printChar)
{
ITM->PORT[ITM_PORT_NUMBER].u8 = (uint8_t)currentChar;
}
return printChar;
}
//
// Display a formatted string.
//
void SWOPrintString(const char* pFmt,...)
{
//
// Check tracing is enabled
//
if(CheckTraceEnabled(ITM_PORT_NUMBER))
{
//
// Build the string
//
const int maxSWOBuffer = 256;
char swoBuffer[maxSWOBuffer+1];
va_list vArgs;
va_start(vArgs, pFmt);
vsprintf(swoBuffer,pFmt,vArgs);
va_end(vArgs);
//
// Output it over the SWO pin character by character
//
uint32_t logMsgLen = strlen(swoBuffer);
for(uint32_t ndx=0;ndx<logMsgLen;ndx++)
{
SWOPrintChar(swoBuffer[ndx]);
}
SWOPrintChar('\n');
}
}
At the start of main() add the line below. This will enable output over the SWO pin:
SWOInit();
Now whenever you want to output text you can do this in the same manner as you would from a desktop application via printf:
SWOPrintString("Hello %s %d",someString, someInteger);
main.cpp
Add calls to SWOInit() and SWOPrintString() to main. Main now looks like:
//
// Required includes.
// Defining BOARD_CUSTOM awill cause boards.h to include custom_board.h
// which contains the hardware definitions for the board this program
// is intended for. In particular, custom_board.h defines which GPIO
// the LED is on.
//
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "nrf_delay.h"
#include "boards.h"
#include "main.h"
//
// Main entry point
//
int main()
{
//
// Initialise the board.
//
nrf_gpio_cfg_output(LED_A);
//
// Enable SWO output
//
SWOInit();
SWOPrintString("SWO enabled. Start flashing the LED...");
//
// Loop forever toggling the led ON/OFF
//
unsigned int loopCount = 0;
bool setOn = true;
while (true)
{
if(setOn)
{
nrf_gpio_pin_set(LED_A);
}
else
{
nrf_gpio_pin_clear(LED_A);
}
SWOPrintString("[%10u] LED %s\n",++loopCount,setOn ? "On" : "Off");
setOn = setOn ? false : true;
nrf_delay_ms(500);
}
}
Building and Flashing the Program
Any toolchain/programmer can be used for these steps. All the examples here are built using make and gcc. The binary is flashed using the Raspberry Pi networked programmer. See here for how to set up make, gcc and the Raspberry Pi networked programmer.
Building
From the terminal type:
C:\Projects\BlinkySWO> "c:\Program Files (x86)\GnuWin32\bin\make.exe" -f makefile CONFIG=Debug all
If there are no errors then the binary blinkyswo.elf should be output to the sub-folder bin\debug
Flashing the Binary to the Microcontroller
Hooking up the Programmer to the Microcontroller
See here for how to connect the programmer to the microcontroller.
Flashing
From a terminal type:
C:\Projects\BlinkySWO> "C:\Program Files\NoSMD\SWorD\bin\SWorDProgrammer.exe" -program:bin\debug\blinkyswo.elf -probe:rpi4programmer -pagesize:4096
Attempting to connect to rpi4programmer on 192.168.0.26::33332...
Connected to rpi4programmer on 192.168.0.26::33332...
Progress 100%
Completed with success
C:\Projects\BlinkySWO>
If all is well you should now see the LED blinking.
Viewing the output from the SWO pin
Now start the SWO display application SWorDSWO.exe and you should see it connect to the programmer:
C:\Projects\BlinkySWO> "C:\Program Files\NoSMD\SWorD\bin\SWorDSWO.exe" -probe:rpi4programmer
SWorDSWO V20200615 part of the SWorD SWD programmer
Copyright(C) 2020 NoSMD
This program comes with ABSOLUTELY NO WARRANTY; See COPYING.
This is free software, and you are welcome to redistribute it.
Searching for rpi4programmer... ...please wait.
Attempting to connect to rpi4programmer on 192.168.1.102::33334...
Connected to rpi4programmer on 192.168.1.102::33334...
You should now see printf like output coming from the SWO pin.
SWO enabled. Start flashing the LED...
[ 1] LED On
[ 2] LED Off
[ 3] LED On
[ 4] LED Off
[ 5] LED On
[ 6] LED Off
[ 7] LED On
0 Comments