Aegidius
 Plüss   Aplulogo
   
 www.aplu.ch
 www.java-online.eu
     Print Text 
© 2019, V10.2
 
  RaspiBrickPi Library
 
linkuplogo
LinkUp
linkuplogo

Under construction!

LinkUp: A ESP32 Coprocessor System

Motivation

Simple microcontrollers are widely used in embedded systems for IoT and robotic applications. There is a growing need to connect these systems to the Internet in order to transmit the data collected by sensors to a remote control system or to receive commands for connected actuators. A direct connection of the microcontroller with the Internet via WLAN or the starting of an access point is often impossible, because a corresponding communication hardware is missing on the chip. To solve this problem, a coprocessor can be added to perform these communication tasks.

Data exchange between the microcontroller and the coprocessor should be as simple as possible, as the microcontroller usually has modest resources. The easiest way is to consider the coprocessor as a special type of sensor that receives commands with a standard protocol to perform an action and returns values to the microcontroller. Common protocols for data exchange with sensors are I²C, SPI and UART.

The general concept is shown here:

linkup5

 

Linkup Manager

After flashing the ESP32 with MicroPython, the program LinkupManager.py is started. It runs an I²C slave at address 0x77 and waits for commands in string format received from an I²C master. The command processor performs the requested action and reports the results back to the master. Typically the master is a small microcontroller with little memory and only a few lines of command code is necessary to perfom quite complicate actions on the ESP coprocessor. The programmer is completely isolated from the code of the LinkupManager and only concerned with the interface API, which is restricted to string exchange.

The ESP32 can be installed on any development board, for example as LOLIN32, Huzzah32 Feather, ESP32-WROOM, ESP32MiniKit Wemos, etc. Because of the small dimensions, the latter is preferred here.

For the connection the pins GND, VCC (3.3V), IO18 and IO26 (as SDA and SCL) are used on the ESP32 board. A simple method of connection is to solder a grove cable to these pins and connect it to an I2C hub on the master.

linkup2

 

linkup3

 

 

 

 

 

Note:
The ESP32 and not the ESP8266 is used here, since the latter cannot be configured as an I²C slave. There are WLAN add-on boards with the ESP8266 on the market which communicate via a serial interface (UART). However, since the UART interface on the microcontroller is often used for runtime debugging, the connection of the coprocessor via I²C is preferrable. In addition, the ESP32 is much more powerful than the ESP8266, which is especially noticeable when used as a web server.

 

Linkup Interface Protocol:


Description

ID
(int)

Arguments
(string)

Return value
 (string)

Blocking
(wait for task done)

Login to an access point (disconnect, if already connected)

1

ssid;password

IP address attributed by the access point, empty if login failed

Yes

Create access point

9

ssid;password

empty

Yes

Perform HTTP GET request

2

url/?key=value;...

Response (content only)

Yes

Perform HTTP POST request

3

url?key=value;...

Response
(content only)

Yes

Perform HTTP DELETE request

4

url

empty

Yes

Start Web server

5

empty

address?filename?params

No

Request deep sleep

6

empty

empty

No

Request reboot

7

empty

empty

No

Receive text

8

line<wait>line<wait>...
empty_line

empty

Yes (line per line)

Create MQTT client

10

host\0port\0
user\0password\0\keepalive
keepalive = "0": disabled
keepalive = "1": enabled

empty

Yes

Disconnect from MQTT broker

11

empty

empty

No

Publish MQTT topic

12

topic\0payload\0retain\0qos
qos: "0", "1", "2"
retain = "False", "True"

"True", if successful
"False", if failed

Yes

Subscribe MQTT topic

13

topic\qos
qos: "0", "1", "2"

"True", if successful
"False", if failed

Yes

Request  MQTT message
from Fifo queue

14

empty

topic\1message
empty, if no message in queue

Yes

Perform MQTT ping

15

empty

"True", if successful
"False", if failed

Yes

Set MQTT last will

16

topic\0payload\0retain\0qos
qos: "0", "1", "2"
retain = "False", "True"

True", if successful
"False", if failed

Yes

Connect MQTT broker

17

"True" if clean session; else "False"

True", if successful
"False", if failed

Yes

Get time from NTP server

18

empty or server URL
if empty: pool.ntp.org

yyyy:mm:dd:hh:mm:ss:ww
empty, if failed

Yes

Get version info

19

empty

Version of Linkup firmware

Yes

 

Web Server

Command option 5 starts a Web server that replies to HTTP GET requests on port 80. The command differs from others because in this mode the ESP32 remains in an endless loop and does not respond any more to other commands. To set the ESP32 to normal mode, the reset button must be clicked.

The information of the GET request is extracted and transmitted from the ESP32 to the master via I²C in the form address?filename?(key1=value1,key2=value2,... e.g. for a request with the URL

http://serverIP/index.html?lamp1=on,lamp2=off

"clientIP?index.html?lamp1=on,lamp2=off"

After a string split at '?' the information is separated into clientIP, filename and GET-parameters (in Python dictionary form).

The master answers via I²C with a response string "(value1, value2, ...)". The values are inserted into the format parameters of the HTML page that the ESP32 sends back to the requesting browser. More information can be found in the sample programs.

 

MicroPython library module linkup

A small library module written for the micro:bit is available to communicate with the LinkUp Manager.

API Documentation Module linkup
(Module import: from linkup import *)

connectAP(ssid, password)

connects the Micro:LinkUp with an existing access point (hotspot, router) with ssid and password. Returns the dotted IP address obtained from the access point; empty, if login fails
httpGet(url) executes an HTTP GET request and returns the response. url in the form "http://<server>?key=value&key=value&...". https can also be used instead of http
httpPost(url, content) executes an HTTP POST request and returns the response. url in the form "http://<server>". content in the format "key=value&key=value&...". https can also be used instead of http
httpDelete(url) executes an HTTP DELETE request with the given resource (file name)
startHTTPServer(ssid, password, startAP)

starts an HTTP server (web server on port 80) and listens for HTTP GET requests. When a GET request is received, the file linkup.html is sent as response to the browser, where any %s format fields are replaced with the strings that were passed with sendReply().

If startAP = True, a local access point with given ssid and password is started. If startAP = False, an existing access point with ssid and password is used and the dotted IP address attributed by the access point is returned (empty, if login fails).

The server is blocking. To return to command mode, the Micro:LinkUp must be rebooted

pollRequest() checks if a GET request has been received and returns a tuple with the filename as string ('/' if none has been specified) and with the request parameter as dictionary {key : value} (empty, if none were specified). Returns None, if no request was received
sendReply(param1, param2, ...) transfers values to the Micro:LinkUp after a pollRequest, which are transferred to the HTML as format parameters before the HTML supplemented in this way is sent to the web browser. The number and sequence of the parameters must match the format specifications in the HTML
saveHTML(text) sends the text string to the Micro:LinkUp and saves it there as linkup.hrml in the file system. It may contain %s format fields, which are replaced with strings passed with sendReply()

The source code is part of the LinkUp distribution found here. The module is copied to the micro:bit when the TigerJython flasher is used. The code is optimized to use as little memory as possible (no classes, few functions, short identifiers, no documentation).

 

Master-Slave Communication

The data is exchanged as byte array via a 256-bytes buffer in the I²C slave (ESP32) . The information to be exchanged from a sender to a receiver consists of a command that defines the action to perform, the number of data bytes and the data itself. Master and slave uses the following memory allocation:

Byte Number

Description

Sender

0

nbChars_m

Master

1

command_m

Master

2

nbChars_s

Slave

3

command_s

Slave

4

data

Master/Slave

...

data

Master/Slave

255

data

Master/Slave

For the master (micro:bit), the buffer corresponds to a set of 256 registers of an I²C slave (ESP32), which are filled and read with usual write and read functions from the I²C library. The slave stores or reads data directly with buffer write and read functions. The ESP32 uses the class I2C of the MicroPython firmware written by Boris Lovosevic.

In most cases a handshake is necessary. This uses nbChars_m and nbChars_s as handshake registers.
In idle state both nbChars are set to 0. Master and slave check the corresponding nbChars with a period of approx. 100 ms (i.e. the slave checks nbChars_m and the master nbChars_s).

  • The transmitter fills the data area as well as the command and sets the corresponding nbChars. It remains in a loop as long as nbChars != 0.

  • In the next poll period the receiver notices that nbChars is != 0. It fetches command and nbChars bytes from the data registers and sets nbChars = 0. This is the acknowledgment to the sender that the data transfer is successfully done.

The restrictions of our communication concept are:

  • command in range 0..255
  • maximum number of data bytes: 256 - 4 = 252
  • no duplex communication
  • transmission latency for a block of data 100 - 200 ms