아두이노 UNO R4는 Renesas RA4M1 마이크로컨트롤러를 기반으로 하며, **DMA(Direct Memory Access)**를 통해 CPU 개입 없이 고속 데이터 전송을 지원합니다. 이 가이드는 UART를 이용한 DMA 설정을 중심으로, Renesas의 FSP(Flexible Software Package)와 레지스터 직접 설정 방법을 상세히 설명합니다. 초보자도 따라 할 수 있도록 단계별로 구성했으며, 디버깅 팁과 레지스터 설정의 주의점을 포함했습니다.
DMA와 DTC란?
- DMA(Direct Memory Access): CPU 없이 메모리 간 데이터를 전송하는 하드웨어 모듈입니다. RA4M1은 4개의 DMAC 채널을 제공하며, UART, SPI, ADC 등과 연동 가능합니다.
- DTC(Data Transfer Controller): 이벤트 기반 전송을 지원하며, 인터럽트 트리거로 데이터를 전송합니다.
- 차이점: DMAC는 고속/대량 전송에 최적화, DTC는 특정 이벤트(예: ADC 완료)에 적합합니다.
준비물
- 하드웨어:
- 아두이노 UNO R4 Minima 또는 WiFi
- USB-C 케이블
- 테스트용 장치(예: 시리얼 터미널 또는 외부 UART 장치)
- 소프트웨어:
- 아두이노 IDE (2.x 이상)
- Arduino UNO R4 Boards 패키지 (보드 매니저에서 설치)
- Renesas FSP (선택 사항, DMA 설정 간소화)
- RA4M1 데이터시트 (레지스터 설정 참고)
- 지식:
- 기본적인 아두이노 프로그래밍
- UART, SPI, ADC 등 주변 장치 이해
- 레지스터 조작 기본 (선택 사항)
DMA 설정 단계
아두이노 UNO R4에서 DMA를 설정하려면 아래와 같이 두 가지 접근법이 있습니다:
- FSP 사용: 고수준 API로 간편하게 설정.
- 레지스터 직접 설정: RA4M1의 DMAC 레지스터를 직접 조작.
아래는 UART를 통해 DMA를 설정하는 과정을 두 방법 모두로 설명합니다.
1. 개발 환경 설정
1.1 아두이노 IDE 설정
- 아두이노 IDE 설치:
- 최신 버전(2.x 이상)을 다운로드합니다.
- 보드 매니저에서 "Arduino UNO R4 Boards"를 검색해 설치합니다.
- 도구 > 보드 > Arduino UNO R4 Minima 또는 WiFi를 선택합니다.
- 시리얼 포트 확인:
- UNO R4를 USB-C로 연결하고, 도구 > 포트에서 올바른 포트를 선택합니다.
1.2 FSP 통합 (권장)
FSP는 DMA 설정을 간소화합니다. 설정 방법:
- FSP 다운로드:
- Renesas FSP 페이지에서 최신 버전을 다운로드합니다.
- FSP는 e² studio와 통합되지만, 아두이노 IDE에서도 헤더 파일을 활용 가능합니다.
- FSP 설정:
- FSP 설정 툴에서 UART(SCI0)와 DMAC를 활성화합니다.
- UART 설정: r_sci_uart.h에서 SCI_UART_CFG_DTC_SUPPORTED 활성화.
- DMAC 설정: r_dmac.h에서 채널 및 트리거 구성.
- 아두이노 통합:
- FSP에서 생성된 파일(hal_data.c, hal_data.h 등)을 아두이노 프로젝트 폴더에 추가.
- 아두이노 IDE에서 *.c와 *.h 파일을 인식하도록 스케치에 포함.
1.3 레지스터 직접 설정 준비
레지스터 접근은 FSP 없이 DMAC를 설정하는 방법입니다. 준비 단계:
- 데이터시트 확인:
- RA4M1 데이터시트의 DMAC 섹션(섹션 15)과 SCI UART 섹션(섹션 22)을 참고.
- 레지스터 목록:
- DMAC 관련 레지스터:
- DMACn.DMSAR: 소스 주소
- DMACn.DMDAR: 목적지 주소
- DMACn.DMCRA: 전송 카운트
- DMACn.DMCRB: 블록/반복 설정
- DMACn.DMSTS: 상태 및 활성화
- DMA.DMAST: DMAC 활성화
- SCI UART 관련 레지스터:
- SCIn.SCR: SCI 제어 레지스터
- SCIn.TDR: 전송 데이터 레지스터
- DMAC 관련 레지스터:
- 주의점:
- 레지스터 접근은 실수 시 시스템 충돌 가능성이 있으므로, 디버깅 도구(SWD) 사용을 권장.
- 인터럽트 설정(ICU.IELSR)과 클럭 설정(MSTP)을 반드시 확인.
2. UART와 DMA 연동 (FSP 사용)
UART 데이터를 DMA로 전송하는 예제를 통해 FSP 기반 설정을 먼저 살펴보겠습니다.
2.1 FSP 예제 코드
아래 코드는 "Hello, DMA!"를 시리얼 모니터로 전송합니다.
#include <Arduino.h>
#include <r_sci_uart.h>
#include <r_dmac.h>
// 전송 버퍼 정의
#define BUFFER_SIZE 256
uint8_t tx_buffer[BUFFER_SIZE] = "Hello, DMA on UNO R4!\n";
volatile bool tx_done = false;
// UART 및 DMAC 설정 구조체 (FSP에서 생성)
extern sci_uart_instance_ctrl_t g_uart0_ctrl;
extern const uart_cfg_t g_uart0_cfg;
extern dmac_instance_ctrl_t g_dmac0_ctrl;
extern const dmac_cfg_t g_dmac0_cfg;
void setup() {
// UART 초기화
fsp_err_t err = R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg);
if (err != FSP_SUCCESS) {
Serial.println("UART 초기화 실패!");
while (1);
}
// DMAC 초기화
err = R_DMAC_Open(&g_dmac0_ctrl, &g_dmac0_cfg);
if (err != FSP_SUCCESS) {
Serial.println("DMAC 초기화 실패!");
while (1);
}
// DMAC 설정: 소스(tx_buffer) -> 목적지(UART)
err = R_DMAC_Configure(&g_dmac0_ctrl, (void *)tx_buffer, BUFFER_SIZE, &g_uart0_ctrl);
if (err != FSP_SUCCESS) {
Serial.println("DMAC 설정 실패!");
while (1);
}
}
void loop() {
if (!tx_done) {
// DMA 전송 시작
R_DMAC_Start(&g_dmac0_ctrl);
while (!tx_done) {} // 전송 완료 대기
Serial.println("전송 완료!");
tx_done = true;
delay(1000); // 1초 대기 후 재전송
}
}
// DMA 전송 완료 콜백
void dmac_callback(dmac_callback_args_t *p_args) {
tx_done = true;
}
2.2 FSP 설정
- UART (SCI0):
- Baudrate: 115200
- 인터럽트: TXI (전송 인터럽트) 활성화
- DMAC 지원: 활성화
- DMAC:
- 채널: DMAC0
- 소스: tx_buffer
- 목적지: SCI0.TDR (전송 데이터 레지스터)
- 모드: Normal 전송
- 인터럽트: 전송 완료 시 콜백 호출
3. UART와 DMA 연동 (레지스터 직접 설정)
FSP 없이 DMAC를 설정하려면 RA4M1의 레지스터를 직접 조작해야 합니다. 아래는 UART(SCI0)를 통해 DMA로 데이터를 전송하는 예제입니다.
3.1 레지스터 설정 과정
- 시스템 클럭 활성화:
- DMAC와 SCI0 모듈을 활성화하기 위해 MSTP(Module Stop) 레지스터 설정.
- MSTPCRA에서 DMAC 활성화, MSTPCRD에서 SCI0 활성화.
- UART(SCI0) 설정:
- SCIn.SCR: 전송 활성화, 인터럽트 설정.
- SCIn.SMR: 통신 모드(비동기), 데이터 길이 등 설정.
- SCIn.BRR: Baudrate 설정.
- DMAC 설정:
- DMACn.DMSAR: 소스 주소 (tx_buffer).
- DMACn.DMDAR: 목적지 주소 (SCI0.TDR).
- DMACn.DMCRA: 전송 크기.
- DMACn.DMCRB: 전송 모드 (Normal/Block).
- DMACn.DMSTS: DMAC 활성화 및 상태.
- 인터럽트 설정:
- ICU.IELSR: DMAC 전송 완료 인터럽트를 설정.
- NVIC 활성화로 콜백 처리.
3.2 레지스터 기반 예제 코드
#include <Arduino.h>
// RA4M1 레지스터 정의 (데이터시트 기반)
#define MSTPCRA (*(volatile uint32_t *)0x4001E400) // 모듈 스탑 제어 A
#define MSTPCRD (*(volatile uint32_t *)0x4001E404) // 모듈 스탑 제어 D
#define SCI0_SMR (*(volatile uint8_t *)0x40070000) // SCI0 모드 레지스터
#define SCI0_BRR (*(volatile uint8_t *)0x40070001) // SCI0 Baudrate 레지스터
#define SCI0_SCR (*(volatile uint8_t *)0x40070002) // SCI0 제어 레지스터
#define SCI0_TDR (*(volatile uint8_t *)0x40070003) // SCI0 전송 데이터 레지스터
#define DMAC0_DMSAR (*(volatile uint32_t *)0x40005000) // DMAC0 소스 주소
#define DMAC0_DMDAR (*(volatile uint32_t *)0x40005004) // DMAC0 목적지 주소
#define DMAC0_DMCRA (*(volatile uint32_t *)0x40005008) // DMAC0 전송 카운트
#define DMAC0_DMCRB (*(volatile uint16_t *)0x4000500C) // DMAC0 모드
#define DMAC0_DMSTS (*(volatile uint8_t *)0x40005012) // DMAC0 상태
#define DMA_DMAST (*(volatile uint8_t *)0x40005200) // DMAC 활성화
// 전송 버퍼
#define BUFFER_SIZE 256
uint8_t tx_buffer[BUFFER_SIZE] = "Hello, DMA on UNO R4!\n";
volatile bool tx_done = false;
void setup() {
// 1. 모듈 활성화
MSTPCRA &= ~(1 << 21); // DMAC 활성화
MSTPCRD &= ~(1 << 4); // SCI0 활성화
// 2. UART(SCI0) 설정
SCI0_SMR = 0x00; // 비동기 모드, 8비트 데이터, 패리티 없음
SCI0_BRR = 25; // 115200 baudrate (48MHz 클럭 기준)
SCI0_SCR = 0x40; // 전송 활성화, 수신 비활성화, TXI 인터럽트 활성화
// 3. DMAC0 설정
DMAC0_DMSAR = (uint32_t)tx_buffer; // 소스 주소
DMAC0_DMDAR = (uint32_t)&SCI0_TDR; // 목적지 주소 (SCI0.TDR)
DMAC0_DMCRA = BUFFER_SIZE; // 전송 바이트 수
DMAC0_DMCRB = 0x0000; // Normal 모드
DMAC0_DMSTS = 0x00; // 초기 상태
// 4. DMAC 활성화
DMA_DMAST |= (1 << 0); // DMAC 모듈 활성화
DMAC0_DMSTS |= (1 << 7); // DMAC0 채널 활성화
// 5. 인터럽트 설정 (선택 사항)
// NVIC_EnableIRQ(DMAC0_INT_IRQn); // 전송 완료 인터럽트 활성화
}
void loop() {
if (!tx_done) {
DMAC0_DMSTS |= (1 << 6); // DMA 전송 시작
while (!tx_done) {} // 전송 완료 대기
Serial.println("전송 완료!");
tx_done = true;
delay(1000); // 1초 대기 후 재전송
}
}
// DMAC0 인터럽트 핸들러 (선택 사항)
void DMAC0_INT_IRQHandler(void) {
tx_done = true;
DMAC0_DMSTS &= ~(1 << 6); // 전송 상태 초기화
}
3.3 코드 설명
- 모듈 활성화:
- MSTPCRA, MSTPCRD: DMAC와 SCI0의 클럭을 활성화.
- UART 설정:
- SCI0_SMR: 비동기, 8비트, 패리티 없음.
- SCI0_BRR: 48MHz 클럭 기준 115200 baudrate (계산: BRR = (PCLK / (64 * Baudrate)) - 1).
- SCI0_SCR: 전송 활성화 및 TXI 인터럽트 설정.
- DMAC 설정:
- DMAC0_DMSAR: 소스 주소 (tx_buffer).
- DMAC0_DMDAR: 목적지 주소 (SCI0.TDR).
- DMAC0_DMCRA: 전송 바이트 수.
- DMAC0_DMCRB: Normal 모드.
- DMAC0_DMSTS: DMAC 활성화 및 전송 시작.
- 인터럽트:
- 전송 완료 시 DMAC0_INT_IRQHandler가 호출되어 tx_done 설정.
- 인터럽트는 선택 사항이며, 폴링 방식으로도 상태 확인 가능.
3.4 레지스터 설정 주의점
- 주소 정렬: DMSAR, DMDAR는 32비트 정렬된 주소를 요구할 수 있음.
- 클럭 확인: RA4M1의 PCLK(48MHz)와 설정이 일치해야 함.
- 인터럽트 충돌: 동일한 IRQ를 다른 모듈과 공유하지 않도록 ICU.IELSR 확인.
- 데이터시트 필수: RA4M1 데이터시트의 DMAC(섹션 15)와 SCI(섹션 22)를 반드시 참고.
4. DTC 설정 (대안)
DTC는 DMAC보다 간단한 이벤트 기반 전송을 지원합니다. 예를 들어, UART 전송 완료 시 데이터를 이동하도록 설정 가능.
4.1 DTC 예제 코드
#include <Arduino.h>
#include <r_dtc.h>
// DTC 설정 구조체 (FSP에서 생성)
extern dtc_instance_ctrl_t g_dtc0_ctrl;
extern const dtc_cfg_t g_dtc0_cfg;
void setup() {
// DTC 초기화
fsp_err_t err = R_DTC_Open(&g_dtc0_ctrl, &g_dtc0_cfg);
if (err != FSP_SUCCESS) {
Serial.println("DTC 초기화 실패!");
while (1);
}
// DTC 활성화
R_DTC_Enable(&g_dtc0_ctrl);
}
void loop() {
// DTC는 이벤트(예: UART 전송 완료) 발생 시 자동 전송
}
4.2 DTC 설정
- FSP에서 설정:
- 모듈: DTC
- 트리거: SCI0_TXI (UART 전송 완료 인터럽트)
- 소스/목적지: 메모리 또는 주변 장치
- 특징: DTC는 DMAC보다 설정이 간단하며, 이벤트 트리거에 의존.
5. 디버깅 및 문제 해결
5.1 FSP 디버깅
- 에러 코드: R_DMAC_Open, R_SCI_UART_Open의 fsp_err_t 값을 확인.
- 시리얼 출력: Serial.println으로 상태 출력.
- FSP 로그: FSP 디버그 로그 활성화.
5.2 레지스터 디버깅
- 레지스터 확인: DMACn.DMSTS로 전송 상태 확인.
- SWD 디버깅: UNO R4의 SWD 포트로 레지스터 값 모니터링.
- 문제 원인:
- 잘못된 주소 설정 (DMSAR, DMDAR).
- 클럭 비활성화 (MSTPCRA, MSTPCRD).
- 인터럽트 충돌 (ICU.IELSR).
5.3 흔한 문제
- 데이터 전송 안 됨: 소스/목적지 주소 오류, 인터럽트 비활성화.
- 시스템 멈춤: 잘못된 레지스터 설정으로 인터럽트 루프 발생.
- FSP 오류: 헤더 파일 경로 문제.
6. 응용 사례
- ADC와 DMA: ADC 데이터를 메모리로 전송.
- 트리거: ADC 완료 인터럽트.
- 예: 센서 데이터 수집.
- SPI와 DMA: 대량의 SPI 데이터 전송.
- 트리거: SPI TXI/RXI 인터럽트.
- UART와 DMA: 비블록킹 시리얼 데이터 전송.
- 예: 로그 데이터 전송.
7. 주의사항
- 호환성: UNO R4는 RA4M1 기반으로, UNO R3 라이브러리와 호환되지 않을 수 있음.
- FSP 의존성: 아두이노 코어는 DMA를 직접 지원하지 않으므로, FSP 또는 레지스터 설정 필요.
- 레지스터 복잡성: 레지스터 접근은 오류 가능성이 높으므로, 데이터시트를 꼼꼼히 확인.
- 전원 안정성: DMA는 고속 동작으로 전원 안정성 확인 필수.
추가 자료
- Renesas FSP 문서: FSP 가이드.
- RA4M1 데이터시트: Renesas 웹사이트.
- Arduino 포럼: 포럼에서 DMA 관련 질문 검색.
- YouTube: "Arduino UNO R4 DMA Tutorial"로 검색.
https://www.youtube.com/watch?v=GLSrd_NXoj0
마무리
아두이노 UNO R4에서 DMA를 설정하려면 FSP를 사용하거나 레지스터를 직접 조작할 수 있습니다. 이 가이드의 UART 예제를 따라 설정해보고, 다른 주변장치들 ADC나 SPI로 확장해보세요.