MicroPython Ameba RTL8722 Documentation

Realtek’s RTL8722 is a ARM Cortex-M33 based, dual-band WiFi and BLE 5.0 capable microntroller that is ideal for many IoT applications.

This MicroPython port is for Ameba RTL8722 platform, details of the platform can be found here https://www.amebaiot.com/en/amebad/

1. How to build firmware?

Currently, this SDK only support building on Cygwin or Linux.

Before preceed, please make sure that you have already installed GNU make and the latest Python3.

Open Cygwin terminal/Ubuntu terminal and navigate to “\micropython_amebaD\MicroPython_RTL8722\ports\rtl8722” and then type,

$ make

1.1 FAQ

During the building process, some user may encounter error that suspend the process, this is due to missing system enevironment setup and can be fixed as follows,

By default, MicroPython use python3 to run building scripts for the MicroPython kernals, if you encounter error related to python, it may be because the path of the Python3 executable is not added to system environment variable.

However, if environment variable is already added but the build couldn’t be completed, you may try, 1) Re-start your PC 2) type “python” on your terminal, if the python shown is python3, then please add

PYTHON = python

to the second line of the “Makefile” in our “port/rtl8722” folder

If building process stop when mpy-cross shown as error, there is a step to be done as follows, 1) navigate to “MicroPython_RTL8722/mpy-cross” folder 2) Open your Cygwin/Linux terminal and just type

$ make

Wait for make finish building the MicroPython Cross Compiler, then this should fix the error

2. How to upload?

There are 2 methods to upload Ameba D MicroPython image to your Ameba.

2.1 Release folder

In the release folder, there is a Double-Click-Me-to-Upload.cmd file.

First, we right click on it and select ‘Edit’, and a notepad will open, now check your Ameba’s serial COM port on your PC and update the correct one to the third last line of the file, then save the file and close it.

Now press RESET button while holding down UART Download button to enter UART Download Mode, and you can double click Double-Click-Me-to-Upload.cmd now and the uploading will start shortly.

2.2 port/rtl8722 folder

First, check your ameba Serial/COM port, make sure Ameba D’s port name is correctly updated in the UPLOAD_PATH variable in the “Makefile”;

Second, press RESET button while holding down UART Download button to enter UART Download Mode, Then, type following command,

$ make upload

3. How to use MicroPython RTL8722 Port?

3.1 Brief introduction to MicroPython RTL8722 port

MicroPython distinguishes itself from other compilation-based platforms (Arduino etc.) with its powerful method of real-time interaction to Microcontroller through a built-in feature – REPL.

REPL stands for Read-Evaluation-Print-Loop, it’s an interactive prompt that you can use to access and control your microcontroller.

REPL has been equipped with other powerful features such as tab completion, line editing, auto-indentation, input history and more. It basically functions like the classic Python IDLE but running on microcontroller.

To use REPL, simply open any serial terminal software (most common ones are teraterm, putty etc.) on your PC and connect to your microcontroller’s serial port, then set baudrate to 115200 before manually reset the board, then you will see >>> MicroPython prompt appear on the console. Now you may type in any Python script on REPL as long as it’s support by MicroPython and your microcontroller’s MicroPython port.

Most importantly, try to abuse “help()” function as much as possible to gain more information. For example, upon microcontroller power up and REPL shown, just type

help()

You will see a help page giving you more details about this port; also if you type

help(modules)

it will list out all available builtin modules that are at your disposal

Furthermore, if you want to learn more about a module, such as its API and CONSTANT available, simply type the following code and details of that module will be returned to you,

help(the module of your interest)

Let’s take Pin module (GPIO) as an example:

>>> help(Pin)
object <class 'Pin'> is of type type
  id -- <function>
  init -- <function>
  value -- <function>
  off -- <function>
  on -- <function>
  toggle -- <function>
  board -- <class 'board'>
  IN -- 0
  OUT -- 1
  PULL_NONE -- 0
  PULL_UP -- 1
  PULL_DOWN -- 2

3.2 REPL Hotkeys

  1. Ctrl + d : Soft reboot MicroPython will perform software reboot, this is useful when your microcontroller is behaving abnormally. This will also run scripts in ‘boot.py’ once again.

    Note that this will only reset the MicroPython interpretor not the hardware, all your previously configured hardware will stay the way it is until you manually hard-reset the board.

  2. Ctrl + e : Paste mode Paste mode allow you to perform pasting a large trunk of code into REPL at once without executing code line by line. This is useful when you have found a MicroPython library and wish to test it out immediately by copy and paste

  3. Ctrl + b : Normal mode This hotkey will set REPL back to normal mode. This is useful if you are stuck in certain mode and can not get out.

  4. Ctrl + c : Quick cancel This hotkey help you to cancel any input and return a new line

4. Peripheral Control – machine module

MicroPython Ameba D port supports rich peripheral features through the use of machine module

GPIO

To control GPIO, import Pin module through machine. Here pin PB_18 is used as an example to output logic level 0 and 1 and blink 3 times

from machine import Pin
a = Pin("PB_18", Pin.OUT)
a.value(1)
time.sleep_ms(500)
a.value(0)
time.sleep_ms(500)
a.on()
time.sleep_ms(500)
a.off()
time.sleep_ms(500)
a.toggle()
time.sleep_ms(500)
a.toggle()

Copy and paste the above code into the REPL to try it out.

For Your Information

The above example start with creating an object of class Pin, and it has the following format

Pin("pin_name"[required], direction[required], pull_mode[optional], initial_value[optional] )
#Thus the following are all valid
a = Pin("PB_7", Pin.OUT, Pin.PULL_DOWN, value = 1)
#or this
a = Pin("PA_1", Pin.OUT, Pin.PULL_UP, value = 0)
#or this
a = Pin("PB_13", Pin.IN)
#or this
a = Pin("PA_10", Pin.OUT) # by default, pull_mode = PULL_NONE, value = 0

Use help(Pin) to learn more about CONSTANT and API available under this class.

PS: type the object name you just created to check its configurations, for example

>>> a = Pin("PA_26", Pin.OUT,Pin.PULL_UP, value =1)
>>> a
Pin('PA_26', mode=Pin.OUT, pull=Pin.PULL_UP) # this line is returned by MicroPython

PWM

To use PWM (Pulse Width Modulation), import PWM module through machine. Here pin PA_26 is used as an example to make an LED to slowly brighten up

from machine import Pin, PWM
import time
p = PWM(pin = "PA_26")
# 0 duty cycle thus output 0
p.write(0.0)
# 10% duty cycle
p.write(0.1)
# 50% duty cycle
p.write(0.5)
# 100% duty cycle
p.write(1.0)

Copy and execute each line one by one to see LED gradually bright up

For Your Information

The above example start with creating an object of class PWM, and it has the following format

PWM( unit_id[optional], pin_name[required])

Use help(PWM) to view more information about this class

Note: PWM is only supported on the following pins, PA_23, PA_24, PA_25, PA_26

ADC

To use ADC (Analog to Digital Convertor), import ADC module through machine. Here we connect pin PB_4 to a Potentiometer to read its analogue value

from machine import ADC
a = ADC(0)
a.read()

For Your Information

The above example start with creating an object of class ADC, and it has the following format

ADC( unit_id[required])

Use help(ADC) to view more information about this class

Note: There are only 7 units of ADC pins, they are |unit | Pin
|:—-|:—–: | 0 | PB_4 | 1 | PB_5 | 2 | PB_6 | 3 | PB_7 | 4 | PB_1 | 5 | PB_2 | 6 | PB_3

Delay and Timing

Use the time module to take advantage of time and delays

import time
time.sleep(1)           # sleep for 1 second
time.sleep_ms(500)      # sleep for 500 milliseconds
time.sleep_us(10)       # sleep for 10 microseconds
start = time.ticks_ms() # get millisecond counter

Use help(time) to view more information about this class

Timer

Use the Timer module through machine module

There are 3 sets of 32KHz General Timers available to user, Timer 1/2/3

from machine import Timer
t = Timer(1)  # Use Timer 1/2/3 only
t.start(2000000, t.PERIODICAL)  # Set GTimer fired periodically at duration of 2 seconds, printing text on the terminal

# To stop the periodical timer, type 
t.stop()

For Your Information

The above example start with creating an object of class Timer, and it has the following format

Timer( unit_id[optinal] )
# if leave unit_id blank, it will take default value 1, meaning unit 1

Use help(Timer) to view more information about this class

Note: There are only 3 units of general timer, they are | unit | Timer | Freq |:—–|:——-:|:——-: | 1 | TIMER1 | 32 KHz | 2 | TIMER2 | 32KHz | 3 | TIMER3 | 32KHz

RTC

Use the RTC (Real Time Clock) module through machine module

from machine import RTC
rtc = RTC()
rtc.datetime() # get date and time 
rtc.datetime((2020, 12, 31, 4, 23, 58, 59, 0)) # set a specific date and time (year, month, day, weekday(0 for Monday), hour, minute, second, total seconds)
rtc.datetime() # check the updated date and time

Use help(RTC) to view more information about this class

UART

Use the UART module through machine module

from machine import UART
uart = UART(tx="PA_21", rx= "PA_22")
uart.init()
uart.write('hello')
uart.read(5) # read up to 5 bytes

For Your Information

The above example start with creating an object of class UART, and it has the following format

UART( unit_id[optional], baudrate[optional], databits[optional], stopbit[optional], paritybit[optional], timeout[optional], tx_pin[required], rx_pin[required])

PS: Leaving all parameters except tx and rx blank will set the uart to default values which are

Parameter Default value
unit_id 0
baudrate 115200
databits 8
stopbit 1
paritybit 0
timeout 10 ms

Note: There are currently 2 sets of uart, they are | unit | TX | RX |:—–|:——:|:——-: | 0 | PA_21 | PA_22 | 3 | PA_26 | PA_25

Use help(UART) to view more information about this class

I2C

Use the I2C (Inter-Integrated Circuit) module through machine module

Note: I2C only works in master mode.

from machine import Pin, I2C
i2c = I2C(scl = "PA_25", sda = "PA_26", freq=100000) # configure I2C with pins and freq. of 100KHz
i2c.scan()
i2c.writeto(8, 123) # send 1 byte to slave with address 8
i2c.readfrom(8, 6) # receive 6 bytes from slave

For Your Information

The above example start with creating an object of class I2C, and it has the following format

I2C( unit_id[optional], sda_pin[required], scl_pin[required], frequency[optional])

PS: Leaving optional parameters blank will will assume taking default values which are

Parameter Default value
unit_id 0
frequency 100000 Hz

There is currently 1 set of I2C, it is | unit | sda | scl |:—–|:——:|:——: | 0 | PA_26 | PA_25

Use help(I2C) to view more information about this class

SPI

Use the SPI (Serial Peripheral Interface) module through machine module

from machine import SPI
spi = SPI(0)		  # Only support 2 sets of SPI -- 0 and 1 
spi 				      # type instance name to check for details of the SPI set 
spi.write(123)		# Write number 123 
spi.read()

For Your Information

The above example start with creating an object of class SPI, and it has the following format

SPI( unit_id[required], baudrate[optional], polarity[optional], phase[optional], databits[optional], firstbit[optional], miso[optional], mosi[optional], sck[optional], mode[optional])

PS: Leaving optional parameters blank will assume taking default values which are

Parameter Default value
baudrate 2000000 Hz
polarity inactive_low
phase toggle_middle
databits 8
firstbit MSB
miso N.A.
mosi N.A.
sck N.A.
mode Master

There is currently 2 set of SPI, they are, | unit | mosi | miso | SCK | CS |:—–|:——:|:——-:|:—–:|:—–: | 0 | PB_18 | PB_19 | PB_20 | PB_21 | 1 | PB_4 | PB_5 | PB_6 | PB_7

Note: both unit support master mode, but only unit 0 support slave mode

Use help(SPI) to view more information about this class

5. Netoworking

RTL8722 MicroPython port support WiFi connection through WLAN module.

WiFi

Ameba RTL8722 support dual-band WiFi , namely 2.4GHz and 5GHz, giving itself versatility as well as speed in transmitting data wirelessly.

To use WiFi module, we have to import it from the wireless module, and create an object as follows,

from wireless import WLAN
wifi = WLAN(mode = WLAN.STA) # STA means Station Mode

For Your Information

The above code creates an object of class WLAN, and it has the following format

WLAN( mode[required]) 

Connect to WiFi with WPA2 security type

WPA2 is the most common security type, if not sure what security type your WiFi router is configured as, use this one

from wireless import WLAN
wifi = WLAN(mode = WLAN.STA)
wifi.connect(ssid = "MPSSID", pswd = "upyameba")

For Your Information

connect() API has the following format,

connect( ssid[required], pswd[optional], security[optional])

PS: Leaving optional parameters blank will will assume taking default values which are

Parameter Default value
pswd NULL
security WPA2_AES_PSK

Note: Connecting to an OPEN network is also supported, just omit ‘pswd’ parameter and type in “security = WLAN.OPEN”

Scan network

scanning nearby available networks can be done with script below

from wireless import WLAN
wifi = WLAN(mode = WLAN.STA)
wifi.scan()

Access Point (AP) mode

Set up Ameba as an access point is supported too, follow example below to start your own AP Note: MCU will stay in AP mode to service connections thus will not return to REPL

from wireless import WLAN
wifi = WLAN(mode = WLAN.AP)
wifi.start_ap(ssid = "MPSSID", pswd = "upyameba")

Socket

After WiFi is set up, the best way to access the network is to use socket. Socket is like an imaginary ethernet socket by which you use to connect your PC to some server on the internet like Google or Github. Application layer protocol like HTTP and etc. are built on top of socket. Once you are given an IP address and a port number, you can start to connect to the remote device and talk to it.

import socket to use socket module

Client Socket

import socket
from wireless import WLAN
# first connect to WiFi
wifi = WLAN(mode = WLAN.STA)
wifi.connect(ssid = "MPSSID", pswd = "upyameba") # change the ssid and pswd to yours
# second start a socket object
s = socket.SOCK()
# third connect the client to server
s.connect("www.google.com", 80) # domain google (must be in string), port 80 (integer)

For Your Information

The above example start with creating an object of class SOCK, and it has the following format

socket.SOCK( domain[optional], type[optional] )

PS: Leaving optional parameters blank will will assume taking default values which are

Parameter Default value
domain AF_INET(IPv4)
type SOCK_STREAM(TCP)

Use help(socket) and help(socket.SOCK) to view more information about this class

Server Socket

import socket
from wireless import WLAN
# first connect to WiFi
wifi = WLAN(mode = WLAN.STA)
wifi.connect(ssid = "MPSSID", pswd = "upyameba") # change the ssid and pswd to yours
# second start a socket object
s = socket.SOCK()
# third connect the client to server
port = 5000
s.bind(port) # bind the server to localhost with port 5000 (integer)
s.listen()
conn, addr = s.accept()

Echo Server and Client example

Here is an example of letting a server socket and a client socket to echo each other’s msg, to use this example, you need 2 devices, one of them is ameba RTL8722, the other can be a PC or another wifi board that runs MicroPython.

Server Code
import socket
from wireless import WLAN
wifi = WLAN(mode = WLAN.STA)
wifi.connect(ssid = "MPSSID", pswd = "upyameba") # change the ssid and pswd to yours
s = socket.SOCK()
port = 5000
s.bind(port) 
s.listen()
conn, addr = s.accept()
while True:
data = conn.recv(1024)
conn.send(data+"from server")
Client Code
import socket
from wireless import WLAN
wifi = WLAN(mode = WLAN.STA)
wifi.connect(ssid = "MPSSID", pswd = "upyameba") # change the ssid and pswd to yours
c = socket.SOCK()
# make sure to check the server IP address and update in the next line of code
c.connect("your server IP address", 5000) 
c.send("hello world")
data = c.recv(1024)
print(data)

HTTP Website example

With socket created, we can visit an HTTP website and get whatever information from it

Get information from HTTP website
# use Ctrl+E to enter Paste mode, then copy and paste the following code in Paste mode
import socket
from wireless import WLAN
wifi = WLAN(mode = WLAN.STA)
wifi.connect(ssid = "MPSSID", pswd = "upyameba") # change the ssid and pswd to yours

def http_get(url):
	_, _, host, path = url.split('/', 3)
	c = socket.SOCK()
	# We are visiting MicroPython official website's test page
	c.connect(host, 80) 
	c.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8'))
	while True:
		data = c.recv(100)
		if data:
			print(str(data,'utf8'), end='')
		else:
			break

http_get('http://micropython.org/ks/test.html')

6.SD Card File System

SD File System is supported on MicroPython RTL8722 port through importing the sdfs module. This module is a simplified file system with the aim to highlight SD card manipulation, thus it doesn’t support virtual file system as well as virtual file object.

Note: No hardware connection is needed for RTL8722DM_mini dev. board as it comes with SD Card slot on the back of the development board, and hardware connection has been pre-configured.

Simply import sdfs to use all available APIs

SD Card File System Examples

Use API provided to freely navigate through the SD card and read/write files as you see fit

Listing and navigating through the file system

import sdfs

s=sdfs            # create a short form
s.listdir()       # listing the files and folders under current path
s.mkdir("test")   # create a folder named "test" under current path
s.chdir("test")   # change directory to test folder
s.pwd()           # print out present working directory(current path)
s.chdir("/")      # change directory bach to root directory
s.rm("test")      # delete the test folder

File Manipulation

import sdfs

s=sdfs                  # create a short form
s.create("ameba.txt")   # create a file named "ameba.txt"
s.write("ameba.txt", "ameba supports sd card file system!") # write a string to the file just created
s.read("ameba.txt")     # read the content from the same file
s.rm("ameba.txt")       # delete the file

Note: No file open or close is needed, the API does that automatically for you.