Pages List
List view
STM32 Peripheral
GPIO
GPIO에 대하여
- GPIO MODE register의 Reset Value
- GPIO가 Input 모드일 때는 Output driver가 Off이지만, Output 모드일 때는 Input Driver가 On이므로, 출력값을 다시 읽을 수 있다.
- GPIO Output Type 레지스터, GPIO Output Speed 레지스터는 오로지 GPIO가 Output 모드일 때에만 적용된다.
- OSPEED 레지스터로, GPIO의 H -> L 또는 L to H의 Transition 속도를 결정할 수 있다. (즉, Pin의 Slew rate를 control할 수 있다.)
(각 속도 옵션이 의미하는 스위칭 속도(주파수)는 stm32f407vg 데이터시트의 117p 참고)
- GPIO 핀에는 16개의 Alternative Functionality가 존재한다. (AF0 ~ AF15. stm32f407vg 데이터시트 참고)
- GPIO_AFRL : 핀 0~7, GPIO_AFRH : 핀 8~15
- RCC는 mcu의 모든 영역의 clock을 제어하는 engine이다. (AHB domain, APB domain, processor domain, memory domain, etc)
프로젝트의 전체 구조
- 프로젝트의 전체 아키텍처
MCU의 Peripheral들을 제어하기 위한 Driver Layer가 존재하고, 이 Driver Layer들로 APIs를 작성한다.
- Device Header 파일(stm32f407vg.h)에 들어갈 내용들은 다음과 같다.
- Application과 Driver 소스 파일들은 MCU의 특정 세부사항에 접근하기 위해 device header 파일을 include한다.
Peripheral 레지스터에 대한 구조체 작성
- MCU의 모든 레지스터 주소를 다루기 위해 Memories, Peripheral들의 Base address처럼 매크로를 작성하는 것은 매우 비효율적이기 때문에 구조체를 이용하는 것이 바람직하다.
Derefernce 부분을 더 깔끔하게 정리하면, 다음과 같다.
- volatile qualifier를 각 레지스터 주소에 달아주는 이유는 레지스터에 데이터를 읽거나 쓸 때, 컴파일러가 반복적인 레지스터 접근을 최적화시키는 것을 방지하기 위함이다.
(다시 말해, 레지스터에 값을 쓰거나 읽을 때마다 해당 주소를 매번 참조하도록 하는 것이다.)
Peripheral에 대한 Macro 작성
- Peripheral Definitions를 작성한다.
- Peripheral Macros를 작성한다.
GPIO Handle Structure와 Configurable Structure
- Driver Layer는 User application이 Config 할 수 있는 구조체를 제공해주어야 한다.
(User API는 주어진 구조체에 조작하고 싶은 GPIO의 port를 알려주고, 해당 port의 각 pin의 세팅을 설정한다.)
Driver APIs 작성
Driver APIs의 Definition은 “stm32f407xx_gpio.c”를 참고해라.
(섹션 24~26이 API함수의 정의부분을 작성하는 내용인데, 해당 c파일을 참고해서 이해되면 끝이다.)
Tip) do-while condition zero loop
C 프로그래밍에서 하나의 C 매크로를 사용해, 여러개의 statement를 실행하는 테크닉이다.
(이 매크로를 쓰는 곳에서 세미콜론을 붙이기 때문에, do-while 끝에는 세미콜론을 붙이지 않는다.)
예제 1) LED Toggling
Output type을 Push-Pull (with No Pull-Up/Down) 으로 설정하면, LED가 정상적으로 깜빡거린다.
그러나 Output type을 Open-Drain (with No Pull-Up/Down) 으로 설정하면, LED가 전혀 깜빡거리지 않는다.
Pull-Up 저항이 없는 Open-Drain 상태에서의 출력은 Low 또는 Floating(Hi-z)이기 때문이다.
여기서 Pull-Up 저항을 Enable하면, 출력은 High 또는 Low가 되어 LED가 깜빡거리기는 하는데 Pull-Up 저항의 크기가 매우 커서(40kohm) LED의 밝기가 매우 어둡다.
특정한 이유가 없는 일반적인 상황에서는 GPIO의 Output Type을 Push-Pull로 설정한다.
예제 2) LED ON/OFF by using Button
GPIO를 사용할 때, 주의해야할 점이 있다. 다음과 같이 PA15, PA14, PA13, PB4, PB3는 Debug에 사용되는 Pin이므로, 해당 Pin을 GPIO로 사용하지 않는 것이 바람직하다.
PA15, PA14, PA13, PB4, PB3 은 Reset 직후에 Alternative Function 모드로 설정된다.
GPIO Interrupt
EXTI0-> IRQ6
…
EXTI4 -> IRQ10
EXTI5-9 -> IRQ23(single IRQ number. GPIO의 Pin5~9는 1개의 IRQ로 간주된다.)
EXTI10-15 -> IRQ40(single IRQ number. GPIO의 Pin10~15는 1개의 IRQ로 간주된다.)
EXTI block은 Edge detection과 Processor(NVIC)로의 interrupt delivery를 Enable/Disable 한다.
NVIC에서는 NVIC 레지스터로 각각의 IRQ를 Enable/Disable한다.
어떤 GPIO port가 EXTI line을 차지할지는 SYSCFG_EXTICR에서 결정된다.
EXTI와 NVIC은 각각 Pending register를 갖고 있다.
IRQ를 disable해도 해당 IRQ가 이미 NVIC pending register에 들어와 있으면, ISR이 실행된다.
- GPIO Pin configuration as Input mode
- Configure EXTI block such as Edge trigger setting(RT, FT, RFT), IMR(Interrupt mask)
- Enable Clock of SYSCFG and Configure SYSCFG block such as PortCode
- Configure NVIC block such as IRQ number, priority
- Write ISR corresponding IRQ number
- Make sure that Store the address of ISR at the vector address location corresponding to the IRQ number
Startup 파일에 가보면, ISR들이 weak attribute로 이미 존재하는 것을 볼 수 있다.
User application에서 동일한 이름으로 ISR을 작성하여, override하면 된다.
Tip) memset
구조체를 처음 생성할 때, 구조체의 멤버들에 쓰레기값이 들어있을 수 있다.
이 쓰레기값들을 모두 0으로 초기화하지 않으면, 심각한 문제를 초래할 수 있기 때문에 구조체를 생성할 때는 항상 “memset”을 사용해 0으로 초기화해주는 습관을 갖는 것이 바람직하다.