Usb Linux
Usb Linux
1
3. après avoir développé le premier programme de base (clignoter une LED) sur le microcontrôleur
équipant le FX2LP pour valider la compréhension du compilateur, de la bibliothèque associée et
des outils de communication entre le PC et le microcontrôleur pour exécuter le binaire compilé
sur la cible ...
4. ... nous portons l’implémentation logicielle (bitbang) du bus SPI (Serial Peripheral Interface)
proposée par PocketSDR vers le compilateur SDCC, et apprenons à communiquer par des Vendor
Requests pour exécuter des ordres au travers du bus USB.
5. Finalement, nous complétons le portage du firmware fourni par PocketSDR en ajoutant les com-
munications Bulk sur USB, et validons les divers débits de communication en fonction des registres
de configuration de l’horloge cadençant les convertisseurs analogique-numérique.
6. Le bon fonctionnement du montage est validé sur les signaux “puissants” des satellites en orbite
basse Iridium, puis sur les signaux sous le bruit thermique des satellites de navigation.
7. Dans le prochain article, nous aborderons la conception et réalisation d’une carte fille dédiée
embarquant deux MAX2771 pour des mesures différentielles de signaux radiofréquences acquis
par FX2LP et transmis par USB Bulk vers le PC pour post-traitement, en particulier pour pallier
les déficiences du couplage entre signaux portés par des fils de communication trop longs dans le
premier circuit de prototypage.
8. Finalement, nous ajouterons la capacité à corriger la source de fréquence qui cadence le MAX2771
afin de corriger son écart à la fréquence nominale GPS, et ce en ajoutant de nouvelles Vendor
Requests afin de programmer ce nouveau périphérique ajouté au bus s’apparentant à SPI.
La seule modification lors de l’utilisation de la carte d’évaluation du MAX2771 est de remplacer
l’oscillateur avec sa fréquence par défaut de 16,368 MHz par un oscillateur à 24 MHz afin de pouvoir
utiliser tels quels les fichiers de configuration proposés par PocketSDR. Nous verrons en section 2 com-
ment recompiler le firmware et ainsi pouvoir changer la configuration de PocketSDR pour supporter un
oscillateur à 16,368 MHz.
Ainsi, dans le prochain épisode, quitte à remplacer le microcontrôleur de la carte d’évaluation à plus
de 400 euros, nous poursuivrons en proposant notre propre implémentation d’une carte fille munie de
deux MAX2771 s’adaptant à une carte faible coût (5 euros) munie d’un FX2LP, finalisant la démarche
sur un circuit coûtant moins d’une centaine d’euros tout compris (MAX2771, FX2LP et antennes GNSS
multibandes ou Iridium). En particulier, nous éliminerons de ce fait les rayonnements électromagnétiques
indésirables lorsque des signaux à plusieurs MHz circulent sur des fils non-blindés d’une 10aine de cen-
timètres de long, induisant corruption des signaux numériques et bruit en bande de base lors de l’analyse
des signaux transposés par l’oscillateur local avant conversion analogique-numérique, tel que nous le
verrons en conclusion.
1 Le bus USB
Historiquement, un ordinateur communique en point à point par un protocole sérialisant dans le
temps les données au lieu de les communiquer en parallèle – la seconde approche est limitée en débit
de communication par le couplage inductif entre fils adjacents et la taille de la nappe de fils nécessaire
pour porter tous les bits. RS232 est un exemple de bus série, qualifié d’asynchrone puisque les inter-
locuteurs ne partagent pas d’horloge. Dans la même veine, SPI est un bus série synchrone puisqu’un
maı̂tre distribue un signal d’horloge vers ses esclaves. Le vénérable protocole qu’est RS232, encore lar-
gement utilisé dans l’embarqué, n’est cependant que rarement disponible sur les ordinateurs personnels
actuels, et les interfaces USB-RS232 sont pléthores. Ainsi, le protocole de communication CDC d’USB
– Communications Device Class – fait croire à l’hôte (l’ordinateur) que le périphérique parle le RS232
quand en réalité les informations sont portées sur bus USB. Ce mode de communication est très pra-
tique puisqu’il permet d’utiliser les outils associés à RS232 – minicom et screen pour ne citer qu’eux
– mais ne permet pas de tirer partie de tout le débit accessible sur USB. Dans LUFA par exemple
([Link] un Atmega32U4 se configure facilement en CDC par
#define F_CPU 16000000UL //T=62.5ns
#define F_USB 16000000UL
#include "VirtualSerial.h"
#define N 1024
2
extern USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface;
extern FILE USBSerialStream;
int main(void){
char tab[N]; memset(tab,’U’,N);
SetupHardware();
CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream);
GlobalInterruptEnable();
while(1) {fwrite(tab,1,N,&USBSerialStream); USB_USBTask(); }
}
et connecter le microcontrôleur programmé par cette séquence d’instructions au bus USB d’un PC
fait apparaı̂tre une interface /dev/ttyACM0 accessible par minicom -D /dev/ttyACM0 sans que le débit
(baudrate) n’ait d’importance ici. Quelques mesures de débit, pour N allant de 64 à 1024 en puissances
de deux, indique par
une taille de fichier de l’ordre 965 ± 5 kB donc des débits de l’ordre de 100 kB/s, en accord avec les
tests de [Link] pour l’Atmega32U4
qui équipe une carte Arduino Leonardo. D’après ce même site, un microcontrôleur un peu plus puis-
sant doit atteindre le MB/s, encore loin de la dizaine de MB/s que nous visons pour une application de
radio logicielle. Il faut donc se tourner vers une utilisation optimisée du bus USB et ne pas se contenter
de juste exposer un port série virtuel.
Nombre de dispositifs “récents” n’exploitent pas CDC mais exposent une interface plus riche, et c’est
par exemple le cas du microcontrôleur qui équipe la carte d’évaluation du MAX2771 (Fig. 1). En effet,
ayant acquis cette carte il y a plusieurs années, elle devint un très beau presse-papiers quand j’ai réalisé
que ni GNU/Linux, ni Wine ne pouvaient communiquer avec elle au travers du logiciel propriétaire
fourni par Maxim IC. Comme un presse-papiers à 450 euros acquis avec l’argent du contribuable est
discutable, nous nous interrogeons à comprendre son mode de communication et les échanges entre le
microcontrôleur dont la carte d’évaluation est munie, et le PC. Bien entendu sans accès au code source du
firmware exécuté sur ledit microcontrôleur, nous ne pourrons que tenter une rétro-ingénierie en sondant le
bus USB lorsque le logiciel original communique avec la carte d’évaluation : ce logiciel est exécuté depuis
une machine virtuelle VirtualBox munie de MS-Windows et exécutant le logiciel propriétaire disponible
sur le site du fabriquant [3].
À la connexion de l’interface USB du microcontrôleur, Linux nous informe (dmesg) que
[X] usb 1-2: Product: HID DEVICE
[X] usb 1-2: Manufacturer: [Link]
[X] usb 1-2: SerialNumber: 0123456789
[X] hid-generic 0003:1234:0006.0005: hiddev1,hidraw2: USB HID v1.11 Device
[[Link] HID DEVICE] on usb-0000:00:14.0-2/input0
donc il s’agit d’un Human Interface Device dont nous devons comprendre le protocole de communication.
Bus 001 Device 039: ID 1234:0006 Brain Actuated Technologies HID DEVICE
3
Figure 1 – La carte d’évaluation du MAX2771 de Maxim IC, source de tous nos déboires, avec son
microcontrôleur (en haut à droite) qui ne peut communiquer qu’avec le logiciel propriétaire exécuté sous
MS-Windows, et qui ne s’avère finalement capable que de convertir des commandes USB en SPI. Cette
carte est déjà équipées des liaisons SPI et IQ (bornier à côté du microcontrôleur) que nous redirigerons
vers l’EZ-USB afin de corriger ces déficiences. Seule l’alimentation 3 V (bas-droite, en cyan) est nécessaire
pour faire fonctionner la carte, les alimentations symétriques ne servent que pour les amplificateurs
opérationnels qui ne sont pas utilisés. Pour tester la bande supérieure GNSS, on branchera un signal ou
une antenne active sur le connecteur de gauche (marque 1) et relierons la sortie de l’amplificateur faible
bruit (LNA) à l’entrée du mélangeur (ellipse rouge 2). Une résistance de tirage vers l’alimentation sort
le MAX2771 de son mode veille (ENA) lorsque le microcontrôleur de la carte n’est pas alimenté.
nous utiliserons le premier argument (ici 1) en place de X pour sonder les messages transmis sur ce bus.
Noter qu’il peut être malin de ne pas brancher le microcontrôleur de la carte d’évaluation sur le même
bus USB qu’une souris communiquant par cette interface pour ne pas être pollué par les messages de
celle-ci chaque fois que nous déplaçons le curseur de l’interface graphique. On pourra au pire |grep YYY
avec YYY le numéro de Device pour filtrer.
Tel quel, le microcontrôleur n’est pas causant. Cependant si nous exécutons le logiciel propriétaire
4
proposé par ADi pour communiquer depuis MS-Windows [3], dans VirtualBox, nous obtenons une série
de messages sous réserve que l’utilisateur appartienne au groupe vboxusers et que l’Extension Pack soit
installé (support USB de VirtualBox), de la forme
# cat /sys/kernel/debug/usb/usbmon/3u
ffff89247452b840 3730820207 S Io:3:106:3 -115:1 64 = c9000000 00000000 00000000 0000...
ffff89247452b840 3730821534 C Io:3:106:3 0:1 64 >
ffff89245ffbec00 3730821653 C Ii:3:106:4 0:1 64 = cb010000 00000000 00000000 0000000...
ffff89245ffbe3c0 3730822364 S Ii:3:106:4 -115:1 64 <
ffff8923b4e30480 3731821079 S Io:3:106:3 -115:1 64 = c9000000 00000000 00000000 0000...
ffff8923b4e30480 3731822566 C Io:3:106:3 0:1 64 >
ffff89245ffbe3c0 3731822679 C Ii:3:106:4 0:1 64 = cb010000 00000000 00000000 0000000...
ffff8923b4e309c0 3731823216 S Ii:3:106:4 -115:1 64 <
ffff89245ffbec00 3732762122 S Io:3:106:3 -115:1 64 = c20000a2 24160300 00000000 0000...
...
donc le logiciel sous MS-Windows demande périodiquement au microcontrôleur s’il est présent. Le mi-
crocontrôleur acquitte de chaque requête (message c9 suivi de 0s). En plus de ces requêtes périodiques, le
logiciel propriétaire permet de configurer les registres du MAX2771, et dans ce cas une série de messages
commençant par c2 indique le numéro du registre et la valeur à y stocker. Une fois le protocole iden-
tifié, il ne reste plus qu’à l’implémenter, par exemple en s’inspirant de [Link]
durgod-keymapper/blob/master/[Link] qui nous enseigne comment communiquer un message à un
prériphique HID dont on connaı̂t le Vendor ID et le Product ID (VID:PID – ici 1234:0006 tel qu’indiqué
auparavant par lsusb), de la forme
def tohex(data):
return ’␣’.join(map(lambda x: "%02x" % x, data))
import hid
VENDOR_ID=0x1234
PRODUCT_ID=6
RESET = b"\xc9".ljust(31, b"\x00")
device_info = next(device for device in [Link]()
... if device[’vendor_id’] == VENDOR_ID and device[’product_id’] == PRODUCT_ID)
device=[Link]()
device.open_path(device_info[’path’])
[Link](RESET) # envoi du message C9 00 00 ...
resp=[Link](64, timeout_ms=500) # reception de la reponse
resp=bytearray(resp).rstrip(b’0x00’);
print(tohex(resp))
$ python3 ./[Link]
cb 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...
donc cb 01 indiquant que le microcontrôleur acquitte notre requête formée de 0xc9 suivi de 31 zéros
(b"\xc9".ljust(31, b"\x00")). La voie est donc toute tracée, il ne reste plus qu’à comprendre les
diverses commandes du logiciel propriétaire et les implémenter en Python. Ce faisant, un point attire
cependant une interrogation : aucun bouton sur le logiciel propriétaire de communication ne permet
d’acquérir les données, seulement de communiquer au travers du bus SPI des configurations des registres
du MAX2771. Ayant sollicité l’aide des ingénieurs de Maxim, nous avons eu confirmation que la commu-
nication des données acquises par le MAX2771 était prévue ... mais n’a jamais été implémentée. Nous
avons donc acquis un convertisseur USB vers SPI à 450 euros ! Inutile de câbler les résistances R31/R32
et R44/R45 (I0/I1 to host et Q0/Q1 to host) sur la carte d’évaluation, le microcontrôleur ne saura que
faire de ces signaux IQ représentatifs du signal électrique converti en signal numérique par le MAX2771.
Nous devons donc nous débrouiller seuls pour connecter une interface parallèle-USB sur le bornier J26
1. Tous les codes cités dans cet article sont disponibles à [Link] y compris ce
[Link]
5
propageant les signaux IQ issus du récepteur de signaux GNSS pour les transmettre au PC, et c’est là
qu’intervient le Cypress CY7C68013A.
I0/I1 et Q0/Q1 : conversion analogique-numérique sur 2 ou 3 bits !
On pourrait être surpris de la nomenclature I0/I1 et Q0/Q1 qui laisse penser que les signaux complexes
I + jQ sont codés sur deux bits seulement, ou un bit de signe et un bit de valeur. Ce codage est courant
dans l’analyse des signaux GNSS qui se situent 20 dB sous le bruit thermique (voir section 3) et pour
lesquels un nombre important de bits ne ferait que coder le bruit, pas le signal. La puissance du code
pseudo-aléatoire (CDMA) qui encode les messages GNSS est que la corrélation fait ressortir le signal du
bruit d’un facteur égal au facteur de compression (pulse compression ratio donné par le produit bande
passante multiplié par la durée du code, ou en numérique le nombre de bits du code). Avec un code sur
1023 bits pour GPS L1, le gain de compression est log2 (1023) ≃ 10 bits donc les trois bits deviennent
13 bits après corrélation par le code connu, voir 16 bits pour les codes dix fois plus longs de GPS L5.
À notre grande surprise, aussi peu de bits de codage resteront suffisants pour décoder Iridium qui ne
bénéficie pas d’un gain de compression du codage CDMA mais profite d’un signal bien plus puissant
transmis par ses satellites en orbite basse. Ainsi, le MAX2771 peut soit fournir les mesures complexes
(parties réelle et imaginaire) en bande de base sous forme I + jQ avec I et Q codés sur 2 bits chacun, ou
bien en présence d’une fréquence intermédiaire acquérir la partie réelle uniquement (donc spectre pair)
codée sur 3 bits selon I1, I0, Q1 (donc le bit de poids le plus faible sur Q1 même si l’information porte
sur une valeur réelle), et il sera à la charge de l’utilisateur d’effectuer numériquement la transposition de
fréquence (multiplication par un oscillateur local de fréquence égales à la fréquence intermédiaire) pour
produire les valeurs complexes en bande de base.
En effet, Tomoji Takasu étant moins incompétent que Maxim IC – ou surtout plus motivé que les
mercenaires payés ponctuellement à développer le logiciel de la carte d’évaluation – il fournit la solution
avec l’EZ-USB du FX2LP : ce composant se connectera aux broches IQ du bornier et son horloge associée
(communication synchrone) pour traduire vers un flux USB les mesures proposées au format parallèle
par le MAX2771. Mais pour en arriver là, il faut programmer le microcontrôleur 8051 embarqué dans le
CY7C68013A pour en configurer les interfaces...
6
#include <fx2regs.h>
#include <delay.h>
#define led12 3 // 1<<0 | 1<<1
void main(void)
{unsigned char val=1;
OEA=(led12); // PA0, PA1 output
while (1)
{val=led12-val; // 2 <-> 1
IOA = val;
delay(1000); // wait 1 s
}
}
Figure 2 – Deux photographies de la carte de
développement FX2LP alors que la LED de gauche
est allumée et celle de droite éteinte (gauche) ou
le contraire (droite), à côté du jumper entouré en
vert qui les relie à l’alimentation. Le jumper en-
touré en rouge sert à invalider l’adresse mémoire
de l’EEPROM au démarrage pour permettre de la
reprogrammer (voir section 1.4).
initialise deux bits du port A en sortie (registre OEA, bit à 1 en sortie) puis manipule le registre définissant
l’état des broches en sortie IOA, alternant la LED allumée et éteinte chaque seconde – LED de gauche al-
lumée sur la photographie de gauche et LED de droite sur la photographie de droite dans ces illustrations.
Ce programme, compilé puis lié avec la bibliothèque FX2Lib de [Link]
fx2lib que nous avons au préalable compilée par make pour générer lib/[Link], est converti en fichier
hexadécimal compatible Intel (extension ihx) par sdcc par
sdcc -mmcs51 mainPA.c -I../fx2lib/include/ -L../fx2lib/lib/ [Link]
pour produire implicitement [Link], qui est exécuté depuis la RAM du 8051 par sudo cycfx2prog
prg:[Link] run. Nous constatons sur les deux figures accompagnant le code que les deux jumpers
sont en place, le rouge pour faire booter le FX2LP en mode bootloader et charger l’exécutable au format
Intel hexadécimal (ihx) en RAM, et le vert pour connecter les LEDs à l’alimentation. Divers Makefile
pour FX2LP ajoutent des options d’édition de lien du type --code-size 0x1c00 --xram-size 0x0200
--xram-loc 0x1c00 mais les valeurs par défaut semblent suffisantes pour ne pas devoir les expliciter.
Ce faisant, nous avons programmé le 8051 comme n’importe quel microcontrôleur généraliste, sans
tirer parti d’une de ses originalités. En effet pour faire clignoter une autre LED externe que nous connec-
tons entre PD7 et la masse par exemple, le code
#include <fx2regs.h>
#include <delay.h>
void main()
{OED = (1 << 7); // direction PD7 out
while (1)
{PD7 = 0; // IOD = 0; // IOD: set register
delay(1000);
PD7 = 1; // IOD = (1<<7); // setbit sets one bit only
delay(1000);
}
}
7
Une fois ce programme compilé comme auparavant, cette fois l’exécutable est placé en mémoire
non-volatile EEPROM pour exécution lors de la mise sous tension par
sudo fxload load_eeprom --device 04b4:8613 --ihex-path [Link] -t FX2LP --control-byte 0xC2 -s Vend_Ax.hex
qui a besoin du firmware Vend [Link] pour communiquer avec l’EEPROM et identifier le VID et PID du
FX2LP en mode bootloader (04B4:8613 tel qu’indiqué par lsusb). Noter qu’avec des anciennes versions
de fxload, la commande
sudo fxload -D /dev/bus/usb/001/035 -I [Link] -c 0xc2 -s Vend_Ax.hex -t fx2lp
était beaucoup plus pénible puisque le pseudo-fichier dans /dev/bus/usb change de nom à chaque mise
hors tension puis sous tension du FX2LP avec un identifiant qui s’incrémente à chaque fois. Attention
cependant, nous pouvons écrire une fois en mémoire non-volatile EEPROM, mais pas une seconde fois,
la solution à ce problème sera fournie plus bas (section 1.4). En attendant, nous conseillons de tester le
bon fonctionnement du logiciel en RAM par cycfx2prog.
Le code source complet de cet exemple est disponible à [Link]
fx2lp/tree/main/FX2LP/LED_blink.
Ayant validé la compilation et la programmation du composant en faisant clignoter une LED, nous
pouvons nous attaquer au cœur du sujet, la communication sur bus USB.
8
3. si nous laissons le jumper en place, la réponse b’cdcdcdcdcdcd... indique que l’EEPROM n’a
pas été lue, son adresse ne correspond pas à celle attendue par Vend Ax
4. si nous retirons le jumper, alors la réponse b’c2b404138605a04203f20000 commence bien par
0xC2 tel que documenté en page 8 du manuel technique [8] pour indiquer “During the power-up
sequence, internal logic checks the I2 C port for the connection of an EEPROM whose first byte
is either 0xC0 or 0xC2. If found, it uses the VID/PID/DID values in the EEPROM in place of
the internally stored values (0xC0), or it boot-loads the EEPROM contents into internal RAM
(0xC2).” suivi du VID et PID du composant en format little endian, donc “à l’envers” pour un
lecteur occidental qui lit de gauche à droite : b4041386 s’interprète comme 04b4 :8613.
D’après le code source de fxload à [Link]
c#L674-L676 celui-ci attend une réponse de 1 à la requête GET EEPROM SIZE (Vendor Reqest 0xA5 prise
en charge par Vend Ax) et sinon refuse de reflasher l’EEPROM. Or émettre la commande 0xA5 vers un
FX2LP exécutant Vend Ax renvoie la valeur 0 et donc fxload refuse de continuer la programmation.
Par ailleurs, le premier octet de l’EEPROM contient 0xC2 ou 0xC0 selon la façon de configurer
l’identifiant USB. L’alternative de retirer le jumper pour passer en mode bootloader échoue aussi puisque
le FX2LP voit une EEPROM dont le premier octet contient 0xC2 et donc en exécute le code. La
solution, fort peu élégante, que nous avons trouvée pour reflasher l’EEPROM du FX2LP est d’exécuter un
programme depuis la RAM, donc chargé par cycfx2prog, pour écraser les premiers octets de l’EEPROM
avec 0xFF, et ainsi forcer le microcontrôleur avec le jumper retiré à exécuter son bootloader en l’absence
de firmware valide. Pour ce faire, nous chargeons en RAM (cycfx2prog) le programme Vend [Link] par
sudo cycfx2prog prg:Vend [Link] run et allons profiter de sa Vendor Request 0xA9 pour écrire dans
l’EEPROM tel que décrit à [11], et ainsi écraser le premier octet pour forcer le lancement du bootloader
qui permettra de reflasher l’intégralité de l’EEPROM :
import usb
import binascii
VID = 0x04B4
PID = 0x8613
dev = [Link](idVendor = VID, idProduct = PID)
ret=dev.ctrl_transfer(0xC0,0xa9, 0, 0, 64) # read EEPROM content
print([Link](ret))
msg=bytearray([0xff,0xff,0xff,0xff]); # write EEPROM (erase)
dev.ctrl_transfer(0x40 , 0xa9, 0x0, 0, msg)
ret=dev.ctrl_transfer(0xC0,0xa9, 0, 0, 64) # read EEPROM content
print([Link](ret))
Le contenu de l’EEPROM est maintenant écrasé, et démarrer le FX2LP sans jumper (donc identifi-
cation correcte de l’adresse I2 C) permet de reflasher la mémoire non-volatile.
Denis Bodor fait remarquer qu’une fonctionnalité identique est proposée par [Link]
net/elec/periph/USB-FX2/eeprom/ qui contient erase_eeprom aux fonctionnalités identiques, quitte
éventuellement à remplacer l’adresse I2 C 0xA2 (“assumes that A0 is tied to positive supply and A1,A2
of the EEPROM are tied to ground ”) par 0xA0 selon que le jumper ne soit pas en place ou le soit. Ce
programme efface tout le contenu de l’EEPROM au lieu de juste effacer le premier octet, seule condition
nécessaire à refaire fonctionner fxload pour reflasher l’EEPROM déjà flashée.
9
avec maintenant un couple VID:PID qui vaut 04b4:1004, le nouveau PID étant défini dans le firmware.
Il faut maintenant comprendre comment PocketSDR, dont le code source est disponible, enclenche des
communications entre le FX2LP et le MAX2771 selon un protocole que la documentation technique de ce
dernier qualifie abusivement de compatible SPI, abus de langage puisque MOSI et MISO sont confondus
en un unique “SDATA” qui change d’impédance selon que la transaction se fasse en écriture ou en lecture
(exactement la raison pour laquelle nous détestons I2C dont la direction de la transaction ne peut être
déduite de la trace acquise sur oscilloscope ou analyseur logique).
Nous apprenons dans l’entête de PocketSDR/FE 2CH/FW/v2.1/pocket fw.c qu’un certain nombre de
Vendor Requests permettent, au même titre que les ioctl() dans un module noyau Linux, d’attribuer des
opérations à des codes de commande arbitrairement sélectionnés. Dans le cas particulier de PocketSDR,
la commande 0x40 renverra la version et statut du firmware, 0x41 lit un registre du MAX2771 et 0x42
y écrit (Fig. 4).
RequestType=0xC0 RequestType=0x40
CS#
SCK
Figure 4 – Signaux produits par l’implémentation logicielle de SPI (bien que regroupant sur un même
fil les signaux MOSI et MISO) en lecture et en écriture selon le code de la Vendor Request transmis. De
haut-en bas la sélection du composant CS#, le bus de données SDATA et le bus d’horloge SCK.
Il faut donc apprendre à envoyer des Vendor Requests depuis GNU/Linux afin de se familiariser avec
ces échanges implémentés dans le firmware précompilé de PocketSDR, en vue de s’assurer que notre
implémentation du firmware compatible sdcc atteindra les mêmes objectifs, à savoir les transactions sur
bus SPI. Le résultat est surprenamment facile à atteindre au moyen de la bibliothèque USB de Python3
une fois qu’on a compris le sens des arguments :
import usb
import binascii
VID = 0x04B4
PID = 0x8613
dev = [Link](idVendor = VID, idProduct = PID)
msg=bytearray([0x40,0x04,0x55,0xaa]);
# dev.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data)
ret=dev.ctrl_transfer(bmRequestType=0xC0 ,bRequest=0x41, wValue=0xFF, wIndex=0, data_or_wLength=4)
# 0x155 to activate second CS#, 0x55 to activate first CS#
dev.ctrl_transfer(0x40 , 0x42, 0x55, 0, msg) # write on SPI bus reg @ 0x55 int msg
# FX2LP firmware status
ret=dev.ctrl_transfer(0xC0,0x40, 0, 0, 10) # read VR_STAT: returns 6 bytes (EP0BCL=6;)
print([Link](ret)) # b’105dc0010100’
10
suit bRequest le code de la Vendor Request en adéquation avec le firmware de PocketSDR, suit un mot
wValue qui sera décodé par le 8051 du FX2LP pour identifier le registre du MAX2771 à atteindre (octet de
poids faible) et, dans le cas du circuit “officiel” de la PocketSDR muni de deux MAX2771, lequel des deux
composants activer par son Chip Select adéquat (octet de poids fort). Finalement, wIndex le numéro de
l’interface est toujours nul, et si la transaction est en écriture le dernier argument est un tableau d’octets
transmis sur bus SPI, sinon il s’agit du nombre d’octets à lire. Si nous émettons la commande 0x40 (lecture
du statut) en mode lecture (bmRequestType=0xC0) avec le code Python proposé auparavant, alors nous
recevons b’105dc0010100’ qui correspond au code source PocketSDR/FE 2CH/FW/v2.1/pocket fw.c à
savoir au début la version du firmware 0x10, suivi de deux octets contenant la fréquence de l’oscillateur en
kHz (24000 dans notre cas, donc 0x5DC0 en hexadécimal), suivi du divers statuts sans importance pour
le moment. La transaction est donc convenablement effectuée pour lire une valeur du microcontrôleur
par USB.
Maintenant, pour déclencher des transactions sur USB, nous envoyons l’ordre (bRequest) 0x41 (lec-
ture) ou 0x42 (écriture) suivi du numéro du registre du MAX2771 dans wValue et soit la séquence d’octets
à écrire, soit le nombre d’octets à lire. Nous constatons à l’oscilloscope que les signaux SCLK, SDATA, et
CS# se comportent comme prévu dans une liaison SPI (Fig. 4). Bien qu’il s’agisse d’une implémentation
logicielle (bitbang) de SPI dans le 8051, la période et le rapport cyclique de SCLK, que l’on voit bien ne
pas être constants sur la courbe du bas de Fig. 4, n’ont aucune importance puisqu’il s’agit d’un protocole
synchrone dont seuls les fronts importent. Lorsque nous lisons un résultat, nous constatons dans le code
source de PocketSDR/FE 2CH/FW/v2.1/pocket fw.c que le cas VR_REG_READ se conclut pas EP0BCL=4;
donc le renvoi de 4 octets ou les 32 bits contenus dans chaque registre du MAX2771. Nous mettons en
pratique par
#!/usr/bin/env python3
import usb
import binascii
VID = 0x04B4
PID = 0x1004
dev = [Link](idVendor = VID, idProduct = PID)
#PLL Fractional Division Ratio register 0x05
#default value 0x08000070
# ^^ reserved
#dec2hex(586329)
#ans = 08F259
msg=bytearray([0x08,0xF2,0x59,0x70]);
ret=dev.ctrl_transfer(0xC0 ,0x41, 0x05, wIndex=0, data_or_wLength=4)
print([Link](ret))
dev.ctrl_transfer(0x40 , 0x42, 0x05, 0, msg) # write on SPI bus reg @ 0x5
ret=dev.ctrl_transfer(0xC0 ,0x41, 0x05, wIndex=0, data_or_wLength=4)
print([Link](ret))
qui accède au registre 5 du MAX2771 ou la partie fractionnaire de la division de l’oscillateur dans la
boucle à verrouillage de phase (PLL), en écriture et en lecture, pour vérifier que l’information a bien été
stockée dans le registre.
11
requête est celle que nous avions vue auparavant, mais que nous comprenons n’attendre que 6 octets en
retour
import usb
import binascii
VID = 0x04B4
PID = 0x8613
dev = [Link](idVendor = VID, idProduct = PID)
ret=dev.ctrl_transfer(0xC0,0x40, 0, 0, 6) # read VR_STAT
print([Link](ret))
donc une requête en lecture (0xC0) de la Vendor Request 0x40 (VR STAT) et la réponse est b’105dc0010100’
pour indiquer 0x10 la version du firmware, correspondant aux EP0BUF[0] = VER_FW; dans le code source
du firmware PocketSDR, puisque #define VER_FW 0x10, suivi de 0x5DC0 puisque dans PocketSDR
avec #define F_TCXO 24000. Suivent deux états de broches en entrée que nous ne contrôlons pas pour le
moment. Le code source complet pour sdcc est consultable à [Link]
fx2lp/blob/main/FX2LP/python_access_USB qui bénéficie en partie de ce que Keil et FX2Lib pour
SDCC s’appuient tous deux sur des fichiers de constantes partageant la même nomenclature et donc
facilement interchangeables.
Nous voici donc capables de recevoir des messages depuis le FX2LP grâce aux Vendor Requests, et nous
continuous le plagiat du code de PocketSDR en copiant depuis PocketSDR/FE 2CH/FW/v2.1/pocket fw.c
l’implémentation logicielle (bitbang) du bus SPI puisque la syntaxe de digitalRead(), digitalWrite()
qui accèdent aux broches, mais aussi write sclk(), write sdata() et write head(), sont directement
compatible avec SDCC, la bibliothèque FX2Lib ayant le bon goût d’utiliser les mêmes constantes que le
compilateur Keil tel que nous le constatons en comparant cypress/dscr.a51 de PocketSDR/FE 2CH/FW/v2.1
pour Keil et fx2lib/fw/dscr.a51 pour SDCC. Seul piège : PocketSDR définit une fonction delay()
comme boucle de cyc itérations, alors que FX2Lib propose une fonction du même nom mais dont le
prototype est void delay(WORD millis); et qui prend donc un argument en millisecondes (et non en
cycles d’horloge).
On voit bien que la fonction FX2Lib sera considérablement plus lente que celle de PocketSDR, et
en effet nos observations sur le bus SPI cadencé par logiciel présentaient des variations très lentes de
l’horloge et du bus de données. Une nouvelle fonction de délai avec un nom différent et effectuant bien
un décompte rapide permet de retrouver presque à l’identique le comportement de PocketSDR grâce au
programme compilé par SDCC proposé dans [Link]
main/FX2LP/python_access_USB.
Nous en sommes au point où nous sommes capables de communiquer des ordres depuis le PC au
FX2LP par un programme Python, que le 8051 interprète ces commandes et produise le motif adéquat
sur le bus SPI, donc programme les registres du MAX2771 et en relise le contenu. Il ne reste maintenant
“plus” qu’à capturer les octets placés sur le bus parallèle par le MAX2771 et cadencés par le signal IFCLK
en vue de remplir la mémoire FIFO qui se vide périodiquement sur le bus USB dans une transaction
bulk. Quelques points de “détail” restent cependant à régler avant d’en arriver là.
12
Parmi les autres subtilités de syntaxe, l’espace d’adressage en 16 bits du 8051, xdata de Keil, de-
vient xdata chez SDCC, et les mnémoniques assembleur inclus dans le code C sont préfixés de asm
suivi de l’instruction, par exemple nop, et se concluent avec endasm. Évidemment les vecteurs d’in-
terruptions s’appellent différemment, par exemple void ISR Highspeed(void) interrupt 0 {...} de
Keil devient chez SDCC void hispeed isr(void) interrupt (HISPEED ISR) {...} mais comme
l’exemple bulkloop/ est fonctionnel, ce dernier point nous concerne peu.
À l’issue de cet exemple, nous sommes capables de compiler un firmware proposant toutes les fonc-
tionnalités d’origine, cette fois compilé par sdcc, incluant les Vendor Requests pour communiquer les
configurations sur bus SPI ainsi que le transfert de données acquises du MAX2771 en transactions USB
Bulk.
Figure 5 – La carte équipée du FX2LP prête à être utilisée, et pourtant impossible de la faire commu-
niquer en USB Bulk malgré un code compilé par Tomoji Takasu au moyen du compilateur propriétaire
Keil auquel nous ne pouvons que faire confiance. Le problème vient d’une erreur de sérigraphie sur le
circuit chinois qui induisait une configuration erronée de la direction de communication, tel que nous en
a informé l’auteur japonais de PocketSDR.
Une fois cette erreur corrigée, nous achevons de vérifier les fonctionnalités de communication en profi-
tant de PocketSDR/app/pocket dump/pocket dump pour recevoir des données. Ce faisant, nous n’aurons
13
pas (encore) appris à recevoir nous mêmes des octets depuis la FIFO vers le PC, mais gardons cette
compréhension pour la prochaine section. Par ailleurs, un point un peu “surprenant” est que, quelle que
soit la configuration que nous proposons au MAX2771 par PocketSDR/app/pocket conf/pocket conf,
le débit de communication reste toujours le même puisque pocket dump indique
$ sudo app/pocket_dump/pocket_dump
TIME(s) T CH1(Bytes) T CH2(Bytes) RATE(Ks/s)
5.3 I 126943232 I 126943232 23996.8
soit toujours une communication d’un réel (sans partie imaginaire, indiqué par I) au débit de 24 Méchantillons/s
(que nous noterons désormais MS/s pour Msamples/s).
Un petit détour par la compréhension détaillée du transfert en mode Bulk côté firmware et lecture
côté PC sous GNU/Linux nous permettrait presque de cacher un gros dysfonctionnement qui subsiste,
mais que nous allons dévoiler plus tard et s’avèrera bien plus intéressant qu’il n’y paraı̂t.
14
if (t0_counter == 20)
{ led_flag = 1-led_flag;
if (led_flag) { PD7 = 0; }
else { PD7 = 1; }
t0_counter = 0;
}
}
Ce programme est compilé et transféré en RAM du microcontrôleur du FX2LP pour exécution depuis
le répertoire FX2LP/bulk read example de notre dépôt par
make && sudo cycfx2prog prg:build/fifo_ep6.ihx run
Du point de vue de l’hôte sous GNU/Linux, la récupération des trames s’obtient en exploitant libusb
(paquet libusb-1.0-0-dev sous Debian GNU/Linux) dont la configuration pour l’emplacement des
fichiers d’entête et des bibliothèques peut s’obtenir avec pkg-config). Une fois la séquence d’incantations
connue, le programme est simple et compact avec
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h> // ou <libusb.h> avec pkg-config --cflags libusb-1.0
#define N 512
#define tout_ms 1000
#define vid 0x04b4
#define pid 0x8613 // 0x1004;
int main()
{int i,j,xferred,res;
unsigned char buf[N];
libusb_context *ctx = NULL; // initialize libusb
libusb_init(&ctx);
libusb_device_handle *hndl=libusb_open_device_with_vid_pid(ctx, vid, pid);
15
libusb_claim_interface(hndl, 0);
libusb_set_interface_alt_setting(hndl, 0, 1);
while (1) {
libusb_bulk_transfer(hndl, LIBUSB_ENDPOINT_IN | 6, buf, N, &xferred, tout_ms);
for (i=0; i<N; i+= 2) // affichage du contenu de la FIFO en binaire
{for (j=0;j<8;j++) printf("%d",((buf[i]>>(7-j))&1));
printf("␣");
for (j=0;j<8;j++) printf("%d",((buf[i+1]>>(7-j))&1));
printf("\n");
}
libusb_release_interface(hndl, 0);
libusb_close(hndl);
libusb_exit(ctx);
}
dont les noms de fonctions semblent suffisamment explicites pour suivre naturellement la séquence de
communications. Ce programme se compile avec gcc en pensant à se lier à libusb en complétant la
commande de compilation avec -lusb-1.0.
Les mêmes fonctionnalités sont implémentée en Python3 avec
import [Link]
import [Link]
import binascii
N = 512
tout_ms = 1000
vid = 0x04b4
pid = 0x8613 # 0x1004
Une fois le firmware flashé sur le FX2LP, l’exécution du programme Python sous GNU/Linux indique
$ sudo ./bulk_read.py
array(’B’, [255, 127, 255, 127, 255, 127, 255, 127, 255, 127, 255, 127, 255 ...
alternant l’état des ports B et D (sur 8 bits), tandis que l’exécutable issu du programme C affiche
$ sudo ./fx2lp_ep6_in_fifo
11111111 01111111
11111111 01111111
11111111 11111111
...
avec le 7ème bit qui change d’état selon que PD7 soit à l’état haut ou bas sous contrôle de l’interruption
timer.
Noter qu’en cas d’échec des transactions, il peut être judicieux de vérifier si le module noyau usbtest
n’a pas été automatiquement chargé, et le retirer le cas échéant tel que décrit à [Link]
net/elec/periph/USB-FX2/eeprom/ par sudo rmmod usbtest.
16
lorsque nous configurons la carte avec notre firmware et lançons une acquisition par
PocketSDR/app/pocket dump/pocket dump
la communication se fait toujours à 24 MS/s, même si nous tentons de configurer le convertisseur ana-
logique numérique pour un débit différent, par exemple passer à 12 MS/s en modifiant uniquement le
registre REFDIV de 3 (×1) à 2 (/2). Pire, en modifiant cet unique registre avec une valeur qui semble
cohérente, la communication est perdue. Surement un registre mal configuré quelquepart... mais le
problème s’est avéré à peine plus ardu. Il nous faut résoudre ce dernier problème pour affirmer que
nous pouvons compiler le firmware de la PocketSDR fonctionnel au moyen de SDCC.
Nous connaissions les différents boutismes (endianness) des diverses architectures des processeurs –
avec Intel en little endian qui place l’octet de poids faible d’un mot codé sur plusieurs octets à l’adresse
la plus faible en mémoire, et Motorola qui en big endian place l’octet de poids fort à l’adresse la plus
faible – et nous connaissions l’absence de définition de la nature signée ou non des entiers selon les
déclinaisons des compilateurs C, mais nous découvrons maintenant que divers compilateurs pour une
même architecture peuvent choisir des endianness différentes ! Tant que nous programmions le 8051 en
assembleur, la question de représenter des grandeurs sur plusieurs octets ne se posait pas, puisque les
registres du 8051 ne contiennent qu’un seul octet. Mais comme nous devons passer à la programmation
du microcontrôleur en C au lieu de l’assembleur, nous devons être capables de représenter des nombres
sur 2 octets (short) voir 4 octets (long) même pour une cible qui ne comporte que des registres codant
des valeurs sur 8 bits. Et là les choses se compliquent.
se compile avec l’option -pedantic pour indiquer les dépassements de capacité, vers un micro-
contrôleur AVR, un PC x86 ou un ARM sans système d’exploitation respectivement en
donc les deux premiers compilateurs se plaignent que 240 dépasse la capacité de stockage d’un signed
char (donc signed a été ajouté implicitement), mais arm-none-eabi- ne s’en plaint pas, laissant
présager que là le char est implicitement unsigned, un gros soucis si une boucle teste le passage sous
0 pour cesser ses itérations. On peut compléter cet exemple par la recherche de la valeur minimum
de char par le préprocesseur (gcc -E) :
17
$ arm-none-eabi-gcc -E -dM demo.c | grep CHAR_MIN
#define CHAR_MIN 0
démontrant donc que pour gcc (Intel) et avr-gcc, un char est signé avec une valeur mi-
nimale de −128, alors que pour arm-none-eabi-gcc la valeur minimum d’un char est 0
donc non-signé. Ce dernier cas est peut être lié à la norme imposée par ARM dans https:
//[Link]/documentation/dui0472/m/C-and-C---Implementation-Details/
Basic-data-types-in-ARM-C-and-C-- qui indique
Sans vouloir donner de grain à moudre aux détracteurs du C, ce changement de signe du char
entre déclinaisons du même compilateur nous a causé bien des soucis, en particulier dans les boucles
du type for (k=N;k>=0;k--) qui deviennent infinies avec un unsigned char (toujours positif).
En effet, [13] enseigne que bien que ciblant une même architecture 8 bits, Keil est un compilateur
big endian et SDCC est un compilateur little endian. Tant que les calculs sont gérés par un ordinateur
exécutant un code compilé par un seul compilateur, l’organisation des données en mémoire est cohérente
et il n’y a pas de problème. Cependant en convertissant un code écrit pour Keil vers SDCC qui effectue
des cast de tableaux d’octets (char*) vers un entier codé sur plus de 8 bits (short ou int, ou pour les
utilisateurs de stdint.h, int16 t et int32 t), il faut penser à intervertir les octets qui seront sinon
transférés dans le mauvais ordre vers le MAX2771. Ainsi, les lignes pour compilateur Keil
else if (SETUPDAT[1] == VR_REG_READ) {
*(uint32_t *)EP0BUF = read_reg(SETUPDAT[3], SETUPDAT[2]);
EP0BCH = 0;
EP0BCL = 4;
}
else if (SETUPDAT[1] == VR_REG_WRITE) {
EP0BCH = EP0BCL = 0;
while (EP0CS & bmEPBUSY) ;
write_reg(SETUPDAT[3], SETUPDAT[2], *(uint32_t *)EP0BUF);
}
deviennent pour SDCC (on en a profité pour remplacer les if ... else imbriqués par un switch ...
case) :
case VR_REG_READ:
{ val32=read_reg(SETUPDAT[3], SETUPDAT[2]);
*(uint32_t *)EP0BUF = bswap32(val32);
EP0BCH = 0;
EP0BCL = 4;
return TRUE;break;
}
case VR_REG_WRITE:
{ EP0BCH = EP0BCL = 0;
while (EP0CS & bmEPBUSY) ;
val32=*(uint32_t *)EP0BUF;
val32=bswap32(val32);
write_reg(SETUPDAT[3], SETUPDAT[2], val32);
return TRUE;break;
}
avec
#define bswap32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) \
| (((x) & 0x0000FF00) << 8) | ((x) << 24))
18
de la sorte, tel qu’on s’en convainc en recherchant grep "int32_t\ \*" complete_fw.c dans le code
source du firmware.
Une fois ces dernières erreurs corrigées, nous avons un firmware complet compatible PocketSDR mais
compilable par sdcc sans dépendre d’un compilateur propriétaire, que Tomoji Takasu nous informe par
ailleurs être limité à des exécutables de 4 KB pour sa version gratuite.
Nous avons mentionné en introduction que la carte d’évaluation du MAX2771 est munie d’un oscilla-
teur à 16,368 MHz et que PocketSDR est configurée pour un oscillateur à 24 MHz. Cette information est
renseignée dans le firmware, à [Link]
FW/v2.1/pocket_fw.c#L27 pour la version originale pour Keil ou à [Link]
max2771_fx2lp/blob/main/FX2LP/complete_fw/complete_fw.c#L28 pour notre version pour SDCC :
cette constante F TCXO sera remplacée par 16368 pour que le firmware ainsi recompilé fonctionne direc-
tement avec la carte d’évaluation munie de son oscillateur d’origine.
Ainsi, nous pourrons profiter de tous les exécutables fournis par PocketSDR pour tester le bon
fonctionnement de la carte d’évaluation MAX2771 couplée au FX2LP. Pour ce faire, nous allons explorer
quelques signaux satellitaires transmis dans la moitié supérieure de la bande L, autour de 1500–1600 MHz.
10 log10 (50 × 1000)−20 log10 (1575, 42 · 106 )−20 log10 ( 20000 × 1000 )+ 147, 55 + |{z}13 = −122 dBm
| {z } | {z } | {z } | {z }
W→mW porteuse distance km→m 20 log10 ( 4π
c
) gain
qui se compare avec l’intégration sur une bande passante de 2 MHz du plancher de bruit thermique
à température ambiante donc −174 +10 log10 (2 10}6 ) = −111 dBm, donc un signal 11 dB sous le
| ·{z
| {z }
dBm/Hz Hz
19
bruit thermique. Cette condition n’est pas la plus confortable pour valider un circuit inconnu avec une
configuration inconnue.
avec F DIV ∈ [36 − 32767] la partie fractionnaire du facteur multiplicatif de la fréquence. Pour chaque
configuration, on pourra relire l’état des registres en lançant la commande pocket conf sans argument :
bien entendu en l’absence du second MAX2771 qui équipe la PocketSDR mais est absent de la carte
d’évaluation, la configuration et la lecture des registres du second composant seront incohérentes mais
sans conséquences.
Le choix du débit de données sur le bus USB est déterminé par l’horloge qui cadence les ADC et donc le
signal IFCLK qui rythme le remplissage de la FIFO du FX2LP. L’oscillateur principal (fXtal = 24 MHz)
qui cadence le FX2LP peut être multiplié ou divisé par 1, 2 ou 4 selon la valeur placé dans REFDIV lorsque
ADCCLK = 0, puis les registres REF CLK L CN T et REF CLK L CN T déterminent la cadence des
données par
L CN T
fADC = fXtal (REF DIV )
4096 − M CN T + L CN T
où fXT al (REF DIV ) est l’opération indexée par REF DIV sur fXT al (/4, /2, ×1, ×2, ×4) et nous
constatons que choisir L CN T = 2048 avec M CN T = 0 permet de diviser par 3, donc par exemple de
produire 8 MS/s si REF DIV = 3 pour multiplier par 1 fXtal .
À l’issue de ces explorations, la configuration finalement utilisée exploite une fréquence d’échantillonnage
de 24 MHz (afin d’atteindre après transposition et décimation plus que les 10 MHz que couvre Iridium)
et une fréquence intermédiaire de 6,5 MHz, choisie comme plus que les 5 MHz nécessaires à conser-
ver 10 MHz efficaces en bande de base après transposition. Pour ce faire, NDIV=26925 et RDIV=400
avec INT PLL=1 pour une PLL sans partie fractionnaire, tel que la fréquence de l’oscillateur local soit
24 · 106 /400 × 26925 = 1615.5 · 109 Hz soit 1622 − 6.5 MHz avec 1622 MHz la fréquence centrale d’Iridium.
Pour l’ADC, comme nous conservons la fréquence d’horloge, nous choisissons simplement REFDIV=3.
20
La seconde grande différence entre GPS et Iridium est qu’alors que le premier émet en continu, le
second ne transmet que par impulsions brèves à des instants arbitraires dépendant de la position des
satellites dans le ciel et des requêtes des terminaux au sol. Ainsi, enregistrer en aveugle quelques minutes
d’Iridium pour se rendre compte que peu ou pas de signal est exploitable est frustrant : nous désirons
visualiser en temps-réel le signal au moyen de l’analyseur de spectres (Frequency QT GUI Sink) de GNU
Radio. Bien entendu il n’existe pas d’interface GNU Radio pour le FX2LP, mais comme PocketSDR
fournit pocket dump capable d’écrire dans un fichier, il nous suffit de créer un pipe nommé [16] pour
transférer les données acquises depuis le port USB vers un pseudo-fichier lu par le File Source de
GNU Radio qui alimente l’analyseur de spectres. La chaı̂ne de traitement un peu triviale GNU Radio
Companion est proposée en Fig. 6 (haut-gauche), et sous réserve d’avoir retiré le filtre passe-bande (bas,
gauche) d’une antenne GPS active [14] et avoir inséré un T de polarisation entre le MAX2771 et l’antenne
pour alimenter son amplificateur [14], nous observerons un spectre représentatif des signaux Iridium.
Figure 6 – Gauche : chaı̂ne de traitement GNU Radio prenant en entrée une FIFO sous forme de pipe
nommée /tmp/fifo créée par mkfifo /tmp/fifo. Ce flux d’entiers réels codés sur 8 bits au rythme de
24 MS/s (défini dans le samp rate) est converti en nombres à virgule flottante, transposition de fréquence
par IF = 6, 5 MHz, filtrage et décimation, pour affichage dans l’analyseur de spectres sur une bande
de 12 MHz et émission vers un ZeromMQ Publish dont on pensera à activer Pass Tags: Yes pour être
cohérent avec gr-iridium. Ici la socket est connectée au port 5005 de l’hôte local mais les données
pourraient très bien être transmises sur réseau pour un traitement déporté. Droite : antenne GPS L1
modifiée pour la réception des signaux Iridium en retirant son filtre passe-bande centré sur 1575,42 MHz
pour le remplacer par un condensateur de 1 nF, donc une impédance de 0,1 Ω à cette fréquence, tout
en évitant d’amener la composante DC d’alimentation de l’amplificateur au plus près de l’antenne sur la
broche radiofréquence de l’amplificateur.
Par ailleurs, étant donné que gr-iridium de Sec et Schneider [15] ne connaı̂t pas le concept de
fréquence intermédiaire, nous profitons de l’affichage du spectre par GNU Radio, qui nécessite déjà
d’éliminer cet écart à la porteuse nominale par un Xlating FIR Filter, pour transmettre le résultat
de la transposition dans un flux ZeroMQ Publish. Comme le Xlating FIR Filter a rendu la moitié du
spectre réel inutile, il est muni d’un filtre passe-bas et une décimation d’un facteur 2, de tel sorte que
gr-iridium reçoit un flux de complexes en nombres à virgule flottante à 12 MS/s. Nous avions initiale-
ment tenté de sauver dans un fichier, mais la taille grossit tellement vite à 12 MS/s et les informations
Iridium tellement rares qu’un traitement en temps réel est plus pertinent : 184 MB en format ASCII (’0’
et ’1’) après 3.3 heures d’acquisition et de décodage au lieu de 132 GB qu’auraient occupées les données
brutes.
En effet, gr-iridium sait lire le flux depuis ZeroMQ Subscribe pour le traiter, il faut juste l’infor-
mer du débit de données en modifiant examples/[Link] avec center freq=1622000000 et
sample rate=12000000 tout en s’assurant que address=tcp://[Link]:5005 est cohérent avec le
port sélectionné dans le ZeroMQ Publish de GNU Radio.
Une fois toutes ces briques assemblées, la séquence d’acquisition (Fig. 6) est
1. sudo mkfifo /tmp/fifo pour créer le tuyau,
2. sudo app/pocket conf/pocket conf pocket iridium [Link] pour configurer le MAX2771,
3. sudo app/pocket conf/pocket conf pour vérifier que la configuration a bien été prise en compte,
4. sudo app/pocket dump/pocket dump /tmp/fifo /dev/null pour transmettre le flux IQ de l’unique
MAX2771 vers la tuyau, l’autre flux partant à la poubelle.
21
5. GNU Radio lit depuis le tuyau pour transposer, décimer, afficher le spectre et re-émettre vers
ZeroMQ Publish par python3 fifo [Link] avec le script Python produit par GNU Radio Com-
panion depuis [Link],
6. enfin, gr-iridium reçoit le flux IQ pour en extraire les informations numériques et les sortir
sur stdout. Un premier essai peut consister à attendre les trames Iridium Ring Alert (IRA) qui
démontrent que des signaux de satellites sont bien reçus avec
gr-iridium$ ./apps/iridium-extractor -D 4 --multi-frame ./examples/[Link] | \
python3 -u ../iridium-toolkit/[Link] --harder | grep IRA
mais comme il y a bien plus d’informations qui transitent que IRA, nous préfèrerons stocker ces
bits dans un fichier pour post-traitement par
gr-iridium$ ./apps/iridium-extractor -D 4 --multi-frame ./examples/zeromq-sub_12MSps.conf > \
/tmp/[Link]
7. nous traitons ces bits pour essayer de retrouver des phrases intelligibles avec
iridium-toolkit$ [Link] -p [Link] --harder --uw-ec > [Link]
8. nous pouvons finalement rechercher dans les phrases les trames de localisation et d’identification
des avions selon le protocole ACARS
iridium-toolkit$ [Link] -i [Link] -m acars
ou produire un fichier KML contenant l’emplacement des faisceaux transmis dans les trames IRA
par les satellites détectés
iridium-toolkit$ grep ^IRA [Link] | perl mkkml tracks > [Link]
Figure 7 – Capture d’écran de FlightRadar24 validant l’analyse d’un message ACARS reçu par Iridium.
avec un petit avion effectivement identifié par [Link] à ce moment entre Rome et Milan
(Fig. 7), et un Beluga d’Airbus qui normalement ne devait pas voler à ce moment mais a peut être
effectué un test de communication depuis le sol. La carte des faisceaux (Fig. 8) est cohérente avec une
réception depuis Clermont-Ferrant (étoile jaune) selon une vue partiellement obstruée en direction de
l’est/sud-est.
Nous pouvons donc être à peu près confiants que nous avons bien reçu et décodé des trames Iri-
dium. Rappelons que l’objectif n’est pas de réaliser un récepteur Iridium robuste mais de valider le bon
fonctionnement du MAX2771 sur un signal puissant, qui a tout de même permis de décoder nombre de
trames numériques, un joli hack du MAX2771 au sens original du terme [17].
22
+12h
7 MHz
Figure 8 – Gauche : en haut le spectre affiché par GNU Radio Companion après transposition de
fréquence par le Xlating FIR Filter et décimation d’un facteur deux pour fournir 12 MHz de bande
passante, suffisant pour couvrir tous les signaux d’Iridium en même temps. En haut en début d’acquisition
les canaux individuels de communication sont visibles, en bas après plus de 12 h d’acquisition, le spectre
est devenu uniforme sur les plus de 7 MHz nécessaires à couvrir toutes les sous bandes. Sur ce spectre,
en ellipse bleue foncée un bref burst de communication capturé dans cette image. Droite : carte des
faisceaux identifiés par la trame IRA (fond de carte : OpenStreetMap dans QGIS) pour deux jours
d’acquisition, les 7 et 9 Août 2024 pendant 12 h, pour valider la reproductibilité. Au milieu, gr-iridium
nous informe de nombreuses trames perdues (sous-ligné vert) mais les trames IRA sont tout de même
détectées (sous-ligné rouge).
±5 kHz correspondant uniquement à la vitesse de déplacement du satellite, mais il est prudent en cas
d’échec du décodage d’étendre cette gamme (option -d, une valeur de 30000 pour 30 kHz est raisonnable
pour un résonateur à quartz de qualité convenable). Une fois les satellites identifiés, garantie de la
qualité du signal acquis, nous pourrons finaliser la chaı̂ne de traitement en trouvant la solution optimale
de positionnement du récepteur compte tenu du temps de vol observé pour au moins 4 satellites de la
constellation : cette solution en position, vitesse et temps (PVT) sera obtenue au moyen de gnss-sdr
que nous alimenterons avec le fichier des acquisitions IQ issues du MAX2771, puis obtiendrons en temps
réel.
Dans un premier temps, le MAX2771 est configuré : comme avec Iridium, nous profitons de
app/pocket_conf/pocket_conf
mais cette fois avec un fichier de configuration conf/pocket L1L2 [Link]. Ainsi le MAX2771 est
configuré avec une fréquence centrale de la bande L1 décalée de la fréquence intermédiaire de 2 MHz,
l’échantillonnage à 8 MS/s, et la configuration du second MAX2771 pour la bande L2 simplement
ignorée. Une fois la configuration relue et validée par app/pocket conf/pocket conf sans argument,
nous acquérons les fichiers de mesures par app/pocket dump/pocket dump -t 2 [Link] [Link] avec
-t pour indiquer que nous ne voulons enregistrer que deux secondes, et les arguments optionnels des noms
de fichiers indiquent les deux voies de sortie. De nouveau en l’absence de second MAX2771, le fichier
[Link] ne contiendra aucune valeur exploitable et seul [Link] sera exploitable. Afin d’économiser
l’espace disque, [Link] pourra avantageusement être remplacé par /dev/null sans perte de fonction-
nalité.
Afin de valider la pertinence des données acquises dans [Link], nous allons tenter une acquisition des
satellites, en corrélant séquentiellement les 32 codes pseudo-aléatoires possibles pour tous les décalages
Doppler possibles. Ce résultat s’obtient depuis le répetoire de PocketSDR par
python3 ./python/pocket_acq.py [Link] -f 8 -fi 2 -sig L1CA -prn 1-32 -d 30000
23
pour indiquer que la fréquence d’échantillonnage est 8 MHz, fréquence intermédiaire de 2 MHz, impli-
quant implicitement que les données sont des réels (sans partie imaginaire), et que nous recherchons les
satellites 1 à 32 de GPS avec un décalage de fréquence maximal de 30 kHz. Le résultat est illustré en
Fig. 9 qui valide par ailleurs la cohérence de l’analyse avec l’observation d’un téléphone portable utilisé
comme récepteur GNSS.
Figure 9 – Gauche : le résultat de pocket [Link] de PocketSDR appliqué sur un fichier acquis par
pocket dump du même projet. Milieu : la sortie graphique de la phase d’acquisition des satellites, avec en
abscisse le numéro du satellite (PRN) et en ordonnée le rapport signal à bruit. Droite : observation par
téléphone portable sous Android exécutant GPSTest (cadre rouge), en parfaite cohérence avec le signal
acquis par le MAX2771 (flèches rouges), à l’exception des satellites aux indices les plus élevés qui sont
trop bas sur l’horizon pour être détectables (ellipse rouge).
En configurant de la même façon le MAX2771 en mode IQ, sans fréquence intermédiaire, pour acquérir
au débit de 4 MS/s grâce à conf/pocket L1L2 [Link] de PocketSDR, alors pocket dump affichera
un message de la forme
$ sudo ./app/pocket_dump/pocket_dump -t 2 [Link] [Link]
TIME(s) T CH1(Bytes) T CH2(Bytes) RATE(Ks/s)
2.0 IQ 15990784 IQ 15990784 3993.7
qui permet de bien vérifier le débit (ici 4 MS/s) et la nature (ici IQ, en accord avec la configuration)
même si le second MAX2771 de la PocketSDR est absent.
Le décodage par gnss-sdr nécessite un fichier de configuration qui connecte les diverses étapes de
traitement entre elles selon un graphique ordonnancé par GNU Radio, prenant en particulier compte
du fait que chaque type de donnée en sortie corresponde au type en entrée du bloc de traitement
suivant. Naturellement, un récepteur de radio logicielle voudrait traiter des valeurs complexes en bande
de base, mais nous constatons que notre montage perd la liaison USB rapidement lorsqu’un tel type de
donnée est transféré, probablement à cause d’un couplage électrique excessif entre les lignes portant les
signaux d’horloge et de données au FX2LP (voir conclusion). Ayant donc abandonné l’option de traiter
des complexes (type ibyte dans la nomenclature gnss-sdr) selon la configuration vue juste au-dessus
(pocket L1L2 [Link]), il reste deux voies à explorer, le traitement en temps réel et le post-traitement
de fichiers enregistrés selon la configuration pocket L1L2 [Link].
La première solution est rapidement éliminée puisque le type FIFO qui permettrait de transmettre
des données par un pipe nommé, type Fifo Signal Source du [Link] dans la
configuration de gnss-sdr ne sait pas traiter de nombre réel (sans partie imaginaire), et il ne reste donc
que l’option de traiter un fichier contenant des acquisitions avec fréquence intermédiaire, et convaincre
gnss-sdr de transposer le signal de cette fréquence intermédiaire avant d’en extraire les informations de
temps de vol, donc de peudo-range, donc de solution PVT. Le fichier de configuration commence par le
classique
24
[GNSS-SDR]
GNSS-SDR.internal_fs_sps=8000000
qui indique que les informations sont acquises à 8 MS/s. La source venant d’un fichier contenant des
données sur 8 bits est renseignée par
[Link]=File_Signal_Source
[Link]=[Link]
SignalSource.item_type=byte
SignalSource.sampling_frequency=8000000
qui est intuitif. L’étape suivante est la plus complexe puisque nous devons convertir les entiers en nombres
à virgule flottante complexes après avoir transposé de la fréquence intermédiaire de 2 MHz grâce au
Frequency Xlating FIR Filter de GNU Radio, à savoir un mélange avec un oscillateur local, un filtre
et une décimation :
[Link]=Signal_Conditioner
[Link]=Byte_To_Short
[Link]=Freq_Xlating_Fir_Filter
InputFilter.input_item_type=short
InputFilter.output_item_type=gr_complex
commence par convertir les données d’entrée de 8 à 16 bits en vue d’alimenter le Frequency Xlating
FIR Filter qui sortira des complexes en virgule flottante. Les propriétés du filtre sont déterminées par
sa bande passant et sa bande de coupure (Fig. 10), toujours normalisées à la fréquence de Nyquist (demi
fréquence d’échantillonnage fs ) :
InputFilter.taps_item_type=float
InputFilter.number_of_taps=5
1 P band1 band2
InputFilter.number_of_bands=2
InputFilter.band1_begin=0.0
InputFilter.band1_end=0.40
2f/fs
InputFilter.band2_begin=0.50
0
InputFilter.band2_end=1.0 0 0,4 0,5 1
InputFilter.ampl1_begin=1.0 Figure 10 – Gabarit du filtre
InputFilter.ampl1_end=1.0 passe-bas. Noter l’abscisse graduée
InputFilter.ampl2_begin=0.0 en fréquence normalisée, comme
InputFilter.ampl2_end=0.0 dans tout système échantillonné en
InputFilter.band1_error=1.0 temps discret.
InputFilter.band2_error=1.0
InputFilter.filter_type=bandpass
InputFilter.grid_density=16
InputFilter.sampling_frequency=8000000
[Link]=2000000
ne décime pas le flux mais le transmet aux phases d’acquisition et de traitement tracking pour trouver
la solution PVT issue du signal L1 de la constellation GPS en exploitant au maximum 12 canaux, donc
potentiellement les signaux de 12 satellites. Ce nombre de canaux est limité par la puissance de calcul de
l’ordinateur pour un traitement en temps réel, et en pratique par le nombre de satellites visibles depuis
un site donné :
[Link]=1C
Channels.in_acquisition=1
Channels_1C.count=12
Acquisition_1C.implementation=GPS_L1_CA_PCPS_Acquisition
Acquisition_1C.item_type=gr_complex
Acquisition_1C.doppler_max=30000
25
Acquisition_1C.doppler_step=250
cracking_1C.implementation=GPS_L1_CA_DLL_PLL_Tracking
cracking_1C.item_type=gr_complex
Tracking_1C.early_late_space_chips=0.5
Tracking_1C.pll_bw_hz=25.0;
Tracking_1C.dll_bw_hz=3.0;
Tracking_1C.dump=false;
qui comme auparavant tente de compenser un décalage Doppler jusqu’à 30 kHz, par pas de 250 Hz choisi
comme une valeur petite devant l’inverse de la durée de chaque bit qui est 1 ms, donc petit devant 1 kHz.
Le reste n’est que classique pour conclure la recherche des solutions PVT et est imposé d’après la
documentation de [Link] :
TelemetryDecoder_1C.implementation=GPS_L1_CA_Telemetry_Decoder
[Link]=RTKLIB_PVT
PVT.positioning_mode=PPP_Static
PVT.output_rate_ms=1000
À l’issue de l’exécution par gnss-sdr -c [Link] avec le fichier de configuration contenu dans
[Link], nous avons le plaisir d’obtenir
Initializing GNSS-SDR [Link]-main-87fcfd237 ... Please wait.
RF Channels: 1
Processing file /tmp/[Link], which contains 3137273856 samples (3137273856 bytes)
GNSS signal recorded time to be processed: 392.059 [s]
Current receiver time: 1 s
Tracking of GPS L1 C/A signal started on channel 0 for satellite GPS PRN 01 (Block IIF)
Tracking of GPS L1 C/A signal started on channel 1 for satellite GPS PRN 13 (Block IIR)
Tracking of GPS L1 C/A signal started on channel 2 for satellite GPS PRN 14 (Block III)
Tracking of GPS L1 C/A signal started on channel 3 for satellite GPS PRN 15 (Block IIR-M)
Tracking of GPS L1 C/A signal started on channel 4 for satellite GPS PRN 16 (Block IIR)
Tracking of GPS L1 C/A signal started on channel 5 for satellite GPS PRN 17 (Block IIR-M)
Tracking of GPS L1 C/A signal started on channel 6 for satellite GPS PRN 18 (Block III)
Tracking of GPS L1 C/A signal started on channel 7 for satellite GPS PRN 19 (Block IIR)
Tracking of GPS L1 C/A signal started on channel 8 for satellite GPS PRN 20 (Block IIR)
Tracking of GPS L1 C/A signal started on channel 9 for satellite GPS PRN 21 (Block IIR)
Tracking of GPS L1 C/A signal started on channel 10 for satellite GPS PRN 22 (Block IIR)
Tracking of GPS L1 C/A signal started on channel 11 for satellite GPS PRN 23 (Block III)
Current receiver time: 2 s
Current receiver time: 3 s
...
Current receiver time: 13 s
GPS L1 C/A tracking bit synchronization locked in channel 8 for satellite GPS PRN 20 (Block IIR)
GPS L1 C/A tracking bit synchronization locked in channel 1 for satellite GPS PRN 13 (Block IIR)
...
Current receiver time: 22 s
New GPS NAV message received in channel 8: subframe 2 from satellite GPS PRN 20 (Block IIR) with CN0=45 dB-Hz
New GPS NAV message received in channel 1: subframe 2 from satellite GPS PRN 13 (Block IIR) with CN0=44 dB-Hz
...
New GPS NAV message received in channel 1: subframe 1 from satellite GPS PRN 13 (Block IIR) with
CN0=44 dB-Hz
GPS L1 C/A tracking bit synchronization locked in channel 10 for satellite GPS PRN 07 (Block IIR-
M)
First position fix at 2024-Jul-22 17:57:18.100000 UTC is Lat = 47.2517 [deg], Long = 5.99328 [deg],
Height= 364.788 [m]
Current receiver time: 1 min 17 s
Position at 2024-Jul-22 17:57:19.000000 UTC using 4 observations is Lat = 47.251622 [deg],
Long = 5.993225 [deg], Height = 361.46 [m]
Velocity: East: 0.32 [m/s], North: -0.04 [m/s], Up = -0.05 [m/s]
Current receiver time: 1 min 18 s
Position at 2024-Jul-22 17:57:20.000000 UTC using 4 observations is Lat = 47.251622 [deg],
Long = 5.993205 [deg], Height = 360.35 [m]
...
dont nous n’avons conservé que les principales étapes pour décrire le sens des messages. Les informations
commençant par Tracking n’indiquent nullement la présence d’un signal exploitable dans l’enregistre-
ment, mais uniquement que la signature (code pseudo-aléatoire PRN) d’un certain satellite (GPS PRN
XX) est en cours de recherche dans le signal traité, assigné au canal “channel”. Le point crucial est
l’apparition de tracking bit synchronization locked qui indique que le signal d’un satellite a été
identifié et pourra être analysé en vue de décoder le message de navigation : le numéro du satellite
26
correspond au canal qui lui avait été attribué. Enfin toutes les informations nécessaires à placer le satel-
lite dans l’espace sont acquises lors de New GPS NAV message received, même si en pratique il faudra
décoder les 5 “sub-frames” successives puisque par exemple la première phrase indique les corrections
à appliquer aux horloges atomiques embarquées, les deux suivantes les éphémérides du satellite, puis
la date et les conditions ionosphériques et enfin le statut de la constellation. Nous constaterons que le
succès est souvent au rendez-vous après le décodage d’une “sub-frame” 3 (même si ici ce fut après une
sub-frame 1), sous réserve d’avoir décodé les messages de navigation d’au moins quatre satellites (pour
résoudre l’équation à 4 inconnues que sont la position et le temps) pour fournir le résultat tant attendu
de First position fix qui se répétera ensuite tant que suffisamment de satellites sont visibles. Comme
chaque frame dure 30 secondes, il faut attendre au minimum cette durée une fois le premier message de
navigation obtenu.
27
qui démontre la convergence de la solution en moins de deux minutes, en accord avec les observations de
GPSTest sur téléphone mobile Android utilisé comme récepteur de référence (Fig. 11, droite).
Figure 11 – Gauche : chaı̂ne de traitement GNU Radio lisant des entiers sur 8 bits depuis un fichier
qui est en réalité une FIFO (pipe nommé), suivi de la conversion vers un nombre flottant avec une
homothétie pour ramener le résultat entre −1 et 1, transposition de fréquence et communication du
résultat par socket ZeroMQ Publish, la sortie dans un fichier connecté à un autre pipe n’ayant pas donné
de bons résultats. Droite : capture d’écran de GPSTest exécuté sur téléphone portable utilisé comme
récepteur de référence, démontrant la cohérence avec les sattelites exploités par gnss-sdr pour obtenir
la solution (PRN 2, 8, 21 et 32).
4 Conclusion
Nous avons identifié le protocole de la carte d’évaluation du MAX2771, compris que seule la conversion
de commandes USB vers SPI est prise en charge mais pas le transfert de données haut-débit, appris à
configurer le FX2LP comme interface de transfert entre les mots formés de bits en parallèle et une
horloge vers USB, et acquis ces données sur PC. Cependant, le montage spaghetti avec les longs fils de
communication portant des signaux à plusieurs MHz voir dizaine de MHz ne peut garantir une transaction
robuste, et un circuit dédié s’avère nécessaire pour tirer pleinement parti des performances du MAX2771.
28
08 MHz : -24,9 dB = 0,003 / -45 dB
12 MHz : -21,7 dB = 0,007 / -41 dB
24 MHz : -16,4 dB = 0,023 / -33 dB
48 MHz : -12,1 dB = 0,062 / -28 dB
sortie entrée
50Ω 50Ω
5kΩ 5kΩ
Un analyseur de réseau mesure par son paramètre de transmission S21 le ratio du potentiel
d’entrée Vi au potentiel de sortie Vo (ce sont bien des tensions et non des puissances). La figure
ci-dessus reporte en échelle logarithmique décibels (dB) ainsi que la conversion en échelle linéaire
Vo /Vi = 10dB/10 pour avoir le rapport des tensions entre le signal transmis sur un fil de données et
le couplage sur le fil voisin. Nous avons reporté en noir la mesure lorsque chaque fil est terminé à la
masse par une résistance 50 Ω visant à adapter l’impédance, mais maximisant le courant dans le fil
et donc le couplage. Remplacer la résistance de charge par une valeur de 5 kΩ pourrait laisser penser
que le couplage baisse (en rouge) mais cela induit un autre problème puisque la désadaptation de la
ligne émettrice crée une onde stationnaire qui perturbera la détection des signaux numériques. On
pourrait penser que travailler à 8 MHz n’induit qu’un couplage minime de l’ordre du millième, mais
il faut se rappeler que la transmission de signaux carrés tel que l’horloge émise par le FX2LP porte
toutes les harmoniques de la fréquence d’horloge avec une puissance qui décroı̂t comme le numéro de
l’harmonique. Ainsi, un signal carré de 3,3 V à 8 MHz transporte encore une composante de 0,66 V à
40 MHz (harmonique 5) et 0,47 V à 56 MHz (harmonique 7 puique seules les harmoniques impaires
représentent un signal carré) qui eux couplent inductivement efficacement entre les deux fils. On
comprend donc que le plat de spaghettis du montage reliant la carte d’évaluation du MAX2771 au
FX2LP n’est pas garant de transactions numériques robustes.
Tout comme le PocketSDR qui a inspiré cette étude, nous visons à exploiter les signaux acquis
simultanément par plusieurs MAX2771 pour évaluer la direction d’arrivée d’un signal et éventuellement
annuler une source de leurrage ou de brouillage. Le circuit dédié à ces développements, et bien d’autres,
fera l’objet de l’article qui poursuivra cette description.
Tous les codes sources sont disponibles à [Link] et en
particulier dans le sous répertoire Maxim EvalBoard pour cet article. Les ouvrages de la bibliographie
ont été obtenus sur Library Genesis.
Références
[1] J.-M. Friedt, É. Carry, Enregistrement de trames GPS — développement sur microcontrôleur
8051/8052 sous GNU/Linux, GNU/Linux Magazine France, 81 (Février 2006)
[2] J.-M Friedt, Exploitation des signaux de référence de navigation par satellite pour un positionne-
ment centimétrique : RTKLib fait appel à Centipède et l’IGN pour afficher dans QGis, Hackable 48
(Mai/Juin 2023)
[3] Analog Devices Inc., Software Development : MAX2771EVkit GUI, 1.0.0 à [Link]
[Link]/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/
[Link]
[4] J.-M. Friedt, W. Feng, Anti-leurrage et anti-brouillage de GPS par réseau d’antennes, MISC 110
(Juillet-Août 2020)
29
[5] les projets [Link] et [Link]
html datent de 2011 mais restent d’actualité
[6] [Link] mise à jour le 6 Mars 2024, aussi disponible comme paquet Debian
du même nom
[7] codes sources du firmware de l’analyseur logique sigrok à [Link]
sigrok-firmware-fx2lafw/
[8] Cypress, CY7C68013 EZ-USB FX2 USB Microcontroller – High-Speed USB Peripheral Controller
(2002) à [Link]
[9] [Link]
download;page_name=fx2lp;id=20140817120222-0-10210
[10] Using the Free SDCC C Compiler to Develop Firmware for the DS89C430/450
Family of Microcontrollers à [Link]
using-the-free-sdcc-c-compiler-to-develop-firmware-for-the-ds89c430450-family-of-microcontroller
html
[11] “Reading Serial EEPROM which is Connected to the FX2” à [Link]
t5/Knowledge-Base-Articles/Reading-Serial-EEPROM-which-is-Connected-to-the-FX2/
ta-p/254704 (2008)
[12] [Link]
[13] Keil est big endian selon [Link]
m/3yOfgiqm7_YJ tandis que SDCC est little endian tel que mentionné à [Link]
com/s/article/common-pitfalls-when-using-sdcc
[14] J.-M Friedt, À l’écoute des messages transmis par satellite en orbite basse : Iridium, MISC Hors
Série 29 (2024)
[15] [Link] présenté à Sec et Scheider, Iridium Hacking, Chaos Com-
munication Camp (2015) à [Link]
[16] J.-M Friedt, Échanges de données pour un traitement distribué : communication par réseau ou entre
langages, GNU/Linux Magazine France 267 (Jan-Fév. 2024)
[17] comme les lecteurs de ce journal le savent bien et les journalistes de France Info
ou les auteurs de [Link]
micro-soc-poste-de-travail/edr ne le savent pas, un hack est le détournement d’une techno-
logie de son objectif initial, et aucunement un acte malveillant a priori. Tel que l’indique A. Guitton
dans Hackers. Au cœur de la résistance numérique (Éd. au Diable Vauvert, 2013), le hacker est une
personne s’attachant à “comprendre le fonctionnement d’un mécanisme, afin de pouvoir bidouiller
pour le détourner de son fonctionnement originel” ou de façon répétée dans le début de son ouvrage,
“comprendre, bidouiller, détourner”. La définition au début de R. des Bois, “Lève toi et code : Confes-
sions d’un hacker” (La Martinière, 2018) aurait aussi pu être en relation avec l’introduction de cet
article en affirmant “voir quelque chose de cassé et ne pas pouvoir s’empêcher de ne rien faire, soit
tu l’exploites, soit tu le répares, mais impossible d’ignorer ce dysfonctionnement et le laisser comme
tel.” Quel domage que l’auteur ne se souvienne pas de cette définition dans la suite de son discours,
ouvrage sans intérêt après cette courte mention pertinente, dont le protagoniste se réduit à acheter
sur le web des failles de sécurité pour les exploiter contre des utilisateurs crédules et incompétents
sans faire preuve de créativité technique.
30