315 lines
11 KiB
C
315 lines
11 KiB
C
|
|
/****************************************************************************
|
||
|
|
|
||
|
|
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");
|
||
|
|
}
|