-
-
Save andyturk/23a7cdecdb411f7b9b8b64e53160e99c to your computer and use it in GitHub Desktop.
SystemView code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "versame/sysview.h" | |
#include "panamint/rtx5/kernel.h" | |
#include "panamint/rtx5/thread.h" | |
#include "rtx_os.h" | |
#include "versame/countof.h" | |
#include "versame/mcu_device.h" | |
#include <cassert> | |
#include <cstring> | |
using namespace panamint::rtx5; | |
using namespace versame; | |
enum SystemViewEventId { | |
Preempt = 33, | |
KernelSuspend, | |
KernelResume, | |
}; | |
namespace { | |
SystemView *instance = nullptr; | |
bool kernel_initialized = false; | |
uint32_t id(osThreadId_t thread) { return reinterpret_cast<uint32_t>(thread); } | |
uint32_t id(const osRtxThread_t &thread) { | |
return reinterpret_cast<uint32_t>(&thread); | |
} | |
/// Get Pending SV (Service Call) Flag | |
/// \return Pending SV Flag | |
inline uint8_t GetPendSV (void) { | |
return ((uint8_t)((SCB->ICSR & (SCB_ICSR_PENDSVSET_Msk)) >> 24)); | |
} | |
uint64_t get_time_callback() { | |
switch (osKernelGetState()) { | |
case osKernelRunning: { | |
uint16_t uptime_ticks = osKernelGetTickCount(); | |
return (uptime_ticks * 1000000) / osKernelGetTickFreq(); | |
} | |
case osKernelInactive: | |
return 0; | |
case osKernelReady: | |
case osKernelLocked: | |
case osKernelSuspended: | |
case osKernelError: | |
case osKernelReserved: | |
default: | |
return osRtxInfo.kernel.tick; | |
} | |
} | |
void send_thread_info(const osRtxThread_t &thread) { | |
SEGGER_SYSVIEW_TASKINFO info; | |
memset(&info, 0, sizeof(info)); | |
info.TaskID = id(thread); | |
info.sName = thread.name; | |
info.Prio = thread.priority; | |
info.StackBase = reinterpret_cast<uint32_t>(thread.stack_mem); | |
info.StackSize = thread.stack_size; | |
SEGGER_SYSVIEW_SendTaskInfo(&info); | |
} | |
void send_thread_info(const Thread &thread) { | |
send_thread_info(thread.get_extended_context()); | |
} | |
void send_task_list_callback() { | |
if (kernel_initialized) { | |
Thread * thread_array[20]; | |
unsigned thread_count = | |
Thread::enumerate_threads(thread_array, countof(thread_array)); | |
for (unsigned i = 0; i < thread_count; ++i) { | |
if (thread_array[i] != nullptr) { | |
send_thread_info(*thread_array[i]); | |
} | |
} | |
if (osRtxInfo.thread.idle != nullptr) { | |
send_thread_info(*osRtxInfo.thread.idle); | |
} | |
if (osRtxInfo.timer.thread != nullptr) { | |
send_thread_info(*osRtxInfo.timer.thread); | |
} | |
} | |
} | |
void send_system_description_callback() { | |
assert(instance != nullptr); | |
SEGGER_SYSVIEW_SendSysDesc(instance->get_system_description()); | |
} | |
} // namespace | |
SystemView::SystemView() | |
: sysview_functions_{&get_time_callback, &send_task_list_callback} | |
, _state{UNINITIALIZED} | |
{ | |
assert(instance == nullptr); | |
instance = this; | |
} | |
extern "C" { | |
extern uint32_t SystemCoreClock; | |
} | |
void SystemView::initialize() { | |
if (_state != UNINITIALIZED) return; | |
#if !defined(EVR_RTX_DISABLE) | |
// | |
// If no debugger is connected, the DWT must be enabled by the application | |
// | |
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; | |
// | |
// The cycle counter must be activated in order | |
// to use time related functions. | |
// | |
if ((DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk) == 0) { // Cycle counter supported? | |
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // Enable Cycle counter | |
} | |
SEGGER_SYSVIEW_Init(SystemCoreClock, SystemCoreClock, &sysview_functions_, | |
&send_system_description_callback); | |
SEGGER_SYSVIEW_SetRAMBase(0x20000000); | |
#endif | |
_state = STOPPED; | |
} | |
void SystemView::start() { | |
if (_state != STOPPED) return; | |
#if !defined(EVR_RTX_DISABLE) | |
SEGGER_SYSVIEW_Start(); | |
#endif | |
_state = ACTIVE; | |
} | |
void SystemView::stop() { | |
if (_state != ACTIVE) return; | |
#if !defined(EVR_RTX_DISABLE) | |
SEGGER_SYSVIEW_Stop(); | |
#endif | |
_state = STOPPED; | |
} | |
const char *SystemView::get_system_description() { | |
static char buffer[100]; | |
char kernel_info_string[40]; | |
kernel_version_t version; | |
assert(instance != nullptr); | |
Kernel::get_info(version, kernel_info_string, sizeof(kernel_info_string)); | |
snprintf(buffer, sizeof(buffer), | |
"N=%s," | |
"O=%s," | |
"D=%s," | |
"C=%s," | |
"I=%d", | |
"Application", "RTXv5", "nRF52840", "Cortex-M4", 33); | |
return buffer; | |
} | |
////////////////////////////////////////////////////////////// | |
#if !defined(EVR_RTX_DISABLE) | |
extern "C" { | |
void __assert_func(const char *file, int line, const char *fn, | |
const char *expr) { | |
SEGGER_SYSVIEW_Error(fn); | |
SEGGER_SYSVIEW_Error(expr); | |
asm volatile("bkpt #0"); | |
while (true) | |
; | |
} | |
void SystemView::exit_isr() { | |
if (0 && (GetPendSV() || osRtxInfo.kernel.pendSV)) { | |
SEGGER_SYSVIEW_RecordExitISRToScheduler(); | |
} else { | |
SEGGER_SYSVIEW_RecordExitISR(); | |
} | |
} | |
void EvrRtxKernelInitializeCompleted() { | |
kernel_initialized = true; | |
if (instance != nullptr) { | |
instance->initialize(); | |
send_task_list_callback(); | |
} | |
} | |
void EvrRtxThreadPreempted(osThreadId_t thread_id) { | |
auto thread = reinterpret_cast<const osRtxThread_t *>(thread_id); | |
SEGGER_SYSVIEW_RecordU32(Preempt, (U32)thread); | |
} | |
void EvrRtxThreadCreated(osThreadId_t thread_id) { | |
auto thread = reinterpret_cast<const osRtxThread_t *>(thread_id); | |
send_thread_info(*thread); | |
} | |
void EvrRtxThreadExit(osThreadId_t thread_id) { | |
SEGGER_SYSVIEW_OnTaskTerminate(id(thread_id)); | |
} | |
void EvrRtxThreadUnblocked(osThreadId_t thread_id, uint32_t retval) { | |
SEGGER_SYSVIEW_OnTaskStartReady(id(thread_id)); | |
} | |
void EvrRtxThreadBlocked(osThreadId_t thread_id, uint8_t state, | |
uint32_t retval) { | |
SEGGER_SYSVIEW_OnTaskStopReady(id(thread_id), state); | |
} | |
void EvrRtxKernelSuspended(uint32_t ticks) { | |
SEGGER_SYSVIEW_RecordU32(KernelSuspend, ticks); | |
SEGGER_SYSVIEW_OnIdle(); | |
} | |
void EvrRtxKernelResume(uint32_t sleep_ticks) { | |
SEGGER_SYSVIEW_RecordU32(KernelResume, sleep_ticks); | |
} | |
void EvrRtxThreadSwitched(osThreadId_t thread_id) { | |
// if (thread_id == osRtxInfo.thread.idle) { | |
// SEGGER_SYSVIEW_OnIdle(); | |
// } else { | |
SEGGER_SYSVIEW_OnTaskStartExec(id(thread_id)); | |
// } | |
} | |
} // extern "C" | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -*- Mode:C++ -*- | |
#pragma once | |
#include "SEGGER_SYSVIEW.h" | |
#include "panamint/rtx5/thread.h" | |
#include <cstdint> | |
namespace versame { | |
class SystemView { | |
public: | |
using Thread = panamint::rtx5::Thread; | |
SystemView(); | |
void initialize(); | |
void start(); | |
void stop(); | |
const SEGGER_SYSVIEW_OS_API sysview_functions_; | |
const char * get_system_description(); | |
#if !defined(EVR_RTX_DISABLE) | |
static void enter_isr() { SEGGER_SYSVIEW_RecordEnterISR(); } | |
static void exit_isr(); | |
static void exit_isr_to_scheduler() { | |
SEGGER_SYSVIEW_RecordExitISRToScheduler(); | |
} | |
#else | |
static void enter_isr() {} | |
static void exit_isr() {} | |
static void exit_isr_to_scheduler() {} | |
#endif | |
protected: | |
enum state_t { | |
UNINITIALIZED = 0, | |
STOPPED, | |
ACTIVE, | |
}; | |
state_t _state; | |
}; | |
} // namespace versame |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment