Pages List
List view
STM32 Peripheral
Understanding STM32 HAL program flow with UART Exercise
UART를 예시로 STM32 HAL Program Flow를 알아보자
CubeMx에서 UART2를 Asynchronous로 설정하고 프로젝트를 생성한다.
우리는 바닥에서부터 프로그램을 작성할 것이기 때문에, 생성된 프로젝트의 Src 폴더에서 ‘msp.c’와 ‘it.c’ 를 delete하고 새로 만든다.
그리고 Inc 폴더에서는 ‘main.h’와 ‘it.h’를 delete하고 새로 만든다.
마지막으로 ‘main.c’는 위의 그림과 같이 작성한다.
(앞에서 설명했듯이, main함수에서 가장 먼저 하는 일 2가지는 HAL_Init과 SystemClockConfig함수를 호출하는 것이다.)
(앞에서 설명했듯이, main함수에서 가장 먼저 하는 일 2가지는 HAL_Init과 SystemClockConfig함수를 호출하는 것이다.)
Low Level Hardware Initializations
HAL_Init()은 HAL layer를 Initialize 하기 위해 호출되는데, HAL_Init 의 마지막 부분에서는 Low level Hardware Initialization을 위해서 HAL_MspInit()이 호출된다.
User Application에 따라 다음과 같이 Low level Initializations을 HAL_MspInit()에 작성한다.
① Processor의 Priority group을 Configure한다.
② 필요한 Processor System Exceptions를 Enable한다. (Bus fault, Mem manage, Usage fault, Systick, etc.
③ System exception의 Priority를 Configure 한다.
④ MPU(Memory Protection Unit), FPU(Floating Point Unit), Sleep mode 등을 Initialization
HAL_MspInit()은 “stm32f4xxhal.c”에 weak으로 attributed 되어 있다.
위의 HAL_MspInit()을 msp.c에 복사해서 User Application에 따라 내용을 작성하면 된다.
STM32 Cube HAL Layer는 “hal_cortex.c”라는 아주 중요한 driver file을 제공해준다.
Processor Specific을 다루는데 사용되는 모든 APIs가 “hal_cortex.c”에 모여있다.
NVIC의 Priority Grouping 설정
“hal_cortex.c”의 API중에서 NVIC의 PriorityGrouping을 설정하는 API를 보자.
Pre-emtion priority는 2개 이상의 Interrupt가 pending중일 때, 어떤 Interrupt가 Processor에서 실행될지를 결정한다.
Pre-emtion priority값이 작을수록 우선순위가 높다.
만약에 Pre-emtion priority값이 동일한 Interrupt들이 pending하고 있다면, 각각의 Subpriority를 확인한다.
Subpriority값이 작은 Interrupt가 우선 순위가 높기 때문에 먼저 실행된다.
Priority grouping을 설정하지 않았다면, 기본값인 ‘NVIC_PRIORITYGROUP_4’가 적용된다.
(STM32F4는 4bit로 Pre-emption priority를 설정한다. 그러므로 Pre-emption priority는 0~15의 값이 된다.
0 Pre-emption value는 가장 높은 priority를 의미하고, 15는 가장 낮은 priority를 의미한다.)
0 Pre-emption value는 가장 높은 priority를 의미하고, 15는 가장 낮은 priority를 의미한다.)
System Exception의 Enable
SCB에서 Processor Specific detail을 설정할 수 있다.
SCB는 Cortex-Mx Processor의 다양한 System level activities를 control하는 register들의 집합이다.
SCB의 ‘System Handler Control and State Register’를 보면, System exceptions을 Enable/Disable할 수 있다. (모든 Exception을 Enable/Disable할 수는 없다.)
System Exception의 Priority를 설정
기본적으로 Priority는 가장 높은 Priority인 0로 설정되어 있다.
HAL_NVIC_SetPriority API로 Priority를 설정한 Exception의 IRQ는 “stm32f407xx.h”에서 찾을 수 있다.
HAL_NVIC_SetPriority API에서 Pre-emption Priority와 SubPriority를 설정할 수 있는데,
STM32F4에서는 ‘NVIC_PRIORITYGROUP_4’의 Priority group이 기본값으로 설정되기 때문에 0~15의 Pre-emption Priority를 설정할 수 있고, SubPriority는 기본값이 0으로 따로 설정할 수 없다.
위 그림과 같은 방식으로 SVC 등의 System Exception의 Priority를 설정할 수 있다.
단, SysTick Interrupt는 다음 그림과 같이 HAL_Init()에서 설정하므로, ‘msp.c’에서 설정할 필요가 없다.
Peripheral High Level Initialization
UART2의 High Level Initialization을 수행하는 절차는 다음과 같다.
Peripheral Initialization에는 High Level Initialization과 Low Level Initialization의 2가지가 존재한다.
High Level Initialization은 UART2를 예로 들면 Stop bit의 수, Data bit의 수, Hardware flow control 설정 등이다.
Low Level Initialization은 Pin settings, Clock enable/disable, IRQ enable, NVIC setting 등이다.
위의 요구조건에 알맞게 UART2의 High Level Initialization 코드를 작성하면, 다음 그림과 같다.
Peripheral Low Level Initialization
UART2의 Low Level Initialization을 수행하는 절차는 다음과 같다.
앞에서 본 HAL_Init의 경우처럼, HAL_UART_Init에서도 UART Peripheral의 Low Level Initialization을 수행하기 위해 HAL_UART_MspInit을 호출한다.
HAL_UART_MspInit 또한 HAL_MspInit 처럼 weak으로 atributted 되어 있고, msp.c에서 over-ride해주어야 한다.
Peripheral Low Level Initialization : Configuring Pin Packs
① UART는 통신을 위해 2개의 Pin이 필요하다. 하나는 Tx Pin이고 다른 하나는 Rx Pin이다.
② MCU의 GPIO pin 2개를 UART의 Tx, Rx functionality로 설정한다.
③ GPIO를 UART 통신에 사용하기 전에 그것들을 Alternative functionality mode로 설정해야 한다.
④ Alternative functionality를 UART로 설정한다.
다음 그림과 같이 UART2의 Pin Muxing Configuration을 수행하면 된다.
Peripheral Low Level Initialization : IRQ settings
“stm32f4_hal_cortex.c”의 HAL_NVIC_EnableIRQ 함수로 전달받은 IRQ number에 해당하는 Interrupt를 Enable한다.
STM32 Cube Peripheral Data Handling API Flavors
Peripheral의 data를 송신하거나 수신할 때, 사용할 수 있는 API는 3가지가 있다.
① Polling 방식
② Interrupt 방식
③ DMA를 사용하는 방식 (DMA Interrupt 이용)
어떤 방식을 사용할지는 Application에 따라 다르다.
UART Data Txing (Polling mode)
내 커스텀 보드는 PC의 시리얼 포트로 잡히지 않기 때문에, Arduino와 연결하고 Arduino 시리얼 모니터에서 UART 송수신 테스트를 진행하였다.
[ STM32F407 ]
[ Arduino ]
Default SysTick_Handler는 그냥 Infinite Loop이다.
SysTick_Handler를 ‘it.c’에서 Over-ride하지 않으면, stm32에서 보낸 UART data의 절반 정도만 Arduino가 수신하고 나머지는 잘린다.
(잘 보내지다가 SysTick Interrupt걸리면 Inifite Loop에 갇혀버린다.)
(잘 보내지다가 SysTick Interrupt걸리면 Inifite Loop에 갇혀버린다.)
이 예제의 경우에는 Over-ride만 하면 되므로 Handler의 내용은 작성하지 않아도 된다.
UART Data Rxing (Polling mode)
[ STM32F407 ]
[ Arduino ]
UART Data Rxing (Interrupt mode)
- IRQ handler의 definition은 ‘it.c’에 작성한다.
- IRQ handler의 이름은 startup file에서 가져온다.
- STM32 Cube Framework(HAL)에서는 IRQ handler에서 HAL_XXX_IRQHandler만 호출한다.
이 Interrupt Processing API는 SR 레지스터의 각 bit를 보고, Interrupt가 발생한 원인을 찾아서 알맞은 Callback 함수를 호출한다.
User는 Application에 알맞은 Callback함수를 ‘main.c’에 define하면 된다.
Interrupt 핸들링 절차는 다음 그림과 같다.
[ STM32F407 ]
Understanding STM32 HAL program flow with UART ExerciseUART를 예시로 STM32 HAL Program Flow를 알아보자Low Level Hardware InitializationsNVIC의 Priority Grouping 설정System Exception의 EnableSystem Exception의 Priority를 설정Peripheral High Level InitializationPeripheral Low Level InitializationPeripheral Low Level Initialization : Configuring Pin PacksPeripheral Low Level Initialization : IRQ settingsSTM32 Cube Peripheral Data Handling API FlavorsUART Data Txing (Polling mode)UART Data Rxing (Polling mode)UART Data Rxing (Interrupt mode)