читать дальшеНо есть ещё одна очень нужная штука в ОС: критические секции.
Бывают такие места в коде, которые ну никак прерывать нельзя. Ну или нежелательно.
Пока у меня таких мест нет, но всё бывает. Для поддержки такой функциональности введены две процедуры:
Принцип их прост: при начале секции отключается системный таймер, а при конце включается. При этом не должно происходить смены контекста, что даёт уверенность, что обработка критичных данных (которые используются и конкурирующими процессами) пройдёт нормально. И никто никому не помешает и не затрёт результат его деятельности.
А то как бывает... Есть код:
читать содержимое переменной X в регистр А.
изменить содержимое регистра А (например, выставить бит)
записать значение регистра А в переменную Х.
При этом, если процессов с подобным два или больше, возникает опасность гонки:
ПРОЦ1: ляляля
ПРОЦ1: читать содержимое переменной Х (0x10, например)
ПРОЦ1: выставить флаг (0x12)
ЯДРО: смена контекста на ПРОЦ2
ПРОЦ2: ляляля
ПРОЦ2: читать содержимое переменной Х (всё те же 0x10, не успели записать изменённое)
ПРОЦ2: выставить флаг (0x14)
ПРОЦ2: записать содержимое переменной Х (теперь там 0x14)
ПРОЦ2: ляляля
ЯДРО: смена контекста на ПРОЦ1
ПРОЦ1: записать содержимое переменной Х (теперь там 0x12), а флаг 0x04 потерялся. Затёрли его.
ПРОЦ1: ляляля
...
Использование критических секций предотвращает подобное поведение.
Из железного... Отключение прерываний (TICKINT) не предотвращает появления ещё одного, последнего прерывания, когда таймер досчитает до нуля. Не знаю почему так, пока что я не разобрался.
ПРЕДУПРЕЖДЕНИЕ! В данной версии проекта есть ещё возможность залипнуть из-за критической секции: системный таймер может успеть досчитать к моменту его выключения, выставить флаг и отправить прерывание на обработку. Ну нет такой штуки в контроллере, которая прерывание таймера бы намертво заглушила сразу и навсегда .з. Потому я в следующих версиях добавил проверку на выключенность системного таймера прямо в процедуре переключения контекстов!
Для этого сделана простенькая процедура SysTickInterruptEnable. Пока что так.
Конечно, если секция длиннющая, то все тайминги процессов и задержек поползут. Но секции такие в принципе должны быть как можно короче.
Что ещё поменялось? При входе в прерывание остальные прерывания запрещаются.
Есть такая полезная инструкция CPS (Change Processor State). Раньше флаг глобального разрешения прерываний хранился в регистре CPSR и требовалось его считать, установить и записать (Команды MSR, MRS). Теперь всё делается за одну команду.
Аналоги оных функций на АВР: sei и cli.
Проект тот же самый. Только доавился ещё один процесс и код события. Новый процесс опрашивает акселерометр (в критической секции) и считает вектор ускорения. Если он превышает заданный предел, то генерируется событие "Перегрузка": INPUT_ACCEL_ONSHOCK.
И процесс моргательный моргает сразу почти всеми светодиодами. За исключением второго, который моргает с разной частотой в зависимости от показаний акселерометра по оси Z. Чем больше намеряно, тем реже моргает.
Функции LedOn и LedOff тоже поменялись в угоду скорости: теперь передаётся в них маска. То есть младшие 4 бита определяют, какие светодиоды гасим или зажигаем.
Ещё поменянна файловая структура проекта для удобства. Все файлы исходного кода помещены в папку source, а компиляция осуществляется в папку build. Внутри проекта тоже файлы разделены по категориям:
1. NyaOS. Файлы, относящиеся к ОС;
2. Main. Файлы запуска контроллера и файл main.c;
3. Drivers. Файлы для работы с периферией: светодиоды, SPI и акселерометр.
Файлы не прикладываю, там особых изменений нет.
Проект целиком.
<< Предыдущее Следующее >>
@темы: arm, программизмы, электроника, ассемблер, stm32f4discovery, stm32