Bare metal C Ch17 DMA - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki

Ch17. Direct Memory Access (DMA)

ํ•œ ์ค„ ์š”์•ฝ: DMA2 Stream0์˜ Memory-to-Memory mode๋กœ uint16_t ๋ฐฐ์—ด์„ CPU ๋ณต์‚ฌ loop ์—†์ด ๋‹ค๋ฅธ ๋ฐฐ์—ด๋กœ ์ „์†กํ•˜๊ณ , ์™„๋ฃŒ interrupt๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.

1. ํ•ต์‹ฌ ์ด๋ก 

DMA๋Š” CPU ๋Œ€์‹  data movement๋ฅผ ๋‹ด๋‹นํ•˜๋Š” hardware block์ด๋‹ค.

CPU
 โ””โ”€ source / destination / length ์„ค์ •
        โ†“
       DMA
        โ†“
 data transfer ์ˆ˜ํ–‰
        โ†“
 interrupt๋กœ ์™„๋ฃŒ ํ†ต๋ณด

์ „์†ก ๋ฐฉํ–ฅ

  • Peripheral โ†’ Memory

  • Memory โ†’ Peripheral

  • Memory โ†’ Memory

์ด๋ฒˆ ์‹ค์Šต์€ ์™ธ๋ถ€ ์žฅ์น˜ ์—†์ด ๊ฒ€์ฆ ๊ฐ€๋Šฅํ•œ Memory-to-Memory๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

ํ•ต์‹ฌ register

Register | ์—ญํ•  -- | -- DMA2_Stream0->CR | enable, direction, increment, size, interrupt NDTR | ์ „์†ก ๊ฐœ์ˆ˜ PAR | source address๋กœ ์‚ฌ์šฉ M0AR | destination address FCR | FIFO DMA2->LISR | status flags DMA2->LIFCR | flag clear

Increment

๋ฐฐ์—ด์„ ์ˆœ์ฐจ ๋ณต์‚ฌํ•˜๋ฏ€๋กœ source์™€ destination ๋ชจ๋‘ address increment๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

MINC = 1
PINC = 1

ISR ๊ณต์œ  ๋ณ€์ˆ˜

g_transfer_cmplt๋Š” ISR์ด ๋ณ€๊ฒฝํ•˜๊ณ  main loop๊ฐ€ ํ™•์ธํ•˜๋ฏ€๋กœ ์‹ค์ œ ์ฝ”๋“œ์—์„œ๋„ volatile๋กœ ์„ ์–ธ๋˜์–ด ์žˆ๋‹ค.

2. ๋™์ž‘ ํ๋ฆ„

sensor_data_arr[]
       โ”‚
       โ–ผ
 DMA2 Stream0
       โ”‚
       โ”œโ”€ 16-bit width
       โ”œโ”€ source increment
       โ”œโ”€ destination increment
       โ””โ”€ length = 5
       โ”‚
       โ–ผ
temp_data_arr[]
       โ”‚
       โ–ผ
Transfer Complete
       โ”‚
       โ–ผ
DMA2_Stream0_IRQHandler
       โ”‚
       โ–ผ
g_transfer_cmplt = 1
       โ”‚
       โ–ผ
UART๋กœ ๊ฒฐ๊ณผ ์ถœ๋ ฅ

3. ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ


Ch17_dma/

โ”œโ”€โ”€ Inc/dma.h

โ”œโ”€โ”€ Src/dma.c

โ”œโ”€โ”€ Inc/uart.h

โ”œโ”€โ”€ Src/uart.c

โ”œโ”€โ”€ Src/main.c

syscalls.c, sysmem.c, startup file, linker script, CubeIDE metadata/build output์€ Ch04์—์„œ ๋‹ค๋ฃฌ ๊ณตํ†ต ๊ธฐ๋ฐ˜์ด๋ฏ€๋กœ ์ด ํŽ˜์ด์ง€์—์„œ๋Š” ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ์•„๋ž˜์—๋Š” ์ด chapter ๊ธฐ๋Šฅ ๊ตฌํ˜„์— ์ง์ ‘ ์‚ฌ์šฉํ•œ source/header๋ฅผ ์ „๋ถ€ ๊ธฐ๋กํ•œ๋‹ค.

4. ์ „์ฒด ์ฝ”๋“œ

Inc/dma.h

#ifndef DMA_H__
#define DMA_H__

#include <stdint.h> #include "stm32f4xx.h"

#define LISR_TCIF0 (1U << 5) #define LIFCR_CTCIF0 (1U << 5) #define LISR_TEIF0 (1U << 3) #define LIFCR_CTEIF0 (1U << 3)

void dma2_mem2mem_config(void); void dma_transfer_start(uint32_t src_buff, uint32_t dest_buff, uint32_t len);

#endif

Src/dma.c

#include "dma.h"

#define DMA2EN (1U << 22) #define DMA_SCR_EN (1U << 0) #define DMA_SCR_MINC (1U << 10) #define DMA_SCR_PINC (1U << 9) #define DMA_SCR_TCIE (1U << 4) #define DMA_SCR_TEIE (1U << 2) #define DMA_SFCR_DMDIS (1U << 2)

void dma2_mem2mem_config(void) { RCC->AHB1ENR |= DMA2EN;

DMA2_Stream0-&gt;CR = 0;
while ((DMA2_Stream0-&gt;CR &amp; DMA_SCR_EN)) {}

DMA2_Stream0-&gt;CR |= (1U &lt;&lt; 13);
DMA2_Stream0-&gt;CR &amp;= ~(1U &lt;&lt; 14);

DMA2_Stream0-&gt;CR |= (1U &lt;&lt; 11);
DMA2_Stream0-&gt;CR &amp;= ~(1U &lt;&lt; 12);

DMA2_Stream0-&gt;CR |= DMA_SCR_MINC;
DMA2_Stream0-&gt;CR |= DMA_SCR_PINC;

DMA2_Stream0-&gt;CR &amp;= ~(1U &lt;&lt; 6);
DMA2_Stream0-&gt;CR |= (1U &lt;&lt; 7);

DMA2_Stream0-&gt;CR |= DMA_SCR_TCIE;
DMA2_Stream0-&gt;CR |= DMA_SCR_TEIE;

DMA2_Stream0-&gt;FCR |= DMA_SFCR_DMDIS;
DMA2_Stream0-&gt;FCR |= (1U &lt;&lt; 0);
DMA2_Stream0-&gt;FCR |= (1U &lt;&lt; 1);

NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

void dma_transfer_start(uint32_t src_buff, uint32_t dest_buff, uint32_t len) { DMA2_Stream0->PAR = src_buff; DMA2_Stream0->M0AR = dest_buff; DMA2_Stream0->NDTR = len; DMA2_Stream0->CR |= DMA_SCR_EN; }

Inc/uart.h

#ifndef UART_H
#define UART_H

#include "stm32f4xx.h"

void uart_init(void); void uart_write_string(const char *s); int __io_putchar(int ch);

#endif

Src/uart.c

#include <stdint.h>
#include "uart.h"

#define GPIODEN (1U << 3) #define USART3EN (1U << 18)

#define DBG_UART_BAUDRATE 115200U #define SYS_FREQ 16000000U #define APB1_CLK SYS_FREQ

#define CR1_TE (1U << 3) #define CR1_UE (1U << 13) #define SR_TXE (1U << 7)

static void uart_write(int ch); static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate); static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate);

int __io_putchar(int ch) { uart_write(ch); return ch; }

void uart_init(void) { RCC->AHB1ENR |= GPIODEN;

GPIOD-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (8 * 2));
GPIOD-&gt;MODER |=  (0x2UL &lt;&lt; (8 * 2));
GPIOD-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (9 * 2));
GPIOD-&gt;MODER |=  (0x2UL &lt;&lt; (9 * 2));

GPIOD-&gt;AFR[1] &amp;= ~(0xFUL &lt;&lt; 0);
GPIOD-&gt;AFR[1] |=  (0x7UL &lt;&lt; 0);   /* PD8 -&gt; AF7 (USART3_TX) */
GPIOD-&gt;AFR[1] &amp;= ~(0xFUL &lt;&lt; 4);
GPIOD-&gt;AFR[1] |=  (0x7UL &lt;&lt; 4);   /* PD9 -&gt; AF7 (USART3_RX) */

RCC-&gt;APB1ENR |= USART3EN;

uart_set_baudrate(APB1_CLK, DBG_UART_BAUDRATE);

USART3-&gt;CR1 = CR1_TE;
USART3-&gt;CR1 |= CR1_UE;

}

static void uart_write(int ch) { while (!(USART3->SR & SR_TXE)) { } USART3->DR = (ch & 0xFF); }

void uart_write_string(const char *s) { while (*s) uart_write((int)*s++); }

static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate) { return (uint16_t)((periph_clk + (baudrate / 2U)) / baudrate); }

static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate) { USART3->BRR = compute_uart_bd(periph_clk, baudrate); }

Src/main.c

#include <stdio.h>
#include "dma.h"

extern void uart_init(void);

#define BUFFER_SIZE 5

uint16_t sensor_data_arr[BUFFER_SIZE] = { 892, 731, 1234, 90, 23 }; uint16_t temp_data_arr[BUFFER_SIZE]; volatile uint8_t g_transfer_cmplt;

int main(void) { g_transfer_cmplt = 0;

uart_init();
dma2_mem2mem_config();

dma_transfer_start((uint32_t)sensor_data_arr, (uint32_t)temp_data_arr, BUFFER_SIZE);

while (!g_transfer_cmplt) {}

for (int i = 0; i &lt; BUFFER_SIZE; i++)
{
    printf("Temp buffer[%d]: %d\r\n", i, temp_data_arr[i]);
}

g_transfer_cmplt = 0;

while (1) {}

}

void DMA2_Stream0_IRQHandler(void) { if ((DMA2->LISR) & LISR_TCIF0) { g_transfer_cmplt = 1; DMA2->LIFCR |= LIFCR_CTCIF0; }

if ((DMA2-&gt;LISR) &amp; LISR_TEIF0)
{
    DMA2-&gt;LIFCR |= LIFCR_CTEIF0;
}

}

5. ์‹ค์Šต ๊ฒฐ๊ณผ

Notion ๊ธฐ๋ก ๊ธฐ์ค€ ์‹ค์ œ ๋ณด๋“œ ๊ฒ€์ฆ ์™„๋ฃŒ.

Source:

892, 731, 1234, 90, 23

UART ์ถœ๋ ฅ์—์„œ destination buffer๊ฐ€ ๋™์ผํ•˜๊ฒŒ ๋ณต์‚ฌ๋œ ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

Temp buffer[0]: 892
...
Temp buffer[4]: 23
text = 1640 bytes
data = 12 bytes
bss  = 2572 bytes
warning ์—†์Œ

Notion์—์„œ๋Š” ADC DMA์™€ UART DMA๋Š” ๊ฐœ๋…๋งŒ ์ •๋ฆฌํ•˜๊ณ  ์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜๋‹ค๊ณ  ๋ช…์‹œํ–ˆ๋‹ค.

6. ํ•ต์‹ฌ ์ •๋ฆฌ

  • DMA๋Š” CPU ๋Œ€์‹  data movement๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • ์ด๋ฒˆ ์‹ค์Šต์€ DMA2 Stream0 Memory-to-Memory transfer๋‹ค.

  • ์ „์†ก ์™„๋ฃŒ/์—๋Ÿฌ flag๋Š” ISR์—์„œ ๊ฐ๊ฐ ์ฒ˜๋ฆฌํ•œ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ