์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

STM32 USB Device CDC ๊ณ ์† ์ „์†ก ์ค‘ ๋Š๊น€ ์›์ธ ๋ถ„์„: PMA ๋ฒ„ํผ ์–ธ๋”๋Ÿฐ ํ•ด๊ฒฐ ๋ฐ ์ด์ค‘ ๋ฒ„ํผ๋ง ์ตœ์ ํ™” ๊ฐ€์ด๋“œ

๊ฒŒ์ž„๊ต์ˆ˜ 2026. 9. 4. 16:03
๋ฐ˜์‘ํ˜•

๐ŸŒ English Abstract

This technical article provides an in-depth troubleshooting guide for connection drops during high-speed data transmission using the STM32 USB Device CDC protocol. It explains the root cause of Packet Memory Area (PMA) buffer underrun and demonstrates how to resolve host-side timeouts and packet loss. Furthermore, it details the step-by-step implementation of double buffering and ring buffer management to achieve maximum USB Full-Speed throughput and system stability.

1. ์„œ๋ก : STM32 USB CDC ๊ณ ์† ๋ฐ์ดํ„ฐ ์ „์†ก ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์—ฐ๊ฒฐ ๋Š๊น€ ํ˜„์ƒ

STM32 ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ์—์„œ USB CDC(Communication Device Class) ํ”„๋กœํ† ์ฝœ์€ ๊ฐ€์ƒ ์ปดํฌํŠธ(Virtual COM Port, VCP)๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ PC์™€ ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ ๊ฐ„ ๊ณ ์† ๋ฐ์ดํ„ฐ ํ†ต์‹ ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์„ผ์„œ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆฌ๋ฐ, ๊ณ ํ•ด์ƒ๋„ ๋กœ๊น…, ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ์žฅ์น˜(DAQ) ๋“ฑ ์—ฐ์†์ ์ธ ๊ณ ์† ๋ฐ์ดํ„ฐ(High-Throughput)๋ฅผ ์ „์†กํ•˜๋Š” ์‹ค๋ฌด ํ˜„์žฅ์—์„œ ์›์ธ์„ ์•Œ ์ˆ˜ ์—†๋Š” **USB ์—ฐ๊ฒฐ ๋Š๊น€(Disconnection)**, **ํŒจํ‚ท ๋ˆ„๋ฝ(Packet Loss)**, ๋˜๋Š” **ํ˜ธ์ŠคํŠธ ๋“œ๋ผ์ด๋ฒ„ ๋จนํ†ต ํ˜„์ƒ**์„ ์ž์ฃผ ๊ฒช๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋Š” ๋Œ€๊ฐœ ๋‹จ์ˆœํ•œ C์–ธ์–ด ์ฝ”๋“œ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹Œ, STM32 ๋‚ด๋ถ€ **USB ์ฃผ๋ณ€์žฅ์น˜(Peripheral)์˜ ํ•˜๋“œ์›จ์–ด ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ**์™€ **HAL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์†Œํ”„ํŠธ์›จ์–ด ํƒ€์ด๋ฐ ๊ฐ„ ๋ถˆ์ผ์น˜**์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ USB ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ง์ ‘ ์ „์šฉ SRAM์— ์ ‘๊ทผํ•˜๋Š” ์˜์—ญ์ธ **PMA(Packet Memory Area) ๋ฒ„ํผ์˜ ์–ธ๋”๋Ÿฐ(Underrun) ๋ฐ ์˜ค๋ฒ„๋Ÿฐ(Overrun)** ํ˜„์ƒ์ด ์ฃผ์š” ์›์ธ์ž…๋‹ˆ๋‹ค.

๋ณธ ํฌ์ŠคํŒ…์—์„œ๋Š” STM32 USB CDC ํ†ต์‹  ์ค‘ ๋Œ€์šฉ๋Ÿ‰ ์ „์†ก ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„ํผ ์–ธ๋”๋Ÿฐ ํ˜„์ƒ์˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ•˜๋“œ์›จ์–ด ๋ ˆ๋ฒจ์—์„œ ๋ถ„์„ํ•˜๊ณ , ์ด๋ฅผ ๊ทผ๋ณธ์ ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” **์ด์ค‘ ๋ฒ„ํผ๋ง(Double Buffering)** ๋ฐ **์›ํ˜• ๋ฒ„ํผ(Ring Buffer) ์ตœ์ ํ™” ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…** ๊ธฐ๋ฒ•์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.



2. ์›์ธ ๋ถ„์„: PMA(Packet Memory Area) ๊ตฌ์กฐ์™€ ์–ธ๋”๋Ÿฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜

2.1. PMA(Packet Memory Area) ๋ฉ”๋ชจ๋ฆฌ ๋งคํ•‘ ๊ตฌ์กฐ์˜ ์ดํ•ด

STM32 MCU(์˜ˆ: STM32F1, F3, L4 ์‹œ๋ฆฌ์ฆˆ ๋“ฑ)์˜ USB ํ•˜๋“œ์›จ์–ด๋Š” ์ผ๋ฐ˜ SRAM๊ณผ ๋ถ„๋ฆฌ๋œ **PMA(Packet Memory Area)**๋ผ๋Š” ์ „์šฉ ํŒจํ‚ท ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๊ฐ–์Šต๋‹ˆ๋‹ค. USB ์ฃผ๋ณ€์žฅ์น˜ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ํ˜ธ์ŠคํŠธ(PC)์™€ ํŒจํ‚ท์„ ์ฃผ๊ณ ๋ฐ›์„ ๋•Œ ์ด PMA๋ฅผ ์ง์ ‘ ์ฝ๊ฑฐ๋‚˜ ์”๋‹ˆ๋‹ค.

  • ๋ฒ„ํผ ๋””์Šคํฌ๋ฆฝํ„ฐ ํ…Œ์ด๋ธ” (Buffer Descriptor Table): PMA์˜ ์ตœ์ƒ๋‹จ์— ์œ„์น˜ํ•˜๋ฉฐ, ๊ฐ ์—”๋“œํฌ์ธํŠธ(Endpoint)์˜ TX/RX ๋ฒ„ํผ ์‹œ์ž‘ ์ฃผ์†Œ ๋ฐ ๋ฐ์ดํ„ฐ ๊ธธ์ด๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • SRAM ์ ‘๊ทผ ์ œ์•ฝ ์‚ฌํ•ญ: ์ผ๋ถ€ STM32 ํŒจ๋ฐ€๋ฆฌ์—์„œ๋Š” PMA ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ 16๋น„ํŠธ ๋‹จ์œ„ ๋˜๋Š” 32๋น„ํŠธ ๋‹จ์œ„๋กœ ์–ต์„ธ์Šค ์ œํ•œ์ด ์žˆ์œผ๋ฉฐ, ์‹œ์Šคํ…œ CPU ๋ฉ”๋ชจ๋ฆฌ(SRAM)์—์„œ PMA๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•  ๋•Œ ํ•˜๋“œ์›จ์–ด ๋ ˆ๋ฒจ์˜ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

2.2. Single Buffer ํ™˜๊ฒฝ์—์„œ PMA Buffer Underrun์ด ๋ฐœ์ƒํ•˜๋Š” ์ด์œ 

STM32CubeMX๋กœ ์ž๋™ ์ƒ์„ฑ๋œ ๊ธฐ๋ณธ CDC ์ฝ”๋“œ(Class Driver)๋Š” ๋Œ€๋ถ€๋ถ„ **๋‹จ์ผ ๋ฒ„ํผ๋ง(Single Buffering)** ๊ตฌ์กฐ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ์ „์†ก ํ๋ฆ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜์—ญ์—์„œ USBD_CDC_TransmitPacket() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  2. ๋‚ด๋ถ€ CDC_Itf_Transmit()๊ฐ€ USBD_CDC_SetTxBuffer()๋ฅผ ํ†ตํ•ด ์ „์†ก ๋ฒ„ํผ ์ฃผ์†Œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  3. USB ์ฃผ๋ณ€์žฅ์น˜๊ฐ€ IN ์—”๋“œํฌ์ธํŠธ ์š”์ฒญ(IN Token)์„ ํ˜ธ์ŠคํŠธ๋กœ๋ถ€ํ„ฐ ์ˆ˜์‹ ํ•˜๋ฉด PMA์˜ ๋ฐ์ดํ„ฐ๋ฅผ PHY ๋ผ์ธ์œผ๋กœ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.
  4. ์ „์†ก์ด ์™„๋ฃŒ๋˜๋ฉด USBD_CDC_DataIn() ์ฝœ๋ฐฑ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ TxState๊ฐ€ IDLE(0) ์ƒํƒœ๋กœ ๋ณต๊ท€ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ ๋ฐœ์ƒ ์ง€์ : ํ˜ธ์ŠคํŠธ PC๊ฐ€ 1ms ๋งˆ๋‹ค(Full-Speed ๊ธฐ์ค€ Frame ๋‹จ์œ„) IN ํ† ํฐ์„ ์†ก์‹ ํ•  ๋•Œ, MCU ์ธก์—์„œ USBD_CDC_TransmitPacket()์„ ํ†ตํ•ด ๋‹ค์Œ ํŒจํ‚ท์„ PMA์— ๋‹ค ์ฑ„์šฐ๊ธฐ๋„ ์ „์— IN ํ† ํฐ์ด ๋“ค์–ด์˜ค๋ฉด, USB ํ•˜๋“œ์›จ์–ด๋Š” ๋ณด๋‚ด์ค„ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์–ด **NAK(Negative Acknowledgment)** ํŒจํ‚ท์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์—ฐ์†์ ์ธ ๊ณ ์† ์ „์†ก ์ƒํ™ฉ์—์„œ CPU๊ฐ€ ๋‹ค๋ฅธ ์šฐ์„ ์ˆœ์œ„ ๋†’์€ ์ธํ„ฐ๋ŸฝํŠธ(์˜ˆ: DMA, TIM, UART ISR)๋ฅผ ์ฒ˜๋ฆฌํ•˜๋А๋ผ USBD_CDC_TransmitPacket() ํ˜ธ์ถœ ํƒ€์ด๋ฐ์„ ๋†“์น˜๊ฑฐ๋‚˜, TxState๊ฐ€ BUSY ์ƒํƒœ์ผ ๋•Œ ๊ณ„์† ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ€์–ด ๋„ฃ์œผ๋ฉด, ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฎ์–ด์”Œ์›Œ์ง€๊ฑฐ๋‚˜ PMA ์ „์†ก ํƒ€์ด๋ฐ์ด ๋’คํ‹€๋ฆฌ๋ฉด์„œ **PMA Buffer Underrun / Overrun**์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ํ˜ธ์ŠคํŠธ ์‘๋‹ต ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์–ด USB ์ œ์–ด ์‹ ํ˜ธ๊ฐ€ ๋ฆฌ์…‹(Bus Reset)๋˜๋ฉด์„œ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง€๋Š” ๊ฒฐ๊ณผ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

3. ํ•ด๊ฒฐ์ฑ… 1: ์ด์ค‘ ๋ฒ„ํผ๋ง(Double Buffering) ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๊ตฌ์ถ•

3.1. ์ด์ค‘ ๋ฒ„ํผ๋ง(Ping-Pong Buffer)์˜ ๋™์ž‘ ์›๋ฆฌ

๋‹จ์ผ ๋ฒ„ํผ ๊ตฌ์กฐ์˜ ํ•œ๊ณ„๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด **์ด์ค‘ ๋ฒ„ํผ๋ง(Double Buffering / Ping-Pong Buffering)** ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ตฌ์กฐ์—์„œ๋Š” ํ•˜๋“œ์›จ์–ด๊ฐ€ Buffer 0์—์„œ ํŒจํ‚ท์„ USB ๋ผ์ธ์œผ๋กœ ์ „์†กํ•˜๋Š” ๋™์•ˆ, CPU๋Š” Buffer 1์— ๋‹ค์Œ ์ „์†กํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ์ค€๋น„(Write)ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ๊ณ„ (Time Slot) USB Hardware (PMA Send) CPU / Application (Buffer Write)
Slot N Buffer 0 ์ฝ์–ด์„œ PC๋กœ ์ „์†ก Buffer 1์— ๋‹ค์Œ ๋ฐ์ดํ„ฐ ์ฑ„์šฐ๊ธฐ
Slot N+1 Buffer 1 ์ฝ์–ด์„œ PC๋กœ ์ „์†ก Buffer 0์— ๋‹ค์Œ ๋ฐ์ดํ„ฐ ์ฑ„์šฐ๊ธฐ

์ด ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด USB ๋ผ์ธ์ด Idle ์ƒํƒœ์— ๋น ์ ธ NAK์„ ๋‚จ๋ฐœํ•˜๋Š” ํ˜„์ƒ์„ ๋Œ€ํญ ์ค„์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, CPU ์ธํ„ฐ๋ŸฝํŠธ ์ง€์—ฐ์‹œ๊ฐ„(Interrupt Latency)์— ๋Œ€ํ•œ ๋งˆ์ง„์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



4. ์‹ค๋ฌด ์ฝ”๋“œ ์ตœ์ ํ™”: ๋ง ๋ฒ„ํผ(Ring Buffer) ๋ฐ Non-Blocking ์„ค๊ณ„

์ด์ค‘ ๋ฒ„ํผ๋ง ๊ธฐ๋ฒ•์„ ์•ˆ์ •์ ์œผ๋กœ ์šด์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜์—ญ๊ณผ USB ๋“œ๋ผ์ด๋ฒ„ ๊ณ„์ธต ์‚ฌ์ด์— **์„ ์ž…์„ ์ถœ(FIFO) ๋ฐฉ์‹์˜ ์›ํ˜• ๋ง ๋ฒ„ํผ(Ring Buffer)**๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด CPU๊ฐ€ ๋ฉ”์ธ ๋ฃจํ”„์—์„œ ๋น ๋ฅด๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„ํผ๋งํ•˜๊ณ , USB ISR(Interrupt Service Routine)์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ PMA๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํผ๋‚˜๋ฅด๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

4.1. ์Šค๋ ˆ๋“œ ์„ธ์ดํ”„(Thread-Safe) ๋ง ๋ฒ„ํผ ๊ตฌํ˜„

์•„๋ž˜ C์–ธ์–ด ์ฝ”๋“œ๋Š” CDC ํ†ต์‹ ์˜ ๋ฐ์ดํ„ฐ ์œ ์‹ค ๋ฐ ์–ธ๋”๋Ÿฐ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๋Œ€์šฉ๋Ÿ‰ Ring Buffer ๊ตฌ์กฐ์ฒด ๋ฐ ์ „์†ก ํ•จ์ˆ˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

#define CDC_RING_BUFFER_SIZE 4096  // ์ถฉ๋ถ„ํ•œ ํฌ๊ธฐ์˜ ๋ง๋ฒ„ํผ ํ• ๋‹น (2์˜ ๊ฑฐ๋“ญ์ œ๊ณฑ ๊ถŒ์žฅ)
#define USB_MAX_PACKET_SIZE  64    // USB FS CDC Max Packet Size

typedef struct {
    uint8_t buffer[CDC_RING_BUFFER_SIZE];
    volatile uint32_t head;
    volatile uint32_t tail;
} USB_RingBuffer_t;

static USB_RingBuffer_t cdc_tx_ring;

// ๋ง ๋ฒ„ํผ ๋ฐ์ดํ„ฐ ํ‘ธ์‹œ ํ•จ์ˆ˜
bool CDC_RingBuffer_Write(const uint8_t *pData, uint32_t length) {
    for (uint32_t i = 0; i < length; i++) {
        uint32_t next_head = (cdc_tx_ring.head + 1) % CDC_RING_BUFFER_SIZE;
        if (next_head == cdc_tx_ring.tail) {
            return false; // Buffer Full (์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐฉ์ง€)
        }
        cdc_tx_ring.buffer[cdc_tx_ring.head] = pData[i];
        cdc_tx_ring.head = next_head;
    }
    return true;
}

// USB TX ์ธํ„ฐ๋ŸฝํŠธ ์ฒ˜๋ฆฌ ๋ฐ ์—ฐ์† ์ „์†ก ํŠธ๋ฆฌ๊ฑฐ ํ•จ์ˆ˜
void CDC_Continue_Transmit(void) {
    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) hUsbDeviceFS.pClassData;
    
    // USB ๊ฐ€ ํ˜„์žฌ ์ „์†ก ๋ถˆ๊ฐ€๋Šฅ ์ƒํƒœ(BUSY)์ด๋ฉด ๋ฆฌํ„ด
    if (hcdc->TxState != 0) {
        return;
    }

    uint32_t fill_size = 0;
    static uint8_t temp_packet[USB_MAX_PACKET_SIZE];

    // ๋ง ๋ฒ„ํผ์—์„œ ๋ฐ์ดํ„ฐ ๊บผ๋‚ด๊ธฐ
    while (cdc_tx_ring.tail != cdc_tx_ring.head && fill_size < USB_MAX_PACKET_SIZE) {
        temp_packet[fill_size++] = cdc_tx_ring.buffer[cdc_tx_ring.tail];
        cdc_tx_ring.tail = (cdc_tx_ring.tail + 1) % CDC_RING_BUFFER_SIZE;
    }

    if (fill_size > 0) {
        USBD_CDC_SetTxBuffer(&hUsbDeviceFS, temp_packet, fill_size);
        USBD_CDC_TransmitPacket(&hUsbDeviceFS);
    }
}

4.2. usbd_cdc_if.c ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ˆ˜์ •

USB ์ „์†ก์ด ์™„๋ฃŒ๋˜์—ˆ์„ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜์ธ CDC_TransmitCplt_FS() ๋‚ด๋ถ€์—์„œ ๋ง๋ฒ„ํผ์— ๋‚จ์•„์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฆ‰์‹œ ๋ณต์‚ฌํ•˜์—ฌ ํŒจํ‚ท์„ ์žฌ์ „์†กํ•˜๋„๋ก ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum) {
    uint8_t result = USBD_OK;
    
    // ์ด์ „์— ์†ก์‹  ์ค‘์ด๋˜ ์ธํ„ฐ๋ŸฝํŠธ ์™„๋ฃŒ ํ›„ ์—ฐ์† ๋ฐ์ดํ„ฐ ์†ก์‹ 
    CDC_Continue_Transmit();
    
    return (int8_t)result;
}

5. ๋””๋ฒ„๊น… ๋ฐ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ์—ฃ์ง€ ์ผ€์ด์Šค (Edge Cases)

5.1. Zero-Length Packet (ZLP) ์ฒ˜๋ฆฌ ์ด์Šˆ

USB ํ†ต์‹  ๊ทœ์•ฝ์ƒ, ์ „์†กํ•˜๋ ค๋Š” ๋ฐ์ดํ„ฐ ํŒจํ‚ท์˜ ํฌ๊ธฐ๊ฐ€ ์ •ํ™•ํžˆ Endpoint์˜ ์ตœ๋Œ€ ํฌ๊ธฐ์ธ 64๋ฐ”์ดํŠธ์˜ ๋ฐฐ์ˆ˜์ผ ๊ฒฝ์šฐ, ํ˜ธ์ŠคํŠธ PC๋Š” ๋ฐ์ดํ„ฐ ์ „์†ก์ด ์•„์ง ๋๋‚˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•˜๊ณ  ์ˆ˜์‹  ๋Œ€๊ธฐ ์ƒํƒœ์— ๋น ์ง‘๋‹ˆ๋‹ค.

  • ์ฆ์ƒ: PC ์ธก ์ˆ˜์‹  ํ”„๋กœ๊ทธ๋žจ์ด 64, 128, 256 ๋ฐ”์ดํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์„ ๋•Œ ์‘๋‹ต์„ ๋ฉˆ์ถ”๊ฑฐ๋‚˜ ํƒ€์ž„์•„์›ƒ ๋ฐœ์ƒ.
  • ํ•ด๊ฒฐ์ฑ…: ์ „์†ก ๋ฐ์ดํ„ฐ ๊ธธ์ด๊ฐ€ 64๋ฐ”์ดํŠธ์˜ ๋ฐฐ์ˆ˜์ผ ๊ฒฝ์šฐ ๊ธธ์ด๊ฐ€ 0์ธ **ZLP(Zero-Length Packet)**๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€ ์†ก์‹ ํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜ ์ข…๊ฒฐ์„ ํ˜ธ์ŠคํŠธ์— ์•Œ๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

5.2. Priority Inversion (์šฐ์„ ์ˆœ์œ„ ์—ญ์ „) ๋ฐ ISR ์ง€์—ฐ

STM32์˜ USB Interrupt ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‹ค๋ฅธ ์ฃผ๋ณ€์žฅ์น˜(์˜ˆ: Systick, FreeRTOS Kernel Tick, USART ISR)๋ณด๋‹ค ๋‚ฎ๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ์œผ๋ฉด, USB ์ „์†ก ์™„๋ฃŒ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ์ง€์—ฐ๋˜์–ด PMA ๋ฒ„ํผ๊ฐ€ ๋น„์–ด์žˆ๋Š” ์ฑ„๋กœ ์ฑ„์›Œ์ง€์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ์ƒ๊น๋‹ˆ๋‹ค.

  • NVIC ์„ค์ • ์‹œ **USB Interrupt Priority**๋ฅผ ์‹œ์Šคํ…œ ๋‚ด์—์„œ ์ƒ๋Œ€์ ์œผ๋กœ ๋†’๊ฒŒ ์„ค์ •(์ˆซ์ž๋ฅผ ๋‚ฎ๊ฒŒ ์กฐ์ •)ํ•˜์—ฌ ์ธํ„ฐ๋ŸฝํŠธ ์‘๋‹ต ์†๋„๋ฅผ ์ตœ์ ํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


6. ๊ฒฐ๋ก  ๋ฐ ๊ณ ์„ฑ๋Šฅ USB CDC ์„ค๊ณ„๋ฅผ ์œ„ํ•œ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

STM32 MCU ๊ธฐ๋ฐ˜์˜ USB CDC ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•  ๋•Œ ๊ณ ์† ์ „์†ก ์ค‘ ๋Š๊น€ ํ˜„์ƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ํ•ต์‹ฌ ์š”์•ฝ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. PMA ๋ฒ„ํผ์˜ ์ง์ ‘์  ์—ฐ์† ์“ฐ๊ธฐ ๊ธˆ์ง€: USBD_CDC_TransmitPacket()์ด ์™„๋ฃŒ(IDLE)๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ์—ฐ์† ํ˜ธ์ถœ์„ ์ง€์–‘ํ•˜๊ณ , Intermediate **Ring Buffer**๋ฅผ ๊ฒฝ๊ตฌํ•˜์—ฌ ์ œ์–ดํ•  ๊ฒƒ.
  2. ์ด์ค‘ ๋ฒ„ํผ๋ง(Double Buffering) ํ™œ์„ฑํ™”: ํ•˜๋“œ์›จ์–ด ๋ ˆ๋ฒจ ์ง€์› MCU์˜ ๊ฒฝ์šฐ Double Buffer EP ๋ชจ๋“œ๋ฅผ ์„ค์ •ํ•˜์—ฌ PMA ํ• ๋‹น ๋งˆ์ง„์„ ๋‘ ๋ฐฐ๋กœ ๋Š˜๋ฆด ๊ฒƒ.
  3. NVIC ์šฐ์„ ์ˆœ์œ„ ์กฐ์ •: USB ํ•ธ๋“ค๋Ÿฌ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ํƒ€ ์ง€์—ฐ ์š”์†Œ(Timers, External Interrupts)์— ๋ฐ€๋ ค PMA ์ฑ„์šฐ๊ธฐ๊ฐ€ ๋Šฆ์–ด์ง€์ง€ ์•Š๋„๋ก ์กฐ์ •ํ•  ๊ฒƒ.
  4. ZLP ์ฒ˜๋ฆฌ ์ฒดํฌ: 64๋ฐ”์ดํŠธ ๋‹จํŽธํ™” ํŒจํ‚ท ์ „์†ก ์‹œ ๋งˆ์ง€๋ง‰ ์ œ์–ด ์ œ๋กœ ํŒจํ‚ท ์ฒ˜๋ฆฌ๋ฅผ ๋ช…ํ™•ํžˆ ํฌํ•จํ•  ๊ฒƒ.

์œ„์™€ ๊ฐ™์ด ๋Œ€์šฉ๋Ÿ‰ ๋ง ๋ฒ„ํผ๋ง๊ณผ ๋น„๋™๊ธฐ ISR ์ฒ˜๋ฆฌ ๊ตฌ์กฐ๋ฅผ ํ™•๋ฆฝํ•˜๋ฉด, STM32 USB CDC ์‚ฌ์šฉ ์‹œ ํ’€์Šคํ”ผ๋“œ(Full-Speed) ๋Œ€์—ญํญ์ธ **12Mbps(์‹คํšจ ์†๋„ ์•ฝ 800~900KB/s)** ์ˆ˜์ค€์„ ์—ฐ๊ฒฐ ๋Š๊น€ ์—†์ด ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•