1. OS
Process = 프로그램
Thread = Process 내부에서 동작하는 프로그램
Process → Process Direct Access 불가능 ⇒ IPC(Inter Process Communication) 사용
Windows, Linux : 범용 OS ← 8GB 이상
임베디드용 OS : 제한된 기능(스케줄링, 메모리 제어) ← 10kB 이하
- 종류 : RTOS, Micrium OS, …
OS 필수 기능
⇒ 스케줄링
- 프로세스가 실행되는 순서를 결정
- FCFS(선착순)
: 프로세스는 준비 대기열에 도착한 순서대로 실행. 비선점형 스케줄링 알고리즘
- 우선순위 스케줄링
: 각 프로세스에 우선순위 할당
- Round Robin(RR) ← 대부분의 OS에서 사용
: 각 프로세스에 실행할 시간 할당, 프로세스 순환하여 순서대로 실행
프로세스가 해당 시간 내에 완료되지 않으면 선점되어 대기열 뒤로 이동
2. RTOS(Real Time OS)
: 실시간 OS
(실시간 == 정해진 시간내에 thread가 동작)
CMSIS RTOS
: Cortex-M 마이크로컨트롤러용으로 설계된 실시간 운영 체제용 API
- CMSIS
- Cortex-M 프로세서를 위한 하드웨어 추상화 계층
- 하드웨어 주변장치 접근, 소프트웨어 구성을 용이하게 함
- 예시) HAL 라이브러리, NVIC, Systick 타이머, RTOS, …
- API
- OS와 프로세스가 통신하기 위한 프로토콜
- 특정 프로세스에서 메모리에 접근하기 위해서는 API가 필요
- 기본적이 메모리 접근은 malloc() 과 같은 함수를 사용할 수 있지만 복잡한 메모리 작업에서는 OS의 API를 사용해야 함.
scheduling 의 시간은 timer를 이용해서 계산
→ STM32에서는 Systick 기능 이용
`osDelay()` 대신 `HAL_Delay()` 를 사용하면 Block 이벤트가 발생하지 않아 Runing ↔ Ready state에서만 움직임
매개변수
- `defaultTask` : Task 이름
- `StartDefaultTask` : 함수 이름
- `osPriorityNormal` : 우선 순위
- `128` : stack Memory size
- `osThreadCreate(osThread(defaultTask), NULL)` 메모리에 Task 생성
`osKernelStart()` 함수가 실행되면 scheduling이 실행되며 이 아래있는 코드는 실행되지 않음
2-1. RTOS 사용 LED toggle
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
osDelay(50);
}
/* USER CODE END 5 */
}
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_8);
osDelay(100);
}
/* USER CODE END StartTask02 */
}
void StartTask03(void const * argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_6);
osDelay(500);
}
/* USER CODE END StartTask03 */
}
void StartTask04(void const * argument)
{
/* USER CODE BEGIN StartTask04 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_5);
osDelay(1000);
}
/* USER CODE END StartTask04 */
}
⇒ Task를 Thread라고 생각하면 됨
2-2. RTOS 사용 버튼 누르면 LED toggle
/* USER CODE BEGIN 0 */
int state = 0; // 전역변수
/* USER CODE END 0 */
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
osDelay(50);
}
/* USER CODE END 5 */
}
/* USER CODE BEGIN Header_ButtonTask */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_ButtonTask */
void ButtonTask(void const * argument)
{
/* USER CODE BEGIN ButtonTask */
Button_t Button1, Button2, Button3;
button_init(&Button1, GPIOC, GPIO_PIN_10);
button_init(&Button2, GPIOC, GPIO_PIN_11);
button_init(&Button3, GPIOC, GPIO_PIN_12);
/* Infinite loop */
for(;;)
{
if(button_getState(&Button1) == ACT_RELEASED)
state = 1;
if(button_getState(&Button2) == ACT_RELEASED)
state = 2;
if(button_getState(&Button3) == ACT_RELEASED)
state = 3;
osDelay(50);
}
/* USER CODE END ButtonTask */
}
/* USER CODE BEGIN Header_ledTask */
/**
* @brief Function implementing the Task3 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_ledTask */
void ledTask(void const * argument)
{
/* USER CODE BEGIN ledTask */
LED_t LED1, LED2, LED3;
LED_init(&LED1, GPIOC, GPIO_PIN_8);
LED_init(&LED2, GPIOC, GPIO_PIN_6);
LED_init(&LED3, GPIOC, GPIO_PIN_5);
/* Infinite loop */
for(;;)
{
if(state == 1)
{
LED_toggle(&LED1);
state = 0;
}
else if(state == 2)
{
LED_toggle(&LED2);
state = 0;
}
else if(state == 3)
{
LED_toggle(&LED3);
state = 0;
}
osDelay(200);
}
/* USER CODE END ledTask */
}
3. Shared Memory
Thread는 독립적으로 프로그램이 동작하는 것처럼 보인다.
공유자원 Shared Memory를 사용하여 각 쓰레드가 상호작용할 수 있다.
⇒ 2개의 쓰레드에서 동시에 Shared Memory에 Write하면? ← 중요
/* USER CODE END Header_LCDTask01 */
void LCDTask01(void const * argument)
{
/* USER CODE BEGIN LCDTask01 */
int lcdCounter1 = 0;
char buff[30];
/* Infinite loop */
for(;;)
{
sprintf(buff, "Task1 : %d ", lcdCounter1++);
LCD_writeStringXY(0, 0, buff);
osDelay(200);
}
/* USER CODE END LCDTask01 */
}
/* USER CODE BEGIN Header_LCDTask02 */
/**
* @brief Function implementing the lcdTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_LCDTask02 */
void LCDTask02(void const * argument)
{
/* USER CODE BEGIN LCDTask02 */
int lcdCounter2 = 0;
char buff[30];
/* Infinite loop */
for(;;)
{
sprintf(buff, "Task2 : %d ", lcdCounter2++);
LCD_writeStringXY(1, 0, buff);
osDelay(300);
}
/* USER CODE END LCDTask02 */
}
위 결과와 같이 제대로 출력이 안됨
Critical Section(임계 구역)
- Race Condition이 발생하는 시간, 구간
Race Condition : 여러개의 Thread가 동시에 같은 공유 자원을 사용하려고 하는 상황
공유 자원 처리방법
⇒ 상호배제(Mutual exclusion)
: key가 있어야 공유메모리에 접근할 수 있다 → 한번에 하나의 스레드만 접근 가능 → 사용 후 key를 다른 thread에 넘겨줌
- Mutex : key 1개
- Semephore : key 여러개
MUTEX 사용하기
`osMutexWait()` : 공유자원 사용하기 위해 key를 기다림 + 공유 자원에 접근하게되면 Lock
- Lock 상태에서는 다른 thread가 접근하지 못함
- scheduling 상태에서 Block 상태로 넘어감 → key 넘어오면 Ready로 이동
`LCD_writeStringXY()` : 공유 자원
`osMutexRelease()` : key를 넘겨줌
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
osDelay(500);
}
/* USER CODE END 5 */
}
/* USER CODE BEGIN Header_LCDTask01 */
/**
* @brief Function implementing the lcdTask01 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_LCDTask01 */
void LCDTask01(void const * argument)
{
/* USER CODE BEGIN LCDTask01 */
int lcdCounter1 = 0;
char buff[30];
/* Infinite loop */
for(;;)
{
sprintf(buff, "Task1 : %d ", lcdCounter1++);
if(osMutexWait(LCDMutexHandle, osWaitForever) == osOK)
{
LCD_writeStringXY(0, 0, buff);
osMutexRelease(LCDMutexHandle);
}
osDelay(500);
}
/* USER CODE END LCDTask01 */
}
/* USER CODE BEGIN Header_LCDTask02 */
/**
* @brief Function implementing the lcdTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_LCDTask02 */
void LCDTask02(void const * argument)
{
/* USER CODE BEGIN LCDTask02 */
int lcdCounter2 = 0;
char buff[30];
/* Infinite loop */
for(;;)
{
sprintf(buff, "Task2 : %d ", lcdCounter2++);
if(osMutexWait(LCDMutexHandle, osWaitForever) == osOK)
{
LCD_writeStringXY(1, 0, buff);
osMutexRelease(LCDMutexHandle);
}
osDelay(300);
}
/* USER CODE END LCDTask02 */
}
Made By Minseok KIM
'ARM > 2_Study' 카테고리의 다른 글
[ARM] STM32_Serial Communication(UART), Queue (0) | 2024.04.29 |
---|---|
[ARM] STM32_PWM, Driver(Motor) (0) | 2024.04.29 |
[ARM] STM32_Driver(CLCD I2C, Ultrasonic) (0) | 2024.04.26 |
[ARM] STM32_메모리 저장&실행 과정, Driver(Button, LED) (0) | 2024.04.26 |
[ARM] STM32_Low level Programming (0) | 2024.04.24 |
Let's Be Happy!
도움이 되었으면 좋겠어요 :)