This is the engineering reference for the model: what it implements, register by register, for people writing firmware against it. For using the board in the editor, start with The Arduino Leonardo and the board page.
Arduino Leonardo board contract (Phase 9)
The Leonardo is the Arduino whose USB socket goes to the microcontroller. One kernel component (leonardo in crates/parts) wraps an ATmega32U4 SoC model (crates/atmega32u4) on the same AVR core as the Uno and the Mega (crates/avr-core). The core is shared; the chip around it is not. This document is the contract, and it wins over any comment in the code.
The catalog type is leonardo. Where a section says "as docs/uno.md", that document is the contract for that part.
The one fact that makes this board different from every other AVR here: Serial is not a UART. The ATmega32U4 has a full-speed USB device on the die, the board's only socket is wired to it, and the serial monitor is a CDC endpoint the sketch's own firmware opens. Serial1 (the actual USART) is on header pins 0 and 1 and reaches nothing unless something is wired to it. Section 3.6 is explicit about how much of USB is modeled, and the answer is: the byte pipe, and nothing above it.
1. Board pins (catalog order)
Top view, the micro-USB socket and the barrel jack on the left edge. The board is 68.6 x 53.3 mm and the shield headers are an Uno's, hole for hole, including the Uno's 0.16 inch gap between the two blocks of the digital header.
Top row, left to right (18 holes): SCL, SDA, AREF, GND, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0.
Bottom row, left to right (13 holes): IOREF, RESET, 3V3, 5V, GNDb, GNDc, VIN, A0 to A5.
31 pins. The ICSP header is not a pin. That is where a real Leonardo's SPI pins are, so the stock SPI.h (which bit-bangs the bus) puts SCK, MISO, MOSI and SS on 13, 12, 11 and 10 instead, the holes an Uno uses for SPI: a device is wired to a Leonardo here exactly as to an Uno.
Port mapping, which is the thing this board's pin table exists for:
| pins | port |
|---|---|
0, 1 |
PD2, PD3 |
2, 3 |
PD1, PD0 |
4 |
PD4 |
5 |
PC6 |
6 |
PD7 |
7 |
PE6 |
8 to 11 |
PB4 to PB7 |
12 |
PD6 |
13 |
PC7 |
A0 to A3 |
PF7 down to PF4 |
A4, A5 |
PF1, PF0 |
Five ports, B to F. There is no port A and no port G on this part. In the 44-pin package the Leonardo uses, port B and port D are whole, port C brings out PC6 and PC7 only, port E brings out PE2 and PE6, and port F is missing PF2 and PF3. A pad the package does not have never drives anything and reads back 0.
Electrical:
- Every GPIO drives push-pull at 5 V through
R_STRONG, sits high-Z, or pulls up through 35 k, exactly asdocs/uno.mdsection 1 sets out. An input reads high at 2.5 V; a floating or contended net reads 0. SCL/SDAbesideAREFare the same two pieces of metal as pins3and2, notA5andA4as on an Uno, because on this chip I2C is on port D. That is the one place the shared shield footprint is not the shared chip, and it is the thing to check when moving a sketch across. Both holes of each pair carry what the pin is driving plus whatever the other side's net is doing, throughR_STRAP.5VandIOREFdrive 5 V atR_SUPPLY;3V3drives 3.3 V;GND,GNDbandGNDcdrive 0 V.VINis an input the board ignores: it is always USB powered.RESETcarries a 10 k pull-up to 5 V. Pulling it below 2.5 V holds the CPU in reset; letting go is an external reset, which is whatMCUSRreports.AREFis only ever read, never driven. With an internal reference selected the pin is left alone.- Pin
13has the on-boardLLED through 1 k to ground. A0toA5are ordinary digital pins as well as analog inputs.
2. Memory map
| flash | 32 KB, 16 K instruction words, PC 14 bits |
| SRAM | 2560 bytes at 0x0100 to 0x0AFF, RAMEND = 0x0AFF |
| EEPROM | 1 KB |
| I/O | 0x20 to 0x5F, reached by IN/OUT/SBI/CBI |
| extended I/O | 0x60 to 0xFF, reached only by LDS/STS and the pointer loads |
There is no RAMPZ and no EIND: 32 KB of flash fits inside Z, so LPM reaches all of it and a return address is two bytes. A raw image larger than the flash is refused by name.
On a real board the top 4 KB of flash holds the USB bootloader, which is how it reprogrammes itself over the same socket the sketch talks through. Nothing here loads through a bootloader (an image is placed in flash), so the whole 32 KB is available and firmware/leonardo/link.ld says so.
3. Peripherals
Every address below is a data-space address, the way LDS/STS and a volatile pointer see them. Every register not named here reads its reset value and counts as a stray access.
3.1 Ports
Five ports, three registers each, PINx then DDRx then PORTx, all in the low I/O window:
| port | PINx |
|---|---|
| B | 0x23 |
| C | 0x26 |
| D | 0x29 |
| E | 0x2C |
| F | 0x2F |
0x20 to 0x22 is where port A would be on a part that had one, and this one does not: those three addresses are strays. MCUCR (0x55) bit 4 PUD disables every pull-up at once. Writing a one to a PINx bit toggles the PORTx bit.
3.2 Timer/counter 0
Eight bits, two compare channels, the ordinary prescaler table. TCCR0A 0x44, TCCR0B 0x45, TCNT0 0x46, OCR0A 0x47, OCR0B 0x48, TIMSK0 0x6E, TIFR0 0x35, GTCCR 0x43. Every waveform mode as docs/uno.md section 3.2 gives them. OC0A is PB7 (pin 11) and OC0B is PD0 (pin 3).
3.3 Timer/counters 1 and 3
Sixteen bits, sixteen waveform modes, the same fourteen-register block twice: TCCRnA at the base, then +1 TCCRnB, +2 TCCRnC, +4 TCNTnL, +5 TCNTnH, +6 ICRnL, +7 ICRnH, +8..+13 OCRnAL through OCRnCH. Timer 1 is at 0x80 and timer 3 at 0x90. TIMSK1 0x6F, TIMSK3 0x71, TIFR1 0x36, TIFR3 0x38.
Timer 3 has one compare channel. TCCR3A carries COM3A1:0 and the WGM3 bits and nothing else, OCR3B and OCR3C are not registers, and 0x9A to 0x9D are strays. TIMSK3 accepts TOIE3, OCIE3A and ICIE3 only.
OC1A is PB5 (pin 9), OC1B is PB6 (pin 10), OC1C is PB7 (pin 11, shared with OC0A), and OC3A is PC6 (pin 5). Input capture: ICP1 is PD4, ICP3 is PC7.
Two peripherals wired to one pad is the part's own doing, and the datasheet leaves it to firmware not to enable both. Here the one that switches its output on owns the pad, and only the owner can hand it back.
3.4 Timer/counter 4, the ten-bit one
This is the peripheral that is not a wider or narrower version of something on an ATmega328P. Ten bits behind a shared high byte, TOP in a register rather than a mode, and three compare channels called A, B and D. There is no channel C, because OCR4C is TOP.
| register | address |
|---|---|
TCNT4 |
0xBE |
TC4H |
0xBF |
TCCR4A |
0xC0 |
TCCR4B |
0xC1 |
TCCR4C |
0xC2 |
TCCR4D |
0xC3 |
TCCR4E |
0xC4 |
OCR4A |
0xCF |
OCR4B |
0xD0 |
OCR4C (TOP) |
0xD1 |
OCR4D |
0xD2 |
DT4 |
0xD4 |
TIMSK4 |
0x72 |
TIFR4 |
0x39 |
TIFR4 and TIMSK4 bits: TOV4/TOIE4 bit 2, OCF4B/OCIE4B bit 5, OCF4A/OCIE4A bit 6, OCF4D/OCIE4D bit 7. CS43:0 in TCCR4B stops the counter at 0 and otherwise divides by 2^(n-1), up to 16384. OCR4C resets to 0xFF, which is why an eight-bit duty works without writing TOP. Every ten-bit register goes through TC4H, which is a separate latch from the 16-bit timers' TEMP.
Modeled: fast PWM (WGM41:0 = 0) and phase-and-frequency-correct PWM (WGM41:0 = 1), the three compare outputs on OC4A (PC7, pin 13), OC4B (PB6, pin 10) and OC4D (PD7, pin 6), and the four flags with their enables. A channel needs its PWM4x bit as well as its COM4x bits; COM4x alone does nothing.
Not modeled, and this is the list to read before trusting a waveform: the clock is CK, the 16 MHz system clock, which is what PLLFRQ.PINMUX selects at reset. The 48 or 64 MHz PCK path through the PLL is not there. PLLCSR (0x49) and PLLFRQ (0x52) are stored, and PLOCK reads back set once PLLE is set so firmware that waits for a lock does not spin. The complementary outputs (!OC4A, !OC4B, !OC4D), the dead-time generator in DT4, the output-enable bits in TCCR4E, the enhanced-resolution mode, the fault-protection unit and the two PWM6 modes are all absent. COM4x = 1 and COM4x = 2 both behave as non-inverting here, because the complementary output that tells them apart is what is missing.
3.5 USART1
One USART, and it is Serial1. Seven registers from 0xC8: UCSR1A, +1 UCSR1B, +2 UCSR1C, +3 UCSR1D, +4 UBRR1L, +5 UBRR1H, +6 UDR1. The bit positions are the Uno's (docs/uno.md section 3.4). UCSR1D is stored and read back as 0; hardware flow control is not modeled.
It is wired to its pins and to nothing else: RXD1 is PD2 (pin 0) and TXD1 is PD3 (pin 1). A frame is driven through the pad one bit at a time (a start bit low, eight data bits least significant first, a stop bit high, each 16 (UBRR + 1) CPU cycles, half that with U2X1), so a jumper from pin 1 to pin 0 really does carry a character. Receive samples the middle of each bit, which is why a mismatched baud rate garbles text here the same way it does on a desk.
TXEN1 takes TXD1 whatever DDRD says, and RXEN1 holds RXD1 as an input: that is the datasheet's rule, and it is why Serial1.begin() needs no pinMode.
3.6 The USB device: a stub that carries bytes
This is the place the model is deliberately not the chip, and it matters enough to say plainly.
Modeled, at the real addresses: UHWCON 0xD7, USBCON 0xD8, USBSTA 0xD9, USBINT 0xDA, UDCON 0xE0, UDINT 0xE1, UDIEN 0xE2, UDADDR 0xE3, UDFNUML 0xE4, UDFNUMH 0xE5, UEINTX 0xE8, UENUM 0xE9, UERST 0xEA, UECONX 0xEB, UECFG0X 0xEC, UECFG1X 0xED, UESTA0X 0xEE, UESTA1X 0xEF, UEIENX 0xF0, UEDATX 0xF1, UEBCLX 0xF2, UEBCHX 0xF3, UEINT 0xF4. Seven endpoints, 0 to 6.
What behaves:
USBCON.USBEswitches the controller on;UDCON.DETACHclear attaches it. Until both, everyUExregister reads 0 and writes go nowhere.UENUMselects an endpoint.UECONX.EPENenables it andUECFG0X.EPDIRgives it a direction: set is IN (device to host), clear is OUT.UEINTXis computed rather than stored. On an enabled IN endpoint it readsTXINI | FIFOCON, plusRWALwhile the 64-byte bank has room. On an enabled OUT endpoint it readsRXOUTI | FIFOCON | RWALexactly while the monitor has sent something nobody has read, and 0 otherwise.- Writing
UEINTXfollows the AVR USB convention: a bit is cleared by writing a zero to it. ClearingFIFOCONorTXINIon an IN endpoint hands the staged bank to the serial monitor. A bank that reaches 64 bytes goes out on its own. UEDATXmoves bytes: a write stages one on the selected IN endpoint, a read takes one from the selected OUT endpoint.UEBCLXcounts what is staged or waiting, saturating at 255.UEINThas a bit per endpoint with something to do.USBSTAreadsVBUSset andUESTA0XreadsCFGOKset: the board is plugged in and an endpoint this model has is always allocated, because there is no FIFO memory to run out of.
What is not there: the host, the bus, bus reset, SETUP packets, descriptors, enumeration, addressing, the frame counter, the 1 ms start-of-frame, endpoint banking, NAK, STALL, double buffering, and both USB interrupts. USB_GENERAL and USB_ENDPOINT are never raised, so a CDC runtime on this model polls.
Two consequences a sketch can see. while (!Serial) {} returns immediately here and waits on a desk, because there is no host to enumerate the device. And a sketch that inspects a control transfer, or that uses Keyboard or Mouse, has nothing to work with.
3.7 ADC
Ten bits, fourteen channels, ADCL 0x78, ADCH 0x79, ADCSRA 0x7A, ADCSRB 0x7B, ADMUX 0x7C, DIDR2 0x7D, DIDR0 0x7E, DIDR1 0x7F. Prescaler, ADSC, ADIF, ADIE, ADATE in free-running mode and ADLAR all behave as docs/uno.md section 3.3 gives them; a conversion is 13 ADC clocks, 25 for the first after ADEN.
Two things differ from an ATmega328P and one from an ATmega2560:
- The channel selector is six bits and its top bit,
MUX5, isADCSRBbit 5, not bit 3, which is where an ATmega2560 puts it. - The channels above seven are not a second port.
ADC8toADC13are PD4, PD6, PD7, PB4, PB5 and PB6, which is why A6 to A11 on an Arduino Leonardo are also digital pins 4, 12, 6, 8, 9 and 10. This board brings outA0toA5on the analog header; the rest are reached by their digital pin numbers. - There is no 1.1 V reference.
REFS1:0is 0 forAREF, 1 for AVCC, 3 for the internal 2.56 V, and 2 is reserved. The 1.1 V bandgap is still available as a channel atMUX5:0= 0x1E.
Channel to pad: ADC0 PF0, ADC1 PF1, ADC4 PF4, ADC5 PF5, ADC6 PF6, ADC7 PF7, ADC8 PD4, ADC9 PD6, ADC10 PD7, ADC11 PB4, ADC12 PB5, ADC13 PB6. ADC2 and ADC3 are in the mux and not bonded out on this package; selecting one reads 0. The differential and gain channels and the temperature sensor are not modeled and read 0.
3.8 External and pin-change interrupts
EICRA 0x69, EICRB 0x6A, EIMSK 0x3D, EIFR 0x3C, PCICR 0x68, PCIFR 0x3B, PCMSK0 0x6B.
Five external interrupts and three gaps: INT0 PD0 (pin 3), INT1 PD1 (pin 2), INT2 PD2 (pin 0), INT3 PD3 (pin 1), INT6 PE6 (pin 7). INT4, INT5 and INT7 are reserved slots with no pin behind them; enabling one can never assert anything. Sense bits are EICRA for 0 to 3 and EICRB for 4 to 7, two bits each: 0 low level, 1 any edge, 2 falling, 3 rising. A low-level interrupt asserts while the pin is low and sets no flag.
One pin-change group, PCINT0, and it is the whole of port B.
3.9 Sleep and EEPROM
SMCR 0x53 with SE bit 0, and every sleep mode behaves as idle: the CPU clock stops, the peripherals keep running, and any enabled interrupt brings it back. MCUSR 0x54 reports PORF after a power-on reset and EXTRF after the reset pin was held. WDTCSR, CLKPR, PRR0, PRR1, OSCCAL, RCCTRL, SPMCSR and GPIOR0..2 are stored and read back.
EEPROM is 1 KB at EECR 0x3F, EEDR 0x40, EEARL 0x41, EEARH 0x42, with EEARH two bits wide. Reads and writes complete immediately, so EEPE and EERE read back as zero.
3.10 Vectors
Forty-three vectors, two words apart from word address 0, numbered in priority order. crates/atmega32u4/src/vectors.rs and firmware/leonardo/include/leonardo.h carry the table; the shape that matters here is that slots 5, 6, 8, 13, 14 and 15 are reserved on this part, and that the two USB vectors sit between the pin-change group and the watchdog, an ordering no other AVR here has.
The ones the runtime uses: INT0..INT3 are 1 to 4, INT6 is 7, PCINT0 is 9, TIMER0_OVF is 23, USART1_RX is 25, ADC is 29, and timer 4's four are 38 to 41.
4. Host channel
host_write puts bytes into the USB OUT endpoint firmware reads; host_read takes the bytes firmware has sent on the IN endpoint. That is Serial in a sketch and the serial monitor in the UI. Bytes are UTF-8 as far as the UI is concerned and opaque to the model.
Serial1 is not on this channel and never will be: it is two header pins.
5. Time model and the part
As docs/uno.md section 5. 16 MHz, a cycle is exactly 62.5 ns, a slice is 10 us and exactly 160 cycles, and the cycle counter is anchored to kernel time at the start of every slice. Inside a slice the core is stepped one instruction at a time with the bus told the cycle each instruction starts at, so a pin change carries the cycle that caused it.
probe is a bitmask: 1 running, 2 sleeping, 4 the on-board L LED on pin 13, 8 USB transmit in the last 20 ms, 16 USB receive. 0 with no program.
poke: 2 holds RESET, 3 releases it.
6. Firmware (firmware/leonardo/)
An Arduino-shaped runtime written from this document: setup() and loop(), pinMode, digitalWrite, digitalRead, analogRead, analogWrite, millis, micros, delay, delayMicroseconds, attachInterrupt, Serial and Serial1. No Arduino core, no avr-libc, no libc.
Built with clang --target=avr -mmcu=atmega32u4, linked by ld.lld against firmware/leonardo/link.ld. Five of the runtime's files are the Uno's, compiled again for this part rather than copied: the number formatting, the math helpers, the freestanding floor and its assembly half, and Print. The catalog program string is elf32 avr atmega32u4.
PWM pins and their timers:
| pin | output | timer | frequency |
|---|---|---|---|
| 3 | OC0B |
0, fast PWM | 976.5625 Hz |
| 11 | OC0A |
0, fast PWM | 976.5625 Hz |
| 13 | OC4A |
4, fast PWM, TOP = OCR4C |
976.5625 Hz |
| 6 | OC4D |
4, fast PWM, TOP = OCR4C |
976.5625 Hz |
| 9 | OC1A |
1, 8-bit phase correct | 490.196 Hz |
| 10 | OC1B |
1, 8-bit phase correct | 490.196 Hz |
| 5 | OC3A |
3, 8-bit phase correct | 490.196 Hz |
digitalPinToInterrupt: pin 3 is 0, pin 2 is 1, pin 0 is 2, pin 1 is 3, pin 7 is 4. Anything else is -1.
Four examples: blink, button (a switch on pin 7, which is INT6), serial (which prints to both ports so the difference between them is on screen), and fade (which drives pin 13 off timer 4 and pin 9 off timer 1, so both kinds of PWM hardware run at once). An example is budgeted at 8 KB of the 32 KB flash.
7. What is not modeled
SPI, TWI, the analog comparator, the watchdog, the temperature sensor, the bootloader section and its fuses, the clock prescaler, the PLL and the fast clock it feeds timer 4, timer 4's complementary outputs and dead-time generator, and everything above the USB byte pipe listed in section 3.6. Those registers read their reset value and count as strays.
8. What this model is sure of, and what it is not
Taken from the data sheet, and run through by real firmware. Every address, bit
position and reset value in section 3 is from the ATmega16U4/ATmega32U4 Data Sheet, in
data-space numbering, including the extended I/O window from 0x60 to 0xFF that decides
which registers IN/OUT can reach and which need sts. Five ports, timers 0, 1, 3 and
the ten-bit timer 4 with OCR4C for TOP, USART1, the fourteen ADC channels, INT0 to
INT3 and INT6, and the one pin-change group are the data sheet's.
crates/atmega32u4/tests/runtime.rs runs the shipped blink, serial and fade ELFs
through the ports, both timer widths and the USB byte pipe.
Modeled, but not held to the data sheet's numbers. Behaviors rather than addresses:
- The USB device controller is a stub that carries bytes, as section 3.6 says
plainly. There is no enumeration, no descriptor exchange, no endpoint configuration, no
SOF timing, no suspend or resume and no 1200-baud-touch reset.
Serialis a byte pipe to the host channel that answersSerialandSerial.dtr()the way a connected CDC port would. So the one thing that makes a Leonardo a Leonardo (that a sketch can block forever waiting forwhile (!Serial)) is a decision this model makes rather than a protocol it runs. - The rest is the Uno's list.
docs/uno.mdsection 7's middle group applies unchanged: an ADC with no error in it, an exact 16 MHz clock, three pad states and a threshold with a 35 kΩ pull-up, an ideal supply that cannot brown out, a one-microsecond start-up, and a 10 us slice.
Deliberately absent, as section 7 lists: SPI, TWI, the analog comparator, the watchdog, the temperature sensor, the bootloader section and its fuses, the clock prescaler, the PLL and the fast clock it feeds timer 4, timer 4's complementary outputs and dead-time generator, and everything above the USB byte pipe. Those registers read their reset value and count as strays.