728x90

1. ISP

- 한쪽이 USB포트

- USB to UART 변환 칩이 있어 USB 단자를 PC에 꽃으면 COM으로 인식

- 처음 연결 시 USB to UART 변환 칩의 디바이스 드라이버를 찾음

 

ATmega128의 인터페이스

J8 : ISP 포트 <-에 연결

J5 : JATG 포트

ATmega128 인터페이스 회로도

 

JTAG 연결

- JTAG 장비의 빨간선이 보드 1번 핀에 맞도록 연결

 

 

AVR JTAGICE Mk II

 

STM32F103

- ARM Cortex-M3 코어 내장 CPU

- ARM Cortex-M 지원하는 JTAG 장비 사용 -> ST-Link V2가 가장많이 사용

- ARM Cortex-M 시리즈는 JTAG20핀 사용

STM32 시리즈 CPU만 지원

 

ARM Cortex-M 시리즈 JTAG 핀

 

STM32CubeMX 툴

- 기본적인 펌웨어 코드 생성

-> IAR Workbench, Keil MDK 등 다양한 개발환경 선택해서 사용 가능

300x250
728x90

AVR용 교차 개발환경

- Atmel 사의 AVR Studio

- IAR System 사의 IAR Embeded Workbench

- 코드 편집, 컴파일, 디버깅 등이 가능한 통합 개발환경

 

AVR Studio

- GNU에서 배포하는 GCC 사용

- 타 컴파일러들은 자체 제작 컴파일러로 라이센스 제한이 있음

- AVR Studio는 GNU 라이센스를 따르므로 무료 배포 가능 -> GPL 라이센스

- GNU General Public License 자유 소프트웨어 재단에서 만든 라이센스

 

STM32F103용 교차 개발환경

- 레조넌스사의 RIDE7

- IAR system사의 IAR Embeded Workbench

- Keil사의 MDK-ARM 등

 

Exynos 4412 개발환경

- 가상화 소프트웨어, 호스트 머신 리눅스, GNU ARM Toolchain 필요

- 윈도우가 필요할 수 있으므로 윈도우 환경에서 가상 머신 리눅스 사용이 좋음

 

리눅스 설치 판 존류

- 툴체인 종류 : Sourcery CodeBench, Linaro

- 레드햇 계열 : 페도라, 센토스

- 데비안 : 우분투

- 모두 리눅스 커널 사용

- 설치 명령어 : 래드햇 계열 RPM 또는 Yum, 데비안 계열은 Apt

 

데미안 계열

- Apt = Advanced Packaging Tool

- Apt-get 명령어로 패키지 업데이트

- /etc/apt/sources.list 파일에서 저장소 정보 관리

300x250
728x90

프로그래밍 

- edit -> build -> download -> debug

 

1) 디버깅

- 프로그램이나 하드웨어 장치의 문제점을 찾아 해결하는 것

- 일반 범용 PC의 디버깅 환경 -> IDE 내에 디버깅 내장 -> 문제 프로그램의 소스를 보면서 변수나 메모리 값 확인

 

임베디드 시스템 디버깅 환경

-  호스트 컴퓨터 - IDE <-> 디버거 장비 <--> AVR 타겟보드 - 디버깅할 프로그램

- 중간에 디버거 장비가 필요. 타겟 보드에 따라 디버거 장비가 결정

- AVR 타겟보드 디버깅 시 AVR용 디버거 사용

 

2) 소스레벨 디버깅

소스레벨 디버깅

- 프로그램 소스 코드 보면서 디버깅 하는 것

- 프린트 문으로 변수, 메모리 값 확인 시 : 문제가 되는 코드 위치와 CPU 내부 값 확인이 힘듬

-> 소스 레벨 디버깅 : 프로그램 진행을 멈추어 확인하고싶은 변수나 메모리, 어셈블리 값, CPU 상태도 확인 가능

 

3) JTAG

디버거

- 에뮬레이터라는 용어와 혼용해서 많이 사용

- JTAG이라는 디버깅 방식 개발전에 에뮬레이터 방식으로 제작됨

 

에뮬레이터

- CPU나 메모리 동작을 흉내내어주는 디버깅에 사용되는 장비나 소프트웨어

- 종류 : CPU 에뮬레이터, ROM 에뮬레이터

- 고가, CPU 100Mhz 이상인 경우 잡음이 심해 잡음이 어려움, CPU 모든 핀 연결해야하나 핀수가 많고 소형화되어 힘듬

 

JTAG

- Joint Test Action Group

- IEEE 1148.1 아이트리플이

- 조립된 PCB 테스트 목적으로 연구

- 디바이스 패키지, 고집적화로 물리적 접촉 방식으로 테스트가 힘듬 -> JTAG 탄색

- 외부로 나온 핀을 직접 접촉하지 않고, 테스트 목적의 셀을 칩 내부에 장착하여 전용 데이터 입력 핀인 데이터 입력으로, 입력시 데이터 아웃으로 출력하게 하여 칩이나 보드에 이상유무를 확인

-> Boundary Scan Architecture

- PCB 보드 검증 뿐만 아니라 디버거 만드는데서도 활용 가능 -> 에뮬레이터 방식의 대안이 됨

JTAG 방식

JTAG 디버거

- JTAG 단자라고 하는 편개의 신호만 연결하면 디버깅이 가능한 장비

- 보드에 존재했던 모듈들이 하나의 칩안으로 들어감(SoC), RAM, ROM, IO 등 칩안에 들어감

-> JTAG이 현실적인 대안이 됨

JTAG 인퍼테이스

- TDI : Test Data Input

- TDO : Test Data Output

- TMS : Test Mode Select

- TCK : Test clock

- nTRST : Test Rest

- 디버그 목적으로 몇개 신호선 추가 : nRESET, Vtref, DBGRQ

-> 타겟 시스템 자원을 소모하지 않아 디버깅으로 인한 타겟 소모나 영향이 없음

 

IEEE1149.1 디바이스 구조

- 시리얼 방식 사용 - 데이터라인이 TDO 한개 뿐이므로

- TAP 컨트롤러 : 스테이트 머신 방식, TMS 신호에 의해 Test Mode 전환 과정

  -> TAP 상태에 따라 TDI가 명령이거나 데이터 일 수 있음. TDO 값도 어드레스 이거나 데이터일수있음

- JTAG 이용 -> TAP 컨트롤러를 제어하여 필요한 명령어나 데이터를 읽고 쓰는 방식

- 동작 주파수가 10~100MHz인 TCK핀이 일반적으로 사용됨.

IEEE1149.1 디바이스 구조

 

JTAG Pin 배치

- CPU 코어나 종류, 버전에 따라 다양한 핀배치를 가짐

AVR JTAG

- AVR : 총 10개의 핀으로 구성

- nTRST : TAP 컨트롤러를 리셋하기 위한 신호

- nSRST : CPU 코어를 리셋하기 위한신호

AVR의 JTAG

ARM JTAG

- ARM 코어는 버전에 따라 핀맵이 달라짐

- ARM7 : 총 14개 핀

- ARM9 : 총 20개 핀

ARM코어 JTAG 핀

TMS (Test Mode Select)

- 디버깅 상태에서 Scan Chain을 결정하고 Bypass와 같은 디버깅 모드 선택에 사용

 

TCK Test Clock

- JTAG을 구동하는 Clock으로 보틍 10MHz

 

nTRST test rest

- JTAG의 Tap 컨트롤러 리셋

 

VTref Test Voltage reference

- JTAG 인터페이스의 입출력 전압 레벨을 설정. 전원 공급용이 아님

- JTAG Logic이 들어있는 프로세서 전압은 따로 공급이 필요

 

nSRST = nRESET

- Target CPU를 리셋하거나 리셋을 검출하는데 사용

 

DBGRQ

- 외부 트리거 신호로 프로그램 신호를 멈춤

 

DBGACK

- 정확한 시간 측정

- 프로그램 실행 정지 시 다른 디바이스를 정확하게 트리거 할수있도록 해줌

 

1) ISP 방식

ISP 장비

- CPU 내부 플래시 메모리, EEPROM을 지우거나 프로그래밍만 가능

JTAG

- 프로그래밍 + 소스레벨 디버깅이 가능

 

기존의 EPROM 형태 개발

- ISP 개발 이전 방식

- 외부의 EPROM을 사용하거나 EPROM과 CPU가 내장된 단일 칩을 땟따 붙여 롬라이터로 프로그래밍하고 디버깅하는 방식

- EPROM CPU를 ROM eraser에 넣어 삭제(1시간 이상걸림) 후 ROM Writer로 쓰기함.

 

ISP in system programming

- 플래시 메모리와 CPU가 단일칩이 되면서 등장

- 보드상 플래시 메모리 프로그래밍 가능

- 프로그래밍 시간이 수분 내로 획기적으로 축소

- AVR의 플래쉬 메모리에 직렬통신으로 실행 프로그램을 다운로드함

-> ISP를 사용하기 위해 ISP 프로그래머가 필요

 

PC와 연결 방식

- 병렬포트, 직렬포트, USB 포트

-> 근래는 USB포르를 대부부분 사용

 

AVR ISP방식 하드웨어 연결

- 6핀 방식과 10핀 방식 연결 방법 존재

  실제 사용하는 신호선 종류와 기능은 동일

  타겟 보드의 ISP 인터페이스를 보고 선택

- ISP 프로그래머는 둘다 지원

  ISP 프로그래머는 SPI인터페이스를 사용하여 연결

 SPI 인터페이스는 직렬통신 한 종류 -> 이 인터페이스로 ISP 사용

ISP 핀맵

 

SPI Serial Peripheral Interface

- 마스터와 슬레이 개념을 이용한 통신

- 사용 신호선 : MOSI, MIOS, SCLK, SS 등

- MISO : Master Input Slave Output

- MOSI : Master Output Slave Input

- SCK : Serial Clock

- SS : Slave Select (여러개 슬레이브가 존재시 선택하는 신호)

SPI 인터페이스

AVR의 ISP 신호

- 슬레이브가 AVR CPU 한 개이므로 SS는 사용하지 않음

- VCC라는 전원 신호와 /RES(AVR Reset)라는 리셋 신호를 추가하여 AVR ISP 신호선 완성

- 마스터 : ISP 프로그래머가 됨

- 슬레이브 : AVR CPU가 되어 PC 코드를 AVR의 플래쉬메모리나 EEPROM에 프로그래밍하게됨.

 

 

상용 JTAG 디버거 특징

- 다양하지만 대부분 고가

- 특정 CPU 코어만 지원하는경우가 대부분

 -> 다양한 CPU를 지원해도 라이센스 구매가 필요할수있음

 

TRACE32

- 거의 모든 코어 지원

- JTAG 장비 중 가장 비쌈

 

 

 

300x250
728x90

오실로스코프

- 회로 신호 검증 및 테스트 장비

- 신호의 상승 하강, 주파수 엣지사이 경과시간 정교하게 측정. 

- 동시 측정 가능한 입력 신호 갯수 4개

 

로직 애널라이저

- 32/64비트 데이터 버스 등 동시에 많은 신호 측정에 사용

- 채널 수 : 34 ~ 136개

- 오실로스코프처럼 아날로그적 특성은 측정 x. 0,1 디지털로직신호만 측정

- 디지털 설계 검증 디버깅에 도움됨

- 디시털 신호 동시 추적 및 상관관계 설정에 이용

 

1. 데이터 시트와 레퍼런스보드

데이터시트

- 부품, 하부 시스템, 소프트웨어 등 성능 특성등을 모아든 문서, 일반적으로 제조사에서 만듬

- 제조사 이름, 제품 형번, 이름, 제품특성, 기능 설명, 핀접속 다이어그램, 추천동작환경

- 직류/교류 특성, 입/출력 파형표, 검증 회로, 정오표

 

래퍼런스 보드

- CPU올려 테스트 가능한 보드의 회로도와 OS 관련 자료들

- 래패런스 보드 = 평가 보드 = 개발 보드

- ATmega128  래퍼런스 보드 : STK500

- STM32F103 래퍼런스 보드 : STM32 Nucleo

- Exynos4412 래퍼런스 보드 : Odriod-X

 

부품 배치도 component placement

-  PCB 보드상 부품이 놓여진 위치 소개

 

 

3. AVR 용 디버거

디버거 debugger

- 프로그램 테스트

- 프로그램 정확성이나 오류 찾아냄

 

AVR 용 디버거 장비

- Atmel-ICE, JATGICE : ARM Coretex-M 코어 CPU용 장비

- AVR ISP mk2, AVR Dragon :  AVR용 디버거 장비

- ISP 다운로드, ISP 다운로드 및 소스레벨 디버깅 가능 장비로 나뉨

 

ISP in system programming

- 보드에 장착된 CPU 내부 플래시 메모리를 지우고 프로그램하는 장비

- 이게 없을때 보드에서 CPU를 분리하여 롬라이터를 이용해 메모리를 지우거나 프로그래밍 함

 

ISP 다운로드

- 플래시 메모리에 펌웨어 다운로드

 

소스레벨 디버깅

- 펌웨어 소스를 화면으로 보면서 CPU 실행을 멈추고, CPU 메모리상태를 볼 수 있음

- JTAG 인터페이스를 통해 사용 가능

 

4. 계측 장비

1) 오실로 스코프

2) 멀티 테스터기

 

1) 오실로스코프

- 특정 시간 간격의 전압 변화를 볼수있는 장비

- 주기적으로 반복되는 전자신호 표시

- 시간에 따라 변하는 신호를 주기적이고 반복적인 하나의 전압 형태로 파악

- ex) 테트로닉스 사의 오실로스포크, 에질런트사의 오실로스코프

- 대역폭, 샘플링 속도, 채널 개수에 따라 다양

- 대역폭이 클수록 아날로그 신호 정확하게 측정 가능

- 최대 동작 주파수의 2배 이상 샘플링 가능해야만 신호 측정 가능

 -> ex) ATmega128 = 16Mhz 클럭 -> 샘플링 속도 32Mhz 이상

 

2) 멀티테스터기 multimeter

- 전압, 전류, 전기 저항 측정

- 보드 전원 체크 및 전원 사용량 등 측정시 멀티테스터기 사용

 

거버 파일 gerber file

- PCB 작업 결과 파일

- 부품, 핀 정보를 가짐 ->부품배치도

 

BOM 리스트

- 보드에 장착된 부품을 정리한 부품 리스트 파일

- 부품 구매 및 관리에 이용

- 설계 확정 후 최종 출력

 

ST-LINK

 

데이터 시트와 사용자 설명서 차이

- 데이터 시트 : 전기적/하드웨어적 특성 언급

- 사용자 설명서 : 레지스터 메모리맵과 같이 소프트웨어 관련 내용 언급

 

300x250
728x90

펌웨어 구현 준비물

1. CPU 보드

- 래퍼런스 보드, 평가보드 evaluation board, 개발보드 development board 라고도 부름

- AVR CPU, STK600 -> cpu 성능 평가, 재품 개발 기간 단축

써드 파티 <- 고가 보드를 본따 저가 보드 제조 판매

 

2. CPU 회로도

- 회로도 : 보드에 장차고딘 IC칩들간 연결을 그려놓은 설계도

- OrCAD나 PADS로 그림..

- CPU 판매사에서 제공. CPU 내부핀과 외부침 연결을 알수잇음

AVR  CPU 호로도

 

3. 데이터 시트

- IC칩 제조사가 만든 IC칩 사용 설명서

- 방대하고 어려운 문서. but 알아야 할부분은 제한적이므로 다 이해할필요는 없음

- 칩 부품번호, 번호 의미

- 일반적인 사항, 특징, 응용분야

- 온도/전압 범위

- 핀배치

- 전기/시간적 특성

AVR CPU 핀 배열

 

CPU 데이터시트

- CPU 내부 레지스터 구조

- 메모리맵

 -> CPU가 외부 디바이스나 내부모듈 제어를위해 필요한 레지스터들의 주소지도

 -> 펌웨어 구현에 반드시 필요

 

4.. 교차 개발 환경

- CPU가 실행할수있는 실행 파일을 만들고 타겟 보드에 다운로드 하기 위한 환경

- 타겟 보드는 성능이 부족해 실행파일 만들기 힘듬

- 호스트 PC에 에서 만듬

- 시리얼 케이블, 이더넷 케이블, USB 케이블 등으로 타겟 보드에 다운로드

 

터미널 프로그램

- 시리얼 케이블을 통해 타겟 보드와 호스트 PC가 통신하는데 사용

 

5. 디버거 장비

- 디버깅 및 기타 용도로 사용

- CPU의 내부 레지스터나 메모리값 등 확인 가능

 -> 소스 레벨 디버깅이 가능하도록 해줌. 소프트웨어를 멈추고 메모리 값을 확인할수있음

- 플래쉬 메모리에 펌웨어를 넣음

 -> 롬라이터 없으 온보드되어있는 플래쉬 메모리에 원하는값 써줌

 

6. 계측장비

오실로 스코프

- 하드웨어 개발을 위해 필요하며, 개발한 펌웨어가 제대로 동작하는지 확인

- 전기 신호를 시간 변화에 따라 화면에 그래프를 보여주는 장비

 -> 입력 신호 시간에 대한 전압 크기, 주기적인 신호 주파수, 성능에 따라 다양하게 측정 가능

* CPU나 메모리 동작상태나 신호 출력상태 확인에 필요

 

멀티 테스터기

- 개발한 펌웨어가 제대로 동작하는지 확인하는데 사용

- 저항값, 전압레벨, 전류값 등 확인 가능 

 

 

1) 자료 확보

ATmega128, STM32F103 -> 데이터 시트, 회로도 등 홈페이지에서 다운로드 가능

스냅드래곤 시리즈 -> 일반에 공개하지 않음

 

2) 펌웨어 개발에 필요한 소프트웨어

 1. 교차 개발환경

 2. 래퍼런스 펌웨어 소스

   개발자들이 자사의 CPU를 올바르게 사용할수있도록 제공

 3. 부트로더

   다운로더와 장비없이 펌웨어 업데이트가 가능, 실시간 운영체제를 올리는데 사용

 4. 실시간 운영체제

   네트워크 프로그램 같은 고차원 펌웨어 사용에 필요

 5. 디버거 장비용 소프트웨어

 

1. 교차 개발환경

- Atmel사의 AVR Studio

- Hp InfoTech 사의 CodeVision

- IAR System 사의 IAR Embedded Workbench

 

2. 래퍼런스 펌웨어 소스 

 avr soure 검색 -> 재조사나 깃헙 등으로 획득 가능

 

3. 부트로더

ATmega128(8비트 CPU)

- 운영체제 없이 쓰거나 부트로더없이 운영체제를 올리는 구조

-> 보통 부트로더를 필요로 하지 않음

- 디버거 장비없이 시리얼 만으로 호스트의 펌웨어를 가져와 업데이트 할때 부트로더를 사용할수있음

- 무선통신 : 지그비, RF4CE로 펌웨어 업데이트 가능

- OTAU(Over The Air Upgrade) : OTA 부트로더

 

4. 실시간 운영체제

- 멀티 태스크 환경을 구현하여 복잡한 프로그래밍을 세분화하여 쉽게구현가능한 환경

- 8비트 MCU에는 거의 사용되지 않았었음

- 8비트 CPU 발전과 복잡한 로직 구현 필요로 많이 채용되고 있음

 

FreeRTOS

- 무료로 제공

- 핵심 모듈 기본 제공

- 파일시스템이나 TCP/IP 스택은 필요에 따라 추가 가능

 

5. 디버거 장비용 소프트웨어

ISP 다운로더 장비 : CPU 내부에 접속하여 내부 플래시 메모리, 퓨즈, EEPROM 등을 지우거나 프로그래밍 하는 장비

JTAG 장비 : AVR CPU용 디버거 장비. AVR Dragon, JTAG ICE, JTAGICE mkII 등 다양함

* ISP는 다운로드만, JTAG 은 다운로드와 디버거 지원

 

 

300x250
728x90

BIOS

- Basic Input Output system

- 하드웨어 초기화 담당

- ROM에 저장 -> 하드디스크 준비 전 BIOS 실행 되어야 하기 때문

 

펌웨어 용어 시작

- 자연 시계 -> 기계식 시계 -> 전자식 쿼츠 시계 -> 디지털 시계

- 하드웨어로만 구현 : 복잡

- 마이크로 프로세서로 구현 (하드웨어 + 소프트웨어) : 하드웨어로 구현한것보단 간단. but SW없이 구동불가

  -> 하드웨어를 구동시키는 소프트웨어라는 의미  "펌웨어"

 

마이크로 프로세서와 펌웨어

- 프로그래밍 : 하드웨어로 구현한 기능을 소프트웨어로 구현

 -> 하드웨어는 수정 불가하나 프로그램은 추후 수정 가능

 

임베디드 시스템

- 마이크로 프로세서 혹은 CPU가 내장된 시스템

- 전기 사용되는 대부분 전자제품

 

펌웨어

- 임베디드 시스템의 HW/SW 연결

- 부트로더, 운영체제 커널, 디바이스 드라이버

 

스마트 폰 예시

- 터치 스크린 장치

- LCD - 터치센서 - 터치 컨트롤러

- 터치센서는 x/y축 좌표를 터치 컨트롤러에 전달.

- 터치 컨트롤러는 CPU에 좌표 전달 -> 디바이스 드라이버 이용

 

I2C 인터페이스

- 터치 컨트롤러의 인터페이스로 I2C 버스인터페이스사용

- 2개의 선으로 칩 간 통신 가능

- I2C 디바이스 드라이버 필요 -> CPU 내부 I2C 컨트롤러 블록 동작시키기 위해

-> CPU 특정 하드웨어 동작을위해 그에 맞는 펌웨어가 필요

 

I2C 컨트롤러 블록 동작 방법

- 특정 어드레스에 특정 값을 쓰면 하드웨어 블록들이 해당 동작을 수행

- status 레지스터, control 레지스터 보유

 

삼성 Exynos4412 CPU 구성

- 8개의 I2C 인터페이스와 컨트롤러

- 각각 32비트인 5개의 레지스터

- 어드레스 테이블을 매모리 맵이라 부름

 

부트로더

- 임베디드 시스템에 운영체제를 올림 + 하드웨어 초기화 작업

- 범용 컴퓨터 PC의 BIOS와 동일한 역활

- 임베디드 시스템에서는 RTOS라고 하는 작은 운영체제를 많이 사용했었음

 -> 근래 성능 향상으로 리눅스를 많이 사용

 

부트로더 저장 위치

- 가장 먼저 동작해야하므로 CPU의 리셋벡터 혹은 ROM의 시작 번지

-> CPU가 리셋되면 기계적으로 최초 어드레스에서 코드를 읽어오는 동작 수행(reset 벡터)

-> ROM에서 코드를 읽어와 순차적으로  실행 한 후 RAM에 복사하여 부팅 진행

 

부트로더 기능

1. CPU 초기화

 - 인터럽트 비활성화

 - watchdog 비활성화

 - clock, timer 셋팅

  * 부팅 관련 부분만 활성화 하고 나머지는 비활성화하거나 초기화

2. 메모리 컨트롤러 초기화

 - DRAM 컨트롤러 셋팅

3. 주변장치 초기화

 - 직렬 포트(UART) 초기화

 - 네트워크 장치 초기화

4. 커널 적재 및 램디스크 설치

 - 커널 - 운영체제의 핵심. 스케쥴러나 디바이스 드라이버 등이 포함됨

5. 커널 부팅

 

부트로더 종류

- 지원 CPU : ARM, Power PC, MIPS 등

- U-boot(Universal bootloader) : 가장 널리 쓰임. 다양한 CPU 지원

- FastBoot : 안드로이드 플랫폼에서 기본적으로 장착된 부트로더

- Redboot : 레드햇사 자사 RTOS인 리눅스 eCos의 부트로더로 사용하기 위해 제작

300x250
728x90

지수 함수

- e: 자연로그의 밑. 2.7182.무리수

로그함수

- 지수함수의 역함수

 

회귀식

- 회귀 분석 -> 회귀식 y=ax+b를 구함

- y : 종속변수

- x: 독리변수

- a: 회귀계수

- b: 기여율 (바이어스)

 

회귀 분석의 예

1. 독립 변수와 종속변수의 점 그래프 그림

2. 회귀식 구함

3. 회귀식 정도 확인

3. 회귀 계수 검정

4. 모 회귀 Ax + B 추정

5. 예측

 

최소 제곱법 least square method

- 모델 파라미터를 구하는 대표적인 방법

- 잔차의 제곱 합이 최소가 되도록 하는 a, b를 구해야함

 

최소 제곱법 계산

1. S_xx (x 편차 제곱합), S_yy (y 편차 제곱합), S_xy(xy 편자 곱합) 구함

2. S_e (잔차 제곱합) 계산

3. S_e를 a와 b에 대해 편미분 후 0으로 놓음

4. 회귀식을 구함

최소 제곱법을 이용한 회귀식

중상관계수 multiple correlation coefficeint

- 점과 회귀식이 어느정도 가까이 있는지 나타냄

- 결정계수 = R^2 (범위는 0~1)

- 회귀식에 가까울수록 결정계수가 1에 가까워짐

중회귀분석 multiple regression analysis

- 독립변수가 2개 이상인 회귀분석

- 중회귀식 사용

 

로지스틱 회귀분석 logistic regression

- 회귀분석과 달리 확률을 예측하기 위한 모델

 

로지스틱 회귀식

 

로지스틱 회귀식의 그래프 표현

 

최대우도법

- maximum likelihood method

- 우도 함수나 로그 우도 함수가 최대가 되는 확률 p(최우 추정값) 계산

- 확률 p가 10번 중 7번 발생하는 경우 예시

최우 추정값 계산

1. 로그 우도 계산

2. 로그우도 함수를 구하고 정리

3. 로그 우도 함수 L을 p에 대해 미분하고, 0과 대응

4. 위 식을 정리하여 최대 우도 p를 계산 가능

 

로지스틱 회귀식 계산

1. 추정 값 계산

2. 우도 함수 계산

3. 로그 우도 함수 계산

4. 최우 추정값 계산 -> 회귀 계수 a와 편향 b 구함 

5. 회귀 식 정리

오즈 odds

- 사건 A가 (발생확률)/(발생하지 않을 확률) 비

- P(A)가 1에 가까울수록 오즈는 커짐

로짓 logit

- 오즈에 자연로그를 취한것

300x250
728x90

디바이스 드라이버 작성

-> 디바이스 드라이버 작성 및 테스트 필요

- 처음부터 개발 <-> 개발 시간 절약을 위해 기존 다비이스 드라이버 참고 or 유사 기능 디바이스 드라이버 참고

- 커널 소스트리 driver 디렉토리 밑에있는 디바이스 드라이버 참고 or 공개된 디바이스드라이버 참고

-> 기능 검증으로 사용시 에러가 발생되지 않고, 사용자가 쉽게 써야함

 

(1) 디바이스 드라이버 개요

1) 디바이스 드라이버 제어

2) 디바이스 유형

3) 디바이스 드라이버

4) 주번호, 부번호

 

1) 디바이스 드라이버 제어

디바이스 제어 방법

1. /dev/mem 디바이스 파일 사용

 - memory mapped io인경우 메모리 어드레스를 사용한 장치접근

 - 디바이스 상태 진단을위해 주기적으로 상태점검해야하는 폴링방식 사용

    -> 디바이스로부터 인터럽트 요구에 대한 핸들러 구현이 복잡

2. 디바이스 드라이버 사용 

 

리눅스에서 디바이스 접근

- 사용자 프로그램 : 디바이스 파일을 사용해 접근

- 커널 : 디바이스 식별자(주번호, 부번호) 사용

- 주번호 : 디바이스 드라이버 식별

- 부번호: 같은 디바이스드라이버를 사용하는 여러개 드라이버 식별하기위해 사용

 

디바이스 파일

- 디바이스 드라이버에 대한 파일형태 인터페이스

- 디바이스 드라이버에 대한 접근과 일반 파일에 대한 접근이 동일

- 커널에서 사용하는 디바이스 파일은 /dev 디렉토리에 저장

 

디바이스 파일 생성

- 디바이스 파일 생성 : mknde [디바이스 파일이름] [디바이스 유형] [주번호] [부번호]

 ex) mknod /dev/mydevice c 240 1

    -> mydevice 라는 문자형 디바이스 파일을 /dev/디렉토리 밑에 만들고 주번호 240, 부번호 1로 설정

- 디바이스파일처리 : 저수준 파일입출력함수사용

 

저수준 파일입출력함수

- open 열기

- close 닫기

- read 읽기

- write 쓰기

- lseek 이동

- ioctl(제어)

- fsync(동기)

- 저수준 입출력함수는 버퍼를 사용하지 않고 직접 시스템 콜 호출

- 스트림 파일 입출력 함수 : 중간처리용 버퍼를 사용해 형식화된 입출력가능, 함수이름앞에 접두사 "f" 붙음

 

디바이스 드라이버 소스

- /usr/src/linux/drivers : 에 있는 소스들을 참고/변형하여 새로운 디바이스 드라이버 제작

- 모듈 형태로 디바이스 드라이버 개발시 -> 커널 재구성때 Loadable module support 옵션 선택해야함

 

2) 디바이스 유형

리눅스 디바이스 유형

1. 문자 디바이스

2. 블록 디바이스

3. 네트워크 디바이스

 

문자 디바이스

- 자료의 순차성을 지닌 디바이스

- 버퍼 캐시를 사용하지 않음

- 장치의 raw 데이터를 사용자에게 제공

 ex) 터미널, 시리얼포트, 병렬포트, 키보드, 사운드카드, 스캐너

- 리눅스에서 문자 디바이스 : 디바이스 유형이 'c'로 표시

 

블록 디바이스

- 랜덤 액세스 가능

- 버퍼캐시를 사용한 블록단위 입출력

- 파일시스템에 의해 마운트 되어 관리되는 디바이스

 ex) 디스크, RAM-DISK, CD-ROM

- 리눅스에서 블록 디바이스 : 디바이스 유형이 'b'로 표시

 

네트워크 디바이스

- 대응되는 디바이스 파일이 없음

- 네트워크를 통해 패킷을 송수신할수있는 디바이스

- 응용프로그램과의 통신은 socket(), bind() 등 전용 시스템 콜함수사용

 ex) 이더넷, PPP, ATM

 

3) 디바이스 드라이버

개요

- 커널은 디바이스 드라이버를 통해 입출력 디바이스 액세스

- 디바이스를 제어하는데 사용되는 데이터 구조체와 함수들로 구성

- 사용자 : /dev 디렉토리에 저장된 특수 파일의 파일명을 사용해 액세스

- 커널 : 디바이스 드라이버와 디바이스 주번호, 부번호로 액세스

user program <-> device file <-> VFS <-> device driver <-> real device

* 사용자 프로그램과 디바이스 드라이버 인터페이스는 가상 파일 시스템 상에 구현된 디바이스 드라이버를 통해 됨

 

사용자 관점에서 디바이스 드라이버

- 사용자는 디바이스 자체 자세한 정보 알필요없음

 ->디바이스는 하나의 파일로 인식

- 디바이스 파일 접근을 통해 실제 디바이스에 접근 가능

 

4) 주번호, 부번호

주번호 major number

- 리눅스 커널에서 사용할 디바이스 드라이버의 식별자로 0~255 숫자할당

- 2.4 커널 8비트 할당, 2.6커널 12비트 할당

 ex) 21: SCSI, 3 : IDE HDD

- 커널에서 사용하는 주번호 정보 : include/linux/major.h

 

부번호 minor number

- 동일한 디바이스 드라이버를 사용하는 서로 다른 장치 구분

- 2.4 커널 8비트

- 2.6 커널 20비트 할당

 ex) IDE 하드디스크 드라이버의 주번호=3인경우 첫번째 하드디스크 부번호 0, 두번째 하드디스크 번호는 1

 

 

 

 

(2) 디바이스 드라이버 작성

1) 디바이스 드라이버 작성 절차

2) 디바이스 드라이버 등록과 삭제

3) 파일 처리 함수

4) 디바이스 드라이버 컴파일

 

1) 디바이스 드라이버 작성 절차

작성 절차

1. 디바이스 드라이버 모듈 프로그램 작성 및 컴파일

2. insmod 유틸리티를 통해 디바이스 드라이버 모듈 적재 (커널에서 디바이스 드라이버 주번호 할당)

3. mknod 를 이용해 할당된 주번호로 디바이스 파일 생성

4. lsmod 유틸리티로 디바이스 드라이버 정상 등록 유무 확인

5. 디바이스 사용

6. 사용끝나면 rmmod 유틸리티를 사용하여 디바이스 드라이버 모듈 해제

 

기본 함수

- init_module() : 디바이스 드라이버 등록, 메모리 할당, 초기화

- cleanup_module() : 디바이스 드라이버 제거, 할당된 IO memory 영역 변환

- 함수 : read(), ioctl(), write(), open(), release()

-> 사용자 공간과 커널 공간의 데이터 전송, 메모리에 값을 읽거나 씀

 

디바이스 드라이버 원형

- 파일 처리 함수 데이터 구조체 생성 및 구조체 맴버변수에 제작한 함수 매핑

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
// 헤더 파일

int device_open(){}
int device_release(){}
ssize_t device_write(){}
ssize_t device_read(){}
// 함수 프로토 타입

static struct file_operations device_fops =
{
	read:device_read,
    write:device_write,
    open:device_open,
    release:device_release
};
// 파일 처리 함수

int init_module(void){} // 모듈 설치시 초기화 수행
void cleanup_module(void){} // 모듈 제거시 반환 작업 수행

/*
디바이스 드라이버는 모듈 프로그램 사용
-> 모듈 프로그램 원형에 디바이스 드라이버에 필요한 파일 처리 함수부분 추가
*/

 

 

2) 디바이스 드라이버 등록과 삭제

디바이스 드라이버 등록

- 디바이스 드라이버를 커널에 등록하는 함수

- 문자형 디바이스 : int device_chrdev(unsigned int major, const char *name, struct file_operations *fops);

- 블록형 함수 : int register_blkdev(unsigned int major, const char *name, struct file_operations *fops);

- 파라미터

  주번호 : 0을 주면 사용하지 않는 값반환

  이름 : /proc/devices에 표시 

  fops : 디바이스와 연관된 파일 연선 구조체 포인터 

- 음수가 반환시 오류가 발생한것. 디바이스 드라이버의 init_module()에서 호출

 

디바이스 드라이버 제거

커널에 등록되어있는 디바이스 드라이버 제거

- 문자형 디바이스 : int unregister_chrdev(unsigned int major, const char *name);

- 블록형 디바이스 : int unregister_blkdev(unsigend int major, const char *name);

- 디바이스 드라이버내 cleanup_module 루틴 안에서 호출

 

3) 파일 처리 함수

개요

- 디바이스 드라이버를 일반적인 파일과 유사한 인터페이스를 이용해 관리

- 디바이스는 파일 형태로 존재

- 커널은 파일 연산을 이용해 IO 연산수행하도록 인터페이스 구성

- 디바이스 드라이버 구현? -> 파일 연산 구조체에서 요구되는 기능들을 프로그래밍

ex) "mydev" character device의 파일 연산 구조체 예시

static struct file_operations mydev_fops = {
	write:mydev_put,
    read:mydev_get,
    ioctl:mydev_ioctl,
    open:mydev_open,
    release:mydev_release,
};

void mydev_put(){};
void mydev_get(){};
void mydev_ioctl(){};
void mydev_open(){};
void mydev_release(){};

 

file_operations 구조체

- 디바이스에 따라 선택적으로 사용

- 디바이스 연고나 연산은 함수를 직접구현하여 이 구조체의 해당함수로 매핑

 

파일 연산 구조체의 맴버 연선

- lseek() : 파일 액세스 지점 이동

- read() : 디바이스로 부터 데이트 입력받음

- write() : 디바이스로부터 데이터를 출력받음

- readdir() : 디렉토리 엔트리읽음

- poll() : 디바이스로부터 이벤트를 대기하므로 현재 프로세스를 대기큐에 넣음

- ioctl() : 디바이스 파일을 제어하며, read/write 함수로 처리할수없는 입출력 데이터 처리에 사용.

- mmap() : 파일이나 디바이스를 현재 프로세스의 메모리공간에 매핑

- open(),release()  : 디바이스 열기 닫기

- fsync() ; 버퍼에 남은 데이터를 모두 디바이스에 사용

 

4) 디바이스 드라이버 컴파일

- 일반 어플리케이션 컴파일 방법에도 별도 옵션 추가

-> 디바이스 드라이버는 모듈로 되어잇어 모듈프로그램 컴파일과 동일

ex) arm-linux-gcc -c -Wall -D__KERNEL__ -DMODULE -O2 driver.c

-> arm 용 크로스컴파일러를 사용한 예시

 

디바이스 드라이버 컴파일 옵션

- -c : 목적 파일이 insmod 명령을 통해 커널과 동적으로 링크 -> 링커를 호출하지 않고 컴파일만 진행

- -D__KERNEL__ : 소스의 선택적 컴파일

- -DMODULE : 소스의 선택적 컴파일을 위해 심볼 정의필요, 모듈 프로그램인 경우 커널과 모듈 심볼은 반드시 정의

- -O2 : 컴파일 최적화 레벨을 2로 설정. 컴파일러는 실행코드가 너무커지지 않는범위서

        실행속도를 빠르게하는 최적화 작업 수행

 

디바이스 드라이버 컴파일

- makefile을 작성해 make

CFLAGS=-D__KERNEL__ -DMODULE -Wall -O2
MODULE_OBJS=hello.o
$(MODULE_OBJS):
	arm-linux-gcc $(CFLAGS) -c hello.c
clean:
	rm -f *.o

 

 

 

(3) 디바이스 드라이버 사용 및 분석

1) 디바이스 드라이버 사용 절차

2) 디바이스 드라이버 작성 예시

3) 디바이스 드라이버 분석

 

 

1) 디바이스 드라이버 사용 절차

디바이스 드라이버 사용절차

1. 디바이스 드라이버 로딩

 - 컴파일한 모듈을 insmod 명령어로 로등

 - mknod 명령어로 디바이스 파일 생성

2. 응용프로그램 작성

 - open 함수로 디바이스 파일 열기

 - 디바이스 드라이버에서 제공하는 함수를 이용해 디바이스 제어

 - close()함수로 디바이스 파일 닫기

3. 디바이스 드라이버 제거

 - rmmod 명령어로 모듈 제거

 

2) 디바이스 드라이버 작성 예시

모듈 프로그램 소스

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

int init_module(void){
	printk("Start pf module!!\n");
}

void cleanup_module(void){
	printk("end of module!!\n");
}

Makefile

CC=arm-linux-gcc
KEERNELDIR=/working/kernel/linux-2.4.20
INCLUDEDIR=-I$(KERNELDIR)/include -I./

CFLAGS=-D__KERNEL__ -DMODULE -Wall -O2 -I$(INCLUDEDIR)

MODULE_OBJS=mymod.o
MODULE_SRCS=mymod.c

$(MODULE_OBJS):
	$(CC) $(CFLAGS) -c $(MODULE_SRCS)

clean:
	rm -f *.o

 

드라이버 적재 및 삭제

# insmod mymod.o // 모듈을 커널에 로딩
Using mymod.o
Start of Module !! //init_module 함수가 실행되어 printk함수에 의해 출력

# lsmod
Module	size	Usedby
mymod	247		0(unused)

# rmmod mymod //cleanup_module 함수 실행
End of Module !!

 

3) 디바이스 드라이버 분석

디바이스 드라이버

- ARM 프로세서 기반 하드웨어 플랫폼에서 ARM의 GPIO에 연결된 LED를 제어하는 LED 디바이스 드라이버소스

#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>

#define LED_MAJOR 0
#define LED_NAME "LED PORT"
#define LED_MODULE_VERSION "v1.0"
#define LED_ADDR 0xf1600000
#define LED_ADDR_RANGE 1
// LED 디바이스 주번호, 디바이스이름, 버전번호, 가상어드레스 주소, 어드레스 범위

static int led_usage = 0;
static int led_major = 0;
//LED 사용 여부 표시하는변수, 주번호 저장하는 변수

int led_open(struct inode *minode, struct file *mfile);
int led_release(struct inode *minode, struct file *mfile);
ssize_t led_writeb(struct inode *minode, const char *gdata, size_t length, loff_t *off_what);

static struct file_operations_led_fops = {
	write:led_writeb,
    open:led_open,
    release:led_release,
};

int init_module(void){
	int result;
    
    result = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
    if (resulr <0){
    	printk(KERN_WARNING "can't get any major\n");
    	return result;
    }
    led_major =result;
    //커널에 등록된 IO자원중 지정된 주소로부터 일정 크기 영역사용가능한지 여부 확인
    if(!check_region(LED_ADDR, LED_ADDR_RANGE))
    	request_region(LED_ADDR, LED_ADDR_RANGE,LED_NAME); //시용영역확부
    else
    	printk("Can't get IO region");
    printf("init module, led major number : %d\n",result);
    return 0;
}

void cleanup_module(void){
	release_region(LED_ADDR, LED_ADDR_RANGE);
    if (unregister_chrdev(led_major, LED_NAME))
    	printk(KERNEL_WARNING "%s driver cleanup failed \n",LED_NAME);
}

int led_open(struct inode *mindoe, struct file *mfile){
	if (led_usage !=0) return -EBUSY;
    MOD_INC_USE_COUNT;
    led_usage=1;
    return 0;
}

int led_open(struct inode *mindoe, struct file *mfile){
    MOD_INC_USE_COUNT;
    led_usage=0;
    return 0;
}

//디바이스에 데이터를 써넣는 함수
ssize_t led_Writeb(struct file *inode, const char *gdata, size_t length, loff_t *off_what){
	unsigned char *addr;
    unsigned char c;
    
    //사용자 영역변수인 gdata로부터 커널영역인 c변수로 데이터 전달받음
    get_user(c, gdata);
    addr=(unsigned char*)(LED_ADDR);
    *addr=c;
    return length;
}

 

 

응용 프로그램

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv){
	int dev;
    char buff;
    
    if (argc <= 1) return -1;
    dev = open("/dev/led", O_WRONLY);
    if (dev != -1){
    	buff =atoi(argv[1]);
        write(dev, &buff, 1);
        close(dev);
    }
    else {
    	printf("Device open Error\n");
        exit(-1);
    }
    return 0;
}

 

300x250
728x90

리눅스에서 입출력

- 수많은 입출력 장치해야함

- 디바이스 드라이버를 커널에 포함시켜 제공

- 직접 개발한 입출력 장치 추가하는경우 -> 장치 제어를 위한 디바이스 드라이버를 개발해야함

- 리눅스는 모놀리식 커널 -> 커널 기능 추가 및 변경 후 재컴파일 필요

- 대신 모듈을 사용해 커널에 동적으로 추가하거나 제거 ->재컴파일 해결, 필요할때만 커널의 크기를 줄이기가능

 

(1) 커널 프로그래밍 개요

1) 커널 프로그램과 응용 프로그램 비교

2) 커널 프로그래밍 주의사항

3) 커널 프로그램 함수

 

1) 커널 프로그램과 응용프로그램비교

실행 방식차이

1. 응용프로그램 : 실행 순서가 순차적임

  

2. 커널프로그램 : 커널에서 제공하는 시스템 콜/인터럽트에 의한 비동기적 프로그램

              -응용프로그램에서 시스템 콜 호출 or 외부 장치의 인터럽트

 

라이브러리

1. 응용프로그램 : 대부분 라이브러리를 링크하여 사용가능

2. 커널 프로그램 : 커널에서 export한 전용함수만 사용

 

어드레스 공간

- 응용프로그램, 커널 프로그램 : 서로 다른 어드레스 영역을 사용하여 각각 프로그램 코드에서 영향주지않음

- 페이지 오프셋 매크로를 기준으로 하위는 사용자 공간 상위는 커널공간이 된다.

 

사용자 공간과 커널 공간

1. 응용 프로그램 

 - 사용자 공간에서 실행. 직접적으로 하드웨어 장치나 메모리 접근 불가

2. 커널 프로그램

 - 커널 공간에서 실행. 직접적으로 하드웨어나 메모리 접근 가능.

 

변수및 함수명 충돌

1. 응용프로그램

 -현재개발하는 프로그램에서만 함수와 변수명 등 구별

2. 커널 프로그램

 - 커널 전반적인 함수와 변수명이 충돌하지 않도록 프로그래밍 해야함

 

2) 커널 프로그래밍 주의사항

커널 프로그래밍 주의사항

1. 라이브러리

 - 응용 프로그램에서 쓰던 "stdio.h" 같은 헤더파일의 중복성 유의

 - 커널에서 포함하는 헤더파일 사용

2. 변수및 함수명 충돌방지

 - 외부파일과 링크할 필요없는 심볼은 static 으로선언

 - 외부 파일과 링크할 필요있는 심볼은 심볼 테이블에 등록

 - 전역변수는 잘 정의된 접두어 사용

3. 주소 공간

 - 커널 스택 크기 제한. 인터럽트 핸들러 동일한 스택 사용 -> 큰 배열을쓰거나 재귀호출이 많이 안나도록 주의

 - 응용프로그램과 커널의 주소공간이 다르므로 응용프로그램과 데이터를 주고받기위해 특별한 함수사용

4. 에러 처리

 - 커널은 하드웨어 접근에 어떠한 제어 없음 - 커널 오류 ->치명적인 결과

 - 함수 호출시 에러발생 여부 검사해주고 처리

 

3) 커널 프로그램 함수

입출력 포트함수

- 일반 라이브러리 사용 불가

- 커널이 export 해준 함수만 사용가능

1. 입출력 포트함수

 - 디바이스 드라이버 프로그래밍에서 디바이스 레지스터 액세스에 활용

 - 입출력 포트 액세스 방법

    입출력 포트 함수 사용 : 입출력 포트 액세스 권한 획득 -> 포트 입출력 함수 호출

 - 디바이스 파일 통한 방법 : 디바이스 파일 /dev/port 오픈 -> read/write 함수 사용

2. 입출력 포트 할당

 - 커널 모드에서 액세스 권한 획득 - requset_region 함수

 - 커널에서 사용하고 있는 포트 확인 :/proc/ioports

 - 사용자 모드에서 액세스 권한 획득. ioperm 특정 포트에 대한개별설정함수, iopl 레벨로 권한설정하는 함수 함수

3. 데이터 입출력 함수

 - 입출력 포트로부터 데이터 입력 : inb,inw,inl(1,2,4바이트 입력)

 - 입출력 포트로부터 데이터 출력 : outb,outw,outl(1,2,4 바이트 출력)

4. 스트링 단위 데이터 입력 함수

 - insb, insw, insl(1*,2*,4* count 바이트 만큼 addr이 지정한 주소에 저장)

5. 스트링 단위 데이터 출력 함수

 - outsb,outsw,outsl(8비트, 16비트, 32비트  *count 만큼 출력)

 

인터럽트 처리 함수

- 디바이스 드라이버 -> 디바이스 관리 소프트웨어

- 인터럽트 핸들러 필요 -> 디바이스 드라이버에서 인터럽트 핸들러 등록 및 제어

- 인터럽트를 설정하고 처리하는 함수/매크로

1. 인터럽트 제어 함수

 - cli() :인터럽트 금지

 - sti() : 인터럽트 가능

2. 프로세서 상태 저장/복수 함수

 - save_flags : 현재 프로세서 상태를 flags 파라미터에 저장하는 함수

 - restore_flags : flags 파라미터에 저장딘 프로세서 상태 복원

3. 인터럽트 핸들러 등록/해제

 - request_irq : 인터럽트 핸들러 등록

 - free_irq : 등록된 인터럽트 핸들러 해제

4. 커널에서 동적 메모리 할당할떄 쓰는 함수

 - get_free_page, free_page : 한페이지 메모리할당하고 해제하는데 사용

 - kmalloc(), kfree() : 물리적으로 메모리를 할당하고 해제하는데 사용

 

(2) 모듈 프로그램

1) 커널 모듈

2) 모듈 프로그램 구성

3) 모듈 유틸리티

4) 모듈 컴파일

 

1) 커널 모듈

커널 모듈

- 커널 일부 기능을 독립적으로 구현한 코드

 -> 커널 실행중 동적으로 적재하거나 삭제 가능. 임베디드 시스템에 필요한 기능을 적재하는데 커널 모듈 사용

- 타겟 보드 목적과 구성에 따라 입출력 디바이스 설정

- 커널 설정시 모듈 설치가능 -> 정적로딩

- 커널이 실행되는 중간에 모듈 설치 ->동적 로딩

=> 사용자는 시스템 콜함수을 사용하여 모듈 사용가능

1. 디바이스 드라이버를 모듈로 설계

2. 커널 실행중 디바이스 드라이버를 동적으로 적재하거나 삭제

3. 커널을 반복적으로 재컴파일 하는 과정을 없앰

-> 개발시간 단축 + 불필요한 기능 동적 제거 => 커널 자원 효율적 이용

 

2) 모듈 프로그램 구성

모듈 프로그램 구성

1. 커널에서 수행될때 필요한 헤더파일과 모듈에 필요한 헤더파일 포함

2. init_module() 함수 정의

 - 모듈이 설치될때 초기화 수행 코드

 - 모듈에 필요한 메모리 할당 및 초기화 작업 실행

3. cleanup_module() 함수 정의

 - 모듈 제거시 반환작업 시행하는 코드

4. 모듈 설치될때초기화를 수행하는 코드와 모듈이 제거될때 반환하는 작업을 수행하는 코드 작성

5. init_module()과 cleanup_module() 함수 호출

 

모듈 관련 매크로

- MODULE_AUTHOR(string) : 모듈 제작자 정보

- MODULE_DESCRIPTION(string) : 모듈에 대한 설명 추가

- MODULE_PARAM() 모듈 파라미터 지정시

- MODULE_LICENSE() : 모듈 라이센스 설정

 

3) 모듈 유틸리티

모듈 적재

- /sbin/insmod [option] [-o module_name] object_file

- 옵션

  f : 커널과 모듈 버전이 달라도 강제 적제

  k : 모듈 일정시간안쓸시 kerneld 데몬이 자동 삭제

  m : 커널 패닉때 로드맵 출력해서 디버깅 쉽게함

  p : 모듈 적재 가능성 검사

  o : 모듈 이름 직접지정시 사용

  s : syslog에 메시지 출력

 

모듈 삭제

- /sbin/rmmod [option] module_name

- 옵션

 f : 강제 제거

 w : 모듈이 제거될수있을때까지 기다리다 제거

 s : syslog 매시지 출력

 

적재된 모듈 확인

- /sbin/insmod 나 cat /proc/modules로 확인 가능

 

모듈 사이 의존성 검사

- depmod 유틸리티

 

모듈의 적재 및 제거

- modprobe -> /etc/modules를 탐색하여 해당 모듈과 의존관계 있는 모듈들을 같이 적재

 

4) 모듈 컴파일

컴파일 옵션

- c 옵션 : 커널 모듈은 독립적 실행이 아니라 커널에 링크되어 실행됨. 링크 호출 제거

- Wall 옵션 : 잘못 동작되면 오류메시지 출력

- O 옵션 : 최적화 실행

 

심볼 정의

- _KERNEL 심볼 : 모듈이 커널모드에서만 실행

- MODULE 심볼 : 헤더파일에게 모듈에서 사용되는 코드로 인식

- LINUX 심볼 :리눅스를 인식

300x250
728x90

임베디드 시스템에서 입출력 장치 접근

1. 디바이스 드라이버 사용하는방법

 - 디바이스 데이터 입출력 기능과 디바이스 제어하는 기능

 - 디바이스에 대한 공통 인터페이스(파일 인터페이스)를 통해 모든 디바이스에 유사한 방법으로 접근

2. 물리 어드레스를 통해 직접 접근하는 방법

 - 운영체제 안쓰는 경우 디바이스 물리 어드레스맵으로 물리어드레스를 알수있슴

 - 리눅스 경우 메모리 디바이스 파일을 이용해 물리 어드레스 공간에 접근

 -> 물리 어드레스로 디바이스 제어를 위해 디바이스 동작과 제어 방법을 이해해야함

 

(1) 입출력 장치 제어 방법

1) 임베디드 시스템 정의

2) 가상주소를 이용한 접근

 

1) 입출력 장치 제어

입출력 장치 접근방법

1. 물리 어드레스 사용한 접근

 - 가상 어드레스를 물리 어드레스로 변경하는 전용함수로 입출력 장치 접근

2. 디바이스 드라이버 사용한 간접 접근

 - 운영체제서 제공하는 디바이스 드라이버로 간접적으로 접근

 

입출력 장치 제어 프로그램 구현 방법

1. 물리 어드레스 사용한 접근

 - 가상 메모리 변환 함수 사용

2. 디바이스 드라이버 사용한 간접 접근

 - 커널에 디바이스 드라이버 모듈 등록

=> 사용자 응용 프로그램 특성에 따라 입출력 제어방식 선택

 

입출력 장치 어드레스 매핑 방식

1. Memorry Mapped IO

 - 입출력 장치와 메모리가 동일한 주소체계

 - 프로세서는 입출력 장치도 메모리 처럼취급

 -> 다양한 메모리 접근 명령어들을 입출력 장치에 동일하게 사용가능

 <-> 메모리 공간이 줄어듬

2. IO Mapped IO

 - 메모리 주소체계와 입출력 장치 주소체계를 분리해서 사용

 - 입출력 전용 명령어 및 전용 주소 체계 사용

 -> 메모리 공간 손실 없음

 <-> 입출력 전용 명령어 필요

=> 대부분 32비트 프로세서는 Memoery Mapped IO 사용

 

가상 어드레스 Virtual Address

- 리눅스 커널 내부에서 사용하는 논리적 어드레스 체계

- 메모리 관리 시스템 MMU을 사용하여 물리 어드레스와 가상 어드레스 변환

- TLB Translation Looaside Buffer

  1. MMU 내부에 존재

  2. 물리 어드레스 또는 가상 어드레스로 변환시 참조하는 테이블

  3. 응용프로그램에서 사용하는 가상 어드레스는 TLB를 사용해 물리 어드레스로 변환되어 메인 메모리를 직접 액세스

  4. 대부분 32비트 프로세서는 Memory mapped io 사용

   -> TLB를 통해 가상 어드레스만으로 입출력 장치를 직접 액세스

 

포인터를 사용한 데이터 전송

- 응용프로그램에서 입출력 장치에 데이터 전송하는것은 포인터 변수에 물리 어드레스줘 데이터를 쓰고읽으며 이루어짐

* 리눅스 커널에서 물리적 접근을 허가하지 않기 때문에 아래의 경우 오류가 발생 -> 가상주소를 사용해야함

unsigned int *ptr;
ptr = 0xf1000000;	//물리주소 할당
*ptr = 0xc0;		//포인터를 사용한 데이터 쓰기

2) 가상주소를 사용한 접근

메모리 디바이스

- 메모리 디바이스 파일 /dev/mem

  -> 시스템 메모리 공간에 접근할수 있는 장치파일

- 메인 메모리의 이미지를 가진 문자형 디바이스

- 주로 시스템 테스트 용도로 사용

- 입출력 장치를 직접접근하는 디바이스로 활용

 

응용 프로그램에서 특정 물리 어드레스 접근

- 가상 어드레스 획득 : mmap()함수

1. 입출력 장치의 가상어드레스 획득

2. 어드레스에 대한 읽기 쓰기 작업 실행

3. 입출력 장치와 데이터 전송

- 데이터 읽기쓰기 : 메모리 장치 디바이스를 통한 lseek(), read(), write()함수 사용

 

mmap 함수 사용

- 파일이나 디바이스를 메모리로 매핑시켜주는 함수

- 반환값 : 주어진 물리주소에 해당하는 가상주소값

 

응용 프로그램 코드에서 "mmap()" 함수 사용절차

1. mmap() 호출

2. 커널은 내부적으로 mmap() 함수 파라미터를 해석하여 매핑 영역 설정

3. 그 위치에 해당하는 가상주소를 계산하여 반환

4. 응용프로그램에서는 반환된  가상주소를 포인터 변수에 대입

5. 포인터 변수에 값을 할당하거나 변수 값을 읽어 데이터 전송

 

2)munmap()

- munmap() - mmap() : par 함수

- mmap으로 맵핑된 메모리 해제

- 형식

#include <unistd.h>
#include <sys/mman.h>
int munmap(void *start, size_t length);

- 파라미터

  start : mmap()에서 반환했던 가상주소를 대입하여 해제할 매핑영역 전달

  length : 해제할때 영역의 길이를 byte 단위로 계산하여 대입

- 성공시 0 실패시 -1 반환

 

munmap() 실행에 따른 오류반환값

1. EBADF : fd가 유효하지 않거나 MAP_ANONYMOUS가 설정되지않음

2. EACCES : MAP_PRIVATE가 설정되어있지만, fd가 못쓰는 경우

3. EINVAL : starrt나 length나 offest 이 적당하지 않음, 너무크거나 PAGESIZE 경계로 정렬되지 않음

4. EAGAIN : 파일이 잠겨있거나 너무 많은 memory가 잠김

 

mmap/munmap 함수사용하는 방법

1. open()함수로 파일 디스크립터 획득

2. mmap()함수로 제어할 IO 포인터 획득

3. 포인터로 값을 읽거나 원하는 값을씀

4. munmap() 함수로 매핑한 메모리 공간 해제

5. close()함수로 오픈한 파일디스크깁터 반환

 

간단한 LED 제어

#include <unistd.h>
#include <sys/mman.h>

#define ADDR_LED 0x00a1111

fd = open("/dev/mem",O_RDWR);
addr= mmap(NULL,1,PROT_WRITE,MAP_SHARED,fd,ADDR_LED);
//1바이트를 메모리에 매핑, 매핑 영역에 대한 쓰기 권한 허용, 다른프로세서에서 쓸수있도록 매핑공유
*addr=0xaa;
munmap(addr,1);
close(fd)

간단한 전체 프로그램

#include <unistd.h>
#include <sys/mman.h>
#include <asm/fcntl.h>

int main()
{
	int fd;
    unsigned int *maddr, *ptr;
    if (((fd=open("/dev/mem", O_RDWR)) < 0) exit(1);
    
    maddr=mmap(NULL, 1024, PROT_WRITE, MAP_SHARED, fd, 0xf0000000);
    if ((int)maddr <0) return -1;
    ptr = maddr;
    ptr= ptr+68;
    *ptr=0x1000401;
    ptr++;
    *ptr=0xf10080000;
    munmap(maddr,1024);
    close(fd);
    return (0);
}
300x250

+ Recent posts