Skip to content

임베디드 리눅스 프로그래밍 수업 정리

임베디드 시스템의 특징

  • 임베디드 시스템: 내부에 Computer(마이크로 프로세서/마이크로 컨트롤러)를 내장한 제품 혹은 시스템
  • 일반적인 계산 목적이 아니라 특별한 임무를 수행하도록 프로그램이 내장되어 있는 시스템
  • 목적에 알맞은 Processor의 특징에 의존한다
  • 일반적으로 보다 큰 시스템의 일부이거나 독립됨
  • 하드웨어와 소프트웨어의 변경이 매우 어려움
  • 가격에 예민함

임베디드 시스템처럼 호스트 시스템과 타겟 시스템이 다를 때 애플리케이션을 개발하기 위해선:

  • 효과적인 개발을 위한 특정 툴과 개발방법이 필요, 개발툴에 Hardware에 대한 Setting을 해줘야 함
  • Host 시스템이 Target에 알맞은 기계어를 생성하기 위해서 Cross Toolchain이 있어야 한다
  • 타켓 시스템의 디버깅을 위해 전용 디버깅 장비를 사용함
  • 개발 툴에 대해서, 그리고 개발 툴이 어떻게 동작하는지에 대해서 일반 애플리케이션 개발자보다 더 많이 알고 있어야 한다.

선점형 스케줄링

  • 하나의 프로세스가 CPU를 차지하고 있을 때, 우선순위가 높은 다른 프로세스가 현재 프로세스를 중단시키고 CPU를 점유하는 스케줄링 방식
  • 실시간 응답환경, Deadline 응답환경 등 우선순위가 높은 프로세스를 빠르게 처리해야 할 경우 등에 유용
  • 리눅스에서도 선점형 우선순위 Task를 지원함
  • 임베디드 시스템은 반응, 동작 시간에 예민하기에 선점형 스케줄링을 지원하는 리눅스를 주로 사용함

NFS(Network File System)의 정의

  • 네트워크 상에 연결된 다른 컴퓨터의 하드디스크를 내 컴퓨터의 하드디스크처럼 사용하는 것

minicom

  • 115200, 8N1로 세팅
  • Modem and Dialing 세팅은 A,B를 모두 비워줌
  • 설정이 끝난 후에 Save setup as dfl 실행하여 저장

ROM과 RAM의 차이

ROM의 주요 특징:

  • 비휘발성: ROM은 전원이 꺼져도 저장된 데이터가 유지된다.
  • 읽기 전용: 기본적으로 데이터를 읽을 수만 있고, 쓰기나 수정이 어렵다.
  • 느린 접근 속도: RAM에 비해 데이터 접근 속도가 상대적으로 느리다.
  • 영구 저장: 부팅 정보, 펌웨어 등 변경이 거의 없는 중요 데이터를 저장한다.
  • 낮은 용량: 일반적으로 RAM보다 저장 용량이 작다.
  • ROM에 파일시스템을 압축해 넣도록 설계된 cramfs라는 파일시스템이 있다. 간단하고 작으며 압축률이 높은 것이 특징이다.

이에 반해 RAM은 휘발성이며, 읽기와 쓰기가 모두 가능하고, 접근 속도가 빠르지만 전원이 꺼지면 저장된 데이터가 사라진다.

HDMI

  • High Definition Multimedia Interface (고선명 멀티미디어 인터페이스)

  • HDMI는 디지털 셋톱박스, DVD 플레이어 등에서 출력되는 고화질의 디지털 멀티미디어 신호를 모니터, 디지털 텔레비전 등의 디스플레이 장치에 연결할 때 사용하는 비압축 방식의 디지털 오디오/비디오 인터페이스 규격

  • HDMI는 PC와 디스플레이의 인터페이스 표준 규격인 DVI(Digital Visual Interface)를 A/V 가전용으로 변경한 것

  • 영상과 음성 신호를 압축하지 않고 플레이어에서 디스플레이 장치로 전송하기 때문에 별도의 디코더 칩이나 소프트웨어를 필요로 하지 않으며, 영상/음성/제어 신호 가 하나의 케이블로 전송되므로 기존의 번거로운 A/V 배선을 간단하게 할 수 있다.

  • 2002년 12월에 HDMI 1.0의 규격이 발표됨 (현재는 HDMI 2.0까지 나옴)

  • HDMI 시스템 구조는 신호를 발생시키는 소스(Source)와 수신하는 싱크(Sink)로 구성

  • 신호는 차등신호를 이용하여 신호손실을 줄인 TMDS(Transition Minimized Differential Signaling) 채널과 디스플레이 장치가 지원하는 비디오 포맷 정보를 전달하기 위한 DDC(Display Data Channel), 그리고 제어신호를 전달하기 위한 CEC(Consumer Electronics Control)로 구성되어 있다.

비디오 주사 방식

  • Non Interlace Scanning(Progresive Scanning)
    • 순차적으로 주사선을 이동
  • Interlace Scanning
    • 짝수, 홀수 라인을 교대로 제공
    • 순차 스캔에 비해 1/2의 스캔라인 신호를 전송하기에 작은 대역폭으로 전송 가능
    • 초당 60번의 데이터를 전송, 자연스럽게 초당 60회 CRT 화면에 새롭게 재생(refresh)되어 깜박거림이 없어지게 됨
  • 표시
    • 마지막에 p자가 붙으면 Progresive (ex. 720p, 1080p, etc..)
    • 마지막에 i자가 붙으면 Interlace (ex. 1080i)
  • https://blog.naver.com/fainstec_sales/221643541674

프레임버퍼

  • frame buffer란 linux system에서 그래픽을 표현할 수 있는 특정 메모리 디바이스를 말함.

  • PC라면 그래픽 카드, 일반 임베디드 시스템에서 LCD controller를 frame buffer 장치라고 함.

  • 최근에는 IP화 되어서 CPU에 내장

  • frame buffer를 user level application이 제어할 수 있도록 만들어진 device driver를 frame buffer driver라고 함 (/dev/fb0)

  • LCD에 출력하는 원리

    • User level에서 전송한 frame buffer data를 LCD driver가 수신하여 LCD controller가 TFT-LCD에 출력한다.
    • User level과 driver간에 “/dev/fb0”라는 node를 통하여 data를 전송하며, driver가 할당한 memory를 user application에서도 사용할 수 있도록 memory mapping을 한다.
  • 빨간색 사각형 박스 그리는 예제
...
include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include "videodev2.h"
#include "hdmi_api.h"
#include "hdmi_lib.h"
#include "s3c_lcd.h"
#define FB_DEV "/dev/fb0"
typedef struct FrameBuffer {
int fd;
void *start;
size_t length;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
} FrameBuffer;
int fb_open(FrameBuffer *fb) {
int fd, ret;
fd = open(FB_DEV, O_RDWR);
if(fd < 0){ perror("FB Open"); return -1; }
ret = ioctl(fd, FBIOGET_FSCREENINFO, &fb->fix);
if(ret < 0){ perror("FB ioctl"); close(fd); return -1; }
ret = ioctl(fd, FBIOGET_VSCREENINFO, &fb->var);
if(ret < 0){ perror("FB ioctl"); close(fd); return -1; }
fb->start = (unsigned char *)mmap (0, fb->fix.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(fb->start == NULL) { perror("FB mmap"); close(fd); return -1; }
fb->length = fb->fix.smem_len;
fb->fd = fd;
return fd;
}
void fb_close(FrameBuffer *fb){
if (fb->fd > 0) close(fb->fd);
if (fb->start > 0) {
msync(fb->start, fb->length, MS_INVALIDATE | MS_SYNC);
munmap(fb->start, fb->length);
}
}
int main() {
int i, j, x, y, ret, endFlag=0, ch;
unsigned int *pos;
unsigned int phyLCDAddr = 0;
FrameBuffer gfb;
printf("Hdmi Draw Box Test Program Start\n");
ret = fb_open(&gfb);
if(ret < 0){
printf("Framebuffer open error");
perror("");
return -1;
}
// get physical framebuffer address for LCD
if (ioctl(ret, S3CFB_GET_LCD_ADDR, &phyLCDAddr) == -1) {
printf("%s:ioctl(S3CFB_GET_LCD_ADDR) fail\n", __func__);
return 0;
}
printf("phyLCD:%x\n", phyLCDAddr);
hdmi_initialize();
hdmi_gl_initialize(0);
hdmi_gl_set_param(0, phyLCDAddr, 1280, 720, 0, 0, 0, 0, 1);
hdmi_gl_streamon(0);
x = 50, y = 100;
pos = (unsigned int*)gfb.start;
//Clear Screen(Black)
memset(pos, 0x00, 1280*720*4);
// Draw Box
for (i=x; i<x+100; i++) {
for (j=y; j<(y+100); j++) {
pos[j*1280+i] = 0xFFFF0000; // Red
}
}
// ...
hdmi_gl_streamoff(0);
hdmi_gl_deinitialize(0);
hdmi_deinitialize();
fb_close(&gfb);
return 0;
}

2D H/W Acceleration

  • 그래픽 버퍼를 처리하는 H/W 가속 기능

    • H/W 이미지 카피: 원하는 위치에 이미지 카피, 소스 이미지를 자름, H/W DMA를 통한 고속 변환 (CPU의 자원 소모 없음)
    • 이미지 포맷 변환: Ex) ARGB32 -> RGB16
    • 스케일 변환(이미지 크기 변환)
    • 로테이션: 이미지를 회전, 반전시킴
    • Alpha Blending: 반투명화

더블 버퍼링

  • 디스플레이 되는 영역에 메모리 Write가 일어나면 화면 깜빡임 (Flickering)이 일어남
  • 여분의 버퍼에 모든 화면을 그리고 난 뒤에 해당 버퍼를 디스플레이 버퍼에 옮김

아날로그(소리) 신호

  • 주기 (Period): 진동이 한 번 완전히 반복되는 데 걸리는 시간

  • 주파수 (Frequency): 신호가 1초 동안 진동하는 횟수

  • 진폭 (Amplitude): 진동의 중심에서 최대 변위까지의 거리, 소리의 경우 진폭이 클수록 더 큰 소리를 의미한다.

  • 나이키스트의 정리

    • 표본화 시 원음을 그대로 반영하기 위해서는 원음이 가지는 최고 주파수의 2배 이상으로 표본화 해야 한다.
    • 음악 CD의 표본화율이 44.1KHz

TinyALSA API의 기본 동작 과정

사운드를 재생하거나 마이크 입력을 받을 때

  • TinyALSA는 리눅스 커널에서 ALSA와 인터페이스하기위한 작은 라이브러리
  • 녹음 및 플레이를 위한 기본 pcm 및 믹서 API를 제공
  • 기본 API
    • pcm_open: 사운드 디바이스를 사용하기 위해서 Open 한다.
    • int pcm_write(struct pcm *pcm, const void *data, unsigned int count);: 사운드 디바이스에 데이터를 넣는다. 즉 사운드를 Play한다.
    • int pcm_read(struct pcm *pcm, void *data, unsigned int count);: 사운드 디바이스로부터 데이터를 받는다. 마이크등의 입력을 Capture한다.
    • int pcm_close(struct pcm *pcm);: 사운드 디바이스를 닫는다.

WM9715를 활용한 마이크 입력 볼륨 셋팅하기

  • 볼륨값에 해당하는 레지스터 값을 read 하여 수정하면 된다.

  • ioctl로 register에 대한 fd를 읽어 조작

  • 아래와 같은 데이터시트를 읽고 요구사항에 맞는 값을 설정한다.