Урок ОК02

Начальная страница курса.

Урок OK02 основан на коде урока OK01. Здесь мы заставим светодиод ОК или ACT включаться и отключаться бесконечно. Предполагается использование кода урока OK01 как основы для этого.

1. Задержка

Как ни странно задержка (ожидание) это очень полезная часть операционной системы. Часто операционным системам нечего выполнять и нужно ожидать. В данном примере мы хотим сделать задержку для того, чтобы промежутки включения-отключения были заметны. Если мы будем просто включать и отключать светодиод, этого не будет видно из-за того, что процессор будет делать это много тысяч раз в секунду. В следующих уроках мы рассмотрим точные задержки, но сейчас достаточно просто тратить время.

mov r2,#0x3F0000
wait1$:
sub r2,#1
cmp r2,#0
bne wait1$ 

Код, приведенный выше, создает задержку, которая из-за того что все Raspberry Pi одинаковы создает примерно одинаковую задержку. Это делается при помощи команды mov, которая загружает в регистр r2 число 0x3F0000. Затем происходит вычитание 1 от содержимого регистра r2 до тех пор пока его значение не достигнет 0. Тут мы использовали новые команды: sub, cmp и bne.

sub – команда нахождения разности. Она отнимает второй аргумент от первого и помещает результат в первый.

cmp – более интересная команда. Она сравнивает первый аргумент со вторым и сохраняет результат сравнения в специальном регистре, который называют регистром статуса (статусным регистром). Вам не стоит переживать по этому поводу, достаточно сказать, что эта команда запоминает, среди прочего, какое из чисел больше или меньше, или они равны.[1]

bne – команда ветвления. В ассемблере для ARM любая команда может быть выполнена условно. Это значит, что инструкция будет выполнена только если предыдущее сравнение имело определенный результат. Мы будем интенсивно использовать это позже для интересных трюков. А в данном случае мы используем суффикс ne для команды b. Это значит перейти по адресу метки только если при сравнении значения были не равны. Суффикс ne может быть использован с любой другой командой, как и некоторые другие условия (всего их 16) вроде eq (equal) для равных значений и lt (less than) для меньших.

2. Все вместе

Я упоминал в прошлый раз, что статусный светодиод может быть включен снова путем записи со смещением 28 в контроллер GPIO, вместо 40 (т. е. str r1, [r0, #28]). Поэтому нужно изменить код урока OK01, чтобы включить светодиод, выполнить код задержки и выключить снова, а затем добавить ветвление в начало цикла. Обратите внимание, что не обязательно настраивать вывод GPIO 16 снова, нам нужно выполнить это только один раз. Если вы будете действовать эффективно, что я строго поощряю, вы будете использовать значение в регистре r1 повторно. Как и для всех уроков код для этого находится в секции загрузок. Убедитесь что все ваши метки уникальны. Если вы написали wait1$: вы уже не можете назначить метку wait1$ другой строке.
На моем Raspberry Pi светодиод загорается примерно дважды в секунду. Это может быть легко изменено при помощи изменения значения в регистре r2. Однако, к сожалению, мы не можем точно предсказать скорость работы. Если у Вас что-либо не получилось обратитесь к разделу решения проблем, в ином случае, мои поздравления.


Как мы помним из предыдущего урока, в Raspberry Pi B+ ACT светодиод подключен к выводу GPIO47.
Итоговый код программы для Raspberry Pi B+.

.section .init
.globl _start
_start:

/* 
* This command loads the physical address of the GPIO region into r0.
*/
ldr r0,=0x20200000

mov r1,#1
lsl r1,#21

/*
* Set the GPIO function select.
*/
str r1,[r0,#16]

/* 
* Set the 15th bit of r1.
*/
mov r1,#1
lsl r1,#15

/* NEW
* Label the next line loop$ for the infinite looping
*/
loop$: 

/*
* Set GPIO47 to low, causing the LED to turn on.
*/
str r1,[r0,#44]

/* NEW
* Now, to create a delay, we busy the processor on a pointless quest to 
* decrement the number 0x3F0000 to 0!
*/
mov r2,#0x3F0000
wait1$:
        sub r2,#1
        cmp r2,#0
        bne wait1$

/* NEW
* Set GPIO47 to high, causing the LED to turn off.
*/
str r1,[r0,#32]

/* NEW
* Wait once more.
*/
mov r2,#0x3F0000
wait2$:
        sub r2,#1
        cmp r2,#0
        bne wait2$

/*
* Loop over this process forevermore
*/
b loop$

В этом уроке мы выучили еще 2 ассемблерные команды: sub и cmp, а также рассмотрели условные операции в ARM.

В следующем уроке OK03 мы оценим как мы пишем код и введем несколько стандартов, которые позволят нам использовать код повторно если это нужно и работать с C и C++ кодом.


[1] Я предполагаю, что если вы перешли по ссылке, то действительно хотите знать об этом. Регистр CPSR это 32 битный регистр состоящий из маленьких однобитных полей. Тут есть битовые поля для положительного, нулевого и отрицательного результата. Когда используется инструкция cmp происходит нахождение разности второго аргумента и первого и устанавливаются флаги в зависимости от результата. Нулевой результат значит, что числа равны (a-b=0 значит что a=b), положительный значит что a больше b (a-b>0 значит что a>b), а отрицательный, что a меньше b. Существуют и другие инструкции сравнения, но cmp наиболее интуитивно понятная.

 

Похожий код:

Фото аватара
Алексей Петров

Программист, разработчик с 5 летним опытом работы. Учусь на разработчика игр на Unity и разработчика VR&AR реальности (виртуальной реальности). Основные языки программирования: C#, C++.

Оцените автора
Бла, бла код
Добавить комментарий