Raspbery Pi Pico W 2023

Nechal jsem se zlákat lákavou cenou, a pořídil na Aliexpressu dvě vývojové desky, které se tvářily jako 1:1 klon Raspbery Pi Pico W, avšak skutečnost byla poněkud jiná. Oproti originálu tento klon pro komunikaci WiFi používá MCU ESP8285 (vylepšená obdoba ESP8266), který s hlavním MCU RP2040 komunikuje pomocí UART a AT příkazů. Výhodou proti originální desce je osazený USB-C konektor.

    

Potíže s dokumentací

Snažil jsem se na webu najít, jak s touto deskou pracovat, a co se týká samotného programování, bez využívání WiFi, je to celkem jednoduché. Deska je prakticky 100% kompatibilní s originálním Raspbery Pi Pico bez WiFi rozšíření, s plnou podporou programování v Pythonu i v Arduino IDE. Komplikace nastávají, pokud chci najít, jak využít její trochu atypické WiFi rozšíření. Co vypadalo slibně bylo to, že je deska ohledně WiFi koncipovaná podobně jako Challenger RP2040 WiFi, a zde jsou také k dispozici nějaké rady, jak s WiFi zacházet v Arduino IDE. Nicméně po nějakém dalším pátrání se mi mezi velmi chaotickými informacemi podařilo vypátrat (na fóru o tomto klonu), že WiFi modul je u mé desky připojen jednoduše k HW portu UART0 (piny GP0, GP1), který se v IDE dá jednoduše definovat jako Serial1, a pak s ním lze naprosto jednoduše komunikovat. Jednoduchý program pro testování modemu jsem pak našel ZDE, dle něj je pak vytvořen i kód, který přikládám níže v odstavci TESTOVACÍ APLIKACE.

Přidání podpory vývojové desky do IDE

S testovací aplikací jsem ale poněkud přeskočil postup, takže se vraťme trochu zpět. Pro desky s MCU RP2040 sice lze do IDE doinstalovat podpora přímo od Arduina (nakonec i jejich originální deska Arduino Nano RP2040 Connect je založena na tomto MCU), avšak jako nejvhodnější (a nejstabilnější) je komunitou doporučována podpora od Earle F. Philhower, která má široké portfolio podporovaných desek tohoto typu i nálož příkladů kódu pro různé účely.

Upload firmware modemu

Na fóru o potížích s klonem jsem nabyl dojmu, že se autoři příspěvků potýkali s tím, že ESP8285 nereagoval na AT příkazy, a nejdřív do něj bylo nutné nahrát nějaký FW. Já jsem takové potíže ale neměl, a jakmile jsem pochopil, jak je provedené propojení mezi RP2040 a modemem s ESP8285, pomocí testovací aplikace mi modem na příkazy korektně odpovídal bez nutnosti zavádění FW (ESP již obsahovalo FW SDK V2.2.1 z dubna 2018). Pokud by však bylo z nějakého důvodu třeba zavést (např. upgradovat) jiný FW, lze k tomu využít postupu uvedeného ZDE, popř. zde či zde.

Dokumentace ohledně dostupných AT příkazů lze najít na různých místech, je zřejmě vhodné vycházet z dokumentace pro konkrétní verzi, která je v ESP8285 zavedena. Alternativy jsou v následujících odkazech:

Dokumentace Espressif / ESP32 / ESP8266 / esp AT na Github

Knihovna pro komunikaci s WiFi modemem

Pro nějakou složitější komunikaci v bezdrátové síti je vhodné do IDE doinstalovat knihovnu, která tuto komunikaci usnadní a současně do IDE přidá i nějaké příklady, z kterých lze při vlastním programování vycházet či se na nich učit. Pro tento účel je vhodná knihovna WifiEspAT.

Odkazy:

https://github.com/earlephilhower/arduino-pico/issues/475

GEMINI: raspberry pi pico w klon s esp8285 / arduino pico

TESTOVACÍ APLIKACE

Kód pro Arduino IDE, v němž lze komunikovat pomocí terminálu s AT modemem na klonu Pico W 2023:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Test komunikace RP2040 s WiFi modulem ESP8285
// Návrh pro klon Raspbery Pico W 2023
// ========================================================


void setup() {
  Serial.begin(9600);       // UART pro komunikaci USB
  Serial1.begin(115200);    // UART pro komunikaci s ESP8285 (WiFi modem)
  delay(3000);
  Serial.println("Inicializace spojení...");
}

void loop() {
  if(Serial.available()>0) {
    char c = Serial.read();
    Serial1.print(c);
  }
  if(Serial1.available()>0) {
    char c = Serial1.read();
    Serial.print(c);
  }
 
}

/*
---------------------------------------------------------------
Pár příkladů zadaných příkazů v sériovém monitoru vč. odpovědí
---------------------------------------------------------------
AT+GMR
AT version:1.6.2.0(Apr 13 2018 11:10:59)
SDK version:2.2.1(6ab97e9)
compile time:Sep 10 2019 17:31:08
OK

(pozn: před připojením k WiFi je třeba nejdřív nastavit mód modemu)
AT+CWMODE_CUR=3
OK

AT+CWJAP_CUR="moje_ssid","moje_pwd"
WIFI CONNECTED
WIFI GOT IP
OK

AT+CIFSR
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"c6:4f:33:df:16:7b"
+CIFSR:STAIP,"192.168.0.47"
+CIFSR:STAMAC,"c4:4f:33:df:16:7b"
OK

AT+UART?
+UART:115273,8,1,0,1
OK
*/

Vzorová aplikace (webserver)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 Výchozí kód:
 WiFiEsp example: WebServer
 Upraveno pro RP2040 Pico W-2023

 A simple web server that shows the value of the analog input 
 pins via a web page using an ESP8266 module.
 This sketch will print the IP address of your ESP8266 module (once connected)
 to the Serial monitor. From there, you can open that address in a web browser
 to display the web page.
 The web page will be automatically refreshed each 20 seconds.

 For more details see: https://yaab-arduino.blogspot.com/p/wifiesp.html
*/

#include "WiFiEsp.h"

char ssid[] = "xxx";            // your network SSID (name)
char pass[] = "xxxx";        // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
int reqCount = 0;                // number of requests received

WiFiEspServer server(80);

void setup()
{
  // initialize serial for debugging
  Serial.begin(115200);
  // initialize serial for ESP module
  Serial1.begin(115200);
  // initialize ESP module
  WiFi.init(&Serial1);

  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue
    while (true);
  }

  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }

  Serial.println("You're connected to the network");
  //delay(3000);
  printWifiStatus();
  
  // start the web server on port 80
  server.begin();
}


void loop()
{
  // listen for incoming clients
  WiFiEspClient client = server.available();
  if (client) {
    Serial.println("New client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          Serial.println("Sending response");
          
          // send a standard http response header
          // use \r\n instead of many println statements to speedup data send
          client.print(
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html\r\n"
            "Connection: close\r\n"  // the connection will be closed after completion of the response
            "Refresh: 20\r\n"        // refresh the page automatically every 20 sec
            "\r\n");
          client.print("<!DOCTYPE HTML>\r\n");
          client.print("<html>\r\n");
          client.print("<h1>Hello World!</h1>\r\n");
          client.print("Requests received: ");
          client.print(++reqCount);
          client.print("<br>\r\n");
          // output the value of analog input pins
          for (int analogChannel = 0; analogChannel < 4; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.print("Teplota MCU: ");
          client.print(analogReadTemp());
          client.print("°C<br>\r\n");
          client.print("</html>\r\n");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(10);

    // close the connection:
    client.stop();
    Serial.println("Client disconnected");
  }
}


void printWifiStatus()
{
  // print the SSID of the network you're attached to
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address
//  IPAddress ip = WiFi.localIP();  Příkaz nefunguje, pokud je ponechán, program se zde kousne
  Serial.print("IP Address: ");
  Serial.println("ip"); // proměnná vložena do uvozovek
  
  // print where to go in the browser
  Serial.println();
  Serial.print("To see this page in action, open a browser to https://");
  Serial.println("ip"); // proměnná vložena do uvozovek
  Serial.println();
}