MicroPython documentation and references¶
Python API for Codey Rocky¶
This article includes the following python API for Codey Rocky:
- Python API for Codey:refers to some API for Codey Rocky’s onboard driver.
- Python API for Rocky:API on Codey which used for control the Rocky to move or to receive dates send from sensors on Rocky.
- Python API for third-party libraries:some build-in interface for third-party libraries of Codey Rocky, such as mqtt or urequest.
- Python API for extension Neuron modules:API which may used when add Neuron modules to Codey Rocky.
Python API for Codey¶
Python API for Codey includes the following reference tables:
Python API list for Codey¶
led
— Onboard RGB LED¶
The main functionality and function of the led
module
Function¶
-
led.
show
(r, g, b)¶ Set the displayed color of the RGB LED, parameters:
- r refers to the value of red component, parameter range is
0 ~ 255
,0 with no red component and 255 the highest red component. - g refers to the value of green component, parameter range is
0 ~ 255
,0 with no green component and 255 the highest green component. - b refers to the value of blue component, parameter range is
0 ~ 255
,0 with no blue component and 255 the highest blue component.
- r refers to the value of red component, parameter range is
-
led.
set_red
(val)¶ Set the red color value of the RGB LED, parameters:
- val refers to the value of red component, parameter range is
0 ~ 255
,0 with no red component and 255 the highest red component.
- val refers to the value of red component, parameter range is
-
led.
set_green
(val)¶ Set the green color value of the RGB LED, parameters:
- val refers to the value of green component, parameter range is
0 ~ 255
,0 with no green component and 255 the highest green component.
- val refers to the value of green component, parameter range is
-
led.
set_blue
(val)¶ Set the blue color value of the RGB LED, parameters:
- val refers to the value of blue component, parameter range is
0 ~ 255
,0 with no blue component and 255 the highest blue component.
- val refers to the value of blue component, parameter range is
-
led.
off
()¶ Turn off the RGB LED
Sample Code:¶
import codey
import time
codey.led.show(255,255,255)
time.sleep(2)
codey.led.off()
time.sleep(2)
while True:
codey.led.set_red(255)
time.sleep(1)
codey.led.set_green(255)
time.sleep(1)
codey.led.set_blue(255)
time.sleep(1)
codey.led.off()
time.sleep(1)
display
— Face Panel¶
The main functionality and function of the display
module
Face Panel Explanation¶

As shown in the figure above, the face panel has the upper left corner as the coordinate 0 point, and the direction of x and y is indicated by the arrow. About parameters displayed, take above figure as an example. The upper three of the first column data are lit and the data is converted to 11100000
, that is, hexadecimal 0xe0.The second column verse is converted to 00001101
, that is, In hexadecimal 0x0d. All the lattices in the above figure are converted to e00d0000000000000000000000000000
.
Function¶
-
display.
show_image
(image, pos_x = 0, pos_y = 0, time_s = None)¶ Display custom dot matrix graphics as image parameters, parameters:
- image string data, each column of the dot matrix has 8 display points, which is 1 byte of data, converted to a hexadecimal string. Therefore, 16 columns of lattices need to be represented by 32 string data.
- pos_x displays the offset of the x-axis of the graph on the panel. The parameter range is
-15 ~ 15
, It starts from the 0 position as default if this parameter is not set. - pos_y displays the offset of the graph on the y-axis of the panel. The parameter range is
-7 ~ 7
, It starts from the 0 position as default if this parameter is not set. - time_s displays the time in seconds (in seconds). If this parameter is not set, the display remains unchanged until there is a clear screen or resetting the panel operation.
-
display.
show
(var, pos_x = 0, pos_y = 0, wait = True)¶ Display data in full-type data parameters, parameters:
- var full type, where the display of numeric and time types is treated specially, and the time format display needs to satisfy:
[x]x:[x]x
format (regular expressiond?d:dd?
) - pos_x displays the offset of the data on the x-axis of the panel. The parameter range is
-15 ~ 15
. It starts from the 0 position as default if this parameter is not set. - pos_y displays the offset of the data on the y-axis of the panel. The parameter range is
-7 ~ 7
. It starts from the 0 position as default if this parameter is not set. - wait sets whether to block the display, where
True
: means blocking until the display is complete,False
: means display but not blocking.
- var full type, where the display of numeric and time types is treated specially, and the time format display needs to satisfy:
-
display.
set_pixel
(pos_x, pos_y, status)¶ Set the brightness and deactivation status of a single pixel of the panel, Parameters:
- pos_x The coordinates of the x-axis for the pixel on the panel. The parameter range is
0 ~ 15
. - pos_y The coordinates of the y-axis for the pixel on the panel. The parameter range is
0 ~ 7
. - status Boolean value,where
True
indicates that the pixel is lit, andFalse
: indicates that the pixel is off.
- pos_x The coordinates of the x-axis for the pixel on the panel. The parameter range is
-
display.
get_pixel
(pos_x, pos_y)¶ Get the current on and off states of a single pixel on the panel. The return value is a Boolean value, where
True
: indicates that the pixel is lit, andFalse
: indicates that the pixel is off, parameter:- pos_x The coordinates of the x-axis for the pixel on the panel. The parameter range is
0 ~ 15
. - pos_y The coordinates of the y-axis for the pixel on the panel. The parameter range is
0 ~ 7
.
- pos_x The coordinates of the x-axis for the pixel on the panel. The parameter range is
-
display.
toggle_pixel
(pos_x, pos_y)¶ Toggle the current on and off states of a single pixel on the panel, parameter:
- pos_x The coordinates of the x-axis for the pixel on the panel. The parameter range is
0 ~ 15
. - pos_y The coordinates of the y-axis for the pixel on the panel. The parameter range is
0 ~ 7
.
- pos_x The coordinates of the x-axis for the pixel on the panel. The parameter range is
-
display.
clear
()¶ Turn off all the LED lights on the display.
Sample Code:¶
import codey
import time
codey.display.show("ffffff")
codey.display.show("123")
time.sleep(1)
codey.display.show("12345", 3, 1)
codey.display.set_pixel(1, 1, True)
image = "ffffffffff000000000000000000000000"
codey.display.show_image(image, pos_x = 3, pos_y = 4)
time.sleep(1)
codey.display.clear()
print("[1, 1]:", codey.display.get_pixel(1, 1))
codey.display.show("12:28")
while True:
codey.display.toggle_pixel(7, 2)
codey.display.toggle_pixel(7, 4)
time.sleep(1)
speaker
— Onboard Speaker¶
The main functionality and function of the speaker
module
Function¶
-
speaker.
stop_sounds
()¶ Stop all sounds.
-
speaker.
play_melody
(file_name)¶ Playing an audio file, the function will not block when playing, but if it is called continuously, the next playback will stop the previous playback, Parameters:
- file_name String type, the audio file name of the wav format burned in Codey Rocky flash. When inputting, the format suffix
.wav
can also be omitted
The optional sound file has- file_name String type, the audio file name of the wav format burned in Codey Rocky flash. When inputting, the format suffix
hello.wav : hello
hi.wav : hi
bye.wav : bye
yeah.wav : yeah
wow.wav : wow
laugh.wav : laugh
hum.wav : hum
sad.wav : sad
sigh.wav : sigh
annoyed.wav : annoyed
angry.wav : angry
surprised.wav : scared
yummy.wav : pettish
curious.wav : curious
embarrassed.wav : embarrassed
ready.wav : ready
sprint.wav : sprint
sleepy.wav : snore
meow.wav : meow
start.wav : start
switch.wav : switch
beeps.wav : beeps
buzzing.wav : buzz
exhaust.wav : air-out
explosion.wav : explosion
gotcha.wav : gotcha
hurt.wav : painful
jump.wav : jump
laser.wav : laser
level up.wav : level-up
low energy.wav : low-energy
metal clash.wav : metal-clash
prompt tone.wav : prompt-tone
right.wav : right
wrong.wav : wrong
ring.wav : ringtone
score.wav : score
shot.wav : shot
step_1.wav : step_1
step_2.wav : step_2
wake.wav : activate
warning.wav : warning
-
speaker.
play_melody_until_done
(file_name)¶ The audio file is played until it stops, and the function blocks playback, that is, the next instruction cannot be executed until the sound is played, parameter:
- file_name String type, the audio file name of the wav format burned in Codey Rocky flash. When inputting, the format name
.wav
can also be omitted. For specific optional parameters, seeplay_melody
.
- file_name String type, the audio file name of the wav format burned in Codey Rocky flash. When inputting, the format name
-
speaker.
play_note
(note_num, beat = None)¶ Play note, digital note definitions please refer to: scratch digital note description, prameters:
- note_num numeric value, range of values
48 - 72
, or string type, such asC4
. - beat value data, indicates the number of beats, the default value is always playing.
notes and frequency is as follows:
['C2','65'], ['D2','73'], ['E2','82'], ['F2','87'], ['G2','98'], ['A2','110'], ['B2','123'], ['C3','131'], ['D3','147'], ['E3','165'], ['F3','175'], ['G3','196'], ['A3','220'], ['B3','247'], ['C4','262'], ['D4','294'], ['E4','330'], ['F4','349'], ['G4','392'], ['A4','440'], ['B4','494'], ['C5','523'], ['D5','587'], ['E5','659'], ['F5','698'], ['G5','784'], ['A5','880'], ['B5','988'], ['C6','1047'], ['D6','1175'], ['E6','1319'], ['F6','1397'], ['G6','1568'], ['A6','1760'], ['B6','1976'], ['C7','2093'], ['D7','2349'], ['E7','2637'], ['F7','2794'], ['G7','3136'], ['A7','3520'], ['B7','3951'], ['C8','4186'], ['D8','4699'],
- note_num numeric value, range of values
-
speaker.
play_tone
(frequency, time = None)¶ Play the setting frequency sound, parameters:
- frequency Numerical data, the frequency of sound which is played, and its value range is
0 ~ 5000
. - time Numerical data, indicating the playback time (in
milliseconds - ms
) and its value range is0 ~ the value range limit
.
- frequency Numerical data, the frequency of sound which is played, and its value range is
-
speaker.
rest
(number)¶ Stop the beat, parameters:
- number Numerical data, the number of paused beats, its value range is
0 ~ the value range limit
.
- number Numerical data, the number of paused beats, its value range is
Constant¶
-
speaker.
volume
¶ Numerical data, the property value of the volume, you can modify or read this value. Modify this value to control the volume. Its value range is
0 ~ 100
.
-
speaker.
tempo
¶ Numerical data, indicating the nature of the playback speed, in
bmp
(beat per minute), which is the length of each beat.Its value range is6 ~ 600
. The default value is 60, which means that the duration of one beat is 1 second. The beats of therest
andplay_note
functions are affected by this constant.
Sample Code:¶
import codey
import time
codey.speaker.play_melody("hello", True)
codey.display.show("hello")
codey.display.clear()
codey.speaker.play_note(48, 1)
codey.speaker.rest(1)
codey.display.show("note")
codey.display.clear()
codey.speaker.play_note("C4", 1)
codey.speaker.rest(1)
codey.display.show("C4")
codey.display.clear()
codey.speaker.play_tone(1000, 2)
codey.speaker.rest(1)
codey.display.show("tone")
codey.display.clear()
print("tempo:", end = "")
print(codey.speaker.tempo)
codey.speaker.play_note("C4", 1)
codey.speaker.rest(1)
codey.speaker.tempo = 120
codey.speaker.volume = 20
codey.speaker.play_note("C4", 1)
codey.speaker.rest(1)
sound_sensor
— Onboard Sound Sensor¶
The main functionality and function of the sound_sensor
module
Function¶
-
sound_sensor.
get_loudness
()¶ Get the sound intensity detected by the sound sensor, and the return value is the volume. The value range is
0 ~ 100
.
Sample Code:¶
import codey
while True:
codey.display.show(codey.sound_sensor.get_loudness())
light_sensor
— Onboard Light Sensor¶
The main functionality and function of the light_sensor
module
Function¶
-
light_sensor.
get_value
()¶ Get the light intensity detected by the light sensor, and the return value is the intensity value of visible light. The value range is
0 ~ 100
.
Sample Code:¶
import codey
while True:
codey.display.show(codey.light_sensor.get_value())
potentiometer
— Onboard Potentiometer¶
The main functionality and function of the potentiometer
module
Function¶
-
potentiometer.
get_value
()¶ Get the current value of the potentiometer knob. The value range is
0 ~ 100
.
Sample Code:¶
import codey
while True:
codey.display.show(codey.potentiometer.get_value())
button_a
— Onboard Button A¶
The main functionality and function of the button_a
module
Function¶
Get the current state of button A. The result returned is
True
: the button is pressed, or theFalse
: button is not pressed.
Sample Code:¶
import codey
def loop():
while True:
if codey.button_a.is_pressed():
print("button A is pressed")
loop()
button_b
— Onboard Button B¶
The main functionality and function of the button_b
module
Function¶
Get the current state of button B. The result returned is
True
: the button is pressed, or theFalse
: button is not pressed.
Sample Code:¶
import codey
def loop():
while True:
if codey.button_b.is_pressed():
print("button B is pressed")
loop()
button_c
— Onboard Button C¶
The main functionality and function of the button_c
module
Function¶
Get the current state of button C. The result returned is
True
: the button is pressed, or theFalse
: button is not pressed.
Sample Code:¶
import codey
def loop():
while True:
if codey.button_c.is_pressed():
print("button C is pressed")
loop()
motion_sensor
— Onboard Motion Sensor¶
The main functionality and function of the motion_sensor
module
Motion sensor description¶

As shown in the picture above, the direction of the roll and pitch are based on the right-handed screw rule.
Both roll and pitch are 0°
when the Codey is horizontally placed.
Roll range: -90° ~ 90°
Pitch range: -180 ° ~ 180 °
Function¶
-
motion_sensor.
get_roll
()¶ Get the roll of the Euler angle, the returned data range is
-90 ~ 90
.
-
motion_sensor.
get_pitch
()¶ Get the pitch of the Euler angle, the returned data range is
-180 ~ 180
.
-
motion_sensor.
get_yaw
()¶ Get the yaw of the Euler angle, The returned data range is
0 ~ 360
. Since the Codey onboard sensor is a six-axis sensor, there is no electronic compass. So in fact the yaw angle is just the integral of the Z-axis angular velocity. It has accumulated errors. If you want to get a true yaw angle, this API is not suitable for use.
-
motion_sensor.
get_rotation
(axis)¶ Get the angle at which the Codey rotates on the three axes, and the counterclockwise direction is the positive direction, parameter:
- axis String type, with
x
,y
,z
representing the axis defined by Codey.
- axis String type, with
-
motion_sensor.
reset_rotation
(axis = "all")¶ The current angle of initial rotation around the three axes is 0, and the
get_rotation()
will start at 0, parameter:- axis string type, with
x
,y
,z
representing the axis defined by Codey, andall
representing all three axes. This is also the default value for this function.
- axis string type, with
-
motion_sensor.
is_shaked
()¶ Check if the Codey is shaken, the return value is a Boolean value, where
True
means that Codey is shaken, andFalse
means that Codey is not shaken.
-
motion_sensor.
get_shake_strength
()¶ If the Codey is shaken, this function can obtain the intensity of the shaking. The value of the return value range is
0 ~ 100
. The larger the value, the greater the intensity of the shaking.
-
motion_sensor.
is_tilted_left
()¶ Check if Codey is tilted to the left, and the return value is a Boolean value, where
True
means that Codey is tilted to the left, andFalse
means that Codey is not tilted to the left.
-
motion_sensor.
is_tilted_right
()¶ Check if Codey is tilted to the right, and the return value is a Boolean value, where
True
means that Codey is tilted to the right, andFalse
means that Codey is not tilted to the right.
-
motion_sensor.
is_ears_up
()¶ Check if the ear of Codey is up, the return value is a Boolean value, where
True
means that the ear of Codey is facing up, andFalse
means that the ear of Codey is not facing up.
-
motion_sensor.
is_ears_down
()¶ Check if the ear of Codey is down, the return value is a Boolean value, where
True
means that the ear of Codey is facing down, andFalse
means that the ear of Codey is not facing down.
-
motion_sensor.
is_display_up
()¶ Check if the face panel of Codey is up, the return value is a Boolean value, where
True
means that the panel of Codey is facing up, andFalse
means that the panel of Codey is not facing up.
-
motion_sensor.
is_display_down
()¶ Check if the face panel of Codey is down, the return value is a Boolean value, where
True
means that the panel of Codey is facing down, andFalse
means that the panel of Codey is not facing down.
-
motion_sensor.
is_upright
()¶ Check if Codey is upright, the return value is a Boolean value, where
True
means that Codey is upright, andFalse
means that Codey is not upright.
-
motion_sensor.
get_acceleration
(axis)¶ Get the acceleration values of the three axes in
m/s^2
, Parameters:- axis String type, with
x
,y
,z
representing the axis defined by Codey.
- axis String type, with
-
motion_sensor.
get_gyroscope
(axis)¶ Get the angular velocity values of the three axes in
°/sec
, Parameters:- axis String type, with
x
,y
,z
representing the axis defined by Codey。
- axis String type, with
Sample Code 1:¶
import codey
import time
while True:
roll = codey.motion_sensor.get_roll()
pitch = codey.motion_sensor.get_pitch()
yaw = codey.motion_sensor.get_yaw()
print("roll:", end = "")
print(roll, end = "")
print(" ,pitch:", end = "")
print(pitch, end = "")
print(" ,yaw:", end = "")
print(yaw)
time.sleep(0.05)
Sample Code 2:¶
import codey
while True:
if codey.motion_sensor.is_shaked():
print("shake_strength:", end = "")
print(codey.motion_sensor.get_shake_strength())
Sample Code 3:¶
import codey
while True:
if codey.motion_sensor.is_tilted_left():
print("tilted_left")
if codey.motion_sensor.is_tilted_right():
print("tilted_right")
if codey.motion_sensor.is_ears_up():
print("ears_up")
if codey.motion_sensor.is_ears_down():
print("ears_down")
if codey.motion_sensor.is_display_up():
print("display_up")
if codey.motion_sensor.is_display_down():
print("display_down")
if codey.motion_sensor.is_upright():
print("upright")
ir
— Onboard Infrared Transceiver¶
The main functionality and function of the ir
module
Function¶
-
ir.
receive
()¶ Returns the string information received by the infrared receiver, so the data sent by the infrared sender must end with
\n
. If it is a remote control command that receives the NEC encoding protocol, use another functionreceive_remote_code()
.
-
ir.
receive_remote_code
()¶ Get the date from infrared remote controller. The data contains two parts: address and content, so it returns a list data which length 2. The first parameter is the address code, and the latter parameter is the data code.
-
ir.
send
(str)¶ Send infrared string, parameters:
- str The string data to be emitted, the function
send
will add the\n
terminator at the end of the string automatically.
- str The string data to be emitted, the function
-
ir.
start_learning
()¶ Start infrared learning and only support remote control commands that learn the standard NEC protocol.
-
ir.
stop_learning
()¶ Stop infrared learning.
-
ir.
save_learned_result
(index)¶ Save the learned infrared coding result to the corresponding area, parameters:
- index the value range is
0 ~ 15
, a total of 16 storage areas.
- index the value range is
-
ir.
send_learned_result
(index = 1)¶ Send infrared learning saved infrared code, the learning result of the area with index = 1 is set as default, parameters:
- index The index value range is
0 ~ 15
, a total of 16 storage areas.
- index The index value range is
-
ir.
learn
(time = 3)¶ Infrared learning
time
seconds, after calling this API will save the infrared information learned intime
seconds. Default saved to the area with index = 1, parameter:- time learning time, in
seconds
.
- time learning time, in
Sample Code 1:¶
import codey
import event
@event.start
def start_cb():
print("start event succeeded")
while True:
codey.display.show(codey.ir.receive_remote_code()[1])
Sample Code 2:¶
import codey
import event
@event.button_a_pressed
def button_a_cb():
print("button a event succeeded")
codey.ir.learn()
codey.led.show(0, 100, 0)
@event.button_b_pressed
def button_a_cb():
print("button b event succeeded")
while True:
codey.ir.send_learned_result()
@event.button_c_pressed
def button_c_cb():
print("button b event succeeded")
while True:
codey.display.show(codey.ir.receive())
wifi
— Onboard Wifi¶
The main functionality and function of the wifi
module
Function¶
-
wifi.
start
(ssid = "wifi_ssid", password = "password", mode = codey.wifi.STA)¶ - Start wifi connection, the API will not block process, API exit does not mean that wifi is connected, you need to call
wifi.is_connected()
to judge, Parameter:- ssid string type, wifi account.
- password string type, wifi password.
- mode starts the wifi mode.
-
wifi.
is_connected
()¶ Check if wifi is connected, the return value is Boolean, where
True
means that wifi has established a connection,False
means that wifi has not yet established a connection.
Constant¶
-
wifi.
STA
¶ The wifi station mode, that is, the wireless adapter mode. In this mode, wifi can be connected to the router.
-
wifi.
AP
¶ Wireless access point mode, the general wireless routing / bridge works in this mode. In this mode, it allows other wireless devices to access.
-
wifi.
APSTA
¶ The wifi AP and STA modes coexist.
Sample Code:¶
import codey
codey.wifi.start('makeblock', 'password', codey.wifi.STA)
codey.led.show(0,0,0)
while True:
if codey.wifi.is_connected():
codey.led.show(0,0,255)
else:
codey.led.show(0,0,0)
battery
— Built-in Lithium Battery¶
The main functionality and function of the battery
module
Function¶
-
battery.
get_voltage
()¶ Get the current battery voltage, the return value is a floating point data. The unit is
V
.
-
battery.
get_percentage
()¶ Get the percentage of remaining battery power. The return value is an integer. The data range is
0 ~ 100
, where 100 means there is still 100% of the remaining battery.
Sample Code:¶
import codey
while True:
print("vol" + str(codey.battery.get_voltage()))
print("percentage" + str(codey.battery.get_percentage()))
codey_timer
— Counter¶
The main functionality and function of the codey_timer
module (you do not need to bring the module name when using due to it is a system function)
Function¶
-
codey.
get_timer
()¶ Gets the current value of the timer (the timer runs from the time the user script starts), the return value is a floating point data. The unit is
seconds
.
-
codey.
reset_timer
()¶ Initialize the value of the timer.
程序示例:¶
import codey
codey.reset_timer()
while True:
print("time:", end = "")
print(codey.get_timer())
codey_broadcast
— Broadcast Module¶
The main functionality and function of the codey_broadcast
module (you do not need to bring the module name when using due to it is a system function)
Function¶
-
codey.
broadcast
(str)¶ A broadcast can be sent to the serial port, Bluetooth, and its own event monitoring unit, Parameter:
- str The content of the broadcast.
Sample Code:¶
import codey
import event
@event.button_a_pressed
def button_a_cb():
print("button a event succeeded")
codey.broadcast("hello")
@event.received("hello")
def received_cb():
print("received message: hello")
codey_external_module_detect
— External Module access Detection¶
The main functionality and function of the codey_external_module_detect
module (you do not need to bring the module name when using due to it is a system function)
Function¶
-
codey.
has_neuron_connected
()¶ Check whether there is any neuron module connected to Codey, and the return value is a Boolean value, where
True
indicates that the neuron module is connected to Codey (including the connecting of the Rocky), andFalse
indicates that there is no neuron module connected to the Codey.
-
codey.
is_rocky_connected
()¶ Check if the Rocky is connected to the Codey, the return value is a Boolean value, where
True
means that there is a Rocky connected to the Codey, andFalse
means no Rocky connected to Codey.
Sample Code:¶
import codey
import time
while True:
if codey.is_rocky_connected():
print("rocky is in")
else:
print("rocky is out")
time.sleep(1)
codey_script_control
— Script/thread Control¶
The main functionality and function of the codey_script_control
module (you do not need to bring the module name when using due to it is a system function)
Function¶
-
codey.
stop_this_script
()¶ Stop the current script, consistent with the scratch stop script feature.
-
codey.
stop_other_scripts
()¶ Stop other scripts, consistent with the scratch stop other scripts feature.
-
codey.
stop_this_script
() Stop all scripts, consistent with the scratch stop all scripts.
Sample Code:¶
import codey
import time
import event
@event.start
def start_cb():
while True:
print("start cb executing...")
time.sleep(1)
print("stop this script")
codey.stop_this_script()
@event.button_a_pressed
def button_a_cb():
codey.stop_other_scripts()
while True:
print("button a event")
@event.button_b_pressed
def button_b_cb():
codey.stop_other_scripts()
while True:
print("button b event")
@event.button_c_pressed
def button_c_cb():
codey.stop_all_scripts()
event
— Event Processing Unit¶
The main functionality and function of the event
module
Event processing unit instructions¶
The way user events are used currently supports two ways of writing. One is registration:
import codey
import time
import event
def start_cb():
while True:
codey.led.show(255, 0, 0)
time.sleep(1)
codey.led.show(0, 0, 0)
time.sleep(1)
event.start(start_cb)
The other is to use a decorator, such as:
import codey
import time
import event
@event.start
def start_callback():
while True:
codey.led.show(255, 0, 0)
time.sleep(1)
codey.led.show(0, 0, 0)
time.sleep(1)
Function¶
-
event.
start
(callback)¶ Startup event.
-
event.
shaked
(callback)¶ Codey was shaken event.
-
event.
received
(callback, msgstr)¶ Broadcast reception detection event. In addition to the callback parameter, the parameter:
- msgstr string type, the string to be matched. The event will be triggered when the received string matches the matching string.
Button A pressed event.
Button B pressed event.
Button C pressed event.
-
event.
tilted_left
(callback)¶ Codey left tilt event.
-
event.
tilted_right
(callback)¶ Codey right tilt event.
-
event.
ears_up
(callback)¶ Codey ear up event.
-
event.
ears_down
(callback)¶ Codey ear down event.
-
event.
ir_received
(callback, ir_str)¶ Infrared string reception detection event. In addition to the callback parameter, the parameter:
- ir_str string type, the string to be matched. The event will be triggered when the received string matches the matching string.
-
event.
greater_than
(callback, threshold, type_str)¶ The threshold comparison event, which will be triggered when the threshold is exceeded. In addition to the callback parameter, the parameter:
- threshold value data, set the threshold for triggering.
- type_str string data, currently only supports
sound_sensor
: volume sensor,timer
: timer.
-
event.
less_than
(callback, threshold, type_str)¶ Threshold comparison event, triggered below the threshold, in addition to the callback parameter, the parameter:
- threshold value data, set the threshold for triggering
- type_str string data, currently only supports
light_sensor
: light sensor.
Sample Code:¶
import codey
import event
@event.button_a_pressed
def button_a_cb():
print("button a event triggered")
@event.button_b_pressed
def button_b_cb():
print("button b event triggered")
@event.button_c_pressed
def button_c_cb():
print("button c event triggered")
@event.greater_than(20, "sound_sensor")
def sound_sensor_cb():
print("sound sensor greater event triggered")
@event.greater_than(5, "timer")
def timer_cb():
print("timer greater event triggered")
@event.less_than(30, "light_sensor")
def light_sensor_cb():
print("light sensor event triggered")
Python API for Rocky¶
Here is the python API for Rocky:
Python API list for Rocky¶
motion
— Rocky Chassis Movement¶
The main functionality and function of the motion
module (you do not need to bring the module name when using due to it is a system function)
Function¶
-
rocky.
stop
()¶ Rocky stops moving.
-
rocky.
forward
(speed, t = None, straight = False)¶ Rocky moves forward, parameters:
- speed The value of motion speed, parameter range is
-100 ~ 100
, negative numbers represent backwards, positive numbers represent forward. - t The value of the motion time, in
seconds
, the parameter range is0 ~ the value range limit
. If set to 1, it means the rocky will move forward for 1s. If this parameter is not set, the forward state is maintained until there is the motion stop command or new motion command. - straight Enable the gyro sensor to correct the forward direction or not. If this parameter is not set, it is not enabled by default.
- speed The value of motion speed, parameter range is
-
rocky.
backward
(speed, t = None, straight = False)¶ Rocky moves backward, parameters:
- speed The value of motion speed, parameter range is
-100 ~ 100
, negative numbers represent forward, positive numbers represent backward. - t The value of the motion time, in
seconds
, the parameter range is0 ~ the value range limit
. If set to 1, it means the rocky will move backward for 1s. If this parameter is not set, the backward state is maintained until there is the motion stop command or new motion command. - straight Enable the gyro sensor to correct the backward direction or not. If this parameter is not set, it is not enabled by default.
- speed The value of motion speed, parameter range is
-
rocky.
turn_left
(speed, t = None)¶ Rocky turns left, parameters:
- speed The value of turn speed, parameter range is
-100 ~ 100
, negative numbers represent turn right, positive numbers represent turn left. - t The value of the motion time, in
seconds
, the parameter range is0 ~ the value range limit
. If set to 1, it means the rocky will turn left for 1s. If this parameter is not set, the turn left state is maintained until there is the motion stop command or new motion command.
- speed The value of turn speed, parameter range is
-
rocky.
turn_right
(speed, t = None)¶ Rocky turns right, parameters:
- speed The value of turn speed, parameter range is
-100 ~ 100
, negative numbers represent turn left, positive numbers represent turn right. - t The value of the motion time, in seconds, the parameter range is
0 ~ the value range limit
. If set to 1, it means the rocky will turn right for 1s. If this parameter is not set, the turn right state is maintained until there is the motion stop command or new motion command.
- speed The value of turn speed, parameter range is
-
rocky.
drive
(left_power, right_power)¶ Rocky turns according to the set value for each motor, parameters:
- left_power Motor speed of left wheel, parameter range is
-100 ~ 100
, negative numbers represent the left wheel rotates backward, positive numbers represent the left wheel rotates forward. - right_power Motor speed of right wheel, parameter range is
-100 ~ 100
, negative numbers represent the right wheel rotates backward, positive numbers represent the right wheel rotates forward.
- left_power Motor speed of left wheel, parameter range is
-
rocky.
turn_right_by_degree
(angle, speed = 40)¶ Rocky turns right according to the set degree, parameters:
- angle Angle of rotation, negative numbers represent turn left, positive numbers represent turn right.
- speed Turning speed, parameter range is
0 ~ 100
, if this parameter is not set, the default speed is 40. (Since the gyro sensor is used for turning specific angle, it is recommended not to modify the speed to avoid the turning angle being inaccurate).
-
rocky.
turn_left_by_degree
(angle, speed = 40)¶ Rocky turns left according to the set degree, parameters:
- angle Angle of rotation, negative numbers represent turn right, positive numbers represent turn left.
- speed Turning speed, parameter range is
0 ~ 100
, if this parameter is not set, the default speed is 40. (Since the gyro sensor is used for turning specific angle, it is recommended not to modify the speed to avoid the turning angle being inaccurate).
Sample Code:¶
import codey
import rocky
import time
rocky.forward(50, 1)
rocky.stop()
rocky.backward(50, 1)
rocky.turn_left(50, 1)
rocky.turn_right(50, 1)
rocky.drive(50, 80)
time.sleep(2)
while True:
rocky.turn_right_by_degree(80, 40)
rocky.turn_right_by_degree(80, 20)
color_ir_sensor
— Color IR Sensor¶
The main functionality and function of the color_ir_sensor
module
Color infrared sensor description¶

As shown in the figure, the sensors in front of the rocky are
- White LED:light white to achieve detecting the visible light reflection intensity on the surface of the object with using visible light sensor.
- Visible Light Sensor:detect the visible light intensity.
- RGB LED:light LED with specific RGB value to achieve recognizing the color with using the visible light sensor.
- Infrared Light Sensor:detect the infrared light intensity
- Infrared Transmitter:transmit infrared light to achieve detecting the infrared light reflection intensity on the surface of the object with using the infrared light sensor.
Function¶
-
color_ir_sensor.
get_red
()¶ Get the size of the red color component of the color sensor, parameter range is
0 ~ 100
.
-
color_ir_sensor.
get_green
()¶ Get the size of the green color component of the color sensor, parameter range is
0 ~ 100
.
-
color_ir_sensor.
get_blue
()¶ Get the size of the blue color component of the color sensor, parameter range is
0 ~ 100
.
-
color_ir_sensor.
is_color
(color_str)¶ Judge whether a matching color is detected, parameters:
- color_str color type, including
red, green, blue, yellow, cyan, purple, white, black
, the corresponding parameter isred
,green
,blue
,yellow
,cyan
,purple
,white
,black
. Return value is boolean,Ture
represents color matching,False
represents the colors do not match.
- color_str color type, including
-
color_ir_sensor.
get_light_strength
()¶ Get the ambient light intensity detected by the visible light sensor, parameter range is
0 ~ 100
.
-
color_ir_sensor.
get_greyness
()¶ Get the grayscale value detected by the visible light sensor (using RGB LED and visible light sensor), parameter range is
0 ~ 100
.
-
color_ir_sensor.
get_reflected_light
()¶ Get the visible light reflection intensity detected by the visible light sensor, parameter range is
0 ~ 100
.
-
color_ir_sensor.
get_reflected_infrared
()¶ Get the infrared light reflection intensity detected by the infrared light receiving tube, parameter range is
0 ~ 100
.
-
color_ir_sensor.
is_obstacle_ahead
()¶ Detect if there are obstacles in front, the return value is boolean,
Ture
represents obstacles,False
represents no obstacles.
-
color_ir_sensor.
set_led_color
(color_name)¶ Set color for the RGB LED light of the color sensor, parameters:
- color_name including
red, green, blue, yellow, cyan, purple, white, black
, the corresponding parameter isred
,green
,blue
,yellow
,cyan
,purple
,white
,black
.
- color_name including
Sample Code:¶
import codey
import rocky
while True:
if rocky.color_ir_sensor.is_obstacle_ahead():
rocky.color_ir_sensor.set_led_color('white')
else:
rocky.color_ir_sensor.set_led_color('black')
Python API for third-party library¶
Here is the python API for third-party library:
Python API list for third party libraries¶
urequests
— Network Request Module¶
The main functionality and function of the urequests
module
Function¶
-
urequests.
request
(method, url, data=None, json=None, headers={})¶ Send a network request, it will block the response data returned to the network, parameters:
- method method of establishing a network request. e.g.
HEAD
,GET
,POST
,PUT
,PATCH
,DELETE
. - url URL of the network request.
- data (optional), a dictionary, tuple list [(key, value)] (will be form coded), byte or class file object sent in the request body.
- json (optional), json data sent in the request body.
- headers (optional), HTTP header dictionary to be sent with the request.
- method method of establishing a network request. e.g.
-
urequests.
head
(url, **kw)¶ Send a
HEAD
request, the return type is the response of the request, parameters:- url URL of the network request.
- **kw request optional parameters.
-
urequests.
get
(url, **kw)¶ Send a
GET
request, the return type is the response of the request, parameters:- url URL of the network request.
- **kw request optional parameters.
-
urequests.
post
(url, **kw)¶ Send a
POST
request, the return type is the response of the request, parameters:- url URL of the network request.
- **kw request optional parameters.
-
urequests.
put
(url, **kw)¶ Send a
PUT
request, the return type is the response of the request, parameters:- url URL of the network request.
- **kw request optional parameters.
Sample Code 1:¶
import codey
import urequests as requests
import time
# Fill in your router's ssid and password here.
codey.wifi.start('wifi_ssid', 'password')
codey.led.show(0,0,0)
while True:
if codey.wifi.is_connected():
codey.led.show(0,0,255)
res = requests.get(url='http://www.baidu.com/')
print(res.text)
time.sleep(3)
else:
codey.led.show(0,0,0)
Sample Code 2:¶
import codey
import urequests as requests
import time
# Fill in your router's ssid and password here.
codey.wifi.start('wifi_ssid', 'password')
codey.led.show(0,0,0)
hour = minite = second = "00"
while True:
if codey.wifi.is_connected():
try:
res = requests.get(url = 'http://www.time.ac.cn/timeflash.asp?user=flash').text
hour_begin = res.find('<hour>') + len('<hour>')
hour_end = res.find('</hour>')
minite_begin = res.find('<minite>') + len('<minite>')
minite_end = res.find('</minite>')
second_begin = res.find('<second>') + len('<second>')
second_end = res.find('</second>')
if hour_begin > len('<hour>') and hour_end > hour_begin and \
minite_begin > len('<minite>') and minite_end > minite_begin and \
second_begin > len('<second>') and second_end > second_begin:
if hour_end - hour_begin == 1:
hour = '0' + res[hour_begin:hour_end]
elif hour_end - hour_begin == 2:
hour = res[hour_begin:hour_end]
if minite_end - minite_begin == 1:
minite = '0' + res[minite_begin:minite_end]
elif minite_end - minite_begin == 2:
minite = res[minite_begin:minite_end]
if second_end - second_begin == 1:
second = '0' + res[second_begin:second_end]
elif second_end - second_begin == 2:
second = res[second_begin:second_end]
print(hour + ":" + minite + ":" + second)
cur_time = hour + ':' + minite;
codey.display.show(cur_time)
except:
print("get error data")
else:
codey.led.show(0,0,0)
Sample Code 3:¶
import codey
import urequests as requests
import ujson
# user_account and password is mblock's account and password
def get_user_request_header():
post_data = ujson.dumps({ 'account': 'user_account', 'password': 'password'})
request_url = 'http://passport2.makeblock.com/v1/user/login'
res = requests.post(request_url, headers = {'content-type': 'application/json'}, data = post_data).json()
header_data = ''
if res['code'] == 0:
header_data = { "content-type": 'application/json; charset=utf-8', "devicetype": '1'}
header_data["uid"] = str(res['data']['user']['uid'])
header_data["deviceid"] = '30AEA427EC60'
return header_data
# Get weather information
# cid: checkpoint id
# arg: Information to be queried
# aqi: Air Quality Index
# pm25: PM2.5 concentration
# pm10: PM10 concentration
# co: Carbon monoxide concentration
# so2: Sulfur dioxide concentration
# no2: Nitrogen dioxide concentration
def get_air_quality_info(cid, arg):
if not codey.wifi.is_connected():
return ''
post_data = ujson.dumps({ "cid": cid, "arg": arg})
request_url = 'http://msapi.passport3.makeblock.com/' + 'air/getone'
res = requests.post(request_url, headers = get_user_request_header(), data = post_data)
text = res.text
return float(text)
# Fill in your router's ssid and password here.
codey.wifi.start('wifi_ssid', 'password')
codey.led.show(0,0,0)
while True:
if codey.wifi.is_connected():
codey.led.show(0,0,255)
data = get_air_quality_info('1539','aqi') #1539 is Shenzhen checkpoint id
codey.display.show(data)
else:
codey.led.show(0,0,0)
mqtt
— Message Queue Telemetry Transmission¶
mqtt
The main functionality and functions of the module
Class¶
-
class
mqtt.
MQTTClient
(client_id, server, port=0, user=None, password=None, keepalive=0, ssl=False, ssl_params={})¶ Instantiating the interface object of MQTT client, parameters:
- client_id the unique client id string used when connecting to the broker. If client_id is zero length or None, then one will be randomly generated. In this case, the parameter
clean_session
of theconnect
function must beTrue
. - server The host name or IP address of the remote server.
- port (optional), the network port of the server host to connect to. The default port number is 1883. Please note that the default port number of the MQTT over SSL/TLS is 8833.
- user (optional), the username registered on the server.
- password (optional), the password registered on the server.
- keepalive (optional), the client’s keepalive time out value. Default is 60 s.
- ssl (optional), whether enable the SSL/TLS support.
- ssl_params (optional), SSL/TLS parameter.
-
connect
(clean_session=True)¶
Connect the client to the server, this is a blocking function, parameters:
- clean_session a boolean that determines the client type. If
True
, the broker will remove all information about this client when it disconnects. IfFalse
, the client is a durable client and subscription information and queued messages will be retained when the client disconnects.
-
reconnect
()¶
Reconnect to the server using the details provided previously. You must call
connect
before calling this function.-
disconnect
()¶
Disconnect from the server.
-
ping
()¶
Test the connectivity between the server and client.
-
set_last_will
(topic, msg, retain=False, qos=0)¶
Set the will to be sent to the server. If the client disconnects without calling
disconnect()
, the server will post a message on its behalf, parameters:- topic The topic of the will post.
- msg A will message to send.
- retain If set to
True
, the will message will be set to the last knowngood/reserved message
for the topic. - qos Is used for the quality of service level of the will.
-
publish
(topic, msg, retain=False, qos=0)¶
A message is sent from the client to the agent and then sent from the agent to any client that subscribes to the matching topic, parameters:
- topic The topic of the message should be posted.
- msg The actual message to send.
- retain If set to True, the will message will be set to the last known
good/reserved message
for the topic. - qos The level of quality of service to use.
-
subscribe
(topic, qos=0)¶
Subscribe to a topic of the service, this module provides some helper functions to subscribe and process messages directly. For example
set_callback
, parameters:- topic The subject of the message to subscribe.
- qos The level of quality of service to use.
-
set_callback
(f)¶
Sets the callback function for the topic subscription, which is called when the server responds to our subscription request, parameters:
- f callback function.
-
wait_msg
()¶
Wait for the server until the server has no pending messages. This function is a blocking function.
-
check_msg
()¶
Check if the server has pending messages. If not, return directly, if any, do same processing as function
wait_msg
.- client_id the unique client id string used when connecting to the broker. If client_id is zero length or None, then one will be randomly generated. In this case, the parameter
Sample Code:¶
from mqtt import MQTTClient
import codey
import time
MQTTHOST = "mq.makeblock.com"
MQTTPORT = 1883
# Fill in as you like
client_id = "20180911203800"
# Example Path
Topic = "/sensors/temperature/#"
mqttClient = MQTTClient(client_id, MQTTHOST, port=MQTTPORT, user='test', password='test', keepalive=0, ssl=False)
# Connect to the MQTT server
def on_mqtt_connect():
mqttClient.connect()
# publish a message
def on_publish(topic, payload, retain=False, qos = 0):
mqttClient.publish(topic, payload, retain, qos)
# message processing function
def on_message_come(topic, msg):
print(topic + " " + ":" + str(msg))
codey.display.show(msg)
# subscribe message
def on_subscribe():
mqttClient.set_callback(on_message_come)
mqttClient.subscribe(Topic, qos = 1)
# Fill in your router's ssid and password here.
codey.wifi.start('wifi_ssid', 'password')
codey.led.show(0,0,0)
codey.display.show(0)
while True:
if codey.wifi.is_connected():
on_mqtt_connect()
on_subscribe()
codey.led.show(0,0,255)
while True:
# Blocking wait for message
on_publish("/sensors/temperature/home", str(38), qos = 1)
mqttClient.wait_msg()
time.sleep(1)
else:
codey.led.show(0,0,0)
random
— Get Random Number Module¶
random
The main functionality and functions of the module
Function¶
-
random.
random
()¶ Used to generate a random number of characters from 0 to 1:0 <= n < 1.0
-
random.
uniform
(a, b)¶ Used to generate a random number of characters within a specified range, with two parameters, one upper and one lower.If a > b, then the generated random number n: a <= n <= b.If a <b, then b <= n <= a.Parameters:
- a - Upper/lower limit
- b - Upper/lower limit
The reference code is as follows:
print random.uniform(10, 20)
print random.uniform(20, 10)
# 18.7356606526
# 12.5798298022
-
random.
randint
(a, b)¶ Used to generate an integer within a specified range.Where parameter “a” is the lower limit and parameter “b” is the upper limit, the random number n generated is: a <= n <= b.
- a - Lower limit
- b - Upper limit
The reference code is as follows:
print random.randint(12, 20)
print random.randint(20, 20)
# print random.randint(20, 10)
-
random.
randrange
([start, ]stop[, step])¶ Gets a random number from a collection that is incremented by the specified cardinality within the specified range. Such as: random.randrange(10, 100, 2), the result is equivalent to obtaining a random number from the [10, 12, 14, 16… 96, 98] sequence.
- start - Specified cardinality
- stop - Upper limit
- step - Increasing unit
-
random.
choice
(sequence)¶ Gets a random element from a sequence. Parameters:
- sequence - Represents an ordered type.
The reference code is as follows:
print random.choice("Study Python")
print random.choice(["JGood", "is", "a", "handsome", "boy"])
print random.choice(("Tuple", "List", "Dict"))
-
random.
shuffle
(x[, random])¶ Used to scramble elements in a list, parameters:
- x - Need a shuffled list.
The reference code is as follows:
p = ["Python", "is", "powerful", "simple", "and so on..."]
random.shuffle(p)
print p
# ['powerful', 'simple', 'is', 'Python', 'and so on...']
-
random.
sample
(sequence, k)¶ Gets a random fragment of a specified length from a specified sequence, and the sample function does not modify the original sequence.Parameters:
- sequence - Sequence
- k - Fragment length
The reference code is as follows:
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
slice = random.sample(list, 5)
print slice
print list
Sample Code:¶
import time
import random
while True:
x = int(random.randint(200, 600))
print("x is:", x)
time.sleep(1)
Python API for extension Neuron modules¶
Here is the python API for extension Neuron modules:
Python API List for Neuron Extension Modules¶
dc_motor_driver
— Dual DC Motor Driver¶
The main functionality and function of the dc_motor_driver
module
Function¶
-
dc_motor_driver.
set_power
(speed, ch = 0)¶ Set power for the motor driver in each channel, parameters:
- speed Refers to power value of the motor controlled, the parameter range is
-100 ~ 100
. - ch Refers to channel number of the motor controlled, the parameter range is
0 ~ 2
, and0
: stands for both slots,1
: for slot 1 channel,2
: for slot 2 channel.
- speed Refers to power value of the motor controlled, the parameter range is
Sample Code:¶
import codey
import neurons
import event
@event.button_a_pressed
def on_button_a_pressed():
print("button a event succeeded")
neurons.dc_motor_driver.set_power(100, 1)
@event.button_b_pressed
def on_button_b_pressed():
print("button b event succeeded")
neurons.dc_motor_driver.set_power(100, 2)
@event.button_c_pressed
def on_button_c_pressed():
print("button c event succeeded")
neurons.dc_motor_driver.set_power(100, 0)
neurons.dc_motor_driver.set_power(100, 1, 2)
servo_driver
— Dual Servo Driver¶
The main functionality and function of the servo_driver
module
Function¶
-
servo_driver.
set_angle
(position, ch = 0)¶ set power for the servo driver in each channel, parameters:
- position Refers to turning angle value of the servo controlled, the parameter range is
0 ~ 180
. - ch Refers to channel number servo controlled, the parameter range is
0 ~ 2
, and0
: stands for both slots,1
: for slot 1 channel,2
: for slot 2 channel.
- position Refers to turning angle value of the servo controlled, the parameter range is
Sample Code:¶
import codey
import neurons
import event
import time
neurons.servo_driver.set_angle(0, 0)
time.sleep(1)
@event.button_a_pressed
def on_button_a_pressed():
print("button a event succeeded")
neurons.servo_driver.set_angle(100, 1)
@event.button_b_pressed
def on_button_b_pressed():
print("button b event succeeded")
neurons.servo_driver.set_angle(100, 2)
@event.button_c_pressed
def on_button_c_pressed():
print("button c event succeeded")
neurons.servo_driver.set_angle(100, 0)
led_strip
— LED Strip Driver¶
The main functionality and function of the led_strip
module
Function¶
-
led_strip.
set_single
(index, red_value, green_value, blue_value)¶ Set color of each light on the LED Strip, parameters:
- index Set the light order No, the parameter range is
1 ~ the value of total lights on the LED Strip
。 - red_value Set LED red value, the parameter range is
0 ~ 255
, 0 means no red color, 255 means the brightest red color. - green_value Set LED green value, the parameter range is
0 ~ 255
, 0 means no green color, 255 means the brightest green color. - blue_value Set LED blue value, the parameter range is
0 ~ 255
, 0 means no blue color, 255 means the brightest blue color.
- index Set the light order No, the parameter range is
-
led_strip.
set_all
(red_value, green_value, blue_value)¶ Set color for all lights, parameters:
- red_value Set LED red value, the parameter range is
0 ~ 255
, 0 means no red color, 255 means the brightest red color. - green_value Set LED green value, the parameter range is
0 ~ 255
, 0 means no green color, 255 means the brightest green color. - blue_value Set LED blue value, the parameter range is
0 ~ 255
, 0 means no blue color, 255 means the brightest blue color.
- red_value Set LED red value, the parameter range is
-
led_strip.
set_effect
(mode, speed, list)¶ Set effect of the LED Strip, parameters:
mode effect mode, the parameter range is
0 ~ 5
0: means static mode: lights status keep the last setting。
1: means rolling mode: the front N lights turn on firstly as the setting color, then the N lights move to 2~N+1 and the first one turns off, then 3~N+2 and first two lights turn off, just like below picture:
2: means repeat mode: the front N lights turn on firstly as the setting color, and rest lights will copy that status until the last light, just like below picture:
3: means marquee mode: N light turn on and then move repeatedly at a setting speed, as below picture:
4: means breathing mode: the lights change at the speed of human breath, that is they turn on/off each three seconds.
5: means gradient mode: all lights on the strip change their color gradually to the new setting color in a specific setting time.
speed dynamic change speed, the parameter range is
0 ~ 8
, 0 means the slowest speed and 8 is the fastest(It only works when there is dynamic change setting of lights status).list changeable parameter list, the parameter range is
0 ~ 8
,the first parameter means the first light color, the second parameter means the second light color, and so on; And color parameters are as below:black(0x00)
,red(0x01)
,orange(0x02)
,yellow(0x03)
,green(0x04)
,cray(0x05)
,blue(0x06)
,purple(0x07)
andwhile(0x08)
.
Sample Code:¶
import codey
import neurons
import event
import time
neurons.led_strip.set_all(0, 0, 255)
time.sleep(1)
@event.button_a_pressed
def on_button_a_pressed():
print("button a event successed")
neurons.led_strip.set_all(0, 0, 0)
neurons.led_strip.set_single(1, 255, 0, 0)
time.sleep(1)
neurons.led_strip.set_all(0, 0, 0)
neurons.led_strip.set_single(2, 255, 0, 0)
time.sleep(1)
neurons.led_strip.set_all(0, 0, 0)
neurons.led_strip.set_single(3, 255, 0, 0)
time.sleep(1)
@event.button_b_pressed
def on_button_b_pressed():
print("button b event successed")
neurons.led_strip.set_effect(0, 8, (1,6,8,1,6,8,1,6,8))
time.sleep(3)
neurons.led_strip.set_effect(1, 8, (1,6,8,1,6,8,1,6,8))
time.sleep(3)
neurons.led_strip.set_effect(2, 8, (1,6,8,1,6,8,1,6,8))
time.sleep(3)
neurons.led_strip.set_effect(3, 8, (1,6,8,1,6,8,1,6,8))
time.sleep(3)
neurons.led_strip.set_effect(4, 8, (1,6,8,1,6,8,1,6,8))
time.sleep(3)
neurons.led_strip.set_effect(5, 8, (1,6,8,1,6,8,1,6,8))
time.sleep(3)
@event.button_c_pressed
def on_button_c_pressed():
print("button c event successed")
neurons.led_strip.set_effect(0, 5, (1,1,1,1,1,1,1,1,1))
time.sleep(3)
neurons.led_strip.set_effect(1, 5, (1,1,1,1,1,1,1,1,1))
time.sleep(3)
neurons.led_strip.set_effect(2, 5, (1,1,1,1,1,1,1,1,1))
time.sleep(3)
neurons.led_strip.set_effect(3, 5, (1,1,1,1,1,1,1,1,1))
time.sleep(3)
neurons.led_strip.set_effect(4, 5, (1,1,1,1,1,1,1,1,1))
time.sleep(3)
neurons.led_strip.set_effect(5, 5, (1,1,1,1,1,1,1,1,1))
time.sleep(3)
led_panel
— RGB LED Panel¶
The main functionality and function of the led_panel
module
Function¶
-
led_panel.
set_all
(red_value, green_value, blue_value)¶ Set and display color of all lights on the panel, parameters:
- red_value Set LED red value, the parameter range is
0 ~ 255
, 0 means no red color, 255 means the brightest red color. - green_value Set LED green value, the parameter range is
0 ~ 255
, 0 means no green color, 255 means the brightest green color. - blue_value Set LED blue value, the parameter range is
0 ~ 255
, 0 means no blue color, 255 means the brightest blue color.
- red_value Set LED red value, the parameter range is
-
led_panel.
set_pixel
(x, y, red_value, green_value, blue_value)¶ Set color for each pixel on the panel, parameters:
- x pixel’s X position on the panel, the parameter range is
0 ~ 7
. - y pixel’s Y position on the panel, the parameter range is
0 ~ 7
. - red_value Set LED red value, the parameter range is
0 ~ 255
, 0 means no red color, 255 means the brightest red color. - green_value Set LED green value, the parameter range is
0 ~ 255
, 0 means no green color, 255 means the brightest green color. - blue_value Set LED blue value, the parameter range is
0 ~ 255
, 0 means no blue color, 255 means the brightest blue color.
- x pixel’s X position on the panel, the parameter range is
-
led_panel.
show_image
(list, mode = 0)¶ Set the display content as image parameter mode, parameters:
- list changeable parameter list, each value ranges is
0 ~ 8
, the first parameter means the first light color, the second parameter means the second light color, and so on. And color parameters are as below:black(0x00)
,red(0x01)
,orange(0x02)
,yellow(0x03)
,green(0x04)
,cray(0x05)
,blue(0x06)
,purple(0x07)
andwhile(0x08)
. - mode contents displaying mode, the parameter range is
0 ~ 3
0:means emerging mode, setting image will display directly.
1:means erase mode, original image disappear gradually and new setting image will display gradually and vertically.
2:means left moving mode, original image moves to the left and disappear gradually and new setting image will move to the left until display the whole image.
3:means right moving mode, original image moves to the right and disappear gradually and new setting image will move to the right until display the whole image.
- list changeable parameter list, each value ranges is
-
led_panel.
set_animation
(frame_index, list)¶ Set the animation content on the panel, parameters:
- frame_index index of the animation frame, the parameter range is
0 ~ 3
; 0 mean the first frame, 1 means the second, and so on. - list changeable parameter list, each value ranges is
0 ~ 8
, the first parameter means the first light color, the second parameter means the second light color, and so on; And color parameters are as below:black(0x00)
,red(0x01)
,orange(0x02)
,yellow(0x03)
,green(0x04)
,cray(0x05)
,blue(0x06)
,purple(0x07)
andwhile(0x08)
.
- frame_index index of the animation frame, the parameter range is
-
led_panel.
show_animation
(frame_speed, mode)¶ Show the animation frame setting by
set_animation
, parameters:- frame_speed switch speed of the animation frame content, the parameter range is
0 ~ 2
0:means slow speed that the animation frame rolls every one second
1:means normal speed that the animation frame rolls every half second
2:means fast speed that the animation frame rolls every 0.2 second.
mode frame change mode, the parameter range is
0 ~ 3
0:means emerging mode, setting image will display directly.
1:means erase mode, original image disappear gradually and new setting image will display gradually and vertically.
2:means left moving mode, original image moves to the left and disappear gradually and new setting image will move to the left until display the whole image.
3:means right moving mode, original image moves to the right and disappear gradually and new setting image will move to the right until display the whole image.
- frame_speed switch speed of the animation frame content, the parameter range is
-
led_panel.
show_string
(red_value, green_value, blue_value, list)¶ Display the string as the setting color, parameters:
- red_value Set LED red value, the parameter range is
0 ~ 255
, 0 means no red color, 255 means the brightest red color. - green_value Set LED green value, the parameter range is
0 ~ 255
, 0 means no green color, 255 means the brightest green color. - blue_value Set LED blue value, the parameter range is
0 ~ 255
, 0 means no blue color, 255 means the brightest blue color. - list changeable parameter list, the first character, the second character, the third character…
- red_value Set LED red value, the parameter range is
-
led_panel.
clear
()¶ Clear the display of the panel.
Sample Code:¶
import codey
import neurons
import event
import time
neurons.led_panel.clear()
neurons.led_panel.set_all(0, 0, 255)
time.sleep(1)
neurons.led_panel.clear()
@event.button_a_pressed
def on_button_a_pressed():
print("button a event successed")
neurons.led_panel.set_pixel(0, 0, 255, 0, 0)
time.sleep(1)
neurons.led_panel.set_pixel(4, 4, 255, 0, 0)
time.sleep(1)
neurons.led_panel.set_pixel(7, 7, 255, 0, 0)
time.sleep(1)
neurons.led_panel.set_pixel(0, 6, 255, 0, 0)
time.sleep(1)
@event.button_b_pressed
def on_button_b_pressed():
print("button b event successed")
neurons.led_panel.show_image([1,6,8,0,0,0,1,6,8],0)
time.sleep(1)
neurons.led_panel.show_image([1,1,1,1,1,1,1,1,1],1)
time.sleep(1)
neurons.led_panel.show_image([6,6,6,6,6,6,6,6,6],2)
time.sleep(1)
neurons.led_panel.show_image([8,8,8,8,8,8,8,8,8],3)
time.sleep(1)
@event.button_c_pressed
def on_button_c_pressed():
print("button c event successed")
neurons.led_panel.set_animation(0, (1,6,8,1,6,8,0,0,0))
neurons.led_panel.set_animation(1, (6,6,6,6,6,6,6,6,6))
neurons.led_panel.set_animation(2, [6,6,6,6,6,6,6,6,6])
neurons.led_panel.set_animation(3, (8,8,8,8,8,8,8,8,8))
neurons.led_panel.show_animation(1, 2)
time.sleep(6)
neurons.led_panel.show_string(255, 0, 0, "hello")
time.sleep(4)
neurons.led_panel.show_string(255, 0, 0, (100))
time.sleep(4)
neurons.led_panel.show_string(255, 0, 0, (1,2,3))
time.sleep(4)
buzzer
— Buzzer¶
The main functionality and function of the buzzer
module
Function¶
-
buzzer.
play_note
(note_num, beat = None)¶ Play note, digital note definitions please refer to: scratch digital note description, prameters:
- note_num numeric value, range of values
48 - 72
, or string type, such asC4
. - beat value data, indicates the number of beats, the default value is always playing.
notes and frequency is as follows:
['C2','65'], ['D2','73'], ['E2','82'], ['F2','87'], ['G2','98'], ['A2','110'], ['B2','123'], ['C3','131'], ['D3','147'], ['E3','165'], ['F3','175'], ['G3','196'], ['A3','220'], ['B3','247'], ['C4','262'], ['D4','294'], ['E4','330'], ['F4','349'], ['G4','392'], ['A4','440'], ['B4','494'], ['C5','523'], ['D5','587'], ['E5','659'], ['F5','698'], ['G5','784'], ['A5','880'], ['B5','988'], ['C6','1047'], ['D6','1175'], ['E6','1319'], ['F6','1397'], ['G6','1568'], ['A6','1760'], ['B6','1976'], ['C7','2093'], ['D7','2349'], ['E7','2637'], ['F7','2794'], ['G7','3136'], ['A7','3520'], ['B7','3951'], ['C8','4186'], ['D8','4699'],
- note_num numeric value, range of values
-
buzzer.
play_tone
(frequency, time = None)¶ Play the tone of setting frequency, prameters:
- frequency Numerical data, the frequency of sound which is played, and its value range is
0 ~ 5000
. - time Numerical data, indicating the playback time (in
milliseconds - ms
) and its value range is0 ~ the value range limit
.
- frequency Numerical data, the frequency of sound which is played, and its value range is
-
buzzer.
rest
(number)¶ Stop the beat, parameters:
- number Numerical data, the number of paused beats, its value range is
0 ~ the value range limit
.
- number Numerical data, the number of paused beats, its value range is
Constant¶
-
buzzer.
tempo
¶ Numerical data, indicating the nature of the playback speed, in
bmp
(beat per minute), which is the length of each beat.Its value range is6 ~ 600
. The default value is 60, which means that the duration of one beat is 1 second. The beats of therest
andplay_note
functions are affected by this constant.
Sample Code:¶
import codey
import time
import neurons
codey.display.show("hello")
neurons.buzzer.play_note(48, 1)
neurons.buzzer.rest(1)
codey.display.show("note")
codey.display.clear()
neurons.buzzer.play_note("C4", 1)
neurons.buzzer.rest(1)
codey.display.show("C4")
codey.display.clear()
neurons.buzzer.play_tone(1000, 2)
neurons.buzzer.rest(1)
codey.display.show("tone")
codey.display.clear()
while True:
neurons.buzzer.tempo = 60
print("tempo:", end = "")
print(neurons.buzzer.tempo)
neurons.buzzer.play_note("C4", 1)
neurons.buzzer.rest(2)
neurons.buzzer.tempo = 240
neurons.buzzer.play_note("C4", 1)
neurons.buzzer.rest(2)
button
— Button¶
The main functionality and function of the button
module
Function¶
Get current status of button; the result will be
True
: button pressed orFalse
: button is not pressed.
Sample Code:¶
import neurons
while True:
if neurons.button.is_pressed():
print("pressed!")
funny_touch
— Funny Touch¶
The main functionality and function of the funny_touch
module
Funny touch user Guide¶

Funny touch can be connected to any conductive object (such as bananas and water) and turn it into a touch switch. A simple and interesting interactive effect can be achieved by detecting the conducting state between funny switches and GND wire.
How to use?
- Plug the funny switch to slot 1 and the GND wire to slot 2.
- Clip a funny switch to a conductive object.
3. Hold the metal clip of the GND wire and touch the conductive object with the other hand, the relevant indicator will light up and the block will send out an on signal.
Tips: Alligator clip is sharp, please do not clip yourself with the funny switch or the clip of GND wire, it may hurt you.
Function¶
-
funny_touch.
is_red_touched
()¶ Whether the red clip is touched or not, result will be
True
: yes, it is touched, orFalse
: no, it isn’t touched.
-
funny_touch.
is_green_touched
()¶ Whether the green clip is touched or not, result will be
True
: yes, it is touched, orFalse
: no, it isn’t touched.
-
funny_touch.
is_yellow_touched
()¶ Whether the yellow clip is touched or not, result will be
True
: yes, it is touched, orFalse
: no, it isn’t touched.
-
funny_touch.
is_blue_touched
()¶ Whether the blue clip is touched or not, result will be
True
: yes, it is touched, orFalse
: no, it isn’t touched.
Sample Code:¶
import codey
import time
import event
import neurons
@event.start
def start_cb():
while True:
if neurons.funny_touch.is_blue_touched():
print("blue touched")
if neurons.funny_touch.is_red_touched():
print("red touched")
if neurons.funny_touch.is_green_touched():
print("green touched")
if neurons.funny_touch.is_yellow_touched():
print("yellow touched")
time.sleep(0.1)
ultrasonic_sensor
— Ultrasonic Sensor¶
The main functionality and function of the ultrasonic_sensor
module
Function¶
-
ultrasonic_sensor.
get_distance
()¶ Get the distance (
cm
) between the obstacle ahead and ultrasonic sensor; the result is floating point, ranging3 ~ 300
cm; but measure distance ranges3 ~ 300
cm as detection is not exact enough within 3 cm.
Sample Code:¶
import codey
import time
import event
import neurons
@event.start
def start_cb():
while True:
print(neurons.ultrasonic_sensor.get_distance())
time.sleep(0.2)
gyro_sensor
— Gyro Sensor¶
The main functionality and function of the gyro_sensor
module
Function¶
-
gyro_sensor.
get_roll
()¶ Get the roll of the Euler angle, the returned data range is
-90 ~ 90
.
-
gyro_sensor.
get_pitch
()¶ Get the pitch of the Euler angle, the returned data range is
-180 ~ 180
.
-
gyro_sensor.
get_yaw
()¶ Get the yaw of the Euler angle, The returned data range is
-32768 ~ 32767
,Since the gyro sensor is a six-axis sensor, there is no electronic compass. So in fact the yaw angle is just the integral of the Z-axis angular velocity. It has accumulated errors. If you want to get a true yaw angle, this API is not suitable for use.
-
gyro_sensor.
is_shaked
()¶ Check if the gyro sensor is shaken, the return value is a Boolean value, where
True
means that gyro sensor is shaken, andFalse
means that gyro sensor is not shaken.
-
gyro_sensor.
get_acceleration
(axis)¶ Get the acceleration values of the three axes in
g
, Parameters:- axis String type, with
x
,y
,z
representing the axis defined by gyro sensor.
- axis String type, with
-
gyro_sensor.
get_gyroscope
(axis)¶ Get the angular velocity values of the three axes in
°/sec
, Parameters:- axis String type, with
x
,y
,z
representing the axis defined by gyro sensor.
- axis String type, with
Sample Code 1:¶
import rocky
import event
import neurons
@event.button_a_pressed
def on_button_a_callback():
codey.stop_other_scripts()
codey.display.show("pit")
while True:
print(neurons.gyro_sensor.get_pitch())
time.sleep(0.05)
@event.button_b_pressed
def on_button_b_callback():
codey.stop_other_scripts()
codey.display.show("rol")
while True:
print(neurons.gyro_sensor.get_roll())
time.sleep(0.05)
@event.button_c_pressed
def on_button_c_callback():
codey.stop_other_scripts()
codey.display.show("yaw")
while True:
print(neurons.gyro_sensor.get_yaw())
time.sleep(0.05)
Sample Code 2:¶
import rocky
import event
import neurons
@event.start
def start_cb():
codey.display.show("sha")
while True:
print(neurons.gyro_sensor.is_shaked())
time.sleep(0.2)
Sample Code 3:¶
import rocky
import event
import neurons
@event.start
def start_cb():
while True:
print("gyro z:", end = "")
print(neurons.gyro_sensor.get_gyroscope("z"))
print("accel z:", end = "")
print(neurons.gyro_sensor.get_acceleration("z"))
time.sleep(0.2)
pir_sensor
— PIR Sensor¶
The main functionality and function of the pir_sensor
module
Function¶
-
pir_sensor.
is_activated
()¶ Get the detecting result from the sensor. Result will be
True
: it detects human nearby orFalse
: it doesn’t detect human nearby.
Sample Code:¶
import codey
import time
import event
import neurons
@event.start
def start_cb():
while True:
print(neurons.pir_sensor.is_activated())
time.sleep(0.2)
soil_moisture
— Soil Moisture¶
The main functionality and function of the soil_moisture
module
Function¶
-
soil_moisture.
get_value
()¶ Get humidity of soil detected, ranging
0 ~ 100
; the higher value is, the higher humidity is.
Sample Code:¶
import codey
import time
import event
import neurons
@event.start
def start_cb():
while True:
print(neurons.soil_moisture.get_value())
time.sleep(0.2)
Codey&Rocky’s example tutorial¶
The purpose of this tutorial is to get you started using codey&rocky. We need you to have a codey or codey&rocky, and secondly you need a USB cable (or Bluetooth dongle) to connect to the codey&rocky. If you are using Python programming for codey&rocky for the first time, It is recommended to read this section.
codey&rocky typical example
Codey&Rocky’s micropython instructions¶
添加自定义类库或者代码文件¶
如何将自己编写的一些Python脚本,或者python的类库添加到固件中。
使用mblock5软件¶
可以下载和使用 mblock5 来进行python程序的编写以及程序的上传。

- 如上图所示,打开mblock5软件后,连接好设备,并确定当前模式是 上传模式。
- 确定当前是 python 模式(默认是积木模式)
- 在代码编辑区编写自己的执行代码
- 点击
上传到设备
将代码烧录进小程。
使用firefly_upload脚本¶
可以下载和使用 firefly_upload 这个python脚本来进行python程序的上传。它除了可以上传 main.py, 也可以上传第三方或者自定义的类库以供 main.py调用。
下载地址: https://github.com/YanMinge/firefly_upload

- 下载脚本,该脚本可以支持 python2 和 python3 环境下的使用。
- 因为上传会使用到串口,所以需要安装 pyserial 的库,最好是用 pip 安装
pip install pyserial
- 因为上传使用了一个进度条的工具,所以需要安装 progressbar2 的库,最好是用 pip 安装
pip install progressbar2
- 在 shell 或者 cmd 界面 输入 在shell 中输入 python firefly_upload.py -p [串口名称] -i [文件的路径] -o [文件烧入flash的路径]
如windows示例:
python firefly_upload.py -p COM5 -i C:/Users/MBENBEN/Desktop/test/main.py -o /flash/main.py
使用mpy-cross工具生成mpy文件¶
版权声明:文本编辑整理属于Yanminge,转载时请以超链接形式标明文章原始出处和作者信息及本声明
接触过Python语言的人都知道,Python可以编译成.pyc文件,它是一种二进制文件,可以提高程序的加载速度,同时也是一种保护源代码的有效方法。 在micropython中,也提供了类似的功能,可以将.py文件编译成.mpy文件。接下来,介绍一下具体的实现步骤。(本文以 mingw32 工具链为例, 使用小程作为目标主板)
搭建micropython编译环境¶
注意:
在不同的系统环境以及不同的目标主板,micropython的开发环境安装是有差别的,这里仅以乐鑫esp32的mingw32工具链作为示意。我们需要用到它的 xtensa-esp32-elf
- 参考乐鑫 设置工具链,以 windows系统为例,可以从乐鑫的官网下载 Windows all-in-one工具链 & MSYS2 zip包,将zip文件解压缩到C盘的根目录(也可以是其他一些位置,但本文档假定为
C:\
),它将创建一个带有预先准备好的环境的msys32目录。 - 下载micropython源码包到本地,我下载到了G盘的根目录下。
生成mpy文件¶
- 执行msys32目录中的
mingw32.exe
切换到/g/micropython/mpy-cross
目录执行make,编译生成mpy-cross工具。


- 在mpy-cross目录新建一下main.py文件,以小程为例,写一个测试程序用于验证。
import codey
import time
codey.led.show(2555,255,255)
time.sleep(2)
codey.led.off()
time.sleep(2)
while True:
codey.led.set_red(255)
time.sleep(1)
codey.led.set_green(255)
time.sleep(1)
codey.led.set_blue(255)
time.sleep(1)
codey.led.off()
time.sleep(1)
- 执行编译mpy文件的命令。
其他相关功能可查看同目录下的README.md文件。
- 命令执行成功后,你就能发现同目录下出现了一个main.mpy文件。

- 将 main.mpy 文件拷贝放到小程的flash中,如果是 main文件名的话,小程会自动运行。
注意: 如果运行时出现“ValueError: invalid .mpy file”错误的话,需要更新一下主板的micropython固件(最新固件跟随mblock最新版本发布)。
Python API for Haloboard¶
This article includes the following python API for Haloboard:
- Python API for Haloboard:refers to some API for Haloboard’s onboard driver.
- Python API for third-party libraries:some build-in interface for third-party libraries of Haloboard, such as mqtt or urequest.
- Python API for extension Neuron modules:API which may used when add Neuron modules to Haloboard.
Python API for Haloboard¶
Python API for Haloboard includes the following reference tables:
The python interface class for the haloboard¶
Broadcast’s interface list¶
broadcast
— Broadcast Message¶
broadcast
The main functionality and functions of the module
-
broadcast.
broadcast
(message_str)¶ Broadcast message, after broadcast message, other threads can receive the message, parameters:
- message_str - The message type is string, message value.
# -*- coding: utf-8 -*-
import haloboard
import time
import event
@event.button_pressed
def on_button_a_pressed():
print("button is pressed")
haloboard.broadcast("hello")
@event.received("hello")
def received_cb():
print("received message: hello")
haloboard.mesh
— Mesh Broadcast Message¶
haloboard.mesh
The main functionality and functions of the module
This module mainly introduces the function API based on mesh network module.
-
haloboard.mesh.
start
(type = "node")¶ Start mesh communication,parameter:
- type - Refers to the type in the mesh network, which can be root or node by default.
# mesh boardcast
-
haloboard.mesh.
get_number_of_nodes
()¶ Get the current number of nodes in the mesh network.
-
haloboard.mesh.
on_mesh_message_come
(msg)¶ Process mesh messages.
- msg - Mesh messages that currently need to be processed.
-
haloboard.mesh.
get_info
(msg)¶ Get the information of the mesh message.
- msg - Mesh messages that currently need to be processed.
-
haloboard.mesh.
get_info_status
(msg)¶ Gets the current state of the mesh message.
- msg - Mesh messages that currently need to be processed.
# for online mode
-
haloboard.mesh.
get_all_info_status
()¶ Gets the current state of all mesh messages
-
haloboard.mesh.
get_info_once
(msg)¶ Get the information of the mesh message a single time.
- msg - Mesh messages that currently need to be processed.
# -*- coding: utf-8 -*-
# as a node
import haloboard
import time
import event
count = 0
@event.start
def on_start():
haloboard.mesh.start(type = "node")
@event.button_pressed
def on_button_a_pressed():
global count
print("button is pressed")
haloboard.mesh.broadcast("hello", str(count))
count += 1
@event.mesh_message("hello")
def received_cb():
print("received message: hello")
print("value:", haloboard.mesh.get_info("hello"))
# -*- coding: utf-8 -*-
# as a root
import haloboard
import time
import event
@event.start
def on_start():
haloboard.mesh.start(type = "root")
@event.button_pressed
def on_button_a_pressed():
print("button is pressed")
haloboard.mesh.broadcast("hello", '123')
@event.mesh_message("hello")
def received_cb():
print("received message: hello")
print("value:", haloboard.mesh.get_info("hello"))
Driver’s interface list¶
button
— Onboard Button¶
button
The main functionality and functions of the module
Gets the current state of key A. The returned result is ` ` True ` ` : button is pressed, or ` ` False ` ` : button is not pressed.
import haloboard
def loop():
while True:
if haloboard.button.is_pressed():
haloboard.led.show_all(255, 255, 255)
else:
haloboard.led.show_all(0, 0, 0)
loop()
clock
— Onboard Baseboard Clock¶
clock
The main functionality and functions of the module
-
clock.
get_date_and_time
(clock_id)¶ - Gets the value of the time.
- clock_id - Time type parameter, can be hours: clock.HOUR_INDEX,minute:clock.MINUTE_INDEX,second:clock.SECOND_INDEX。
from haloboard import *
import time
minute = 0
hour = 0
count = 0
while True:
hour = clock.get_date_and_time(clock.HOUR_INDEX)
minute = clock.get_date_and_time(clock.MINUTE_INDEX)
second = clock.get_date_and_time(clock.SECOND_INDEX)
print("hour:%d, minute:%d, second:%d" %(hour, minute, second))
time.sleep(1)
led
— Onboard RGB LED¶
led
The main functionality and functions of the module
-
led.
show_single
(led_id, r, g, b)¶ Set the color and parameters of a single RGB LED light, parameter:
- led_id - The number of a single LED, the parameter range is 1-12, the corresponding position is as shown below:

r - The value of the red component of full-color LED, the parameter range is 0 ~ 255, 0 is no red component, 255 is the brightest red component.
g - The value of the green component of full-color LED, the parameter range is 0 ~ 255, 0 is no green component, 255 is the brightest green component.
b - The value of the blue component of full-color LED, the parameter range is 0 ~ 255, 0 is no blue component, 255 is the brightest blue component.
- Corresponding table of common color RGB:
-
led.
show_all
(r, g, b)¶ Set all RGB LED lights to the same color.
- r - The value of the red component of full-color LED, the parameter range is 0 ~ 255, 0 is no red component, 255 is the brightest red component.
- g - The value of the green component of full-color LED, the parameter range is 0 ~ 255, 0 is no green component, 255 is the brightest green component.
- b - The value of the blue component of full-color LED, the parameter range is 0 ~ 255, 0 is no blue component, 255 is the brightest blue component.
-
led.
off_all
()¶ Turn off all LED lights.
-
led.
clear
()¶ Turn off all LED lights and turn on the out sign.
-
led.
off_single
(led_id)¶ Extinguishing single RGB LED, parameters:
- led_id - The number of a single LED, the parameter range is 1-12.
-
led.
show_ring
(color_str, offset=0)¶ Set 12 RGB leds as the corresponding color. Parameters:
- color_str - String type, string format should be “color1, color2, color3, color4”,
- Where colorx is “red”/”green”/”blue”/”yellow”/”cyan”/”purple”/”white”/”orange”/”black/”gray” color characters separated by a single space,When the number of colors is greater than 12, it will be truncated into 12.
- offset - Value type, value range 0-12.
-
led.
ring_graph
(percentage)¶ Percentage displayed by the status of LED ring, parameters:
- percentage - Value type, value range 0-100.
-
led.
meteor_effect
()¶ Display meteor Lighting effects.
-
led.
rainbow_effect
()¶ Display rainbow Lighting effects.
-
led.
spoondrift_effect
()¶ Display rainbow spoondrift effects.
-
led.
firefly_effect
()¶ Display rainbow firefly effects.
-
led.
show_animation
(name)¶ Display default light effect, block type, parameters:
- name - The name of default light effect ,there four:spoondrift, meteor, rainbow, firefly。
import haloboard
import time
haloboard.led.show_single(1, 255, 255,255)
time.sleep(2)
haloboard.led.show_single(2, 255, 0, 0)
time.sleep(2)
haloboard.led.show_single(3, 0, 255, 0)
time.sleep(2)
haloboard.led.show_single(4, 0, 0, 255)
time.sleep(2)
haloboard.led.show_all(255, 255, 255)
time.sleep(2)
while True:
haloboard.led.off_single(1)
time.sleep(1)
haloboard.led.show_single(1, 255, 0, 0)
time.sleep(1)
import haloboard
import time
haloboard.led.show_single(1, 255, 255,255)
time.sleep(2)
haloboard.led.show_single(2, 255, 0, 0)
time.sleep(2)
haloboard.led.show_single(3, 0, 255, 0)
time.sleep(2)
haloboard.led.show_single(4, 0, 0, 255)
time.sleep(2)
haloboard.led.show_all(255, 255, 255)
time.sleep(2)
while True:
haloboard.led.off_single(1)
time.sleep(1)
haloboard.led.show_single(1, 255, 0, 0)
time.sleep(1)
import haloboard
import time
import random
while True:
for i in range(101):
haloboard.led.ring_graph(i)
time.sleep(0.1)
print(i)
for i in range(101):
haloboard.led.ring_graph(100 - i)
time.sleep(0.1)
print(i)
for i in range(13):
haloboard.led.show_ring("green blue yellow purple cyan white green blue yellow purple cyan white", i)
time.sleep(0.5)
import haloboard
import time
import event
@event.touchpad0_active
def on_touchpad0_active():
haloboard.stop_other_scripts()
while True:
haloboard.led.show_animation('spoondrift')
@event.touchpad1_active
def on_touchpad1_active():
haloboard.stop_other_scripts()
while True:
haloboard.led.show_animation('meteor')
@event.touchpad2_active
def on_touchpad2_active():
haloboard.stop_other_scripts()
while True:
haloboard.led.show_animation('rainbow')
@event.touchpad3_active
def on_touchpad3_active():
haloboard.stop_other_scripts()
while True:
haloboard.led.show_animation('firefly')
motion_sensor
— Onboard Motion Sensor¶
motion_sensor
The main functionality and functions of the module
- Description of onboard attitude sensor module:
As shown in the figure above, the direction of roll and pitch is based on the right hand screw rule. Haloboard horizontal roll and pitch of 0 °
- roll - Scope: - 90 ° ~ 90 °
- pitch - Scope: -180° ~ 180°
-
motion_sensor.
get_roll
()¶ Gets the roll angle of the attitude angle, and the range of returned data is -90 ~ 90.
-
motion_sensor.
get_pitch
()¶ Get the pitch angle of the attitude angle, and the data range returned is -180 ~ 180.
-
motion_sensor.
get_yaw
()¶ The yaw angle of the attitude angle is obtained, and the range of data returned is 0 ~ 360. Since there is no electronic compass, the yaw angle is actually just an integral of the z-axis angular velocity.It has accumulated errors.If you want to get real yaw angles, this API is not suitable.
-
motion_sensor.
get_acceleration
(axis)¶ For three axis acceleration value, the unit is m/s ^ 2, and parameters:
- axis - String type, x, y, z represents the axis defined by the haloboard.
-
motion_sensor.
get_gyroscope
(axis)¶ Get three shaft angular velocity value, the unit is ° / SEC, parameters:
- axis - String type, x, y, z represents the axis defined by the haloboard.
-
motion_sensor.
get_rotation
(axis)¶ Obtain the rotation angle of the haloboard on three axes, with the counterclockwise rotation as the positive direction, parameters:
- axis - String type, x, y, z represents the axis defined by the haloboard.
-
motion_sensor.
reset_rotation
(axis = "all")¶ The current angle of rotation around three axes is 0. The get_rotation() function will start from 0, parameter:
- axis - String type, x, y, z represents the axis defined by the haloboard, “all” represents all three axes and is the default value for this function.
-
motion_sensor.
is_tilted_left
()¶ Detect whether haloboard tilt to the left, threshold 15 °, the return value is a boolean value, “True” said haloboard tilt to the left, “False” said haloboard not tilt to the left.
-
motion_sensor.
is_tilted_right
()¶ Detect whether haloboard tilt to the right, threshold 15 °, the return value is a boolean value, “True” said haloboard tilt to the right, “False” said haloboard not tilt to the right.
-
motion_sensor.
is_arrow_up
()¶ Detect whether get arrow up state, threshold 15 °, the return value is a boolean value, which “True” arrow up, says “False” indicates no up arrow.
-
motion_sensor.
is_arrow_down
()¶ Detect whether get arrow down state, threshold 15 °, the return value is a boolean value, which “True” arrow down, says “False” indicates no down arrow.
-
motion_sensor.
is_shaked
()¶ Detect whether the haloboard is shaken, and the return value is boolean, where “True” means that the haloboard is shaken, and “False” means that the haloboard is not shaken.
-
motion_sensor.
is_led_ring_up
()¶ Detect whether the LED lamp ring is upwards and return a boolean value, where “True” means the lamp ring is upwards and “False” means the lamp ring is not upwards.
-
motion_sensor.
is_led_ring_down
()¶ Detect whether the LED lamp ring is downwards and return a boolean value, where “True” means the lamp ring is downwards and “False” means the lamp ring is not downwards.
-
motion_sensor.
get_shake_strength
()¶ If the haloboard is shaken, this function can obtain the strength of the shaking. The value range of the return value is 0 ~ 100. The larger the value is, the stronger the shaking will be.
import haloboard
import time
while True:
acceleration_x = haloboard.motion_sensor.get_acceleration("x")
acceleration_y = haloboard.motion_sensor.get_acceleration("y")
acceleration_z = haloboard.motion_sensor.get_acceleration("z")
print("acceleration_x:", end = "")
print(acceleration_x, end = "")
print(" ,acceleration_y:", end = "")
print(acceleration_y, end = "")
print(" ,acceleration_z:", end = "")
print(acceleration_z)
time.sleep(0.05)
import haloboard
import time
while True:
roll = haloboard.motion_sensor.get_roll()
pitch = haloboard.motion_sensor.get_pitch()
yaw = haloboard.motion_sensor.get_yaw()
print("roll:", end = "")
print(roll, end = "")
print(" ,pitch:", end = "")
print(pitch, end = "")
print(" ,yaw:", end = "")
print(yaw)
time.sleep(0.05)
import haloboard
import time
while True:
gyroscope_x = haloboard.motion_sensor.get_gyroscope("x")
gyroscope_y = haloboard.motion_sensor.get_gyroscope("y")
gyroscope_z = haloboard.motion_sensor.get_gyroscope("z")
print("gyroscope_x:", end = "")
print(gyroscope_x, end = "")
print(" ,gyroscope_y:", end = "")
print(gyroscope_y, end = "")
print(" ,gyroscope_z:", end = "")
print(gyroscope_z)
time.sleep(0.05)
import haloboard
import time
while True:
if haloboard.motion_sensor.is_tilted_left():
print("tilted_left")
if haloboard.motion_sensor.is_tilted_right():
print("tilted_right")
if haloboard.motion_sensor.is_arrow_up():
print("arrow_up")
if haloboard.motion_sensor.is_arrow_down():
print("arrow_down")
import haloboard
import time
while True:
rotation_x = haloboard.motion_sensor.get_rotation("x")
rotation_y = haloboard.motion_sensor.get_rotation("y")
rotation_z = haloboard.motion_sensor.get_rotation("z")
print("rotation_x:", end = "")
print(rotation_x, end = "")
print(" ,rotation_y:", end = "")
print(rotation_y, end = "")
print(" ,rotation_z:", end = "")
print(rotation_z)
time.sleep(0.05)
import haloboard
import time
while True:
if haloboard.motion_sensor.is_shaked():
print("shake_strength:", end = "")
print(haloboard.motion_sensor.get_shake_strength())
import haloboard
import time
while True:
if haloboard.motion_sensor.is_led_ring_up():
print("led ring up")
if haloboard.motion_sensor.is_led_ring_down():
print("led ring down")
time.sleep(0.3)
touchpad0
— Touch Button0¶
touchpad0
The main functionality and functions of the module
-
touchpad0.
is_touched
()¶ Gets the current state of touch button 0.This returns True: the touch button 0 is touched, or False: the touch button 0 is not touched.
-
touchpad0.
get_value
()¶ Gets the touched state of the touch button. Values range from 0 to 10000.
-
touchpad0.
set_touch_threshold
()¶ Set the threshold value of the touch button, parameters:
- val - The percentage of touch change, when the detected change amplitude is greater than this percentage,
- it is considered to be touched, and the value range is 0-1.
import haloboard
import time
haloboard.touchpad0.set_touch_threshold(0.01 * 2)
haloboard.touchpad1.set_touch_threshold(0.01 * 2)
haloboard.touchpad0.set_touch_threshold(0.005 * 2)
haloboard.touchpad0.set_touch_threshold(0.015 * 2)
while True:
if haloboard.touchpad0.is_touched():
print("TouchPad 0 is touched!")
if haloboard.touchpad1.is_touched():
print("TouchPad 1 is touched!")
if haloboard.touchpad2.is_touched():
print("TouchPad 2 is touched!")
if haloboard.touchpad3.is_touched():
print("TouchPad 3 is touched!")
print("val:" + str(haloboard.touchpad0.get_value()) + " ," + str(haloboard.touchpad1.get_value()) + " ," + str(haloboard.touchpad2.get_value()) + " ," + str(haloboard.touchpad3.get_value()))
time.sleep(0.01)
touchpad0
— Touch Button1¶
touchpad0
The main functionality and functions of the module
-
touchpad0.
is_touched
()¶ Gets the current state of touch button 1.This returns True: the touch button 1 is touched, or False: the touch button 1 is not touched.
-
touchpad0.
get_value
()¶ Gets the touched state of the touch button. Values range from 0 to 10000.
-
touchpad0.
set_touch_threshold
()¶ Set the threshold value of the touch button, parameters:
- val - The percentage of touch change, when the detected change amplitude is greater than this percentage,
- it is considered to be touched, and the value range is 0-1.
import haloboard
import time
haloboard.touchpad0.set_touch_threshold(0.01 * 2)
haloboard.touchpad1.set_touch_threshold(0.01 * 2)
haloboard.touchpad0.set_touch_threshold(0.005 * 2)
haloboard.touchpad0.set_touch_threshold(0.015 * 2)
while True:
if haloboard.touchpad0.is_touched():
print("TouchPad 0 is touched!")
if haloboard.touchpad1.is_touched():
print("TouchPad 1 is touched!")
if haloboard.touchpad2.is_touched():
print("TouchPad 2 is touched!")
if haloboard.touchpad3.is_touched():
print("TouchPad 3 is touched!")
print("val:" + str(haloboard.touchpad0.get_value()) + " ," + str(haloboard.touchpad1.get_value()) + " ," + str(haloboard.touchpad2.get_value()) + " ," + str(haloboard.touchpad3.get_value()))
time.sleep(0.01)
touchpad0
— Touch Button2¶
touchpad0
The main functionality and functions of the module
-
touchpad0.
is_touched
()¶ Gets the current state of touch button 2.This returns True: the touch button 2 is touched, or False: the touch button 2 is not touched.
-
touchpad0.
get_value
()¶ Gets the touched state of the touch button. Values range from 0 to 10000.
-
touchpad0.
set_touch_threshold
()¶ Set the threshold value of the touch button, parameters:
- val - The percentage of touch change, when the detected change amplitude is greater than this percentage,
- it is considered to be touched, and the value range is 0-1.
import haloboard
import time
haloboard.touchpad0.set_touch_threshold(0.01 * 2)
haloboard.touchpad1.set_touch_threshold(0.01 * 2)
haloboard.touchpad0.set_touch_threshold(0.005 * 2)
haloboard.touchpad0.set_touch_threshold(0.015 * 2)
while True:
if haloboard.touchpad0.is_touched():
print("TouchPad 0 is touched!")
if haloboard.touchpad1.is_touched():
print("TouchPad 1 is touched!")
if haloboard.touchpad2.is_touched():
print("TouchPad 2 is touched!")
if haloboard.touchpad3.is_touched():
print("TouchPad 3 is touched!")
print("val:" + str(haloboard.touchpad0.get_value()) + " ," + str(haloboard.touchpad1.get_value()) + " ," + str(haloboard.touchpad2.get_value()) + " ," + str(haloboard.touchpad3.get_value()))
time.sleep(0.01)
touchpad0
— Touch Button3¶
touchpad0
The main functionality and functions of the module
-
touchpad0.
is_touched
()¶ Gets the current state of touch button 3.This returns True: the touch button 3 is touched, or False: the touch button 3 is not touched.
-
touchpad0.
get_value
()¶ Gets the touched state of the touch button. Values range from 0 to 10000.
-
touchpad0.
set_touch_threshold
()¶ Set the threshold value of the touch button, parameters:
- val - The percentage of touch change, when the detected change amplitude is greater than this percentage,
- it is considered to be touched, and the value range is 0-1.
import haloboard
import time
haloboard.touchpad0.set_touch_threshold(0.01 * 2)
haloboard.touchpad1.set_touch_threshold(0.01 * 2)
haloboard.touchpad0.set_touch_threshold(0.005 * 2)
haloboard.touchpad0.set_touch_threshold(0.015 * 2)
while True:
if haloboard.touchpad0.is_touched():
print("TouchPad 0 is touched!")
if haloboard.touchpad1.is_touched():
print("TouchPad 1 is touched!")
if haloboard.touchpad2.is_touched():
print("TouchPad 2 is touched!")
if haloboard.touchpad3.is_touched():
print("TouchPad 3 is touched!")
print("val:" + str(haloboard.touchpad0.get_value()) + " ," + str(haloboard.touchpad1.get_value()) + " ," + str(haloboard.touchpad2.get_value()) + " ," + str(haloboard.touchpad3.get_value()))
time.sleep(0.01)
vibration_motor
— Vibration Motor¶
vibration_motor
The main functionality and functions of the module
-
vibration_motor.
set_strength
(val)¶ Set the dynamic value of vibration motor, set but not executed, parameters:
- val - Values range from 0 to 100.
-
vibration_motor.
on
(value=None)¶ The vibration motor starts to execute. If no parameters are set, the default value is 100. Parameters:
- value - Values range from 0 to 100.
import haloboard
import time
while True:
print("set_strength 100")
haloboard.vibration_motor.set_strength(100)
haloboard.vibration_motor.on(100)
time.sleep(3)
haloboard.vibration_motor.on(0)
time.sleep(2)
print("set_strength 50")
haloboard.vibration_motor.set_strength(50)
haloboard.vibration_motor.on()
time.sleep(3)
microphone
— Onboard Microphone¶
microphone
The main functionality and functions of the module
-
microphone.
get_loudness
(type)¶ Get the loudness of sound, parameter:
- type - String parameter, a total of two: average, obtain the average loudness in a period of time;Maximum, the maximum loudness over a period of time,
- is the default parameter.The return values range from 0 to 100.
import haloboard
import time
import event
@event.start
def on_start():
while True:
average = haloboard.microphone.get_loudness("average")
maximum = haloboard.microphone.get_loudness("maximum")
print("average:" + str(average), " ,maximum" + str(maximum))
time.sleep(0.2)
@event.greater_than(20, 'microphone')
def on_greater_than():
haloboard.led.show_all(10, 0, 0)
time.sleep(0.2)
haloboard.led.show_all(0, 0, 0)
speaker
— Onboard Speaker¶
speaker
The main functionality and functions of the module
- speaker.volume - Numerical data, the volume of the property value, can be modified or read this value, can modify this value to control the volume.
- Its numerical range is 0 ~ 100。
- speaker.tempo - The numerical data represent the attributes of the playback speed in BMP (beat per minute), the length of each beat.
- The values range form 6 to 600, the default value is 60, which means the duration of a beat is 1 second.The beat of the rest and play_note functions is affected by this constant.
-
speaker.
stop_sound
()¶ Stop audio playback.
-
speaker.
play_melody_until_done
(file_name)¶ Play audio file, this function blocks when playing, parameters:
- file_name- String type, audio file name in wav format burned in haloboard flash, input, can also omit the format suffix.
-
speaker.
play_melody
(file_name)¶ Play audio file, this function does not block when playing, parameters:
- file_name - String type, audio file name in wav format burned in haloboard flash, input, can also omit the format suffix.
-
speaker.
play_tone
(frequency, time_ms=None)¶ Play tone by frequency, parameters:
- frequency - Numerical data, the frequency at which the sound is played, and its numerical range is 0-1000.
- time_ms - Numerical data, indicating the playback time (in millisecond -ms).
- If this parameter is not filled, the playback will continue; otherwise, the playback will be blocked.
-
speaker.
play_note
(note, beat=None)¶ Play notes, numerical note definitions refer to the scratch numerical note description,parameter:
note_num - Numeric types, ranging from 48 to 72, or string types, such as C4, are automatically recognized.
beat - Numerical data, representing the number of beats, if not filled, then play.
- The corresponding relationship between note and frequency is as follows:
-
speaker.
rest
(beat)¶ Speaker stop/rest beats time.
- beat - Numerical type , refers to the number of beats.
import haloboard
import time
haloboard.speaker.tempo = 60
haloboard.speaker.volume = 100
haloboard.speaker.play_melody_until_done("hello")
haloboard.speaker.play_note(48, 1)
haloboard.speaker.rest(1)
haloboard.speaker.play_note("C4", 1)
haloboard.speaker.rest(1)
haloboard.speaker.play_tone(1000, 2)
haloboard.speaker.rest(1)
print("tempo:", end = "")
print(haloboard.speaker.tempo)
print("volume:", end = "")
print(haloboard.speaker.volume)
haloboard.speaker.play_note("C4", 3)
haloboard.speaker.rest(1)
haloboard.speaker.tempo = 120
haloboard.speaker.volume = 20
haloboard.speaker.play_note("C4", 3)
haloboard.speaker.rest(1)
Event’s interface list¶
event
— Event Module¶
event
The main functionality and functions of the module
Method 1: registration method, as the following example:
event.start(test_callback)
event.received(callback, 'hello')
Method 2: modifier notation, as in the following example:
@event.start
def start_callback():
print(123)
@event.received('hello')
def received_callback():
print(123)
Note: when the function has parameters other than callback, the parameter is added.
-
event.
start
(callback)¶ Start event, parameters:
- callback - Callback function.
-
event.
shaked
(callback)¶ Shaking events, parameters:
- callback - Callback function.
Button press event, parameters:
- callback - Callback function.
-
event.
tilted_left
(callback)¶ Tilted left events, parameters:
- callback - Callback function.
-
event.
tilted_right
(callback)¶ Tilted right events, parameters:
- callback - Callback function.
-
event.
arrow_up
(callback)¶ Arrow up event, parameters:
- callback - Callback function.
-
event.
arrow_down
(callback)¶ Arrow down event, parameters:
- callback - Callback function.
-
event.
receieved
(callback, message_str)¶ Broadcast event, parameters:
- callback - Callback function.
- message_str - The name of the broadcast to listen for.
-
event.
cloud_message
(message)¶ Cloud broadcast event, parameters:
- message - String data, the name of the information to broadcast.
-
event.
mesh_message
(message)¶ Mesh broadcast event, parameters:
- message - String data, the name of the information to broadcast.
-
event.
greater_than
(callback, threshold, type_str)¶ Threshold comparison event. If the threshold is exceeded, the event will be triggered. Parameter:
- callback - Callback function.
- threshold - Numeric, trigger threshold.
- type_str - microphone/timer,represents the sound sensor and the timer, which are currently supported only.
-
event.
touchpad0_active
(callback)¶ Touched button, parameters:
- callback - Callback function.
-
event.
touchpad1_active
(callback)¶ Touched button, parameters:
- callback - Callback function.
-
event.
touchpad2_active
(callback)¶ Touched button, parameters:
- callback - Callback function.
-
event.
touchpad3_active
(callback)¶ Touched button, parameters:
- callback - Callback function.
import haloboard
import time
import event
@event.button_pressed
def on_button_pressed():
print("button event successed")
haloboard.broadcast('hello')
haloboard.mesh.broadcast('hello')
@event.start
def on_start():
print("start event successed")
@event.shaked
def on_shaked():
print("shaked event activate")
@event.received("hello")
def received_cb():
print("broadcast received event successed")
@event.tilted_left
def on_tilted_left():
print("tilted left event successed")
@event.tilted_right
def on_tilted_right():
print("tilted right event successed")
@event.arrow_up
def on_arrow_up():
print("arrow up event successed")
@event.arrow_down
def on_arrow_up():
print("arrow down event successed")
@event.greater_than(80, "microphone")
def on_greater_than():
print("sound sensor greater event successed")
@event.greater_than(2, "timer")
def on_greater_than():
print("timer greater event successed")
@event.touchpad0_active
def on_touchpad0_active():
print("touchpad0 active")
@event.touchpad1_active
def on_touchpad1_active():
print("touchpad1 active")
@event.touchpad2_active
def on_touchpad2_active():
print("touchpad2 active")
@event.touchpad3_active
def on_touchpad3_active():
print("touchpad3 active")
@event.cloud_message("hello")
def on_cloud_message():
print("cloud message event successed")
@event.mesh_message("hello")
def on_mesh_message():
print("mesh message event successed")
Cloud message interface list¶
cloud_message
— Cloud Message¶
cloud_message
The main functionality and functions of the module
-
cloud_message.
start
(topic_head, cliend_id=None, server="mq.makeblock.com", port=1883, user=None, password=None, keepalive=60, ssl=False)¶ To turn on the cloud broadcast, you need to ensure the wi-fi connection, and this opening action will take effect, parameter:
- topic_head - Prefix directory for cloud broadcast topics.
- client_id - The unique client ID string used when connecting to the agent is randomly generated if client_id is zero length or none.In this case, the clean_session parameter of the connect function must be True.
- server - The host name or IP address of the remote server.
- port - The network port for the server host to connect to, by default, is 1883.Note: the default port for MQTT over SSL/TLS is 8883.(Optional)
- user - User name registered on the server.(Optional)
- password - The password registered on the server.(Optional)
- keepalive - The client keepalive timeout value is 60 seconds by default.(Optional)
- ssl - Whether SSL/TLS support can be enabled.(Optional)
-
cloud_message.
get_info
(message)¶ Get the attached parameter of broadcast information, return string type or numeric data, parameter:
- message - The name of the information to broadcast.
-
cloud_message.
broadcast
(message, value = "")¶ Broadcast information with parameters, parameters:
- message - The name of the information to broadcast.
- value - Parameters attached to the broadcast message.
import haloboard
import event
haloboard.cloud_message.start('/USER/1014148/MESSAGE')
@event.start
def on_start():
haloboard.wifi.start(ssid = 'Maker-guest', password = 'makeblock', mode = haloboard.wifi.WLAN_MODE_STA)
while not haloboard.wifi.is_connected():
pass
haloboard.led.show_all(126, 211, 33)
time.sleep(2)
haloboard.led.off_all()
haloboard.cloud_message.broadcast('hello', '')
# -*- coding: utf-8 -*-
# generated by mBlock5 for <product>
# codes make you happy
import time
import math
import random
import haloboard, event
# from micropython import mem_info
@event.start
def on_start():
haloboard.led.show_all(50, 50, 50)
haloboard.wifi.start(ssid = 'Maker-guest', password = 'makeblock', mode = haloboard.wifi.WLAN_MODE_STA)
haloboard.cloud_message.start('/USER/11/MESSAGE')
while not haloboard.wifi.is_connected():
pass
haloboard.led.show_all(0, 50, 0)
@event.cloud_message('b')
def on_cloud_message1():
haloboard.led.show_all(50, 0, 0)
print(haloboard.cloud_message.get_info("b"))
@event.cloud_message('a')
def on_cloud_message2():
haloboard.led.show_all(0, 0, 50)
print(haloboard.cloud_message.get_info("a"))
# mem_info()
@event.button_pressed
def on_button_pressed():
haloboard.cloud_message.broadcast('b', "test1")
haloboard.cloud_message.broadcast('a', "test2")
Pin’s interface list¶
pin0
— Pin Port 0¶
pin0
The main functionality and functions of the module
-
pin0.
is_touched
()¶ Gets the current state of the pin port.The result is either “True”: the pin is touched, or “False”: the pin is not touched.
-
pin0.
get_touchpad_value
()¶ Gets the value of the pin that is touched. Values range from 0 to 10000.
-
pin0.
set_touchpad_threshold
(val)¶ Set the touch trigger threshold of pin, parameters:
- val - The percentage of change, when the detected amplitude of change is greater than this percentage,
- it is considered to be touched, and the value is 0.0-1.
-
pin0.
read_digital
()¶ Get the pin port numeric input with a value of 0 or 1.
-
pin0.
write_digital
(val)¶ Set pin digital output, parameters:
- val - The digital output value is 0 or 1.
-
pin0.
write_analog
(val)¶ Set analog output (PWM), parameters:
- val - Analog output values, values range from 0 to 1023.
-
pin0.
read_analog
()¶ Gets the simulated input value (PWM).Values range from 0 to 3300 in mv.
-
pin0.
servo_write
(val)¶ Set servo rotation angle, parameters:
- val - The angle of rotation of the servo, or the high level maintenance time of the servo control pulse, the value is 0-19999.
- When the value is less than 544, if the input data is less than 0, it will be converted to 0, if it is greater than 180, it will be converted to 180, which represents the rotation angle of the simulated steering gear; When the value is greater than or equal to 544, it means that the time width (in us) of the high level of 50Hz PWM wave is set, so the maximum value is 19999, which is nearly 20ms. If it is greater than 19999, it will be converted to 19999.
-
pin0.
analog_set_frequency
(frequency)¶ Set pin analog output (PWM) frequency, parameters:
- frequency - PWM frequency value, value range 0-5000.
import haloboard
import event
@event.start
def on_start():
global results
if haloboard.pin0.is_touched():
haloboard.led.show_all(126, 211, 33)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
PIN_MODE_WRITE_SERVO = 6
pin_mode = PIN_MODE_TOUCH
pin_index = 0
@event.button_pressed
def on_button_pressed():
global pin_mode, pin_index
pin_index = (pin_index + 1) % 10
if pin_index % 2 == 0:
pin_mode = PIN_MODE_TOUCH
print("*****", "in tp mode")
elif pin_index == 1:
pin_mode = PIN_MODE_WRITE_ANALOG
print("*****", "in write analog mode")
elif pin_index == 3:
pin_mode = PIN_MODE_READ_DIGITAL
print("*****", "in read digital mode")
elif pin_index == 5:
pin_mode = PIN_MODE_WRITE_DIGITAL
print("*****", "in write digital mode")
elif pin_index == 7:
pin_mode = PIN_MODE_READ_ANALOG
print("*****", "in read analog mode")
elif pin_index == 9:
pin_mode = PIN_MODE_WRITE_SERVO
print("*****", "in servo mode")
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
time.sleep(0.1)
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_SERVO:
print("write_servo 150")
haloboard.pin2.servo_write(150)
haloboard.pin3.servo_write(150)
time.sleep(2)
print("write_servo 10000")
haloboard.pin2.servo_write(10000)
haloboard.pin3.servo_write(10000)
time.sleep(2)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
import haloboard
import event
pin_mode = 0
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
pin_mode %= 8
if pin_mode < 4:
if pin_mode == 0:
print("pin write servo 0")
haloboard.pin0.servo_write(0)
elif pin_mode == 1:
print("pin write servo 90")
haloboard.pin0.servo_write(90)
elif pin_mode == 2:
print("pin write servo 120")
haloboard.pin0.servo_write(120)
elif pin_mode == 3:
print("pin write servo 180")
haloboard.pin0.servo_write(180)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
pin_mode = PIN_MODE_TOUCH
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
if pin_mode > PIN_MODE_READ_ANALOG:
pin_mode = PIN_MODE_TOUCH
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
pin1
— Pin Port 1¶
pin1
The main functionality and functions of the module
-
pin1.
is_touched
()¶ Gets the current state of the pin port.The result is either “True”: the pin is touched, or “False”: the pin is not touched.
-
pin1.
get_touchpad_value
()¶ Gets the value of the pin that is touched. Values range from 0 to 10000.
-
pin1.
set_touchpad_threshold
(val)¶ Set the touch trigger threshold of pin, parameters:
- val - The percentage of change, when the detected amplitude of change is greater than this percentage,
- it is considered to be touched, and the value is 0.0-1.
-
pin1.
read_digital
()¶ Get the pin port numeric input with a value of 0 or 1.
-
pin1.
write_digital
(val)¶ Set pin digital output, parameters:
- val - The digital output value is 0 or 1.
-
pin1.
write_analog
(val)¶ Set analog output (PWM), parameters:
- val - Analog output values, values range from 0 to 1023.
-
pin1.
read_analog
()¶ Gets the simulated input value (PWM).Values range from 0 to 3300 in mv.
-
pin1.
servo_write
(val)¶ Set servo rotation angle, parameters:
- val - The angle of rotation of the servo, or the high level maintenance time of the servo control pulse, the value is 0-19999.
- When the value is less than 544, if the input data is less than 0, it will be converted to 0, if it is greater than 180, it will be converted to 180, which represents the rotation angle of the simulated steering gear; When the value is greater than or equal to 544, it means that the time width (in us) of the high level of 50Hz PWM wave is set, so the maximum value is 19999, which is nearly 20ms. If it is greater than 19999, it will be converted to 19999.
-
pin1.
analog_set_frequency
(frequency)¶ Set pin analog output (PWM) frequency, parameters:
- frequency - PWM frequency value, value range 0-5000.
import haloboard
import event
@event.start
def on_start():
global results
if haloboard.pin0.is_touched():
haloboard.led.show_all(126, 211, 33)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
PIN_MODE_WRITE_SERVO = 6
pin_mode = PIN_MODE_TOUCH
pin_index = 0
@event.button_pressed
def on_button_pressed():
global pin_mode, pin_index
pin_index = (pin_index + 1) % 10
if pin_index % 2 == 0:
pin_mode = PIN_MODE_TOUCH
print("*****", "in tp mode")
elif pin_index == 1:
pin_mode = PIN_MODE_WRITE_ANALOG
print("*****", "in write analog mode")
elif pin_index == 3:
pin_mode = PIN_MODE_READ_DIGITAL
print("*****", "in read digital mode")
elif pin_index == 5:
pin_mode = PIN_MODE_WRITE_DIGITAL
print("*****", "in write digital mode")
elif pin_index == 7:
pin_mode = PIN_MODE_READ_ANALOG
print("*****", "in read analog mode")
elif pin_index == 9:
pin_mode = PIN_MODE_WRITE_SERVO
print("*****", "in servo mode")
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
time.sleep(0.1)
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_SERVO:
print("write_servo 150")
haloboard.pin2.servo_write(150)
haloboard.pin3.servo_write(150)
time.sleep(2)
print("write_servo 10000")
haloboard.pin2.servo_write(10000)
haloboard.pin3.servo_write(10000)
time.sleep(2)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
import haloboard
import event
pin_mode = 0
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
pin_mode %= 8
if pin_mode < 4:
if pin_mode == 0:
print("pin write servo 0")
haloboard.pin0.servo_write(0)
elif pin_mode == 1:
print("pin write servo 90")
haloboard.pin0.servo_write(90)
elif pin_mode == 2:
print("pin write servo 120")
haloboard.pin0.servo_write(120)
elif pin_mode == 3:
print("pin write servo 180")
haloboard.pin0.servo_write(180)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
pin_mode = PIN_MODE_TOUCH
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
if pin_mode > PIN_MODE_READ_ANALOG:
pin_mode = PIN_MODE_TOUCH
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
pin2
— Pin Port 2¶
pin2
The main functionality and functions of the module
-
pin2.
is_touched
()¶ Gets the current state of the pin port.The result is either “True”: the pin is touched, or “False”: the pin is not touched.
-
pin2.
get_touchpad_value
()¶ Gets the value of the pin that is touched. Values range from 0 to 10000.
-
pin2.
set_touchpad_threshold
(val)¶ Set the touch trigger threshold of pin, parameters:
- val - The percentage of change, when the detected amplitude of change is greater than this percentage,
- it is considered to be touched, and the value is 0.0-1.
-
pin2.
read_digital
()¶ Get the pin port numeric input with a value of 0 or 1.
-
pin2.
write_digital
(val)¶ Set pin digital output, parameters:
- val - The digital output value is 0 or 1.
-
pin2.
write_analog
(val)¶ Set analog output (PWM), parameters:
- val - Analog output values, values range from 0 to 1023.
-
pin2.
read_analog
()¶ Gets the simulated input value (PWM).Values range from 0 to 3300 in mv.
-
pin2.
servo_write
(val)¶ Set servo rotation angle, parameters:
- val - The angle of rotation of the servo, or the high level maintenance time of the servo control pulse, the value is 0-19999.
- When the value is less than 544, if the input data is less than 0, it will be converted to 0, if it is greater than 180, it will be converted to 180, which represents the rotation angle of the simulated steering gear; When the value is greater than or equal to 544, it means that the time width (in us) of the high level of 50Hz PWM wave is set, so the maximum value is 19999, which is nearly 20ms. If it is greater than 19999, it will be converted to 19999.
-
pin2.
analog_set_frequency
(frequency)¶ Set pin analog output (PWM) frequency, parameters:
- frequency - PWM frequency value, value range 0-5000.
import haloboard
import event
@event.start
def on_start():
global results
if haloboard.pin0.is_touched():
haloboard.led.show_all(126, 211, 33)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
PIN_MODE_WRITE_SERVO = 6
pin_mode = PIN_MODE_TOUCH
pin_index = 0
@event.button_pressed
def on_button_pressed():
global pin_mode, pin_index
pin_index = (pin_index + 1) % 10
if pin_index % 2 == 0:
pin_mode = PIN_MODE_TOUCH
print("*****", "in tp mode")
elif pin_index == 1:
pin_mode = PIN_MODE_WRITE_ANALOG
print("*****", "in write analog mode")
elif pin_index == 3:
pin_mode = PIN_MODE_READ_DIGITAL
print("*****", "in read digital mode")
elif pin_index == 5:
pin_mode = PIN_MODE_WRITE_DIGITAL
print("*****", "in write digital mode")
elif pin_index == 7:
pin_mode = PIN_MODE_READ_ANALOG
print("*****", "in read analog mode")
elif pin_index == 9:
pin_mode = PIN_MODE_WRITE_SERVO
print("*****", "in servo mode")
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
time.sleep(0.1)
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_SERVO:
print("write_servo 150")
haloboard.pin2.servo_write(150)
haloboard.pin3.servo_write(150)
time.sleep(2)
print("write_servo 10000")
haloboard.pin2.servo_write(10000)
haloboard.pin3.servo_write(10000)
time.sleep(2)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
import haloboard
import event
pin_mode = 0
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
pin_mode %= 8
if pin_mode < 4:
if pin_mode == 0:
print("pin write servo 0")
haloboard.pin0.servo_write(0)
elif pin_mode == 1:
print("pin write servo 90")
haloboard.pin0.servo_write(90)
elif pin_mode == 2:
print("pin write servo 120")
haloboard.pin0.servo_write(120)
elif pin_mode == 3:
print("pin write servo 180")
haloboard.pin0.servo_write(180)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
pin_mode = PIN_MODE_TOUCH
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
if pin_mode > PIN_MODE_READ_ANALOG:
pin_mode = PIN_MODE_TOUCH
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
pin3
— Pin Port 3¶
pin3
The main functionality and functions of the module
-
pin3.
is_touched
()¶ Gets the current state of the pin port.The result is either “True”: the pin is touched, or “False”: the pin is not touched.
-
pin3.
get_touchpad_value
()¶ Gets the value of the pin that is touched. Values range from 0 to 10000.
-
pin3.
set_touchpad_threshold
(val)¶ Set the touch trigger threshold of pin, parameters:
- val - The percentage of change, when the detected amplitude of change is greater than this percentage,
- it is considered to be touched, and the value is 0.0-1.
-
pin3.
read_digital
()¶ Get the pin port numeric input with a value of 0 or 1.
-
pin3.
write_digital
(val)¶ Set pin digital output, parameters:
- val - The digital output value is 0 or 1.
-
pin3.
write_analog
(val)¶ Set analog output (PWM), parameters:
- val - Analog output values, values range from 0 to 1023.
-
pin3.
read_analog
()¶ Gets the simulated input value (PWM).Values range from 0 to 3300 in mv.
-
pin3.
servo_write
(val)¶ Set servo rotation angle, parameters:
- val - The angle of rotation of the servo, or the high level maintenance time of the servo control pulse, the value is 0-19999.
- When the value is less than 544, if the input data is less than 0, it will be converted to 0, if it is greater than 180, it will be converted to 180, which represents the rotation angle of the simulated steering gear; When the value is greater than or equal to 544, it means that the time width (in us) of the high level of 50Hz PWM wave is set, so the maximum value is 19999, which is nearly 20ms. If it is greater than 19999, it will be converted to 19999.
-
pin3.
analog_set_frequency
(frequency)¶ Set pin analog output (PWM) frequency, parameters:
- frequency - PWM frequency value, value range 0-5000.
import haloboard
import event
@event.start
def on_start():
global results
if haloboard.pin0.is_touched():
haloboard.led.show_all(126, 211, 33)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
PIN_MODE_WRITE_SERVO = 6
pin_mode = PIN_MODE_TOUCH
pin_index = 0
@event.button_pressed
def on_button_pressed():
global pin_mode, pin_index
pin_index = (pin_index + 1) % 10
if pin_index % 2 == 0:
pin_mode = PIN_MODE_TOUCH
print("*****", "in tp mode")
elif pin_index == 1:
pin_mode = PIN_MODE_WRITE_ANALOG
print("*****", "in write analog mode")
elif pin_index == 3:
pin_mode = PIN_MODE_READ_DIGITAL
print("*****", "in read digital mode")
elif pin_index == 5:
pin_mode = PIN_MODE_WRITE_DIGITAL
print("*****", "in write digital mode")
elif pin_index == 7:
pin_mode = PIN_MODE_READ_ANALOG
print("*****", "in read analog mode")
elif pin_index == 9:
pin_mode = PIN_MODE_WRITE_SERVO
print("*****", "in servo mode")
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
time.sleep(0.1)
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_SERVO:
print("write_servo 150")
haloboard.pin2.servo_write(150)
haloboard.pin3.servo_write(150)
time.sleep(2)
print("write_servo 10000")
haloboard.pin2.servo_write(10000)
haloboard.pin3.servo_write(10000)
time.sleep(2)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
import haloboard
import event
pin_mode = 0
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
pin_mode %= 8
if pin_mode < 4:
if pin_mode == 0:
print("pin write servo 0")
haloboard.pin0.servo_write(0)
elif pin_mode == 1:
print("pin write servo 90")
haloboard.pin0.servo_write(90)
elif pin_mode == 2:
print("pin write servo 120")
haloboard.pin0.servo_write(120)
elif pin_mode == 3:
print("pin write servo 180")
haloboard.pin0.servo_write(180)
import haloboard
import event
PIN_MODE_TOUCH = 1
PIN_MODE_READ_DIGITAL = 2
PIN_MODE_WRITE_DIGITAL = 3
PIN_MODE_WRITE_ANALOG = 4
PIN_MODE_READ_ANALOG = 5
pin_mode = PIN_MODE_TOUCH
@event.button_pressed
def on_button_pressed():
global pin_mode
pin_mode = pin_mode + 1
if pin_mode > PIN_MODE_READ_ANALOG:
pin_mode = PIN_MODE_TOUCH
print("pin mode is: " + str(pin_mode))
@event.start
def on_start():
global pin_mode
while True:
if pin_mode == PIN_MODE_TOUCH:
if haloboard.pin0.is_touched():
print("pin0 is touched")
if haloboard.pin1.is_touched():
print("pin1 is touched")
if haloboard.pin2.is_touched():
print("pin2 is touched")
if haloboard.pin3.is_touched():
print("pin3 is touched")
if pin_mode == PIN_MODE_READ_DIGITAL:
print("pin0:", end = "")
print(haloboard.pin0.read_digital(), end = "")
print(" ,pin1:", end = "")
print(haloboard.pin1.read_digital(), end = "")
print(" ,pin2:", end = "")
print(haloboard.pin2.read_digital(), end = "")
print(" ,pin3:", end = "")
print(haloboard.pin3.read_digital())
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_DIGITAL:
print("write_digital HIGH")
haloboard.pin0.write_digital(1)
haloboard.pin1.write_digital(1)
haloboard.pin2.write_digital(1)
haloboard.pin3.write_digital(1)
time.sleep(1)
print("write_digital LOW")
haloboard.pin0.write_digital(0)
haloboard.pin1.write_digital(0)
haloboard.pin2.write_digital(0)
haloboard.pin3.write_digital(0)
time.sleep(1)
if pin_mode == PIN_MODE_WRITE_ANALOG:
print("write_analog 512")
haloboard.pin0.write_analog(512)
haloboard.pin1.write_analog(512)
haloboard.pin2.write_analog(512)
haloboard.pin3.write_analog(512)
time.sleep(1)
if pin_mode == PIN_MODE_READ_ANALOG:
print("pin2:", end = "")
print(haloboard.pin2.read_analog(), end = "")
print("pin3:", end = "")
print(haloboard.pin3.read_analog())
time.sleep(1)
Speech recognition interface list¶
speech_recognition
— Speech Recognition¶
speech_recognition
The main functionality and functions of the module
-
speech_recognition.
start
(server, language)¶ Start the speech recognition service, parameters:
- server - server name
- language - Recognized language
-
speech_recognition.
get_error_code
()¶ Gets the error code for the resulting data. The corresponding result of the return value is as follows:
- 0 : Right back
- 3300:Incorrect voice input parameters
- 3301:Voice data is not clear
- 3302:Authentication failed
- 3303:Raw audio or server issues
- 3304:User request overrun (QPS)
- 3305:User request overrun (pv-daily request volume)
- 3307: Server side problem
- 3308:Audio data is too long
- 3309:Audio data anomaly
- 3310:Audio file too large
- 3311:Sampling rate error
- 3312:Audio format error
- 3333:Unknown error
- 3334:Response timeout
-
speech_recognition.
get_error_message
()¶ Gets the details of the error, string type.
-
speech_recognition.
get_result_code
()¶ Gets the recognized result and returns an empty string if an error or timeout occurs.
-
speech_recognition.
get_sn_code
()¶ Get the unique identity of voice data, generated by the server system.
-
speech_recognition.
get_all_respond
()¶ Get the speech recognition result, including the whole reply message, such as error message, etc.
# -*- coding: utf-8 -*-
import haloboard
import time
import event
@event.start
def use_code():
haloboard.wifi.start(ssid = "Maker-guest", password = "makeblock", mode = haloboard.wifi.WLAN_MODE_STA)
while(True):
if haloboard.wifi.is_connected() == True:
print("wifi is connected!")
break;
while True:
if haloboard.button.is_pressed():
haloboard.led.show_all(0, 0, 50)
haloboard.speech_recognition.start(haloboard.speech_recognition.SERVER_MICROSOFT, haloboard.speech_recognition.LAN_DEFAULT, 2)
if haloboard.speech_recognition.get_error_code() != 0:
str = haloboard.speech_recognition.get_error_message()
print("error_message:" + str)
else:
result = haloboard.speech_recognition.get_result_code()
print("result:" + result)
if '红色' in result:
haloboard.led.show_all(50, 0, 0)
elif '黄色' in result:
haloboard.led.show_all(50, 50, 0)
elif '白色' in result:
haloboard.led.show_all(50, 50, 50)
elif '蓝色' in result:
haloboard.led.show_all(0, 0, 50)
elif '绿色' in result:
haloboard.led.show_all(0, 50, 0)
else:
haloboard.led.show_all(0, 0, 0)
time.sleep(0.5)
# -*- coding: utf-8 -*-
import haloboard
import time
import event
haloboard.speech_recognition.set_recognition_url(haloboard.speech_recognition.SERVER_MICROSOFT, "http://msapi.passport3.makeblock.com/ms/bing_speech/interactive")
haloboard.speech_recognition.set_token(haloboard.speech_recognition.SERVER_MICROSOFT, "ed8xubrmidv")
# haloboard.speech_recognition.set_account(haloboard.speech_recognition.SERVER_MICROSOFT, "embeded@makeblock.com", "123456")
@event.start
def use_code():
haloboard.wifi.start(ssid = "Maker-guest", password = "makeblock", mode = haloboard.wifi.WLAN_MODE_STA)
while(True):
if haloboard.wifi.is_connected() == True:
print("wifi is connected!")
break;
while True:
if haloboard.button.is_pressed():
haloboard.led.show_all(0, 0, 50)
haloboard.speech_recognition.start(haloboard.speech_recognition.SERVER_MICROSOFT, haloboard.speech_recognition.LAN_DEFAULT, 2)
if haloboard.speech_recognition.get_error_code() != 0:
str = haloboard.speech_recognition.get_error_message()
print("error_message:" + str)
else:
result = haloboard.speech_recognition.get_result_code()
print("result:" + result)
if '红色' in result:
haloboard.led.show_all(50, 0, 0)
elif '黄色' in result:
haloboard.led.show_all(50, 50, 0)
elif '白色' in result:
haloboard.led.show_all(50, 50, 50)
elif '蓝色' in result:
haloboard.led.show_all(0, 0, 50)
elif '绿色' in result:
haloboard.led.show_all(0, 50, 0)
else:
haloboard.led.show_all(0, 0, 0)
time.sleep(0.5)
Timer’s interface list¶
timer
— Timer¶
timer
The main functionality and functions of the module
-
timer.
get_timer
()¶ Gets the system timer time in seconds.
-
timer.
reset_timer
()¶ Reset system timer time.
import haloboard
import time
haloboard.reset_timer()
while True:
if haloboard.button.is_pressed():
haloboard.reset_timer()
print("reset_timer")
print("time:", end = "")
print(haloboard.get_timer())
Wifi’s interface list¶
wifi
— Onboard WIFI¶
wifi
The main functionality and functions of the module
-
wifi.
start
(ssid = "wifi_ssid", password = "password", mode = haloboard.wifi.STA)¶ Start wifi connection, the API is not blocked, API exit does not mean that the Wi-Fi is connected, “wifi.is_connected()”” needs to be called to determine, parameter:
- ssid - String type, Wi-Fi account.
- password - String type, Wi-Fi password.
- mode - Enable Wi-Fi mode, currently only supports WLAN_MODE_STA mode.
-
wifi.
set_mode
(mode)¶ Set Wi-Fi mode, parameters:
- mode - Refers to Wi-Fi mode, currently only supports WLAN_MODE_STA mode.
-
wifi.
connect
()¶ Connect WiFi.
-
wifi.
is_connected
()¶ Detect the wi-fi connection status, and the return value is a boolean value, where “True” indicates that the Wi-Fi connection has been established and “False” indicates that the Wi-Fi connection has not been established.
-
wifi.
disconnect
()¶ Disconnect WiFi.
import haloboard
haloboard.wifi.start('Maker-guest', 'makeblock')
haloboard.led.show_all(0,0,0)
while True:
if haloboard.wifi.is_connected():
haloboard.led.show_all(0,0,255)
else:
haloboard.led.show_all(0,0,0)
import haloboard
import event
@event.button_pressed
def on_button():
haloboard.stop_other_scripts()
print("start toconnect Maker-guest")
haloboard.wifi.start('Maker-guest', 'makeblock')
haloboard.led.show_all(0,0,0)
while True:
if haloboard.wifi.is_connected():
haloboard.led.show_all(0,0,255)
break
else:
haloboard.led.show_all(0,0,0)
@event.touchpad0_active
def on_touchpad0_active():
haloboard.stop_other_scripts()
print("start toconnect iPhone fftust")
haloboard.wifi.start('iPhone fftust', '19920112')
haloboard.led.show_all(0,0,0)
while True:
if haloboard.wifi.is_connected():
haloboard.led.show_all(0,0,255)
break
else:
haloboard.led.show_all(0,0,0)
Haloboard’s example tutorial¶
The purpose of this tutorial is to get you started using haloboard. We need you to have a haloboard, and secondly you need a USB cable (or Bluetooth dongle) to connect to the haloboard. If you are using Python programming for haloboard for the first time, It is recommended to read this section.
haloboard typical example
Haloboard’s micropython instructions¶
Open and connect the webrepl in Haloboard¶
Webrepl is micropython’s management platform for providing wireless connectivity.
- Step 1:Burn down firmware
- Make sure your firmware is ready.
- Step 2:Connect to the network
- Open the serial assistant (such as putty, secureCRT, etc.), use USB to connect the haloboard and the computer. Press CTRL +e to enter the code paste mode.(Note: ssid is the name of WiFi, password is the password of WiFi)
import network
import time
ssid=''
password=''
wlan=network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid,password)
i=0
while(wlan.ifconfig()[0]=='0.0.0.0' and i < 100):
i=i+1
time.sleep(1)
if(wlan.ifconfig()[0]=='0.0.0.0'):
print('connect Wifi False!')
#return False
else:
print('connect Wifi True!')
print(wlan.ifconfig())
#return True

As shown in the figure above, the network configuration is completed and the IP address of the module is output.
- Step 3:Configuration webrepl
- 1.Input to the serial port
import webrepl_setup

As shown in the figure above, input to the serial port: import webrepl_setup.
2.Enter E to confirm the opening of webrepl, and enter the password twice continuously to complete the configuration

As shown in the figure above, enter the password twice.
3.Manual input: import webrepl and webrepl.start() ,open webrepl

As shown in the figure above, open webrepl.
- Step 4:Connect webrepl
- 1.Open the webrepl network address:http://micropython.org/webrepl/

As shown in the figure above, webrepl UI.
2.Enter the IP address in step 3, click Connect, and enter the password (Note: the password is not displayed when entering!).

As shown in the figure above, interface successfully connected.
3.You can try this by typing help()

- Step 5:Configure boot connection WiFi and turn on webrepl
- 1.New boot.py,as follow:
import time
ssid=''
password=''
def connectWifi():
wlan=network.WLAN(network.STA_IF) #create a wlan object
wlan.active(True) #Activate the network interface
wlan.connect(ssid,password)
i=0
while(wlan.ifconfig()[0]=='0.0.0.0' and i < 10):
i=i+1
time.sleep(1)
if(wlan.ifconfig()[0]=='0.0.0.0'):
print('connect Wifi False!')
return False
else:
print('connect Wifi True!')
print(wlan.ifconfig())
return True
if(connectWifi() == True):
import webrepl
webrepl.start()
Note: fill in the ssid and password of the code above.
2.Back to the website interface of webrepl, click browse under “Send a file” in the right column, select boot.py just written, click “Send to device”, and wait for the upload to complete

As shown in the figure above, send a file.
- 3.Enter CTRL +d or restart Haloboard without power. Connect again after the restart.
- At this point in the open webrepl website can be managed haloboard, rather than a serial line.
MicroPython libraries¶
Warning
Important summary of this section
- MicroPython implements a subset of Python functionality for each module.
- To ease extensibility, MicroPython versions of standard Python modules
usually have
u
(“micro”) prefix. - Any particular MicroPython variant or port may miss any feature/function described in this general documentation (due to resource constraints or other limitations).
This chapter describes modules (function and class libraries) which are built into MicroPython. There are a few categories of such modules:
- Modules which implement a subset of standard Python functionality and are not intended to be extended by the user.
- Modules which implement a subset of Python functionality, with a provision for extension by the user (via Python code).
- Modules which implement MicroPython extensions to the Python standard libraries.
- Modules specific to a particular
MicroPython port
and thus not portable.
Note about the availability of the modules and their contents: This documentation in general aspires to describe all modules and functions/classes which are implemented in MicroPython project. However, MicroPython is highly configurable, and each port to a particular board/embedded system makes available only a subset of MicroPython libraries. For officially supported ports, there is an effort to either filter out non-applicable items, or mark individual descriptions with “Availability:” clauses describing which ports provide a given feature.
With that in mind, please still be warned that some functions/classes
in a module (or even the entire module) described in this documentation may be
unavailable in a particular build of MicroPython on a particular system. The
best place to find general information of the availability/non-availability
of a particular feature is the “General Information” section which contains
information pertaining to a specific MicroPython port
.
On some ports you are able to discover the available, built-in libraries that can be imported by entering the following at the REPL:
help('modules')
Beyond the built-in libraries described in this documentation, many more
modules from the Python standard library, as well as further MicroPython
extensions to it, can be found in micropython-lib
.
Python standard libraries and micro-libraries¶
The following standard Python libraries have been “micro-ified” to fit in with
the philosophy of MicroPython. They provide the core functionality of that
module and are intended to be a drop-in replacement for the standard Python
library. Some modules below use a standard Python name, but prefixed with “u”,
e.g. ujson
instead of json
. This is to signify that such a module is
micro-library, i.e. implements only a subset of CPython module functionality.
By naming them differently, a user has a choice to write a Python-level module
to extend functionality for better compatibility with CPython (indeed, this is
what done by the micropython-lib
project mentioned above).
On some embedded platforms, where it may be cumbersome to add Python-level
wrapper modules to achieve naming compatibility with CPython, micro-modules
are available both by their u-name, and also by their non-u-name. The
non-u-name can be overridden by a file of that name in your library path (sys.path
).
For example, import json
will first search for a file json.py
(or package
directory json
) and load that module if it is found. If nothing is found,
it will fallback to loading the built-in ujson
module.
Builtin functions and exceptions¶
All builtin functions and exceptions are described here. They are also
available via builtins
module.
Functions and types¶
-
abs
()¶
-
all
()¶
-
any
()¶
-
bin
()¶
-
class
bool
¶
-
class
bytearray
¶
-
class
bytes
¶ See CPython documentation:
python:bytes
.
-
callable
()¶
-
chr
()¶
-
classmethod
()¶
-
compile
()¶
-
class
complex
¶
-
delattr
(obj, name)¶ The argument name should be a string, and this function deletes the named attribute from the object given by obj.
-
class
dict
¶
-
dir
()¶
-
divmod
()¶
-
enumerate
()¶
-
eval
()¶
-
exec
()¶
-
filter
()¶
-
class
float
¶
-
class
frozenset
¶
-
getattr
()¶
-
globals
()¶
-
hasattr
()¶
-
hash
()¶
-
hex
()¶
-
id
()¶
-
input
()¶
-
class
int
¶
-
isinstance
()¶
-
issubclass
()¶
-
iter
()¶
-
len
()¶
-
class
list
¶
-
locals
()¶
-
map
()¶
-
max
()¶
-
class
memoryview
¶
-
min
()¶
-
next
()¶
-
class
object
¶
-
oct
()¶
-
open
()¶
-
ord
()¶
-
pow
()¶
-
print
()¶
-
property
()¶
-
range
()¶
-
repr
()¶
-
reversed
()¶
-
round
()¶
-
class
set
¶
-
setattr
()¶
-
class
slice
¶ The slice builtin is the type that slice objects have.
-
sorted
()¶
-
staticmethod
()¶
-
class
str
¶
-
sum
()¶
-
super
()¶
-
class
tuple
¶
-
type
()¶
-
zip
()¶
Exceptions¶
-
exception
AssertionError
¶
-
exception
AttributeError
¶
-
exception
Exception
¶
-
exception
ImportError
¶
-
exception
IndexError
¶
-
exception
KeyboardInterrupt
¶
-
exception
KeyError
¶
-
exception
MemoryError
¶
-
exception
NameError
¶
-
exception
NotImplementedError
¶
-
exception
OSError
¶ See CPython documentation:
python:OSError
. MicroPython doesn’t implementerrno
attribute, instead use the standard way to access exception arguments:exc.args[0]
.
-
exception
RuntimeError
¶
-
exception
StopIteration
¶
-
exception
SyntaxError
¶
-
exception
SystemExit
¶ See CPython documentation:
python:SystemExit
.
-
exception
TypeError
¶ See CPython documentation:
python:TypeError
.
-
exception
ValueError
¶
-
exception
ZeroDivisionError
¶
array
– arrays of numeric data¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:array
.
Supported format codes: b
, B
, h
, H
, i
, I
, l
,
L
, q
, Q
, f
, d
(the latter 2 depending on the
floating-point support).
Classes¶
-
class
array.
array
(typecode[, iterable])¶ Create array with elements of given type. Initial contents of the array are given by iterable. If it is not provided, an empty array is created.
-
append
(val)¶ Append new element val to the end of array, growing it.
-
extend
(iterable)¶ Append new elements as contained in iterable to the end of array, growing it.
-
cmath
– mathematical functions for complex numbers¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:cmath
.
The cmath
module provides some basic mathematical functions for
working with complex numbers.
Availability: not available on WiPy and ESP8266. Floating point support required for this module.
Functions¶
-
cmath.
cos
(z)¶ Return the cosine of
z
.
-
cmath.
exp
(z)¶ Return the exponential of
z
.
-
cmath.
log
(z)¶ Return the natural logarithm of
z
. The branch cut is along the negative real axis.
-
cmath.
log10
(z)¶ Return the base-10 logarithm of
z
. The branch cut is along the negative real axis.
-
cmath.
phase
(z)¶ Returns the phase of the number
z
, in the range (-pi, +pi].
-
cmath.
polar
(z)¶ Returns, as a tuple, the polar form of
z
.
-
cmath.
rect
(r, phi)¶ Returns the complex number with modulus
r
and phasephi
.
-
cmath.
sin
(z)¶ Return the sine of
z
.
-
cmath.
sqrt
(z)¶ Return the square-root of
z
.
gc
– control the garbage collector¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:gc
.
Functions¶
-
gc.
enable
()¶ Enable automatic garbage collection.
-
gc.
disable
()¶ Disable automatic garbage collection. Heap memory can still be allocated, and garbage collection can still be initiated manually using
gc.collect()
.
-
gc.
collect
()¶ Run a garbage collection.
-
gc.
mem_alloc
()¶ Return the number of bytes of heap RAM that are allocated.
Difference to CPython
This function is MicroPython extension.
-
gc.
mem_free
()¶ Return the number of bytes of available heap RAM, or -1 if this amount is not known.
Difference to CPython
This function is MicroPython extension.
-
gc.
threshold
([amount])¶ Set or query the additional GC allocation threshold. Normally, a collection is triggered only when a new allocation cannot be satisfied, i.e. on an out-of-memory (OOM) condition. If this function is called, in addition to OOM, a collection will be triggered each time after amount bytes have been allocated (in total, since the previous time such an amount of bytes have been allocated). amount is usually specified as less than the full heap size, with the intention to trigger a collection earlier than when the heap becomes exhausted, and in the hope that an early collection will prevent excessive memory fragmentation. This is a heuristic measure, the effect of which will vary from application to application, as well as the optimal value of the amount parameter.
Calling the function without argument will return the current value of the threshold. A value of -1 means a disabled allocation threshold.
Difference to CPython
This function is a MicroPython extension. CPython has a similar function -
set_threshold()
, but due to different GC implementations, its signature and semantics are different.
math
– mathematical functions¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:math
.
The math
module provides some basic mathematical functions for
working with floating-point numbers.
Note: On the pyboard, floating-point numbers have 32-bit precision.
Availability: not available on WiPy. Floating point support required for this module.
Functions¶
-
math.
acos
(x)¶ Return the inverse cosine of
x
.
-
math.
acosh
(x)¶ Return the inverse hyperbolic cosine of
x
.
-
math.
asin
(x)¶ Return the inverse sine of
x
.
-
math.
asinh
(x)¶ Return the inverse hyperbolic sine of
x
.
-
math.
atan
(x)¶ Return the inverse tangent of
x
.
-
math.
atan2
(y, x)¶ Return the principal value of the inverse tangent of
y/x
.
-
math.
atanh
(x)¶ Return the inverse hyperbolic tangent of
x
.
-
math.
ceil
(x)¶ Return an integer, being
x
rounded towards positive infinity.
-
math.
copysign
(x, y)¶ Return
x
with the sign ofy
.
-
math.
cos
(x)¶ Return the cosine of
x
.
-
math.
cosh
(x)¶ Return the hyperbolic cosine of
x
.
-
math.
degrees
(x)¶ Return radians
x
converted to degrees.
-
math.
erf
(x)¶ Return the error function of
x
.
-
math.
erfc
(x)¶ Return the complementary error function of
x
.
-
math.
exp
(x)¶ Return the exponential of
x
.
-
math.
expm1
(x)¶ Return
exp(x) - 1
.
-
math.
fabs
(x)¶ Return the absolute value of
x
.
-
math.
floor
(x)¶ Return an integer, being
x
rounded towards negative infinity.
-
math.
fmod
(x, y)¶ Return the remainder of
x/y
.
-
math.
frexp
(x)¶ Decomposes a floating-point number into its mantissa and exponent. The returned value is the tuple
(m, e)
such thatx == m * 2**e
exactly. Ifx == 0
then the function returns(0.0, 0)
, otherwise the relation0.5 <= abs(m) < 1
holds.
-
math.
gamma
(x)¶ Return the gamma function of
x
.
-
math.
isfinite
(x)¶ Return
True
ifx
is finite.
-
math.
isinf
(x)¶ Return
True
ifx
is infinite.
-
math.
isnan
(x)¶ Return
True
ifx
is not-a-number
-
math.
ldexp
(x, exp)¶ Return
x * (2**exp)
.
-
math.
lgamma
(x)¶ Return the natural logarithm of the gamma function of
x
.
-
math.
log
(x)¶ Return the natural logarithm of
x
.
-
math.
log10
(x)¶ Return the base-10 logarithm of
x
.
-
math.
log2
(x)¶ Return the base-2 logarithm of
x
.
-
math.
modf
(x)¶ Return a tuple of two floats, being the fractional and integral parts of
x
. Both return values have the same sign asx
.
-
math.
pow
(x, y)¶ Returns
x
to the power ofy
.
-
math.
radians
(x)¶ Return degrees
x
converted to radians.
-
math.
sin
(x)¶ Return the sine of
x
.
-
math.
sinh
(x)¶ Return the hyperbolic sine of
x
.
-
math.
sqrt
(x)¶ Return the square root of
x
.
-
math.
tan
(x)¶ Return the tangent of
x
.
-
math.
tanh
(x)¶ Return the hyperbolic tangent of
x
.
-
math.
trunc
(x)¶ Return an integer, being
x
rounded towards 0.
sys
– system specific functions¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:sys
.
Functions¶
-
sys.
exit
(retval=0)¶ Terminate current program with a given exit code. Underlyingly, this function raise as
SystemExit
exception. If an argument is given, its value given as an argument toSystemExit
.
-
sys.
print_exception
(exc, file=sys.stdout)¶ Print exception with a traceback to a file-like object file (or
sys.stdout
by default).Difference to CPython
This is simplified version of a function which appears in the
traceback
module in CPython. Unliketraceback.print_exception()
, this function takes just exception value instead of exception type, exception value, and traceback object; file argument should be positional; further arguments are not supported. CPython-compatibletraceback
module can be found inmicropython-lib
.
Constants¶
-
sys.
argv
¶ A mutable list of arguments the current program was started with.
-
sys.
byteorder
¶ The byte order of the system (
"little"
or"big"
).
-
sys.
implementation
¶ Object with information about the current Python implementation. For MicroPython, it has following attributes:
- name - string “micropython”
- version - tuple (major, minor, micro), e.g. (1, 7, 0)
This object is the recommended way to distinguish MicroPython from other Python implementations (note that it still may not exist in the very minimal ports).
Difference to CPython
CPython mandates more attributes for this object, but the actual useful bare minimum is implemented in MicroPython.
-
sys.
maxsize
¶ Maximum value which a native integer type can hold on the current platform, or maximum value representable by MicroPython integer type, if it’s smaller than platform max value (that is the case for MicroPython ports without long int support).
This attribute is useful for detecting “bitness” of a platform (32-bit vs 64-bit, etc.). It’s recommended to not compare this attribute to some value directly, but instead count number of bits in it:
bits = 0 v = sys.maxsize while v: bits += 1 v >>= 1 if bits > 32: # 64-bit (or more) platform ... else: # 32-bit (or less) platform # Note that on 32-bit platform, value of bits may be less than 32 # (e.g. 31) due to peculiarities described above, so use "> 16", # "> 32", "> 64" style of comparisons.
-
sys.
modules
¶ Dictionary of loaded modules. On some ports, it may not include builtin modules.
-
sys.
path
¶ A mutable list of directories to search for imported modules.
-
sys.
platform
¶ The platform that MicroPython is running on. For OS/RTOS ports, this is usually an identifier of the OS, e.g.
"linux"
. For baremetal ports it is an identifier of a board, e.g."pyboard"
for the original MicroPython reference board. It thus can be used to distinguish one board from another. If you need to check whether your program runs on MicroPython (vs other Python implementation), usesys.implementation
instead.
-
sys.
version
¶ Python language version that this implementation conforms to, as a string.
-
sys.
version_info
¶ Python language version that this implementation conforms to, as a tuple of ints.
ubinascii
– binary/ASCII conversions¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:binascii
.
This module implements conversions between binary data and various encodings of it in ASCII form (in both directions).
Functions¶
-
ubinascii.
hexlify
(data[, sep])¶ Convert binary data to hexadecimal representation. Returns bytes string.
Difference to CPython
If additional argument, sep is supplied, it is used as a separator between hexadecimal values.
-
ubinascii.
unhexlify
(data)¶ Convert hexadecimal data to binary representation. Returns bytes string. (i.e. inverse of hexlify)
-
ubinascii.
a2b_base64
(data)¶ Decode base64-encoded data, ignoring invalid characters in the input. Conforms to RFC 2045 s.6.8. Returns a bytes object.
ucollections
– collection and container types¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:collections
.
This module implements advanced collection and container types to hold/accumulate various objects.
Classes¶
-
ucollections.
deque
(iterable, maxlen[, flags])¶ Deques (double-ended queues) are a list-like container that support O(1) appends and pops from either side of the deque. New deques are created using the following arguments:
- iterable must be the empty tuple, and the new deque is created empty.
- maxlen must be specified and the deque will be bounded to this maximum length. Once the deque is full, any new items added will discard items from the opposite end.
- The optional flags can be 1 to check for overflow when adding items.
As well as supporting
bool
andlen
, deque objects have the following methods:-
deque.
append
(x)¶ Add x to the right side of the deque. Raises IndexError if overflow checking is enabled and there is no more room left.
-
deque.
popleft
()¶ Remove and return an item from the left side of the deque. Raises IndexError if no items are present.
-
ucollections.
namedtuple
(name, fields)¶ This is factory function to create a new namedtuple type with a specific name and set of fields. A namedtuple is a subclass of tuple which allows to access its fields not just by numeric index, but also with an attribute access syntax using symbolic field names. Fields is a sequence of strings specifying field names. For compatibility with CPython it can also be a a string with space-separated field named (but this is less efficient). Example of use:
from ucollections import namedtuple MyTuple = namedtuple("MyTuple", ("id", "name")) t1 = MyTuple(1, "foo") t2 = MyTuple(2, "bar") print(t1.name) assert t2.name == t2[1]
-
ucollections.
OrderedDict
(...)¶ dict
type subclass which remembers and preserves the order of keys added. When ordered dict is iterated over, keys/items are returned in the order they were added:from ucollections import OrderedDict # To make benefit of ordered keys, OrderedDict should be initialized # from sequence of (key, value) pairs. d = OrderedDict([("z", 1), ("a", 2)]) # More items can be added as usual d["w"] = 5 d["b"] = 3 for k, v in d.items(): print(k, v)
Output:
z 1 a 2 w 5 b 3
uerrno
– system error codes¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:errno
.
This module provides access to symbolic error codes for OSError
exception.
A particular inventory of codes depends on MicroPython port
.
Constants¶
-
EEXIST, EAGAIN, etc.
Error codes, based on ANSI C/POSIX standard. All error codes start with “E”. As mentioned above, inventory of the codes depends on
MicroPython port
. Errors are usually accessible asexc.args[0]
whereexc
is an instance ofOSError
. Usage example:try: uos.mkdir("my_dir") except OSError as exc: if exc.args[0] == uerrno.EEXIST: print("Directory already exists")
-
uerrno.
errorcode
¶ Dictionary mapping numeric error codes to strings with symbolic error code (see above):
>>> print(uerrno.errorcode[uerrno.EEXIST]) EEXIST
uhashlib
– hashing algorithms¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:hashlib
.
This module implements binary data hashing algorithms. The exact inventory of available algorithms depends on a board. Among the algorithms which may be implemented:
- SHA256 - The current generation, modern hashing algorithm (of SHA2 series). It is suitable for cryptographically-secure purposes. Included in the MicroPython core and any board is recommended to provide this, unless it has particular code size constraints.
- SHA1 - A previous generation algorithm. Not recommended for new usages, but SHA1 is a part of number of Internet standards and existing applications, so boards targeting network connectivity and interoperatiability will try to provide this.
- MD5 - A legacy algorithm, not considered cryptographically secure. Only selected boards, targeting interoperatibility with legacy applications, will offer this.
Constructors¶
-
class
uhashlib.
sha256
([data])¶ Create an SHA256 hasher object and optionally feed
data
into it.
-
class
uhashlib.
sha1
([data])¶ Create an SHA1 hasher object and optionally feed
data
into it.
-
class
uhashlib.
md5
([data])¶ Create an MD5 hasher object and optionally feed
data
into it.
Methods¶
-
hash.
update
(data)¶ Feed more binary data into hash.
-
hash.
digest
()¶ Return hash for all data passed through hash, as a bytes object. After this method is called, more data cannot be fed into the hash any longer.
-
hash.
hexdigest
()¶ This method is NOT implemented. Use
ubinascii.hexlify(hash.digest())
to achieve a similar effect.
uheapq
– heap queue algorithm¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:heapq
.
This module implements the heap queue algorithm.
A heap queue is simply a list that has its elements stored in a certain way.
uio
– input/output streams¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:io
.
This module contains additional types of stream
(file-like) objects
and helper functions.
Conceptual hierarchy¶
Difference to CPython
Conceptual hierarchy of stream base classes is simplified in MicroPython, as described in this section.
(Abstract) base stream classes, which serve as a foundation for behavior of all the concrete classes, adhere to few dichotomies (pair-wise classifications) in CPython. In MicroPython, they are somewhat simplified and made implicit to achieve higher efficiencies and save resources.
An important dichotomy in CPython is unbuffered vs buffered streams. In MicroPython, all streams are currently unbuffered. This is because all modern OSes, and even many RTOSes and filesystem drivers already perform buffering on their side. Adding another layer of buffering is counter- productive (an issue known as “bufferbloat”) and takes precious memory. Note that there still cases where buffering may be useful, so we may introduce optional buffering support at a later time.
But in CPython, another important dichotomy is tied with “bufferedness” - it’s whether a stream may incur short read/writes or not. A short read is when a user asks e.g. 10 bytes from a stream, but gets less, similarly for writes. In CPython, unbuffered streams are automatically short operation susceptible, while buffered are guarantee against them. The no short read/writes is an important trait, as it allows to develop more concise and efficient programs - something which is highly desirable for MicroPython. So, while MicroPython doesn’t support buffered streams, it still provides for no-short-operations streams. Whether there will be short operations or not depends on each particular class’ needs, but developers are strongly advised to favor no-short-operations behavior for the reasons stated above. For example, MicroPython sockets are guaranteed to avoid short read/writes. Actually, at this time, there is no example of a short-operations stream class in the core, and one would be a port-specific class, where such a need is governed by hardware peculiarities.
The no-short-operations behavior gets tricky in case of non-blocking streams, blocking vs non-blocking behavior being another CPython dichotomy, fully supported by MicroPython. Non-blocking streams never wait for data either to arrive or be written - they read/write whatever possible, or signal lack of data (or ability to write data). Clearly, this conflicts with “no-short-operations” policy, and indeed, a case of non-blocking buffered (and this no-short-ops) streams is convoluted in CPython - in some places, such combination is prohibited, in some it’s undefined or just not documented, in some cases it raises verbose exceptions. The matter is much simpler in MicroPython: non-blocking stream are important for efficient asynchronous operations, so this property prevails on the “no-short-ops” one. So, while blocking streams will avoid short reads/writes whenever possible (the only case to get a short read is if end of file is reached, or in case of error (but errors don’t return short data, but raise exceptions)), non-blocking streams may produce short data to avoid blocking the operation.
The final dichotomy is binary vs text streams. MicroPython of course supports these, but while in CPython text streams are inherently buffered, they aren’t in MicroPython. (Indeed, that’s one of the cases for which we may introduce buffering support.)
Note that for efficiency, MicroPython doesn’t provide abstract base classes corresponding to the hierarchy above, and it’s not possible to implement, or subclass, a stream class in pure Python.
Functions¶
-
uio.
open
(name, mode='r', **kwargs)¶ Open a file. Builtin
open()
function is aliased to this function. All ports (which provide access to file system) are required to support mode parameter, but support for other arguments vary by port.
Classes¶
-
class
uio.
FileIO
(...)¶ This is type of a file open in binary mode, e.g. using
open(name, "rb")
. You should not instantiate this class directly.
-
class
uio.
TextIOWrapper
(...)¶ This is type of a file open in text mode, e.g. using
open(name, "rt")
. You should not instantiate this class directly.
-
class
uio.
StringIO
([string])¶
-
class
uio.
BytesIO
([string])¶ In-memory file-like objects for input/output.
StringIO
is used for text-mode I/O (similar to a normal file opened with “t” modifier).BytesIO
is used for binary-mode I/O (similar to a normal file opened with “b” modifier). Initial contents of file-like objects can be specified with string parameter (should be normal string forStringIO
or bytes object forBytesIO
). All the usual file methods likeread()
,write()
,seek()
,flush()
,close()
are available on these objects, and additionally, a following method:-
getvalue
()¶ Get the current contents of the underlying buffer which holds data.
-
ujson
– JSON encoding and decoding¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:json
.
This modules allows to convert between Python objects and the JSON data format.
Functions¶
-
ujson.
dump
(obj, stream)¶ Serialise obj to a JSON string, writing it to the given stream.
-
ujson.
dumps
(obj)¶ Return obj represented as a JSON string.
-
ujson.
load
(stream)¶ Parse the given stream, interpreting it as a JSON string and deserialising the data to a Python object. The resulting object is returned.
Parsing continues until end-of-file is encountered. A
ValueError
is raised if the data in stream is not correctly formed.
-
ujson.
loads
(str)¶ Parse the JSON str and return an object. Raises
ValueError
if the string is not correctly formed.
uos
– basic “operating system” services¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:os
.
The uos
module contains functions for filesystem access and mounting,
terminal redirection and duplication, and the uname
and urandom
functions.
General functions¶
-
uos.
uname
()¶ Return a tuple (possibly a named tuple) containing information about the underlying machine and/or its operating system. The tuple has five fields in the following order, each of them being a string:
sysname
– the name of the underlying systemnodename
– the network name (can be the same assysname
)release
– the version of the underlying systemversion
– the MicroPython version and build datemachine
– an identifier for the underlying hardware (eg board, CPU)
-
uos.
urandom
(n)¶ Return a bytes object with n random bytes. Whenever possible, it is generated by the hardware random number generator.
Filesystem access¶
-
uos.
chdir
(path)¶ Change current directory.
-
uos.
getcwd
()¶ Get the current directory.
-
uos.
ilistdir
([dir])¶ This function returns an iterator which then yields tuples corresponding to the entries in the directory that it is listing. With no argument it lists the current directory, otherwise it lists the directory given by dir.
The tuples have the form (name, type, inode[, size]):
- name is a string (or bytes if dir is a bytes object) and is the name of the entry;
- type is an integer that specifies the type of the entry, with 0x4000 for directories and 0x8000 for regular files;
- inode is an integer corresponding to the inode of the file, and may be 0 for filesystems that don’t have such a notion.
- Some platforms may return a 4-tuple that includes the entry’s size. For file entries, size is an integer representing the size of the file or -1 if unknown. Its meaning is currently undefined for directory entries.
-
uos.
listdir
([dir])¶ With no argument, list the current directory. Otherwise list the given directory.
-
uos.
mkdir
(path)¶ Create a new directory.
-
uos.
remove
(path)¶ Remove a file.
-
uos.
rmdir
(path)¶ Remove a directory.
-
uos.
rename
(old_path, new_path)¶ Rename a file.
-
uos.
stat
(path)¶ Get the status of a file or directory.
-
uos.
statvfs
(path)¶ Get the status of a fileystem.
Returns a tuple with the filesystem information in the following order:
f_bsize
– file system block sizef_frsize
– fragment sizef_blocks
– size of fs in f_frsize unitsf_bfree
– number of free blocksf_bavail
– number of free blocks for unpriviliged usersf_files
– number of inodesf_ffree
– number of free inodesf_favail
– number of free inodes for unpriviliged usersf_flag
– mount flagsf_namemax
– maximum filename length
Parameters related to inodes:
f_files
,f_ffree
,f_avail
and thef_flags
parameter may return0
as they can be unavailable in a port-specific implementation.
-
uos.
sync
()¶ Sync all filesystems.
Terminal redirection and duplication¶
-
uos.
dupterm
(stream_object, index=0)¶ Duplicate or switch the MicroPython terminal (the REPL) on the given
stream
-like object. The stream_object argument must implement thereadinto()
andwrite()
methods. The stream should be in non-blocking mode andreadinto()
should returnNone
if there is no data available for reading.After calling this function all terminal output is repeated on this stream, and any input that is available on the stream is passed on to the terminal input.
The index parameter should be a non-negative integer and specifies which duplication slot is set. A given port may implement more than one slot (slot 0 will always be available) and in that case terminal input and output is duplicated on all the slots that are set.
If
None
is passed as the stream_object then duplication is cancelled on the slot given by index.The function returns the previous stream-like object in the given slot.
Filesystem mounting¶
Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple
“real” filesystems within this VFS. Filesystem objects can be mounted at either
the root of the VFS, or at a subdirectory that lives in the root. This allows
dynamic and flexible configuration of the filesystem that is seen by Python
programs. Ports that have this functionality provide the mount()
and
umount()
functions, and possibly various filesystem implementations
represented by VFS classes.
-
uos.
mount
(fsobj, mount_point, *, readonly)¶ Mount the filesystem object fsobj at the location in the VFS given by the mount_point string. fsobj can be a a VFS object that has a
mount()
method, or a block device. If it’s a block device then the filesystem type is automatically detected (an exception is raised if no filesystem was recognised). mount_point may be'/'
to mount fsobj at the root, or'/<name>'
to mount it at a subdirectory under the root.If readonly is
True
then the filesystem is mounted read-only.During the mount process the method
mount()
is called on the filesystem object.Will raise
OSError(EPERM)
if mount_point is already mounted.
-
uos.
umount
(mount_point)¶ Unmount a filesystem. mount_point can be a string naming the mount location, or a previously-mounted filesystem object. During the unmount process the method
umount()
is called on the filesystem object.Will raise
OSError(EINVAL)
if mount_point is not found.
Block devices¶
A block device is an object which implements the block protocol, which is a set
of methods described below by the AbstractBlockDev
class. A concrete
implementation of this class will usually allow access to the memory-like
functionality a piece of hardware (like flash memory). A block device can be
used by a particular filesystem driver to store the data for its filesystem.
-
class
uos.
AbstractBlockDev
(...)¶ Construct a block device object. The parameters to the constructor are dependent on the specific block device.
-
readblocks
(block_num, buf)¶ Starting at the block given by the index block_num, read blocks from the device into buf (an array of bytes). The number of blocks to read is given by the length of buf, which will be a multiple of the block size.
-
writeblocks
(block_num, buf)¶ Starting at the block given by the index block_num, write blocks from buf (an array of bytes) to the device. The number of blocks to write is given by the length of buf, which will be a multiple of the block size.
-
ioctl
(op, arg)¶ Control the block device and query its parameters. The operation to perform is given by op which is one of the following integers:
- 1 – initialise the device (arg is unused)
- 2 – shutdown the device (arg is unused)
- 3 – sync the device (arg is unused)
- 4 – get a count of the number of blocks, should return an integer (arg is unused)
- 5 – get the number of bytes in a block, should return an integer,
or
None
in which case the default value of 512 is used (arg is unused)
-
By way of example, the following class will implement a block device that stores
its data in RAM using a bytearray
:
class RAMBlockDev:
def __init__(self, block_size, num_blocks):
self.block_size = block_size
self.data = bytearray(block_size * num_blocks)
def readblocks(self, block_num, buf):
for i in range(len(buf)):
buf[i] = self.data[block_num * self.block_size + i]
def writeblocks(self, block_num, buf):
for i in range(len(buf)):
self.data[block_num * self.block_size + i] = buf[i]
def ioctl(self, op, arg):
if op == 4: # get number of blocks
return len(self.data) // self.block_size
if op == 5: # get block size
return self.block_size
It can be used as follows:
import uos
bdev = RAMBlockDev(512, 50)
uos.VfsFat.mkfs(bdev)
vfs = uos.VfsFat(bdev)
uos.mount(vfs, '/ramdisk')
ure
– simple regular expressions¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:re
.
This module implements regular expression operations. Regular expression
syntax supported is a subset of CPython re
module (and actually is
a subset of POSIX extended regular expressions).
Supported operators are:
'.'
- Match any character.
'[...]'
- Match set of characters. Individual characters and ranges are supported,
including negated sets (e.g.
[^a-c]
). '^'
- Match the start of the string.
'$'
- Match the end of the string.
'?'
- Match zero or one of the previous entity.
'*'
- Match zero or more of the previous entity.
'+'
- Match one or more of the previous entity.
'??'
'*?'
'+?'
'|'
- Match either the LHS or the RHS of this operator.
'(...)'
- Grouping. Each group is capturing (a substring it captures can be accessed
with
match.group()
method).
NOT SUPPORTED: Counted repetitions ({m,n}
), more advanced assertions
(\b
, \B
), named groups ((?P<name>...)
), non-capturing groups
((?:...)
), etc.
Functions¶
-
ure.
match
(regex_str, string)¶ Compile regex_str and match against string. Match always happens from starting position in a string.
-
ure.
search
(regex_str, string)¶ Compile regex_str and search it in a string. Unlike
match
, this will search string for first position which matches regex (which still may be 0 if regex is anchored).
-
ure.
sub
(regex_str, replace, string, count=0, flags=0)¶ Compile regex_str and search for it in string, replacing all matches with replace, and returning the new string.
replace can be a string or a function. If it is a string then escape sequences of the form
\<number>
and\g<number>
can be used to expand to the corresponding group (or an empty string for unmatched groups). If replace is a function then it must take a single argument (the match) and should return a replacement string.If count is specified and non-zero then substitution will stop after this many substitutions are made. The flags argument is ignored.
Note: availability of this function depends on
MicroPython port
.
-
ure.
DEBUG
¶ Flag value, display debug information about compiled expression. (Availability depends on
MicroPython port
.)
Regex objects¶
Compiled regular expression. Instances of this class are created using
ure.compile()
.
-
regex.
match
(string)¶ -
regex.
search
(string)¶ -
regex.
sub
(replace, string, count=0, flags=0)¶ Similar to the module-level functions
match()
,search()
andsub()
. Using methods is (much) more efficient if the same regex is applied to multiple strings.
-
regex.
split
(string, max_split=-1)¶ Split a string using regex. If max_split is given, it specifies maximum number of splits to perform. Returns list of strings (there may be up to max_split+1 elements if it’s specified).
Match objects¶
Match objects as returned by match()
and search()
methods, and passed
to the replacement function in sub()
.
-
match.
group
([index])¶ Return matching (sub)string. index is 0 for entire match, 1 and above for each capturing group. Only numeric groups are supported.
-
match.
groups
()¶ Return a tuple containing all the substrings of the groups of the match.
Note: availability of this method depends on
MicroPython port
.
-
match.
start
([index])¶ -
match.
end
([index])¶ Return the index in the original string of the start or end of the substring group that was matched. index defaults to the entire group, otherwise it will select a group.
Note: availability of these methods depends on
MicroPython port
.
-
match.
span
([index])¶ Returns the 2-tuple
(match.start(index), match.end(index))
.Note: availability of this method depends on
MicroPython port
.
uselect
– wait for events on a set of streams¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:select
.
This module provides functions to efficiently wait for events on multiple
streams
(select streams which are ready for operations).
Functions¶
-
uselect.
poll
()¶ Create an instance of the Poll class.
-
uselect.
select
(rlist, wlist, xlist[, timeout])¶ Wait for activity on a set of objects.
This function is provided by some MicroPython ports for compatibility and is not efficient. Usage of
Poll
is recommended instead.
class Poll
¶
Methods¶
-
poll.
register
(obj[, eventmask])¶ Register
stream
obj for polling. eventmask is logical OR of:uselect.POLLIN
- data available for readinguselect.POLLOUT
- more data can be written
Note that flags like
uselect.POLLHUP
anduselect.POLLERR
are not valid as input eventmask (these are unsolicited events which will be returned frompoll()
regardless of whether they are asked for). This semantics is per POSIX.eventmask defaults to
uselect.POLLIN | uselect.POLLOUT
.
-
poll.
unregister
(obj)¶ Unregister obj from polling.
-
poll.
modify
(obj, eventmask)¶ Modify the eventmask for obj.
-
poll.
poll
(timeout=-1)¶ Wait for at least one of the registered objects to become ready or have an exceptional condition, with optional timeout in milliseconds (if timeout arg is not specified or -1, there is no timeout).
Returns list of (
obj
,event
, …) tuples. There may be other elements in tuple, depending on a platform and version, so don’t assume that its size is 2. Theevent
element specifies which events happened with a stream and is a combination ofuselect.POLL*
constants described above. Note that flagsuselect.POLLHUP
anduselect.POLLERR
can be returned at any time (even if were not asked for), and must be acted on accordingly (the corresponding stream unregistered from poll and likely closed), because otherwise all further invocations ofpoll()
may return immediately with these flags set for this stream again.In case of timeout, an empty list is returned.
Difference to CPython
Tuples returned may contain more than 2 elements as described above.
-
poll.
ipoll
(timeout=-1, flags=0)¶ Like
poll.poll()
, but instead returns an iterator which yields acallee-owned tuple
. This function provides an efficient, allocation-free way to poll on streams.If flags is 1, one-shot behavior for events is employed: streams for which events happened will have their event masks automatically reset (equivalent to
poll.modify(obj, 0)
), so new events for such a stream won’t be processed until new mask is set withpoll.modify()
. This behavior is useful for asynchronous I/O schedulers.Difference to CPython
This function is a MicroPython extension.
usocket
– socket module¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:socket
.
This module provides access to the BSD socket interface.
Difference to CPython
For efficiency and consistency, socket objects in MicroPython implement a stream
(file-like) interface directly. In CPython, you need to convert a socket to
a file-like object using makefile()
method. This method is still supported
by MicroPython (but is a no-op), so where compatibility with CPython matters,
be sure to use it.
Socket address format(s)¶
The native socket address format of the usocket
module is an opaque data type
returned by getaddrinfo
function, which must be used to resolve textual address
(including numeric addresses):
sockaddr = usocket.getaddrinfo('www.micropython.org', 80)[0][-1]
# You must use getaddrinfo() even for numeric addresses
sockaddr = usocket.getaddrinfo('127.0.0.1', 80)[0][-1]
# Now you can use that address
sock.connect(addr)
Using getaddrinfo
is the most efficient (both in terms of memory and processing
power) and portable way to work with addresses.
However, socket
module (note the difference with native MicroPython
usocket
module described here) provides CPython-compatible way to specify
addresses using tuples, as described below. Note that depending on a
MicroPython port
, socket
module can be builtin or need to be
installed from micropython-lib
(as in the case of MicroPython Unix port
),
and some ports still accept only numeric addresses in the tuple format,
and require to use getaddrinfo
function to resolve domain names.
Summing up:
- Always use
getaddrinfo
when writing portable applications. - Tuple addresses described below can be used as a shortcut for quick hacks and interactive use, if your port supports them.
Tuple address format for socket
module:
- IPv4: (ipv4_address, port), where ipv4_address is a string with
dot-notation numeric IPv4 address, e.g.
"8.8.8.8"
, and port is and integer port number in the range 1-65535. Note the domain names are not accepted as ipv4_address, they should be resolved first usingusocket.getaddrinfo()
. - IPv6: (ipv6_address, port, flowinfo, scopeid), where ipv6_address
is a string with colon-notation numeric IPv6 address, e.g.
"2001:db8::1"
, and port is an integer port number in the range 1-65535. flowinfo must be 0. scopeid is the interface scope identifier for link-local addresses. Note the domain names are not accepted as ipv6_address, they should be resolved first usingusocket.getaddrinfo()
. Availability of IPv6 support depends on aMicroPython port
.
Functions¶
-
usocket.
socket
(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP)¶ Create a new socket using the given address family, socket type and protocol number. Note that specifying proto in most cases is not required (and not recommended, as some MicroPython ports may omit
IPPROTO_*
constants). Instead, type argument will select needed protocol automatically:# Create STREAM TCP socket socket(AF_INET, SOCK_STREAM) # Create DGRAM UDP socket socket(AF_INET, SOCK_DGRAM)
-
usocket.
getaddrinfo
(host, port, af=0, type=0, proto=0, flags=0)¶ Translate the host/port argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. Arguments af, type, and proto (which have the same meaning as for the
socket()
function) can be used to filter which kind of addresses are returned. If a parameter is not specified or zero, all combinations of addresses can be returned (requiring filtering on the user side).The resulting list of 5-tuples has the following structure:
(family, type, proto, canonname, sockaddr)
The following example shows how to connect to a given url:
s = usocket.socket() # This assumes that if "type" is not specified, an address for # SOCK_STREAM will be returned, which may be not true s.connect(usocket.getaddrinfo('www.micropython.org', 80)[0][-1])
Recommended use of filtering params:
s = usocket.socket() # Guaranteed to return an address which can be connect'ed to for # stream operation. s.connect(usocket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1])
Difference to CPython
CPython raises a
socket.gaierror
exception (OSError
subclass) in case of error in this function. MicroPython doesn’t havesocket.gaierror
and raises OSError directly. Note that error numbers ofgetaddrinfo()
form a separate namespace and may not match error numbers from theuerrno
module. To distinguishgetaddrinfo()
errors, they are represented by negative numbers, whereas standard system errors are positive numbers (error numbers are accessible usinge.args[0]
property from an exception object). The use of negative values is a provisional detail which may change in the future.
-
usocket.
inet_ntop
(af, bin_addr)¶ Convert a binary network address bin_addr of the given address family af to a textual representation:
>>> usocket.inet_ntop(usocket.AF_INET, b"\x7f\0\0\1") '127.0.0.1'
-
usocket.
inet_pton
(af, txt_addr)¶ Convert a textual network address txt_addr of the given address family af to a binary representation:
>>> usocket.inet_pton(usocket.AF_INET, "1.2.3.4") b'\x01\x02\x03\x04'
Constants¶
-
usocket.
AF_INET
¶ -
usocket.
AF_INET6
¶ Address family types. Availability depends on a particular
MicroPython port
.
-
usocket.
IPPROTO_UDP
¶ -
usocket.
IPPROTO_TCP
¶ IP protocol numbers. Availability depends on a particular
MicroPython port
. Note that you don’t need to specify these in a call tousocket.socket()
, becauseSOCK_STREAM
socket type automatically selectsIPPROTO_TCP
, andSOCK_DGRAM
-IPPROTO_UDP
. Thus, the only real use of these constants is as an argument tosetsockopt()
.
-
usocket.SOL_*
Socket option levels (an argument to
setsockopt()
). The exact inventory depends on aMicroPython port
.
-
usocket.SO_*
Socket options (an argument to
setsockopt()
). The exact inventory depends on aMicroPython port
.
Constants specific to WiPy:
-
usocket.
IPPROTO_SEC
¶ Special protocol value to create SSL-compatible socket.
class socket¶
Methods¶
-
socket.
close
()¶ Mark the socket closed and release all resources. Once that happens, all future operations on the socket object will fail. The remote end will receive EOF indication if supported by protocol.
Sockets are automatically closed when they are garbage-collected, but it is recommended to
close()
them explicitly as soon you finished working with them.
-
socket.
bind
(address)¶ Bind the socket to address. The socket must not already be bound.
-
socket.
listen
([backlog])¶ Enable a server to accept connections. If backlog is specified, it must be at least 0 (if it’s lower, it will be set to 0); and specifies the number of unaccepted connections that the system will allow before refusing new connections. If not specified, a default reasonable value is chosen.
-
socket.
accept
()¶ Accept a connection. The socket must be bound to an address and listening for connections. The return value is a pair (conn, address) where conn is a new socket object usable to send and receive data on the connection, and address is the address bound to the socket on the other end of the connection.
-
socket.
connect
(address)¶ Connect to a remote socket at address.
-
socket.
send
(bytes)¶ Send data to the socket. The socket must be connected to a remote socket. Returns number of bytes sent, which may be smaller than the length of data (“short write”).
-
socket.
sendall
(bytes)¶ Send all data to the socket. The socket must be connected to a remote socket. Unlike
send()
, this method will try to send all of data, by sending data chunk by chunk consecutively.The behavior of this method on non-blocking sockets is undefined. Due to this, on MicroPython, it’s recommended to use
write()
method instead, which has the same “no short writes” policy for blocking sockets, and will return number of bytes sent on non-blocking sockets.
-
socket.
recv
(bufsize)¶ Receive data from the socket. The return value is a bytes object representing the data received. The maximum amount of data to be received at once is specified by bufsize.
-
socket.
sendto
(bytes, address)¶ Send data to the socket. The socket should not be connected to a remote socket, since the destination socket is specified by address.
-
socket.
recvfrom
(bufsize)¶ Receive data from the socket. The return value is a pair (bytes, address) where bytes is a bytes object representing the data received and address is the address of the socket sending the data.
-
socket.
setsockopt
(level, optname, value)¶ Set the value of the given socket option. The needed symbolic constants are defined in the socket module (SO_* etc.). The value can be an integer or a bytes-like object representing a buffer.
-
socket.
settimeout
(value)¶ Note: Not every port supports this method, see below.
Set a timeout on blocking socket operations. The value argument can be a nonnegative floating point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations will raise an
OSError
exception if the timeout period value has elapsed before the operation has completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket is put in blocking mode.Not every
MicroPython port
supports this method. A more portable and generic solution is to useuselect.poll
object. This allows to wait on multiple objects at the same time (and not just on sockets, but on genericstream
objects which support polling). Example:# Instead of: s.settimeout(1.0) # time in seconds s.read(10) # may timeout # Use: poller = uselect.poll() poller.register(s, uselect.POLLIN) res = poller.poll(1000) # time in milliseconds if not res: # s is still not ready for input, i.e. operation timed out
Difference to CPython
CPython raises a
socket.timeout
exception in case of timeout, which is anOSError
subclass. MicroPython raises an OSError directly instead. If you useexcept OSError:
to catch the exception, your code will work both in MicroPython and CPython.
-
socket.
setblocking
(flag)¶ Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking, else to blocking mode.
This method is a shorthand for certain
settimeout()
calls:sock.setblocking(True)
is equivalent tosock.settimeout(None)
sock.setblocking(False)
is equivalent tosock.settimeout(0)
-
socket.
makefile
(mode='rb', buffering=0)¶ Return a file object associated with the socket. The exact returned type depends on the arguments given to makefile(). The support is limited to binary modes only (‘rb’, ‘wb’, and ‘rwb’). CPython’s arguments: encoding, errors and newline are not supported.
Difference to CPython
As MicroPython doesn’t support buffered streams, values of buffering parameter is ignored and treated as if it was 0 (unbuffered).
Difference to CPython
Closing the file object returned by makefile() WILL close the original socket as well.
-
socket.
read
([size])¶ Read up to size bytes from the socket. Return a bytes object. If size is not given, it reads all data available from the socket until EOF; as such the method will not return until the socket is closed. This function tries to read as much data as requested (no “short reads”). This may be not possible with non-blocking socket though, and then less data will be returned.
-
socket.
readinto
(buf[, nbytes])¶ Read bytes into the buf. If nbytes is specified then read at most that many bytes. Otherwise, read at most len(buf) bytes. Just as
read()
, this method follows “no short reads” policy.Return value: number of bytes read and stored into buf.
-
socket.
readline
()¶ Read a line, ending in a newline character.
Return value: the line read.
-
socket.
write
(buf)¶ Write the buffer of bytes to the socket. This function will try to write all data to a socket (no “short writes”). This may be not possible with a non-blocking socket though, and returned value will be less than the length of buf.
Return value: number of bytes written.
-
exception
usocket.
error
¶ MicroPython does NOT have this exception.
ussl
– SSL/TLS module¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:ssl
.
This module provides access to Transport Layer Security (previously and widely known as “Secure Sockets Layer”) encryption and peer authentication facilities for network sockets, both client-side and server-side.
Functions¶
-
ussl.
wrap_socket
(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None)¶ Takes a
stream
sock (usually usocket.socket instance ofSOCK_STREAM
type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in an SSL context. Returned object has the usualstream
interface methods likeread()
,write()
, etc. In MicroPython, the returned object does not expose socket interface and methods likerecv()
,send()
. In particular, a server-side SSL socket should be created from a normal socket returned fromaccept()
on a non-SSL listening server socket.Depending on the underlying module implementation in a particular
MicroPython port
, some or all keyword arguments above may be not supported.
Warning
Some implementations of ussl
module do NOT validate server certificates,
which makes an SSL connection established prone to man-in-the-middle attacks.
ustruct
– pack and unpack primitive data types¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:struct
.
Supported size/byte order prefixes: @
, <
, >
, !
.
Supported format codes: b
, B
, h
, H
, i
, I
, l
,
L
, q
, Q
, s
, P
, f
, d
(the latter 2 depending
on the floating-point support).
Functions¶
-
ustruct.
calcsize
(fmt)¶ Return the number of bytes needed to store the given fmt.
-
ustruct.
pack
(fmt, v1, v2, ...)¶ Pack the values v1, v2, … according to the format string fmt. The return value is a bytes object encoding the values.
-
ustruct.
pack_into
(fmt, buffer, offset, v1, v2, ...)¶ Pack the values v1, v2, … according to the format string fmt into a buffer starting at offset. offset may be negative to count from the end of buffer.
-
ustruct.
unpack
(fmt, data)¶ Unpack from the data according to the format string fmt. The return value is a tuple of the unpacked values.
-
ustruct.
unpack_from
(fmt, data, offset=0)¶ Unpack from the data starting at offset according to the format string fmt. offset may be negative to count from the end of buffer. The return value is a tuple of the unpacked values.
utime
– time related functions¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:time
.
The utime
module provides functions for getting the current time and date,
measuring time intervals, and for delays.
Time Epoch: Unix port uses standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC. However, embedded ports use epoch of 2000-01-01 00:00:00 UTC.
Maintaining actual calendar date/time: This requires a
Real Time Clock (RTC). On systems with underlying OS (including some
RTOS), an RTC may be implicit. Setting and maintaining actual calendar
time is responsibility of OS/RTOS and is done outside of MicroPython,
it just uses OS API to query date/time. On baremetal ports however
system time depends on machine.RTC()
object. The current calendar time
may be set using machine.RTC().datetime(tuple)
function, and maintained
by following means:
- By a backup battery (which may be an additional, optional component for a particular board).
- Using networked time protocol (requires setup by a port/user).
- Set manually by a user on each power-up (many boards then maintain RTC time across hard resets, though some may require setting it again in such case).
If actual calendar time is not maintained with a system/MicroPython RTC, functions below which require reference to current absolute time may behave not as expected.
Functions¶
-
utime.
localtime
([secs])¶ Convert a time expressed in seconds since the Epoch (see above) into an 8-tuple which contains: (year, month, mday, hour, minute, second, weekday, yearday) If secs is not provided or None, then the current time from the RTC is used.
- year includes the century (for example 2014).
- month is 1-12
- mday is 1-31
- hour is 0-23
- minute is 0-59
- second is 0-59
- weekday is 0-6 for Mon-Sun
- yearday is 1-366
-
utime.
mktime
()¶ This is inverse function of localtime. It’s argument is a full 8-tuple which expresses a time as per localtime. It returns an integer which is the number of seconds since Jan 1, 2000.
-
utime.
sleep
(seconds)¶ Sleep for the given number of seconds. Some boards may accept seconds as a floating-point number to sleep for a fractional number of seconds. Note that other boards may not accept a floating-point argument, for compatibility with them use
sleep_ms()
andsleep_us()
functions.
-
utime.
sleep_ms
(ms)¶ Delay for given number of milliseconds, should be positive or 0.
-
utime.
sleep_us
(us)¶ Delay for given number of microseconds, should be positive or 0.
-
utime.
ticks_ms
()¶ Returns an increasing millisecond counter with an arbitrary reference point, that wraps around after some value.
The wrap-around value is not explicitly exposed, but we will refer to it as TICKS_MAX to simplify discussion. Period of the values is TICKS_PERIOD = TICKS_MAX + 1. TICKS_PERIOD is guaranteed to be a power of two, but otherwise may differ from port to port. The same period value is used for all of
ticks_ms()
,ticks_us()
,ticks_cpu()
functions (for simplicity). Thus, these functions will return a value in range [0 .. TICKS_MAX], inclusive, total TICKS_PERIOD values. Note that only non-negative values are used. For the most part, you should treat values returned by these functions as opaque. The only operations available for them areticks_diff()
andticks_add()
functions described below.Note: Performing standard mathematical operations (+, -) or relational operators (<, <=, >, >=) directly on these value will lead to invalid result. Performing mathematical operations and then passing their results as arguments to
ticks_diff()
orticks_add()
will also lead to invalid results from the latter functions.
-
utime.
ticks_us
()¶ Just like
ticks_ms()
above, but in microseconds.
-
utime.
ticks_cpu
()¶ Similar to
ticks_ms()
andticks_us()
, but with the highest possible resolution in the system. This is usually CPU clocks, and that’s why the function is named that way. But it doesn’t have to be a CPU clock, some other timing source available in a system (e.g. high-resolution timer) can be used instead. The exact timing unit (resolution) of this function is not specified onutime
module level, but documentation for a specific port may provide more specific information. This function is intended for very fine benchmarking or very tight real-time loops. Avoid using it in portable code.Availability: Not every port implements this function.
-
utime.
ticks_add
(ticks, delta)¶ Offset ticks value by a given number, which can be either positive or negative. Given a ticks value, this function allows to calculate ticks value delta ticks before or after it, following modular-arithmetic definition of tick values (see
ticks_ms()
above). ticks parameter must be a direct result of call toticks_ms()
,ticks_us()
, orticks_cpu()
functions (or from previous call toticks_add()
). However, delta can be an arbitrary integer number or numeric expression.ticks_add()
is useful for calculating deadlines for events/tasks. (Note: you must useticks_diff()
function to work with deadlines.)Examples:
# Find out what ticks value there was 100ms ago print(ticks_add(time.ticks_ms(), -100)) # Calculate deadline for operation and test for it deadline = ticks_add(time.ticks_ms(), 200) while ticks_diff(deadline, time.ticks_ms()) > 0: do_a_little_of_something() # Find out TICKS_MAX used by this port print(ticks_add(0, -1))
-
utime.
ticks_diff
(ticks1, ticks2)¶ Measure ticks difference between values returned from
ticks_ms()
,ticks_us()
, orticks_cpu()
functions, as a signed value which may wrap around.The argument order is the same as for subtraction operator,
ticks_diff(ticks1, ticks2)
has the same meaning asticks1 - ticks2
. However, values returned byticks_ms()
, etc. functions may wrap around, so directly using subtraction on them will produce incorrect result. That is whyticks_diff()
is needed, it implements modular (or more specifically, ring) arithmetics to produce correct result even for wrap-around values (as long as they not too distant inbetween, see below). The function returns signed value in the range [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] (that’s a typical range definition for two’s-complement signed binary integers). If the result is negative, it means that ticks1 occurred earlier in time than ticks2. Otherwise, it means that ticks1 occurred after ticks2. This holds only if ticks1 and ticks2 are apart from each other for no more than TICKS_PERIOD/2-1 ticks. If that does not hold, incorrect result will be returned. Specifically, if two tick values are apart for TICKS_PERIOD/2-1 ticks, that value will be returned by the function. However, if TICKS_PERIOD/2 of real-time ticks has passed between them, the function will return -TICKS_PERIOD/2 instead, i.e. result value will wrap around to the negative range of possible values.Informal rationale of the constraints above: Suppose you are locked in a room with no means to monitor passing of time except a standard 12-notch clock. Then if you look at dial-plate now, and don’t look again for another 13 hours (e.g., if you fall for a long sleep), then once you finally look again, it may seem to you that only 1 hour has passed. To avoid this mistake, just look at the clock regularly. Your application should do the same. “Too long sleep” metaphor also maps directly to application behavior: don’t let your application run any single task for too long. Run tasks in steps, and do time-keeping inbetween.
ticks_diff()
is designed to accommodate various usage patterns, among them:Polling with timeout. In this case, the order of events is known, and you will deal only with positive results of
ticks_diff()
:# Wait for GPIO pin to be asserted, but at most 500us start = time.ticks_us() while pin.value() == 0: if time.ticks_diff(time.ticks_us(), start) > 500: raise TimeoutError
Scheduling events. In this case,
ticks_diff()
result may be negative if an event is overdue:# This code snippet is not optimized now = time.ticks_ms() scheduled_time = task.scheduled_time() if ticks_diff(scheduled_time, now) > 0: print("Too early, let's nap") sleep_ms(ticks_diff(scheduled_time, now)) task.run() elif ticks_diff(scheduled_time, now) == 0: print("Right at time!") task.run() elif ticks_diff(scheduled_time, now) < 0: print("Oops, running late, tell task to run faster!") task.run(run_faster=true)
Note: Do not pass
time()
values toticks_diff()
, you should use normal mathematical operations on them. But note thattime()
may (and will) also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem .
-
utime.
time
()¶ Returns the number of seconds, as an integer, since the Epoch, assuming that underlying RTC is set and maintained as described above. If an RTC is not set, this function returns number of seconds since a port-specific reference point in time (for embedded boards without a battery-backed RTC, usually since power up or reset). If you want to develop portable MicroPython application, you should not rely on this function to provide higher than second precision. If you need higher precision, use
ticks_ms()
andticks_us()
functions, if you need calendar time,localtime()
without an argument is a better choice.Difference to CPython
In CPython, this function returns number of seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point, usually having microsecond precision. With MicroPython, only Unix port uses the same Epoch, and if floating-point precision allows, returns sub-second precision. Embedded hardware usually doesn’t have floating-point precision to represent both long time ranges and subsecond precision, so they use integer value with second precision. Some embedded hardware also lacks battery-powered RTC, so returns number of seconds since last power-up or from other relative, hardware-specific point (e.g. reset).
uzlib
– zlib decompression¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:zlib
.
This module allows to decompress binary data compressed with DEFLATE algorithm (commonly used in zlib library and gzip archiver). Compression is not yet implemented.
Functions¶
-
uzlib.
decompress
(data, wbits=0, bufsize=0)¶ Return decompressed data as bytes. wbits is DEFLATE dictionary window size used during compression (8-15, the dictionary size is power of 2 of that value). Additionally, if value is positive, data is assumed to be zlib stream (with zlib header). Otherwise, if it’s negative, it’s assumed to be raw DEFLATE stream. bufsize parameter is for compatibility with CPython and is ignored.
-
class
uzlib.
DecompIO
(stream, wbits=0)¶ Create a
stream
wrapper which allows transparent decompression of compressed data in another stream. This allows to process compressed streams with data larger than available heap size. In addition to values described indecompress()
, wbits may take values 24..31 (16 + 8..15), meaning that input stream has gzip header.Difference to CPython
This class is MicroPython extension. It’s included on provisional basis and may be changed considerably or removed in later versions.
_thread
– multithreading support¶
This module implements a subset of the corresponding CPython
module,
as described below. For more information, refer to the original
CPython documentation: python:_thread
.
This module implements multithreading support.
This module is highly experimental and its API is not yet fully settled and not yet described in this documentation.
MicroPython-specific libraries¶
Functionality specific to the MicroPython implementation is available in the following libraries.
btree
– simple BTree database¶
The btree
module implements a simple key-value database using external
storage (disk files, or in general case, a random-access stream
). Keys are
stored sorted in the database, and besides efficient retrieval by a key
value, a database also supports efficient ordered range scans (retrieval
of values with the keys in a given range). On the application interface
side, BTree database work as close a possible to a way standard dict
type works, one notable difference is that both keys and values must
be bytes
objects (so, if you want to store objects of other types, you
need to serialize them to bytes
first).
The module is based on the well-known BerkelyDB library, version 1.xx.
Example:
import btree
# First, we need to open a stream which holds a database
# This is usually a file, but can be in-memory database
# using uio.BytesIO, a raw flash partition, etc.
# Oftentimes, you want to create a database file if it doesn't
# exist and open if it exists. Idiom below takes care of this.
# DO NOT open database with "a+b" access mode.
try:
f = open("mydb", "r+b")
except OSError:
f = open("mydb", "w+b")
# Now open a database itself
db = btree.open(f)
# The keys you add will be sorted internally in the database
db[b"3"] = b"three"
db[b"1"] = b"one"
db[b"2"] = b"two"
# Assume that any changes are cached in memory unless
# explicitly flushed (or database closed). Flush database
# at the end of each "transaction".
db.flush()
# Prints b'two'
print(db[b"2"])
# Iterate over sorted keys in the database, starting from b"2"
# until the end of the database, returning only values.
# Mind that arguments passed to values() method are *key* values.
# Prints:
# b'two'
# b'three'
for word in db.values(b"2"):
print(word)
del db[b"2"]
# No longer true, prints False
print(b"2" in db)
# Prints:
# b"1"
# b"3"
for key in db:
print(key)
db.close()
# Don't forget to close the underlying stream!
f.close()
Functions¶
-
btree.
open
(stream, *, flags=0, pagesize=0, cachesize=0, minkeypage=0)¶ Open a database from a random-access
stream
(like an open file). All other parameters are optional and keyword-only, and allow to tweak advanced parameters of the database operation (most users will not need them):- flags - Currently unused.
- pagesize - Page size used for the nodes in BTree. Acceptable range is 512-65536. If 0, a port-specific default will be used, optimized for port’s memory usage and/or performance.
- cachesize - Suggested memory cache size in bytes. For a board with enough memory using larger values may improve performance. Cache policy is as follows: entire cache is not allocated at once; instead, accessing a new page in database will allocate a memory buffer for it, until value specified by cachesize is reached. Then, these buffers will be managed using LRU (least recently used) policy. More buffers may still be allocated if needed (e.g., if a database contains big keys and/or values). Allocated cache buffers aren’t reclaimed.
- minkeypage - Minimum number of keys to store per page. Default value of 0 equivalent to 2.
Returns a BTree object, which implements a dictionary protocol (set of methods), and some additional methods described below.
Methods¶
-
btree.
close
()¶ Close the database. It’s mandatory to close the database at the end of processing, as some unwritten data may be still in the cache. Note that this does not close underlying stream with which the database was opened, it should be closed separately (which is also mandatory to make sure that data flushed from buffer to the underlying storage).
-
btree.
flush
()¶ Flush any data in cache to the underlying stream.
-
btree.
__getitem__
(key)¶ -
btree.
get
(key, default=None)¶ -
btree.
__setitem__
(key, val)¶ -
btree.
__detitem__
(key)¶ -
btree.
__contains__
(key)¶ Standard dictionary methods.
-
btree.
__iter__
()¶ A BTree object can be iterated over directly (similar to a dictionary) to get access to all keys in order.
-
btree.
keys
([start_key[, end_key[, flags]]])¶ -
btree.
values
([start_key[, end_key[, flags]]])¶ -
btree.
items
([start_key[, end_key[, flags]]])¶ These methods are similar to standard dictionary methods, but also can take optional parameters to iterate over a key sub-range, instead of the entire database. Note that for all 3 methods, start_key and end_key arguments represent key values. For example,
values()
method will iterate over values corresponding to they key range given. None values for start_key means “from the first key”, no end_key or its value of None means “until the end of database”. By default, range is inclusive of start_key and exclusive of end_key, you can include end_key in iteration by passing flags ofbtree.INCL
. You can iterate in descending key direction by passing flags ofbtree.DESC
. The flags values can be ORed together.
framebuf
— Frame buffer manipulation¶
This module provides a general frame buffer which can be used to create bitmap images, which can then be sent to a display.
class FrameBuffer¶
The FrameBuffer class provides a pixel buffer which can be drawn upon with pixels, lines, rectangles, text and even other FrameBuffer’s. It is useful when generating output for displays.
For example:
import framebuf
# FrameBuffer needs 2 bytes for every RGB565 pixel
fbuf = FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
fbuf.fill(0)
fbuf.text('MicroPython!', 0, 0, 0xffff)
fbuf.hline(0, 10, 96, 0xffff)
Constructors¶
-
class
framebuf.
FrameBuffer
(buffer, width, height, format, stride=width)¶ Construct a FrameBuffer object. The parameters are:
- buffer is an object with a buffer protocol which must be large enough to contain every pixel defined by the width, height and format of the FrameBuffer.
- width is the width of the FrameBuffer in pixels
- height is the height of the FrameBuffer in pixels
- format specifies the type of pixel used in the FrameBuffer; permissible values are listed under Constants below. These set the number of bits used to encode a color value and the layout of these bits in buffer. Where a color value c is passed to a method, c is a small integer with an encoding that is dependent on the format of the FrameBuffer.
- stride is the number of pixels between each horizontal line of pixels in the FrameBuffer. This defaults to width but may need adjustments when implementing a FrameBuffer within another larger FrameBuffer or screen. The buffer size must accommodate an increased step size.
One must specify valid buffer, width, height, format and optionally stride. Invalid buffer size or dimensions may lead to unexpected errors.
Drawing primitive shapes¶
The following methods draw shapes onto the FrameBuffer.
-
FrameBuffer.
fill
(c)¶ Fill the entire FrameBuffer with the specified color.
-
FrameBuffer.
pixel
(x, y[, c])¶ If c is not given, get the color value of the specified pixel. If c is given, set the specified pixel to the given color.
-
FrameBuffer.
hline
(x, y, w, c)¶
-
FrameBuffer.
vline
(x, y, h, c)¶
-
FrameBuffer.
line
(x1, y1, x2, y2, c)¶ Draw a line from a set of coordinates using the given color and a thickness of 1 pixel. The
line
method draws the line up to a second set of coordinates whereas thehline
andvline
methods draw horizontal and vertical lines respectively up to a given length.
-
FrameBuffer.
rect
(x, y, w, h, c)¶
Drawing text¶
-
FrameBuffer.
text
(s, x, y[, c])¶ Write text to the FrameBuffer using the the coordinates as the upper-left corner of the text. The color of the text can be defined by the optional argument but is otherwise a default value of 1. All characters have dimensions of 8x8 pixels and there is currently no way to change the font.
Other methods¶
-
FrameBuffer.
scroll
(xstep, ystep)¶ Shift the contents of the FrameBuffer by the given vector. This may leave a footprint of the previous colors in the FrameBuffer.
-
FrameBuffer.
blit
(fbuf, x, y[, key])¶ Draw another FrameBuffer on top of the current one at the given coordinates. If key is specified then it should be a color integer and the corresponding color will be considered transparent: all pixels with that color value will not be drawn.
This method works between FrameBuffer instances utilising different formats, but the resulting colors may be unexpected due to the mismatch in color formats.
Constants¶
-
framebuf.
MONO_VLSB
¶ Monochrome (1-bit) color format This defines a mapping where the bits in a byte are vertically mapped with bit 0 being nearest the top of the screen. Consequently each byte occupies 8 vertical pixels. Subsequent bytes appear at successive horizontal locations until the rightmost edge is reached. Further bytes are rendered at locations starting at the leftmost edge, 8 pixels lower.
-
framebuf.
MONO_HLSB
¶ Monochrome (1-bit) color format This defines a mapping where the bits in a byte are horizontally mapped. Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. Subsequent bytes appear at successive horizontal locations until the rightmost edge is reached. Further bytes are rendered on the next row, one pixel lower.
-
framebuf.
MONO_HMSB
¶ Monochrome (1-bit) color format This defines a mapping where the bits in a byte are horizontally mapped. Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. Subsequent bytes appear at successive horizontal locations until the rightmost edge is reached. Further bytes are rendered on the next row, one pixel lower.
-
framebuf.
RGB565
¶ Red Green Blue (16-bit, 5+6+5) color format
-
framebuf.
GS2_HMSB
¶ Grayscale (2-bit) color format
-
framebuf.
GS4_HMSB
¶ Grayscale (4-bit) color format
-
framebuf.
GS8
¶ Grayscale (8-bit) color format
machine
— functions related to the hardware¶
The machine
module contains specific functions related to the hardware
on a particular board. Most functions in this module allow to achieve direct
and unrestricted access to and control of hardware blocks on a system
(like CPU, timers, buses, etc.). Used incorrectly, this can lead to
malfunction, lockups, crashes of your board, and in extreme cases, hardware
damage.
A note of callbacks used by functions and class methods of machine
module:
all these callbacks should be considered as executing in an interrupt context.
This is true for both physical devices with IDs >= 0 and “virtual” devices
with negative IDs like -1 (these “virtual” devices are still thin shims on
top of real hardware and real hardware interrupts). See Writing interrupt handlers.
Miscellaneous functions¶
-
machine.
unique_id
()¶ Returns a byte string with a unique identifier of a board/SoC. It will vary from a board/SoC instance to another, if underlying hardware allows. Length varies by hardware (so use substring of a full value if you expect a short ID). In some MicroPython ports, ID corresponds to the network MAC address.
-
machine.
time_pulse_us
(pin, pulse_level, timeout_us=1000000)¶ Time a pulse on the given pin, and return the duration of the pulse in microseconds. The pulse_level argument should be 0 to time a low pulse or 1 to time a high pulse.
If the current input value of the pin is different to pulse_level, the function first (*) waits until the pin input becomes equal to pulse_level, then (**) times the duration that the pin is equal to pulse_level. If the pin is already equal to pulse_level then timing starts straight away.
The function will return -2 if there was timeout waiting for condition marked (*) above, and -1 if there was timeout during the main measurement, marked (**) above. The timeout is the same for both cases and given by timeout_us (which is in microseconds).
-
machine.
rng
()¶ Return a 24-bit software generated random number.
Availability: WiPy.
Constants¶
Classes¶
class Pin – control I/O pins¶
A pin object is used to control I/O pins (also known as GPIO - general-purpose
input/output). Pin objects are commonly associated with a physical pin that can
drive an output voltage and read input voltages. The pin class has methods to set the mode of
the pin (IN, OUT, etc) and methods to get and set the digital logic level.
For analog control of a pin, see the ADC
class.
A pin object is constructed by using an identifier which unambiguously specifies a certain I/O pin. The allowed forms of the identifier and the physical pin that the identifier maps to are port-specific. Possibilities for the identifier are an integer, a string or a tuple with port and pin number.
Usage Model:
from machine import Pin
# create an output pin on pin #0
p0 = Pin(0, Pin.OUT)
# set the value low then high
p0.value(0)
p0.value(1)
# create an input pin on pin #2, with a pull up resistor
p2 = Pin(2, Pin.IN, Pin.PULL_UP)
# read and print the pin value
print(p2.value())
# reconfigure pin #0 in input mode
p0.mode(p0.IN)
# configure an irq callback
p0.irq(lambda p:print(p))
-
class
machine.
Pin
(id, mode=-1, pull=-1, *, value, drive, alt)¶ Access the pin peripheral (GPIO pin) associated with the given
id
. If additional arguments are given in the constructor then they are used to initialise the pin. Any settings that are not specified will remain in their previous state.The arguments are:
id
is mandatory and can be an arbitrary object. Among possible value types are: int (an internal Pin identifier), str (a Pin name), and tuple (pair of [port, pin]).mode
specifies the pin mode, which can be one of:Pin.IN
- Pin is configured for input. If viewed as an output the pin is in high-impedance state.Pin.OUT
- Pin is configured for (normal) output.Pin.OPEN_DRAIN
- Pin is configured for open-drain output. Open-drain output works in the following way: if the output value is set to 0 the pin is active at a low level; if the output value is 1 the pin is in a high-impedance state. Not all ports implement this mode, or some might only on certain pins.Pin.ALT
- Pin is configured to perform an alternative function, which is port specific. For a pin configured in such a way any other Pin methods (exceptPin.init()
) are not applicable (calling them will lead to undefined, or a hardware-specific, result). Not all ports implement this mode.Pin.ALT_OPEN_DRAIN
- The Same asPin.ALT
, but the pin is configured as open-drain. Not all ports implement this mode.
pull
specifies if the pin has a (weak) pull resistor attached, and can be one of:None
- No pull up or down resistor.Pin.PULL_UP
- Pull up resistor enabled.Pin.PULL_DOWN
- Pull down resistor enabled.
value
is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial output pin value if given, otherwise the state of the pin peripheral remains unchanged.drive
specifies the output power of the pin and can be one of:Pin.LOW_POWER
,Pin.MED_POWER
orPin.HIGH_POWER
. The actual current driving capabilities are port dependent. Not all ports implement this argument.alt
specifies an alternate function for the pin and the values it can take are port dependent. This argument is valid only forPin.ALT
andPin.ALT_OPEN_DRAIN
modes. It may be used when a pin supports more than one alternate function. If only one pin alternate function is supported the this argument is not required. Not all ports implement this argument.
As specified above, the Pin class allows to set an alternate function for a particular pin, but it does not specify any further operations on such a pin. Pins configured in alternate-function mode are usually not used as GPIO but are instead driven by other hardware peripherals. The only operation supported on such a pin is re-initialising, by calling the constructor or
Pin.init()
method. If a pin that is configured in alternate-function mode is re-initialised withPin.IN
,Pin.OUT
, orPin.OPEN_DRAIN
, the alternate function will be removed from the pin.
-
Pin.
init
(mode=-1, pull=-1, *, value, drive, alt)¶ Re-initialise the pin using the given parameters. Only those arguments that are specified will be set. The rest of the pin peripheral state will remain unchanged. See the constructor documentation for details of the arguments.
Returns
None
.
-
Pin.
value
([x])¶ This method allows to set and get the value of the pin, depending on whether the argument
x
is supplied or not.If the argument is omitted then this method gets the digital logic level of the pin, returning 0 or 1 corresponding to low and high voltage signals respectively. The behaviour of this method depends on the mode of the pin:
Pin.IN
- The method returns the actual input value currently present on the pin.Pin.OUT
- The behaviour and return value of the method is undefined.Pin.OPEN_DRAIN
- If the pin is in state ‘0’ then the behaviour and return value of the method is undefined. Otherwise, if the pin is in state ‘1’, the method returns the actual input value currently present on the pin.
If the argument is supplied then this method sets the digital logic level of the pin. The argument
x
can be anything that converts to a boolean. If it converts toTrue
, the pin is set to state ‘1’, otherwise it is set to state ‘0’. The behaviour of this method depends on the mode of the pin:Pin.IN
- The value is stored in the output buffer for the pin. The pin state does not change, it remains in the high-impedance state. The stored value will become active on the pin as soon as it is changed toPin.OUT
orPin.OPEN_DRAIN
mode.Pin.OUT
- The output buffer is set to the given value immediately.Pin.OPEN_DRAIN
- If the value is ‘0’ the pin is set to a low voltage state. Otherwise the pin is set to high-impedance state.
When setting the value this method returns
None
.
-
Pin.
__call__
([x])¶ Pin objects are callable. The call method provides a (fast) shortcut to set and get the value of the pin. It is equivalent to Pin.value([x]). See
Pin.value()
for more details.
-
Pin.
on
()¶ Set pin to “1” output level.
-
Pin.
off
()¶ Set pin to “0” output level.
-
Pin.
mode
([mode])¶ Get or set the pin mode. See the constructor documentation for details of the
mode
argument.
-
Pin.
pull
([pull])¶ Get or set the pin pull state. See the constructor documentation for details of the
pull
argument.
-
Pin.
drive
([drive])¶ Get or set the pin drive strength. See the constructor documentation for details of the
drive
argument.Not all ports implement this method.
Availability: WiPy.
-
Pin.
irq
(handler=None, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING), *, priority=1, wake=None)¶ Configure an interrupt handler to be called when the trigger source of the pin is active. If the pin mode is
Pin.IN
then the trigger source is the external value on the pin. If the pin mode isPin.OUT
then the trigger source is the output buffer of the pin. Otherwise, if the pin mode isPin.OPEN_DRAIN
then the trigger source is the output buffer for state ‘0’ and the external pin value for state ‘1’.The arguments are:
handler
is an optional function to be called when the interrupt triggers.trigger
configures the event which can generate an interrupt. Possible values are:Pin.IRQ_FALLING
interrupt on falling edge.Pin.IRQ_RISING
interrupt on rising edge.Pin.IRQ_LOW_LEVEL
interrupt on low level.Pin.IRQ_HIGH_LEVEL
interrupt on high level.
These values can be OR’ed together to trigger on multiple events.
priority
sets the priority level of the interrupt. The values it can take are port-specific, but higher values always represent higher priorities.wake
selects the power mode in which this interrupt can wake up the system. It can bemachine.IDLE
,machine.SLEEP
ormachine.DEEPSLEEP
. These values can also be OR’ed together to make a pin generate interrupts in more than one power mode.
This method returns a callback object.
class Signal – control and sense external I/O devices¶
The Signal class is a simple extension of the Pin
class. Unlike Pin, which
can be only in “absolute” 0 and 1 states, a Signal can be in “asserted”
(on) or “deasserted” (off) states, while being inverted (active-low) or
not. In other words, it adds logical inversion support to Pin functionality.
While this may seem a simple addition, it is exactly what is needed to
support wide array of simple digital devices in a way portable across
different boards, which is one of the major MicroPython goals. Regardless
of whether different users have an active-high or active-low LED, a normally
open or normally closed relay - you can develop a single, nicely looking
application which works with each of them, and capture hardware
configuration differences in few lines in the config file of your app.
Example:
from machine import Pin, Signal
# Suppose you have an active-high LED on pin 0
led1_pin = Pin(0, Pin.OUT)
# ... and active-low LED on pin 1
led2_pin = Pin(1, Pin.OUT)
# Now to light up both of them using Pin class, you'll need to set
# them to different values
led1_pin.value(1)
led2_pin.value(0)
# Signal class allows to abstract away active-high/active-low
# difference
led1 = Signal(led1_pin, invert=False)
led2 = Signal(led2_pin, invert=True)
# Now lighting up them looks the same
led1.value(1)
led2.value(1)
# Even better:
led1.on()
led2.on()
Following is the guide when Signal vs Pin should be used:
- Use Signal: If you want to control a simple on/off (including software PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or read simple binary sensors, like normally open or normally closed buttons, pulled high or low, Reed switches, moisture/flame detectors, etc. etc. Summing up, if you have a real physical device/sensor requiring GPIO access, you likely should use a Signal.
- Use Pin: If you implement a higher-level protocol or bus to communicate with more complex devices.
The split between Pin and Signal come from the usecases above and the architecture of MicroPython: Pin offers the lowest overhead, which may be important when bit-banging protocols. But Signal adds additional flexibility on top of Pin, at the cost of minor overhead (much smaller than if you implemented active-high vs active-low device differences in Python manually!). Also, Pin is a low-level object which needs to be implemented for each support board, while Signal is a high-level object which comes for free once Pin is implemented.
If in doubt, give the Signal a try! Once again, it is offered to save developers from the need to handle unexciting differences like active-low vs active-high signals, and allow other users to share and enjoy your application, instead of being frustrated by the fact that it doesn’t work for them simply because their LEDs or relays are wired in a slightly different way.
-
class
machine.
Signal
(pin_obj, invert=False)¶ -
class
machine.
Signal
(pin_arguments..., *, invert=False) Create a Signal object. There’re two ways to create it:
- By wrapping existing Pin object - universal method which works for any board.
- By passing required Pin parameters directly to Signal constructor, skipping the need to create intermediate Pin object. Available on many, but not all boards.
The arguments are:
pin_obj
is existing Pin object.pin_arguments
are the same arguments as can be passed to Pin constructor.invert
- if True, the signal will be inverted (active low).
-
Signal.
value
([x])¶ This method allows to set and get the value of the signal, depending on whether the argument
x
is supplied or not.If the argument is omitted then this method gets the signal level, 1 meaning signal is asserted (active) and 0 - signal inactive.
If the argument is supplied then this method sets the signal level. The argument
x
can be anything that converts to a boolean. If it converts toTrue
, the signal is active, otherwise it is inactive.Correspondence between signal being active and actual logic level on the underlying pin depends on whether signal is inverted (active-low) or not. For non-inverted signal, active status corresponds to logical 1, inactive - to logical 0. For inverted/active-low signal, active status corresponds to logical 0, while inactive - to logical 1.
-
Signal.
on
()¶ Activate signal.
-
Signal.
off
()¶ Deactivate signal.
class ADC – analog to digital conversion¶
Usage:
import machine
adc = machine.ADC() # create an ADC object
apin = adc.channel(pin='GP3') # create an analog pin on GP3
val = apin() # read an analog value
-
class
machine.
ADC
(id=0, *, bits=12)¶ Create an ADC object associated with the given pin. This allows you to then read analog values on that pin. For more info check the pinout and alternate functions table.
Warning
ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it can withstand). When GP2, GP3, GP4 or GP5 are remapped to the ADC block, 1.8 V is the maximum. If these pins are used in digital mode, then the maximum allowed input is 3.6V.
-
ADC.
channel
(id, *, pin)¶ Create an analog pin. If only channel ID is given, the correct pin will be selected. Alternatively, only the pin can be passed and the correct channel will be selected. Examples:
# all of these are equivalent and enable ADC channel 1 on GP3 apin = adc.channel(1) apin = adc.channel(pin='GP3') apin = adc.channel(id=1, pin='GP3')
-
ADC.
init
()¶ Enable the ADC block.
-
ADC.
deinit
()¶ Disable the ADC block.
class ADCChannel — read analog values from internal or external sources¶
ADC channels can be connected to internal points of the MCU or to GPIO pins. ADC channels are created using the ADC.channel method.
-
machine.
adcchannel
()¶ Fast method to read the channel value.
-
adcchannel.
value
()¶ Read the channel value.
-
adcchannel.
init
()¶ Re-init (and effectively enable) the ADC channel.
-
adcchannel.
deinit
()¶ Disable the ADC channel.
class UART – duplex serial communication bus¶
UART implements the standard UART/USART duplex serial communications protocol. At the physical level it consists of 2 lines: RX and TX. The unit of communication is a character (not to be confused with a string character) which can be 8 or 9 bits wide.
UART objects can be created and initialised using:
from machine import UART
uart = UART(1, 9600) # init with given baudrate
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
Supported parameters differ on a board:
Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With parity=None, only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits are supported.
WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2.
A UART object acts like a stream
object and reading and writing is done
using the standard stream methods:
uart.read(10) # read 10 characters, returns a bytes object
uart.read() # read all available characters
uart.readline() # read a line
uart.readinto(buf) # read and store into the given buffer
uart.write('abc') # write the 3 characters
-
UART.
init
(baudrate=9600, bits=8, parity=None, stop=1, *, ...)¶ Initialise the UART bus with the given parameters:
- baudrate is the clock rate.
- bits is the number of bits per character, 7, 8 or 9.
- parity is the parity,
None
, 0 (even) or 1 (odd). - stop is the number of stop bits, 1 or 2.
Additional keyword-only parameters that may be supported by a port are:
- tx specifies the TX pin to use.
- rx specifies the RX pin to use.
- txbuf specifies the length in characters of the TX buffer.
- rxbuf specifies the length in characters of the RX buffer.
On the WiPy only the following keyword-only parameter is supported:
- pins is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
Any of the pins can be None if one wants the UART to operate with limited functionality.
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
When no pins are given, then the default set of TX and RX pins is taken, and hardware
flow control will be disabled. If pins is
None
, no pin assignment will be made.
-
UART.
deinit
()¶ Turn off the UART bus.
-
UART.
any
()¶ Returns an integer counting the number of characters that can be read without blocking. It will return 0 if there are no characters available and a positive number if there are characters. The method may return 1 even if there is more than one character available for reading.
For more sophisticated querying of available characters use select.poll:
poll = select.poll() poll.register(uart, select.POLLIN) poll.poll(timeout)
-
UART.
read
([nbytes])¶ Read characters. If
nbytes
is specified then read at most that many bytes, otherwise read as much data as possible.Return value: a bytes object containing the bytes read in. Returns
None
on timeout.
-
UART.
readinto
(buf[, nbytes])¶ Read bytes into the
buf
. Ifnbytes
is specified then read at most that many bytes. Otherwise, read at mostlen(buf)
bytes.Return value: number of bytes read and stored into
buf
orNone
on timeout.
-
UART.
readline
()¶ Read a line, ending in a newline character.
Return value: the line read or
None
on timeout.
-
UART.
write
(buf)¶ Write the buffer of bytes to the bus.
Return value: number of bytes written or
None
on timeout.
-
UART.
sendbreak
()¶ Send a break condition on the bus. This drives the bus low for a duration longer than required for a normal transmission of a character.
-
UART.
irq
(trigger, priority=1, handler=None, wake=machine.IDLE)¶ Create a callback to be triggered when data is received on the UART.
- trigger can only be
UART.RX_ANY
- priority level of the interrupt. Can take values in the range 1-7. Higher values represent higher priorities.
- handler an optional function to be called when new characters arrive.
- wake can only be
machine.IDLE
.
Note
The handler will be called whenever any of the following two conditions are met:
- 8 new characters have been received.
- At least 1 new character is waiting in the Rx buffer and the Rx line has been silent for the duration of 1 complete frame.
This means that when the handler function is called there will be between 1 to 8 characters waiting.
Returns an irq object.
Availability: WiPy.
- trigger can only be
class SPI – a Serial Peripheral Interface bus protocol (master side)¶
SPI is a synchronous serial protocol that is driven by a master. At the physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices can share the same bus. Each device should have a separate, 4th signal, SS (Slave Select), to select a particular device on a bus with which communication takes place. Management of an SS signal should happen in user code (via machine.Pin class).
-
class
machine.
SPI
(id, ...)¶ Construct an SPI object on the given bus,
id
. Values ofid
depend on a particular port and its hardware. Values 0, 1, etc. are commonly used to select hardware SPI block #0, #1, etc. Value -1 can be used for bitbanging (software) implementation of SPI (if supported by a port).With no additional parameters, the SPI object is created but not initialised (it has the settings from the last initialisation of the bus, if any). If extra arguments are given, the bus is initialised. See
init
for parameters of initialisation.
-
SPI.
init
(baudrate=1000000, *, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=None, mosi=None, miso=None, pins=(SCK, MOSI, MISO))¶ Initialise the SPI bus with the given parameters:
baudrate
is the SCK clock rate.polarity
can be 0 or 1, and is the level the idle clock line sits at.phase
can be 0 or 1 to sample data on the first or second clock edge respectively.bits
is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware.firstbit
can beSPI.MSB
orSPI.LSB
.sck
,mosi
,miso
are pins (machine.Pin) objects to use for bus signals. For most hardware SPI blocks (as selected byid
parameter to the constructor), pins are fixed and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver (id
= -1).pins
- WiPy port doesn’tsck
,mosi
,miso
arguments, and instead allows to specify them as a tuple ofpins
parameter.
-
SPI.
deinit
()¶ Turn off the SPI bus.
-
SPI.
read
(nbytes, write=0x00)¶ Read a number of bytes specified by
nbytes
while continuously writing the single byte given bywrite
. Returns abytes
object with the data that was read.
-
SPI.
readinto
(buf, write=0x00)¶ Read into the buffer specified by
buf
while continuously writing the single byte given bywrite
. ReturnsNone
.Note: on WiPy this function returns the number of bytes read.
-
SPI.
write
(buf)¶ Write the bytes contained in
buf
. ReturnsNone
.Note: on WiPy this function returns the number of bytes written.
-
SPI.
write_readinto
(write_buf, read_buf)¶ Write the bytes from
write_buf
while reading intoread_buf
. The buffers can be the same or different, but both buffers must have the same length. ReturnsNone
.Note: on WiPy this function returns the number of bytes written.
class I2C – a two-wire serial protocol¶
I2C is a two-wire protocol for communicating between devices. At the physical level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
I2C objects are created attached to a specific bus. They can be initialised when created, or initialised later on.
Printing the I2C object gives you information about its configuration.
Example usage:
from machine import I2C
i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz
# depending on the port, extra parameters may be required
# to select the peripheral and/or pins to use
i2c.scan() # scan for slaves, returning a list of 7-bit addresses
i2c.writeto(42, b'123') # write 3 bytes to slave with 7-bit address 42
i2c.readfrom(42, 4) # read 4 bytes from slave with 7-bit address 42
i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of slave 42,
# starting at memory-address 8 in the slave
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of slave 42
# starting at address 2 in the slave
-
class
machine.
I2C
(id=-1, *, scl, sda, freq=400000)¶ Construct and return a new I2C object using the following parameters:
- id identifies a particular I2C peripheral. The default value of -1 selects a software implementation of I2C which can work (in most cases) with arbitrary pins for SCL and SDA. If id is -1 then scl and sda must be specified. Other allowed values for id depend on the particular port/board, and specifying scl and sda may or may not be required or allowed in this case.
- scl should be a pin object specifying the pin to use for SCL.
- sda should be a pin object specifying the pin to use for SDA.
- freq should be an integer which sets the maximum frequency for SCL.
-
I2C.
init
(scl, sda, *, freq=400000)¶ Initialise the I2C bus with the given arguments:
- scl is a pin object for the SCL line
- sda is a pin object for the SDA line
- freq is the SCL clock rate
-
I2C.
deinit
()¶ Turn off the I2C bus.
Availability: WiPy.
-
I2C.
scan
()¶ Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of those that respond. A device responds if it pulls the SDA line low after its address (including a write bit) is sent on the bus.
The following methods implement the primitive I2C master bus operations and can be combined to make any I2C transaction. They are provided if you need more control over the bus, otherwise the standard methods (see below) can be used.
These methods are available on software I2C only.
-
I2C.
start
()¶ Generate a START condition on the bus (SDA transitions to low while SCL is high).
-
I2C.
stop
()¶ Generate a STOP condition on the bus (SDA transitions to high while SCL is high).
-
I2C.
readinto
(buf, nack=True)¶ Reads bytes from the bus and stores them into buf. The number of bytes read is the length of buf. An ACK will be sent on the bus after receiving all but the last byte. After the last byte is received, if nack is true then a NACK will be sent, otherwise an ACK will be sent (and in this case the slave assumes more bytes are going to be read in a later call).
-
I2C.
write
(buf)¶ Write the bytes from buf to the bus. Checks that an ACK is received after each byte and stops transmitting the remaining bytes if a NACK is received. The function returns the number of ACKs that were received.
The following methods implement the standard I2C master read and write operations that target a given slave device.
-
I2C.
readfrom
(addr, nbytes, stop=True)¶ Read nbytes from the slave specified by addr. If stop is true then a STOP condition is generated at the end of the transfer. Returns a
bytes
object with the data read.
-
I2C.
readfrom_into
(addr, buf, stop=True)¶ Read into buf from the slave specified by addr. The number of bytes read will be the length of buf. If stop is true then a STOP condition is generated at the end of the transfer.
The method returns
None
.
-
I2C.
writeto
(addr, buf, stop=True)¶ Write the bytes from buf to the slave specified by addr. If a NACK is received following the write of a byte from buf then the remaining bytes are not sent. If stop is true then a STOP condition is generated at the end of the transfer, even if a NACK is received. The function returns the number of ACKs that were received.
Some I2C devices act as a memory device (or set of registers) that can be read from and written to. In this case there are two addresses associated with an I2C transaction: the slave address and the memory address. The following methods are convenience functions to communicate with such devices.
-
I2C.
readfrom_mem
(addr, memaddr, nbytes, *, addrsize=8)¶ Read nbytes from the slave specified by addr starting from the memory address specified by memaddr. The argument addrsize specifies the address size in bits. Returns a
bytes
object with the data read.
-
I2C.
readfrom_mem_into
(addr, memaddr, buf, *, addrsize=8)¶ Read into buf from the slave specified by addr starting from the memory address specified by memaddr. The number of bytes read is the length of buf. The argument addrsize specifies the address size in bits (on ESP8266 this argument is not recognised and the address size is always 8 bits).
The method returns
None
.
-
I2C.
writeto_mem
(addr, memaddr, buf, *, addrsize=8)¶ Write buf to the slave specified by addr starting from the memory address specified by memaddr. The argument addrsize specifies the address size in bits (on ESP8266 this argument is not recognised and the address size is always 8 bits).
The method returns
None
.
class RTC – real time clock¶
The RTC is and independent clock that keeps track of the date and time.
Example usage:
rtc = machine.RTC()
rtc.init((2014, 5, 1, 4, 13, 0, 0, 0))
print(rtc.now())
-
class
machine.
RTC
(id=0, ...)¶ Create an RTC object. See init for parameters of initialization.
-
RTC.
init
(datetime)¶ Initialise the RTC. Datetime is a tuple of the form:
(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])
-
RTC.
now
()¶ Get get the current datetime tuple.
-
RTC.
deinit
()¶ Resets the RTC to the time of January 1, 2015 and starts running it again.
-
RTC.
alarm
(id, time, *, repeat=False)¶ Set the RTC alarm. Time might be either a millisecond value to program the alarm to current time + time_in_ms in the future, or a datetimetuple. If the time passed is in milliseconds, repeat can be set to
True
to make the alarm periodic.
-
RTC.
alarm_left
(alarm_id=0)¶ Get the number of milliseconds left before the alarm expires.
-
RTC.
cancel
(alarm_id=0)¶ Cancel a running alarm.
-
RTC.
irq
(*, trigger, handler=None, wake=machine.IDLE)¶ Create an irq object triggered by a real time clock alarm.
trigger
must beRTC.ALARM0
handler
is the function to be called when the callback is triggered.wake
specifies the sleep mode from where this interrupt can wake up the system.
class Timer – control hardware timers¶
Hardware timers deal with timing of periods and events. Timers are perhaps the most flexible and heterogeneous kind of hardware in MCUs and SoCs, differently greatly from a model to a model. MicroPython’s Timer class defines a baseline operation of executing a callback with a given period (or once after some delay), and allow specific boards to define more non-standard behavior (which thus won’t be portable to other boards).
See discussion of important constraints on Timer callbacks.
Note
Memory can’t be allocated inside irq handlers (an interrupt) and so
exceptions raised within a handler don’t give much information. See
micropython.alloc_emergency_exception_buf()
for how to get around this
limitation.
If you are using a WiPy board please refer to machine.TimerWiPy instead of this class.
-
class
machine.
Timer
(id, ...)¶ Construct a new timer object of the given id. Id of -1 constructs a virtual timer (if supported by a board).
-
Timer.
init
(*, mode=Timer.PERIODIC, period=-1, callback=None)¶ Initialise the timer. Example:
tim.init(period=100) # periodic with 100ms period tim.init(mode=Timer.ONE_SHOT, period=1000) # one shot firing after 1000ms
Keyword arguments:
mode
can be one of:Timer.ONE_SHOT
- The timer runs once until the configured period of the channel expires.Timer.PERIODIC
- The timer runs periodically at the configured frequency of the channel.
-
Timer.
deinit
()¶ Deinitialises the timer. Stops the timer, and disables the timer peripheral.
class WDT – watchdog timer¶
The WDT is used to restart the system when the application crashes and ends up into a non recoverable state. Once started it cannot be stopped or reconfigured in any way. After enabling, the application must “feed” the watchdog periodically to prevent it from expiring and resetting the system.
Example usage:
from machine import WDT
wdt = WDT(timeout=2000) # enable it with a timeout of 2s
wdt.feed()
Availability of this class: pyboard, WiPy.
class SD – secure digital memory card¶
Warning
This is a non-standard class and is only available on the cc3200 port.
The SD card class allows to configure and enable the memory card
module of the WiPy and automatically mount it as /sd
as part
of the file system. There are several pin combinations that can be
used to wire the SD card socket to the WiPy and the pins used can
be specified in the constructor. Please check the pinout and alternate functions
table. for
more info regarding the pins which can be remapped to be used with a SD card.
Example usage:
from machine import SD
import os
# clk cmd and dat0 pins must be passed along with
# their respective alternate functions
sd = machine.SD(pins=('GP10', 'GP11', 'GP15'))
os.mount(sd, '/sd')
# do normal file operations
micropython
– access and control MicroPython internals¶
Functions¶
-
micropython.
const
(expr)¶ Used to declare that the expression is a constant so that the compile can optimise it. The use of this function should be as follows:
from micropython import const CONST_X = const(123) CONST_Y = const(2 * CONST_X + 1)
Constants declared this way are still accessible as global variables from outside the module they are declared in. On the other hand, if a constant begins with an underscore then it is hidden, it is not available as a global variable, and does not take up any memory during execution.
This
const
function is recognised directly by the MicroPython parser and is provided as part of themicropython
module mainly so that scripts can be written which run under both CPython and MicroPython, by following the above pattern.
-
micropython.
opt_level
([level])¶ If level is given then this function sets the optimisation level for subsequent compilation of scripts, and returns
None
. Otherwise it returns the current optimisation level.The optimisation level controls the following compilation features:
- Assertions: at level 0 assertion statements are enabled and compiled into the bytecode; at levels 1 and higher assertions are not compiled.
- Built-in
__debug__
variable: at level 0 this variable expands toTrue
; at levels 1 and higher it expands toFalse
. - Source-code line numbers: at levels 0, 1 and 2 source-code line number are stored along with the bytecode so that exceptions can report the line number they occurred at; at levels 3 and higher line numbers are not stored.
The default optimisation level is usually level 0.
-
micropython.
alloc_emergency_exception_buf
(size)¶ Allocate size bytes of RAM for the emergency exception buffer (a good size is around 100 bytes). The buffer is used to create exceptions in cases when normal RAM allocation would fail (eg within an interrupt handler) and therefore give useful traceback information in these situations.
A good way to use this function is to put it at the start of your main script (eg
boot.py
ormain.py
) and then the emergency exception buffer will be active for all the code following it.
-
micropython.
mem_info
([verbose])¶ Print information about currently used memory. If the verbose argument is given then extra information is printed.
The information that is printed is implementation dependent, but currently includes the amount of stack and heap used. In verbose mode it prints out the entire heap indicating which blocks are used and which are free.
-
micropython.
qstr_info
([verbose])¶ Print information about currently interned strings. If the verbose argument is given then extra information is printed.
The information that is printed is implementation dependent, but currently includes the number of interned strings and the amount of RAM they use. In verbose mode it prints out the names of all RAM-interned strings.
-
micropython.
stack_use
()¶ Return an integer representing the current amount of stack that is being used. The absolute value of this is not particularly useful, rather it should be used to compute differences in stack usage at different points.
-
micropython.
heap_lock
()¶
-
micropython.
heap_unlock
()¶ Lock or unlock the heap. When locked no memory allocation can occur and a
MemoryError
will be raised if any heap allocation is attempted.These functions can be nested, ie
heap_lock()
can be called multiple times in a row and the lock-depth will increase, and thenheap_unlock()
must be called the same number of times to make the heap available again.
-
micropython.
kbd_intr
(chr)¶ Set the character that will raise a
KeyboardInterrupt
exception. By default this is set to 3 during script execution, corresponding to Ctrl-C. Passing -1 to this function will disable capture of Ctrl-C, and passing 3 will restore it.This function can be used to prevent the capturing of Ctrl-C on the incoming stream of characters that is usually used for the REPL, in case that stream is used for other purposes.
-
micropython.
schedule
(func, arg)¶ Schedule the function func to be executed “very soon”. The function is passed the value arg as its single argument. “Very soon” means that the MicroPython runtime will do its best to execute the function at the earliest possible time, given that it is also trying to be efficient, and that the following conditions hold:
- A scheduled function will never preempt another scheduled function.
- Scheduled functions are always executed “between opcodes” which means that all fundamental Python operations (such as appending to a list) are guaranteed to be atomic.
- A given port may define “critical regions” within which scheduled functions will never be executed. Functions may be scheduled within a critical region but they will not be executed until that region is exited. An example of a critical region is a preempting interrupt handler (an IRQ).
A use for this function is to schedule a callback from a preempting IRQ. Such an IRQ puts restrictions on the code that runs in the IRQ (for example the heap may be locked) and scheduling a function to call later will lift those restrictions.
Note: If
schedule()
is called from a preempting IRQ, when memory allocation is not allowed and the callback to be passed toschedule()
is a bound method, passing this directly will fail. This is because creating a reference to a bound method causes memory allocation. A solution is to create a reference to the method in the class constructor and to pass that reference toschedule()
. This is discussed in detail here reference documentation under “Creation of Python objects”.There is a finite stack to hold the scheduled functions and
schedule()
will raise aRuntimeError
if the stack is full.
ucryptolib
– cryptographic ciphers¶
Classes¶
-
class
ucryptolib.
aes
¶ -
classmethod
__init__
(key, mode[, IV])¶ Initialize cipher object, suitable for encryption/decryption. Note: after initialization, cipher object can be use only either for encryption or decryption. Running decrypt() operation after encrypt() or vice versa is not supported.
Parameters are:
key is an encryption/decryption key (bytes-like).
mode is:
1
(orucryptolib.MODE_ECB
if it exists) for Electronic Code Book (ECB).2
(orucryptolib.MODE_CBC
if it exists) for Cipher Block Chaining (CBC)
IV is an initialization vector for CBC mode.
-
classmethod
uctypes
– access binary data in a structured way¶
This module implements “foreign data interface” for MicroPython. The idea
behind it is similar to CPython’s ctypes
modules, but the actual API is
different, streamlined and optimized for small size. The basic idea of the
module is to define data structure layout with about the same power as the
C language allows, and then access it using familiar dot-syntax to reference
sub-fields.
See also
- Module
ustruct
- Standard Python way to access binary data structures (doesn’t scale well to large and complex structures).
Defining structure layout¶
Structure layout is defined by a “descriptor” - a Python dictionary which encodes field names as keys and other properties required to access them as associated values. Currently, uctypes requires explicit specification of offsets for each field. Offset are given in bytes from a structure start.
Following are encoding examples for various field types:
Scalar types:
"field_name": offset | uctypes.UINT32
in other words, value is scalar type identifier ORed with field offset (in bytes) from the start of the structure.
Recursive structures:
"sub": (offset, { "b0": 0 | uctypes.UINT8, "b1": 1 | uctypes.UINT8, })
i.e. value is a 2-tuple, first element of which is offset, and second is a structure descriptor dictionary (note: offsets in recursive descriptors are relative to the structure it defines).
Arrays of primitive types:
"arr": (offset | uctypes.ARRAY, size | uctypes.UINT8),
i.e. value is a 2-tuple, first element of which is ARRAY flag ORed with offset, and second is scalar element type ORed number of elements in array.
Arrays of aggregate types:
"arr2": (offset | uctypes.ARRAY, size, {"b": 0 | uctypes.UINT8}),
i.e. value is a 3-tuple, first element of which is ARRAY flag ORed with offset, second is a number of elements in array, and third is descriptor of element type.
Pointer to a primitive type:
"ptr": (offset | uctypes.PTR, uctypes.UINT8),
i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, and second is scalar element type.
Pointer to an aggregate type:
"ptr2": (offset | uctypes.PTR, {"b": 0 | uctypes.UINT8}),
i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, second is descriptor of type pointed to.
Bitfields:
"bitf0": offset | uctypes.BFUINT16 | lsbit << uctypes.BF_POS | bitsize << uctypes.BF_LEN,
i.e. value is type of scalar value containing given bitfield (typenames are similar to scalar types, but prefixes with “BF”), ORed with offset for scalar value containing the bitfield, and further ORed with values for bit offset and bit length of the bitfield within scalar value, shifted by BF_POS and BF_LEN positions, respectively. Bitfield position is counted from the least significant bit, and is the number of right-most bit of a field (in other words, it’s a number of bits a scalar needs to be shifted right to extract the bitfield).
In the example above, first a UINT16 value will be extracted at offset 0 (this detail may be important when accessing hardware registers, where particular access size and alignment are required), and then bitfield whose rightmost bit is lsbit bit of this UINT16, and length is bitsize bits, will be extracted. For example, if lsbit is 0 and bitsize is 8, then effectively it will access least-significant byte of UINT16.
Note that bitfield operations are independent of target byte endianness, in particular, example above will access least-significant byte of UINT16 in both little- and big-endian structures. But it depends on the least significant bit being numbered 0. Some targets may use different numbering in their native ABI, but
uctypes
always uses the normalized numbering described above.
Module contents¶
-
class
uctypes.
struct
(addr, descriptor, layout_type=NATIVE)¶ Instantiate a “foreign data structure” object based on structure address in memory, descriptor (encoded as a dictionary), and layout type (see below).
-
uctypes.
LITTLE_ENDIAN
¶ Layout type for a little-endian packed structure. (Packed means that every field occupies exactly as many bytes as defined in the descriptor, i.e. the alignment is 1).
-
uctypes.
BIG_ENDIAN
¶ Layout type for a big-endian packed structure.
-
uctypes.
NATIVE
¶ Layout type for a native structure - with data endianness and alignment conforming to the ABI of the system on which MicroPython runs.
-
uctypes.
sizeof
(struct)¶ Return size of data structure in bytes. Argument can be either structure class or specific instantiated structure object (or its aggregate field).
-
uctypes.
addressof
(obj)¶ Return address of an object. Argument should be bytes, bytearray or other object supporting buffer protocol (and address of this buffer is what actually returned).
-
uctypes.
bytes_at
(addr, size)¶ Capture memory at the given address and size as bytes object. As bytes object is immutable, memory is actually duplicated and copied into bytes object, so if memory contents change later, created object retains original value.
-
uctypes.
bytearray_at
(addr, size)¶ Capture memory at the given address and size as bytearray object. Unlike bytes_at() function above, memory is captured by reference, so it can be both written too, and you will access current value at the given memory address.
Structure descriptors and instantiating structure objects¶
Given a structure descriptor dictionary and its layout type, you can
instantiate a specific structure instance at a given memory address
using uctypes.struct()
constructor. Memory address usually comes from
following sources:
- Predefined address, when accessing hardware registers on a baremetal system. Lookup these addresses in datasheet for a particular MCU/SoC.
- As a return value from a call to some FFI (Foreign Function Interface) function.
- From uctypes.addressof(), when you want to pass arguments to an FFI function, or alternatively, to access some data for I/O (for example, data read from a file or network socket).
Structure objects¶
Structure objects allow accessing individual fields using standard dot
notation: my_struct.substruct1.field1
. If a field is of scalar type,
getting it will produce a primitive value (Python integer or float)
corresponding to the value contained in a field. A scalar field can also
be assigned to.
If a field is an array, its individual elements can be accessed with
the standard subscript operator []
- both read and assigned to.
If a field is a pointer, it can be dereferenced using [0]
syntax
(corresponding to C *
operator, though [0]
works in C too).
Subscripting a pointer with other integer values but 0 are supported too,
with the same semantics as in C.
Summing up, accessing structure fields generally follows C syntax,
except for pointer dereference, when you need to use [0]
operator
instead of *
.
Limitations¶
Accessing non-scalar fields leads to allocation of intermediate objects to represent them. This means that special care should be taken to layout a structure which needs to be accessed when memory allocation is disabled (e.g. from an interrupt). The recommendations are:
- Avoid nested structures. For example, instead of
mcu_registers.peripheral_a.register1
, define separate layout descriptors for each peripheral, to be accessed asperipheral_a.register1
. - Avoid other non-scalar data, like array. For example, instead of
peripheral_a.register[0]
useperipheral_a.register0
.
Note that these recommendations will lead to decreased readability and conciseness of layouts, so they should be used only if the need to access structure fields without allocation is anticipated (it’s even possible to define 2 parallel layouts - one for normal usage, and a restricted one to use when memory allocation is prohibited).
The MicroPython language¶
MicroPython aims to implement the Python 3.4 standard (with selected features from later versions) with respect to language syntax, and most of the features of MicroPython are identical to those described by the “Language Reference” documentation at docs.python.org.
The MicroPython standard library is described in the corresponding chapter. The MicroPython differences from CPython chapter describes differences between MicroPython and CPython (which mostly concern standard library and types, but also some language-level features).
This chapter describes features and peculiarities of MicroPython implementation and the best practices to use them.
Glossary¶
- baremetal
- A system without a (full-fledged) OS, for example an MCU-based system. When running on a baremetal system, MicroPython effectively becomes its user-facing OS with a command interpreter (REPL).
- board
- A PCB board. Oftentimes, the term is used to denote a particular model of an MCU system. Sometimes, it is used to actually refer to MicroPython port to a particular board (and then may also refer to “boardless” ports like Unix port).
- callee-owned tuple
- A tuple returned by some builtin function/method, containing data which is valid for a limited time, usually until next call to the same function (or a group of related functions). After next call, data in the tuple may be changed. This leads to the following restriction on the usage of callee-owned tuples - references to them cannot be stored. The only valid operation is extracting values from them (including making a copy). Callee-owned tuples is a MicroPython-specific construct (not available in the general Python language), introduced for memory allocation optimization. The idea is that callee-owned tuple is allocated once and stored on the callee side. Subsequent calls don’t require allocation, allowing to return multiple values when allocation is not possible (e.g. in interrupt context) or not desirable (because allocation inherently leads to memory fragmentation). Note that callee-owned tuples are effectively mutable tuples, making an exception to Python’s rule that tuples are immutable. (It may be interesting why tuples were used for such a purpose then, instead of mutable lists - the reason for that is that lists are mutable from user application side too, so a user could do things to a callee-owned list which the callee doesn’t expect and could lead to problems; a tuple is protected from this.)
- CPython
- CPython is the reference implementation of Python programming language, and the most well-known one, which most of the people run. It is however one of many implementations (among which Jython, IronPython, PyPy, and many more, including MicroPython). As there is no formal specification of the Python language, only CPython documentation, it is not always easy to draw a line between Python the language and CPython its particular implementation. This however leaves more freedom for other implementations. For example, MicroPython does a lot of things differently than CPython, while still aspiring to be a Python language implementation.
- GPIO
- General-purpose input/output. The simplest means to control
electrical signals. With GPIO, user can configure hardware
signal pin to be either input or output, and set or get
its digital signal value (logical “0” or “1”). MicroPython
abstracts GPIO access using
machine.Pin
andmachine.Signal
classes. - GPIO port
- A group of GPIO pins, usually based on hardware properties of these pins (e.g. controllable by the same register).
- interned string
- A string referenced by its (unique) identity rather than its address. Interned strings are thus can be quickly compared just by their identifiers, instead of comparing by content. The drawbacks of interned strings are that interning operation takes time (proportional to the number of existing interned strings, i.e. becoming slower and slower over time) and that the space used for interned strings is not reclaimable. String interning is done automatically by MicroPython compiler and runtimer when it’s either required by the implementation (e.g. function keyword arguments are represented by interned string id’s) or deemed beneficial (e.g. for short enough strings, which have a chance to be repeated, and thus interning them would save memory on copies). Most of string and I/O operations don’t produce interned strings due to drawbacks described above.
- MCU
- Microcontroller. Microcontrollers usually have much less resources than a full-fledged computing system, but smaller, cheaper and require much less power. MicroPython is designed to be small and optimized enough to run on an average modern microcontroller.
- micropython-lib
MicroPython is (usually) distributed as a single executable/binary file with just few builtin modules. There is no extensive standard library comparable with CPython. Instead, there is a related, but separate project micropython-lib which provides implementations for many modules from CPython’s standard library. However, large subset of these modules require POSIX-like environment (Linux, FreeBSD, MacOS, etc.; Windows may be partially supported), and thus would work or make sense only with
MicroPython Unix port
. Some subset of modules is however usable forbaremetal
ports too.Unlike monolithic CPython stdlib, micropython-lib modules are intended to be installed individually - either using manual copying or using upip.
- MicroPython port
- MicroPython supports different boards, RTOSes, and OSes, and can be relatively easily adapted to new systems. MicroPython with support for a particular system is called a “port” to that system. Different ports may have widely different functionality. This documentation is intended to be a reference of the generic APIs available across different ports (“MicroPython core”). Note that some ports may still omit some APIs described here (e.g. due to resource constraints). Any such differences, and port-specific extensions beyond MicroPython core functionality, would be described in the separate port-specific documentation.
- MicroPython Unix port
- Unix port is one of the major MicroPython ports. It is intended to run on POSIX-compatible operating systems, like Linux, MacOS, FreeBSD, Solaris, etc. It also serves as the basis of Windows port. The importance of Unix port lies in the fact that while there are many different boards, so two random users unlikely have the same board, almost all modern OSes have some level of POSIX compatibility, so Unix port serves as a kind of “common ground” to which any user can have access. So, Unix port is used for initial prototyping, different kinds of testing, development of machine-independent features, etc. All users of MicroPython, even those which are interested only in running MicroPython on MCU systems, are recommended to be familiar with Unix (or Windows) port, as it is important productivity helper and a part of normal MicroPython workflow.
- port
- Either MicroPython port or GPIO port. If not clear from context, it’s recommended to use full specification like one of the above.
- stream
- Also known as a “file-like object”. An object which provides sequential
read-write access to the underlying data. A stream object implements
a corresponding interface, which consists of methods like
read()
,write()
,readinto()
,seek()
,flush()
,close()
, etc. A stream is an important concept in MicroPython, many I/O objects implement the stream interface, and thus can be used consistently and interchangeably in different contexts. For more information on streams in MicroPython, seeuio
module. - upip
- (Literally, “micro pip”). A package manage for MicroPython, inspired by CPython’s pip, but much smaller and with reduced functionality. upip runs both on Unix port and on baremetal ports (those which offer filesystem and networking support).
The MicroPython Interactive Interpreter Mode (aka REPL)¶
This section covers some characteristics of the MicroPython Interactive Interpreter Mode. A commonly used term for this is REPL (read-eval-print-loop) which will be used to refer to this interactive prompt.
Auto-indent¶
When typing python statements which end in a colon (for example if, for, while) then the prompt will change to three dots (…) and the cursor will be indented by 4 spaces. When you press return, the next line will continue at the same level of indentation for regular statements or an additional level of indentation where appropriate. If you press the backspace key then it will undo one level of indentation.
If your cursor is all the way back at the beginning, pressing RETURN will then execute the code that you’ve entered. The following shows what you’d see after entering a for statement (the underscore shows where the cursor winds up):
>>> for i in range(30):
... _
If you then enter an if statement, an additional level of indentation will be provided:
>>> for i in range(30):
... if i > 3:
... _
Now enter break
followed by RETURN and press BACKSPACE:
>>> for i in range(30):
... if i > 3:
... break
... _
Finally type print(i)
, press RETURN, press BACKSPACE and press RETURN again:
>>> for i in range(30):
... if i > 3:
... break
... print(i)
...
0
1
2
3
>>>
Auto-indent won’t be applied if the previous two lines were all spaces. This means that you can finish entering a compound statement by pressing RETURN twice, and then a third press will finish and execute.
Auto-completion¶
While typing a command at the REPL, if the line typed so far corresponds to
the beginning of the name of something, then pressing TAB will show
possible things that could be entered. For example, first import the machine
module by entering import machine
and pressing RETURN.
Then type m
and press TAB and it should expand to machine
.
Enter a dot .
and press TAB again. You should see something like:
>>> machine.
__name__ info unique_id reset
bootloader freq rng idle
sleep deepsleep disable_irq enable_irq
Pin
The word will be expanded as much as possible until multiple possibilities exist.
For example, type machine.Pin.AF3
and press TAB and it will expand to
machine.Pin.AF3_TIM
. Pressing TAB a second time will show the possible
expansions:
>>> machine.Pin.AF3_TIM
AF3_TIM10 AF3_TIM11 AF3_TIM8 AF3_TIM9
>>> machine.Pin.AF3_TIM
Interrupting a running program¶
You can interrupt a running program by pressing Ctrl-C. This will raise a KeyboardInterrupt which will bring you back to the REPL, providing your program doesn’t intercept the KeyboardInterrupt exception.
For example:
>>> for i in range(1000000):
... print(i)
...
0
1
2
3
...
6466
6467
6468
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt:
>>>
Paste Mode¶
If you want to paste some code into your terminal window, the auto-indent feature will mess things up. For example, if you had the following python code:
def foo():
print('This is a test to show paste mode')
print('Here is a second line')
foo()
and you try to paste this into the normal REPL, then you will see something like this:
>>> def foo():
... print('This is a test to show paste mode')
... print('Here is a second line')
... foo()
...
File "<stdin>", line 3
IndentationError: unexpected indent
If you press Ctrl-E, then you will enter paste mode, which essentially turns off
the auto-indent feature, and changes the prompt from >>>
to ===
. For example:
>>>
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 allows blank lines to be pasted. The pasted text is compiled as if it were a file. Pressing Ctrl-D exits paste mode and initiates the compilation.
Soft Reset¶
A soft reset will reset the python interpreter, but tries not to reset the method by which you’re connected to the MicroPython board (USB-serial, or Wifi).
You can perform a soft reset from the REPL by pressing Ctrl-D, or from your python code by executing:
machine.soft_reset()
For example, if you reset your MicroPython board, and you execute a dir() command, you’d see something like this:
>>> dir()
['__name__', 'pyb']
Now create some variables and repeat the dir() command:
>>> i = 1
>>> j = 23
>>> x = 'abc'
>>> dir()
['j', 'x', '__name__', 'pyb', 'i']
>>>
Now if you enter Ctrl-D, and repeat the dir() command, you’ll see that your variables no longer exist:
PYB: sync filesystems
PYB: soft reboot
MicroPython v1.5-51-g6f70283-dirty on 2015-10-30; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> dir()
['__name__', 'pyb']
>>>
The special variable _ (underscore)¶
When you use the REPL, you may perform computations and see the results. MicroPython stores the results of the previous statement in the variable _ (underscore). So you can use the underscore to save the result in a variable. For example:
>>> 1 + 2 + 3 + 4 + 5
15
>>> x = _
>>> x
15
>>>
Raw Mode¶
Raw mode is not something that a person would normally use. It is intended for programmatic use. It essentially behaves like paste mode with echo turned off.
Raw mode is entered using Ctrl-A. You then send your python code, followed by a Ctrl-D. The Ctrl-D will be acknowledged by ‘OK’ and then the python code will be compiled and executed. Any output (or errors) will be sent back. Entering Ctrl-B will leave raw mode and return the the regular (aka friendly) REPL.
The tools/pyboard.py
program uses the raw REPL to execute python files on the
MicroPython board.
Writing interrupt handlers¶
On suitable hardware MicroPython offers the ability to write interrupt handlers in Python. Interrupt handlers - also known as interrupt service routines (ISR’s) - are defined as callback functions. These are executed in response to an event such as a timer trigger or a voltage change on a pin. Such events can occur at any point in the execution of the program code. This carries significant consequences, some specific to the MicroPython language. Others are common to all systems capable of responding to real time events. This document covers the language specific issues first, followed by a brief introduction to real time programming for those new to it.
This introduction uses vague terms like “slow” or “as fast as possible”. This is deliberate, as speeds are application dependent. Acceptable durations for an ISR are dependent on the rate at which interrupts occur, the nature of the main program, and the presence of other concurrent events.
Tips and recommended practices¶
This summarises the points detailed below and lists the principal recommendations for interrupt handler code.
- Keep the code as short and simple as possible.
- Avoid memory allocation: no appending to lists or insertion into dictionaries, no floating point.
- Consider using
micropython.schedule
to work around the above constraint. - Where an ISR returns multiple bytes use a pre-allocated
bytearray
. If multiple integers are to be shared between an ISR and the main program consider an array (array.array
). - Where data is shared between the main program and an ISR, consider disabling interrupts prior to accessing the data in the main program and re-enabling them immediately afterwards (see Critical Sections).
- Allocate an emergency exception buffer (see below).
MicroPython Issues¶
The emergency exception buffer¶
If an error occurs in an ISR, MicroPython is unable to produce an error report unless a special buffer is created for the purpose. Debugging is simplified if the following code is included in any program using interrupts.
import micropython
micropython.alloc_emergency_exception_buf(100)
Simplicity¶
For a variety of reasons it is important to keep ISR code as short and simple as possible. It should do only what has to be done immediately after the event which caused it: operations which can be deferred should be delegated to the main program loop. Typically an ISR will deal with the hardware device which caused the interrupt, making it ready for the next interrupt to occur. It will communicate with the main loop by updating shared data to indicate that the interrupt has occurred, and it will return. An ISR should return control to the main loop as quickly as possible. This is not a specific MicroPython issue so is covered in more detail below.
Communication between an ISR and the main program¶
Normally an ISR needs to communicate with the main program. The simplest means of doing this is via one or more
shared data objects, either declared as global or shared via a class (see below). There are various restrictions
and hazards around doing this, which are covered in more detail below. Integers, bytes
and bytearray
objects
are commonly used for this purpose along with arrays (from the array module) which can store various data types.
The use of object methods as callbacks¶
MicroPython supports this powerful technique which enables an ISR to share instance variables with the underlying code. It also enables a class implementing a device driver to support multiple device instances. The following example causes two LED’s to flash at different rates.
import pyb, micropython
micropython.alloc_emergency_exception_buf(100)
class Foo(object):
def __init__(self, timer, led):
self.led = led
timer.callback(self.cb)
def cb(self, tim):
self.led.toggle()
red = Foo(pyb.Timer(4, freq=1), pyb.LED(1))
green = Foo(pyb.Timer(2, freq=0.8), pyb.LED(2))
In this example the red
instance associates timer 4 with LED 1: when a timer 4 interrupt occurs red.cb()
is called causing LED 1 to change state. The green
instance operates similarly: a timer 2 interrupt
results in the execution of green.cb()
and toggles LED 2. The use of instance methods confers two
benefits. Firstly a single class enables code to be shared between multiple hardware instances. Secondly, as
a bound method the callback function’s first argument is self
. This enables the callback to access instance
data and to save state between successive calls. For example, if the class above had a variable self.count
set to zero in the constructor, cb()
could increment the counter. The red
and green
instances would
then maintain independent counts of the number of times each LED had changed state.
Creation of Python objects¶
ISR’s cannot create instances of Python objects. This is because MicroPython needs to allocate memory for the object from a store of free memory block called the heap. This is not permitted in an interrupt handler because heap allocation is not re-entrant. In other words the interrupt might occur when the main program is part way through performing an allocation - to maintain the integrity of the heap the interpreter disallows memory allocations in ISR code.
A consequence of this is that ISR’s can’t use floating point arithmetic; this is because floats are Python objects. Similarly an ISR can’t append an item to a list. In practice it can be hard to determine exactly which code constructs will attempt to perform memory allocation and provoke an error message: another reason for keeping ISR code short and simple.
One way to avoid this issue is for the ISR to use pre-allocated buffers. For example a class constructor
creates a bytearray
instance and a boolean flag. The ISR method assigns data to locations in the buffer and sets
the flag. The memory allocation occurs in the main program code when the object is instantiated rather than in the ISR.
The MicroPython library I/O methods usually provide an option to use a pre-allocated buffer. For
example pyb.i2c.recv()
can accept a mutable buffer as its first argument: this enables its use in an ISR.
A means of creating an object without employing a class or globals is as follows:
def set_volume(t, buf=bytearray(3)):
buf[0] = 0xa5
buf[1] = t >> 4
buf[2] = 0x5a
return buf
The compiler instantiates the default buf
argument when the function is
loaded for the first time (usually when the module it’s in is imported).
An instance of object creation occurs when a reference to a bound method is created. This means that an ISR cannot pass a bound method to a function. One solution is to create a reference to the bound method in the class constructor and to pass that reference in the ISR. For example:
class Foo():
def __init__(self):
self.bar_ref = self.bar # Allocation occurs here
self.x = 0.1
tim = pyb.Timer(4)
tim.init(freq=2)
tim.callback(self.cb)
def bar(self, _):
self.x *= 1.2
print(self.x)
def cb(self, t):
# Passing self.bar would cause allocation.
micropython.schedule(self.bar_ref, 0)
Other techniques are to define and instantiate the method in the constructor
or to pass Foo.bar()
with the argument self.
Use of Python objects¶
A further restriction on objects arises because of the way Python works. When an import
statement is executed the
Python code is compiled to bytecode, with one line of code typically mapping to multiple bytecodes. When the code
runs the interpreter reads each bytecode and executes it as a series of machine code instructions. Given that an
interrupt can occur at any time between machine code instructions, the original line of Python code may be only
partially executed. Consequently a Python object such as a set, list or dictionary modified in the main loop
may lack internal consistency at the moment the interrupt occurs.
A typical outcome is as follows. On rare occasions the ISR will run at the precise moment in time when the object is partially updated. When the ISR tries to read the object, a crash results. Because such problems typically occur on rare, random occasions they can be hard to diagnose. There are ways to circumvent this issue, described in Critical Sections below.
It is important to be clear about what constitutes the modification of an object. An alteration to a built-in type such as a dictionary is problematic. Altering the contents of an array or bytearray is not. This is because bytes or words are written as a single machine code instruction which is not interruptible: in the parlance of real time programming the write is atomic. A user defined object might instantiate an integer, array or bytearray. It is valid for both the main loop and the ISR to alter the contents of these.
MicroPython supports integers of arbitrary precision. Values between 2**30 -1 and -2**30 will be stored in a single machine word. Larger values are stored as Python objects. Consequently changes to long integers cannot be considered atomic. The use of long integers in ISR’s is unsafe because memory allocation may be attempted as the variable’s value changes.
Overcoming the float limitation¶
In general it is best to avoid using floats in ISR code: hardware devices normally handle integers and conversion to floats is normally done in the main loop. However there are a few DSP algorithms which require floating point. On platforms with hardware floating point (such as the Pyboard) the inline ARM Thumb assembler can be used to work round this limitation. This is because the processor stores float values in a machine word; values can be shared between the ISR and main program code via an array of floats.
Using micropython.schedule¶
This function enables an ISR to schedule a callback for execution “very soon”. The callback is queued for execution which will take place at a time when the heap is not locked. Hence it can create Python objects and use floats. The callback is also guaranteed to run at a time when the main program has completed any update of Python objects, so the callback will not encounter partially updated objects.
Typical usage is to handle sensor hardware. The ISR acquires data from the hardware and enables it to issue a further interrupt. It then schedules a callback to process the data.
Scheduled callbacks should comply with the principles of interrupt handler design outlined below. This is to avoid problems resulting from I/O activity and the modification of shared data which can arise in any code which pre-empts the main program loop.
Execution time needs to be considered in relation to the frequency with which interrupts can occur. If an
interrupt occurs while the previous callback is executing, a further instance of the callback will be queued
for execution; this will run after the current instance has completed. A sustained high interrupt repetition
rate therefore carries a risk of unconstrained queue growth and eventual failure with a RuntimeError
.
If the callback to be passed to schedule()
is a bound method, consider the
note in “Creation of Python objects”.
Exceptions¶
If an ISR raises an exception it will not propagate to the main loop. The interrupt will be disabled unless the exception is handled by the ISR code.
General Issues¶
This is merely a brief introduction to the subject of real time programming. Beginners should note that design errors in real time programs can lead to faults which are particularly hard to diagnose. This is because they can occur rarely and at intervals which are essentially random. It is crucial to get the initial design right and to anticipate issues before they arise. Both interrupt handlers and the main program need to be designed with an appreciation of the following issues.
Interrupt Handler Design¶
As mentioned above, ISR’s should be designed to be as simple as possible. They should always return in a short, predictable period of time. This is important because when the ISR is running, the main loop is not: inevitably the main loop experiences pauses in its execution at random points in the code. Such pauses can be a source of hard to diagnose bugs particularly if their duration is long or variable. In order to understand the implications of ISR run time, a basic grasp of interrupt priorities is required.
Interrupts are organised according to a priority scheme. ISR code may itself be interrupted by a higher priority interrupt. This has implications if the two interrupts share data (see Critical Sections below). If such an interrupt occurs it interposes a delay into the ISR code. If a lower priority interrupt occurs while the ISR is running, it will be delayed until the ISR is complete: if the delay is too long, the lower priority interrupt may fail. A further issue with slow ISR’s is the case where a second interrupt of the same type occurs during its execution. The second interrupt will be handled on termination of the first. However if the rate of incoming interrupts consistently exceeds the capacity of the ISR to service them the outcome will not be a happy one.
Consequently looping constructs should be avoided or minimised. I/O to devices other than to the interrupting device
should normally be avoided: I/O such as disk access, print
statements and UART access is relatively slow, and
its duration may vary. A further issue here is that filesystem functions are not reentrant: using filesystem I/O
in an ISR and the main program would be hazardous. Crucially ISR code should not wait on an event. I/O is acceptable
if the code can be guaranteed to return in a predictable period, for example toggling a pin or LED. Accessing the
interrupting device via I2C or SPI may be necessary but the time taken for such accesses should be calculated or
measured and its impact on the application assessed.
There is usually a need to share data between the ISR and the main loop. This may be done either through global variables or via class or instance variables. Variables are typically integer or boolean types, or integer or byte arrays (a pre-allocated integer array offers faster access than a list). Where multiple values are modified by the ISR it is necessary to consider the case where the interrupt occurs at a time when the main program has accessed some, but not all, of the values. This can lead to inconsistencies.
Consider the following design. An ISR stores incoming data in a bytearray, then adds the number of bytes received to an integer representing total bytes ready for processing. The main program reads the number of bytes, processes the bytes, then clears down the number of bytes ready. This will work until an interrupt occurs just after the main program has read the number of bytes. The ISR puts the added data into the buffer and updates the number received, but the main program has already read the number, so processes the data originally received. The newly arrived bytes are lost.
There are various ways of avoiding this hazard, the simplest being to use a circular buffer. If it is not possible to use a structure with inherent thread safety other ways are described below.
Reentrancy¶
A potential hazard may occur if a function or method is shared between the main program and one or more ISR’s or between multiple ISR’s. The issue here is that the function may itself be interrupted and a further instance of that function run. If this is to occur, the function must be designed to be reentrant. How this is done is an advanced topic beyond the scope of this tutorial.
Critical Sections¶
An example of a critical section of code is one which accesses more than one variable which can be affected by an ISR. If
the interrupt happens to occur between accesses to the individual variables, their values will be inconsistent. This is
an instance of a hazard known as a race condition: the ISR and the main program loop race to alter the variables. To
avoid inconsistency a means must be employed to ensure that the ISR does not alter the values for the duration of
the critical section. One way to achieve this is to issue pyb.disable_irq()
before the start of the section, and
pyb.enable_irq()
at the end. Here is an example of this approach:
import pyb, micropython, array
micropython.alloc_emergency_exception_buf(100)
class BoundsException(Exception):
pass
ARRAYSIZE = const(20)
index = 0
data = array.array('i', 0 for x in range(ARRAYSIZE))
def callback1(t):
global data, index
for x in range(5):
data[index] = pyb.rng() # simulate input
index += 1
if index >= ARRAYSIZE:
raise BoundsException('Array bounds exceeded')
tim4 = pyb.Timer(4, freq=100, callback=callback1)
for loop in range(1000):
if index > 0:
irq_state = pyb.disable_irq() # Start of critical section
for x in range(index):
print(data[x])
index = 0
pyb.enable_irq(irq_state) # End of critical section
print('loop {}'.format(loop))
pyb.delay(1)
tim4.callback(None)
A critical section can comprise a single line of code and a single variable. Consider the following code fragment.
count = 0
def cb(): # An interrupt callback
count +=1
def main():
# Code to set up the interrupt callback omitted
while True:
count += 1
This example illustrates a subtle source of bugs. The line count += 1
in the main loop carries a specific race
condition hazard known as a read-modify-write. This is a classic cause of bugs in real time systems. In the main loop
MicroPython reads the value of t.counter
, adds 1 to it, and writes it back. On rare occasions the interrupt occurs
after the read and before the write. The interrupt modifies t.counter
but its change is overwritten by the main
loop when the ISR returns. In a real system this could lead to rare, unpredictable failures.
As mentioned above, care should be taken if an instance of a Python built in type is modified in the main code and that instance is accessed in an ISR. The code performing the modification should be regarded as a critical section to ensure that the instance is in a valid state when the ISR runs.
Particular care needs to be taken if a dataset is shared between different ISR’s. The hazard here is that the higher priority interrupt may occur when the lower priority one has partially updated the shared data. Dealing with this situation is an advanced topic beyond the scope of this introduction other than to note that mutex objects described below can sometimes be used.
Disabling interrupts for the duration of a critical section is the usual and simplest way to proceed, but it disables all interrupts rather than merely the one with the potential to cause problems. It is generally undesirable to disable an interrupt for long. In the case of timer interrupts it introduces variability to the time when a callback occurs. In the case of device interrupts, it can lead to the device being serviced too late with possible loss of data or overrun errors in the device hardware. Like ISR’s, a critical section in the main code should have a short, predictable duration.
An approach to dealing with critical sections which radically reduces the time for which interrupts are disabled is to use an object termed a mutex (name derived from the notion of mutual exclusion). The main program locks the mutex before running the critical section and unlocks it at the end. The ISR tests whether the mutex is locked. If it is, it avoids the critical section and returns. The design challenge is defining what the ISR should do in the event that access to the critical variables is denied. A simple example of a mutex may be found here. Note that the mutex code does disable interrupts, but only for the duration of eight machine instructions: the benefit of this approach is that other interrupts are virtually unaffected.
Interrupts and the REPL¶
Interrupt handlers, such as those associated with timers, can continue to run after a program terminates. This may produce unexpected results where you might have expected the object raising the callback to have gone out of scope. For example on the Pyboard:
def bar():
foo = pyb.Timer(2, freq=4, callback=lambda t: print('.', end=''))
bar()
This continues to run until the timer is explicitly disabled or the board is
reset with ctrl D
.
Maximising MicroPython Speed¶
Contents
This tutorial describes ways of improving the performance of MicroPython code. Optimisations involving other languages are covered elsewhere, namely the use of modules written in C and the MicroPython inline assembler.
The process of developing high performance code comprises the following stages which should be performed in the order listed.
- Design for speed.
- Code and debug.
Optimisation steps:
- Identify the slowest section of code.
- Improve the efficiency of the Python code.
- Use the native code emitter.
- Use the viper code emitter.
- Use hardware-specific optimisations.
Designing for speed¶
Performance issues should be considered at the outset. This involves taking a view on the sections of code which are most performance critical and devoting particular attention to their design. The process of optimisation begins when the code has been tested: if the design is correct at the outset optimisation will be straightforward and may actually be unnecessary.
Algorithms¶
The most important aspect of designing any routine for performance is ensuring that the best algorithm is employed. This is a topic for textbooks rather than for a MicroPython guide but spectacular performance gains can sometimes be achieved by adopting algorithms known for their efficiency.
RAM Allocation¶
To design efficient MicroPython code it is necessary to have an understanding of the way the interpreter allocates RAM. When an object is created or grows in size (for example where an item is appended to a list) the necessary RAM is allocated from a block known as the heap. This takes a significant amount of time; further it will on occasion trigger a process known as garbage collection which can take several milliseconds.
Consequently the performance of a function or method can be improved if an object is created once only and not permitted to grow in size. This implies that the object persists for the duration of its use: typically it will be instantiated in a class constructor and used in various methods.
This is covered in further detail Controlling garbage collection below.
Buffers¶
An example of the above is the common case where a buffer is required, such as one used for communication with a device. A typical driver will create the buffer in the constructor and use it in its I/O methods which will be called repeatedly.
The MicroPython libraries typically provide support for pre-allocated buffers. For
example, objects which support stream interface (e.g., file or UART) provide read()
method which allocates new buffer for read data, but also a readinto()
method
to read data into an existing buffer.
Floating Point¶
Some MicroPython ports allocate floating point numbers on heap. Some other ports may lack dedicated floating-point coprocessor, and perform arithmetic operations on them in “software” at considerably lower speed than on integers. Where performance is important, use integer operations and restrict the use of floating point to sections of the code where performance is not paramount. For example, capture ADC readings as integers values to an array in one quick go, and only then convert them to floating-point numbers for signal processing.
Arrays¶
Consider the use of the various types of array classes as an alternative to lists.
The array
module supports various element types with 8-bit elements supported
by Python’s built in bytes
and bytearray
classes. These data structures all store
elements in contiguous memory locations. Once again to avoid memory allocation in critical
code these should be pre-allocated and passed as arguments or as bound objects.
When passing slices of objects such as bytearray
instances, Python creates
a copy which involves allocation of the size proportional to the size of slice.
This can be alleviated using a memoryview
object. memoryview
itself
is allocated on heap, but is a small, fixed-size object, regardless of the size
of slice it points too.
ba = bytearray(10000) # big array
func(ba[30:2000]) # a copy is passed, ~2K new allocation
mv = memoryview(ba) # small object is allocated
func(mv[30:2000]) # a pointer to memory is passed
A memoryview
can only be applied to objects supporting the buffer protocol - this
includes arrays but not lists. Small caveat is that while memoryview object is live,
it also keeps alive the original buffer object. So, a memoryview isn’t a universal
panacea. For instance, in the example above, if you are done with 10K buffer and
just need those bytes 30:2000 from it, it may be better to make a slice, and let
the 10K buffer go (be ready for garbage collection), instead of making a
long-living memoryview and keeping 10K blocked for GC.
Nonetheless, memoryview
is indispensable for advanced preallocated buffer
management. readinto()
method discussed above puts data at the beginning
of buffer and fills in entire buffer. What if you need to put data in the
middle of existing buffer? Just create a memoryview into the needed section
of buffer and pass it to readinto()
.
Identifying the slowest section of code¶
This is a process known as profiling and is covered in textbooks and
(for standard Python) supported by various software tools. For the type of
smaller embedded application likely to be running on MicroPython platforms
the slowest function or method can usually be established by judicious use
of the timing ticks
group of functions documented in utime
.
Code execution time can be measured in ms, us, or CPU cycles.
The following enables any function or method to be timed by adding an
@timed_function
decorator:
def timed_function(f, *args, **kwargs):
myname = str(f).split(' ')[1]
def new_func(*args, **kwargs):
t = utime.ticks_us()
result = f(*args, **kwargs)
delta = utime.ticks_diff(utime.ticks_us(), t)
print('Function {} Time = {:6.3f}ms'.format(myname, delta/1000))
return result
return new_func
MicroPython code improvements¶
The const() declaration¶
MicroPython provides a const()
declaration. This works in a similar way
to #define
in C in that when the code is compiled to bytecode the compiler
substitutes the numeric value for the identifier. This avoids a dictionary
lookup at runtime. The argument to const()
may be anything which, at
compile time, evaluates to an integer e.g. 0x100
or 1 << 8
.
Caching object references¶
Where a function or method repeatedly accesses objects performance is improved by caching the object in a local variable:
class foo(object):
def __init__(self):
ba = bytearray(100)
def bar(self, obj_display):
ba_ref = self.ba
fb = obj_display.framebuffer
# iterative code using these two objects
This avoids the need repeatedly to look up self.ba
and obj_display.framebuffer
in the body of the method bar()
.
Controlling garbage collection¶
When memory allocation is required, MicroPython attempts to locate an adequately sized block on the heap. This may fail, usually because the heap is cluttered with objects which are no longer referenced by code. If a failure occurs, the process known as garbage collection reclaims the memory used by these redundant objects and the allocation is then tried again - a process which can take several milliseconds.
There may be benefits in pre-empting this by periodically issuing gc.collect()
.
Firstly doing a collection before it is actually required is quicker - typically on the
order of 1ms if done frequently. Secondly you can determine the point in code
where this time is used rather than have a longer delay occur at random points,
possibly in a speed critical section. Finally performing collections regularly
can reduce fragmentation in the heap. Severe fragmentation can lead to
non-recoverable allocation failures.
The Native code emitter¶
This causes the MicroPython compiler to emit native CPU opcodes rather than bytecode. It covers the bulk of the MicroPython functionality, so most functions will require no adaptation (but see below). It is invoked by means of a function decorator:
@micropython.native
def foo(self, arg):
buf = self.linebuf # Cached object
# code
There are certain limitations in the current implementation of the native code emitter.
- Context managers are not supported (the
with
statement). - Generators are not supported.
- If
raise
is used an argument must be supplied.
The trade-off for the improved performance (roughly twices as fast as bytecode) is an increase in compiled code size.
The Viper code emitter¶
The optimisations discussed above involve standards-compliant Python code. The Viper code emitter is not fully compliant. It supports special Viper native data types in pursuit of performance. Integer processing is non-compliant because it uses machine words: arithmetic on 32 bit hardware is performed modulo 2**32.
Like the Native emitter Viper produces machine instructions but further optimisations are performed, substantially increasing performance especially for integer arithmetic and bit manipulations. It is invoked using a decorator:
@micropython.viper
def foo(self, arg: int) -> int:
# code
As the above fragment illustrates it is beneficial to use Python type hints to assist the Viper optimiser.
Type hints provide information on the data types of arguments and of the return value; these
are a standard Python language feature formally defined here PEP0484.
Viper supports its own set of types namely int
, uint
(unsigned integer), ptr
, ptr8
,
ptr16
and ptr32
. The ptrX
types are discussed below. Currently the uint
type serves
a single purpose: as a type hint for a function return value. If such a function returns 0xffffffff
Python will interpret the result as 2**32 -1 rather than as -1.
In addition to the restrictions imposed by the native emitter the following constraints apply:
- Functions may have up to four arguments.
- Default argument values are not permitted.
- Floating point may be used but is not optimised.
Viper provides pointer types to assist the optimiser. These comprise
ptr
Pointer to an object.ptr8
Points to a byte.ptr16
Points to a 16 bit half-word.ptr32
Points to a 32 bit machine word.
The concept of a pointer may be unfamiliar to Python programmers. It has similarities
to a Python memoryview
object in that it provides direct access to data stored in memory.
Items are accessed using subscript notation, but slices are not supported: a pointer can return
a single item only. Its purpose is to provide fast random access to data stored in contiguous
memory locations - such as data stored in objects which support the buffer protocol, and
memory-mapped peripheral registers in a microcontroller. It should be noted that programming
using pointers is hazardous: bounds checking is not performed and the compiler does nothing to
prevent buffer overrun errors.
Typical usage is to cache variables:
@micropython.viper
def foo(self, arg: int) -> int:
buf = ptr8(self.linebuf) # self.linebuf is a bytearray or bytes object
for x in range(20, 30):
bar = buf[x] # Access a data item through the pointer
# code omitted
In this instance the compiler “knows” that buf
is the address of an array of bytes;
it can emit code to rapidly compute the address of buf[x]
at runtime. Where casts are
used to convert objects to Viper native types these should be performed at the start of
the function rather than in critical timing loops as the cast operation can take several
microseconds. The rules for casting are as follows:
- Casting operators are currently:
int
,bool
,uint
,ptr
,ptr8
,ptr16
andptr32
. - The result of a cast will be a native Viper variable.
- Arguments to a cast can be a Python object or a native Viper variable.
- If argument is a native Viper variable, then cast is a no-op (i.e. costs nothing at runtime)
that just changes the type (e.g. from
uint
toptr8
) so that you can then store/load using this pointer. - If the argument is a Python object and the cast is
int
oruint
, then the Python object must be of integral type and the value of that integral object is returned. - The argument to a bool cast must be integral type (boolean or integer); when used as a return type the viper function will return True or False objects.
- If the argument is a Python object and the cast is
ptr
,ptr
,ptr16
orptr32
, then the Python object must either have the buffer protocol with read-write capabilities (in which case a pointer to the start of the buffer is returned) or it must be of integral type (in which case the value of that integral object is returned).
The following example illustrates the use of a ptr16
cast to toggle pin X1 n
times:
BIT0 = const(1)
@micropython.viper
def toggle_n(n: int):
odr = ptr16(stm.GPIOA + stm.GPIO_ODR)
for _ in range(n):
odr[0] ^= BIT0
A detailed technical description of the three code emitters may be found on Kickstarter here Note 1 and here Note 2
Accessing hardware directly¶
Note
Code examples in this section are given for the Pyboard. The techniques described however may be applied to other MicroPython ports too.
This comes into the category of more advanced programming and involves some knowledge of the target MCU. Consider the example of toggling an output pin on the Pyboard. The standard approach would be to write
mypin.value(mypin.value() ^ 1) # mypin was instantiated as an output pin
This involves the overhead of two calls to the Pin
instance’s value()
method. This overhead can be eliminated by performing a read/write to the relevant bit
of the chip’s GPIO port output data register (odr). To facilitate this the stm
module provides a set of constants providing the addresses of the relevant registers.
A fast toggle of pin P4
(CPU pin A14
) - corresponding to the green LED -
can be performed as follows:
import machine
import stm
BIT14 = const(1 << 14)
machine.mem16[stm.GPIOA + stm.GPIO_ODR] ^= BIT14
MicroPython on Microcontrollers¶
MicroPython is designed to be capable of running on microcontrollers. These have hardware limitations which may be unfamiliar to programmers more familiar with conventional computers. In particular the amount of RAM and nonvolatile “disk” (flash memory) storage is limited. This tutorial offers ways to make the most of the limited resources. Because MicroPython runs on controllers based on a variety of architectures, the methods presented are generic: in some cases it will be necessary to obtain detailed information from platform specific documentation.
Flash Memory¶
On the Pyboard the simple way to address the limited capacity is to fit a micro SD card. In some cases this is impractical, either because the device does not have an SD card slot or for reasons of cost or power consumption; hence the on-chip flash must be used. The firmware including the MicroPython subsystem is stored in the onboard flash. The remaining capacity is available for use. For reasons connected with the physical architecture of the flash memory part of this capacity may be inaccessible as a filesystem. In such cases this space may be employed by incorporating user modules into a firmware build which is then flashed to the device.
There are two ways to achieve this: frozen modules and frozen bytecode. Frozen modules store the Python source with the firmware. Frozen bytecode uses the cross compiler to convert the source to bytecode which is then stored with the firmware. In either case the module may be accessed with an import statement:
import mymodule
The procedure for producing frozen modules and bytecode is platform dependent; instructions for building the firmware can be found in the README files in the relevant part of the source tree.
In general terms the steps are as follows:
- Clone the MicroPython repository.
- Acquire the (platform specific) toolchain to build the firmware.
- Build the cross compiler.
- Place the modules to be frozen in a specified directory (dependent on whether the module is to be frozen as source or as bytecode).
- Build the firmware. A specific command may be required to build frozen code of either type - see the platform documentation.
- Flash the firmware to the device.
RAM¶
When reducing RAM usage there are two phases to consider: compilation and execution. In addition to memory consumption, there is also an issue known as heap fragmentation. In general terms it is best to minimise the repeated creation and destruction of objects. The reason for this is covered in the section covering the heap.
Compilation Phase¶
When a module is imported, MicroPython compiles the code to bytecode which is then executed by the MicroPython virtual machine (VM). The bytecode is stored in RAM. The compiler itself requires RAM, but this becomes available for use when the compilation has completed.
If a number of modules have already been imported the situation can arise where there is insufficient RAM to run the compiler. In this case the import statement will produce a memory exception.
If a module instantiates global objects on import it will consume RAM at the time of import, which is then unavailable for the compiler to use on subsequent imports. In general it is best to avoid code which runs on import; a better approach is to have initialisation code which is run by the application after all modules have been imported. This maximises the RAM available to the compiler.
If RAM is still insufficient to compile all modules one solution is to precompile modules. MicroPython has a cross compiler capable of compiling Python modules to bytecode (see the README in the mpy-cross directory). The resulting bytecode file has a .mpy extension; it may be copied to the filesystem and imported in the usual way. Alternatively some or all modules may be implemented as frozen bytecode: on most platforms this saves even more RAM as the bytecode is run directly from flash rather than being stored in RAM.
Execution Phase¶
There are a number of coding techniques for reducing RAM usage.
Constants
MicroPython provides a const
keyword which may be used as follows:
from micropython import const
ROWS = const(33)
_COLS = const(0x10)
a = ROWS
b = _COLS
In both instances where the constant is assigned to a variable the compiler
will avoid coding a lookup to the name of the constant by substituting its
literal value. This saves bytecode and hence RAM. However the ROWS
value
will occupy at least two machine words, one each for the key and value in the
globals dictionary. The presence in the dictionary is necessary because another
module might import or use it. This RAM can be saved by prepending the name
with an underscore as in _COLS
: this symbol is not visible outside the
module so will not occupy RAM.
The argument to const()
may be anything which, at compile time, evaluates
to an integer e.g. 0x100
or 1 << 8
. It can even include other const
symbols that have already been defined, e.g. 1 << BIT
.
Constant data structures
Where there is a substantial volume of constant data and the platform supports
execution from Flash, RAM may be saved as follows. The data should be located in
Python modules and frozen as bytecode. The data must be defined as bytes
objects. The compiler ‘knows’ that bytes
objects are immutable and ensures
that the objects remain in flash memory rather than being copied to RAM. The
ustruct
module can assist in converting between bytes
types and other
Python built-in types.
When considering the implications of frozen bytecode, note that in Python strings, floats, bytes, integers and complex numbers are immutable. Accordingly these will be frozen into flash. Thus, in the line
mystring = "The quick brown fox"
the actual string “The quick brown fox” will reside in flash. At runtime a
reference to the string is assigned to the variable mystring
. The reference
occupies a single machine word. In principle a long integer could be used to
store constant data:
bar = 0xDEADBEEF0000DEADBEEF
As in the string example, at runtime a reference to the arbitrarily large
integer is assigned to the variable bar
. That reference occupies a
single machine word.
It might be expected that tuples of integers could be employed for the purpose of storing constant data with minimal RAM use. With the current compiler this is ineffective (the code works, but RAM is not saved).
foo = (1, 2, 3, 4, 5, 6, 100000)
At runtime the tuple will be located in RAM. This may be subject to future improvement.
Needless object creation
There are a number of situations where objects may unwittingly be created and destroyed. This can reduce the usability of RAM through fragmentation. The following sections discuss instances of this.
String concatenation
Consider the following code fragments which aim to produce constant strings:
var = "foo" + "bar"
var1 = "foo" "bar"
var2 = """\
foo\
bar"""
Each produces the same outcome, however the first needlessly creates two string objects at runtime, allocates more RAM for concatenation before producing the third. The others perform the concatenation at compile time which is more efficient, reducing fragmentation.
Where strings must be dynamically created before being fed to a stream such as a file it will save RAM if this is done in a piecemeal fashion. 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:
var = "Temperature {:5.2f} Pressure {:06d}\n".format(temp, press)
Buffers
When accessing devices such as instances of UART, I2C 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 buf
The first creates a buffer on each pass whereas the second re-uses a pre-allocated buffer; this is both faster and more efficient in terms of memory fragmentation.
Bytes are smaller than ints
On most platforms an integer consumes four bytes. Consider the two calls to the
function foo()
:
def foo(bar):
for x in bar:
print(x)
foo((1, 2, 0xff))
foo(b'\1\2\xff')
In the first call a tuple of integers is created in RAM. The second efficiently
creates a bytes
object consuming the minimum amount of RAM. If the module
were frozen as bytecode, the bytes
object would reside in flash.
Strings Versus Bytes
Python3 introduced Unicode support. This introduced a distinction between a
string and an array of bytes. MicroPython ensures that Unicode strings take no
additional space so long as all characters in the string are ASCII (i.e. have
a value < 126). If values in the full 8-bit range are required bytes
and
bytearray
objects can be used to ensure that no additional space will be
required. Note that most string methods (e.g. str.strip()
) apply also to bytes
instances so the process of eliminating Unicode can be painless.
s = 'the quick brown fox' # A string instance
b = b'the quick brown fox' # A bytes instance
Where it is necessary to convert between strings and bytes the str.encode()
and the bytes.decode()
methods can be used. Note that both strings and bytes
are immutable. Any operation which takes as input such an object and produces
another implies at least one RAM allocation to produce the result. In the
second line below a new bytes object is allocated. This would also occur if foo
were a string.
foo = b' empty whitespace'
foo = foo.lstrip()
Runtime compiler execution
The Python funcitons eval
and exec
invoke the compiler at runtime, which
requires significant amounts of RAM. Note that the pickle
library from
micropython-lib
employs exec
. It may be more RAM efficient to use the
ujson
library for object serialisation.
Storing strings in flash
Python strings are immutable hence have the potential to be stored in read only memory. The compiler can place in flash strings defined in Python code. As with frozen modules it is necessary to have a copy of the source tree on the PC and the toolchain to build the firmware. The procedure will work even if the modules have not been fully debugged, so long as they can be imported and run.
After importing the modules, execute:
micropython.qstr_info(1)
Then copy and paste all the Q(xxx) lines into a text editor. Check for and remove lines which are obviously invalid. Open the file qstrdefsport.h which will be found in ports/stm32 (or the equivalent directory for the architecture in use). Copy and paste the corrected lines at the end of the file. Save the file, rebuild and flash the firmware. The outcome can be checked by importing the modules and again issuing:
micropython.qstr_info(1)
The Q(xxx) lines should be gone.
The Heap¶
When a running program instantiates an object the necessary RAM is allocated
from a fixed size pool known as the heap. When the object goes out of scope (in
other words becomes inaccessible to code) the redundant object is known as
“garbage”. A process known as “garbage collection” (GC) reclaims that memory,
returning it to the free heap. This process runs automatically, however it can
be invoked directly by issuing gc.collect()
.
The discourse on this is somewhat involved. For a ‘quick fix’ issue the following periodically:
gc.collect()
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
Fragmentation¶
Say a program creates an object foo
, then an object bar
. Subsequently
foo
goes out of scope but bar
remains. The RAM used by foo
will be
reclaimed by GC. However if bar
was allocated to a higher address, the
RAM reclaimed from foo
will only be of use for objects no bigger than
foo
. In a complex or long running program the heap can become fragmented:
despite there being a substantial amount of RAM available, there is insufficient
contiguous space to allocate a particular object, and the program fails with a
memory error.
The techniques outlined above aim to minimise this. Where large permanent buffers or other objects are required it is best to instantiate these early in the process of program execution before fragmentation can occur. Further improvements may be made by monitoring the state of the heap and by controlling GC; these are outlined below.
Reporting¶
A number of library functions are available to report on memory allocation and
to control GC. These are to be found in the gc
and micropython
modules.
The following example may be pasted at the REPL (ctrl e
to enter paste mode,
ctrl d
to run it).
import gc
import micropython
gc.collect()
micropython.mem_info()
print('-----------------------------')
print('Initial free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
def func():
a = bytearray(10000)
gc.collect()
print('Func definition: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
func()
print('Func run free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
gc.collect()
print('Garbage collect free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
print('-----------------------------')
micropython.mem_info(1)
Methods employed above:
gc.collect()
Force a garbage collection. See footnote.micropython.mem_info()
Print a summary of RAM utilisation.gc.mem_free()
Return the free heap size in bytes.gc.mem_alloc()
Return the number of bytes currently allocated.micropython.mem_info(1)
Print a table of heap utilisation (detailed below).
The numbers produced are dependent on the platform, but it can be seen that
declaring the function uses a small amount of RAM in the form of bytecode
emitted by the compiler (the RAM used by the compiler has been reclaimed).
Running the function uses over 10KiB, but on return a
is garbage because it
is out of scope and cannot be referenced. The final gc.collect()
recovers
that memory.
The final output produced by micropython.mem_info(1)
will vary in detail but
may be interpreted as follows:
Symbol | Meaning |
---|---|
. | free block |
h | head block |
= | tail block |
m | marked head block |
T | tuple |
L | list |
D | dict |
F | float |
B | byte code |
M | module |
Each letter represents a single block of memory, a block being 16 bytes. So each line of the heap dump represents 0x400 bytes or 1KiB of RAM.
Control of Garbage Collection¶
A GC can be demanded at any time by issuing gc.collect()
. It is advantageous
to do this at intervals, firstly to pre-empt fragmentation and secondly for
performance. A GC can take several milliseconds but is quicker when there is
little work to do (about 1ms on the Pyboard). An explicit call can minimise that
delay while ensuring it occurs at points in the program when it is acceptable.
Automatic GC is provoked under the following circumstances. When an attempt at allocation fails, a GC is performed and the allocation re-tried. Only if this fails is an exception raised. Secondly an automatic GC will be triggered if the amount of free RAM falls below a threshold. This threshold can be adapted as execution progresses:
gc.collect()
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
This will provoke a GC when more than 25% of the currently free heap becomes occupied.
In general modules should instantiate data objects at runtime using constructors
or other initialisation functions. The reason is that if this occurs on
initialisation the compiler may be starved of RAM when subsequent modules are
imported. If modules do instantiate data on import then gc.collect()
issued
after the import will ameliorate the problem.
String Operations¶
MicroPython handles strings in an efficient manner and understanding this can
help in designing applications to run on microcontrollers. When a module
is compiled, strings which occur multiple times are stored once only, a process
known as string interning. In MicroPython an interned string is known as a qstr
.
In a module imported normally that single instance will be located in RAM, but
as described above, in modules frozen as bytecode it will be located in flash.
String comparisons are also performed efficiently using hashing rather than character by character. The penalty for using strings rather than integers may hence be small both in terms of performance and RAM usage - a fact which may come as a surprise to C programmers.
Postscript¶
MicroPython passes, returns and (by default) copies objects by reference. A reference occupies a single machine word so these processes are efficient in RAM usage and speed.
Where variables are required whose size is neither a byte nor a machine word
there are standard libraries which can assist in storing these efficiently and
in performing conversions. See the array
, ustruct
and uctypes
modules.
Footnote: gc.collect() return value¶
On Unix and Windows platforms the gc.collect()
method returns an integer
which signifies the number of distinct memory regions that were reclaimed in the
collection (more precisely, the number of heads that were turned into frees). For
efficiency reasons bare metal ports do not return this value.
Distribution packages, package management, and deploying applications¶
Just as the “big” Python, MicroPython supports creation of “third party” packages, distributing them, and easily installing them in each user’s environment. This chapter discusses how these actions are achieved. Some familiarity with Python packaging is recommended.
Overview¶
Steps below represent a high-level workflow when creating and consuming packages:
- Python modules and packages are turned into distribution package archives, and published at the Python Package Index (PyPI).
upip
package manager can be used to install a distribution package on aMicroPython port
with networking capabilities (for example, on the Unix port).- For ports without networking capabilities, an “installation image” can be prepared on the Unix port, and transferred to a device by suitable means.
- For low-memory ports, the installation image can be frozen as the bytecode into MicroPython executable, thus minimizing the memory storage overheads.
The sections below describe this process in details.
Distribution packages¶
Python modules and packages can be packaged into archives suitable for transfer between systems, storing at the well-known location (PyPI), and downloading on demand for deployment. These archives are known as distribution packages (to differentiate them from Python packages (means to organize Python source code)).
The MicroPython distribution package format is a well-known tar.gz format, with some adaptations however. The Gzip compressor, used as an external wrapper for TAR archives, by default uses 32KB dictionary size, which means that to uncompress a compressed stream, 32KB of contguous memory needs to be allocated. This requirement may be not satisfiable on low-memory devices, which may have total memory available less than that amount, and even if not, a contiguous block like that may be hard to allocate due to memory fragmentation. To accommodate these constraints, MicroPython distribution packages use Gzip compression with the dictionary size of 4K, which should be a suitable compromise with still achieving some compression while being able to uncompressed even by the smallest devices.
Besides the small compression dictionary size, MicroPython distribution
packages also have other optimizations, like removing any files from
the archive which aren’t used by the installation process. In particular,
upip
package manager doesn’t execute setup.py
during installation
(see below), and thus that file is not included in the archive.
At the same time, these optimizations make MicroPython distribution
packages not compatible with CPython
’s package manager, pip
.
This isn’t considered a big problem, because:
- Packages can be installed with
upip
, and then can be used with CPython (if they are compatible with it). - In the other direction, majority of CPython packages would be incompatible with MicroPython by various reasons, first of all, the reliance on features not implemented by MicroPython.
Summing up, the MicroPython distribution package archives are highly optimized for MicroPython’s target environments, which are highly resource constrained devices.
upip
package manager¶
MicroPython distribution packages are intended to be installed using
the upip
package manager. upip
is a Python application which is
usually distributed (as frozen bytecode) with network-enabled
MicroPython ports
. At the very least,
upip
is available in the MicroPython Unix port
.
On any MicroPython port
providing upip
, it can be accessed as
following:
import upip
upip.help()
upip.install(package_or_package_list, [path])
Where package_or_package_list is the name of a distribution package to install, or a list of such names to install multiple packages. Optional path parameter specifies filesystem location to install under and defaults to the standard library location (see below).
An example of installing a specific package and then using it:
>>> import upip
>>> upip.install("micropython-pystone_lowmem")
[...]
>>> import pystone_lowmem
>>> pystone_lowmem.main()
Note that the name of Python package and the name of distribution
package for it in general don’t have to match, and oftentimes they
don’t. This is because PyPI provides a central package repository
for all different Python implementations and versions, and thus
distribution package names may need to be namespaced for a particular
implementation. For example, all packages from micropython-lib
follow this naming convention: for a Python module or package named
foo
, the distribution package name is micropython-foo
.
For the ports which run MicroPython executable from the OS command
prompts (like the Unix port), upip
can be (and indeed, usually is)
run from the command line instead of MicroPython’s own REPL. The
commands which corresponds to the example above are:
micropython -m upip -h
micropython -m upip install [-p <path>] <packages>...
micropython -m upip install micropython-pystone_lowmem
[TODO: Describe installation path.]
Cross-installing packages¶
For MicroPython ports
without native networking
capabilities, the recommend process is “cross-installing” them into a
“directory image” using the MicroPython Unix port
, and then
transferring this image to a device by suitable means.
Installing to a directory image involves using -p
switch to upip
:
micropython -m upip install -p install_dir micropython-pystone_lowmem
After this command, the package content (and contents of every depenency
packages) will be available in the install_dir/
subdirectory. You
would need to transfer contents of this directory (without the
install_dir/
prefix) to the device, at the suitable location, where
it can be found by the Python import
statement (see discussion of
the upip
installation path above).
Cross-installing packages with freezing¶
For the low-memory MicroPython ports
, the process
described in the previous section does not provide the most efficient
resource usage,because the packages are installed in the source form,
so need to be compiled to the bytecome on each import. This compilation
requires RAM, and the resulting bytecode is also stored in RAM, reducing
its amount available for storing application data. Moreover, the process
above requires presence of the filesystem on a device, and the most
resource-constrained devices may not even have it.
The bytecode freezing is a process which resolves all the issues mentioned above:
- The source code is pre-compiled into bytecode and store as such.
- The bytecode is stored in ROM, not RAM.
- Filesystem is not required for frozen packages.
Using frozen bytecode requires building the executable (firmware)
for a given MicroPython port
from the C source code. Consequently,
the process is:
- Follow the instructions for a particular port on setting up a
toolchain and building the port. For example, for ESP8266 port,
study instructions in
ports/esp8266/README.md
and follow them. Make sure you can build the port and deploy the resulting executable/firmware successfully before proceeding to the next steps. - Build
MicroPython Unix port
and make sure it is in your PATH and you can executemicropython
. - Change to port’s directory (e.g.
ports/esp8266/
for ESP8266). - Run
make clean-frozen
. This step cleans up any previous modules which were installed for freezing (consequently, you need to skip this step to add additional modules, instead of starting from scratch). - Run
micropython -m upip install -p modules <packages>...
to install packages you want to freeze. - Run
make clean
. - Run
make
.
After this, you should have the executable/firmware with modules as the bytecode inside, which you can deploy the usual way.
Few notes:
- Step 5 in the sequence above assumes that the distribution package
is available from PyPI. If that is not the case, you would need
to copy Python source files manually to
modules/
subdirectory of the port port directory. (Note that upip does not support installing from e.g. version control repositories). - The firmware for baremetal devices usually has size restrictions, so adding too many frozen modules may overflow it. Usually, you would get a linking error if this happens. However, in some cases, an image may be produced, which is not runnable on a device. Such cases are in general bugs, and should be reported and further investigated. If you face such a situation, as an initial step, you may want to decrease the amount of frozen modules included.
Creating distribution packages¶
Distribution packages for MicroPython are created in the same manner
as for CPython or any other Python implementation, see references at
the end of chapter. Setuptools (instead of distutils) should be used,
because distutils do not support dependencies and other features. “Source
distribution” (sdist
) format is used for packaging. The post-processing
discussed above, (and pre-processing discussed in the following section)
is achieved by using custom sdist
command for setuptools. Thus, packaging
steps remain the same as for the standard setuptools, the user just
needs to override sdist
command implementation by passing the
appropriate argument to setup()
call:
from setuptools import setup
import sdist_upip
setup(
...,
cmdclass={'sdist': sdist_upip.sdist}
)
The sdist_upip.py module as referenced above can be found in
micropython-lib
:
https://github.com/micropython/micropython-lib/blob/master/sdist_upip.py
Application resources¶
A complete application, besides the source code, oftentimes also consists of data files, e.g. web page templates, game images, etc. It’s clear how to deal with those when application is installed manually - you just put those data files in the filesystem at some location and use the normal file access functions.
The situation is different when deploying applications from packages - this is more advanced, streamlined and flexible way, but also requires more advanced approach to accessing data files. This approach is treating the data files as “resources”, and abstracting away access to them.
Python supports resource access using its “setuptools” library, using
pkg_resources
module. MicroPython, following its usual approach,
implements subset of the functionality of that module, specifically
pkg_resources.resource_stream(package, resource)
function.
The idea is that an application calls this function, passing a
resource identifier, which is a relative path to data file within
the specified package (usually top-level application package). It
returns a stream object which can be used to access resource contents.
Thus, the resource_stream()
emulates interface of the standard
open()
function.
Implementation-wise, resource_stream()
uses file operations
underlyingly, if distribution package is install in the filesystem.
However, it also supports functioning without the underlying filesystem,
e.g. if the package is frozen as the bytecode. This however requires
an extra intermediate step when packaging application - creation of
“Python resource module”.
The idea of this module is to convert binary data to a Python bytes
object, and put it into the dictionary, indexed by the resource name.
This conversion is done automatically using overridden sdist
command
described in the previous section.
Let’s trace the complete process using the following example. Suppose your application has the following structure:
my_app/
__main__.py
utils.py
data/
page.html
image.png
__main__.py
and utils.py
should access resources using the
following calls:
import pkg_resources
pkg_resources.resource_stream(__name__, "data/page.html")
pkg_resources.resource_stream(__name__, "data/image.png")
You can develop and debug using the MicroPython Unix port
as usual.
When time comes to make a distribution package out of it, just use
overridden “sdist” command from sdist_upip.py module as described in
the previous section.
This will create a Python resource module named R.py
, based on the
files declared in MANIFEST
or MANIFEST.in
files (any non-.py
file will be considered a resource and added to R.py
) - before
proceeding with the normal packaging steps.
Prepared like this, your application will work both when deployed to filesystem and as frozen bytecode.
If you would like to debug R.py
creation, you can run:
python3 setup.py sdist --manifest-only
Alternatively, you can use tools/mpy_bin2res.py script from the MicroPython distribution, in which can you will need to pass paths to all resource files:
mpy_bin2res.py data/page.html data/image.png
References¶
- Python Packaging User Guide: https://packaging.python.org/
- Setuptools documentation: https://setuptools.readthedocs.io/
- Distutils documentation: https://docs.python.org/3/library/distutils.html
Inline Assembler for Thumb2 architectures¶
This document assumes some familiarity with assembly language programming and should be read after studying the tutorial. For a detailed description of the instruction set consult the Architecture Reference Manual detailed below. The inline assembler supports a subset of the ARM Thumb-2 instruction set described here. The syntax tries to be as close as possible to that defined in the above ARM manual, converted to Python function calls.
Instructions operate on 32 bit signed integer data except where stated otherwise. Most supported instructions
operate on registers R0-R7
only: where R8-R15
are supported this is stated. Registers R8-R12
must be
restored to their initial value before return from a function. Registers R13-R15
constitute the Link Register,
Stack Pointer and Program Counter respectively.
Document conventions¶
Where possible the behaviour of each instruction is described in Python, for example
- add(Rd, Rn, Rm)
Rd = Rn + Rm
This enables the effect of instructions to be demonstrated in Python. In certain case this is impossible because Python doesn’t support concepts such as indirection. The pseudocode employed in such cases is described on the relevant page.
Instruction Categories¶
The following sections details the subset of the ARM Thumb-2 instruction set supported by MicroPython.
Register move instructions¶
Document conventions¶
Notation: Rd, Rn
denote ARM registers R0-R15. immN
denotes an immediate
value having a width of N bits. These instructions affect the condition flags.
Register moves¶
Where immediate values are used, these are zero-extended to 32 bits. Thus
mov(R0, 0xff)
will set R0 to 255.
- mov(Rd, imm8)
Rd = imm8
- mov(Rd, Rn)
Rd = Rn
- movw(Rd, imm16)
Rd = imm16
- movt(Rd, imm16)
Rd = (Rd & 0xffff) | (imm16 << 16)
movt writes an immediate value to the top halfword of the destination register. It does not affect the contents of the bottom halfword.
- movwt(Rd, imm32)
Rd = imm32
movwt is a pseudo-instruction: the MicroPython assembler emits a movw
followed
by a movt
to move a 32-bit value into Rd.
Load register from memory¶
Document conventions¶
Notation: Rt, Rn
denote ARM registers R0-R7 except where stated. immN
represents an immediate
value having a width of N bits hence imm5
is constrained to the range 0-31. [Rn + immN]
is the contents
of the memory address obtained by adding Rn and the offset immN
. Offsets are measured in
bytes. These instructions affect the condition flags.
Register Load¶
- ldr(Rt, [Rn, imm7])
Rt = [Rn + imm7]
Load a 32 bit word - ldrb(Rt, [Rn, imm5])
Rt = [Rn + imm5]
Load a byte - ldrh(Rt, [Rn, imm6])
Rt = [Rn + imm6]
Load a 16 bit half word
Where a byte or half word is loaded, it is zero-extended to 32 bits.
The specified immediate offsets are measured in bytes. Hence in the case of ldr
the 7 bit value
enables 32 bit word aligned values to be accessed with a maximum offset of 31 words. In the case of ldrh
the
6 bit value enables 16 bit half-word aligned values to be accessed with a maximum offset of 31 half-words.
Store register to memory¶
Document conventions¶
Notation: Rt, Rn
denote ARM registers R0-R7 except where stated. immN
represents an immediate
value having a width of N bits hence imm5
is constrained to the range 0-31. [Rn + imm5]
is the
contents of the memory address obtained by adding Rn and the offset imm5
. Offsets are measured in
bytes. These instructions do not affect the condition flags.
Register Store¶
- str(Rt, [Rn, imm7])
[Rn + imm7] = Rt
Store a 32 bit word - strb(Rt, [Rn, imm5])
[Rn + imm5] = Rt
Store a byte (b0-b7) - strh(Rt, [Rn, imm6])
[Rn + imm6] = Rt
Store a 16 bit half word (b0-b15)
The specified immediate offsets are measured in bytes. Hence in the case of str
the 7 bit value
enables 32 bit word aligned values to be accessed with a maximum offset of 31 words. In the case of strh
the
6 bit value enables 16 bit half-word aligned values to be accessed with a maximum offset of 31 half-words.
Logical & Bitwise instructions¶
Document conventions¶
Notation: Rd, Rn
denote ARM registers R0-R7 except in the case of the
special instructions where R0-R15 may be used. Rn<a-b>
denotes an ARM register
whose contents must lie in range a <= contents <= b
. In the case of instructions
with two register arguments, it is permissible for them to be identical. For example
the following will zero R0 (Python R0 ^= R0
) regardless of its initial contents.
- eor(r0, r0)
These instructions affect the condition flags except where stated.
Logical instructions¶
- and_(Rd, Rn)
Rd &= Rn
- orr(Rd, Rn)
Rd |= Rn
- eor(Rd, Rn)
Rd ^= Rn
- mvn(Rd, Rn)
Rd = Rn ^ 0xffffffff
i.e. Rd = 1’s complement of Rn - bic(Rd, Rn)
Rd &= ~Rn
bit clear Rd using mask in Rn
Note the use of “and_” instead of “and”, because “and” is a reserved keyword in Python.
Shift and rotation instructions¶
- lsl(Rd, Rn<0-31>)
Rd <<= Rn
- lsr(Rd, Rn<1-32>)
Rd = (Rd & 0xffffffff) >> Rn
Logical shift right - asr(Rd, Rn<1-32>)
Rd >>= Rn
arithmetic shift right - ror(Rd, Rn<1-31>)
Rd = rotate_right(Rd, Rn)
Rd is rotated right Rn bits.
A rotation by (for example) three bits works as follows. If Rd initially
contains bits b31 b30..b0
after rotation it will contain b2 b1 b0 b31 b30..b3
Special instructions¶
Condition codes are unaffected by these instructions.
- clz(Rd, Rn)
Rd = count_leading_zeros(Rn)
count_leading_zeros(Rn) returns the number of binary zero bits before the first binary one bit in Rn.
- rbit(Rd, Rn)
Rd = bit_reverse(Rn)
bit_reverse(Rn) returns the bit-reversed contents of Rn. If Rn contains bits b31 b30..b0
Rd will be set
to b0 b1 b2..b31
Trailing zeros may be counted by performing a bit reverse prior to executing clz.
Arithmetic instructions¶
Document conventions¶
Notation: Rd, Rm, Rn
denote ARM registers R0-R7. immN
denotes an immediate
value having a width of N bits e.g. imm8
, imm3
. carry
denotes
the carry condition flag, not(carry)
denotes its complement. In the case of instructions
with more than one register argument, it is permissible for some to be identical. For example
the following will add the contents of R0 to itself, placing the result in R0:
- add(r0, r0, r0)
Arithmetic instructions affect the condition flags except where stated.
Addition¶
- add(Rdn, imm8)
Rdn = Rdn + imm8
- add(Rd, Rn, imm3)
Rd = Rn + imm3
- add(Rd, Rn, Rm)
Rd = Rn +Rm
- adc(Rd, Rn)
Rd = Rd + Rn + carry
Subtraction¶
- sub(Rdn, imm8)
Rdn = Rdn - imm8
- sub(Rd, Rn, imm3)
Rd = Rn - imm3
- sub(Rd, Rn, Rm)
Rd = Rn - Rm
- sbc(Rd, Rn)
Rd = Rd - Rn - not(carry)
Negation¶
- neg(Rd, Rn)
Rd = -Rn
Multiplication and division¶
- mul(Rd, Rn)
Rd = Rd * Rn
This produces a 32 bit result with overflow lost. The result may be treated as signed or unsigned according to the definition of the operands.
- sdiv(Rd, Rn, Rm)
Rd = Rn / Rm
- udiv(Rd, Rn, Rm)
Rd = Rn / Rm
These functions perform signed and unsigned division respectively. Condition flags are not affected.
Comparison instructions¶
These perform an arithmetic or logical instruction on two arguments, discarding the result but setting the condition flags. Typically these are used to test data values without changing them prior to executing a conditional branch.
Document conventions¶
Notation: Rd, Rm, Rn
denote ARM registers R0-R7. imm8
denotes an immediate
value having a width of 8 bits.
The Application Program Status Register (APSR)¶
This contains four bits which are tested by the conditional branch instructions. Typically a
conditional branch will test multiple bits, for example bge(LABEL)
. The meaning of
condition codes can depend on whether the operands of an arithmetic instruction are viewed as
signed or unsigned integers. Thus bhi(LABEL)
assumes unsigned numbers were processed while
bgt(LABEL)
assumes signed operands.
APSR Bits¶
- Z (zero)
This is set if the result of an operation is zero or the operands of a comparison are equal.
- N (negative)
Set if the result is negative.
- C (carry)
An addition sets the carry flag when the result overflows out of the MSB, for example adding 0x80000000 and 0x80000000. By the nature of two’s complement arithmetic this behaviour is reversed on subtraction, with a borrow indicated by the carry bit being clear. Thus 0x10 - 0x01 is executed as 0x10 + 0xffffffff which will set the carry bit.
- V (overflow)
The overflow flag is set if the result, viewed as a two’s compliment number, has the “wrong” sign in relation to the operands. For example adding 1 to 0x7fffffff will set the overflow bit because the result (0x8000000), viewed as a two’s complement integer, is negative. Note that in this instance the carry bit is not set.
Comparison instructions¶
These set the APSR (Application Program Status Register) N (negative), Z (zero), C (carry) and V (overflow) flags.
- cmp(Rn, imm8)
Rn - imm8
- cmp(Rn, Rm)
Rn - Rm
- cmn(Rn, Rm)
Rn + Rm
- tst(Rn, Rm)
Rn & Rm
Conditional execution¶
The it
and ite
instructions provide a means of conditionally executing from one to four subsequent
instructions without the need for a label.
- it(<condition>) If then
Execute the next instruction if <condition> is true:
cmp(r0, r1)
it(eq)
mov(r0, 100) # runs if r0 == r1
# execution continues here
- ite(<condition>) If then else
If <condtion> is true, execute the next instruction, otherwise execute the subsequent one. Thus:
cmp(r0, r1)
ite(eq)
mov(r0, 100) # runs if r0 == r1
mov(r0, 200) # runs if r0 != r1
# execution continues here
This may be extended to control the execution of upto four subsequent instructions: it[x[y[z]]] where x,y,z=t/e; e.g. itt, itee, itete, ittte, itttt, iteee, etc.
Branch instructions¶
These cause execution to jump to a target location usually specified by a label (see the label
assembler directive). Conditional branches and the it
and ite
instructions test
the Application Program Status Register (APSR) N (negative), Z (zero), C (carry) and V
(overflow) flags to determine whether the branch should be executed.
Most of the exposed assembler instructions (including move operations) set the flags but there are explicit comparison instructions to enable values to be tested.
Further detail on the meaning of the condition flags is provided in the section describing comparison functions.
Document conventions¶
Notation: Rm
denotes ARM registers R0-R15. LABEL
denotes a label defined with the
label()
assembler directive. <condition>
indicates one of the following condition
specifiers:
- eq Equal to (result was zero)
- ne Not equal
- cs Carry set
- cc Carry clear
- mi Minus (negative)
- pl Plus (positive)
- vs Overflow set
- vc Overflow clear
- hi > (unsigned comparison)
- ls <= (unsigned comparison)
- ge >= (signed comparison)
- lt < (signed comparison)
- gt > (signed comparison)
- le <= (signed comparison)
Branch to label¶
- b(LABEL) Unconditional branch
- beq(LABEL) branch if equal
- bne(LABEL) branch if not equal
- bge(LABEL) branch if greater than or equal
- bgt(LABEL) branch if greater than
- blt(LABEL) branch if less than (<) (signed)
- ble(LABEL) branch if less than or equal to (<=) (signed)
- bcs(LABEL) branch if carry flag is set
- bcc(LABEL) branch if carry flag is clear
- bmi(LABEL) branch if negative
- bpl(LABEL) branch if positive
- bvs(LABEL) branch if overflow flag set
- bvc(LABEL) branch if overflow flag is clear
- bhi(LABEL) branch if higher (unsigned)
- bls(LABEL) branch if lower or equal (unsigned)
Long branches¶
The code produced by the branch instructions listed above uses a fixed bit width to specify the branch destination, which is PC relative. Consequently in long programs where the branch instruction is remote from its destination the assembler will produce a “branch not in range” error. This can be overcome with the “wide” variants such as
- beq_w(LABEL) long branch if equal
Wide branches use 4 bytes to encode the instruction (compared with 2 bytes for standard branch instructions).
Subroutines (functions)¶
When entering a subroutine the processor stores the return address in register r14, also known as the link register (lr). Return to the instruction after the subroutine call is performed by updating the program counter (r15 or pc) from the link register, This process is handled by the following instructions.
- bl(LABEL)
Transfer execution to the instruction after LABEL
storing the return address in
the link register (r14).
- bx(Rm) Branch to address specified by Rm.
Typically bx(lr)
is issued to return from a subroutine. For nested subroutines the
link register of outer scopes must be saved (usually on the stack) before performing
inner subroutine calls.
Stack push and pop¶
Document conventions¶
The push()
and pop()
instructions accept as their argument a register set containing
a subset, or possibly all, of the general-purpose registers R0-R12 and the link register (lr or R14).
As with any Python set the order in which the registers are specified is immaterial. Thus the
in the following example the pop() instruction would restore R1, R7 and R8 to their contents prior
to the push():
- push({r1, r8, r7}) Save three registers on the stack.
- pop({r7, r1, r8}) Restore them
Stack operations¶
- push({regset}) Push a set of registers onto the stack
- pop({regset}) Restore a set of registers from the stack
Miscellaneous instructions¶
- nop()
pass
no operation. - wfi() Suspend execution in a low power state until an interrupt occurs.
- cpsid(flags) set the Priority Mask Register - disable interrupts.
- cpsie(flags) clear the Priority Mask Register - enable interrupts.
- mrs(Rd, special_reg)
Rd = special_reg
copy a special register to a general register. The special register may be IPSR (Interrupt Status Register) or BASEPRI (Base Priority Register). The IPSR provides a means of determining the exception number of an interrupt being processed. It contains zero if no interrupt is being processed.
Currently the cpsie()
and cpsid()
functions are partially implemented.
They require but ignore the flags argument and serve as a means of enabling and disabling interrupts.
Floating Point instructions¶
These instructions support the use of the ARM floating point coprocessor
(on platforms such as the Pyboard which are equipped with one). The FPU
has 32 registers known as s0-s31
each of which can hold a single
precision float. Data can be passed between the FPU registers and the
ARM core registers with the vmov
instruction.
Note that MicroPython doesn’t support passing floats to
assembler functions, nor can you put a float into r0
and expect a
reasonable result. There are two ways to overcome this. The first is to
use arrays, and the second is to pass and/or return integers and convert
to and from floats in code.
Document conventions¶
Notation: Sd, Sm, Sn
denote FPU registers, Rd, Rm, Rn
denote ARM core
registers. The latter can be any ARM core register although registers
R13-R15
are unlikely to be appropriate in this context.
Arithmetic¶
- vadd(Sd, Sn, Sm)
Sd = Sn + Sm
- vsub(Sd, Sn, Sm)
Sd = Sn - Sm
- vneg(Sd, Sm)
Sd = -Sm
- vmul(Sd, Sn, Sm)
Sd = Sn * Sm
- vdiv(Sd, Sn, Sm)
Sd = Sn / Sm
- vsqrt(Sd, Sm)
Sd = sqrt(Sm)
Registers may be identical: vmul(S0, S0, S0)
will execute S0 = S0*S0
Move between ARM core and FPU registers¶
- vmov(Sd, Rm)
Sd = Rm
- vmov(Rd, Sm)
Rd = Sm
The FPU has a register known as FPSCR, similar to the ARM core’s APSR, which stores condition codes plus other data. The following instructions provide access to this.
- vmrs(APSR_nzcv, FPSCR)
Move the floating-point N, Z, C, and V flags to the APSR N, Z, C, and V flags.
This is done after an instruction such as an FPU comparison to enable the condition codes to be tested by the assembler code. The following is a more general form of the instruction.
- vmrs(Rd, FPSCR)
Rd = FPSCR
Move between FPU register and memory¶
- vldr(Sd, [Rn, offset])
Sd = [Rn + offset]
- vstr(Sd, [Rn, offset])
[Rn + offset] = Sd
Where [Rn + offset]
denotes the memory address obtained by adding Rn to the offset. This
is specified in bytes. Since each float value occupies a 32 bit word, when accessing arrays of
floats the offset must always be a multiple of four bytes.
Data Comparison¶
- vcmp(Sd, Sm)
Compare the values in Sd and Sm and set the FPU N, Z,
C, and V flags. This would normally be followed by vmrs(APSR_nzcv, FPSCR)
to enable the results to be tested.
Convert between integer and float¶
- vcvt_f32_s32(Sd, Sm)
Sd = float(Sm)
- vcvt_s32_f32(Sd, Sm)
Sd = int(Sm)
Assembler Directives¶
Labels¶
- label(INNER1)
This defines a label for use in a branch instruction. Thus elsewhere in the code a b(INNER1)
will cause execution to continue with the instruction after the label directive.
Defining inline data¶
The following assembler directives facilitate embedding data in an assembler code block.
- data(size, d0, d1 .. dn)
The data directive creates n array of data values in memory. The first argument specifies the size in bytes of the subsequent arguments. Hence the first statement below will cause the assembler to put three bytes (with values 2, 3 and 4) into consecutive memory locations while the second will cause it to emit two four byte words.
data(1, 2, 3, 4)
data(4, 2, 100000)
Data values longer than a single byte are stored in memory in little-endian format.
- align(nBytes)
Align the following instruction to an nBytes value. ARM Thumb-2 instructions must be two
byte aligned, hence it’s advisable to issue align(2)
after data
directives and
prior to any subsequent code. This ensures that the code will run irrespective of the
size of the data array.
Usage examples¶
These sections provide further code examples and hints on the use of the assembler.
Hints and tips¶
The following are some examples of the use of the inline assembler and some
information on how to work around its limitations. In this document the term
“assembler function” refers to a function declared in Python with the
@micropython.asm_thumb
decorator, whereas “subroutine” refers to assembler
code called from within an assembler function.
Code branches and subroutines¶
It is important to appreciate that labels are local to an assembler function. There is currently no way for a subroutine defined in one function to be called from another.
To call a subroutine the instruction bl(LABEL)
is issued. This transfers
control to the instruction following the label(LABEL)
directive and stores
the return address in the link register (lr
or r14
). To return the
instruction bx(lr)
is issued which causes execution to continue with
the instruction following the subroutine call. This mechanism implies that, if
a subroutine is to call another, it must save the link register prior to
the call and restore it before terminating.
The following rather contrived example illustrates a function call. Note that
it’s necessary at the start to branch around all subroutine calls: subroutines
end execution with bx(lr)
while the outer function simply “drops off the end”
in the style of Python functions.
@micropython.asm_thumb
def quad(r0):
b(START)
label(DOUBLE)
add(r0, r0, r0)
bx(lr)
label(START)
bl(DOUBLE)
bl(DOUBLE)
print(quad(10))
The following code example demonstrates a nested (recursive) call: the classic Fibonacci sequence. Here, prior to a recursive call, the link register is saved along with other registers which the program logic requires to be preserved.
@micropython.asm_thumb
def fib(r0):
b(START)
label(DOFIB)
push({r1, r2, lr})
cmp(r0, 1)
ble(FIBDONE)
sub(r0, 1)
mov(r2, r0) # r2 = n -1
bl(DOFIB)
mov(r1, r0) # r1 = fib(n -1)
sub(r0, r2, 1)
bl(DOFIB) # r0 = fib(n -2)
add(r0, r0, r1)
label(FIBDONE)
pop({r1, r2, lr})
bx(lr)
label(START)
bl(DOFIB)
for n in range(10):
print(fib(n))
Argument passing and return¶
The tutorial details the fact that assembler functions can support from zero to
three arguments, which must (if used) be named r0
, r1
and r2
. When
the code executes the registers will be initialised to those values.
The data types which can be passed in this way are integers and memory
addresses. With current firmware all possible 32 bit values may be passed and
returned. If the return value may have the most significant bit set a Python
type hint should be employed to enable MicroPython to determine whether the
value should be interpreted as a signed or unsigned integer: types are
int
or uint
.
@micropython.asm_thumb
def uadd(r0, r1) -> uint:
add(r0, r0, r1)
hex(uadd(0x40000000,0x40000000))
will return 0x80000000, demonstrating the
passing and return of integers where bits 30 and 31 differ.
The limitations on the number of arguments and return values can be overcome by means
of the array
module which enables any number of values of any type to be accessed.
If a Python array of integers is passed as an argument to an assembler function, the function will receive the address of a contiguous set of integers. Thus multiple arguments can be passed as elements of a single array. Similarly a function can return multiple values by assigning them to array elements. Assembler functions have no means of determining the length of an array: this will need to be passed to the function.
This use of arrays can be extended to enable more than three arrays to be used.
This is done using indirection: the uctypes
module supports addressof()
which will return the address of an array passed as its argument. Thus you can
populate an integer array with the addresses of other arrays:
from uctypes import addressof
@micropython.asm_thumb
def getindirect(r0):
ldr(r0, [r0, 0]) # Address of array loaded from passed array
ldr(r0, [r0, 4]) # Return element 1 of indirect array (24)
def testindirect():
a = array.array('i',[23, 24])
b = array.array('i',[0,0])
b[0] = addressof(a)
print(getindirect(b))
These may be handled by means of arrays of the appropriate data type. For example, single precision floating point data may be processed as follows. This code example takes an array of floats and replaces its contents with their squares.
from array import array
@micropython.asm_thumb
def square(r0, r1):
label(LOOP)
vldr(s0, [r0, 0])
vmul(s0, s0, s0)
vstr(s0, [r0, 0])
add(r0, 4)
sub(r1, 1)
bgt(LOOP)
a = array('f', (x for x in range(10)))
square(a, len(a))
print(a)
The uctypes module supports the use of data structures beyond simple arrays. It enables a Python data structure to be mapped onto a bytearray instance which may then be passed to the assembler function.
Named constants¶
Assembler code may be made more readable and maintainable by using named constants rather than littering code with numbers. This may be achieved thus:
MYDATA = const(33)
@micropython.asm_thumb
def foo():
mov(r0, MYDATA)
The const() construct causes MicroPython to replace the variable name with its value at compile time. If constants are declared in an outer Python scope they can be shared between multiple assembler functions and with Python code.
Assembler code as class methods¶
MicroPython passes the address of the object instance as the first argument to class methods. This is normally of little use to an assembler function. It can be avoided by declaring the function as a static method thus:
class foo:
@staticmethod
@micropython.asm_thumb
def bar(r0):
add(r0, r0, r0)
Use of unsupported instructions¶
These can be coded using the data statement as shown below. While
push()
and pop()
are supported the example below illustrates the
principle. The necessary machine code may be found in the ARM v7-M
Architecture Reference Manual. Note that the first argument of data
calls such as
data(2, 0xe92d, 0x0f00) # push r8,r9,r10,r11
indicates that each subsequent argument is a two byte quantity.
Overcoming MicroPython’s integer restriction¶
The Pyboard chip includes a CRC generator. Its use presents a problem in MicroPython because the returned values cover the full gamut of 32 bit quantities whereas small integers in MicroPython cannot have differing values in bits 30 and 31. This limitation is overcome with the following code, which uses assembler to put the result into an array and Python code to coerce the result into an arbitrary precision unsigned integer.
from array import array
import stm
def enable_crc():
stm.mem32[stm.RCC + stm.RCC_AHB1ENR] |= 0x1000
def reset_crc():
stm.mem32[stm.CRC+stm.CRC_CR] = 1
@micropython.asm_thumb
def getval(r0, r1):
movwt(r3, stm.CRC + stm.CRC_DR)
str(r1, [r3, 0])
ldr(r2, [r3, 0])
str(r2, [r0, 0])
def getcrc(value):
a = array('i', [0])
getval(a, value)
return a[0] & 0xffffffff # coerce to arbitrary precision
enable_crc()
reset_crc()
for x in range(20):
print(hex(getcrc(0)))
References¶
- Assembler Tutorial
- Wiki hints and tips
- uPy Inline Assembler source-code, emitinlinethumb.c
- ARM Thumb2 Instruction Set Quick Reference Card
- RM0090 Reference Manual
- ARM v7-M Architecture Reference Manual (Available on the ARM site after a simple registration procedure. Also available on academic sites but beware of out of date versions.)
MicroPython differences from CPython¶
The operations listed in this section produce conflicting results in MicroPython when compared to standard Python.
Syntax¶
Generated Sun 07 Oct 2018 06:47:55 UTC
Spaces¶
uPy requires spaces between literal numbers and keywords, CPy doesn’t¶
Sample code:
try:
print(eval('1and 0'))
except SyntaxError:
print('Should have worked')
try:
print(eval('1or 0'))
except SyntaxError:
print('Should have worked')
try:
print(eval('1if 1else 0'))
except SyntaxError:
print('Should have worked')
CPy output: | uPy output: |
0
1
1
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Core Language¶
Generated Sun 07 Oct 2018 06:47:55 UTC
Classes¶
Special method __del__ not implemented for user-defined classes¶
Sample code:
import gc
class Foo():
def __del__(self):
print('__del__')
f = Foo()
del f
gc.collect()
CPy output: | uPy output: |
__del__
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Method Resolution Order (MRO) is not compliant with CPython¶
Cause: Depth first non-exhaustive method resolution order
Workaround: Avoid complex class hierarchies with multiple inheritance and complex method overrides. Keep in mind that many languages don’t support multiple inheritance at all.
Sample code:
class Foo:
def __str__(self):
return "Foo"
class C(tuple, Foo):
pass
t = C((1, 2, 3))
print(t)
CPy output: | uPy output: |
Foo
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
When inheriting from multiple classes super() only calls one class¶
Cause: See Method Resolution Order (MRO) is not compliant with CPython
Workaround: See Method Resolution Order (MRO) is not compliant with CPython
Sample code:
class A:
def __init__(self):
print("A.__init__")
class B(A):
def __init__(self):
print("B.__init__")
super().__init__()
class C(A):
def __init__(self):
print("C.__init__")
super().__init__()
class D(B,C):
def __init__(self):
print("D.__init__")
super().__init__()
D()
CPy output: | uPy output: |
D.__init__
B.__init__
C.__init__
A.__init__
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Calling super() getter property in subclass will return a property object, not the value¶
Sample code:
class A:
@property
def p(self):
return {"a":10}
class AA(A):
@property
def p(self):
return super().p
a = AA()
print(a.p)
CPy output: | uPy output: |
{'a': 10}
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Functions¶
Error messages for methods may display unexpected argument counts¶
Cause: MicroPython counts “self” as an argument.
Workaround: Interpret error messages with the information above in mind.
Sample code:
try:
[].append()
except Exception as e:
print(e)
CPy output: | uPy output: |
append() takes exactly one argument (0 given)
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
User-defined attributes for functions are not supported¶
Cause: MicroPython is highly optimized for memory usage.
Workaround: Use external dictionary, e.g. FUNC_X[f] = 0
.
Sample code:
def f():
pass
f.x = 0
print(f.x)
CPy output: | uPy output: |
0
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Generator¶
Context manager __exit__() not called in a generator which does not run to completion¶
Sample code:
class foo(object):
def __enter__(self):
print('Enter')
def __exit__(self, *args):
print('Exit')
def bar(x):
with foo():
while True:
x += 1
yield x
def func():
g = bar(0)
for _ in range(3):
print(next(g))
func()
CPy output: | uPy output: |
Enter
1
2
3
Exit
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Runtime¶
Local variables aren’t included in locals() result¶
Cause: MicroPython doesn’t maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can’t be accessed by a name.
Sample code:
def test():
val = 2
print(locals())
test()
CPy output: | uPy output: |
{'val': 2}
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Code running in eval() function doesn’t have access to local variables¶
Cause: MicroPython doesn’t maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can’t be accessed by a name. Effectively, eval(expr)
in MicroPython is equivalent to eval(expr, globals(), globals())
.
Sample code:
val = 1
def test():
val = 2
print(val)
eval("print(val)")
test()
CPy output: | uPy output: |
2
2
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
import¶
__path__ attribute of a package has a different type (single string instead of list of strings) in MicroPython¶
Cause: MicroPython does’t support namespace packages split across filesystem. Beyond that, MicroPython’s import system is highly optimized for minimal memory usage.
Workaround: Details of import handling is inherently implementation dependent. Don’t rely on such details in portable applications.
Sample code:
import modules
print(modules.__path__)
CPy output: | uPy output: |
['/Users/yanminge/project/micropython-api-doc/tests/cpydiff/modules']
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Failed to load modules are still registered as loaded¶
Cause: To make module handling more efficient, it’s not wrapped with exception handling.
Workaround: Test modules before production use; during development, use del sys.modules["name"]
, or just soft or hard reset the board.
Sample code:
import sys
try:
from modules import foo
except NameError as e:
print(e)
try:
from modules import foo
print('Should not get here')
except NameError as e:
print(e)
CPy output: | uPy output: |
foo
name 'xxx' is not defined
foo
name 'xxx' is not defined
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
MicroPython does’t support namespace packages split across filesystem.¶
Cause: MicroPython’s import system is highly optimized for simplicity, minimal memory usage, and minimal filesystem search overhead.
Workaround: Don’t install modules belonging to the same namespace package in different directories. For MicroPython, it’s recommended to have at most 3-component module search paths: for your current application, per-user (writable), system-wide (non-writable).
Sample code:
import sys
sys.path.append(sys.path[1] + "/modules")
sys.path.append(sys.path[1] + "/modules2")
import subpkg.foo
import subpkg.bar
print("Two modules of a split namespace package imported")
CPy output: | uPy output: |
Two modules of a split namespace package imported
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Builtin Types¶
Generated Sun 07 Oct 2018 06:47:55 UTC
Exception¶
Exception chaining not implemented¶
Sample code:
try:
raise TypeError
except TypeError:
raise ValueError
CPy output: | uPy output: |
Traceback (most recent call last):
File "<stdin>", line 8, in <module>
TypeError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 10, in <module>
ValueError
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
User-defined attributes for builtin exceptions are not supported¶
Cause: MicroPython is highly optimized for memory usage.
Workaround: Use user-defined exception subclasses.
Sample code:
e = Exception()
e.x = 0
print(e.x)
CPy output: | uPy output: |
0
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Exception in while loop condition may have unexpected line number¶
Cause: Condition checks are optimized to happen at the end of loop body, and that line number is reported.
Sample code:
l = ["-foo", "-bar"]
i = 0
while l[i][0] == "-":
print("iter")
i += 1
CPy output: | uPy output: |
iter
iter
Traceback (most recent call last):
File "<stdin>", line 10, in <module>
IndexError: list index out of range
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Exception.__init__ method does not exist.¶
Cause: Subclassing native classes is not fully supported in MicroPython.
Workaround: Call using super()
instead:
class A(Exception):
def __init__(self):
super().__init__()
Sample code:
class A(Exception):
def __init__(self):
Exception.__init__(self)
a = A()
CPy output: | uPy output: |
/bin/sh: ../ports/unix/micropython: No such file or directory
|
bytearray¶
Array slice assignment with unsupported RHS¶
Sample code:
b = bytearray(4)
b[0:1] = [1, 2]
print(b)
CPy output: | uPy output: |
bytearray(b'\x01\x02\x00\x00\x00')
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
bytes¶
bytes objects support .format() method¶
Cause: MicroPython strives to be a more regular implementation, so if both str
and bytes
support __mod__()
(the % operator), it makes sense to support format()
for both too. Support for __mod__
can also be compiled out, which leaves only format()
for bytes formatting.
Workaround: If you are interested in CPython compatibility, don’t use .format()
on bytes objects.
Sample code:
print(b'{}'.format(1))
CPy output: | uPy output: |
Traceback (most recent call last):
File "<stdin>", line 7, in <module>
AttributeError: 'bytes' object has no attribute 'format'
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
bytes() with keywords not implemented¶
Workaround: Pass the encoding as a positional paramter, e.g. print(bytes('abc', 'utf-8'))
Sample code:
print(bytes('abc', encoding='utf8'))
CPy output: | uPy output: |
b'abc'
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Bytes subscription with step != 1 not implemented¶
Cause: MicroPython is highly optimized for memory usage.
Workaround: Use explicit loop for this very rare operation.
Sample code:
print(b'123'[0:3:2])
CPy output: | uPy output: |
b'13'
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
float¶
uPy and CPython outputs formats may differ¶
Sample code:
print('%.1g' % -9.9)
CPy output: | uPy output: |
-1e+01
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
int¶
No int conversion for int-derived types available¶
Workaround: Avoid subclassing builtin types unless really needed. Prefer https://en.wikipedia.org/wiki/Composition_over_inheritance .
Sample code:
class A(int):
__add__ = lambda self, other: A(int(self) + other)
a = A(42)
print(a+a)
CPy output: | uPy output: |
84
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
list¶
List delete with step != 1 not implemented¶
Workaround: Use explicit loop for this rare operation.
Sample code:
l = [1, 2, 3, 4]
del l[0:4:2]
print(l)
CPy output: | uPy output: |
[2, 4]
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
List slice-store with non-iterable on RHS is not implemented¶
Cause: RHS is restricted to be a tuple or list
Workaround: Use list(<iter>)
on RHS to convert the iterable to a list
Sample code:
l = [10, 20]
l[0:1] = range(4)
print(l)
CPy output: | uPy output: |
[0, 1, 2, 3, 20]
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
List store with step != 1 not implemented¶
Workaround: Use explicit loop for this rare operation.
Sample code:
l = [1, 2, 3, 4]
l[0:4:2] = [5, 6]
print(l)
CPy output: | uPy output: |
[5, 2, 6, 4]
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
str¶
Start/end indices such as str.endswith(s, start) not implemented¶
Sample code:
print('abc'.endswith('c', 1))
CPy output: | uPy output: |
True
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Attributes/subscr not implemented¶
Sample code:
print('{a[0]}'.format(a=[1, 2]))
CPy output: | uPy output: |
1
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
str(…) with keywords not implemented¶
Workaround: Input the encoding format directly. eg print(bytes('abc', 'utf-8'))
Sample code:
print(str(b'abc', encoding='utf8'))
CPy output: | uPy output: |
abc
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
str.ljust() and str.rjust() not implemented¶
Cause: MicroPython is highly optimized for memory usage. Easy workarounds available.
Workaround: Instead of s.ljust(10)
use "%-10s" % s
, instead of s.rjust(10)
use "% 10s" % s
. Alternatively, "{:<10}".format(s)
or "{:>10}".format(s)
.
Sample code:
print('abc'.ljust(10))
CPy output: | uPy output: |
abc
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
None as first argument for rsplit such as str.rsplit(None, n) not implemented¶
Sample code:
print('a a a'.rsplit(None, 1))
CPy output: | uPy output: |
['a a', 'a']
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Instance of a subclass of str cannot be compared for equality with an instance of a str¶
Sample code:
class S(str):
pass
s = S('hello')
print(s == 'hello')
CPy output: | uPy output: |
True
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Subscript with step != 1 is not yet implemented¶
Sample code:
print('abcdefghi'[0:9:2])
CPy output: | uPy output: |
acegi
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Modules¶
Generated Sun 07 Oct 2018 06:47:55 UTC
array¶
Looking for integer not implemented¶
Sample code:
import array
print(1 in array.array('B', b'12'))
CPy output: | uPy output: |
False
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Array deletion not implemented¶
Sample code:
import array
a = array.array('b', (1, 2, 3))
del a[1]
print(a)
CPy output: | uPy output: |
array('b', [1, 3])
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Subscript with step != 1 is not yet implemented¶
Sample code:
import array
a = array.array('b', (1, 2, 3))
print(a[3:2:2])
CPy output: | uPy output: |
array('b')
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
builtins¶
Second argument to next() is not implemented¶
Cause: MicroPython is optimised for code space.
Workaround: Instead of val = next(it, deflt)
use:
try:
val = next(it)
except StopIteration:
val = deflt
Sample code:
print(next(iter(range(0)), 42))
CPy output: | uPy output: |
42
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
deque¶
Deque not implemented¶
Workaround: Use regular lists. micropython-lib has implementation of collections.deque.
Sample code:
import collections
D = collections.deque()
print(D)
CPy output: | uPy output: |
deque([])
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
json¶
JSON module does not throw exception when object is not serialisable¶
Sample code:
import json
a = bytes(x for x in range(256))
try:
z = json.dumps(a)
x = json.loads(z)
print('Should not get here')
except TypeError:
print('TypeError')
CPy output: | uPy output: |
TypeError
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
struct¶
Struct pack with too few args, not checked by uPy¶
Sample code:
import struct
try:
print(struct.pack('bb', 1))
print('Should not get here')
except:
print('struct.error')
CPy output: | uPy output: |
struct.error
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
Struct pack with too many args, not checked by uPy¶
Sample code:
import struct
try:
print(struct.pack('bb', 1, 2, 3))
print('Should not get here')
except:
print('struct.error')
CPy output: | uPy output: |
struct.error
|
/bin/sh: ../ports/unix/micropython: No such file or directory
|
MicroPython license information¶
The MIT License (MIT)
Copyright (c) 2013-2017 Damien P. George, and others
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.