Files
2023-09-02 13:50:57 +08:00

692 lines
14 KiB
C

/******************************************************************************
* @file SWO.c
* @brief CMSIS-DAP SWO I/O
* @version V1.00
* @date 20. May 2015
*
* @note
* Copyright (C) 2015 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#include "DAP_config.h"
#include "DAP.h"
#if (SWO_UART != 0)
#include "Driver_USART.h"
#endif
#if (SWO_UART != 0)
#ifndef USART_PORT
#define USART_PORT 0 /* USART Port Number */
#endif
// USART Driver
#define _USART_Driver_(n) Driver_USART##n
#define USART_Driver_(n) _USART_Driver_(n)
extern ARM_DRIVER_USART USART_Driver_(USART_PORT);
#define pUSART (&USART_Driver_(USART_PORT))
static uint8_t USART_Ready;
#endif /* (SWO_UART != 0) */
#if ((SWO_UART != 0) || (SWO_MANCHESTER != 0))
// Trace State
static uint8_t TraceTransport = 0U; /* Trace Transport */
static uint8_t TraceMode = 0U; /* Trace Mode */
static uint8_t TraceStatus = 0U; /* Trace Status without Errors */
static uint8_t TraceError[2] = {0U, 0U}; /* Trace Error flags (banked) */
static uint8_t TraceError_n = 0U; /* Active Trace Error bank */
// Trace Buffer
static uint8_t TraceBuf[SWO_BUFFER_SIZE]; /* Trace Buffer (must be 2^n) */
static volatile uint32_t TraceIn = 0U; /* Incoming Trace Index */
static volatile uint32_t TraceOut = 0U; /* Outgoing Trace Index */
static volatile uint32_t TracePending = 0U; /* Pending Trace Count */
// Trace Helper functions
static void ClearTrace(void);
static uint32_t GetTraceSpace(void);
static uint32_t GetTraceCount(void);
static uint8_t GetTraceStatus(void);
static void SetTraceError(uint8_t flag);
#if (SWO_UART != 0)
// USART Driver Callback function
// event: event mask
static void USART_Callback(uint32_t event)
{
uint32_t count;
if (event & ARM_USART_EVENT_RECEIVE_COMPLETE)
{
TracePending = 0U;
TraceIn += pUSART->GetRxCount();
count = GetTraceSpace();
if (count != 0U)
{
pUSART->Receive(&TraceBuf[TraceIn & (SWO_BUFFER_SIZE - 1U)], count);
}
else
{
TraceStatus = DAP_SWO_CAPTURE_ACTIVE | DAP_SWO_CAPTURE_PAUSED;
}
}
if (event & ARM_USART_EVENT_RX_OVERFLOW)
{
SetTraceError(DAP_SWO_BUFFER_OVERRUN);
}
if (event & (ARM_USART_EVENT_RX_BREAK |
ARM_USART_EVENT_RX_FRAMING_ERROR |
ARM_USART_EVENT_RX_PARITY_ERROR))
{
SetTraceError(DAP_SWO_STREAM_ERROR);
}
}
// Enable or disable UART SWO Mode
// enable: enable flag
// return: 1 - Success, 0 - Error
__weak uint32_t UART_SWO_Mode(uint32_t enable)
{
int32_t status;
USART_Ready = 0U;
if (enable)
{
status = pUSART->Initialize(USART_Callback);
if (status != ARM_DRIVER_OK)
{
return (0U);
}
status = pUSART->PowerControl(ARM_POWER_FULL);
if (status != ARM_DRIVER_OK)
{
pUSART->Uninitialize();
return (0U);
}
}
else
{
pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U);
pUSART->PowerControl(ARM_POWER_OFF);
pUSART->Uninitialize();
}
return (1U);
}
// Configure UART SWO Baudrate
// baudrate: requested baudrate
// return: actual baudrate or 0 when not configured
__weak uint32_t UART_SWO_Baudrate(uint32_t baudrate)
{
int32_t status;
uint32_t count;
if (baudrate > SWO_UART_MAX_BAUDRATE)
{
baudrate = SWO_UART_MAX_BAUDRATE;
}
if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE)
{
pUSART->Control(ARM_USART_CONTROL_RX, 0U);
if (pUSART->GetStatus().rx_busy)
{
TracePending = 0U;
TraceIn += pUSART->GetRxCount();
pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U);
}
}
status = pUSART->Control(ARM_USART_MODE_ASYNCHRONOUS |
ARM_USART_DATA_BITS_8 |
ARM_USART_PARITY_NONE |
ARM_USART_STOP_BITS_1,
baudrate);
if (status == ARM_DRIVER_OK)
{
USART_Ready = 1U;
}
else
{
USART_Ready = 0U;
baudrate = 0U;
}
if ((TraceStatus & DAP_SWO_CAPTURE_ACTIVE) && USART_Ready)
{
pUSART->Control(ARM_USART_CONTROL_RX, 1U);
count = GetTraceSpace();
if (count != 0U)
{
pUSART->Receive(&TraceBuf[TraceIn & (SWO_BUFFER_SIZE - 1U)], count);
}
else
{
TraceStatus = DAP_SWO_CAPTURE_ACTIVE | DAP_SWO_CAPTURE_PAUSED;
}
}
return (baudrate);
}
// Control UART SWO Capture
// active: active flag
// return: 1 - Success, 0 - Error
__weak uint32_t UART_SWO_Control(uint32_t active)
{
int32_t status;
if (active)
{
if (!USART_Ready)
{
return (0U);
}
status = pUSART->Control(ARM_USART_CONTROL_RX, 1U);
if (status != ARM_DRIVER_OK)
{
return (0U);
}
status = pUSART->Receive(TraceBuf, SWO_BUFFER_SIZE);
if (status != ARM_DRIVER_OK)
{
return (0U);
}
}
else
{
pUSART->Control(ARM_USART_CONTROL_RX, 0U);
if (pUSART->GetStatus().rx_busy)
{
TracePending = 0U;
TraceIn += pUSART->GetRxCount();
pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U);
}
}
return (1U);
}
// Start UART SWO Capture
// buf: pointer to buffer for capturing
// count: number of bytes to capture
__weak void UART_SWO_Capture(uint8_t *buf, uint32_t count)
{
pUSART->Receive(buf, count);
}
// Update UART SWO Trace Info
__weak void UART_SWO_Update(void)
{
TracePending = pUSART->GetRxCount();
}
#endif /* (SWO_UART != 0) */
#if (SWO_MANCHESTER != 0)
// Enable or disable Manchester SWO Mode
// enable: enable flag
// return: 1 - Success, 0 - Error
__weak uint32_t Manchester_SWO_Mode(uint32_t enable)
{
return (0U);
}
// Configure Manchester SWO Baudrate
// baudrate: requested baudrate
// return: actual baudrate or 0 when not configured
__weak uint32_t Manchester_SWO_Baudrate(uint32_t baudrate)
{
return (0U);
}
// Control Manchester SWO Capture
// active: active flag
// return: 1 - Success, 0 - Error
__weak uint32_t Manchester_SWO_Control(uint32_t active)
{
return (0U);
}
// Start Manchester SWO Capture
// buf: pointer to buffer for capturing
// count: number of bytes to capture
__weak void Manchester_SWO_Capture(uint8_t *buf, uint32_t count)
{
}
// Update Manchester SWO Trace Info
__weak void Manchester_SWO_Update(void)
{
}
#endif /* (SWO_MANCHESTER != 0) */
// Clear Trace Errors and Data
static void ClearTrace(void)
{
TraceError[0] = 0U;
TraceError[1] = 0U;
TraceError_n = 0U;
TraceIn = 0U;
TraceOut = 0U;
TracePending = 0U;
}
// Get Trace Space
// return: number of contiguous free bytes in trace buffer
static uint32_t GetTraceSpace(void)
{
uint32_t index;
uint32_t limit;
uint32_t count;
index = TraceIn & (SWO_BUFFER_SIZE - 1U);
limit = SWO_BUFFER_SIZE - index;
count = SWO_BUFFER_SIZE - (TraceIn - TraceOut);
if (count > limit)
{
count = limit;
}
return (count);
}
// Get Trace Count
// return: number of available data bytes in trace buffer
static uint32_t GetTraceCount(void)
{
uint32_t count;
if (TraceStatus == DAP_SWO_CAPTURE_ACTIVE)
{
count = (TraceIn - TraceOut) + TracePending;
if (TracePending == 0U)
{
count = TraceIn - TraceOut;
}
}
else
{
count = TraceIn - TraceOut;
}
return (count);
}
// Get Trace Status (clear Error flags)
// return: Trace Status (Active flag and Error flags)
static uint8_t GetTraceStatus(void)
{
uint8_t status;
uint32_t n;
n = TraceError_n;
TraceError_n ^= 1U;
status = TraceStatus | TraceError[n];
TraceError[n] = 0U;
return (status);
}
// Set Trace Error flag(s)
// flag: error flag(s) to set
static void SetTraceError(uint8_t flag)
{
TraceError[TraceError_n] |= flag;
}
// Process SWO Transport command and prepare response
// request: pointer to request data
// response: pointer to response data
// return: number of bytes in response (lower 16 bits)
// number of bytes in request (upper 16 bits)
uint32_t SWO_Transport(const uint8_t *request, uint8_t *response)
{
uint8_t transport;
uint32_t result;
if (!(TraceStatus & DAP_SWO_CAPTURE_ACTIVE))
{
transport = *request;
switch (transport)
{
case 0:
case 1:
TraceTransport = transport;
result = 1U;
break;
default:
result = 0U;
break;
}
}
else
{
result = 0U;
}
if (result != 0U)
{
*response = DAP_OK;
}
else
{
*response = DAP_ERROR;
}
return ((1U << 16) | 1U);
}
// Process SWO Mode command and prepare response
// request: pointer to request data
// response: pointer to response data
// return: number of bytes in response (lower 16 bits)
// number of bytes in request (upper 16 bits)
uint32_t SWO_Mode(const uint8_t *request, uint8_t *response)
{
uint8_t mode;
uint32_t result;
mode = *request;
switch (TraceMode)
{
#if (SWO_UART != 0)
case DAP_SWO_UART:
UART_SWO_Mode(0U);
break;
#endif
#if (SWO_MANCHESTER != 0)
case DAP_SWO_MANCHESTER:
Manchester_SWO_Mode(0U);
break;
#endif
default:
break;
}
switch (mode)
{
case DAP_SWO_OFF:
result = 1U;
break;
#if (SWO_UART != 0)
case DAP_SWO_UART:
result = UART_SWO_Mode(1U);
break;
#endif
#if (SWO_MANCHESTER != 0)
case DAP_SWO_MANCHESTER:
result = Manchester_SWO_Mode(1U);
break;
#endif
default:
result = 0U;
break;
}
if (result != 0U)
{
TraceMode = mode;
}
else
{
TraceMode = DAP_SWO_OFF;
}
TraceStatus = 0U;
ClearTrace();
if (result != 0U)
{
*response = DAP_OK;
}
else
{
*response = DAP_ERROR;
}
return ((1U << 16) | 1U);
}
// Process SWO Baudrate command and prepare response
// request: pointer to request data
// response: pointer to response data
// return: number of bytes in response (lower 16 bits)
// number of bytes in request (upper 16 bits)
uint32_t SWO_Baudrate(const uint8_t *request, uint8_t *response)
{
uint32_t baudrate;
baudrate = (*(request + 0) << 0) |
(*(request + 1) << 8) |
(*(request + 2) << 16) |
(*(request + 3) << 24);
switch (TraceMode)
{
#if (SWO_UART != 0)
case DAP_SWO_UART:
baudrate = UART_SWO_Baudrate(baudrate);
break;
#endif
#if (SWO_MANCHESTER != 0)
case DAP_SWO_MANCHESTER:
baudrate = Manchester_SWO_Baudrate(baudrate);
break;
#endif
default:
baudrate = 0U;
break;
}
if (baudrate == 0U)
{
TraceStatus = 0U;
}
*response++ = (uint8_t)(baudrate >> 0);
*response++ = (uint8_t)(baudrate >> 8);
*response++ = (uint8_t)(baudrate >> 16);
*response = (uint8_t)(baudrate >> 24);
return ((4U << 16) | 4U);
}
// Process SWO Control command and prepare response
// request: pointer to request data
// response: pointer to response data
// return: number of bytes in response (lower 16 bits)
// number of bytes in request (upper 16 bits)
uint32_t SWO_Control(const uint8_t *request, uint8_t *response)
{
uint8_t active;
uint32_t result;
active = *request & DAP_SWO_CAPTURE_ACTIVE;
if (active != (TraceStatus & DAP_SWO_CAPTURE_ACTIVE))
{
if (active)
{
ClearTrace();
}
switch (TraceMode)
{
#if (SWO_UART != 0)
case DAP_SWO_UART:
result = UART_SWO_Control(active);
break;
#endif
#if (SWO_MANCHESTER != 0)
case DAP_SWO_MANCHESTER:
result = Manchester_SWO_Control(active);
break;
#endif
default:
result = 0U;
break;
}
if (result != 0U)
{
TraceStatus = active;
}
}
else
{
result = 1U;
}
if (result != 0U)
{
*response = DAP_OK;
}
else
{
*response = DAP_ERROR;
}
return ((1U << 16) | 1U);
}
// Process SWO Status command and prepare response
// response: pointer to response data
// return: number of bytes in response
uint32_t SWO_Status(uint8_t *response)
{
uint8_t status;
uint32_t count;
if (TraceStatus == DAP_SWO_CAPTURE_ACTIVE)
{
switch (TraceMode)
{
#if (SWO_UART != 0)
case DAP_SWO_UART:
UART_SWO_Update();
break;
#endif
#if (SWO_MANCHESTER != 0)
case DAP_SWO_MANCHESTER:
Manchester_SWO_Update();
break;
#endif
default:
break;
}
}
status = GetTraceStatus();
count = GetTraceCount();
*response++ = status;
*response++ = (uint8_t)(count >> 0);
*response++ = (uint8_t)(count >> 8);
*response++ = (uint8_t)(count >> 16);
*response = (uint8_t)(count >> 24);
return (5U);
}
// Process SWO Data command and prepare response
// request: pointer to request data
// response: pointer to response data
// return: number of bytes in response (lower 16 bits)
// number of bytes in request (upper 16 bits)
uint32_t SWO_Data(const uint8_t *request, uint8_t *response)
{
uint8_t status;
uint32_t count;
uint32_t n;
if (TraceStatus == DAP_SWO_CAPTURE_ACTIVE)
{
switch (TraceMode)
{
#if (SWO_UART != 0)
case DAP_SWO_UART:
UART_SWO_Update();
break;
#endif
#if (SWO_MANCHESTER != 0)
case DAP_SWO_MANCHESTER:
Manchester_SWO_Update();
break;
#endif
default:
break;
}
}
status = GetTraceStatus();
count = GetTraceCount();
if (TraceTransport == 1U)
{
n = (*(request + 0) << 0) |
(*(request + 1) << 8);
}
else
{
n = 0U;
}
if (count > n)
{
count = n;
}
*response++ = status;
*response++ = (uint8_t)(count >> 0);
*response++ = (uint8_t)(count >> 8);
for (n = count; n; n--)
{
*response++ = TraceBuf[TraceOut++ & (SWO_BUFFER_SIZE - 1U)];
}
if (TraceStatus == (DAP_SWO_CAPTURE_ACTIVE | DAP_SWO_CAPTURE_PAUSED))
{
n = GetTraceSpace();
if (n != 0U)
{
switch (TraceMode)
{
#if (SWO_UART != 0)
case DAP_SWO_UART:
UART_SWO_Capture(&TraceBuf[TraceIn & (SWO_BUFFER_SIZE - 1U)], n);
TraceStatus = DAP_SWO_CAPTURE_ACTIVE;
break;
#endif
#if (SWO_MANCHESTER != 0)
case DAP_SWO_MANCHESTER:
Manchester_SWO_Capture(&TraceBuf[TraceIn & (SWO_BUFFER_SIZE - 1U)], n);
TraceStatus = DAP_SWO_CAPTURE_ACTIVE;
break;
#endif
default:
break;
}
}
}
return ((2U << 16) | (3U + count));
}
#endif /* ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) */