On va étudier ici l’assembleur du ATMEGA328P à 16MHz, on va découvrir ici quelques mnémoniques:

  • sbi : set bit , 1 cycle d’horloge
  • cbi : clear bit , 1 cycle d’horloge
  • rjmp : saut relatif , 2 cycles d’horloge
  • jmp : jump (saut) , 3 cycles d’horloge
  • nop ; non opération , un cycle d’horloge
void setup() {
  // Configure la broche 10 (PORTB2) en sortie
  DDRB |= (1 << PB2);
}

void loop() {
  // Boucle en assembleur pour basculer la broche 10
  asm volatile (
    "sbi %[port], %[bit] \n\t"  // Met la broche à HIGH (1 cycle)
    "cbi %[port], %[bit] \n\t"  // Met la broche à LOW (1 cycle)
    "rjmp .-4          \n\t"    // Saute en arrière de 2 instructions (2 cycles)
    :
    : [port] "I" (_SFR_IO_ADDR(PORTB)), [bit] "I" (PB2)
  );
}

plus lisible ! on retrouve les addresses DDRB dans me datasheet de l’ATMEGA328P

void setup() {
  // L'adresse I/O de DDRB est 0x04
  // On veut le bit 2 (valeur = 1 << 2 = 4)
  asm volatile (
    "ldi r24, 4     \n\t"  // Valeur à écrire dans DDRB
    "out 0x04, r24  \n\t"  // DDRB = 0x04
  );
}

void loop() {
  asm volatile (
    "start:           \n\t"
    "sbi 0x05, 2      \n\t"  // PORTB.2 = 1
    "cbi 0x05, 2      \n\t"  // PORTB.2 = 0
    "jmp start        \n\t"  // Boucle
  );
}

Les adresses I/O importantes (ATmega328P)

RegistreAdresse I/ODescription
DDRB0x04Data Direction Register B
PORTB0x05Data Register B (sortie)
PINB0x03Input Pins Address B (entrée)
DDRD0x0APort D Direction
PORTD0x0BPort D Data
void setup() {
  // L'adresse I/O de DDRB est 0x04
  // On veut le bit 2 (valeur = 1 << 2 = 4)
  asm volatile (
    "ldi r24, 4     \n\t"  // Valeur à écrire dans DDRB
    "out 0x04, r24  \n\t"  // DDRB = 0x04
  );
}

void loop() {
  asm volatile (
    "start:           \n\t"
    "sbi 0x05, 2      \n\t"  // PORTB.2 = 1
    "nop \n\t"
    "nop \n\t"
    "nop \n\t"
    "cbi 0x05, 2      \n\t"  // PORTB.2 = 0
    "jmp start        \n\t"  // Boucle
  );
}

setup()

ldi r24, 4     ; 1 cycle  (Load Immediate)
out 0x04, r24  ; 1 cycle  (Output to I/O)
               ; TOTAL setup: 2 cycles = 125 ns

loop()

start:
  sbi 0x05, 2      ; 2 cycles  (Set Bit I/O)
  nop              ; 1 cycle   (No Operation)
  nop              ; 1 cycle   (No Operation)
  nop              ; 1 cycle   (No Operation)
  cbi 0x05, 2      ; 2 cycles  (Clear Bit I/O)
  jmp start        ; 3 cycles  (Jump)
                   ; TOTAL loop: 10 cycles = 625 ns

Timing détaillé (16 MHz Arduino) :

InstructionCyclesDurée (ns)Temps cumulé (ns)État broche
sbi 0x05,22125125HIGH
nop162.5187.5HIGH
nop162.5250.0HIGH
nop162.5312.5HIGH
cbi 0x05,22125437.5LOW
jmp start3187.5625.0LOW
Retour à sbi625.0LOW

Langage Machine a gauche et Assembleur AVR à droite

; Toutes les versions produisent :
9A 25       ; sbi 0x05, 2
00 00 00    ; nop nop nop  
98 25       ; cbi 0x05, 2
0C 94 00 00 ; jmp start (adresse relative)