1. 개발 환경 구축
1.1. 개발 환경 구축이란
- 개발을 할 수 있는 환경을 구축하는 준비과정
- 보통 컴파일 + "Hello World"가 출력되는 상황 + 디버깅이 되는 상황을 환경구축이 완료되었다고 한다
- 임베디드 분야는 환경 구축이 유난히 어려움
- 임베디드 계열의 "Hello World" 는 GPIO 제어 : 이번 강의의 목적
1.2. IDE란
- IDE (Integrated Development Environment) : 통합 개발 환경을 의미
- Coding, Debugging, Compile, 배포 등 프로그램 개발에 관련된 모든 작업을 하나의 프로그램 안에서 처리할 수 있는 환경을 제공하는 Software
- Ex) Visual Studio, Jupyter
- IDE = Source code editor + Compiler + Local bulid 자동화 + Debugger
- Source code editor : 코드를 편집할 수 있는 공간
- Linux의 경우 VI Editor나 메모장 등에서 코딩 진행 가능
- Local build 자동화 : 버튼 하나만 누르면 여러 파일로 나눠져있는 코드들을 알아서 합쳐서 build 해줌
Linux 환경에선 make file 문법을, Android 환경은 gradle debugger를 사용해야 함
- 위의 기능들은 모두 별도의 프로그램
- Linux 환경에서는 make file을 통해 위의 것들을 일일히 다 별도로 사용해야 함
- Ex) Debugger : GDB
- Local build 자동화 : make file 생성
- Compiler : GCC
- Source code editor : Vi Editor
- 각 언어 및 OS에 따라 대표적인 IDE가 있다 : 각각에 따라 대표적인 IDE가 있음
- Ex) JAVA는 Eclipse, Window는 Visual Studio 등
- Eclipse : JAVA를 기반으로 한 IDE
- 소스 코드가 오픈되어 있어 그걸 기반으로 Cube IDE가 만들어짐 -> 사용 방법 동일
- 용량이 크다는 단점이 있다
1.2.1 강의 사용 IDE
- 이번 강의에서 사용할 IDE는 STM32 Cube IDE
- STM32 Cude IDE를 사용하는 이유
- 무료 IDE
- Eclipse를 써봤다면 편리함
- STM32 Cube IDE가 Eclipse 기반으로 되어있음
- ST 제품은 setting만으로 기본 코드가 완성됨
- 기존에 IAR Embedded Workbench for ARM을 사용해보셨는데 유료이고 큰 단점이 있음
- 유료 (많이 비쌈)
- 많이 무거움
- 편집툴이 불편함. Debugging 한번 완료시 다른 모든 파일들이 사라짐
- Setting으로 자동 완성되는 기능이 없음
- IAR Embedded Workbench for ARM은 ARM 전용 컴파일러를 제공함
- 각 컴파일러 마다 같은 코드를 수행해도 어셈블리 코드가 다름 : 고성능을 요할 때 각자 최적화 되어있는 것에 따라 성능이 좌우되는 경우도 있음
1.3. STM32CubeIDE 설치
- 아래 링크에 접속 후 자신의 OS에 맞는 Version 설치
- https://www.st.com/en/development-tools/stm32cubeide.html#get-software
- 설치 파일 압축 해제 후 실행
- 설치 진행 중 'NSIS Error during installation '이라는 Error가 뜨면 Installer의 directory를 C:로 바꿔볼 것
- J-Link, ST-Link driver 모두 선택
- Debugger를 따로 설치할 필요가 없음
1.3.1 환경 구성
- STM32CubeIDE 실행
- 프로젝트를 생성하고 칩 설정 : STM32F103C8T6
- 위와 같은 Update Job, Workbench 관련 오류 발생
- 위 경고 문구에 표시된 .lock 파일을 삭제하여 해결
1. .lock 파일
- File -> New -> STM32 Project 선택 (좀 오래 기다려야 함)
- STM32 Project 창에서 제품 찾기 : Series에서 STM32F1 선택 -> 그 중에서 STM32F103C8T6선택
- 혹은 좌측의 항목들을 통해 Chip을 찾을 수 있다
- STM32CubeIDE 장점. 이런 편리한 기능이 많음
- Package의 LQFP48은 칩의 형태를 나타냄. 핀의 수는 기준점으로부터 반시계방향으로 셈
- 위의 Datasheet창을 선택하면 해당 칩의 최신 datasheet가 나옴
- Project 이름 설정. Options는 아래와 같이 설정
- 각 동작시마다 지정되어있는 설정(layer)을 불러올 것이냐는 질문. Yes 선택
- Project 생성 완료
2. STMCubeIDE 관련
2.1. ioc
- STMCubeIDE의 ioc 화면
- IOC (Inversion Of Control) : 메소드나 객체의 호출을 사용자가 아닌 외부에서 결정하는 것
- 설정 후 저장(Ctrl + S) 시 위의 설정에 맞는 코드를 자동으로 생성해줌
2.2. 코드 작성 관련
- 코드 작성은 USER CODE BEGIN XXX 과 USER CODE END XXX 사이에 입력
- Includes, PTD 등의 위치는 상관 없음
- 그 외 구역에 입력하면 아래 그림처럼 코드 생성시 사라짐
2.3. 한글 작성 관련
- 한글 주석 작성 시 오른쪽처럼 깨질 수 있음
3. 프로그래밍 및 Debug
- ST Link와 보드 연결
- 전원은 ST Link에만 연결
- 보드 상의 USB 포트는 추가 전원 포트
- ST Link에서 공급하는 전원 만으로도 충분히 동작함
- (연결 사진 추가)
- HAL_init에 breakpoint 삽입 (더블 클릭)
2. HAL
- 상단의 벌레 모양 버튼 클릭을 통해 Debug 시작
- 위의 창이 뜨면 바로 OK 클릭
3.1. 펌웨어 업데이트 방법
- https://www.st.com/en/development-tools/stsw-link004.html#get-software 로 접속한 후 Download latest 클릭.
ST-LINK Utility 실행 - ST-Link -> Firmware update 선택 -> USB 다시 연결 후 Device Connect, yes를 눌러 firmware update 진행
- Debugger Update 완료
- Debugger Update 완료 후 SystemClock_cinfig();에 breakpoint를 찍고 debug 실행
- target이 응답이 없다며 종료됨 : Pin 설정 필요
3.2. Pin Setting
- ico 창으로 이동
- System Core -> SYS 클릭
- Debug는 Serial Wire, Timebase Source는 SysTick으로 설정 (Debug interface 종류)
- JTAG (Joint Test Action Group) : 디지털 회로에서 특정 node의 digital 입출력을 위해 Serial 통신 방식으로 output data를 전송하거나 input data를 수신하는 방식
- 5개의 핀 (TDI, TMS, TCK, NRST, TDO) 사용. 20개의 핀으로 구성되어 있어 보드의 자리를 많이 차지함
- 제품의 동작 테스트시 핀 마다의 동작을 표준으로 만들어 테스트하기 용이하게 만들어놓은 형태
- Embedded System의 MCU를 테스트 한다기 보단 Board 자체를 테스트 함
- Hardware Debugger의 일종으로 사용자가 CPU를 직접 조절하며 Debugging 가능
- JTAG Interface 구성은 아래와 같다
- TDI (Test Data In) : Test를 위한 data 신호. TMS에 의해 전이된 TAP state에 따라 TDI가 Command/Data가 될 수 있음
- TDO (Test Data Out) : Test 결과를 외부에서 확인하기 위한 핀. TDI와 마찬가지로 TAP state에 따라 Address/Data가 될 수 있음
- TCK (Test Clock) : Test의 Clock 설정
- TMS (Test Mode Select) : Test Mode로의 전환을 위한 제어 신호
- TRST (Test Reset) : Test 초기화
- Serial Wire : Serial(직렬) 통신으로 Clock(SWCLK)과 Data(SWDIO) 2개의 핀만을 사용
- HW 개발자들은 Serial Wire를 선호
- 2개의 Pin만을 사용
- JTAG은 최소 4개의 Pin 사용 필요
- 저장하여 코드 생성
3.3. Debug 시작
- while 문 안에 HAL_Delay(100) 작성
- 100ms를 의미
- 상단의 Resume을 눌러 한 breakpoint에서 다음 breakpoint로 이동
- HAL_Delay(100)에서 계속 머뭄
- 위처럼 임베디드 프로그램은 하나의 loop문 (while문) 안에서 계속 돌아간다. 예외로 interrupt는 loop문 바깥에 존재
- 임베디드 시스템은 OS가 없는 프로그래밍을 함. Thread와는 별개
- 쓰레드는 누군가 OS를 만들어 준 것이고 그 OS를 기반으로 코딩을 하는 것
- 쓰레드 (Thread) : 한 program 내에서, 특히 process 내에서 실행되는 흐름의 단위.
한 program은 환경에 따라 둘 이상의 thread를 동시에 실행할 수 있다
- 쓰레드 (Thread) : 한 program 내에서, 특히 process 내에서 실행되는 흐름의 단위.
4. GPIO 제어
- GPIO (General Purpose Input/Output) : 사용자의 의도에 따라 입출력이 제어될 수 있는 범용 입출력 포트
다른 핀들과 달리 특정한 목적이 미리 정의되지 않으며 사용자가 설정하기 전에는 사용이 불가능 하다. - 각 포트에는 3개의 레지스터가 있다
- DDRx (Portx Data Direction Register) : A ~ G I/O Port의 입/출력 방향 결정. 0은 입력, 1은 출력
- PORTx (Portx Data Register) : Portx로 출력할 데이터 저장
- PINx (Portx Pin Input Address) : Portx에서 입력받은 데이터 저장
- 보드 회로도 중 일부. D2의 위치에 있는 LED를 제어하기 위해서는 PC13의 GPIO를 제어해야 한다
- PC13 : GPIO중 GPIOC의 그룹중 13이라는 번호를 가진 Pin
- PC13의 GPIO를 Output으로 설정
- 이후 위 사진과 같이 설정 후 저장
- 각 설정 별 상세 의미는 다음 강에서 설명
- User Label을 사용하면 변경사항이 생겼을 때 코드를 일일히 변경할 필요 없이 Label에 해당하는 값만 바꿔주면 된다
- 이후 main.c에 MX_GPIO_Init(void)가 자동으로 생성됨 (Function Prototype)
- Ctrl + 좌클릭을 하면 function의 정의 부분으로 가서 내부를 볼 수 있다
- 일일히 코딩해야 하나, ioc를 통해 생성됨
- 이후 while문 내부에 아래 코드 작성
- 위의 statements중 WritePin 선택
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState)
- GPIOx는 GPIO GROUP을 넣는 자리로, GPIO_LED_GPIO_Port 나 GPIOC를 넣으면 됨
- GPIO_Pin은 GPIO_LED_Pin 이나 GPIO_PIN_13을 넣음
- PinState는 Pin의 상태를 설정. 1이 HIGH
- 위 내용들은 main.h에 정의되어있음
- 위처럼 User Label을 사용하면 그 Label에 해당하는 값(GPIO_LED)들이 정의가 된다
- uint16_t는 <stdint.h> header에 정의된 data type으로, 모든 platform에서 동일한 bit 수를 사용하도록 설정하기 위해 사용한다
- C언어에서는 Compiler의 종류나 OS의 차이에 따라 data type의 크기가 변경될 수 있다
- Memory 관리가 중요한 Embedded 환경에서 주로 사용한다
- 0x2000 : GPIO 13번 Pin을 제어함을 의미
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
HAL_Delay(100);
}
}
- main문 안의 while문에 위처럼 코드 작성
- GPIO Port의 PC13 Pin의 GPIO를 설정
- 이후 Debug 실행 -> while 문 내부로 진입
- D2의 LED가 0.1초 간격으로 깜빡임
(동영상 삽입)
4.1. GPIO를 input으로 설정하여 스위치를 이용해서 LED를 껏다가 켜보기
- S2 스위치에 input이 들어올 시 D2의 LED에 불이 들어오게 하기
- S2 스위치 사용을 위해선 PA0을 GPIO input으로 사용해야 함
- PA0을 GPIO input으로 설정하고 위와 같이 설정 후 저장해서 코드 생성
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
if(!HAL_GPIO_ReadPin(GPIO_SW_GPIO_Port, GPIO_SW_Pin)){
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
}
else{
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
}
HAL_Delay(100);
}
}
- main.h에 정의된 코드를 기반으로 while문에 코드 작성
- S2 스위치를 누르면 LED가 점등된다
5. etc
5.1. 보드에 전원이 안들어오는 이유 :
- ST Link를 통해 보드에 주는 전류가 충분하지 않기 때문
- 해결 방법 : 보드 구성품에 포함되어 있는 USB 연결선으로 보드에 전원을 별도로 준다
- 주의 : 핀에 5V전원을 동시에 주면 보호회로가 없어 보드가 타버림
- Appendix
1. .lock 파일
1.1. 사용 이유
1) Resource Management
- 한 Program에 대한 다수의 Instance 사용, 여러 사용자가 한 자원에 대해 동시에 접근하는 것을 방지
- 동시적 접근으로 인한 충돌이나 Data 손실을 방지
2) Indication of Activity
- 특정 자원이 사용 중임을 나타냄
- lock 파일이 존재하는 한, Application의 다른 instance들은 해당 자원을 수정하지 말아햐 함을 알게 됨
3) Safe Updates
- Software update나 설치 시 현재 update 중인 파일의 수정을 방지
- Update 과정이 다른 동작에 의해 방해받지 않게 함
1.2. 동작 과정
1) 설치 & 제거
- Program이 어떤 자원에 대한 독점적인 접근이 필요한 동작을 수행할 경우, 관련 Directory에 lock file을 생성
- 해당 동작 완료 시, Program은 lock file을 삭제해야 함
2) .lock file 확인
- 동작 수행 전 lock file의 존재 여부를 확인
- lock file이 존재할 경우, 해당 자원이 이미 사용되고 있음을 확인하여 동작을 대기하거나 중단
3) 관련 오류
- 일반적으로, 한 자원에 대한 동작을 완료한 후 그에 해당하는 lock file을 삭제해야 함
- 그런데, Program이 충돌하거나 예상치못하게 종료된 경우, lock file이 삭제되지 않을 수 있음
- 이는 위와 같은 오류를 유발할 수 있음
- 이로 인해 파일이 시스템 상에서 "stale lock" 상태로 남아 Program이 해당 자원이 여전히 사용 중이라 여기게 함
- 자원과 관련된 .lock file을 직접 삭제하여 해결 가능
- 또는 자원과 관련된 Directory에 .lock file을 생성하거나 제거할 권한이 없는 경우, 오류를 유발할 수 있음
- Program을 관리자 권한으로 실행하여 해결 가능
2. HAL (Hardware Abstraction Layer)
- Computer의 물리적인 Hardware와 Computer에서 실행되는 Software 사이의 추상화 계층
- Hardware의 변화를 감지하여 수많은 종류의 Hardware상에서 별 차이없이 Software가 동작할 수 있도록 함
- OS의 kernel 또는 장치 드라이버에서 호출
- OS 단이 아닌 Hardware 공급쪽에서 구현해야 하는 Standard Interface
- OS에서 하위 수준의 Driver 구현을 고려하지 않아도 되게 해줌
- 하드웨어(MCU)에 따라 설정을 바꿔줘야 하나, 사용하고자 하는 MCU만 선택하면 관련 설정을 자동으로 수행
- Hardware의 차이를 숨겨 응용 프로그램이 Hardware에 상관없이 작동할 수 있는 일관된 플랫폼을 제공
- 구체적으로는 추상화된 API를 통해 응용 프로그램들이 Host System의 Hardware를 발견하고 사용할 수 있게 함
- API (Application Programming Interface) : Computer나 Software를 서로 연결하는 Interface
System이 동작하는 방식에 관한 세세한 부분을 숨겨 그 내용들이 변경되더라도 사용자가 계속 사용할 수 있고
일정한 관리가 가능한 부분만 노출시킨다
- 즉 API는 서로 다른 프로그램들이 상호 소통이 가능하게 해주는 중간 매개채 역할을 한다
- HAL에서는 하드웨어 부품에 따라 해야 할 복잡한 과정을 일관성 있고, 간략한 인터페이스로 제공하기 위해
같은 류의 하드웨어를 공통 명령어 집합으로 묶어두는데, 이를 "하드웨어 추상화"라고 함
- STM32에서의 HAL은 STM32의 어떤 하드웨어라도 쉽게 개발을 할 수 있도록 도와주는 Interface로써 Middleware와 연결이 용이하고 Cube와 연계하여 몇가지 MCU 설정만으로도 기본 Source Code를 자동 생성
- Middleware : 서로 다른 Application이 서로 통신하는데 사용되는 Software로, 양쪽을 연결하여 data를 주고받을 수 있도록 중간에서 매개체 역할을 하는 Software와 Network를 통해 연결된 여러 개의 컴퓨터에 있는 많은 Process들에게 어떤 서비스를 사용할 수 있도록 연결해주는 Software
- 응용 프로그램이 OS로부터 제공받는 서비스 외에 추가적으로 이용할 수 있는 서비스를 제공하는 Software
2.1. Register Abstraction
- Pointer로 Register를 직접 제어할 수 있으나, 이는 매번 Register의 주소값을 확인해야 하는 번거로움이 존재함
- 이를 해결하기 위해 Structure 및 Union을 활용하여 Register Abstraction을 할 수 있다
3. startup 코드 관련
- startup_stm... : Start 코드 (어셈블리)
- 위처럼 각 함수가 Mapping 되어있음
- DMA는 인터럽트 함수를 의미
- 특정 조건에서 발생하는 함수
- 위의 함수를 stm32f1xx_it.c에 선언해줘야 하나 이도 ioc setting으로 설정 가능
위 내용의 모든 출처는 유튜버 '[오제이 튜브]OJ Tube' 님께 있습니다.
https://www.youtube.com/watch?v=YZJ6RfhuGd0&list=PLz--ENLG_8TNjRg1OtyFBvUyV4PHaKwmu&index=7
https://community.st.com/s/question/0D50X0000Anr4B5SQI/stm32cubeide-nsis-error-during-installation
https://blog.naver.com/wararat/220695063632
https://ko.wikipedia.org/wiki/%ED%95%98%EB%93%9C%EC%9B%A8%EC%96%B4_%EC%B6%94%EC%83%81%ED%99%94
'Study_Embedded > [오제이 튜브의 임베디드 실전 강의]' 카테고리의 다른 글
[오제이 튜브의 임베디드 실전 강의] 6강 GPIO제어 뿌셔 먹기 (0) | 2022.02.08 |
---|---|
[오제이 튜브의 임베디드 실전 강의] 5강 혼자서 임베디드 고수 되는 법 (0) | 2022.01.24 |
[오제이 튜브의 임베디드 실전 강의] 3강 전기 기본 상식 - 모르면 보드 태워먹는다 (0) | 2021.12.02 |
[오제이 튜브의 임베디드 실전 강의] 2강 실무자는 어떻게 칩을 고르나요? (0) | 2021.11.28 |
[오제이 튜브의 임베디드 실전 강의] 1강 임베디드가 뭔가요? (0) | 2021.11.28 |