- •Глава 1. Сведения о компиляторе
- •1.1.Введение
- •1.2. Основные вопросы
- •1.3. Описание компилятора и документация
- •1.4. Компилятор и другие средства разработки
- •1.5. Набор возможностей компилятора
- •1.5.1. Стандарт ANSI Си
- •1.5.2. Оптимизация
- •1.5.3. Поддержка стандартной ANSI библиотеки
- •1.5.4. Гибкие модели памяти
- •1.5.5. Драйвер компилятора
- •Глава 2. Отличия 16-битового компилятора от ANSI
- •2.1. Введение
- •2.2. Основные вопросы
- •2.3. Отличия ключевых слов
- •2.3.1. Определение атрибутов переменных
- •2.3.2. Определение атрибутов функций
- •2.3.3. Inline функции
- •2.3.4. Переменные в определенных регистрах
- •2.3.4.1. Определение глобальных регистровых переменных
- •2.3.4.2. Определение локальных регистровых переменных
- •2.3.5. Комплексные числа
- •2.3.6. Целые размером в двойное слово
- •2.3.7. Ссылки на тип с помощью typeof
- •2.4. Отличия операторов
- •2.4.1. Метки как значения
- •2.4.2. Условные операторы с опущенными операндами
- •2.4.3. Диапазоны case
- •2.5. Отличия выражений
- •2.5.1. Двоичные константы
- •Глава 3. Использование компилятора в командной строке
- •3.1. Введение
- •3.2. Основные вопросы
- •3.3. Обзор
- •3.4. Соглашение для имен файлов
- •3.5. Опции
- •3.5.1. Опции, специфические для устройств dsPIC
- •3.5.2. Опции для управления типом результатов
- •3.5.3. Опции для управления диалектом Cи
- •3.5.5. Опции для отладки
- •3.5.6. Опции для управления оптимизацией
- •3.5.7. Опции для управления препроцессором
- •3.5.8. Опции для ассемблера
- •3.5.9. Опции для компоновщика
- •3.5.10. Опции для поиска в каталогах
- •3.5.11. Опции для соглашений по генерации кода
- •3.6. Переменные окружения
- •3.7. Предопределенные имена макро
- •3.9. Компиляция нескольких файлов в командной строке
- •3.10. Особенные символы
- •Глава 4. Среда периода исполнения
- •4.1. Введение
- •4.2. Основные вопросы
- •4.3. Адресное пространство
- •4.4. Запуск и инициализация
- •4.5. Пространства памяти
- •4.6. Модели памяти
- •4.6.1. Ближние и дальние данные
- •4.6.2. Ближний и дальний код
- •4.7. Расположение кода и данных
- •4.8. Программный стек
- •4.9. Использование стека в Си
- •4.11. Соглашения по вызову функций
- •4.11.1. Параметры функции
- •4.11.2. Возвращаемое значение
- •4.12. Соглашения о регистрах
- •4.13. Двоичная инверсия и модульная адресация
- •4.14.1. Загрузочные и защищенные константы
- •4.14.2. Строковые константы как аргументы
- •4.14.3. Переменные с квалификатором const в безопасной Flash
- •4.14.4. Модель совместимости объектов
- •Глава 5. Типы данных
- •5.1. Введение
- •5.2. Основные вопросы
- •5.3. Представление данных
- •5.4. Целые
- •5.5. С плавающей точкой
- •5.6. Указатели
- •Глава 6. Дополнительные типы указателей Си
- •6.1. Введение
- •6.2. Управляющие PSV указатели
- •6.2.1. Определение данных для управления доступом PSV
- •6.2.2. Управляемый доступ PSV
- •6.2.3. Рассмотрение ISR
- •6.3. PMP указатели
- •6.3.1. Инициализация PMP
- •6.3.2. Объявление нового пространства памяти
- •6.3.3. Определение переменных в пространстве PMP
- •6.4. Внешние указатели
- •6.4.1. Объявление нового пространства памяти
- •6.4.2. Определение переменных во внешнем пространстве
- •6.4.3. Определение способа доступа к пространству памяти
- •6.4.3.2. Функции записи
- •6.4.4. Пример внешней памяти
- •Глава 7. Файлы поддержки устройства
- •7.1. Введение
- •7.2. Основные вопросы
- •7.3. Файлы заголовков процессора
- •7.4. Файлы определения регистров
- •7.5. Использование SFR
- •7.6. Использование макросов
- •7.6.1. Макросы настройки битов конфигурации
- •7.6.2. Макросы использования ассемблера inline
- •7.6.3. Макросы выделения памяти данных
- •7.6.4. Макросы объявления ISR
- •7.7. Адресация EEDATA из Си - только для dsPIC30F
- •7.7.1. Доступ к EEDATA через PSV
- •7.7.2. Доступ к EEDATA посредством команд TBLRDx
- •7.7.3. Дополнительные источники информации
- •Глава 8. Прерывания
- •8.1. Введение
- •8.2. Основные вопросы
- •8.3. Написание программы обработки прерывания
- •8.3.1. Рекомендации по написанию ISR
- •8.3.3. Кодирование ISR
- •8.3.4. Использование макросов для объявления простых ISR
- •8.4. Запись вектора прерывания
- •8.4.1. Вектора прерываний dsPIC30F (без SMPS)
- •8.4.3. Вектора прерываний PIC24F
- •8.4.4. Вектора прерываний dsPIC33F/PIC24H
- •8.5. Сохранение контекста в ISR
- •8.7. Вложенные прерывания
- •8.8. Разрешение/запрещение прерываний
- •8.9. Разделение памяти между основной программой и ISR
- •8.9.1. Разработка проблем
- •8.9.2. Разработка решений
- •8.9.3. Пример приложения
- •8.10. Использование PSV в ISR
- •Глава 9. Совместное использование ассемблера и Си
- •9.1. Введение
- •9.2. Основные вопросы
- •9.3. Смесь переменных и функций на ассемблере и Си
- •9.4. Использование ассемблера inline
- •Приложение A. Определяемое реализацией поведение
- •A.12. Квалификаторы
- •A.13. Деклараторы
- •A.14. Операторы
- •A.17. Сигналы
- •A.18. Потоки и файлы
- •A.20. Errno
- •A.22. Abort
- •A.23. Exit
- •A.24. Getenv
- •A.25. Система
- •A.26. Strerror
- •Приложение B. Встроенные функции
- •B.2. Список встроенных функций
- •Приложение C. Диагностика
- •Приложение D. Компиляторы Си PIC18 и PIC24/dsPIC
- •D.6. Использование стека
- •D.11. Банк доступа
- •D.12. Inline ассемблер
- •D.13. Прагмы
- •D.14. Модели памяти
- •D.15. Соглашения о вызове
- •D.16. Код запуска
- •D.17. Управляемые компилятором ресурсы
- •D.18. Оптимизация
- •D.20. Определяемое реализацией поведение
- •D.21. Битовые поля
Глава 8. Прерывания
void foo(void) {
int current_cpu_ipl;
SET_AND_SAVE_CPU_IPL(current_cpu_ipl,7); /* запрет прерываний с приоритетом ниже 7 */
/* здесь защищенный код */ RESTORE_CPU_IPL(current_cpu_ipl);
}
8.9.Разделение памяти между основной программой и ISR
Следует проявить осторожность при модификации одной и той же переменной в |
|
пределах основной программы или низкоприоритетной ISR и высокоприоритетной |
|
A |
создает многокомандную |
ISR. Когда функция с низким приоритетом. |
последовательность чтение-модификация-запись, то прерывания с более высоким приоритетом, будучи разрешены, могут прервать ее, что даст неожиданные результаты при доступе к той жеWilsonпеременной. Следовательно, встроенные системы должны применять атомарные операции для предотвращения вмешательства высокоприоритетных ISR, записывающих информацию в ту же переменную, из которой низкоприоритетная ISR уже прочитала, а записать еще не успела.
Атомарная операция — та, которая не может быть разбита на составные части, т.е. не может быть прервана. В зависимости от конкретных особенностей архитектуры, не все выражения Cи переводятся в атомарные операции. В устройствах dsPIC, эти выражения главным образом подразделяются на следующие категории: 32-битовые выражения, арифметика с плавающей точкой, деление и операции над многобитовыми полями битов. На то, будет ли сгенерирована атомарная операция или нет, влияют и другие факторы,by как например, установки модели памяти, уровень оптимизации и доступность ресурсов.
Рассмотрим обычное выражение:
Оператор (op) может быть или не быть атомарным, в зависимости от архитектуры устройства. Так или иначе, компилятор может быть не способен сгенерировать атомарную операцию во всех случаях — это будет сильно зависеть от нескольких причин:
• наличие подходящей атомарной машинной команды
• доступность ресурса — специальные регистры или другие ограничения
• уровень оптимизации и другие опции, которые влияют на размещение данных и кода
Без знания архитектуры разумно предположить, что обычное выражение требует двух операций чтения, по одной на каждый операнд, и одной операции записи для сохранения результата. Некоторые трудности могут возникнуть в присутствии последовательностей прерываний, это сильно зависит от конкретного приложения.
8.9.1. Разработка проблем
Translatedfoo = bar op baz;
Вот некоторые примеры:
ПРИМЕР 8-1. BAR ДОЛЖНА СООТВЕТСТВОВАТЬ BAZ
Если требуется, чтобы bar и baz соответствовали, (т.е. обновлялись синхронно друг другу), есть возможный риск, когда bar или baz может быть скорректирована выражением в пределах прерывания с более высоким приоритетом. Вот некоторые примеры последовательности событий:
1.Безопасный: чтение bar чтение baz
© 2008 Microchip Technology Inc. |
DS51284H(ru) стр. 8-15 |
16-битовый компилятор Си. Руководство
выполнение операции запись результата в foo
2. Небезопасный: чтение bar
прерывание модифицирует baz
чтение baz выполнение операции
запись результата в foo
3. Безопасный: |
|
. |
чтение bar |
|
|
|
A |
|
чтение baz |
|
|
прерывание модифицирует bar или baz |
||
выполнение операции |
Wilson |
|
запись результата в foo |
|
|
|
|
Первая ситуация безопасна, поскольку прерывание происходит за пределами выражения. Вторая — небезопасна, поскольку приложение требует, чтобы bar и baz корректировалась синхронно друг с другом. Третья — вероятно безопасна, foo возможно будет получать старую величину, но она будет соответствовать данным, которые были доступны в начале вычисления выражения.
ПРИМЕР 8-2. ТИП FOO, BAR И BAZ
Другая разновидность происходит от типов foo, bar и baz. Операции «чтение bar», «чтение baz» или «запись результата в foo» могут не быть атомарными в зависимости от архитектурыby целевого процессора. Например, устройства dsPIC могут прочитать или записать 8-битовую, 16-битовую или 32-битовую величину одной командой (атомарно). Но 32-битовое значение может потребовать две команды в зависимости от выбора команд (который в свою очередь будет зависеть от
данным. Тогда доступ становится таким:
оптимизацииTranslatedи установленных параметров модели памяти). Предположим, что типы данных long и компилятор не может выбирать атомарные операции для доступа к
чтение младшего слова bar чтение старшего слова bar чтение младшего слова baz чтение старшего слова baz
выполнение операции (над младшим и старшим словами) запись младшего слова результата в foo
запись старшего слова результата в foo
Здесь появляется масса возможностей, когда обновление bar или baz приводит к непредсказуемым результатам.
ПРИМЕР 8-3. БИТОВЫЕ ПОЛЯ
Третья причина для беспокойства — битовые поля. Cи допускает распределение памяти на битовом уровне, но не определяет какие-либо битовые операции. В буквальном смысле, любая операция на битом будет рассматриваться, как операция над основным типом битового поля, и обычно будет требовать операции извлечения поля из bar и baz или вставки поля в foo. Следует отметить важное соображение, что (опять же в зависимости от архитектуры команд, уровня оптимизации и настроек памяти) прерываемая программа, которая пишет в любую часть битового поля, где располагается foo, может быть ненадежной. Это особенно явно в случае, когда один из операндов также является приемником.
Набор команд dsPIC может оперировать над 1 битом атомарно. Компилятор может выбрать эти команды в зависимости от уровня оптимизации, установочных параметров памяти и доступности ресурсов.
DS51284H(ru) стр. 8-16 |
© 2008 Microchip Technology Inc. |
Глава 8. Прерывания
ПРИМЕР 8-4. КЭШИРОВАНИЕ ЗНАЧЕНИЙ ПАМЯТИ В РЕГИСТРАХ
Наконец, компилятор может выбрать кеширование величин из памяти в регистрах. Они часто называются регистровыми переменными и являются особенно уязвимыми для повреждения прерыванием, даже тогда, когда операция с участием переменной не прервана. Убедитесь, что ресурсы памяти, разделяемые между ISR и прерываемой функцией определены как volatile. Этим вы сообщите компилятору, что ячейка памяти может быть скорректирована извне кодовой последовательности. Это не защитит против эффекта неатомарных операций, но является все же важным.
8.9.2. Разработка решений |
|
Здесь приведено несколько стратегий для снижения потенциальных рисков: |
|
|
. |
• Разрабатывайте программную систему так, чтобыA конфликтующие события не могли произойти. Не разделяйте память между ISR и другими функциями. Делайте ISR по возможности простыми и переносите реальную работу в основной код.
•Будьте аккуратны при разделении памяти и, если возможно, избегайте разделения битовых полей, содержащих много битов.
•Защищайте не атомарное обновление разделяемой памяти от прерываний, как вы должны защищать критические участки кода. Для этого может использоваться следующий макрос:
#define INTERRUPT_PROTECT(x) { |
\ |
|
char saved_ipl; |
Wilson |
\ |
|
\ |
|
|
|
|
SET_AND_SAVE_CPU IPL(saved_ipl,7); |
\ |
|
x; |
|
\ |
RESTORE_CPU_IPL(saved_ipl); } |
|
|
|
by |
|
Этот макрос запрещает все прерывания с приоритетом ниже 7 путем подъема уровняTranslatedприоритета процессора до 7, исполняет необходимые действия, а затем восстанавливает предыдущий уровень приоритета.
8.9.3. Пример приложения
Следующий пример иллюстрирует некоторые аспекты, обсужденные в данном подразделе:
void attribute__((interrupt)) HigherPriorityInterrupt(void) { /* Здесь код пользователя */
LATGbits.LATG15 = 1; /* Установка бита 15 LATG */ IPC0bits.INT0IP = 2; /* Смена 0 уровня приоритета на 2
(используется несколько битов) */
}
int main(void) {
/* Еще код пользователя */
LATGbits.LATG10 ^= 1; /* Потенциальный РИСК — Сначала LATG читается в W, выполняется операция XOR,
затем результат пишется в LATG */
LATG = 0x1238; /* Проблем не возникнет, это просто запись в операции присваивания */
LATGbits.LATG5 = 1; /* Вероятно, проблем не будет,
это просто присваивание одного бита, которое будет выполнено единственной
командой установки бита */
© 2008 Microchip Technology Inc. |
DS51284H(ru) стр. 8-17 |