ST/STM32F103C8

STM32F103C8 - ADC(DMA interrupt)

engineer4ever 2025. 8. 8. 10:29

 

MCU
STM32F103(ST)
IDE
Atollic(TrueSTUDIO), STM32CubeMX
목표
HAL driver를 사용하여 ADC를 여러개를 DMA interrupt mode로 주기적으로 multi conversion 한다.

 

1. STM32CubeMX : ADC-DMA 설정

- 'Pinout & Configuration' Tab으로 이동

1) Analog 선택

2) ADC1 항목 선택

 

- ADC Configuration 확인

ADC_Settings >

1) Scan Convsersion Mode : Enabled

여러 채널을 샘플링 하는 경우 scan 모드를 enable 하고 한개 채널만 샘플링 하는 경우 disable

2) Continous conversion mode : Enabled

3) Discontinous conversion mode : Disabled

 

ADC_Regular_Conversion Mode >

1) Enable Regular Conversions : Enable

2) Number of Conversion : 3

3) 각 Rank 별로 원하는 ADC 채널 선택

 

- DMA Settings 확인

1) DMA Request : ADC1

2) ADC1 and ADC2 global interrupts : Enabled에 체크

3)Data Width : Word(uint32_t), Half Word(uint16_t)

4)Mode : Normal(HAL_ADC_Start_DMA() 함수를 계속 호출해야 함),

Circular(HAL_ADC_Start_DMA() 함수를 최초에 한번만 호출하면 됨)

- GENERATE CODE 클릭


2. ATOLLIC : main.c 수정

- 변수 선언 ; CubeMX에서 Half Word(uint16_t)로 설정

/* USER CODE BEGIN 0 */
uint16_t adc_read[3] = {1, };
 

- HAL_ADC_Start_DMA 호출 ; CubeMX에서 DMA 설정을 Circular로 했기 때문에 1번만 호출해 주면됨(매번 호출할 필요 없음)

- DMA와 설정은 같으나, interrupt handler에서 주기적으로 읽어오기 위해 아래와 같은 방법을 사용합니다.

/* USER CODE BEGIN 2 */
HAL_ADC_Start_DMA(&hadc1,(uint16_t*)&(adc_read[0]),3);

/* USER CODE END 2 */
 

- ATOLLIC : stm32f1xx_it.c 수정

아래와 같이 작성하였는데 동일 값이 두번씩 중복되어 들어옴

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */

  /* USER CODE END DMA1_Channel1_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc1);
  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
	if(adc_flag == 1)
	{
		adc_read1[adc_index] = adc_read[0];
		adc_read2[adc_index] = adc_read[1];
		adc_read3[adc_index++] = adc_read[2];
		if(adc_index > 999) {
			adc_flag = 0;
		}
	}
  /* USER CODE END DMA1_Channel1_IRQn 1 */
}
 

- ATOLLIC : stm32f1xx_hal_dma.c 수정

- HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma) 함수 안으로 들어가 보면 Half Transfer인지 Full Trasfer인지 flag 확인하는 부분이 있는데 Full Trasfer안에 코드 작성

/* Transfer Complete Interrupt management ***********************************/
else if (((flag_it & (DMA_FLAG_TC1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_TC) != RESET))
{
	if(adc_flag == 1)
	{
		adc_read1[adc_index] = adc_read[0];
		adc_read2[adc_index] = adc_read[1];
		adc_read3[adc_index++] = adc_read[2];
		if(adc_index > 999) {
			adc_flag = 0;
		}
	}
 

- ADC를 DMA로 읽어오면서 굳이 interrupt안에서 짤 필요가 있나 생각할 수 있는데 필요에 의해 위와 같이 작성. 일반적인 상황에서는 DMA로 지정한 변수(adc_read)만 사용해도 충분함

 

 

'ST > STM32F103C8' 카테고리의 다른 글

STM32F103C8 - 1cycle Time  (0) 2025.08.08
STM32F103C8 - I2C HAL driver 오류  (0) 2025.08.08
STM32F103C8 - I2C(EEPROM)  (1) 2025.08.08
STM32F103C8 - RTC(Systick handler)  (0) 2025.08.08
STM32F103C8 - PWM  (0) 2025.08.08