En résumé
- Le bootloader se connecte au webservice de mise à jour à chaque démarrage pour vérifier — et, si besoin, télécharger — une nouvelle version de firmware.
- Cette connexion échoue par intermittence, toujours au même endroit : juste après le message
Starting PDP, au moment d'ouvrir la connexion de données (+CME ERROR: no network serviceouoperation not allowed). - Conséquence : l'OTA peut échouer (de façon intermittente, ~2 fois sur 3) — aussi bien la mise à jour d'une sonde en service (qui tourne alors en boucle, log du 19/06) que le premier chargement du firmware sur une carte neuve. L'enjeu est donc la fiabilité, pas une panne systématique.
- Cause de fond (confirmée par les logs terrain) : le bootloader force
AT+CGACT=1,1— commande nécessaire en 2G mais refusée en LTE-M (le contexte de données y est déjà monté). Le BL passe quand le modem accroche en 2G, échoue le plus souvent en LTE-M — d'où l'intermittence. - Aggravant : quand la sonde a déjà un firmware valide, un échec de connexion ne déclenche aucun nouvel essai automatique — le bootloader démarre l'application et remet la mise à jour au prochain redémarrage. Sur une sonde montée, la seule relance possible est un reset long à l'aimant : il rejoue bien l'OTA, mais échoue lui-même ~2 fois sur 3 → la mise à jour peut nécessiter plusieurs tentatives, voire rester bloquée.
1 Contexte & portée
La mise à jour à distance (OTA) échoue par intermittence sur les prototypes M10 (modem u-blox SARA-R422M10S) : le bootloader n'arrive pas toujours à joindre le webservice — que ce soit pour mettre à jour une sonde en service ou pour charger le firmware sur une carte neuve.
Ce document le décrit, propose un diagnostic appuyé sur la lecture du code et la documentation u-blox, distingue ce qui est vérifié de ce qui reste hypothèse, et liste les mesures et les tests à mener.
L'analyse est statique : lecture du code source du bootloader (branche à jour, v0.1.9) et de la documentation u-blox. Elle n'a pas encore été confrontée à une trace réseau réelle ni à une mesure électrique. Les conclusions sont donc graduées (vérifié / probable / à tester), et la section Tests est conçue précisément pour lever les incertitudes avant de figer un correctif.
2 Le mécanisme OTA, étape par étape
À chaque démarrage, le bootloader exécute toujours la même séquence avant de passer la main à l'application.
- Allumage du modem Mise sous tension et séquence de power-on.
- Initialisation & attente d'enregistrement réseau Le modem doit être enregistré sur le réseau avant d'aller plus loin.
- Lecture de l'IMEI Identifiant unique utilisé pour interroger le serveur.
- Ouverture du contexte de données — « Starting PDP » C'est ici qu'échoue la connexion. (La trace « Starting PDP » n'apparaît qu'en build verbeux
APP_VERBOSE.) - Connexion au serveur & comparaison de checksum Le bootloader compare le checksum du serveur au firmware flashé et, si une mise à jour est en attente, la télécharge. S'il ne peut pas se connecter (étape 4), la mise à jour échoue.
La séquence est lisible telle quelle dans la boucle principale du bootloader :
// 1. Power on SARA_R422 ret = SARA_R422_Power_On(&appdata->SARA_R422); // 2. Initialize SARA_R422 (inclut l'attente d'enregistrement réseau) ret = SARA_R422_Init(&appdata->SARA_R422); // 3. Read and store IMEI ret = SARA_R422_Get_IMEI(&appdata->SARA_R422, appdata->IMEI, ...); debug_print("[DEBUG]Starting PDP...\r\n"); // 4. SARA R422 PDP activate <-- POINT DE PANNE ret = SARA_R422_PDP_Connect(&appdata->SARA_R422, APN); // 5. Enable HTTP, puis GET du checksum, comparaison, upgrade...
L'ouverture du contexte (étape 4) repose sur ces deux commandes :
// Configure PDP Context sprintf(buf, "AT+CGDCONT=1,\"IP\",\"%s\"\r\n", Apn); // APN = "tsiot" ret = SARA_R422_Execute_Cmd(SARA_R422, buf); ... // Enable PDP Context ret = SARA_R422_Execute_Cmd(SARA_R422, "AT+CGACT=1,1\r\n"); // <-- commande qui échoue
3 Le symptôme et les deux opérations touchées
La défaillance est toujours la même — l'ouverture de la connexion de données échoue juste après Starting PDP, et le bootloader ne peut plus joindre le webservice. Mais elle frappe dans deux opérations OTA bien réelles : la mise à jour d'une sonde en service, et le premier chargement du firmware sur une carte neuve.
C'est le cas qui a déclenché l'analyse (log du 19/06). Le firmware reçoit une nouvelle version cible et redémarre dans le bootloader pour la télécharger — mais le bootloader échoue à se connecter (no network service), repart sur l'ancien firmware, que l'application redemande aussitôt de mettre à jour : la mise à jour tourne en boucle.
...rebooting to bootloader to get the new firmware NVM Firmware checksum : c4c2…e2dd0 // firmware actuel Configuration message Firmware checksum : 5c9c…91e42 // nouvelle cible reçue par l'app ... [DEBUG]Starting PDP... [ERROR]CME ERROR Received : +CME ERROR: no network service // <-- la connexion échoue [ERROR]Can not connect to TCP [DEBUG]Jumping on App... // repart sur l'ancien firmware -> boucle
Les deux opérations touchées, avec deux codes d'erreur distincts mais au même endroit du code :
Opération A — mise à jour (sonde en service)
+CME ERROR: no network service CME 30- Déclencheur
- Nouvelle version poussée par le serveur (ou redémarrage à l'aimant, qui relance la vérification OTA).
- Fréquence
- Échoue ~2 fois sur 3 au reboot-aimant ; un power-off complet, lui, réussit.
- Contournement
- Power-off complet puis redémarrage (impossible sur sonde montée).
- Enjeu terrain
- Une sonde montée ne peut plus être éteinte ; seul le reset long à l'aimant relance l'OTA — mais ~1 fois sur 3 seulement.
Opération B — premier chargement (carte neuve)
+CME ERROR: operation not allowed CME 3- Déclencheur
- Tout premier allumage d'une carte vierge — l'installation initiale du firmware (production).
- Fréquence
- ~2 fois sur 3 ; le BL « ne va pas plus loin ».
- Contournement
- Power-off + redémarrage aimant fonctionne à tous les coups.
Sur les 30 cartes (logs à l'appui) : le bootloader passe quand le modem accroche en 2G et échoue le plus souvent en 4G (LTE-M). C'est cohérent avec la nature de AT+CGACT=1,1 : en 2G le contexte doit être activé à la main (commande utile → OK) ; en LTE-M le bearer est déjà monté (commande refusée → « operation not allowed »). L'intermittence ≈ la proportion de fois où le modem choisit LTE-M (sa techno préférée, URAT=7,9 = LTE-M + 2G). Corrélation forte mais non absolue — il arrive que ça passe aussi en LTE-M (selon le timing de l'attachement).
Les deux opérations échouent donc pour la même raison : le modem accroche en LTE-M et y voit CGACT refusé. (Sur une carte neuve, l'attachement de première fois — init SIM/eSIM, première sélection d'opérateur — peut s'ajouter ; le manuel AT décrit le code 3 comme « the MT is in a state which does not allow performing the entered command », p. 48. Mais cette piste « provisioning » reste secondaire face à la corrélation RAT.)
4 La racine commune
Dans tous les cas, le bootloader force AT+CGACT=1,1 — l'activation manuelle du contexte de données. Or, selon la techno sur laquelle le modem accroche, cette commande est soit nécessaire (2G), soit refusée (LTE-M, où le contexte est déjà monté).
Le levier choisi pour ouvrir la connexion est AT+CGACT=1,1, une commande standard (3GPP TS 27.007) d'activation explicite du contexte PDP, héritée du modèle GPRS où le contexte devait être activé à la main. Or :
Le manuel des commandes AT le pose noir sur blanc : « The initial EPS bearer established during LTE attach procedure is actually a default EPS bearer. » Le contexte de données par défaut (cid 1) est donc monté par l'attachement réseau lui-même. Forcer ensuite AT+CGACT=1,1 est redondant — et c'est la première commande de données émise, celle qui échoue dès que l'attachement n'est pas tout à fait terminé.
Réf. : LEXI-R4 / SARA-R4 series — AT commands manual (UBX-18068860, R31), §13.1.1 « PDP contexts » p. 189-190 ; +CGACT §13.7 p. 201, +CGPADDR §13.9 p. 205.
Autrement dit, le code force une étape que le réseau fait déjà de lui-même, et l'émet au moment le plus fragile. Les deux codes d'erreur (« no network service » et « operation not allowed ») ne sont que deux façons, pour le modem, de dire « je ne suis pas prêt pour ça maintenant ».
Niveau de preuve : le mécanisme (CGACT refusé en LTE-M) est confirmé par la corrélation RAT de terrain (forte, non absolue). Ce qui reste à préciser : pourquoi un démarrage donné accroche en LTE-M plutôt qu'en 2G, et une éventuelle composante serveur (test curl §9). La piste « alimentation / rail batterie » est, elle, largement supplantée.
5 Une fausse piste, écartée en toute transparence
Une première intuition — « le redémarrage aimant rallume le modem trop vite, il faut forcer un cycle d'alimentation plus propre » — ne résiste pas à la lecture du code.
Le bootloader force déjà un power-off complet à chaque échec. En fin de boucle, il coupe proprement le modem puis met la carte en veille profonde 5 minutes, alimentation modem coupée :
while (1)
{
ret = Application_Loop(&appdata);
Modem_Reset(&appdata); // coupe proprement le modem (voir ci-dessous)
// If an error occured, sleep to retry
if (ret < 0 && appdata.FwIsConsistent != 1)
Sleep(SLEEP_DURATION_SEC); // 300 s = 5 min, alim modem coupée
else
Jump_To_App(&appdata); // démarre l'application
}
SARA_R422_Execute_Cmd(SARA_R422, "AT+CPWROFF\r\n"); // extinction logicielle ... ret = SARA_R422_Wait_Powered(SARA_R422_AT_SUPPLY_OFF_DELAY, GPIO_PIN_RESET); // attend que VINT retombe — modem réellement OFF (2000 ms) ... HAL_GPIO_WritePin(SARA_R422_POWER_SUPPLY, GPIO_PIN_RESET); // coupe l'alimentation
Le firmware refait donc déjà, tout seul, l'essentiel de ce qu'un power-off manuel accomplit : coupure de l'alimentation modem + rail coupé 5 minutes + redémarrage à froid. « Forcer un cycle propre » est donc largement redondant — ce n'est pas là qu'est la solution. Cette correction est assumée : mieux vaut écarter une fausse piste que de coder un faux remède.
Quatre essais ont montré : power-off complet = OK, mais reboot-aimant = KO ~2/3. Cela infirme l'opposition « démarrage à froid vs reset logiciel » : l'intermittence est liée au cycle d'alimentation, pas au type de reset. Conséquence : inutile de recoder un « forçage de démarrage à froid » — c'est déjà ce que fait le nouvel essai, et ça ne suffit pas toujours.
6 Le vrai trou : un nouvel essai conditionné au mauvais critère
Si le bootloader sait refaire un cycle propre, pourquoi faut-il quand même une intervention humaine ?
Parce que ce nouvel essai automatique ne se déclenche que si le firmware interne est jugé « non cohérent ». La condition exacte (revoir l'extrait section 5) est :
if (ret < 0 && FwIsConsistent != 1) → Sleep(300s) ; else → Jump_To_App
Si le firmware en place est cohérent (FwIsConsistent == 1), un échec de connexion ne déclenche aucun nouvel essai : le bootloader démarre l'application et la tentative OTA est silencieusement abandonnée jusqu'au prochain redémarrage. C'est précisément ce qui oblige aujourd'hui à un power-off manuel.
Sur une sonde déjà montée, on ne peut pas faire de power-off ; la seule relance est un reset long à l'aimant, qui rejoue bien l'OTA mais échoue lui-même ~2 fois sur 3 (le modem repart probablement « tiède », rail batterie pas vraiment à zéro). Résultat : sans nouvel essai interne, la mise à jour dépend de la chance — il faut parfois répéter le geste, et elle peut rester bloquée — alors qu'un simple retry logiciel la fiabiliserait.
Le correctif en découle directement : il faut un nouvel essai de la phase de données, indépendant de la cohérence du firmware — c'est l'automatisation du geste manuel « power-off + redémarrage » constaté sur le terrain.
7 Ce que dit la documentation u-blox
Plusieurs recommandations du fabricant convergent vers le même constat : la séquence actuelle est conçue « à l'ancienne » et mérite d'être alignée sur les bonnes pratiques Cat-M1.
| Ce que disent les manuels | Implication pour le bootloader |
|---|---|
| Le bearer EPS par défaut est établi par la procédure d'attachement LTE (manuel AT, p. 190). | Forcer AT+CGACT=1,1 est redondant en Cat-M1 — le contexte est déjà monté par l'attachement. |
AT+CGPADDR lit l'adresse IP attribuée au contexte (manuel AT, §13.9, p. 205). | Vérifier l'obtention d'une IP (lecture non destructive) plutôt qu'activer le contexte de force. |
+CEREG et son URC (AT+CEREG=2, avec TAC/cell-id) sont documentés pour le SARA-R422M10S (manuel AT, §13.14, p. 214-216). | Suivre l'enregistrement par URC est plus fiable et plus sobre que le polling actuel toutes les 500 ms. |
| « VCC supply can be removed only after V_INT goes low » — sinon « unrecoverable faulty state » (System Integration Manual, p. 32). | Déjà respecté à l'extinction ; en revanche le power-on ne confirme pas l'extinction avant de réalimenter (voir §8). |
Références vérifiées dans les deux documents u-blox de référence : le LEXI-R4 / SARA-R4 series — AT commands manual (UBX-18068860, R31) et le SARA-R4 series — System Integration Manual (UBX-16029218, R32). Les pages sont citées au fil du texte.
8 Points à améliorer (par ordre de priorité)
Ce sont des spécifications. Elles vont du correctif direct du symptôme aux durcissements de fond.
① Ne plus faire de « operation not allowed » un échec — valider sur l'IP priorité haute — correctif racine
Le problème n'est pas AT+CGACT=1,1 en soi (elle reste nécessaire en 2G), mais le fait d'en faire un échec quand elle est refusée. En LTE-M, « operation not allowed » veut juste dire « contexte déjà monté ». Le correctif : émettre CGACT, ne pas bloquer sur sa réponse, et valider sur l'obtention d'une IP (AT+CGPADDR). Marche en 2G comme en LTE-M — et donc après le retrait de la 2G. → Le correctif de fond, ciblé sur la cause prouvée (corrélation RAT).
// CGACT reste nécessaire en 2G — mais on NE bloque PLUS sur sa réponse : SARA_R422_Execute_Cmd(SARA_R422, "AT+CGACT=1,1\r\n"); // "OK" -> 2G : contexte activé // "+CME ERROR: operation not allowed" -> LTE-M : déjà actif => les DEUX sont OK // La vraie validation : a-t-on une IP ? do { SARA_R422_Execute_Cmd(SARA_R422, "AT+CGPADDR=1\r\n"); // "+CGPADDR: 1,<ip>" -> succès si ip != 0.0.0.0 } while (ip_invalide && !timeout); if (ip_invalide) return -1; // là seulement, vrai échec
② Nouvel essai de la phase de données, indépendant de FwIsConsistent robustesse
Autour de l'appel à SARA_R422_PDP_Connect (application.c, lignes 462-470), prévoir 2 à 3 tentatives qui rejouent un cycle radio propre avant d'abandonner : AT+CFUN=0 puis AT+CFUN=1 force un nouvel attachement sans redémarrage complet. Avec le correctif ①, la connexion réussit dès la 1ʳᵉ tentative quelle que soit la techno : ce retry n'est donc plus le correctif central, mais un bon filet contre les vrais creux réseau (pas de couverture à l'instant T) — et il évite de dépendre d'un redémarrage externe.
③ Attendre la disponibilité réelle de la donnée avant de l'utiliser durcissement
L'attente actuelle valide l'enregistrement réseau, mais rien ne garantit ensuite que le service paquet est prêt avant d'émettre la première commande de données. Vérifier explicitement l'attachement paquet (AT+CGATT? = 1) — et idéalement passer l'enregistrement en notification URC (AT+CEREG=2) — comble cet écart. ⚠️ Si on passe en URC, il faut tokeniser le champ <stat> : le strncmp actuel sur « +CEREG: 0,1 » casse avec l'URC « +CEREG: 1,1 ».
④ Reprendre la main sur la sélection d'opérateur au démarrage cas carte neuve
Reprendre la main sur la séquence d'enregistrement (démarrer en mode « déconnecté » puis déclencher l'enregistrement explicitement) permet de maîtriser le choix de techno et le timing au démarrage — utile notamment au premier allumage d'une carte neuve. Secondaire une fois ① en place.
⑤ Renforcer le power-on probablement supplanté
Au power-on, la décharge avant réalimentation repose sur de simples temporisations aveugles (1 s avant réalimentation, 1 s après), sans jamais vérifier que le modem est réellement éteint :
HAL_GPIO_WritePin(SARA_R422_PWR_ON, GPIO_PIN_RESET); // (L399) HAL_GPIO_WritePin(SARA_R422_POWER_SUPPLY, GPIO_PIN_RESET); // coupe l'alim (L400) // Wait capacitors to discharge HAL_Delay(SARA_R422_SUPPLY_ON_DELAY); // 1000 ms AVEUGLE, pas de contrôle VINT (L403) HAL_GPIO_WritePin(SARA_R422_POWER_SUPPLY, GPIO_PIN_SET); // réalimente (L406) HAL_Delay(SARA_R422_SUPPLY_ON_DELAY); // encore 1000 ms aveugle (L407)
On pourrait attendre le passage à l'état bas de VINT (la primitive existe déjà) et allonger la marge de décharge — la règle u-blox « couper VCC seulement après VINT bas » figure au System Integration Manual, p. 32. Mais la corrélation RAT supplante très probablement cette piste : ce qui décide de l'échec, c'est la techno d'accroche (LTE-M), pas la propreté du cycle d'alim — un power-cycle plus propre ne ferait, au mieux, que biaiser le choix de techno. À ne considérer que si ① ne suffisait pas.
Aujourd'hui, le seul chemin fiable est le repli 2G (où CGACT est utile et passe). Or le retrait de la 2G est décidé pour la certif RED : URAT=7,9 → URAT=7,8 (LTE-M + NB-IoT, 0 % 2G), cohérence bootloader ↔ application. En LTE-M/NB-IoT seuls, l'OTA reposerait sur le chemin qui ne passe qu'occasionnellement → elle deviendrait largement non fiable. Le correctif ① est donc un pré-requis pratique au retrait de la 2G (à faire d'abord). Risque très élevé — pas une garantie de panne totale.
9 Tests à mener (avant de figer un correctif)
L'analyse est statique. Une instrumentation légère tranchera entre les causes possibles et confirmera (ou non) chaque hypothèse.
Instrumentation à ajouter
Faire enregistrer par le bootloader, juste avant l'ouverture du contexte de données et en numérotant le passage (1er démarrage / nouvel essai n°…) :
| À capturer | Ce que ça révèle |
|---|---|
AT+CMEE=2 (absent du code — à activer) | Affiche le numéro d'erreur exact (3 vs 30) |
Quelle commande échoue : CGDCONT (L814) ou CGACT (L831) | Localise précisément le point de rupture |
AT+CEREG? | Enregistré / en recherche / refusé |
AT+CGATT? | Service paquet attaché ou non |
AT+CSQ | Qualité du signal (99 = pas de signal → piste radio) |
AT+CGPADDR | Une IP est-elle déjà attribuée ? |
La techno (RAT) — champ <AcT> de AT+CEREG? ou AT+COPS? | 2G vs LTE-M — le discriminant clé (le BL ne la logge pas aujourd'hui) |
La preuve est déjà largement là (corrélation de Serge sur 30 cartes) : noter la RAT à chaque essai et la croiser avec le résultat doit confirmer « échec ⟺ LTE-M / succès ⟺ 2G ». Et surtout : vérifier qu'avec le correctif ① une accroche LTE-M passe.
Test secondaire (ancienne piste alimentation, désormais peu probable) : sur plusieurs reboots-aimant, voir si l'échec persiste au 2ᵉ passage automatique (après les 5 min de veille). S'il disparaît → composante premier-démarrage ; s'il persiste → ce n'est pas l'alim.
La boucle pourrait avoir une composante serveur non encore écartée. Vérifier ce que renvoie le webservice pour l'IMEI concerné : curl …/otafwupgrade/checksum?imei=<IMEI> → renvoie-t-il la nouvelle cible (5C9C…) ou encore l'ancien checksum (C4C2…) ? Tant que ce point n'est pas vérifié, on ne peut pas affirmer que la boucle est un échec purement réseau.
Table de décision
| Observation | Cause probable | Correctif visé |
|---|---|---|
CGACT KO + modem en LTE-M (bon CSQ, CEREG 1/5) | Contexte déjà monté (cause confirmée) | ① tolérer + CGPADDR |
CSQ=99 ou CEREG 0/2 persistant | Radio / couverture / eSIM | ④ COPS, pas l'alim |
| Échec disparaît au 2e passage (rare) | Composante premier-démarrage | ② retry (⑤ supplanté) |
Carte neuve, operation not allowed au CGACT | Accroche LTE-M (même cause) | ① tolérer + CGPADDR |
Checklist
- Activer
AT+CMEE=2et recompiler en mode verbeux. - Instrumenter le log (code CME, commande fautive, RAT (2G/LTE-M), CEREG/CGATT/CSQ/CGPADDR, n° de passage).
- Série de ≥10 redémarrages aimant — noter persistance ou non au 2e passage.
- Idem sur carte neuve : vérifier qu'elle accroche aussi en LTE-M.
- Décider, table en main, quels correctifs figer.
10 Niveaux de confiance
| Affirmation | Confiance |
|---|---|
| La phase post-« Starting PDP » est fragile, sans nouvel essai indépendant de la cohérence firmware | Élevée — vérifié dans le code |
| Le BL fait déjà un power-off complet de 5 min au nouvel essai | Élevée — vérifié dans le code |
CGACT=1,1 refusé en LTE-M (contexte déjà monté), nécessaire en 2G | Élevée — confirmé par la corrélation RAT terrain (échec ⟺ LTE-M, succès ⟺ 2G) ; forte mais non absolue |
| Carte neuve : échoue pour la même cause RAT (accroche LTE-M) | Élevée ; la part « provisioning eSIM » spécifique reste Modérée |
Correctif ① (tolérer « operation not allowed » + valider sur CGPADDR) | Élevée — adresse la cause prouvée, couvre 2G + LTE-M ; à valider au banc |
| Le renforcement du power-on changerait quelque chose | Probablement supplanté — la RAT explique le symptôme, pas le cycle d'alim |
Le sujet est le durcissement de la fiabilité OTA — déterminant pour le déploiement terrain, où une sonde montée ne peut être relancée qu'à l'aimant. C'est un travail de robustesse, à confirmer par l'instrumentation avant tout correctif.
11 Carte du code (repères)
| Élément | Fichier — lignes |
|---|---|
| Boucle principale + logique de nouvel essai | main.c — 112-123 |
| Séquence de la boucle applicative (étapes 1-5) | application.c — 416-470 |
Critère de cohérence firmware (FwIsConsistent) | application.c — 388, 400, 530, 615-616 |
| Ouverture du contexte de données (point de panne) | SARA_R422.c — 809-859 |
| Attente d'enregistrement réseau (CREG + CEREG) | SARA_R422.c — 190-241 |
| Power-on (décharge aveugle, 2 × 1 s) | SARA_R422.c — 394-420 |
| Power-off (CPWROFF + attente VINT + coupure alim ; early-return si alim déjà coupée) | SARA_R422.c — 422-458 |
Analyse réalisée sur le bootloader v0.1.9, branche rapatriée à jour. Les extraits ci-dessus sont des spécifications, pas des modifications appliquées.