2892 lines
77 KiB
C
2892 lines
77 KiB
C
/***************************************************************************
|
|
*
|
|
* Copyright 2015-2019 BES.
|
|
* All rights reserved. All unpublished rights reserved.
|
|
*
|
|
* No part of this work may be used or reproduced in any form or by any
|
|
* means, or stored in a database or retrieval system, without prior written
|
|
* permission of BES.
|
|
*
|
|
* Use of this work is governed by a license granted by BES.
|
|
* This work contains confidential and proprietary information of
|
|
* BES. which is protected by copyright, trade secret,
|
|
* trademark and other intellectual property rights.
|
|
*
|
|
****************************************************************************/
|
|
#if !(defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
// Implement a local copy of dummy trace functions for library linking (which
|
|
// might be built with DEBUG enabled)
|
|
#define TRACE_FUNC_SPEC
|
|
#endif
|
|
#include "hal_trace.h"
|
|
#include "cmsis_nvic.h"
|
|
#ifdef RTOS
|
|
#include "cmsis_os.h"
|
|
#endif
|
|
#include "hal_bootmode.h"
|
|
#include "hal_chipid.h"
|
|
#include "hal_cmu.h"
|
|
#include "hal_codec.h"
|
|
#include "hal_dma.h"
|
|
#include "hal_iomux.h"
|
|
#include "hal_location.h"
|
|
#include "hal_memsc.h"
|
|
#include "hal_sysfreq.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_uart.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
|
|
#ifdef CORE_DUMP
|
|
#include "CrashCatcherApi.h"
|
|
#endif
|
|
|
|
extern const char sys_build_info[];
|
|
extern void nv_record_flash_flush(void);
|
|
|
|
#ifdef FAULT_DUMP
|
|
void hal_trace_fault_dump(const uint32_t *regs, const uint32_t *extra,
|
|
uint32_t extra_len);
|
|
#ifndef __ARM_ARCH_ISA_ARM
|
|
static void hal_trace_fault_handler(void);
|
|
#endif
|
|
#endif
|
|
|
|
#if !(defined(ROM_BUILD) || defined(PROGRAMMER))
|
|
#define ASSERT_MUTE_CODEC
|
|
#define CRASH_DUMP_ENABLE
|
|
#if !(defined(NO_TRACE_TIME_STAMP) || defined(AUDIO_DEBUG_V0_1_0))
|
|
#define TRACE_TIME_STAMP
|
|
#endif
|
|
#if (defined(DUMP_LOG_ENABLE) || defined(DUMP_CRASH_ENABLE))
|
|
#define TRACE_TO_APP
|
|
#endif
|
|
#ifdef CHIP_HAS_CP
|
|
#define CP_TRACE_ENABLE
|
|
#endif
|
|
#endif
|
|
|
|
#define TRACE_IDLE_OUTPUT 0
|
|
|
|
#ifndef TRACE_BAUD_RATE
|
|
#define TRACE_BAUD_RATE (921600)
|
|
#endif
|
|
|
|
#ifndef TRACE_BUF_SIZE
|
|
#ifdef AUDIO_DEBUG
|
|
#define TRACE_BUF_SIZE (6 * 1024)
|
|
#else
|
|
#define TRACE_BUF_SIZE (4 * 1024)
|
|
#endif
|
|
#endif
|
|
|
|
#define CRASH_BUF_SIZE 100
|
|
#define CRASH_BUF_ATTR ALIGNED(4) USED
|
|
|
|
#ifndef TRACE_STACK_DUMP_PREV_WORD
|
|
#define TRACE_STACK_DUMP_PREV_WORD 16
|
|
#endif
|
|
#ifndef TRACE_STACK_DUMP_WORD
|
|
#define TRACE_STACK_DUMP_WORD 32
|
|
#endif
|
|
#ifndef TRACE_BACKTRACE_NUM
|
|
#define TRACE_BACKTRACE_NUM 20
|
|
#endif
|
|
#ifndef TRACE_BACKTRACE_SEARCH_WORD
|
|
#define TRACE_BACKTRACE_SEARCH_WORD 1024
|
|
#endif
|
|
|
|
#define STACK_DUMP_CNT_PER_LEN 4
|
|
#define STACK_DUMP_CNT_PREV \
|
|
((TRACE_STACK_DUMP_PREV_WORD + STACK_DUMP_CNT_PER_LEN - 1) / \
|
|
STACK_DUMP_CNT_PER_LEN * STACK_DUMP_CNT_PER_LEN)
|
|
#define STACK_DUMP_CNT \
|
|
((TRACE_STACK_DUMP_WORD + STACK_DUMP_CNT_PER_LEN - 1) / \
|
|
STACK_DUMP_CNT_PER_LEN * STACK_DUMP_CNT_PER_LEN)
|
|
|
|
#define TRACE_FLUSH_TIMEOUT MS_TO_TICKS(2000)
|
|
|
|
#define TRACE_NEAR_FULL_THRESH 200
|
|
|
|
#define TRACE_CRLF
|
|
|
|
#ifdef TRACE_CRLF
|
|
#define NEW_LINE_STR "\r\n"
|
|
#else
|
|
#define NEW_LINE_STR "\n"
|
|
#endif
|
|
|
|
#define HAL_TRACE_ASSERT_ID 0xBE57AAAA
|
|
#define HAL_TRACE_EXCEPTION_ID 0xBE57EEEE
|
|
|
|
#define HAL_MEMSC_ID_TRACE HAL_MEMSC_ID_0
|
|
|
|
#define TRACE_BUF_LOC SYNC_FLAGS_LOC
|
|
|
|
struct ASSERT_INFO_T {
|
|
uint32_t ID;
|
|
uint32_t CPU_ID;
|
|
const char *FILE;
|
|
const char *FUNC;
|
|
uint32_t LINE;
|
|
const char *FMT;
|
|
uint32_t R[15];
|
|
#ifndef __ARM_ARCH_ISA_ARM
|
|
uint32_t MSP;
|
|
uint32_t PSP;
|
|
uint32_t CONTROL;
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
uint32_t MSPLIM;
|
|
uint32_t PSPLIM;
|
|
#endif
|
|
#endif
|
|
};
|
|
|
|
struct EXCEPTION_INFO_T {
|
|
uint32_t ID;
|
|
uint32_t CPU_ID;
|
|
const uint32_t *REGS;
|
|
#ifdef __ARM_ARCH_ISA_ARM
|
|
const uint32_t *extra;
|
|
uint32_t extra_len;
|
|
#else
|
|
uint32_t MSP;
|
|
uint32_t PSP;
|
|
uint8_t PRIMASK;
|
|
uint8_t FAULTMASK;
|
|
uint8_t BASEPRI;
|
|
uint8_t CONTROL;
|
|
uint32_t ICSR;
|
|
uint32_t AIRCR;
|
|
uint32_t SCR;
|
|
uint32_t CCR;
|
|
uint32_t SHCSR;
|
|
uint32_t CFSR;
|
|
uint32_t HFSR;
|
|
uint32_t AFSR;
|
|
uint32_t MMFAR;
|
|
uint32_t BFAR;
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
uint32_t MSPLIM;
|
|
uint32_t PSPLIM;
|
|
#endif
|
|
#endif
|
|
};
|
|
|
|
static CRASH_BUF_ATTR char crash_buf[CRASH_BUF_SIZE];
|
|
|
|
STATIC_ASSERT(sizeof(crash_buf) >= sizeof(((struct ASSERT_INFO_T *)0)->R),
|
|
"crash_buf too small to hold assert registers");
|
|
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
|
|
struct HAL_TRACE_BUF_T {
|
|
unsigned char buf[TRACE_BUF_SIZE];
|
|
unsigned short wptr;
|
|
unsigned short rptr;
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
unsigned short sends[2];
|
|
#endif
|
|
unsigned short discards;
|
|
bool sending;
|
|
bool in_trace;
|
|
bool wrapped;
|
|
};
|
|
|
|
STATIC_ASSERT(TRACE_BUF_SIZE <
|
|
(1 << (8 * sizeof(((struct HAL_TRACE_BUF_T *)0)->wptr))),
|
|
"TRACE_BUF_SIZE is too large to fit in wptr/rptr variable");
|
|
|
|
static const struct HAL_UART_CFG_T uart_cfg = {
|
|
.parity = HAL_UART_PARITY_NONE,
|
|
.stop = HAL_UART_STOP_BITS_1,
|
|
.data = HAL_UART_DATA_BITS_8,
|
|
.flow = HAL_UART_FLOW_CONTROL_NONE, // HAL_UART_FLOW_CONTROL_RTSCTS,
|
|
.tx_level = HAL_UART_FIFO_LEVEL_1_2,
|
|
.rx_level = HAL_UART_FIFO_LEVEL_1_2,
|
|
.baud = TRACE_BAUD_RATE,
|
|
#ifdef HAL_TRACE_RX_ENABLE
|
|
.dma_rx = true,
|
|
#else
|
|
.dma_rx = false,
|
|
#endif
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
.dma_tx = true,
|
|
#else
|
|
.dma_tx = false,
|
|
#endif
|
|
.dma_rx_stop_on_err = false,
|
|
};
|
|
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
static const enum HAL_DMA_PERIPH_T uart_periph[] = {
|
|
HAL_GPDMA_UART0_TX,
|
|
#if (CHIP_HAS_UART > 1)
|
|
HAL_GPDMA_UART1_TX,
|
|
#endif
|
|
#if (CHIP_HAS_UART > 2)
|
|
HAL_GPDMA_UART2_TX,
|
|
#endif
|
|
};
|
|
|
|
static const struct HAL_UART_CFG_T uart_rx_enable_cfg = {
|
|
.parity = HAL_UART_PARITY_NONE,
|
|
.stop = HAL_UART_STOP_BITS_1,
|
|
.data = HAL_UART_DATA_BITS_8,
|
|
.flow = HAL_UART_FLOW_CONTROL_NONE, // HAL_UART_FLOW_CONTROL_RTSCTS,
|
|
.tx_level = HAL_UART_FIFO_LEVEL_1_2,
|
|
.rx_level = HAL_UART_FIFO_LEVEL_1_2,
|
|
.baud = TRACE_BAUD_RATE,
|
|
.dma_rx = true,
|
|
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
.dma_tx = true,
|
|
#else
|
|
.dma_tx = false,
|
|
#endif
|
|
.dma_rx_stop_on_err = false,
|
|
};
|
|
|
|
static struct HAL_DMA_CH_CFG_T dma_cfg;
|
|
TRACE_BUF_LOC static struct HAL_DMA_DESC_T dma_desc[2];
|
|
#endif
|
|
|
|
static enum HAL_TRACE_TRANSPORT_T trace_transport = HAL_TRACE_TRANSPORT_QTY;
|
|
static enum HAL_UART_ID_T trace_uart;
|
|
|
|
TRACE_BUF_LOC
|
|
static struct HAL_TRACE_BUF_T trace;
|
|
|
|
POSSIBLY_UNUSED
|
|
static const char newline[] = NEW_LINE_STR;
|
|
|
|
static const char discards_prefix[] = NEW_LINE_STR "LOST ";
|
|
static const uint32_t max_discards = 99999;
|
|
// 5 digits + "\r\n" = 7 chars
|
|
static char discards_buf[sizeof(discards_prefix) - 1 + 7];
|
|
static const unsigned char discards_digit_start = sizeof(discards_prefix) - 1;
|
|
|
|
static bool crash_dump_onprocess = false;
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
static HAL_TRACE_CRASH_DUMP_CB_T
|
|
crash_dump_cb_list[HAL_TRACE_CRASH_DUMP_MODULE_END];
|
|
static bool crash_handling;
|
|
#ifdef TRACE_TO_APP
|
|
static HAL_TRACE_APP_NOTIFY_T app_notify_cb = NULL;
|
|
static HAL_TRACE_APP_OUTPUT_T app_output_cb = NULL;
|
|
static HAL_TRACE_APP_OUTPUT_T app_crash_custom_cb = NULL;
|
|
static bool app_output_enabled =
|
|
#if defined(DUMP_LOG_ENABLE)
|
|
true;
|
|
#else
|
|
false;
|
|
#endif
|
|
#endif // TRACE_TO_APP
|
|
#endif // CRASH_DUMP_ENABLE
|
|
#ifdef CP_TRACE_ENABLE
|
|
static HAL_TRACE_APP_NOTIFY_T cp_notify_cb = NULL;
|
|
static HAL_TRACE_BUF_CTRL_T cp_buffer_cb = NULL;
|
|
#endif
|
|
|
|
#ifdef AUDIO_DEBUG_V0_1_0
|
|
static const char trace_head_buf[] = "[trace]";
|
|
#endif
|
|
|
|
static enum LOG_LEVEL_T trace_max_level;
|
|
static uint32_t trace_mod_map[(LOG_MODULE_QTY + 31) / 32];
|
|
|
|
static bool hal_trace_is_uart_transport(enum HAL_TRACE_TRANSPORT_T transport) {
|
|
if (transport == HAL_TRACE_TRANSPORT_UART0
|
|
#if (CHIP_HAS_UART > 1)
|
|
|| transport == HAL_TRACE_TRANSPORT_UART1
|
|
#endif
|
|
#if (CHIP_HAS_UART > 2)
|
|
|| transport == HAL_TRACE_TRANSPORT_UART2
|
|
#endif
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
|
|
static void hal_trace_uart_send(void) {
|
|
uint32_t wptr, rptr;
|
|
uint32_t sends[2];
|
|
uint32_t lock;
|
|
|
|
lock = int_lock();
|
|
|
|
wptr = trace.wptr;
|
|
rptr = trace.rptr;
|
|
|
|
// There is a race condition if we do not check s/w flag, but only check the
|
|
// h/w status. [e.g., hal_gpdma_chan_busy(dma_cfg.ch)] When the DMA is done,
|
|
// but DMA IRQ handler is still pending due to interrupt lock or higher
|
|
// priority IRQ, it will have a chance to send the same content twice.
|
|
if (!trace.sending && wptr != rptr) {
|
|
trace.sending = true;
|
|
|
|
sends[1] = 0;
|
|
if (wptr > rptr) {
|
|
sends[0] = wptr - rptr;
|
|
} else {
|
|
sends[0] = TRACE_BUF_SIZE - rptr;
|
|
if (sends[0] <= HAL_DMA_MAX_DESC_XFER_SIZE) {
|
|
sends[1] = wptr;
|
|
}
|
|
}
|
|
if (sends[0] > HAL_DMA_MAX_DESC_XFER_SIZE) {
|
|
sends[1] = sends[0] - HAL_DMA_MAX_DESC_XFER_SIZE;
|
|
sends[0] = HAL_DMA_MAX_DESC_XFER_SIZE;
|
|
}
|
|
if (sends[1] > HAL_DMA_MAX_DESC_XFER_SIZE) {
|
|
sends[1] = HAL_DMA_MAX_DESC_XFER_SIZE;
|
|
}
|
|
|
|
dma_cfg.src = (uint32_t)&trace.buf[rptr];
|
|
if (sends[1] == 0) {
|
|
dma_cfg.src_tsize = sends[0];
|
|
hal_gpdma_init_desc(&dma_desc[0], &dma_cfg, NULL, 1);
|
|
} else {
|
|
dma_cfg.src_tsize = sends[0];
|
|
hal_gpdma_init_desc(&dma_desc[0], &dma_cfg, &dma_desc[1], 0);
|
|
|
|
if (rptr + sends[0] < TRACE_BUF_SIZE) {
|
|
dma_cfg.src = (uint32_t)&trace.buf[rptr + sends[0]];
|
|
} else {
|
|
dma_cfg.src = (uint32_t)&trace.buf[0];
|
|
}
|
|
dma_cfg.src_tsize = sends[1];
|
|
hal_gpdma_init_desc(&dma_desc[1], &dma_cfg, NULL, 1);
|
|
}
|
|
trace.sends[0] = sends[0];
|
|
trace.sends[1] = sends[1];
|
|
|
|
hal_gpdma_sg_start(&dma_desc[0], &dma_cfg);
|
|
}
|
|
|
|
int_unlock(lock);
|
|
}
|
|
|
|
static void hal_trace_uart_xfer_done(uint8_t chan, uint32_t remain_tsize,
|
|
uint32_t error,
|
|
struct HAL_DMA_DESC_T *lli) {
|
|
uint32_t sends[2];
|
|
uint32_t lock;
|
|
|
|
lock = int_lock();
|
|
|
|
sends[0] = trace.sends[0];
|
|
sends[1] = trace.sends[1];
|
|
|
|
if (error) {
|
|
if (lli || sends[1] == 0) {
|
|
if (sends[0] > remain_tsize) {
|
|
sends[0] -= remain_tsize;
|
|
} else {
|
|
sends[0] = 0;
|
|
}
|
|
sends[1] = 0;
|
|
} else {
|
|
if (sends[1] > remain_tsize) {
|
|
sends[1] -= remain_tsize;
|
|
} else {
|
|
sends[1] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
trace.rptr += sends[0] + sends[1];
|
|
if (trace.rptr >= TRACE_BUF_SIZE) {
|
|
trace.rptr -= TRACE_BUF_SIZE;
|
|
}
|
|
trace.sends[0] = 0;
|
|
trace.sends[1] = 0;
|
|
trace.sending = false;
|
|
|
|
hal_trace_uart_send();
|
|
|
|
int_unlock(lock);
|
|
}
|
|
|
|
static void hal_trace_send(void) {
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (hal_trace_is_uart_transport(trace_transport)) {
|
|
hal_trace_uart_send();
|
|
}
|
|
}
|
|
|
|
#else // TRACE_IDLE_OUTPUT
|
|
|
|
static void hal_trace_uart_idle_send(void) {
|
|
int i;
|
|
uint32_t lock;
|
|
unsigned short wptr, rptr;
|
|
|
|
lock = int_lock();
|
|
wptr = trace.wptr;
|
|
rptr = trace.rptr;
|
|
int_unlock(lock);
|
|
|
|
if (wptr == rptr) {
|
|
return;
|
|
}
|
|
|
|
if (wptr < rptr) {
|
|
for (i = rptr; i < TRACE_BUF_SIZE; i++) {
|
|
hal_uart_blocked_putc(trace_uart, trace.buf[i]);
|
|
}
|
|
rptr = 0;
|
|
}
|
|
|
|
for (i = rptr; i < wptr; i++) {
|
|
hal_uart_blocked_putc(trace_uart, trace.buf[i]);
|
|
}
|
|
|
|
trace.rptr = wptr;
|
|
if (trace.rptr >= TRACE_BUF_SIZE) {
|
|
trace.rptr -= TRACE_BUF_SIZE;
|
|
}
|
|
}
|
|
|
|
void hal_trace_idle_send(void) {
|
|
if (hal_trace_is_uart_transport(trace_transport)) {
|
|
hal_trace_uart_idle_send();
|
|
}
|
|
}
|
|
|
|
#endif // TRACE_IDLE_OUTPUT
|
|
|
|
int hal_trace_open(enum HAL_TRACE_TRANSPORT_T transport) {
|
|
int ret;
|
|
|
|
crash_dump_onprocess = false;
|
|
|
|
#if (CHIP_HAS_UART > 1)
|
|
#ifdef FORCE_TRACE_UART1
|
|
transport = HAL_TRACE_TRANSPORT_UART1;
|
|
#endif
|
|
#endif
|
|
|
|
#if (CHIP_HAS_UART > 2)
|
|
#ifdef FORCE_TRACE_UART2
|
|
transport = HAL_TRACE_TRANSPORT_UART2;
|
|
#endif
|
|
#endif
|
|
|
|
if (transport >= HAL_TRACE_TRANSPORT_QTY) {
|
|
return 1;
|
|
}
|
|
#ifdef CHIP_HAS_USB
|
|
if (transport == HAL_TRACE_TRANSPORT_USB) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
if (trace_transport != HAL_TRACE_TRANSPORT_QTY) {
|
|
return hal_trace_switch(transport);
|
|
}
|
|
|
|
trace_max_level = LOG_LEVEL_INFO;
|
|
for (int i = 0; i < ARRAY_SIZE(trace_mod_map); i++) {
|
|
trace_mod_map[i] = ~0;
|
|
}
|
|
|
|
memcpy(discards_buf, discards_prefix, discards_digit_start);
|
|
|
|
trace.wptr = 0;
|
|
trace.rptr = 0;
|
|
trace.discards = 0;
|
|
trace.sending = false;
|
|
trace.in_trace = false;
|
|
trace.wrapped = false;
|
|
|
|
if (hal_trace_is_uart_transport(transport)) {
|
|
trace_uart = HAL_UART_ID_0 + (transport - HAL_TRACE_TRANSPORT_UART0);
|
|
ret = hal_uart_open(trace_uart, &uart_cfg);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
trace.sends[0] = 0;
|
|
trace.sends[1] = 0;
|
|
|
|
memset(&dma_cfg, 0, sizeof(dma_cfg));
|
|
dma_cfg.dst = 0; // useless
|
|
dma_cfg.dst_bsize = HAL_DMA_BSIZE_8;
|
|
dma_cfg.dst_periph = uart_periph[trace_uart - HAL_UART_ID_0];
|
|
dma_cfg.dst_width = HAL_DMA_WIDTH_BYTE;
|
|
dma_cfg.handler = hal_trace_uart_xfer_done;
|
|
dma_cfg.src_bsize = HAL_DMA_BSIZE_32;
|
|
dma_cfg.src_periph = 0; // useless
|
|
dma_cfg.src_width = HAL_DMA_WIDTH_BYTE;
|
|
dma_cfg.type = HAL_DMA_FLOW_M2P_DMA;
|
|
dma_cfg.try_burst = 0;
|
|
dma_cfg.ch = hal_gpdma_get_chan(dma_cfg.dst_periph, HAL_DMA_HIGH_PRIO);
|
|
|
|
ASSERT(dma_cfg.ch != HAL_DMA_CHAN_NONE, "Failed to get DMA channel");
|
|
#endif
|
|
}
|
|
|
|
#ifdef FAULT_DUMP
|
|
#ifdef __ARM_ARCH_ISA_ARM
|
|
GIC_SetFaultDumpHandler(hal_trace_fault_dump);
|
|
#else
|
|
NVIC_SetDefaultFaultHandler(hal_trace_fault_handler);
|
|
#endif
|
|
#endif
|
|
|
|
trace_transport = transport;
|
|
|
|
#ifdef HAL_TRACE_RX_ENABLE
|
|
hal_trace_rx_open();
|
|
#endif
|
|
|
|
// Show build info
|
|
static const char dbl_new_line[] = NEW_LINE_STR NEW_LINE_STR;
|
|
hal_trace_output((unsigned char *)dbl_new_line, sizeof(dbl_new_line));
|
|
hal_trace_output((unsigned char *)sys_build_info, strlen(sys_build_info) + 1);
|
|
|
|
char buf[50];
|
|
int len;
|
|
len = snprintf(buf, sizeof(buf),
|
|
NEW_LINE_STR NEW_LINE_STR "------" NEW_LINE_STR
|
|
"METAL_ID: %d" NEW_LINE_STR
|
|
"------" NEW_LINE_STR NEW_LINE_STR,
|
|
hal_get_chip_metal_id());
|
|
hal_trace_output((unsigned char *)buf, len + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_switch(enum HAL_TRACE_TRANSPORT_T transport) {
|
|
uint32_t POSSIBLY_UNUSED lock;
|
|
int ret;
|
|
|
|
#if (CHIP_HAS_UART > 1)
|
|
#ifdef FORCE_TRACE_UART1
|
|
transport = HAL_TRACE_TRANSPORT_UART1;
|
|
#endif
|
|
#endif
|
|
|
|
#if (CHIP_HAS_UART > 2)
|
|
#ifdef FORCE_TRACE_UART2
|
|
transport = HAL_TRACE_TRANSPORT_UART2;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CHIP_HAS_USB
|
|
if (transport == HAL_TRACE_TRANSPORT_USB) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
if (transport >= HAL_TRACE_TRANSPORT_QTY) {
|
|
return 1;
|
|
}
|
|
if (trace_transport >= HAL_TRACE_TRANSPORT_QTY) {
|
|
return 1;
|
|
}
|
|
if (trace_transport == transport) {
|
|
return 0;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
#if (CHIP_HAS_UART > 1)
|
|
|
|
lock = int_lock();
|
|
|
|
if (hal_trace_is_uart_transport(trace_transport)) {
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
if (dma_cfg.ch != HAL_DMA_CHAN_NONE) {
|
|
hal_gpdma_cancel(dma_cfg.ch);
|
|
}
|
|
#endif
|
|
hal_uart_close(trace_uart);
|
|
}
|
|
|
|
if (hal_trace_is_uart_transport(transport)) {
|
|
trace_uart = HAL_UART_ID_0 + (transport - HAL_TRACE_TRANSPORT_UART0);
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
dma_cfg.dst_periph = uart_periph[trace_uart - HAL_UART_ID_0];
|
|
trace.sends[0] = 0;
|
|
trace.sends[1] = 0;
|
|
#endif
|
|
ret = hal_uart_open(trace_uart, &uart_cfg);
|
|
if (ret) {
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
hal_gpdma_free_chan(dma_cfg.ch);
|
|
dma_cfg.ch = HAL_DMA_CHAN_NONE;
|
|
#endif
|
|
trace_transport = HAL_TRACE_TRANSPORT_QTY;
|
|
goto _exit;
|
|
}
|
|
}
|
|
|
|
trace.sending = false;
|
|
|
|
trace_transport = transport;
|
|
|
|
_exit:
|
|
int_unlock(lock);
|
|
|
|
#endif // CHIP_HAS_UART > 1
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hal_trace_close(void) {
|
|
if (trace_transport >= HAL_TRACE_TRANSPORT_QTY) {
|
|
goto _exit;
|
|
}
|
|
#ifdef CHIP_HAS_USB
|
|
if (trace_transport == HAL_TRACE_TRANSPORT_USB) {
|
|
goto _exit;
|
|
}
|
|
#endif
|
|
|
|
if (hal_trace_is_uart_transport(trace_transport)) {
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
if (dma_cfg.ch != HAL_DMA_CHAN_NONE) {
|
|
hal_gpdma_cancel(dma_cfg.ch);
|
|
hal_gpdma_free_chan(dma_cfg.ch);
|
|
dma_cfg.ch = HAL_DMA_CHAN_NONE;
|
|
}
|
|
#endif
|
|
hal_uart_close(trace_uart);
|
|
}
|
|
|
|
_exit:
|
|
trace_transport = HAL_TRACE_TRANSPORT_QTY;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_enable_log_module(enum LOG_MODULE_T module) {
|
|
if (module >= LOG_MODULE_QTY) {
|
|
return 1;
|
|
}
|
|
|
|
trace_mod_map[module >> 5] |= (1 << (module & 0x1F));
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_disable_log_module(enum LOG_MODULE_T module) {
|
|
if (module >= LOG_MODULE_QTY) {
|
|
return 1;
|
|
}
|
|
|
|
trace_mod_map[module >> 5] &= ~(1 << (module & 0x1F));
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_set_log_module(const uint32_t *map, uint32_t word_cnt) {
|
|
if (map == NULL || word_cnt == 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (word_cnt > ARRAY_SIZE(trace_mod_map)) {
|
|
word_cnt = ARRAY_SIZE(trace_mod_map);
|
|
}
|
|
for (int i = 0; i < word_cnt; i++) {
|
|
trace_mod_map[i] = map[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_set_log_level(enum LOG_LEVEL_T level) {
|
|
if (level >= LOG_LEVEL_QTY) {
|
|
return 1;
|
|
}
|
|
|
|
trace_max_level = level;
|
|
return 0;
|
|
}
|
|
|
|
void hal_trace_get_history_buffer(const unsigned char **buf1,
|
|
unsigned int *len1,
|
|
const unsigned char **buf2,
|
|
unsigned int *len2) {
|
|
uint32_t lock;
|
|
uint8_t *b1, *b2;
|
|
uint32_t l1, l2;
|
|
|
|
b1 = b2 = NULL;
|
|
l1 = l2 = 0;
|
|
|
|
lock = int_lock();
|
|
|
|
if (TRACE_BUF_SIZE > trace.wptr) {
|
|
if (trace.wrapped) {
|
|
b1 = &trace.buf[trace.wptr];
|
|
l1 = TRACE_BUF_SIZE - trace.wptr;
|
|
b2 = &trace.buf[0];
|
|
l2 = trace.wptr;
|
|
} else {
|
|
b1 = &trace.buf[0];
|
|
l1 = trace.wptr;
|
|
b2 = NULL;
|
|
l2 = 0;
|
|
}
|
|
}
|
|
|
|
int_unlock(lock);
|
|
|
|
if (buf1) {
|
|
*buf1 = b1;
|
|
}
|
|
if (len1) {
|
|
*len1 = l1;
|
|
}
|
|
if (buf2) {
|
|
*buf2 = b2;
|
|
}
|
|
if (len2) {
|
|
*len2 = l2;
|
|
}
|
|
}
|
|
|
|
static void hal_trace_print_discards(uint32_t discards) {
|
|
static const uint8_t base = 10;
|
|
char digit[5], *d, *out;
|
|
uint16_t len;
|
|
uint16_t size;
|
|
|
|
if (discards > max_discards) {
|
|
discards = max_discards;
|
|
}
|
|
|
|
d = &digit[0];
|
|
do {
|
|
*d++ = (discards % base) + '0';
|
|
} while (discards /= base);
|
|
|
|
out = &discards_buf[discards_digit_start];
|
|
do {
|
|
*out++ = *--d;
|
|
} while (d > &digit[0]);
|
|
#ifdef TRACE_CRLF
|
|
*out++ = '\r';
|
|
#endif
|
|
*out++ = '\n';
|
|
len = out - &discards_buf[0];
|
|
|
|
size = TRACE_BUF_SIZE - trace.wptr;
|
|
if (size >= len) {
|
|
size = len;
|
|
}
|
|
memcpy(&trace.buf[trace.wptr], &discards_buf[0], size);
|
|
if (size < len) {
|
|
memcpy(&trace.buf[0], &discards_buf[size], len - size);
|
|
}
|
|
trace.wptr += len;
|
|
if (trace.wptr >= TRACE_BUF_SIZE) {
|
|
trace.wptr -= TRACE_BUF_SIZE;
|
|
}
|
|
}
|
|
|
|
#ifdef AUDIO_DEBUG_V0_1_0
|
|
static void hal_trace_print_head(void) {
|
|
uint16_t len;
|
|
uint16_t size;
|
|
|
|
len = sizeof(trace_head_buf) - 1;
|
|
|
|
size = TRACE_BUF_SIZE - trace.wptr;
|
|
if (size >= len) {
|
|
size = len;
|
|
}
|
|
memcpy(&trace.buf[trace.wptr], &trace_head_buf[0], size);
|
|
if (size < len) {
|
|
memcpy(&trace.buf[0], &trace_head_buf[size], len - size);
|
|
}
|
|
trace.wptr += len;
|
|
if (trace.wptr >= TRACE_BUF_SIZE) {
|
|
trace.wptr -= TRACE_BUF_SIZE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int hal_trace_output(const unsigned char *buf, unsigned int buf_len) {
|
|
int ret;
|
|
uint32_t lock;
|
|
uint32_t avail;
|
|
uint32_t out_len;
|
|
uint16_t size;
|
|
|
|
ret = 0;
|
|
|
|
lock = int_lock();
|
|
#ifdef CP_TRACE_ENABLE
|
|
while (hal_memsc_lock(HAL_MEMSC_ID_TRACE) == 0)
|
|
;
|
|
#endif
|
|
|
|
// Avoid troubles when NMI occurs during trace
|
|
if (!trace.in_trace) {
|
|
trace.in_trace = true;
|
|
|
|
if (trace.wptr >= trace.rptr) {
|
|
avail = TRACE_BUF_SIZE - (trace.wptr - trace.rptr) - 1;
|
|
} else {
|
|
avail = (trace.rptr - trace.wptr) - 1;
|
|
}
|
|
|
|
out_len = buf_len;
|
|
#ifdef AUDIO_DEBUG_V0_1_0
|
|
out_len += sizeof(trace_head_buf) - 1;
|
|
#endif
|
|
if (trace.discards) {
|
|
out_len += sizeof(discards_buf);
|
|
}
|
|
|
|
if (avail < out_len) {
|
|
ret = 1;
|
|
if (trace.discards < (1 << (sizeof(trace.discards) * 8)) - 1) {
|
|
trace.discards++;
|
|
}
|
|
#ifdef CP_TRACE_ENABLE
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
hal_trace_send();
|
|
#endif
|
|
#endif
|
|
} else {
|
|
#ifdef AUDIO_DEBUG_V0_1_0
|
|
hal_trace_print_head();
|
|
#endif
|
|
|
|
if (trace.discards) {
|
|
hal_trace_print_discards(trace.discards);
|
|
trace.discards = 0;
|
|
}
|
|
|
|
size = TRACE_BUF_SIZE - trace.wptr;
|
|
if (size >= buf_len) {
|
|
size = buf_len;
|
|
}
|
|
memcpy(&trace.buf[trace.wptr], &buf[0], size);
|
|
if (size < buf_len) {
|
|
memcpy(&trace.buf[0], &buf[size], buf_len - size);
|
|
}
|
|
trace.wptr += buf_len;
|
|
if (trace.wptr >= TRACE_BUF_SIZE) {
|
|
trace.wptr -= TRACE_BUF_SIZE;
|
|
trace.wrapped = true;
|
|
}
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
hal_trace_send();
|
|
#endif
|
|
}
|
|
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
if (cp_buffer_cb) {
|
|
if (avail < out_len) {
|
|
cp_buffer_cb(HAL_TRACE_BUF_STATE_FULL);
|
|
} else if (avail - out_len < TRACE_NEAR_FULL_THRESH) {
|
|
cp_buffer_cb(HAL_TRACE_BUF_STATE_NEAR_FULL);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
trace.in_trace = false;
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
#ifdef TRACE_TO_APP
|
|
if (app_output_cb && app_output_enabled) {
|
|
bool saved_output_state;
|
|
|
|
saved_output_state = app_output_enabled;
|
|
app_output_enabled = false;
|
|
|
|
app_output_cb(buf, buf_len);
|
|
|
|
app_output_enabled = saved_output_state;
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#ifdef CP_TRACE_ENABLE
|
|
hal_memsc_unlock(HAL_MEMSC_ID_TRACE);
|
|
#endif
|
|
int_unlock(lock);
|
|
|
|
return ret ? 0 : buf_len;
|
|
}
|
|
#ifdef USE_TRACE_ID
|
|
// define USE_CRC_CHECK
|
|
//#define LITE_VERSION
|
|
|
|
typedef struct {
|
|
uint32_t crc : 6;
|
|
uint32_t count : 4;
|
|
uint32_t tskid : 5;
|
|
uint32_t addr : 17; // 127 KB trace space support
|
|
} trace_info_t;
|
|
|
|
typedef struct {
|
|
uint32_t crc : 8;
|
|
uint32_t timestamp : 24; // 4 hours support
|
|
} trace_head_t;
|
|
|
|
typedef struct {
|
|
#ifndef LITE_VERSION
|
|
trace_head_t trace_head;
|
|
#endif
|
|
trace_info_t trace_info;
|
|
} __attribute__((packed)) LOG_DATA_T;
|
|
|
|
extern const char *unkonw_str;
|
|
|
|
extern uint32_t __trc_str_start__[];
|
|
extern uint32_t __trc_str_end__[];
|
|
uint8_t crc8(uint8_t *data, uint32_t length) {
|
|
uint8_t i;
|
|
uint8_t crc = 0; // Initial value
|
|
while (length--) {
|
|
crc ^= *data++; // crc ^= *data; data++;
|
|
for (i = 0; i < 8; i++) {
|
|
if (crc & 0x80)
|
|
crc = (crc << 1) ^ 0x07;
|
|
else
|
|
crc <<= 1;
|
|
}
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
uint8_t crc6(uint8_t *data, uint32_t length) {
|
|
uint8_t i;
|
|
uint8_t crc = 0; // Initial value
|
|
while (length--) {
|
|
crc ^= *data++; // crc ^= *data; data++;
|
|
for (i = 0; i < 8; ++i) {
|
|
if (crc & 1)
|
|
crc = (crc >> 1) ^ 0x30; // 0x30 = (reverse 0x03)>>(8-6)
|
|
else
|
|
crc = (crc >> 1);
|
|
}
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
static int hal_trace_format_id(uint32_t attr, char *buf, uint32_t size,
|
|
const char *fmt, va_list ap) {
|
|
uint8_t num;
|
|
unsigned int value[10];
|
|
LOG_DATA_T trace;
|
|
|
|
if (size < sizeof(trace) + sizeof(value)) {
|
|
return -1;
|
|
}
|
|
|
|
num = GET_BITFIELD(attr, LOG_ATTR_ARG_NUM);
|
|
if (num > 10) {
|
|
num = 10;
|
|
}
|
|
for (int i = 0; i < num; i++) {
|
|
value[i] = va_arg(ap, unsigned long);
|
|
}
|
|
|
|
// memset(buf, 0, size);
|
|
|
|
trace.trace_info.count = num;
|
|
trace.trace_info.addr =
|
|
(uint32_t)fmt -
|
|
(uint32_t)0xFFFC0000; //(uint32_t)fmt-(uint32_t)__trc_str_start__;
|
|
trace.trace_info.tskid = osGetThreadIntId();
|
|
trace.trace_info.crc = 0x2A;
|
|
#ifndef LITE_VERSION
|
|
trace.trace_head.timestamp = TICKS_TO_MS(hal_sys_timer_get());
|
|
#ifdef USE_CRC_CHECK
|
|
trace.trace_head.crc = crc8(((uint8_t *)&trace) + 1, 7);
|
|
#else
|
|
trace.trace_head.crc = 0xBE;
|
|
#endif
|
|
#else
|
|
trace.trace_info.crc = crc6(((uint8_t *)&trace) + 1, 3);
|
|
#endif
|
|
memcpy(buf, &trace, sizeof(trace));
|
|
if (num != 0) {
|
|
memcpy(buf + sizeof(trace), value, 4 * num);
|
|
}
|
|
|
|
return sizeof(trace) + 4 * num;
|
|
}
|
|
#endif
|
|
|
|
static int hal_trace_print_time(enum LOG_LEVEL_T level,
|
|
enum LOG_MODULE_T module, char *buf,
|
|
unsigned int size) {
|
|
#ifdef TRACE_TIME_STAMP
|
|
static const char level_ch[] = {
|
|
'C', 'E', 'W', 'N', 'I', 'D', 'V', '-',
|
|
};
|
|
char ctx[10];
|
|
int len;
|
|
int i;
|
|
const char *mod_name;
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
if (crash_handling) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
if (0) {
|
|
#ifdef CP_TRACE_ENABLE
|
|
} else if (get_cpu_id()) {
|
|
ctx[0] = ' ';
|
|
ctx[1] = 'C';
|
|
ctx[2] = 'P';
|
|
ctx[3] = '\0';
|
|
#endif
|
|
} else if (in_isr()) {
|
|
len = snprintf(ctx, sizeof(ctx), "%2d", (int8_t)NVIC_GetCurrentActiveIRQ());
|
|
if (len + 1 < ARRAY_SIZE(ctx)) {
|
|
ctx[len] = 'E';
|
|
ctx[len + 1] = '\0';
|
|
} else {
|
|
ctx[ARRAY_SIZE(ctx) - 2] = '.';
|
|
ctx[ARRAY_SIZE(ctx) - 1] = '\0';
|
|
}
|
|
} else {
|
|
#ifdef RTOS
|
|
#ifdef KERNEL_RTX5
|
|
/* const char *thread_name = osGetThreadName(); */
|
|
/* snprintf(ctx, sizeof(ctx), "%.9s", thread_name ? (char *)thread_name :
|
|
* "NULL"); */
|
|
ctx[0] = ' ';
|
|
ctx[1] = ' ';
|
|
ctx[2] = 't';
|
|
ctx[3] = '\0';
|
|
#else
|
|
snprintf(ctx, sizeof(ctx), "%3d", osGetThreadIntId());
|
|
#endif
|
|
#else
|
|
ctx[0] = ' ';
|
|
ctx[1] = ' ';
|
|
ctx[2] = '0';
|
|
ctx[3] = '\0';
|
|
#endif
|
|
}
|
|
ctx[ARRAY_SIZE(ctx) - 1] = '\0';
|
|
len = 0;
|
|
len += snprintf(&buf[len], size - len, "%9u/",
|
|
(unsigned)TICKS_TO_MS(hal_sys_timer_get()));
|
|
if (size > len + 2) {
|
|
buf[len++] = level_ch[level];
|
|
buf[len++] = '/';
|
|
}
|
|
if (size > len + 7) {
|
|
mod_name = hal_trace_get_log_module_desc(module);
|
|
for (i = 0; i < 6; i++) {
|
|
if (mod_name[i] == '\0') {
|
|
break;
|
|
}
|
|
buf[len++] = mod_name[i];
|
|
}
|
|
for (; i < 6; i++) {
|
|
buf[len++] = ' ';
|
|
}
|
|
buf[len++] = '/';
|
|
}
|
|
len += snprintf(&buf[len], size - len, "%s | ", ctx);
|
|
return len;
|
|
#else // !TRACE_TIME_STAMP
|
|
return 0;
|
|
#endif // !TRACE_TIME_STAMP
|
|
}
|
|
|
|
static inline int hal_trace_format_va(uint32_t attr, char *buf,
|
|
unsigned int size, const char *fmt,
|
|
va_list ap) {
|
|
int len;
|
|
|
|
len = vsnprintf(&buf[0], size, fmt, ap);
|
|
if ((attr & LOG_ATTR_NO_LF) == 0) {
|
|
#ifdef TRACE_CRLF
|
|
if (len + 2 < size) {
|
|
buf[len++] = '\r';
|
|
}
|
|
#endif
|
|
if (len + 1 < size) {
|
|
buf[len++] = '\n';
|
|
}
|
|
}
|
|
// if (len < size) buf[len] = 0;
|
|
|
|
return len;
|
|
}
|
|
|
|
static int hal_trace_printf_internal(uint32_t attr, const char *fmt,
|
|
va_list ap) {
|
|
#ifdef USE_TRACE_ID
|
|
char buf[60];
|
|
#else
|
|
char buf[120];
|
|
#endif
|
|
int len = 0;
|
|
enum LOG_LEVEL_T level;
|
|
enum LOG_MODULE_T module;
|
|
|
|
level = GET_BITFIELD(attr, LOG_ATTR_LEVEL);
|
|
module = GET_BITFIELD(attr, LOG_ATTR_MOD);
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
if (!crash_handling)
|
|
#endif
|
|
{
|
|
if (level > trace_max_level) {
|
|
return 0;
|
|
}
|
|
if (level > LOG_LEVEL_CRITICAL &&
|
|
(trace_mod_map[module >> 5] & (1 << (module & 0x1F))) == 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#ifdef USE_TRACE_ID
|
|
if ((attr & LOG_ATTR_NO_ID) ||
|
|
(len = hal_trace_format_id(attr, buf, sizeof(buf), fmt, ap)) < 0)
|
|
#endif
|
|
{
|
|
len = 0;
|
|
if ((attr & LOG_ATTR_NO_TS) == 0) {
|
|
len += hal_trace_print_time(level, module, &buf[len], sizeof(buf) - len);
|
|
}
|
|
len += hal_trace_format_va(attr, &buf[len], sizeof(buf) - len, fmt, ap);
|
|
}
|
|
|
|
return hal_trace_output((unsigned char *)buf, len);
|
|
}
|
|
|
|
int hal_trace_printf(uint32_t attr, const char *fmt, ...) {
|
|
int ret;
|
|
va_list ap;
|
|
|
|
if (attr & LOG_ATTR_IMM) {
|
|
hal_trace_flush_buffer();
|
|
}
|
|
|
|
va_start(ap, fmt);
|
|
ret = hal_trace_printf_internal(attr, fmt, ap);
|
|
va_end(ap);
|
|
|
|
if (attr & LOG_ATTR_IMM) {
|
|
hal_trace_flush_buffer();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hal_trace_dump(const char *fmt, unsigned int size, unsigned int count,
|
|
const void *buffer) {
|
|
char buf[255] = {0};
|
|
int len = 0, n = 0, i = 0;
|
|
|
|
switch (size) {
|
|
case sizeof(uint32_t):
|
|
while (i < count && len < sizeof(buf)) {
|
|
len += snprintf(&buf[len], sizeof(buf) - len, fmt,
|
|
*(uint32_t *)((uint32_t *)buffer + i));
|
|
i++;
|
|
}
|
|
break;
|
|
case sizeof(uint16_t):
|
|
while (i < count && len < sizeof(buf)) {
|
|
len += snprintf(&buf[len], sizeof(buf) - len, fmt,
|
|
*(int16_t *)((int16_t *)buffer + i));
|
|
i++;
|
|
}
|
|
break;
|
|
case sizeof(uint8_t):
|
|
default:
|
|
while (i < count && len < sizeof(buf)) {
|
|
len += snprintf(&buf[len], sizeof(buf) - len, fmt,
|
|
*(uint8_t *)((uint8_t *)buffer + i));
|
|
i++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef TRACE_CRLF
|
|
if (len + 2 < sizeof(buf)) {
|
|
buf[len++] = '\r';
|
|
}
|
|
#endif
|
|
if (len + 1 < sizeof(buf)) {
|
|
buf[len++] = '\n';
|
|
}
|
|
|
|
n = hal_trace_output((unsigned char *)buf, len + 1);
|
|
|
|
return n;
|
|
}
|
|
|
|
int hal_trace_busy(void) {
|
|
union HAL_UART_FLAG_T flag;
|
|
|
|
if (hal_trace_is_uart_transport(trace_transport)) {
|
|
if (hal_uart_opened(trace_uart)) {
|
|
flag = hal_uart_get_flag(trace_uart);
|
|
return flag.BUSY;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_pause(void) {
|
|
if (hal_trace_is_uart_transport(trace_transport)) {
|
|
return hal_uart_pause(trace_uart);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int hal_trace_continue(void) {
|
|
if (hal_trace_is_uart_transport(trace_transport)) {
|
|
return hal_uart_continue(trace_uart);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int hal_trace_flush_buffer(void) {
|
|
uint32_t lock;
|
|
uint32_t time;
|
|
int ret;
|
|
enum HAL_DMA_RET_T dma_ret;
|
|
|
|
if (!hal_trace_is_uart_transport(trace_transport)) {
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
if (cp_buffer_cb) {
|
|
cp_buffer_cb(HAL_TRACE_BUF_STATE_FLUSH);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
hal_uart_continue(trace_uart);
|
|
|
|
lock = int_lock();
|
|
|
|
time = hal_sys_timer_get();
|
|
while (trace.wptr != trace.rptr &&
|
|
hal_sys_timer_get() - time < TRACE_FLUSH_TIMEOUT) {
|
|
#if (TRACE_IDLE_OUTPUT == 0)
|
|
while (hal_gpdma_chan_busy(dma_cfg.ch))
|
|
;
|
|
dma_ret = hal_gpdma_irq_run_chan(dma_cfg.ch);
|
|
if (dma_ret != HAL_DMA_OK) {
|
|
hal_trace_send();
|
|
}
|
|
#else
|
|
hal_trace_idle_send();
|
|
#endif
|
|
}
|
|
|
|
ret = (trace.wptr == trace.rptr) ? 0 : 1;
|
|
|
|
int_unlock(lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t hal_trace_get_backtrace_addr(uint32_t addr) {
|
|
if (!hal_trace_address_executable(addr)) {
|
|
return 0;
|
|
}
|
|
|
|
#ifndef __ARM_ARCH_ISA_ARM
|
|
#if defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)
|
|
// BL Instruction
|
|
// OFFSET: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 15 14 13 12 11 10
|
|
// 09 08 07 06 05 04 03 02 01 00 VALUE : 1 1 1 1 0 - - - - - - -
|
|
// - - - - 1 1 - 1 - - - - - - - - - - - -
|
|
|
|
// BLX Instruction
|
|
// OFFSET: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
|
|
// VALUE : 0 1 0 0 0 1 1 1 1 - - - - - - -
|
|
|
|
uint16_t val;
|
|
uint32_t new_addr;
|
|
|
|
new_addr = (addr & ~1) - 2;
|
|
|
|
val = *(uint16_t *)new_addr;
|
|
if ((val & 0xFF80) == 0x4780) {
|
|
// BLX
|
|
return new_addr;
|
|
} else if ((val & 0xD000) == 0xD000) {
|
|
new_addr -= 2;
|
|
val = *(uint16_t *)new_addr;
|
|
if ((val & 0xF800) == 0xF000) {
|
|
// BL
|
|
return new_addr;
|
|
}
|
|
}
|
|
#else
|
|
#error "Only ARMv7-M/ARMv8-M function can be checked for BL/BLX instructions"
|
|
#endif
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifndef __ARM_ARCH_ISA_ARM
|
|
void hal_trace_print_special_stack_registers(void) {
|
|
int len;
|
|
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline) - 1);
|
|
|
|
len =
|
|
snprintf(crash_buf, sizeof(crash_buf), "MSP=%08X, PSP=%08X" NEW_LINE_STR,
|
|
(unsigned)__get_MSP(), (unsigned)__get_PSP());
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
len = snprintf(crash_buf, sizeof(crash_buf),
|
|
"MSPLIM=%08X, PSPLIM=%08X" NEW_LINE_STR,
|
|
(unsigned)__get_MSPLIM(), (unsigned)__get_PSPLIM());
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void hal_trace_print_common_registers(const uint32_t *regs) {
|
|
int len;
|
|
int i;
|
|
int index;
|
|
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline) - 1);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
index = i * 4;
|
|
len = snprintf(
|
|
crash_buf, sizeof(crash_buf),
|
|
"R%-2d=%08X, R%-2d=%08X, R%-2d=%08X, R%-2d=%08X" NEW_LINE_STR, index,
|
|
(unsigned)regs[index], index + 1, (unsigned)regs[index + 1], index + 2,
|
|
(unsigned)regs[index + 2], index + 3, (unsigned)regs[index + 3]);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
}
|
|
len = snprintf(crash_buf, sizeof(crash_buf),
|
|
"R12=%08X, SP =%08X, LR =%08X" NEW_LINE_STR,
|
|
(unsigned)regs[12], (unsigned)regs[13], (unsigned)regs[14]);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
}
|
|
|
|
void hal_trace_print_stack(uint32_t addr) {
|
|
static const char stack_title[] = "Stack:" NEW_LINE_STR;
|
|
int len = 0;
|
|
int i;
|
|
int pos;
|
|
uint32_t *stack;
|
|
|
|
addr &= ~3;
|
|
if (!hal_trace_address_writable(addr)) {
|
|
return;
|
|
}
|
|
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline) - 1);
|
|
hal_trace_output((const unsigned char *)stack_title, sizeof(stack_title) - 1);
|
|
|
|
stack = (uint32_t *)addr - STACK_DUMP_CNT_PREV;
|
|
for (i = 0; i < (STACK_DUMP_CNT_PREV + STACK_DUMP_CNT); i++) {
|
|
if (!hal_trace_address_writable((uint32_t)&stack[i])) {
|
|
break;
|
|
}
|
|
pos = (i % STACK_DUMP_CNT_PER_LEN);
|
|
if (pos == 0) {
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "%c %08X: %08X",
|
|
(i == STACK_DUMP_CNT_PREV) ? '*' : ' ',
|
|
(unsigned)&stack[i], (unsigned)stack[i]);
|
|
} else {
|
|
len += snprintf(crash_buf + len, sizeof(crash_buf) - len, " %08X",
|
|
(unsigned)stack[i]);
|
|
if (pos == (STACK_DUMP_CNT_PER_LEN - 1)) {
|
|
#ifdef TRACE_CRLF
|
|
if (len + 2 < sizeof(crash_buf)) {
|
|
crash_buf[len++] = '\r';
|
|
}
|
|
#endif
|
|
if (len + 1 < sizeof(crash_buf)) {
|
|
crash_buf[len++] = '\n';
|
|
}
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
hal_trace_flush_buffer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void hal_trace_print_backtrace(uint32_t addr, uint32_t search_cnt,
|
|
uint32_t print_cnt) {
|
|
static const char bt_title[] = "Possible Backtrace:" NEW_LINE_STR;
|
|
int i, j;
|
|
int len;
|
|
uint32_t *stack;
|
|
uint32_t call_addr;
|
|
|
|
addr &= ~3;
|
|
if (!hal_trace_address_writable(addr)) {
|
|
return;
|
|
}
|
|
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
hal_trace_output((const unsigned char *)bt_title, sizeof(bt_title));
|
|
|
|
stack = (uint32_t *)addr;
|
|
for (i = 0, j = 0; i < search_cnt && j < print_cnt; i++) {
|
|
if (!hal_trace_address_writable((uint32_t)&stack[i])) {
|
|
break;
|
|
}
|
|
call_addr = hal_trace_get_backtrace_addr(stack[i]);
|
|
if (call_addr) {
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "%8X" NEW_LINE_STR,
|
|
(unsigned)call_addr);
|
|
hal_trace_output((unsigned char *)crash_buf, len + 1);
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t hal_trace_get_baudrate(void) { return uart_cfg.baud; }
|
|
|
|
bool hal_trace_crash_dump_onprocess(void) { return crash_dump_onprocess; }
|
|
|
|
int hal_trace_crash_dump_register(enum HAL_TRACE_CRASH_DUMP_MODULE_T module,
|
|
HAL_TRACE_CRASH_DUMP_CB_T cb) {
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
ASSERT(module < HAL_TRACE_CRASH_DUMP_MODULE_END, "%s module %d", __func__,
|
|
module);
|
|
crash_dump_cb_list[module] = cb;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
static void hal_trace_crash_dump_callback(void) {
|
|
int i;
|
|
|
|
crash_handling = true;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(crash_dump_cb_list); i++) {
|
|
if (crash_dump_cb_list[i]) {
|
|
crash_dump_cb_list[i]();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void hal_trace_app_register(HAL_TRACE_APP_NOTIFY_T notify_cb,
|
|
HAL_TRACE_APP_OUTPUT_T output_cb) {
|
|
#ifdef TRACE_TO_APP
|
|
app_notify_cb = notify_cb;
|
|
app_output_cb = output_cb;
|
|
#endif
|
|
}
|
|
|
|
void hal_trace_app_custom_register(HAL_TRACE_APP_NOTIFY_T notify_cb,
|
|
HAL_TRACE_APP_OUTPUT_T output_cb,
|
|
HAL_TRACE_APP_OUTPUT_T crash_custom_cb) {
|
|
#ifdef TRACE_TO_APP
|
|
hal_trace_app_register(notify_cb, output_cb);
|
|
app_crash_custom_cb = crash_custom_cb;
|
|
#endif
|
|
}
|
|
|
|
void hal_trace_cp_register(HAL_TRACE_APP_NOTIFY_T notify_cb,
|
|
HAL_TRACE_BUF_CTRL_T buf_cb) {
|
|
#ifdef CP_TRACE_ENABLE
|
|
cp_notify_cb = notify_cb;
|
|
cp_buffer_cb = buf_cb;
|
|
#endif
|
|
}
|
|
|
|
#else // !(DEBUG || REL_TRACE_ENABLE)
|
|
|
|
int hal_trace_open(enum HAL_TRACE_TRANSPORT_T transport) {
|
|
#ifdef FAULT_DUMP
|
|
#ifdef __ARM_ARCH_ISA_ARM
|
|
GIC_SetFaultDumpHandler(hal_trace_fault_dump);
|
|
#else
|
|
NVIC_SetDefaultFaultHandler(hal_trace_fault_handler);
|
|
#endif
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif // !(DEBUG || REL_TRACE_ENABLE)
|
|
|
|
int hal_trace_open_cp(void) {
|
|
#ifdef CP_TRACE_ENABLE
|
|
#ifdef FAULT_DUMP
|
|
NVIC_SetDefaultFaultHandler_cp(hal_trace_fault_handler);
|
|
#endif
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_address_writable(uint32_t addr) {
|
|
if (RAM_BASE < addr && addr < RAM_BASE + RAM_SIZE) {
|
|
return 1;
|
|
}
|
|
#ifdef PSRAM_BASE
|
|
if (PSRAM_BASE < addr && addr < PSRAM_BASE + PSRAM_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef PSRAM_NC_BASE
|
|
if (PSRAM_NC_BASE < addr && addr < PSRAM_NC_BASE + PSRAM_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef PSRAMUHS_BASE
|
|
if (PSRAMUHS_BASE < addr && addr < PSRAMUHS_BASE + PSRAMUHS_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef PSRAMUHS_NC_BASE
|
|
if (PSRAMUHS_NC_BASE < addr && addr < PSRAMUHS_NC_BASE + PSRAMUHS_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef RAMRET_BASE
|
|
if (RAMRET_BASE < addr && addr < RAMRET_BASE + RAMRET_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef RAMCP_BASE
|
|
if (RAMCP_BASE < addr && addr < RAMCP_BASE + RAMCP_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_address_executable(uint32_t addr) {
|
|
// Avoid reading out of valid memory region when parsing instruction content
|
|
#define X_ADDR_OFFSET 0x10
|
|
|
|
// Check thumb code
|
|
if ((addr & 1) == 0) {
|
|
return 0;
|
|
}
|
|
// Check location
|
|
if (RAMX_BASE + X_ADDR_OFFSET < addr && addr < RAMX_BASE + RAM_SIZE) {
|
|
return 1;
|
|
}
|
|
if (FLASHX_BASE + X_ADDR_OFFSET < addr && addr < FLASHX_BASE + FLASH_SIZE) {
|
|
return 1;
|
|
}
|
|
#ifdef PSRAMX_BASE
|
|
if (PSRAMX_BASE + X_ADDR_OFFSET < addr && addr < PSRAMX_BASE + PSRAM_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef PSRAMUHSX_BASE
|
|
if (PSRAMUHSX_BASE + X_ADDR_OFFSET < addr &&
|
|
addr < PSRAMUHSX_BASE + PSRAMUHS_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef RAMXRET_BASE
|
|
if (RAMXRET_BASE < addr && addr < RAMXRET_BASE + RAMRET_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
//#define CHECK_ROM_CODE
|
|
#ifdef CHECK_ROM_CODE
|
|
#ifndef USED_ROM_SIZE
|
|
#define USED_ROM_SIZE ROM_SIZE
|
|
#endif
|
|
if (ROM_BASE + (NVIC_USER_IRQ_OFFSET * 4) < addr &&
|
|
addr < ROM_BASE + USED_ROM_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
if (FLASHX_NC_BASE < addr && addr < FLASHX_NC_BASE + FLASH_SIZE) {
|
|
return 1;
|
|
}
|
|
#ifdef PSRAMX_NC_BASE
|
|
if (PSRAMX_NC_BASE < addr && addr < PSRAMX_NC_BASE + PSRAM_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef PSRAMUHSX_NC_BASE
|
|
if (PSRAMUHSX_NC_BASE < addr && addr < PSRAMUHSX_NC_BASE + PSRAMUHS_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_address_readable(uint32_t addr) {
|
|
if (hal_trace_address_writable(addr)) {
|
|
return 1;
|
|
}
|
|
if (hal_trace_address_executable(addr)) {
|
|
return 1;
|
|
}
|
|
if (FLASH_BASE < addr && addr < FLASH_BASE + FLASH_SIZE) {
|
|
return 1;
|
|
}
|
|
if (FLASH_NC_BASE < addr && addr < FLASH_NC_BASE + FLASH_SIZE) {
|
|
return 1;
|
|
}
|
|
#ifdef PSRAM_NC_BASE
|
|
if (PSRAM_NC_BASE < addr && addr < PSRAM_NC_BASE + PSRAM_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef PSRAMUHS_NC_BASE
|
|
if (PSRAMUHS_NC_BASE < addr && addr < PSRAMUHS_NC_BASE + PSRAMUHS_SIZE) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void NORETURN hal_trace_crash_end(void) {
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
hal_trace_flush_buffer();
|
|
hal_sys_timer_delay(MS_TO_TICKS(5));
|
|
#endif
|
|
|
|
// Tag failure for simulation environment
|
|
hal_cmu_simu_fail();
|
|
#ifndef PROGRAMMER
|
|
#ifndef __BES_OTA_MODE__
|
|
nv_record_flash_flush();
|
|
#endif
|
|
#endif
|
|
#ifdef CRASH_REBOOT
|
|
|
|
hal_sw_bootmode_set(HAL_SW_BOOTMODE_REBOOT |
|
|
HAL_SW_BOOTMODE_REBOOT_FROM_CRASH);
|
|
hal_cmu_sys_reboot();
|
|
#else
|
|
hal_iomux_set_analog_i2c();
|
|
hal_iomux_set_jtag();
|
|
hal_cmu_jtag_clock_enable();
|
|
#endif
|
|
|
|
SAFE_PROGRAM_STOP();
|
|
}
|
|
|
|
__STATIC_FORCEINLINE uint32_t get_cpu_id_tag(void) {
|
|
uint32_t cpu_id;
|
|
#ifdef CP_TRACE_ENABLE
|
|
cpu_id = get_cpu_id();
|
|
#elif defined(__ARM_ARCH_ISA_ARM)
|
|
cpu_id = 0xAAAA0000 | (get_cpu_id() & 0xFFFF);
|
|
#else
|
|
cpu_id = 0;
|
|
#endif
|
|
return cpu_id;
|
|
}
|
|
|
|
static void NORETURN USED hal_trace_assert_dump_internal(ASSERT_DUMP_ARGS) {
|
|
const uint32_t *p_regs;
|
|
struct ASSERT_INFO_T info;
|
|
int i;
|
|
|
|
// MUST SAVE REGISTERS FIRST!
|
|
p_regs = (const uint32_t *)crash_buf;
|
|
for (i = 0; i < ARRAY_SIZE(info.R); i++) {
|
|
info.R[i] = p_regs[i];
|
|
}
|
|
|
|
int_lock_global();
|
|
|
|
info.ID = HAL_TRACE_ASSERT_ID;
|
|
info.CPU_ID = get_cpu_id_tag();
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE)) && \
|
|
defined(ASSERT_SHOW_FILE_FUNC)
|
|
info.FILE = file;
|
|
#elif (defined(DEBUG) || defined(REL_TRACE_ENABLE)) && defined(ASSERT_SHOW_FILE)
|
|
info.FILE = scope;
|
|
#else
|
|
info.FILE = NULL;
|
|
#endif
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE)) && \
|
|
defined(ASSERT_SHOW_FILE_FUNC)
|
|
info.FUNC = func;
|
|
#elif (defined(DEBUG) || defined(REL_TRACE_ENABLE)) && defined(ASSERT_SHOW_FUNC)
|
|
info.FUNC = scope;
|
|
#else
|
|
info.FUNC = NULL;
|
|
#endif
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE)) && \
|
|
(defined(ASSERT_SHOW_FILE_FUNC) || defined(ASSERT_SHOW_FILE) || \
|
|
defined(ASSERT_SHOW_FUNC))
|
|
info.LINE = line;
|
|
#else
|
|
info.LINE = 0;
|
|
#endif
|
|
info.FMT = fmt;
|
|
#ifndef __ARM_ARCH_ISA_ARM
|
|
info.MSP = __get_MSP();
|
|
info.PSP = __get_PSP();
|
|
info.CONTROL = __get_CONTROL();
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
info.MSPLIM = __get_MSPLIM();
|
|
info.PSPLIM = __get_PSPLIM();
|
|
#endif
|
|
#endif
|
|
|
|
*(volatile uint32_t *)RAM_BASE = (uint32_t)&info;
|
|
|
|
#ifdef ASSERT_MUTE_CODEC
|
|
bool crash_mute = true;
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
// Forbid CP to access CODEC
|
|
crash_mute = false;
|
|
}
|
|
#endif
|
|
if (crash_mute) {
|
|
hal_codec_crash_mute();
|
|
}
|
|
#endif
|
|
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
|
|
static const char POSSIBLY_UNUSED desc_file[] = "FILE : ";
|
|
static const char POSSIBLY_UNUSED desc_func[] = "FUNCTION: ";
|
|
static const char POSSIBLY_UNUSED desc_line[] = "LINE : ";
|
|
int len;
|
|
va_list ap;
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
bool full_dump = true;
|
|
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
full_dump = false;
|
|
if (cp_notify_cb) {
|
|
cp_notify_cb(HAL_TRACE_STATE_CRASH_ASSERT_START);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (full_dump) {
|
|
#ifdef TRACE_TO_APP
|
|
if (app_notify_cb) {
|
|
app_notify_cb(HAL_TRACE_STATE_CRASH_ASSERT_START);
|
|
}
|
|
app_output_enabled = true;
|
|
#endif
|
|
|
|
crash_dump_onprocess = true;
|
|
for (uint8_t i = 0; i < 10; i++) {
|
|
REL_TRACE_IMM(0, " "
|
|
" ");
|
|
REL_TRACE_IMM(0, " "
|
|
" " NEW_LINE_STR);
|
|
hal_sys_timer_delay(MS_TO_TICKS(50));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
hal_sysfreq_req(HAL_SYSFREQ_USER_INIT, HAL_CMU_FREQ_52M);
|
|
|
|
len = hal_trace_print_time(LOG_LEVEL_CRITICAL, LOG_MODULE_NONE, &crash_buf[0],
|
|
sizeof(crash_buf));
|
|
if (len > 0) {
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
}
|
|
len = snprintf(&crash_buf[0], sizeof(crash_buf),
|
|
NEW_LINE_STR "### ASSERT @ 0x%08X ###" NEW_LINE_STR,
|
|
(unsigned)info.R[14]);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
#if defined(ASSERT_SHOW_FILE_FUNC) || defined(ASSERT_SHOW_FILE) || \
|
|
defined(ASSERT_SHOW_FUNC)
|
|
const char separate_line[] =
|
|
"----------------------------------------" NEW_LINE_STR;
|
|
#ifdef ASSERT_SHOW_FILE
|
|
const char *file = scope;
|
|
#elif defined(ASSERT_SHOW_FUNC)
|
|
const char *func = scope;
|
|
#endif
|
|
|
|
#if defined(ASSERT_SHOW_FILE_FUNC) || defined(ASSERT_SHOW_FILE)
|
|
hal_trace_output((const unsigned char *)desc_file, sizeof(desc_file));
|
|
hal_trace_output((const unsigned char *)file, strlen(file) + 1);
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
#endif
|
|
|
|
#if defined(ASSERT_SHOW_FILE_FUNC) || defined(ASSERT_SHOW_FUNC)
|
|
hal_trace_output((const unsigned char *)desc_func, sizeof(desc_func));
|
|
hal_trace_output((const unsigned char *)func, strlen(func) + !);
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
#endif
|
|
|
|
hal_trace_output((const unsigned char *)desc_line, sizeof(desc_func));
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "%u", line);
|
|
hal_trace_output((const unsigned char *)crash_buf, len);
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
|
|
hal_trace_output((unsigned char *)separate_line, sizeof(separate_line));
|
|
|
|
hal_trace_flush_buffer();
|
|
#endif
|
|
|
|
va_start(ap, fmt);
|
|
len = hal_trace_format_va(0, crash_buf, sizeof(crash_buf), fmt, ap);
|
|
va_end(ap);
|
|
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
hal_trace_print_common_registers(info.R);
|
|
hal_trace_print_special_stack_registers();
|
|
|
|
hal_trace_print_stack(info.R[13]);
|
|
|
|
hal_trace_print_backtrace(info.R[13], TRACE_BACKTRACE_SEARCH_WORD,
|
|
TRACE_BACKTRACE_NUM);
|
|
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
if (full_dump) {
|
|
hal_trace_crash_dump_callback();
|
|
hal_trace_flush_buffer();
|
|
hal_sys_timer_delay(MS_TO_TICKS(5));
|
|
|
|
#ifdef CORE_DUMP
|
|
AssertCatcher_Entry();
|
|
hal_sys_timer_delay(MS_TO_TICKS(5));
|
|
#endif
|
|
|
|
#ifdef TRACE_TO_APP
|
|
if (app_notify_cb) {
|
|
app_notify_cb(HAL_TRACE_STATE_CRASH_END);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
if (cp_notify_cb) {
|
|
cp_notify_cb(HAL_TRACE_STATE_CRASH_END);
|
|
}
|
|
SAFE_PROGRAM_STOP();
|
|
}
|
|
#endif
|
|
#endif // CRASH_DUMP_ENABLE
|
|
|
|
#endif // DEBUG || REL_TRACE_ENABLE
|
|
|
|
hal_trace_crash_end();
|
|
}
|
|
|
|
void NORETURN NAKED hal_trace_assert_dump(ASSERT_DUMP_ARGS) {
|
|
asm volatile("subs sp, sp, #4*" TO_STRING(
|
|
STACK_DUMP_CNT_PREV) ";"
|
|
".cfi_def_cfa_offset 4*" TO_STRING(
|
|
STACK_DUMP_CNT_PREV) ";"
|
|
"push {r0, r1};"
|
|
"ldr r0, =crash_buf;"
|
|
"ldr r1, [sp];"
|
|
"str r1, [r0], 4;"
|
|
"ldr r1, [sp, 4];"
|
|
"str r1, [r0], 4;"
|
|
"stmia r0!, {r2-r12};"
|
|
"add r1, sp, "
|
|
"#4*(2+" TO_STRING(
|
|
STACK_DUMP_CNT_PREV) ")"
|
|
";"
|
|
"s"
|
|
"t"
|
|
"r"
|
|
" "
|
|
"r"
|
|
"1"
|
|
","
|
|
" "
|
|
"["
|
|
"r"
|
|
"0"
|
|
"]"
|
|
","
|
|
" "
|
|
"4"
|
|
";"
|
|
"s"
|
|
"t"
|
|
"r"
|
|
" "
|
|
"l"
|
|
"r"
|
|
","
|
|
" "
|
|
"["
|
|
"r"
|
|
"0"
|
|
"]"
|
|
","
|
|
" "
|
|
"4"
|
|
";"
|
|
"p"
|
|
"o"
|
|
"p"
|
|
" "
|
|
"{"
|
|
"r"
|
|
"0"
|
|
","
|
|
" "
|
|
"r"
|
|
"1"
|
|
"}"
|
|
";"
|
|
"b"
|
|
"."
|
|
"w"
|
|
" "
|
|
"h"
|
|
"a"
|
|
"l"
|
|
"_"
|
|
"t"
|
|
"r"
|
|
"a"
|
|
"c"
|
|
"e"
|
|
"_"
|
|
"a"
|
|
"s"
|
|
"s"
|
|
"e"
|
|
"r"
|
|
"t"
|
|
"_"
|
|
"d"
|
|
"u"
|
|
"m"
|
|
"p"
|
|
"_"
|
|
"i"
|
|
"n"
|
|
"t"
|
|
"e"
|
|
"r"
|
|
"n"
|
|
"a"
|
|
"l"
|
|
";");
|
|
}
|
|
|
|
#ifdef FAULT_DUMP
|
|
static void hal_trace_fill_exception_info(struct EXCEPTION_INFO_T *info,
|
|
const uint32_t *regs,
|
|
const uint32_t *extra,
|
|
uint32_t extra_len) {
|
|
info->ID = HAL_TRACE_EXCEPTION_ID;
|
|
info->CPU_ID = get_cpu_id_tag();
|
|
info->REGS = regs;
|
|
#ifdef __ARM_ARCH_ISA_ARM
|
|
info->extra = extra;
|
|
info->extra_len = extra_len;
|
|
#else
|
|
info->MSP = __get_MSP();
|
|
info->PSP = __get_PSP();
|
|
info->PRIMASK = regs[17];
|
|
info->FAULTMASK = __get_FAULTMASK();
|
|
info->BASEPRI = __get_BASEPRI();
|
|
info->CONTROL = __get_CONTROL();
|
|
info->ICSR = SCB->ICSR;
|
|
info->AIRCR = SCB->AIRCR;
|
|
info->SCR = SCB->SCR;
|
|
info->CCR = SCB->CCR;
|
|
info->SHCSR = SCB->SHCSR;
|
|
info->CFSR = SCB->CFSR;
|
|
info->HFSR = SCB->HFSR;
|
|
info->AFSR = SCB->AFSR;
|
|
info->MMFAR = SCB->MMFAR;
|
|
info->BFAR = SCB->BFAR;
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
info->MSPLIM = __get_MSPLIM();
|
|
info->PSPLIM = __get_PSPLIM();
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
#ifdef __ARM_ARCH_ISA_ARM
|
|
static void hal_trace_print_fault_info_ca(const struct EXCEPTION_INFO_T *info) {
|
|
const struct FAULT_REGS_T *fregs;
|
|
const uint32_t *extra;
|
|
// uint32_t extra_len;
|
|
enum EXCEPTION_ID_T id;
|
|
int len;
|
|
uint32_t val;
|
|
const char *desc;
|
|
|
|
fregs = (const struct FAULT_REGS_T *)info->REGS;
|
|
extra = info->extra;
|
|
// extra_len = info->extra_len;
|
|
|
|
id = (enum EXCEPTION_ID_T)extra[0];
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "PC =%08X",
|
|
(unsigned)fregs->r[15]);
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
", ExceptionNumber=%d" NEW_LINE_STR, id);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
hal_trace_print_common_registers(fregs->r);
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "SPSR=%08X",
|
|
(unsigned)fregs->spsr);
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, ", APSR=%c%c%c%c%c",
|
|
(fregs->spsr & (1 << 31)) ? 'N' : 'n',
|
|
(fregs->spsr & (1 << 30)) ? 'Z' : 'z',
|
|
(fregs->spsr & (1 << 29)) ? 'C' : 'c',
|
|
(fregs->spsr & (1 << 28)) ? 'V' : 'v',
|
|
(fregs->spsr & (1 << 27)) ? 'Q' : 'q');
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, ", XC=%c%c%c%c%c",
|
|
(fregs->spsr & (1 << 9)) ? 'E' : 'e',
|
|
(fregs->spsr & (1 << 8)) ? 'A' : 'a',
|
|
(fregs->spsr & (1 << 7)) ? 'I' : 'i',
|
|
(fregs->spsr & (1 << 6)) ? 'F' : 'f',
|
|
(fregs->spsr & (1 << 5)) ? 'T' : 't');
|
|
val = fregs->spsr & 0x1F;
|
|
if (val == 0x10) {
|
|
desc = "USR";
|
|
} else if (val == 0x11) {
|
|
desc = "FIQ";
|
|
} else if (val == 0x12) {
|
|
desc = "IRQ";
|
|
} else if (val == 0x13) {
|
|
desc = "SVC";
|
|
} else if (val == 0x16) {
|
|
desc = "MON";
|
|
} else if (val == 0x17) {
|
|
desc = "ABT";
|
|
} else if (val == 0x1A) {
|
|
desc = "HYP";
|
|
} else if (val == 0x1B) {
|
|
desc = "UND";
|
|
} else if (val == 0x1F) {
|
|
desc = "SYS";
|
|
} else {
|
|
desc = "UNKNOWN";
|
|
}
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, ", MODE=%02X (%s)",
|
|
(unsigned)val, desc);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
if (id == EXCEPTION_UNDEF) {
|
|
} else if (id == EXCEPTION_SVC) {
|
|
} else if (id == EXCEPTION_PABT) {
|
|
} else if (id == EXCEPTION_DABT) {
|
|
} else {
|
|
}
|
|
}
|
|
#else
|
|
static void hal_trace_print_fault_info_cm(const struct EXCEPTION_INFO_T *info) {
|
|
const uint32_t *regs;
|
|
int len;
|
|
uint32_t val;
|
|
uint32_t primask;
|
|
|
|
regs = info->REGS;
|
|
primask = regs[17];
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "PC =%08X", (unsigned)regs[15]);
|
|
val = __get_IPSR();
|
|
if (val == 0) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
", ThreadMode" NEW_LINE_STR);
|
|
} else {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
", ExceptionNumber=%d" NEW_LINE_STR, (int)val - 16);
|
|
}
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
hal_trace_print_common_registers(regs);
|
|
hal_trace_print_special_stack_registers();
|
|
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
|
|
len = snprintf(
|
|
crash_buf, sizeof(crash_buf),
|
|
"PRIMASK=%02X, FAULTMASK=%02X, BASEPRI=%02X, CONTROL=%02X" NEW_LINE_STR,
|
|
(unsigned)primask, (unsigned)__get_FAULTMASK(), (unsigned)__get_BASEPRI(),
|
|
(unsigned)__get_CONTROL());
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "XPSR=%08X", (unsigned)regs[16]);
|
|
len += snprintf(
|
|
&crash_buf[len], sizeof(crash_buf) - len, ", APSR=%c%c%c%c%c",
|
|
(regs[16] & (1 << 31)) ? 'N' : 'n', (regs[16] & (1 << 30)) ? 'Z' : 'z',
|
|
(regs[16] & (1 << 29)) ? 'C' : 'c', (regs[16] & (1 << 28)) ? 'V' : 'v',
|
|
(regs[16] & (1 << 27)) ? 'Q' : 'q');
|
|
val = regs[16] & 0xFF;
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
", EPSR=%08X, IPSR=%02X", (unsigned)(regs[16] & 0x0700FC00),
|
|
(unsigned)val);
|
|
if (val == 0) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (NoException)");
|
|
}
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf),
|
|
"ICSR =%08X, AIRCR=%08X, SCR =%08X, CCR =%08X" NEW_LINE_STR,
|
|
(unsigned)info->ICSR, (unsigned)info->AIRCR,
|
|
(unsigned)info->SCR, (unsigned)info->CCR);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf),
|
|
"SHCSR=%08X, CFSR =%08X, HFSR =%08X, AFSR =%08X" NEW_LINE_STR,
|
|
(unsigned)info->SHCSR, (unsigned)info->CFSR,
|
|
(unsigned)info->HFSR, (unsigned)info->AFSR);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf),
|
|
"MMFAR=%08X, BFAR =%08X" NEW_LINE_STR, (unsigned)info->MMFAR,
|
|
(unsigned)info->BFAR);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
|
|
if (info->HFSR & (1 << 30)) {
|
|
len = snprintf(crash_buf, sizeof(crash_buf),
|
|
"(Escalation HardFault)" NEW_LINE_STR);
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
}
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "FaultInfo :");
|
|
if ((info->SHCSR & 0x3F) == 0) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (None)");
|
|
} else {
|
|
if (info->SHCSR & (1 << 0)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (MemFault)");
|
|
}
|
|
if (info->SHCSR & (1 << 1)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (BusFault)");
|
|
}
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
if (info->SHCSR & (1 << 2)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (HardFault)");
|
|
}
|
|
#endif
|
|
if (info->SHCSR & (1 << 3)) {
|
|
len +=
|
|
snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (UsageFault)");
|
|
}
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
if (info->SHCSR & (1 << 4)) {
|
|
len +=
|
|
snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (SecureFault)");
|
|
}
|
|
if (info->SHCSR & (1 << 5)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (NMI)");
|
|
}
|
|
#endif
|
|
}
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
|
|
len = snprintf(crash_buf, sizeof(crash_buf), "FaultCause:");
|
|
if (info->CFSR == 0) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (None)");
|
|
} else {
|
|
if (info->CFSR & (1 << 0)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Instruction access violation)");
|
|
}
|
|
if (info->CFSR & (1 << 1)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Data access violation)");
|
|
}
|
|
if (info->CFSR & (1 << 3)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (MemFault on unstacking for a return from exception)");
|
|
}
|
|
if (info->CFSR & (1 << 4)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (MemFault on stacking for exception entry)");
|
|
}
|
|
if (info->CFSR & (1 << 5)) {
|
|
len +=
|
|
snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (MemFault during floating-point lazy state preservation)");
|
|
}
|
|
if (info->CFSR & (1 << 7)) {
|
|
len +=
|
|
snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (MMFAR valid)");
|
|
}
|
|
if (len) {
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
hal_trace_flush_buffer();
|
|
len = 0;
|
|
}
|
|
if (info->CFSR & (1 << 8)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Instruction bus error)");
|
|
}
|
|
if (info->CFSR & (1 << 9)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Precise data bus error)");
|
|
}
|
|
#ifndef __ARM_ARCH_8M_MAIN__
|
|
if (info->CFSR & (1 << 10)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Imprecise data bus error)");
|
|
}
|
|
#endif
|
|
if (info->CFSR & (1 << 11)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (BusFault on unstacking for a return from exception)");
|
|
}
|
|
if (info->CFSR & (1 << 12)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (BusFault on stacking for exception entry)");
|
|
}
|
|
if (info->CFSR & (1 << 13)) {
|
|
len +=
|
|
snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (BusFault during floating-point lazy state preservation)");
|
|
}
|
|
if (info->CFSR & (1 << 15)) {
|
|
len +=
|
|
snprintf(&crash_buf[len], sizeof(crash_buf) - len, " (BFAR valid)");
|
|
}
|
|
if (len) {
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
hal_trace_flush_buffer();
|
|
len = 0;
|
|
}
|
|
if (info->CFSR & (1 << 16)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Undefined instruction UsageFault)");
|
|
}
|
|
if (info->CFSR & (1 << 17)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Invalid state UsageFault)");
|
|
}
|
|
if (info->CFSR & (1 << 18)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Invalid PC load by EXC_RETURN UsageFault)");
|
|
}
|
|
if (info->CFSR & (1 << 19)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (No coprocessor UsageFault)");
|
|
}
|
|
#ifdef __ARM_ARCH_8M_MAIN__
|
|
if (info->CFSR & (1 << 20)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Stack overflow UsageFault)");
|
|
}
|
|
#endif
|
|
if (info->CFSR & (1 << 24)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Unaligned access UsageFault)");
|
|
}
|
|
if (info->CFSR & (1 << 25)) {
|
|
len += snprintf(&crash_buf[len], sizeof(crash_buf) - len,
|
|
" (Divide by zero UsageFault)");
|
|
}
|
|
}
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
}
|
|
#endif
|
|
|
|
static void hal_trace_print_fault_info(const struct EXCEPTION_INFO_T *info) {
|
|
#ifdef __ARM_ARCH_ISA_ARM
|
|
hal_trace_print_fault_info_ca(info);
|
|
#else
|
|
hal_trace_print_fault_info_cm(info);
|
|
#endif
|
|
}
|
|
#endif // DEBUG || REL_TRACE_ENABLE
|
|
|
|
void hal_trace_fault_dump(const uint32_t *regs, const uint32_t *extra,
|
|
uint32_t extra_len) {
|
|
struct EXCEPTION_INFO_T info;
|
|
|
|
int_lock_global();
|
|
|
|
hal_trace_fill_exception_info(&info, regs, extra, extra_len);
|
|
|
|
*(volatile uint32_t *)RAM_BASE = (uint32_t)&info;
|
|
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
|
|
static const char title[] = NEW_LINE_STR "### EXCEPTION ###" NEW_LINE_STR;
|
|
int len;
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
bool full_dump = true;
|
|
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
full_dump = false;
|
|
if (cp_notify_cb) {
|
|
cp_notify_cb(HAL_TRACE_STATE_CRASH_FAULT_START);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (full_dump) {
|
|
#ifdef TRACE_TO_APP
|
|
if (app_notify_cb) {
|
|
app_notify_cb(HAL_TRACE_STATE_CRASH_FAULT_START);
|
|
}
|
|
if (app_crash_custom_cb == NULL) {
|
|
app_output_enabled = true;
|
|
}
|
|
#endif
|
|
|
|
crash_dump_onprocess = true;
|
|
for (uint8_t i = 0; i < 10; i++) {
|
|
REL_TRACE_IMM(0, " "
|
|
" ");
|
|
REL_TRACE_IMM(0, " "
|
|
" " NEW_LINE_STR);
|
|
hal_sys_timer_delay(MS_TO_TICKS(50));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
hal_sysfreq_req(HAL_SYSFREQ_USER_INIT, HAL_CMU_FREQ_52M);
|
|
|
|
len = hal_trace_print_time(LOG_LEVEL_CRITICAL, LOG_MODULE_NONE, &crash_buf[0],
|
|
sizeof(crash_buf));
|
|
if (len > 0) {
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
hal_trace_output((unsigned char *)crash_buf, len);
|
|
}
|
|
hal_trace_output((unsigned char *)title, sizeof(title));
|
|
|
|
hal_trace_print_fault_info(&info);
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
hal_trace_print_stack(regs[13]);
|
|
|
|
hal_trace_print_backtrace(regs[13], TRACE_BACKTRACE_SEARCH_WORD,
|
|
TRACE_BACKTRACE_NUM);
|
|
|
|
hal_trace_output((const unsigned char *)newline, sizeof(newline));
|
|
|
|
hal_trace_flush_buffer();
|
|
|
|
#ifdef CRASH_DUMP_ENABLE
|
|
if (full_dump) {
|
|
hal_trace_crash_dump_callback();
|
|
hal_trace_flush_buffer();
|
|
|
|
#ifndef __ARM_ARCH_ISA_ARM
|
|
#ifdef TRACE_TO_APP
|
|
// Crash-Dump "Lite-Version"
|
|
if (app_crash_custom_cb) {
|
|
app_crash_custom_cb((unsigned char *)regs,
|
|
CRASH_DUMP_REGISTERS_NUM_BYTES);
|
|
stack = (uint32_t *)(__get_MSP() & ~3);
|
|
app_crash_custom_cb((unsigned char *)stack,
|
|
((CRASH_DUMP_STACK_NUM_BYTES) / 2));
|
|
stack = (uint32_t *)(__get_PSP() & ~3);
|
|
app_crash_custom_cb((unsigned char *)stack,
|
|
((CRASH_DUMP_STACK_NUM_BYTES) / 2));
|
|
}
|
|
#endif
|
|
|
|
#ifdef CORE_DUMP
|
|
{
|
|
static CrashCatcherExceptionRegisters eregs;
|
|
|
|
eregs.msp = info.MSP;
|
|
eregs.psp = info.PSP;
|
|
eregs.exceptionPSR = regs[16] & 0x0700FE00;
|
|
eregs.r4 = regs[4];
|
|
eregs.r5 = regs[5];
|
|
eregs.r6 = regs[6];
|
|
eregs.r7 = regs[7];
|
|
eregs.r8 = regs[8];
|
|
eregs.r9 = regs[9];
|
|
eregs.r10 = regs[10];
|
|
eregs.r11 = regs[11];
|
|
eregs.exceptionLR = regs[14];
|
|
CrashCatcher_Entry(&eregs);
|
|
}
|
|
#endif
|
|
#endif // !__ARM_ARCH_ISA_ARM
|
|
|
|
#ifdef TRACE_TO_APP
|
|
if (app_notify_cb) {
|
|
app_notify_cb(HAL_TRACE_STATE_CRASH_END);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef CP_TRACE_ENABLE
|
|
if (get_cpu_id()) {
|
|
if (cp_notify_cb) {
|
|
cp_notify_cb(HAL_TRACE_STATE_CRASH_END);
|
|
}
|
|
SAFE_PROGRAM_STOP();
|
|
}
|
|
#endif
|
|
#endif // CRASH_DUMP_ENABLE
|
|
|
|
#endif // DEBUG || REL_TRACE_ENABLE
|
|
|
|
hal_trace_crash_end();
|
|
}
|
|
|
|
#ifndef __ARM_ARCH_ISA_ARM
|
|
static void NAKED hal_trace_fault_handler(void) {
|
|
// TODO: Save FP registers (and check lazy Floating-point context
|
|
// preservation)
|
|
asm volatile(
|
|
// Check EXC_RETURN.SPSEL (bit[2])
|
|
"tst lr, #0x04;"
|
|
"ite eq;"
|
|
// Using MSP
|
|
"mrseq r3, msp;"
|
|
// Using PSP
|
|
"mrsne r3, psp;"
|
|
// Check EXC_RETURN.FType (bit[4])
|
|
"tst lr, #0x10;"
|
|
"ite eq;"
|
|
// FPU context saved
|
|
"moveq r1, #1;"
|
|
// No FPU context
|
|
"movne r1, #0;"
|
|
#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
|
"mov, r0, #0;"
|
|
// -- Check EXC_RETURN.S (bit[6])
|
|
"tst lr, #0x40;"
|
|
"beq _done_sec_cntx;"
|
|
// -- Check EXC_RETURN.ES (bit[0])
|
|
"tst lr, #0x01;"
|
|
"bne _done_sec_cntx;"
|
|
// -- Check EXC_RETURN.DCRS (bit[5])
|
|
"tst lr, #0x20;"
|
|
"bne _done_sec_cntx;"
|
|
"mov, r0, #1;"
|
|
"push {r4-r11};"
|
|
"add r3, #2*4;"
|
|
"ldm r3!, {r4-r11};"
|
|
"_done_sec_cntx:;"
|
|
"push {r0};"
|
|
#endif
|
|
// Make room for r0-r15,psr,primask
|
|
"sub sp, #18*4;"
|
|
".cfi_def_cfa_offset 18*4;"
|
|
// Save r4-r11
|
|
"add r0, sp, #4*4;"
|
|
"stm r0, {r4-r11};"
|
|
".cfi_offset r4, -14*4;"
|
|
".cfi_offset r5, -13*4;"
|
|
".cfi_offset r6, -12*4;"
|
|
".cfi_offset r7, -11*4;"
|
|
".cfi_offset r8, -10*4;"
|
|
".cfi_offset r9, -9*4;"
|
|
".cfi_offset r10, -8*4;"
|
|
".cfi_offset r11, -7*4;"
|
|
// Save r0-r3
|
|
"ldm r3, {r4-r7};"
|
|
"stm sp, {r4-r7};"
|
|
".cfi_offset r0, -18*4;"
|
|
".cfi_offset r1, -17*4;"
|
|
".cfi_offset r2, -16*4;"
|
|
".cfi_offset r3, -15*4;"
|
|
// Save r12
|
|
"ldr r0, [r3, #4*4];"
|
|
"str r0, [sp, #12*4];"
|
|
".cfi_offset r12, -6*4;"
|
|
// Save sp
|
|
"teq r1, 0;"
|
|
"itt eq;"
|
|
"addeq r0, r3, #8*4;"
|
|
"beq _done_stack_frame;"
|
|
"add r0, r3, #(8+18)*4;"
|
|
#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
|
// -- Check EXC_RETURN.S (bit[6])
|
|
"tst lr, #0x40;"
|
|
"beq _done_stack_frame;"
|
|
// -- Check FPCCR_S.TS (bit[26])
|
|
"ldr r4, =0xE000EF34;"
|
|
"ldr r4, [r4];"
|
|
"tst r4, #(1 << 26);"
|
|
"it ne;"
|
|
"addne r3, #16*4;"
|
|
#endif
|
|
"_done_stack_frame:;"
|
|
// -- Check RETPSR.SPREALIGN (bit[9])
|
|
"ldr r4, [r3, #7*4];"
|
|
"tst r4, #(1 << 9);"
|
|
"it ne;"
|
|
"addne r0, #4;"
|
|
"str r0, [sp, #13*4];"
|
|
// Save lr
|
|
"ldr r0, [r3, #5*4];"
|
|
"str r0, [sp, #14*4];"
|
|
// Save pc
|
|
"ldr r0, [r3, #6*4];"
|
|
"str r0, [sp, #15*4];"
|
|
// Save PSR
|
|
"ldr r0, [r3, #7*4];"
|
|
"str r0, [sp, #16*4];"
|
|
// Save primask
|
|
"mrs r0, primask;"
|
|
"str r0, [sp, #17*4];"
|
|
// Save current exception lr
|
|
"mov r4, lr;"
|
|
".cfi_register lr, r4;"
|
|
// Invoke the fault handler
|
|
"mov r0, sp;"
|
|
"ldr r2, =hal_trace_fault_dump;"
|
|
"blx r2;"
|
|
// Restore current exception lr
|
|
"mov lr, r4;"
|
|
// Restore r4-r7
|
|
"add r0, sp, #4*4;"
|
|
"ldm r0, {r4-r7};"
|
|
"mov r0, r3;"
|
|
// Restore sp
|
|
"add sp, #18*4;"
|
|
#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
|
"pop {r0};"
|
|
"cmp r0, #1;"
|
|
"it eq;"
|
|
"popeq {r4-r11};"
|
|
#endif
|
|
"bx lr;"
|
|
"");
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#define HAL_TRACE_RX_HEAD_SIZE 4
|
|
#define HAL_TRACE_RX_NAME_SIZE 20
|
|
#define HAL_TRACE_RX_BUF_SIZE 1024
|
|
#define HAL_TRACE_RX_ROLE_NUM 6
|
|
|
|
#define HAL_TRACE_RX_HEAD '['
|
|
#define HAL_TRACE_RX_END ']'
|
|
#define HAL_TRACE_RX_SEPARATOR ','
|
|
|
|
// static struct HAL_DMA_CH_CFG_T dma_cfg_rx;
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
static struct HAL_DMA_DESC_T dma_desc_rx;
|
|
#endif
|
|
|
|
typedef struct {
|
|
char *name;
|
|
uint32_t len;
|
|
uint8_t *buf;
|
|
} HAL_TRACE_RX_CFG_T;
|
|
|
|
typedef struct {
|
|
char name[HAL_TRACE_RX_NAME_SIZE];
|
|
HAL_TRACE_RX_CALLBACK_T callback;
|
|
} HAL_TRACE_RX_LIST_T;
|
|
|
|
typedef struct {
|
|
uint32_t list_num;
|
|
HAL_TRACE_RX_LIST_T list[HAL_TRACE_RX_ROLE_NUM];
|
|
|
|
uint32_t rx_enable;
|
|
uint32_t pos;
|
|
uint8_t buf[HAL_TRACE_RX_BUF_SIZE];
|
|
} HAL_TRACE_RX_T;
|
|
|
|
#if defined(_AUTO_TEST_)
|
|
extern int auto_test_prase(uint8_t *cmd);
|
|
#endif
|
|
|
|
HAL_TRACE_RX_T hal_trace_rx;
|
|
|
|
int hal_trace_rx_dump_list(void) {
|
|
for (int i = 0; i < HAL_TRACE_RX_ROLE_NUM; i++) {
|
|
TRACE(2, "%d: %s", i, hal_trace_rx.list[i].name);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_rx_is_in_list(const char *name) {
|
|
for (int i = 0; i < HAL_TRACE_RX_ROLE_NUM; i++) {
|
|
if (!strcmp(hal_trace_rx.list[i].name, name)) {
|
|
return i;
|
|
}
|
|
}
|
|
hal_trace_rx_dump_list();
|
|
// TRACE(1,"%s", hal_trace_rx.list[0].name);
|
|
// TRACE(1,"%s", name);
|
|
// TRACE(1,"%d", strlen(hal_trace_rx.list[0].name));
|
|
// TRACE(1,"%d", strlen(name));
|
|
// TRACE(1,"%d", strcmp(hal_trace_rx.list[0].name, name));
|
|
return -1;
|
|
}
|
|
|
|
int hal_trace_rx_add_item_to_list(const char *name,
|
|
HAL_TRACE_RX_CALLBACK_T callback) {
|
|
for (int i = 0; i < HAL_TRACE_RX_ROLE_NUM; i++) {
|
|
if (hal_trace_rx.list[i].name[0] == 0) {
|
|
memcpy(hal_trace_rx.list[i].name, name, strlen(name));
|
|
hal_trace_rx.list[i].callback = callback;
|
|
hal_trace_rx.list_num++;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int hal_trace_rx_del_item_to_list(int id) {
|
|
memset(hal_trace_rx.list[id].name, 0, sizeof(hal_trace_rx.list[id].name));
|
|
hal_trace_rx.list[id].callback = NULL;
|
|
hal_trace_rx.list_num--;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_rx_register(const char *name, HAL_TRACE_RX_CALLBACK_T callback) {
|
|
TRACE(2, "[%s] Add %s", __func__, name);
|
|
if (hal_trace_rx_is_in_list(name) == -1) {
|
|
hal_trace_rx_add_item_to_list(name, callback);
|
|
return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int hal_trace_rx_deregister(const char *name) {
|
|
int id = 0;
|
|
|
|
id = hal_trace_rx_is_in_list(name);
|
|
|
|
if (id != -1) {
|
|
hal_trace_rx_del_item_to_list(id);
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
static int hal_trace_rx_reset(void) {
|
|
|
|
hal_trace_rx.pos = 0;
|
|
memset(hal_trace_rx.buf, 0, HAL_TRACE_RX_BUF_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
// [test,12,102.99]
|
|
static int hal_trace_rx_parse(int8_t *buf, HAL_TRACE_RX_CFG_T *cfg) {
|
|
// TRACE(1,"[%s] Start...", __func__);
|
|
int pos = 0;
|
|
int len = 0;
|
|
|
|
for (; pos < HAL_TRACE_RX_HEAD_SIZE; pos++) {
|
|
if (buf[pos] == HAL_TRACE_RX_HEAD) {
|
|
buf[pos] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pos == HAL_TRACE_RX_HEAD_SIZE) {
|
|
return 3;
|
|
}
|
|
|
|
pos++;
|
|
|
|
cfg->name = (char *)(buf + pos);
|
|
for (; pos < HAL_TRACE_RX_NAME_SIZE + HAL_TRACE_RX_HEAD_SIZE; pos++) {
|
|
if (buf[pos] == HAL_TRACE_RX_SEPARATOR) {
|
|
buf[pos] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// TRACE(1,"Step1: %s", cfg->name);
|
|
// TRACE(1,"%d", strlen(cfg->name));
|
|
|
|
if (pos == HAL_TRACE_RX_NAME_SIZE) {
|
|
return 1;
|
|
}
|
|
|
|
pos++;
|
|
|
|
len = 0;
|
|
cfg->buf = (uint8_t *)(buf + pos);
|
|
for (; pos < HAL_TRACE_RX_BUF_SIZE; pos++) {
|
|
if (buf[pos] == HAL_TRACE_RX_END) {
|
|
buf[pos] = 0;
|
|
break;
|
|
}
|
|
len++;
|
|
}
|
|
cfg->len = len;
|
|
if (pos == HAL_TRACE_RX_BUF_SIZE) {
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(IBRT)
|
|
void app_ibrt_peripheral_automate_test(const char *ibrt_cmd, uint32_t cmd_len);
|
|
void app_ibrt_peripheral_perform_test(const char *ibrt_cmd);
|
|
#endif
|
|
|
|
int hal_trace_rx_process(uint8_t *buf, uint32_t len) {
|
|
HAL_TRACE_RX_CFG_T cfg;
|
|
int id = 0;
|
|
int res = 0;
|
|
|
|
#if defined(IBRT)
|
|
if (buf && strlen((char *)buf) >= 10 &&
|
|
((strncmp((char *)buf, "auto_test:", 10) == 0) ||
|
|
(strncmp((char *)buf, "ibrt_test:", 10) == 0))) {
|
|
#ifdef BES_AUTOMATE_TEST
|
|
app_ibrt_peripheral_automate_test((char *)(buf + 10), len - 10);
|
|
#else
|
|
app_ibrt_peripheral_perform_test((char *)(buf + 10));
|
|
#endif
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
res = hal_trace_rx_parse((int8_t *)buf, &cfg);
|
|
|
|
if (res) {
|
|
TRACE(1, "ERROR: hal_trace_rx_parse %d", res);
|
|
return 1;
|
|
} else {
|
|
// TRACE(1,"%s rx OK", cfg.name);
|
|
}
|
|
|
|
id = hal_trace_rx_is_in_list(cfg.name);
|
|
|
|
if (id == -1) {
|
|
TRACE(1, "%s is invalid", cfg.name);
|
|
return -1;
|
|
}
|
|
|
|
if (hal_trace_rx.list[id].callback) {
|
|
hal_trace_rx.list[id].callback(cfg.buf, cfg.len);
|
|
} else {
|
|
TRACE(1, "%s has not callback", hal_trace_rx.list[id].name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#if (defined(DEBUG) || defined(REL_TRACE_ENABLE))
|
|
void hal_trace_rx_start(void) {
|
|
uint32_t desc_cnt = 1;
|
|
union HAL_UART_IRQ_T mask;
|
|
|
|
mask.reg = 0;
|
|
mask.BE = 0;
|
|
mask.FE = 0;
|
|
mask.OE = 0;
|
|
mask.PE = 0;
|
|
mask.RT = 1;
|
|
|
|
hal_uart_dma_recv_mask(trace_uart, hal_trace_rx.buf, HAL_TRACE_RX_BUF_SIZE,
|
|
&dma_desc_rx, &desc_cnt, &mask);
|
|
}
|
|
|
|
void hal_trace_rx_irq_handler(uint32_t xfer_size, int dma_error,
|
|
union HAL_UART_IRQ_T status) {
|
|
int res;
|
|
// TRACE(4,"[%s] %d, %d, %d", __func__, xfer_size, dma_error, status);
|
|
|
|
if (xfer_size) {
|
|
hal_trace_rx.buf[xfer_size] = 0;
|
|
#if defined(_AUTO_TEST_)
|
|
res = auto_test_prase(hal_trace_rx.buf);
|
|
if (res) {
|
|
TRACE(2, "%s:auto_test_prase prase data error, err_code = %d", __func__,
|
|
res);
|
|
}
|
|
#else
|
|
// TRACE(2,"[%s] RX = %s", __func__, hal_trace_rx.buf);
|
|
res = hal_trace_rx_process(hal_trace_rx.buf, xfer_size);
|
|
if (res) {
|
|
TRACE(2, "%s:hal_trace_rx_process prase data error, err_code = %d",
|
|
__func__, res);
|
|
}
|
|
#endif
|
|
hal_trace_rx_reset();
|
|
hal_trace_rx_start();
|
|
}
|
|
}
|
|
|
|
uint32_t app_test_callback(unsigned char *buf, uint32_t len) {
|
|
TRACE(2, "[%s] len = %d", __func__, len);
|
|
|
|
// Process string
|
|
int num_int = 0;
|
|
int num_float = 0.0;
|
|
TRACE(2, "[%s] %s", __func__, buf);
|
|
hal_trace_rx_parser((char *)buf, "%d,%d", &num_int, &num_float);
|
|
|
|
TRACE(3, "[%s] %d:%d", __func__, num_int, num_float);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_rx_open() {
|
|
hal_uart_irq_set_dma_handler(trace_uart, hal_trace_rx_irq_handler, NULL);
|
|
hal_trace_rx_start();
|
|
|
|
hal_trace_rx_register("test", (HAL_TRACE_RX_CALLBACK_T)app_test_callback);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_trace_rx_reopen() {
|
|
hal_uart_reopen(trace_uart, &uart_rx_enable_cfg);
|
|
hal_trace_rx_open();
|
|
|
|
return 0;
|
|
}
|
|
#endif
|