0% found this document useful (0 votes)
115 views61 pages

Introduction To The Pyboard

The document provides an introduction to using the pyboard microcontroller. It discusses caring for the hardware by being gentle with plugging/unplugging cables and avoiding static electricity. It then describes the layout of the pyboard including the LEDs, switches, and ports. It explains how to connect the pyboard via USB to power it and access the filesystem. It demonstrates how to write a simple Python script that turns on an LED, save it to the pyboard's flash drive, reset the board to run it, and use the REPL serial prompt to interact with and test code on the pyboard.

Uploaded by

olawale gbadebo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
115 views61 pages

Introduction To The Pyboard

The document provides an introduction to using the pyboard microcontroller. It discusses caring for the hardware by being gentle with plugging/unplugging cables and avoiding static electricity. It then describes the layout of the pyboard including the LEDs, switches, and ports. It explains how to connect the pyboard via USB to power it and access the filesystem. It demonstrates how to write a simple Python script that turns on an LED, save it to the pyboard's flash drive, reset the board to run it, and use the REPL serial prompt to interact with and test code on the pyboard.

Uploaded by

olawale gbadebo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 61

Introduction to the pyboard

To get the most out of your pyboard, there are a few basic things to

Understand about how it works.

Caring for your pyboard

Because the pyboard does not have a housing it needs a bit of care:

- Be gentle when plugging/unplugging the USB cable. Whilst the USB


connector is soldered through the board and is relatively strong, if it breaks
off it can be very difficult to fix.

- Static electricity can shock the components on the pyboard and destroy
them. If you experience a lot of static electricity in your area (eg dry and
cold climates), take extra care not to shock the pyboard. If your pyboard
came in a black plastic box, then this box is the best way to store and carry
the pyboard as it is an anti-static box (it is made of a conductive plastic,
with conductive foam inside).

As long as you take care of the hardware, you should be okay. It's almost

impossible to break the software on the pyboard, so feel free to play


around

with writing code as much as you like. If the filesystem gets corrupt, see

below on how to reset it. In the worst case you might need to reflash the

MicroPython software, but that can be done over USB.

Layout of the pyboard

The micro USB connector is on the top right, the micro SD card slot on

the top left of the board. There are 4 LEDs between the SD slot and

USB connector. The colours are: red on the bottom, then green, orange,

and blue on the top. There are 2 switches: the right one is the reset
switch, the left is the user switch.Plugging in and powering on

The pyboard can be powered via USB. Connect it to your PC via a micro
USB cable. There is only one way that the cable will fit. Once connected,

the green LED on the board should flash quickly.Powering by an external


power source The pyboard can be powered by a battery or other external
power source.

Be sure to connect the positive lead of the power supply to VIN, and

ground to GND. There is no polarity protection on the pyboard so you

must be careful when connecting anything to VIN.The input voltage must


be between 3.6V and 10V.

Running your first script

Let's jump right in and get a Python script running on the pyboard. After

all, that's what it's all about!

Connecting your pyboard

Connect your pyboard to your PC (Windows, Mac or Linux) with a micro


USB cable.

There is only one way that the cable will connect, so you can't get it
wrong.

When the pyboard is connected to your PC it will power on and enter the
start up process (the boot process). The green LED should light up for half
a second or less, and when it turns off it means the boot process has
completed.

Opening the pyboard USB drive


-----------------------------

Your PC should now recognise the pyboard. It depends on the type of PC


you

have as to what happens next:

- **Windows**: Your pyboard will appear as a removable USB flash


drive.

Windows may automatically pop-up a window, or you may need to go


there

using Explorer.

Windows will also see that the pyboard has a serial device, and it will

try to automatically configure this device. If it does, cancel the process.

We will get the serial device working in the next tutorial.

- **Mac**: Your pyboard will appear on the desktop as a removable disc.

It will probably be called ``PYBFLASH``. Click on it to open the


pyboard folder.

- **Linux**: Your pyboard will appear as a removable medium. On


Ubuntu

it will mount automatically and pop-up a window with the pyboard


folder.
On other Linux distributions, the pyboard may be mounted
automatically,

or you may need to do it manually. At a terminal command line, type


``lsblk``

to see a list of connected drives, and then ``mount /dev/sdb1``


(replace ``sdb1``

with the appropriate device). You may need to be root to do this.

Okay, so you should now have the pyboard connected as a USB flash drive,
and

a window (or command line) should be showing the files on the pyboard
drive.

The drive you are looking at is known as ``/flash`` by the pyboard, and
should contain

the following 4 files:

* `boot.py <http://micropython.org/resources/fresh-pyboard/boot.py>`_
-- the various configuration options for the pyboard.

It is executed when the pyboard boots up.

* `main.py <http://micropython.org/resources/fresh-pyboard/main.py>`_
-- the Python program to be run.

It is executed after ``boot.py``.


* `README.txt
<http://micropython.org/resources/fresh-pyboard/README.txt>`_ -- basic
information about getting started with the pyboard.

This provides pointers for new users and can be safely deleted.

* `pybcdc.inf
<http://micropython.org/resources/fresh-pyboard/pybcdc.inf>`_ -- the
Windows driver file to configure the serial USB device.

More about this in the next tutorial.

Editing ``main.py``

-------------------

Now we are going to write our Python program, so open the ``main.py``

file in a text editor. On Windows you can use notepad, or any other editor.

On Mac and Linux, use your favourite text editor. With the file open you
will

see it contains 1 line::

# main.py -- put your code here!

This line starts with a # character, which means that it is a *comment*.


Such

lines will not do anything, and are there for you to write notes about your
program.

Let's add 2 lines to this ``main.py`` file, to make it look like this::

# main.py -- put your code here!

import pyb

pyb.LED(4).on()

The first line we wrote says that we want to use the ``pyb`` module.

This module contains all the functions and classes to control the features

of the pyboard.

The second line that we wrote turns the blue LED on: it first gets the
``LED``

class from the ``pyb`` module, creates LED number 4 (the blue LED), and
then

turns it on.

Resetting the pyboard

---------------------

To run this little script, you need to first save and close the ``main.py``
file,
and then eject (or unmount) the pyboard USB drive. Do this like you
would a

normal USB flash drive.

When the drive is safely ejected/unmounted you can get to the fun part:

press the RST switch on the pyboard to reset and run your script. The RST

switch is the small black button just below the USB connector on the
board,

on the right edge.

When you press RST the green LED will flash quickly, and then the blue

LED should turn on and stay on.

Congratulations! You have written and run your very first MicroPython

program!

Getting a MicroPython REPL prompt

=================================

REPL stands for Read Evaluate Print Loop, and is the name given to the

interactive MicroPython prompt that you can access on the pyboard. Using

the REPL is by far the easiest way to test out your code and run
commands.

You can use the REPL in addition to writing scripts in ``main.py``.


To use the REPL, you must connect to the serial USB device on the
pyboard.

How you do this depends on your operating system.

Windows

-------

You need to install the pyboard driver to use the serial USB device.

The driver is on the pyboard's USB flash drive, and is called


``pybcdc.inf``.

To install this driver you need to go to Device Manager

for your computer, find the pyboard in the list of devices (it should have

a warning sign next to it because it's not working yet), right click on

the pyboard device, select Properties, then Install Driver. You need to

then select the option to find the driver manually (don't use Windows auto
update),

navigate to the pyboard's USB drive, and select that. It should then install.

After installing, go back to the Device Manager to find the installed


pyboard,

and see which COM port it is (eg COM4).

More comprehensive instructions can be found in the


`Guide for pyboard on Windows (PDF)
<http://micropython.org/resources/Micro-Python-Windows-setup.pdf>`_.

Please consult this guide if you are having problems installing the driver.

You now need to run your terminal program. You can use HyperTerminal
if you

have it installed, or download the free program PuTTY:

`putty.exe
<http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html>`_.

Using your serial program you must connect to the COM port that you
found in the

previous step. With PuTTY, click on "Session" in the left-hand panel, then
click

the "Serial" radio button on the right, then enter you COM port (eg COM4)
in the

"Serial Line" box. Finally, click the "Open" button.

Mac OS X

--------

Open a terminal and run::

screen /dev/tty.usbmodem*
When you are finished and want to exit screen, type CTRL-A CTRL-\\.

Linux

-----

Open a terminal and run::

screen /dev/ttyACM0

You can also try ``picocom`` or ``minicom`` instead of screen. You may
have to

use ``/dev/ttyACM1`` or a higher number for ``ttyACM``. And, you may


need to give

yourself the correct permissions to access this devices (eg group ``uucp``
or ``dialout``,

or use sudo).

Using the REPL prompt

---------------------

Now let's try running some MicroPython code directly on the pyboard.
With your serial program open (PuTTY, screen, picocom, etc) you may see
a blank

screen with a flashing cursor. Press Enter and you should be presented
with a

MicroPython prompt, i.e. ``>>>``. Let's make sure it is working with the
obligatory test::

>>> print("hello pyboard!")

hello pyboard!

In the above, you should not type in the ``>>>`` characters. They are
there to

indicate that you should type the text after it at the prompt. In the end,
once

you have entered the text ``print("hello pyboard!")`` and pressed Enter,
the output

on your screen should look like it does above.

If you already know some python you can now try some basic commands
here.

If any of this is not working you can try either a hard reset or a soft reset;

see below.
Go ahead and try typing in some other commands. For example::

>>> pyb.LED(1).on()

>>> pyb.LED(2).on()

>>> 1 + 2

>>> 1 / 2

0.5

>>> 20 * 'py'

'pypypypypypypypypypypypypypypypypypypypy'

Resetting the board

-------------------

If something goes wrong, you can reset the board in two ways. The first is
to press CTRL-D

at the MicroPython prompt, which performs a soft reset. You will see a
message something like ::

>>>

MPY: sync filesystems

MPY: soft reboot

Micro Python v1.0 on 2014-05-03; PYBv1.0 with STM32F405RG


Type "help()" for more information.

>>>

If that isn't working you can perform a hard reset (turn-it-off-and-on-


again) by pressing the RST

switch (the small black button closest to the micro-USB socket on the
board). This will end your

session, disconnecting whatever program (PuTTY, screen, etc) that you


used to connect to the pyboard.

If you are going to do a hard-reset, it's recommended to first close your


serial program and eject/unmount

the pyboard drive.

Turning on LEDs and basic Python concepts

=========================================

The easiest thing to do on the pyboard is to turn on the LEDs attached to


the board. Connect the board, and log in as described in tutorial 1. We will
start by turning and LED on in the interpreter, type the following ::

>>> myled = pyb.LED(1)

>>> myled.on()

>>> myled.off()
These commands turn the LED on and off.

This is all very well but we would like this process to be automated. Open
the file MAIN.PY on the pyboard in your favourite text editor. Write or
paste the following lines into the file. If you are new to python, then make
sure you get the indentation correct since this matters! ::

led = pyb.LED(2)

while True:

led.toggle()

pyb.delay(1000)

When you save, the red light on the pyboard should turn on for about a
second. To run the script, do a soft reset (CTRL-D). The pyboard will then
restart and you should see a green light continuously flashing on and off.
Success, the first step on your path to building an army of evil robots!
When you are bored of the annoying flashing light then press CTRL-C at
your terminal to stop it running.

So what does this code do? First we need some terminology. Python is an
object-oriented language, almost everything in python is a *class* and
when you create an instance of a class you get an *object*. Classes have
*methods* associated to them. A method (also called a member function)
is used to interact with or control the object.
The first line of code creates an LED object which we have then called led.
When we create the object, it takes a single parameter which must be
between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED
class has three important member functions that we will use: on(), off()
and toggle(). The other function that we use is pyb.delay() this simply
waits for a given time in milliseconds. Once we have created the LED
object, the statement while True: creates an infinite loop which toggles the
led between on and off and waits for 1 second.

**Exercise: Try changing the time between toggling the led and turning on
a different LED.**

**Exercise: Connect to the pyboard directly, create a pyb.LED object and


turn it on using the on() method.**

A Disco on your pyboard

-----------------------

So far we have only used a single LED but the pyboard has 4 available.
Let's start by creating an object for each LED so we can control each of
them. We do that by creating a list of LEDS with a list comprehension. ::

leds = [pyb.LED(i) for i in range(1,5)]

If you call pyb.LED() with a number that isn't 1,2,3,4 you will get an error
message.
Next we will set up an infinite loop that cycles through each of the LEDs
turning them on and off. ::

n=0

while True:

n = (n + 1) % 4

leds[n].toggle()

pyb.delay(50)

Here, n keeps track of the current LED and every time the loop is executed
we cycle to the next n (the % sign is a modulus operator that keeps n
between 0 and 3.) Then we access the nth LED and toggle it. If you run
this you should see each of the LEDs turning on then all turning off again
in sequence.

One problem you might find is that if you stop the script and then start it
again that the LEDs are stuck on from the previous run, ruining our
carefully choreographed disco. We can fix this by turning all the LEDs off
when we initialise the script and then using a try/finally block. When you
press CTRL-C, MicroPython generates a VCPInterrupt exception. Exceptions
normally mean something has gone wrong and you can use a try:
command to "catch" an exception. In this case it is just the user
interrupting the script, so we don't need to catch the error but just tell
MicroPython what to do when we exit. The finally block does this, and we
use it to make sure all the LEDs are off. The full code is::

leds = [pyb.LED(i) for i in range(1,5)]


for l in leds:

l.off()

n=0

try:

while True:

n = (n + 1) % 4

leds[n].toggle()

pyb.delay(50)

finally:

for l in leds:

l.off()

The Special LEDs

----------------

The yellow and blue LEDs are special. As well as turning them on and off,
you can control their intensity using the intensity() method. This takes a
number between 0 and 255 that determines how bright it is. The following
script makes the blue LED gradually brighter then turns it off again. ::

led = pyb.LED(4)

intensity = 0
while True:

intensity = (intensity + 1) % 255

led.intensity(intensity)

pyb.delay(20)

You can call intensity() on LEDs 1 and 2 but they can only be off or on. 0
sets them off and any other number up to 255 turns them on.

.. _pyboard_tutorial_switch:

Switches, callbacks and interrupts

==================================

The pyboard has 2 small switches, labelled USR and RST. The RST switch

is a hard-reset switch, and if you press it then it restarts the pyboard

from scratch, equivalent to turning the power off then back on.

The USR switch is for general use, and is controlled via a Switch object.

To make a switch object do::

>>> sw = pyb.Switch()

Remember that you may need to type ``import pyb`` if you get an error
that
the name ``pyb`` does not exist.

With the switch object you can get its status::

>>> sw.value()

False

This will print ``False`` if the switch is not held, or ``True`` if it is held.

Try holding the USR switch down while running the above command.

There is also a shorthand notation to get the switch status, by "calling" the

switch object::

>>> sw()

False

Switch callbacks

----------------

The switch is a very simple object, but it does have one advanced feature:

the ``sw.callback()`` function. The callback function sets up something to

run when the switch is pressed, and uses an interrupt. It's probably best
to start with an example before understanding how interrupts work. Try

running the following at the prompt::

>>> sw.callback(lambda:print('press!'))

This tells the switch to print ``press!`` each time the switch is pressed

down. Go ahead and try it: press the USR switch and watch the output on

your PC. Note that this print will interrupt anything you are typing, and

is an example of an interrupt routine running asynchronously.

As another example try::

>>> sw.callback(lambda:pyb.LED(1).toggle())

This will toggle the red LED each time the switch is pressed. And it will

even work while other code is running.

To disable the switch callback, pass ``None`` to the callback function::

>>> sw.callback(None)
You can pass any function (that takes zero arguments) to the switch
callback.

Above we used the ``lambda`` feature of Python to create an anonymous


function

on the fly. But we could equally do::

>>> def f():

... pyb.LED(1).toggle()

...

>>> sw.callback(f)

This creates a function called ``f`` and assigns it to the switch callback.

You can do things this way when your function is more complicated than a

``lambda`` will allow.

Note that your callback functions must not allocate any memory (for
example

they cannot create a tuple or list). Callback functions should be relatively

simple. If you need to make a list, make it beforehand and store it in a

global variable (or make it local and close over it). If you need to do

a long, complicated calculation, then use the callback to set a flag which

some other code then responds to.


Technical details of interrupts

-------------------------------

Let's step through the details of what is happening with the switch

callback. When you register a function with ``sw.callback()``, the switch

sets up an external interrupt trigger (falling edge) on the pin that the

switch is connected to. This means that the microcontroller will listen

on the pin for any changes, and the following will occur:

1. When the switch is pressed a change occurs on the pin (the pin goes

from low to high), and the microcontroller registers this change.

2. The microcontroller finishes executing the current machine instruction,

stops execution, and saves its current state (pushes the registers on

the stack). This has the effect of pausing any code, for example your

running Python script.

3. The microcontroller starts executing the special interrupt handler

associated with the switch's external trigger. This interrupt handler

get the function that you registered with ``sw.callback()`` and executes

it.

4. Your callback function is executed until it finishes, returning control

to the switch interrupt handler.

5. The switch interrupt handler returns, and the microcontroller is


notified that the interrupt has been dealt with.

6. The microcontroller restores the state that it saved in step 2.

7. Execution continues of the code that was running at the beginning.


Apart

from the pause, this code does not notice that it was interrupted.

The above sequence of events gets a bit more complicated when multiple

interrupts occur at the same time. In that case, the interrupt with the

highest priority goes first, then the others in order of their priority.

The switch interrupt is set at the lowest priority.

Further reading

---------------

For further information about using hardware interrupts see

:ref:`writing interrupt handlers <isr_rules>`.

The accelerometer

=================

Here you will learn how to read the accelerometer and signal using LEDs
states like tilt left and tilt right.

Using the accelerometer


-----------------------

The pyboard has an accelerometer (a tiny mass on a tiny spring) that can
be used

to detect the angle of the board and motion. There is a different sensor for

each of the x, y, z directions. To get the value of the accelerometer, create


a

pyb.Accel() object and then call the x() method. ::

>>> accel = pyb.Accel()

>>> accel.x()

This returns a signed integer with a value between around -30 and 30.
Note that

the measurement is very noisy, this means that even if you keep the board

perfectly still there will be some variation in the number that you measure.

Because of this, you shouldn't use the exact value of the x() method but
see if

it is in a certain range.

We will start by using the accelerometer to turn on a light if it is not flat. ::


accel = pyb.Accel()

light = pyb.LED(3)

SENSITIVITY = 3

while True:

x = accel.x()

if abs(x) > SENSITIVITY:

light.on()

else:

light.off()

pyb.delay(100)

We create Accel and LED objects, then get the value of the x direction of
the

accelerometer. If the magnitude of x is bigger than a certain value


``SENSITIVITY``,

then the LED turns on, otherwise it turns off. The loop has a small
``pyb.delay()``

otherwise the LED flashes annoyingly when the value of x is close to

``SENSITIVITY``. Try running this on the pyboard and tilt the board left
and right

to make the LED turn on and off.


**Exercise: Change the above script so that the blue LED gets brighter the
more

you tilt the pyboard. HINT: You will need to rescale the values, intensity
goes

from 0-255.**

Making a spirit level

---------------------

The example above is only sensitive to the angle in the x direction but if
we

use the ``y()`` value and more LEDs we can turn the pyboard into a spirit
level. ::

xlights = (pyb.LED(2), pyb.LED(3))

ylights = (pyb.LED(1), pyb.LED(4))

accel = pyb.Accel()

SENSITIVITY = 3

while True:

x = accel.x()
if x > SENSITIVITY:

xlights[0].on()

xlights[1].off()

elif x < -SENSITIVITY:

xlights[1].on()

xlights[0].off()

else:

xlights[0].off()

xlights[1].off()

y = accel.y()

if y > SENSITIVITY:

ylights[0].on()

ylights[1].off()

elif y < -SENSITIVITY:

ylights[1].on()

ylights[0].off()

else:

ylights[0].off()

ylights[1].off()

pyb.delay(100)
We start by creating a tuple of LED objects for the x and y directions.
Tuples

are immutable objects in python which means they can't be modified once
they are

created. We then proceed as before but turn on a different LED for positive
and

negative x values. We then do the same for the y direction. This isn't

particularly sophisticated but it does the job. Run this on your pyboard and
you

should see different LEDs turning on depending on how you tilt the board.

Safe mode and factory reset

===========================

If something goes wrong with your pyboard, don't panic! It is almost

impossible for you to break the pyboard by programming the wrong thing.

The first thing to try is to enter safe mode: this temporarily skips

execution of ``boot.py`` and ``main.py`` and gives default USB settings.

If you have problems with the filesystem you can do a factory reset,

which restores the filesystem to its original state.


Safe mode

---------

To enter safe mode, do the following steps:

1. Connect the pyboard to USB so it powers up.

2. Hold down the USR switch.

3. While still holding down USR, press and release the RST switch.

4. The LEDs will then cycle green to orange to green+orange and back
again.

5. Keep holding down USR until *only the orange LED is lit*, and then let

go of the USR switch.

6. The orange LED should flash quickly 4 times, and then turn off.

7. You are now in safe mode.

In safe mode, the ``boot.py`` and ``main.py`` files are not executed,
and so

the pyboard boots up with default settings. This means you now have
access

to the filesystem (the USB drive should appear), and you can edit
``boot.py``

and ``main.py`` to fix any problems.


Entering safe mode is temporary, and does not make any changes to the

files on the pyboard.

Factory reset the filesystem

----------------------------

If you pyboard's filesystem gets corrupted (for example, you forgot to

eject/unmount it), or you have some code in ``boot.py`` or ``main.py``


which

you can't escape from, then you can reset the filesystem.

Resetting the filesystem deletes all files on the internal pyboard storage

(not the SD card), and restores the files ``boot.py``, ``main.py``,


``README.txt``

and ``pybcdc.inf`` back to their original state.

To do a factory reset of the filesystem you follow a similar procedure as

you did to enter safe mode, but release USR on green+orange:

1. Connect the pyboard to USB so it powers up.

2. Hold down the USR switch.

3. While still holding down USR, press and release the RST switch.
4. The LEDs will then cycle green to orange to green+orange and back
again.

5. Keep holding down USR until *both the green and orange LEDs are lit*,
and

then let go of the USR switch.

6. The green and orange LEDs should flash quickly 4 times.

7. The red LED will turn on (so red, green and orange are now on).

8. The pyboard is now resetting the filesystem (this takes a few seconds).

9. The LEDs all turn off.

10. You now have a reset filesystem, and are in safe mode.

11. Press and release the RST switch to boot normally.

Making the pyboard act as a USB mouse

=====================================

The pyboard is a USB device, and can configured to act as a mouse instead

of the default USB flash drive.

To do this we must first edit the ``boot.py`` file to change the USB

configuration. If you have not yet touched your ``boot.py`` file then it

will look something like this::

# boot.py -- run on boot-up

# can run arbitrary Python, but best to keep it minimal


import pyb

#pyb.main('main.py') # main script to run after this one

#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device

#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse

To enable the mouse mode, uncomment the last line of the file, to

make it look like::

pyb.usb_mode('VCP+HID') # act as a serial device and a mouse

If you already changed your ``boot.py`` file, then the minimum code it

needs to work is::

import pyb

pyb.usb_mode('VCP+HID')

This tells the pyboard to configure itself as a VCP (Virtual COM Port,

ie serial port) and HID (human interface device, in our case a mouse)

USB device when it boots up.

Eject/unmount the pyboard drive and reset it using the RST switch.
Your PC should now detect the pyboard as a mouse!

Sending mouse events by hand

----------------------------

To get the py-mouse to do anything we need to send mouse events to the


PC.

We will first do this manually using the REPL prompt. Connect to your

pyboard using your serial program and type the following (no need to type

the ``#`` and text following it)::

>>> hid = pyb.USB_HID()

>>> hid.send((0, 100, 0, 0)) # (button status, x-direction, y-direction,


scroll)

Your mouse should move 100 pixels to the right! In the command above
you

are sending 4 pieces of information: **button status**, **x-direction**,


**y-direction**, and **scroll**. The

number 100 is telling the PC that the mouse moved 100 pixels in the x
direction.

Let's make the mouse oscillate left and right::


>>> import math

>>> def osc(n, d):

... for i in range(n):

... hid.send((0, int(20 * math.sin(i / 10)), 0, 0))

... pyb.delay(d)

...

>>> osc(100, 50)

The first argument to the function ``osc`` is the number of mouse events
to send,

and the second argument is the delay (in milliseconds) between events.
Try

playing around with different numbers.

**Exercise: make the mouse go around in a circle.**

Making a mouse with the accelerometer

-------------------------------------

Now lets make the mouse move based on the angle of the pyboard, using
the

accelerometer. The following code can be typed directly at the REPL


prompt,
or put in the ``main.py`` file. Here, we'll put in in ``main.py`` because
to do

that we will learn how to go into safe mode.

At the moment the pyboard is acting as a serial USB device and an HID (a
mouse).

So you cannot access the filesystem to edit your ``main.py`` file.

You also can't edit your ``boot.py`` to get out of HID-mode and back to
normal

mode with a USB drive...

To get around this we need to go into *safe mode*. This was described in

the [safe mode tutorial](tut-reset), but we repeat the instructions here:

1. Hold down the USR switch.

2. While still holding down USR, press and release the RST switch.

3. The LEDs will then cycle green to orange to green+orange and back
again.

4. Keep holding down USR until *only the orange LED is lit*, and then let

go of the USR switch.

5. The orange LED should flash quickly 4 times, and then turn off.

6. You are now in safe mode.


In safe mode, the ``boot.py`` and ``main.py`` files are not executed,
and so

the pyboard boots up with default settings. This means you now have
access

to the filesystem (the USB drive should appear), and you can edit
``main.py``.

(Leave ``boot.py`` as-is, because we still want to go back to HID-mode


after

we finish editing ``main.py``.)

In ``main.py`` put the following code::

import pyb

switch = pyb.Switch()

accel = pyb.Accel()

hid = pyb.USB_HID()

while not switch():

hid.send((0, accel.x(), accel.y(), 0))

pyb.delay(20)
Save your file, eject/unmount your pyboard drive, and reset it using the
RST

switch. It should now act as a mouse, and the angle of the board will
move

the mouse around. Try it out, and see if you can make the mouse stand
still!

Press the USR switch to stop the mouse motion.

You'll note that the y-axis is inverted. That's easy to fix: just put a

minus sign in front of the y-coordinate in the ``hid.send()`` line above.

Restoring your pyboard to normal

--------------------------------

If you leave your pyboard as-is, it'll behave as a mouse everytime you plug

it in. You probably want to change it back to normal. To do this you need

to first enter safe mode (see above), and then edit the ``boot.py`` file.

In the ``boot.py`` file, comment out (put a # in front of) the line with the

``VCP+HID`` setting, so it looks like::

#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse


Save your file, eject/unmount the drive, and reset the pyboard. It is now

back to normal operating mode.

The Timers

==========

The pyboard has 14 timers which each consist of an independent counter

running at a user-defined frequency. They can be set up to run a function

at specific intervals.

The 14 timers are numbered 1 through 14, but 3 is reserved

for internal use, and 5 and 6 are used for servo and ADC/DAC control.

Avoid using these timers if possible.

Let's create a timer object::

>>> tim = pyb.Timer(4)

Now let's see what we just created::

>>> tim

Timer(4)

The pyboard is telling us that ``tim`` is attached to timer number 4, but


it's not yet initialised. So let's initialise it to trigger at 10 Hz

(that's 10 times per second)::

>>> tim.init(freq=10)

Now that it's initialised, we can see some information about the timer::

>>> tim

Timer(4, prescaler=624, period=13439, mode=UP, div=1)

The information means that this timer is set to run at the peripheral

clock speed divided by 624+1, and it will count from 0 up to 13439, at


which

point it triggers an interrupt, and then starts counting again from 0. These

numbers are set to make the timer trigger at 10 Hz: the source frequency

of the timer is 84MHz (found by running ``tim.source_freq()``) so we

get 84MHz / 625 / 13440 = 10Hz.

Timer counter

-------------

So what can we do with our timer? The most basic thing is to get the
current value of its counter::

>>> tim.counter()

21504

This counter will continuously change, and counts up.

Timer callbacks

---------------

The next thing we can do is register a callback function for the timer to

execute when it triggers (see the :ref:`switch tutorial


<pyboard_tutorial_switch>`

for an introduction to callback functions)::

>>> tim.callback(lambda t:pyb.LED(1).toggle())

This should start the red LED flashing right away. It will be flashing

at 5 Hz (2 toggle's are needed for 1 flash, so toggling at 10 Hz makes

it flash at 5 Hz). You can change the frequency by re-initialising the

timer::
>>> tim.init(freq=20)

You can disable the callback by passing it the value ``None``::

>>> tim.callback(None)

The function that you pass to callback must take 1 argument, which is

the timer object that triggered. This allows you to control the timer

from within the callback function.

We can create 2 timers and run them independently::

>>> tim4 = pyb.Timer(4, freq=10)

>>> tim7 = pyb.Timer(7, freq=20)

>>> tim4.callback(lambda t: pyb.LED(1).toggle())

>>> tim7.callback(lambda t: pyb.LED(2).toggle())

Because the callbacks are proper hardware interrupts, we can continue

to use the pyboard for other things while these timers are running.

Making a microsecond counter

----------------------------
You can use a timer to create a microsecond counter, which might be

useful when you are doing something which requires accurate timing.

We will use timer 2 for this, since timer 2 has a 32-bit counter (so

does timer 5, but if you use timer 5 then you can't use the Servo

driver at the same time).

We set up timer 2 as follows::

>>> micros = pyb.Timer(2, prescaler=83, period=0x3fffffff)

The prescaler is set at 83, which makes this timer count at 1 MHz.

This is because the CPU clock, running at 168 MHz, is divided by

2 and then by prescaler+1, giving a frequency of 168 MHz/2/(83+1)=1


MHz

for timer 2. The period is set to a large number so that the timer

can count up to a large number before wrapping back around to zero.

In this case it will take about 17 minutes before it cycles back to

zero.

To use this timer, it's best to first reset it to 0::


>>> micros.counter(0)

and then perform your timing::

>>> start_micros = micros.counter()

... do some stuff ...

>>> end_micros = micros.counter()

.. _pyboard_tutorial_assembler:

Inline assembler

================

Here you will learn how to write inline assembler in MicroPython.

**Note**: this is an advanced tutorial, intended for those who already

know a bit about microcontrollers and assembly language.

MicroPython includes an inline assembler. It allows you to write

assembly routines as a Python function, and you can call them as you
would
a normal Python function.

Returning a value

-----------------

Inline assembler functions are denoted by a special function decorator.

Let's start with the simplest example::

@micropython.asm_thumb

def fun():

movw(r0, 42)

You can enter this in a script or at the REPL. This function takes no

arguments and returns the number 42. ``r0`` is a register, and the value

in this register when the function returns is the value that is returned.

MicroPython always interprets the ``r0`` as an integer, and converts it to


an

integer object for the caller.

If you run ``print(fun())`` you will see it print out 42.

Accessing peripherals
---------------------

For something a bit more complicated, let's turn on an LED::

@micropython.asm_thumb

def led_on():

movwt(r0, stm.GPIOA)

movw(r1, 1 << 13)

strh(r1, [r0, stm.GPIO_BSRRL])

This code uses a few new concepts:

- ``stm`` is a module which provides a set of constants for easy

access to the registers of the pyboard's microcontroller. Try

running ``import stm`` and then ``help(stm)`` at the REPL. It will

give you a list of all the available constants.

- ``stm.GPIOA`` is the address in memory of the GPIOA peripheral.

On the pyboard, the red LED is on port A, pin PA13.

- ``movwt`` moves a 32-bit number into a register. It is a convenience


function that turns into 2 thumb instructions: ``movw`` followed by
``movt``.

The ``movt`` also shifts the immediate value right by 16 bits.

- ``strh`` stores a half-word (16 bits). The instruction above stores

the lower 16-bits of ``r1`` into the memory location ``r0 +


stm.GPIO_BSRRL``.

This has the effect of setting high all those pins on port A for which

the corresponding bit in ``r0`` is set. In our example above, the 13th

bit in ``r0`` is set, so PA13 is pulled high. This turns on the red LED.

Accepting arguments

-------------------

Inline assembler functions can accept up to 4 arguments. If they are

used, they must be named ``r0``, ``r1``, ``r2`` and ``r3`` to reflect
the registers

and the calling conventions.

Here is a function that adds its arguments::

@micropython.asm_thumb

def asm_add(r0, r1):


add(r0, r0, r1)

This performs the computation ``r0 = r0 + r1``. Since the result is put

in ``r0``, that is what is returned. Try ``asm_add(1, 2)``, it should


return

3.

Loops

-----

We can assign labels with ``label(my_label)``, and branch to them using

``b(my_label)``, or a conditional branch like ``bgt(my_label)``.

The following example flashes the green LED. It flashes it ``r0`` times. ::

@micropython.asm_thumb

def flash_led(r0):

# get the GPIOA address in r1

movwt(r1, stm.GPIOA)

# get the bit mask for PA14 (the pin LED #2 is on)

movw(r2, 1 << 14)


b(loop_entry)

label(loop1)

# turn LED on

strh(r2, [r1, stm.GPIO_BSRRL])

# delay for a bit

movwt(r4, 5599900)

label(delay_on)

sub(r4, r4, 1)

cmp(r4, 0)

bgt(delay_on)

# turn LED off

strh(r2, [r1, stm.GPIO_BSRRH])

# delay for a bit

movwt(r4, 5599900)

label(delay_off)

sub(r4, r4, 1)
cmp(r4, 0)

bgt(delay_off)

# loop r0 times

sub(r0, r0, 1)

label(loop_entry)

cmp(r0, 0)

bgt(loop1)

Further reading

---------------

For further information about supported instructions of the inline


assembler,

see the :ref:`reference documentation <asm_thumb2_index>`.

Power control

=============

:meth:`pyb.wfi` is used to reduce power consumption while waiting for an

event such as an interrupt. You would use it in the following situation::

while True:
do_some_processing()

pyb.wfi()

Control the frequency using :meth:`pyb.freq`::

pyb.freq(30000000) # set CPU frequency to 30MHz

.. _pyboard_quickref:

Quick reference for the pyboard

===============================

The below pinout is for PYBv1.1. You can also view pinouts for

other versions of the pyboard:

`PYBv1.0 <http://micropython.org/resources/pybv10-pinout.jpg>`__

or `PYBLITEv1.0-AC <http://micropython.org/resources/pyblitev10ac-
pinout.jpg>`__

or `PYBLITEv1.0 <http://micropython.org/resources/pyblitev10-
pinout.jpg>`__.

.. only:: not latex

.. image:: http://micropython.org/resources/pybv11-pinout.jpg

:alt: PYBv1.1 pinout


:width: 700px

.. only:: latex

.. image:: http://micropython.org/resources/pybv11-pinout-800px.jpg

:alt: PYBv1.1 pinout

Below is a quick reference for the pyboard. If it is your first time working
with

this board please consider reading the following sections first:

.. toctree::

:maxdepth: 1

general.rst

tutorial/index.rst

General board control

---------------------

See :mod:`pyb`. ::
import pyb

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

pyb.wfi() # pause CPU, waiting for interrupt

pyb.freq() # get CPU and bus frequencies

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

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

Delay and timing

----------------

Use the :mod:`time <utime>` module::

import time

time.sleep(1) # sleep for 1 second

time.sleep_ms(500) # sleep for 500 milliseconds

time.sleep_us(10) # sleep for 10 microseconds

start = time.ticks_ms() # get value of millisecond counter

delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference

Internal LEDs
-------------

See :ref:`pyb.LED <pyb.LED>`. ::

from pyb import LED

led = LED(1) # 1=red, 2=green, 3=yellow, 4=blue

led.toggle()

led.on()

led.off()

# LEDs 3 and 4 support PWM intensity (0-255)

LED(4).intensity() # get intensity

LED(4).intensity(128) # set intensity to half

Internal switch

---------------

See :ref:`pyb.Switch <pyb.Switch>`. ::

from pyb import Switch


sw = Switch()

sw.value() # returns True or False

sw.callback(lambda: pyb.LED(1).toggle())

Pins and GPIO

-------------

See :ref:`pyb.Pin <pyb.Pin>`. ::

from pyb import Pin

p_out = Pin('X1', Pin.OUT_PP)

p_out.high()

p_out.low()

p_in = Pin('X2', Pin.IN, Pin.PULL_UP)

p_in.value() # get value, 0 or 1

Servo control

-------------

See :ref:`pyb.Servo <pyb.Servo>`. ::


from pyb import Servo

s1 = Servo(1) # servo on position 1 (X1, VIN, GND)

s1.angle(45) # move to 45 degrees

s1.angle(-60, 1500) # move to -60 degrees in 1500ms

s1.speed(50) # for continuous rotation servos

External interrupts

-------------------

See :ref:`pyb.ExtInt <pyb.ExtInt>`. ::

from pyb import Pin, ExtInt

callback = lambda e: print("intr")

ext = ExtInt(Pin('Y1'), ExtInt.IRQ_RISING, Pin.PULL_NONE, callback)

Timers

------

See :ref:`pyb.Timer <pyb.Timer>`. ::


from pyb import Timer

tim = Timer(1, freq=1000)

tim.counter() # get counter value

tim.freq(0.5) # 0.5 Hz

tim.callback(lambda t: pyb.LED(1).toggle())

RTC (real time clock)

---------------------

See :ref:`pyb.RTC <pyb.RTC>` ::

from pyb import RTC

rtc = RTC()

rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and


time

rtc.datetime() # get date and time

PWM (pulse width modulation)

----------------------------
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.Timer <pyb.Timer>`. ::

from pyb import Pin, Timer

p = Pin('X1') # X1 has TIM2, CH1

tim = Timer(2, freq=1000)

ch = tim.channel(1, Timer.PWM, pin=p)

ch.pulse_width_percent(50)

ADC (analog to digital conversion)

----------------------------------

See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.ADC <pyb.ADC>`. ::

from pyb import Pin, ADC

adc = ADC(Pin('X19'))

adc.read() # read value, 0-4095

DAC (digital to analog conversion)

----------------------------------
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.DAC <pyb.DAC>`. ::

from pyb import Pin, DAC

dac = DAC(Pin('X5'))

dac.write(120) # output between 0 and 255

UART (serial bus)

-----------------

See :ref:`pyb.UART <pyb.UART>`. ::

from pyb import UART

uart = UART(1, 9600)

uart.write('hello')

uart.read(5) # read up to 5 bytes

SPI bus

-------
See :ref:`pyb.SPI <pyb.SPI>`. ::

from pyb import SPI

spi = SPI(1, SPI.MASTER, baudrate=200000, polarity=1, phase=0)

spi.send('hello')

spi.recv(5) # receive 5 bytes on the bus

spi.send_recv('hello') # send and receive 5 bytes

I2C bus

-------

Hardware I2C is available on the X and Y halves of the pyboard via


``I2C('X')``

and ``I2C('Y')``. Alternatively pass in the integer identifier of the


peripheral,

eg ``I2C(1)``. Software I2C is also available by explicitly specifying the

``scl`` and ``sda`` pins instead of the bus name. For more details see

:ref:`machine.I2C <machine.I2C>`. ::

from machine import I2C

i2c = I2C('X', freq=400000) # create hardware I2c object


i2c = I2C(scl='X1', sda='X2', freq=100000) # create software I2C
object

i2c.scan() # returns list of slave addresses

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


0x42

i2c.readfrom(0x42, 5) # read 5 bytes from slave

i2c.readfrom_mem(0x42, 0x10, 2) # read 2 bytes from slave 0x42,


slave memory 0x10

i2c.writeto_mem(0x42, 0x10, 'xy') # write 2 bytes to slave 0x42, slave


memory 0x10

Note: for legacy I2C support see :ref:`pyb.I2C <pyb.I2C>`.

CAN bus (controller area network)

---------------------------------

See :ref:`pyb.CAN <pyb.CAN>`. ::

from pyb import CAN

can = CAN(1, CAN.LOOPBACK)


can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))

can.send('message!', 123) # send a message with id 123

can.recv(0) # receive message on FIFO 0

Internal accelerometer

----------------------

See :ref:`pyb.Accel <pyb.Accel>`. ::

from pyb import Accel

accel = Accel()

print(accel.x(), accel.y(), accel.z(), accel.tilt())

You might also like