목록분류 전체보기 (321)
지노랩 /JinoLab
FreeRTOS와 같은 RTOS 환경에서는 **크리티컬 섹션(Critical Section)**을 보호하는 데 보통 **뮤텍스(Mutex)**나 세마포어(Semaphore) 같은 커널 서비스를 사용합니다.하지만 때로는 “OS 서비스를 호출하지 않고, 정말 빠르고 단순하게” CPU 상에서 실행 중인 코드를 보호하고 싶을 때도 있습니다. 이런 경우 가장 원시적인 방법은 **“인터럽트(Interrupt)와 태스크 선점(Preemption)을 아예 막아 버리는 것”**입니다.이번 포스팅에서는 이 인터럽트 비활성화(Disable Interrupt) + 선점 비활성화(Disable Preemption) 방식(흔히 “크리티컬 섹션 매크로”라 부르기도 합니다)을 중심으로,왜 쓰는지단점/주의사항FreeRTOS에서 제공하..
임베디드 시스템, 특히 FreeRTOS 기반 환경에서 **“인터럽트가 빠르게 연속으로 발생할 때 이벤트를 절대로 놓치지 않고 모두 처리”**해야 하는 상황이 자주 발생합니다. 이럴 때 흔히 쓰는 기법이 바로 **카운팅 세마포어(Counting Semaphore)**를 이용한 “이벤트 라칭(쌓아두기) + 순차 처리” 패턴입니다. 오늘은 카운팅 세마포어 개념부터, 왜 바이너리 세마포어만으로는 한계가 있는지, 그리고 FreeRTOS에서 카운팅 세마포어를 활용해 연속 인터럽트 이벤트를 안전하게 처리하는 구체적인 예제를 함께 살펴보겠습니다.1. 문제: 빠르게 반복되는 인터럽트를 놓치지 않고 처리해야 할 때임베디드 기기는 초당 수십 회 혹은 수백 회까지 외부 인터럽트가 발생할 수 있습니다.예를 들어 센서 데이터가 ..
임베디드/FreeRTOS 환경에서는 **여러 번 연속으로 발생하는 이벤트(또는 빠르게 반복되는 인터럽트)**를 놓치지 않고 모두 처리하려면, 한 번에 하나의 처리(Task)가 유지하는 방식으로 “이벤트를 줄줄이 쌓아뒀다가” 순서대로 꺼내 주는 설계가 필요합니다. 이를 위해 FreeRTOS는 **카운팅 세마포어(Counting Semaphore)**라는 커널 오브젝트를 제공합니다.아래 글에서는 **“카운팅 세마포어로 연속 발생한 이벤트(인터럽트)를 놓치지 않고 순차 처리”**하는 원리와 구현 예제를 단계별로 살펴보겠습니다.1. 문제 정의: ‘빠르게 연속 발생하는 인터럽트’를 놓치지 않는 방법1.1. 연속 발생 인터럽트 시나리오임베디드 기기에서 외부 인터럽트가 초당 수십~수백 회 발생할 수 있습니다.단순히 ..
멀티태스킹 RTOS 환경에서 여러 태스크(Task)나 인터럽트(ISR)가 **공유 자원(Shared Resource)**을 동시에 접근할 때, 그 자원을 보호하기 위해 “한 번에 딱 한 주체만” 그 자원에 진입하도록 설계해야 합니다. 이 패턴을 흔히 **상호 배제(Mutual Exclusion)**라고 부르며, FreeRTOS에서는 주로 세마포어(Semaphore) 혹은 **뮤텍스(Mutex)**라는 커널 오브젝트를 사용해 구현합니다.이 글에서는 **바이너리 세마포어(Binary Semaphore)**를 이용해 간단한 상호 배제(mutex) 예제를 구현하는 방법을 자세히 설명합니다.1. 왜 ‘상호 배제(뮤텍스)’가 필요한가?모든 코드는 어떤 메모리나 하드웨어 레지스터를 읽거나 쓰는 방식으로 동작합니다. ..
임베디드 시스템에서 인터럽트나 이벤트가 아주 빠르게 반복해서 발생하는 상황이 있습니다. 예를 들어 버튼을 살짝만 눌러도 하드웨어 글리치 때문에 짧은 시간 안에 5~6번 미세하게 인터럽트가 튈 수도 있고, 어떤 센서 모듈에서 분당 수십 회 데이터를 쏟아낼 수도 있습니다. 이렇게 **“짧은 시간에 연속 이벤트가 발생”**할 때, 일반적인 이진 세마포어(Binary Semaphore)로는 최대 1건까지만 이벤트를 잡아두기 때문에 나머지 이벤트들은 전부 유실됩니다.이럴 때 유용한 방법이 바로 **카운팅 세마포어(Counting Semaphore)**를 이용해 “발생한 이벤트 건수만큼 세마포어 카운터를 +1씩 누적”해 두고, 헬퍼 태스크가 일괄로(=순차적으로) 처리하는 패턴입니다. 이 글에서는:왜 이진 세마포어만..
임베디드 시스템(특히 STM32 + FreeRTOS)에서, **짧은 시간에 여러 번 발생하는 인터럽트(이벤트)**를 한 건도 놓치지 않고 차례대로 처리해야 할 때가 있습니다. 예를 들어, GPIO 입력(버튼 누름)이 매우 빠르게 연속 발생하거나, 센서 데이터가 초당 수십 회 이상 쏟아지는 경우 등입니다. 이럴 때 **이진 세마포어(Binary Semaphore)**만으로는 “연속 인터럽트”를 모두 받아내고 처리하기 어렵습니다. 왜냐하면 이진 세마포어는 내부 카운터가 0⇔1 사이만 오가므로, 1건만 잡아두었다가 헬퍼(Task)에서 한 번 처리하고 나면 나머지 인터럽트가 모두 사라지기 때문입니다.이 문제를 해결해 주는 것이 바로 **카운팅 세마포어(Counting Semaphore)**입니다. 이 글에서는이..
앞선 강의에서 **이진 세마포어(Binary Semaphore)**를 이용해 “인터럽트→태스크” 동기화를 배웠습니다.다시 요약하면:세마포어 생성 시 “0(토큰 없음)” 상태가 된다.Helper Task(도우미 태스크)는 xSemaphoreTake(..., portMAX_DELAY) 호출 직후 블록(Block) → 무한 대기ISR(인터럽트 핸들러)에서 xSemaphoreGiveFromISR()을 한 번 호출하면, 세마포어 값이 “0→1”로 바뀌고,곧바로 헬퍼 태스크가 Ready 상태로 깨어난다.헬퍼 태스크는 xSemaphoreTake(...,0)로 즉시 “1→0”을 가져가(=Take) → 블록 해제된 뒤 실제 작업을 수행작업 끝나면 다시 xSemaphoreTake(..., portMAX_DELAY) 호출 ..
실시간 시스템에서 **인터럽트(Interrupt Service Routine, ISR)**와 태스크(Task) 사이에 작업을 분리하여 처리하고자 할 때, 이진 세마포어(Binary Semaphore)가 매우 유용한 도구가 됩니다. 다음 예제에서는:ISR(Interrupt Service Routine): “즉시 처리해야 하는 작은 작업”만 수행하고, 나머지 시간이 걸리는 연산은 “도우미 태스크(Helper Task)”에 넘겨 처리Helper Task: ISR이 깨어준(=Give) 세마포어를 받아 시간이 걸리는 실제 작업 수행이런 패턴을 사용하면 **ISR이 가능한 한 짧게 유지(“Sharp ISR”)**되기 때문에 시스템 응답성이 크게 향상됩니다.아래에서 “왜 필요한지”부터 “어떻게 구현하는지”까지 차근차..
이 글에서는 FreeRTOS에서 **이진 세마포어(Binary Semaphore)**를 이용해 두 개의 태스크(Manager와 Employee)를 순차적으로 동기화하는 과정을 자세히 살펴봅니다.Manager Task (생성자, Producer 역할): 티켓 ID를 생성 → 큐에 보관 → 이진 세마포어로 Employee Task에 “신호”Employee Task (소비자, Consumer 역할): 세마포어 “신호”를 기다렸다가 → 큐에서 티켓 ID를 꺼내 처리이 흐름을 통해 **“Manager가 먼저 티켓 ID를 준비하면, Employee가 그 ID를 즉시 처리”**하도록 구현함으로써, 불필요한 루프 대기 없이 효율적인 동기화를 이루는 방법을 소개합니다.목차왜 세마포어로 동기화하는가?이진 세마포어(Bin‐..
FreeRTOS에서는 여러 태스크가 서로 데이터를 주고받거나 작업 순서를 보장(동기화)해야 할 때, **세마포어(Semaphore)**를 자주 사용합니다. 특히 **이진 세마포어(Binary Semaphore)**는 “A 태스크가 데이터를 준비했을 때 B 태스크를 깨워서 처리하도록 한다”는 매우 대표적인 동기화 패턴을 간단히 구현할 수 있게 해줍니다. 본 글에서는 **“이진 세마포어를 사용해 두 태스크를 순차적으로 동기화하는 방법”**을 단계별로 살펴보겠습니다.1. 왜 동기화(Synchronization)가 필요한가?가령 다음과 같은 시나리오를 생각해 봅시다.Task 1(Producer): 센서에서 데이터를 읽어서 처리 결과(또는 가공 결과)를 준비한다.Task 2(Consumer): Task 1이 준비..
실시간 운영체제(RTOS)에서는 여러 태스크(Task)와 인터럽트(ISR)가 공유 자원(Resource)을 안전하게 사용하거나 이벤트를 신호(Signaling)하기 위해 **세마포어(Semaphore)**라는 커널 객체를 자주 사용합니다. FreeRTOS는 이 세마포어를 두 가지 주요 유형으로 제공합니다:Binary Semaphore (이진 세마포어)Counting Semaphore (카운팅 세마포어)본 글에서는 두 가지 세마포어의 특징과 용도를 정리하고, 실전 예시로 언제 어떻게 사용하면 좋을지 살펴보겠습니다.1. Binary Semaphore (이진 세마포어)1-1. 구조와 동작 원리값의 범위: 오직 0 또는 1 두 값만 가질 수 있습니다.값이 1일 때 → “세마포어 토큰(=열쇠)이 있다(Availa..
FreeRTOS를 사용하다 보면 “세마포어를 어떻게 생성하고, 내부적으로 어떤 정보가 관리되는가”가 궁금해질 때가 많습니다.이 글에서는 세마포어가 막 생성되었을 때 커널 내부에서 어떻게 관리되고, 각 태스크가 어떻게 대기·획득되는지 단계별로 살펴보겠습니다.1. 세마포어란 무엇인가?**세마포어(Semaphore)**는 여러 태스크(Task)나 ISR(Interrupt Service Routine)이“공유 자원(리소스)” 또는 “이벤트 신호”를 주고받으며 동기화(Synchronization) 또는 **상호 배제(Mutual Exclusion)**를 구현하게 하는 커널 객체입니다.FreeRTOS에서는 크게 두 종류의 세마포어를 지원합니다.Binary Semaphore (이진 세마포어)0 또는 1의 값만 가짐...
프로그램이 복수의 작업(스레드/태스크)을 동시에 수행하는 멀티태스킹 환경에서,여러 작업이 협력하여 원하는 결과를 올바르게 만들어내려면❗ “동기화” 와 ❗ “상호 배제” 개념을 반드시 이해해야 합니다.특히 임베디드 시스템에서는 FreeRTOS와 같은 실시간 운영체제를 많이 사용하므로,FreeRTOS가 제공하는 세마포어(Semaphore)·뮤텍스(Mutex) 같은 커널 객체를 활용해이 두 개념을 실전에서 어떻게 구현하는지 살펴보는 것이 중요합니다.1. 동기화(Synchronization)란?1-1. 일상(Real World) 예시“동기화”란 쉽게 말해 **“일정한 규칙(또는 시점)에 따라 여러 주체가 함께 움직인다”**는 의미입니다.예를 들어, 내일 오전 11시에 상사와 1:1 미팅이 잡혀 있다고 합시다.명..
FreeRTOS의 **소프트웨어 타이머(Software Timer)**는 실제 하드웨어 타이머 없이, 오로지 코드만으로 일정 주기마다 특정 콜백 함수를 호출해 주는 기능입니다.“500ms마다 LED를 깜빡이게 하고 싶다”거나 “1초마다 특정 작업을 수행해야 한다” 같은 반복적이고 주기적인 작업을 간편하게 처리할 수 있도록 도와줍니다.1. 하드웨어 타이머 vs. 소프트웨어 타이머1-1. 하드웨어 타이머MCU(예: STM32)의 타이머 페리페럴(TIM1, TIM2, …)을 직접 설정초단위(μs, ns) 정밀도 가능설정 단계타이머 클럭 분주(프리스케일러) 설정자동 리로드 레지스터(ARR)에 주기 값 설정인터럽트(업데이트 이벤트, CC 인터럽트 등) 활성화ISR(Interrupt Service Routine)에..
이 예제에서는 FreeRTOS 큐(Queue), 소프트웨어 타이머(Software Timer), 그리고 **태스크(Task)**와 **태스크 알림(Task Notification)**을 결합하여,UART로부터 사용자의 명령을 받아LED 이펙트 제어(LED 플래싱 패턴)실시간 시계(RTC) 설정 / 조회기능을 수행하는 심플한 콘솔 애플리케이션을 완성해 봅니다.1. 전체 구조 및 흐름 개요이 애플리케이션은 크게 **4개의 주요 구성 요소(모듈)**으로 나눌 수 있습니다.UART 입출력 모듈사용자로부터 **명령어(Command)**를 받아 파싱응답(메뉴, 에러 메시지 등)을 다시 UART로 출력명령어 처리(Task)“사용자 입력 → 큐(Queue)로 전송 → 명령어 파싱 태스크(CommandParserTask..
FreeRTOS 큐는 태스크 간 또는 ISR↔태스크 간 데이터를 주고받기 위한 강력한 도구입니다.이 글에서는 큐에서 데이터를 꺼낼 때 사용하는 두 가지 핵심 API—xQueueReceive() (큐에서 꺼내는 기본 함수)xQueuePeek() (큐 머리(Head) 내용을 확인만 하는 함수)—의 매개변수, 반환값, 동작 원리 및 실전 예제를 중심으로 자세히 설명합니다.1. 왜 데이터 수신 API가 중요한가?FIFO 통신문(First-In, First-Out)생산자(Producer) 태스크가 xQueueSendToBack() 또는 xQueueSendToFront()로 큐에 데이터를 넣으면,소비자(Consumer) 태스크가 xQueueReceive()를 통해 큐 머리(Head)에 쌓여 있는 데이터를 꺼내 처리..
FreeRTOS에서 **큐(Queue)**는 태스크 간 또는 ISR과 태스크 간 데이터를 주고받는 기본 메커니즘입니다.이 글에서는 큐에 데이터를 넣는 두 가지 주요 API—xQueueSendToFront()와 xQueueSendToBack()—를 왜, 언제, 어떻게 사용하는지를 “블로그 포스트” 스타일로 자세히 안내합니다. 각 매개변수의 의미부터 동작 원리, 예제 코드, 주의사항까지 빠짐없이 다룹니다.1. 큐에 데이터를 보내는 이유태스크 간 통신: 센서값, 명령, 로그 등을 생산자(Producer) 태스크가 큐에 넣으면 소비자(Consumer) 태스크가 꺼내 처리우선순위 조절:xQueueSendToBack(): 일반적인 “FIFO(First-In, First-Out)” 방식. 데이터가 큐의 끝(Tail)..
FreeRTOS에서 큐(Queue)는 태스크 간, 또 태스크와 ISR 간에 데이터를 안전하게 주고받기 위해 가장 기본이자 강력한 동기화 수단입니다. 이번 글에서는 큐를 **“어떻게 생성하는지”**에 초점을 맞추어, FreeRTOS의 xQueueCreate() API를 하나하나 해설하며, 실제 사용 예제까지 살펴보겠습니다.1. 큐를 왜 동적으로 생성하는가?FreeRTOS는 가벼운 RTOS이지만, “몇 개짜리 큐를 만들고, 아이템 하나는 몇 바이트인지” 미리 컴파일 타임에 알 수 없는 경우가 많습니다. 예를 들어:센서 개수가 OTA(Over-The-Air) 업데이트마다 바뀔 수 있다.데이터 구조체 형식이 프로젝트별로 달라진다.한 번에 몇 개의 데이터를 버퍼링해야 할지 런타임 중 결정되어야 한다.이럴 때 **..
임베디드 시스템에서 여러 태스크(Task)가 데이터를 안전하게 주고받는 방법은 여러 가지가 있습니다. 그중 가장 많이 사용되는 것이 바로 **큐(Queue)**입니다. 이 글에서는 FreeRTOS의 큐가 무엇이고, 어떤 특징을 가지며, 어떻게 생성·사용하는지를 자세히 살펴봅니다.1. 큐(Queue)란 무엇인가?**큐(Queue)**는 컴퓨터 공학에서 “FIFO(First In, First Out)” 구조를 구현한 자료구조입니다.입력(Enqueue): 큐의 끝(“tail”)에 데이터를 추가출력(Dequeue): 큐의 앞(“head”)에서 데이터를 제거만약 큐가 “영화관 매표소 앞의 줄”과 같다면, 가장 먼저 줄에 선 사람이 티켓을 먼저 받고 입장하는 것과 같습니다. [Head] ── 첫 번째 요소(데이..
LED 블링킹 예제(003 LED_Block_Tasks)에서 50 mA → ≈ 18 mA로!1. 문제: Block 지연으로 CPU 가 놀고 있다 🤦♂️vTaskDelay()를 써서 LED 를 토글하면, 각 태스크는 Blocked 로 빠지고 스케줄러는 Idle Task 를 실행합니다.Tracealyzer 로 보면 대부분의 시간(흰색)이 Idle Task 구간이죠.“Idle 동안 코어 클럭을 끄면 전력이 확 줄 텐데…?”2. 해결: Idle Hook 에서 Sleep 진입Idle Task 는 매 사이클 아래 과정을 거칩니다.내부 정리/클린업(TCB 반환 등)사용자 Hook 함수 호출 ➜ 여기서 저전력 진입!2-1. FreeRTOS 설정FreeRTOSConfig.h#define configUSE_IDLE_H..