| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- .. _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>`.
|