| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- analogInput
- Queue
- 클래스
- STM32
- adc
- 임베디드
- LinkedList
- 컴포즈
- kotlin
- 큐
- STM32폴링
- Class
- Stack
- STM32GPIO
- Android
- 우송대
- 자료구조
- GPIO
- List
- 우송대학교
- 라즈베리파이 피코
- 아두이노
- MCU
- 안드로이드
- 스택
- 아날로그입력
- deque
- 코틀린
- STM32ADC
- analog
- Today
- Total
개발자의 생활
GPIO ADC_DMA(STM32G030F6P6) 본문
https://han-studio.tistory.com/79
GPIO ADC_이론 및 설정(STM32G030F6P6)
이번에는 STM32에 내장되어 있는 ADC를 사용해 보겠습니다. 1. ADC란ADC는 (Analog-to-Digital Converter)의 약자로 아날로그 신호를 디지털로 변환해 주는 장치입니다.2. ADC 과정Analog에서 Digital로 변환하는
han-studio.tistory.com
https://han-studio.tistory.com/80
GPIO ADC_폴링(STM32G030F6P6)
https://han-studio.tistory.com/79 GPIO ADC_이론 및 설정(STM32G030F6P6)이번에는 STM32에 내장되어 있는 ADC를 사용해 보겠습니다. 1. ADC란ADC는 (Analog-to-Digital Converter)의 약자로 아날로그 신호를 디지털로 변환해
han-studio.tistory.com
이전에는 ADC의 이론과 설정에 대해 알아보고, 폴링을 사용해서 아날로그 입력을 해보았습니다.
폴링을 사용했을 때는 변환이 될 때까지 CPU가 일을 하지 못하고 기다려야 했습니다. 하지만 DMA를 사용하면 CPU의 개입 없이 아날로그로 입력된 전압을 ADC가 변환한 데이터를 자동으로 레지스터에 들어가게 됩니다. 그래서 CPU는 변환된 데이터가 필요할 때는 레지스터에서 가져오기만 하면 됩니다.
그럼 먼저 DMA를 사용해서 ADC가 변환한 데이터를 자동으로 레지스터에 들어가도록 CubeMX에서 설정해 보겠습니다.
1. Pinout & Configuration 설정

핀 설정은 폴링과 거의 동일하지만 DMA Continuous Requests를 Enabled로 설정해주셔야 합니다.

이제 중요한 건 DMA 설정입니다. ADD를 클릭해서 DMA채널을 하나 추가한 뒤 DMA Request를 ADC로 설정해 주세요.
그리고 DMA Request Settings 설정에 대해 알아보겠습니다.
- Mode
- Circular
DMA의 버퍼가 다 차면 다시 처음으로 돌아가서 데이터를 덮어쓰게 됩니다. - Normal
DMA의 버퍼가 다 차면 끝나게 됩니다.
- Circular
- Increment Address
- Peripheral
MX자체에서 설정이 불가능합니다. - Memory
Enabled 시 저장할 메모리의 위치를 자동으로 한 칸씩 이동하게 됩니다.
(여러 채널의 ADC를 사용할 때 배열의 인덱스에 읽어온 순서대로 저장하게 됩니다)
- Peripheral
- Data Width
이는 DMA 한번 읽고 쓸 때의 데이터크기를 설정하는 부분입니다.- Byte: 8bit
- Haif Word: 16bit(ADC는 최대 DR이 16bit 이기 때문에 Haif Word으로 설정해 주시면 됩니다.)
- Word: 32bit(일부 고성능 MCU는 ADC의 분해능이 16bit를 넘을 수 있으므로 그런 경우에는 Word으로 설정해 주셔야 합니다.)
2. Clock & Configuration 설정
클럭 설정은 GPIO ADC_이론 및 설정과 동일하게 진행하겠습니다.
3_1. 코드
/* USER CODE BEGIN PV */
#define ADC_BUF_LEN 100
uint16_t adc_dma_buffer[ADC_BUF_LEN]; // ADC 값을 저장할 메모리 버퍼
uint32_t adc_sum = 0;
uint16_t adc_avg = 0;
/* USER CODE END PV */
ADC_BUF_LEN 상수를 100으로 정의합니다.
16bit 크기의 정수형 배열을 선언합니다.(DMA가 가져온 값을 담을 배열입니다.)
32bit 크기의 정수형 변수를 선언합니다.
16bit 크기의 정수형 변수를 선언합니다.
/* USER CODE BEGIN WHILE */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_dma_buffer, ADC_BUF_LEN);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
adc_sum = 0;
for(int i = 0; i < ADC_BUF_LEN; i++)
{
adc_sum += adc_dma_buffer[i];
}
adc_avg = adc_sum / ADC_BUF_LEN;
HAL_Delay(100); // 100ms 간격으로 확인
}
/* USER CODE END 3 */
위 코드에서 while 들어가기 전에 HAL_ADC_Start_DMA 함수를 호출하고 있습니다. 이 함수에는 adc의 주소와 데이터 버퍼용 배열, 버퍼크기를 파라미터로 받습니다.
이 함수가 호출되면 CPU와는 독립적으로 자동으로 adc가 읽어온 데이터를 배열에 담는 동작을 하게 됩니다.
저의는 그럼 필요할 때 adc_dma_buffer에 있는 값을 꺼내 쓰면 됩니다.
위 코드에서는 하나의 채널에 들어온 100개의 값을 평균을 내 비교적 정밀한 아날로그 입력 값을 읽도록 하였습니다.
2개 이상의 채널 값 구하기
읽어야 하는 아날로그 값이 2개 이상일 경우라도 간단하게 해결할 수 있습니다.

MX에서 Number Of Conversion에서 사용할 채널의 개수만큼 설정합니다.(저는 2개의 채널만 사용해 보겠습니다.)
그리고 MCU에서 원하는 GPIO핀에서 동일한 ADC로 채널을 추가합니다.
추가된 Rank에서 채널을 원하는 순서(ADC는 위 순서대로 값을 읽습니다.)에 맞게 설정을 합니다.
3_2. 코드
#define ADC_BUF_LEN 100
uint16_t adc_dma_buffer[ADC_BUF_LEN][2]; // ADC 값을 저장할 메모리 버퍼
uint32_t adc_sum1 = 0;
uint16_t adc_avg1 = 0;
uint32_t adc_sum2 = 0;
uint16_t adc_avg2 = 0;
이번에는 2차원 배열로 생성하였습니다. 버퍼의 크기와 채널 수만큼 방을 만들어서 담긴 adc 각 채널의 값을 구분하기 위함입니다.
/* USER CODE BEGIN WHILE */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_dma_buffer, ADC_BUF_LEN * 2);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
adc_sum1 = 0;
adc_sum2 = 0;
for(int i = 0; i < ADC_BUF_LEN; i++)
{
adc_sum1 += adc_dma_buffer[i][0];
adc_sum2 += adc_dma_buffer[i][1];
}
adc_avg1 = adc_sum1 / ADC_BUF_LEN;
adc_avg2 = adc_sum2 / ADC_BUF_LEN;
HAL_Delay(100); // 100ms 간격으로 확인
}
/* USER CODE END 3 */
HAL_ADC_Start_DMA 함수에서 변경된 부분은 버퍼 사이즈 * 채널수를 하였습니다.
(DMA입장에서는 각 채널마다 100번을 수행해야 하기 때문입니다.)
값을 읽을 때는 배열 인덱스의 순서대로 채널을 읽으면 됩니다. 여기서는 ADC가 채널 0, 채널 1 순서대로 변환을 수행하고 그 순서대로 DMA가 배열(버퍼)에 저장하기 때문입니다.
'STM32' 카테고리의 다른 글
| GPIO ADC_폴링(STM32G030F6P6) (0) | 2026.08.30 |
|---|---|
| GPIO ADC_이론 및 설정(STM32G030F6P6) (0) | 2026.08.21 |
| GPIO 입력_인터럽트[HAL](STM32G030F6P6) (0) | 2026.08.12 |
| GPIO 입력_폴링[HAL](STM32G030F6P6) (0) | 2026.08.10 |
| STM32 처음 시작 & GPIO 출력[HAL](STM32G030F6P6) (0) | 2026.08.08 |