FreeRTOS 작업 추적

6722 단어 FreeRTOS
자세한 건 이쪽을 보세요.
FreeRTOS trace macros

제가 뭘 할 수 있을까요?


나는 어떤 임무, 언제, 얼마나 오래 운행하고 있는지 알고 싶다!!
예를 들어 다음과 같은 느낌이 있다.

맨 위에서부터 오더,task1,task2,tasuk3의 시간을 순서대로 표시하고,task1은 4마이크로초 정도의 소처리를 한다.이어task3은 63us 정도의 처리를 하고,task2는 122us 정도의 처리를 한다.오더는 남은 시간을 소모하고 1ms 주기로 이런 절차를 반복하면 알 수 있다.
이 예에서 단순히 1ms 주기 처리를 보았을 뿐이지만 더 복잡한 처리에서도 특정 임무에서 터치하면 이동 빈도가 낮은 임무 처리의 시기를 알 수 있다.
물론 논리 분석기에서도 이 작업이 시작될 때 입력한 신호와 이 작업이 출력된 신호를 볼 수 있다.작은 백으로 촉발하면 시뮬레이션 신호를 동시에 볼 수 있다.
문서에 따르면 임무의 행위를 추적할 수 있을 뿐만 아니라 대열, 무더기, 다양한 행위도 추적할 수 있다.어떤 대열이 언제 조작되었는지, 그때 어떤 임무가 움직이고 있는지 감시할 수 있다.

어떻게 쓰는 거지?


작업을 추적할 때 정의#define traceTASK_SWITCHED_OUT()#define traceTASK_SWITCHED_IN() 두 개의 매크로(어떤 실현은 OUT가 필요하지 않음)를 사용합니다.
RTOS 설치에서 참조되기 때문에 상당히 높은 위치에서 정의해야 합니다.이번에는 STM32 CubeMX에서 생성된 FreertosConfig입니다.구문을 사용합니다.
아래의 느낌입니다.
IN/OUT 주변 추적
/* USER CODE BEGIN Defines */
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */

#define configUSE_APPLICATION_TASK_TAG 1

#include <stm32f4xx.h>

#define traceTASK_SWITCHED_OUT()                                                             \
    {                                                                                        \
        GPIOB->BSRR = (uint32_t)(GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11) << 16; \
    }

#define traceTASK_SWITCHED_IN()                    \
    {                                              \
        switch ((uint32_t)pxCurrentTCB->pxTaskTag) \
        {                                          \
        default:                                   \
            GPIOB->BSRR = (uint32_t)(GPIO_PIN_8);  \
            break;                                 \
        case 1:                                    \
            GPIOB->BSRR = (uint32_t)(GPIO_PIN_9);  \
            break;                                 \
        case 2:                                    \
            GPIOB->BSRR = (uint32_t)(GPIO_PIN_10); \
            break;                                 \
        case 3:                                    \
            GPIOB->BSRR = (uint32_t)(GPIO_PIN_11); \
            break;                                 \
        }                                          \
    }

/* USER CODE END Defines */
GPIO의 출력 대상을 선택하는 데 사용되기 때문에 TASKTAG를 유효화합니다.
그런 다음 STM32 라이브러리를 읽은 후 OUT/IN에서 GPIO를 실행합니다.처리를 마치면 OUT에서 GPIO 비트를 지우고 작업을 시작할 때 IN에서 GPIO 비트를 설정합니다.또한 IN은 pxTaskTag을 사용하여 설정한 비트를 선택합니다.
매크로가 정의되면 임의로 불릴 수 있지만 GPIO의 초기화와 표시의 설정이 필요합니다.
GPIO의 초기화는 MX_GPIO_Init(); 이후 또는 적절한 장소에서 수행됩니다.
GPIO 초기화
__HAL_RCC_GPIOB_CLK_ENABLE();

GPIO_InitTypeDef GPIO_InitStruct = {
    .Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11,
    .Mode = GPIO_MODE_OUTPUT_PP,
    .Pull = GPIO_NOPULL,
    .Speed = GPIO_SPEED_FREQ_VERY_HIGH,
};
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
감시하고 싶은 작업 중 vTaskSetApplicationTaskTag(NULL, (void *)1); 처럼 표시를 설정합니다.
예를 들면 아래의 느낌.
void StartDefaultTask(void const *argument)
{
    /* USER CODE BEGIN 5 */
    vTaskSetApplicationTaskTag(NULL, (void *)1);
    /* Infinite loop */
    for (;;)
    {
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, (HAL_GetTick() % 1000) < 100 ? GPIO_PIN_SET : GPIO_PIN_RESET);
        osDelay(1);
    }
    /* USER CODE END 5 */
}
이 경우 HAL은 1ms 간격으로GetTick을 읽으면 PD2에 너비 10% 주기 1sec의 펄스가 발생하고 실행 중task1의 핀이 설정됩니다(이번 예는 PB9).

주의점


확인되지 않았으나 심한 처리를 중단하면 정상적으로 감시할 수 없을 것 같습니다. (중단은 RTOS의 관할 범위에 속하지 않기 때문에 OUT/IN 처리를 할 수 없습니다.)
새치기를 포함한 시점을 확인하려면 새치기나 출타 시점에 책임을 지고 GPIO를 돌릴 필요가 있다.
이번에는 가끔 시동을 걸 때 다운된다.pxCurrentTCB는 NULL에서 초기화된 것으로 RTOS가 실행되기 전에 SysTick이 상하문 스위치를 호출하여 traceTASK_SWITCHED_IN에서 NULL을 참조하면 떨어질 것 같다.
대책으로는 traceTASK_SWITCHED_IN에서 NULL이 아닌 것을 확인하거나, RTOS를 시작하기 전에 SysTick을 중지하는 방법 등을 고려할 수 있다.

응용 프로그램


이번에는 각 임무에 대해 GPIO를 할당했고 다른 방법도 사용할 수 있다.예를 들어 정식 문서에서 DAC로 출력하고 오실로그래프로 전압을 보고 임무를 식별한다.이 외에도 빠른 출력(SPI 등) 방법을 사용할 수 있습니다.이 방법이라면 비교적 적은 GPIO로 많은 정보(8비트와 16비트)를 출력할 수 있다.

좋은 웹페이지 즐겨찾기