10. Ассемблерная вставка

Здесь вы узнаете как сделать ассемблерную вставку в код Micro Python.

Примечание: эта часть учебника для опытных программистов, для тех, кто уже немного знаком с микроконтроллерами и ассемблером.

С помощью ассемблерных вставок вы можете писать процедуры ассемблера и вызывать их как обычные функции в Python.

10.1. Возвращение значения

Ассемблерные вставки обозначаются специальным символом. Начнём с простого примера:

@micropython.asm_thumb
def fun():
    movw(r0, 42)

Вы можете написать этот скрипт в REPL. Эта функция не принемает никаких аргументов и возвращает число 42. r0 - это регистр, значение этого регистра вернётся вместе с 42. Micro Python всегда распознаёт r0 как integer и конвертирует его в объект для получателя.

Если мы запустим print(fun()) - то увидим как на экране появится 42.

10.2. Доступ к периферийным устройствам

Для того, чтобы немного усложнить задачу, давайте включим светодиод:

@micropython.asm_thumb
def led_on():
    movwt(r0, stm.GPIOA)
    movw(r1, 1 << 13)
    strh(r1, [r0, stm.GPIO_BSRRL])

Здесь есть несколько новых элементов:

  • stm - это модуль, который предоставляет множество констант для простого доступа к регистрам микроконтроллера. Попытайтесь импортировать stm (import stm) и затем вызовите help(stm) в REPL. Должен появиться список всевозможных конастант.
  • stm.GPIOA - это адресс в памяти периферийного устройства GPIOA. На pyboard красный светодиод на порт A, пин PA13.
  • movwt перемещает 32-разрядное число в регистр. Это удобная функция, которая превращается в две отличные инструкции: movw следует за movt. Также, movt немедленно сдвигает значение вправо на 16 бит.
  • strh хранит полу-слова (16 бит). Инструкция выше сохраняет нижние 16 бит из r1 в ячейку памяти 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. Это включает красный светодиод.

10.3. Получение аргументов

Встроенные ассемблерные функции могут принемать до 3-х аргументов. Если они используются, то должны быть названы r0, r1 и r2 для отображения регистров и вызова соглашения(???).

Ниже функция, которая добавляет эти аргументы:

@micropython.asm_thumb
def asm_add(r0, r1):
    add(r0, r0, r1)

Эта функция выполняет вычисление r0 = r0 + r1. Результат помещается в r0 и возвращается. Попробуйте asm_add(1,2) - это должно вернуть 3ю

10.4. Циклы

Мы можем назначать метки label(my_label) и ветвить их, используя, b(my_label) или условно ветвить как bgt(my_label).

В следующем примере мигает залёный светодиод. Он мигает r0 раз.

@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)