All guides
TECHNICAL GUIDESTM32L4R5GPIO2026

GPIO Pin Mux
Alternate Functions on the STM32L4R5

Register-accurate reference for MODER/OTYPER/OSPEEDR/PUPDR/IDR/ODR/BSRR/AFRL/AFRH on the STM32L4R5 (Cortex-M4F, RM0432) — with LL and HAL variants, AF maps, and fast BSRR toggling.

01 Why GPIO on the L4R5 works this way

Every pin on the STM32L4R5 is a mux. Each I/O can be driven as a general-purpose input, a general-purpose output, one of up to sixteen alternate functions (USART, SPI, I2C, timers, …), or an analog input. Getting a peripheral onto real copper is always the same two-step: pick the pin's mode, then — for a peripheral — pick which alternate function number that pin should route.

GPIO ports live on the AHB2 bus. The port base is 0x48000000 and each port is a 1 KB register block, so port addresses are simply spaced 0x400 apart. HCLK on the L4R5 runs up to 120 MHz, and because GPIO sits directly on AHB2 (not behind an APB bridge), single-cycle register access and very fast toggling are possible.

PortBase addressRCC_AHB2ENR bitNotes
GPIOA0x48000000GPIOAEN (bit 0)PA13/PA14/PA15 reset to SWD/JTAG
GPIOB0x48000400GPIOBEN (bit 1)PB3/PB4 reset to JTAG (TDO/NJTRST)
GPIOC0x48000800GPIOCEN (bit 2)PC13 = user button B1 on Nucleo
GPIOD0x48000C00GPIODEN (bit 3)
GPIOE0x48001000GPIOEEN (bit 4)
GPIOF0x48001400GPIOFEN (bit 5)
GPIOG0x48001800GPIOGEN (bit 6)PG[15:2] need VDDIO2 (PWR_CR2.IOSV)
GPIOH0x48001C00GPIOHEN (bit 7)PH0/PH1 = OSC in/out
GPIOI0x48002000GPIOIEN (bit 8)Only on large BGA packages
CLOCK FIRST

A GPIO port is dead until its clock is enabled in RCC_AHB2ENR. Before it, register reads return 0 and writes are dropped — the classic "my LED won't light" bug. RCC_AHB2ENR is at RCC offset 0x4C (absolute 0x4002104C).

L4+ DIFFERENCE — NO ASCR

Unlike the original STM32L47x/L48x devices, the STM32L4R5 (an L4+ part) has no GPIOx_ASCR analog-switch register. Its GPIO_TypeDef ends at BRR (offset 0x28). For an analog input you only set MODER = 11 — there is no analog switch bit to toggle. Code ported from an L476 that writes ASCR will not compile against stm32l4r5xx.h.

02 The GPIO register block

Eleven 32-bit registers per port. Two-bits-per-pin registers (MODER, OSPEEDR, PUPDR) use field 2n..2n+1 for pin n; one-bit-per-pin registers (OTYPER, IDR, ODR) use bit n; the AF registers use a 4-bit nibble per pin split across two words.

OffsetRegisterWidth/pinAccessPurpose
0x00MODER2 bitsrw00 input · 01 output · 10 alternate · 11 analog
0x04OTYPER1 bitrw0 push-pull · 1 open-drain
0x08OSPEEDR2 bitsrw00 low · 01 medium · 10 high · 11 very-high
0x0CPUPDR2 bitsrw00 none · 01 pull-up · 10 pull-down · 11 reserved
0x10IDR1 bitrLive input level of each pin (read-only)
0x14ODR1 bitrwOutput latch; prefer BSRR for atomic writes
0x18BSRR1 bit ×2w[15:0] set-to-1 · [31:16] reset-to-0 (atomic)
0x1CLCKR1 bitrwConfig lock (needs magic sequence); frozen until reset
0x20AFRL / AFR[0]4 bitsrwAlternate function select for pins 0–7
0x24AFRH / AFR[1]4 bitsrwAlternate function select for pins 8–15
0x28BRR1 bitwReset-only shortcut: write 1 to clear a pin

This is exactly the layout in the official CMSIS device header, which you can rely on for pointer arithmetic:

stm32l4r5xx.h — GPIO_TypeDef
typedef struct {
    volatile uint32_t MODER;    /* 0x00  mode        (2 bits/pin) */
    volatile uint32_t OTYPER;   /* 0x04  output type (1 bit/pin)  */
    volatile uint32_t OSPEEDR;  /* 0x08  speed       (2 bits/pin) */
    volatile uint32_t PUPDR;    /* 0x0C  pull up/dn  (2 bits/pin) */
    volatile uint32_t IDR;      /* 0x10  input data  (read-only)  */
    volatile uint32_t ODR;      /* 0x14  output data              */
    volatile uint32_t BSRR;     /* 0x18  bit set/reset (atomic)   */
    volatile uint32_t LCKR;     /* 0x1C  config lock              */
    volatile uint32_t AFR[2];   /* 0x20 AFRL (0-7), 0x24 AFRH (8-15) */
    volatile uint32_t BRR;      /* 0x28  bit reset                */
    /* NOTE: no ASCR on L4R5 (L4+) — struct ends here */
} GPIO_TypeDef;

Field math you will use constantly. For pin n:

bit-field helpers
/* 2-bit fields (MODER / OSPEEDR / PUPDR): shift = 2*n, mask = 0x3 */
#define MODE_MASK(n)   (0x3UL << ((n) * 2))
#define MODE_VAL(n,v)  (((uint32_t)(v)) << ((n) * 2))

/* 1-bit fields (OTYPER / IDR / ODR): shift = n */
#define BIT(n)         (1UL << (n))

/* BSRR: set pin n -> bit n ; reset pin n -> bit n+16 */
#define BSRR_SET(n)    (1UL << (n))
#define BSRR_RST(n)    (1UL << ((n) + 16))

/* AFR nibble: pins 0-7 use AFR[0], pins 8-15 use AFR[1] */
#define AFR_IDX(n)     ((n) >> 3)          /* 0 or 1            */
#define AFR_SH(n)      (((n) & 7) * 4)      /* nibble position  */
#define AFR_MASK(n)    (0xFUL << AFR_SH(n))
#define AFR_VAL(n,af)  (((uint32_t)(af)) << AFR_SH(n))
RESET STATE

To save power most pins reset to analog mode. Documented MODER reset values: GPIOA = 0xABFFFFFF (PA13/14/15 = SWD AF), GPIOB = 0xFFFFFEBF (PB3 = TDO AF, PB4 = NJTRST input), all other ports = 0xFFFFFFFF (fully analog). You must therefore explicitly program output/AF mode — never assume input.

03 Configuring a pin: input / output / AF / analog

Four modes, four recipes. Each is: clock the port, clear the 2-bit MODER field, write the new mode, then set the mode-specific extras.

ModeMODERAlso setIgnored
Digital input00PUPDR (opt.)OTYPER, OSPEEDR
Digital output01OTYPER, OSPEEDR, PUPDRAFR
Alternate function10AFRL/AFRH nibble, OTYPER, OSPEEDR, PUPDR
Analog11nothing (no ASCR on L4R5)OTYPER, OSPEEDR, PUPDR

Input — read a button (PC13, active-low)

input.c
RCC->AHB2ENR |= (1UL << 2);          /* GPIOCEN */
(void)RCC->AHB2ENR;                   /* sync read after clock enable */

GPIOC->MODER &= ~(0x3UL << (13*2));   /* 00 = input */
GPIOC->PUPDR &= ~(0x3UL << (13*2));
GPIOC->PUPDR |=  (0x1UL << (13*2));   /* 01 = pull-up */

int pressed = (GPIOC->IDR & (1UL << 13)) == 0;  /* B1 is active-low */

Output — push-pull LED (PB7)

output.c
RCC->AHB2ENR |= (1UL << 1);           /* GPIOBEN */
(void)RCC->AHB2ENR;

GPIOB->MODER   &= ~(0x3UL << (7*2));
GPIOB->MODER   |=  (0x1UL << (7*2));  /* 01 = output */
GPIOB->OTYPER  &= ~(1UL   << 7);      /* 0  = push-pull */
GPIOB->OSPEEDR &= ~(0x3UL << (7*2)); /* 00 = low speed (LED needs nothing more) */
GPIOB->PUPDR   &= ~(0x3UL << (7*2)); /* no pull */

GPIOB->BSRR = (1UL << 7);             /* drive high */

Alternate function — route a peripheral (PA5 = SPI1_SCK, AF5)

af.c
RCC->AHB2ENR |= (1UL << 0);           /* GPIOAEN */
(void)RCC->AHB2ENR;

GPIOA->MODER   &= ~(0x3UL << (5*2));
GPIOA->MODER   |=  (0x2UL << (5*2));  /* 10 = alternate function */
GPIOA->OTYPER  &= ~(1UL   << 5);      /* push-pull (SPI clock) */
GPIOA->OSPEEDR |=  (0x3UL << (5*2)); /* 11 = very-high for clean SPI edges */

/* AF5 into AFRL nibble for pin 5 (pins 0-7 -> AFR[0]) */
GPIOA->AFR[0] &= ~(0xFUL << (5*4));
GPIOA->AFR[0] |=  (5UL   << (5*4));   /* 5 = AF5 = SPI1 */

Analog — feed the ADC (PA0 = ADC1_IN5)

analog.c
RCC->AHB2ENR |= (1UL << 0);           /* GPIOAEN */
(void)RCC->AHB2ENR;

GPIOA->MODER |= (0x3UL << (0*2));     /* 11 = analog. That is all — */
                                     /* the L4R5 has no ASCR to set. */
GPIOA->PUPDR &= ~(0x3UL << (0*2));    /* disable pulls on an analog pin */
OPEN-DRAIN FOR I2C

I2C lines must be open-drain: set the pin to AF mode and OTYPER = 1, then rely on external pull-ups (typ. 4.7 kΩ). The internal PUPDR pull-up (~30–50 kΩ) is far too weak for standard/fast-mode bus edges.

04 Alternate-function & peripheral pin maps

The AF number you write into AFRL/AFRH decides which internal peripheral a pin connects to. The 16 AF slots are grouped by peripheral family and are consistent across the STM32L4 line. The authoritative per-pin table is "Alternate function mapping" in datasheet DS12023 — the maps below cover the pins you use daily.

AF number → peripheral family

AFPeripheralsAFPeripherals
AF0SYS (SWD/JTAG, MCO, LSCO, RTC_REFIN)AF8UART4, UART5, LPUART1
AF1TIM1, TIM2, TIM5, TIM8_BKIN, LPTIM1, IRAF9CAN1, TSC
AF2TIM1, TIM2, TIM3, TIM4, TIM5AF10OCTOSPI1, OTG_FS
AF3SAI1, TIM8AF11Device-specific (see DS12023)
AF4I2C1, I2C2, I2C3, I2C4AF12SDMMC1, COMP1/2, FMC, SWPMI1
AF5SPI1, SPI2, DFSDM1AF13SAI1, SAI2
AF6SPI3, DFSDM1AF14TIM2, TIM15, TIM16, TIM17, LPTIM2
AF7USART1, USART2, USART3AF15EVENTOUT

USART / UART pins

SignalPinsAF
USART1_TX / _RXPA9 / PA10  ·  PB6 / PB7AF7
USART1_CTS / _RTS-DE / _CKPA11 / PA12 / PA8AF7
USART2_TX / _RXPA2 / PA3  ·  PD5 / PD6AF7
USART3_TX / _RXPB10 / PB11 · PC4 / PC5 · PD8 / PD9AF7
UART4_TX / _RXPA0 / PA1  ·  PC10 / PC11AF8
LPUART1_TX / _RXPB11 / PB10 · PC1 / PC0 · PG7 / PG8AF8

SPI pins

BusNSSSCKMISOMOSIAF
SPI1PA4 / PA15PA5 / PB3PA6 / PB4PA7 / PB5AF5
SPI2PB12 / PB9PB13 / PB10PB14 / PC2PB15 / PC3AF5
SPI3PA4 / PA15PB3 / PC10PB4 / PC11PB5 / PC12AF6

I2C pins (open-drain, need external pull-ups)

BusSCLSDAAF
I2C1PB6 / PB8PB7 / PB9AF4
I2C2PB10 / PF1PB11 / PF0AF4
I2C3PC0 / PG7PC1 / PG8AF4

Timer channel pins

TimerCH1 / CH2 / CH3 / CH4AF
TIM1 (adv.)PA8 / PA9 / PA10 / PA11  (CHxN: PA7,PB13 / PB0,PB14 / PB1,PB15)AF1
TIM2PA0,PA5,PA15 / PA1,PB3 / PA2,PB10 / PA3,PB11AF1
TIM3PA6,PB4,PC6 / PA7,PB5,PC7 / PB0,PC8 / PB1,PC9AF2
TIM4PB6,PD12 / PB7,PD13 / PB8,PD14 / PB9,PD15AF2
TIM15 / 16 / 17TIM15: PA2/PA3 · TIM16: PA6/PB8 · TIM17: PA7/PB9AF14

ADC external channels (ADC1 & ADC2 share these pins)

Set the pin to analog (MODER = 11); no AF nibble applies to analog. Channel numbering matches ADC1/ADC2 on the L4R5:

PinChannelPinChannelPinChannel
PC0IN1PA2IN7PA7IN12
PC1IN2PA3IN8PC4IN13
PC2IN3PA4IN9PC5IN14
PC3IN4PA5IN10PB0IN15
PA0IN5PA6IN11PB1IN16
PA1IN6
A PIN HAS MANY AFs

Most pins list a function on several AF numbers. PB7, for example, is USART1_RX on AF7 and I2C1_SDA on AF4 — you choose by the nibble you write. Always confirm the exact package/pin against the DS12023 alternate-function table before committing a board layout; a few signals move between L4 variants.

05 Register-level example: blink + USART2 AF

A complete, self-contained main.c — no CMSIS/HAL headers required, only raw addresses — that blinks the Nucleo-L4R5ZI blue LED (PB7) and brings up USART2 on PA2/PA3 (AF7). Runs on the reset default MSI clock (4 MHz).

main.c — bare-metal (no vendor headers)
#include <stdint.h>

/* ---- minimal register model (RM0432 addresses) ---- */
typedef struct {
    volatile uint32_t MODER, OTYPER, OSPEEDR, PUPDR;
    volatile uint32_t IDR, ODR, BSRR, LCKR;
    volatile uint32_t AFR[2];        /* AFRL @0x20, AFRH @0x24 */
    volatile uint32_t BRR;           /* @0x28  (no ASCR on L4R5) */
} GPIO_TypeDef;

typedef struct {
    volatile uint32_t CR1, CR2, CR3, BRR, GTPR, RTOR, RQR, ISR, ICR, RDR, TDR;
} USART_TypeDef;

#define GPIOA   ((GPIO_TypeDef *)0x48000000UL)
#define GPIOB   ((GPIO_TypeDef *)0x48000400UL)
#define USART2  ((USART_TypeDef *)0x40004400UL)

#define RCC_AHB2ENR   (*(volatile uint32_t *)0x4002104CUL)
#define RCC_APB1ENR1  (*(volatile uint32_t *)0x40021058UL)

#define GPIOAEN   (1UL << 0)
#define GPIOBEN   (1UL << 1)
#define USART2EN  (1UL << 17)          /* RCC_APB1ENR1 bit 17 */

#define USART_CR1_UE  (1UL << 0)
#define USART_CR1_RE  (1UL << 2)
#define USART_CR1_TE  (1UL << 3)
#define USART_ISR_TXE (1UL << 7)

#define LED_PIN   7                    /* PB7 = blue LED (LD2) */

static void delay(volatile uint32_t n) { while (n--) __asm__ volatile("nop"); }

static void led_init(void)
{
    RCC_AHB2ENR |= GPIOBEN;
    (void)RCC_AHB2ENR;                 /* sync after clock enable */

    GPIOB->MODER   &= ~(0x3UL << (LED_PIN * 2));
    GPIOB->MODER   |=  (0x1UL << (LED_PIN * 2));   /* output */
    GPIOB->OTYPER  &= ~(1UL   << LED_PIN);         /* push-pull */
    GPIOB->OSPEEDR &= ~(0x3UL << (LED_PIN * 2));   /* low speed */
    GPIOB->PUPDR   &= ~(0x3UL << (LED_PIN * 2));   /* no pull */
}

static void usart2_init(void)
{
    RCC_AHB2ENR  |= GPIOAEN;
    RCC_APB1ENR1 |= USART2EN;
    (void)RCC_APB1ENR1;

    /* PA2 (TX) and PA3 (RX) -> AF mode */
    GPIOA->MODER &= ~((0x3UL << (2*2)) | (0x3UL << (3*2)));
    GPIOA->MODER |=  ((0x2UL << (2*2)) | (0x2UL << (3*2)));   /* 10 = AF */

    /* AF7 for pins 2 and 3, both in AFRL (AFR[0]) */
    GPIOA->AFR[0] &= ~((0xFUL << (2*4)) | (0xFUL << (3*4)));
    GPIOA->AFR[0] |=  ((7UL   << (2*4)) | (7UL   << (3*4)));

    /* 9600 8N1, PCLK1 = 4 MHz (MSI reset default), OVER8=0 */
    USART2->BRR = 4000000UL / 9600UL;              /* ~416 */
    USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}

static void usart2_putc(char c)
{
    while (!(USART2->ISR & USART_ISR_TXE)) { }
    USART2->TDR = (uint8_t)c;
}

int main(void)
{
    led_init();
    usart2_init();

    for (;;) {
        GPIOB->BSRR = (1UL << LED_PIN);            /* LED on  (atomic) */
        usart2_putc('*');
        delay(400000);
        GPIOB->BSRR = (1UL << (LED_PIN + 16));     /* LED off (atomic) */
        delay(400000);
    }
}
BUILD

Compile with arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostdlib -T link.ld startup.s main.c -o fw.elf. You still need a vector table / startup and a linker script placing .text at 0x08000000 and stack at top of SRAM. The USART VCP routing on the Nucleo-L4R5ZI is board-specific (solder bridges, see UM2179) — for a guaranteed link, wire a USB-serial adapter to PA2/PA3.

06 Fast toggle (BSRR/BRR), LL & HAL variants

Never read-modify-write ODR from more than one context. BSRR is a write-only "command" register: the lower 16 bits set pins, the upper 16 reset them, in a single atomic bus write with no lock and no interference between pins on the same port.

fast-toggle.c
/* Atomic, ISR-safe — preferred */
GPIOB->BSRR = (1UL << 7);          /* PB7 = 1  (lower half = SET)   */
GPIOB->BSRR = (1UL << (7 + 16));   /* PB7 = 0  (upper half = RESET) */
GPIOB->BRR  = (1UL << 7);          /* PB7 = 0  (BRR is reset-only)  */

/* Set several pins, clear others, in ONE write: */
GPIOB->BSRR = (1UL << 0) | (1UL << 1) | (1UL << (2 + 16));
/* -> PB0=1, PB1=1, PB2=0 simultaneously */

/* Software toggle needs a read of ODR — NOT atomic vs. an ISR
   touching another pin on the same port: */
GPIOB->ODR ^= (1UL << 7);

/* Maximum square-wave: back-to-back BSRR stores.
   GPIO is on AHB2, so the rate is limited by store latency at HCLK. */
for (;;) {
    GPIOB->BSRR = (1UL << 7);
    GPIOB->BSRR = (1UL << (7 + 16));
}
BSRR PRIORITY

If, in the same BSRR write, you set both the set-bit (n) and reset-bit (n+16) for one pin, the set action wins (RM0432). Use BRR when you only ever clear a pin.

Same thing with ST LL (stm32l4xx_ll_gpio.h)

ll.c
#include "stm32l4xx_ll_bus.h"
#include "stm32l4xx_ll_gpio.h"

LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_7, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_7, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_7, LL_GPIO_SPEED_FREQ_LOW);
LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_7, LL_GPIO_PULL_NO);

LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_7);     /* -> BSRR set   */
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_7);   /* -> BRR / BSRR */
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_7);        /* reads ODR, writes BSRR */

/* AF pin: PA2 = USART2_TX (AF7). AFRL helper for pins 0-7: */
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_2, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_2, LL_GPIO_AF_7);
/* pins 8-15 would use LL_GPIO_SetAFPin_8_15() for AFRH */

Same thing with the HAL (stm32l4xx_hal_gpio.h)

hal.c
#include "stm32l4xx_hal.h"

__HAL_RCC_GPIOB_CLK_ENABLE();

GPIO_InitTypeDef led = {0};
led.Pin   = GPIO_PIN_7;
led.Mode  = GPIO_MODE_OUTPUT_PP;
led.Pull  = GPIO_NOPULL;
led.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &led);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);   /* uses BSRR */
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);

/* Alternate function: USART2 TX/RX on PA2/PA3 */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef af = {0};
af.Pin       = GPIO_PIN_2 | GPIO_PIN_3;
af.Mode      = GPIO_MODE_AF_PP;
af.Pull      = GPIO_PULLUP;
af.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
af.Alternate = GPIO_AF7_USART2;        /* the AF7 nibble, chosen by macro */
HAL_GPIO_Init(GPIOA, &af);
WHY THREE APIs

Register code is smallest and clearest about what the silicon does; LL gives you named helpers that still map 1:1 to registers (great for performance-sensitive drivers); the HAL validates parameters and handles clock/AF bookkeeping (fastest to bring up, larger footprint). All three ultimately write the same MODER/AFR/BSRR bits shown above.

07 Gotchas & common mistakes

Almost every "GPIO doesn't work" ticket is one of these. Scan this list before you reach for a scope.

SymptomCauseFix
Writes to a port do nothing; reads return 0Port clock not enabledSet the bit in RCC_AHB2ENR first, then a dummy read to let the clock domain sync
Other pins on the port stopped workingUsed = instead of |=/&= on MODER/AFRRead-modify-write the field: clear with &= ~mask, then |= the value
Pin picks up the wrong mode valueForgot to clear the old 2-bit fieldAlways MODER &= ~(0x3<<2n) before OR-ing
Peripheral wired but silentMODER left as output, or wrong AF nibbleMODER = 10 and correct AF in AFRL (0-7) / AFRH (8-15)
PG2–PG15 deadVDDIO2 domain not poweredEnable PWR clock, then PWR->CR2 |= PWR_CR2_IOSV (bit 9)
Debugger drops after configuring PA13/14/15 or PB3/PB4Reprogrammed the SWD/JTAG pinsLeave PA13 (SWDIO) / PA14 (SWCLK) alone; free PB3/PB4/PA15 only if you don't need JTAG
I2C bus stuck / no ACKPush-pull instead of open-drain, or no pull-upsOTYPER = 1 on SCL/SDA + external ~4.7 kΩ pull-ups
SPI/OCTOSPI edges too slow, data corruptOSPEEDR left lowSet high or very-high speed on clock/data lines
Overheating / EMI / extra currentVery-high speed on pins that don't need itUse the lowest OSPEEDR that meets the rise-time budget
ADC reads garbagePin not in analog mode, or pull still enabledMODER = 11 and PUPDR = 00 (L4R5 needs no ASCR)
ISR and main both toggle a pin, glitchesRead-modify-write on ODR racesUse BSRR/BRR — single atomic write, no read
3.3V logic damaged by 5V inputDrove 5V into a non-FT pinCheck the pin's I/O type in DS12023; only FT pins tolerate 5V
TWO EASY-TO-MISS L4R5 SPECIFICS

1. No ASCR. Do not copy analog-input code from an STM32L476 project — the L4R5 has no GPIOx_ASCR; setting MODER = 11 is sufficient and ASCR will not even exist in the header.
2. VDDIO2 gate. Port G bits 2–15 are on the independent VDDIO2 supply. Even with the GPIOG clock on, those pins stay Hi-Z until you enable the PWR peripheral clock and set PWR_CR2.IOSV. This bites anyone using PG7/PG8 for LPUART1 or I2C3.

LOCKING CONFIG

LCKR freezes a pin's MODER/OTYPER/OSPEEDR/PUPDR/AFR until the next reset. The lock only takes effect after the documented write sequence (write 1+bits, write 0+bits, write 1+bits, then read twice). Use it to protect a critical pin from a runaway write — but remember it is one-way until reset.