nRF52840은 노르딕 세미컨덕터에서 제공하는 강력한 무선 마이크로컨트롤러(MCU)입니다. 이 MCU를 기반으로 다양한 응용 프로그램을 개발할 때, 여러 작업을 병렬로 처리하거나 다양한 이벤트를 효율적으로 처리하는 것이 중요합니다. 이를 위해 nRF SDK는 Application Scheduler라는 도구를 제공하고 있습니다. 이 가이드는 nRF SDK의 Application Scheduler를 설정하고 사용하는 방법에 대해 설명하며, 코드 예제와 함께 사용 시 주의할 점도 다룹니다.
1. Application Scheduler란?
Application Scheduler는 nRF SDK에서 제공하는 모듈로, 시스템에서 발생하는 다양한 이벤트를 효과적으로 처리할 수 있도록 돕는 스케줄링 도구입니다. 이를 사용하면 인터럽트 핸들러나 비동기 작업에서 발생하는 이벤트들을 안전하게 처리할 수 있으며, 병렬 작업을 효율적으로 관리할 수 있습니다.
특히, 블루투스 통신, 센서 데이터 처리, 타이머 기반 작업 등 여러 작업이 동시에 발생하는 상황에서 유용합니다. 각 작업을 안전하게 큐에 등록하고, 메인 루프에서 이벤트를 실행하는 방식으로 구현되기 때문에 시스템 자원을 효율적으로 사용할 수 있습니다.
2. Application Scheduler 모듈 설정
Application Scheduler를 사용하려면 먼저 프로젝트의 설정 파일인 sdk_config.h에서 해당 모듈을 활성화해야 합니다. 기본적으로는 다음과 같이 설정할 수 있습니다.
// sdk_config.h 파일 설정
#define APP_SCHEDULER_ENABLED 1 // Application Scheduler 활성화
#define APP_SCHEDULER_WITH_PAUSE 0 // 일시정지 기능 비활성화
#define APP_SCHEDULER_WITH_PROFILER 0 // 프로파일링 기능 비활성화
또한, 스케줄러 모듈을 사용하는 데 필요한 라이브러리 파일 경로도 프로젝트에 포함되어 있어야 합니다.
.\components\libraries\scheduler\app_scheduler.c
.\components\libraries\util\app_util_platform.c
3. Application Scheduler 초기화
Application Scheduler를 사용하기 위해서는 먼저 초기화를 해야 합니다. 이 과정에서 큐의 크기와 각 이벤트의 데이터 크기를 정의해야 하며, 이를 통해 메모리를 할당하게 됩니다.
APP_SCHED_INIT() 매크로를 사용하여 초기화를 할 수 있습니다. 이때 SCHED_MAX_EVENT_DATA_SIZE와 SCHED_QUEUE_SIZE는 프로젝트의 요구사항에 맞게 설정할 수 있습니다.
// app_scheduler.h 파일 내 정의된 APP_SCHED_INIT 매크로
#define APP_SCHED_INIT(EVENT_SIZE, QUEUE_SIZE) \
do \
{ \
static uint32_t APP_SCHED_BUF[CEIL_DIV(APP_SCHED_BUF_SIZE((EVENT_SIZE), (QUEUE_SIZE)), \
sizeof(uint32_t))]; \
uint32_t ERR_CODE = app_sched_init((EVENT_SIZE), (QUEUE_SIZE), APP_SCHED_BUF); \
APP_ERROR_CHECK(ERR_CODE); \
} while (0)
3.1 초기화 코드 예제
다음은 Application Scheduler 초기화 및 메인 루프에서의 실행 예제입니다. 이 코드는 최대 4개의 이벤트를 큐에 저장하고 각 이벤트의 크기가 0바이트인 상황을 가정한 코드입니다.
#include "app_scheduler.h"
#include "nrf_log.h"
#define APP_SCHED_MAX_EVENT_SIZE 0 /**< 최대 이벤트 크기 설정 */
#define APP_SCHED_QUEUE_SIZE 4 /**< 큐에 저장할 수 있는 최대 이벤트 수 */
int main(void)
{
// 기타 초기화 코드
NRF_LOG_INIT(NULL);
/* Application Scheduler 초기화 */
APP_SCHED_INIT(APP_SCHED_MAX_EVENT_SIZE, APP_SCHED_QUEUE_SIZE);
while (1)
{
/* 스케줄된 이벤트를 처리 */
app_sched_execute();
/* 로그 버퍼를 플러시하여 남은 로그가 있다면 전송 */
NRF_LOG_FLUSH();
/* 저전력 상태로 진입, 이벤트 대기 */
__WFE();
}
}
APP_SCHED_INIT() 매크로는 큐와 메모리를 초기화하며, 메인 루프에서 app_sched_execute() 함수를 주기적으로 호출하여 큐에 등록된 이벤트를 처리합니다.
4. Event 등록
Application Scheduler에 이벤트를 등록하려면 app_sched_event_put() 함수를 사용해야 합니다. 이 함수는 특정 이벤트가 발생했을 때 호출될 이벤트 핸들러와 함께 이벤트 데이터를 스케줄러 큐에 넣습니다.
4.1 Event 등록 코드 예제
다음 코드는 간단한 이벤트를 등록하는 예제입니다. 이벤트가 발생하면 time_to_task() 함수가 호출됩니다.
#include "app_scheduler.h"
// 이벤트 핸들러 함수 정의
void time_to_task(void * p_event_data, uint16_t event_size)
{
// 처리할 작업 수행
NRF_LOG_INFO("Event handled!");
}
int main(void)
{
// 기타 초기화 코드
APP_SCHED_INIT(0, 4); // 이벤트 크기 0, 큐 크기 4
// 이벤트 등록
app_sched_event_put(NULL, 0, time_to_task);
while (1)
{
app_sched_execute(); // 스케줄된 이벤트 실행
NRF_LOG_FLUSH();
__WFE();
}
}
이 코드에서 app_sched_event_put() 함수는 이벤트 핸들러 time_to_task()와 함께 큐에 등록되며, app_sched_execute() 함수가 호출될 때마다 큐에 있는 이벤트가 처리됩니다.
5. Event 실행
메인 루프에서 app_sched_execute() 함수를 주기적으로 호출하여 큐에 저장된 이벤트가 있다면 이를 처리합니다. 이 함수는 큐에 있는 모든 이벤트를 실행하고 큐를 비웁니다.
5.1 Event 실행 코드 분석
Application Scheduler의 핵심은 app_sched_execute() 함수입니다. 이 함수는 큐에서 이벤트를 가져와 등록된 이벤트 핸들러를 호출합니다.
void app_sched_execute(void)
{
while (!is_app_sched_paused() && !APP_SCHED_QUEUE_EMPTY())
{
uint16_t event_index = m_queue_start_index;
void * p_event_data;
uint16_t event_data_size;
app_sched_event_handler_t event_handler;
p_event_data = &m_queue_event_data[event_index * m_queue_event_size];
event_data_size = m_queue_event_headers[event_index].event_data_size;
event_handler = m_queue_event_headers[event_index].handler;
// 이벤트 핸들러 실행
event_handler(p_event_data, event_data_size);
// 큐의 시작 인덱스를 다음 이벤트로 이동
m_queue_start_index = next_index(m_queue_start_index);
}
}
위 코드에서 큐에 있는 모든 이벤트를 차례대로 처리하며, 이벤트 핸들러를 호출한 후 큐에서 해당 이벤트를 제거합니다.
6. Application Scheduler 사용 시 주의 사항
Application Scheduler를 사용할 때는 몇 가지 주의할 점이 있습니다.
- 큐 크기 조정: 큐 크기를 적절하게 설정하지 않으면 큐가 가득 차서 새로운 이벤트를 등록하지 못할 수 있습니다. 시스템의 요구사항에 맞게 큐 크기를 설정해야 합니다.
- 인터럽트에서 직접 호출 금지: 인터럽트 핸들러에서 직접 작업을 수행하는 대신, Application Scheduler를 사용하여 작업을 큐에 등록해야 합니다. 이는 시스템의 안정성과 응답성을 보장합니다.
- 동기화 문제: Application Scheduler는 메인 루프에서 실행되기 때문에 실시간성을 요구하는 작업에는 적합하지 않을 수 있습니다. 예를 들어 블루투스 통신과 같이 매우 짧은 시간 내에 응답이 필요한 경우는 별도의 처리 방식이 필요할 수 있습니다.
7. 결론
Application Scheduler는 nRF52 시리즈 MCU에서 여러 이벤트를 효율적으로 관리하고 처리할 수 있도록 돕는 강력한 도구입니다. 이를 통해 인터럽트 핸들러의 복잡성을 줄이고, 병렬 작업을 안전하게 처리할 수 있습니다.
적절하게 설정하고 사용하는 경우 시스템 성능을 크게 향상시킬 수 있으며, 특히 다중 센서 데이터 처리나 블루투스 이벤트 처리와 같은 작업에 적합합니다. 이 글에서는 Application Scheduler의 설정과 기본적인 사용법에 대해 설명했으며, 실무 환경에 적용할 때는 큐 크기와 이벤트 크기를 프로젝트 요구사항에 맞게 최적화하는 것이 중요합니다.
'nRF52' 카테고리의 다른 글
nRF52 fstorage 사용 가이드 (0) | 2024.09.17 |
---|---|
nRF52 RTC(Real-Time Clock)를 활용한 캘린더 구현 (0) | 2024.09.16 |
nRF52 Application Timer 설정 및 사용 (0) | 2024.09.14 |
nRF52를 이용한 BLE Central 가이드 (0) | 2024.09.13 |
nRF52 BLE Peripheral에서 Advertising Service Data 활용하기 (0) | 2024.09.12 |