Programming reference

Start coding in MicroPython on systematica products using code snippets from this programming reference!
Both alpha and omega boards come with MicroPython preinstalled, ready to use.

See also

Check out the official MicroPython documentation for more in-depth information on MicroPython itself.
See also the official website MicroPython.org and the official MicroPython Github repository.

official MycroPython documentation

Boxes like this throughout the page provide direct links to specific relevant pages in the official MicroPython documentation.

Digital IOs

Digital Inputs

alpha:ONE provides 12 digital inputs, compatible with 11-36V input voltage.
The inputs are isolated, therefore at least one reference ground has to be connected to the input ground on one of the pins labeled GND between the inputs (by default they are all connected together).

Each digital input has a green LED that lights up when voltage is applied to the input (meaning the input state is then logic high).

The state of the input can be read simply by calling the method value() from the corresponding Pin object:

input_1.value()      # returns the input logic state, either 0 or 1

official MycroPython documentation

pyb.Pin class

Digital outputs

alpha:ONE provides six power outputs compatible with a supply voltage between 9 and 48V and delivering up to 32A.
The outputs are short-circuit protected. A red LED will light up if there is a fault.
At high current levels it is recommended to monitor the board temperature. Cooling may be required in some applications.
The outputs can be switched on and off by calling the methods high() and low(), respectively.
Each output has a yellow LED that lights up to show when the output has been switched on.
The outputs are high-side switches, meaning they switch the supply voltage.
The low side of the load is permanently connected to ground.
This example switches on output 1 for one second:
from pyb import delay

output_1.high()    # output_1 is switched on
pyb.delay(1000)
output_1.low()     # output_1 is switched off

Attention

Make sure inductive loads such as solenoids and relays have a free-wheeling diode installed anti-parallel to the load. This is critical to avoid voltage spikes when the load is turned off.

official MycroPython documentation

pyb.Pin class

H-Bridges

alpha:ONE does not provide H-Bridge outputs.

LEDs

MicroPython LEDs

alpha:ONE has one RGB LED, accessible through the module pyb, where each color is controlled by a different LED object

LED(1)

red

LED(2)

blue

LED(3)

green

The LEDs can be turned on and off simply using the on() and off() methods:

import pyb

pyb.LED(1).on()          # red LED is switched on
pyb.delay(1000)
pyb.LED(1).off()         # red LED is switched off

For better code readability, you can also use a more explanatory variable:

import pyb

LED_red = pyb.LED(1)

LED_red.on()          # red LED is switched on
pyb.delay(1000)
LED_red.off()         # red LED is switched off

Finally, the toggle() method also exists:

import pyb

LED_red = pyb.LED(1)

LED_red.toggle()          # red LED is toggled

Note

MicroPython LEDs are also directly accessed by MicroPython:
LED(1) is used to signal when data is being written to the flash memory.

official MycroPython documentation

pyb.LED class

RGB Status LEDs

alpha:ONE provides three additional user-controllable RGB status LEDs, accessed using the module status_LEDs.

The object status_LEDs has to be instantiated first:

import status_LEDs

status_LEDs = status_LEDs.status_LEDs()      # instantiate the object status_LEDs
To set one of the LEDs to a specific color you can use the method set_LED_color(LED_nr, color, brightness)

LED_nr

1 to 3

color

‘red’, ‘green’, ‘blue’, ‘yellow’, ‘orange’, ‘turquoise’, ‘aqua’, ‘pink’, ‘white’, ‘off’

brightness

0 to 31

status_LEDs.set_LED_color(LED_nr=1,color='red')                   # with default brightness = 1
status_LEDs.set_LED_color(LED_nr=2,color='green', brightness=5)
status_LEDs.set_LED_color(3, 'blue')                              # shorter, using positional arguments

You can also set the LEDs to any RGB color using the method set_LED_rgb(LED_nr, red, green, blue, brightness)

LED_nr

1 to 3

red

0 to 255

green

0 to 255

blue

0 to 255

brightness

0 to 31

status_LEDs.set_LED_rgb(LED_nr=1, red=167, green=23, blue=255, brightness=3)

To turn it off you can set color = 'off':

status_LEDs.set_LED_color(LED_nr=1, color='off')

Though setting brightness = 0 would also lead to the same result.

Timing and interrupts

Delay and timing

Insert a delay in the execution of a program, using the module pyb

import pyb

pyb.delay(100)                      # wait for 100 milliseconds
pyb.udelay(10)                      # wait for 10 microsenconds

Insert a delay in the execution of a program, using the module time

import time

time.sleep(1)                       # sleep for 1 second
time.sleep_ms(500)                  # sleep for 500 milliseconds
time.sleep_us(10)                   # sleep for 10 microseconds

Measure the duration of a program in milliseconds

from pyb import delay, millis, elapsed_millis

start_ms_count = millis()           # store the starting time

delay(100)                          # the program or code block you want to measure

delta_t = elapsed_millis(start_ms_count)
print("elapsed time:", delta_t, "ms")

Measure the duration of a program in microseconds

from pyb import delay, micros, elapsed_micros

start_us_count = micros()           # store the starting time

delay(100)                          # the program or code block you want to measure

delta_t = elapsed_micros(start_us_count)
print("elapsed time:", delta_t, "us")

alternatively you can also use the time module

import time

start_ms_count = time.ticks_ms()    # store the start time in milliseconds

delay(100)                          # the program or code block you want to measure

delta_t = time.ticks_diff(time.ticks_ms(), start_ms_count)    # compute time difference
print("elapsed time:", delta_t, "ms")

official MycroPython documentation

External interrupts

External interrupts automatically invoke a user-provided callback function each time a digital input changes value.
They can be enabled on the individual digital inputs using the class pyb.ExtInt(pin, mode, pull, callback),
where mode can have following values:

ExtInt.IRQ_RISING

The interrupt will be triggered only by rising edges

ExtInt.IRQ_FALLING

The interrupt will be triggered only by falling edges

ExtInt.IRQ_RISING_FALLING

The interrupt will be triggered both by rising and falling edges

pull is defined like with any GPIO input pin.
The following example demonstrates toggling the LED each time the digital input goes from low to high (flip-flop logic):
from pyb import Pin, ExtInt

led = pyb.LED(1)

# first define the callback function
def cb_func():
   led.toggle()

# this will call the callback function cb_func() each time the pin object input_1 goes high, toggling the LED
ext_input_1 = ExtInt(input_1, ExtInt.IRQ_RISING, Pin.PULL_NONE, cb_func)

Important

Special care has to be given when writing callback functions (also called interrupt handlers) since they can be invoked at any time during the execution of the code and could therefore have unwanted consequences. For more information on this topic, see the detailed information in the official MicroPython documentation: Writing interrupt handlers.

Attention

Be careful with mecanical switches as they generally bounce when opening and closing, firing off multiple interrupts rather than just one. Hardware debouncing, such as a simple RC circuit, is recommended in this case.
See A Guide to Debouncing if you’re interested in a deep-dive into the topic.
Note that the isolation circuit present on the inputs will already provide some filtering of the fastest bounces.
As a minimum, at least software debouncing should be implemented, see the external interrupt datalogger example.
Software debouncing is not ideal, since multiple interrupts will still fire off, and need to be processed, but it should at least ensure that the software generally behaves as expected.

official MycroPython documentation

Timers

Timers are hardware peripherals that can be used for a variety of tasks, from frequency and pulse counting to generating PWM signals. See the official Micropython documentation for all the supported features.

Here is an example where it is used to repeatedly trigger a callback function at a precise frequency given in Hz:
import pyb

# first define the callback function
def cb_func(t):
     pyb.LED(1).toggle()

# then create the timer and assign the callback function
tim = pyb.Timer(1, freq=1, callback=cb_func)    # Timer1 set to a frequency of 1 Hz

Alternatively, the callback function can also be defined or changed after creating the timer, here demonstrated using a lambda function

import pyb

tim = pyb.Timer(1, freq=1)                      # Timer1 set to a frequency of 1 Hz
tim.callback(lambda t: pyb.LED(1).toggle())

The callback function can be disabled by setting it to None

tim.callback(None)

Using the machine module, a timer can also be configured to trigger a callback function just once after a delay specified in milliseconds:

import machine

def cb_function(t):
    print('test')

tim = machine.Timer()
tim.init(mode=machine.Timer.ONE_SHOT, period=2000, callback=cb_function)

official MycroPython documentation

pyb.Timer class
machine.Timer class

RTC

The pyb.RTC class provides access to the microcontroller’s Real Time Clock, which keeps track of time and date also when unpowered thanks to the CR2032 backup battery.
The method datetime() is used both to set and to read the current datetime and uses a tuple with format
(year, month, day, weekday, hours, minutes, seconds, microseconds):
from pyb import RTC, delay

rtc = RTC()                                     # instantiate the RTC object
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0))    # set a specific date and time

delay(1000)                                     # 1 s delay so you see a difference in the current time
rtc.datetime()                                  # returns a tuple corresponding to the current datetime

If you need a datetime string, such as for a timestamp, you can format it like this:

import pyb
rtc = pyb.RTC()                                 # instantiate the RTC object

t = rtc.datetime()
datetime_string = '{:02d}-{:02d}-{:04d} {:02d}:{:02d}:{:02d}'.format(t[2], t[1], t[0], t[4], t[5], t[6])
print(datetime_string)

Alternatively, the time module provides access to different time formats, such as the Epoch (in seconds since Jan 1, 2000)

import time

print(time.mktime(time.localtime()))            # seconds since Jan 1, 2000

official MycroPython documentation

Communication interfaces

Ethernet

alpha:ONE provides an ethernet interface through a Wiznet W5500 ethernet controller.
The network object can be instantiated as follows:
import network, pyb

W5500_pwr.high()    # enable power to the W5500 controller
pyb.delay(10)

eth = network.WIZNET5K(pyb.SPI('W5500'), W5500_cs, W5500_rst)

The network interface then needs to be activated and configured, e.g. using DHCP:

eth.active(True)
eth.ifconfig('dhcp')

You can also configure a static IP by passing a tuple (ip_address, subnet_mask, gateway, dns_server)

eth.active(True)
eth.ifconfig(('192.168.1.88','255.255.255.0','192.168.1.1','192.168.1.1'))

This snippet prints out information on the state of the ethernet interface, so you can verify it is connected:

print('eth.status =', eth.status())
print('eth.active =', eth.active())
print('eth.isconnected =', eth.isconnected())
print('eth.ifconfig =', eth.ifconfig())

Look-up the IP address of a host using socket (it will automatically use the network interface available):

import usocket as socket
ip_addr = socket.getaddrinfo('www.systematica.ch',80)[0][-1][0]
print('www.systematica.ch has address', ip_addr)
To ping a host / ip address you can use the uping utility. Download uping, and copy uping.py to PYBFLASH.
It can then be imported and used as follows:
from uping import ping
ping('www.systematica.ch', count=4, interval=1000)    # ping www.systematica.ch four times with an interval of 1000 ms

Use a socket to receive data from a server:

import usocket as socket

addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23)
addr = addr_info[0][-1]

s = socket.socket()
s.connect(addr)

while True:
  data = s.recv(500)
  print(str(data, 'utf8'), end='')

You can interrupt the program execution with Ctrl + C as usual

official MycroPython documentation

network module
network.WIZNET5K class
network.LAN class
socket module

CAN bus

alpha:ONE has a single CAN Bus interface named CAN
It supports baudrates up to 1 Mbit/s and tolerates bus fault voltages up to +/- 70V.
The 120 Ohm bus terminator is permanently connected.

CAN Bus test in loopback mode (to be able to test without actual bus nodes connected)

from pyb import CAN

can = CAN('CAN', mode=CAN.LOOPBACK, baudrate=250000)
can.setfilter(0, pyb.CAN.RANGE, 0, (123, 126))       # set a filter to receive messages with id=123, 124, 125, 126
can.send('message!', 123)                            # send a message with id 123
can.recv(0)                                          # receive message on FIFO 0

CAN Bus test in normal mode (at least one more node has to be present on the bus so, that the messages are acknowledged)

from pyb import CAN

can = CAN('CAN', mode=CAN.NORMAL, baudrate=250000)
can.setfilter(0, pyb.CAN.RANGE, 0, (123, 126))       # set a filter to receive messages with id=123, 124, 125, 126
can.send('message!', 123)                            # send a message with id 123
can.recv(0)                                          # receive message on FIFO 0

official MycroPython documentation

pyb.CAN class

RS422/485

alpha:ONE provides two RS422/485 Full-duplex interfaces, named RS485_1 and RS485_2.
They support baudrates up to 20 Mbit/s and tolerate line fault voltages up to +/- 60V.
The 120 Ohm terminators are permanently connected.
The low-EMI mode up to 250 kbit/s is software selectable using the RS485_x_nSLOW pin.
To use the interface in 4-wire, full-duplex mode, connect AB and YZ and use the following code:
import pyb

RS485_1 = pyb.UART('RS485_1', baudrate=9600)  # to use RS485 2 set 'RS485_2'
RS485_1_nRE.low()  # pin low enables the receiver
RS485_1_DE.high()  # pin high enables the driver permanently, only ok in full-duplex mode (4 wires)
RS485_1_nSLOW.low()  # pin low enables low-EMI mode for <= 250 kBit/s

RS485_1.write('Test RS485 full-duplex')

official MycroPython documentation

pyb.UART class

RS232/485

alpha:ONE provides a serial interface switchable between RS232 and RS485 half duplex.
The interface is named RS232_485 can be instantiated and used as follows:
For RS232 mode, connect Tx, Rx and GND to the device and use following code
import pyb

# set up interface in RS232 mode
RS232_485 = pyb.UART('RS232_485', baudrate=9600)
RS232_485_n232.low()                        # pin low enables RS232 mode
RS232_485_DE485_F232.low()                  # pin low enables low-EMI mode for <= 250 kBit/s

# send a test message
RS232_485.write('Test RS232')
For RS485 half-duplex mode, connect A, B and GND to the device and use following code
import pyb

# set up interface in RS485 half-duplex mode
RS232_485 = pyb.UART('RS232_485', baudrate=9600)
RS232_485_n232.high()                       # pin high enables RS485 mode

# send a test message
RS232_485_DE485_F232.high()                 # enable the driver to transmit
RS232_485.write('Test RS485 half-duplex')
RS232_485_DE485_F232.low()                  # disable the driver right after each transmission in order to receive

Note that it is necessary to turn off the driver enable pin right after transmitting each message in order to be able to receive the response, as the bus is half-duplex only.

official MycroPython documentation

pyb.UART class

Multifunction pins

alpha:ONE provides 21 multifunction pins, which can be used to expand the functionality of the board and connect to expansion boards.
These pins can be used freely as they are dedicated exclusively to this function and are named GPIO_1 to GPIO_21.

Attention

These pins are 3.3 V level and may need additional circuitry to interface to third party hardware with other voltage levels.
Voltages higher than 3.3 V and reverse voltage may cause permanent damage to the board!

GPIO output

These pins can be used as 3.3 V digital output, providing up to a few mA.
Current-limiting resistors may be needed, for example if you connect an LED.
from pyb import Pin, delay

# initialize the output by instantiating the Pin object
p_out = Pin(Pin.cpu.A4, Pin.OUT_PP)

# turn on the output for 1s
p_out.high()
delay(1000)
p_out.low()

official MycroPython documentation

pyb.Pin class

GPIO input

They can also be used as inputs with a maximum voltage of 3.3 V.
You also have to specify what kind of pull you need:

Pin.PULL_UP

enables a pull up of about 40 kOhm to 3.3 V

Pin.PULL_DOWN

enables a pull down of about 40 kOhm to ground

Pin.PULL_NONE

leaves it floating if the circuit you connect already has a pull resistor installed

from pyb import Pin

p_in = Pin(GPIO_2, Pin.IN, Pin.PULL_UP)
p_in.value()    # get value, 0 or 1

official MycroPython documentation

pyb.Pin class

PWM

Pulse-width modulation is also supported on selected pins, using timer hardware.
Verify which timer and channel correspond to which pin first.
from pyb import Pin, Timer

# instantiate the timer with a frequency of 1 kHz
tim = Timer(13, freq=1000)    # the frequency will be the PWM carrier frequency

# then create the pwm channel on the pin
ch = tim.channel(1, Timer.PWM, Pin.cpu.F8)

# you can then set or change the pulse width in percent to be output using
ch.pulse_width_percent(50)

official MycroPython documentation

pyb.Pin class
pyb.Timer class

ADC

The Analog to Digital Converter allows you to convert an analog voltage to a digital value. (available on selected pins)
The ADC has a resolution of 12 bit, meaning the measured value will be between 0 and 4095.
from pyb import Pin, ADC

adc = ADC(Pin.cpu.A4)                    # 'A4' or GPIO_8
adc.read()                               # read value, 0 to 4095 corresponding to a voltage of 0 to 3.3V

official MycroPython documentation

pyb.Pin class
pyb.ADC class

DAC

The Digital to Analog Converter generates an analog voltage proportional to a digital value. (available on selected pins)
The DAC default resolution is 8 bit, meaning the value will have to be between 0 and 255 for an output of 0 to 3.3V.
from pyb import Pin, DAC

dac = DAC(Pin.cpu.A4, buffering=True)    # 'A4' or GPIO_8
dac.write(120)                           # output between 0 and 255
A higher resolution of 12 bits can be selected by passing the argument bits=12
It is recommended to enable output buffering using buffering=True, unless your load has a very high impedance (MOhm range).

official MycroPython documentation

pyb.Pin class
pyb.DAC class

UART

Universal Asynchronous Receiver-Transmitter, a.k.a. serial ports
An UART uses two pins and is full-duplex capable:

TX

transmit data

RX

receive data

UARTS on multifunctioni pins are compatible with 3.3V TTL level. An external transceiver is needed for other levels.
Hardware UARTS are available on selected pins using pyb.UART()
from pyb import UART

uart = UART(4, 9600)
uart.write('hello')
uart.read(5)    # read up to 5 bytes

official MycroPython documentation

pyb.UART class

SPI bus

Serial Peripheral Interface Bus | It uses 4 pins and is full-duplex capable:

SCK

clock signal

MISO

Master-in, Slave-out data

MOSI

Master-out, Slave-in data

CS

Chip Select, must be pull low to enable communication with a slave

Hardware SPI buses are available on selected pins using pyb.SPI()
from pyb import SPI, Pin

# configure SPI2 as a master/controller (pinout for omega)
spi = SPI(2, mode=SPI.MASTER, baudrate=1000000, polarity=1, phase=0)
cs = Pin(Pin.cpu.E10, Pin.OUT, value=1)

cs.low()                              # enable chip select
spi.send(b'\x01\x02\x03\x04')         # send bytes on the bus
spi.recv(5)                           # receive 5 bytes on the bus
spi.send_recv(b'\x01\x02\x03\x04')    # send message and simultaneously receive 4 bytes
cs.high()                             # disable chip select

A softwre SPI bus can be created on any pin using machine.SoftSPI()

from machine import SoftSPI
from pyb import Pin

# create Software SPI bus as a master/controller (pinout for omega)
spi = SoftSPI(baudrate=500000, polarity=1, phase=0, bits=8, firstbit=SoftSPI.MSB, sck=Pin.cpu.E7, mosi=Pin.cpu.E8, miso=Pin.cpu.E9)
cs = Pin(Pin.cpu.E10, Pin.OUT, value=1)

cs.low()                              # enable chip select
spi.write(b'\x01\x02\x03\x04')        # send bytes on the bus
spi.read(4)                           # receive 4 bytes on the bus
cs.high()                             # disable chip select

official MycroPython documentation

pyb.SPI class
machine.SPI class

I2C bus

Inter-Integrated Circuit Bus
It uses two pins and is only half-duplex capable

SCL

clock signal

SDA

transmit and receive data

Hardware I2C buses are available on selected pins using pyb.I2C()
from pyb import I2C, Pin

# create hardware I2C1 object
i2c = I2C(1, I2C.CONTROLLER, baudrate=400000)

addresses = i2c.scan()                                        # returns list of slave addresses
i2c.send('123', addr=0x42)                                    # send 3 bytes to slave with address 0x42
data = i2c.recv(2, addr=0x42)                                 # read 2 bytes from bus

i2c.mem_write(b'\x01\x02', addr=0x42, memaddr=0x10)           # write 2 bytes to slave 0x42,  memory address 0x10
data = i2c.mem_read(2, addr=0x42, memaddr=0x10)               # read 2 bytes from slave 0x42, starting from memory address 0x10

A software I2C bus can be created on any avilable pin using machine.SoftI2C()

from machine import SoftI2C
from pyb import Pin

# create Software I2C bus as a controller (pinout example for omega)
i2c = SoftI2C(scl=Pin.cpu.E7, sda=Pin.cpu.E8, freq=400000)    # create software I2C object

i2c.writeto(0x42, 'hello')                                    # write 5 bytes to slave with address 0x42
i2c.readfrom(0x42, 5)                                         # read 5 bytes from slave

official MycroPython documentation

pyb.I2C class
machine.I2C class

Storage

flash memory

All boards provide onboard, non-removable flash storage of 8 Mb, which is automatically mounted in the file system under /flash and can be used to store small files in addition to boot.py and main.py.

basic file system operations

You can list the /flash directory content using:
import os

print(os.listdir('/flash'))

To create a file and/or write data to it use the open() function with mode='w':

FILENAME = '/flash/test.txt'              # any file extension can be used

# create file
file = open(FILENAME, mode='w')
file.write('First line\n')                # write the first line to the file
file.close()                              # always close the file when it is not used anymore

To append data to a file use mode='a':

# append data to file
with open(FILENAME, mode='a') as file:    # 'w' would over write the data in the file
    file.write('Second line\n')           # '\n' is the escape sequence for the new line character

To print the content of a file use mode='r' to open it with read-only access, so you don’t accedentally modify it:

# read data from file
with open(FILENAME, mode='r') as f:       # using 'with' the file will be automatically closed afterwards
    for line in f.readlines():
      print(line)
Note: the statement with open() as f: makes sure the file is automatically closed after the operation.

To delete a file use os.remove()

import os

os.remove('/flash/test.txt')

To create and remove directories you can use os.mkdir(path) and os.rmdir(path), see the documentation below.

For examples on how to test for the presence or absence of files, see the code in the advanced examples

official MycroPython documentation

microSD Card

The microSD card slot adds the possibility to store larger amounts of data, such as for long-term logging.

Important

Make sure the microSD card is formatted to FAT32.
Note that FAT32 supports a maximum card size of 32 GB.

To use the microSD card, insert it into the slot and mount it using:

import pyb, os

os.mount(pyb.SDCard(), '/sd')

# list the SD card content
print(os.listdir('/sd'))

Attention

If an SD card is detected when booting, MicroPython will ignore the files under /flash , automatically mount the SD card and boot using the files under /sd.
If no files are found, nothing will be executed (i.e. it will not fall back to booting from /flash)!
While this can be useful in some cases, it is often source of unexpected behaviour and generally it seems preferrable to always boot from /flash.
To force booting from /flash, create a folder or an empty file named SKIPSD under /flash:
import os

os.mkdir('/flash/SKIPSD')

print(os.listdir('/flash'))    # list the current directory content to verify the SKIPSD folder has been created

official MycroPython documentation

Accessing storage over USB

By default, the memory currently in use by MicroPython (flash memory or microSD card) is exposed to the Host PC as Mass Storage Device, so you can read and write files to them. This is controlled by the command found in boot.py:
import pyb

pyb.usb_mode( 'VCP+MSC', msc=(pyb.Flash(),) )    # default setting

Meaning that both the Virtual Com Port for the REPL as well as the Mass Storage Device are enabled on the USB port.

Attention

Always safely remove the USB drive(s) by clicking Eject before unplugging / power cycling / hard resetting the board!
Failure to do so could cause memory corruption. You may lose the files on the device as a consequence.
→ frequently perform backup copies of important code while you develop it on the board!
To simultaneously access both the microSD card and the board’s internal flash memory from your computer as separate mass storage devices use the following command:
import pyb

pyb.usb_mode( 'VCP+MSC', msc=(pyb.Flash(), pyb.SDCard()) )
To make this setting permanent you can add this line to boot.py.

official MycroPython documentation

pyb.usb_mode() function

General board control

power-saving sleep mode

For power saving purposes in battery applications you can put the CPU in a low-power state. An external interrupt or an interrupt from the RTC is then needed to wake it up.

import pyb

pyb.stop()    # stop CPU, waiting for external or RTC interrupt

See rtc.wakeup() to configure a real-time-clock wakeup event, respectively pyb.ExtInt for external interrupts.

official MycroPython documentation

pyb.RTC.wakeup() method
pyb.ExtInt class

CPU frequency

You can read the CPU operating frequency, as well as the frequency of the different peripheral buses:

import pyb

pyb.freq()            # get CPU and bus frequencies
In special cases, you can also change the CPU operating frequency, for instance to reduce the power consumption.
For the majority of the applications, it is however recommended to leave the default settings.
import pyb

pyb.freq(60000000)    # set CPU freq to 60MHz

official MycroPython documentation

pyb.freq() method

miscellaneous functions

You can duplicate the REPL on an UART using pyb.repl_uart()

import pyb

pyb.repl_uart(pyb.UART(1, 9600))    # duplicate REPL on UART(1)

info() prints lots of information about the board

import pyb

pyb.info()    # print out lots of information about the board

official MycroPython documentation

pyb miscellaneous functions

unique ID

Each microcontroller has a globally-unique ID you can read out to identify a specific board:

import pyb

pyb.unique_id()    # returns a 96 bit microcontroller unique identifier

official MycroPython documentation

pyb.unique_id method

Advanced examples

external interrupt datalogger

This example logs the current timestamp to a csv file located on the microSD card each time the input pin sees a rising edge (goes from low to high).
FOLDER = '/sd/'                  # where the log file will be saved
FILENAME = 'datalog_INT.csv'     # log filename, any other file extension such as .log or .txt can be used
INTERRUPT_PIN = input_1          # the input pin triggering the interrupt
DEBOUNCING_THRESHOLD = 20        # debouncing window in ms (determines minimum valid repetition rate)

import pyb, os, micropython

micropython.alloc_emergency_exception_buf(100)

rtc = pyb.RTC()
last_event = pyb.millis()

# mount sd card if it isn't already
if 'sd' not in os.listdir('/'):
   os.mount(pyb.SDCard(), '/sd')

# create a new file to log to if it doesn't already exist
if FILENAME not in os.listdir(FOLDER):
   with open(FOLDER+FILENAME, 'w') as f:
      f.write('Timestamp;\n')     # write column header

# define the callback function
def schedule_log(line):
   micropython.schedule(log_event,line)

#define the logger function
def log_event(line):
   t = rtc.datetime()
   global last_event
   if pyb.elapsed_millis(last_event) > DEBOUNCING_THRESHOLD:
      last_event = pyb.millis()
      timestamp = '{:02d}-{:02d}-{:04d} {:02d}:{:02d}:{:02d}.{:02d};\n'.format(t[2], t[1], t[0], t[4], t[5], t[6], t[7])
      with open(FOLDER+FILENAME, 'a') as f:    # 'a' appends data to the file
         f.write(timestamp)  #

# attach the external interrupt to input_1
extint_pin = pyb.ExtInt(INTERRUPT_PIN, pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_NONE, schedule_log)

# define function to print the log file content
def print_log():
   with open(FOLDER+FILENAME, 'r') as f:
      for line in f.readlines():
         print(line, end='')

timed ADC datalogger

This example logs the timestamp and the value of an ADC pin to a csv file located on the microSD card at fixed intervals, controlled by a timer.
The voltage to be measured has to be between 0 and 3.3V, corrisponding to ADC values between 0 and 4095.
FOLDER = '/sd/'                  # where the log file will be saved
FILENAME = 'datalog_ADC.csv'     # log filename, any other file extension such as .log or .txt can be used
ADC_PIN = 'A4'                   # the ADC pin to measure
LOGGING_FREQUENCY = 10           # logging frequency in Hz

import pyb, os, micropython

micropython.alloc_emergency_exception_buf(100)

rtc = pyb.RTC()

# create the ADC object on the specified pin
adc = pyb.ADC(eval('pyb.Pin.cpu.' + ADC_PIN))

# mount sd card if it isn't already
if 'sd' not in os.listdir('/'):
   os.mount(pyb.SDCard(), '/sd')

# create a new file to log to if it doesn't already exist
if FILENAME not in os.listdir(FOLDER):
   with open(FOLDER+FILENAME, 'w') as f:
      f.write('Timestamp;ADC_value;\n')     # write column header

# define the callback function
def schedule_log(tim):
   micropython.schedule(log_ADC,tim)

#define the logger function
def log_ADC(tim):
   t = rtc.datetime()
   value = str(adc.read())
   timestamp = '{:02d}-{:02d}-{:04d} {:02d}:{:02d}:{:02d}.{:02d};'.format(t[2], t[1], t[0], t[4], t[5], t[6], t[7])
   with open(FOLDER+FILENAME, 'a') as f:    # 'a' appends data to the file
      f.write(timestamp + value + ';\n')    #

# create timer with interrupt
timer_log = pyb.Timer(1, freq=LOGGING_FREQUENCY, callback=schedule_log)

# define function to print the log file content
def print_log():
   with open(FOLDER+FILENAME, 'r') as f:
      for line in f.readlines():
         print(line, end='')

printing log files

You can print the log file content by calling the function print_log() defined in both datalogger examples.