Опубликован: 24.11.2024 | Доступ: свободный | Студентов: 2 / 0 | Длительность: 05:47:00
Лекция 4:

GPIO

< Лекция 3 || Лекция 4: 123456 || Лекция 5 >

Макроопределения базы и смещения

Возвращаясь к коду, давайте посмотрим на __metal_driver_sifive_gpio0_enable_output() снова:

int __metal_driver_sifive_gpio0_enable_output(struct metal_gpio *ggpio, long source) {
    long base = __metal_driver_sifive_gpio0_base(ggpio);
    __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) |= source;
    return 0;
}

Если вы будете следовать объявлению для base и METAL_SIFIVE_GPIO0_OUTPUT_EN, вы в конечном итоге найдете их макроопределения в ./bsp/install/include/metal/machine/platform.h:

/* From gpio@10012000 */
#define METAL_SIFIVE_GPIO0_10012000_BASE_ADDRESS 268509184UL
#define METAL_SIFIVE_GPIO0_0_BASE_ADDRESS 268509184UL
#define METAL_SIFIVE_GPIO0_10012000_SIZE 4096UL
#define METAL_SIFIVE_GPIO0_0_SIZE 4096UL
#define METAL_SIFIVE_GPIO0
#define METAL_SIFIVE_GPIO0_VALUE 0UL
#define METAL_SIFIVE_GPIO0_INPUT_EN 4UL
#define METAL_SIFIVE_GPIO0_OUTPUT_EN 8UL
#define METAL_SIFIVE_GPIO0_PORT 12UL
#define METAL_SIFIVE_GPIO0_PUE 16UL
#define METAL_SIFIVE_GPIO0_DS 20UL
#define METAL_SIFIVE_GPIO0_RISE_IE 24UL
#define METAL_SIFIVE_GPIO0_RISE_IP 28UL
#define METAL_SIFIVE_GPIO0_FALL_IE 32UL
#define METAL_SIFIVE_GPIO0_FALL_IP 36UL
#define METAL_SIFIVE_GPIO0_HIGH_IE 40UL
#define METAL_SIFIVE_GPIO0_HIGH_IP 44UL
#define METAL_SIFIVE_GPIO0_LOW_IE 48UL
#define METAL_SIFIVE_GPIO0_LOW_IP 52UL
#define METAL_SIFIVE_GPIO0_IOF_EN 56UL
#define METAL_SIFIVE_GPIO0_IOF_SEL 60UL
#define METAL_SIFIVE_GPIO0_OUT_XOR 64UL

В этом коде первым определением является значение, присвоенное base, а его длинное десятичное число равно 0x10012000. Вторая группа определений - это смещения регистра конфигурации. METAL_SIFIVE_GPIO0_OUTPUT_EN - четвертый.

Если вы вернетесь к таблицам 51 и 52 в руководстве FE310, вы увидите, что это действительно базовый адрес GPIO0 и смещение регистра output_en. Вот они, для вашего удобства:


Базовый адрес GPIO0 и смещения регистра конфигурации (Взято с руководства пользователя FE310-G002, размещено с разрешения SiFive, Inc.)

Рис. 3.10. Базовый адрес GPIO0 и смещения регистра конфигурации (Взято с руководства пользователя FE310-G002, размещено с разрешения SiFive, Inc.)
Базовый адрес GPIO0 и смещения регистра конфигурации (Взято с руководства пользователя FE310-G002, размещено с разрешения SiFive, Inc.)

Рис. 3.11. Базовый адрес GPIO0 и смещения регистра конфигурации (Взято с руководства пользователя FE310-G002, размещено с разрешения SiFive, Inc.)

Альтернативный способ увидеть, что происходит

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

Теперь мы увидим краткое описание процесса, который мы только что прошли. Это также более здравый взгляд на код, который на самом деле выполняется. Этот альтернативный процесс заключается в отладке приложения по мере его запуска на плате Red-V Thing Plus.

Как и раньше, мы хотим посмотреть, что происходит в строке 58 hello.c. Для этого давайте просто откроем проект Blinky и нажмем кнопку Debug.

Об отладке проекта Blinky

Рис. 3.12. Об отладке проекта Blinky

Теперь, перед запуском приложения, поставьте точку останова непосредственно перед запуском строки 58. Чтобы сделать это, перейдите к строке 58 и дважды щелкните по желобу слева, прямо над цифрой 58.

Двойной щелчок по номеру строки переключает точку прерывания

Рис. 3.13. Двойной щелчок по номеру строки переключает точку прерывания

Пошаговое выполнение

Для выполнения кода мы будем использовать кнопки выполнения кода:

Resume, Suspend, Terminate, Disconnect, Step Into, Step Over, Step Return, Instruction Stepping Mode

Рис. 3.14. Resume, Suspend, Terminate, Disconnect, Step Into, Step Over, Step Return, Instruction Stepping Mode

Если вы нажмете кнопку Resume , чтобы запустить приложение, оно остановится непосредственно перед выполнением строки 58.

Отладчик остановился в точке прерывания. Обратите внимание на ассемблерный код справа

Рис. 3.15. Отладчик остановился в точке прерывания. Обратите внимание на ассемблерный код справа

Обратите внимание на следующие детали на рисунке выше:

Терминал показывает приветственное сообщение.

Выполнение находится в строке 58 в исходном коде C.

Разборка показывает реализацию вызова функции в виде 3 инструкций по сборке RISC-V.

Нажмите кнопку Step Into , чтобы перейти внутрь функции metal_gpio_enable_output(). После выполнения двух шагов вызов виртуальной функции можно найти в строке 98 из ./bsp/install/include/metal/gpio.h:

Функция metal_gpio_enable_output() при пошаговом выполнении

Рис. 3.16. Функция metal_gpio_enable_output() при пошаговом выполнении

Один раз войдя в эту функцию, мы сразу попадаем в функцию __metal_driver_sifive_gpio0_enable_output():

Функция __metal_driver_sifive_gpio0_enable_output() при пошаговом выполнении

Рис. 3.17. Функция __metal_driver_sifive_gpio0_enable_output() при пошаговом выполнении

Первый вызов функции - это фактическая функция, которая извлекает базовый адрес. Жаль, что приходится делать это во время выполнения, когда компилятор мог бы позаботиться об этом, сэкономив бесценное процессорное время.

После возврата из функции __metal_driver_sifive_gpio0_base() обратите внимание на состояние приложения непосредственно перед записью 1 в интересующий бит:

Состояние выполнения заявки до присвоения интереса

Рис. 3.18. Состояние выполнения заявки до присвоения интереса

Напомним, что строка 61 в исходном коде C выполняет побитовую операцию OR с регистром output_en с маской в параметре source. Посмотрите на представление переменных слева: Значение source равно 0x20. Это 100000 в двоичном формате (маска с 1 в бите 5 и 0 в других), что именно то, что нам нужно, чтобы включить выходной буфер для вывода 5 в GPIO0.

Справа у нас есть множество инструкций по сборке, которые реализуют эту простую операцию. Опять же, использование функций для этого может оказаться затратным, поскольку переменные и аргументы должны быть извлечены. Этот заключительный шаг выполняется в 8 командах по сборке RISC-V. Вы сосчитали все команды до этого момента?

Теперь мы подтвердили, что output_en действительно высокоактивен, засвидетельствовав это во время выполнения.

Правда ли нам нужна библиотека Freedom Metal?

Вся структура библиотеки Freedom Metal, которую вы только что видели, может показаться немного избыточной для набора регистров, к которым вы можете получить доступ (в конце концов, output_en находится по адресу 0x10012008), но эта чрезвычайно модульная конструкция создана ради гибкости и переносимости.

Что еще более важно, весь процесс определения местоположения регистров и функций обычно выполняется компилятором один раз. Однако это не относится к библиотеке Freedom Metal, где большинство этих функций встроены и преобразуются компилятором в код на ассемблере.

С другой стороны, это не влечет за собой значительных накладных расходов (в конечном итоге все сводится к нескольким косвенным указаниям и вызовам функций), и конечное приложение в конечном итоге получит наиболее эффективный машинный код, который может создать компилятор.

Итак, суть в том, что вам, вероятно, лучше воспользоваться библиотекой Freedom Metal или любой другой официальной библиотекой, если уж на то пошло.

Тем не менее, давайте подумаем о создании вашего собственного кода на основе того, что мы узнали из руководства пользователя. Мы должны делать это ради максимальной эффективности и нулевой терпимости к накладным расходам.

< Лекция 3 || Лекция 4: 123456 || Лекция 5 >