๐ ์ ์ฒด ๊ตฌ์กฐ ๊ฐ์
- ์ด ํ๋ก๋ ์ ๋ ฅ๊ณผ ์ถ๋ ฅ ๋ชจ๋ ๊ฐ๋ฅํ I/O ํ์ ๋ด๋ถ ๊ตฌ์กฐ์ ๋๋ค.
- ๋ด๋ถ์ ์ผ๋ก๋ ๋ค์ํ ๋ ์ง์คํฐ์ ๋๋ผ์ด๋ฒ ํ๋ก, ์๋ฏธํธ ํธ๋ฆฌ๊ฑฐ๊ฐ ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
- ๊ฐ ๊ธฐ๋ฅ์ STM32์ GPIOx_MODER, GPIOx_IDR, GPIOx_ODR, GPIOx_AFR, ๊ทธ๋ฆฌ๊ณ PUPDR ๊ฐ์ ๋ ์ง์คํฐ๋ก ์ ์ด๋ฉ๋๋ค.
๐น ์ฃผ์ ๋ธ๋ก ์ค๋ช (โ ๊ด๋ จ ๋ ์ง์คํฐ ์ฐ๊ฒฐ ํฌํจ)
โ Input Path (์ ๋ ฅ ๊ฒฝ๋ก)
- TTL Schmitt Trigger: ๋์งํธ ์ ๋ ฅ ์ ํธ๋ฅผ ์์ ์ ์ผ๋ก ์ฒ๋ฆฌํ๋๋ก ํ์คํ ๋ฆฌ์์ค ๊ธฐ๋ฅ์ด ์๋ ๋น๊ต๊ธฐ์ ๋๋ค.
- ์ฐ๊ฒฐ๋ ๋ ์ง์คํฐ:
โ
GPIOx_IDR
- ์ธ๋ถ I/O ํ์์ ๋ค์ด์จ ์ ํธ๋ TTL ์๋ฏธํธ ํธ๋ฆฌ๊ฑฐ๋ฅผ ๊ฑฐ์ณ
Input data register
๋ก ์ ๋ฌ๋๊ณ , ์ํํธ์จ์ด์์GPIOx_IDR
์ ์ฝ์ผ๋ฉด ํ์ฌ ํ ์ํ๋ฅผ ์ ์ ์์ต๋๋ค.
- ์ธ๋ถ I/O ํ์์ ๋ค์ด์จ ์ ํธ๋ TTL ์๋ฏธํธ ํธ๋ฆฌ๊ฑฐ๋ฅผ ๊ฑฐ์ณ
โก Output Path (์ถ๋ ฅ ๊ฒฝ๋ก)
Output control
๋ธ๋ก์ P-MOS, N-MOS๋ฅผ ์ ์ดํ์ฌ ํ์ ์ถ๋ ฅ์ ๋ณด๋ ๋๋ค.- ์ฐ๊ฒฐ๋ ๋ ์ง์คํฐ:
โ
GPIOx_ODR
โ
GPIOx_BSRR
/GPIOx_BRR
(๋นํธ ์ธํธ/๋ฆฌ์ ์ฉ)- ์ํํธ์จ์ด์์
GPIOx_ODR
๋๋BSRR/BRR
์ ์ฌ์ฉํ์ฌ ํ์ High/Low๋ก ์ค์ ํฉ๋๋ค.
- ์ํํธ์จ์ด์์
โข Alternate Function (๋์ฒด ๊ธฐ๋ฅ ๊ฒฝ๋ก)
- ์ธ๋ถ ์ฅ์น(UART, SPI, PWM ๋ฑ)์ ์ฐ๊ฒฐ ์ ์ฌ์ฉ๋ฉ๋๋ค.
- ์ฐ๊ฒฐ๋ ๋ ์ง์คํฐ:
โ
GPIOx_AFR[0/1]
(Alternate Function Low/High Register)โ
GPIOx_MODER
: ํด๋น ํ์ alternate ๊ธฐ๋ฅ์ผ๋ก ์ค์ MODER
์์ ํน์ ํ์ Alternate ๋ชจ๋(10
)๋ก ์ค์ ํ๋ฉด ์ด ๊ฒฝ๋ก๊ฐ ํ์ฑํ๋ฉ๋๋ค.- ์ดํ
AFRL
/AFRH
๋ฅผ ํตํด ์ด๋ค ์ฃผ๋ณ ๊ธฐ๋ฅ(UART, SPI ๋ฑ)์ ์ฐ๊ฒฐํ ์ง ๊ฒฐ์ ํฉ๋๋ค.
โฃ Pull-up / Pull-down ์ ์ด
- ๋ด๋ถ ํ์ /ํ๋ค์ด ์ ํญ์ ์ฐ๊ฒฐํ์ฌ ์ ๋ ฅ ์์ ํ ์ญํ ์ ํฉ๋๋ค.
- ์ฐ๊ฒฐ๋ ๋ ์ง์คํฐ:
โ
GPIOx_PUPDR
- ๊ฐ ํ๋ง๋ค 2๋นํธ์ฉ ์ค์ :
00
: ์์,01
: Pull-up,10
: Pull-down,11
: ์์ฝ
- ๊ฐ ํ๋ง๋ค 2๋นํธ์ฉ ์ค์ :
โค Protection Diodes (๋ณดํธ ๋ค์ด์ค๋)
- ESD(์ ์ ๊ธฐ)๋ ๊ณผ์ ์ ๋ณดํธ๋ฅผ ์ํด VDD, VSS์ ์ฐ๊ฒฐ๋ ๋ณดํธ ๋ค์ด์ค๋.
- ํ๋์จ์ด์ ๋ณดํธ์ฅ์น๋ก, ๋ ์ง์คํฐ์ ์ง์ ์ฐ๊ฒฐ๋์ง๋ ์์ง๋ง, ์ธ๋ถ ์ ์ ์ธ๊ฐ ์ ์ค์ ์ญํ .
๐ ์์ฝ: ์ฃผ์ ๋ ์ง์คํฐ ์ ๋ฆฌ
๊ธฐ๋ฅ | ๊ด๋ จ ๋ ์ง์คํฐ | ์ค๋ช |
---|---|---|
์ ์ถ๋ ฅ ๋ชจ๋ ์ค์ | GPIOx_MODER |
00: ์ ๋ ฅ, 01: ์ถ๋ ฅ, 10: AF, 11: ์๋ ๋ก๊ทธ |
์ ๋ ฅ ๊ฐ ์ฝ๊ธฐ | GPIOx_IDR |
์ ๋ ฅ๋ High/Low ์ํ ํ์ธ |
์ถ๋ ฅ ๊ฐ ์ค์ | GPIOx_ODR , BSRR , BRR |
ํ์ High/Low๋ก ์ค์ |
Pull-up/down ์ ํญ ์ค์ | GPIOx_PUPDR |
๋ด๋ถ ํ์ /ํ๋ค์ด ์ ํญ ์ค์ |
Alternate Function ์ค์ | GPIOx_AFR[0/1] |
์ฃผ๋ณ ์ฅ์น์ ์ฐ๊ฒฐ ์ค์ |
#define RCC_APB1ENR ((volatile uint32_t)0x40023840) โ 0x 40023800 + 0x40
RCC_APB1ENR |= (1 << 17);
โ 1. USART2 ๊ธฐ๋ณธ ์ ๋ณด
ํญ๋ชฉ | ๋ด์ฉ |
---|---|
TX ํ | PA2 (AF7) |
ํด๋ญ | APB1 (RCC_APB1ENR) |
USART2 ๋ฒ ์ด์ค ์ฃผ์ | 0x4000 4400 |
๐ USART_SR (Status Register) ๋นํธ ์ค๋ช
๋นํธ | ์ด๋ฆ | ์์ฑ | ์๋ฏธ |
---|---|---|---|
15 | Reserved | – | ์ฌ์ฉ๋์ง ์์ |
14 | Reserved | – | ์ฌ์ฉ๋์ง ์์ |
13 | CTS (Clear To Send) | rc_w0 | ํ๋์จ์ด ํ๋ฆ์ ์ด์์ CTS ํ ์ํ CTS ์ด๋ฒคํธ ๋ฐ์ ์ 1๋ก ์ค์ ๋จ |
12 | LBD (LIN Break Detection) | rc_w0 | LIN ํ๋กํ ์ฝ์์ Break ๊ฐ์ง ์ 1๋ก ์ค์ ๋จ |
11 | TXE (Transmit Data Register Empty) | r | TX ๋ฒํผ๊ฐ ๋น์์์ ๋ํ๋1์ด๋ฉด ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์ธ ์ ์์ |
10 | TC (Transmission Complete) | rc_w0 | ์ ์ก ์๋ฃ (shift register๊น์ง ์ ๋ถ ์ ์ก ์๋ฃ๋จ) |
9 | RXNE (Read Data Register Not Empty) | rc_w0 | ์์ ๋ ๋ฐ์ดํฐ๊ฐ DR์ ๋์ฐฉํจ์ฝ์ ์ค๋น๊ฐ ๋์์์ ์๋ฏธ |
8 | IDLE | r | IDLE ์ํ ๊ฐ์ง (์ผ์ ์๊ฐ ์์ ์์) |
7 | ORE (Overrun Error) | r | ์์ ๋ฒํผ ์ค๋ฒ๋ฐ ๋ฐ์ ์ 1 (๋ฐ์ดํฐ ์์ค) |
6 | NF (Noise Flag) | r | ์์ ์ค ๋ ธ์ด์ฆ ๊ฐ์ง๋จ |
5 | FE (Framing Error) | r | Start/Stop ๋นํธ ์ค๋ฅ |
4 | PE (Parity Error) | r | ํจ๋ฆฌํฐ ์ค๋ฅ ๋ฐ์ (ํจ๋ฆฌํฐ ๋นํธ ์ค์ ์) |
3~0 | Reserved | – | ์ฌ์ฉํ์ง ์์ (0์ผ๋ก ์ ์ง) |
๐ ์ฃผ์ ๋นํธ ์์ฝ (์ค์ ์ฌ์ฉ์์ ์ค์ํ ๊ฒ)
๋นํธ | ์ด๋ฆ | ์ธ์ ํ์ธ? | ๋์ |
---|---|---|---|
TXE | ์ ์ก ์ค๋น | ์ก์ ํ๊ธฐ ์ | 1์ด๋ฉด USART_DR ์ ๋ฐ์ดํฐ ์จ๋ ๋จ |
TC | ์ ์ก ์๋ฃ | ์ก์ ํ ์ ์ฒด ์๋ฃ ํ์ธ ์ | 1์ด๋ฉด ๋ชจ๋ ์ ์ก ์๋ฃ |
RXNE | ์์ ์ค๋น | ๋ฐ์ดํฐ ์์ ์ | 1์ด๋ฉด USART_DR ์์ ์ฝ๊ธฐ |
ORE | ์ค๋ฅ | ์์ ์ ์ฒ๋ฆฌ ์ง์ฐ๋๋ฉด ๋ฐ์ | RXNE๋ฅผ ์ ์ฝ์ด์ ๋ฐ์ดํฐ ์ ์ค |
PE | ์ค๋ฅ | ํจ๋ฆฌํฐ ์ค์ ํ ๊ฒฝ์ฐ | ์๋ชป๋ ํจ๋ฆฌํฐ ์์ |
FE | ์ค๋ฅ | ์๋ชป๋ Stop bit ์์ | framing error |
๐ rc_w0 ๋ป?
์์ฑ | ์๋ฏธ |
---|---|
r |
Read-only |
rc_w0 |
์ฝ๊ธฐ ๊ฐ๋ฅ, “1”์ ์จ์ผ ํด๋ฆฌ์ด๋จ (write 0 has no effect) |
์ฆ, ์ค๋ฅ ๋นํธ๋ ์ํ ํ๋๊ทธ๋ ‘์ฝ๊ธฐ’ + ‘1 ์ฐ๊ธฐ’๋ก ํด๋ฆฌ์ด ํด์ผ ํฉ๋๋ค:
c
๋ณต์ฌํธ์ง
USART2->SR &= ~(1 << 5); // โ ์๋์ํจ
USART2->SR = ~(1 << 5); // โ ์๋์ํจ
// ์ ์: SR์ ์ฝ๊ณ DR๋ ์ฝ์ด์ผ ํด๋ฆฌ์ด๋จ (RXNE ๋ฑ)
uint8_t dummy = USART2->DR;
โ ์ค์ ์ก์ ๋ฃจํด ์์
c
๋ณต์ฌํธ์ง
// ์ ์ก ์ค๋น๋ ๋๊น์ง ๋๊ธฐ
while (!(USART2->SR & (1 << 7))); // TXE
// ๋ฐ์ดํฐ ์ ์ก
USART2->DR = 'A';
// ์ ์ก ์๋ฃ๊น์ง ๋๊ธฐ (์ต์
)
while (!(USART2->SR & (1 << 6))); // TC
โ ์ค์ ์์ ๋ฃจํด ์์
c
๋ณต์ฌํธ์ง
// ์์ ๋ฐ์ดํฐ ๋์ฐฉ ๋๊ธฐ
while (!(USART2->SR & (1 << 5))); // RXNE
// ์์ ๋ฐ์ดํฐ ์ฝ๊ธฐ
char data = USART2->DR;
// RCC ๋ฐ GPIO ๊ด๋ จ ๋ ์ง์คํฐ ์ ์
#define RCC_AHB1ENR (*(volatile uint32_t*)0x40023830) // AHB1 ํด๋ญ (GPIO์ฉ)
#define RCC_APB1ENR (*(volatile uint32_t*)0x40023840) // APB1 ํด๋ญ (USART2์ฉ)
#define GPIOA_MODER (*(volatile uint32_t*)0x40020000) // GPIOA ๋ชจ๋ ์ค์
#define GPIOA_AFRL (*(volatile uint32_t*)0x40020020) // GPIOA์ AFR[7:0] (PA0 ~ PA7)
#define USART2_BASE 0x40004400 // USART2 ๋ฒ ์ด์ค ์ฃผ์
#define USART2_SR (*(volatile uint32_t*)(USART2_BASE + 0x00)) // ์ํ ๋ ์ง์คํฐ
#define USART2_DR (*(volatile uint32_t*)(USART2_BASE + 0x04)) // ๋ฐ์ดํฐ ๋ ์ง์คํฐ
#define USART2_BRR (*(volatile uint32_t*)(USART2_BASE + 0x08)) // ๋ณด๋ ์ดํธ ์ค์
#define USART2_CR1 (*(volatile uint32_t*)(USART2_BASE + 0x0C)) // ์ ์ด ๋ ์ง์คํฐ 1
// USART2 ์ด๊ธฐํ ํจ์
void usart2_init() {
// 1. ํด๋ญ ์ธ๊ฐ
RCC_AHB1ENR |= (1 << 0); // GPIOA ํด๋ญ ์ธ๊ฐ
RCC_APB1ENR |= (1 << 17); // USART2 ํด๋ญ ์ธ๊ฐ
// 2. GPIO ์ค์ (PA2๋ฅผ USART2 TX๋ก ์ค์ )
GPIOA_MODER &= ~(3 << (2 * 2)); // MODER2 ํด๋ฆฌ์ด
GPIOA_MODER |= (2 << (2 * 2)); // MODER2 = 10 (AF ๋ชจ๋)
GPIOA_AFRL &= ~(0xF << (4 * 2)); // AFRL2 ํด๋ฆฌ์ด
GPIOA_AFRL |= (7 << (4 * 2)); // AFRL2 = 0111 (AF7: USART2)
// 3. USART ์ค์ (9600 bps @ 16 MHz)
USART2_BRR = 0x0683; // 9600bps ์ค์
// 4. USART ๋ฐ ์ก์ ๊ธฐ๋ฅ ํ์ฑํ
USART2_CR1 |= (1 << 13); // UE (USART Enable)
USART2_CR1 |= (1 << 3); // TE (Transmitter Enable)
}
// USART2๋ฅผ ํตํด ๋ฌธ์ 1๊ฐ ์ก์
void usart2_write(char ch) {
while (!(USART2_SR & (1 << 7))); // TXE ๋๊ธฐ
USART2_DR = ch; // ๋ฐ์ดํฐ ์ ์ก
}
int main(void) {
usart2_init(); // USART2 ์ด๊ธฐํ
while (1) {
usart2_write('A'); // ๋ฌธ์ ์ ์ก
for (volatile int i = 0; i < 100000; ++i); // ๋๋ ์ด
}
}
๐ง ์ด ์ฝ๋์ ํต์ฌ ํฌ์ธํธ
- GPIOA ํด๋ญ, USART2 ํด๋ญ, GPIO ํ ๋ชจ๋ ์ค์ , AF ์ค์ , ๋ณด๋ ์ดํธ ๊ณ์ฐ, TX enable, TXE ์ํ ์ฒดํฌ๊น์ง ์ ๋ถ ๋ ์ง์คํฐ๋ก ์ฒ๋ฆฌ
- HAL, CMSIS, StdPeriph ๋ฑ ์ด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฌ์ฉํ์ง ์์
while (!(USART2_SR & (1 << 7)))
๋ TX ๋ฒํผ๊ฐ ๋น์๋์ง ํ์ธํ๋ ์ฝ๋
โ ์์คํ ๊ตฌ์ฑ
ํญ๋ชฉ | ๋ด์ฉ |
---|---|
MCU | STM32F401 |
TX ํ | PA2 (AF7) |
USART2 | TX ์ฌ์ฉ |
DMA | DMA1, Stream 6, Channel 4 (USART2_TX ์ ์ฉ) |
โ ์ ์ฒด ํ๋ฆ
- RCC๋ก USART2 / DMA1 / GPIOA ํด๋ญ ์ธ๊ฐ
- PA2๋ฅผ Alternate Function (AF7)๋ก ์ค์
- USART2 ๋ณด๋ ์ดํธ ์ค์ , TE ํ์ฑํ
- DMA1_Stream6 ์ค์ (๋ฉ๋ชจ๋ฆฌ โ ์ฃผ๋ณ์ฅ์น, ์ ์ก ํฌ๊ธฐ ๋ฑ)
- USART2์ DMA TX ์์ฒญ ํ์ฉ
- DMA Enable โ ์๋ ์ก์ ์์
#include <stdint.h>
// RCC
#define RCC_AHB1ENR (*(volatile uint32_t*)0x40023830)
#define RCC_APB1ENR (*(volatile uint32_t*)0x40023840)
// GPIO
#define GPIOA_MODER (*(volatile uint32_t*)0x40020000)
#define GPIOA_AFRL (*(volatile uint32_t*)0x40020020)
// USART2
#define USART2_BASE 0x40004400
#define USART2_SR (*(volatile uint32_t*)(USART2_BASE + 0x00))
#define USART2_DR (*(volatile uint32_t*)(USART2_BASE + 0x04))
#define USART2_BRR (*(volatile uint32_t*)(USART2_BASE + 0x08))
#define USART2_CR1 (*(volatile uint32_t*)(USART2_BASE + 0x0C))
#define USART2_CR3 (*(volatile uint32_t*)(USART2_BASE + 0x14))
// DMA1 (USART2_TX โ Stream 6, Channel 4)
#define DMA1_BASE 0x40026000
#define DMA1_Stream6_CR (*(volatile uint32_t*)(DMA1_BASE + 0x118))
#define DMA1_Stream6_NDTR (*(volatile uint32_t*)(DMA1_BASE + 0x11C))
#define DMA1_Stream6_PAR (*(volatile uint32_t*)(DMA1_BASE + 0x120))
#define DMA1_Stream6_M0AR (*(volatile uint32_t*)(DMA1_BASE + 0x124))
#define DMA1_HIFCR (*(volatile uint32_t*)(DMA1_BASE + 0x0A8)) // DMA Clear Interrupt Flags
void dma_usart2_init(const char* data, uint32_t len) {
// 1. ํด๋ญ ์ธ๊ฐ
RCC_AHB1ENR |= (1 << 0); // GPIOA
RCC_AHB1ENR |= (1 << 21); // DMA1
RCC_APB1ENR |= (1 << 17); // USART2
// 2. GPIO ์ค์ (PA2 -> AF7)
GPIOA_MODER &= ~(3 << (2 * 2));
GPIOA_MODER |= (2 << (2 * 2)); // AF ๋ชจ๋
GPIOA_AFRL &= ~(0xF << (4 * 2));
GPIOA_AFRL |= (7 << (4 * 2)); // AF7: USART2
// 3. USART2 ๋ณด๋ ์ดํธ ๋ฐ ํ์ฑํ
USART2_BRR = 0x0683; // 9600bps @ 16MHz
USART2_CR3 |= (1 << 7); // DMAT ํ์ฑํ (DMA enable transmitter)
USART2_CR1 |= (1 << 13) | (1 << 3); // USART Enable + Transmitter Enable
// 4. DMA ์ค์ (Stream6, Channel 4)
DMA1_Stream6_CR &= ~(1 << 0); // Stream disable
while (DMA1_Stream6_CR & 1); // Stream์ด ์์ ํ ๊บผ์ง ๋๊น์ง ๋๊ธฐ
DMA1_HIFCR |= (0x3D << 16); // ๋ชจ๋ ์ธํฐ๋ฝํธ ํ๋๊ทธ ํด๋ฆฌ์ด
DMA1_Stream6_CR &= ~(7 << 25); // CHSEL[2:0] ํด๋ฆฌ์ด
DMA1_Stream6_CR |= (4 << 25); // Channel 4 ์ ํ (USART2_TX)
DMA1_Stream6_CR &= ~(3 << 6); // DIR = 01 (Memory โ Peripheral)
DMA1_Stream6_CR |= (1 << 6);
DMA1_Stream6_CR &= ~(1 << 10); // Peripheral increment disable
DMA1_Stream6_CR |= (1 << 10); // Memory increment enable
DMA1_Stream6_CR &= ~(3 << 13); // Memory data size = 8-bit
DMA1_Stream6_CR &= ~(3 << 11); // Peripheral data size = 8-bit
DMA1_Stream6_PAR = (uint32_t)&USART2_DR; // ๋ชฉ์ ์ง ์ฃผ์: USART2_DR
DMA1_Stream6_M0AR = (uint32_t)data; // ์์ค ์ฃผ์: ๋ฌธ์์ด
DMA1_Stream6_NDTR = len; // ์ ์กํ ๋ฐ์ดํธ ์
DMA1_Stream6_CR |= (1 << 0); // DMA Stream Enable
}
int main(void) {
const char msg[] = "Hello DMA USART2!\\r\\n";
dma_usart2_init(msg, sizeof(msg) - 1);
while (1); // ์ ์ก ์๋ฃ๋ ๋๊น์ง ๋๊ธฐ
}
โ ํต์ฌ ์์ฝ
ํญ๋ชฉ | ์ค๋ช |
---|---|
DMA ์ฑ๋ | DMA1 Stream6, Channel 4 (USART2_TX) |
๋ฐ์ดํฐ ํ๋ฆ | Memory โ USART2_DR |
์ฅ์ | CPU ๊ฐ์ ์์ด ๋ฌธ์์ด ์ ์ก ๊ฐ๋ฅ |
DMA ์ข ๋ฃ ์ฒ๋ฆฌ | DMA๋ ์๋ ์ข ๋ฃ, ์๋ ํด๋ฆฌ์ด ๊ฐ๋ฅ |
๋๋ฒ๊น ๋ฐฉ๋ฒ | ์ค์ค๋ก์ค์ฝํ๋ UART ๋ชจ๋ํฐ๋ก ํ์ธ |
โ ์์คํ ๊ตฌ์ฑ
ํญ๋ชฉ | ๋ด์ฉ |
---|---|
MCU | STM32F401 |
TX ํ | PA2 (AF7) |
USART2 | TX ์ฌ์ฉ |
DMA | DMA1, Stream 6, Channel 4 (USART2_TX ์ ์ฉ) |
โ ์ ์ฒด ํ๋ฆ
- RCC๋ก USART2 / DMA1 / GPIOA ํด๋ญ ์ธ๊ฐ
- PA2๋ฅผ Alternate Function (AF7)๋ก ์ค์
- USART2 ๋ณด๋ ์ดํธ ์ค์ , TE ํ์ฑํ
- DMA1_Stream6 ์ค์ (๋ฉ๋ชจ๋ฆฌ โ ์ฃผ๋ณ์ฅ์น, ์ ์ก ํฌ๊ธฐ ๋ฑ)
- USART2์ DMA TX ์์ฒญ ํ์ฉ
- DMA Enable โ ์๋ ์ก์ ์์
#include <stdint.h>
// RCC
#define RCC_AHB1ENR (*(volatile uint32_t*)0x40023830)
#define RCC_APB1ENR (*(volatile uint32_t*)0x40023840)
// GPIO
#define GPIOA_MODER (*(volatile uint32_t*)0x40020000)
#define GPIOA_AFRL (*(volatile uint32_t*)0x40020020)
// USART2
#define USART2_BASE 0x40004400
#define USART2_SR (*(volatile uint32_t*)(USART2_BASE + 0x00))
#define USART2_DR (*(volatile uint32_t*)(USART2_BASE + 0x04))
#define USART2_BRR (*(volatile uint32_t*)(USART2_BASE + 0x08))
#define USART2_CR1 (*(volatile uint32_t*)(USART2_BASE + 0x0C))
#define USART2_CR3 (*(volatile uint32_t*)(USART2_BASE + 0x14))
// DMA1 Stream6 for USART2_TX
#define DMA1_BASE 0x40026000
#define DMA1_Stream6_CR (*(volatile uint32_t*)(DMA1_BASE + 0x118))
#define DMA1_Stream6_NDTR (*(volatile uint32_t*)(DMA1_BASE + 0x11C))
#define DMA1_Stream6_PAR (*(volatile uint32_t*)(DMA1_BASE + 0x120))
#define DMA1_Stream6_M0AR (*(volatile uint32_t*)(DMA1_BASE + 0x124))
#define DMA1_HIFCR (*(volatile uint32_t*)(DMA1_BASE + 0x0A8))
// NVIC
#define NVIC_ISER1 (*(volatile uint32_t*)0xE000E104)
volatile char rx_data = 0;
void dma_usart2_tx(const char* data, uint32_t len) {
DMA1_Stream6_CR &= ~(1 << 0); // Disable DMA stream
while (DMA1_Stream6_CR & 1);
DMA1_HIFCR |= (0x3D << 16); // Clear all DMA interrupt flags
DMA1_Stream6_CR &= ~(7 << 25); // CHSEL = 4
DMA1_Stream6_CR |= (4 << 25);
DMA1_Stream6_CR &= ~(3 << 6);
DMA1_Stream6_CR |= (1 << 6); // Memory to Peripheral
DMA1_Stream6_CR &= ~(1 << 10); // Peripheral increment disable
DMA1_Stream6_CR |= (1 << 10); // Memory increment enable
DMA1_Stream6_CR &= ~(3 << 13); // 8-bit mem
DMA1_Stream6_CR &= ~(3 << 11); // 8-bit periph
DMA1_Stream6_PAR = (uint32_t)&USART2_DR;
DMA1_Stream6_M0AR = (uint32_t)data;
DMA1_Stream6_NDTR = len;
DMA1_Stream6_CR |= (1 << 0); // Enable DMA stream
}
void usart2_init_dma_rx(void) {
// Enable clocks
RCC_AHB1ENR |= (1 << 0) | (1 << 21); // GPIOA, DMA1
RCC_APB1ENR |= (1 << 17); // USART2
// GPIOA2 = TX, A3 = RX
GPIOA_MODER &= ~((3 << (2 * 2)) | (3 << (3 * 2)));
GPIOA_MODER |= ((2 << (2 * 2)) | (2 << (3 * 2))); // AF mode
GPIOA_AFRL &= ~((0xF << (4 * 2)) | (0xF << (4 * 3)));
GPIOA_AFRL |= ((7 << (4 * 2)) | (7 << (4 * 3))); // AF7
USART2_BRR = 0x0683; // 9600 bps
USART2_CR3 |= (1 << 7); // DMAT enable
USART2_CR1 |= (1 << 13) | (1 << 3) | (1 << 2) | (1 << 5); // UE, TE, RE, RXNEIE
NVIC_ISER1 |= (1 << (USART2_IRQn - 32)); // USART2 interrupt enable
}
void USART2_IRQHandler(void) {
if (USART2_SR & (1 << 5)) { // RXNE
rx_data = USART2_DR; // Read to clear RXNE
// echo back
dma_usart2_tx(&rx_data, 1);
}
}
int main(void) {
usart2_init_dma_rx();
const char* msg = "USART2 DMA TX + RX interrupt ready\\r\\n";
dma_usart2_tx(msg, 34);
while (1);
}
USART2๋ฅผ ํตํด DMA๋ก ๋ฌธ์์ด์ ์ก์ ํ๊ณ , ์์ ๋ ๋ฌธ์๋ฅผ ์ธํฐ๋ฝํธ์์ ๋ฐ์ ์ฆ์ DMA๋ก ๋ค์ ์ก์ (์์ฝ)ํ๋ ๊ตฌ์กฐ์ ๋๋ค.