this is using the mbed os version 5-13-1
Embed:
(wiki syntax)
Show/hide line numbers
mbed_memory_status.cpp
00001 /* 00002 mbed Memory Status Helper 00003 Copyright (c) 2017 Max Vilimpoc 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy 00006 of this software and associated documentation files (the "Software"), to deal 00007 in the Software without restriction, including without limitation the rights 00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00009 copies of the Software, and to permit persons to whom the Software is 00010 furnished to do so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in 00013 all copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00021 THE SOFTWARE. 00022 */ 00023 00024 /** 00025 * Purpose: Print out thread info and other useful details using 00026 * only raw serial access. 00027 * 00028 * Based on mbed_board.c's error printing functionality, minus 00029 * pulling in all the printf() code. 00030 */ 00031 00032 // Not great having to pull in all of mbed.h just to get the MBED_VERSION macro, 00033 // but it's the only way to do it for both pre- and post-5.4 releases 00034 // 00035 // If you're only supporting something newer than 5.4, you could use this alone: 00036 // #include "platform/mbed_version.h" 00037 // 00038 // platform/mbed_version.h says: 00039 // 999999 is default value for development version (master branch) 00040 00041 #include "mbed.h" 00042 00043 // Critical sections header file renamed in mbed OS 5.4 release 00044 // See: https://github.com/ARMmbed/mbed-os/commit/aff49d8d1e3b5d4dc18286b0510336c36ae9603c 00045 00046 #ifndef MBED_VERSION 00047 #warning "You're probably using an unsupported version of mbed older than 5.2." 00048 #endif 00049 00050 #if MBED_VERSION >= 50400 00051 #include "platform/mbed_critical.h" 00052 #elif MBED_VERSION >= 50200 00053 #include "platform/critical.h" 00054 #endif 00055 00056 #include "platform/mbed_stats.h" 00057 00058 #if !MBED_STACK_STATS_ENABLED 00059 #warning MBED_STACK_STATS_ENABLED != 1, so there will be no stack usage measurements. 00060 #endif 00061 00062 #ifndef DEBUG_ISR_STACK_USAGE 00063 #define DEBUG_ISR_STACK_USAGE 0 00064 #endif 00065 00066 #ifndef DEBUG_MEMORY_CONTENTS 00067 #define DEBUG_MEMORY_CONTENTS 0 00068 #endif 00069 00070 #define OUTPUT_SERIAL 1 00071 #define OUTPUT_RTT 0 00072 #define OUTPUT_SWO 0 00073 00074 #if DEBUG_ISR_STACK_USAGE 00075 #include "compiler_abstraction.h" 00076 00077 // Value is sprayed into all of the ISR stack at boot time. 00078 static const uint32_t ISR_STACK_CANARY = 0xAFFEC7ED; // AFFECTED 00079 00080 // Refers to linker script defined symbol, may not be available 00081 // on all platforms. 00082 extern uint32_t __StackLimit; 00083 extern uint32_t __StackTop; 00084 00085 void fill_isr_stack_with_canary(void) 00086 { 00087 uint32_t * bottom = &__StackLimit; 00088 uint32_t * top = (uint32_t *) GET_SP(); 00089 00090 for (; bottom < top; bottom++) 00091 { 00092 *bottom = ISR_STACK_CANARY; 00093 } 00094 } 00095 #endif // DEBUG_ISR_STACK_USAGE 00096 00097 #if OUTPUT_SERIAL && DEVICE_SERIAL 00098 #include "hal/serial_api.h" 00099 00100 extern int stdio_uart_inited; 00101 extern serial_t stdio_uart; 00102 00103 static void output_serial_init(void) 00104 { 00105 if (!stdio_uart_inited) 00106 { 00107 serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); 00108 serial_baud(&stdio_uart, 115200); // This is hard coded. 00109 } 00110 } 00111 00112 static void output_serial_print_label(const char * label) 00113 { 00114 #if MBED_VERSION < 50902 00115 // After mbed OS 5.9.2, this locks up the system. 00116 core_util_critical_section_enter(); 00117 #endif 00118 00119 output_serial_init(); 00120 00121 while (*label) serial_putc(&stdio_uart, *label++); 00122 00123 #if MBED_VERSION < 50902 00124 core_util_critical_section_exit(); 00125 #endif 00126 } 00127 #endif // OUTPUT_SERIAL && DEVICE_SERIAL 00128 00129 #if OUTPUT_RTT 00130 #include "RTT/SEGGER_RTT.h" 00131 00132 enum 00133 { 00134 DEFAULT_RTT_UP_BUFFER = 0 00135 }; 00136 00137 static void output_rtt_init(void) 00138 { 00139 static int initialized = 0; 00140 00141 if (!initialized) 00142 { 00143 SEGGER_RTT_ConfigUpBuffer(DEFAULT_RTT_UP_BUFFER, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM); 00144 00145 initialized = 1; 00146 } 00147 } 00148 00149 static void output_rtt_print_label(const char * label) 00150 { 00151 output_rtt_init(); 00152 SEGGER_RTT_WriteString(DEFAULT_RTT_UP_BUFFER, label); 00153 } 00154 #endif // OUTPUT_RTT 00155 00156 #if OUTPUT_SWO 00157 #if defined (NRF52) && !defined (ENABLE_SWO) 00158 #error "You need to enable SWO using `-D ENABLE_SWO` on the mbed compile command line." 00159 #endif 00160 00161 #ifdef NRF52 00162 #include "nrf.h" 00163 #endif 00164 00165 static void output_swo_init(void) 00166 { 00167 static int initialized = 0; 00168 00169 if (!initialized) 00170 { 00171 NRF_CLOCK->TRACECONFIG = (NRF_CLOCK->TRACECONFIG & ~CLOCK_TRACECONFIG_TRACEPORTSPEED_Msk) | 00172 (CLOCK_TRACECONFIG_TRACEPORTSPEED_4MHz << CLOCK_TRACECONFIG_TRACEPORTSPEED_Pos); 00173 00174 ITM->TCR |= 1; 00175 ITM->TER |= 1; 00176 00177 initialized = 1; 00178 } 00179 } 00180 00181 static void output_swo_print_label(const char * label) 00182 { 00183 output_swo_init(); 00184 while (*label) ITM_SendChar(*label++); 00185 } 00186 #endif // OUTPUT_SWO 00187 00188 static void nway_print_label(const char * label) 00189 { 00190 #if OUTPUT_SERIAL 00191 output_serial_print_label(label); 00192 #endif 00193 00194 #if OUTPUT_RTT 00195 output_rtt_print_label(label); 00196 #endif 00197 00198 #if OUTPUT_SWO 00199 output_swo_print_label(label); 00200 #endif 00201 } 00202 00203 static const char HEX[] = "0123456789ABCDEF"; 00204 00205 static void debug_print_u32(uint32_t u32) 00206 { 00207 char output[9] = {0}; 00208 00209 // Always printed as big endian. 00210 output[0] = HEX[(((uint32_t) u32 & 0xf0000000) >> 28)]; 00211 output[1] = HEX[(((uint32_t) u32 & 0x0f000000) >> 24)]; 00212 output[2] = HEX[(((uint32_t) u32 & 0x00f00000) >> 20)]; 00213 output[3] = HEX[(((uint32_t) u32 & 0x000f0000) >> 16)]; 00214 output[4] = HEX[(((uint32_t) u32 & 0x0000f000) >> 12)]; 00215 output[5] = HEX[(((uint32_t) u32 & 0x00000f00) >> 8)]; 00216 output[6] = HEX[(((uint32_t) u32 & 0x000000f0) >> 4)]; 00217 output[7] = HEX[(((uint32_t) u32 & 0x0000000f) >> 0)]; 00218 00219 nway_print_label(output); 00220 } 00221 00222 static void debug_print_pointer(const void * pointer) 00223 { 00224 debug_print_u32((uint32_t) pointer); 00225 } 00226 00227 #define DPL(X) nway_print_label((X)) 00228 00229 #if (defined (MBED_CONF_RTOS_PRESENT) && (MBED_CONF_RTOS_PRESENT != 0)) 00230 #include "cmsis_os.h" 00231 00232 // cmsis_os.h provides some useful defines: 00233 // 00234 // For mbed OS 5.4 and lower, osCMSIS == 0x10002U (see: rtos/rtx/TARGET_CORTEX_M) 00235 // For mbed OS 5.5 and higher, osCMSIS == 0x20001U (see: rtos/TARGET_CORTEX/rtx{4|5}) 00236 // 00237 // Starting in mbed OS 5.5, a new RTOS layer was introduced with a different API. 00238 00239 #if (osCMSIS < 0x20000U) 00240 // Temporarily #undef NULL or the compiler complains about previous def. 00241 #undef NULL 00242 #include "rt_TypeDef.h" 00243 #else 00244 #include "rtx_lib.h" 00245 // #include <stdlib.h> // Include if you need malloc() / free() below. (probably better for non-C99 compilers) 00246 #endif 00247 00248 #if (osCMSIS < 0x20000U) 00249 00250 // No public forward declaration for this. 00251 extern "C" P_TCB rt_tid2ptcb (osThreadId thread_id); 00252 00253 static void print_thread_info(osThreadId threadId) 00254 { 00255 if (!threadId) return; 00256 00257 osEvent event; 00258 00259 P_TCB tcb = rt_tid2ptcb(threadId); 00260 00261 DPL(" stack ( start: "); 00262 debug_print_pointer(tcb->stack); 00263 00264 event = _osThreadGetInfo(threadId, osThreadInfoStackSize); 00265 00266 DPL(" end: "); 00267 debug_print_pointer(((uint8_t *) tcb->stack + event.value.v)); // (tcb->priv_stack))); 00268 00269 DPL(" size: "); 00270 debug_print_u32(event.value.v); 00271 00272 event = _osThreadGetInfo(threadId, osThreadInfoStackMax); 00273 DPL(" used: "); 00274 debug_print_u32(event.value.v); 00275 00276 00277 DPL(" ) "); 00278 00279 DPL("thread ( id: "); 00280 debug_print_pointer(threadId); 00281 00282 event = _osThreadGetInfo(threadId, osThreadInfoEntry); 00283 DPL(" entry: "); 00284 debug_print_pointer(event.value.p); 00285 00286 DPL(" )\r\n"); 00287 } 00288 00289 void print_all_thread_info(void) 00290 { 00291 osThreadEnumId enumId = _osThreadsEnumStart(); 00292 osThreadId threadId = (osThreadId) NULL; // Can't use nullptr yet because mbed doesn't support C++11. 00293 00294 while ((threadId = _osThreadEnumNext(enumId))) 00295 { 00296 print_thread_info(threadId); 00297 } 00298 00299 _osThreadEnumFree(enumId); 00300 } 00301 00302 #else 00303 00304 static void print_thread_info(osThreadId threadId) 00305 { 00306 // Refs: rtx_lib.h - #define os_thread_t osRtxThread_t 00307 // rtx_os.h - typedef struct osRtxThread_s { } osRtxThread_t 00308 00309 if (!threadId) return; 00310 00311 os_thread_t * tcb = (os_thread_t *) threadId; 00312 00313 uint32_t stackSize = osThreadGetStackSize(threadId); 00314 uint32_t stackUsed = osThreadGetStackSpace(threadId); 00315 00316 DPL(" stack ( start: "); 00317 debug_print_pointer(tcb->stack_mem); 00318 00319 DPL(" end: "); 00320 debug_print_pointer((uint8_t *) tcb->stack_mem + stackSize); 00321 00322 DPL(" size: "); 00323 debug_print_u32(stackSize); 00324 00325 DPL(" used: "); 00326 debug_print_u32(stackSize - stackUsed); 00327 00328 DPL(" ) "); 00329 00330 DPL("thread ( id: "); 00331 debug_print_pointer(threadId); 00332 00333 DPL(" entry: "); 00334 debug_print_u32(tcb->thread_addr); 00335 00336 DPL(" name: "); 00337 DPL(osThreadGetName(threadId) ? osThreadGetName(threadId) : "unknown"); 00338 00339 DPL(" )\r\n"); 00340 } 00341 00342 void print_all_thread_info(void) 00343 { 00344 // Refs: mbed_stats.c - mbed_stats_stack_get_each() 00345 00346 uint32_t threadCount = osThreadGetCount(); 00347 osThreadId_t threads[threadCount]; // g++ will throw a -Wvla on this, but it is likely ok. 00348 00349 // osThreadId_t * threads = malloc(sizeof(osThreadId_t) * threadCount); 00350 // MBED_ASSERT(NULL != threads); 00351 00352 memset(threads, 0, threadCount * sizeof(osThreadId_t)); 00353 00354 // This will probably only work if the number of threads remains constant 00355 // (i.e. the number of thread control blocks remains constant) 00356 // 00357 // This is probably the case on a deterministic realtime embedded system 00358 // with limited SRAM. 00359 00360 osKernelLock(); 00361 00362 threadCount = osThreadEnumerate(threads, threadCount); 00363 00364 for (uint32_t i = 0; i < threadCount; i++) 00365 { 00366 // There seems to be a Heisenbug when calling print_thread_info() 00367 // inside of osKernelLock()! 00368 00369 // This error may appear on the serial console: 00370 // mbed assertation failed: os_timer->get_tick() == svcRtxKernelGetTickCount(), file: .\mbed-os\rtos\TARGET_CORTEX\mbed_rtx_idle.c 00371 00372 // The RTOS seems to be asserting an idle constraint violation due 00373 // to the slowness of sending data through the serial port, but it 00374 // does not happen consistently. 00375 print_thread_info(threads[i]); 00376 } 00377 00378 osKernelUnlock(); 00379 00380 // free(threads); 00381 } 00382 00383 #endif 00384 00385 void print_current_thread_id(void) 00386 { 00387 DPL("Current thread: "); 00388 debug_print_pointer(osThreadGetId()); 00389 DPL("\r\n"); 00390 } 00391 #endif // MBED_CONF_RTOS_PRESENT 00392 00393 #if DEBUG_MEMORY_CONTENTS 00394 static void print_memory_contents(const uint32_t * start, const uint32_t * end) 00395 { 00396 uint8_t line = 0; 00397 00398 for (; start < end; start++) 00399 { 00400 if (0 == line) 00401 { 00402 debug_print_pointer(start); 00403 DPL(": "); 00404 } 00405 00406 debug_print_u32(*start); 00407 00408 line++; 00409 00410 if (16 == line) 00411 { 00412 DPL("\r\n"); 00413 line = 0; 00414 } 00415 } 00416 } 00417 #endif 00418 00419 extern uint32_t mbed_stack_isr_size; 00420 00421 #if DEBUG_ISR_STACK_USAGE 00422 uint32_t calculate_isr_stack_usage(void) 00423 { 00424 for (const uint32_t * stack = &__StackLimit; stack < &__StackTop; stack++) 00425 { 00426 if (*stack != ISR_STACK_CANARY) 00427 { 00428 return (uint32_t) &__StackTop - (uint32_t) stack; 00429 } 00430 } 00431 00432 return mbed_stack_isr_size; 00433 } 00434 #endif 00435 00436 void print_heap_and_isr_stack_info(void) 00437 { 00438 #ifdef ENABLE_MEMORY_CHECKS 00439 extern unsigned char * mbed_heap_start; 00440 extern uint32_t mbed_heap_size; 00441 00442 extern unsigned char * mbed_stack_isr_start; 00443 00444 mbed_stats_heap_t heap_stats; 00445 00446 mbed_stats_heap_get(&heap_stats); 00447 00448 DPL(" heap ( start: "); 00449 debug_print_pointer(mbed_heap_start); 00450 00451 DPL(" end: "); 00452 debug_print_pointer(mbed_heap_start + mbed_heap_size); 00453 00454 DPL(" size: "); 00455 debug_print_u32(mbed_heap_size); 00456 00457 DPL(" used: "); 00458 debug_print_u32(heap_stats.max_size); 00459 00460 DPL(" ) alloc ( ok: "); 00461 debug_print_u32(heap_stats.alloc_cnt); 00462 00463 DPL(" fail: "); 00464 debug_print_u32(heap_stats.alloc_fail_cnt); 00465 00466 DPL(" )\r\n"); 00467 00468 DPL("isr_stack ( start: "); 00469 debug_print_pointer(mbed_stack_isr_start); 00470 00471 DPL(" end: "); 00472 debug_print_pointer(mbed_stack_isr_start + mbed_stack_isr_size); 00473 00474 DPL(" size: "); 00475 debug_print_u32(mbed_stack_isr_size); 00476 00477 #if DEBUG_ISR_STACK_USAGE 00478 DPL(" used: "); 00479 debug_print_u32(calculate_isr_stack_usage()); 00480 #endif 00481 00482 DPL(" )\r\n"); 00483 00484 #if DEBUG_MEMORY_CONTENTS 00485 // Print ISR stack contents. 00486 print_memory_contents(&__StackLimit, &__StackTop); 00487 #endif 00488 #endif 00489 } 00490
Generated on Wed Jul 13 2022 05:40:26 by
1.7.2