L’Arduino RP2040 possède un circuit WiFi le U-blox® Nina W102 qui basé sur un processeur de type ESP32 permettant de gérer le WiFi, le bluetooth, une led RGB et d’autres entrées-sorties !!
Présentation du circuit
Le datasheet est consultable à l’adresse suivant : https://content.arduino.cc/assets/Arduino_NINA-W10_DataSheet_%28UBX-17065507%29.pdf
Comment est-il possible qu’un simple microcontrôleur puisse gérer le WiFi et le Bluetooth, même le BLE ?
La solution est assez simple : utiliser un autre microcontrôleur qui va les prendre en charge.
C’est le cas ici du circuit Nina W102 du fabriquant U-blox :
- Bluetooth V4.2 (Bluetooth BR/EDR et Bluetooth Low Energy (LE).
- Wi-Fi 802.11b/g/n, jusque 100 Mbits/s, point d’accès jusque 4 machines, WPA/WPA2
- Antenne intégrée
- Interfaces UART, SPI, I2C
- 20 broches GPIO
- Convertisseur Analogique Numérique
Le schéma bloc est celui-ci :
Processeur de type ESP32 (Xtensa LX6) avec :
- 448 ko de ROM pour le boot et des fonctions principales
- 520 ko de SRAM pour les données et les instructions
- 16 Mbit de FLASH pour le code
- 1 kbit de EFUSE (mémoire non effacable), adresse MAC …
Intégration sur la carte
Sur le schéma électronique
SPI, UART et I2C
Très classiquement, ce circuit à base d’ESP32 est connecté en SPI :
- (1) SPI sur les ports CS, CLK MISO, MOSI et ACK (respectivement sur la RP2040 (D9, D14, D8, D11, D10)
Par contre, après cela devient très originale :
- (2) Un led RGB est connecté aux ports 16, 17 et 18
- (3) L’UART, pour notamment utiliser le Bluetooth, partage les mêmes ports quel SPI !!
Et pour terminer, je ne comprends pas l’utilité de l’avoir connecté également en i2c (4). Ainsi le U-blox® Nina W102 est connectée en 2ic à co-processeur de cryptographie et à l’accéléromètre/gyroscope.
L’antenne
L’antenne est intégrée au circuit. Elle est de type PIFA, Planar Inverted-F Antenna : antenne quart d’onde court-circuitée. De faible coût et compacte, on trouve ce type d’antenne dans de nombreux équipements portables réseaux.
Led RGB
Quel rapport entre le WiFi et la led RGB me diriez-vous ?
Et bien, cette dernière est accessible par l’intermédiaire du composant WiFi :
Le chemin entre l’ESP32 est la led RGB est assez long !!
Pour quelle raison ? Peut-être pour économiser des broches sur le processeur. À noter d’ailleurs que d’autres entrées sorties, analogiques, sont accessibles à travers le circuit gérant le wifi (et le bluetooth) qui rappelons-le est un esp32
Premier programme : firmware, adresses MAC et réseaux disponibles
D’après https://learn.adafruit.com/circuitpython-on-the-arduino-nano-rp2040-connect/wifi
Bibliothèques nécessaires
Pour ce premier code, nous allons afficher la version du firmware, l’adresse MAC ainsi que les réseaux disponibles :
Pour ce faire, nous avons besoin de la bibliothèque adafruit_esp32spi (répertoire) et adafruit_requests.mpy (fichier).
Ces deux éléments sont à copier sur le lecteur CIRCUITY (voir si besoin http://www.framboiseetcompagnie.fr/installation-des-bibliotheques-libraries-circuitpython/)
Explications du code
Après les classiques importations :
import board import busio from digitalio import DigitalInOut from adafruit_esp32spi import adafruit_esp32spi #A ajouter import adafruit_requests as requests
Configuration de l’ESP32 :
esp32_cs = DigitalInOut(board.CS1) esp32_ready = DigitalInOut(board.ESP_BUSY) esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK1, board.MOSI1, board.MISO1) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
Affichage de la version du firmware et de l’adresse MAC en utilisant des attributs de esp
print("Firmware vers.", esp.firmware_version) print("MAC addr:", [hex(i) for i in esp.MAC_address]) print(':'.join([str(hex(i))[2:] for i in esp.MAC_address])) # format MAC adresse
Scan et affichage des différents réseaux disponibles :
for reseaux in esp.scan_networks():#Scan des réseaux disponibles print("%s \tRSSI: %d" % (str(reseaux['ssid'], 'utf-8'), reseaux['rssi']))
Le code complet
Le code complet avec l’affichage et différentes vérifications :
import board import busio from digitalio import DigitalInOut from adafruit_esp32spi import adafruit_esp32spi #A ajouter import adafruit_requests as requests print("Arduino nano connect RP2040 - Wifi test") # Voir configuration électronique esp32_cs = DigitalInOut(board.CS1) esp32_ready = DigitalInOut(board.ESP_BUSY) esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK1, board.MOSI1, board.MISO1) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) if esp.status == adafruit_esp32spi.WL_IDLE_STATUS: print("ESP32 found and in idle mode") print("Firmware vers.", esp.firmware_version) print("MAC addr:", [hex(i) for i in esp.MAC_address]) print(':'.join([str(hex(i))[2:] for i in esp.MAC_address])) # format MAC adresse print("Réseaux disponibles :") print("Nom\tRSSI") print("-----------------------") for reseaux in esp.scan_networks():#Scan des réseaux disponibles print("%s \tRSSI: %d" % (str(reseaux['ssid'], 'utf-8'), reseaux['rssi'])) print("Terminé")
Connection à un réseaux et ping
Dans ce programme nous allons :
- Nous connecter à un réseau WiFi
- Afficher l’adresse IP obtenu
- Afficher l’adresse IP correspondante à adafruit.com
- Effectuer un ping sur une autre adresse IP
Cacher le mot de passe wifi dans un fichier
En suivant les tutoriels, d’Adafruit, l’idée est de mettre le nom et le mot de passe de votre réseau WiFi dans un fichier appelé : wifi.py qui est, au sens python, un dictionnaire contenant deux clés (au moins), ssid et password
Par exemple
secrets = { 'ssid' : 'Freebox-A3434F', 'password' : 'dj3ULy66- Xm44nSs9- G7u4cqK2- 7khpLS89' }
Ce fichier doit se trouver à la racine du lecteur RP2040.
Connexion à un réseau Wifi :
Le dictionnaire secrets contient le nom et le mot de passe :
print("Connection au réseau ", secrets['ssid'])
Il est possible que la connexion ne se fasse pas tout de suite d’où la boucle :
while not esp.is_connected: try: esp.connect_AP(secrets['ssid'], secrets['password']) except RuntimeError as e: print("Connection impossible, réessait : ", e) continue
Il est possible d’afficher le nom du réseau et de sa puissance de réception avec esp.ssid et esp.rssi :
print("Connecté au reseau ", str(esp.ssid, "utf-8"), "et la force du signal : ","\tRSSI:", esp.rssi,"dBm")
Affichage de l’adresse IP
Tout simplement par esp.ip_address :
print("Adresse IP obtenu", esp.pretty_ip(esp.ip_address))
Résolution d’adresse DNS
get_host_by_name permet simplement d’obtenir l’adresse IP à partir de l’adresse DNS (url) :
print( "IP lookup adafruit.com: %s" % esp.pretty_ip(esp.get_host_by_name("adafruit.com")) )
Ping sur une machine
Il est également possible d’effectuer un ping afin de savoir si une machine est accessible avec esp.ping :
MACHINE = '192.168.1.26' #Adresse IP d'une machine ping = esp.ping(MACHINE) print("Ping sur la machine distante :", ping, "ms")
Le code complet
import board import busio from digitalio import DigitalInOut import adafruit_requests as requests from adafruit_esp32spi import adafruit_esp32spi MACHINE = '192.168.1.26' #Adresse IP d'une machine # Get wifi details and more from a secrets.py file try: from secrets import secrets except ImportError: print("Les données secrètes du WiFi doivent se trouver le fichier secrets.py") raise print("Raspberry Pi RP2040 - ESP32 SPI webclient test") esp32_cs = DigitalInOut(board.CS1) esp32_ready = DigitalInOut(board.ESP_BUSY) esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK1, board.MOSI1, board.MISO1) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) print("Connection au réseau ", secrets['ssid']) while not esp.is_connected: try: esp.connect_AP(secrets['ssid'], secrets['password']) except RuntimeError as e: print("Connection impossible, réessait : ", e) continue print("Connecté au reseau ", str(esp.ssid, "utf-8"), "et la force du signal : ","\tRSSI:", esp.rssi,"dBm") print("Adresse IP obtenu", esp.pretty_ip(esp.ip_address)) # test vers la machine distante par un ping ping = esp.ping(MACHINE) print("Ping sur la machine distante :", ping, "ms") if ping == 65535: print('Impossible pinger la machine')
Récupération d’un fichier json ou autre
Les bibliothèques
Trois sont nécessaires, celle de l’esp32, une autre pour récupérer une socket et request
from adafruit_esp32spi import adafruit_esp32spi # A ajouter import adafruit_esp32spi.adafruit_esp32spi_socket as socket import adafruit_requests as requests # A ajouter
Téléchargement de fichiers à distance
Dans l’exemple d’Adafruit, nous allons télécharger puis lire deux fichiers :
- Un fichier html
- Un fichier json
TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html" JSON_URL = http://api.coindesk.com/v1/bpi/currentprice/USD.json
La bibliothèque qui sera utilisée est adafruit_requests : elle permet d’interagir avec le web
https://circuitpython.readthedocs.io/projects/requests/en/latest/api.html
Dans notre exemple, elle va nous permettre de récupérer une socket, une sorte de connecteur, avec lequel nous allons demander les fichiers :
requests.set_socket(socket, esp) # Récupération d'une socket
Ensuite pour demander un fichier texte :
r = requests.get(TEXT_URL)
Et le lire
print(r.text)
Même chose pour un fichier json :
r = requests.get(JSON_URL) print(r.json())
Pour les deux, il faudra fermer la connexion
r.close()
Code complet :
import board import busio from digitalio import DigitalInOut import adafruit_requests as requests from adafruit_esp32spi import adafruit_esp32spi # A ajouter import adafruit_requests as requests # A ajouter import adafruit_esp32spi.adafruit_esp32spi_socket as socket TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html" JSON_URL = "http://api.coindesk.com/v1/bpi/currentprice/USD.json" try: from secrets import secrets except ImportError: print("Les données secrètes du WiFi doivent se trouver le fichier secrets.py") raise print("Raspberry Pi RP2040 - ESP32 SPI webclient test") esp32_cs = DigitalInOut(board.CS1) esp32_ready = DigitalInOut(board.ESP_BUSY) esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK1, board.MOSI1, board.MISO1) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) print("Connection au réseau ", secrets['ssid']) while not esp.is_connected: try: esp.connect_AP(secrets['ssid'], secrets['password']) except RuntimeError as e: print("Connection impossible, réessait : ", e) continue print("Connecté au reseau ", str(esp.ssid, "utf-8")) requests.set_socket(socket, esp) # Récupération d'une socket print("Récupération d'un texte de ", TEXT_URL) r = requests.get(TEXT_URL) print("-" * 40) print(r.text) print("-" * 40) r.close() print() print("Fetching json from", JSON_URL) r = requests.get(JSON_URL) print("-" * 40) print(r.json()) print("-" * 40) r.close()
La suite :
Échange de données entre l’Arduino RP2040 et une Raspberry PI en wifi