Le MS41.0 est le calculateur Siemens qui gère le six-cylindres en ligne M52 (et le S50 sur certaines variantes) des BMW E36, E39 et Z3. Cette page documente en détail son logiciel pour la calibration ID41, l’une des plus répandues du parc : numéro de pièce 1429861, matériel 11, logiciel 41. Elle a la forme d’un wiki : chaque partie décrit une fonction du calculateur, explique ce qu’elle fait, donne le nom des fonctions et des variables tels qu’ils figurent dans la base de désassemblage, leur adresse en mémoire et, quand c’est utile, les calculs qu’elles réalisent.
Les adresses de fonctions et de variables sont données dans l’espace vu par le processeur (le fichier « délinéarisé » chargé dans IDA, voir partie II). Les adresses de calibration sont données soit en adresse absolue (0x10xxx), soit en adresse logique de calibration, c’est-à-dire la position dans le fichier partiel de 24 Ko, qui est aussi l’adresse utilisée par la définition RomRaider. Une valeur notée 0x... est en hexadécimal.
Sommaire
- Cible et sources
- I. Architecture matérielle
- II. Organisation de la mémoire
- III. Démarrage et fonctionnement temps réel
- IV. Synchronisation moteur et allumage
- V. Injection et mélange carburant
- 1. Les états moteur
- 2. Le débitmètre et la charge
- 3. Le lancement et la première injection
- 4. Le temps d’injection en fonctionnement
- 5. Le phasage de l’injection
- 6. Les enrichissements et corrections transitoires
- 7. Le maintien de régime au lever de pied (rev hang)
- 8. La régulation lambda
- 9. Le chauffage des sondes lambda
- 10. La purge canister
- VI. Régulation du ralenti
- VII. VANOS, cliquetis, limiteur et autres fonctions moteur
- VIII. Les adaptations
- IX. Les octets de codage véhicule
- X. Antidémarrage et accès sécurisés
- XI. Communication
- XII. Détection des pannes et codes défaut
- XIII. Lecture, reprogrammation et sommes de contrôle
- Conclusion et crédits
Cible et sources
Le travail porte sur un calculateur réel lu en entier (lecture mémoire de 256 Ko par la K-line, calculateur sous tension), décompilé avec IDA Pro. Le firmware a été recoupé avec plusieurs sources :
- les datasheets des composants montés sur la carte : processeur Siemens SAB80C166W, contrôleur CAN Siemens SAE81C91, microcontrôleur STMicroelectronics de la famille ST9 (ST90E30), étages de puissance de type HIP0082/HIP0084, EEPROM 24C04, flash Intel 28F200 ;
- des documents et relevés personnels sur le matériel : liste des fonctions des broches du processeur, relevé du schéma de la carte (étages de puissance, décodeur d’adresse, RAM, verrous), extraction de la table de vérité du PALCE16V8 sur banc Arduino, mesures à l’oscilloscope et captures série réelles de lecture et d’écriture ;
- la décompilation des fichiers de diagnostic EDIABAS du MS41, qui donne les libellés des codes défaut et la forme des trames utilisées par le testeur BMW ;
- la définition RomRaider de l’ID41, seule ressource communautaire utilisée, qui a été vérifiée table par table contre le code puis complétée ;
- le MS41 Checksum Calculator, projet open source publié sur GitHub par Kim Freding, pour le recalcul des sommes de contrôle.
I. Architecture matérielle
1. Le processeur SAB80C166W
Le cœur du calculateur est un Siemens SAB80C166W, microcontrôleur 16 bits de la famille C166, cadencé à 12 MHz (fréquence mesurée sur la sortie CLKOUT, broche P3.15, et confirmée par le débit de la K-line). Il travaille sur un bus externe multiplexé adresse/données porté par le port 0, dispose de registres adressables bit par bit (ce qui permet au code de piloter chaque broche en une seule instruction), d’unités CAPCOM (capture et comparaison) pour tout le temps réel moteur, de deux UART et d’un convertisseur analogique-numérique 10 bits à 10 voies.
Le CPU ne travaille pas seul. Il est entouré d’une flash Intel 28F200 de 256 Ko organisée en mots de 16 bits, d’une RAM statique externe de 8 Ko (UM6264A), d’un décodeur d’adresse PALCE16V8, d’un contrôleur CAN SAE81C91, d’un microcontrôleur satellite ST9 qui exécute son propre programme, d’une EEPROM série 24C04 et de six étages de puissance qui commandent les actionneurs.
+------------------------------+
| SAB80C166W (CPU, 12 MHz) |
+--+-----+------+------+-------+
| | | |
P0 / RD / WR / ALE| |P2.8 | | P5.0-P5.9 : 10 entrées analogiques
(bus partagé) | | | |
v v | |
+----------------+ +-----------+| | +-------------------------+
| Flash 28F200 | | SAE81C91 || | | GAL PALCE16V8 |
| 256 Ko | | CAN @D000 || | | sélections flash / CAN /|
| A16/A17 : P4 | +-----------+| | | RAM, recalcule A13 flash|
+----------------+ | | +-------------------------+
+----------------+ | |
| UM6264A RAM | P3.8/P3.9 | | P3.3 / P3.12
| 8 Ko @D800 | (ASC1) v v
+----------------+ +-----------+ +-----------+
| ST90E30 | | 24C04 |
| satellite | | EEPROM I2C|
+-----------+ +-----------+
P1.0-P1.5 : bobines cyl. 1/5/3/6/2/4 P2.0-P2.5 : injecteurs cyl. 1/5/3/6/2/4
P2.9 : vanne de ralenti P2.12 : VANOS P3.0 : relais DME
P3.1 : voyant moteur P3.5 : relais de pompe à essence
P2.15 + P3.2 : vilebrequin 60-2 P2.13 : arbre à cames P3.4 : compte-tours TD P3.6 : fenêtre de cliquetis
2. Le rôle des broches du CPU
L’ordre des canaux suit l’ordre d’allumage 1-5-3-6-2-4 : le canal CAPCOM n pilote le n-ième cylindre dans l’ordre de combustion, aussi bien pour l’injection (P2.0 à P2.5) que pour l’allumage (P1.0 à P1.5). Cette affectation est établie par le relevé physique des étages de puissance et par le catalogue de défauts BMW (code 23 = injecteur du cylindre 6 sur P2.3, code 24 = injecteur du cylindre 4 sur P2.5).
| Broche | Fonction |
|---|---|
P0.0–P0.15 | bus multiplexé adresse/données, partagé par la flash, la RAM externe et le contrôleur CAN |
P1.0–P1.5 | commande des bobines d’allumage, cylindres 1, 5, 3, 6, 2, 4 |
P1.10 | entrée logique de défaut du débitmètre HFM (déclenche directement l’anomalie du code 8) |
P1.12, P1.13, P1.14 | trois fils d’intervention du calculateur ABS/ASC (réduction de couple, MSR), entrées actives à 1 |
P2.0–P2.5 | injecteurs, cylindres 1, 5, 3, 6, 2, 4 (canaux CC0 à CC5) |
P2.6 | tension de programmation (VPP) de la flash, active pendant l’écriture et l’effacement |
P2.7 | commande du circuit de mesure du retour d’allumage |
P2.8 | ligne d’interruption du contrôleur CAN (non utilisée, le CAN est scruté) |
P2.9 | vanne de ralenti, commande PWM 100 Hz des deux enroulements (CC9) |
P2.10 | entrée du capteur de vitesse véhicule : capture CC10 sur front descendant (Timer 1), chaque impulsion incrémente VSS_PulseCounter (0xF0F2) ; la broche est aussi reliée au GAL d’adressage |
P2.11 | signal de consommation vers le combiné (CC11) : une impulsion active à 0 par tour vilebrequin |
P2.12 | électrovanne VANOS (CC12, tout-ou-rien) |
P2.13 | capteur d’arbre à cames (capture CC13 sur les deux fronts) |
P2.14 | sortie PWM 100 Hz proportionnelle à la position du papillon (CC14) |
P2.15 | capteur de vilebrequin, cible 60-2 (capture CC15, une interruption par dent) |
P3.0 | relais principal DME (actif à 0) |
P3.1 | voyant de défaut moteur (actif à 0) |
P3.2 | entrée CAPIN du Timer 5, reliée au capteur de vilebrequin : mesure de la période des dents |
P3.3 / P3.12 | horloge (SCL) et donnée (SDA) du bus I2C vers l’EEPROM |
P3.4 | signal de compte-tours (TD) : trois impulsions par tour, rapport cyclique 25 % |
P3.5 | relais de pompe à essence (actif à 0) |
P3.6 | fenêtre de mesure du cliquetis vers le satellite : à 1 de 0° à 60° après chaque PMH |
P3.7 | entrée numérique du retour d’allumage (Timer 2 en mode porte) |
P3.8 / P3.9 | liaison série ASC1 vers le microcontrôleur satellite (TxD1 / RxD1) |
P3.13 | signal d’écriture (WR) du bus externe, commun à la flash, la RAM et le CAN |
P3.15 | horloge 12 MHz fournie au contrôleur CAN |
P4.0 / P4.1 | bits d’adresse hauts A16 / A17 de la flash |
P5.0–P5.9 | les dix entrées analogiques AN0 à AN9 |
Quelques broches méritent une explication. La sortie P2.11 émet une impulsion par tour vilebrequin, 42° après les PMH des cylindres 1 et 6, active à 0. Sa largeur FuelCons_PulseWidth vaut le temps d’injection moyen d’un cylindre multiplié par le facteur « Fuel Economy Gauge – Scaling Factor », puis par la proportion de cylindres non coupés (environ 0,96 ms au ralenti chaud) : c’est l’information de consommation de l’ordinateur de bord. Elle est produite par la machine à dents du vilebrequin (cas 2 et 62, partie IV), et par la machine du mode secours quand le capteur de vilebrequin manque. La sortie P2.14 est un PWM de 100 Hz dont le niveau haut va d’environ 9 % à 91 % selon TPS_Angle, environ 4 % quand le capteur papillon est en défaut ; elle est arrêtée lorsque la K-line est déverrouillée.
Les broches P3.4 et P3.6 sont deux sorties logicielles synchronisées sur le moteur. P3.4 porte le signal de compte-tours TD vers le combiné : trois impulsions par tour (une par allumage), avec un niveau haut de 25 % de la période. P3.6 est la fenêtre de mesure du cliquetis envoyée au satellite : elle passe à 1 au PMH de chaque cylindre, au moment où part le message ASC1 0x101 (gain et position du cylindre), et retombe 60° plus tard ; le niveau mesuré est demandé au satellite 48° après le PMH. Cette fenêtre est fixe en angle, les fenêtres de détection calibrées par cylindre (partie VII) étant appliquées par ailleurs.
3. Les dix entrées analogiques
Le convertisseur est configuré en balayage automatique continu (ADCON = 0xA9). Il convertit du canal 9 vers le canal 0 et un transfert PEC range chaque résultat à partir de 0xFA94. L’emplacement n du tableau (0xFA94 + 2n) contient donc la broche AN(9 − n). La référence VAREF mesurée vaut 5,2 V : un pas 10 bits vaut 5,078 mV, et les valeurs ramenées sur un octet valent 20,3 mV par pas.
| Broche | Emplacement | Signal | Traitement |
|---|---|---|---|
| AN0 | 9 (0xFAA6) | température moteur | table « ECT Sensor Scaling » vers CoolantTemp_Lin, code 10 |
| AN1 | 8 | non connectée | lecture brute par le diagnostic seulement |
| AN2 | 7 (0xFAA2) | potentiomètre papillon | zéro auto-calibré, code 12 |
| AN3 | 6 (0xFAA0) | niveau du retour d’allumage | échantillonné une fois par étincelle, diagnostic des bobines |
| AN4 | 5 (0xFA9E) | débitmètre HFM | table MAF de 256 mots 0x2B4A, intégrée, code 8 |
| AN5 | 4 (0xFA9C) | tension batterie (pont diviseur de 4,92, soit 0,1 V par pas sur l’octet) | filtrée vers VBatt_Filtered_FB47 |
| AN6 | 3 (0xFA9A) | sonde lambda amont banc 1 | O2Sensor_B1_Voltage, régulation lambda |
| AN7 | 2 (0xFA98) | sonde lambda amont banc 2 | O2Sensor_B2_Voltage, régulation lambda |
| AN8, AN9 | 1, 0 | sondes lambda aval | lecture brute par le diagnostic seulement |
La température d’air d’admission, la pression du fluide de climatisation et le niveau de cliquetis ne passent pas par cet ADC : ils sont mesurés par le satellite et transmis au CPU par la liaison ASC1.
La tension batterie suit un chemin particulier : Timer3_Interrupt_Handler (0x2FBCC) la compare au seuil 0xC8 avec anti-rebond (drapeau de sous-tension word_FD00.7), cumule 8 échantillons et divise par 32 pour obtenir VBatt_Avg_Raw, recopiée dans VBatt_Filtered_FB47 (0xFB47, environ 0,1 V par pas). Cette variable sert d’axe à quatre tables de calibration dont le temps mort des injecteurs et le temps de charge des bobines. L’échelle de 0,1 V par pas correspond à un pont diviseur de 4,92 à l’entrée AN5.
Le drapeau de sous-tension word_FD00.7 sert aussi à détecter la coupure du contact : le calculateur reste alimenté par son relais principal, et c’est la chute de tension vue sur AN5 qui fait passer DME_RunState dans l’état 4 (post-fonctionnement). Six secondes après l’arrêt du moteur, ou 300 s si le moteur n’a pas tourné, le calculateur sauvegarde l’EEPROM puis relâche P3.0, ce qui coupe son relais principal.
4. Le décodeur d’adresse PALCE16V8
Le PALCE16V8 est le décodeur d’adresse central de la carte. Pour chaque adresse présentée par le CPU, il décide quel boîtier répond (flash, RAM externe ou contrôleur CAN) et il recalcule une ligne d’adresse de la flash. Sa table de vérité complète (512 combinaisons) a été extraite sur banc puis réduite en équations, qui ont été confrontées sans aucun écart au câblage relevé et à l’image mémoire.
| Broche | Signal | Équation (bits d’adresse octet du CPU) | Effet |
|---|---|---|---|
| 15 | A13 de la flash | /A14 | délinéarisation XOR 0x4000 sur toute la flash |
| 16 | CE# flash | /A17·/A16·A15·A14·(A11+A12+A13) | flash sélectionnée partout sauf 0x0C800–0x0FFFF |
| 14 | CS# CAN | /A14+/A15+/A12+A11+A13+A16+A17 | contrôleur CAN en 0xD000–0xD7FF |
| 13 | CE1# RAM | /A14+/A15+A16+A17+/A12·/A13+/A13·/A11+A12·A13·A11 | RAM externe en 0xD800–0xF7FF (8 Ko) |
Le décodage a une granularité de 2 Ko et ne touche que le haut du segment 0. Aucune sortie du GAL ne commande le signal d’écriture de la flash : il n’assure donc aucune protection matérielle de la zone d’identité. Les broches 18 et 19, reliées entre elles par un réseau RC de 4 µs (R35 2 kΩ, C27 2 nF), ne vont vers aucun autre composant et n’ont pas d’effet fonctionnel ; la broche 17 correspond à la position « A17 » du boîtier flash, non connectée sur un 28F200 (compatibilité broche à broche avec un 28F400). La broche 12 est une constante à 1 ; le relevé de la carte la place sur le même nœud que P2.10 au travers de R33, alors que le programme lit la vitesse véhicule sur P2.10 : le câblage exact de ce nœud reste à vérifier.
La RAM externe est un boîtier unique de 8 Ko adressé à l’octet, câblé sur l’octet bas du bus. Elle fonctionne parce que la fenêtre CS1 programmée au reset (ADDRSEL1 = 0x00C1, BUSCON1 octet bas 0x6E) couvre 0xC000–0xFFFF en bus 8 bits multiplexé avec un état d’attente : c’est la zone des périphériques 8 bits (CAN et RAM), la flash 16 bits occupant le bus par défaut partout ailleurs.
5. Le microcontrôleur satellite ST9
Le satellite (U3, famille ST90E30) est un véritable microcontrôleur, avec son propre CPU, 8 Ko d’EPROM interne, ses timers, son convertisseur et sa RAM. Il exécute son propre programme, absent de l’image du CPU principal. Il échange avec le CPU par la liaison série ASC1 (partie XI).
Son rôle est plus important qu’il n’y paraît. Il commande toutes les fonctions d’émissions et de confort : les quatre chauffages de sondes lambda, la purge canister, la vanne « running losses », la ventilation du réservoir, le relais de compresseur de climatisation, la pompe à air secondaire et le volet d’échappement. Il mesure la température d’air d’admission, la pression du fluide de climatisation et le niveau de cliquetis, lit les entrées de climatisation et relaie le message de l’antidémarrage EWS. Enfin il porte le bus série de diagnostic des six étages de puissance : c’est lui qui lit l’état « court-circuit, circuit ouvert, surchauffe » de chaque sortie, y compris celles commandées par le CPU, et qui renvoie un octet de diagnostic par sortie.
6. Les étages de puissance
Les six boîtiers U5 à U10 (marquage DPS716789, brochage des HIP0082/HIP0084 en SIP-15) contiennent chacun quatre sorties MOSFET côté masse commandées par une entrée active à l’état bas, et une interface série de diagnostic. Leur bus de diagnostic (horloge, sens, donnée et une sélection par boîtier) appartient au satellite, et leur reset est commun avec celui du satellite.
| Boîtier | Sortie 1 | Sortie 2 | Sortie 3 | Sortie 4 |
|---|---|---|---|---|
U5 | injecteur 2 (CPU P2.4) | injecteur 5 (CPU P2.1) | volet d’échappement (satellite) | chauffage sonde avant 1 (satellite) |
U6 | injecteur 1 (CPU P2.0) | injecteur 3 (CPU P2.2) | ralenti, ouverture (CPU P2.9) | ralenti, fermeture (CPU P2.9 inversé) |
U7 | injecteur 6 (CPU P2.3) | injecteur 4 (CPU P2.5) | VANOS (CPU P2.12) | chauffage sonde avant 2 (satellite) |
U8 | purge canister (satellite) | running losses (satellite) | voyant moteur (CPU P3.1) | chauffage sonde arrière 1 (satellite) |
U9 | relais de clim (satellite) | relais de pompe à essence (CPU P3.5) | relais principal DME (CPU P3.0) | ventilation du réservoir (satellite) |
U10 | air secondaire (satellite) | air secondaire (satellite) | non connectée | chauffage sonde arrière 2 (satellite) |
Le CPU commande donc douze sorties (les six injecteurs, la vanne de ralenti, le VANOS, le voyant, le relais principal et le relais de pompe), le satellite les douze autres. La vanne de ralenti a deux enroulements commandés en opposition à partir de la seule broche P2.9 : directement pour l’ouverture, au travers d’un transistor inverseur pour la fermeture. Le rapport cyclique fixe la position du boisseau, sans que le logiciel ait à gérer deux sorties.
Les bobines d’allumage ne passent par aucun de ces boîtiers : elles sont commandées par des transistors dédiés (Q3 à Q8).
7. L’EEPROM 24C04
L’EEPROM série de 512 octets est pilotée en I2C logiciel sur P3.3 (SCL) et P3.12 (SDA), à l’adresse d’appareil 0xA0. Elle conserve tout ce qui doit survivre à la coupure du contact : adaptations, pannes mémorisées, compteurs, décisions d’auto-détection et copie de l’identité. Sa carte complète est donnée en partie II.
Le contrôleur CAN est décrit avec les messages qu’il échange en partie XI.
II. Organisation de la mémoire
1. La délinéarisation de la flash
Une lecture brute de la puce flash (lecture complète ou « full read », celle d’un programmateur ou des outils de lecture habituels) ne range pas les octets dans l’ordre où le processeur les voit. La correspondance est un échange de blocs de 16 Ko adjacents sur toute la puce :
adresse_vue_par_le_CPU = adresse_brute XOR 0x4000
L’origine est matérielle : la broche 15 du PALCE16V8 pilote la ligne A13 de la flash avec l’équation A13 = /A14. Inverser le bit 14 de l’adresse revient exactement à un XOR 0x4000. Le fichier réordonné pour correspondre à la vue du CPU est le fichier délinéarisé : c’est lui qu’il faut charger dans IDA, et c’est aussi l’ordre d’une lecture mémoire par la K-line (« memory read »).
Un fichier lu sans cette permutation se reconnaît facilement : il commence par le motif FA 00 XX YY répété avec une adresse qui augmente. C’est l’instruction JMPS de la table des vecteurs d’interruption, qui devrait se trouver à l’offset 0x4000 du fichier.
2. La pagination DPP
Le C166 n’adresse ses données que sur 16 bits. Pour atteindre 256 Ko, il passe par quatre registres de page DPP : les deux bits de poids fort d’une adresse de donnée choisissent le registre, les 14 bits restants donnent le décalage dans une page de 16 Ko. Le code de démarrage les initialise ainsi (0x4A0–0x4A8) :
| Adresse logique dans le code | Registre | Adresse physique | Contenu |
|---|---|---|---|
0x0000–0x3FFF | DPP0 = 4 | 0x10000–0x13FFF | calibration, page 0 (cartes carburant, allumage, ralenti, seuils) |
0x4000–0x7FFF | DPP1 = 5 | 0x14000–0x17FFF | calibration, page 1 (presque vide) |
0x8000–0xBFFF | DPP2 = 0 | 0x00000–0x03FFF | code et tables fixes du firmware |
0xC000–0xFFFF | DPP3 = 3 | 0x0C000–0x0FFFF | CAN, RAM externe, RAM interne, registres |
Cette traduction est la clé de toute la lecture du firmware. Le code s’exécute en page 0, mais quand il lit une donnée à l’adresse logique 0x059A, la lecture part en réalité en 0x1059A, dans la calibration. De même, une table que le code lit en 0xAC9C se trouve physiquement en 0x2C9C. La règle pratique : une adresse de donnée commençant par 0 à 7 prend +0x10000, une adresse commençant par 8 à B prend −0x8000, une adresse commençant par C à F est inchangée. Les sauts et appels de code, eux, utilisent le registre de segment et restent en page physique.
3. La carte de l’espace d’adressage
| Plage (vue CPU) | Contenu |
|---|---|
0x0000–0x01FF | table des vecteurs d’interruption |
0x0200–0x1C13 | secteur de démarrage : Reset_Handler, routines de programmation flash et de login |
0x1C80 | CRC du secteur de démarrage |
0x1CC0–0x1D34 | bloc d’identité d’usine : date, fournisseur, numéro de production, ISN, VIN compacté |
0x2000–0x2071 | zone d’identité du programme : numéros, CRC du programme, mot de passe, champs de codage |
0x2100–0x7FFF | code programme (partie basse) et tables fixes (0x2400–0x2D8F) |
0x8000–0xC7FF | flash effacée, jamais pointée par un DPP |
0xC800–0xCFFF | aucun boîtier (bus flottant) |
0xD000–0xD7FF | contrôleur CAN (256 registres répétés 8 fois) |
0xD800–0xF7FF | RAM externe UM6264A, 8 Ko |
0xF800–0xF9FF | aucun boîtier |
0xFA00–0xFDFF | RAM interne du CPU (1 Ko, pile, bancs de registres, mots d’état) |
0xFE00–0xFFFF | registres SFR |
0x10000–0x15FFF | calibration (24 Ko) |
0x16000–0x1FFFF | flash non utilisée |
0x20000–0x3FFFF | code programme principal |
Le code applicatif est donc réparti en deux zones avec la calibration entre les deux, ce qui permet de recalibrer sans déplacer le code. Les offsets bruts 0x08800–0x0BFFF de la puce (14 Ko) sont physiquement inaccessibles au processeur : le GAL y désélectionne la flash pour placer le CAN et la RAM. Seul un programmateur peut les lire.
4. Les trois types de fichiers
Trois fichiers circulent couramment, avec trois conventions d’adresse. Pour une table de calibration d’adresse logique L :
| Fichier | Taille | Ordre | Adresse de la table |
|---|---|---|---|
| lecture partielle (calibration) | 24 Ko | délinéarisé, extrait 0x10000–0x15FFF | L |
| lecture mémoire (memory read, base IDA) | 256 Ko | délinéarisé | L + 0x10000 |
| lecture complète (full read) | 256 Ko | ordre physique de la puce | L + 0x14000 |
Dans une lecture mémoire de 256 Ko, la plage 0x0C800–0x0FFFF ne contient pas de flash mais l’état vivant du CAN, des deux RAM et des registres au moment de la lecture. Les valeurs « réalistes » qu’on y trouve viennent donc du calculateur sous tension.
5. Les zones d’identité
La flash contient deux zones d’identité. La première, dans le secteur de démarrage, est écrite en usine : semaine et année de fabrication (0x1CD5), indice de codage, numéro de fournisseur (0x1CDB), numéro de production (0x1CE5, dont les quatre derniers caractères en 0x1CEA forment l’ISN, le code partagé avec le boîtier EWS) et le champ d’information utilisateur en 0x1D07 (VIN compacté sur 13 octets, date, numéros de logiciel, d’homologation et d’assemblage). Cette zone n’est jamais transmise par une écriture K-line : le VIN ne se modifie qu’en programmant la puce hors du véhicule.
La seconde, au début du programme, porte l’identification du programme 111006064101 en 0x2001 (les positions 9 et 10 donnent « 41 »), le numéro de pièce 1429861 répété six fois à partir de 0x2025, le CRC attendu du programme en 0x2050, les octets de validation de la liaison satellite en 0x205A, l’octet d’activation des CRC en 0x205C, le mot de passe K-line 6577205110 en 0x205E et les champs du codage en 0x2068. L’identification de la calibration est en 0x10012 (1110060041010000).
Le VIN est stocké de façon compacte : le premier caractère tient sur un octet, les seize suivants sur 6 bits chacun, extraits par divisions successives avec l’alphabet 0-9A-Z. La date tient sur deux octets : jour sur 5 bits, mois sur 4 bits, année sur 7 bits.
6. La carte de l’EEPROM
Au démarrage, PersistedState_MasterRestore (0x24F60) lit un bloc de 422 octets depuis l’offset 0 de l’EEPROM vers la RAM 0xEF02, puis le répartit dans les variables de travail. Une fonction de maintenance périodique réécrit chaque catégorie, et la séquence d’extinction qui suit la coupure du contact (avant l’ouverture du relais principal) sauvegarde les pannes et les adaptations. Chaque bloc est protégé par une somme de contrôle et par un test de plausibilité : un bloc incohérent est remplacé par une valeur neutre.
| Offset | Taille | Contenu |
|---|---|---|
0x000–0x005 | 6 o | horodatage de panne (trois copies) |
0x006–0x009 | 4 o | compteur d’heures maître |
0x00E–0x051 | 68 o | moyennes des 64 cellules d’adaptation anticliquetis et cellule annexe (neutre 0x80) |
0x052–0x055 | 4 o | correction de purge canister |
0x056–0x05B | 6 o | position de repos apprise de la came (VANOS) |
0x05C–0x05F | 4 o | zéro du papillon |
0x060–0x067 | 8 o | groupe de cinq octets E9xxCluster et somme de contrôle |
0x068–0x073 | 12 o | adaptations lambda additive et multiplicative des deux bancs |
0x074–0x0E9 | 118 o | pannes mémorisées (dix au plus) |
0x0EA–0x0F5 | 12 o | adaptation d’air de ralenti et décalage de ralenti réglé au testeur |
0x180–0x183 | 4 o | température moteur mémorisée à l’arrêt après une marche courte (redémarrage à chaud) |
0x18E–0x191 | 4 o | index de séquence tournante |
0x196–0x199 | 4 o | décisions d’auto-détection (boîte automatique, sondes lambda) |
0x1DD–0x1E0 | 4 o | état de programmation de la flash (trois copies) |
0x1E3–0x1FC | 26 o | copie de l’identité du programme (0x2001, 0x2025, 0x203A) |
La copie de l’identité est écrite par IdentityBlock_ProvisionToEEPROM (0x1A8E) et relue au démarrage par IdentityBlock_LoadFromEEPROM (0x1ACA) dans la RAM 0xE74E–0xE76F. C’est elle que renvoie l’identification en session de programmation et pendant le login : elle date du dernier provisionnement et peut différer du programme réellement en flash.
7. La RAM et les mots d’état
La RAM externe (0xD800–0xF7FF) contient la grande majorité des variables : cellules d’adaptation anticliquetis en 0xD840, instantanés de diagnostic en 0xDA0C–0xDAB2, bloc d’extension en 0xDC20, tampons K-line et algorithmes flash en 0xE320–0xE767, contrôle moteur en 0xE8C6–0xE9FE, gestion des pannes en 0xEA00–0xEC8F, corrections carburant en 0xEC90, structures lambda en 0xED56 et 0xED90, miroir de l’EEPROM en 0xEF00, échanges avec le satellite en 0xF138–0xF19C et minuteries logicielles en 0xF19E–0xF1FE. Plus de 1 200 positions y sont nommées.
La RAM interne (0xFA00–0xFDFF) contient les variables rapides du temps réel (captures CAPCOM, résultats ADC, régime RPM_Word en 0xFAE4 et RPM_Byte en 0xFAE6, tension 0xFB47) et surtout la zone bit-adressable 0xFD00–0xFDFF, où le firmware range tous ses indicateurs dans des mots d’état testables en une instruction. Les plus importants sont :
| Mot | Rôle |
|---|---|
word_FD06 | état global : .3 moteur en marche, .5 moteur tournant, .10 cycle de chauffe validé |
word_FD0A | configuration et antidémarrage : .0 blocage actif (entrée satellite), .1 posé à la mise sous tension sans ce codage, .5 démarrage non autorisé, .9 EWS actif, .11 clim à capteur de pression |
word_FD14 | état moteur, un bit parmi six : arrêt, lancement, ralenti, charge partielle, décélération papillon fermé, coupure en frein moteur |
word_FD18 | entrées véhicule : fils ABS/ASC, clim, demande compresseur, rapport engagé, démarrage refusé |
word_FD1E / word_FD20 | masque et polarité des bits de word_FD18, fixés par le codage |
word_FD2E | VANOS : engagé (.0), came en pleine avance, came hors fenêtres, position de repos apprise, temporisation après démarrage écoulée (.6), température moteur suffisante (.9) |
word_FD30 à word_FD36 | drapeaux « défaut présent » de chaque contrôle |
word_FD42 | interface ABS/ASC : réduction de couple, retard, coupure totale, modes MSR |
word_FD4C | drapeaux issus des octets de codage (ConfigFlags_FD4C) |
word_FD4E | mot pivot de la synchronisation moteur (.0 = cluster de timing coupé, .8 = came absente ou figée, .9 = travail à faire par la boucle de fond) |
word_FD50 | ticks de l’ordonnanceur et coupure d’allumage (.10) |
Les unités de base reviennent partout : un pas de Timer 1 vaut 5,333 µs (temps d’injection et de charge), un facteur carburant vaut 1,0 à 0x1000, une correction centrée vaut 0 % à 0x8000, une température linéarisée se convertit par °C = 0,75 × x − 48 et un angle par 0,375° vilebrequin par pas.
8. Le format des tables de calibration
Toutes les tables sont lues par deux fonctions partagées (environ 120 appels). Table_FindBreakpointIndex reçoit l’adresse de l’en-tête, suit le pointeur vers un axe partagé, cherche où tombe la clé dans cet axe et mémorise l’index et la fraction d’interpolation. Table_LookupValue (octet) ou Table_LookupValue_Word (mot) lit ensuite la valeur avec interpolation linéaire. Les cartes à deux dimensions passent par Table3D_BilinearLookup (interpolation bilinéaire) ou Table3D_Lookup_NoInterp.
en-tête (adresse logique) : [ pointeur vers l'axe : 2 octets ][ valeur0 ][ valeur1 ] ...
axe partagé : [ nombre de points : 1 octet ][ clé0 ][ clé1 ] ... (clés croissantes)
carte 2D : adresse - 4 = axe des colonnes, adresse - 2 = axe des lignes,
cellule = grille[nombre_de_colonnes × index_ligne + index_colonne]
Un même axe peut servir à plusieurs tables. Deux axes structurent beaucoup de corrections : l’axe de tension batterie (0x104CC, huit points de 5,9 à 24,5 V) et l’axe de température moteur (0x11A7E, huit points de −30 à +90 °C). Le code lit au total 249 tables différentes, toutes dans la page 0 de la calibration.
III. Démarrage et fonctionnement temps réel
1. Du reset au lancement de l’application : Reset_Handler
À la mise sous tension, le CPU saute au vecteur de reset, qui mène à Reset_Handler (0x430, aussi nommé Reset_HardwareBootstrap). Avant même d’initialiser la pile, il programme le bus : SYSCON règle le bus par défaut de la flash (16 bits multiplexé, sortie d’horloge CLKOUT active pour le contrôleur CAN, A16/A17 sortis sur le port 4), puis ADDRSEL1 = 0xC1 et BUSCON1 ouvrent la fenêtre CS1 de 0xC000 à 0xFFFF en bus 8 bits pour la RAM et le CAN. Il configure ensuite P3.8 en sortie haute et P3.9 en entrée pour la liaison série vers le satellite.
Viennent ensuite l’amorçage classique du C166 : chien de garde, pointeurs de pile (STKOV, STKUN, SP) puis l’instruction EINIT, qui verrouille définitivement les registres système protégés. Le relais principal (P3.0) passe en sortie et les registres de page sont fixés (DPP0 = 4, DPP1 = 5, DPP2 = 0). Vient alors le test des mémoires vives, par écriture et relecture des motifs 0x5555, 0xAAAA et 0x0000 : la RAM interne (0xFA00–0xFA13 puis 0xFA16–0xFDFE) et la RAM externe par mots (0xD800–0xDBFE, 0xE420–0xF200, puis 0xDC00–0xE41E, zone sautée si l’octet flash 0x2000 vaut 0xA8), enfin 0xD080–0xD0FF octet par octet. Le résultat est rangé dans Reset_BootStatus (0xE732) : 0x0002 pour un échec des tests par mots, 0x0008 pour un échec du test par octets. Il pourra lever le code défaut 100. Après un reset par le chien de garde, la lecture faite en 0x43E passe par DPP2 = 2 et Reset_BootStatus vaut 0xFFFF.
Le secteur de démarrage relit alors l’état de reprogrammation de la flash. IdentityBlock_LoadFromEEPROM (0x1ACA) recopie 34 octets de l’EEPROM (0x1DD–0x1FE) vers la RAM 0xE74E–0xE76F, puis FlashProg_State_Restore (0x1A1C) reconstitue FlashProg_State (0xE740) à partir de ses trois copies, qui valent la valeur, la valeur + 1 et la valeur + 2. Si les copies ne concordent pas, l’état vaut 0.
FlashProg_State = 1(programme effacé, écriture non terminée) : la K-line est configurée à 9615 bauds et le calculateur entre dans la session de programmationBootSector_FlashSession_Main(0x073C). L’application n’est pas lancée, ce qui garantit qu’un calculateur interrompu en pleine écriture reste toujours joignable.- Autres valeurs : l’application est appelée par
AppEntry_CallByIndex(0x0720) via l’entrée 0 deAppEntry_Table(0x233A), qui mène àSystemBoot_MasterInit.
2. L’initialisation logicielle : SystemBoot_MasterInit
SystemBoot_MasterInit (0x261A8) donne vie à chaque sous-système l’un après l’autre. Il reconfigure les broches selon la variante matérielle, détecte le contrôleur CAN (CAN_DetectRegisterLayout), active les interruptions, lance le convertisseur en balayage continu (Init_ADC_AutoScan_PEC, ADCON = 0xA9) et configure la liaison ASC1 vers le satellite (Init_ASC1_EWS_Channel).
Il vérifie ensuite la calibration. Si la table des régions CRC (0x15E00) est vierge, la calibration est considérée comme absente et le calculateur reste en mode service (ni allumage ni injection). Sinon, quatre caractères de l’identification de la calibration (0x1000C–0x1000F, « 0641 ») sont comparés à l’identification du programme ; une différence lève le code 100.
Viennent ensuite la relecture de l’horodatage de panne, la validation de l’index de séquence tournante, puis le décodage des cinq octets de codage par CodingBytes_Unpack_ApplyFlags (0x26800, partie IX), la copie du bloc d’extension (22 octets de la calibration 0x10050–0x10065 recopiés à chaque démarrage en 0xDC20, partie V) et la restauration de toutes les valeurs apprises par PersistedState_MasterRestore (0x24F60). Une réinitialisation globale efface les cibles, temporisations et compteurs du cycle précédent, les trois contrôles CRC sont lancés (IntegrityChecks_ReinitAfterCoding) et la tâche 46 CommInit_And_AbsLines_Checks est postée. Tout se termine par l’appel à MainSuperLoop_Forever, qui ne revient jamais.
3. La boucle principale et l’ordonnanceur
Le MS41 n’a pas de système d’exploitation. Son travail est découpé en 58 tâches numérotées de 0 à 57, dont les adresses forment Task_EntryTable (0x2410). Les interruptions et le tick de 10 ms ne font qu’ajouter des numéros de tâche dans trois files circulaires de 32 entrées : la file haute TaskQueue_High (0xE865), la file moyenne TaskQueue_Mid (0xE885) et la file basse TaskQueue_Low (0xE8A5).
MainSuperLoop_Forever (0x208EA) est un while(1) : chaque chemin de sortie revient à son propre début. À chaque tour, la boucle regarde si un événement d’allumage a eu lieu (word_FD4E.9, posé à chaque changement de cylindre, soit tous les 120° vilebrequin) et poste alors les tâches synchronisées sur le moteur ; si le tick de 10 ms est levé (SchedTick_Flags_FD50.14), elle appelle BackgroundTask_Scheduler (0x3248) qui poste les tâches périodiques ; puis elle exécute une seule tâche, prise dans la file haute, sinon la moyenne, sinon la basse. Une tâche n’est jamais interrompue par une autre tâche, seulement par les interruptions. Quand les trois files sont vides, la boucle fait avancer les autotests d’intégrité (MultiCheck_Dispatcher_E655) au lieu de rester inactive.
Ce découpage applique un principe que l’on retrouve partout dans le firmware : les routines d’interruption sont courtes, elles se contentent de lever un drapeau, et c’est la boucle de fond qui fait le travail lourd. Un calcul non critique ne retarde ainsi jamais une injection ou une étincelle.
À chaque allumage, la file haute reçoit dans l’ordre le calcul du régime et de la masse d’air (tâche 4), le contrôleur de coupure et de limiteur (6), le temps de charge par cylindre (28), le diagnostic des bobines (34), la régularité moteur au ralenti (56), les corrections transitoires de carburant (15), l’anti-à-coups (48), l’avance finale (11), le temps d’injection (12) et l’instantané de diagnostic (3). Selon l’index du cylindre, d’autres tâches ne tournent qu’une ou deux fois par cycle : contrôle vilebrequin/came, position de came VANOS, consommation, adaptation du cliquetis, protection catalyseur et correction de charge à froid.
Le tick de 10 ms poste la machine d’états DME_RunState_Machine, la lecture du papillon, le contrôle de l’antidémarrage (tâche 53, tant qu’il est en attente), la régulation lambda et le groupe TaskGroup00_10ms (interface ABS/ASC, bus CAN, dispatcher de pannes, gestion du compresseur). Toutes les 100 ms passent le groupe TaskGroup37_100ms (VANOS, volet, contrôles ABS/ASC et EGS1, purge), les paramètres dépendant de la température, la pression de clim, le chauffage des sondes et la purge. Toutes les secondes passent le limiteur de vitesse, la protection catalyseur et le groupe TaskGroup52_1s (zéro papillon, plausibilité de la charge). La tâche 45 (blocage par une entrée du satellite, partie X) n’est postée qu’avec le codage « EWS supprimé, entrée satellite » (word_FD1E.7). Les tâches de ralenti sont postées par IdleControl_PostTasks (0x29B14) : toutes les 10 ms sous 2500 tr/min, toutes les 40 ms au-dessus.
BackgroundTask_Scheduler gère aussi trois tables de minuteries logicielles : la table A (14 compteurs décomptés toutes les 10 ms, callbacks en 0x2964), la table B (23 compteurs à 100 ms, callbacks en 0x2980) et la table C (12 compteurs à 1 s, callbacks en 0x29AE). Les valeurs de calibration chargées dans ces minuteries s’expriment donc en 10 ms, 100 ms ou 1 s. À l’inverse, un compteur décrémenté par une tâche postée à chaque allumage avance d’un tiers de tour moteur par pas : sa durée dépend du régime.
4. Les interruptions
La table des vecteurs figée dans le silicium (à partir de 0x0) ne contient que des sauts vers une seconde table décalée de +0x2100, entretenue par la chaîne d’outils Keil C166, qui saute à son tour vers le vrai gestionnaire. Les principaux vecteurs sont :
| Vecteur | Gestionnaire | Rôle |
|---|---|---|
| CC0INT à CC5INT | Injector1_CompareEnd_ISR_P2_0 … Injector4_CompareEnd_ISR_P2_5 | fin d’impulsion de chaque injecteur |
| CC6INT / CC7INT | CC6_IgnitionDwell_VectorHandler (0x326D0) / CC7_IgnitionDwellStart_VectorHandler (0x3278C) | charge des bobines |
| CC13INT | CC13_Capture_ISR (0x31FAA) | capteur d’arbre à cames : période d’un tour et premières injections groupées |
| CC15INT | Injector_CAPCOM_ISR (0x405A) | machine à dents du vilebrequin (120 cas, table 0x2A32) : armement des injections, fenêtre de cliquetis, relance de l’allumage |
| T4INT | CylinderSequence_AngleStateMachine (0x5510) | machine à états angulaire : séquence des cylindres et étincelle |
| T5INT | CC13_CaptureTimeout_ShutdownHandler (0x3265C) | détection de perte du signal moteur |
| T6INT | CC15_Interrupt_Handler (0x4E78) | timer d’angle : trou de la couronne, et machine à dents du mode secours sans capteur de vilebrequin (table 0x2B6A) |
| T0INT | T0_Tick10ms_ISR (0x322EC) | base de temps 10 ms, PWM de ralenti, relance ASC1 |
| T3INT | Timer3_Interrupt_Handler (0x2FB42) | tension batterie, débitmètre, retour d’allumage, sécurité bobines |
| CC10INT | gestionnaire CC10 (0x326BE) | capteur de vitesse véhicule (comptage des impulsions) |
| CC14INT | TPS_PWM_CC14_ISR (0x2FCFC) | sortie PWM papillon |
| T1INT | Timer1_Interrupt_Handler (0x32606) | compte les débordements du Timer 1 pour la mesure de la période de came |
| ADCINT / ADEINT | ADC_ConversionComplete_ISR / ADC_Error_ISR | fin de balayage et erreur ADC |
| S0TINT / S0RINT / S0EINT | KLine_ASC0_TransmitComplete_ISR, KLine_RxByte_ISR, KLine_ASC0_Error_Recovery_ISR | K-line |
| S1TINT / S1RINT / S1EINT | loc_325C2, EWS_ASC1_Receive_ISR, EWS_ASC1_PEC_TransceiverSetup | liaison ASC1 avec le satellite |
Cinq vecteurs bouclent sur eux-mêmes (CC8INT, CRINT, CC9INT, CC12INT, T2INT) : ces sources ne sont jamais armées, et si l’une d’elles se déclenchait par accident le CPU se figerait jusqu’au reset par le chien de garde plutôt que d’exécuter du code au hasard. Le contrôleur CAN, en particulier, n’est pas servi par interruption mais scruté depuis la boucle principale.
5. Les sécurités
Le firmware préfère systématiquement couper proprement plutôt que de continuer sur un état incertain. Les quatre exceptions graves du processeur mènent toutes à un arrêt sûr :
| Exception | Gestionnaire | Réponse |
|---|---|---|
| NMI (défaut d’alimentation, oscillateur) | NMI_EmergencyShutdown_Handler (0x2FF7A) | coupe le port 2 (injecteurs), puis fait clignoter le voyant moteur sans fin |
| débordement de pile | SafetyShutdown_KillIgnitionInjection (0x325D2) | coupe allumage et injection, ouvre le relais DME, fige le CPU |
| sous-débordement de pile | StackUnderflow_Trap_SafeState (0x325EC) | sorties au repos, relais coupé, attente du reset |
| opcode illégal | SafetyShutdown_KillIgnitionInjection_Dup (0x2FCE2) | arrêt moteur sécurisé |
Le signal de position moteur, le plus critique de tout le système, est surveillé par deux mécanismes matériels indépendants qui aboutissent au même bloc de désactivation du cluster de timing (Timer 5, CC13, CC15, Timer 6) et posent word_FD4E.0. Le premier, CC13_CaptureTimeout_ShutdownHandler, détecte une capture qui n’évolue plus : il est armé par la première capture valide, avec un délai égal à huit fois la période moteur courante, donc plus tolérant à bas régime qu’à haut régime. Le second compte les échecs de séquencement de la machine à dents dans CrankSync_ErrorCounter : le compteur monte à chaque échec et redescend quand la séquence se déroule normalement (0x4F2E) ; des échecs répétés coupent le cluster.
Enfin, chaque bobine dispose d’un filet de sécurité indépendant de la synchronisation moteur. À chaque interruption du Timer 3, pour chaque broche P1.0 à P1.5 encore en charge, un compteur propre au cylindre (PerCylinder_DwellTiming_Table), chargé de quelques unités au début de la charge (2 à 4 au ralenti), est décrémenté ; s’il atteint 0 avant la coupure normale par comparaison, la broche est forcée haute et la bobine est coupée. Une bobine ne peut ainsi jamais rester sous tension, même en cas de dérive logicielle.
6. Les bases de temps
Init_CAPCOM_Timer01 programme T01CON = 0x4340 : le Timer 0 compte à 1,5 MHz et se recharge à 0xC568, soit 15 000 comptes ou 10,0 ms. T0_Tick10ms_ISR pose les drapeaux 10 ms, 100 ms et 1 s de l’ordonnanceur, recharge le PWM de la vanne de ralenti et relance les échanges avec le satellite. Le Timer 1, qui compte à 187,5 kHz (5,333 µs par pas), sert de référence à toutes les comparaisons d’injection et d’allumage. Le Timer 3 tourne à 1 ms exactement et cadence la tension batterie, le débitmètre et le délai de silence de la K-line.
La machine d’états DME_RunState_Machine (0x30650, DME_RunState en 0xE9ED) suit l’état global du calculateur. L’état 5 est le mode service : allumage et injection neutralisés jusqu’à la coupure du contact. On y entre par DME_EnterServiceState, notamment après un test d’actionneur lancé moteur arrêté, un déverrouillage K-line ou une écriture flash.
IV. Synchronisation moteur et allumage
1. La capture de la position moteur
La position du vilebrequin est lue sur une cible 60-2 : 60 positions de 6°, dont deux dents manquantes qui repèrent un point fixe du tour. Le capteur est relié à deux entrées du CPU : P2.15, capture du canal CAPCOM 15, qui déclenche une interruption à chaque dent, et P3.2 (CAPIN), entrée de capture du Timer 5, qui mesure la période des dents. Chaque dent fait avancer la machine à dents décrite au chapitre suivant, qui cadence l’injection, la fenêtre de cliquetis et la relance de l’allumage.
Le capteur d’arbre à cames arrive sur P2.13, capture du canal CAPCOM 13 sur les deux fronts. Sa cible donne un front par tour vilebrequin : la came est à un niveau pendant un tour et à l’autre niveau pendant le tour suivant. À chaque front, CC13_Capture_ISR (0x31FAA) lit la valeur capturée par le Timer 1, dont les débordements sont comptés par Timer1_Interrupt_Handler, calcule l’écart avec la capture précédente et le divise par 60 à l’aide de l’unité de division matérielle : le résultat, CC13_CrankPeriod (0xFA7C), est la durée moyenne d’une dent sur le dernier tour. Cette période est rejetée si elle sort de la plage 22 à 5859 pas, ce qui correspond à environ 32 à 8500 tr/min, ou si elle varie trop brutalement d’un échantillon à l’autre (rapport supérieur à 4 ou inférieur à 1/8). Elle sert à charger le Timer 6, l’horloge d’angle qui remplace les dents quand le signal du vilebrequin manque.
Le régime est calculé à chaque segment de 120° par la tâche 4 EngineSpeed_AirMass_SegmentCalc (0x2C47C) : RPM_Word = 30 000 000 / Crank_SegmentPeriod donne directement le régime en tr/min, et RPM_Byte en est la version sur un octet à 32 tr/min par pas. La même tâche calcule le gradient de régime, la masse d’air moyenne, l’index du cylindre courant (CylIndex_Latched, 0xFB49) et la position du front d’arbre à cames (CamEdge_CrankPosition, 0xFB46).
L’arbre à cames sert aussi à distinguer les deux tours du cycle de 720°. Il est échantillonné deux fois par tour, juste avant le trou de la couronne (dents 53/54 et 113/114 de la machine à dents), et chaque échantillon est décalé dans CrankCam_SyncPattern (0xFB4E). Avec un signal normal, le motif alterne entre 0x33 et 0xCC, et la paire lue juste avant le trou doit donner 0x0C au premier tour et 0x03 au second. Quand les quatre derniers échantillons sont égaux, la came est absente ou figée : word_FD4E.8 est posé, l’injection passe en groupes et l’allumage en double étincelle, le calculateur ne sachant plus quel PMH est celui de la combustion. La plausibilité de l’ensemble est contrôlée deux fois par cycle par CC13_CC15_TimingPlausibility_Check (0x21EAA), qui lève le code 83 (vilebrequin) ou le code 65 (arbre à cames).
2. La machine à dents du vilebrequin
À chaque dent du vilebrequin, Injector_CAPCOM_ISR (0x405A, vecteur CC15INT) bascule sur sa propre banque de registres (CP = 0xFC42), incrémente l’index rl0 puis saute par jmpi (0x406A) au cas lu dans la table 0x2A32. L’index va de 1 à 121 sur un cycle de 720° : 120 positions de dent sur deux tours, plus les cas de reprise autour du trou. La plupart des cas ne font rien ; les autres exécutent une action précise à un angle précis. Le motif se répète tous les 20 index, soit 120°, décalé d’un cylindre dans l’ordre d’allumage 1-5-3-6-2-4.
Pour chaque cylindre, le PMH étant pris à 0° :
| Angle | Index (cylindre 1) | Action |
|---|---|---|
| −18° | 12, 32, 52… | armement de l’injection du cylindre situé deux rangs plus loin dans l’ordre d’allumage (word_FD04.8–.13), puis T4IR |
| 0° (PMH) | 15, 35, 55… | P3.6 = 1 (ouverture de la fenêtre de cliquetis) et émission du message ASC1 0x101 (gain et position du cylindre) |
| +24° | 19, 39, 59… | temps écoulé depuis la dernière capture (CC15 − 0xFA78) rangé en 0xFA8C, word_FD02.13, T4IR : relance de la machine angulaire de l’allumage |
| +36° | 1, 21, 41… | capture et lancement du Timer 5 (0xFA7A) |
| +42° | 2, 22, 42… | arrêt du Timer 5 ; CylSeq_CurrentCyl (0xDA62) reçoit ce cylindre, 0xFA80 et 0xF139 le suivant ; bascule du jeu de recharges du temps de charge (word_FD00.0) ; word_FD4E.9 (tâches moteur demandées à la boucle) ; impulsion de consommation sur P2.11 aux index 2 et 62 seulement |
| +48° | 3, 23, 43… | demande du message 0x102 (niveau de cliquetis) au satellite, 0xF138 ← gain |
| +60° | 5, 25, 45… | P3.6 = 0 (fermeture de la fenêtre de cliquetis) |
- Trou de la couronne (index 57 à 61 et 117 à 121) : le Timer 6 est chargé avec 1,5 fois la période de la dernière dent pour recréer les dents manquantes, la capture
CC15est coupée pendant le trou puis réactivée, et l’index repart à 1 après le cas 121. - Reprise : l’index de reprise de la machine angulaire
AngleSM_ResyncIndexreçoit0x3Aà l’index 44 et0x76à l’index 104 ; les bitsword_FD4E.4à.6sont remis à 0 aux index 56 et 116. - Lecture de la came aux index 53/54 et 113/114 (chapitre précédent).
- Prochain événement d’injection :
Inj_NextEvent_ToothIdx(0xFAB8) etInj_NextEvent_Case(0xFAB9, table0xAA1A) désignent la dent et le cas du prochain armement.
Mode secours sans capteur de vilebrequin. Si le signal du vilebrequin disparaît moteur tournant (code 83), le moteur continue de tourner. CC15_Interrupt_Handler (0x4E78, vecteur T6INT) cadence alors les dents avec le Timer 6, chargé à partir de la période mesurée sur la came (CC13_CrankPeriod), et saute par une seconde table, 0x2B6A (jmpi en 0x4F70). Les actions sont les mêmes (injection, fenêtre de cliquetis, messages au satellite, impulsion de consommation), sans lecture de la came ni mesure par le Timer 5, et word_FD02.3 est posé à chaque changement de cylindre. La précision angulaire dépend alors du calage de la came.
3. Le calcul de l’avance
L’avance est calculée dans la boucle de fond, puis placée en temps réel par la machine à états angulaire. La chaîne compte quatre étapes :
BaseMaps_PerEngineState_Calc (0x2F91E) carte de base selon l'état moteur
+ correction VANOS pondérée
-> IgnTiming_BaseValue (0xE96E)
IgnTiming_Accumulate_Corrections (0x3193A) corrections (tables 0x1F46, 0x1BA2, 0x0FFA...)
-> IgnTiming_SetPoint (0xE984)
IgnTiming_Ramp_And_TorqueModel (0x31562) rampe asymétrique + régulation de ralenti
par l'allumage
-> IgnTiming_Ramped (0xE988)
complément : CylinderSeq_AccumValue (0xFB00) = 255 - (IgnTiming_Ramped >> 8)
-> CylinderSequence_AngleStateMachine (0x5510, T4INT)
La carte de base dépend de l’état moteur (word_FD12 & 7). Au lancement, l’avance suit une courbe fonction du régime (0x1BAA) corrigée par la température (« Ignition Timing – Cranking – ECT Correction », 0x1BB0). Au ralenti, elle vient de la carte 0x1F30 (régime × charge). Dans les autres états, elle vient de « Ignition Timing – Base » (0x0E26) si la régulation lambda est codée, ou de « Ignition Timing – Base 2 » (0x0D62) pour les véhicules sans sonde lambda : cette seconde carte n’est pas une carte de secours, c’est la carte des moteurs non catalysés. S’y ajoute « Ignition Timing – Base – VANOS Correction » (0x11C8), centrée sur 128 et pondérée par la position réelle de la came.
La rampe lisse les changements d’avance avec des pentes différentes à la montée (0x110, 0x112, 0x11C) et à la descente (0x10E). C’est aussi à cet endroit qu’agit le gouverneur de ralenti par l’allumage : en charge de ralenti, l’avance est rognée ou augmentée pour tenir le régime, l’allumage étant l’actionneur de couple le plus rapide. La régulation d’air de ralenti est une fonction séparée (partie VI).
L’avance n’est jamais convertie en degrés dans la chaîne de calcul. Elle reste en valeur brute jusqu’au complément, qui en fait un angle à décompter. La machine à états lui ajoute d’abord la correction de cliquetis du cylindre (Knock_CylState, 0xFB26), puis découpe l’octet : le quartet haut donne un nombre de dents, le quartet bas une fraction de dent en seizièmes. Un pas vaut donc 6°/16 = 0,375° vilebrequin, ce qui fixe l’échelle de toutes les cartes d’avance.
4. La carte d’avance de base
La carte « Ignition Timing – Base » (0x10E26) compte 16 lignes de régime et 12 colonnes de charge, soit 192 octets. Ses axes réels sont :
- régime (tr/min) : 420, 640, 900, 1200, 1500, 1730, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6400 ;
- charge (
EngineLoad, valeur brute 16 bits) : 2359, 3303, 4388, 5662, 7219, 9531, 11843, 14154, 16985, 20288, 23591, 30196.
Ses valeurs brutes vont de 31 à 171. Elles ont la forme attendue d’une carte d’avance : l’avance croît avec le régime et décroît avec la charge, avec un maximum vers les régimes moyens à hauts en charge légère et un minimum à forte charge et bas régime. La correction VANOS ajoute de l’avance en charge légère (jusqu’à +19 pas) et en retire à forte charge (jusqu’à −16 pas).
D’autres cartes agissent sur l’allumage : « Ignition Retard – ASC » (0x0F1E) pour l’antipatinage, « Ignition Timing – Anti-Jerk » (0x0EEA) pour l’anti-à-coups, et « Ignition Retard – Decreasing TPS – Step Size » (0x18AC) pour la décélération (partie V).
5. Le placement de l’étincelle et la charge des bobines
CylinderSequence_AngleStateMachine (0x5510), déclenchée par le Timer 4, gère la séquence des cylindres. Elle calcule un index de dispatch à partir du canal en cours (CC6_CC7_ChannelIndex) et du phasage d’injection (InjTiming_Angle_FAE2, de 0 à 100 en cinq segments de 20), et saute dans la table 0x2C9C (24 pointeurs). Les angles y sont exprimés modulo 120, l’intervalle entre deux allumages d’un six-cylindres quatre temps. La même machine applique la coupure de cylindre du limiteur (partie VII).
L’angle est converti en instants de comparaison sur les canaux CC6 (début de charge) et CC7 (fin de charge et étincelle). Deux tables de charge existent, choisies par word_FD4E.8 : 0x29CC quand la came est présente (allumage séquentiel), 0x29DE quand elle est absente ou figée. Le temps de charge de base, IgnDwell_Time_FB02, vient de « Ignition Timing – Dwell Time » (0x054A), fonction de la tension batterie : de 20 ms sous 7 V à 1,45 ms vers 24 V. Quand la tension et la température sont basses, une fonction multi-étincelles recharge la bobine entre plusieurs étincelles (« Multi-Spark – Dwell Time », 0x0538).
L’allumage est neutralisé globalement par SchedTick_Flags_FD50.10, posé en cas d’intervention ABS/ASC maximale, de blocage par l’antidémarrage ou tant que le système n’est pas initialisé avec une tension correcte : CC6_IgnitionDwell_VectorHandler ne charge alors aucune bobine.
6. Le retour d’allumage et le diagnostic des bobines
Le MS41 surveille chaque étincelle par un circuit de retour d’allumage. Au début de chaque charge, P2.7 est mis à 0 et l’état de l’entrée P3.7 est relevé ; le Timer 2, en mode porte, mesure la durée pendant laquelle P3.7 reste haute entre deux étincelles (IgnFb_Duration_ChN, en 0xFB2C + 4 × cylindre) ; l’entrée analogique AN3 est échantillonnée une fois par étincelle (IgnFb_Level_ChN), puis P2.7 est remis à 1.
La tâche 28 IgnDwell_PerCyl_Feedback_Task compare le niveau de retour à la carte « Ignition Dwell – Feedback Threshold » (0x05BA) : au-delà, le facteur de charge du cylindre baisse, ce qui ajuste le temps de charge cylindre par cylindre. La tâche 34 IgnFeedback_PerCylinder_Diag compare la durée de retour à la valeur minimale attendue (« Ignition Feedback Diagnosis – Minimum Value », 0x044C), moteur chaud et sous un régime limite. Une bobine en défaut lève son code (1, 2, 3, 29, 30, 31 selon le cylindre) et coupe l’injection de ce cylindre pour protéger le catalyseur. L’absence de retour sur les six cylindres lève le code 56, et trois bobines en défaut ou plus lèvent le code 210 (résistance de retour d’allumage).
7. L’anti-à-coups
La tâche 48 AntiJerk_Detect_And_Retard (0x20132) détecte les oscillations de la transmission. Elle calcule AntiJerk_PeriodGradient (0xE964) = 262 144 × (T récent − T précédent) / T récent, où T est la durée du dernier segment de 120° à bas régime, ou de trois segments (360°) au-dessus de « Anti-Jerk – Gradient Source RPM ». Une valeur négative signifie que le moteur accélère ; 1 % de variation de période vaut 2621 pas.
Quand le gradient passe sous le seuil de détection (« Anti-Jerk – Detection Threshold », table « First » pour la première oscillation, « Next » pour les suivantes), un retard d’allumage tiré de « Ignition Timing – Anti-Jerk » (0x0EEA) est appliqué, puis retiré quand le gradient dépasse le seuil de fin. Les seuils sont stockés décalés de 0x8000 ; sur ce calculateur, la détection se fait entre −0,7 et −2,1 % de variation de période et la fin entre +0,5 et +3,0 % selon le régime.
V. Injection et mélange carburant
1. Les états moteur
Tout le calcul carburant dépend de l’état moteur, tenu par EngineState_Machine (0x30BD8) dans word_FD12 (bits 0 à 2 : numéro de l’état courant) et dans word_FD14 (un bit par état) : arrêt, lancement, ralenti, charge partielle, décélération papillon fermé et coupure d’injection en frein moteur. La transition d’un état à l’autre est mémorisée dans word_FD16, ce qui permet par exemple d’appliquer une correction particulière à la reprise après une coupure.
word_FD16 porte un bit par transition :
| Bit | Transition | Bit | Transition |
|---|---|---|---|
| 0 | lancement → charge partielle | 7 | décélération → ralenti |
| 1, 3 | → lancement | 8 | décélération → coupure |
| 2 | lancement → ralenti | 9 | → décélération |
| 4 | ralenti → charge partielle | 10 | charge partielle → décélération |
| 5 | → ralenti | 11 | décélération → charge partielle |
| 6 | ralenti → décélération | 12 | coupure → ralenti |
| 13 | coupure → charge partielle |
2. Le débitmètre et la charge
Le débitmètre HFM est lu sur AN4. Dans Timer3_Interrupt_Handler, sa valeur divisée par 4 indexe la table « MAF » de 256 mots (0x2B4A, 1/64 kg/h par pas), et le résultat est intégré à chaque interruption dans MAF_AirMass_Accumulator. La tâche 4 en tire le débit moyen AirFlow_Avg (0,25 kg/h par pas) et la masse d’air par admission, puis la charge EngineLoad (environ 0,021 mg par course et par pas), trois admissions ayant lieu par tour. Un octet de calibration choisit l’échelle du calcul (« MAF Mode ») : la valeur 0x32 double le débit lu, pour un débitmètre de 2048 kg/h.
MAF_HFM_PlausibilityCheck (0x2A780) contrôle le débitmètre toutes les 20 ms : tension hors plage, entrée de défaut P1.10 active, ou débit incohérent avec l’ouverture du papillon et de la vanne de ralenti. Un défaut de plausibilité du débitmètre (code 8) fait passer le limiteur de régime en mode dégradé (partie VII).
3. Le lancement et la première injection
La première injection est calculée par Fuel_Cranking_InitialPulse_Calc (0x25434, tâche 8). Le temps mort de l’injecteur (« Fuel Injector – Dead Time / Latency », 0x59C, fonction de la tension batterie, de 6 ms à 5,9 V à quelques dizaines de µs à 24 V) forme la base. La quantité vient de « Fuel Injection – Cranking – Initial » (0x1B92), qui décroît fortement avec la température moteur, multipliée par « Fuel Injection – Cranking – Hot Start Factor » (0x1B88) en cas de redémarrage à chaud, puis par le facteur propre au cylindre.
Le redémarrage à chaud est détecté grâce à ECT_ShortRunStop (0xECD0, sauvegardé en EEPROM 0x180). Quand le moteur s’arrête après avoir tourné moins de 240 s depuis la fin du lancement, sa température est mémorisée ; au démarrage suivant, si la température actuelle est proche de cette valeur, word_FD40.5 est posé et le facteur de redémarrage à chaud s’applique. Passé le délai, la valeur repasse à 0xFF (invalide).
Les toutes premières impulsions sont données par CC13_Capture_ISR elle-même, avant que la machine angulaire soit synchronisée. À la première capture, le temps Injector_PulseWidth est chargé dans trois canaux à la fois et les trois injecteurs démarrent ensemble : un groupe formé des canaux CC1, CC2 et CC3 (cylindres 5, 3 et 6) et un groupe formé de CC0, CC4 et CC5 (cylindres 1, 2 et 4), choisis selon l’état du signal de came. À la capture suivante, l’autre groupe est injecté. Ces deux injections groupées amorcent le moteur avant l’injection séquentielle.
Pendant tout le lancement, Fuel_InjectionTime_Calc applique le facteur « Fuel Injection – Cranking – Decay » (0x1B1C), fonction de la température et du nombre d’injections déjà faites, à la quantité de base de lancement « Fuel Injection – Cranking » (0x1B56, régime × température).
4. Le temps d’injection en fonctionnement
Fuel_InjectionTime_Calc (0x254F2, tâche 12) tourne à chaque allumage. Il calcule un temps d’injection par banc, en parcourant les deux structures de régulation lambda (banc 1 en 0xED56, banc 2 en 0xED90) :
- la masse de carburant de base
Fuel_BaseMap_Value(carte0x9F8, régime × charge) plus la correction VANOS (0x0BCC, pondérée par la position réelle de la came) ; - multipliée par le facteur de mélange du banc (champ
+0x1Ade la structure, 4096 = 1,0), qui réunit la sortie du régulateur lambda, l’adaptation multiplicative et la correction de purge ; sans régulation lambda, ce facteur est corrigé par « Fuel Injection – Load/RPM Correction (No Lambda) » (0xB80) ; - augmentée de l’adaptation additive du banc, de l’enrichissement après démarrage, de la correction de régulation de ralenti (
0x1F20), des corrections d’accélération et de décélération et de la correction de reprise après coupure ; - réduite en cas de coupure de cylindre ou de limitation de régime, puis bornée en bas.
Le résultat donne InjTime_B1 et InjTime_B2, hors temps mort, et leur moyenne InjTime_Mean. Pour le cylindre en cours, la table fixe 0x28C8 (Inj_CylBank_Table) choisit le banc dans l’ordre d’allumage (cylindres 1, 2, 3 sur le banc 1, cylindres 4, 5, 6 sur le banc 2), puis le facteur propre au cylindre (0,5 + v/256, neutre à 0x80) est appliqué. Le temps mort est ajouté pour donner Injector_CAPCOM_Reload_1 et _2, et la fin d’impulsion de l’injecteur est programmée sur son canal CAPCOM par rapport au Timer 1.
Les facteurs par cylindre Ext_Trim_InjCyl (0xDC28–0xDC2D) appartiennent au bloc d’extension de la RAM externe 0xDC20–0xDC35, qui regroupe aussi des corrections de phasage, de ralenti, de chauffage des sondes et de purge. Ce bloc est recopié à chaque démarrage depuis la calibration (0x10050–0x10065) :
| Calibration | RAM | Contenu |
|---|---|---|
0x10050 | 0xDC20 | mot (0x0064) |
0x10052 | 0xDC22 | phasage de l’injection |
0x10053 | 0xDC23 | décalage du temps mort des injecteurs (× 16 × 5,333 µs) |
0x10054 | 0xDC24 | décalage de la vanne de ralenti |
0x10055 / 0x10056 | 0xDC25 / 0xDC26 | correction du chauffage des sondes, bancs 1 et 2 |
0x10057 | 0xDC27 | purge canister |
0x10058–0x1005D | 0xDC28–0xDC2D | facteurs d’injection par cylindre (0,5 + x/256, neutre à 0x80, dans l’ordre d’allumage) |
0x1005E–0x10063 | 0xDC2E–0xDC33 | décalages de retard de cliquetis par cylindre (× 0,375°) |
0x10064 | 0xDC34 | CRC |
Le fichier ID41 d’origine est neutre sur toutes ces valeurs. On rencontre des fichiers modifiés qui portent 0x64 sur les six cylindres, soit 11 % d’injection en moins. La zone 0xDC20–0xDC36 peut aussi être écrite par la K-line. Comme la région 0x10050–0x10065 est la région 4 des sommes de contrôle (CRC en 0x10064), toute modification de la calibration impose de recalculer ce CRC.
5. Le phasage de l’injection
L’instant d’injection de chaque cylindre est placé par la machine angulaire au segment indiqué par InjTiming_Angle_FAE2, de 0 à 100 (cinq segments de 20). Cette valeur vient de « Injection Timing – Angle » (0x818, régime × temps d’injection), ou de 0x7DC au lancement, augmentée de la correction VANOS (0x7F0) et de la correction en température (0x1574). Sous un régime seuil, InjTiming_LowRPM_FAE3 lit une table particulière (0x83E).
6. Les enrichissements et corrections transitoires
La tâche 15 Fuel_TransientCorrections_Update (0x2ED3C) gère toutes les corrections de régime transitoire, à chaque allumage :
- après démarrage : un enrichissement figé au démarrage puis décroissant avec le nombre de cycles (« After-Start Enrichment », « Decay », « Hot Start Factor »,
0x1B42,0x1AE8,0x1B36) ; - accélération : un enrichissement déclenché par la vitesse d’ouverture du papillon (
TPS_Angleet sa variation en0xE8D6) ; - reprise après coupure :
FuelCut_Resume_Correctionreçoit, à la sortie d’une coupure, la valeur de l’une des quatre tables « Overrun Exit Correction A à D » (0x197C–0x19B2, en pas de 5,333 µs), puis revient vers 0 d’un pas à chaque allumage. Dans ce fichier, la reprise en roue libre ajoute de 0,75 à 0,96 ms ; - décélération : l’appauvrissement progressif décrit ci-dessous.
La protection catalyseur (COP_Activation_StateMachine et COP_Enrichment_Calc) ajoute un enrichissement quand les conditions de surchauffe du catalyseur sont réunies.
7. Le maintien de régime au lever de pied (rev hang)
Sur un MS41 à papillon mécanique, le régime reste « accroché » une à trois secondes après un relâchement rapide de la pédale, typiquement au passage d’un rapport. Ce n’est pas un défaut : le papillon revient bien à sa butée, c’est le calculateur qui retarde volontairement la transition vers les réglages papillon fermé.
Threshold_Crossing_Debounced_E8D0 calcule la vitesse de fermeture du papillon. Si elle dépasse « Detection – Fast Decreasing TPS – Min. Throttle Gradient » (0x145), word_FD24.4 est posé et une session s’ouvre (Deceleration_Enleanment_SessionTimer, tâche 15). Pendant cette session, le carburant est appauvri progressivement (« Fuel Enleanment – Decreasing TPS », 0x1788, forme de décroissance 0x177E) et l’avance est retardée puis rendue par pas (« Ignition Retard – Decreasing TPS – Step Size », 0x18AC, fonction jumelle RPM_Load_Correction_WithDecay). Les deux effets décroissent ensemble au lieu de basculer d’un coup.
La durée de la session vient de « Fuel Enleanment – Decreasing TPS – Session Duration » (0x1888), une carte régime × température. Elle s’exprime en nombre d’allumages, pas en temps : le compteur avance à chaque événement moteur, soit régime/20 fois par seconde. La durée en secondes vaut environ la valeur de la carte × 20 / régime. C’est cette table qu’il faut réduire, progressivement, pour raccourcir le phénomène ; une suppression complète dégrade les émissions en décélération et peut provoquer un raté si la transition devient trop brutale.
8. La régulation lambda
La régulation lambda est active quand elle est codée (ConfigFlags_FD4C.15, octet de codage 6), au-dessus d’une température minimale (« Closed Loop – Minimum Coolant Temperature », 0x231A au ralenti, 0x2322 au-dessus), au-dessus d’un régime minimal (0x1A9), hors démarrage et sans défaut de sonde. Avec deux sondes, chaque banc est régulé séparément ; avec une seule, le banc 1 sert de référence.
Lambda_ClosedLoop_Update (0x279D0, tâche 18) traite un banc à chaque passage de 10 ms, donc chaque banc toutes les 20 ms. Chaque banc a une structure de 58 octets (0xED56 et 0xED90) qui contient la correction du régulateur (+0x06, 0x8000 = neutre), ses bornes, les adaptations additive (+0x10) et multiplicative (+0x18), le facteur total, les crêtes riche et pauvre de la tension de sonde, les seuils de basculement, le nombre de basculements et les compteurs de mise en action.
La chaîne de calcul est la suivante. Lambda_WriteSample_WithCheck prend l’échantillon de tension et contrôle sa plausibilité. Lambda_Tracker met à jour les crêtes riche et pauvre filtrées, et Lambda_ComputeDetectionBands en déduit les seuils de basculement. Lambda_PerBank_PI_Jump applique alors un régulateur proportionnel-intégral : à chaque passage, une pente intégrale lue dans « STFT – Neg I » ou « Pos I » (0x2108, 0x2190, régime × charge) ; à chaque basculement de la sonde, un saut proportionnel lu dans « STFT – Neg P » ou « Pos P » (0x214C, 0x21D4). Les deux sont multipliés par un coefficient de banc et par « STFT – ECT Factor » (0x2100). Avec les valeurs du fichier, la pente vaut 0,03 à 0,12 % du mélange toutes les 20 ms et le saut environ 1,1 à 1,3 %. La correction est bornée par « Lambda Integrator – Minimum / Maximum Limit » (0x86 / 0x84), soit ±28 %.
Lambda_Adaptation_Update apprend ensuite les adaptations additive et multiplicative dans leurs plages de régime et de charge, bornées par les limites 0xD0 à 0xD6. Sous la température d’apprentissage, Lambda_CombineControllerAndAdaptation pondère les adaptations par les cartes de compensation de mise en température (0x22A4, 0x22C2). Le facteur de mélange du banc vaut alors (adaptation multiplicative + facteur issu de la correction) / 16, avec 4096 = 1,0 : un pas de correction vaut 1/65536 du mélange.
Les sondes amont sont des sondes au dioxyde de titane, alimentées en 5 V : leur résistance varie avec la teneur en oxygène, et la tension lue est environ 4,6 V en mélange pauvre et 0,1 V en mélange riche, sans électronique d’inversion. La tension centrale nominale vaut 2,80 V et les limites de plausibilité 0,10 V et 5,16 V.
Le diagnostic lève le code 75 ou 76 pour une tension hors plage, 200 ou 201 quand la bande de détection reste trop étroite (un compteur chargé à 254 arrive à 0), 202 ou 203 quand la correction bute sur ses bornes.
9. Le chauffage des sondes lambda
Les chauffages des sondes amont sont commandés par le satellite ; le CPU calcule le rapport cyclique de chaque banc (tâche 2 O2Heater_Duty_Update, 0x2ABA8) et l’envoie dans le message ASC1 0x106. Le cycle comprend quatre phases. Au démarrage, le rapport cyclique est au minimum (2,3 %). Vient ensuite une phase de condensation : tant que l’échappement peut contenir de l’eau, le rapport cyclique est limité à environ 35 % de la carte, et un budget initialisé selon la température au démarrage est décrémenté chaque seconde selon le débit d’air (tâche 44). Le budget épuisé, le chauffage passe à pleine puissance (97,3 %) pendant 10 s, puis les sondes sont déclarées prêtes et la régulation commence : le rapport cyclique suit la carte « O2 Sensor Heater – Base Duty » (0x227C, régime × charge) par rampes, multiplié par un facteur d’adaptation.
Ce facteur s’adapte au signal de la sonde : O2Heater_AdaptFactor_Calc (0x2AF1C) calcule le centre de l’oscillation, (crête riche + crête pauvre) / 2, et augmente ou diminue le facteur selon qu’il est au-dessus ou au-dessous de la référence. En coupure en frein moteur, le rapport cyclique tend vers une valeur propre (0x224E) ; en surtension au-delà de 16 V, le satellite reçoit le minimum. La commande K-line 0x22 sous-commande 4 remet le budget de condensation à zéro pour un contrôle rapide au garage.
10. La purge canister
La purge est active si elle est codée (octet 7, bit 3). Le niveau de purge AdaptiveCorrection_CellValue (255 = 100 %) est le produit de la cible « Canister Purge – Purge Ratio Target » (0x2A6C, régime × charge) par une fraction de rampe qui monte ou descend toutes les 100 ms selon le débit d’air. AdaptiveCorrection_Init convertit ce niveau en rapport cyclique (« Canister Purge Valve – Duty », 0x58A), corrigé selon la tension batterie (0x592), et le résultat part vers le satellite qui pilote la vanne.
La correction de mélange due aux vapeurs est apprise à partir de l’écart du régulateur lambda d’un banc (choisi par l’octet de calibration 0x199), avec trois modes de convergence et une confirmation sur plusieurs cycles stables avant validation. Elle est sauvegardée en EEPROM (0x052) et n’est appliquée qu’une fois la cellule déclarée apprise (AdaptiveCorrection_PersistedFlag, 0xEC9C).
VI. Régulation du ralenti
1. La consigne de régime
IdleSpeed_Target_Calc (0x2A500, tâche 17) choisit entre quatre courbes de consigne, recalculées en fonction de la température moteur par ECT_Dependent_Params_Update. Le choix dépend de deux bits de word_FD18 : rapport engagé sur une boîte automatique (.6) et climatisation enclenchée (.4).
| Courbe | Table | −30 °C | −10 °C | +10 °C | +30 °C | +60 °C | +90 °C |
|---|---|---|---|---|---|---|---|
| base | 0x1D8A | 1120 | 960 | 850 | 785 | 755 | 750 |
| boîte auto en prise | 0x1D24 | 1050 | 900 | 800 | 760 | 750 | 750 |
| climatisation | 0x1D32 | 1120 | 960 | 850 | 800 | 785 | 780 |
| boîte en prise et clim | 0x1D04 | 1050 | 900 | 820 | 790 | 780 | 780 |
La climatisation relève donc le ralenti de 30 tr/min moteur chaud. Plusieurs corrections s’ajoutent à la courbe choisie. Après le démarrage, un bonus pris selon la température au démarrage (ECT_AtStart), jusqu’à +120 tr/min (+60 tr/min en Drive), décroît ensuite d’un pas par cycle. Le décalage réglable au testeur (IdleSpeed_TesterOffset_E92C, commande K-line 0x41) est pondéré par la table 0x1CF6 pour n’agir que moteur chaud. Un plancher fonction de la tension batterie remonte la consigne en sous-tension (780 ou 700 tr/min, 760 ou 680 en Drive, ce dernier seulement véhicule en mouvement). Enfin la consigne, travaillée multipliée par 4, ne varie que de 0,25 tr/min à chaque exécution, dans les deux sens : l’enclenchement de la clim se traduit par une rampe douce et non par une marche.
La consigne finale alimente IdleSpeed_PID_Controller (0x29FDE, tâche 23), régulateur à intégrale et dérivée dont le terme proportionnel IdleSpeed_PD_Term est visible par la K-line. La pré-commande de la vanne (IACV_PreControl_Calc, tâche 13) anticipe l’ouverture nécessaire selon la position du papillon et les modes MSR, et IACV_Duty_Sum_Output (tâche 14) somme tous les termes. En parallèle, l’allumage corrige le régime à court terme (partie IV).
2. La vanne de ralenti
Le logiciel ne pilote qu’une broche, P2.9, en PWM à 100 Hz : le gestionnaire du Timer 0 (0x322EC) recharge le comparateur CC9 avec IdleValve_CC9_TargetValue (0xFB52) à chaque période. La commande interne est un mot de 16 bits (65536 = 100 %) converti en fin de niveau haut dans la période de 10 ms. Les deux enroulements de la vanne sont commandés en opposition par le matériel (partie I), et le rapport cyclique fixe la position du boisseau.
Les positions de base de la vanne suivent la température : de 221 à 56 sans climatisation, de 221 à 61 avec climatisation. La variante clim reste un peu plus ouverte pour anticiper le débit d’air avant même que le régulateur corrige. La latence de la vanne est compensée en sous-tension par « IACV – Latency » (0x56E).
L’air de ralenti est adapté en continu (partie VIII) et le diagnostic des deux enroulements (codes 53 et 27) n’est actif que si l’octet de codage 8 bit 2 est posé. Le code 211 signale une adaptation de ralenti hors limites ou une masse d’air incohérente.
3. La climatisation et le compresseur
Les entrées de climatisation sont lues par le satellite et transmises au CPU par le message ASC1 0x103 dans Sat_ACInputs_F13F (0xF13F) : bit 0 demande de compresseur, bit 1 interrupteur de clim. SystemMode_Aggregator (0x2507A) les recopie dans word_FD18.5 et .4, puis applique le masque et la polarité fixés par le codage : FD18 = (FD18 XOR word_FD20) AND word_FD1E. Un véhicule non codé « clim » ne voit donc jamais ces bits, quel que soit l’état des entrées.
L’octet de codage 4 choisit entre deux câblages. En mode interrupteurs (bit 4 à 0), la demande et l’interrupteur viennent directement du satellite, avec une polarité réglable, et le niveau de compensation de couple est figé au maximum. En mode capteur de pression (bit 4 à 1), AC_PressureSensor_Evaluate (0x2B27A) lit la pression du fluide mesurée par le satellite et en déduit les deux bits : clim coupée sous la pression minimale ou en surpression, interrupteur actif au-dessus d’un premier seuil, compresseur autorisé au-dessus d’un second, et quatre niveaux de compensation de couple selon la pression. Un capteur en défaut (code 16) est remplacé par une valeur de pression basse.
Les seuils portent sur l’octet de pression brut, à 0,1 bar par pas. Jusqu’à 0x39 (5,7 bar), la clim est coupée ; de 0x3A à 0x60 (9,6 bar), seul word_FD18.4 est posé ; au-delà, word_FD18.4 et .5 sont posés, avec les niveaux de compensation 1 à 4 à 0x86, 0xAC, 0xD3 et 0xF3 ; au-dessus de 0xF3 (24,3 bar), la surpression coupe la clim. La mesure n’est prise en compte que si l’octet d’état transmis par le satellite (0xF170) a son bit 7 à 1 (mesure valide) ; son bit 0 signale un défaut.
La gestion du compresseur passe par AC_Compressor_OnOffDelay_Manager (0x2B15C). À l’apparition de la demande, une temporisation fonction du régime retarde l’enclenchement (360 ms à 800 tr/min, 50 ms à 3600 tr/min) pour laisser le ralenti monter avant que la charge du compresseur arrive ; à sa fin, le relais est autorisé en effaçant le bit 5 de 0xF141 (ordre « relais coupé » envoyé au satellite), et word_FD18.12 est posé, recopié dans le bit 6 de l’octet 0 de DME1. Dès l’apparition de la demande, la table 0x1E40 ajoute une ouverture immédiate de la vanne de ralenti (+3,5 à +6,3 %) pour anticiper la charge du compresseur. À la disparition de la demande, une temporisation plus courte précède la coupure.
En accélération franche, AC_Compressor_WOT_Cutoff (0x2B1E8) coupe brièvement le compresseur pour rendre le couple au moteur, seulement à basse vitesse (15 km/h sur un moteur à régulation lambda), puis verrouille la fonction pour éviter les répétitions. La coupure dure environ 4 s (40 × 100 ms) ; le compresseur est réenclenché 0,5 à 1 s après le retour en charge partielle. Un défaut du relais de compresseur (code 74) maintient le relais coupé.
4. La boîte automatique et le ralenti
Quand une boîte automatique est codée ou détectée sur le bus CAN, le code de rapport reçu dans le message EGS1 (partie XI) pose word_FD18.6 pour les codes 2, 3, 4, 5 et 7. Ce bit sélectionne les courbes de consigne « Drive », le bonus après démarrage Drive et le plancher Drive conditionné à la vitesse. L’octet 2 de EGS1, mis à l’échelle 0-255, est injecté dans le régulateur de ralenti et dans la rampe d’allumage : la charge annoncée par la boîte est anticipée. Le codage automatique choisit aussi une autre table de charge au démarrage (0x10FC au lieu de 0x1184).
L’octet 2 de EGS1 n’est pris qu’au ralenti. Une demande non nulle maintenue 3 s (30 × 100 ms) pose word_FD08.12, après quoi l’octet 2 est forcé à 0 : une demande bloquée ne peut pas maintenir le ralenti haut indéfiniment. Les codes de rapport 0, 1, 6, 8 et 9 ne posent pas le bit « rapport engagé ».
VII. VANOS, cliquetis, limiteur et autres fonctions moteur
1. Le VANOS
Le VANOS d’admission est piloté en tout-ou-rien sur P2.12 (étage U7) : P2.12 = 1 laisse la came au repos, P2.12 = 0 engage le VANOS et avance la came. word_FD2E.0 mémorise l’état engagé. La fonction n’existe que si elle est codée (octet de codage 4, bits 5-7 = 001, ConfigFlags_FD4C.0).
La décision est prise toutes les 100 ms par VANOS_Control_Update (0x2F766, tâche 21). La came revient au repos moteur arrêté ou en lancement, en cas de défaut vilebrequin ou arbre à cames, au ralenti, en décélération et en coupure. Au-dessus du seuil « Detection – Light/Heavy Throttle » (0x1958), la carte « VANOS – On/Off (Heavy Throttle) » (0x19F2) décide directement. En charge partielle, le VANOS s’engage quand la charge dépasse « VANOS – Min. Load (Light Throttle) » (0x15CA en boîte manuelle, 0x1580 en automatique, régime × température) et revient au repos sous ce seuil moins une hystérésis ; entre les deux, l’état ne change pas. Le régime utilisé suit une hystérésis de 96 tr/min.
Trois autres conditions maintiennent la came au repos : pendant 2,0 s après la fin du lancement (CAL_00F6, minuterie qui pose word_FD2E.6), sous la vitesse véhicule minimale CAL_0248 (0 dans le fichier ID41), et tant que word_FD2E.9 vaut 0, c’est-à-dire tant que la température moteur n’a pas dépassé AfterStart_ECT_Threshold (0xECD2). Ce seuil est fixé au démarrage à partir de la température d’air : environ 6,8 °C avec un air à 20 °C.
L’engagement (VANOS_Engage, 0x2F50C) charge un retard de retour (0x241, 7 passages). Au retour (VANOS_Release, 0x2F4DE), sous « VANOS – Immediate Release RPM » (2400 tr/min) la came revient immédiatement ; au-dessus, elle attend la fin de ce retard. Un régime qui oscille autour d’un seuil ne fait donc pas claquer l’électrovanne. Un défaut de l’étage de puissance (bit 0x80 de FaultDispatch_ActiveMask) interdit l’engagement.
La position réelle de la came est mesurée à chaque front d’arbre à cames par VANOS_CamPosition_Check (0x2F530, tâche 20), en pas de 0,375° vilebrequin (numéro de dent × 16 + fraction de dent). Elle est comparée à deux fenêtres centrées sur la position de repos apprise VANOS_CamRest_Learned : la fenêtre de repos et la fenêtre de pleine avance, décalée de la course « VANOS – Cam Advance Travel » (0x26F, 66 pas soit 24,75°, la course connue du VANOS d’admission du M52). Le rapport VANOS_CamAdvance_Ratio = (mesure − repos) × 256 / course donne la position de la came entre 0 (repos) et 255 (pleine avance) ; c’est lui qui pondère les corrections VANOS des cartes d’injection et d’avance.
La position de repos est apprise par VANOS_CamRest_Learn (0x2F610), une fois tous les dix passages, VANOS au repos et sans défaut : elle est filtrée vers la mesure, bornée autour de la valeur par défaut (0x1E2, 25,9°), et déclarée apprise quand l’écart passe sous 1,9°. La tolérance des fenêtres passe alors de 9,0° à 1,9°. La position apprise est sauvegardée en EEPROM.
Deux codes défaut concernent le VANOS : le code 21 pour un défaut électrique de l’électrovanne, remonté par le satellite, et le code 212 quand la position mesurée ne correspond pas à la commande ou sort des deux fenêtres, évalué au-dessus d’un régime minimal et après un délai réarmé à chaque bascule.
2. La régulation anticliquetis
Les deux capteurs de cliquetis ne sont pas lus par le CPU : le satellite traite leur signal et renvoie à chaque événement moteur un niveau pour le cylindre en cours (message ASC1 0x102, rangé dans Knock_SatLevel_Idx0, 0xFB20–0xFB25). Au PMH de chaque cylindre, au moment où s’ouvre la fenêtre de mesure sur P3.6, le CPU lui envoie le gain d’amplification (Knock_SatGain_Tx, 0xFB13) et la position du cylindre (message 0x101) ; 48° plus tard, il lui demande le niveau mesuré (message 0x102).
La régulation, Knock_Control_Update (0x26E16), n’existe que si elle est codée (octet de codage 5, bit 7). Elle n’agit qu’au-dessus d’une charge minimale (« Knock Detection – Min. Load », 0x23B0) et hors démarrage. Pour chaque cylindre, elle lit sans interpolation des fenêtres de détection début et fin (douze cartes en 0x25DA–0x28C6) et des facteurs de seuil (0x2442–0x2596), au point régime × charge courant.
Chaque cylindre a un niveau de référence (le bruit de fond normal), initialisé par « Knock Detection – Reference Level Initial » (0x23A4) et filtré vers la mesure, plus vite en mode dynamique (forte variation de régime ou ouverture rapide du papillon). Le cliquetis est détecté quand le niveau mesuré dépasse la référence multipliée par le facteur de seuil. L’avance du cylindre est alors retardée d’un pas (« Knock Retard – Step Size », 0x292C), puis rendue progressivement en l’absence de cliquetis (« No Knock Advance – Step Size », 0x2938), dans la limite d’un retard maximal fonction de la température (0x23DE sans régulation lambda, 0x2402 avec, pondéré par 0x2424). Le retard appliqué est rangé dans Knock_CylState (0xFB26–0xFB2B) et ajouté à l’angle d’allumage par la machine angulaire ; les bits word_FD2C.0 à .5 signalent un retard en cours pour chaque rang d’allumage.
Au-dessus de « Knock Adaptation – Min. Load » (0x2908), le retard est appris cylindre par cylindre dans une carte de 64 cellules régime × charge (AdaptationCells_Table, 0xD840, 384 octets), neutre à 0x80. Un décalage global lent (AdaptationCells_ExtraCell, 0xE9D9) s’y ajoute. Le gain envoyé au satellite est lui aussi adapté : les six niveaux de référence sont moyennés, et l’écart à la valeur nominale est intégré dans Knock_SatGain_Adapt.
Le diagnostic des capteurs (codes 57 et 59) est évalué au-dessus d’un régime minimal quand les trois cylindres d’un même capteur présentent une anomalie.
3. Le limiteur de régime et la coupure tournante
Le limiteur ne coupe pas tout le carburant d’un coup : il calcule un niveau de sévérité de 0 à 6, traduit en coupure tournante cylindre par cylindre.
RevLimit_ModeSelect_Debounced choisit d’abord la limite applicable. En fonctionnement normal, c’est « Engine Speed Limiter (Hard Limiter) » (6496 tr/min dans ce fichier), avec une coupure immédiate à 6592 tr/min. Un défaut du capteur de vitesse fait passer à 6560 tr/min. En mode dégradé (défaut papillon ou débitmètre), la limite suit une courbe fonction de l’angle papillon (1504 à 6016 tr/min), descend à 1216 tr/min sur défaut papillon et à 2496 tr/min sur défaut cumulé papillon et débitmètre.
RevLimit_ComputeOutputByte calcule ensuite la sévérité RevLimit_OutputByte (0xFADE), consultée dans tout le firmware. Elle vaut le compteur d’anti-rebond du limiteur, plafonné par un compteur de persistance qui monte d’un pas à chaque passage où la condition dure, jusqu’à 6 ; au niveau maximal, le relais de pompe à essence est aussi coupé. Elle est forcée à 6 (tous les cylindres coupés) dans quatre cas : moteur arrêté ou calé, coupure d’injection en frein moteur, intervention ABS/ASC maximale, et blocage par l’antidémarrage.
La coupure elle-même est appliquée par CylinderSequence_AngleStateMachine. Le masque des injecteurs coupés est lu dans la table fixe 0x2CF6 (6 phases × 8 colonnes) à l’index « phase + sévérité », puis écrit dans word_FD04, le portillon des injecteurs : pour chaque bit posé, l’injecteur correspondant ne pulse pas sur ce cycle. La sévérité fixe combien de cylindres sont coupés, et la phase fait glisser le cylindre de tête dans l’ordre d’allumage à chaque engagement pour répartir la coupure.
| Sévérité | Masque (phase 0) | Cylindres coupés |
|---|---|---|
| 1 | 0x01 | 1 |
| 2 | 0x09 | 1, 6 |
| 3 | 0x0B | 1, 5, 6 |
| 4 | 0x1B | 1, 5, 6, 2 |
| 5 | 0x1F | 1, 5, 3, 6, 2 |
| 6 | 0x3F | tous |
Pendant une limitation, la plupart des surveillances de pannes sont suspendues, la coupure produisant des signaux transitoires qui provoqueraient de fausses détections. Un limiteur de vitesse véhicule existe aussi (« Vehicle Speed Limit », 0x272) mais il est inactif dans ce fichier (valeur 255).
4. Le volet d’échappement
Le volet est géré par ExhaustFlap_Control (0x20000), à condition d’être codé (octet 8, bit 3). Il est ouvert juste après le démarrage, fermé sous une vitesse véhicule minimale (0x248, le même seuil que la vitesse minimale du VANOS), et au-delà il s’ouvre quand l’angle papillon dépasse un seuil lu dans la carte « Muffler Flap Solenoid » (0x153A, régime × température moteur), puis se referme quand l’angle redescend sous ce seuil moins une hystérésis (0x147). La commande part vers le satellite par le bit 6 de SystemStatus_WidelyShared (0xF141). En cas de défaut de l’électrovanne (code 52), le volet reste commandé ouvert.
5. L’interface ABS/ASC
Quand l’octet de codage 7 a ses bits 0-2 à 001, le calculateur ABS/ASC commande le moteur par trois fils lus sur P1.14, P1.13 et P1.12. ABS_ASC_WireInterface_Update traite le code formé par ces trois fils :
| Fils actifs | Effet |
|---|---|
| aucun | fin d’intervention |
P1.14 | réduction de couple |
P1.14 + P1.13 | réduction de couple avec retard d’allumage |
P1.14 + P1.12 | coupure d’injection et d’allumage en charge partielle |
P1.13 | MSR mode 1 : l’air de ralenti suit « IACV – TPS (MSR Mode 1) » pour réduire le frein moteur |
P1.13 + P1.12 | MSR mode 2 |
| autres combinaisons | code invalide, défaut 215 |
Chaque fil a une durée maximale d’activation : 5,1 s pour P1.14 (code 82), 2,5 s pour P1.13 (code 81, MSR actif trop longtemps) et 2,5 s pour P1.12 (code 80).
6. La régularité moteur
Le MS41 mesure la régularité de chaque combustion sans capteur dédié, à partir du temps de rotation du vilebrequin. EngineRoughness_SegmentNormalize (0x2B026, tâche 56) tourne à chaque segment de 120° au ralenti. Elle calcule six fois l’écart entre deux segments consécutifs, corrigé de la dérive de régime mesurée sur un cycle complet ; en régime stable, un cylindre qui brûle normalement donne une valeur proche de 0. Cet écart est rapporté à la référence « Engine Roughness – Reference » (0x418, régime × charge, pondérée par la température via 0x35A), puis filtré à environ 12 % par mesure.
Le résultat, Roughness_Value (0xE854), contient six mots signés, un par cylindre dans l’ordre d’allumage : 0 pour un cylindre régulier, une valeur négative pour une combustion plus faible, 4096 pour un écart égal à la référence. Il se lit par la commande K-line 0x2B sous-commande 0x05 et sert à repérer un cylindre faible. Ce logiciel ne contient aucun code de raté de combustion : la régularité est une mesure de diagnostic, pas une surveillance.
VIII. Les adaptations
1. Principe
Le calculateur apprend des corrections, trajet après trajet, pour compenser l’usure et les dérives : injecteurs, tolérances mécaniques, capteurs, qualité du carburant. Ce n’est pas un système unique mais plusieurs sous-systèmes indépendants, chacun avec sa propre logique de convergence. Tous travaillent en RAM et sont recopiés en EEPROM moteur tournant et à l’extinction ; au démarrage, chaque bloc passe une somme de contrôle et un test de plausibilité, et une valeur douteuse est remplacée par une valeur neutre.
| Adaptation | Variable | EEPROM | Neutre |
|---|---|---|---|
| retard anticliquetis par cellule et par cylindre | AdaptationCells_Table (0xD840) | 0x00E (moyenne par cellule) | 0x80 |
| décalage global anticliquetis | AdaptationCells_ExtraCell (0xE9D9) | avec les cellules | 0x80 |
| adaptations lambda additive et multiplicative | structures 0xED56 / 0xED90 | 0x068 | 0x8000 |
| correction de purge canister | AdaptiveCorrection_* | 0x052 | non apprise |
| zéro du papillon | TPS_AutoZero_Bound | 0x05C | 0x14B |
| air de ralenti, sans et avec clim | AdaptationZone1_Live / AdaptationZone3_Live | 0x0EA | 0 |
| position de repos de la came | VANOS_CamRest_Learned | 0x056 | 0x1E2 |
2. Fonctionnement de chaque adaptation
L’adaptation anticliquetis mémorise six valeurs par cellule (une par cylindre) dans 64 cellules régime × charge, mais seule la moyenne de chaque cellule est sauvegardée en EEPROM puis redistribuée au démarrage. Elle n’existe que si la régulation anticliquetis est codée.
Les adaptations lambda sont apprises dans leurs zones de régime et de charge propres et bornées par la calibration (partie V). Le zéro du papillon est recalé en continu dès qu’une lecture cohérente papillon fermé est détectée, ce qui compense la dérive du potentiomètre. L’air de ralenti apprend l’ouverture de vanne nécessaire pour tenir la consigne, dans une zone sans climatisation et une zone avec, appliquées par IACV_Target_Calc.
Un groupe de cinq octets (AdaptByte_Unused_1 à _5, 0xE999–0xE9A1) est sauvegardé et restauré avec sa somme de contrôle, mais aucun calcul ne le lit dans ce logiciel.
3. L’effacement sélectif
La commande K-line 0x43 (KLine_Cmd43_ClearAdaptations, 0x23D96) reçoit un masque dont chaque bit efface un groupe indépendamment :
| Bit | Groupe remis à neutre |
|---|---|
0x01 | adaptation anticliquetis (384 cellules et décalage global) |
0x02 | adaptation d’air de ralenti |
0x04 | adaptations lambda des deux bancs |
0x08 | zéro du papillon (recalé sur la lecture actuelle, à faire papillon fermé) |
0x10 | drapeau « cellule de purge apprise » |
0x20 | position de repos de la came (VANOS) |
0x40 | les cinq octets inutilisés |
Un second octet demande en plus une nouvelle auto-détection de la boîte et des sondes lambda. Le testeur BMW envoie le masque 0xFF. La commande ne modifie que la RAM : les valeurs neutres sont écrites en EEPROM par la séquence d’extinction suivante.
IX. Les octets de codage véhicule
1. Principe
Cinq octets de la calibration, de 0x10004 à 0x10008, décrivent l’équipement du véhicule. Une seule fonction les décode au démarrage, CodingBytes_Unpack_ApplyFlags (0x26800) : elle les recopie en RAM (CodingByte_4 à _8, 0xEDF9–0xEDFD) et pose des drapeaux dans ConfigFlags_FD4C, dans le masque word_FD1E et la polarité word_FD20 des entrées, et dans word_FD0A. Au départ, word_FD1E n’autorise que quelques entrées : toute fonction optionnelle (clim, rapport engagé, fils ABS/ASC) doit être autorisée par le codage pour exister. Le calculateur de référence est codé 26 AC 1C 09 0F.
2. Octet 4 : climatisation et VANOS
Les bits 0 à 4 décrivent la climatisation. S’ils sont tous à 0, il n’y a pas de clim. Le bit 4 à 1 choisit le mode capteur de pression ; à 0, le mode interrupteurs, dans lequel le bit 0 règle la polarité de la demande de compresseur, et les bits 1 à 4 à la valeur 001 permettent à l’interrupteur de clim d’agir sur la consigne de ralenti (le bit 1 réglant sa polarité). La valeur d’usine courante (bits 1 et 2 à 1) correspond au câblage habituel.
Les bits 5 à 7 à 001 (valeur 0x20) activent le VANOS.
3. Octet 5 : boîte de vitesses et anticliquetis
Les bits 0 à 5 forment une valeur, pas des bits indépendants : 0x00 pour une boîte manuelle, 0x2B pour une boîte automatique (EGS présente sur le CAN), 0x2C pour une auto-détection. En auto-détection, le calculateur relit d’abord la décision mémorisée en EEPROM (0x196), puis écoute le bus : la réception d’un message EGS1 confirme la boîte automatique, son absence pendant 50 ticks retient la boîte manuelle, et la décision est réécrite en EEPROM pour le démarrage suivant.
La boîte automatique (ConfigFlags_FD4C.7) active la surveillance du bus CAN, autorise le bit « rapport engagé » pour le ralenti, injecte la demande de la boîte dans la régulation et choisit une autre table de charge au démarrage.
Le bit 6 active la remontée de l’état des défauts mémorisés vers le voyant. Le bit 7 active la régulation anticliquetis (ConfigFlags_FD4C.12) : sans lui, Knock_Control_Update sort immédiatement et les cellules ne sont pas sauvegardées.
4. Octet 6 : sondes lambda
Les bits 2 à 4 décrivent la régulation lambda : 0x00 pour une sonde, 0x08 pour deux sondes, 0x18 et 0x1C pour une ou deux sondes avec auto-détection. Toute autre valeur, par exemple 0x04, supprime la régulation lambda. En auto-détection, le calculateur compte les évaluations du chauffage de sonde : sept évaluations sans défaut sur dix valident la présence des sondes.
Le drapeau produit, ConfigFlags_FD4C.15 (« régulation lambda présente »), est le bit de codage le plus utilisé du firmware, avec une quarantaine de lectures. Il bascule les cartes d’avance et de carburant, les paramètres dépendant de la température, la régulation lambda et ses adaptations, les durées de chauffe du catalyseur, la télémétrie K-line et le seuil de vitesse de la coupure clim. Un moteur sans sondes roule donc sur un jeu de cartes distinct.
Les bits 0 et 1 ne servent que lorsque l’EWS est supprimé : à 01, une entrée du satellite remplace le signal de démarrage refusé. Les bits 5 à 7 non nuls activent la surveillance du bus CAN, au même titre que la boîte automatique.
5. Octet 7 : entrées, CAN, purge et CRC
Les bits 0 à 2 autorisent les entrées P1.12 à P1.14 ; à 001 ils activent l’interface ABS/ASC par trois fils (partie VII), et le bit 2 à 1 active la surveillance du bus CAN. Le bit 3 active la purge canister et le diagnostic de la vanne de ventilation du réservoir (code 68). Le bit 4 à 1 désactive le contrôle CRC de la calibration. Les bits 5 à 7 sont décodés, mais aucun code ne lit les drapeaux qu’ils produisent.
6. Octet 8 : diagnostics et EWS
Le bit 2 active le diagnostic des deux enroulements de la vanne de ralenti. Le bit 3 active le volet d’échappement (fonction, diagnostic et test d’actionneur). Les bits 0 et 1 sont lus puis ignorés et les bits 4 à 6 ne sont lus par aucune fonction.
Le bit 7 supprime l’antidémarrage. À 0 (EWS actif), le calculateur pose word_FD0A.9 et word_FD0A.5 et calcule le code attendu de l’EWS à partir de l’ISN. À 1, l’ordre « EWS supprimé » est transmis au satellite (bit 0 de 0xF141) et le démarrage n’attend plus de message.
Dans la définition RomRaider, ces octets sont présentés selon leur nature : cases à cocher pour les octets formés de bits indépendants, liste de sélection pour le type de boîte et pour la configuration lambda. Les octets bruts restent disponibles pour les versions de RomRaider qui ne connaissent pas les cases à cocher.
X. Antidémarrage et accès sécurisés
1. Trois mécanismes distincts
Trois mécanismes sont souvent confondus. L’antidémarrage EWS autorise ou non le démarrage du moteur ; il passe par le satellite. Le login « BMW » autorise la programmation de la flash ; il passe par la K-line. Le déverrouillage par mot de passe fait passer la K-line dans un mode d’accès étendu et change son débit. Aucun des deux mécanismes K-line n’intervient dans l’autorisation de démarrage.
2. L’antidémarrage EWS
Le calculateur et le boîtier EWS partagent un code individuel, l’ISN, formé des quatre derniers caractères du numéro de production (ISN_Data, 0x1CEA). Au décodage du codage, si l’EWS est actif, le calculateur pose « démarrage non autorisé » et calcule le code attendu EWS_ExpectedISN (0xF0BE) à partir des quartets bas des quatre caractères : 1000 × A + 100 × B + 10 × C + D, gardé sur 12 bits.
Le CPU ne parle pas directement au boîtier EWS : le satellite lui relaie le message par le message ASC1 0x109 (5 octets en 0xF171–0xF175) : trois octets de code, une somme de contrôle (somme des trois octets + 1) et un statut (0xA0 nouveau message, 0xFF pas de réponse de l’EWS). L’échange a lieu dès la mise du contact, avant l’action du démarreur.
Le code transmis n’est pas l’ISN en clair. Avec n le quartet haut du premier octet, k la valeur sur 12 bits formée du premier octet et du quartet haut du deuxième, et c la valeur formée du quartet bas du deuxième octet et du troisième, le message est accepté si la rotation à droite de l’ISN de n bits sur 12 bits, combinée par OU exclusif avec k, donne c. Un même ISN peut ainsi être transmis sous 4096 formes différentes.
EWS_CheckDispatcher (0x252A8, tâche 53) tourne tant que le contrôle est en attente. Sur un statut 0xA0, il appelle EWS_CodeCheck (0x25140), qui vérifie la somme de contrôle, décode le code transmis et le compare à EWS_ExpectedISN. Si le code est correct, le démarrage est autorisé, le contrôle se termine et le calage moteur est initialisé. Si aucun message valide n’arrive avant l’échéance « System – Coding Check Timer », le code 18 est évalué. Un code incorrect donne le code 209. Si la synchronisation avec le satellite est perdue, le contrôle est abandonné et le démarrage autorisé.
Avec l’EWS normal, un démarrage refusé se traduit simplement par l’absence d’initialisation du calage moteur : RPM_Word reste à 0 et le calculateur ne produit ni injection ni allumage, même si le démarreur entraîne le moteur.
La tâche 45 EWS_Immobilizer_Update (0x24FC4) n’existe qu’avec le codage « EWS supprimé, entrée satellite » (word_FD1E.7, voir ci-dessous). Tant que l’entrée signale un démarrage refusé, EWS_Immobilizer_Counter (0xEDF8) monte de 6 par passage ; à 24, word_FD0A.0 est posé et le calculateur coupe l’injection, l’allumage et le relais de pompe à essence. Quand le refus disparaît, le compteur redescend de 1 par passage et le blocage n’est levé qu’à 0 : il s’installe en quatre passages et se lève en vingt-quatre. Sans ce codage, word_FD0A.1 est posé à la mise sous tension.
Avec le codage « EWS supprimé » (octet 8, bit 7), le contrôle n’a pas lieu. Si de plus les bits 0-1 de l’octet 6 valent 01, le signal de démarrage refusé est pris sur une entrée du satellite (bit 2 de 0xF13F).
3. Le login « BMW » (défi et clé)
Le login autorise l’écriture de la flash par la commande 0x07. Il est traité par une routine du secteur de démarrage, Boot_KLine_Cmd90_Login (0x0A84), identique en fonctionnement normal et en session de programmation. Son état est rangé dans KLine_LoginState (0xE658) : 0 aucun, 1 défi envoyé, 2 authentifié.
L’outil envoie d’abord 12 08 90 42 4D 57 GG CS, soit « BMW » suivi d’une graine GG. Le calculateur répond par son identification de 46 octets (version du secteur de démarrage, avec la copie de l’identité gardée en EEPROM). L’outil renvoie alors une clé de quatre octets, chacun somme de trois octets de cette réponse, modulo 256 :
clé[i] = ( d[GG - 3 + i] + d[15 + i] + d[38 + i] ) mod 256 pour i = 0 à 3
d[0..41] : les 42 octets de données de la réponse
d[15..18] : semaine et année de fabrication (0x1CD5)
d[38..41] : ISN (0x1CEA)
Une clé correcte donne 12 05 A0 00 B7 et autorise la programmation jusqu’au prochain redémarrage. Le défi étant l’identification du calculateur, il ne change jamais : un même calculateur donne toujours la même clé pour une même graine.
Le login n’est accepté que 10 s après le démarrage (avant, la réponse est 12 04 A1 B7, occupé). Une clé fausse répond 12 04 B0 A6 et impose un nouveau délai de 10 s ; après deux clés fausses, toute tentative est refusée (12 04 A2 B4) jusqu’à la coupure du contact.
Exemple avec un ISN fictif 1234 : la réponse au défi contient FF FF FF FF aux positions 11 à 14, la date « 2699 » (32 36 39 39) aux positions 15 à 18 et l’ISN (31 32 33 34) aux positions 38 à 41. Avec la graine 0x0E, le premier octet de la clé vaut FF + 32 + 31 = 0x162, soit 0x62 modulo 256. La clé complète vaut 62 67 6B 6C, envoyée dans la trame 12 08 90 62 67 6B 6C 88.
4. Le déverrouillage par mot de passe et le changement de débit
La trame 12 0F 90 SS P0 … P9 CS porte un sélecteur de débit SS et les dix octets du mot de passe, comparés à SecurityAccess_Password (0x205E), qui vaut 6577205110 sur ce logiciel. Ce mot de passe est lisible sans déverrouillage : son adresse figure dans la réponse de la commande 0x53 et il se lit par 0x06.
Le déverrouillage exige le moteur arrêté, puis un échange de contrôle avec le satellite : le CPU lit son bloc de configuration (message 0x10A) et le lui renvoie permuté (message 0x10C), les deux statuts devant valoir 0xA0. En cas de succès, KLine_ModeFlag_U (0xF18E) passe à 'U' (mode déverrouillé), le calculateur entre en mode service jusqu’à la coupure du contact (le moteur ne peut plus démarrer), les échanges périodiques avec le satellite s’arrêtent, et la réponse 12 04 A0 B6 est émise.
Le changement de débit est un effet de ce déverrouillage, il n’existe pas d’autre moyen. Quand le dernier octet de la réponse est sorti, KLine_ASC0_TransmitComplete_ISR applique le sélecteur : bits 0 à 5 dans le diviseur S0BG, bit 6 pour diviser par 16 au lieu de 32.
débit = 12 000 000 / (32 x (S0BG + 1)) si bit 6 = 0
débit = 12 000 000 / (16 x (S0BG + 1)) si bit 6 = 1
SS | Débit | Remarque |
|---|---|---|
0x26 | 9615 bauds | débit d’origine |
0x19 | 14423 bauds | |
0x66 | 19231 bauds | |
0x0C ou 0x59 | 28846 bauds | |
0x4C | 57692 bauds | le plus utile, fiable |
0x01 | 187500 bauds | non standard, moins fiable |
Exemple : 12 0F 90 4C 36 35 37 37 32 30 35 31 31 30 C5 déverrouille et passe à 57692 bauds. L’outil doit basculer son port série juste après avoir reçu la réponse. Le débit choisi reste en place jusqu’au redémarrage, même si une trame 0x90 sans le bon mot de passe reverrouille la K-line.
XI. Communication
1. La liaison avec le satellite (ASC1)
Le CPU échange avec le satellite par son second UART, ASC1, sur P3.8/P3.9, configuré par Init_ASC1_EWS_Channel (0x2668E, S1CON = 0x801C, débit élevé). Par-dessus tourne un protocole de messages numérotés en mode multiprocesseur, où un neuvième bit à 1 marque un octet d’adresse. Le canal est étiqueté « EWS » dans le code parce que le message de l’antidémarrage y transite, mais c’est le lien général avec le satellite.
Le mot ASC1_MsgRequest_FDDC (0xFDDC) est un masque de quinze demandes d’échange. Un sous-système pose un bit puis déclenche l’interruption ASC1 ; EWS_ASC1_PEC_TransceiverSetup (0x32378) envoie alors l’octet d’adresse 0x101 + n du bit en attente de plus faible numéro, puis programme un transfert PEC qui copie les octets entre l’UART et le tampon RAM du message, sans intervention du programme. Le Timer 0 relance le cycle toutes les 10 ms.
| Message | Sens | Tampon | Contenu |
|---|---|---|---|
0x101 | CPU vers satellite | 0xF138 | gain cliquetis et index du cylindre, à chaque PMH (six fois par cycle), à l’ouverture de la fenêtre P3.6 |
0x102 | satellite vers CPU | 0xF13A | niveau de cliquetis, demandé 48° après le PMH, et index renvoyé (celui du cylindre annoncé deux messages plus tôt) |
0x103 | satellite vers CPU | 0xF13E | octet 0 : diagnostic d’un étage de sortie par message (numéro en bits 0 à 4, type en bits 5 à 7) ; octet 1 : entrées de climatisation (0xF13F) |
0x104 | CPU vers satellite | 0xF140 | commande des actionneurs déportés : EWS actif ou supprimé (bit 0 de 0xF141), coupure du relais de clim (bit 5), volet (bit 6), purge |
0x105 | satellite vers CPU | 0xF144 | octets de validation de la configuration, comparés au bloc flash 0x205A |
0x106 | CPU vers satellite | 0xF148 | rapports cycliques de chauffage des sondes lambda |
0x107 | CPU vers satellite | 0xF14C | paramètres de cadencement du protocole |
0x108 | satellite vers CPU | 0xF16C | température d’air, pression de clim et octet d’état (octet 4, bit 7 = mesure valide) |
0x109 | satellite vers CPU | 0xF171 | message de l’antidémarrage EWS |
0x10A | satellite vers CPU | 0xF176 | bloc de configuration (lu au déverrouillage K-line) |
0x10B / 0x10D | requête / réponse | 0xE621 / 0xE626 | bloc de 9 octets lu en mode déverrouillé |
0x10C | CPU vers satellite | 0xF183 | renvoi permuté du bloc 0x10A (déverrouillage) |
0x10E | satellite vers CPU | 0xE625 | statut d’un échange |
En plus de ces messages, l’interruption de réception range à partir de 0xF153 les 24 octets de diagnostic des étages de puissance, un par sortie (partie XII). Le satellite doit suivre la position du moteur : Sat_CylSync_Check (0x2B9EC) vérifie que l’index de cylindre qu’il renvoie correspond au cylindre précédent de celui en cours côté CPU, et une perte de synchronisation lève le code 100 et fait passer en repli l’anticliquetis, la pression de clim et l’antidémarrage.
2. Le bus CAN
Le contrôleur CAN Siemens SAE81C91 (U17) est associé à un émetteur-récepteur SN65LBC031 (U1). C’est un contrôleur autonome, sans programme propre, qui gère 16 objets messages. Il répond en 0xD000–0xD7FF (256 registres répétés huit fois) sur le bus 8 bits de la fenêtre CS1, reçoit l’horloge 12 MHz du CPU sur P3.15 et n’utilise pas sa ligne d’interruption : il est piloté par scrutation.
Au démarrage, CAN_DetectRegisterLayout (0x20D66) vérifie la disposition des registres (le firmware prévoit aussi un second composant dont les registres seraient décalés d’un octet, non monté sur cette carte). CAN_Init_SAE81C91 (0x21332) écrit la configuration : BL1 = 0x36, BL2 = 0x40, OC = 0xF8, BRP = 0. Avec une horloge de 12 MHz, cela donne 500 kbit/s, le débit du bus moteur BMW. Les objets 0 à 11 sont désactivés, seuls quatre messages sont utilisés :
| Objet | Identifiant | Sens | Message | Contenu principal |
|---|---|---|---|---|
| 15 | 0x316 | émission | DME1 | condition de marche, compresseur autorisé, couple de ralenti, défaut débitmètre, régime (× 6,4), charge, octet 5 fonction du régime |
| 14 | 0x329 | émission | DME2 | octet multiplexé, température moteur, température d’air, vitesse véhicule, papillon |
| 12 | 0x545 | émission | DME4 | démarrage refusé, compteur de consommation, niveau de température et surchauffe (125 °C) |
| 13 | 0x43F | réception | EGS1 | code de rapport (octet 1) et demande de la boîte automatique (octet 2) |
CAN_MainTask (0x2124E) tourne toutes les 10 ms dans le groupe de tâches 0. Elle surveille le bus-off, traite la réception de EGS1, construit les trois trames (CAN_TX_Build_DME1_0x316, _DME2_0x329, _DME4_0x545), réécrit au besoin un descripteur corrompu et demande l’émission des trois objets. Les trames partent donc toutes les 10 ms ; les premières sortent environ 0,13 s après la mise sous tension (initialisation du contrôleur, puis onze ticks d’attente).
La température moteur est envoyée telle quelle (CoolantTemp_Lin, °C = 0,75 × x − 48), ou 0xFF si le capteur est en défaut. Le compteur de consommation de DME4 est incrémenté à chaque calcul d’injection de la quantité injectée pondérée par la proportion de cylindres non coupés : le combiné en déduit la consommation.
DME1 (0x316) : octet 0 bit 0 = condition de marche, posé dès la mise du contact ; octet 0 bit 6 = compresseur de clim autorisé (word_FD18.12) ; octet 1 bits 0 à 4 = couple de ralenti en charge partielle (word_FD14.3), bit 7 = défaut du débitmètre (word_FD30.1) ; octets 2-3 = régime × 6,4, le facteur étant appliqué sous la forme × 0xFFFF / 0x2800, ce qui donne un octet bas à 0xFF aux régimes ronds ; octet 4 = charge / 147. L’octet 5 ne dépend que du régime : 29 à 500 tr/min, 32 à 1000, 34 à 1500, 36 à 2000, 39 à 2500, 43 à 3000, 45 à 3500, 46 de 4000 à 4500, 48 de 5000 à 6000 et 50 à 6500.
DME2 (0x329) : l’octet 0 est multiplexé, 0x05 ou 0x80 une trame sur sept ; températures en °C = 0,75 × x − 48 ; vitesse véhicule en 1/128 km/h ; papillon = TPS × 254/201. DME4 (0x545) : le compteur de consommation est un compteur 16 bits qui reboucle ; l’octet 3 bit 3 signale la surchauffe à partir de 125 °C.
La réception de EGS1 confirme la présence d’une boîte automatique. Avec le codage de détection automatique, la boîte n’est reconnue que si EGS1 arrive dans les 0,5 s (50 ticks) qui suivent la mise sous tension. Le code de rapport (octet 1, bits 0 à 3) donne le bit « rapport engagé » pour les codes 2, 3, 4, 5 et 7 ; un code supérieur ou égal à 9 relève du code 216. L’octet 2 (bits 0 à 4) est mis à l’échelle 0-255 et injecté dans la régulation de ralenti et la rampe d’allumage. L’absence de EGS1 pendant 20 ticks alors que la boîte a été vue lève le code 217, et un bus-off le code 219, après quoi le contrôleur est réinitialisé. Dans la calibration ID41, le pas d’anti-rebond des codes 216 et 219 vaut 0 : ces deux codes ne sont jamais mémorisés.
Seul sur le bus, sans autre nœud pour acquitter ses trames, le contrôleur passe en erreur passive (compteurs d’erreurs au-delà de 128) : les trois émissions restent en attente (TRSR2 = 0xD0), sans aller jusqu’au bus-off.
3. La K-line : couche physique et trames
La K-line utilise l’UART ASC0, sur une ligne unique en half-duplex : 9615 bauds au démarrage (S0BG = 0x26), 8 bits de données, parité paire, un bit de stop en réception et deux en émission. Un port série réglé à 9600 bauds convient. L’outil relit en écho chaque octet qu’il émet : il doit lire et jeter autant d’octets qu’il en a envoyé avant de lire la réponse.
Requêtes et réponses ont la même structure :
12 LL CC [données...] CS
12 octet de synchronisation
LL longueur totale de la trame, 12 et CS compris
CC code de commande (requête) ou code de statut (réponse)
CS XOR de tous les octets précédents
exemple : 12 04 05 13 (12 xor 04 xor 05 = 13)
Les temps comptent : le calculateur ouvre une trame sur un 0x12 précédé d’au moins 30 ms de silence, et abandonne la trame si plus de 20 ms séparent deux octets. Une trame au checksum faux, tronquée ou mal temporisée ne reçoit aucune réponse. La réponse part entre 30 et 70 ms après le dernier octet de la requête. En pratique, il faut vider le tampon de réception avant chaque émission et détecter la fin d’une réponse par une cinquantaine de millisecondes d’inactivité.
Les trames sont traitées par la tâche 41 KLine_Task41_FrameHandler (0x226DC). Au démarrage, tant qu’aucun dialogue n’a été ouvert, la réception est coupée au-dessus de 2000 tr/min : le premier diagnostic doit commencer moteur arrêté ou sous ce régime. Une fois ouvert, le dialogue reste ouvert à tout régime, jusqu’à 30 s sans trame ou une commande 0x9F.
| Statut | Signification |
|---|---|
0xA0 | commande exécutée |
0xA1 | occupé, renvoyer la même requête |
0xA2 | refusé, conditions non remplies |
0xB0 | sous-commande ou paramètre invalide (ou clé de login fausse) |
0xB2 | mot de passe faux |
0xFF | commande inconnue dans l’état courant |
4. Les modes d’accès
KLine_ServiceID_Dispatcher (0x22428) distingue trois niveaux. Le niveau 1 est toujours disponible : 0x00, 0x04, 0x14, 0x53, 0x06, 0x07, 0x0B, 0x90. En mode normal, le niveau 2 ajoute les commandes de diagnostic : 0x0A, 0x0C, 0x05, 0x9E, 0x9F, 0x0D, 0x40 à 0x43, 0x2B, 0x22, 0x23. En mode déverrouillé, ces commandes répondent 0xFF et le niveau 3 ajoute 0x25, 0x31 et 0x21, puis la recherche de modules d’extension : une couche « FEPRAM » chargée en RAM externe (0xDC20) ou « FEPROM » en flash (0x1C000, vierge ici) peut traiter des commandes supplémentaires.
En session de programmation (secteur de démarrage), seules six commandes existent : 0x00, 0x06, 0x07, 0x0A, 0x0D et 0x90, traitées par BootSector_ServiceID_Dispatcher (0x152E), interruptions coupées et UART lue par scrutation.
5. Le jeu de commandes
| Code | Fonction | Mode | Gestionnaire |
|---|---|---|---|
0x00 | identification (46 octets ASCII) | tous | KLine_Cmd00_Ident (0x23B52) |
0x04 | lecture des défauts confirmés | normal, déverrouillé | KLine_Cmd04_14_ReadFaults (0x2281E) |
0x05 | effacement de la mémoire des défauts | normal | KLine_Cmd05_ClearFaults (0x22980) |
0x06 | lecture mémoire (CPU, ou EEPROM déverrouillé) | tous | KLine_Cmd06_MemoryRead (0x2354A) |
0x07 | écriture RAM, EEPROM, effacement et programmation flash | tous | KLine_Cmd07_31_MemoryWrite (0x23688) |
0x0A | état des contrôles CRC | normal, programmation | KLine_Cmd0A_IntegrityStatus (0x22A7A) |
0x0B | mesures et lectures étendues | normal, déverrouillé | KLine_Cmd0B_LiveData (0x22C68) |
0x0C | test d’actionneur | normal | KLine_Cmd0C_ActuatorTest (0x23448) |
0x0D | adresses des blocs d’identification | normal, programmation | KLine_Cmd0D_AddressTable (0x23D70) |
0x14 | lecture des défauts détectés, confirmés ou non | normal, déverrouillé | KLine_Cmd04_14_ReadFaults |
0x21 | test destructif de l’EEPROM | déverrouillé | KLine_Cmd21_EEPROMTest (0x24096) |
0x22 | fin de la phase de condensation des sondes | normal | KLine_Cmd22_Misc (0x23A5C) |
0x23 | commande sans effet | normal | KLine_Cmd23_Stub (0x23AB0) |
0x25 | présence de la calibration | déverrouillé | KLine_Cmd25_CalibBlankCheck (0x24156) |
0x2B | régularité par cylindre, crêtes des sondes | normal | KLine_Cmd2B_Roughness_O2Peaks (0x23960) |
0x31 | accès mémoire, variante déverrouillée de 0x07 | déverrouillé | KLine_Cmd07_31_MemoryWrite |
0x40 / 0x41 / 0x42 | lecture, réglage et mémorisation du CO et du ralenti | normal | 0x23EE8 / 0x23F36 / 0x23FEC |
0x43 | effacement des adaptations | normal | KLine_Cmd43_ClearAdaptations (0x23D96) |
0x53 | adresses des champs d’identification | normal, déverrouillé | KLine_Cmd53_IdentAddrTable (0x23BC8) |
0x90 | déverrouillage, débit, login « BMW » | tous | KLine_Cmd90_Unlock (0x23C62) |
0x9E | maintien de la session | normal | KLine_Cmd9E_SessionKeepAlive (0x22A32) |
0x9F | fin de la session de diagnostic | normal | KLine_Cmd9F_SessionEnd (0x22A40) |
Aucun autre code de commande n’obtient de réponse utile : tous les autres renvoient 0xFF.
6. Les principales commandes en détail
Identification (0x00). La requête 12 04 00 16 renvoie 42 octets ASCII : numéro de pièce, numéro de matériel, indices de codage, de diagnostic et de bus, semaine et année de fabrication, numéro de fournisseur, numéro de logiciel, indice de modification et numéro de production, dont les quatre derniers caractères sont l’ISN. La plupart des champs viennent du secteur de démarrage, les numéros propres au programme de la flash 0x2025 et 0x2068–0x2071. Le VIN n’y figure pas : il se lit par 0x06 à l’adresse 0x1D07, désignée par la commande 0x0D.
Lecture mémoire (0x06). La trame 12 09 06 00 AH AM AL NN CS lit NN octets (jusqu’à 252) à l’adresse physique de 24 bits, sans aucune authentification, dans tout l’espace CPU de 0x00000 à 0x3FFFF. La sous-commande 0x03 lit l’EEPROM série, en mode déverrouillé seulement. C’est le mécanisme des lectures complètes de 256 Ko.
Écriture mémoire (0x07). La même forme d’adresse sert à écrire. La sous-commande 0x00 écrit en RAM avec relecture, limitée à la fenêtre 0xDC20–0xDC36 en mode normal et à 0xDC20–0xE31F en mode déverrouillé ; la sous-commande 0x03 écrit l’EEPROM en mode déverrouillé ; les sous-commandes 0x02, 0x06 et 0x0F écrivent, effacent et finalisent la flash après le login (partie XIII).
Mesures (0x0B). La sous-commande 0x03 renvoie une trame de 25 mesures : régime, vitesse, tension papillon, masse d’air, tensions des sondes de température, avance appliquée, temps d’injection, terme de régulation de ralenti, commande de la vanne, position de came, tension batterie, corrections lambda des deux bancs et chauffage des sondes. La sous-commande 0x04 renvoie trois octets d’états logiques (position du papillon, fils ABS/ASC, démarrage refusé, clim, boîte, états moteur, boucle fermée, relais de pompe, compresseur, VANOS, volet). La sous-commande 0x02 lit un champ isolé : une entrée ADC brute ou un niveau de cliquetis. Les sous-commandes 0x91 à 0x94 renvoient les adaptations lambda, le zéro papillon et l’adaptation de ralenti, le décalage anticliquetis et l’octet d’état de la configuration. Enfin, les sous-commandes 0x01 et 0x00 permettent à l’outil de programmer une liste de jusqu’à 49 grandeurs (octet ou mot à une adresse donnée, ou champ) puis de les relire toutes en une seule trame.
Test d’actionneur (0x0C). La trame 12 07 0C CC P0 P1 CS désigne l’actionneur par son numéro de code défaut et donne une durée et une période. Moteur arrêté, le calculateur passe d’abord en mode service et pulse la sortie sans fin : injecteurs (06, 05, 16, 18, 21, 17 pour les cylindres 1 à 6), vanne de ralenti (35), relais de pompe (45), relais de clim (4A), vanne de purge (44). Moteur tournant, un code d’injecteur coupe l’injection de ce cylindre, ce qui sert de test de contribution au ralenti, et les codes 34 et 15 ferment le volet ou engagent le VANOS au ralenti. Le test s’arrête à la commande suivante, à 0x9F ou après 30 s sans trame ; le mode service, lui, dure jusqu’à la coupure du contact.
Réglage du CO et du ralenti (0x40 à 0x42). Sur un moteur sans régulation lambda, 0x41 sous-commande 1 règle la richesse au ralenti à l’analyseur, par pas de 0,39 % du mélange, moteur chaud et sans défaut. La sous-commande 2 règle un décalage du régime de ralenti en tr/min. Les réglages agissent immédiatement mais ne survivent à la coupure du contact qu’après la commande 0x42.
Test de l’EEPROM (0x21). En mode déverrouillé, cette commande écrit cinq motifs dans toute l’EEPROM et la laisse à 0x00, sauf les moyennes des cellules anticliquetis. Elle efface donc les adaptations, les défauts mémorisés, le compteur d’heures, les décisions d’auto-détection et la copie de l’identité.
7. Correspondance avec le testeur BMW
Les jobs EDIABAS du MS41 utilisent ces commandes. IDENT et ISN_LESEN lisent l’identification, AIF_LESEN le champ d’information utilisateur, FS_LESEN, FS_QUICK_LESEN et FS_SHADOW_LESEN les défauts, FS_LOESCHEN les efface, ADAPT_LOESCHEN efface les adaptations, les jobs STATUS_… lisent les trames 0x0B, les jobs STEUERN_… lancent les tests d’actionneurs, CO_ABGLEICH_… règle et mémorise le CO, et DIAGNOSE_ENDE ferme la session. Les températures affichées par le testeur sont des droites appliquées aux tensions brutes des sondes, pas les valeurs linéarisées du calculateur.
Le job STEUERN_TEV envoie le code 0x46 pour la vanne de purge, qui n’existe pas dans l’ID41 (sa vanne de purge est le code 0x44) : le test répond une erreur.
XII. Détection des pannes et codes défaut
1. La chaîne, du contrôle au code mémorisé
Chaque défaut possède une fiche fixe de 16 octets dans la flash et un enregistrement de 10 octets en RAM, rangés par index de 0 à 51. Le numéro affiché par le testeur est l’octet 0 de la fiche, distinct de l’index.
fiche = 0x2582 + index x 16 (lue par le code en 0xA582, DPP2 = 0)
enregistrement = 0xEA1A + index x 10
fiche : [0] numéro de code [1] drapeaux (bit 4 : défaut lié aux émissions)
[2..7] paramètres [8..15] quatre pointeurs vers les grandeurs à figer
enregistrement : [0] octet d'état [1] compteur d'anti-rebond
[2] compteur de fréquence [3] compteur d'oubli
[4..7] freeze-frame [8..9] temps de fonctionnement
La chaîne est toujours la même. La fonction de contrôle propre à chaque défaut place le type d’anomalie constaté dans FaultMonitor_GlobalInhibit (0xEA0E) : 0 si tout va bien, 1, 2, 4 ou 8 sinon. Le testeur affiche 1 comme un court-circuit au plus, 2 comme un court-circuit à la masse, 4 comme un circuit ouvert (pour un capteur : valeur trop haute, trop basse ou absente) ; 8 sert aux défauts de plausibilité, d’absence de message et de somme de contrôle. Elle appelle ensuite le moteur de confirmation, qui gère l’anti-rebond, le freeze-frame et les listes. À la fin d’un cycle de chauffe, les défauts disparus vieillissent, et à l’extinction les dix premiers défauts confirmés sont sauvegardés en EEPROM.
2. Le moteur de confirmation
Trois fonctions, utilisées en 110 points du programme, forment le moteur de confirmation : FaultMonitor_Evaluate_A (0x259E6), _B (0x25C9C) et _Both (0x25B10). Elles reçoivent l’adresse de l’enregistrement, celle de la fiche, un pas d’incrément et un seuil de confirmation, ces deux derniers étant des octets de calibration propres à chaque contrôle (0x1014F–0x10185).
À la première anomalie sur un enregistrement vide, le défaut est détecté : son index entre dans la liste FaultList_Detected (0xEC5A), le freeze-frame est figé et le temps de fonctionnement noté. Tant que l’anomalie persiste, le compteur d’anti-rebond monte du pas ; quand il atteint le seuil, le défaut est confirmé : il entre dans FaultList_Confirmed (0xEC26), les bits « confirmé » et « présent » sont posés, le compteur d’oubli est remis à 40 et le compteur de fréquence augmente. Sans anomalie, le compteur d’anti-rebond redescend de 1 par passage ; à 0, un défaut confirmé perd son bit « présent » et devient sporadique.
Le pas et le seuil règlent la vitesse de confirmation. Les bobines, par exemple, montent par pas de 2 jusqu’à 80, soit environ quarante passages en défaut avant confirmation, tandis que les bornes de la régulation lambda ont un pas égal au seuil et sont confirmées immédiatement. La variante _A garde le type d’anomalie de la première détection, _B le met à jour à chaque passage en défaut, et _Both inscrit le défaut directement dans les deux listes, sans anti-rebond.
| Bit de l’octet d’état | Signification |
|---|---|
| 0 à 3 | type d’anomalie (1, 2, 4, 8) |
| 4 | défaut lié aux émissions |
| 5 | défaut confirmé |
| 6 | défaut présent |
| 7 | défaut sporadique (confirmé puis disparu au moins une fois) |
3. Le freeze-frame
À la première détection, le moteur de confirmation lit les quatre octets désignés par les pointeurs de la fiche et les range dans l’enregistrement. Chaque code a sa propre combinaison, et le freeze-frame n’est plus remplacé ensuite. Le régime (RPM_Byte) est la première grandeur de presque toutes les fiches ; viennent ensuite, selon le défaut, la charge, la tension batterie, les températures, le correcteur lambda du banc concerné, la tension et le chauffage des sondes, l’angle papillon, la commande de la vanne de ralenti, la position de came, la vitesse véhicule, le gain et le bruit de cliquetis ou la durée de retour d’allumage du cylindre.
| Grandeur figée | Conversion |
|---|---|
| régime | x × 32 tr/min |
| charge | x × 5,447 mg/course |
| angle papillon | x × 0,47 % |
| tension batterie | x × 0,1 V |
| températures moteur et air | x × 0,75 − 48 °C |
| correcteur lambda | (x − 128) × 0,39 % |
| tensions de sondes et de capteurs | x × 20,3 mV |
| chauffage des sondes, commande de ralenti | x × 0,39 % |
| position de came | x × 0,375 ° vilebrequin |
| débit d’air | x × 4 kg/h |
| durée de retour d’allumage | octet bas × 5,333 µs, octet haut × 1,365 ms |
4. L’oubli automatique et le voyant moteur
Un cycle de chauffe est validé quand la température moteur dépasse 71 °C et a gagné plus de 21 °C depuis le démarrage, moteur tournant. À la fin d’un tel cycle, FaultList_AgeAndExpire (0x25E08) décrémente le compteur d’oubli de chaque défaut confirmé qui n’est plus présent ; à 0, l’enregistrement est effacé et l’index retiré des deux listes. Un défaut disparaît donc seul après 40 cycles de chauffe sans réapparaître.
Toutes les 500 ms, la tâche 27 FaultList_ScanAndPropagateStatus (0x200B6) parcourt les défauts confirmés. Le voyant moteur (P3.1) est éteint en sous-tension, allumé moteur arrêté contact mis (contrôle de l’ampoule), et moteur tournant allumé seulement si un défaut confirmé est présent et que la fonction est codée (octet 5, bit 6).
Le temps de fonctionnement Fault_OperatingTime (0xEC8E) augmente de 1 toutes les 360 s calculateur alimenté, soit 0,1 h par pas, et Fault_ClearTime (0xEC22) garde sa valeur au dernier effacement.
5. La sauvegarde en EEPROM
PersistedFaults_SaveToEEPROM (0x24D36) prépare dans le miroir RAM 0xEF76 puis écrit à l’adresse EEPROM 0x74, pendant la séquence d’extinction, le nombre de défauts (dix au plus), leurs index, leurs enregistrements, le masque des raisons du code 100 et une somme de contrôle. Au démarrage, PersistedFaults_RestoreOnBoot (0x248E6) vérifie la somme, reconstruit les deux listes et repose le drapeau « défaut actif » de chaque défaut présent : les modes dégradés reprennent dès le démarrage. Au-delà de dix défauts confirmés, les suivants sont perdus à la coupure du contact, et les défauts seulement détectés ne sont jamais sauvegardés.
L’effacement par la K-line (0x05) remet à zéro les enregistrements, les listes, les drapeaux « défaut actif » et les limitations dégradées en RAM ; il est écrit en EEPROM à l’extinction suivante. Un défaut toujours présent est aussitôt détecté de nouveau.
6. La surveillance des sorties de puissance
Les défauts de circuit des sorties sont traités par FaultDetection_MasterDispatcher (0x21404), la plus grosse fonction du firmware, appelée toutes les 10 ms. C’est une machine à 21 états (FaultDispatch_StateIndex, table de saut en 0x2504) qui étale la charge de calcul sur plusieurs passages. Chaque état vérifie que le régime est suffisant, qu’aucune limitation de régime n’est active et que le cylindre concerné n’est pas coupé, puis teste les bits 5 à 7 de l’octet de diagnostic de la sortie reçu du satellite (SatDiag_*, 0xF153–0xF162) et appelle le moteur de confirmation.
| Octet satellite | Sortie | Code |
|---|---|---|
0xF153 / 0xF154 | injecteurs 2 / 5 | 5 / 33 |
0xF155 | volet d’échappement | 52 |
0xF156 | chauffage sonde avant 1 | 25 |
0xF157 / 0xF158 | injecteurs 1 / 3 | 6 / 22 |
0xF159 / 0xF15A | vanne de ralenti, ouverture / fermeture | 53 / 27 |
0xF15B / 0xF15C | injecteurs 6 / 4 | 23 / 24 |
0xF15D | électrovanne VANOS | 21 |
0xF15E | chauffage sonde avant 2 | 55 |
0xF15F | relais de compresseur de clim | 74 |
0xF160 | relais de pompe à essence | 69 |
0xF161 | relais principal DME | pas de code, le CPU coupe la commande |
0xF162 | ventilation du réservoir | 68 |
Pour certains défauts, le dispatcher pose aussi un bit de FaultDispatch_ActiveMask (0xEA10), qui agit directement sur la sortie : 0x20 maintient le volet ouvert, 0x40 coupe le relais de compresseur et 0x80 interdit l’engagement du VANOS. Les octets des boîtiers U8 et U10 (chauffages arrière, purge, running losses, voyant, air secondaire) sont reçus mais non exploités par ce logiciel.
7. Le code 100 et les contrôles d’intégrité
Le code 100 (« DME Control Unit – Self-Test », fiche 44) ne passe pas par l’anti-rebond. Chaque contrôle interne pose ou efface une raison dans FaultDispatch_ExtraMask (0xEA0C), puis SystemEvent_LogAndAccumulate (0x25BDC) inscrit le code dès qu’une raison est posée. Le freeze-frame de ce code fige la tension de la sonde de température, la tension batterie et les raisons cumulées.
| Raison | Contrôle |
|---|---|
0x0001, 0x0002, 0x0008, 0x2000 | test de la RAM au reset |
0x0004, 0x0010, 0x0200 | configuration de la liaison avec le satellite |
0x0020 | calibration incompatible avec le programme |
0x0040 | l’EEPROM n’acquitte pas |
0x0080 | écriture EEPROM non vérifiée |
0x0100 | CRC du programme ou du secteur de démarrage faux |
0x0400 | CRC de la calibration faux |
0x1000 | synchronisation avec le satellite perdue |
Un CRC faux n’a pas d’autre effet que ce code : le moteur fonctionne normalement. Les trois contrôles CRC sont détaillés en partie XIII.
8. Les 52 codes défaut de l’ID41
Les libellés viennent des fichiers EDIABAS du MS41. Les codes de la liste EDIABAS absents de ce tableau n’existent pas dans ce logiciel : il ne contient notamment aucun code de raté de combustion, aucun code de pédale ou de papillon motorisé, et aucun code de sonde aval.
| Code | Désignation | Contrôle |
|---|---|---|
| 1, 2, 3 | bobines d’allumage cylindres 2, 4, 6 | retour d’allumage par cylindre |
| 29, 30, 31 | bobines d’allumage cylindres 1, 3, 5 | retour d’allumage par cylindre |
| 5, 6, 22 | injecteurs cylindres 2, 1, 3 | étages de sortie (satellite) |
| 23, 24, 33 | injecteurs cylindres 6, 4, 5 | étages de sortie (satellite) |
| 8 | débitmètre HFM | plausibilité et entrée P1.10 |
| 10 | sonde de température moteur | plage et variation |
| 12 | capteur papillon | plage et zéro |
| 14 | sonde de température d’air | valeur transmise par le satellite |
| 16 | capteur de pression de climatisation | mode capteur de pression |
| 18 | antidémarrage : pas de réponse de l’EWS, message faux ou délai dépassé | message ASC1 0x109 |
| 209 | antidémarrage : code reçu différent de l’ISN | EWS_CodeCheck |
| 21 | VANOS, défaut électrique | étage de sortie |
| 212 | VANOS, position de came incohérente avec la commande | DTC212_Check |
| 25, 55 | chauffage des sondes lambda bancs 1 et 2 | étages de sortie |
| 75, 76 | tension des sondes lambda bancs 1 et 2 | plage |
| 200, 201 | régulation lambda bancs 1 et 2 : bande de détection trop étroite | régulation |
| 202, 203 | régulation lambda bancs 1 et 2 : correction en butée | régulation |
| 27, 53 | vanne de ralenti, enroulements de fermeture et d’ouverture | étages de sortie |
| 211 | plausibilité de la masse d’air, adaptation de ralenti hors limites | adaptation |
| 52 | volet d’échappement | étage de sortie |
| 56 | résistance de retour d’allumage ouverte | aucun retour sur les six cylindres |
| 210 | résistance de retour d’allumage | trois bobines en défaut ou plus |
| 57, 59 | capteurs de cliquetis 1 et 2 | niveaux renvoyés par le satellite |
| 65 | arbre à cames | synchronisation |
| 83 | vilebrequin | plausibilité du signal |
| 68 | vanne de ventilation du réservoir | étage de sortie |
| 69 | relais de pompe à essence | étage de sortie |
| 74 | relais de compresseur de climatisation | étage de sortie |
| 80, 81, 82 | interface ABS/ASC (P1.12, MSR trop long sur P1.13, P1.14) | durée maximale des fils |
| 215 | code invalide sur les fils ABS/ASC | combinaison interdite |
| 214 | capteur de vitesse véhicule | plausibilité |
| 216 | code de rapport EGS1 invalide | bus CAN, jamais mémorisé avec la calibration ID41 |
| 217 | message EGS1 absent | bus CAN |
| 218 | avertissement du module CAN | fiche présente, jamais appelée |
| 219 | bus CAN hors service (bus-off) | contrôleur CAN, jamais mémorisé avec la calibration ID41 |
| 100 | auto-test du calculateur | intégrité, EEPROM, RAM, satellite |
Un défaut de capteur active un mode dégradé : valeur de substitution pour la température d’air ou moteur, angle papillon reconstruit à partir du débit d’air en cas de défaut papillon (« TPS Substitute »), limiteur de régime réduit sur défaut papillon ou débitmètre, coupure de l’injection d’un cylindre dont la bobine est en défaut, et suspension de la régulation lambda sur défaut de sonde.
XIII. Lecture, reprogrammation et sommes de contrôle
1. La lecture du calculateur
Aucune authentification n’est nécessaire pour lire : la commande 0x06 lit tout l’espace du CPU par blocs (128 octets en pratique). Trois lectures sont courantes. La lecture partielle parcourt 0x10000–0x15FFF et donne le fichier de calibration de 24 Ko (les outils l’appellent souvent « EEPROM », bien que ce soit de la flash). La lecture brute parcourt 0x00000–0x3FFFF et donne la mémoire telle que la voit le CPU (lecture mémoire, ordre délinéarisé). La lecture complète au format standard range les blocs de 16 Ko dans l’ordre physique de la puce : adresse CPU = offset du fichier XOR 0x4000, avec la zone CPU 0x0C000–0x0FFFF et les pages 0x18000–0x1FFFF remplies de 0xFF.
2. Le principe de l’écriture flash
L’écriture de la flash est toujours exécutée par le secteur de démarrage (0x0000–0x1C13), qui n’est jamais effacé par cette procédure. Elle exige le login « BMW » (KLine_LoginState = 2) et un calculateur à l’arrêt ; le calculateur passe d’abord en mode service, coupe les interruptions puis donne la main au secteur de démarrage par sa table de points d’entrée (BootSector_EntryTable, 0x0200) :
- pour une adresse de programme (
0x2000–0x7FFFou0x20000–0x3FFFF), il entre dans la session de programmationBootSector_FlashSession_Main(0x073C) et y reste jusqu’à la coupure du contact ; - pour la calibration (
0x10000–0x15FFF), l’opération est exécutée directement parBootSector_FlashWriteErase_Handler(0x0E86), puis l’application reprend.
Les algorithmes propres à la puce 28F200 sont copiés de la flash vers la RAM (0xE320–0xE41F) et exécutés depuis la RAM, la flash ne pouvant pas être lue pendant sa programmation. FlashAlgo_ProgramWords (0x0230) met P2.6 à 1 pour appliquer la tension de programmation, envoie pour chaque mot la commande 0x40 puis la donnée et attend le bit « prêt » du registre d’état ; FlashAlgo_EraseBlock (0x032E) envoie la séquence 0x50, 0x20, 0xD0 et attend la fin de l’effacement en servant le chien de garde. Les erreurs de tension, de programmation ou d’effacement de la puce donnent le code résultat 2.
L’état de la programmation, FlashProg_State (0xE740), est sauvegardé en EEPROM en trois copies : 1 quand le programme est effacé sans être réécrit, 3 pour la calibration, 0 une fois l’écriture terminée et contrôlée. C’est grâce à lui qu’un calculateur interrompu pendant l’écriture du programme redémarre directement en session de programmation et reste joignable.
3. La séquence d’écriture
Toutes les trames d’écriture ont la forme 12 LL 07 SS AH AM AL NN [données] CS et reçoivent une réponse de 10 octets dont l’avant-dernier est le code résultat (1 = correct).
1. login 0x90 "BMW" (défi puis clé)
2. trame 07 0F, longueur 0 : contrôles de fin, puis arme l'effacement
3. trame 07 06 : efface la zone
4. trames 07 02 de 128 octets : écrit les données
5. trame 07 0F à l'adresse 0 : contrôles de fin
6. commande 0x0A en boucle : attend la fin du contrôle CRC (réponse A0)
calibration : 12 09 07 0F 00 01 00 00 12 puis 12 09 07 06 01 00 00 00 1B
programme : 12 09 07 0F 00 00 20 00 33 puis 12 09 07 06 00 20 00 00 3A
données : 12 89 07 02 01 00 00 80 [128 octets] CS (adresse 0x10000)
L’effacement de la calibration vise le bloc 0x10000 ; celui du programme efface les blocs 0x2200, 0x4000 et 0x20000. Le calculateur refuse d’écrire sur une zone non vierge (code 3) : une flash ne peut passer ses bits que de 1 à 0, seul l’effacement les remet à 1. Les données sont programmées mot par mot ; une trame qui commence ou finit sur une adresse impaire est complétée par 0xFF.
La trame de fin vérifie la cohérence de ce qui a été écrit. Elle lit les identifications du secteur de démarrage (0x1CEF), du programme (0x2001) et de la calibration (0x10012), contrôle leur compatibilité, puis la présence des marqueurs de fin : l’octet qui précède 0x32816 pour le programme, le mot 0x15E1E pour la calibration. Si tout est correct, FlashProg_State repasse à 0. Après une écriture complète, la trame de fin est indispensable : sans elle, le calculateur redémarre en session de programmation.
| Code résultat | Signification |
|---|---|
| 1 | opération correcte |
| 2 | erreur de la puce flash |
| 3 | cible non vierge |
| 7 / 8 | écriture de calibration ou de programme demandée pendant une écriture de l’autre zone non terminée |
9, 0x0A, 0x0D | lecture d’une identification impossible |
0x0B / 0x0E | programme incompatible avec le secteur de démarrage / calibration incompatible avec le programme |
0x0C / 0x0F | programme / calibration incomplet (marqueur de fin vierge) |
4. Écriture partielle et écriture complète
L’écriture partielle reprogramme la calibration de 24 Ko : effacement du bloc 0x10000, puis écriture de 0x10000 à 0x15F7F par blocs de 128 octets (le dernier bloc, vierge, n’est pas transmis). Elle reste dans l’application, mais laisse le calculateur en mode service jusqu’à la coupure du contact. Elle se termine sans trame de fin : l’état reste à 3, ce qui n’empêche pas le démarrage, et la trame de fin de l’écriture suivante remet l’état à 0.
L’écriture complète efface le programme et la calibration puis écrit treize régions, soit 179 968 octets sur 262 144 : les banques sont permutées comme pour la lecture, les deux zones vierges ne sont pas transmises, et le secteur de démarrage 0x0000–0x1FFF (vecteurs, amorçage, VIN, identité d’usine) n’est jamais écrit. Elle se termine par la trame de fin puis par le sondage 0x0A jusqu’à la réponse 12 05 A0 00 B7.
5. Les sommes de contrôle
Le firmware vérifie trois zones par un CRC-16/ARC (polynôme réfléchi 0xA001, CRC16_ProcessByte), calculé par petites étapes depuis la boucle principale pour ne rien bloquer. L’état des contrôles est rangé dans SystemIntegrity_StatusFlags (0xE655) et lisible par la commande 0x0A.
| Zone | Couverture | Valeur de départ | CRC attendu | Fonction |
|---|---|---|---|---|
| secteur de démarrage | 0x0000–0x1C13 | 0x4711 | mot 0x1C80 | BootSector_CRC_Validator (0x2B662) |
| programme | 0x2100–0x36AD, 0x4000–0x5E7F, 0x20000–0x32815 | octets 0x2066–0x2067 (fin du mot de passe) | mot 0x2050 | FlashIntegrity_IncrementalScanner (0x2B6B0) |
| calibration | 16 régions | octets 0x1000E–0x1000F | mot de fin de chaque région | CalibCRC_Validator (0x2B786) |
Les erreurs du programme et du secteur de démarrage ne comptent que si l’octet 0x205C ne vaut pas 0xFF (il vaut 0x30 d’origine) : mettre cet octet à 0xFF désactive ces deux contrôles. Le contrôle de la calibration est actif si la table des régions (0x15E00) est programmée et si le bit 4 de l’octet de codage 7 est à 0.
La calibration est découpée en régions chaînées. La table commence par le marqueur 4E 00 FF FF en 0x10000 ; chaque région commence par un mot qui donne, en adresse logique, l’adresse de fin de la région, où est rangé son CRC. Le CRC couvre la région depuis ce mot jusqu’à l’adresse de fin exclue, avec la même valeur de départ pour chaque région, et la région suivante commence deux octets plus loin. La chaîne s’arrête sur un mot 0xFFFF. Une seizième région couvre la table des régions elle-même (0x15DFE–0x15E1F).
En pratique, une calibration modifiée doit avoir les CRC de ses régions recalculés, sinon le code 100 apparaît ; une modification du code programme impose de recalculer le CRC du programme ou de désactiver ce contrôle. Les champs du VIN et de l’identité ne sont couverts par aucun CRC. Deux outils font ce calcul : le MS41 Checksum Calculator, projet open source publié sur GitHub par Kim Freding, qui parcourt la même chaîne de régions à partir du marqueur 4E 00 FF FF, et le script ms41_id41_crc_fix.py livré avec la définition RomRaider, qui vérifie et recalcule les trois familles de CRC sur un fichier de 256 Ko et les CRC de la calibration sur un fichier de 24 Ko.
Conclusion et crédits
Le MS41.0 apparaît comme un calculateur à deux processeurs dont le partage des rôles est net. Le CPU principal gère tout ce qui est critique dans le temps et dans la sécurité : synchronisation, injection séquentielle, allumage, VANOS, ralenti, régulation lambda, diagnostic et communication. Le satellite ST9 gère les sorties d’émissions et de confort, mesure les signaux lents ou délicats (température d’air, pression de climatisation, cliquetis), surveille toutes les sorties de puissance et relaie l’antidémarrage. Le firmware est structuré autour d’un ordonnanceur coopératif sans système d’exploitation, de routines d’interruption courtes, et d’une philosophie de sécurité constante : en cas de doute, il coupe proprement.
Les pistes encore ouvertes concernent le matériel autour de quelques broches (origine du signal de défaut du débitmètre sur P1.10, circuit du retour d’allumage, destinataire de la sortie PWM papillon P2.14, nœud commun à P2.10 et à la broche 12 du GAL), le firmware propre du satellite, qui n’est pas lisible depuis la K-line, la signification de l’octet 5 de DME1, et la valeur du prédiviseur du contrôleur CAN relue dans l’image mémoire (0xF8), différente de celle écrite à l’initialisation.
Crédits : décompilation, relevés matériels, documents sur les broches et le schéma de la carte, captures et analyses par Diolum. Définition RomRaider de l’ID41 issue de la communauté, vérifiée et complétée. Recalcul des sommes de contrôle : MS41 Checksum Calculator, projet open source de Kim Freding sur GitHub. Libellés des codes défaut et des jobs de diagnostic : fichiers EDIABAS du MS41.
