MicroPython on ESP32 with SPIRAM support

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
loboris
Posts: 317
Joined: Fri Oct 02, 2015 6:19 pm

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by loboris » Thu Aug 31, 2017 7:29 am

@cable134
Thank you for reporting.
I'm working on SPI driver which is causing the error just now, it will be ready today or tomorow.
I'll test it with your code.

By the way, if you are not using psRAM you don't need to to run in unicore mode, on modules without psRAM MIcroPython runs on both cores just fine.

cable134
Posts: 24
Joined: Sun Aug 20, 2017 10:51 pm

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by cable134 » Thu Aug 31, 2017 8:09 am

Thank you for quick response and advice.
Will look forward and wish you the best.

loboris
Posts: 317
Joined: Fri Oct 02, 2015 6:19 pm

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by loboris » Thu Aug 31, 2017 3:30 pm

@cable134

The spi driver (module) is now updated, I've tested with your example and it works fine.
  • The spi module now supports handling of CS. If defined, no external CS handling is needed.
  • Duplex (default) and half duplex modes are supported:
    • If duplex mode is set, data are transmitted and received simultaneously.
    • If half duplex mode is set, data are received after transmission
  • mosi, miso, sck, and cs parameters can be machine.Pin objects or gpio numbers (integers)
ssd1306, writer, and freesans20 modules are included as frozen modules.

ssd1306 is modified so that cs & res are optional parameters. CS can be handled by spi driver and res (reset) does not have to be defined if not used.
The module can be used both ways:

The old way:

Code: Select all

import machine
from ssd1306 import SSD1306_SPI, SSD1306_I2C

WIDTH = const(128)
HEIGHT = const (64)
pdc = machine.Pin(27, machine.Pin.OUT)
pcs = machine.Pin(26, machine.Pin.OUT)
sck_pin = machine.Pin(19, machine.Pin.OUT)
mosi_pin = machine.Pin(23, machine.Pin.IN)
miso_pin = machine.Pin(25, machine.Pin.OUT)

prst = machine.Pin(18, machine.Pin.OUT)

spi = machine.SPI(1,baudrate=1000000, sck=sck_pin, mosi=mosi_pin, miso=miso_pin)

ssd = SSD1306_SPI(WIDTH, HEIGHT, spi, pdc, prst, pcs)

import freesans20

from writer import Writer
wri2 = Writer(ssd, freesans20, verbose=True)

Writer.set_clip(True, True)
Writer.set_textpos(0, 0)
wri2.printstring('MicroPython\n')

ssd.show()
And the new way:

Code: Select all

import machine
from ssd1306 import SSD1306_SPI, SSD1306_I2C

WIDTH = const(128)
HEIGHT = const (64)
pdc = machine.Pin(27, machine.Pin.OUT)

spi = machine.SPI(machine.SPI.HSPI, baudrate=10000000, sck=19, mosi=23, miso=25, cs=26)

ssd = SSD1306_SPI(WIDTH, HEIGHT, spi, pdc)

import freesans20

from writer import Writer
wri2 = Writer(ssd, freesans20, verbose=True)

Writer.set_clip(True, True)
Writer.set_textpos(0, 0)
wri2.printstring('MicroPython\n')

ssd.show()

cable134
Posts: 24
Joined: Sun Aug 20, 2017 10:51 pm

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by cable134 » Sat Sep 02, 2017 2:46 pm

Thank you so much for your awesome job.
It works now.

And thank you for Repl over Telnet.

Some info for out colleagues:
It's quite easy to start Telnet server on ESP32.
First of all enable it via ./BUILS.sh menuconfig
Check telnet among Python modules.

Than flash ESP32 and start it.

It's my boot.py

# boot.py
import sys,time,network
sys.path[1] = '/flash/lib'

wlan = network.WLAN(network.STA_IF)
if not wlan.isconnected():
print("Waiting for WiFi connection...")
wlan.active(True)
wlan.connect('WiFI_SSID', 'password')
while not wlan.isconnected():
time.sleep(1)
network.telnet.start() ## default lofin/password is micro/python
print(wlan.ifconfig())

loboris
Posts: 317
Joined: Fri Oct 02, 2015 6:19 pm

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by loboris » Sat Sep 02, 2017 3:45 pm

If you start WiFi in boot.py (or main.py), I would recommend to also synchronize the time via ntp server, like this:

Code: Select all

import machine, network, utime
print("")
print("Starting WiFi ...")
sta_if = network.WLAN(network.STA_IF); sta_if.active(True)
sta_if.connect("mySSID", "myPassword")
while not sta_if.isconnected():
    utime.sleep_ms(100)
print("WiFi started")
utime.sleep_ms(500)

rtc = machine.RTC()
print("Synchronize time from NTP server ...")
rtc.ntp_sync(server="pool.ntp.org")
while not rtc.synced():
    utime.sleep_ms(100)
print("Time set to: {}".format(utime.strftime("%c", utime.localtime())))

# If you want to start telnet server:
utime.sleep(1)
network.telnet.start()  ## default login/password is micro/python
print(sta_if.ifconfig())
You can also set your time zone in menuconfig (→ MicroPython → Time zone). Correct time zone string for your location you can find in MicroPython_ESP32_psRAM_LoBo/MicroPython_BUILD/components/micropython/docs/zones.csv
You can use only the first entry from the timezone string, for example:
"Europe/Zagreb","CET-1CEST,M3.5.0,M10.5.0/3"
or the whole timezone string:
"Europe/Zagreb","CET-1CEST,M3.5.0,M10.5.0/3"

slzatz
Posts: 92
Joined: Mon Feb 09, 2015 1:09 am

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by slzatz » Sun Sep 03, 2017 1:51 am

First of all, thanks very much for your micropython work on the ESP32 -- it's really impressive. I am currently running on a board without psRAM but look forward to testing with psRAM in the future.

My question is about mqtt.

The following code works to publish:

Code: Select all

import network
m = network.mqtt(server="x.x.x.x", name="xyz")
m.publish(topic, msg)
However, it's not clear to me how to subscribe with a callback. The subscribe method does not appear to take a callback function. Would it be possible to provide a subscribe example? Thanks.

patrick.pollet
Posts: 16
Joined: Fri Apr 29, 2016 7:08 pm

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by patrick.pollet » Sun Sep 03, 2017 4:39 am

@loboris:

Thanks a lot for such a great work.

Unfotunately after cloning the github repository and starting with ./BUILD.sh menuconfig i had an error :

[code]
patrickpollet@patrickpollet-VirtualBox:~/esp32psram/MicroPython_ESP32_psRAM_LoBo/MicroPython_BUILD$ ./BUILD.sh menuconfig
unpacking 'esp-idf'
unpacking 'esp-idf_psram'
unpacking 'xtensa-esp32-elf'
unpacking 'xtensa-esp32-elf_psram'

Building MicroPython for ESP32 with esp-idf master branch

DEFCONFIG
/home/patrickpollet/esp32psram/MicroPython_ESP32_psRAM_LoBo/esp-idf/tools/kconfig/conf: 1: /home/patrickpollet/esp32psram/MicroPython_ESP32_psRAM_LoBo/esp-idf/tools/kconfig/conf: Syntax error: ")" unexpected
[/code]

If i retry ./BUILD.sh menuconfig i had a different error (and if i retry again i still have this error):
[code]
Building MicroPython for ESP32 with esp-idf master branch

MENUCONFIG
/home/patrickpollet/esp32psram/MicroPython_ESP32_psRAM_LoBo/esp-idf/tools/kconfig/mconf: 1: /home/patrickpollet/esp32psram/MicroPython_ESP32_psRAM_LoBo/esp-idf/tools/kconfig/mconf: Syntax error: "(" unexpected
'make menuconfig' FAILED!
[/code]

./BUILD.sh clean gives also an error.

Every help will be appreciate.

Regards.

Patrick

User avatar
pythoncoder
Posts: 3367
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by pythoncoder » Sun Sep 03, 2017 6:18 am

Why not use the official umqtt library?
Peter Hinch

slzatz
Posts: 92
Joined: Mon Feb 09, 2015 1:09 am

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by slzatz » Sun Sep 03, 2017 9:28 am

Why not use the official umqtt library?
Well, given the impressive set of features in this port (https://github.com/loboris/MicroPython_ ... /README.md, hard not to test them.

Just being able to use the standard esp-idf menuconfig system to configure the ESP32 and certain MicroPython options makes for a very convenient build process.

So yes, I typically include the standard mqtt library as a frozen module in the binary but seemed well worth exploring this alternative for the ESP32.

Steve

loboris
Posts: 317
Joined: Fri Oct 02, 2015 6:19 pm

Re: MicroPython on ESP-WROVER with 4MB of psRAM

Post by loboris » Sun Sep 03, 2017 10:15 am

This implementation of mgtt is written completely in C and runs (when client is created) in background (as separate freeRTOS) task.
Multiple clients can be created, connected to the different mqtt servers (brokers). Secure (ssl) and unsecure connection is supported.

To create the new mqtt client, only two parameters are mandatory and can be given as positional or kw parameters:
mqtt = network.mqtt("description", "server")
or
mqtt = network.mqtt(name="description", server="server")
The name parameter is used to identfy the client if multiple clients uses the same callback function.

The rest of the parameters can be given on creation, or by calling mqtt.config() method.
user = "user_name" user name, default: ""
password = "password" password, default: ""
port = 1234 server port, integer, default: 1883 for nonsecure or 8883 for secure connection
autoreconnect = 60 timeout to reconnect if connection lost in seconds, if set to 0, does not reconnect, default: 0
clientid = "my_mqtt_ID" client ID, default: "mpy_mqtt_client"
cleansession = True clean session, default: False
keepalive = 60 keepalive interval in seconds, default: 120
qos = 1 QoS, default 0
retain = 1 retain, default: 0
secure = True use secure (SSL) connection, default: False
connected_cb = my_function callback function executed when connected to server, default: None
disconnected_cb = my_function callback function executed when disconnected from server, default: None
subscribed_cb = my_function callback function executed when the topic is succesfully subscribed, default: None
published_cb = my_function callback function executed when succesfully published to the topic, default: None
data_cb = my_function callback function executed when data received, default: None

connected, disconnected and subscribed callback functions have one input parameter, the client name.
published callback function has tuple input parameter with client name and publish type
data callback function has tuple input parameter with client name, topic's name and data received)

Example demonstrating all mqtt methods and callback functions:

Code: Select all

def conncb(task):
    print("[{}] Connected".format(task))

def disconncb(task):
    print("[{}] Disconnected".format(task))

def subscb(task):
    print("[{}] Subscribed".format(task))

def pubcb(pub):
    print("[{}] Published: {}".format(pub[0], pub[1]))

def datacb(msg):
    print("[{}] Data arrived from topic: {}, Message:\n".format(msg[0], msg[1]), msg[2])

mqtts = network.mqtt("eclipse", "iot.eclipse.org", secure=True)
>>> I (2492310) [Mqtt client]: Starting Mqtt task
I (2492311) [Mqtt client]: Resolve dns for domain: iot.eclipse.org
I (2492326) [Mqtt client]: Connecting to server 198.41.30.241:8883,45858
I (2492455) [Mqtt client]: Creating SSL object...
I (2492457) [Mqtt client]: Start SSL connect..
I (2493728) [Mqtt client]: Connected!
I (2493729) [Mqtt client]: Connected to server iot.eclipse.org:8883
I (2493729) [Mqtt client]: Sending MQTT CONNECT message, type: 1, id: 0000
I (2493738) [Mqtt client]: Reading MQTT CONNECT response message
I (2493877) [Mqtt client]: Connected
I (2493877) [Mqtt client]: Connected to MQTT broker, creating sending thread before calling connected callback
I (2493881) [Mqtt client]: Sending task started
I (2493886) [Mqtt client]: mqtt_start_receive_schedule

>>> mqtts
Mqtt[eclipse](Server: iot.eclipse.org:8883, Status: Connected
     Client ID: mpy_mqtt_client, Clean session=False, Keepalive=120 sec, QoS=0, Retain=False, Secure=True
     Used stack: 2840/10240 + 1576/2048
    )
>>> mqtts.config(subscribed_cb=subscb, published_cb=pubcb, data_cb=datacb)
>>> mqtts.subscribe("mipy_topic")
I (3341733) [Mqtt client]: Queue subscribe, topic"mipy_topic", id: 1
>>> I (3341919) [Mqtt client]: Subscribe successful
[eclipse] Subscribed

>>> mqtts.publish("other_topic","test from mpy")
I (3409081) [Mqtt client]: Published 45 bytes
I (3409084) [Mqtt client]: Queuing publish, length: 28, queue size(0/1024)
True
>>> [eclipse] Published: Sent

>>> mqtts.publish("mipy_topic","test from mpy, I'm subscribed to this topic")
I (3482472) [Mqtt client]: Published 102 bytes
I (3482475) [Mqtt client]: Queuing publish, length: 57, queue size(0/1024)
True
>>> [eclipse] Published: Sent
I (3482609) [Mqtt client]: deliver_publish
[eclipse] Data arrived from topic: mipy_topic, Message:
 test from mpy, I'm subscribed to this topic
>>> mqtts.unsubscribe("mipy_topic")
I (3559931) [Mqtt client]: Queue unsubscribe, topic"mipy_topic", id: 2
>>>
>>> mqtts.status()
(1, 'Connected')
>>> mqtts.stop()
>>> I (3621157) [Mqtt client]: Closing client socket
I (3621162) [Mqtt client]: Client freed

>>> mqtts.status()
(4, 'Stopped')
>>> mqtts.free()
True
>>> mqtts.status()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: Mqtt client destroyed
>>> mqtts
Mqtt[eclipse]( Destroyed )

No debug messages are printed if you set lower CONFIG_MQTT_LOG_LEVEL using menuconfig, the dafault is Error, here it is set to Info.

@pythoncoder
I hope this answers your question.

Post Reply