/**************************************************************************** Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT be copied by any method or incorporated into another program without the express written consent of Aerospace C.Power. This Information or any portion thereof remains the property of Aerospace C.Power. The Information contained herein is believed to be accurate and Aerospace C.Power assumes no responsibility or liability for its use in any way and conveys no license or title under any patent or copyright and makes no representation or warranty that this Information is free from patent or copyright infringement. ****************************************************************************/ /* FreeRTOS includes. */ #include "FreeRTOS.h" #include "task.h" #include "iot_io.h" #include "ledc.h" #include "watchdog.h" #include "irq.h" #include "cpu.h" #include "snapshot.h" #include "iot_config.h" #include "iot_system.h" /* common includes */ #include "iot_module.h" #include "iot_dbglog_parser.h" #include "iot_dbglog_api.h" #include "iot_pkt_api.h" #include "hw_war.h" #include "iot_busmon.h" #include "iot_oem_api.h" #include "iot_rtc.h" #include "platform.h" extern int g_feed_dog; extern int g_disable_feed_dog; extern iot_wdg_info g_wdg_info; #if DUAL_WDG_ON_ONE_CPU_ENABLE extern iot_wdg_info g_wdg_info_1; #endif extern uint32_t total_mem; extern uint32_t g_snapshot_triggered; extern uint32_t g_stick_triggered; extern unsigned int _heap_end; uint32_t os_task_lost_sceduler_cnt = 0; uint64_t os_task_total_time = 0; uint32_t g_idle_task_cpu_ratio = 0; #if IOT_PKT_INFO_DUMP_DEBUG extern void iot_pkt_dump_info(void); #endif #if INTERRUPT_LATENCY_DEBUG extern void dump_interrupt_stat_info(); #endif #if IOT_MAP_GPIO_SIGNAL_INFO_DUMP_DEBUG extern void gpio_signal_mapping_dump(); #endif extern uint32_t os_get_system_state(TaskStatus_t * const pxTaskStatusArray, const uint32_t uxArraySize, uint32_t * const pulTotalRunTime); uint32_t os_idle_task_cpu_ratio() { return g_idle_task_cpu_ratio; } static void os_write_interrupt_err_trigger_cnt_to_flash(uint8_t force_write) { #if IOT_INTERRUPT_ERR_TRIGGER_WRITE_FLASH_ENABLE uint32_t interrupt_err_trigger_cnt = interrupt_get_err_trigger(); static uint32_t invoking_cnt = 0; static uint32_t interrupt_err_trigger_cnt_last = 0; if (force_write) { iot_dbglog_input(IOT_DRIVER_MID, DBGLOG_ERR, IOT_DRIVER_INTERRUPT_TRIGGER_ERR_ID, 1, interrupt_err_trigger_cnt); return; } /* write log per 1 hours */ if (0 == invoking_cnt % IOT_INTERRUPT_ERR_TRIGGER_WRITE_FLASH_PER) { if ((interrupt_err_trigger_cnt_last != interrupt_err_trigger_cnt) || (0 == invoking_cnt % IOT_INTERRUPT_ERR_TRIGGER_WRITE_FLASH_FIXED_TIME)) { iot_dbglog_input(IOT_DRIVER_MID, DBGLOG_ERR, IOT_DRIVER_INTERRUPT_TRIGGER_ERR_ID, 1, interrupt_err_trigger_cnt); if (IOT_INTERRUPT_ERR_TRIGGER_WRITE_FLASH_FIXED_TIME == invoking_cnt) { invoking_cnt = 0; } interrupt_err_trigger_cnt_last = interrupt_err_trigger_cnt; } } ++invoking_cnt; #endif return ; } static void os_dump_taskinfo() { TaskStatus_t *pxTaskStatusArray; volatile UBaseType_t uxArraySize, x; uint32_t ulTotalRunTime = 0, ulStatsAsPercentage; uint32_t ulTotalTaskTime = 0; uint32_t ulTotalRun = 0; uint32_t tmpData = 0; static uint32_t ulTotalRunPrev = 0; uint8_t cpuRatio = 0; static uint8_t cpuRatioMax = 0; static uint8_t fistRun = 1; // Take a snapshot of the number of tasks in case it changes while this // function is executing. uxArraySize = uxTaskGetNumberOfTasks(); // Allocate a TaskStatus_t structure for each task. An array could be // allocated statically at compile time. pxTaskStatusArray = (TaskStatus_t*)&_heap_end; if( pxTaskStatusArray != NULL ){ // Generate raw status information about each task. uxArraySize = os_get_system_state( pxTaskStatusArray, uxArraySize, &ulTotalRun ); //Handling of the overflow situation. if(ulTotalRun < ulTotalRunPrev){ tmpData = 0xffffffff - ulTotalRunPrev; ulTotalRunTime = tmpData + ulTotalRun + 1; //iot_printf("total run time!!!:%u, %u, %u\n", ulTotalRunTime, ulTotalRun, ulTotalRunPrev); ulTotalRunPrev = ulTotalRun; } else{ ulTotalRunTime = ulTotalRun - ulTotalRunPrev; ulTotalRunPrev = ulTotalRun; } // For percentage calculations. ulTotalRunTime /= 100UL; // Avoid divide by zero errors. if( ulTotalRunTime > 0 ){ for( x = 0; x < uxArraySize; x++){ // IDLE and TmrSvr if((pxTaskStatusArray[ x].xTaskNumber != 2) && (pxTaskStatusArray[ x].xTaskNumber !=3)){ ulTotalTaskTime += pxTaskStatusArray[ x ].ulRunTimeCounter; } } if(ulTotalTaskTime == os_task_total_time){ os_task_lost_sceduler_cnt++; } else{ os_task_total_time = ulTotalTaskTime; os_task_lost_sceduler_cnt = 0; } // For each populated position in the pxTaskStatusArray array, // format the raw data as human readable ASCII data for( x = 0; x < uxArraySize; x++ ){ // What percentage of the total run time has the task used? // This will always be rounded down to the nearest integer. // ulTotalRunTimeDiv100 has already been divided by 100. ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime; if(ulStatsAsPercentage > 100){ ulStatsAsPercentage = 100; } /* IDLE task */ if(pxTaskStatusArray[ x ].xTaskNumber == 2){ g_idle_task_cpu_ratio = ulStatsAsPercentage; cpuRatio = 100 - ulStatsAsPercentage; } if( ulStatsAsPercentage > 0UL ){ iot_printf("%8d %8d %8d %2d%% #%08x %s\n", pxTaskStatusArray[ x ].xTaskNumber, pxTaskStatusArray[ x ].usStackHighWaterMark, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage, pxTaskStatusArray[ x ].pxStackBase, pxTaskStatusArray[ x].pcTaskName); } else { // If the percentage is zero here then the task has // consumed less than 1% of the total run time. iot_printf("%8d %8d %8d <1%% #%08x %s\n", pxTaskStatusArray[ x ].xTaskNumber, pxTaskStatusArray[ x ].usStackHighWaterMark, pxTaskStatusArray[ x ].ulRunTimeCounter, pxTaskStatusArray[ x ].pxStackBase, pxTaskStatusArray[ x ].pcTaskName); } } if(cpuRatio > cpuRatioMax){ if(fistRun != 1){ cpuRatioMax = cpuRatio; iot_dbglog_input(IOT_STATISTICS_MID, DBGLOG_WARN, OS_CPU_RATIO, 1, cpuRatioMax); } else { fistRun = 0; } } iot_printf("the max cpu ratio:%d%%, intc fault %d.\n", cpuRatioMax, interrupt_get_err_trigger()); os_write_interrupt_err_trigger_cnt_to_flash(0); #if IOT_MAP_GPIO_SIGNAL_INFO_DUMP_DEBUG /* print the mapping of signal and gpio. */ gpio_signal_mapping_dump(); #endif } } } void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) { /* This function will get called if a task overflows its stack. If the parameters are corrupt then inspect pxCurrentTCB to find which was the offending task. */ ( void ) pxTask; ( void ) pcTaskName; iot_printf("%s:Stack overflow\n", pcTaskName); IOT_ASSERT(0); } void vApplicationMallocFailedHook( void ) { /* vApplicationMallocFailedHook() will only be called if configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook function that will get called if a call to pvPortMalloc() fails. pvPortMalloc() is called internally by the kernel whenever a task, queue, timer or semaphore is created. It is also called by various parts of the demo application. If heap_1.c or heap_2.c are used, then the size of the heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used to query the size of free heap space that remains (although it does not provide information on how the remaining heap might be fragmented). */ iot_printf("Malloc Failed\n"); iot_printf("total:%dK\n", (total_mem>>10)); IOT_ASSERT(0); } #if IOT_INTERRUPT_ERR_TRIGGER_CRASH extern uint32_t err_trigger_assert; #endif void vApplicationIdleHook( void ) { /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle task. It is essential that code added to this hook function never attempts to block in any way (for example, call xQueueReceive() with a block time specified, or call vTaskDelay()). If the application makes use of the vTaskDelete() API function (as this demo application does) then it is also important that vApplicationIdleHook() is permitted to return to its calling function, because it is the responsibility of the idle task to clean up memory allocated by the kernel to any task that has since been deleted. */ static int count = 0; if (iot_wdg_need_feed()) { iot_wdg_do_feed_dog(); } count++; if((count%5000) == 0){ /* update rtc count */ iot_rtc_count_update(); uint32_t free_mem = xPortGetFreeHeapSize(); uint32_t lowest_mem = xPortGetMinimumEverFreeHeapSize(); iot_printf("core id:%d idle: %d, cpu1:%d\n", cpu_get_mhartid(), xTaskGetTickCount(), iot_cpu1_count_get()); iot_printf("free:%lu lowest:%lu\n", free_mem, lowest_mem); os_dump_taskinfo(); #if IOT_PKT_INFO_DUMP_DEBUG iot_pkt_dump_info(); #endif if(iot_cpu1_crash_get()){ iot_cpu1_crash_dump(); } iot_led_blink_from_hook(IOT_PLC_TX_LED, 1); #if IOT_INTERRUPT_ERR_TRIGGER_CRASH if (interrupt_get_err_trigger()) { os_write_interrupt_err_trigger_cnt_to_flash(1); err_trigger_assert = 1; IOT_ASSERT(0); } #endif #if INTERRUPT_LATENCY_DEBUG dump_interrupt_stat_info(); #endif } #if SNAPSHOT_MONITOR_DEBUG iot_busmon_cap(); #endif if(os_task_lost_sceduler_cnt > 200){ IOT_ASSERT(0); } __asm volatile ("wfi"); __asm volatile ("nop"); __asm volatile ("nop"); __asm volatile ("nop"); }