MCU
STM32F103(ST)
IDE
Atollic(TrueSTUDIO), STM32CubeMX
목표
LL driver를 사용하여 ADC를 DMA mode로 conversion 한다.

 

1. STM32CubeMX

- DMA, ADC LL driver 설정

 

- ADC Configuration 확인

ADC_Settings >

1) Scan Convsersion Mode : Disabled

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

2) Continous conversion mode : Disabled

3) Discontinous conversion mode : Disabled

 

ADC_Regular_Conversion Mode >

1) Enable Regular Conversions : Enable

2) Number of Conversion : 1

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

 

- DMA Settings 확인

1) DMA Request : ADC1

2) Data Width : Word(uint32_t)

3) Mode : Circular

- GENERATE CODE 클릭


2. ATOLLIC

- main.c 수정

uint32_t adc_val[20] = {1, };

LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_1);

LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1,
					  LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA),
					  (uint32_t)&adc_val, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 4);

LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1);

LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_1);

LL_ADC_REG_SetDMATransfer(ADC1,LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
LL_ADC_Enable(ADC1);

HAL_GPIO_WritePin (LED_WDT_GPIO_Port, LED_WDT_Pin, GPIO_PIN_RESET);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
	LL_ADC_REG_StartConversionSWStart(ADC1);
	printf("%d\n", adc_val[0]);
}
 
static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);

  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
  /**ADC1 GPIO Configuration
  PA2   ------> ADC1_IN2
  PC5   ------> ADC1_IN15
  PB0   ------> ADC1_IN8
  PB1   ------> ADC1_IN9
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  LL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_0|LL_GPIO_PIN_1;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* ADC1 DMA Init */

  /* ADC1 Init */
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);

  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);

  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);

  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);

  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_WORD);

  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_WORD);

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */
  /** Common config
  */
  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
  ADC_InitStruct.SequencersScanMode = LL_ADC_SEQ_SCAN_DISABLE;
  LL_ADC_Init(ADC1, &ADC_InitStruct);
  ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
  ADC_REG_InitStruct.SequencerLength = 1;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
  /** Configure Regular Channel
  */
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_15);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_15, LL_ADC_SAMPLINGTIME_55CYCLES_5);
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}
 

 

- stm32f1xx_it.c : DMA1_Channel1_IRQHandler(void) 수정

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
	 if( LL_DMA_IsActiveFlag_TC1(DMA1))
	 {
		  LL_DMA_ClearFlag_TC1(DMA1);
	 }
	 else if(LL_DMA_IsActiveFlag_TE1(DMA1))
	 {
	 	 LL_DMA_ClearFlag_TE1(DMA1);
	 }
  /* USER CODE END DMA1_Channel1_IRQn 0 */

  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */

  /* USER CODE END DMA1_Channel1_IRQn 1 */
}
 

 

- 실행 결과

 

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

STM32F103C8 - I2C LCD(SSD1306)  (0) 2025.08.08
STM32F103C8 - RAM 48KB + bonus?  (0) 2025.08.08
STM32F103C8 - 1cycle Time  (0) 2025.08.08
STM32F103C8 - I2C HAL driver 오류  (0) 2025.08.08
STM32F103C8 - ADC(DMA interrupt)  (1) 2025.08.08

 

CubeMX에서 pheriperal인 GPIO, USART, TIMER, PWM를 설정할때 기본이 HAL divrer로 설정된다.

하지만 HAL driver는 이식성을 좋게 하기 위해 용량이 커지고 코드 실행 시간이 길어진다. 그래서 코드 최적화 하여 코드 실행 시간을 줄일 수 있는 LL driver 설정 방법은 다음과 같다.

 

1. CubeMX 실행

 

2. CubeMX - Project Manager

 

3. CubeMX - Project Manager - Advanced Settings

: HAL 또는 LL driver 선택

'ST > 개발 환경 및 구조' 카테고리의 다른 글

ST MCU/MPU Security Features  (0) 2025.03.18
CMSIS  (0) 2025.03.18
STM32 Driver(Library)  (0) 2025.03.18
Linker Script(2) - 구조 및 설명  (0) 2025.03.17
Linker Script(1) - Segment  (0) 2025.03.17

 

보통 STM32를 F/W를 개발할 때 HAL(Hardware Abstraction Layer) driver를 사용하는데, 이 driver 말고도 아래와 같이 다양한 library가 있다.

https://www.st.com/content/ccc/resource/sales_and_marketing/presentation/product_presentation/37/55/ff/bc/a8/71/4f/c5/stm32_embedded_software_offering.pdf/files/stm32_embedded_software_offering.pdf/jcr:content/translations/en.stm32_embedded_software_offering.pdf

 

 

ST에서 제공하는 library는 아래와 같다.

1. STM32Snippets

2. STM32 Cube LL(low layer)

3. Standard Peripheral Library

4. STM32Cube HAL

X. Mbed Core(32비트 ARM Cortex-M 마이크로 컨트롤러 개발을 위한 인터넷 플랫폼 및 온라인 운영 체제)

 

 

1. STM32Snippets

STM32 주변 레지스터를 직접 기반으로 하는 코드 예제 모음

- Highly Optimized : 최적화

- Register Level Access : 이기 때문에

- Small code expressions : 코드 사이즈 최소화

- Lack of abstraction means developers must understand peripheral operation at register level

 

2. STM32 Cube LL(low layer)

- Highly Optimized : 최적화

- Register Level Access : 이기 때문에

- Small code expressions : 코드 사이즈 최소화

- Can work with STM32CubeMX to generate initialization code for STM32L0/F0/F3/L4

 

3. Standard Peripheral Library

STM32Cube 출시전의 library

- No need for direct register manipulation : 간접 제어

- 100% coverage of all peripherals

- Doesn’t support forward STM32 series starting with STM32 L0, L4 and F7 : 이제 지원 안함

 

4. STM32Cube HAL(Hardware abstraction layer)

MCU를 제어할 때, 내부 register를 직접 제어(심지어 bit 세팅) 해야 하지만, HAL Driver를 사용할 경우 Register 제어가 library화 되어 있어 쉬우며, CubeMX를 사용할 경우 그래픽으로 시각화 하여 몇가지 설정만으로 기본 소스 코를 자동 생성되므로 쉽게 설정이 가능

- High level and functional abstraction

- Easy port from one series to another

- 100% coverage of all peripherals

- Integrates complex middleware such as USB/TCP-IP/Graphics/Touch Sense/RTOS

- Can work with STM32CubeMX to generate initialization code

- Higher portability creates bigger software footprints or more time spent executing

adaptation code

 

X. Mbed Core

Mbed는 32비트 ARM Cortex-M 마이크로 컨트롤러 개발을 위한 인터넷 플랫폼 및 온라인 운영 체제

ARM Cortex-MX 계열의 코딩및 빌드를 위해 온라인상으로 IDE 및 컴파일을 제공

https://os.mbed.com/

 

Free open source IoT OS and development tools from Arm | Mbed

Mbed OS Mbed OS provides a well-defined API to develop your C++ application, plus free tools and thousands of code examples, libraries and drivers for common components. With a built-in security stack, core components such as storage, and several connectiv

os.mbed.com

 

아래는 ST에서 제공하는 library를 이식성, 최적화, 접근성, 가독성, 하드웨어 적용 범위를 비교한 표이다.

HAL driver는 이식성, 가독성, 하드웨어 적용 범위는 좋으나, 최적화는 좋지 않아, 최적화를 해야 할 경우 LL driver를 사용하기도 한다.

 

'ST > 개발 환경 및 구조' 카테고리의 다른 글

CMSIS  (0) 2025.03.18
STM32 CubeMX LL driver  (0) 2025.03.18
Linker Script(2) - 구조 및 설명  (0) 2025.03.17
Linker Script(1) - Segment  (0) 2025.03.17
ST 개발 보드 소개(2) - 32F746GDISCOVERY  (0) 2025.03.17

+ Recent posts