Bare metal C Ch17 DMA - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
ํ ์ค ์์ฝ: DMA2 Stream0์ Memory-to-Memory mode๋ก uint16_t ๋ฐฐ์ด์ CPU ๋ณต์ฌ loop ์์ด ๋ค๋ฅธ ๋ฐฐ์ด๋ก ์ ์กํ๊ณ , ์๋ฃ interrupt๋ฅผ ์ฒ๋ฆฌํ๋ค.
DMA๋ CPU ๋์ data movement๋ฅผ ๋ด๋นํ๋ hardware block์ด๋ค.
CPU
โโ source / destination / length ์ค์
โ
DMA
โ
data transfer ์ํ
โ
interrupt๋ก ์๋ฃ ํต๋ณด
Peripheral โ Memory
Memory โ Peripheral
Memory โ Memory
์ด๋ฒ ์ค์ต์ ์ธ๋ถ ์ฅ์น ์์ด ๊ฒ์ฆ ๊ฐ๋ฅํ Memory-to-Memory๋ฅผ ์ฌ์ฉํ๋ค.
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๋ฐฐ์ด์ ์์ฐจ ๋ณต์ฌํ๋ฏ๋ก source์ destination ๋ชจ๋ address increment๋ฅผ ์ฌ์ฉํ๋ค.
MINC = 1
PINC = 1
g_transfer_cmplt๋ ISR์ด ๋ณ๊ฒฝํ๊ณ main loop๊ฐ ํ์ธํ๋ฏ๋ก ์ค์ ์ฝ๋์์๋ volatile๋ก ์ ์ธ๋์ด ์๋ค.
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๋ก ๊ฒฐ๊ณผ ์ถ๋ ฅ
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๋ฅผ ์ ๋ถ ๊ธฐ๋กํ๋ค.
#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
#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->CR = 0;
while ((DMA2_Stream0->CR & DMA_SCR_EN)) {}
DMA2_Stream0->CR |= (1U << 13);
DMA2_Stream0->CR &= ~(1U << 14);
DMA2_Stream0->CR |= (1U << 11);
DMA2_Stream0->CR &= ~(1U << 12);
DMA2_Stream0->CR |= DMA_SCR_MINC;
DMA2_Stream0->CR |= DMA_SCR_PINC;
DMA2_Stream0->CR &= ~(1U << 6);
DMA2_Stream0->CR |= (1U << 7);
DMA2_Stream0->CR |= DMA_SCR_TCIE;
DMA2_Stream0->CR |= DMA_SCR_TEIE;
DMA2_Stream0->FCR |= DMA_SFCR_DMDIS;
DMA2_Stream0->FCR |= (1U << 0);
DMA2_Stream0->FCR |= (1U << 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;
}
#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
#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->MODER &= ~(0x3UL << (8 * 2));
GPIOD->MODER |= (0x2UL << (8 * 2));
GPIOD->MODER &= ~(0x3UL << (9 * 2));
GPIOD->MODER |= (0x2UL << (9 * 2));
GPIOD->AFR[1] &= ~(0xFUL << 0);
GPIOD->AFR[1] |= (0x7UL << 0); /* PD8 -> AF7 (USART3_TX) */
GPIOD->AFR[1] &= ~(0xFUL << 4);
GPIOD->AFR[1] |= (0x7UL << 4); /* PD9 -> AF7 (USART3_RX) */
RCC->APB1ENR |= USART3EN;
uart_set_baudrate(APB1_CLK, DBG_UART_BAUDRATE);
USART3->CR1 = CR1_TE;
USART3->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);
}
#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 < 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->LISR) & LISR_TEIF0)
{
DMA2->LIFCR |= LIFCR_CTEIF0;
}
}
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๋ ๊ฐ๋ ๋ง ์ ๋ฆฌํ๊ณ ์ด ํ๋ก์ ํธ์์๋ ๊ตฌํํ์ง ์์๋ค๊ณ ๋ช ์ํ๋ค.
DMA๋ CPU ๋์ data movement๋ฅผ ์ํํ๋ค.
์ด๋ฒ ์ค์ต์ DMA2 Stream0 Memory-to-Memory transfer๋ค.
์ ์ก ์๋ฃ/์๋ฌ flag๋ ISR์์ ๊ฐ๊ฐ ์ฒ๋ฆฌํ๋ค.