[RESOLU] accès vecteurs sur arduino

EDIT : j'ai changé le titre : en fait ma requête se résume à "comment mettre l'adresse d'une fonction (pointeur?) dans la case mémoire correspondant à une interruption"...

Bon, voilà, après avoir galéré dans tous les sens, la fonction attachInterrupt() n'a jamais marché sur ma mega2560.

void raz_ph123() {  
  digitalWrite(13, !digitalRead(13));
}

void setup(){
  pinMode(13, OUTPUT);
  pinMode(21, INPUT);
  digitalWrite(13, LOW);
  attachInterrupt (0, raz_ph123, RISING);
  sei();               // avec ou sans, ça marche pas.
}

void loop(){
}

On ne peut pas faire plus simple : la led 13 doit clignoter deux fois moins vite que le signal carré sur la broche 21 (INT0), mais un coup elle est allumée, un reset et elle s'éteint... assez aléatoire! (pour info, mon impultion est à 50Hz, 0 à 5V bien propre, d'une durée de 1ms).

Puis j'ai fait ça :

ISR(INT0_vect){
  digitalWrite(13, !digitalRead(13));
}

void setup(){
  pinMode(13, OUTPUT);
  pinMode(21, INPUT);
  digitalWrite(13, LOW);
  EICRA = 0x03;             // INT0 sur RISING
  EIMSK = 0x01;             // Activer INT0
  sei();
}

void loop(){
}

Et là, ça marche!

résolu? ben non, car comment je fais pour changer ma proc d'interruption? Quelqu'un a une idée pour aller écrire l'adresse d'une fonction dans l'adresse 0x0002 (adresse du pointeur INT0) un truc genre :

void maFonction(){
  (...)
}

INT0_pointer = maFonction;

help please!

EDIT : je viens de regarder la lib WInterrupt.c :

void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
  if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
    intFunc[interruptNum] = userFunc;

    switch (interruptNum) {
#if defined(EICRA) && defined(EICRB) && defined(EIMSK)  // config MEGA2560
    case 2:
      EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
      EIMSK |= (1 << INT0);
      break;
    case 3:
      EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
      EIMSK |= (1 << INT1);
      break;
    case 4:
      EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
      EIMSK |= (1 << INT2);
      break;
    case 5:
      EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
      EIMSK |= (1 << INT3);
      break;
    case 0:
      EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
      EIMSK |= (1 << INT4);
      break;
    case 1:
      EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
      EIMSK |= (1 << INT5);
      break;
    case 6:
      EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
      EIMSK |= (1 << INT6);
      break;
    case 7:
      EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
      EIMSK |= (1 << INT7);
      break;
#endif
    }
  }
}

en gros, attachInterrupt(int, fonction, mode) renseigne les registres du gestionnaire d'interruption comme je l'ai fait, et assigne fonction à un pointeur. Mais dans mon cas, quand je demande interrupt_num = 0, ça active l'INT4. Un peu navrant, non? Petite vérif : en effet, attachInterrupt fonctionne mais en envoyant mon signal sur la broche INT4... ET CA ME PLAIT PAS DU TOUT!

ensuite, on trouve :

SIGNAL(INT0_vect) {
  if(intFunc[EXTERNAL_INT_2])
    intFunc[EXTERNAL_INT_2]();
}

A chaque fois que je tente un truc qui sort du blink, je trouve des erreurs à foison dans les libs du core arduino! Et après on s'étonne que je veuille toujours passer par les registres!!!

donc en cours de programme, quand on appelle attachInterrupt(), ça modifie juste le pointeur intFunc[EXTERNAL_INT_2].

Mais moi, je trouve plus sûr et plus précis d'aller directement écrire l'adresse d'une fonction dans la case mémoire "INT0" (voir tableau page 105 ou chapitre 14.1 du datasheet de ATMEGA2560.pdf). Mais comment qu'on fait? il faudrait trouver le mot clé qui correspond à l'adresse mémoire 0x0002...

Je vais chercher comment ça se passe pour PORTA = 0xFF par exemple, car PORTA renvoie sur l'adresse 0x02 (bas de page 415 du PDF), il doit y avoir une constante qui correspond à l'adresse de mon vecteur!

Ah putain, tu m'étonne, mon pauvre Super_Cinci... pas moyen de s'y retrouver là-dedans!

C'est encore plus compliqué que la loi française!

Je crois que je vais me rabattre sur attachInterrupt(2, maFonction, RISING); pour atteindre mon INT0... mais ça me gave trop, j'ai ouvert 17 fichiers .h ou .c, chacun contenant un #include vers ceux que j'ai déjà parcourus, et toujours pas trouvé. je suis remonté jusqu'à "vectors ## N" sans pour autant savoir si je suis encore sur la bonne piste... c'est franchement du boulot de cochon, tiré grave par les cheveux!

Mais si le mot clé SIGNAL ne peut être déclaré qu'une fois et qu'on ne peut pas le changer, alors c'est mort!!!

Yop,

résolu? ben non, car comment je fais pour changer ma proc d'interruption?

Juste par curiosité parce que je comprend pas très bien la finalité ?

Tu as obtenu ton interruption "ISR(INT0_vect)" , à part placé ton code dedans ou appelé une fonction depuis celle ci je comprend pas ce que tu désires ?
Donner une valeur ou une adresse à un emplacement mémoire précis, je me suis jamais posé la question mais je pense pas que ce soit possible ???
"void pointeur = (void)0x02;" ?
Regarder dans la lib avr interrupt.h peut être ?
Je suis également très curieux de savoir tout ce qui ce cache là derrière.

Edit:

Mais si le mot clé SIGNAL ne peut être déclaré qu'une fois et qu'on ne peut pas le changer, alors c'est mort!!!

Je pense avoir saisis (à 2h du mat :grin:), vu que SIGNAL(INT0_vect) est déjà défini dans WInterrups.c tu ne peux pas le définir une deuxième fois ?
Si c'est ça il y a une façon radical comme je l'ai fais avec HardwareSerial c'est tout simplement de supprimer toute inclusion du core arduino.
Edit2: Ah be non contrairement à HardwareSerial il n'est inclus nulle part, sauf dans ton code peut être ?
Ton histoire me stresse lol. :sweat_smile:
Je commence également à de plus en plus utilisé les registre directement et fonctions de la lib avr, juste utile à compilé et uploader.
Entre () SIGNAL est déprécié, ISR() le remplace.

C'est assez compliqué, je vais tenter de reprendre ce que je cherche :

Page 105 du datasheet 2560, on a un tableau qui donne l'emplacement mémoire de tous les vecteurs d'interruption.

Simplement, un vecteur d'interruption, c'est une case mémoire (dans la mémoire flash) dans laquelle se trouve l'adresse de la fonction à appeler. Sauf erreur de ma part, les mots clé SIGNAL et ISR ont la même signification, à la compilation, une fonction (qui du coup n'a pas de nom dans le programme) déclarée SIGNAL ou ISR sera compilée normalement, avec en bonus, l'adresse de la première instruction de cette fonction sera écrite dans la case mémoire du vecteur d'interruption donné en paramètre de SIGNAL ou ISR.

Exemple :

ISR(TIMER1_COMPA_vect){
//instructions;
}

au reset après upload, l'adresse de la fonction sera écrite dans la mémoire flash à l'adresse 0x0022 ou 0x1F22 selon l'état des fusibles et du registre MCUCR. (déjà, ça se corse).
Une fois le programme en route, et quand le timer sera activé, si OCR1A == TCNT1, alors le compteur d'adresse programme sera automatiquement égal à 0x0022 (ou 0x1F22) (équivalent à "jmp 0X0022" ou "jmp 0X1F22"), où le code est : "jmp TIM1_COMPA", TIM1_COMPA étant l'étiquette (adresse programme) de l'ISR de mon exemple. (donc on perd déjà deux instruction, soit 125ns entre l'interruption et la première instruction de ma fonction, bon à savoir...).

(je suis simplement en train de faire un tuto sur le déclenchement des interruptions, là, j'apprends en même temps que vous...)

Par ailleurs, le vecteur "RESET" se trouve à l'adresse 0x0000, logique, car au reset, tout est à 0, donc le SP pointe directement sur 0x0000, le programme va donc démarrer sur un "jmp RESET", soit au début du bootloader.

Bon, ma requête commence à avoir une réponse : si je veux modifier un vecteur d'interruption, il faut écrire dans la flash. Comme dans mon programme, je change l'interruption toutes les 10ms, en une centaine ou un millier de secondes, j'aurai fusillé la mémoire flash (10 000 ou 100 000 cycles, c'est ça?)...

Je crois qu'il faut donc que j'écrive mon propre gestionnaire d'interruption du coup...

void *fonction_INT0 = &dumy_fonction;  // pointeur sur la fonction appelée en interruption 0
void *fonction_INT1 = &dumy_fonction;  // pointeur sur la fonction appelée en interruption 1

void dumy_fonction(){  // fonction vide
}

ISR(INT0_vect){       // interruption INT0
  fonction_INT0();
}
ISR(INT1_vect){       // interruption INT1
  fonction_INT1();
}

void myFunction(){
  // du code...
}
(...)

// au cours du programme :

  fonction_INT1 = &myFunction;  // affectation de myFunction sur l'INT1...
(...)
  fonction_INT1 = &dumy_fonction;  // fin de myFunction sur l'INT1...

Je sais, je suis le spécialiste pour répondre à mes propres questions... mais si quelqu'un en sait un peu plus, je suis preneur!

Bon ben tu as bien fais de mettre le titre très hard. :grin:
Sinon pour la manipulation des registre voir tout les iom328.h ,iom2560.h etc

#define PINB    _SFR_IO8(0X03)
#define PINB7   7
#define PINB6   6
#define PINB5   5
#define PINB4   4
#define PINB3   3
#define PINB2   2
#define PINB1   1
#define PINB0   0

Voir sfr_defs.h:

/* avr/sfr_defs.h - macros for accessing AVR special function registers */

#define _SFR_MEM8(mem_addr) (mem_addr)
#define _SFR_MEM16(mem_addr) (mem_addr)
#define _SFR_MEM32(mem_addr) (mem_addr)
#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)
#define _SFR_IO16(io_addr) ((io_addr) + __SFR_OFFSET)

#define _SFR_IO_ADDR(sfr) ((sfr) - __SFR_OFFSET)
#define _SFR_MEM_ADDR(sfr) (sfr)
#define _SFR_IO_REG_P(sfr) ((sfr) < 0x40 + __SFR_OFFSET)

Je sais pas si ça peut t'être utile ?

Bon, voilà, après avoir galéré dans tous les sens, la fonction attachInterrupt() n'a jamais marché sur ma mega2560.

void raz_ph123() {  

digitalWrite(13, !digitalRead(13));
}

void setup(){
  pinMode(13, OUTPUT);
  pinMode(21, INPUT);
  digitalWrite(13, LOW);
  attachInterrupt (0, raz_ph123, RISING);
  sei();              // avec ou sans, ça marche pas.
}

void loop(){
}



On ne peut pas faire plus simple : la led 13 doit clignoter deux fois moins vite que le signal carré sur la broche 21 (INT0), mais un coup elle est allumée, un reset et elle s'éteint... assez aléatoire! (pour info, mon impultion est à 50Hz, 0 à 5V bien propre, d'une durée de 1ms).

Selon la doc arduino, la broche 21 c'est l'interruption numéro 2 et non pas 0

Most Arduino boards have two external interrupts: numbers 0 (on digital pin 2) and 1 (on digital pin 3). The Arduino Mega has an additional four: numbers 2 (pin 21), 3 (pin 20), 4 (pin 19), and 5 (pin 18).

Comme dans mon programme, je change l'interruption toutes les 10ms

Difficile à comprendre. Une interruption cela peut tomber n'importe quand. Donc dire qu'on la change tout le temps c'est risquer d'en perdre et donc cela est un non-sens.
Je me demande si cette solution compliquée ne serait pas la conséquence d'un problème mal posé XD

En fin de compte qu'elle est la finalité...

C'est également ça que je n'ai pas compris, qu'est ce qui change ? quel est le but final ?
L'interuption, le code, ... ???
Je suppose que c'est en rapport avec le dimmer 220v ?
Que de question et en même temps ça en apporte d'autres. :grin:

Une autre question en rapport avec les interruptions et qui me tracasse également, une interruption peut être interrompue par une autre ? :relaxed: :sweat_smile:

Une autre question en rapport avec les interruptions et qui me tracasse également, une interruption peut être interrompue par une autre ?

oui si elle est de priorité supérieure

(Extrait de la doc Atmel)
The interrupts have priority in accordance with their Interrupt Vector position. The lower the Interrupt Vector address, the higher the priority.

Les interruptions ont une priorité fonction de leur position dans la table des vecteurs d'interruption. Les adresses de vecteurs les plus basses ont une priorité plus grande.

@fdufnews : Quand je dis "je change l'interruption", c'est la fonction appelée qui change. dans mon cas, la même INT peut générer trois comportements différents selon où l'on se trouve dans le code, et je n'ai pas envie (le temps) de faire un test sur une variable "flag" : la première instruction de ma fonction doit intervenir le plus vite possible.

La finalité? dans un premier temps, mon code n'a pas le droit de lambiner, on travaille à 16MHz, et c'est limite pour mon application.

Mon projet qui génère tout ce tatouin est effectivement le dimmer 220V en triphasé.

Les ressources que j'utilise :
INT0, 1 et 2 (passage à zéro des phases : appel toutes les 3.3ms de l'une de ces INT) pour mesure fréquence secteur et RAZ des timers
Réception DMX : un timer qui génère une INT toutes les 4µs
Les impulsions de commande des triacs ne gênent absolument pas, je fais tourner les timers en Fast PWM, et ce sont les INT0, 1 et 2 qui les synchronisent sur les différentes phases.

A partir de là, le temps d'exécution est drôlement précieux, et je n'ai pas le droit de rater une seule INT! Je garde mon chalenge à faire tourner cela sur un méga2560, alors qu'il existe des plateformes bien plus performantes (il existe une copie de la mega2560 à base d'un PIC 32bits à 80MHz).

Ce matin, j'ai réussi à faire un premier test qui marche correctement, avec juste un potar sur A0 et une seule sortie dimmer en monophasé. Reste maintenant à faire tourner ça sur trois phases, et 12 voies (mais là, je me heurte à d'autres problèmes comme comment faire un RAZ sur une sortie OCnX d'un timer qui tourne en mode "normal", toujours rien trouvé, une fois la comparaison obtenue, la sortie est à 1 et y reste quoiqu'il arrive jusqu'au prochain reset général).

Quand à la priorité des interruptions, je pense que c'est dans le cas où plusieurs interruptions arrivent sur le même cycle horloge, et dans ce cas, seule la plus prioritaire est traitée, les autres sont ignorées. Mais une fois une interruption déclenchée, je crois que toute autre interruption est prise en compte, même si c'est la même (et dans ce cas, il y aura un moment où ça va déborder de partout et plantage, il n'y a pas de limite à la pile (stack) à part la taille de la ram). D'où l'utilité de mettre en route le watch-dog dans un programme qui reçoit beaucoup d'interruptions.

Super_Cinci:
@fdufnews : Quand je dis "je change l'interruption", c'est la fonction appelée qui change. dans mon cas, la même INT peut générer trois comportements différents selon où l'on se trouve dans le code, et je n'ai pas envie (le temps) de faire un test sur une variable "flag" : la première instruction de ma fonction doit intervenir le plus vite possible.

Entre l'affectation d'une fonction par son adresse (en sortie de traitement ?) et une simple comparaison (flag) je sais pas si tu y gagne réellement en timing ou instruction ?
Sinon sous quel conditions le changement de fonction, il y a quand même une condition (flag ?) pour savoir la quel affecter à l'interruption ?
Tout ça va quand même être coton vu la tolérance que tu demandes et ça ne laisse pas beaucoup de place pour autre chose ?

Super_Cinci:
Quand à la priorité des interruptions, je pense que c'est dans le cas où plusieurs interruptions arrivent sur le même cycle horloge, et dans ce cas, seule la plus prioritaire est traitée, les autres sont ignorées. Mais une fois une interruption déclenchée, je crois que toute autre interruption est prise en compte, même si c'est la même (et dans ce cas, il y aura un moment où ça va déborder de partout et plantage, il n'y a pas de limite à la pile (stack) à part la taille de la ram). D'où l'utilité de mettre en route le watch-dog dans un programme qui reçoit beaucoup d'interruptions.

La collision entre interruptions peut quand même être problématique comme dans mon cas avec le bus rs485,avec une INT tout les 3.3 ms il y a de forte chance de perdre la moitier des données transmise vu l'emplacement dans le vecteur des interruptions lié à l'usart (j'en utilise 2 dont 1 UDRE et sur RX qui a son importance ) ?
La question serais plutôt est ce qu'une interruption peux interrompre le traitement en cours du code situé dans une autre interruption ou même celle en cours quelque soit l'emplacement dans le vecteur ?
J'ai l'impression qu'il y a plutôt un choix sur les priorité entre l'une et l'autre, on s'arrangera pour bloqué la moin prioritaire (niveau besoin) pendant le traitement de la prioritaire ?

est ce qu'une interruption peux interrompre le traitement en cours du code situé dans une autre interruption

Une interruption récursive en quelque sorte.
Quelques explications sur la difficulté de la chose dans la partie anglaise de l'ancien forum :
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261124850/0#0
mes 1c€

Cela voudrait-il dire que pendant qu'une ISR se déroule, toute autre interruption est ignorée? c'est gênant... Et dans le cas où l'on réactive les interruptions dans l'ISR (ISR réentrante), on arrive à un stack-overflow automatiquement, même si par moment on se retrouve quand même hors de toute ISR?

C'est ce qu'il me semble avoir compris, mais comme dans ce domaine je n'ai pas beaucoup d'expérience j'ai laissé le lecteur se faire son opinion et je vois que l'on a la même conclusion, hélas.

Salut,

Super_Cinci:
Cela voudrait-il dire que pendant qu'une ISR se déroule, toute autre interruption est ignorée? c'est gênant... Et dans le cas où l'on réactive les interruptions dans l'ISR (ISR réentrante), on arrive à un stack-overflow automatiquement, même si par moment on se retrouve quand même hors de toute ISR?

Il ne peut y avoir qu'une seule interruption simultané, il est cependant possible de permettre à une autre interruption de s'exécuter pendant l'exécution d'une autre, mais la 1er interruption sera "écrasé".
C'est pourquoi il ya toute une série de consigne de priorité au niveau des interruptions qui permet d'éviter que deux interruptions ne s'écrase mutuellement.

Si la oc fait 450 pages, c'est qu'il y a une raison, et je reconnais que je passe presque plus de temps à lire la doc qu'à programmer. Du coup, j'ai installé un second écran sur mon PC, un pour programmer, l'autre pour afficher la doc en même temps, c'est super pratique!

Donc, page 18 du PDF de l'ATMEGA2560, on peut lire :

En quelques mots (lexique : ISR = Interrupt Sub-Routine = routine d'interruption) :

1 - le bit qui autorise toutes les INT est mis à 0 dès qu'une INT se produit, et remis à 1 à la sortie de l'ISR.
2 - dans ce cas, si une (ou plusieur) INT se produit, le flag de cette INT est mis à 1, et l'ISR correspondante s'exécutera à la sortie de l'ISR qui était en cours. Dans le cas de plusieurs INT, elles seront exécutées dans l'ordre de priorité qu'annonçait fdufnews.
3 - On peut cependant, dans l'ISR, le remettre à 1 pour autoriser une nouvelle interruption. Dans ce cas, si une interruption se présente, elle interrompt l'ISR en cours le temps de s'exécuter, et si 10 INT s'imbriquent, peu importe, elles sont traitées dans l'ordre d'arrivée en interrompant tout de suite la précédante.
4 - il existe deux types d'INT, celles qui ont un flag et qui seront exécutées, même dix ans après, tant qu'on n'est pas sorti de l'ISR précédente. Et celles qui ne s'éxécuteront que si la condition de l'INT est encore vérifiée au moment où c'est leur tour.
5 - Rien n'est conservé lors d'une INT à part l'adresse programme de retour, pas même le registre de statut (peut-être gênant sur les opérations 16 ou 32 bits : le bit de retenue peut être modifié dans l'ISR?) Il revient au programmeur de s'assurer des bonnes sauvegardes au démarrage de son ISR.

Il me semble avoir lu qu'il n'y a pas de limite de pile (stack, la base des sauvegardes lors d'appels de fonctions ou ISR), sauf la taille de la RAM. Si on utilise beaucoup de variables et beaucoup d'appels de fonctions, alors il se peut que la pile déborde sur les variables en RAM, et là, tout est mort. La pile démarre au dernier emplacement de la RAM et descend vers le début, d'où cette possibilité de "collision", mais ce serait la seule contrainte.

Un appel d'ISR par INT occupe 5 cycles d'horloge (soit 312.5ns) et autant pour le retour, ce qui dans certains cas doit être pris en compte...

voilà donc quelques infos supplémentaires... ci-dessous le texte original en anglais.

When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a Return from Interrupt instruction – RETI – is executed. There are basically two types of interrupts. The first type is triggered by an event that sets the Interrupt Flag. For these interrupts, the Program Counter is vectored to the actual Interrupt Vector in order to execute the interrupt handling routine, and hardware clears the corresponding Interrupt Flag. Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s) to be cleared. If an interrupt condition occurs while the corresponding interrupt enable bit is cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the Global Interrupt Enable bit is set, and will then be executed by order of priority.
The second type of interrupts will trigger as long as the interrupt condition is present. These interrupts do not necessarily have Interrupt Flags. If the interrupt condition disappears before the interrupt is enabled, the interrupt will not be triggered.
When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction before any pending interrupt is served.
Note that the Status Register is not automatically stored when entering an interrupt routine, nor restored when returning from an interrupt routine. This must be handled by software. When using the CLI instruction to disable interrupts, the interrupts will be immediately disabled. No interrupt will be executed after the CLI instruction, even if it occurs simultaneously with the CLI instruction.

Bon, on va dire "résolu" dans la mesure où j'ai ma réponse :

On ne peut accéder aux vecteurs d'interruption qu'à la programmation, puisque la table des vecteurs se trouve dans la flash, à un endroit pas facilement trouvable (dépend des fusibles et de quelques registres)...

Yop,
On en apprend des choses. :open_mouth:
Et si j'ai bien compris le vecteur d’interruption correspond on va dire à un simple tableau (vecteur) sur lequel on boucle constamment d'où les priorité suivant la place dans ce "tableau", si une de ses valeurs est à 0 la boucle est interrompue (mais on peux la relancé à n'importe quel moment) et on appel la fonction correspondante à cet emplacement (vecteurs d'adresses de ses fonctions ?)
Tout ça parait logique en fait, merci pour ses recherches très instructives.

Du coup, j'ai installé un second écran sur mon PC, un pour programmer, l'autre pour afficher la doc en même temps, c'est super pratique!

Ca fait quelques années que je ne travail plus que comme ça, l'essayer c'est l'adopter tellement c'est pratique. 8) :wink:

osaka:
Et si j'ai bien compris le vecteur d’interruption correspond on va dire à un simple tableau (vecteur) sur lequel on boucle constamment d'où les priorité suivant la place dans ce "tableau", si une de ses valeurs est à 0 la boucle est interrompue (mais on peux la relancé à n'importe quel moment) et on appel la fonction correspondante à cet emplacement (vecteurs d'adresses de ses fonctions ?)
Tout ça parait logique en fait, merci pour ses recherches très instructives.

Je ne sais pas trop comment ça fonctionne, mais il n'y a pas de boucle. La première int force le code suivant dès la fin de l'instruction en cours (même si c'est une instruction nécessitant plusieurs cycles, elle sera exécutée en entier).

ASM:
  push PC   // sauvegarde compteur programme actuel
  cli           // désactivation des interruptions
  mov PC, int_vect  // pointeur programme sur le vecteur d'int (équivalent à un jmp)

// d'ici, on va directement à la routine d'interruption programmée par l'utilisateur
// et c'est ici que l'on revient grâce au "reti" à la fin de la routine d'int

  cbi int_flag   // clear flag de l'int
  sei         // réactivation des int
  pop PC  // rappel du compteur programme donc retour là où on en était avant l'int.

plus loin dans la flash, au beau milieu du code

int_vect: 
  sei          // à mettre d'entrée de jeu si l'on veut autoriser les autres interruptions pendant la routine ISR...
  usercode          // code de l'ISR...
  reti  // retour d'interruption.

Dans le premier code, on l'on distingue deux parties (une avant la routine ISR, une autre après), chacune de ces parties occupe 5 coups d'horloge (les fameuses 312.5ns).

Ce qu'il faut savoir, dans le cas où une int arrive pendant que l'on en traite déjà une, elle est sauvegardée par son flag qui reste à 1. une fois sorti du premier code ci-dessus, une instruction du programme en cours est traitée avant de relancer la procédure ci-dessus, car ce n'est que pendant que l'on traite une instruction que l'on peut détecter qu'un des flags d'int est à 1.

C'est surtout le fait de parler de vecteur et priorité ascendante dans celui-ci qui me fais pensé (imaginé) une boucle, disons que si j'avais du réalisé un tel système niveau soft c'est comme ça que j'aurais procédé.
On pourrais faire notre propre système d'interruption sur toute les entrées du microcontrôleur, une simple boucle sur les trois registres BCD, au moindre changement d'un bit de l'un deux on appel une fonction dans un tableau d'adresse correspondante. XD (idée d'un module alarme pour le système domotique avec un code extrêmement réduit )
Dans tout les cas même si j'ai pas compris le fonctionnement au plus bas du bas niveau (hard), on a compris leurs utilisations et leurs contraintes grâce à toi. :wink: