kopia lustrzana https://github.com/micropython/micropython
124 wiersze
3.7 KiB
ReStructuredText
124 wiersze
3.7 KiB
ReStructuredText
|
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)
|