본문 바로가기
Embedded System

[Lecture 12] Joystick

by Hangii 2022. 12. 6.

- JoyStick

  • JoyStick의 input은 아날로그 시그널이므로 이를 컴퓨터가 이해할 수 있도록 디지털 시그널로 바꿔줘야 한다. 
  • ADC(Analog-to-Digital Converters)는 아날로그 시그널로 들어오는 voltage 값을 디지털(bit sequence)로 바꿔준다.
    • 연속적인 analog값을 일정 주기로 sampling해서 디지털로 변환할 수 있다. 이때 sampling의 주기가 짧을수록 더 정교한(원래 아날로그 값과 비슷한) 데이터를 표현할 수 있다. 
    • sampling의 주기에 따라 같은 아날로그 시그널도 서로 다른 여러 개의 디지털 시그널로 표현될 수 있다.

  •   
    •  ADC에 사용 가능한 bit 수에 따라서도 디지털 시그널의 정교함이 달라진다. 0-10 사이의 값을 가지는 아날로그 시그널을 디지털화할 때, 12bit를 사용한다면 4096가지 다른 지점을 표현할 수 있고, 3bit를 사용한다면 8가지 다른 지점을 표현할 수 있게 된다. 

- Obtaining ADC values by Joystick

/*Store ADC14 conversion results: ADC를 통해 입력받은 현재 위치를 아날로그->디지털로 전환한다.*/
/*그리고 이 디지털 값을 resultsBuffer[]에 저장한다.*/
resultsBuffer[0] = ADC14_getResult(ADC_MEM0);  /*x좌표 위치 저장*/
resultsBuffer[1] = ADC14_getResult(ADC_MEM1);  /*y좌표 위치 저장*/

/*%5d 사용: resultsBuffer는 integer값임을 알 수 있다.*/
sprintf(string, "X: %5d", resultsBuffer[0]);
Graphics_drawStringCentered(&g_sContext, 
							(int8_t *)string,
                                8,
                                64,
                                50,
                                OPAQUE_TEXT);
sprintf(string, "Y: %5d", resultsBuffer[1]);
Graphics_drawStringCentered(&g_sContext,
							(int8_t *)string,
                                8,
                                64,
                                70,
                                OPAQUE_TEXT);

- sprintf() function

  • printf는 출력하고자 하는 값을 display에 나타내는 반면, sprintf는 출력값을 쓰고자 하는 string에 값을 저장한다.
  • sprintf 예시 1)
char mesg[20];
char hello[10] = "hello";
char world[10] = "world";
sprintf(mesg, "%s, %s!", hello, world);
printf("%s\n", mesg);

/*출력값: hello, world!*/
  • sprintf 예시 2)
#include <stdio.h>
#define MAX 20

int main(void){
	char first[MAX];
    char last[MAX];
    char formal[2*MAX+10];
    double prize;
    
    puts("Enter your first name:");
    gets(first);
    puts("Enter your last name:");
    gets(last);
    puts("Enter your prize money:");
    scanf("%lf", &prize);
    sprintf(formal, "%s, %-19s: $%6.2f\n", last, first, prize);
    puts(formal);
    
    return 0; 
 }

- Real-Time Operating Systems(RTOS)

  • RTOS가 필요한 이유
    • Task scheduling과 I/O handling이 자동으로 된다.
    • Task scheduling: To handle multiple tasks with different invocation rates or priorities(우선순위 기준으로 task 수행 - 동일한 우선순위를 가진다면 time slice를 한번씩 돌아가면서 실행한다.)
    • I/O handling: To handle multiple interrupts from internal and/or external events(interrupt를 통해 하던 일을 중단하고 프로세스 내에 어떤 일을 수행하도록 끼워넣을 수 있다.)
  • 프로그래머가 while문을 작성하면, while문 내의 코드들이 순서대로 실행된다. 따라서 최악의 경우, 지금 막 condition을 check하는 코드를 지났는데 input값이 변경될 수 있다. 이러면 while문을 끝까지 돌고 다음 while문 주기가 돌아와서야 변경된 input값이 반영된 결과를 얻을 수 있다.
  • GUI는 OS가 아니다. main OS는 보통 커널이라고 부른다. 이 커널 위에 GUI만 바꾸면 새로운 OS처럼 보이도록 할 수 있다. 
    • Android는 Linux 커널 기반의 OS이다. Ubuntu와 Andriod는 동일하게 Linux 기반의 OS인데, GUI만 다른 경우에 해당한다.
  • RTOS Application Code Example
void main(void){
	/*Initialize(but don't start)the RTOS: RTOS를 application레벨에서 사용한다고 설정*/
    InitRTOS();
    
    /*RTOS가 어떤 동작을 할 것인지 설정. OS는 등록된 task를 어떤 scheduling을 사용해 실행할 것인지 결정함*/
    StartTask(RespondToButton, HIGH_PRIORITY);
    StartTask(CalculateTakeLevels, LOW_PRIORITY);
    
    /*RTOS 실행시키기(this function never returns)*/
    StartRTOS();
  • RTOS: Tasks
    • Task들은 우선순위 순서대로 scheduling된다.
    • 각 Task들은 unique하게 가지는 context가 있다. (이 부분은 다른 task에 의해 접근이 불가하다.)
      • register values
      • program counter
      • stack
    • 여러 개의 task가 priority에 따라 하나씩 실행된다. (Multitasking) 이때 사용되는 방법은 priority-driven scheduler이다. prioirty순으로 실행할 task가 선택된다. 특정 task의 priority가 현재 수행하는 task보다 높아지면 현재 수행하던 것을 멈추는 방법이 있고, 현재 수행 task가 끝날 때까지 기다린 후 수행하는 방법도 있다.
    • 만약 동일 priority를 가지는 여러개의 task가 존재한다면 time-slicing을 통해 1ms씩 context 로딩->수행-> context저장의 과정을 거친다.
  • Preemption
    • Preemptive RTOS: 더 높은 priority의 task가 나타나면 기존에 돌고 있던 task의 context를 저장하고 중단한 후 새로운 task를 실행한다. 
    • Non-preemptive RTOS: 더 높은 priority의 task가 나타나면 기존에 돌던 task를 모두 마친 후 새 task를 실행한다.
  • Scheduler
    • Scheduler는 현재 진행중인 task와 새로운 task간의 priority 비교, 다음 실행할 task 지정 등의 일을 한다. 따라서 좁은 관점에서 scheduler 또한 하나의 task라고 할 수 있겠다.
    • 각 task들은 다음 특성 값을 가진다:
      • priority
      • state(running/ready/blocked/interrupted)

  • 여러 개의 task들이 하나의 global memory에 접근할 수 있으므로 특정 task가 global memory값을 수정하는 와중에 다른 task가 값을 읽어들인다면 두 task간의 정보 차이가 발생할 수 있다. 이는 공유 자원인 global memory에 하나 이상의 task가 동시에 접근했기 때문이다. 이런 문제를 피하기 위해서 flag을 설정한다. 
    • global memory에서 생기는 이런 문제를 사거리의 다른 방향에서 여러 대의 차가 접근하는 경우에 대입해서 이해해볼 수 있다. 이 경우 사거리의 중심부에서 차가 충돌하는 경우를 피하기 위해 flag를 설치한 후 이 flag을 먼저 가져간 차량이 먼저 사거리를 지나도록 하면 된다. flag을 가진 차량이 사거리를 지난 후에는 flag가 원위치로 돌아간다.

  • mutual exclusion: 하나의 task만이 critical section에 접근할 수 있다. 위의 사거리 예시에서는 깃발이 위치한 영역에 한번에 한 대의 차량만이 접근할 수 있다는 의미이다.
  • critical section: 코드 상에서 resource가 공유되고 있는 부분.
  • Semaphore
    • Flag = Semaphore
    • 여러 개의 flag(semaphore)가 존재할 수도 있다.(binary semaphore의 경우 깃발이 1개)
    • Get and Give: semaphore를 가져오는 것/원위치에 가져다 놓는 것
    • Take and Release
    • Pend and Post
    • P and V

 

'Embedded System' 카테고리의 다른 글

[Lab 10]  (0) 2022.12.05
[Lecture 11] LCD  (1) 2022.12.05

댓글