Analog-to-digital converterADC1 Chapter

ADC1 Register Reference Chapter

Official register map, bit fields, and the modeled PA1 / CURRENT_SENSE path

ADC User Description: TIM2 event, EOC, and ADC1_2 interrupt route

Document ID
ADC1-DS002
Revision
Rev 3.2
Official ADC1 base
0x40012400
Scope
STM32-style concepts + simulated subset
The official STM32F103 ADC1 block starts at 0x40012400. Section 4 reproduces the complete RM0008 ADC register map. Section 5 expands five executable official-layout registers: ADC_SR, ADC_CR1, ADC_CR2, ADC_SQR3, and ADC_DR. It also documents ADC_SMPR2 as an internally stored reference register that is stored without a modeled sample-cycle timing side effect. Private ADC1_CR/DR_CH0/DR_CH1 names are Trainer compatibility aliases retained for earlier lessons, not STM32F103 registers. The System Trainer uses the official regular-conversion path to read the PB0 / ADC1_IN8 NTC divider and, when Feedback=POSITION, PA6 / ADC1_IN6: firmware alternates SQ1=8 and SQ1=6, issues SWSTART, waits for EOC, and reads ADC_DR. PA10 / USART1_RX remains a separate UART input.

Contents

  1. General description
  2. Main features
  3. Reference figures and tables
  4. Official ADC1 register map
  5. Modeled register descriptions
  6. Trainer contract and legacy boundary

1 General description

ADC1 converts an analog input voltage into a 12-bit digital result. The ADC path is GPIO analog input -> ADC_SQR3-selected Analog MUX -> Sample & Hold -> ADC converter -> ADC_DR, with status and transfer helpers such as EOC, DMA, and Analog watchdog around that path.

A GPIO pin is the physical analog pad, while the ADC channel number is the selector value that tells the regular sequencer and Analog MUX which input to forward. For example, PA1 maps to ADC1_IN1, while other package pins map to different ADC channel numbers. The channel selection logic controls the MUX; it is not another signal-processing stage after it.

In the current motor-driver trainer lab, PA1 carries the CURRENT_SENSE signal. That fixed implemented route is separate from full STM32-style multiplexed channel coverage.

2 Main features

2.1 Official STM32-style concepts

  • 12-bit unsigned conversion result, 0 .. 4095
  • Official STM32F103 analog input range: 0 V .. VREF+; VREF+ ≤ VDDA, with VDDA = 2.4 V .. 3.6 V
  • Regular conversion, single-shot, continuous mode, and scan mode
  • Channel order configured through ADC_SQR1 and ADC_SQR3
  • Sample time configured through ADC_SMPR1 and ADC_SMPR2
  • End-of-conversion status in ADC_SR.EOC
  • DMA request support and analog watchdog thresholds
  • Temperature sensor and VREFINT internal channels

2.2 Currently simulated subset

  • Fixed implemented channel for PA1 / ADC1_IN1 / CURRENT_SENSE
  • Official-layout regular path through ADC_SQR3, ADC_CR1/CR2, ADC_SR, and ADC_DR
  • TIM2_CC2 trigger, EOC, ADC1_2 interrupt, and DR-read EOC clear behavior
  • Private ADC1_CR/DR_CH0/DR_CH1 aliases retained only for legacy lessons; PB0 channel 8 and selectable PA6 channel 6 use the official regular path
  • Common PA1 / CURRENT_SENSE uses the Trainer's 3.3 V ADC reference: 0.0 V .. 3.3 V maps to 0 .. 4095
  • GPIO analog-input setup should still be taught for realism through GPIOA->CRL

3 Reference figures and tables

Reconstructed regular conversion ADC block diagram showing ADC_SQR3 control of the Analog MUX, based on RM0008 Figure 22

Figure 1. Reconstructed ADC regular-conversion path based on RM0008 Figure 22

Reference source: RM0008 Reference Manual, p.217, Figure 22. Single ADC block diagram.

What this figure means: This redraw follows the RM0008 Figure 22 reading direction but isolates the regular-conversion path used in this chapter. Injected conversion blocks, ADC3-only trigger variants, and remap branches are intentionally left out of the figure so the main path GPIO analog pad -> ADC_SQR3-controlled Analog MUX -> Sample & Hold -> converter -> ADC_DR stays clear. ADC_SQR3.SQ1 controls which MUX input is forwarded; it is not a serial signal-processing block after the MUX.

Related registers: ADC_SQRx, ADC_SMPRx, ADC_CR2, ADC_SR, ADC_DR.

Reconstructed ADC input equivalent circuit based on STM32F103 datasheet Figure 38

Figure 2. Reconstructed ADC input equivalent circuit based on DS5319 Figure 38

Reference source: STM32F103 Datasheet, p.77, Figure 38. Typical connection diagram using the ADC.

What this figure means: This redraw follows the official equivalent-circuit layout. The ADC does not read the input wire directly forever. It must briefly charge an internal sampling capacitor, so source impedance and sample time directly affect accuracy.

Related registers: ADC_SMPR1, ADC_SMPR2.

Reconstructed regular conversion timing diagram based on RM0008 Figure 23

Figure 3. Reconstructed regular conversion timing based on RM0008 Figure 23

Reference source: RM0008 Reference Manual, p.220, Figure 23. Timing diagram.

What this figure means: This redraw follows the original timing-lane layout. Enabling the ADC does not instantly produce a valid result. After enable and trigger, the converter spends time sampling and converting, then ADC_SR.EOC indicates completion and ADC_DR becomes readable.

Related registers: ADC_CR2.ADON, ADC_CR2.SWSTART, ADC_SR.EOC, ADC_DR.

Reconstructed analog watchdog guarded-area diagram based on RM0008 Figure 24

Figure 4. Reconstructed analog watchdog guarded area based on RM0008 Figure 24

Reference source: RM0008 Reference Manual, p.220, Figure 24. Analog watchdog guarded area.

What this figure means: This redraw follows the official guarded-area layout. The analog watchdog compares each conversion result with configured high and low thresholds. If a result leaves the allowed range, the watchdog sets the status flag.

Related registers: ADC_HTR, ADC_LTR, ADC_CR1.AWDEN, ADC_SR.AWD.

Table 1. Pin mapping examples used in this chapter
Signal source ADC channel Meaning
PA1ADC1_IN1External analog input pin; current trainer route is CURRENT_SENSE
PA6ADC1_IN6Selectable AS5600 analog absolute-angle input. The common hardware profile is 3.3 V mode, OUTS=00, and programmed MANG=180°; official STM32F103 pin tables name this pad function ADC12_IN6.
PB0ADC_IN8Independent NTCLE100E3103 temperature divider node: 3.3 V → R1 10 kΩ → PB0 → NTC → GND
PB1ADC_IN9Official STM32 ADC input; not connected by the current System Trainer harness
Temperature sensorADC_IN16Internal channel, not an external GPIO pad
VREFINTADC_IN17Internal reference channel

Reference source: STM32F103 Datasheet, p.29, Table 5. Pin definitions. What this table means: GPIO pin names and ADC channel numbers are different concepts. Related registers: ADC_SQRx, GPIOx_CRL, GPIOx_CRH; for the current trainer route, PA1 means GPIOA_CRL[7:4] plus ADC1_IN1.

3.1 PA1, PA6, and PB0 GPIO nibbles before ADC conversion

Pin / ADC inputGPIO field4-bit valueActual pin behaviorCurrent trainer result
PA1 / ADC1_IN1GPIOA_CRL[7:4], shift 4, mask 0x000000F00x0 (0000): CNF=00, MODE=00Analog input. The digital input buffer and output driver are disabled so the ADC can own the pad path.The PA1 route requires this exact nibble together with IOPAEN, ADC1EN, and ADC_SQR3.SQ1 = 1.
PA6 / ADC1_IN6GPIOA_CRL[27:24], shift 24, mask 0x0F0000000x0 (0000): CNF=00, MODE=00Analog input for the 3.3 V AS5600 OUT voltage.Feedback=POSITION requires IOPAEN, ADC1EN, PA6 analog mode, and SQ1=6. With local OUTS=00 / MANG=180°, the sensor provides 2048 distinct DAC steps across 0..180°; the STM32 ADC still reports a 12-bit 0..4095 code, so adjacent ADC codes can repeat.
PB0 / ADC1_IN8GPIOB_CRL[3:0], shift 0, mask 0x0000000F0x0 (0000): CNF=00, MODE=00Analog input for the NTC divider node.NTC measurement requires IOPBEN, ADC1EN, PB0 analog mode, and SQ1=8. With R1=10 kΩ and NTCLE100E3103 R25=10 kΩ, the node is 1.65 V and ADC raw is about 2048 at 25 °C.

Write the PA1 field as GPIOA->CRL &= ~(0xFu << 4), PA6 as GPIOA->CRL &= ~(0xFu << 24), and PB0 as GPIOB->CRL &= ~0xFu. The complete 0x0..0xF mode table and shift calculation are in the GPIO Register Datasheet.

4 Official ADC1 register map

The register block below follows RM0008 Rev 21, Section 11.12 and Table 72. ADC peripheral registers are accessed as 32-bit words. Absolute addresses use ADC1 base 0x40012400 + offset.

Offset Absolute address Register Reset value Official purpose Trainer status
0x000x40012400ADC_SR0x00000000Status flagsEOC modeled
0x040x40012404ADC_CR10x00000000Scan, watchdog, and interrupt controlEOCIE modeled
0x080x40012408ADC_CR20x00000000Trigger, alignment, DMA, calibration, and enable controlADON / EXTSEL / EXTTRIG / SWSTART modeled; CONT stored only
0x0C0x4001240CADC_SMPR10x00000000Sample time for channels 10 to 17미지원
0x100x40012410ADC_SMPR20x00000000Sample time for channels 0 to 9Stored/readback only; sample-cycle timing side effect is 미지원
0x140x40012414ADC_JOFR10x00000000Injected channel 1 data offset미지원
0x180x40012418ADC_JOFR20x00000000Injected channel 2 data offset미지원
0x1C0x4001241CADC_JOFR30x00000000Injected channel 3 data offset미지원
0x200x40012420ADC_JOFR40x00000000Injected channel 4 data offset미지원
0x240x40012424ADC_HTR0x00000FFFAnalog watchdog high threshold미지원
0x280x40012428ADC_LTR0x00000000Analog watchdog low threshold미지원
0x2C0x4001242CADC_SQR10x00000000Regular sequence length and slots 13 to 16미지원
0x300x40012430ADC_SQR20x00000000Regular sequence slots 7 to 12미지원
0x340x40012434ADC_SQR30x00000000Regular sequence slots 1 to 6SQ1 modeled
0x380x40012438ADC_JSQR0x00000000Injected sequence미지원
0x3C0x4001243CADC_JDR10x00000000Injected data 1미지원
0x400x40012440ADC_JDR20x00000000Injected data 2미지원
0x440x40012444ADC_JDR30x00000000Injected data 3미지원
0x480x40012448ADC_JDR40x00000000Injected data 4미지원
0x4C0x4001244CADC_DR0x00000000Regular conversion data12-bit result modeled

Source: RM0008 Rev 21, Section 11.12, Table 72. The table keeps the complete official map visible even when a register is not executable in the trainer.

5 Register descriptions

Yellow fields have an active trainer side effect. Blue fields are official fields that remain stored or are shown for register reading. Reserved fields must remain at their reset value.

5.1 ADC status register (ADC_SR)

Address offset: 0x00   Address: 0x40012400   Reset value: 0x00000000

BitNameAccess / valuesMeaningCurrent trainer register-value behavior
31:5Reserved-Keep at reset value-
4STRTrc_w0; 0 = no regular conversion has started, 1 = regular conversion has startedHardware status flag for regular conversion start.미지원
3JSTRTrc_w0; 0 = no injected conversion has started, 1 = injected conversion has startedHardware status flag for injected conversion start.미지원
2JEOCrc_w0; 0 = injected conversion not complete, 1 = injected conversion completeHardware status flag for injected conversion completion.미지원
1EOCrc_w0; 0 = conversion not complete, 1 = conversion completeHardware status flag for regular or injected group conversion completion.Set when ADC_DR is updated; ADC_DR read clears it
0AWDrc_w0; 0 = no analog watchdog event, 1 = analog watchdog event occurredHardware status flag for an analog watchdog threshold event.미지원

5.2 ADC control register 1 (ADC_CR1)

Address offset: 0x04   Address: 0x40012404   Reset value: 0x00000000

BitNameAccess / valuesMeaningCurrent trainer register-value behavior
23AWDENrw; 0 = disabled, 1 = enabledWatchdog on regular channels미지원
22JAWDENrw; 0 = disabled, 1 = enabledWatchdog on injected channels미지원
19:16DUALMOD[3:0]rw; 0000 = independent, 0001..1001 = official dual-ADC modes, 1010..1111 = ReservedDual ADC operating mode. STM32F103 medium-density ADC1 trainer uses independent behavior only.미지원
15:13DISCNUM[2:0]rw; 000 = 1 channel, 001 = 2 channels, ..., 111 = 8 channelsNumber of regular channels converted in discontinuous mode after an external trigger.미지원
12, 11JDISCEN, DISCENrw; each bit: 0 = discontinuous mode disabled, 1 = discontinuous mode enabledEnable injected and regular discontinuous conversion mode.미지원
10JAUTOrw; 0 = automatic injected conversion disabled, 1 = automatic injected conversion enabledRun injected group conversion automatically after regular group conversion.미지원
9AWDSGLrw; 0 = watchdog on all channels, 1 = watchdog on selected channelSelect whether the analog watchdog watches every channel or the channel named by AWDCH[4:0].미지원
8SCANrw; 0 = scan mode disabled, 1 = scan mode enabledConvert selected ADC_SQRx or ADC_JSQRx sequence entries as a scan.미지원
7, 6JEOCIE, AWDIErw; each bit: 0 = interrupt disabled, 1 = interrupt enabledEnable injected-EOC and analog-watchdog interrupt requests.미지원
5EOCIErw; 0 = disabled, 1 = interrupt enabledEnd-of-conversion interrupt enableEOC와 함께 ADC1_2 handler 요청을 만듭니다.
4:0AWDCH[4:0]rw; 00000..10001 = ADC channel 0..17, 10010..11111 = ReservedAnalog watchdog channel selection.미지원

5.3 ADC control register 2 (ADC_CR2)

Address offset: 0x08   Address: 0x40012408   Reset value: 0x00000000

BitNameAccess / valuesMeaningCurrent trainer register-value behavior
23TSVREFErw; 0 = temperature sensor and VREFINT disabled, 1 = enabledEnable the internal temperature sensor and VREFINT channel.미지원
22, 21SWSTART, JSWSTARTrw; each bit: 0 = reset state, 1 = start the selected regular or injected conversion groupSoftware start request for regular and injected groups. Hardware clears the bit after conversion starts.SWSTART executes one PB0/IN8 or PA6/IN6 regular conversion selected by SQ1, then clears; JSWSTART is not modeled
20EXTTRIGrw; 0 = disabled, 1 = external trigger enabledEnable external trigger for regular groupRequired for common TIM2_CC2 current conversion and PB0/PA6 SWSTART conversion
19:17EXTSEL[2:0]rw; see shared decoder belowSelect regular-group trigger event011 executes TIM2_CC2; 111 selects the PB0/PA6 SWSTART route
15JEXTTRIGrw; 0 = disabled, 1 = enabledEnable injected external trigger미지원
14:12JEXTSEL[2:0]rw; ADC1/ADC2: 000 = TIM1_TRGO, 001 = TIM1_CC4, 010 = TIM2_TRGO, 011 = TIM2_CC1, 100 = TIM3_CC4, 101 = TIM4_TRGO, 110 = EXTI15/TIM8_CC4, 111 = JSWSTARTSelect injected trigger event.미지원
11ALIGNrw; 0 = right alignment, 1 = left alignmentSelect ADC_DR data alignment.Stored; trainer result remains right-aligned
8DMArw; 0 = DMA mode disabled, 1 = DMA mode enabledEnable ADC DMA request generation.미지원
3, 2RSTCAL, CALrw; RSTCAL: 0 = calibration register initialized, 1 = initialize calibration register; CAL: 0 = calibration complete, 1 = start calibrationReset calibration registers and start A/D calibration.Stored; calibration timing not modeled
1CONTrw; 0 = single conversion mode, 1 = continuous conversion modeContinuous conversion mode.Stored; continuous conversion not modeled
0ADONrw; 0 = ADC disabled and powered down, 1 = ADC enabled; writing 1 again while already enabled starts conversion on hardwareADC enable and software conversion start sequence.Common PA1/TIM2_CC2 and PB0/PA6 SWSTART paths require ADON=1; stabilization and repeated-ADON timing are simplified

Shared ADC_CR2 EXTSEL decoder: the values below are official RM0008 regular-group trigger selections. The trainer execution column is a separate support boundary.

EXTSELOfficial ADC1/ADC2 regular triggerTrainer execution
000TIM1_CC1미지원
001TIM1_CC2미지원
010TIM1_CC3미지원
011TIM2_CC2Value 011 executes TIM2_CC2 when ADON=1, EXTTRIG=1, and the ADC/TIM2 route is configured.
100TIM3_TRGO미지원
101TIM4_CC4미지원
110EXTI11 / TIM8_TRGO미지원
111SWSTARTExecutes one PB0/IN8 or PA6/IN6 conversion when ADON=1, EXTTRIG=1, SQ1 selects channel 8 or 6, and SWSTART is written.

5.4 ADC sample time register 2 (ADC_SMPR2)

Address offset: 0x10   Address: 0x40012410   Reset value: 0x00000000

FieldNameAccess / valuesMeaningCurrent trainer register-value behavior
SMP9[2:0] .. SMP0[2:0]Sample time fieldsrw; 000=1.5, 001=7.5, 010=13.5, 011=28.5, 100=41.5, 101=55.5, 110=71.5, 111=239.5 cyclesSample time for ADC channels 9 to 0.Official reference only in the focused trainer API; cycle-accurate timing is simplified
SMP1[5:3]PA1 / ADC1_IN1rw; same 3-bit sample-time encodingSample time for the trainer's PA1 analog input channel.Internally stored reference field; no modeled sample-cycle timing side effect

5.5 ADC regular sequence register 3 (ADC_SQR3)

Address offset: 0x34   Address: 0x40012434   Reset value: 0x00000000

FieldNameAccess / valuesMeaningCurrent trainer register-value behavior
29:25SQ6[4:0]rw; channel numberSixth regular conversion channel.미지원 sequence slot
24:20SQ5[4:0]rw; channel numberFifth regular conversion channel.미지원 sequence slot
19:15SQ4[4:0]rw; channel numberFourth regular conversion channel.미지원 sequence slot
14:10SQ3[4:0]rw; channel numberThird regular conversion channel.미지원 sequence slot
9:5SQ2[4:0]rw; channel numberSecond regular conversion channel.미지원 sequence slot
4:0SQ1[4:0]rw; 00000..10001 = ADC channel 0..17, 10010..11111 = ReservedFirst regular conversion channel.Value 00001 selects PA1 / ADC1_IN1

5.6 ADC regular data register (ADC_DR)

Address offset: 0x4C   Address: 0x4001244C   Reset value: 0x00000000

FieldNameAccess / valuesMeaningCurrent trainer register-value behavior
31:16ADC2DATA[15:0]roADC2 regular data in dual mode.미지원
15:0DATA[15:0]ro; 0..4095 for a right-aligned 12-bit result, alignment controlled by ADC_CR2.ALIGNRegular conversion data, left or right aligned by ALIGN.Right-aligned 12-bit PA1/IN1, PA6/IN6, or PB0/IN8 sample in bits 11:0; read clears EOC

5.7 Reference-only ADC register field details

These official registers stay in the ADC1 map so students can recognize the complete RM0008 block. They are not exposed as focused trainer fields unless the trainer behavior column says otherwise.

Register / offsetNameAccess / valuesMeaningCurrent trainer register-value behavior
ADC_SMPR1 / 0x0CSMP17[2:0]..SMP10[2:0]rw; same 3-bit sample-time encoding as ADC_SMPR2Sample time for channels 10 through 17.미지원; channels 10-17 are not routed by the current trainer.
ADC_JOFR1 / 0x14JOFFSET1[11:0]rw; 12-bit offsetInjected channel 1 data offset.미지원; injected conversions are not modeled.
ADC_JOFR2 / 0x18JOFFSET2[11:0]rw; 12-bit offsetInjected channel 2 data offset.미지원; injected conversions are not modeled.
ADC_JOFR3 / 0x1CJOFFSET3[11:0]rw; 12-bit offsetInjected channel 3 data offset.미지원; injected conversions are not modeled.
ADC_JOFR4 / 0x20JOFFSET4[11:0]rw; 12-bit offsetInjected channel 4 data offset.미지원; injected conversions are not modeled.
ADC_HTR / 0x24HT[11:0]rw; reset 0xFFFAnalog watchdog high threshold.미지원; analog watchdog comparison is not modeled.
ADC_LTR / 0x28LT[11:0]rw; reset 0x000Analog watchdog low threshold.미지원; analog watchdog comparison is not modeled.
ADC_SQR1 / 0x2CL[3:0], SQ16..SQ13rw; sequence length and channel slotsRegular sequence length and final slots.미지원; the trainer uses one regular slot through ADC_SQR3.SQ1.
ADC_SQR2 / 0x30SQ12..SQ7rw; channel slot numbersMiddle regular sequence slots.미지원; multi-slot scanning is not modeled.
ADC_JSQR / 0x38JL[1:0], JSQ4..JSQ1rw; injected length and slotsInjected conversion sequence.미지원; injected conversions are not modeled.
ADC_JDR1 / 0x3CJDATA[15:0]ro; injected dataInjected data register 1.미지원; no trainer injected result is produced.
ADC_JDR2 / 0x40JDATA[15:0]ro; injected dataInjected data register 2.미지원; no trainer injected result is produced.
ADC_JDR3 / 0x44JDATA[15:0]ro; injected dataInjected data register 3.미지원; no trainer injected result is produced.
ADC_JDR4 / 0x48JDATA[15:0]ro; injected dataInjected data register 4.미지원; no trainer injected result is produced.

6 Trainer contract and legacy boundary

Required pathRegister or fieldCurrent behavior
Peripheral clocksRCC_APB2ENR.IOPAEN + ADC1ENBoth gates are required.
ADC clockRCC_CFGR.ADCPREPCLK2 -> ADCPRE -> ADCCLK; the field is stored, while cycle timing is simplified.
Analog padGPIOA_CRL[7:4] = 0000PA1 must be analog input.
Sample fieldADC_SMPR2.SMP1Official reference only; conversion latency remains same-tick.
Regular slotADC_SQR3.SQ1 = 1Selects ADC1_IN1.
TriggerADC_CR2.ADON = 1, EXTSEL = 011, EXTTRIG = 1TIM2_CC2 starts the conversion only while the ADC enable gate is open.
CompletionADC_SR.EOC, ADC_DRResult update sets EOC; reading ADC_DR clears EOC.
InterruptADC_CR1.EOCIE + ADC_SR.EOC현재 Trainer에서 두 bit가 ADC1_2_IRQHandler 실행 조건입니다.
ANGLE sensor clocksRCC_APB2ENR.IOPAEN + ADC1ENBoth gates are required for PA6/IN6.
ANGLE sensor padGPIOA_CRL PA6 nibble = 0000AS5600 OUT is sampled as PA6 / ADC1_IN6. Local setup is 3.3 V mode, OUTS=00 analog full range, and programmed MANG=180°. The resulting 2048 distinct sensor-DAC steps are sampled into a 12-bit ADC register. I²C programming, DIR, PWM output, and magnet diagnostics are vendor reference-only.
ANGLE software conversionSQ1 = 6; ADON=1; EXTSEL=111; EXTTRIG=1; SWSTART=1One selected-channel sample updates ADC_DR and EOC, then hardware clears SWSTART.
NTC boundary3.3 V → R1 10 kΩ → PB0 / ADC1_IN8 → NTCLE100E3103 → GNDThe vendor source gives R25=10 kΩ, B25/85=3977 K, and the R/T table. The local code converts the 12-bit divider sample with a 5 °C-step LUT. PA10 / USART1_RX is an independent UART input.
NTC tolerance boundaryNTCLE100E3 vendor limits + board tolerancesNTC resistance tolerance, B tolerance, R1 tolerance, VDDA/VREF error, self-heating, wiring resistance, and thermal lag must be budgeted on hardware; the Trainer uses nominal values and an immediate temperature plant.
Raw current boundary0.05 Ω shunt → PA1 / ADC1_IN1This is a local unamplified path, not a VNH5019A-E CS or DRV8873 IPROPI claim. Use Kelvin sense routing, rate shunt power (I²R; 5 A = 1.25 W, 8.5 A = 3.61 W), and add ADC input RC/clamp protection. The raw low-side sample does not prove bidirectional or recirculation current and must stay within 0..VDDA.

The register-value behavior above is enough to review ADC code. The companion ADC User Description owns learner-facing UI confirmation steps; the same pasteable core sequence is included at the end of this chapter. Student C uses the sandbox pointer ADC1 = 0x1200, whose exposed field offsets mirror the official register layout above.

Legacy compatibility only: ADC1_CR = 0x50001000, ADC1_DR_CH0 = 0x50001004, and ADC1_DR_CH1 = 0x50001008. These private Trainer aliases are not part of the official ADC1 map and are not used for the PB0 NTC or selectable PA6 Position sensor.

Reference-only on real STM32F103: injected conversions, DMA execution, analog watchdog execution, TIM3/TIM4 trigger runtime, calibration timing, continuous/scan sequencing, and cycle-accurate ADCCLK timing.

6.1 PB0 NTC / selectable PA6 Position SWSTART example

현재 기본 실행 기준: PB0/ADC1_IN8 NTC 분압은 SQ1=8 → SWSTART → EOC polling → ADC_DR로 측정합니다. Feedback=POSITION이면 PA6/ADC1_IN6의 SQ1=6과 채널을 번갈아 선택합니다. PA10 UART는 이 ADC 경로와 독립입니다.

#include "training_api.h"

#define SENSOR_ADC_NTC_CHANNEL 8u
#define SENSOR_ADC_POSITION_CHANNEL 6u

static uint32_t sensor_adc_pending_channel = SENSOR_ADC_NTC_CHANNEL;
static uint32_t ntc_adc_raw = 0u;
static uint32_t ntc_temperature_c_x10 = 0u;
static uint32_t pa6_position_raw = 0u;

/* NTCLE100E3103, R1=10 kΩ, 0..125 °C in 5 °C steps. */
static const uint32_t ntc_adc_raw_by_5c[26] = {
    3133u, 2936u, 2724u, 2501u, 2274u, 2048u, 1827u, 1618u, 1424u,
    1246u, 1085u, 942u, 816u, 706u, 611u, 528u, 457u, 396u, 343u,
    298u, 260u, 227u, 198u, 174u, 152u, 134u
};

static uint32_t ntc_temperature_c_x10_from_raw(uint32_t raw)
{
    uint32_t index;
    if (raw >= ntc_adc_raw_by_5c[0]) return 0u;
    if (raw <= ntc_adc_raw_by_5c[25]) return 1250u;
    for (index = 0u; index < 25u; index += 1u)
    {
        uint32_t high_raw = ntc_adc_raw_by_5c[index];
        uint32_t low_raw = ntc_adc_raw_by_5c[index + 1u];
        if (raw <= high_raw && raw >= low_raw)
        {
            uint32_t span = high_raw - low_raw;
            uint32_t offset = high_raw - raw;
            return index * 50u + (offset * 50u + span / 2u) / span;
        }
    }
    return 1250u;
}

static uint32_t feedback_is_position(void)
{
    return TRAINER->FEEDBACK_MODE == TRAINER_FEEDBACK_ANGLE;
}

static void gpio_init(void)
{
    GPIOB->CRL &= ~0xFu; /* PB0 / ADC1_IN8 NTC divider node */
    if (feedback_is_position())
    {
        GPIOA->CRL &= ~(0xFu << 24); /* PA6 / ADC1_IN6 angle analog input */
    }
}

static void sensor_adc_start(uint32_t channel)
{
    sensor_adc_pending_channel = channel;
    if (channel == SENSOR_ADC_NTC_CHANNEL) {
        ADC1->SQR3 = ADC_SQR3_SQ1_ADC1_IN8;
    } else {
        ADC1->SQR3 = ADC_SQR3_SQ1_ADC1_IN6;
    }
    ADC1->CR2 |= ADC_CR2_SWSTART;
}

static void adc_init(void)
{
    ADC1->CR = ADC1_CR_CH1EN; /* PA1 current legacy compatibility path */
    ADC1->SQR1 = 0u;
    ADC1->SQR2 = 0u;
    ADC1->CR1 = 0u; /* EOC polling */
    ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_EXTSEL_SWSTART | ADC_CR2_EXTTRIG;
    sensor_adc_start(SENSOR_ADC_NTC_CHANNEL);
}

static void sensor_adc_service(void)
{
    uint32_t raw;
    if ((ADC1->SR & ADC_SR_EOC) == 0u) return;
    raw = ADC1->DR;
    if (sensor_adc_pending_channel == SENSOR_ADC_NTC_CHANNEL)
    {
        ntc_adc_raw = raw;
        ntc_temperature_c_x10 = ntc_temperature_c_x10_from_raw(raw);
        if (feedback_is_position()) {
            sensor_adc_start(SENSOR_ADC_POSITION_CHANNEL);
        } else {
            sensor_adc_start(SENSOR_ADC_NTC_CHANNEL);
        }
    }
    else
    {
        pa6_position_raw = raw;
        sensor_adc_start(SENSOR_ADC_NTC_CHANNEL);
    }
}

void user_init(void)
{
    trainer_clock_init_72mhz();
    RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_ADC1EN;
    gpio_init();
    adc_init();
}

void user_loop(void)
{
    sensor_adc_service();
    watch_u32("PB0_NTC_ADC_RAW", ntc_adc_raw);
    watch_u32("NTC_TEMPERATURE_C_X10", ntc_temperature_c_x10);
    watch_u32("PA6_ANGLE_ADC_RAW", pa6_position_raw); /* compatibility Watch name */
    watch_u32("PA1_CURRENT_ADC_RAW", ADC1->DR_CH1);
    watch_u32("ADC_SQR3", ADC1->SQR3);
}

PA1 current / TIM2_CC2 polling anchor: the executable polling pattern is EXTSEL=011 + EXTTRIG + ADON → TIM2_CC2 → EOC → ADC_DR read. PA1 raw-shunt conversion remains available through the compatibility channel while the common sensor scheduler owns SQ1.

PA1 current / TIM2_CC2 IRQ anchor: add ADC_CR1.EOCIE and service ADC1_2_IRQHandler; read ADC_DR to clear EOC. The current User Description owns the full timing proof.

ADC1 official map / modeled subsetRev 3.2