An4964 Micropython Scripting Language Over spwf04s Stmicroelectronics
An4964 Micropython Scripting Language Over spwf04s Stmicroelectronics
Application note
MicroPython scripting language over SPWF04S
Introduction
This document describes how to access MicroPython within SPWF04S modules, classes and their
methods, the scripts integrated in the software and a few useful examples for further development.
The SPWF04S software integrates a MicroPython engine enabling MicroPython scripts to be executed
in the STM32 micro, thus allowing end-user software to be embedded in SPWF04S modules. Therefore,
it is possible to create fully standalone Wi-Fi devices with SPWF04S modules without using an external
MCU in order to reduce the final device size and cost.
MicroPython on SPWF04S can support the development of fairly complex and powerful applications,
providing the necessary libraries for managing Wi-Fi connections, security, data transfer and analysis
and SPWF04S hardware interfaces such as UART, SPI, I2C, GPIO, PWM, DAC and ADC available in
the module.
Both the standard and custom MicroPython classes exporting the SPWF04S hardware and protocol
stack capabilities are available to the user for script development.
For a detailed description of MicroPython concepts and standard classes, you can refer to Section 6:
"Tips and tricks".
Figure 1: SPWF04S architecture diagram
Contents
1 MicroPython on the SPWF04 .......................................................... 6
1.1 Getting started................................................................................... 6
1.2 Storage volume IDs........................................................................... 6
1.3 Operational modes ............................................................................ 6
1.3.1 REPL: interactive console .................................................................. 7
1.3.2 Run time script execution ................................................................... 7
1.3.3 Hard script execution .......................................................................... 7
1.4 Flashing LEDs and errors ................................................................. 7
1.5 Configuration ..................................................................................... 8
1.5.1 Configuration variables ....................................................................... 8
1.5.2 GPIOs ................................................................................................. 8
1.5.3 AT command ...................................................................................... 9
List of tables
Table 1: Storage volume IDs ...................................................................................................................... 6
Table 2: Console-enabled configuration summary ..................................................................................... 8
Table 3: MicroPython modes ...................................................................................................................... 9
Table 4: micropython.mem_info(1) output ................................................................................................ 30
Table 5: Document revision history .......................................................................................................... 35
List of figures
Figure 1: SPWF04S architecture diagram .................................................................................................. 1
Figure 2: MicroPython modes ..................................................................................................................... 7
Figure 3: MicroPython modes ................................................................................................................... 12
Figure 4: DAC waveform on GPIO15 ....................................................................................................... 24
1.5 Configuration
1.5.1 Configuration variables
The available configuration variables are:
console_enabled: defined to set the console on SPWF04S. To enable the
MicroPython engine you can use just two allowed values (refer to Table 2: "Console-
enabled configuration summary");
console_enabled = 2 (UART_PYTHON mode): mainly used for debug, it allows the
user to switch between the AT console and the REPL. Therefore, the user can also
execute a script (runtime mode script) and go back to AT command at script
completion.
console_enabled = 3 (PYTHON_ONLY mode): allows executing only a preloaded
MicroPython script. No UART/SPI communication is allowed to/from external host
through an embedded AT/SPI console.
python_memsize: configures the amount of memory to be reserved for MicroPython
script/REPL execution. The default value is 32 (in units of 1024 bytes).
python_script: configures the script name executed at boot when console_enabled is
set to 3 (PYTHON_ONLY). The default value is 3:/uPython_test.py (a ROM resident
example script).
Table 2: Console-enabled configuration summary
Setting Mode Notes Description
console_enabled = 1 UART_ONLY Default Enables the UART console use
console_enabled = 0 SPI_ONLY - Enables the SPI console use
Enables the REPL activation and
console_enabled = 2 UART_PYTHON -
MicroPython scripts via an AT Command
console_enabled = 3 PYTHON_ONLY - Activates Python script execution at boot
1.5.2 GPIOs
The available GPIOs are:
GPIO (8): reserved to enter PYTHON_ONLY mode via hardware. If the GPIO (8) level
is high at startup, the SPWF04 firmware boots directly in MicroPython mode and runs
the default script configured in the python_script configuration variable.
GPIO (14) (CONSOLE_LED): held high or low according to the MicroPython
execution mode and status (refer to Section 1.4: "Flashing LEDs and errors").
1.5.3 AT command
AT+s.PYTHON command is defined to run the REPL or a MicroPython script when the
UART AT console is enabled. It requires the console-enabled variable set to 2 to be
effective.
The following table shows MicroPython modes characteristics and the main device settings
required to enable the desired mode.
Table 3: MicroPython modes
Mode Device setting Command CONSOLE_LED
AT+S.PYTHON; this
AT+S.SCFG = command returns the string:
console_enabled, 2 AT-S.OK MicroPython The
UART_PYTHON, v1.6.2-84-g7f202fb CONSOLE_LED is
AT+S.SCFG =
REPL use on when REPL is
python_memsize, 32 on 2016-07-13; active.
GPIO(8): low SPWF04Sx with
STM32F439 >>>
AT+S.PYTHON=LED.py;
this command returns the
string: AT-S.Launching
script:2:LED.py AT-
AT+S.SCFG = S.OK
console_enabled, 2 +WIND:0:Console The
UART_PYTHON,
AT+S.SCFG =
active CONSOLE_LED is
script execution on when the script
python_memsize, 32 When an error is detected
is running.
GPIO(8): low by the MicroPython engine,
the execution is stopped and
the error is displayed on
REPL prompt, before closing
it and coming back to AT
command shell.
The
AT+S.SCFG = At every reboot, the GPIO
CONSOLE_LED is
python_memsize, 32 (8) is checked. If high, the
on at startup, off
PYTHON_ONLY, script pointed at by the
AT+S.SCFG = python_script, when the script
hardware driven python_script variable is
3:/uPython_test.py starts, TOGGLE
executed independently of
GPIO(8): high when the script
the console_enabled value.
finishes
AT+S.SCFG =
The
console_enabled, 3 CONSOLE_LED is
AT+S.SCFG = At every reboot the script
on at startup, off
PYTHON_ONLY , python_memsize, 32 pointed at by the
when the script
variable driven python_script variable is
AT+S.SCFG = python_script, starts, TOGGLE
executed.
3:/uPython_test.py when the script
finishes.
GPIO(8): low
2 Using REPL
When enabled, the REPL is always available on the SPWF04 AT console serial interface.
Through a USB-serial convertor, you can access REPL directly from a PC.
To access the prompt over USB-serial you need to install a terminal emulator on your PC
(e.g. TeraTerm, Minicom, Putty).
So you can edit your MicroPython script using the preferred editor and check it by the
REPL console.
After launching the command AT+s.python, the REPL prompt appears (>>>>>). Refer to
Figure 2: "MicroPython modes" to get the complete list of console switch modes).
Then, if you enter an if statement, an additional level of indentation is added and you can
insert the required commands inside the if statement like a break command followed by
RETURN and BACKSPACE:
>>> for i in range(30):
... if i > 3:
... break
... _
Finally type print(i), press RETURN, BACKSPACE and then RETURN again:
>>> for i in range(30):
... if i > 3:
... break
... print(i)
...
0
1
2
3
>>>
Auto-indent is not applied if the previous two lines are all spaces. This means you can
finish a compound statement by pressing RETURN twice, and then pressing it one last time
to execute the script.
Ctrl-E activates paste mode, which essentially turns off the auto-indent feature and
changes the prompt from >>> to ===.:
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== def foo():
=== print('This is a test to show paste mode')
=== print('Here is a second line')
=== foo()
===
This is a test to show paste mode
Here is a second line
>>>
Paste mode also allows pasting blank lines. The pasted text is compiled as if it were a file.
Pressing Ctrl-D exits paste mode and starts compiling.
3 MicroPython libraries
The following sections describe standard Python libraries built in MicroPython.
Additional libraries can be downloaded from the MicroPython-lib repository:
github.com/micropython/micropython-lib.
a Resulting error codes includes 1 (error on bus), 2 (bus is busy) and 3 (timeout).
4 Built-in examples
The module includes the following pre-loaded Python script in the internal filesystem:
WLAN_STA.py: shows how to configure the device as a station or mini access point
using the MicroPython WLAN module.
RL_TCP_CL.py: connects to a remote server using TCP socket client and waits for
incoming commands.
RL_UDP_CL.py: connects to a remote server using UDP socket client and waits for
incoming commands. The server can then send commands to switch a LED on/off.
RL_TCP_SE.py: instantiates a local TCP server and wait for incoming connections.
The client then sends commands to switch a LED on/off.
RL_UDP_SE.py: instantiates a local UDP server and waits for incoming connections.
The client then sends commands to switch a LED on/off.
RL_TCP_SE_GC_COLLECT.py: instantiates a local TCP server and waits for
incoming connections.mThe client then sends commands to switch a LED on/off.
When free available memory is lower than 24000 bytes, the script triggers a garbage
collection.
5.1 Basics
A very simple script containing some while and if and messages print on the REPL
console:
a = 0
while True:
a = a + 1
if a % 100 == 0:
print(a)
results in:
100
200
300
5.2 WIND
The WIND built-in module manages asynchronous messages coming from the SPWF04S
network events and resident software stack events.
The script:
from pyb import WIND
import utime
counter = 0
def cb():
global counter
try:
params=wind.params()
if int(params[0]) == 35:
print('network scanned without results')
counter = counter + 1
else:
print('Indication '+str(params[0])+' occurred')
except:
pass
return
w = WIND()
w.callback(cb)
while True:
if counter == 3:
print("3 loops with scan/complete. Suggest: switch in miniAP
mode!")
utime.sleep(1)
5.4 WLAN
Use the WLAN module to configure the device to join a defined network or reconfigure it as
a mini access point (miniAP mode) in case the preferred network was not found or
association failed.
The script:
from network import WLAN
w = WLAN()
MySsid = 'HomeNetwork'
Found = False
print('INIT')
nets = w.scan()
for net in nets:
if net.ssid == MySsid:
found = True
print('<'+MySsid+'> found: trying to connect...')
w.init(mode=WLAN.STA, ssid=net.ssid)
break
if w.isconnected() == False and found == False:
print(MySsid+' not available')
w.init(mode=WLAN.AP, ssid='ApLost')
print(‘END of Job')
results in:
INIT
HOMENETWORK NOT AVAILABLE
END OF JOB
5.5 Socket
The following script shows how to use the built-in socket module to open a socket server,
listen for incoming messages and, if the command is recognized, execute the required
results in:
INIT
TURN ON THE LAMP
TURN OFF THE LAMP
END OF JOB
def func():
i=0
A='HELLO'
while(i<10):
A=A*2
print(gc.mem_free())
i=i+1
print(gc.mem_free())
print('END FUNC')
return
print('RUN 1')
print(gc.mem_free())
func()
print('TRIGGER GC')
gc.collect()
print('RUN 2')
func()
print('TRIGGER GC')
gc.collect()
print(gc.mem_free())
Handle communication properly to avoid data loss. Hardware flow control enabled
at peripheral initialization is highly recommended.
The full AT command parsing can be directly handled using MicroPython without any extra
external host.
from pyb import UART
import utime
uart = UART(1,115200)
uart.init(115200,bits=8,stop=1,parity=None)
temp = uart.write('at+ab discovery')
uart.writechar(0x0D)
data = False
while data == False:
data = uart.any()
utime.sleep(1)
s = bytearray(256)
temp = uart.readinto(s)
print(s)
5.7.3 I²C
The following example shows how to use I²C built-in class. In particular, the X-NUCLEO-
IKS01A1 MEMS inertial and environmental sensor board is used here to interface the
SPWF04 module using the I²C(3) peripheral.
It is designed around STMicroelectronics:
LSM6DS0 3-axis accelerometer
LIS3MDL 3-axis magnetometer
HTS221 humidity and temperature sensor
LPS25HB pressure sensor.
The script initializes the peripheral and performs a scan operation to detect all the
connected slaves, printing the I²C address list.
In this example, a non existing device is also checked to show how to handle exception
cases.
from pyb import I2C
i2c = I2C(3,I2C.MASTER)
i2c.init(I2C.MASTER,baudrate=20000)
if i2c.is_ready(11) != True:
print(‘Cannot detect LCD Display!')
i2c.scan()
else:
print(‘LCD Display detected!')
5.7.4 ADC
A built-in ADC module facilitates STM32 ADC peripheral management.
from pyb import ADC
import utime
a = ADC(1)
while True:
print(a.read())
utime.sleep(1)
Using a 2 kΩ trimmer on GPIO1 (min. to max. shift, then max. to min. again), this results in:
3299
2712
2151
1349
929
0
0
0
217
762
2325
3299
5.7.5 DAC
A simple MicroPython script example shows how to deal with STM32 DAC peripheral,
running on SPWF04S Wi-Fi module:
from pyb import DAC
import utime
counter = 0
up = True
d = DAC(1)
while True:
d.write(counter)
if up == True:
counter = counter + 100
if counter == 3300:
up = False
else:
counter = counter – 100
if counter == 0:
up = True
utime.sleep_ms(100)
This results in the following waveform on GPIO15 (split into 33 steps on each side):
Figure 4: DAC waveform on GPIO15
5.7.6 Timer
Timer class controls the internal timers and allow calling a function at a specified
frequency:
import pyb
a=pyb.Timer(2)
a.init(freq=20)
led=pyb.LED(1)
def toggle(l):
l.toggle()
a.callback(lambda t:toggle(led))
5.7.7 AsyncIo
Asyncio is a very minimal cooperative multithreading like framework ported on
MicroPython. It allows to define tasks and handle asynchronous events. Here a simple
MicroPython script allowing parallel execution of 3 tasks:
import asyncio_slow as asyncio
def factorial(name, number):
f = 1
for i in range(2, number+1):
tasks = [
asyncio.Task(factorial("A", 2)),
asyncio.Task(factorial("B", 3)),
asyncio.Task(factorial("C", 4))]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
5.7.8 TFTP
TFTP module allow to transfer files from/to the SPWF04Sx to/from a remote TFTP server.
The following example retrieve a file from a remote TFTP server assigning a local file
name, and then upload the file back to the server:
from TFTP import TFTP
t=TFTP(('192.168.1.129', 69))
t.get(downfile='remotefile',localfile='localfile')
t.put(upfile='localfile')
5.7.9 HTTP
HTTP module allow to perform get and post request to a remote http/https server. The
following example perform a combination of http/https get/post requests, showing the 'save
the answer to a file' feature:
import HTTP
5.7.10 SMTP
SMTP module is used to send email using the SMTP protocol. The following code show the
SMTP basic usage. The first example send an email through a local server, the second
example rely on gmail smtp service:
import SMTP
Send an email through gmail (Equifax Secure Certificate Authority certificate must
be loaded)
SMTP object: SMTP(host=(smtp.gmail.com; 465; 9), login=(myAddress; myPassword),
ID=SPWF04Sx, from=Me <[email protected]>)
Email sent
5.7.11 MQTT
Using the MQTT module, a user can connect to a MQTT broker and subscribe and/or
publish messages. The following code show a simple example of usage. In order to display
the messages pushed to subscribers, the class WIND must be used:
from pyb import WIND
from MQTT import MQTT
from utime import sleep_ms
class wind_receiver:
def __init__(self):
self.wi = WIND()
self.wi.callback(self.print)
self.ind = None
def __del__(self):
del self.wi
def print(self):
self.ind = self.wi.params()
if self.ind[0] == 86: # MQTT Published
print(self.ind)
5.7.12 Websocket
Websocket module is used to establish a websocket connection with a remote server. In
the following code a connection is opened to an echo server. A message is sent through
the connection and the same message is received back. Apart from the connection
establishment, the usage is similar to conventional TCP sockets.
from websocket import websocket
try:
6.2 Buffers
When accessing devices such as instances of UART, I²C and SPI interfaces, using pre-
allocated buffers avoids the creation of needless objects. Consider these two loops:
while True:
var = spi.read(100)
# process data
buf = bytearray(100)
while True:
spi.readinto(buf)
# process data in bufis passed
The first creates a buffer on each pass, whereas the second re-uses a pre-allocated buffer.
The latter solution is faster and more efficient in terms of memory fragmentation.
In the first call a tuple of integers is created in the RAM; instead, the second call efficiently
creates a byte object consuming the minimum amount of RAM. If the module is frozen as
bytecode, the bytes object resides in the Flash memory.
6.4 Arrays
Consider the use of the various types of array classes as an alternative to lists. The array
module supports several element types with 8-bit elements supported by Python built-in
bytes and bytearray classes. These data structures store elements in contiguous memory
locations. Therefore, to avoid memory allocation in critical code, these should be pre-
allocated and elaborated as arguments or as bound objects.
A memoryview can only be applied to objects supporting the buffer protocol (including
arrays but not lists). While the memoryview object is live, it also keeps the original buffer
object alive. For instance, in the example above, if you have a 10K buffer and just need
bytes 30:2000 from it, it may be better to make a portion, and release the 10K buffer (ready
for garbage collection), instead of making a long-living memoryview and keeping 10K
blocked for garbage collection.
Nonetheless, memoryview is indispensable for advanced pre-allocated buffer
management.
The .readinto() method puts data at the beginning of the buffer and fills the entire buffer.
If you need to put data in the middle of an existing buffer, create a memoryview in the
buffer section and pass it to .readinto().
All of them return the same output, but the first one creates two string objects at runtime,
allocating more RAM for concatenation before producing the third. The others perform the
concatenation when compiling, thus reducing fragmentation.
Rather than creating a large string object, create a substring and feed it to the stream
before dealing with the next.
The best way to create dynamic strings is by means of the string format method:
X=5.3
var="test {:5.4f}\n".format(temp)
print(var)
Nevertheless, when a module is compiled, strings which occur multiple times are stored
only once (string interning). In MicroPython an interned string is called qstr. In an imported
module normally that single instance is located in the RAM.
String comparisons are also performed efficiently using hashing rather than character by
character.
8 References
1. MicroPython homepage: http://micropython.org/
2. Documentation: http://docs.micropython.org/
3. Forum: http://forum.micropython.org/
4. Wiki: http://wiki.micropython.org/
5. Tutorials: https://micropython.org/doc/tut-contents
6. Source code repository: https://github.com/micropython/micropython
7. Garbage collector quick tour: https://segfault.net.nz/posts/2014-06-07-micropython:-a-
quick-gc-tour.html
8. Python 3.X: https://docs.python.org/3.4/whatsnew/3.0.html#print-is-a-function
9. Pyboard MicroPython Documentation:
http://docs.micropython.org/en/latest/micropython-pyboard.pdf
9 Revision history
Table 5: Document revision history
Date Version Changes
17-Jan-2017 1 Initial release.
Added figure Figure 3: "MicroPython modes". Updated Section 3.3:
"Specific libraries for the SPWF04S port".
Added Section 5.7.6: "Timer".
15-Nov-2017 2 Updated Section 3.3: "Specific libraries for the SPWF04S port".
Updated Section 5.7.8: "TFTP", Section 5.7.9: "HTTP", Section 5.7.10:
"SMTP", and Section 5.7.11: "MQTT".
Minor text changes.
STMicroelectronics NV and its subsidiaries (“ST”) reserve the right to make changes, corrections, enhancements, modifications, and
improvements to ST products and/or to this document at any time without notice. Purchasers should obtain the latest relevant information on ST
products before placing orders. ST products are sold pursuant to ST’s terms and conditions of sale in place at the time of order
acknowledgement.
Purchasers are solely responsible for the choice, selection, and use of ST products and ST assumes no liability for application assistance or the
design of Purchasers’ products.
Resale of ST products with provisions different from the information set forth herein shall void any warranty granted by ST for such product.
ST and the ST logo are trademarks of ST. All other product or service names are the property of their respective owners.
Information in this document supersedes and replaces information previously supplied in any prior versions of this document.