🧠 Introduction à l'ATmega328P

Le cœur de l'Arduino Uno décortiqué — architecture AVR, registres et programmation bas niveau en C

Qu'est-ce que l'ATmega328P ?

L'ATmega328P est un microcontrôleur 8 bits de la famille AVR, conçu par Atmel (racheté par Microchip Technology en 2016). C'est le microcontrôleur qui équipe l'Arduino Uno et l'Arduino Nano, ce qui en fait le MCU le plus utilisé au monde pour le prototypage.

Cependant, l'ATmega328P est bien plus qu'un « chip Arduino ». C'est un microcontrôleur complet et puissant que l'on peut programmer sans la couche d'abstraction Arduino, en accédant directement aux registres avec AVR-GCC (le compilateur C officiel pour AVR). Cette approche « bare metal » offre un contrôle total sur le matériel, des performances optimales et une compréhension profonde du fonctionnement interne.

📊 Caractéristiques techniques

CaractéristiqueValeur
ArchitectureAVR 8 bits, Harvard modifiée, RISC (131 instructions)
Fréquence max20 MHz (16 MHz sur Arduino Uno)
Mémoire Flash32 Ko (programme)
SRAM2 Ko (variables, pile)
EEPROM1 Ko (stockage persistant)
GPIO23 broches (3 ports : B, C, D)
ADC6 canaux, 10 bits
TimersTimer0 (8 bits), Timer1 (16 bits), Timer2 (8 bits)
PWM6 canaux
CommunicationUSART, SPI, I2C (TWI)
Interruptions26 vecteurs (INT0, INT1, PCINT, Timer, ADC, USART…)
Tension de fonctionnement1.8V – 5.5V
BoîtierDIP-28, TQFP-32, QFN-32

🏗️ Architecture AVR

L'ATmega328P utilise une architecture Harvard modifiée avec des bus séparés pour les instructions (Flash) et les données (SRAM). Cela permet au processeur de lire une instruction et d'accéder aux données simultanément, améliorant les performances.

Les 3 espaces mémoire

Les 32 registres de travail

Le cœur AVR dispose de 32 registres 8 bits (R0 à R31) qui servent à effectuer les opérations arithmétiques et logiques. Les registres R26-R31 peuvent être utilisés par paires comme pointeurs 16 bits (X, Y, Z) pour l'adressage indirect. La plupart des instructions s'exécutent en un seul cycle d'horloge, ce qui rend l'AVR très efficace.

📌 Les ports GPIO de l'ATmega328P

L'ATmega328P organise ses 23 broches GPIO en 3 ports :

PortBrochesArduino UnoFonctions spéciales
PORTBPB0–PB5 (6 bits utiles)D8–D13SPI (PB2-PB5), Quartz (PB6-PB7), PWM (PB1,PB2,PB3)
PORTCPC0–PC5 (6 bits utiles)A0–A5ADC (PC0-PC5), I2C (PC4=SDA, PC5=SCL), Reset (PC6)
PORTDPD0–PD7 (8 bits)D0–D7USART (PD0=RX, PD1=TX), INT0/INT1 (PD2,PD3), PWM (PD3,PD5,PD6)

Chaque port est contrôlé par 3 registres :

🛠️ Outils de développement

Programmateurs compatibles

💻 Premier programme « bare metal »

Voici l'équivalent du Blink Arduino, mais en accès direct aux registres :

#include <avr/io.h>
#include <util/delay.h>

int main(void) {
    // PB5 = broche 13 Arduino = LED intégrée
    DDRB |= (1 << PB5);     // PB5 en sortie

    while (1) {
        PORTB |= (1 << PB5);   // PB5 = HIGH (LED ON)
        _delay_ms(500);

        PORTB &= ~(1 << PB5);  // PB5 = LOW (LED OFF)
        _delay_ms(500);
    }

    return 0;
}

Ce code fait exactement la même chose que le Blink Arduino, mais en ~178 octets de Flash contre ~900 octets pour la version Arduino. La différence : pas de bootloader, pas de framework, juste du pur C et des registres.

💡 Compilation en ligne de commande :
avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL -Os -o blink.elf blink.c
avr-objcopy -O ihex blink.elf blink.hex
avrdude -c usbasp -p m328p -U flash:w:blink.hex

🔄 ATmega328P vs Arduino : pourquoi programmer « sans Arduino » ?