ArduinoRP2040 et wifi

 

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 :

  1. Nous connecter à un réseau WiFi
  2. Afficher l’adresse IP obtenu
  3. Afficher l’adresse IP correspondante à adafruit.com
  4. 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

Leave a Reply