하드웨어 제어에서, Interrupt의 중요성
키보드, 마우스, 네트워크 통신 등 이 모든 것은 바로 인터럽트이다.
인터럽트가 발생하면,
해당 인터럽트가 발생 시 호출되는 함수가 돌아와진다 -> 콜백 함수
펌웨어에서의 인터럽트 발생과 리눅스(OS)에서의 인터럽트 발생은 차이가 있다.
펌웨어에서의 인터럽트 발생
- 펌웨어는 하드웨어에 가까운 소프트웨어로, 하드웨어를 초기화하고, 특정 하드웨어 기능을 제어하는 역할
- 펌웨어에서 인터럽트가 발생하면, 펌웨어 내부의 인터럽트 핸들러가 직접 인터럽트를 처리
- 이 경우, 인터럽트 처리는 매우 간단하며, 빠른 처리 속도가 중요합니다.
리눅스(운영체제)에서의 인터럽트 발생
- 리눅스와 같은 운영체제에서 인터럽트가 발생하면, 커널에서 인터럽트를 처리
- 커널은 인터럽트 발생시, 해당 인터럽트에 대한 처리 루틴을 찾고, 인터럽트 처리를 위한 커널 루틴을 실행
- 이 과정에서 운영체제는 인터럽트 처리를 위해 리소스 할당, 스케줄링, 동기화 등과 같은 고급 기능을 사용하여 처리
타이머
delay() vs timer()
delay()는 정확한 시간 측정이 어렵다 -> 커널이 멈추기 때문
timer() : CPU의 클럭 수를 이용해서 시간을 측정
Bootloader
운영체제를 실행하기 전에 메모리에 올려지는 프로그램을 의미
하드웨어 초기화, 운영체제 로딩 등을 담당
기존의 Device Driver를 개발 시, app & device file & H/W 등이 필요하지만,
부트로더에서는 H/W랑 echo.c를 수정한 test code만 있으면 OS 진입전에 H/W 접근이 가능해서 빠른 테스트가 가능하다.
Image
특정 프로세스를 실행하기 위한 모든 파일과 설정 값을 지닌 것으로, 더 이상의 의존성 파일을 컴파일하거나 이것저것 설치할 필요 없는 상태의 바이너리 파일을 의미
리눅스 커널 이미지 파일은 "/boot"에 있다
리눅스 커널 이미지는 일반적으로 압축되어 관리되는데, 부트로더가 압축을 풀어 메모리에 적재한다.
- zImage : gzip으로 압축된 kernel image
- bzImage : 파일 크기가 큰 kernel image (통상 1MB 이상 수준)
그래서 나만의 리눅스 운영체제를 제작할 수 있다.
1) 원하는 버전의 리눅스 커널을 인터넷에서 다운로드
2) 리눅스 커널 수정
- 디바이스 드라이버 개발, 추가, 나만의 OS에 맞춰 각종 소스코드 수정
3) 리눅스 커널을 컴파일(build)해서 리눅스 커널 이미지를 생성
4) 부트로더를 인터넷에서 다운로드
- 보통은 리눅스의 경우, GRUB이 같이 빌드 된다. 그 외의 부트로더를 쓰고 싶다면 다운로드받으면 된다.
5) Board 동작 시키기
- 보드에 부트로더와 리눅스 커널 이미지를 함께 사용해서 보드를 동작 <-- Bring Up 이라고 함
PC Booting Process
CMOS (Complementary Metal-Oxide-Semiconductor)
- 비휘발성 메모리가 들어있는 하드웨어
- 메모리 크기, 부팅 순서, HW 구성 정보, 설정 값 등의 CMOS Data를 저장함
- 배터리 전원을 사용
- 부팅 시, BIOS가 CMOS에 있는 정보를 가져와 부팅을 시작
BIOS (Basic Input/Output System)
기본적인 I/O 를 위한 Firmware
- 컴퓨터 부팅시 바로 BIOS(Firmware) 가 동작을 시작
- ROM BIOS 에 BIOS 설정 Utility가 들어있음
- CMOS의 설정값을 변경 가능
POST (Power-on self-test)
BIOS에서 Power를 켜자마자 주변장치들을 검사하는 과정
- BIOS가 POST를 하고 있을 때 , Log Message가 출력 됨
UEFI (Unified Extensible Firmware Interface)
64bit 기반 LBA 시스템
- BIOS와의 차이점
- 화려한 그래픽 UI
- 2.2TB 이상 디스크 사용을 위한 GPT(GUID Partition Table) 지원
GRUB (GRand Unified Bootloader 2)
GNU 프로젝트에서 개발한 부트로더
- 현 대부분 리눅스 배포판은 GRUB2를 사용
GRUB 설정 파일 변경
$ sudo vi /etc/default/grub
위의 네모 박스와 같이 값을 수정해 줌
$ sudo update-grub
해당 명령어를 실행해야, grub 수정 사항이 저장된다.
수정 사항은 "/boot/grub/grub.cfg"에 update-grub 명령어를 통해 환경설정 파일이 만들어진다.
이후 재부팅 진행
$ sudo reboot
다음 키를 누르면, 키에 설정된 옵션이 진행된다.
- E : grub.cnf 내용 확인
- C : command 모드로 진입
여러 옵션이 있으니 나중에 찾아보면서 설정을 바꿔보자
U-boot (Universal Bootloader)
컴퓨터의 부팅 프로세스를 제어하는 오픈 소스 부트로더
*ARM : "Advanced RISC Machines"의 약어로, 저전력 임베디드 시스템에서 많이 사용되는 프로세서 아키텍처
*ROM : "Read-Only Memory"의 약어로, 컴퓨터 시스템에서 사용되는 기억장치
PC 계열과 ARM 부트로더의 차이
x64_86
- 0 단계 : ROM 코드
- 1 단계 : BIOS or UEFI
- 2 단계 : Bootloader (GRUB)
- Linux Kernel 실행
ARM
- 0, 1 단계 : 칩셋 사 제공
- 2 단계 : Bootloader (u-boot)
- Linux Kernel 실행
Rpi4에서 U-boot 동작시키기
1. Rpi4 - UART - Desktop 시리얼 통신 형성
Rpi4 - UART 연결
PC - UART - Rpi4 연결을 통해 시리얼 통신이 가능하도록 만든다.
Rpi4에서, Serial 환경 설정 Enabled로 바꾸기
Desktop에서, UART Driver 설치
https://ftdichip.com/drivers/vcp-drivers/
모델명 : FT232BL
압축 해제 후, 해당 설치 파일을 설치 후 재부팅하면 된다.
UART 테스트 진행
mobaXterm에서 지원하는 Serial 연결을 이용, 아래 사진처럼 setting 진행
2. U-boot 이미지 빌드
U-boot 이미지 생성을 위한 환경 설정
RaspberryPi, ubuntu 두 곳에 모두 진행할 것
# Requirement 설치
$ sudo apt install git vim gcc
$ sudo apt install bc bison flex libssl-dev make libc6-dev
$ sudo apt install libncurses5-dev #
$ sudo apt install crossbuild-essential-armhf # 크로스컴파일 툴체인 설치
# Home directory에 설치
$ git clone https://github.com/u-boot/u-boot.git
# config 파일 수정
$ cd ./u-boot
$ sudo vi config.mk
config.mk 파일 내에 다음 문장 추가 (오타 주의) --> CROSS_COMPILE make 변수 추가
CROSS_COMPILE := arm-linux-gnueabihf-
.config 파일 생성
마찬가지로 RaspberryPi, ubuntu 두 곳에 모두 진행할 것
# U-boot 폴더 내에서 진행
$ sudo make rpi_4_32b_defconfig
.config 파일 변경
.config 파일 변경 시에는 command line interface를 이용한다. (수동으로 작업 x)
$ make menuconfig
u-boot 빌드하기
RaspberryPi에서만 진행할 것
$ sudo make -j4 # 코어 개수에 맞게 숫자 설정
# 완료 후, 빌드된 u-boot.bin 파일을 /boot 디렉토리에 이동시키기
$ sudo cp ./u-boot.bin /boot/.
u-boot로 부팅하기 위한 사전 작업 진행
마찬가지로, RaspberryPi에서만 진행할 것
# /boot 디렉토리에, config.txt 수정
$ cd /boot/
# 해당 파일이 복사되었는 지 확인
$ ls -al u-boot.bin
# config 수정
$ sudo vi ./config.txt
위 그림처럼, config.txt 맨 아래에 kernel=u-boot.bin 을 가장 아래에 추가
해당 세팅을 저장하면, Rpi4가 기존 부트로더로 부팅하지 않고 u-boot.bin을 활용해 부팅을 한다. 이유는 아래 그림을 참고
3. 재부팅
$ sudo shutdown -h now
부팅 진입 순서
1. 라즈베리파이의 전원 빼기
2. UART USB 빼기 <-- USB를 빼야 Rpi의 전원이 완전히 끊김
3. 1 초간 대기
4. UART USB 연결
5. 라즈베리파이 전원 연결
6. Serial 로 진입
U-boot command는 document를 찾아볼 것
U-boot Custom Command 생성
해당 방법을 을용해서 Device Control도 가능하다.
먼저 ubuntu에서 다음 파일을 보자.
$ cd ~/u-boot/cmd
$ ls -al echo.c
위 코드를 응용해서 custom command를 만들어보자
echo.c 파일 복사해서 template 만들기
# echo.c 복사
$ sudo cp ./echo.c ./custom.c
$ sudo vi custom.c
1. :%s/echo/custom/g : 코드 내 echo를 모두 custom으로 바꿈
2. max argument를 0으로 수정
cmd/Kconfig 파일 수정 후 저장
echo와 양식을 맞춰서 이름만 변경 후 기입
cmd/Makefile 파일 수정 후 저장
echo로 검색해서 복사 붙여넣기를 통해 CUSTOM 이름으로 한 줄 더 생성
Custom 명령어 등록 체크
$ cd ~/u-boot
$ sudo make menuconfig
Command line interface 진입 후 / 입력 시, 검색창에서 "custom" 검색하면 명령어가 뜬다.
Save 버튼을 누른 후 나오기
u-boot.bin 파일 생성
$ cd ~/u-boot
$ sudo make -j4
RaspberryPi 부팅 파일 삽입
이제 Ubuntu에서 생성한 u-boot.bin 파일을, Raspberry Pi의 microSD 카드의 /boot/ 디렉토리에 삽입
이후 UART를 이용해서 command를 입력 시, command가 작동하는 것을 알 수 있다.
'IT_Study > Embedded System' 카테고리의 다른 글
[Internet of Things] : 스마트 홈 IoT 연동 표준 - 매터 (0) | 2023.07.28 |
---|---|
Embedded System (6) : 객체 지향 프로그래밍, Qt & GUI Framework 예제 (0) | 2023.05.08 |
Embedded System (5) : Memory Map, LPAE, H/W 제어, Module Parameter (0) | 2023.04.24 |
Embedded System (4) : Raspberry Pi와 Control Sensor 연동 및 IMU 제어 (0) | 2023.04.20 |
Embedded System (3) : PWM, Motor 및 Raspberry Pi 연동 (1) | 2023.04.20 |