Skip to content

Instantly share code, notes, and snippets.

@andyturk
Created July 31, 2019 14:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save andyturk/23a7cdecdb411f7b9b8b64e53160e99c to your computer and use it in GitHub Desktop.
Save andyturk/23a7cdecdb411f7b9b8b64e53160e99c to your computer and use it in GitHub Desktop.
SystemView code
#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
// -*- 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