| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
 | Inline assembler
================
Here you will learn how to write inline assembler in Micro Python.
**Note**: this is an advanced tutorial, intended for those who already
know a bit about microcontrollers and assembly language.
Micro Python 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.
Micro Python 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 3 arguments.  If they are
used, they must be named ``r0``, ``r1`` and ``r2`` 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)
 |