ADC1 User Description

P01의 PA1/CURRENT_SENSE → TIM2_CC2 경로와, P02의 PB0/ADC1_IN8 NTC → SWSTART 및 PA6/ADC1_IN6 AS5600 절대각 경로를 설명합니다.

1. 그림에서 먼저 보기

Figure 1의 번호는 아래 표의 같은 번호 행과 연결됩니다. P01은 PA1/ADC1_IN1과 TIM2_CC2를 사용합니다. P02는 PB0/IN8의 SWSTART 변환과 PA6/IN6의 AS5600 전압 측정을 사용합니다.

ADC regular conversion path where ADC_SQR3 controls the Analog MUX, with numbered callouts 1 2 3 4 5

Figure 1. ADC regular channel, TIM2 trigger, EOC, and ADC1_2 interrupt path

Source reconstruction: RM0008 ADC regular-group structure with the current implementation TIM2_CC2/IRQ overlay.

2. TIM2 event와 ADC interrupt timing

Figure 2는 Figure 1의 4번과 5번이 시간 순서로 어떻게 이어지는지 보여줍니다. CCR2 compare는 TIM2 CPU interrupt가 아니라 ADC regular conversion trigger입니다.

TIM2 CC2 event to ADC EOC and ADC1_2 interrupt timing

Figure 2. TIM2_CC2 → conversion → EOC → ADC1_2 IRQ → DR read

Current implementation event contract. ADC completion occurs in the same simulator tick; ADC_DR read clears EOC.

3. 블록 → 레지스터 비트

읽는 순서: 지원되는 항목을 먼저 확인하고, 미지원 항목은 문서 하단의 지원하지 않는 항목에서 확인합니다.

레지스터와 필드 / bit 열은 공식 RM0008 표기만 사용합니다. 현재 코드 값, PA1/CURRENT_SENSE 경로, 같은 tick 완료 같은 현재 구현의 단순화는 설명 칸에서 분리해 연결합니다.

그림 블록레지스터필드 / bit그림에서 하는 일 / 값 의미지원 여부
1Figure 1 PA1 → GPIO analog input 경로
GPIOA clock gateRCC_APB2ENRIOPAEN[2]그림 밖에서: GPIOA register block과 PA1 mode 설정 경로에 PCLK2를 공급합니다.0 = GPIOA clock 차단1 = GPIOA clock 공급ADC1_IN1 입력이 동작하려면 IOPAEN=1, ADC1EN=1, PA1 analog mode가 모두 필요합니다.지원됨
ADC1 clock gateRCC_APB2ENRADC1EN[9]그림 밖에서: ADC1 register block과 regular conversion 경로에 PCLK2를 공급합니다.0 = ADC1 clock 차단1 = ADC1 clock 공급이 gate는 ADC 경로를 활성화하지만 PA1의 GPIO mode나 regular channel을 대신 선택하지 않습니다.지원됨
PA1 analog modeGPIOA_CRLCNF1[7:6] / MODE1[5:4]그림에서: PA1 pad의 digital input/output driver를 끄고 ADC1_IN1 analog 경로를 엽니다.MODE1 = 00 input modeCNF1 = 00 analog inputCRL[7:4] = 0x0 PA1에 쓰는 완성된 4-bit 설정값다른 MODE/CNF 조합은 GPIO User Description의 공통 decoder 표에서 확인합니다.지원됨
2Figure 1 ADC_SQR3 → Analog MUX 채널 선택
Regular sequence slot 1ADC_SQR3SQ1[4:0]그림에서: regular sequence의 첫 번째 변환 channel을 지정해 Analog MUX가 해당 입력을 Sample & Hold로 전달하게 합니다.00000..10001 = ADC channel 0..1700001 = P01·P02 PA1 / ADC1_IN1 전류00110 = P02 PA6 / ADC1_IN6 AS560001000 = P02 PB0 / ADC1_IN8 NTC01001 = 공식 STM32 PB1 / ADC1_IN9 (현재 P02 미사용)10010..11111 = 예약값, 사용하지 않음P02 제공 코드는 SQ1을 1, 6, 8 순서로 설정하고, 각 SWSTART 뒤 EOC를 확인해 같은 ADC_DR에서 PA1 전류, AS5600, NTC 결과를 읽습니다.지원됨
3Figure 1 12-bit conversion → EOC / ADC_DR 갱신
Conversion completion boundaryADC_SR / ADC_DREOC[1] / DATA[15:0]그림에서: 12-bit conversion block이 PA1 sample을 ADC_DR에 기록하고 완료 상태를 ADC_SR.EOC로 넘깁니다.EOC 0 = 변환 미완료EOC 1 = 변환 완료DATA = 0..4095 우측 정렬된 12-bit 결과공식 DATA 필드는 bits 15:0입니다. 현재 구현은 bits 11:0에 결과를 저장하고 TIM2_CC2 trigger를 받은 같은 simulator tick에 EOC를 1로 만듭니다. EOC와 DATA의 owning read/status 동작은 5번에서 분리해 확인합니다.지원됨
4Figure 1 / 2 TIM2_CC2 event → ADC regular trigger
TIM2 clock gateRCC_APB1ENRTIM2EN[0]그림 밖에서: TIM2 counter에 peripheral clock을 공급해 compare event를 만들 수 있게 합니다.0 = TIM2 clock 차단, counter 정지1 = TIM2 clock 공급TIM2EN=0이면 CEN이 1이어도 현재 구현의 TIM2_CNT와 TIM2_CC2 event가 진행되지 않습니다.지원됨
Counter / compareTIM2_CR1 / TIM2_CCR2CEN[0] / CCR2[15:0]그림에서: counter를 진행시키고 CCR2 compare 지점에서 TIM2_CC2 event를 만듭니다.CEN 0 = counter 정지CEN 1 = counter 시작CCR2 = 0..65535 compare count현재 구현은 한 simulator tick 동안 CNT가 CCR2에 도달하거나 지나면 event를 기록합니다. 이 event는 TIM2 CPU interrupt가 아니라 ADC trigger입니다.지원됨
ADC power / enableADC_CR2ADON[0]그림 밖에서: ADC를 power-down 상태에서 활성화해 regular conversion 경로가 동작할 수 있게 합니다.0 = ADC 비활성화 / power-down1 = ADC 활성화실제 STM32F1은 처음 ADON=1 뒤 안정화·calibration 과정이 필요하고, 이미 1인 ADON에 다시 1을 쓰는 시작 방식도 있습니다. 현재 Trainer는 안정화·calibration과 ADON 재쓰기 시작을 모델링하지 않습니다. P01은 ADON=1을 TIM2_CC2 trigger 변환의 실행 gate로, P02는 SWSTART 변환의 실행 gate로 사용합니다.지원됨
Regular trigger selectADC_CR2EXTSEL[19:17] / EXTTRIG[20] / SWSTART[22]그림에서: regular conversion을 시작할 event를 선택하고 trigger 입력을 허용합니다.EXTSEL 000 = TIM1_CC1EXTSEL 001 = TIM1_CC2EXTSEL 010 = TIM1_CC3EXTSEL 011 = TIM2_CC2EXTSEL 100 = TIM3_TRGOEXTSEL 101 = TIM4_CC4EXTSEL 110 = EXTI11 / TIM8_TRGOEXTSEL 111 = SWSTARTEXTTRIG 0 = trigger 비활성화EXTTRIG 1 = trigger 활성화SWSTART 0 = software 시작 요청 없음SWSTART 1 = 선택한 regular channel 변환 1회 시작P01은 EXTSEL=011과 EXTTRIG=1을 사용합니다. P02는 위 ADON=1, EXTSEL=111, EXTTRIG=1 상태에서 SQ1=1, 6, 8 중 하나를 선택하고 SWSTART=1을 써서 한 번 변환합니다. Trainer는 시작 요청을 받으면 SWSTART를 0으로 clear합니다.지원됨
5Figure 1 / 2 EOC → ADC1_2 IRQ → ADC_DR read
Conversion complete statusADC_SREOC[1]그림에서: regular conversion 결과가 준비되었는지 알려 주는 하드웨어 상태 bit입니다.0 = 변환 미완료1 = 변환 완료, ADC_DR 결과 읽기 가능실제 STM32와 현재 구현 모두 software가 결과 상태를 읽는 bit입니다. 현재 구현에서는 ADC_DR read가 EOC를 clear합니다.지원됨
EOC interrupt gateADC_CR1EOCIE[5]그림에서: EOC[1] / EOCIE[5] checkpoint가 완료 상태를 ADC1_2 interrupt request로 넘길지 결정합니다.0 = EOC interrupt 비활성화1 = EOC interrupt 활성화현재 Trainer에서는 EOC=1과 EOCIE=1이면 ADC1_2 handler를 실행합니다.지원됨
Regular result readADC_DRDATA[15:0]그림에서: regular conversion의 data register를 읽습니다.0..4095 = 우측 정렬된 12-bit PA1/IN1, PA6/IN6, 또는 PB0/IN8 결과공식 field 범위는 DATA[15:0]이고 현재 구현 결과는 bits 11:0에 저장됩니다. ADC_DR read는 EOC를 clear하며, P02는 읽은 결과를 현재 SQ1 채널의 캐시에 저장합니다.지원됨

4. 데이터시트 필드 ↔ 현재 코드

현재 코드 / 값데이터시트 필드로 해석화면에서 확인
RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_ADC1ENIOPAEN[2] = 1, IOPBEN[3] = 1, ADC1EN[9] = 1: PA1·PA6·PB0 analog pad와 ADC1 register 경로를 엽니다.Registers > Clock에서 GPIOA/GPIOB/ADC1 gate ON
GPIOA->CRL &= ~(0xFu << 4)GPIOA_CRL.CNF1[7:6] = 00, MODE1[5:4] = 00; 해당 pin 설정 nibble은 CRL[7:4] = 0x0Board > Lab pin routes에서 PA1 analog ADC path
ADC_SQR3_SQ1_ADC1_IN1ADC_SQR3.SQ1[4:0] = 00001Registers > ADC_SQR3에서 SQ1 1
ADC1->SQR3 = 1, 6, 8
ADC1->DR
SQ1=1 → 6 → 8 순서로 각 채널마다 SWSTART → EOC → ADC_DR을 수행Board PA1/CURRENT_SENSE·PA6/ANGLE_SENSE·PB0/SYSTEM_TEMP, Registers와 Watch
P02: ADC1->CR2 = ADC_CR2_ADONADC_CR2.ADON[0] = 1: ADC를 활성화하고 P02 SWSTART 변환의 실행 gate를 엽니다.Registers > ADC_CR2에서 ADON bit 0 확인
ADC_CR2_EXTSEL_SWSTART | ADC_CR2_EXTTRIG
ADC1->CR2 |= ADC_CR2_SWSTART
EXTSEL[19:17] = 111, EXTTRIG[20] = 1, SWSTART[22] = 1: software 시작 경로를 선택·허용한 뒤 실제 regular conversion을 한 번 시작합니다.Registers > ADC_CR2와 Docs / Log의 SQ1 → SWSTART → EOC 순서
P01: ADC1->CR2 = ADC_CR2_EXTSEL_TIM2_CC2 | ADC_CR2_EXTTRIG
ADC1->CR2 |= ADC_CR2_ADON
ADON[0] = 1, EXTSEL[19:17] = 011, EXTTRIG[20] = 1: DC 모터 PA1 전류 ADC를 활성화하고 TIM2_CC2 event 시작 경로를 허용합니다. SWSTART는 사용하지 않습니다.Registers > ADC_CR2, Graph의 TIM2_CC2 marker, Docs / Log의 ADC sample event
ADC1_2_IRQHandlerADC_SR.EOC[1], ADC_CR1.EOCIE[5], ADC_DR.DATA[15:0]
현재 구현 result는 우측 정렬된 bits 11:0입니다.
Code Watch, Registers, Docs / Log

5. 현재 Trainer 실행 예제

각 주석의 번호는 위 블록 → 레지스터 비트 표와 연결됩니다. ADC_CR2_ADON은 ADC 활성화입니다. P01 DC 모터는 EXTSEL=011의 TIM2_CC2 event가 변환을 시작하고 SWSTART를 사용하지 않습니다. 아래 P02는 ADC_CR2_EXTSEL_SWSTART로 시작 방식을 선택하고 ADC_CR2_EXTTRIG로 경로를 허용한 뒤, ADC_CR2_SWSTART로 실제 한 번의 변환을 시작합니다. 이 설정은 변환 주기가 아닙니다. P02 실행 예제는 private ADC1->CR / DR_CH1 alias를 사용하지 않으며, sample cycle에 영향을 주지 않는 ADC_SMPR2도 제외했습니다.

#include "training_api.h"

#define ADC1_INPUT_CHANNEL_CURRENT 1u
#define ADC1_INPUT_CHANNEL_ANGLE 6u
#define ADC1_INPUT_CHANNEL_NTC 8u

static uint32_t adc1_pending_channel = ADC1_INPUT_CHANNEL_ANGLE;
static uint32_t pa1_current_raw_cache = 0u;
static uint32_t pa6_angle_raw_cache = 2048u;
volatile uint32_t g_ntc_adc_raw = 0u;
volatile uint32_t g_ntc_sample_ready = 0u;

static void gpio_init(void)
{
    GPIOA->CRL = 0x40422B00u; /* GPIO User Description 4번: PA1·PA6 analog input */
    GPIOB->CRL = 0x44444440u; /* GPIO User Description 4번: PB0 analog input */
}

static void adc1_start_channel(uint32_t channel)
{
    ADC1->SQR3 = channel;               /* ADC User Description 2번: 다음 변환 채널 선택 */
    ADC1->CR2 |= ADC_CR2_SWSTART;       /* ADC User Description 4번: 실제 변환 1회 시작. 실제로 한 번 시작합니다. */
}

static void adc_init(void)
{
    ADC1->CR1 = 0u;                          /* ADC User Description 5번: EOCIE=0, polling 사용 */
    ADC1->CR2 = ADC_CR2_ADON;                /* ADC User Description 4번: P02 software start 전제 */
    ADC1->CR2 |= ADC_CR2_EXTSEL_SWSTART;     /* ADC User Description 4번: SWSTART 방식 선택 */
    ADC1->CR2 |= ADC_CR2_EXTTRIG;            /* ADC User Description 4번: 시작 경로 허용, 주기 설정 아님. 주기 설정이 아닙니다. */

    adc1_pending_channel = ADC1_INPUT_CHANNEL_ANGLE;
    adc1_start_channel(ADC_SQR3_SQ1_ADC1_IN6);
}

static void adc_service(void)
{
    uint32_t raw;

    if ((ADC1->SR & ADC_SR_EOC) == 0u) return; /* ADC User Description 3·5번: 완료 확인 */

    raw = ADC1->DR; /* ADC User Description 3·5번: 결과 read, EOC clear */
    if (adc1_pending_channel == ADC1_INPUT_CHANNEL_ANGLE)
    {
        pa6_angle_raw_cache = raw;
        adc1_pending_channel = ADC1_INPUT_CHANNEL_NTC;
        adc1_start_channel(ADC_SQR3_SQ1_ADC1_IN8);
    }
    else if (adc1_pending_channel == ADC1_INPUT_CHANNEL_NTC)
    {
        g_ntc_adc_raw = raw;
        g_ntc_sample_ready = 1u;
        adc1_pending_channel = ADC1_INPUT_CHANNEL_CURRENT;
        adc1_start_channel(ADC_SQR3_SQ1_ADC1_IN1);
    }
    else
    {
        pa1_current_raw_cache = raw;
        adc1_pending_channel = ADC1_INPUT_CHANNEL_ANGLE;
        adc1_start_channel(ADC_SQR3_SQ1_ADC1_IN6);
    }
}

void user_init(void)
{
    trainer_clock_init_72mhz();               /* RCC User Description 1~4번: 72 MHz clock 경로 */
    RCC->APB2ENR = RCC_APB2ENR_AFIOEN;       /* P02 공통 Port API의 AFIO gate */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;      /* ADC User Description 1번: GPIOA gate */
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;      /* P02 PB0/ADC1_IN8용 GPIOB gate */
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;      /* ADC User Description 1번: ADC1 gate */
    gpio_init();                              /* ADC input pad 전제: GPIO User Description 4번 */
    adc_init();                               /* ADC User Description 2·4·5번 설정 */
}

void user_loop(void)
{
    adc_service(); /* ADC User Description 2~5번 변환 흐름 */
    watch_u32("angle_adc_raw", pa6_angle_raw_cache); /* PA6/IN6 결과 cache */
    watch_u32("g_ntc_adc_raw", g_ntc_adc_raw);       /* PB0/IN8 결과 cache */
    watch_u32("g_ntc_sample_ready", g_ntc_sample_ready);
    watch_u32("adc1_pending_channel", adc1_pending_channel);
    watch_u32("current_adc_raw", pa1_current_raw_cache);
    watch_u32("ADC_SQR3", ADC1->SQR3);
}

6. 사이트에서 확인

바로 위 실행 예제로 SQ1=1/6/8 순환 polling과 각 채널의 Watch 값을 확인합니다.

7. 지원하지 않는 항목

항목공식 STM32 의미현재 구현 경계지원 여부
ADC_SMPR2.SMP1ADC1_IN1 sample cycle 선택필드 값의 저장·표시는 가능하지만 sample cycle이나 conversion latency에는 반영되지 않습니다. 현재 실행 예제에서는 사용하지 않습니다.미지원
Watchdog / injected / DMA / internal channelsfull ADC1 peripheral 기능현재 화면에 없는 기능이므로 primary figure/table/code에 넣지 않습니다.미지원

ADC_SMPR2 sample cycle, calibration, continuous/scan mode, injected conversion, DMA, analog watchdog, internal temperature sensor, VREFINT는 공식 ADC1 Datasheet에서 Reference-only로 확인합니다. 현재 Trainer에서 ADON은 P01 TIM2_CC2 전류 측정 경로와 P02 SWSTART 센서 경로의 공통 실행 gate입니다. 변환 시작 event는 P01의 TIM2_CC2와 P02의 SWSTART로 구분합니다.