인프런 커뮤니티 질문&답변

chucky2님의 프로필 이미지
chucky2

작성한 질문수

FreeRTOS 프로그래밍

소스코드 분석-configUSE_IDLE_HOOK

[질문/해결완료] configUSE_IDLE_HOOK 를 1로 설정하고 동작 시 BusFault exception 발생

해결된 질문

작성

·

329

1

test시 code는 아래와 같이 수정하였습니다.

  1. freertosconfig.h에서 configUSE_IDLE_HOOK를 1로 설정

  2. 각 task마다, 각 task에 할당된 전역변수를 1씩 증가

  3. vApplicationIdleHook에서 task별 증가된 전역변수값 출력

디버깅을 위해서 exception hander를 모두 enable (control.shcsr [18:16] = 0x7 로 설정) 하고 test 결과.

busfault exception이 발생하였습니다.

vApplicationIdleHook() 수정상황

UART 상황: task1~3값은 0이고 idle task에서만 count 증가한 것처럼 출력니다. reset 하고 동작시에도 항상 고정적인 위치 (Idle task에서 증가한 변수가 180인 시점) 에서 발생합니다. (재현 100%)

해당 시점의 register 상황입니다. lr이 0xfffffff1로 보아 exception 처리 중 busfault exception이 발생한 듯 보입니다만 추가적인 stack 분석은 능력 밖이네요.

fflush 등의 uart 처리가 상대적으로 느려서 뭔가 문제가 발생하는 걸까요? 타 환경에서라도 test 부탁드립니다.

답변 2

0

chucky2님의 프로필 이미지
chucky2
질문자

문제의 원인은 idle task의 stack overflow로 추정됩니다.

혹시 exception 상황에서 stack 분석하는 방법이 정리된 내용이 있으면 공유 부탁 드립니다.

내공이 부족하여....:<

 

stack size 조절 전

idle task의 stack 마지막 위치는 0x200000e4. 정상동작 시에는 stack에 문제 없음

image

문제 발생 시, idle task의 stack이 변수 영역을 침범하여 exception이 발생하는 것으로 보임

image

stack 조절

freertosconfig_base.h에서 idle stack size를 늘려서 test 해본 결과 정상 동작 확인하였습니다.

#define configUSE_TICK_HOOK                      0
#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
#define configTICK_RATE_HZ                       ((TickType_t)1000)
#define configMAX_PRIORITIES                     ( 20 )
//#define configMINIMAL_STACK_SIZE                 ((uint16_t)128) //cms: org stack sz
#define configMINIMAL_STACK_SIZE                 ((uint16_t)256) //cms: test
#define configTOTAL_HEAP_SIZE                    ((size_t)15360)
#define configMAX_TASK_NAME_LEN                  ( 16 )
#define configUSE_16_BIT_TICKS                   0
#define configUSE_MUTEXES                        1
#define configQUEUE_REGISTRY_SIZE                8

uart 출력 상황

image감사합니다.

0

홍영기님의 프로필 이미지
홍영기
지식공유자

안녕하세요. chucky2님!

제가 해보았을 때는 잘 동작하는군요. ㅎ (테스트 환경 f103rb)

T1 194, T2 194, T3 38, Idle 58991
T1 194, T2 194, T3 38, Idle 58992
T1 194, T2 194, T3 38, Idle 58993
T1 194, T2 194, T3 38, Idle 58994
T1 194, T2 194, T3 38, Idle 58995
T1 194, T2 194, T3 38, Idle 58996
T1 194, T2 194, T3 38, Idle 58997
T1 194, T2 194, T3 38, Idle 58998
T1 194, T2 194, T3 38, Idle 58999
...


참고하시라고 소스를 올려드립니다.

/*
 * task.c
 *
 *  Created on: Dec 22, 2020
 *      Author: admin
 */

/* FreeRTOS.org includes. */
#include "main.h"
#include "cmsis_os.h"
#include <stdio.h>

//#define CMSIS_OS

/* task's priority */
#define TASK_MAIN_PRIO	20
#define TASK_1_PRIO		10
#define TASK_2_PRIO		 9
#define TASK_3_PRIO		 8

struct Param_types {	/* struct for parameter passing to task */
       char *msg;
       int  P1,P2;
} Param_Tbl;

/* The task functions. */
static void TaskMain( void const *pvParameters );
static void Task1( void const *pvParameters );
static void Task2( const struct Param_types *Param );
static void Task3( const struct Param_types *Param );

#ifdef CMSIS_OS
osThreadId defaultTaskHandle;
osThreadId xHandleMain, xHandle1, xHandle2, xHandle3;
#else
TaskHandle_t xHandleMain, xHandle1, xHandle2, xHandle3;
#endif

int	task1timer, task2timer, task3timer, idletimer;

/*-----------------------------------------------------------*/

void USER_THREADS( void )
{

	/* Setup the hardware for use with the Beagleboard. */
	//prvSetupHardware();
#ifdef CMSIS_OS
	osThreadDef(defaultTask, TaskMain, osPriorityHigh, 0, 256);
	defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
#else
	/* Create one of the two tasks. */
	xTaskCreate(	(TaskFunction_t)TaskMain,		/* Pointer to the function that implements the task. */
					"TaskMain",	/* Text name for the task.  This is to facilitate debugging only. */
					256,		/* Stack depth - most small microcontrollers will use much less stack than this. */
					NULL,		/* We are not using the task parameter. */
					TASK_MAIN_PRIO,	/* This task will run at this priority */
					&xHandleMain );		/* We are not using the task handle. */
#endif
}

static void TaskMain( void const *pvParameters )
{
	const char *pcTaskName = "TaskMain";
	struct Param_types *Param;

	pvParameters = pvParameters; // for compiler warning

	/* Print out the name of this task. */
	printf( "%s is running\r\n", pcTaskName );

	// TASK CREATE
	/* TODO #1:
		Task1을 생성
		use 'xTaskCreate' */
#ifdef CMSIS_OS
	osThreadDef(Task1, Task1, osPriorityNormal, 0, 256);
	xHandle1 = osThreadCreate(osThread(Task1), NULL);
#else
	/* Create the other task in exactly the same way. */
	xTaskCreate(	(TaskFunction_t)Task1,		/* Pointer to the function that implements the task. */
					"Task1",	/* Text name for the task.  This is to facilitate debugging only. */
					256,		/* Stack depth - most small microcontrollers will use much less stack than this. */
					NULL,		/* We are not using the task parameter. */
					TASK_1_PRIO,	/* This task will run at this priority */
					&xHandle1 );		/* We are not using the task handle. */
#endif // TODO #1

	/* Create the other task in exactly the same way. */
	Param = &Param_Tbl;		/* get parameter tbl addr */
	Param->P1 = 111111;		/* set parameter */
	Param->P2 = 222222;
#ifdef CMSIS_OS
	osThreadDef(Task2, (void const *)Task2, osPriorityBelowNormal, 0, 256);
	xHandle2 = osThreadCreate (osThread(Task2), (void*)Param);
#else
	xTaskCreate( (TaskFunction_t)Task2, "Task2", 128, (void*)Param, TASK_2_PRIO, &xHandle2 );
#endif

#ifdef CMSIS_OS
	osThreadDef(Task3, (void const *)Task3, osPriorityBelowNormal, 0, 256);
	xHandle3 = osThreadCreate (osThread(Task3), (void*)Param);
#else
	xTaskCreate( (TaskFunction_t)Task3, "Task3", 128, (void*)Param, TASK_3_PRIO, &xHandle3 );
#endif

	/* TODO #2:
		Task1을 중지
		use 'vTaskSuspend' */
#if 0
	vTaskSuspend (xHandle1);
#endif // TODO #2

	/* TODO #4:
		Task1의 우선 순위를 'TASK_3_PRIO' 으로 변경
		use 'vTaskPrioritySet' and 'vTaskResume' */
#if 0
	vTaskPrioritySet (xHandle1, TASK_3_PRIO); // vTaskPrioritySet (NULL, 1);
	vTaskResume (xHandle1);
#endif // TODO #4

	/* delete self task */
	vTaskDelete (xHandleMain);	// vTaskDelete (NULL);
}

static void Task1( void const *pvParameters )
{
	const char *pcTaskName = "Task1";

	pvParameters = pvParameters; // for compiler warning

	/* Print out the name of this task. */
	printf( "%s is running\n", pcTaskName );

	printf("\n-------  Task1 information -------\n");
	printf("task1 name = %s \n",pcTaskGetName( xHandle1 ));
	printf("task1 priority = %d \n",(int)uxTaskPriorityGet( xHandle1 ));
//	printf("task1 status = %d \n",eTaskGetState( xHandle1 ));
	printf("----------------------------------\n");

	while(1) {
	/* TODO #3:
		코드를 실행 하여 보고
		vTaskDelay() 코드를 주석 처리한 후 그 결과를 설명한다 */
#if 1 // No comment
vTaskDelay (pdMS_TO_TICKS (1000));
printf("a"); fflush(stdout);	// 문자 'a' 출력
#endif // TODO #3

		task1timer++;
	}
}

static void Task2( const struct Param_types *Param )
{
	const char *pcTaskName = "Task2";

	/* Print out the name of this task. */
	printf( "%s is running\n", pcTaskName );

	printf("\n-------  Task2 parameter passed from main --------\n");
	printf("task2 first parameter = %d \n",Param->P1);
	printf("task2 second parameter = %d \n",Param->P2);
	printf("--------------------------------------------------\n");

	while(1) {
	/* TODO #3:
		코드를 실행 하여 보고
		vTaskDelay() 코드를 주석 처리한 후 그 결과를 설명한다 */
#if 1 // No comment
vTaskDelay (pdMS_TO_TICKS (1000));
//printf("b"); fflush(stdout);	// 문자 'b' 출력
printf("T1 %d, T2 %d, T3 %d, Idle %d\n", task1timer, task2timer, task3timer, idletimer);
#endif // TODO #3

		task2timer++;
	}
}

static void Task3( const struct Param_types *Param)
{
	while(1)
	{
		vTaskDelay(pdMS_TO_TICKS(5000));
//		printf("T1 %d, T2 %d, T3 %d, Idle %d\n", task1timer, task2timer, task3timer, idletimer);
		fflush(stdout);
		task3timer++;
	}
}

/*-----------------------------------------------------------*/

void vApplicationIdleHook (void)
{
	idletimer++;
	printf("T1 %d, T2 %d, T3 %d, Idle %d\n", task1timer, task2timer, task3timer, idletimer);

	if(idletimer % 1000 == 0)
	{
		printf("."); fflush(stdout);
	}
}
chucky2님의 프로필 이미지
chucky2
질문자

답변 감사합니다.

idle hook 함수에서, 출력 간격을 늘리면 동작 시간이 길어지긴 하지만, 결과적으로는 exception이 발생하여 멈춥니다.

idle hook에서 출력하는 대신에 일반 task에서 출력하도록 하면 문제 없이 동작합니다.

제 생각에는 103rb와 401re 간 core 동작 속도 차이도 있을 수 있으니, 다시 한번 확인해주세요.

source 첨부합니다.

idletime % 10000 으로 설정 시...

image

idletime % 100000 으로 설정 시...

image

task3에서 출력하도록 설정 시...

image

source

강사님이 upload 해주신 code를 기반으로 test 했습니다.

cms_enable_print_at_idel_hook 을 0으로 설정하면 task3에서 count를 출력하고

1로 설정하면 idle hook에서 출력 (문제 발생 상황) 됩니다.

/*
 * task.c
 *
 *  Created on: Dec 22, 2020
 *      Author: YUNGKI HONG (guileschool@gmail.com)
 *      Copyright © 2015 guileschool
 */

/* FreeRTOS.org includes. */
#include "main.h"
#include "cmsis_os.h"
#include <stdio.h>

//#define CMSIS_OS

/* task's priority */
#define TASK_MAIN_PRIO	20
#define TASK_1_PRIO		10
#define TASK_2_PRIO		 9
#define TASK_3_PRIO		 8

struct Param_types {	/* struct for parameter passing to task */
       char *msg;
       int  P1,P2;
} Param_Tbl;

/* The task functions. */
static void TaskMain( void const *pvParameters );
static void Task1( void const *pvParameters );
static void Task2( const struct Param_types *Param );
static void Task3( const struct Param_types *Param );

#ifdef CMSIS_OS
osThreadId defaultTaskHandle;
osThreadId xHandleMain, xHandle1, xHandle2;
#else
TaskHandle_t xHandleMain, xHandle1, xHandle2, xHandle3;
#endif

int	task1timer, task2timer, task3timer, idletimer;

/*-----------------------------------------------------------*/

void USER_THREADS( void )
{

	/* Setup the hardware for use with the Beagleboard. */
	//prvSetupHardware();
#ifdef CMSIS_OS
	osThreadDef(defaultTask, TaskMain, osPriorityHigh, 0, 256);
	defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
#else
	/* Create one of the two tasks. */
	xTaskCreate(	(TaskFunction_t)TaskMain,		/* Pointer to the function that implements the task. */
					"TaskMain",	/* Text name for the task.  This is to facilitate debugging only. */
					256,		/* Stack depth - most small microcontrollers will use much less stack than this. */
					NULL,		/* We are not using the task parameter. */
					TASK_MAIN_PRIO,	/* This task will run at this priority */
					&xHandleMain );		/* We are not using the task handle. */
#endif
}

static void TaskMain( void const *pvParameters )
{
	const char *pcTaskName = "TaskMain";
	struct Param_types *Param;

	pvParameters = pvParameters; // for compiler warning

	/* Print out the name of this task. */
	printf( "%s is running\r\n", pcTaskName );

	// TASK CREATE
	/* TODO #1:
		Task1을 생성
		use 'xTaskCreate' */
#ifdef CMSIS_OS
	osThreadDef(Task1, Task1, osPriorityNormal, 0, 256);
	xHandle1 = osThreadCreate(osThread(Task1), NULL);
#else
	/* Create the other task in exactly the same way. */
	xTaskCreate(	(TaskFunction_t)Task1,		/* Pointer to the function that implements the task. */
					"Task1",	/* Text name for the task.  This is to facilitate debugging only. */
					256,		/* Stack depth - most small microcontrollers will use much less stack than this. */
					NULL,		/* We are not using the task parameter. */
					TASK_1_PRIO,	/* This task will run at this priority */
					&xHandle1 );		/* We are not using the task handle. */
#endif // TODO #1

	/* Create the other task in exactly the same way. */
	Param = &Param_Tbl;		/* get parameter tbl addr */
	Param->P1 = 111111;		/* set parameter */
	Param->P2 = 222222;
#ifdef CMSIS_OS
	osThreadDef(Task2, (void const *)Task2, osPriorityBelowNormal, 0, 256);
	xHandle2 = osThreadCreate (osThread(Task2), (void*)Param);
#else
	xTaskCreate( (TaskFunction_t)Task2, "Task2", 128, (void*)Param, TASK_2_PRIO, &xHandle2 );
#endif

#ifdef CMSIS_OS
	osThreadDef(Task3, (void const *)Task3, osPriorityBelowNormal, 0, 256);
	xHandle3 = osThreadCreate (osThread(Task3), (void*)Param);
#else
	xTaskCreate( (TaskFunction_t)Task3, "Task3", 128, (void*)Param, TASK_3_PRIO, &xHandle3 );
#endif

	/* TODO #2:
		Task1을 중지
		use 'vTaskSuspend' */
#if 0
	vTaskSuspend (xHandle1);
#endif // TODO #2

	/* TODO #4:
		Task1의 우선 순위를 'TASK_3_PRIO' 으로 변경
		use 'vTaskPrioritySet' and 'vTaskResume' */
#if 0
	vTaskPrioritySet (xHandle1, TASK_3_PRIO); // vTaskPrioritySet (NULL, 1);
	vTaskResume (xHandle1);
#endif // TODO #4

	/* delete self task */
	vTaskDelete (xHandleMain);	// vTaskDelete (NULL);
}

static void Task1( void const *pvParameters )
{
	const char *pcTaskName = "Task1";

	pvParameters = pvParameters; // for compiler warning

	/* Print out the name of this task. */
	printf( "%s is running\n", pcTaskName );

	printf("\n-------  Task1 information -------\n");
	printf("task1 name = %s \n",pcTaskGetName( xHandle1 ));
	printf("task1 priority = %d \n",(int)uxTaskPriorityGet( xHandle1 ));
//	printf("task1 status = %d \n",eTaskGetState( xHandle1 ));
	printf("----------------------------------\n");

	while(1) {
	/* TODO #3:
		코드를 실행 하여 보고
		vTaskDelay() 코드를 주석 처리한 후 그 결과를 설명한다 */
#if 1 // No comment
    vTaskDelay (pdMS_TO_TICKS (1000));
    printf("a"); fflush(stdout);	// 문자 'a' 출력
#endif // TODO #3

		task1timer++;
	}
}

static void Task2( const struct Param_types *Param )
{
	const char *pcTaskName = "Task2";

	/* Print out the name of this task. */
	printf( "%s is running\n", pcTaskName );

	printf("\n-------  Task2 parameter passed from main --------\n");
	printf("task2 first parameter = %d \n",Param->P1);
	printf("task2 second parameter = %d \n",Param->P2);
	printf("--------------------------------------------------\n");

	while(1) {
	/* TODO #3:
		코드를 실행 하여 보고
		vTaskDelay() 코드를 주석 처리한 후 그 결과를 설명한다 */
#if 1 // No comment
        vTaskDelay (pdMS_TO_TICKS (1000));
        printf("b"); fflush(stdout);	// 문자 'b' 출력
#endif // TODO #3

		task2timer++;
	}
}

static void Task3( const struct Param_types *Param)
{
	while(1)
	{
		vTaskDelay(pdMS_TO_TICKS(5000));
#if (defined (cms_enable_print_at_idel_hook) && ( cms_enable_print_at_idel_hook == 1))
		;
#else
		printf("\nT1 %d, T2 %d, T3 %d, Idle %d\n", task1timer, task2timer, task3timer, idletimer);
		fflush(stdout);
#endif
		task3timer++;
	}
}

/*-----------------------------------------------------------*/

void vApplicationIdleHook (void)
{
#if (defined (cms_enable_print_at_idel_hook) && ( cms_enable_print_at_idel_hook == 1))
    if(idletimer % 10000 == 0)
    {
        printf("T1 %d, T2 %d, T3 %d, Idle %d\n", task1timer, task2timer, task3timer, idletimer);
        printf("."); fflush(stdout);
    }
#endif
    idletimer++;
}
chucky2님의 프로필 이미지
chucky2

작성한 질문수

질문하기