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

RP2040 PIO์™€ Dual-Core ๊ณ ์† ์„ผ์„œ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘: FIFO ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐ์ดํ„ฐ ์œ ์‹ค ํ•ด๊ฒฐ ๋ฐ DMA ๋ง๋ฒ„ํผ·๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด ์ตœ์ ํ™” ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

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

๐ŸŒ English Abstract

This article provides an in-depth technical guide on diagnosing and resolving FIFO overflow data loss in high-speed parallel sensor data acquisition systems built on the Raspberry Pi RP2040 microcontroller. By combining PIO (Programmable I/O) state machines, Dual ARM Cortex-M0+ cores, and DMA Ring Buffers, we tackle severe bus contention and interrupt latency issues. Readers will gain practical insights into hardware DREQ synchronization, Ping-Pong DMA configuration, and critical ARM Cortex-M Memory Barriers (__dmb) for deterministic, zero-data-loss execution.

๋ผ์ฆˆ๋ฒ ๋ฆฌ ํŒŒ์ด์˜ RP2040 ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋…์ฐฝ์ ์ธ PIO(Programmable I/O, ํ”„๋กœ๊ทธ๋ž˜๋จธ๋ธ” ์ž…์ถœ๋ ฅ) ํ•˜๋“œ์›จ์–ด ํŽ˜๋ฆฌํŽ˜๋Ÿด๊ณผ ๋“€์–ผ ARM Cortex-M0+ ์ฝ”์–ด๋ฅผ ๋‚ด์žฅํ•˜์—ฌ, ์ €๋น„์šฉ์œผ๋กœ๋„ ๊ณ ์† ์‚ฌ์–‘์˜ ๋ณ‘๋ ฌ ์„ผ์„œ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘(Parallel Sensor Data Acquisition) ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” ๋›ฐ์–ด๋‚œ ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ MHz ๋‹จ์œ„์˜ ๋†’์€ ์ƒ˜ํ”Œ๋ง ์ฃผํŒŒ์ˆ˜๋‚˜ ๋‹ค์ฑ„๋„ ๋ณ‘๋ ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•  ๋•Œ, PIO RX FIFO ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ(Overflow)๋กœ ์ธํ•œ ๊ฐ„ํ—์  ๋ฐ์ดํ„ฐ ์œ ์‹ค ๋ฌธ์ œ๋Š” ์‹œ์Šคํ…œ ์ „์ฒด์˜ ์‹ ๋ขฐ์„ฑ์„ ๋–จ์–ด๋œจ๋ฆฌ๋Š” ์ฃผ์š” ์›์ธ์ด ๋ฉ๋‹ˆ๋‹ค.

๋ณธ ํฌ์ŠคํŒ…์—์„œ๋Š” RP2040 ํ™˜๊ฒฝ์—์„œ ์ดˆ๊ณ ์† ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ๋ง ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„์Šค ๊ฒฝํ•ฉ(Bus Contention) ๋ฐ ์ง€์—ฐ ์‹œ๊ฐ„(Latency) ๋ฌธ์ œ๋ฅผ ์ •๋ฐ€ ์ง„๋‹จํ•˜๊ณ , DMA ๋ง๋ฒ„ํผ(Ring Buffer) ๊ธฐ์ˆ ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด(Memory Barrier) ๋™๊ธฐํ™” ์ตœ์ ํ™”๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์œ ์‹ค๋ฅ  0%๋ฅผ ๋‹ฌ์„ฑํ•˜๋Š” ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ๊ณผ์ • ๋ฐ ์‹ค๋ฌด ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ƒ์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

1. ๊ณ ์† ์„ผ์„œ ์ˆ˜์ง‘ ์‹œ์Šคํ…œ์˜ ๊ตฌ์กฐ ๋ฐ ๋ฐ์ดํ„ฐ ๋ณ‘๋ชฉ ์›์ธ

RP2040์˜ PIO๋Š” ๋ฉ”์ธ CPU์˜ ๊ฐœ์ž… ์—†์ด ๋…๋ฆฝ์ ์ธ ํด๋ก ์ฃผ๊ธฐ์— ๋งž์ถฐ GPIO ํ•€์˜ ์‹ ํ˜ธ๋ฅผ ์ฝ์–ด ๋“ค์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ผ์„œ๋กœ๋ถ€ํ„ฐ ์ˆ˜์‹ ๋œ ๋ฐ์ดํ„ฐ๋Š” ์‹œํ”„ํŠธ ๋ ˆ์ง€์Šคํ„ฐ(Shift Register)๋ฅผ ๊ฑฐ์ณ RX FIFO(First-In, First-Out)์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ PIO ๋‚ด๋ถ€์˜ RX FIFO ๊นŠ์ด๋Š” ๊ฐ ์ƒํƒœ ๋จธ์‹ (State Machine)๋‹น ๋‹จ 4์›Œ๋“œ(16๋ฐ”์ดํŠธ)์— ๋ถˆ๊ณผํ•ฉ๋‹ˆ๋‹ค.

CPU๊ฐ€ ํด๋ง(Polling) ๋ฐฉ์‹์ด๋‚˜ ์ธํ„ฐ๋ŸฝํŠธ(Interrupt, ISR) ๋ฐฉ์‹์œผ๋กœ ์ด FIFO๋ฅผ ๋น„์šฐ๋ ค ํ•  ๊ฒฝ์šฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹ฌ๊ฐํ•œ ์•„ํ‚คํ…์ฒ˜์  ๋ณ‘๋ชฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค:

  • ์ธํ„ฐ๋ŸฝํŠธ ์ง€์—ฐ ์‹œ๊ฐ„(Interrupt Latency): Cortex-M0+ ์ฝ”์–ด์˜ ์ธํ„ฐ๋ŸฝํŠธ ์ง„์ž…/์ง„์ถœ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ(Context Switching) ์˜ค๋ฒ„ํ—ค๋“œ๋กœ ์ธํ•ด, ์ดˆ๋‹น ์ˆ˜์‹ญ๋งŒ ๋ฒˆ ์ด์ƒ ๋ฐœ์ƒํ•˜๋Š” ์„ผ์„œ ์ž…๋ ฅ์„ CPU ์ธํ„ฐ๋ŸฝํŠธ๋งŒ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • XIP Flash ์ง€์—ฐ ํ˜„์ƒ: ์‹คํ–‰ ์ฝ”๋“œ๋‚˜ ISR์ด ์™ธ๋ถ€ QSPI Flash(Execute-In-Place)์—์„œ ์‹คํ–‰๋  ๊ฒฝ์šฐ, ์บ์‹œ ๋ฏธ์Šค(Cache Miss) ๋ฐœ์ƒ ์‹œ ์ˆ˜์‹ญ ๋‚ด์ง€ ์ˆ˜๋ฐฑ ํด๋ก ์ฃผ๊ธฐ์˜ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•˜๋ฉฐ, ๊ทธ ์‚ฌ์ด RX FIFO๋Š” ์ฆ‰์‹œ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ์ƒํƒœ(FDEBUG ๋ ˆ์ง€์Šคํ„ฐ์˜ RXOVER ๋น„ํŠธ ์…‹)์— ์ง๋ฉดํ•ฉ๋‹ˆ๋‹ค.
  • ๋“€์–ผ์ฝ”์–ด SRAM ๊ฒฝํ•ฉ: Core 0๊ณผ Core 1์ด ๋™์ผํ•œ SRAM ๋ฑ…ํฌ(Bank)์— ๋™์‹œ์— ์ ‘๊ทผํ•  ๋•Œ, AHB ๋ฒ„์Šค ํฌ๋กœ์Šค๋ฐ”(AHB Bus Crossbar)์—์„œ ์ค‘์žฌ(Arbitration) ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ด์†ก์ด ์ง€์—ฐ๋ฉ๋‹ˆ๋‹ค.



2. PIO hardware DREQ ๋ฐ DMA ์ฒด์ด๋‹ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋ถ„์„

FIFO ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋ฅผ ๊ทผ๋ณธ์ ์œผ๋กœ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” CPU์˜ ๊ฐœ์ž…์„ ์™„์ „ํžˆ ๋ฐฐ์ œํ•˜๊ณ , ํ•˜๋“œ์›จ์–ด ์š”์ฒญ ์‹ ํ˜ธ์ธ DREQ(Data Request) ๊ธฐ๋ฐ˜์˜ DMA(Direct Memory Access)๋ฅผ ์ „๋ฉด์— ๋ฐฐ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

PIO ์ƒํƒœ ๋จธ์‹ ์€ RX FIFO์— ๋ฐ์ดํ„ฐ๊ฐ€ 1๊ฐœ ์ด์ƒ ๋“ค์–ด์˜ค๋Š” ์ˆœ๊ฐ„ ํ•˜๋“œ์›จ์–ด DREQ ์‹ ํ˜ธ(DREQ_PIOx_RXy)๋ฅผ ์–ด์„ค์…˜(Assertion)ํ•ฉ๋‹ˆ๋‹ค. DMA ์ฑ„๋„์€ ์ด DREQ ์‹ ํ˜ธ๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ์ฆ‰์‹œ ๋ฒ„์Šค ๋งˆ์Šคํ„ฐ๋กœ์„œ SRAM์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์ด๋ ‰ํŠธ ํŠธ๋žœ์Šคํผํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‹จ์ˆœ ๋‹จ์ผ DMA ๋ฒ„ํผ ์„ค์ •์€ ๋ฒ„ํผ๊ฐ€ ๊ฐ€๋“ ์ฐผ์„ ๋•Œ ์žฌ์„ค์ •(Reconfiguration) ๊ณผ์ •์—์„œ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•ด ๋‹ค์‹œ FIFO ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.

์ด์ค‘ ๋ฒ„ํผ๋ง(Ping-Pong DMA)๊ณผ DMA ์ฒด์ด๋‹

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐœ์˜ DMA ์ฑ„๋„(Channel A, Channel B)์„ ์ƒํ˜ธ ์—ฐ๊ฒฐํ•˜๋Š” DMA ์ฒด์ด๋‹(DMA Chaining) ๋ฐฉ์‹์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. Channel A๊ฐ€ ๋ฒ„ํผ 1๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋™์•ˆ, ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘์ด ๋๋‚˜๋ฉด ์™„๋ฃŒ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๋™์‹œ์— Channel B๋ฅผ ํ•˜๋“œ์›จ์–ด์ ์œผ๋กœ ์ฆ‰์‹œ ํŠธ๋ฆฌ๊ฑฐํ•˜์—ฌ ๋ฒ„ํผ 2๋กœ ์ˆ˜์ง‘์„ ์ด์–ด๊ฐ‘๋‹ˆ๋‹ค.

// DMA ์ฒด์ด๋‹ ๋ฐ DREQ ์„ค์ • ์˜ˆ์‹œ (RP2040 C/C++ SDK)
int dma_chan_a = dma_claim_unused_channel(true);
int dma_chan_b = dma_claim_unused_channel(true);

dma_channel_config c_a = dma_channel_get_default_config(dma_chan_a);
channel_config_set_read_increment(&c_a, false);               // PIO RX FIFO ์ฃผ์†Œ ๊ณ ์ •
channel_config_set_write_increment(&c_a, true);                // SRAM ๋ฒ„ํผ ์ฃผ์†Œ ์ฆ๊ฐ€
channel_config_set_dreq(&c_a, pio_get_dreq(pio, sm, false));   // PIO RX DREQ ์—ฐ๊ฒฐ
channel_config_set_chain_to(&c_a, dma_chan_b);                 // ์ฑ„๋„ A ์™„๋ฃŒ ์‹œ ์ฑ„๋„ B ์ž๋™ ์‹คํ–‰

dma_channel_configure(
    dma_chan_a, &c_a,
    buffer_a,                  // ๋ชฉ์ ์ง€ ์ฃผ์†Œ (SRAM)
    &pio->rxf[sm],             // ์†Œ์Šค ์ฃผ์†Œ (PIO RX FIFO)
    BUFFER_SIZE_WORDS,         // ์ „์†ก ํฌ๊ธฐ
    false                      // ์•„์ง ์‹œ์ž‘ํ•˜์ง€ ์•Š์Œ
);



3. DMA ๋ง๋ฒ„ํผ(Ring Buffer)์™€ ๋ฉ”๋ชจ๋ฆฌ ๋ฑ…ํฌ ๋ถ„ํ•  ์ตœ์ ํ™”

์ฒด์ด๋‹ ๋ฐฉ์‹ ์™ธ์—๋„, ์ฃผ์†Œ ๋น„ํŠธ ๋งˆ์Šคํ‚น์„ ํ™œ์šฉํ•œ DMA ๋ง๋ฒ„ํผ(Ring Buffer) ๋ชจ๋“œ๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋‹จ์ผ DMA ์ฑ„๋„๋งŒ์œผ๋กœ๋„ ์—ฐ์†๋œ ์ˆœํ™˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ์˜ค๋ฒ„ํ—ค๋“œ ์—†์ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ„์† ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

DMA Ring Buffer ์„ค์ • ๊ทœ์น™

RP2040์˜ DMA ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ •๋ ฌ๋œ(Aligned) ๋ฉ”๋ชจ๋ฆฌ ๊ฒฝ๊ณ„ ๋‚ด์—์„œ 2^n ๋ฐ”์ดํŠธ ํฌ๊ธฐ์˜ ๋ง๋ฒ„ํผ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. channel_config_set_ring() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์“ฐ๊ธฐ(Write) ์ฃผ์†Œ๋ฅผ ์ˆœํ™˜ํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฉ”๋ชจ๋ฆฌ ์–ผ๋ผ์ธ๋จผํŠธ(Memory Alignment): ๋ง๋ฒ„ํผ์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋Š” ๋ฐ˜๋“œ์‹œ ๋ง๋ฒ„ํผ ํฌ๊ธฐ(2^n ๋ฐ”์ดํŠธ)์˜ ๋ฐฐ์ˆ˜ ์ฃผ์†Œ์— ์œ„์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: uint32_t ring_buffer[1024] __attribute__((aligned(4096)));
  • SRAM ๋ฑ…ํฌ ๋ถ„ํ• (SRAM Bank Partitioning): RP2040์€ 4๊ฐœ์˜ ์ •๊ทœ SRAM ๋ฑ…ํฌ(SRAM0~3, ๊ฐ 64KB)์™€ 2๊ฐœ์˜ ์Šคํฌ๋ž˜์น˜ํŒจ๋“œ ๋ฑ…ํฌ(SRAM4~5, ๊ฐ 4KB)๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. DMA ์“ฐ๊ธฐ ๋ฒ„ํผ๋ฅผ SRAM0์— ๋ฐฐ์น˜ํ•˜๊ณ , Core 1์˜ ์Šคํƒ ๋ฐ ์ฒ˜๋ฆฌ ๋กœ์ง ๋ฉ”๋ชจ๋ฆฌ๋ฅผ SRAM1 ๋ฐ SRAM2์— ๋ถ„๋ฆฌ ๋ฐฐ์น˜ํ•จ์œผ๋กœ์จ AHB ๋ฒ„์Šค ํฌ๋กœ์Šค๋ฐ”์—์„œ์˜ ๊ฒฝํ•ฉ(Bus Contention)์„ ์™„๋ฒฝํžˆ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

4. Dual-Core ํŒŒ์ดํ”„๋ผ์ธ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด(__dmb) ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

DMA๊ฐ€ SRAM ๋ง๋ฒ„ํผ๋กœ ์„ผ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ ์† ์ด์†กํ•˜๋Š” ๋™์•ˆ, ๋ฐ์ดํ„ฐ์˜ ํ›„์ฒ˜๋ฆฌ(FFT, ํ•„ํ„ฐ๋ง, ํ”„๋กœํ† ์ฝœ ํŒŒ์‹ฑ ๋“ฑ)๋Š” Core 1์—์„œ ๋‹ด๋‹นํ•˜๊ณ  ์„ผ์„œ ์ˆ˜์ง‘ ํ†ต์ œ ๋ฐ ๋„คํŠธ์›Œํฌ ์ „์†ก์€ Core 0์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๋“€์–ผ์ฝ”์–ด ํŒŒ์ดํ”„๋ผ์ธ(Dual-Core Pipeline) ๊ตฌ์กฐ๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด๋•Œ, Core 1์ด DMA์˜ ์“ฐ๊ธฐ ํฌ์ธํ„ฐ๋ฅผ ์ถ”์ ํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๊ฐˆ ๋•Œ ๋ฐ์ดํ„ฐ ๊นจ์ง(Data Corruption) ๋ฐ ๊ฐฑ์‹  ๋ฏธ์ธ์‹ ํ˜„์ƒ์ด ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ตœ์ ํ™” ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๋ฐ ARM Cortex-M0+์˜ ํŒŒ์ดํ”„๋ผ์ธ ๋ฐ ๋ฒ„์Šค ์ธํ„ฐ์ปค๋„ฅํŠธ์—์„œ์˜ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ์ˆœ์„œ ์žฌ๋ฐฐ์น˜(Memory Reordering) ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…: ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด(Memory Barrier)์˜ ํ•„์—ฐ์„ฑ

C ์–ธ์–ด์˜ volatile ํ‚ค์›Œ๋“œ๋งŒ์œผ๋กœ๋Š” CPU ํ•˜๋“œ์›จ์–ด ๋‹จ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ก ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. DMA๊ฐ€ SRAM์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ์ผ๋”๋ผ๋„, ์ฝ”์–ด์˜ ๋กœ์ปฌ ๋ฒ„์Šค ๋ฒ„ํผ๋ง์ด๋‚˜ ๋ ˆ์ง€์Šคํ„ฐ ์บ์‹ฑ์œผ๋กœ ์ธํ•ด ์ฝ”์–ด๊ฐ€ ์ตœ์‹  ์„ผ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์ง€ ๋ชปํ•˜๊ณ  ์ด์ „ ๊ฐ’์„ ์ฝ๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ARM ์–ด์…ˆ๋ธ”๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด ๋ช…๋ น์–ด๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฝ์ž…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • __dmb() (Data Memory Barrier): ๋ฐฐ๋ฆฌ์–ด ์ด์ „์˜ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ(Read/Write) ์ž‘์—…์ด ์™„๋ฃŒ๋œ ํ›„, ๋ฐฐ๋ฆฌ์–ด ์ดํ›„์˜ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. DMA ํฌ์ธํ„ฐ ์—…๋ฐ์ดํŠธ ํ™•์ธ ์งํ›„ ๋ฐ˜๋“œ์‹œ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • __dsb() (Data Synchronization Barrier): ๋ฐฐ๋ฆฌ์–ด ์ด์ „์˜ ๋ช…๋ น์–ด๊ฐ€ ์™„์ „ํžˆ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์ดํ›„ ๋ช…๋ น์–ด์˜ ์‹คํ–‰์„ ์ •์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • SIO Hardware FIFO ์‚ฌ์šฉ: ์ฝ”์–ด ๊ฐ„ ๋™๊ธฐํ™” ํ”Œ๋ž˜๊ทธ ์ „๋‹ฌ ์‹œ RP2040 ๋‚ด์žฅ์˜ SIO(Single-cycle I/O) ํ•˜๋“œ์›จ์–ด FIFO๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์ธํ„ฐ๋ŸฝํŠธ ์˜ค๋ฒ„ํ—ค๋“œ ์—†์ด 1ํด๋ก ์ฃผ๊ธฐ ๋งŒ์— ์ฝ”์–ด ๊ฐ„ ๋ฉ”์„ธ์ง€๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
// Core 1: ์„ผ์„œ ๋ฐ์ดํ„ฐ ์ˆ˜์‹  ๋ฐ ๋™๊ธฐํ™” ๋ฃจํ‹ด
void core1_entry() {
    uint32_t last_read_idx = 0;

    while (1) {
        // DMA์˜ ํ˜„์žฌ ์“ฐ๊ธฐ ํฌ์ธํ„ฐ ๋ ˆ์ง€์Šคํ„ฐ ์ง์ ‘ ์กฐํšŒ
        uint32_t current_dma_write_addr = dma_hw->ch[dma_chan_a].write_addr;
        uint32_t current_idx = (current_dma_write_addr - (uint32_t)ring_buffer) / sizeof(uint32_t);

        if (current_idx != last_read_idx) {
            // [์ค‘์š”] ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด ํ˜ธ์ถœ: DMA๊ฐ€ SRAM์— ์“ด ๋ฐ์ดํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€์‹œ์„ฑ(Visibility) ๋ณด์žฅ
            __dmb();

            // ์„ผ์„œ ๋ฐ์ดํ„ฐ ์•ˆ์ „ ์ฒ˜๋ฆฌ
            process_sensor_data(&ring_buffer[last_read_idx]);

            // ์ฝ๊ธฐ ์ธ๋ฑ์Šค ์—…๋ฐ์ดํŠธ
            last_read_idx = (last_read_idx + 1) % RING_BUFFER_SIZE;
        }
    }
}

5. ์—ฃ์ง€ ์ผ€์ด์Šค ๋Œ€์‘ ๋ฐ ์‹ค์ „ ์ตœ์ ํ™” ํŒ ( Edge Cases)

๊ณ ์† ์ˆ˜์ง‘ ์‹œ์Šคํ…œ์„ ์žฅ์‹œ๊ฐ„ ์ž‘๋™์‹œํ‚ฌ ๋•Œ ์ง๋ฉดํ•  ์ˆ˜ ์žˆ๋Š” ์—ฃ์ง€ ์ผ€์ด์Šค์™€ ๊ทธ ๋Œ€์ฒ˜๋ฒ•์ž…๋‹ˆ๋‹ค.

  1. Flash Access ์ค‘๋‹จ(Stall) ๋ฐฉ์ง€: Core 0์ด๋‚˜ Core 1์ด Flash ๋ฉ”๋ชจ๋ฆฌ์— ์“ฐ๊ธฐ(Flash Erase/Program) ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ „์ฒด QSPI ๋ฒ„์Šค๊ฐ€ ์ฐจ๋‹จ๋˜์–ด ๋‘ ์ฝ”์–ด ๋ชจ๋‘ ์ •์ง€(Stall)ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ DMA๋งŒ ์ •์ƒ ์ž‘๋™ํ•˜๋ฉฐ, ๋ง๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋„๋ก Flash ์ž‘์—… ์‹œ ์ˆ˜์ง‘ ๋‹จ์œ„๋ฅผ ์งง๊ฒŒ ๋ถ„ํ• ํ•˜๊ฑฐ๋‚˜ ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ SRAM์— ์ƒ์ฃผ(__not_in_flash_func)์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. PIO Clock Divider ์ •๋ฐ€ ๋ถ„ํ• : pio_sm_set_clkdiv_int_frac()์„ ์ด์šฉํ•˜์—ฌ ๋ถ„์ฃผ๋น„๋ฅผ ์ •์ˆ˜ ๋ฐ ์†Œ์ˆ˜์  8๋น„ํŠธ ๋‹จ์œ„๋กœ ์ •๋ฐ€ํ•˜๊ฒŒ ์กฐ์ •ํ•จ์œผ๋กœ์จ ์„ผ์„œ์˜ ์ƒ˜ํ”Œ๋ง ํƒ€์ž„๊ณผ DMA ์ „์†ก ์†๋„ ๊ฐ„์˜ ๋ฏธ์„ธํ•œ ์ง€ํ„ฐ(Jitter)๋ฅผ ์™„๋ฒฝํžˆ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  3. PIO FDEBUG ๋ ˆ์ง€์Šคํ„ฐ ๋ชจ๋‹ˆํ„ฐ๋ง: ์ฃผ๊ธฐ์ ์œผ๋กœ pio->fdebug ๋ ˆ์ง€์Šคํ„ฐ์˜ RXOVER ๋น„ํŠธ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์—ฌ, HW ๋‹จ์—์„œ ๋น„์ •์ƒ์ ์ธ ์ž…๋ ฅ ํด๋ก ํญ์ฃผ๋กœ ์ธํ•œ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐœ์ƒ ์—ฌ๋ถ€๋ฅผ ์‹ค์‹œ๊ฐ„ ํƒ์ง€ํ•˜๋„๋ก ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํƒœ์Šคํฌ๋ฅผ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.



6. ๊ฒฐ๋ก  ๋ฐ ์š”์•ฝ

RP2040 ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ ํ™˜๊ฒฝ์—์„œ ์ดˆ๊ณ ์† ๋ณ‘๋ ฌ ์„ผ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์‹ค ์—†์ด ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹จ์ˆœํ•œ ์ฝ”๋“œ ์ž‘์„ฑ์„ ๋„˜์–ด ํ•˜๋“œ์›จ์–ด ๋‚ด ๋ฒ„์Šค ์•„ํ‚คํ…์ฒ˜, PIO DREQ handshaking, DMA ๋ง๋ฒ„ํผ, ๋ฉ€ํ‹ฐ์ฝ”์–ด ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด์— ๋Œ€ํ•œ ํ†ตํ•ฉ์ ์ธ ์ดํ•ด๊ฐ€ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ ์š”์ธ ๊ทผ๋ณธ ์›์ธ ์ตœ์ ํ™” ํ•ด๊ฒฐ์ฑ…
RX FIFO Overflow PIO FIFO ๊นŠ์ด ๋ถ€์กฑ(4 Words) ๋ฐ CPU ์ง€์—ฐ PIO DREQ ๊ธฐ๋ฐ˜ DMA ์ฒด์ด๋‹ / ๋ง๋ฒ„ํผ ๋„์ž…
Bus Contention DMA์™€ ๋“€์–ผ ์ฝ”์–ด๊ฐ€ ๋™์ผ SRAM ๋ฑ…ํฌ ๋™์‹œ ์ ‘๊ทผ SRAM0(DMA ์ „์šฉ) ๋ฐ SRAM1~2(Core ์ „์šฉ) ๋ถ„ํ•  ๋ฐฐ์น˜
Data Corruption ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ์žฌ๋ฐฐ์น˜ ๋ฐ ๊ฐ€์‹œ์„ฑ(Visibility) ๋ฏธ๋ณด์žฅ ARM ์–ด์…ˆ๋ธ”๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด(__dmb()) ์ ์šฉ

์œ„์—์„œ ์‚ดํŽด๋ณธ ํ•˜๋“œ์›จ์–ด ๋ ˆ๋ฒจ์˜ ์ตœ์ ํ™” ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ์ „๋žต์„ ์ ์šฉํ•˜๋ฉด, ์™ธ๋ถ€ FPGA๋‚˜ ๊ณ ๊ฐ€์˜ DSP ๋„์ž… ์—†์ด๋„ RP2040๋งŒ์œผ๋กœ ์ดˆ๋‹น ์ˆ˜๋ฐฑ๋งŒ ๊ฐœ์˜ ๊ณ ์† ์„ผ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹จ 1๋ฐ”์ดํŠธ์˜ ์œ ์‹ค๋„ ์—†์ด ์™„๋ฒฝํ•˜๊ณ  ์•ˆ์ •์ ์œผ๋กœ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•