Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature-hal-itm] Instrumented Trace Macrocell HAL API for SWO debug output #5956

Merged
merged 3 commits into from Feb 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 71 additions & 0 deletions drivers/SerialWireOutput.h
@@ -0,0 +1,71 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#if defined(DEVICE_ITM)

#include "hal/itm_api.h"
#include "platform/FileHandle.h"

class SerialWireOutput : public FileHandle {
public:
SerialWireOutput(void)
{
/* Initialize ITM using internal init function. */
mbed_itm_init();
}

virtual ssize_t write(const void *buffer, size_t size)
{
const unsigned char *buf = static_cast<const unsigned char *>(buffer);

/* Send buffer one character at a time over the ITM SWO port */
for (size_t i = 0; i < size; i++) {
mbed_itm_send(ITM_PORT_SWO, buf[i]);
}
return size;
}

virtual ssize_t read(void *buffer, size_t size)
{
/* Reading is not supported by this file handle */
return -EBADF;
}

virtual off_t seek(off_t offset, int whence = SEEK_SET)
{
/* Seeking is not support by this file handler */
return -ESPIPE;
}

virtual off_t size()
{
/* Size is not defined for this file handle */
return -EINVAL;
}

virtual int isatty()
{
/* File handle is used for terminal output */
return true;
}

virtual int close()
{
return 0;
}
};

#endif
91 changes: 91 additions & 0 deletions hal/itm_api.h
@@ -0,0 +1,91 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef MBED_ITM_API_H
#define MBED_ITM_API_H

#if defined(DEVICE_ITM)

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup hal_itm_port ITM Stimulus Ports
*
* @{
*/

enum {
ITM_PORT_SWO = 0
};

/**@}*/

/**
* \defgroup itm_hal Instrumented Trace Macrocell HAL API
* @{
*/

/**
* @brief Target specific initialization function.
* This function is responsible for initializing and configuring
* the debug clock for the ITM and setting up the SWO pin for
* debug output.
*
* The only Cortex-M register that should be modified is the clock
* prescaler in TPI->ACPR.
*
* The generic mbed_itm_init initialization function will setup:
*
* ITM->LAR
* ITM->TPR
* ITM->TCR
* ITM->TER
* TPI->SPPR
* TPI->FFCR
* DWT->CTRL
*
* for SWO output on stimulus port 0.
*/
void itm_init(void);

/**
* @brief Initialization function for both generic registers and target specific clock and pin.
*/
void mbed_itm_init(void);

/**
* @brief Send data over ITM stimulus port.
*
* @param[in] port The stimulus port to send data over.
* @param[in] data The data to send.
*
* @return value of data sent.
*/
uint32_t mbed_itm_send(uint32_t port, uint32_t data);

/**@}*/

#ifdef __cplusplus
}
#endif

#endif

#endif /* MBED_ITM_API_H */
87 changes: 87 additions & 0 deletions hal/mbed_itm_api.c
@@ -0,0 +1,87 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#if defined(DEVICE_ITM)

#include "hal/itm_api.h"
#include "cmsis.h"

#include <stdbool.h>

#define ITM_ENABLE_WRITE 0xC5ACCE55

#define SWO_NRZ 0x02
#define SWO_STIMULUS_PORT 0x01

void mbed_itm_init(void)
{
static bool do_init = true;

if (do_init) {
do_init = false;

itm_init();

/* Enable write access to ITM registers. */
ITM->LAR = ITM_ENABLE_WRITE;

/* Trace Port Interface Selected Pin Protocol Register. */
TPI->SPPR = (SWO_NRZ << TPI_SPPR_TXMODE_Pos);

/* Trace Port Interface Formatter and Flush Control Register */
TPI->FFCR = (1 << TPI_FFCR_TrigIn_Pos);

/* Data Watchpoint and Trace Control Register */
DWT->CTRL = (1 << DWT_CTRL_CYCTAP_Pos) |
(0xF << DWT_CTRL_POSTINIT_Pos) |
(0xF << DWT_CTRL_POSTPRESET_Pos) |
(1 << DWT_CTRL_CYCCNTENA_Pos);

/* Trace Privilege Register.
* Disable access to trace channel configuration from non-privileged mode.
*/
ITM->TPR = 0x0;

/* Trace Control Register */
ITM->TCR = (1 << ITM_TCR_TraceBusID_Pos) |
(1 << ITM_TCR_DWTENA_Pos) |
(1 << ITM_TCR_SYNCENA_Pos) |
(1 << ITM_TCR_ITMENA_Pos);

/* Trace Enable Register */
ITM->TER = SWO_STIMULUS_PORT;
}
}

uint32_t mbed_itm_send(uint32_t port, uint32_t data)
{
/* Check if ITM and port is enabled */
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
((ITM->TER & (1UL << port) ) != 0UL) ) /* ITM Port enabled */
{
/* write data to port */
ITM->PORT[port].u32 = data;

/* Wait until data has been clocked out */
while (ITM->PORT[port].u32 == 0UL) {
__NOP();
}
}

return data;
}

#endif // defined(DEVICE_ITM)
44 changes: 44 additions & 0 deletions targets/TARGET_NORDIC/TARGET_NRF5/itm_api.c
@@ -0,0 +1,44 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#if defined(DEVICE_ITM)

#include "hal/itm_api.h"

#include "nrf.h"
#include "nrf5x_lf_clk_helper.h"

/* SWO frequency: 4000 kHz */
void itm_init(void)
{
/* Enable SWO trace functionality */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos;

/* set SWO clock speed to 4 MHz */
NRF_CLOCK->TRACECONFIG = (NRF_CLOCK->TRACECONFIG & ~CLOCK_TRACECONFIG_TRACEPORTSPEED_Msk) |
(CLOCK_TRACECONFIG_TRACEPORTSPEED_4MHz << CLOCK_TRACECONFIG_TRACEPORTSPEED_Pos);

/* set SWO pin */
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);

/* set prescaler */
TPI->ACPR = 0;
}

#endif