10. 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.
10.1. 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.
10.2. 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 runningimport stm
and thenhelp(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 bymovt
. Themovt
also shifts the immediate value right by 16 bits.
strh
stores a half-word (16 bits). The instruction above stores the lower 16-bits ofr1
into the memory locationr0 + stm.GPIO_BSRRL
. This has the effect of setting high all those pins on port A for which the corresponding bit inr0
is set. In our example above, the 13th bit inr0
is set, so PA13 is pulled high. This turns on the red LED.
10.3. 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.
10.4. 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)
10.5. Further reading¶
For further information about supported instructions of the inline assembler, see the reference documentation.