Почти готово
2012-05-08 20:24Часть 5. Программирование на голом железе и зачатие операционной системы
- Лаба - знакомство с платой chipKit32 / PIC32 / MIPS и программирование её на С с помощью Arduino-подобного GUI. Кнопочки, лампочки, дисплейчик, IO Shield.
- Введение в ассемблер на примере MIPS
- Лаба - загрузка в память программок на ассемблере
- Концепция простейшей многозадачной операционной системы
- Лаба - своя игрушечная многозадачная ОС, которая бутится, ставит обработку прерывания по таймеру, в котором переключает задачи по схеме round-robin.
В качестве среды программирования используется пакет MPIDE фирмы chipKIT. Это бесплатное программное обеспечение, сделанное на основе компилятора GCC и визуальной среды программирования Arduino. Его можно установить под Linux, Windows или Mac OS X. Скачать пакет можно здесь: https://github.com/chipKIT32/chipKIT32-MAX/downloads
Для первых двух примеров используется визуальная среда программирования. В третьем и четвёртом примерах от студентов потребуется умение работать в режиме командной строки и пользоваться командой make.
Загрузка программ на плату Uno32 производится через порт USB с помощью утилиты avrdude, входящей в состав MPIDE. Отдельный программатор не требуется.
5.1. Знакомство с платой Uno32
Лабораторная работа: знакомство с платой Uno32. Процессор PIC32 с архитектурой MIPS32. Простая среда разработки chipKit MPIDE и программирование на С. Подключение кнопочек и семисегментного индикатора с помощью макетной платы. Концепция прерывания.
Необходимое оборудование:
- Плата Uno32
- Адаптер PICkit 3 (начиная с раздела 5.3)
- Компьютер с Linux или Windows
- Кабель mini-USB
- Универсальная макетная плата
- Две кнопки с проводами
- Семисегментный светодиодный индикатор
- Девять резисторов 220 Ом с проводами
Пример 1: управление двумя светодиодами, имеющимися на плате Uno32, с помощью двух внешних кнопок.
Пример 2: управление семисегментным индикатором. Игра “нажми вместе”. При нажатии двух кнопок на индикаторе отображается разность времени нажатия в миллисекундах. Используется аппаратное прерывание от таймера.
Студентам предлагается доработать примеры в некотором направлении. Возможный список задач:
- Сделать счетчик нажатий кнопок. Одна кнопка увеличивает счётчик, другая уменьшает.
- Секундомер. Первая кнопка запускает отсчет. Вторая увеличивает темп в 10 или 100 раз.
- “Электронный кубик” - генератор случайных чисел.
Пример 5.1.1.
Среда MPIDE. Управление двумя светодиодами, имеющимися на плате Uno32, с помощью двух внешних кнопок. Кнопки надо подключить к контактам 11 и 12 по следующей схеме:
Исходные тексты: example5-1-1.pde (просмотреть).
Пример 5.1.2
Среда MPIDE. Управление семисегментным индикатором. Игра “нажми вместе”. При нажатии двух кнопок на индикаторе отображается разность времени нажатия в миллисекундах. Используется аппаратное прерывание от таймера.
Для подключения 7-сегментного индикатора требуются восемь резисторов 220Ом для ограничения тока через светодиоды. Годится любой светодиодный индикатор с общим катодом. Можно с общим анодом, если поменять местами LATxSET и LATxCLR в функции display().
Контакт Uno32 Digital | Сегмент LED | ||
| 2 | A | ||
| 3 | B | ||
| 4 | C | ||
| 5 | D | ||
| 6 | E | ||
| 7 | F | ||
| 8 | G | ||
| 9 | H |
Исходные тексты: example5-1-2.pde (просмотреть).
Так выглядит плата с подключенным индикатором и кнопками:
5.2. Введение в ассемблер MIPS
Организация оперативной памяти, разбиение на слова. Понятие машинной инструкции и счётчика команд. Регистры общего назначения, номера и имена регистров. Передача параметров и возврат значения в регистрах. Регистр адреса возврата. Стек, регистр стека, место в стеке для каждой вызываемой функции (фрейм).
Основные инструкции системы команд MIPS. Разбиение по функциональным группам. Псевдоинструкции LI, LA.
Управление периферийными модулями: таймер, сигналы ввода-вывода. Концепция управляющих регистров, отображаемых на память.
Здесь может быть полезной книжка "MIPS Assembly Language Programming". Минимальное описание ассемблера есть на странице "MIPS Architecture and Assembly Language Overview". Было бы полезно перевести её на русский.
5.3. Практическая работа на ассемблере
Пример: управление двумя светодиодами с помощью двух внешних кнопок. То же, что в разделе 5.1, но на ассемблере.
Для сборки используется утилита make (скачать makefile). В начале файла makefile следует установить путь к каталогу с установленным пакетом MPIDE, например:
MPIDE_DIR = /opt/mpide-0022-linux32-20110822
Для загрузки программы в плату надо вызывать:
sudo make upload
Задание для продвинутых студентов: переписать на ассемблере пример 2 из раздела 5.1.
Пример 5.3
Управление двумя светодиодами с помощью двух внешних кнопок. Тот же, что в разделе 5.1, но на ассемблере.
Исходные тексты: example5-3.zip (просмотреть).
5.4. Концепция многозадачного выполнения
В основе многозадачности лежит стремление к простоте. В примере 5.1.1 нам приходилось обрабатывать всего два входных сигнала (кнопки). Тем не менее, основной цикл программы выглядит неочевидным. В реальных системах микроконтроллеру приходится обрабатывать десятки или даже сотни входных событий. Хороший способ справиться с этим - разбить программу на независимые части меньшего размера, выполняющиеся параллельно, не мешая друг другу. Такие части называют задачами (tasks). В больших операционных системах задачи, выполняющиеся в раздельных адресных пространствах, называются процессами.
Вот как могли бы выглядеть задачи в примере 5.1.1. Намного проще, не правда ли?
void task1()
{
for (;;) {
if (нажата первая кнопка) {
гасим первый светодиод;
delay (150);
}
зажигаем первый светодиод;
delay (150);
}
}
void task2()
{
for (;;) {
if (нажата вторая кнопка) {
гасим второй светодиод;
delay (150);
}
зажигаем второй светодиод;
delay (150);
}
}
Хотелось бы иметь возможность запускать на одном процессоре несколько задач, но чтобы они оставались независимыми и не мешали друг другу. Для этого нам понадобятся два новых понятия:
- Контекст выполнения
- Прерывания
Контекстом выполнения называется содержимое регистров процессора и стека выполняемой задачи. Ход программы полностью определяется контекстом выполнения. Если бы мы смогли в какой-то момент остановить процессор, запомнить куда-нибудь значения всех регистров (а указатель стека тоже находится в регистре), установить новые значения для регистров и пустить выполнение дальше, мы получили бы совсем другую задачу. Такое действие называется переключением контекста.
Если переключать контекст достаточно быстро, например 1000 раз в секунду, будет создаваться впечатление параллельного и одновременного выполнения всех задач. Скажем, 1 миллисекунду работает первая задача, потом 1 миллисекунду вторая, и дальше по кругу. Такой алгоритм распределения процессорного времени обычно называют циклическим (round robin). В больших операционных системах применяются и другие алгоритмы, более сложные.
Прерывания это особый механизм, посредством которого процессор приостанавливает выполнение текущей программы, и совершает необходимые срочные действия. При этом управление передаётся на специальный фиксированный адрес, по которому расположена функция обработки прерывания. После её завершения происходит выход из прерывания, и выполнение программы продолжается. Для обработки прерываний в процессоре есть специальные регистры (EPC, Status) и инструкции (ERET, EI, DI).
Для получения периодических прерываний в процессоре MIPS есть два 32-битных регистра: Count и Compare. Регистр Count - это счётчик, который растет с фиксированной частотой, в нашем случае 40 МГц. Когда значение Count становится равным регистру Compare, возникает прерывание с номером 0 и происходит переход по адресу 0x9d000200. Старое значение счетчика команд PC прерванной программы заносится в специальный регистр EPC. В регистре Status устанавливается бит EXL, блокирующий обработку других прерываний (если они возникнут). Дальше начинает выполняться функция обработки прерывания. В нашем примере она записывает значения всех регистров (контекст) в стек прерванной задачи, переключает регистр стека на другую задачу, восстанавливает все регистры из стека, и выполняет инструкцию ERET. Это специальная команда, которая снимает бит EXL регистра Status (этим разблокируя прерывания) и пересылает значение регистра EPC в счетчик команд PC. Продолжается выполнение новой задачи, до следующего прерывания.
Вот как выглядит стек при обработке прерывания:
Вопрос на засыпку: почему не нужно сохранять и восстанавливать регистры $26, $27, $28, $29?
5.5. Пример реализации многозадачности
Переключение двух задач по таймеру. Исходные тексты расположены в двух файлах:
- example5-5.c — основная программа на языке Си.
- timer-interrupt.S — функция обработки прерывания на ассемблере. Сохраняет и восстанавливает контекст выполнения в стеке. Для управления таймером и переключения задач вызывает функцию на языке Си.
Исходные тексты: example5-5.zip (просмотреть).
Задание для продвинутых студентов: обобщить пример для произвольного количества задач.
Задание для особо продвинутых студентов: реализовать механизм взаимодействия задач. На выбор: семафоры, мьютексы, рандеву, мониторы, передача сообщений.
Рекомендуемая литература для дальнейшего развития темы:
Д.В.Иртегов, "Введение в операционные системы"
Э.Таненбаум, "Современные операционные системы"


no subject
Date: 2012-05-09 06:25 (UTC)hack
Date: 2012-05-09 07:07 (UTC)no subject
Date: 2012-05-09 11:04 (UTC)С Днем Победы! В XXI веке противником России будет не Гер
Date: 2012-05-10 05:36 (UTC)С Днем Победы! В XXI веке противником России будет не Гер
Date: 2012-05-10 06:04 (UTC)Летняя школа по основам мехатроники
Date: 2012-07-09 22:35 (UTC)Подготовка к лабораторным работам с промышленной реал
Date: 2013-04-07 23:40 (UTC)