From 32e2fbedc0903d95c3af429f7645eb1ac6f3d99f Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 12 Oct 2026 12:25:52 +0300 Subject: [PATCH 01/18] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B0=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B5=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8?= =?UTF-8?q?=20=D0=BB=D0=BE=D0=B3=D0=B3=D0=B5=D1=80=D0=B0=20=D0=A3=D0=9C?= =?UTF-8?q?=D0=9F=20v4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Разрешить 12-словные записи в запросах RTU и CAN. Распознавать статус v4 и декодировать оставшиеся сигналы с сохранением поддержки архивов v2/v3. --- c/set-protocol/src/ump_protocol.c | 3 +- python/set_devices/ump_logger.py | 99 +++++++++++----------------- python/set_devices/ump_logger_can.py | 3 +- 3 files changed, 41 insertions(+), 64 deletions(-) diff --git a/c/set-protocol/src/ump_protocol.c b/c/set-protocol/src/ump_protocol.c index 0aaf7e9..e4e3cc2 100644 --- a/c/set-protocol/src/ump_protocol.c +++ b/c/set-protocol/src/ump_protocol.c @@ -18,7 +18,8 @@ unsigned ump_validate(unsigned fn, uint16_t a, uint16_t n, int can) return can ? ((a == UMP_FIRMWARE_INFO && n == UMP_FIRMWARE_INFO_WORDS) ? 0 : 2) : ((n && n <= UMP_FIRMWARE_INFO + UMP_FIRMWARE_INFO_WORDS - a) ? 0 : 2); if (can) return ((a == UMP_BASE && n == 16) || - (a == UMP_DATA && (n == 40 || n == 80 || n == 120 || n == 42 || n == 84)) || + /* Разрешает целые 12-словные записи v4 до 120 слов; размеры v2/v3 сохраняются для прежних устройств. */ + (a == UMP_DATA && (n == 40 || n == 80 || n == 42 || n == 84 || (n && n <= 120 && !(n % 12U)))) || (a == UMP_LIVE && n == 124)) ? 0 : 2; if (!n || n > 125) return 2; return ((a >= UMP_BASE && a < UMP_BASE+16 && n <= UMP_BASE+16-a) || diff --git a/python/set_devices/ump_logger.py b/python/set_devices/ump_logger.py index def1a43..dd5e312 100644 --- a/python/set_devices/ump_logger.py +++ b/python/set_devices/ump_logger.py @@ -22,6 +22,12 @@ FAST_CAPABILITY = 0x1220 FAST_DATA = 0x2000 WORDS = 40 CAPACITY = 64000 // (2 * WORDS) +# Компактная запись v4 имеет 12 слов; старые 40/42 слова остаются поддержанными для чтения архивов. +COMPACT_WORDS = 12 +# Ёмкость 760 точек сохраняет прежнее число записей постинтервала и поведение кольцевых банков. +COMPACT_CAPACITY = 760 +# Ключи соответствуют индексам оставшихся полей v2/v3, значения — индексам этих же каналов в компактном v4. +COMPACT_INDEX = {2: 2, 3: 3, 4: 4, 5: 5, 9: 6, 24: 7, 25: 8, 40: 9, 41: 10} FIELDS = ( ('off_trigger', 'Событие отключения', 2, 8), ('post_truncated', 'Усечение постинтервала', 2, 9), @@ -33,68 +39,37 @@ FIELDS = ( ('start_out', 'Выход START_DPTB', 5, 0), ('stop_out', 'Выход STOP_DPTB', 5, 1), ('res_out', 'Выход RES_OUT_2', 5, 2), - ('impulse', 'Остаток импульса, мс', 6, None), - ('wake', 'Инициализация ЦАП, тики ЦАП', 7, None), - ('dac', 'Код ЦАП', 8, None), ('current', 'Расчётное задание тока, мА', 9, None), - ('sensor0', 'Измерение 0', 10, None), - ('sensor1', 'Измерение 1', 11, None), - ('sensor2', 'Измерение 2', 12, None), - ('sensor3', 'Измерение 3', 13, None), - ('error0', 'Ошибки 0 (маска)', 14, None), - ('error1', 'Ошибки 1 (маска)', 15, None), - ('error2', 'Ошибки 2 (маска)', 16, None), - ('error3', 'Ошибки 3 (маска)', 17, None), - ('can_header', 'CAN адрес/маска', 18, None), - ('can0', 'CAN слово 0', 19, None), - ('can1', 'CAN слово 1', 20, None), - ('can2', 'CAN слово 2', 21, None), - ('can_count', 'Количество CAN RX (mod 65536)', 22, None), - ('can_timeout', 'Таймауты CAN TX (mod 65536)', 23, None), - ('commands', 'Команды (маска)', 3, None), ('go', 'Начальная уставка, мА', 24, None), ('stop', 'Конечная уставка, мА', 25, None), - ('dac_min', 'Код калибровки 4 мА', 26, None), - ('dac_max', 'Код калибровки 20 мА', 27, None), - ('dac_cal', 'Калибровочный код ЦАП', 28, None), - ('dac04', 'DAC_04 (регистр)', 29, None), - ('dac20', 'DAC_20 (регистр)', 30, None), - ('ramp', 'Счётчик разгона', 31, None), - ('duration', 'Длительность разгона, тики ЦАП', 32, None), - ('effective_go', 'Начальная уставка после ограничений, мА', 33, None), - ('effective_stop', 'Конечная уставка после ограничений, мА', 34, None), - ('position', 'Положение разгона (kod)', 35, None), - ('adc0', 'АЦП канал 0', 36, None), - ('adc1', 'АЦП канал 1', 37, None), - ('adc2', 'АЦП канал 2', 38, None), - ('adc3', 'АЦП канал 3', 39, None), ('zpt1', 'ЗПТ1: U1 + U2 (ПМ67, рег. 306)', 40, None), ('zpt2', 'ЗПТ2: U3 + U4 (ПМ67, рег. 9)', 41, None), ) -def request(controller: int, function: int, address: int, value: int, *, record_words: int = WORDS) -> bytes: - if not 0 <= controller <= 255 or not 0 <= value <= 65535: - raise ValueError('Недопустимый адрес контроллера или значение') - if record_words not in (40, 42): - raise ValueError('Неверный размер записи логгера') - capacity = {40: 800, 42: 760}[record_words] - if function == 3: - valid = ((address == PROTECTION and value == 8) or (address == BASE and value == 16) or - (address == DATA and 1 <= value <= 120 and (value % WORDS == 0 or value in (42, 84))) or (address == LIVE and value == 124) or (address == EMU_CONTROL and value == 4) - or (address == FAST_CAPABILITY and value == 4) - or (FAST_DATA <= address < FAST_DATA + capacity * record_words - and (address - FAST_DATA) % record_words == 0 - and 1 <= value <= 120 and value % record_words == 0 - and address + value <= FAST_DATA + capacity * record_words)) - else: - valid = function == 6 and ((address == PROTECTION + 2 and value in (0, 1, 2, 3)) or - (address == PROTECTION + 3 and 1 <= value <= 60000) or - address in (BASE, BASE + 1, BASE + 2, BASE + 3) or - (address == EMU_CONTROL + 2 and value in (0, 1))) - if not valid: - raise ValueError('Недопустимый запрос логгера УМП') - return protocol.with_crc(bytes((controller, function)) + address.to_bytes(2, 'big') + value.to_bytes(2, 'big')) +def request(controller: int, function: int, address: int, value: int, *, record_words: int = WORDS) -> bytes: # Проверяет запрос с учётом ширины записи, прочитанной из статуса платы. + if not 0 <= controller <= 255 or not 0 <= value <= 65535: # Ограничивает адрес одним октетом, значение — 16-битным словом. + raise ValueError('Недопустимый адрес контроллера или значение') # Запрещает усечение входных параметров при упаковке. + if record_words not in (COMPACT_WORDS, 40, 42): # Допускает только известные компактный и прежние форматы записи. + raise ValueError('Неверный размер записи логгера') # Не позволяет строить адреса по неизвестной ширине. + capacity = {COMPACT_WORDS: COMPACT_CAPACITY, 40: 800, 42: 760}[record_words] # Выбирает реальную границу банка по формату. + if function == 3: # Разрешает только существующие диагностические блоки чтения. + valid = ((address == PROTECTION and value == 8) or (address == BASE and value == 16) # Читает полный блок защиты либо дескриптор журнала. + or (address == DATA and 1 <= value <= 120 and (value % COMPACT_WORDS == 0 or value in (40, 80, 42, 84))) # Принимает целые записи v4 и исторические блоки v2/v3. + or (address == LIVE and value == 124) or (address == EMU_CONTROL and value == 4) # Сохраняет фиксированные размеры онлайн-блока и управления эмуляцией. + or (address == FAST_CAPABILITY and value == 4) # Проверяет возможность ускоренного архивного чтения. + or (FAST_DATA <= address < FAST_DATA + capacity * record_words # Ограничивает адрес началом и концом реального банка. + and (address - FAST_DATA) % record_words == 0 # Требует начала блока на границе записи. + and 1 <= value <= 120 and value % record_words == 0 # Передаёт до 120 слов, содержащих целое число записей. + and address + value <= FAST_DATA + capacity * record_words)) # Исключает пересечение конца банка. + else: # Запись разрешена только прежним управляющим адресам. + valid = function == 6 and ((address == PROTECTION + 2 and value in (0, 1, 2, 3)) # Проверяет маску эмуляции защиты. + or (address == PROTECTION + 3 and 1 <= value <= 60000) # Проверяет тайм-аут свежести CAN в миллисекундах. + or address in (BASE, BASE + 1, BASE + 2, BASE + 3) # Оставляет команды управления журналом без запуска УМП. + or (address == EMU_CONTROL + 2 and value in (0, 1))) # Сохраняет двоичное включение эмулятора. + if not valid: # Запрещает запросы вне согласованных адресов и размеров. + raise ValueError('Недопустимый запрос логгера УМП') # Возвращает прежнее понятное сообщение вызывающему коду. + return protocol.with_crc(bytes((controller, function)) + address.to_bytes(2, 'big') + value.to_bytes(2, 'big')) # Передаёт 16-битный адрес и добавляет общий Modbus CRC. @dataclass(frozen=True) @@ -114,27 +89,27 @@ class Status: @classmethod def decode(cls, words): if (len(words) != 16 or words[0] != 0x554D or - (words[1], words[4], words[5]) not in ((2, 40, 800), (3, 42, 760))): - raise ValueError('Прошивка не поддерживает логгер УМП v2/v3') + (words[1], words[4], words[5]) not in ((2, 40, 800), (3, 42, 760), (4, COMPACT_WORDS, COMPACT_CAPACITY))): # Проверяет согласованные версию, ширину и ёмкость. + raise ValueError('Прошивка не поддерживает логгер УМП v2/v3/v4') # Перечисляет известные форматы без разрешения неизвестной прошивки. if words[9] != 6: raise ValueError('Логгер УМП доступен только на плате нагрузки dsk_LOAD') - if words[2] not in (0, 1, 2, 3) or words[3] > words[5] or not 1 <= words[6] <= 1000 or words[11] != 1000 or words[13] > words[5] or words[14] > 1000 or words[15] not in (0, 1, 3): + post_limit = max(1000, min(65535, words[5] // 10 * words[6])) if words[1] >= 3 else 1000 # Постинтервал v3/v4 занимает 10% точек; при 760 точках и 20 мс его оценка достигает 1520 мс. + if words[2] not in (0, 1, 2, 3) or words[3] > words[5] or not 1 <= words[6] <= 1000 or words[11] != 1000 or words[13] > words[5] or words[14] > post_limit or words[15] not in (0, 1, 3): raise ValueError('Повреждён статус логгера') return cls(words[2], words[3], words[6], words[10], words[11], *words[12:16], words[4], words[5]) def sample(words, frequency=1000): - if len(words) not in (40, 42) or frequency <= 0: + if len(words) not in (COMPACT_WORDS, 40, 42) or frequency <= 0: # Допускает только известную ширину записи и положительную частоту времени. raise ValueError('Неверная запись логгера') result = {'time_ms': (words[0] | words[1] << 16) * 1000 / frequency, 'event': words[2]} for key, _label, index, bit in FIELDS: - value = words[index] if index < len(words) else float('nan') + physical_index = COMPACT_INDEX[index] if len(words) == COMPACT_WORDS else index # Выбирает индекс оставшегося поля по фактической версии записи. + value = words[physical_index] if physical_index < len(words) else float('nan') # ЗПТ в старых 40-словных архивах остаётся неизвестным. if bit is not None: value = (value >> bit) & 1 - elif 10 <= index <= 13 and value >= 32768: - value -= 65536 # Физические единицы приводим здесь, одинаково для CSV и графика. - if key in ('current', 'effective_go', 'effective_stop'): + if key == 'current': # Сохранившееся задание имеет масштаб 0,1 мА; уставки и напряжения передаются целыми единицами. value /= 10.0 result[key] = value return result diff --git a/python/set_devices/ump_logger_can.py b/python/set_devices/ump_logger_can.py index 6e23c5e..902de20 100644 --- a/python/set_devices/ump_logger_can.py +++ b/python/set_devices/ump_logger_can.py @@ -27,7 +27,8 @@ def build_request(mode, token, function, address, value): if not 1 <= token <= 255: raise ValueError('Неверный номер CAN-запроса') valid = ((function == 3 and ((address == PROTECTION and value == 8) or (address == BASE and value == 16) or - (address == DATA and value in (40, 80, 120, 42, 84)) or + # До 120 слов передают целые 12-словные записи v4; старые блоки v2/v3 остаются разрешены. + (address == DATA and (value in (40, 80, 42, 84) or 0 < value <= 120 and value % 12 == 0)) or (address == LIVE and value == MAX_WORDS) or (address == EMU_CONTROL and value == 4))) or (function == 6 and ((BASE <= address <= BASE+3 and 0 <= value <= 65535) or (address == PROTECTION+2 and value in (0, 1, 2, 3)) or From cf65439400450a1345217485628b6d0fe468a7f4 Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 17 Oct 2026 14:43:11 +0300 Subject: [PATCH 02/18] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B2=D1=8B=D0=BF=D1=83=D1=81=D0=BA=20=D0=B8=20?= =?UTF-8?q?=D1=8D=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82=20Flash-=D0=BE=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=BE=D0=B2=20C2000?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/firmware-info/tests/test_c2000_postbuild.py | 87 ++++++++++ c/firmware-info/tools/c2000_postbuild.py | 40 ++++- tools/firmware-build/README.md | 158 ++++++++++++++++-- 3 files changed, 269 insertions(+), 16 deletions(-) create mode 100644 c/firmware-info/tests/test_c2000_postbuild.py diff --git a/c/firmware-info/tests/test_c2000_postbuild.py b/c/firmware-info/tests/test_c2000_postbuild.py new file mode 100644 index 0000000..9a2809f --- /dev/null +++ b/c/firmware-info/tests/test_c2000_postbuild.py @@ -0,0 +1,87 @@ +"""Проверяет совместимость postbuild, экспорт двух образов и отказ от устаревшего Flash OUT.""" # Фиксирует контракт общего выпуска без зависимости от установленного TI-компилятора. +import json # Формирует паспорт текущей сборки для проверки архива и контрольных сумм. +from pathlib import Path # Создаёт независимые пути проекта, компилятора и результатов в каждом тесте. +import subprocess # Использует штатное исключение ненулевого кода проектного сборщика. +import sys # Подключает общий модуль из каталога tools текущей копии templates. +import tempfile # Изолирует проверочные файлы от реальных прошивок и каталогов GUI. +import unittest # Организует проверки публичного контракта postbuild стандартной библиотекой Python. +from unittest.mock import patch # Подменяет только внешние инструменты, оставляя настоящее архивирование и SHA-256. + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'tools')) # Находит проверяемую реализацию относительно теста без путей конкретной рабочей станции. +import c2000_postbuild as c2000 # Вызывает тот же postbuild, который запускается штатным postcompile.bat. +from identity import verify # Проверяет байты скопированных образов по настоящему manifest. + + +class PostbuildTests(unittest.TestCase): # Проверяет общую цепочку от готового OUT до экспортированной папки выпуска. + def setUp(self): # Для каждой проверки создаёт отдельный проект с типичной структурой CCS. + temporary = tempfile.TemporaryDirectory() # Все файлы сценария принадлежат временному каталогу теста. + self.addCleanup(temporary.cleanup) # Освобождает только каталог данной проверки при любом результате. + self.root = Path(temporary.name) # Корень не зависит от реальной прошивки и установленного templates. + self.build = self.root / 'project/Debug' # Проверяет соглашение о расположении сборщика рядом с конфигурациями CCS. + self.build.mkdir(parents=True) # Подготавливает рабочий каталог внешних инструментов. + self.compiler = self.root / 'compiler' # Позволяет проверить передачу компилятора текущего проекта вместо фиксированного пути. + (self.compiler / 'bin').mkdir(parents=True) # Воспроизводит структуру установленного C2000 compiler. + (self.compiler / 'bin/hex2000.exe').write_bytes(b'fake tool') # Проверка наличия инструмента реальна, а выполнение будет подменено. + self.source = self.root / 'Bin/Firmware.out' # Основной OUT размещён вне Debug, как в рабочем проекте пользователя. + self.source.parent.mkdir() # Создаёт отдельный каталог исходного COFF и итогового Flash COFF. + self.source.write_bytes(b'RAM image') # Даёт узнаваемые байты для проверки, что основной образ не подменён Flash-вариантом. + self.metadata = self.build / 'metadata.json' # Один паспорт используется обоими вариантами текущего выпуска. + self.metadata.write_text(json.dumps({'build_id': 'NOGIT000', 'built_at_utc': '2026-10-14T13:00:00+00:00', 'source': {'commit': None}, 'version': [1, 2, 3]}), encoding='utf-8') # Фиксированное время проверяет выбор папки по prebuild, а не времени файлов. + self.output = self.build / 'firmware' # Локальный выпуск получает оба образа и их сопроводительные файлы. + self.export = self.root / 'GUI' # Экспорт изолирован от настоящего GUI и сетевых ресурсов. + + def fake_tool(self, command, **kwargs): # Имитирует границу внешних инструментов, оставляя реальную логику упаковки и проверки. + if '--postbuild' in command: # Вложенная Flash-сборка обязана использовать режим без повторного Make. + self.assertEqual(Path(command[command.index('--compiler') + 1]), self.compiler.resolve()) # Проверяет выбор текущей версии TI compiler. + self.assertEqual(Path(command[command.index('--build-dir') + 1]), self.build.resolve()) # Проверяет использование текущих объектов и generated-паспорта. + image = Path(command[command.index('--output') + 1]) # Результат должен создаваться по переданному временному пути. + self.assertNotEqual(image.parent, self.source.parent) # Запрещает выдавать существующий OUT из Bin за результат текущего вызова. + image.write_bytes(b'current Flash image') # Создаёт узнаваемый новый COFF для сравнения всех копий. + image.with_suffix('.map').write_text('codestart 0033fff6', encoding='utf-8') # Воспроизводит обязательный второй результат сборщика. + else: # Обычная SCI8-конверсия должна продолжать использовать основной RAM OUT. + expected = 'Firmware_flash.out' if '_flash_rs.bin' in command[command.index('-o') + 1] else self.source.name # Только отдельная RS-конверсия должна брать Flash COFF. + self.assertEqual(Path(command[1]).name, expected) # Проверяет, что EEPROM BIN и Flash RS BIN создаются из разных исходных образов. + Path(command[command.index('-o') + 1]).write_bytes(b'EEPROM image') # Выпускает HEX/BIN с отличимыми байтами основного варианта. + Path(command[command.index('-map') + 1]).write_text('RAM map', encoding='utf-8') # Сохраняет карты, необходимые настоящему архиватору. + return subprocess.CompletedProcess(command, 0) # Подтверждает только имитируемый инструмент, не подменяя проверки выпуска. + + def run_postbuild(self): # Вызывает публичную функцию с теми же путями, что передаёт BAT из CCS. + return c2000.postbuild(self.compiler, self.build, str(self.source.with_suffix('')), self.metadata, self.output, self.export) # Включает настоящий экспорт и проверку manifest. + + def test_project_without_flash_builder_keeps_eeprom_workflow(self): # Старые проекты должны работать без новых настроек или Flash-файлов. + with patch.object(c2000.subprocess, 'run', side_effect=self.fake_tool) as calls: # Подменяет только TI Hex Utility. + result = self.run_postbuild() # Выполняет полный прежний выпуск EEPROM. + self.assertEqual(calls.call_count, 2) # Для HEX и BIN выполнены два вызова; дополнительного сборщика не было. + self.assertEqual(self.source.read_bytes(), b'RAM image') # Основной OUT не изменён упаковкой. + self.assertFalse(self.source.with_name('Firmware_flash.out').exists()) # Отсутствие builder не создаёт фиктивный Flash-образ. + self.assertEqual(verify(result, Path(str(result) + '.manifest.json'))['size_bytes'], len(b'EEPROM image')) # Проверяет настоящее содержимое EEPROM BIN и его паспорт. + + def test_flash_and_eeprom_share_current_export_with_separate_checksums(self): # Новый выпуск должен содержать оба варианта под своими именами. + (self.build.parent / 'build_flash.py').write_text('# Сборщик проекта подключён явно.\n', encoding='utf-8') # Наличие сценария включает дополнительный шаг postbuild. + with patch.object(c2000.subprocess, 'run', side_effect=self.fake_tool) as calls: # Flash и hex2000 имитируются на границе процессов. + self.run_postbuild() # Архиватор и экспорт работают без подмены. + self.assertEqual(calls.call_count, 4) # Один Flash-вызов, две EEPROM-конверсии и отдельный RS BIN подтверждают отсутствие рекурсивного Make. + folder = self.export / 'NOGIT000_2026-10-14_16-00-00_UTC+3' # Имя следует времени prebuild с переводом в московский UTC+3. + for directory in (self.source.parent, self.output, folder): # Проверяет копию для CCS, плоский выпуск и архив для GUI. + self.assertEqual((directory / 'Firmware_flash.out').read_bytes(), b'current Flash image') # Каждая копия содержит новый Flash COFF. + self.assertTrue((directory / 'Firmware_flash.map').is_file()) # Карта Flash не теряется при сохранении или экспорте. + for name in ('Firmware_flash.out', 'Firmware_NOGIT000.bin', 'Firmware_flash_rs.bin'): # Контрольные суммы каждого варианта должны проверяться независимо. + verify(folder / name, folder / (name + '.manifest.json')) # Использует реальные SHA-256 экспортированных байтов. + self.assertEqual((folder / self.source.name).read_bytes(), b'RAM image') # Архив сохраняет исходный RAM OUT вместе с новым Flash OUT. + + def test_failed_or_incomplete_builder_cannot_export_stale_flash(self): # Ошибка или отсутствие карты должны остановить выпуск до экспорта старого COFF. + (self.build.parent / 'build_flash.py').write_text('# Подключён неисправный сборщик для проверки отказа.\n', encoding='utf-8') # Включает путь Flash-проверки. + stale = self.source.with_name('Firmware_flash.out') # В Bin уже есть образ от предыдущей успешной сборки. + stale.write_bytes(b'old Flash image') # Отличимые байты выявят ошибочную повторную публикацию. + for failure in (subprocess.CalledProcessError(1, 'builder'), None): # Проверяет ненулевой код и ложный успех без обязательных результатов. + with self.subTest(failure=failure): # Даёт отдельную диагностику двум независимым отказам. + with patch.object(c2000.subprocess, 'run', side_effect=failure) as calls: # Сборщик либо падает, либо не создаёт файлов. + with self.assertRaises((subprocess.CalledProcessError, ValueError)): # Оба отказа должны выйти наружу как ошибка postbuild. + self.run_postbuild() # Не разрешает продолжение EEPROM-конверсии после сбоя Flash. + self.assertEqual(calls.call_count, 1) # После отказа Flash ни hex2000, ни новый сборщик не запускаются. + self.assertEqual(stale.read_bytes(), b'old Flash image') # Предыдущий образ сохраняется, но не считается новым результатом. + self.assertFalse(self.export.exists()) # Неполная сборка не создаёт выпуск для GUI. + + +if __name__ == '__main__': # Позволяет запускать проверки отдельно или через unittest discover. + unittest.main() # Возвращает ненулевой код при нарушении контракта упаковки или экспорта. diff --git a/c/firmware-info/tools/c2000_postbuild.py b/c/firmware-info/tools/c2000_postbuild.py index 8bd0c26..7fe3900 100644 --- a/c/firmware-info/tools/c2000_postbuild.py +++ b/c/firmware-info/tools/c2000_postbuild.py @@ -10,11 +10,25 @@ import json from pathlib import Path import re import subprocess +import sys # Запускает проектный сборщик тем же Python, которым выполняется общий postbuild. import tempfile from identity import archive_build, seal, verify +def build_flash_variant(compiler: Path, build_dir: Path, source: Path, stage: Path) -> tuple: # Возвращает файлы дополнительного Flash-образа только для проектов с явным сборщиком. + builder = build_dir.resolve().parent / "build_flash.py" # Соглашение CCS: Debug/Release расположены рядом с проектным сценарием сборки Flash. + if not builder.is_file(): # Отсутствие сценария оставляет прежний выпуск EEPROM без дополнительных требований к проекту. + return () # Пустой список не добавляет Flash-файлы в архив обычного проекта. + image = stage / (source.stem + "_flash.out") # Отдельное имя и временный каталог исключают подмену RAM-образа и использование устаревшего Flash-файла. + subprocess.run([sys.executable, str(builder), "--postbuild", "--compiler", str(compiler.resolve()), "--build-dir", str(build_dir.resolve()), "--output", str(image)], cwd=build_dir, check=True) # Режим postbuild использует уже собранные объекты и запрещает повторный запуск Make. + files = (image, image.with_suffix(".map")) # Карта линковки сопровождает COFF и позволяет проверить адрес аппаратной точки входа. + for file in files: # Оба результата должны быть выпущены текущим вызовом сборщика. + if not file.is_file() or not file.stat().st_size: # Успешный код процесса без непустого результата не считается успешной сборкой. + raise ValueError(f"Flash builder produced no file: {file}") # Ошибка останавливает postbuild до архивирования или экспорта неполного выпуска. + return files # Передаёт проверенные файлы вызывающему шагу для подписи и сохранения. + + def postbuild(compiler: Path, build_dir: Path, artifact: str, metadata: Path, output: Path, export: Path = None) -> Path: # CCS may include the configured output directory in this macro. @@ -47,6 +61,7 @@ def postbuild(compiler: Path, build_dir: Path, artifact: str, stage = Path(temporary) hex_image = stage / (artifact + ".hex") bin_image = stage / (artifact + "_" + build_id + ".bin") + flash_files = build_flash_variant(compiler, build_dir, source, stage) # Сначала собирает дополнительный Flash-вариант; его ошибка не допускает выпуск нового BIN. for image, mode in ((hex_image, "-i"), (bin_image, "-b")): subprocess.run([str(tool), str(source), "-boot", "-sci8", "-map", str(image.with_suffix(image.suffix + ".map")), @@ -55,13 +70,32 @@ def postbuild(compiler: Path, build_dir: Path, artifact: str, raise ValueError(f"hex2000 produced no image: {image}") seal(bin_image, metadata) verify(bin_image, bin_image.with_suffix(bin_image.suffix + ".manifest.json")) + if flash_files: # Проекты со сборщиком получают независимую проверку точных байтов Flash-образа. + seal(flash_files[0], metadata) # Использует тот же паспорт prebuild для второго варианта этой сборки. + verify(flash_files[0], flash_files[0].with_suffix(".out.manifest.json")) # Проверяет размер и SHA-256 перед сохранением результатов. + serial_image = stage / (artifact + "_flash_rs.bin") # Отдельный SCI8 BIN содержит Flash-адреса и предназначен только для новой команды записи по RS. + serial_map = serial_image.with_suffix('.bin.map') # Карта конверсии позволяет отличить Flash-адреса от EEPROM/RAM BIN. + subprocess.run([str(tool), str(flash_files[0]), '-boot', '-sci8', '-map', str(serial_map), '-o', str(serial_image), '-b'], check=True) # Конвертирует именно Flash COFF с загрузочными адресами секций. + if not serial_image.is_file() or not serial_image.stat().st_size: # Пустая конверсия не должна попасть в выпуск либо каталог GUI. + raise ValueError(f'hex2000 produced no Flash RS image: {serial_image}') # Передаёт ошибку конверсии общему postcompile. + seal(serial_image, metadata) # Привязывает RS BIN к той же версии, ревизии и времени текущего prebuild. + verify(serial_image, serial_image.with_suffix('.bin.manifest.json')) # Проверяет точные байты перед копированием в Bin и архив. + flash_files += (serial_image, serial_map, serial_image.with_suffix('.bin.manifest.json'), serial_image.with_suffix('.bin.sha256')) # Включает транспортный BIN, карту и контрольные файлы в общий выпуск Flash. + for file in flash_files: # Сохраняет COFF и карту также рядом с обычным OUT для выбора в CCS. + destination = source.parent / file.name # Каталог исходного OUT задаёт место назначения без путей конкретного изделия в templates. + destination.write_bytes(file.read_bytes()) # Копирует только результаты успешного текущего вызова, сохраняя исходный RAM-образ. for item in stage.iterdir(): item.replace(output / item.name) - result = output / bin_image.name - archive_build(result, metadata, output, ( + result = output / bin_image.name # BIN остаётся основным образом EEPROM и возвращаемым результатом общего postbuild. + flash_archive = tuple(output / file.name for file in flash_files) # После переноса из временного каталога берёт актуальные Flash-файлы из firmware. + if flash_files: # Добавляет сопроводительные файлы только при выполненной сборке Flash. + flash_archive += (output / (flash_files[0].name + ".manifest.json"), output / (flash_files[0].name + ".sha256")) # Архив и GUI получают отдельный паспорт и контрольную сумму Flash COFF. + print(f"[firmware-build] Flash OUT: {source.parent / flash_files[0].name}") # Показывает пользователю CCS конкретный файл для прошивки внутренней Flash через JTAG. + archive_build(result, metadata, output, ( # Сохраняет файлы текущей сборки в архиве и передаёт весь архив в каталог GUI. + source, # Копирует исходный COFF-файл OUT с символами отладки под его именем для загрузки через JTAG из GUI. output / hex_image.name, output / (hex_image.name + ".map"), - output / (bin_image.name + ".map")), export=export) + output / (bin_image.name + ".map"), *flash_archive), export=export) # Экспортирует EEPROM и Flash в одной папке текущего выпуска. print(f"[firmware-build] BIN: {result}") print(f"[firmware-build] Manifest: {result}.manifest.json") print(f"[firmware-build] SHA-256: {result}.sha256") diff --git a/tools/firmware-build/README.md b/tools/firmware-build/README.md index 3ead431..0453a24 100644 --- a/tools/firmware-build/README.md +++ b/tools/firmware-build/README.md @@ -1,5 +1,93 @@ # Подключение precompile и postcompile из templates +## Пути на этом компьютере + +| Назначение | Полный путь | +|---|---| +| Корень общей библиотеки templates | `K:\git_project\newProject\templates` | +| Сценарии CCS | `K:\git_project\newProject\templates\tools\firmware-build\ccs` | +| Сценарии Keil | `K:\git_project\newProject\templates\tools\firmware-build\keil` | +| Проект Бальзам-166 / TMS320F28335 | `K:\git_project\28335_periph\UKSSTMS320F28335` | +| Каталог сборок Бальзам-166 в SETGUI | `K:\git_project\newProject\SETGUI\..periph_28335\firmware\periph28335\balzam166` | + +Все команды ниже используют эту копию templates. При переносе библиотеки +замените её корень в командах и в include paths компилятора. +`${PROJECT_LOC}`, `${BuildDirectory}`, `${CG_TOOL_ROOT}` и +`${BuildArtifactFileBaseName}` раскрывает CCS; `$P` и `#H` раскрывает Keil. +Для ручного запуска замените макросы полными путями. + +В пути SETGUI `..periph_28335` — существующее имя папки с двумя точками +в начале. Переход к родителю записывается отдельным компонентом `..\`. + +## Текущий проект 28335_periph: вызов через firmware_build.bat + +Для проекта `K:\git_project\28335_periph\UKSSTMS320F28335` используйте +локальную обвязку. Она вызывает общие BAT из templates, увеличивает версию +в проектном JSON и перед публикацией дополнительно проверяет встроенный +паспорт SCI8 и предел EEPROM. + +В CCS → **Project Properties → Build → Steps** задайте для Debug и Release +следующие команды, каждую одной строкой. + +**Pre-build:** + +```bat +cmd /c call "${PROJECT_LOC}/firmware_build.bat" prepare --build-dir "${BuildDirectory}" +``` + +**Post-build:** + +```bat +cmd /c call "${PROJECT_LOC}/firmware_build.bat" build --compiler "${CG_TOOL_ROOT}" --build-dir "${BuildDirectory}" --artifact "${BuildArtifactFileBaseName}" +``` + +Настройки находятся в +`K:\git_project\28335_periph\UKSSTMS320F28335\firmware_identity.json`: + +| Поле | Рабочее значение и смысл | +|---|---| +| `templates` | `../../newProject/templates`; разрешается относительно папки JSON в `K:\git_project\newProject\templates`. Абсолютный эквивалент: `K:/git_project/newProject/templates`. | +| `copy_to` | `../Bin`; копирует проверенные BIN, manifest, SHA-256, HEX и карту в `K:\git_project\28335_periph\Bin`. | +| `increment_version` | `true`; каждый pre-build резервирует следующий номер в поле `version`. | +| `max_image_bytes` | `32508`; предельный размер SCI8 BIN в байтах для этой платы. | + +В JSON используйте `/` либо удваивайте обратные слеши. +`copy_to` принимает также абсолютный путь, например +`K:/git_project/newProject/SETGUI/..periph_28335/firmware/periph28335/balzam166`. +Эта настройка копирует отдельные файлы комплекта. Архивные папки остаются +в `${BuildDirectory}/firmware`. + +`firmware_build.bat build` принимает именованные параметры. Дописывание +каталога после `--artifact` вызывает `unrecognized arguments`; для этой +обвязки каталог копирования задаётся полем `copy_to`. + +Include paths компилятора для текущего проекта: + +| Запись в CCS | Реальный каталог для Debug | +|---|---| +| `${SRC_ROOT}/../newProject/templates/c/firmware-info/include` | `K:\git_project\newProject\templates\c\firmware-info\include` | +| `${SRC_ROOT}/../newProject/templates/c/set-protocol` | `K:\git_project\newProject\templates\c\set-protocol` | +| `${BuildDirectory}/generated` | `K:\git_project\28335_periph\UKSSTMS320F28335\Debug\generated` | + +`${SRC_ROOT}` в этом проекте равен `K:\git_project\28335_periph`. +При переносе templates обновите и JSON, и include paths в CCS. +Подробная инструкция проекта: +[README Бальзам-166](../../../../28335_periph/UKSSTMS320F28335/README.md). + +Готовый BIN ищите по строке `[firmware-build] Verified BIN: ...`. +Постоянный каталог Debug: +`K:\git_project\28335_periph\UKSSTMS320F28335\Debug\firmware`. +Папки `.identity-release-...` временные и удаляются после проверки. + +## Прямое подключение общих BAT к новому CCS-проекту + +Следующие разделы описывают прямые вызовы `ccs/precompile.bat` и +`ccs/postcompile.bat`. В этом варианте дополнительный последний аргумент +postcompile поддерживается и экспортирует целиком папку текущей сборки. +Общие BAT берут версию из JSON и не увеличивают её автоматически. +Выберите одну схему подключения: её pre-build и post-build должны +использовать один набор метаданных. + ## Новый CCS-проект C2000: локальные версия и SCI8 BIN Используйте обновлённую папку templates целиком. Режим `--identity` добавлен для нового проекта: Windows, Python 3.8+ в PATH и TI C2000 compiler с hex2000.exe. Git в PATH нужен для хеша коммита. Без Git либо без commit в проекте или templates используется `NOGIT000`; сборка и локальная конвертация разрешены. Это явно видно в manifest. SETGUI и доступ к серверу не требуются. @@ -20,20 +108,37 @@ ### 2. Добавьте команды в CCS -Project Properties → Build → Steps, для нужной конфигурации. Пример предполагает templates в `C:\Projects\templates`. Замените только этот путь своим; макросы CCS оставьте как есть. +Project Properties → Build → Steps, для нужной конфигурации. Пример предполагает templates в `K:\git_project\newProject\templates`. Замените только этот путь своим; макросы CCS оставьте как есть. Pre-build steps → Command, одной строкой: ```bat -cmd /c call "C:\Projects\templates\tools\firmware-build\ccs\precompile.bat" --identity "${PROJECT_LOC}" "${PROJECT_LOC}\firmware_identity.json" "${BuildDirectory}\generated" +cmd /c call "K:\git_project\newProject\templates\tools\firmware-build\ccs\precompile.bat" --identity "${PROJECT_LOC}" "${PROJECT_LOC}\firmware_identity.json" "${BuildDirectory}\generated" ``` Post-build steps → Command, одной строкой: ```bat -cmd /c call "C:\Projects\templates\tools\firmware-build\ccs\postcompile.bat" --identity "${CG_TOOL_ROOT}" "${BuildDirectory}" "${BuildArtifactFileBaseName}" "${BuildDirectory}\generated\firmware_identity.json" "${BuildDirectory}\firmware" +cmd /c call "K:\git_project\newProject\templates\tools\firmware-build\ccs\postcompile.bat" --identity "${CG_TOOL_ROOT}" "${BuildDirectory}" "${BuildArtifactFileBaseName}" "${BuildDirectory}\generated\firmware_identity.json" "${BuildDirectory}\firmware" ``` +Позиционные аргументы общего `ccs/postcompile.bat` после `--identity`: + +| Позиция | Значение | Источник в CCS | +|---|---|---| +| 1 | Корень TI C2000 compiler, содержащий `bin/hex2000.exe` | `${CG_TOOL_ROOT}` | +| 2 | Каталог текущей конфигурации сборки | `${BuildDirectory}` | +| 3 | Имя или путь OUT без расширения `.out` | `${BuildArtifactFileBaseName}` | +| 4 | Метаданные, созданные pre-build | `${BuildDirectory}\generated\firmware_identity.json` | +| 5 | Постоянный каталог результатов | `${BuildDirectory}\firmware` | +| 6, необязательно | Каталог экспорта архивной папки текущей сборки | Полный путь назначения | + +Здесь templates определяется расположением вызываемого общего BAT. +Для прямой схемы поле `templates` в JSON не заменяет путь в команде CCS. +Добавьте `${BuildDirectory}/generated` в include paths; при подключении +общего порта firmware-info добавьте +`K:/git_project/newProject/templates/c/firmware-info/include`. + Нужны оба шага. Precompile создаёт версию, UTC-время и Git-метаданные до компиляции. Postcompile преобразует OUT в SCI8 HEX/BIN, создаёт manifest и SHA-256 для точного BIN. Он не повторяет запрос Git после компиляции. В этом режиме `firmware-release.cmd` не нужен. `BuildArtifactFileBaseName` передаётся без изменения и без расширения `.out`: допускается простое имя, абсолютный путь или путь относительно BuildDirectory. Postcompile находит OUT по этому пути, а для имён BIN/HEX использует только имя файла. Поэтому отдельная выходная папка проекта (например, `../bin`) не требует правки общей команды. Метаданные и результаты остаются в указанных каталогах generated и firmware. @@ -62,23 +167,23 @@ Debug/ firmware_identity.json ``` -Postcompile автоматически создаёт папку `HASH_YYYY-MM-DD_HH-MM-SS_UTC+3` для каждой сборки. HASH — первые 8 символов commit прошивки из pre-build JSON; при незакоммиченных изменениях добавляется `+`. Дата и время берутся из `built_at_utc` и переводятся в UTC+3 для имени папки. В JSON и заголовке сохраняется UTC. Если commit исходников неизвестен, используется build ID или NOGIT000. Например: `f5c3654e+_2026-10-08_15-30-00_UTC+3`. Сохраняются точные байты образа, manifest, SHA-256 и firmware_identity.json; в CCS также HEX и map. Повтор postcompile с теми же метаданными обновляет ту же папку. Файлы непосредственно в firmware сохраняются, поэтому существующие команды копирования продолжают работать. +Postcompile автоматически создаёт папку `HASH_YYYY-MM-DD_HH-MM-SS_UTC+3` для каждой сборки. HASH — первые 8 символов commit прошивки из pre-build JSON; при незакоммиченных изменениях добавляется `+`. Дата и время берутся из `built_at_utc` и переводятся в UTC+3 для имени папки. В JSON и заголовке сохраняется UTC. Если commit исходников неизвестен, используется build ID или NOGIT000. Например: `f5c3654e+_2026-10-08_15-30-00_UTC+3`. Сохраняются точные байты образа, manifest, SHA-256 и firmware_identity.json; в CCS также исходный OUT, HEX и map. Повтор postcompile с теми же метаданными обновляет ту же папку. Файлы непосредственно в firmware сохраняются, поэтому существующие команды копирования продолжают работать. Добавьте generated и firmware в игнорируемые Git-каталоги. Обычно вся папка Debug уже игнорируется. Полный Rebuild обязателен для выпуска. BAT сами по себе не подтверждают, что OUT собран именно с этим заголовком. -### 4. Копирование папки текущей сборки в SETGUI +### 4. Прямой postcompile: копирование папки текущей сборки в SETGUI -Передайте каталог назначения последним аргументом postcompile. Скрипт скопирует целиком только папку HASH_DATE, созданную текущим запуском: BIN, HEX, map, manifest, SHA-256 и метаданные. Он использует папку из pre-build JSON, не выбирает её по времени изменения файлов и не копирует остальные архивы или отдельные файлы из корня firmware. +При прямом вызове общего ccs/postcompile.bat передайте каталог назначения последним аргументом после output-dir. Это правило относится к общему BAT; проектный firmware_build.bat использует copy_to из JSON. Скрипт скопирует целиком только папку HASH_DATE, созданную текущим запуском: исходный OUT (для CCS), BIN, HEX, map, manifest, SHA-256 и метаданные. OUT сохраняется с исходным именем для выбора и загрузки через JTAG в GUI. Скрипт использует папку из pre-build JSON, не выбирает её по времени изменения файлов и не копирует остальные архивы или отдельные файлы из корня firmware. -Полная команда Post-build для templates в `K:\git_project\newProject\newTEMPL\templates`, одной строкой: +Полная команда Post-build для templates в `K:\git_project\newProject\templates`, одной строкой: ```bat -cmd /c call "K:\git_project\newProject\newTEMPL\templates\tools\firmware-build\ccs\postcompile.bat" --identity "${CG_TOOL_ROOT}" "${BuildDirectory}" "${BuildArtifactFileBaseName}" "${BuildDirectory}\generated\firmware_identity.json" "${BuildDirectory}\firmware" "K:\git_project\newProject\SETGUI\..periph_28335\firmware" +cmd /c call "K:\git_project\newProject\templates\tools\firmware-build\ccs\postcompile.bat" --identity "${CG_TOOL_ROOT}" "${BuildDirectory}" "${BuildArtifactFileBaseName}" "${BuildDirectory}\generated\firmware_identity.json" "${BuildDirectory}\firmware" "K:\git_project\newProject\SETGUI\..periph_28335\firmware\periph28335\balzam166" ``` Старые суффиксы `&& copy ...` и `&& xcopy ...` удалите. Папка назначения создаётся автоматически. В ней появится, например: ```text -K:\git_project\newProject\SETGUI\..periph_28335\firmware\ +K:\git_project\newProject\SETGUI\..periph_28335\firmware\periph28335\balzam166\ f5c3654e+_2026-10-08_15-30-00_UTC+3\ MyFirmware.hex MyFirmware_BUILDID.bin @@ -89,6 +194,33 @@ K:\git_project\newProject\SETGUI\..periph_28335\firmware\ Копирование выполняется после успешного архивирования; SHA-256 копии проверяется. Console покажет `[firmware-build] Exported folder: ...`. Повтор для той же папки обновляет её файлы; другие папки назначения сохраняются. Без последнего аргумента экспорт отключён. Это локальное копирование без сетевой публикации. +### Дополнительный Flash OUT из postbuild CCS + +Если рядом с CCS-проектом, на уровень выше BuildDirectory, есть `build_flash.py`, +общий postbuild автоматически вызывает его с `--postbuild`, `--compiler`, +`--build-dir` и `--output`. Команда postcompile в настройках CCS остаётся прежней. +Сценарий проекта должен использовать уже готовые объекты, не запускать Make +и создать непустые `<имя>_flash.out` и `<имя>_flash.map` по переданному пути. +Адреса секций, отдельный linker-файл и необходимые определения препроцессора +задаёт проектный сборщик, а не общий templates. + +Flash OUT и карта сохраняются рядом с обычным OUT. Копии, отдельный manifest +и SHA-256 попадают в firmware и ту же папку HASH_DATE, что и EEPROM BIN, +а затем копируются в GUI при настроенном export. Обычный BIN по-прежнему +создаётся из основного OUT; Flash OUT не преобразуется в EEPROM SCI8 BIN. +Ошибка сборщика или отсутствие любого результата завершает postcompile +с ненулевым кодом до архивирования и экспорта. Существующий Flash OUT +не считается результатом нового вызова: сборщик работает во временном каталоге. +Без `build_flash.py` дополнительные действия отключены. + +Дополнительно hex2000 преобразует Flash OUT в отдельный `<имя>_flash_rs.bin` +с адресной таблицей SCI8, картой `.bin.map`, manifest и SHA-256. +Эти файлы сохраняются рядом с OUT, в firmware и в экспортируемой папке +HASH_DATE. Flash RS BIN содержит адреса внутренней Flash и предназначен +для совместимого проектного CMD_TFLASH; его нельзя выбирать как обычный +EEPROM BIN. Проект сам должен реализовать проверку адресов и алгоритм +программирования из RAM. Общий postbuild только формирует транспортный файл. + ### Версия внутри устройства Это подготовка метаданных сборки и файла. Чтобы версия присутствовала в программе и ответах устройства, подключите заголовок `firmware_identity.h` к модулю версии и обработчику запроса. Include path: `${BuildDirectory}/generated`. Для C2000 с 16-битным char нужна адаптация байтового контракта; обычный 8-битный порт нельзя считать готовым. Смотрите [PORTING.md](../../c/firmware-info/PORTING.md). @@ -121,24 +253,24 @@ project/ ### 2. Настройте Before/After Build -В Options for Target → Output включите Create HEX File. Затем откройте User и включите выполнение команд Before Build/Rebuild и After Build/Rebuild. Для обеих команд задайте Stop on Exit Code `>=1`, чтобы ошибка скрипта останавливала сборку. Пример предполагает templates в `C:\Projects\templates`; замените этот путь своим. +В Options for Target → Output включите Create HEX File. Затем откройте User и включите выполнение команд Before Build/Rebuild и After Build/Rebuild. Для обеих команд задайте Stop on Exit Code `>=1`, чтобы ошибка скрипта останавливала сборку. Пример предполагает templates в `K:\git_project\newProject\templates`; замените этот путь своим. Before Build/Rebuild, одной строкой: ```bat -cmd /c call "C:\Projects\templates\tools\firmware-build\keil\precompile.bat" --identity "$P.." "$P..\firmware_identity.json" "$PGenerated" +cmd /c call "K:\git_project\newProject\templates\tools\firmware-build\keil\precompile.bat" --identity "$P.." "$P..\firmware_identity.json" "$PGenerated" ``` After Build/Rebuild, одной строкой: ```bat -cmd /c call "C:\Projects\templates\tools\firmware-build\keil\postcompile.bat" --identity "#H" "$PGenerated\firmware_identity.json" +cmd /c call "K:\git_project\newProject\templates\tools\firmware-build\keil\postcompile.bat" --identity "#H" "$PGenerated\firmware_identity.json" ``` Для копирования только папки текущей сборки добавьте каталог назначения последним аргументом: ```bat -cmd /c call "C:\Projects\templates\tools\firmware-build\keil\postcompile.bat" --identity "#H" "$PGenerated\firmware_identity.json" "K:\git_project\newProject\SETGUI\..periph_28335\firmware" +cmd /c call "K:\git_project\newProject\templates\tools\firmware-build\keil\postcompile.bat" --identity "#H" "$PGenerated\firmware_identity.json" "K:\git_project\newProject\SETGUI\..periph_28335\firmware\periph28335\balzam166" ``` Будет скопирована целиком новая папка HASH_DATE с HEX/BIN, manifest, SHA-256 и метаданными. Старые команды copy/xcopy в этой строке не нужны. В Console появится `[firmware-build] Exported folder`. From f6131011244467b9b96715235fe3cbded914e95c Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 17 Oct 2026 14:43:12 +0300 Subject: [PATCH 03/18] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=D0=B0=D1=82=D1=8C=20=D0=B8=D0=BC=D0=BF?= =?UTF-8?q?=D1=83=D0=BB=D1=8C=D1=81=20=D1=81=D0=B2=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BE=D0=B4=D0=B0=20=D0=BF=D1=80=D0=B8=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=B6=D0=B4=D0=BE=D0=BC=20=D0=BF=D1=80=D0=B8=D1=91=D0=BC=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/led-indicator/README.md | 16 +++++++++++++++- c/led-indicator/led_indicator.c | 12 +++++++++++- c/led-indicator/led_indicator.h | 6 ++++++ c/led-indicator/tests/test_led_indicator.c | 22 +++++++++++++++++++++- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/c/led-indicator/README.md b/c/led-indicator/README.md index 7b36a85..7cbcf69 100644 --- a/c/led-indicator/README.md +++ b/c/led-indicator/README.md @@ -28,7 +28,7 @@ | `OFF` / `ON` | постоянно выключен / включён | | `STARTUP` | три коротких импульса, затем постоянно включён | | `WORK` | 100 мс включён, 900 мс выключен | -| `ACTIVITY` | 50/50 мс | +| `ACTIVITY` | один цикл: 100 мс включён, 900 мс выключен, затем остаётся выключенным | | `WARNING` | 250/250 мс | | `ERROR` | два импульса и пауза | | `CRITICAL` | три импульса и пауза | @@ -86,6 +86,20 @@ for (;;) { не начинает рисунок заново. Для нового импульса события служит `LedIndicator_RestartMode`. +Для индикации приёма вызывайте `LedIndicator_TriggerActivity` либо +`LedIndicator_TriggerActivityAt` на каждый принятый пакет. Свечение занимает +10% секундного цикла: 100 мс включён и 900 мс выключен. Новый приём немедленно +перезапускает фазу свечения, даже внутри предыдущего импульса или паузы; +очереди циклов нет. При интервалах между пакетами меньше 100 мс LED может +гореть непрерывно до истечения 100 мс после последнего пакета. Без нового +события `ACTIVITY` не повторяется. Настраиваемая таблица `patterns` по-прежнему +позволяет изменить длительности и повторение для других применений. + +```c +LedIndicator_TriggerActivityAt(&led, 0U, received_ms); /* Каждый приём запускает цикл канала 0 от миллисекундной метки события. */ +LedIndicator_ProcessAt(&led, now_ms); /* Главный цикл обслуживает окончание свечения без задержек и ожидания следующего пакета. */ +``` + ## STM32F103, STM32F4, STM32G431 и STM32G474 Порт `ports/stm32-hal` принимает конкретный `TIM_HandleTypeDef *`; библиотека diff --git a/c/led-indicator/led_indicator.c b/c/led-indicator/led_indicator.c index 13e998d..c3aaa5f 100644 --- a/c/led-indicator/led_indicator.c +++ b/c/led-indicator/led_indicator.c @@ -18,7 +18,7 @@ static const LedIndicator_Pattern g_default_patterns[LED_INDICATOR_MODE_COUNT] = {{0U}, LEVELS_1, 1U, 1U, 1U}, {{100U, 100U, 100U, 100U, 100U, 100U}, LEVELS_101010, 6U, 0U, 1U}, {{100U, 900U}, LEVELS_10, 2U, 1U, 0U}, - {{50U, 50U}, LEVELS_10, 2U, 1U, 0U}, + {{100U, 900U}, LEVELS_10, 2U, 0U, 0U}, /* Один цикл приёма длится 1000 мс: 100 мс свечения составляют 10%, затем 900 мс паузы и выключение. */ {{250U, 250U}, LEVELS_10, 2U, 1U, 0U}, {{100U, 100U, 100U, 700U}, LEVELS_1010, 4U, 1U, 0U}, {{100U, 100U, 100U, 100U, 100U, 700U}, LEVELS_101010, 6U, 1U, 0U} @@ -220,6 +220,16 @@ uint8_t LedIndicator_RestartMode(LedIndicator *instance, size_t channel, instance->port.now_ms(instance->port.context)); } +uint8_t LedIndicator_TriggerActivityAt(LedIndicator *instance, size_t channel, uint32_t now_ms) /* Каждый пакет начинает ACTIVITY заново, даже если предыдущая вспышка ещё продолжается. */ +{ /* Использует общую проверку канала и принудительный сброс фазы в миллисекундной временной базе. */ + return LedIndicator_RestartModeAt(instance, channel, LED_INDICATOR_MODE_ACTIVITY, now_ms); /* Штатный однократный шаблон завершает цикл выключенным уровнем без свободного повторения. */ +} /* Завершает запуск одного цикла приёма без ожидания окончания свечения либо паузы. */ + +uint8_t LedIndicator_TriggerActivity(LedIndicator *instance, size_t channel) /* Предоставляет тот же перезапуск по событию с использованием часов аппаратного порта. */ +{ /* Сохраняет поведение варианта At для приложения без собственного передаваемого времени. */ + return LedIndicator_RestartMode(instance, channel, LED_INDICATOR_MODE_ACTIVITY); /* Часы порта считываются штатным API один раз на зарегистрированный приём. */ +} /* Завершает неблокирующий запуск цикла приёма с аппаратным источником времени. */ + void LedIndicator_ProcessAt(LedIndicator *instance, uint32_t now_ms) { size_t i; diff --git a/c/led-indicator/led_indicator.h b/c/led-indicator/led_indicator.h index a910599..626fe79 100644 --- a/c/led-indicator/led_indicator.h +++ b/c/led-indicator/led_indicator.h @@ -114,6 +114,12 @@ void LedIndicator_Process(LedIndicator *instance); /** Обновляет выходы с явно переданной меткой времени. */ void LedIndicator_ProcessAt(LedIndicator *instance, uint32_t now_ms); +/** Начинает один цикл ACTIVITY на каждый приём; новый вызов немедленно перезапускает свечение, не создавая очередь. */ +uint8_t LedIndicator_TriggerActivityAt(LedIndicator *instance, size_t channel, uint32_t now_ms); /* Стандартный цикл: 100 мс включён, 900 мс выключен; время задаётся в миллисекундах. */ + +/** Использует часы аппаратного порта для такого же перезапуска цикла при каждом приёме. */ +uint8_t LedIndicator_TriggerActivity(LedIndicator *instance, size_t channel); /* Вызывать из контекста Process; передачу событий из ISR обеспечивает приложение. */ + LedIndicator_Mode LedIndicator_GetMode(const LedIndicator *instance, size_t channel); #ifdef __cplusplus diff --git a/c/led-indicator/tests/test_led_indicator.c b/c/led-indicator/tests/test_led_indicator.c index b72cc9d..8db9fc7 100644 --- a/c/led-indicator/tests/test_led_indicator.c +++ b/c/led-indicator/tests/test_led_indicator.c @@ -85,6 +85,26 @@ int main(void) CHECK(LedIndicator_SetMode(&indicator, 3U, LED_INDICATOR_MODE_ON) == 0U); CHECK(LedIndicator_GetMode(&indicator, 0U) == LED_INDICATOR_MODE_WORK); - puts("led indicator tests passed"); + CHECK(patterns[LED_INDICATOR_MODE_ACTIVITY].duration_ms[0] == 100U && patterns[LED_INDICATOR_MODE_ACTIVITY].duration_ms[1] == 900U && patterns[LED_INDICATOR_MODE_ACTIVITY].repeat == 0U); /* Фиксирует согласованные 10% свечения и один цикл на приём в канонической таблице. */ + CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 2500U) != 0U && fake.outputs[0] == 1U); /* Приём сразу включает канал независимо от фазы прежнего WORK. */ + LedIndicator_ProcessAt(&indicator, 2599U); CHECK(fake.outputs[0] == 1U); /* До истечения 100 мс светодиод продолжает гореть. */ + LedIndicator_ProcessAt(&indicator, 2600U); CHECK(fake.outputs[0] == 0U); /* Ровно через 100 мс начинается оставшаяся пауза 900 мс. */ + LedIndicator_ProcessAt(&indicator, 3499U); CHECK(fake.outputs[0] == 0U); /* Конец первого периода не порождает дополнительную вспышку. */ + LedIndicator_ProcessAt(&indicator, 3500U); CHECK(fake.outputs[0] == 0U); /* Однократный ACTIVITY завершается выключенным уровнем на границе 1000 мс. */ + LedIndicator_ProcessAt(&indicator, 4500U); CHECK(fake.outputs[0] == 0U); /* Без новых пакетов свободное периодическое мигание отсутствует. */ + CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5000U) != 0U); /* Начинает новый приём после долгого отсутствия обмена. */ + CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5050U) != 0U); /* Второй пакет приходит внутри текущей фазы свечения. */ + LedIndicator_ProcessAt(&indicator, 5100U); CHECK(fake.outputs[0] == 1U); /* Старый срок выключения больше не действует: отсчёт перезапущен новым пакетом. */ + LedIndicator_ProcessAt(&indicator, 5149U); CHECK(fake.outputs[0] == 1U); /* Новый пакет получает собственные полные 100 мс свечения. */ + LedIndicator_ProcessAt(&indicator, 5150U); CHECK(fake.outputs[0] == 0U); /* Новая фаза паузы начинается ровно от последнего приёма. */ + CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5400U) != 0U && fake.outputs[0] == 1U); /* Приём во время паузы сразу включает LED вместо ожидания границы старого периода. */ + LedIndicator_ProcessAt(&indicator, 5500U); CHECK(fake.outputs[0] == 0U); /* Повторный запуск в паузе не создаёт очередь пропущенных циклов. */ + fake.now = 7000U; CHECK(LedIndicator_TriggerActivity(&indicator, 1U) != 0U && fake.outputs[1] == 1U); /* Проверяет вариант событийного API с часами аппаратного порта и другим каналом. */ + fake.now = 7100U; LedIndicator_Process(&indicator); CHECK(fake.outputs[1] == 0U && fake.outputs[0] == 0U); /* Каналы не перезапускают друг другу фазы и не создают фоновую активность. */ + CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, UINT32_MAX - 49U) != 0U); /* Начинает импульс непосредственно перед переполнением 32-битного времени. */ + LedIndicator_ProcessAt(&indicator, 49U); CHECK(fake.outputs[0] == 1U); /* Через переполнение прошло 99 мс, поэтому свечение ещё активно. */ + LedIndicator_ProcessAt(&indicator, 50U); CHECK(fake.outputs[0] == 0U); /* Через переполнение прошло ровно 100 мс, и LED гаснет без зависания. */ + CHECK(LedIndicator_TriggerActivityAt(NULL, 0U, 0U) == 0U && LedIndicator_TriggerActivityAt(&indicator, 3U, 0U) == 0U); /* Ошибочный экземпляр и канал не вызывают запись чужого GPIO. */ + puts("led indicator tests passed: receive 100/900 ms, immediate retrigger, no repeat, timer wrap"); /* Показывает прохождение новых событийных сценариев вместе с прежней диагностикой. */ return 0; } From 5af8a8e9c8806d4dea612ea4b4857174a9e233eb Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 17 Oct 2026 14:43:12 +0300 Subject: [PATCH 04/18] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BE=D0=B1=D1=89=D1=83=D1=8E=20Qt-=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=81=D0=BE=D0=BB=D1=8C=20=D1=81=20=D1=84=D0=B8=D0=BB?= =?UTF-8?q?=D1=8C=D1=82=D1=80=D0=B0=D0=BC=D0=B8=20=D0=B8=20=D1=8D=D0=BA?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D1=80=D1=82=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/examples/console_examples.py | 46 ++++++++ python/set_devices/qt_ports/CONSOLE.md | 68 +++++++++++ python/set_devices/qt_ports/console.py | 156 +++++++++++++++++++++++++ python/tests/test_console.py | 77 ++++++++++++ 4 files changed, 347 insertions(+) create mode 100644 python/examples/console_examples.py create mode 100644 python/set_devices/qt_ports/CONSOLE.md create mode 100644 python/set_devices/qt_ports/console.py create mode 100644 python/tests/test_console.py diff --git a/python/examples/console_examples.py b/python/examples/console_examples.py new file mode 100644 index 0000000..1453266 --- /dev/null +++ b/python/examples/console_examples.py @@ -0,0 +1,46 @@ +"""Три автономных примера общей консоли templates без подключения к аппаратуре.""" # Примеры показывают служебный текст, CAN и двоичный RS485 на одном компоненте. +import argparse # Ключ --kind выбирает один пример для отдельного запуска. +import time # Время в модели кадра соответствует обычному источнику пакетов приложения. +from set_devices.can485_board import BoardFrame # Штатная модель строит RS485-пакет с настоящим CRC. +from set_devices.can_monitor import decode_protocol # CAN расшифровывается действующим декодером templates. +from set_devices.can_transport import build_frame # Транспортный кадр не собирается вручную в UI. +from set_devices.qt_ports.console import ConsoleView # Все примеры используют ту же консоль, что SETGUI. +try: # Выбираем доступную версию Qt без зависимости от приложения SETGUI. + from PySide6.QtWidgets import QApplication, QTabWidget # Вкладки позволяют сравнить три независимых журнала. +except ImportError: # Сохраняем совместимость примера с портом Qt 5. + from PySide2.QtWidgets import QApplication, QTabWidget # Интерфейс запуска одинаков для обеих версий Qt. + + +def create_examples(): # Фабрика доступна также тесту и генератору снимков интерфейса. + service = ConsoleView(limit=4000) # Первый журнал показывает служебные ответы и команды платы. + service.append_message(">>> V", direction="TX", color="#8fd18f") # Метка отправки демонстрирует независимый фильтр TX. + service.append_message("#OK driver started", direction="RX", color="#6fa8dc") # Ответ устройства показывает цвет и фильтр RX. + service.append_message("#ERR transmit failed (no ack / bus busy)", color="#ff7b7b") # Ошибка остаётся видна независимо от фильтров направления. + can = ConsoleView(limit=4000, payloads=True) # Второй пример добавляет переключение представления настоящих байтов CAN. + frame = build_frame(0x701, b"\x05", ide=False, rtr=False) # ID 0x701 и байт 05 задают heartbeat CANopen узла 1 в Operational. + decoded = decode_protocol(frame, "deif") # Подпись события берётся из штатного протокольного декодера. + can.append_message("RX CAN 0x701 · " + decoded.summary, direction="RX", payload=b"\x05") # Исходный payload позволяет сравнить режимы HEX и ASCII. + rs485 = ConsoleView(limit=4000, payloads=True) # Третий пример показывает транспортный пакет платы отдельно от прикладного CAN. + packet = BoardFrame(time.time(), False, 0x701, False, 1, b"\x05", "RS485").rs485_packet() # Пакет AA55 и CRC8 формируются кодеком templates. + rs485.append_message("RX RS485 · пакет CAN485", direction="RX", payload=packet) # Консоль отображает байты, не повторяя алгоритм разбора пакета. + for console in (can, rs485): # Двоичные примеры сразу демонстрируют одновременно байты и печатное представление. + console.display.setCurrentText("HEX + ASCII") # Пользователь может вернуться к исходной подписи или выбрать один формат. + return (("Служебная консоль", service), ("CAN", can), ("RS485", rs485)) # Каждый журнал владеет своей историей и настройками просмотра. + + +def main(): # Точка входа запускается обычным Python с установленным Qt-портом templates. + parser = argparse.ArgumentParser(description=__doc__) # Справка объясняет назначение примеров без отдельного приложения. + parser.add_argument("--kind", choices=("all", "service", "can", "rs485"), default="all") # Один пример каждого источника доступен отдельной командой. + args = parser.parse_args() # Пользователь выбирает источник до создания окна. + app = QApplication.instance() or QApplication([]) # Одно приложение Qt обслуживает все примеры. + window = QTabWidget() # Общий просмотр не связывает состояния независимых консолей. + for key, (title, console) in zip(("service", "can", "rs485"), create_examples()): # Стабильные ключи соответствуют значениям --kind. + if args.kind in ("all", key): window.addTab(console.panel, title) # Выбранные примеры добавляются с общей панелью инструментов. + window.setWindowTitle("Примеры консоли templates") # Заголовок явно отличает демонстрацию от подключения к плате. + window.resize(1100, 480) # Начальный размер в логических пикселях позволяет видеть все инструменты. + window.show() # Окно появляется только при прямом запуске примера. + return app.exec() # Цикл Qt обрабатывает поиск, паузу, экспорт и изменение масштаба. + + +if __name__ == "__main__": # Импорт фабрики в тестах не должен открывать окно или запускать цикл событий. + raise SystemExit(main()) # Код завершения Qt возвращается вызывающему процессу. diff --git a/python/set_devices/qt_ports/CONSOLE.md b/python/set_devices/qt_ports/CONSOLE.md new file mode 100644 index 0000000..7c32bbf --- /dev/null +++ b/python/set_devices/qt_ports/CONSOLE.md @@ -0,0 +1,68 @@ +# Общая консоль Qt + +`set_devices.qt_ports.console.ConsoleView` — общий порт представления для +журналов SETGUI. Он не управляет портами, опросом и отправкой команд. + +Приложение → `ConsoleView` → Qt 6 / Qt 5. Протокольные декодеры передают +готовые подписи и необязательные исходные байты; консоль не вычисляет CRC. + +| Файл | Назначение и зависимости | +|---|---| +| `set_devices/qt_ports/console.py` | Виджет и файловый экспорт; stdlib и PySide6 либо PySide2 | +| `examples/console_examples.py` | По одному примеру служебной консоли, CAN и RS485; действующие кодеки templates | +| `tests/test_console.py` | Проверки истории, паузы, фильтров, очистки и UTF-8; pytest и Qt | + +## Возможности, собранные из журналов SETGUI + +| Возможность | Источник / поведение общего компонента | +|---|---| +| Очистка | Канальные консоли платы, TX/RX, Modbus; удаляет также скрытые строки и очередь обновления | +| Пауза | Эмуляторы CAN; экран заморожен, история продолжает принимать данные до заданного предела | +| TX/RX | Диагностика и эмуляторы; служебные ошибки без направления остаются видны | +| Автопрокрутка | Мониторы CAN и RS; её можно отключить для чтения истории | +| Цвета | Консоль платы и монитор шины; сохраняются при переразборе фильтра | +| HEX/ASCII | Диагностика RS; формат применяется к явно переданному payload | +| Сохранение | Мониторы CAN и RS; экспорт фактически видимого текста в UTF-8 | +| Поиск, копирование, перенос, масштаб | Общие инструменты всех подключённых текстовых журналов | + +## Подключение + +```python +from set_devices.qt_ports.console import ConsoleView # Подключаем общий порт представления templates. +console = ConsoleView(limit=4000, payloads=True) # Храним не более 4000 строк, включая скрытые и поступившие на паузе. +layout.addWidget(console.panel, 1) # В layout вставляется контейнер с инструментами и редактором. +console.append_message("RX ответ", direction="RX", payload=b"OK") # Передаём готовую подпись и байты без повторного разбора протокола. +console.append_message("Ошибка связи", color="#ff7b7b") # Служебная ошибка остаётся видна при выключенных TX и RX. +console.userCleared.connect(clear_frame_history) # Отдельный буфер кадров очищается тем же пользовательским действием. +``` + +Старые вызовы `appendPlainText`, `appendHtml`, `setPlainText`, `clear`, +`toPlainText` и `setMaximumBlockCount` поддерживаются. `setPlainText` заменяет +снимок истории, учитывая текущую паузу. Для внешней истории кадров подключите +`userCleared`: программный `clear()` повторно этот сигнал не испускает. + +`directions=False` скрывает встроенные флажки, если приложение уже имеет свои +фильтры TX/RX. `payloads=True` показывает форматы HEX/ASCII. События должны +поступать в GUI-потоке Qt, как при работе с обычным `QPlainTextEdit`. + +При заполнении история обновляет экран пачками с интервалом 100 мс. +Количество строк на панели относится ко всей ограниченной истории. +На паузе сохранение и копирование используют замороженный видимый экран. + +## Три запускаемых примера + +Из каталога `python`, с установленными зависимостями `.[qt]`: + +```powershell +python examples/console_examples.py --kind service +python examples/console_examples.py --kind can +python examples/console_examples.py --kind rs485 +``` + +Без `--kind` открываются все три примера. Аппаратура не требуется. +В каждом примере можно проверить очистку, паузу, поиск, TX/RX, экспорт, +копирование, автопрокрутку, перенос и масштаб; в CAN и RS485 — HEX/ASCII. + +Используется в SETGUI: CAN/RS485 и служебная консоль ESP, журналы соединения +и TX/RX, эмуляторы CAN, CAN FD, Modbus, диагностика ПМ35 и ТМС2812, +спектр и логический анализатор Altera. diff --git a/python/set_devices/qt_ports/console.py b/python/set_devices/qt_ports/console.py new file mode 100644 index 0000000..a2efe2b --- /dev/null +++ b/python/set_devices/qt_ports/console.py @@ -0,0 +1,156 @@ +"""Общая консоль Qt: ограниченная история и инструменты просмотра без управления транспортом.""" # Модуль относится к порту представления templates и не реализует протоколы устройств. +from collections import deque # Кольцевая история ограничивает память при непрерывном обмене. +from html import escape # Текст устройства не должен становиться HTML-разметкой журнала. +from pathlib import Path # Экспорт сохраняет явно выбранный пользователем файл в UTF-8. +import re # Метки направления извлекаются только из начала строки после необязательного времени. +try: # Поддерживаем актуальный Qt и существующие установки на Python для Windows 7. + from PySide6.QtCore import QTimer, Signal # Таймер объединяет обновления заполненного журнала. + from PySide6.QtGui import QFont, QTextDocument # Документ извлекает обычный текст из уже оформленных сообщений приложения. + from PySide6.QtWidgets import QApplication, QCheckBox, QComboBox, QFileDialog, QHBoxLayout, QLabel, QLineEdit, QMessageBox, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget # Панель использует только стандартные элементы Qt. +except ImportError: # Старый порт сохраняет тот же публичный интерфейс консоли. + from PySide2.QtCore import QTimer, Signal # В Qt 5 доступны те же сигналы и таймеры. + from PySide2.QtGui import QFont, QTextDocument # Цвета и извлечение текста не зависят от версии Qt. + from PySide2.QtWidgets import QApplication, QCheckBox, QComboBox, QFileDialog, QHBoxLayout, QLabel, QLineEdit, QMessageBox, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget # Состав инструментов одинаков в обоих портах. + + +class ConsoleView(QPlainTextEdit): # Наследование сохраняет привычные appendPlainText, appendHtml и toPlainText у потребителей. + userCleared = Signal() # Владелец отдельной истории может удалить её при явном нажатии «Очистить». + + def __init__(self, parent=None, limit=4000, directions=True, payloads=False): # Предел задан в строках, включая скрытые и поступившие на паузе. + super().__init__(parent) # Владельца редактора впоследствии принимает контейнер panel. + self.records = deque(maxlen=max(1, int(limit))) # Каждая запись хранит текст, оформление, направление и необязательные байты. + self.setReadOnly(True) # Журнал показывает полученные события и не допускает ручной подмены текста. + self.setFont(QFont("Cascadia Mono", 9)) # Моноширинный шрифт выравнивает HEX, адреса и метки времени. + super().setMaximumBlockCount(self.records.maxlen) # Документ ограничен тем же количеством строк, что история. + self.timer = QTimer(self) # Таймер уничтожается вместе с редактором и не переживает закрытие вкладки. + self.timer.setSingleShot(True) # За одну пачку входящих строк достаточно одного полного обновления. + self.timer.setInterval(100) # Интервал 100 мс ограничивает перестроения десятью в секунду при полном буфере. + self.timer.timeout.connect(self.refresh) # Перестроение всегда читает последние записи и текущие фильтры. + self.panel = QWidget(parent) # Контейнер можно вставить в layout или вкладку вместо самого редактора. + layout = QVBoxLayout(self.panel) # Две компактные строки инструментов остаются над областью текста. + layout.setContentsMargins(0, 0, 0, 0) # Внешние отступы задаёт приложение-потребитель. + actions = QHBoxLayout() # Основные операции сгруппированы отдельно от фильтров просмотра. + self.clear_button = QPushButton("Очистить") # Очистка удаляет также скрытую историю и накопленное на паузе. + self.clear_button.clicked.connect(self._user_clear) # Сигнал владельцу позволяет очистить дополнительный буфер кадров. + actions.addWidget(self.clear_button) # Очистка постоянно доступна у левого края консоли. + self.pause = QCheckBox("Пауза") # Пауза замораживает экран, продолжая сохранять входящие сообщения. + actions.addWidget(self.pause) # Пауза относится только к этому экземпляру журнала. + self.follow = QCheckBox("Автопрокрутка") # Прокрутку можно отключить для чтения старых записей. + self.follow.setChecked(True) # По умолчанию новые события видны сразу. + actions.addWidget(self.follow) # Управление расположено рядом с паузой просмотра. + for title, callback in (("Копировать", self.copy_visible), ("Сохранить…", self.save_dialog), ("−", lambda: self.zoomOut(1)), ("+", lambda: self.zoomIn(1))): # Масштаб меняется на один шаг Qt без изменения данных. + button = QPushButton(title) # Кнопки используют тему и шрифт приложения. + button.clicked.connect(callback) # Обработчик вызывается только по явному действию пользователя. + actions.addWidget(button) # Одинаковый порядок действий используется всеми консолями. + actions.addStretch(1) # Свободное место не растягивает подписи инструментов. + layout.addLayout(actions) # Основная строка отделена от параметров отображения. + filters = QHBoxLayout() # Поиск и направления занимают вторую строку для умеренной минимальной ширины. + self.search = QLineEdit() # Фильтр работает по обычному тексту всех сохранённых строк. + self.search.setPlaceholderText("Поиск / фильтр текста") # Подпись показывает, что скрытые строки остаются в истории. + filters.addWidget(self.search, 1) # Поле поиска получает свободную ширину консоли. + self.show_tx, self.show_rx = QCheckBox("TX"), QCheckBox("RX") # Служебные сообщения не относятся ни к одному направлению. + for control in (self.show_tx, self.show_rx): # Оба фильтра действуют независимо и применяются к истории. + control.setChecked(True) # Первое открытие показывает весь обмен. + control.setVisible(directions) # Потребители со своими фильтрами могут скрыть дублирующие элементы. + filters.addWidget(control) # Направления расположены рядом с текстовым фильтром. + self.display = QComboBox() # Формат байтов относится только к сообщениям с явно переданным payload. + self.display.addItems(("Как получено", "HEX", "ASCII", "HEX + ASCII")) # Обычный текст и ответы устройства не перекодируются. + self.display.setToolTip("HEX/ASCII применяется к байтам, переданным через append_message(payload=…).") # Приложение явно определяет границы полезной нагрузки. + self.display.setVisible(payloads) # Выбор байтового представления показывается только потребителю с явным payload. + filters.addWidget(self.display) # Представление можно менять без повторной передачи данных. + self.wrap = QCheckBox("Перенос") # Перенос длинных строк удобен на узких панелях. + filters.addWidget(self.wrap) # Переключатель не изменяет исходный текст при экспорте. + self.count = QLabel() # Счётчик показывает объём ограниченной истории, включая скрытые строки. + filters.addWidget(self.count) # Количество остаётся видно при включённом фильтре. + layout.addLayout(filters) # Параметры находятся непосредственно над текстом. + layout.addWidget(self, 1) # Редактор занимает оставшуюся высоту контейнера. + for control in (self.pause, self.show_tx, self.show_rx, self.follow): # Изменения параметров применяются к уже накопленным данным. + control.toggled.connect(self.refresh) # Снятие паузы показывает сохранённые во время неё события. + self.search.textChanged.connect(self.refresh) # Поиск немедленно обновляет видимую часть истории. + self.display.currentIndexChanged.connect(self.refresh) # Выбор HEX/ASCII заново форматирует сохранённый payload. + self.wrap.toggled.connect(lambda checked: self.setLineWrapMode(QPlainTextEdit.WidgetWidth if checked else QPlainTextEdit.NoWrap)) # Отключённый перенос сохраняет горизонтальную прокрутку. + self.setLineWrapMode(QPlainTextEdit.NoWrap) # Начальный режим совпадает с выключенным флажком переноса. + self.refresh() # Пустой журнал сразу получает корректный счётчик. + + def setMaximumBlockCount(self, limit): # Сохраняем совместимость с существующими настройками журналов SETGUI. + self.records = deque(self.records, maxlen=max(1, int(limit))) # Предел ограничивает и скрытую историю, а не только документ. + super().setMaximumBlockCount(self.records.maxlen) # Согласуем вместимость редактора с кольцевым буфером. + self.refresh() # Уменьшение лимита сразу удаляет вытесненные строки с экрана. + + def append_message(self, text, direction="", color=None, payload=None, _html=None, _defer=False): # Принимаем готовый текст и данные, не выполняя разбор протокола. + for line in str(text).split("\n"): # Многострочные расшифровки также подчиняются общему лимиту строк. + match = re.match(r"^(?:\[[^\]]+\]\s*|\d\d:\d\d:\d\d(?:\.\d+)?\s*)?(TX|RX|>>>)\s", line) # Направление распознаётся только у начальной метки, а не по словам внутри ошибки. + role = direction or (("TX" if match[1] == ">>>" else match[1]) if match else "") # Явная роль имеет приоритет над текстовой эвристикой. + html = _html or ('%s' % (escape(color, quote=True), escape(line)) if color else "") # Безопасное оформление сохраняет исходный текст устройства. + record = (line, html, role, bytes(payload) if payload is not None else None) # Снимок payload не зависит от последующих изменений входного bytearray. + expired = len(self.records) == self.records.maxlen # Вытеснение требует убрать старую строку даже при скрытых новых событиях. + self.records.append(record) # На паузе и под фильтрами данные продолжают сохраняться в пределах лимита. + if not self.pause.isChecked() and not _defer: # Пауза и пакетная замена замораживают документ, но не историю. + if expired or self.timer.isActive(): # Заполненный буфер обновляется пачками для устойчивого интенсивного приёма. + if not self.timer.isActive(): self.timer.start() # Следующие события не отодвигают уже запланированное обновление. + elif self._visible(record): self._append_record(record) # Обычный поток дописывает одну строку без переразбора всей истории. + self.count.setText("%d строк" % len(self.records)) # Счётчик истории обновляется даже при замороженном экране. + + def appendPlainText(self, text): # Старые потребители могут продолжать писать обычный текст. + self.append_message(text) # Ограничения, пауза и фильтры применяются через единый путь записи. + + def appendHtml(self, html): # Прежнее цветное оформление приложения остаётся доступно через API QPlainTextEdit. + document = QTextDocument() # Временный документ преобразует форматированный фрагмент в строки для поиска. + document.setHtml(html) # Разметка поступает от приложения; внешние данные оно должно экранировать. + text = document.toPlainText() # Обычный текст используется для поиска и определения направления. + self.append_message(text, _html=html if "\n" not in text else None) # Однострочное оформление сохраняется без полного обновления истории. + + def setPlainText(self, text): # Снимок внешней истории полностью заменяет данные этого представления. + self.timer.stop() # Старое отложенное обновление не должно вернуть предыдущий снимок. + self.records.clear() # Сохраняется только актуальный результат форматирования потребителя. + if not self.pause.isChecked(): super().clear() # При паузе прежний экран сохраняется до возобновления. + if text: self.append_message(text, _defer=True) # Пустой снимок не создаёт фиктивную запись. + self.refresh() # Поиск и фильтры применяются к новому снимку целиком. + + def clear(self): # Программная очистка удаляет все данные и отменяет ожидающее обновление. + self.timer.stop() # Запланированное обновление больше не требуется. + self.records.clear() # Скрытые записи и накопленное на паузе не должны вернуться. + super().clear() # Явная очистка действует сразу даже при замороженном экране. + self.count.setText("0 строк") # Счётчик согласован с удалённой историей. + + def _user_clear(self): # Только действие оператора уведомляет владельца внешней истории. + self.clear() # Сначала очищаем собственный буфер и видимый документ. + self.userCleared.emit() # Потребитель может безопасно вызвать clear повторно без рекурсивного сигнала. + + def _visible(self, record): # Единое условие применяется при добавлении и полном обновлении. + text, _html, role, _payload = record # Поиск использует исходный текст сообщения независимо от выбранного формата байтов. + return (role != "TX" or self.show_tx.isChecked()) and (role != "RX" or self.show_rx.isChecked()) and self.search.text().casefold() in text.casefold() # Служебные сообщения сохраняются при отключённых направлениях. + + def _append_record(self, record): # Добавляем одну подготовленную запись, учитывая формат и положение прокрутки. + text, html, _role, payload = record # Байты присутствуют только при явной передаче payload приложением. + bar, position = self.verticalScrollBar(), self.verticalScrollBar().value() # Запоминаем позицию до изменения размера документа. + mode = self.display.currentIndex() # Нулевой режим сохраняет текст и цвета, заданные потребителем. + if payload is not None and mode: # Формат меняет только подписанную приложением полезную нагрузку. + hexadecimal = payload.hex(" ").upper() # HEX показывает каждый исходный байт двумя цифрами. + ascii_text = "".join(chr(value) if 32 <= value <= 126 else "." for value in payload) # Диапазон печатного ASCII задан стандартом; управляющие байты заменяются точками. + super().appendPlainText(text + " · " + (hexadecimal if mode == 1 else ascii_text if mode == 2 else hexadecimal + " | " + ascii_text)) # Исходная подпись не теряется при смене представления байтов. + elif html: super().appendHtml(html) # Сохраняем безопасное оформление или прежний фрагмент приложения. + else: super().appendPlainText(text) # Обычный текст не интерпретируется как HTML. + bar.setValue(bar.maximum() if self.follow.isChecked() else position) # Отключённая автопрокрутка сохраняет место чтения. + + def refresh(self, *_args): # Сигналы Qt могут передавать индекс, флаг или текст. + self.timer.stop() # Немедленное обновление заменяет ожидающее пакетное перестроение. + if self.pause.isChecked(): return # Изменения фильтров во время паузы применятся после её снятия. + bar, position = self.verticalScrollBar(), self.verticalScrollBar().value() # Сохраняем место чтения до очистки документа. + super().clear() # Очищаем только документ, сохраняя ограниченную историю. + for record in self.records: # Показываем оставшиеся записи в исходном порядке. + if self._visible(record): self._append_record(record) # Скрытые строки остаются доступными для следующего выбора фильтра. + bar.setValue(bar.maximum() if self.follow.isChecked() else min(position, bar.maximum())) # При сокращении документа ограничиваем прежнюю позицию новым диапазоном. + self.count.setText("%d строк" % len(self.records)) # Счётчик включает временно скрытые записи. + + def copy_visible(self): # Экспортируется фактически показанный текст, включая состояние паузы и фильтра. + QApplication.clipboard().setText(self.toPlainText()) # Копирование всей видимой консоли не требует ручного выделения. + + def save_to(self, path): # Отдельный метод позволяет проверить экспорт без системного диалога. + Path(path).write_text(self.toPlainText(), encoding="utf-8") # UTF-8 сохраняет русские сообщения и расшифровки протоколов. + + def save_dialog(self): # Пользователь самостоятельно выбирает назначение журнала. + path, _filter = QFileDialog.getSaveFileName(self, "Сохранить консоль", "console.txt", "Текст UTF-8 (*.txt);;Все файлы (*)") # Диалог не выполняет автоматической записи при отмене. + if path: # Записываем только явно выбранный файл. + try: self.save_to(path) # Обрабатываем отказ файловой системы без прерывания приёма данных. + except OSError as error: QMessageBox.warning(self, "Сохранение консоли", str(error)) # Причина ошибки остаётся доступна оператору. diff --git a/python/tests/test_console.py b/python/tests/test_console.py new file mode 100644 index 0000000..1b50ff1 --- /dev/null +++ b/python/tests/test_console.py @@ -0,0 +1,77 @@ +"""Проверки общей консоли на настоящем Qt без физического устройства.""" # Проверяем сохранность истории, фильтры и очистку при асинхронном обновлении. +import os # Виртуальная платформа выбирается до импорта Qt. +os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") # Тесты не открывают окна на рабочем столе. +import pytest # Фикстура даёт каждому сценарию независимую консоль. +from set_devices.qt_ports.console import ConsoleView, QApplication # Используем реальный порт templates, а не имитацию обработчиков. + + +@pytest.fixture # Создаём отдельный журнал для проверки независимости состояний. +def console(): # Ссылка на приложение удерживается до завершения сценария. + app = QApplication.instance() or QApplication([]) # Qt требует приложение перед созданием виджетов. + view = ConsoleView(limit=3, payloads=True) # Малый предел проверяет вытеснение без большого массива данных. + yield view # Сценарий управляет настоящими сигналами флажков и кнопок. + view.panel.deleteLater() # Удаляется контейнер вместе с редактором и таймером. + app.processEvents() # Отложенное удаление доставляется до следующего сценария. + + +def test_pause_keeps_bounded_history_and_clear_cannot_resurrect(console): # Очистка на паузе должна удалять также невидимые данные. + console.appendPlainText("первая") # Первая запись сразу видна на экране. + console.pause.setChecked(True) # Замораживаем только представление. + for index in range(5): console.appendPlainText("строка %d" % index) # На паузе поступает больше данных, чем помещается в истории. + assert console.toPlainText() == "первая" and len(console.records) == 3 # Экран заморожен, память ограничена. + console.pause.setChecked(False) # Возобновление показывает последние сохранённые строки. + assert console.toPlainText().splitlines() == ["строка 2", "строка 3", "строка 4"] # Вытеснённые записи больше не появляются. + console.appendPlainText("ожидает таймер") # Полный буфер ставит пакетное обновление в очередь. + assert console.timer.isActive() # Проверяем именно очистку при ожидающем обновлении. + console.pause.setChecked(True) # Очистка должна работать и при замороженном экране. + console.clear_button.click() # Пользователь удаляет весь журнал через общую панель. + console.pause.setChecked(False) # Возобновление не должно вернуть старые данные. + assert not console.records and not console.toPlainText() and not console.timer.isActive() # Документ, история и очередь согласованы. + + +def test_filters_restore_hidden_rows_and_preserve_service_errors(console): # Фильтры направлений не должны скрывать ошибки без метки TX/RX. + console.appendPlainText("[12:00:00] TX команда") # Начальная метка после времени определяет направление. + console.appendPlainText("12:00:01.123 RX ответ") # Поддерживаем существующий формат временных меток SETGUI. + console.appendPlainText("#ERR RX timeout") # Слово RX внутри ошибки не делает её принятым пакетом. + console.show_rx.setChecked(False) # Скрываем только входящие пакеты. + console.show_tx.setChecked(False) # Оба направления можно выключить одновременно. + assert console.toPlainText() == "#ERR RX timeout" # Служебная ошибка остаётся доступной оператору. + console.search.setText("ОТВЕТ") # Регистр запроса не должен влиять на поиск. + console.show_rx.setChecked(True) # Входящие данные восстанавливаются из сохранённой истории. + assert console.toPlainText() == "12:00:01.123 RX ответ" # Поиск применяется к той же записи без повторного приёма. + console.search.clear() # Снимаем текстовый фильтр. + assert len(console.records) == 3 # Фильтры не удаляют события. + + +def test_payload_and_utf8_export_use_visible_snapshot(console, tmp_path): # Сохранение и копирование соответствуют выбранному представлению. + console.append_message("RX пакет <текст>", direction="RX", payload=b"A\x00\xff") # Payload содержит печатный, управляющий и не-ASCII байты. + console.display.setCurrentText("HEX + ASCII") # Выбираем совместное представление байтов. + assert console.toPlainText() == "RX пакет <текст> · 41 00 FF | A.." # Непечатные байты заменяются точками без потери HEX. + path = tmp_path / "журнал.txt" # Проверяем кириллицу в имени и содержимом файла. + console.save_to(path) # Экспорт выполняется без диалога, сохраняя тот же код записи. + assert path.read_text(encoding="utf-8") == console.toPlainText() # UTF-8 сохраняет фактически видимый текст. + console.copy_visible() # Кнопка копирует весь показанный журнал. + assert QApplication.clipboard().text() == console.toPlainText() # Буфер обмена совпадает с экспортом. + + +def test_multiline_html_and_snapshot_obey_limit(console): # Предел относится к строкам, а не к числу вызовов записи. + console.appendPlainText("0\n1\n2\n3\n4") # Один пакет расшифровки превышает лимит документа и истории. + console.refresh() # Применяем запланированное пакетное обновление. + assert console.toPlainText() == "2\n3\n4" # Старые строки не возвращаются при смене фильтра. + console.setPlainText("снимок") # Потребитель может передать результат повторного разбора кадров целиком. + console.appendHtml('<ошибка>') # Проверяем совместимость прежнего цветного API SETGUI. + console.search.setText("ошибка") # Поиск должен работать по тексту без тегов разметки. + assert console.toPlainText() == "<ошибка>" # Спецсимволы устройства остаются обычным текстом. + console.search.clear() # Возвращаем обе записи с исходным оформлением. + assert console.toPlainText() == "снимок\n<ошибка>" # Фильтр не теряет предыдущий снимок истории. + + +def test_clear_notifies_external_owner_once(console): # Владелец может очистить свой буфер и повторно вызвать clear без рекурсии. + external = ["старый кадр"] # Имитируем отдельную историю протокольных кадров приложения. + def clear_owner(): # Обработчик очищает внешний источник повторного форматирования. + external.clear() # Старые кадры не вернутся после смены парсера. + console.clear() # Повторный программный вызов не должен снова эмитировать пользовательский сигнал. + console.userCleared.connect(clear_owner) # Подключаем тот же контракт, что консоли платы и TX/RX SETGUI. + console.appendPlainText("строка") # До очистки журнал содержит данные. + console.clear_button.click() # Нажимаем настоящую кнопку Qt. + assert not external and not console.toPlainText() # Обе истории очищены одним действием. From 0c4eab4615a464f53ef76f77dee983991bbe35e4 Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 17 Oct 2026 14:43:13 +0300 Subject: [PATCH 05/18] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BE=D0=B1=D1=89=D0=B8=D0=B9=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D0=BE=D1=80=20CAN-?= =?UTF-8?q?=D0=BA=D0=B0=D0=B4=D1=80=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20Qt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/README.md | 7 + .../set_devices/qt_ports/can_frame_builder.py | 175 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 python/set_devices/qt_ports/can_frame_builder.py diff --git a/python/README.md b/python/README.md index 4e2b50d..30ba13f 100644 --- a/python/README.md +++ b/python/README.md @@ -24,6 +24,13 @@ Saleae SDK подключается при обращении к устройс в приложении. Общая панель обработки графиков размещена в `qt_ports.plot_processing`: [контракт, подключение нового графика и примеры](../c/set-protocol/docs/PLOT_PROCESSING.md). +Конструкторы CAN-адаптера, CAN DevBoard и RS485 DevBoard используют общий +компонент `set_devices.qt_ports.can_frame_builder.CanFrameFields`. Он задаёт +одинаковые поля и исходный режим «Обычный CAN — ID / DLC / Data», сохраняет +альтернативный режим SETCAN и сообщает об изменениях сигналом `changed`. +`frame_values()` возвращает проверенные ID, IDE, Data и необязательный Body; +упаковка конкретного транспорта и отправка остаются у приложения. + Пути к нативным библиотекам задаёт потребитель перед импортом: `SETPROTOCOL_LIBRARY`, при необходимости `ALTERA_LOGIC_LIBRARY`, `CANDLE_LIBRARY`. Порты не ищут DLL в каталогах SETGUI. C99-ядро собирается из `c/set-protocol`, diff --git a/python/set_devices/qt_ports/can_frame_builder.py b/python/set_devices/qt_ports/can_frame_builder.py new file mode 100644 index 0000000..0e99116 --- /dev/null +++ b/python/set_devices/qt_ports/can_frame_builder.py @@ -0,0 +1,175 @@ +"""Общие поля конструктора CAN и SETCAN для адаптеров и обоих каналов DevBoard.""" +from PySide6.QtCore import Signal # Сигнал изменений позволяет владельцу сбрасывать готовый кадр без зависимости от транспорта. +from PySide6.QtGui import QFont # Моноширинный шрифт сохраняет читаемость HEX-идентификатора и данных. +from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QComboBox, QSpinBox, QLineEdit, QLabel # Один набор виджетов определяет форму всех потребителей. +from protocan import protocan as pc # Сборка полей протокола выполняется существующими обёртками общего C-ядра. +from set_devices import can_transport as tr # Проверка CAN ID и разбор HEX используют действующий общий транспорт. + + +DESCRIPTION = "Обычный CAN: задайте ID, DLC и Data. Для сборки ID по полям протокола выберите SETCAN." # Одинаковое пояснение режимов используется во всех панелях. + + +class CanFrameFields(QWidget): # Компонент содержит только ввод кадра; подключение и отправка остаются у владельца. + changed = Signal() # Любое изменение ввода отменяет ранее собранный кадр в соответствующем канале. + + def __init__(self, settings_factory, parent=None): # Редактор SETTINGS передаётся владельцем как визуальный компонент без копирования его реализации. + super().__init__(parent) # Родитель Qt управляет временем жизни всех полей формы. + layout = QVBoxLayout(self) # Единый вертикальный порядок исключает различия между вкладками. + layout.setContentsMargins(0, 0, 0, 0) # Внешние отступы задаёт панель приложения. + self.mode = QComboBox() # Переключатель сохраняет оба набора введённых значений. + self.mode.addItem("Обычный CAN — ID / DLC / Data", "can") # Исходный режим одинаков для всех трёх конструкторов. + self.mode.addItem("SETCAN — поля протокола", "setcan") # Протокольный режим всегда создаёт расширенный идентификатор. + mode_form = QFormLayout() # Первая строка остаётся видимой в обоих режимах. + mode_form.addRow("Режим", self.mode) # Подпись поясняет назначение переключателя. + layout.addLayout(mode_form) # Выбор режима предшествует зависимым полям. + self.can_panel = QWidget() # Контейнер скрывает вместе подписи и редакторы обычного CAN. + can_form = QFormLayout(self.can_panel) # Формат, идентификатор и длина выровнены общей формой. + can_form.setContentsMargins(0, 0, 0, 0) # Поля обоих режимов начинаются на одной вертикали. + self.format = QComboBox() # IDE задаётся явно независимо от численного значения идентификатора. + self.format.addItem("Стандартный — 11 бит (STD)", False) # STD соответствует диапазону CAN ID 0..0x7FF. + self.format.addItem("Расширенный — 29 бит (EXT)", True) # EXT соответствует диапазону CAN ID 0..0x1FFFFFFF. + self.can_id = QLineEdit("123") # Исходный пример идентификатора записан в HEX. + self.can_id.setToolTip("HEX, с префиксом 0x или без него. STD: 0..7FF; EXT: 0..1FFFFFFF.") # Указываем пределы CAN ID без неявного усечения. + self.dlc = QSpinBox() # Пользователь явно задаёт длину обычного CAN-кадра. + self.dlc.setRange(0, 8) # Классический CAN допускает от нуля до восьми байтов Data. + self.dlc.setToolTip("Количество байтов Data должно точно совпадать с DLC; дополнение и обрезка не выполняются.") # Описываем строгую проверку длины. + can_form.addRow("Формат ID (IDE)", self.format) # Формат отражает фактический флаг IDE. + can_form.addRow("CAN ID (HEX)", self.can_id) # Явно обозначаем систему счисления идентификатора. + can_form.addRow("DLC (0..8 байт)", self.dlc) # Длина дана в байтах полезной нагрузки. + layout.addWidget(self.can_panel) # Обычный CAN занимает то же место, что альтернативная форма SETCAN. + self.setcan_panel = QWidget() # Общий контейнер хранит поля составного 29-битного идентификатора. + form = QFormLayout(self.setcan_panel) # Подписи протокола выравниваются с остальными формами. + form.setContentsMargins(0, 0, 0, 0) # Убираем дополнительные внутренние отступы. + self.priority = QComboBox() # Приоритет соответствует старшему полю SETCAN ID. + self.priority.addItems(["0 — критический", "1 — стандартный"]) # Подписи сохраняют существующие значения приоритета протокола. + self.priority.setCurrentIndex(1) # По умолчанию используется стандартный приоритет. + self.route = QComboBox() # Направление отличает запрос мастера от сообщения устройства. + self.route.addItems(["0 — от мастера (PM)", "1 — от устройства"]) # Сохраняем совместимые значения поля ПМ. + self.dtype = QSpinBox() # Тип устройства выбирается отдельно от номера экземпляра. + self.dtype.setRange(0, 7) # Поле Device Type занимает три бита SETCAN ID. + self.dtype.setValue(1) # Сохраняем прежний исходный тип устройства. + self.did = QSpinBox() # Номер устройства задаёт адрес внутри выбранного типа. + self.did.setRange(0, 15) # Поле Device занимает четыре бита SETCAN ID. + self.did.setValue(2) # Сохраняем прежний исходный адрес устройства. + self.mtype = QComboBox() # Тип сообщения определяет подтип и назначение Body. + self.mtype.addItems([item.name for item in pc.MsgType]) # Каталог типов берётся из общего протокольного модуля. + self.mtype.setCurrentText(pc.MsgType.ANALOG.name) # Начальный протокольный пример остаётся аналоговым сообщением. + self.sub = QComboBox() # Набор подтипов меняется вместе с MsgType. + self.arg = QLineEdit("1") # Числовой аргумент поддерживает десятичный ввод и префикс 0x. + self.settings_body = settings_factory() # Используем переданный редактор байтов Z и Y без зависимости от приложения. + self.arg_panel = QWidget() # Альтернативные редакторы аргумента занимают одну строку. + arg_layout = QHBoxLayout(self.arg_panel) # Горизонтальная компоновка сохраняет левое выравнивание SETTINGS. + arg_layout.setContentsMargins(0, 0, 0, 0) # Исключаем сдвиг аргумента относительно остальных редакторов. + arg_layout.addWidget(self.arg) # Обычный аргумент виден для всех типов кроме SETTINGS. + arg_layout.addWidget(self.settings_body) # Два байта SETTINGS заменяют единое поле аргумента. + arg_layout.addStretch(1) # Свободная ширина остаётся справа от редакторов. + self.count = QSpinBox() # RegCount используется протокольными типами Modbus. + self.count.setRange(0, 15) # Поле количества занимает четыре бита Body Modbus. + self.count.setValue(1) # Исходный запрос относится к одному регистру. + self.sub_label = QLabel("Подтип") # Подпись уточняется при выборе типа сообщения. + self.arg_label = QLabel("SensorID / адрес") # Назначение аргумента зависит от MsgType. + rows = [("Priority", self.priority), ("ПМ", self.route), ("Device Type (0..7)", self.dtype), ("Device (0..15)", self.did), ("Msg Type", self.mtype), (self.sub_label, self.sub), (self.arg_label, self.arg_panel), ("RegCount (Modbus)", self.count)] # Единый порядок полей исключает расхождение форм. + for label, control in rows: # Все протокольные строки добавляются из одного визуального описания. + form.addRow(label, control) # Подпись связана с соответствующим редактором. + layout.addWidget(self.setcan_panel) # Протокольная форма показывается только в режиме SETCAN. + self.data = QLineEdit() # Полезная нагрузка общая для обоих способов ввода идентификатора. + self.data.setPlaceholderText("01 02 03 04 05 06 07 08") # Пример показывает формат ввода HEX-байтов. + data_form = QFormLayout() # Общая строка Data остаётся видимой при смене режима. + data_form.addRow("Data (HEX, до 8 байт)", self.data) # Указываем ограничение классического CAN. + layout.addLayout(data_form) # Данные завершают форму перед кнопками владельца. + for control in (self.mode, self.data): # Длинные поля получают достаточную ширину в обоих режимах. + control.setMaximumWidth(420) # Предел 420 пикселей сохраняет компактность исходного конструктора. + self.format.setMaximumWidth(340) # Название формата целиком помещается в строке шириной до 340 пикселей. + for control in (self.priority, self.route, self.mtype, self.sub, self.arg, self.can_id): # Одинаковая ширина полей ID задаётся в общем компоненте. + control.setMaximumWidth(220) # Предел 220 пикселей соответствует прежней форме SETCAN. + for control in (self.dtype, self.did, self.count, self.dlc): # Короткие числовые поля не растягиваются по ширине панели. + control.setMaximumWidth(100) # Предел 100 пикселей достаточен для всех допустимых значений. + font = QFont("Consolas", 10) # Шрифт с фиксированной шириной знаков упрощает чтение HEX. + for control in (self.can_id, self.data): # Числовой HEX и полезная нагрузка оформляются одинаково. + control.setFont(font) # Используем один шрифт для всех владельцев компонента. + self._subtype() # Настраиваем первоначальные подписи до вычисления ширины столбца. + labels = [part.labelForField(part.itemAt(row, QFormLayout.ItemRole.FieldRole).widget()) for part in (mode_form, can_form, form, data_form) for row in range(part.rowCount())] # Собираем подписи всех форм для общего выравнивания. + width = max(label.sizeHint().width() for label in labels) # Ширина столбца рассчитывается в пикселях по текущему шрифту Qt. + for label in labels: # Поля обоих режимов должны начинаться в одной позиции. + label.setMinimumWidth(width) # Самая длинная подпись задаёт единый левый столбец. + for container in (self, self.can_panel, self.setcan_panel, self.arg_panel): # Промежуточные контейнеры наследуют фон панели без тёмных полос. + container.setObjectName("canBuilderFields") # Локальный селектор ограничивает правило контейнерами формы. + container.setStyleSheet("QWidget#canBuilderFields { background: transparent; }") # Редакторы сохраняют собственный штатный фон. + self.mode.currentIndexChanged.connect(self._mode_changed) # Переключение режима одновременно меняет видимость и отменяет готовность кадра. + self.mtype.currentIndexChanged.connect(self._subtype) # Новый MsgType обновляет подтипы и редактор Body. + for control in (self.format, self.priority, self.route, self.mtype, self.sub): # Любой выбор из списка меняет будущий кадр. + control.currentIndexChanged.connect(lambda *_: self.changed.emit()) # Отбрасываем индекс Qt, поскольку владельцу нужен только сигнал устаревания результата. + for control in (self.can_id, self.arg, self.data): # Все текстовые поля участвуют в сборке кадра. + control.textChanged.connect(lambda *_: self.changed.emit()) # Отбрасываем текст сигнала Qt и отменяем старый кадр даже при неверном промежуточном вводе. + for control in (self.dlc, self.dtype, self.did, self.count, self.settings_body.z, self.settings_body.y): # Слежение включает оба байта SETTINGS. + control.valueChanged.connect(lambda *_: self.changed.emit()) # Отбрасываем числовой аргумент Qt, сохраняя единый сигнал необходимости новой сборки. + self._mode_changed() # Начальная видимость одинакова у всех потребителей. + + def _mode_changed(self): # Режим определяет только видимость; введённые значения сохраняются. + raw = self.mode.currentData() == "can" # Полный CAN ID вводится только в обычном режиме. + self.can_panel.setVisible(raw) # Показываем формат, ID и DLC для обычного CAN. + self.setcan_panel.setVisible(not raw) # Альтернативно показываем составные поля SETCAN. + self.changed.emit() # Смена способа ввода отменяет ранее собранный кадр. + + def _subtype(self): # Общие подписи и список подтипов используются всеми экземплярами формы. + msg_type = pc.MsgType[self.mtype.currentText()] # Значение выбирается из существующего общего каталога. + settings = msg_type == pc.MsgType.SETTINGS # Только SETTINGS редактируется отдельными байтами Z и Y. + self.arg.setVisible(not settings) # Единый числовой аргумент скрывается для SETTINGS. + self.settings_body.setVisible(settings) # Двухбайтовый редактор появляется вместо числового аргумента. + table = {pc.MsgType.BROADCAST: (pc.BroadcastType, "Broadcast.Type", "Body (0..15)"), pc.MsgType.DISCRETE: (pc.DiscreteType, "Discrete.Type", "Body (0..4095)"), pc.MsgType.ANALOG: (pc.AnalogType, "Analog.Type", "SensorID (0..4095)")} # Таблица определяет визуальные подписи существующих протокольных перечислений. + current = self.sub.currentText() # Сохраняем выбранный подтип, если он допустим для нового сообщения. + self.sub.clear() # Старые варианты не должны остаться в новом типе сообщения. + self.sub.setEnabled(msg_type in table) # Отдельный подтип доступен только у трёх перечисленных типов. + if msg_type in table: # Подписи и значения перечислений берутся из одного места. + enum, sub_label, arg_label = table[msg_type] # Получаем визуальное описание выбранного MsgType. + self.sub.addItems([item.name for item in enum]) # Значения берутся из общего протокольного каталога. + if current in [item.name for item in enum]: # Совместимый выбор пользователя сохраняется. + self.sub.setCurrentText(current) # Восстанавливаем допустимый подтип после заполнения списка. + else: # Типы без отдельного подтипа используют Body по собственному назначению. + sub_label = "—" # Подпись явно показывает отсутствие подтипа. + arg_label = "Body (обычно 0)" # Для PULSE сохраняем исходное описание аргумента. + if msg_type in (pc.MsgType.MODBUS_COIL, pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # Все четыре вида Modbus задают начальный адрес. + arg_label = "StrAdr (0..4095)" # Двенадцатибитный адрес показан в прежних единицах регистров. + elif msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE: # GAS использует всё поле Body под адрес. + arg_label = "Адрес регистра (0..65535)" # Полный 16-битный диапазон указан в подписи. + elif msg_type == pc.MsgType.ERROR: # Код ошибки вводится в отдельный байт Body. + arg_label = "ErrorCode (0..255)" # Показываем допустимый однобайтовый диапазон. + elif settings: # SETTINGS редактируется двухбайтовым компонентом. + arg_label = "Body: Z | Y" # Подпись соответствует порядку байтов протокола. + self.sub_label.setText(sub_label) # Одинаковая подпись подтипа обновляется во всех вкладках. + self.arg_label.setText(arg_label) # Аргумент всегда подписан по выбранному MsgType. + + def body(self, msg_type, arg, count): # Общая диспетчеризация вызывает существующие обёртки C-ядра без второй реализации wire-кодека. + if msg_type == pc.MsgType.BROADCAST: # BROADCAST объединяет подтип и четырёхбитный аргумент. + return pc.merge_broadcast(pc.BroadcastType[self.sub.currentText()], arg & 0xF) # Маска 0xF сохраняет прежнее ограничение аргумента четырьмя битами. + if msg_type == pc.MsgType.DISCRETE: # Дискретное сообщение использует собственное перечисление подтипов. + return pc.merge_discrete(pc.DiscreteType[self.sub.currentText()], arg) # Поле собирается общим протокольным модулем. + if msg_type == pc.MsgType.ANALOG: # Аналоговое сообщение передаёт SensorID в Body. + return pc.merge_analog(pc.AnalogType[self.sub.currentText()], arg) # Существующий кодек задаёт расположение подтипа и SensorID. + if msg_type in (pc.MsgType.MODBUS_COIL, pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # У четырёх видов Modbus одинаковый формат Body. + return pc.merge_modbus(arg, count) # Адрес и количество объединяются общей функцией протокола. + if msg_type == pc.MsgType.ERROR: # Сохраняем существующую категорию ошибки с нулевым кодом источника. + return pc.merge_error(0, arg) # Размещение кода ошибки остаётся ответственностью общего ядра. + return arg & 0xFFFF # Остальные типы сохраняют прежнее ограничение Body шестнадцатью битами. + + def frame_values(self): # Возвращаем проверенные параметры CAN без упаковки конкретного транспорта. + data = tr.parse_hex(self.data.text()) # Общий разбор сохраняет поддержку пробелов, запятых и префиксов 0x. + if len(data) > 8: # Классический CAN не допускает более восьми байтов данных. + raise ValueError("данные длиннее 8 байт") # Сообщаем об ошибке до передачи в транспорт. + if self.mode.currentData() == "can": # Обычный режим использует полный идентификатор и явный DLC. + identifier = int(self.can_id.text().strip(), 16) # Поле ID всегда интерпретируется как HEX. + extended = bool(self.format.currentData()) # Малый числовой ID также может иметь выбранный EXT. + tr.validate_can_id(identifier, extended) # Проверка общего транспорта запрещает усечение ID до допустимого диапазона. + if len(data) != self.dlc.value(): # Количество введённых байтов обязано точно совпадать с DLC. + raise ValueError(f"DLC = {self.dlc.value()}, а Data содержит {len(data)} байт; количество байтов должно совпадать.") # Оператор видит обе длины и может исправить ввод. + return identifier, extended, data, None # У обычного CAN нет отдельного протокольного Body. + msg_type = pc.MsgType[self.mtype.currentText()] # SETCAN использует выбранный тип сообщения. + arg = self.settings_body.value() if msg_type == pc.MsgType.SETTINGS else int(self.arg.text().strip() or "0", 0) # SETTINGS читается из Z/Y, остальные аргументы поддерживают привычные числовые префиксы. + body = self.body(msg_type, arg, self.count.value()) # Один путь сборки Body применяется ко всем владельцам формы. + identifier = pc.ProtoCanId.build(self.priority.currentIndex(), self.route.currentIndex(), self.dtype.value(), self.did.value(), msg_type, body) # Идентификатор собирается существующей обёрткой общего C-ядра. + return identifier, True, data, body # SETCAN всегда передаётся с расширенным 29-битным идентификатором. + + def bind(self, owner, prefix): # Сохраняем публичные имена полей приложения при переходе на общий компонент. + names = ("mode", "can_panel", "setcan_panel", "format", "can_id", "dlc", "priority", "route", "dtype", "did", "mtype", "sub", "arg", "settings_body", "count", "data", "sub_label", "arg_label") # Совместимые атрибуты позволяют не менять интеграцию транспорта и внешние потребители. + for name in names: # Каждое старое имя ссылается на настоящий виджет общего компонента. + setattr(owner, prefix + name, getattr(self, name)) # Префиксы build_, builder_ и rs485_builder_ разделяют три независимых состояния. From d42f2e16223e80781e77313a675c2fea1b970070 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 19 Oct 2026 12:02:07 +0300 Subject: [PATCH 06/18] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0=D1=82=D0=BE?= =?UTF-8?q?=D1=80=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B8=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=88=D0=B8=D0=B2=D0=BA=D0=B8=20=D0=B2=20=D0=BE=D0=B1?= =?UTF-8?q?=D1=89=D0=B8=D0=B9=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Увеличивать версию при прямом подключении precompile из CCS и Keil. Сохранять счётчик атомарно и оставлять ручной режим без включённого флага. Добавить проверки итератора и обновить примеры подключения. --- .../tests/test_version_iterator.py | 83 +++++++++++++++++++ c/firmware-info/tools/identity.py | 25 +++++- tools/firmware-build/README.md | 22 +++-- .../ccs/firmware_identity.example.json | 3 +- .../keil/firmware_identity.example.json | 3 +- 5 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 c/firmware-info/tests/test_version_iterator.py diff --git a/c/firmware-info/tests/test_version_iterator.py b/c/firmware-info/tests/test_version_iterator.py new file mode 100644 index 0000000..deb7cc8 --- /dev/null +++ b/c/firmware-info/tests/test_version_iterator.py @@ -0,0 +1,83 @@ +"""Проверяет общий сохраняемый итератор версии до компиляции CCS, Keil и CLI.""" # Запуск: python -m unittest discover -s c/firmware-info/tests -p test_version_iterator.py. +import importlib.util # Загружает тот же генератор, который вызывается штатными BAT templates. +import json # Проверяет исходный JSON и метаданные после резервирования версии. +from pathlib import Path # Изолирует проверочные настройки и generated во временном каталоге. +import tempfile # Удаляет только собственные файлы после каждой проверки. +import unittest # Проверяет последовательность номеров, ручной режим и отказы записи. +from unittest.mock import patch # Воспроизводит ошибки файловой системы без изменения прав пользователя. +TOOL = Path(__file__).resolve().parents[1] / "tools/identity.py" # Находит общую реализацию относительно файла теста. +spec = importlib.util.spec_from_file_location("shared_iterator", TOOL) # Не импортирует проектные обёртки или другой генератор из PATH. +identity = importlib.util.module_from_spec(spec) # Создаёт отдельный экземпляр модуля для изолированной подмены отказов. +spec.loader.exec_module(identity) # Загружает функции без выполнения CLI и без изменения рабочих версий. + + +class VersionIteratorTests(unittest.TestCase): # Проверяет поведение общего prepare независимо от IDE. + def setUp(self): # Готовит настройки другого изделия только во временном каталоге. + temporary = tempfile.TemporaryDirectory(prefix="shared iterator ") # Пробелы в пути не должны влиять на атомарную запись настроек. + self.addCleanup(temporary.cleanup) # Удаляет временные файлы даже после ожидаемого отказа генерации. + self.root = Path(temporary.name) # Ограничивает все изменения проверки собственным каталогом. + self.config = self.root / "config.json" # Отделяет исходную настройку от generated/firmware_identity.json. + self.output = self.root / "generated" # Моделирует отдельный каталог текущей конфигурации сборки. + self.settings = {"product": "Другое изделие", "target": "host", "version": [1, 0, 4], "increment_version": True, "extra": {"keep": "настройка"}} # Дополнительное поле проверяет сохранность проектных настроек в UTF-8. + self.save() # Устанавливает номер, на котором обнаружилась остановка прямого подключения. + + def save(self): # Сохраняет выбранные входные настройки для текущего сценария. + self.config.write_text(json.dumps(self.settings, ensure_ascii=False), encoding="utf-8") # Не использует рабочий счётчик какого-либо проекта. + + def prepare(self): # Запускает публичный общий API с детерминированным состоянием Git. + with patch.object(identity, "git_state", return_value={"commit": None, "dirty": None}): # Доступ к Git не влияет на проверку счётчика. + return identity.prepare(self.root, self.root, self.config, self.output) # Вызывает тот же prepare, что CCS, Keil и CLI. + + def test_sequence_and_matching_outputs(self): # Воспроизводит увеличение после 1.0.4 и отсутствие повторного номера. + for expected in ([1, 0, 5], [1, 0, 6]): # Каждый общий pre-build должен занимать ровно один номер. + metadata = self.prepare() # Генерирует реальный заголовок и JSON после атомарного резервирования. + settings = json.loads(self.config.read_text(encoding="utf-8")) # Читает сохранённый источник следующей версии. + self.assertEqual(settings["version"], expected) # Проверяет увеличение исходного JSON, а не только отображаемой версии. + self.assertEqual(settings["extra"], self.settings["extra"]) # Сохраняет неизвестные общему генератору поля проекта. + self.assertEqual(metadata["version"], expected) # Возвращаемые метаданные содержат уже занятый номер. + self.assertEqual(json.loads((self.output / "firmware_identity.json").read_text(encoding="utf-8"))["version"], expected) # Сохранённый паспорт совпадает с источником версии. + self.assertIn(f"#define FIRMWARE_VERSION_PATCH {expected[2]}U", (self.output / "firmware_identity.h").read_text(encoding="utf-8")) # Компилятор получает тот же patch, что manifest. + + def test_manual_mode_preserves_config_bytes(self): # Старые проекты без флага и явно отключённый итератор сохраняют ручную версию. + for enabled in (None, False): # None обозначает отсутствие поля, а не допустимое значение JSON-флага. + self.settings.pop("increment_version", None) # Сначала моделирует старую конфигурацию без нового переключателя. + if enabled is False: self.settings["increment_version"] = False # Затем проверяет явное отключение без удаления поля. + self.save() # Записывает исходный формат, который генератор не должен переформатировать. + original = self.config.read_bytes() # Сравнивает байты, чтобы заметить любую лишнюю запись. + self.assertEqual(self.prepare()["version"], [1, 0, 4]) # Ручной номер используется без увеличения. + self.assertEqual(self.config.read_bytes(), original) # Исходный JSON остаётся побайтно прежним. + + def test_carry_and_exhaustion(self): # Проверяет ограничения трёх разрядов контракта firmware-info v1. + for previous, expected in (([1, 0, 999], [1, 1, 0]), ([1, 255, 999], [2, 0, 0])): # Patch переносится после 999, minor после 255. + self.settings["version"] = previous # Задаёт последнюю версию перед границей разряда. + self.save() # Передаёт граничное значение публичному prepare через JSON. + self.assertEqual(self.prepare()["version"], expected) # Проверяет перенос вместе с реальной записью настроек. + self.settings["version"] = [255, 255, 999] # Устанавливает последний допустимый номер всего контракта. + self.save() # Сохраняет исходный предел перед ожидаемым отказом. + original = self.config.read_bytes() # Переполнение не должно сбрасывать номер в JSON. + with self.assertRaises(ValueError): self.prepare() # Требует явную ошибку вместо повторного использования версии. + self.assertEqual(self.config.read_bytes(), original) # Сохраняет последний занятый номер без частичной записи. + + def test_invalid_flag_does_not_change_config(self): # Не допускает неявное включение счётчика строками, числами или null. + for value in ("true", "false", 1, 0, None, [], {}): # Только JSON true и false являются допустимыми значениями переключателя. + self.settings["increment_version"] = value # Передаёт неверный тип через настоящий JSON. + self.save() # Фиксирует исходные байты для проверки отказа до резервирования. + original = self.config.read_bytes() # Ошибка настройки не должна занимать номер версии. + with self.assertRaises(ValueError): self.prepare() # Останавливает генерацию до изменения счётчика. + self.assertEqual(self.config.read_bytes(), original) # Подтверждает сохранение исходного JSON при отказе проверки. + + def test_generation_failure_consumes_number(self): # Номер неудачной попытки не должен использоваться следующей сборкой. + with patch.object(identity, "write_atomic", side_effect=OSError("header unavailable")): # Воспроизводит отказ записи заголовка после сохранения следующей версии. + with self.assertRaises(OSError): self.prepare() # Передаёт ошибку вызывающему BAT без маскировки успешным завершением. + self.assertEqual(json.loads(self.config.read_text(encoding="utf-8"))["version"], [1, 0, 5]) # Резервирование фиксируется до генерации выходных файлов. + self.assertEqual(self.prepare()["version"], [1, 0, 6]) # Следующая попытка занимает следующий номер, даже если прежняя не дошла до компиляции. + + def test_failed_config_replace_preserves_original(self): # Атомарная замена не должна портить настройки при отказе файловой системы. + original = self.config.read_bytes() # Сохраняет эталон исходного номера и остальных полей. + with patch.object(identity.Path, "replace", side_effect=PermissionError("config unavailable")): # Имитирует отказ фиксации временного файла вместо записи нового JSON. + with self.assertRaises(PermissionError): self.prepare() # Останавливает pre-build, если номер нельзя надёжно сохранить. + self.assertEqual(self.config.read_bytes(), original) # Исходные настройки не заменены частичным или неверным файлом. + self.assertEqual(list(self.root.glob(".firmware-version-*")), []) # При отказе не остаются собственные временные файлы счётчика. + + +if __name__ == "__main__": unittest.main() # Любое нарушение общего итератора возвращает ненулевой код процесса. diff --git a/c/firmware-info/tools/identity.py b/c/firmware-info/tools/identity.py index 725d4ea..a338bca 100644 --- a/c/firmware-info/tools/identity.py +++ b/c/firmware-info/tools/identity.py @@ -45,15 +45,34 @@ def write_atomic(path: Path, text: str): temporary.replace(path) +def next_version(version): # Вычисляет следующий номер по ограничениям общего контракта firmware-info v1. + result = list(version) # Сохраняет исходный номер до успешной проверки полного переполнения. + for index, limit in ((2, 999), (1, 255), (0, 255)): # Patch имеет диапазон 0..999, minor и major занимают по одному октету 0..255. + if result[index] < limit: # Находит младший разряд, который ещё можно увеличить. + result[index] += 1 # Резервирует следующий номер попытки сборки, включая будущие неудачные компиляции. + return result # Старшие разряды сохраняются, переполненные младшие уже обнулены. + result[index] = 0 # Переносит единицу в следующий разряд после достижения предела текущего. + raise ValueError("Firmware version exhausted at 255.255.999") # Не допускает повторного использования номера после полного переполнения. + + def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict: settings = json.loads(config.read_text(encoding="utf-8-sig")) version = settings["version"] - if (len(version) != 3 or any(type(v) is not int for v in version) - or not all(0 <= v <= limit for v, limit in zip(version, (255, 255, 999)))): - raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]") + if not isinstance(version, list) or len(version) != 3 or any(type(value) is not int or not 0 <= value <= limit for value, limit in zip(version, (255, 255, 999))): # Проверяет JSON-массив трёх целых разрядов до любого изменения сохраняемого счётчика. + raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]") # Ошибочные типы, логические значения и выход за пределы контракта останавливают pre-build. + if type(settings.get("increment_version", False)) is not bool: # Отсутствующий флаг сохраняет ручной режим старых проектов; строки true/false не считаются настройкой. + raise ValueError("increment_version must be true or false") # Требует явное логическое значение JSON вместо неявного преобразования Python. for field in ("product", "target"): if not isinstance(settings.get(field), str) or not settings[field].strip(): raise ValueError(f"missing {field}") + if settings.get("increment_version", False): # Прямые вызовы templates из CCS, Keil и CLI используют один и тот же сохраняемый итератор. + version = settings["version"] = next_version(version) # Вычисляет номер для JSON, заголовка и метаданных только один раз. + with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", newline="\n", dir=config.parent, prefix=".firmware-version-", delete=False) as stream: # Временный файл на том же диске позволяет атомарно заменить настройки без частичной записи. + temporary = Path(stream.name) # Запоминает только собственный файл, чтобы не затронуть пользовательские данные при очистке. + try: stream.write(json.dumps(settings, ensure_ascii=False, indent=2) + "\n") # Сохраняет новый номер и все дополнительные поля проекта в UTF-8. + except BaseException: stream.close(); temporary.unlink(); raise # Ошибка записи оставляет исходный JSON целым и удаляет незавершённый файл. + try: temporary.replace(config) # Занимает номер до дальнейших шагов, поэтому отказ генерации или компиляции не повторит его. + finally: temporary.unlink(missing_ok=True) # Удаляет временный файл при ошибке замены; после успеха он уже переименован. source, dependency = git_state(repository), git_state(templates) # A clean application built with a modified templates checkout is dirty too. known = source["commit"] is not None and dependency["commit"] is not None diff --git a/tools/firmware-build/README.md b/tools/firmware-build/README.md index 0453a24..b86b63e 100644 --- a/tools/firmware-build/README.md +++ b/tools/firmware-build/README.md @@ -22,9 +22,9 @@ ## Текущий проект 28335_periph: вызов через firmware_build.bat Для проекта `K:\git_project\28335_periph\UKSSTMS320F28335` используйте -локальную обвязку. Она вызывает общие BAT из templates, увеличивает версию -в проектном JSON и перед публикацией дополнительно проверяет встроенный -паспорт SCI8 и предел EEPROM. +локальную обвязку. Она вызывает общие BAT из templates; общий генератор +увеличивает версию в проектном JSON. Перед публикацией обвязка дополнительно +проверяет встроенный паспорт SCI8 и предел EEPROM. В CCS → **Project Properties → Build → Steps** задайте для Debug и Release следующие команды, каждую одной строкой. @@ -84,7 +84,11 @@ Include paths компилятора для текущего проекта: Следующие разделы описывают прямые вызовы `ccs/precompile.bat` и `ccs/postcompile.bat`. В этом варианте дополнительный последний аргумент postcompile поддерживается и экспортирует целиком папку текущей сборки. -Общие BAT берут версию из JSON и не увеличивают её автоматически. +Общий генератор увеличивает версию прямо при вызове precompile, если в JSON задано `"increment_version": true`. Отсутствующий флаг или `false` сохраняет ручной режим. + +Итератор общий для CCS, Keil и CLI; проектная обёртка не должна увеличивать номер повторно. + +Каждый pre-build атомарно сохраняет следующий номер до генерации паспорта, включая попытки с последующей ошибкой. После patch 999 увеличивается minor, после minor 255 — major; младшие поля обнуляются. После 255.255.999 сборка останавливается. Clean не сбрасывает JSON; одновременные сборки с одним JSON не поддерживаются. Выберите одну схему подключения: её pre-build и post-build должны использовать один набор метаданных. @@ -94,17 +98,18 @@ postcompile поддерживается и экспортирует целик ### 1. Создайте конфигурацию версии -При первом запуске pre-build автоматически копирует `ccs/firmware_identity.example.json` в путь конфигурации из команды (обычно `${PROJECT_LOC}/firmware_identity.json`, рядом с `.project`), если файла ещё нет. Существующий JSON никогда не перезаписывается. После первого запуска откройте его, задайте свои product, target и version и пересоберите проект. Первый запуск использует значения примера: +При первом запуске pre-build автоматически копирует `ccs/firmware_identity.example.json` в путь конфигурации из команды (обычно `${PROJECT_LOC}/firmware_identity.json`, рядом с `.project`), если файла ещё нет. Существующий JSON не заменяется примером; при включённом итераторе в нём обновляется версия. После первого запуска откройте его, задайте свои product, target и version и пересоберите проект. Исходные значения примера перед первым запуском: ```json { "product": "MY_CONTROLLER", "target": "TMS320F28335", - "version": [0, 1, 0] + "version": [0, 1, 0], + "increment_version": true } ``` -Задайте своё изделие, настоящий контроллер и нужную версию. Для TMS320F2812 замените target. Пример версии — 0.1.0; это не номер предыдущих прошивок. Этот JSON — единственное вручную редактируемое место версии в данной схеме. +Задайте своё изделие, настоящий контроллер и нужную версию. Для TMS320F2812 замените target. Начальный счётчик примера — 0.1.0; при включённом итераторе первый pre-build выдаёт 0.1.1. Этот JSON — единственное вручную редактируемое место версии в данной схеме. ### 2. Добавьте команды в CCS @@ -247,7 +252,8 @@ project/ { "product": "MY_CONTROLLER", "target": "STM32F407", - "version": [0, 1, 0] + "version": [0, 1, 0], + "increment_version": true } ``` diff --git a/tools/firmware-build/ccs/firmware_identity.example.json b/tools/firmware-build/ccs/firmware_identity.example.json index acef913..1faef6a 100644 --- a/tools/firmware-build/ccs/firmware_identity.example.json +++ b/tools/firmware-build/ccs/firmware_identity.example.json @@ -1,5 +1,6 @@ { "product": "MY_CONTROLLER", "target": "TMS320F28335", - "version": [0, 1, 0] + "version": [0, 1, 0], + "increment_version": true } diff --git a/tools/firmware-build/keil/firmware_identity.example.json b/tools/firmware-build/keil/firmware_identity.example.json index 7767f6d..cf7b225 100644 --- a/tools/firmware-build/keil/firmware_identity.example.json +++ b/tools/firmware-build/keil/firmware_identity.example.json @@ -1,5 +1,6 @@ { "product": "MY_CONTROLLER", "target": "STM32F407", - "version": [0, 1, 0] + "version": [0, 1, 0], + "increment_version": true } From 6ecf057a86481323bc0d4b9313e1d5774da84802 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 19 Oct 2026 16:33:40 +0300 Subject: [PATCH 07/18] =?UTF-8?q?feat(c2000-linker):=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BC=D0=BE=D1=89?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BB=D0=B8=D0=BD=D0=BA=D0=B5=D1=80=D0=B0=20C20?= =?UTF-8?q?00?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавить генерацию карт COFF для TMS320F28335 и TMS320F2812, проверку CMD/MAP и русскую инструкцию. Проверки: 14 тестов, включая четыре реальные линковки TI для RAM и Flash. --- tools/c2000-linker/.gitignore | 4 + tools/c2000-linker/README.md | 83 +++++++ tools/c2000-linker/TEST_RESULTS.md | 22 ++ tools/c2000-linker/c2000_linker.py | 317 ++++++++++++++++++++++++++ tools/c2000-linker/tests/run_tests.py | 112 +++++++++ 5 files changed, 538 insertions(+) create mode 100644 tools/c2000-linker/.gitignore create mode 100644 tools/c2000-linker/README.md create mode 100644 tools/c2000-linker/TEST_RESULTS.md create mode 100644 tools/c2000-linker/c2000_linker.py create mode 100644 tools/c2000-linker/tests/run_tests.py diff --git a/tools/c2000-linker/.gitignore b/tools/c2000-linker/.gitignore new file mode 100644 index 0000000..919cfec --- /dev/null +++ b/tools/c2000-linker/.gitignore @@ -0,0 +1,4 @@ +# Кэш Python создаётся локальными проверками и не входит в переносимый исходный комплект. +__pycache__/ +# Скомпилированные модули не являются поставляемыми исходниками helper. +*.pyc diff --git a/tools/c2000-linker/README.md b/tools/c2000-linker/README.md new file mode 100644 index 0000000..55569bd --- /dev/null +++ b/tools/c2000-linker/README.md @@ -0,0 +1,83 @@ +# Помощник linker для TMS320F28335 и TMS320F2812 + +Переносимая утилита Python 3.10+ из стандартной библиотеки. Она создаёт стартовые карты **COFF** для RAM и внутренней Flash, объясняет память и проверяет поддерживаемую часть текстовых CMD/MAP. Работает офлайн без SDK, платы и программатора. EABI сейчас не поддерживается. + +Все адреса, длины MEMORY, размеры секций и copy-symbols выражены в **16-битных словах C28x**. Например, `0x1000` слов занимает 8192 физических октета. PAGE 0 и PAGE 1 — логические страницы линкера; одинаковые адреса RAM/Flash на них не означают независимую память. Высокое зеркало L0–L3 F28335 также не даёт дополнительную RAM. H0 F2812 — самостоятельный блок. + +## Быстрый запуск + +Команды приведены относительно корня общего `templates`: + +```powershell +python tools/c2000-linker/c2000_linker.py profiles # Показывает поддерживаемые устройства, boot modes и ABI. +python tools/c2000-linker/c2000_linker.py explain --device 2812 # Объясняет адреса RAM, Flash, BEGIN, CSM и OTP в hex. +python tools/c2000-linker/c2000_linker.py generate --device 28335 --boot flash --output board_flash.cmd # Создаёт стартовый COFF CMD для внутренней Flash. +python tools/c2000-linker/c2000_linker.py generate --device 2812 --boot ram --output board_ram.cmd # Создаёт отдельную RAM-карту F2812 с входом в H0. +python tools/c2000-linker/c2000_linker.py inspect board_flash.cmd --device 28335 --boot flash # Показывает регионы и потенциальные назначения до линковки. +python tools/c2000-linker/c2000_linker.py validate board_flash.cmd --device 28335 --boot flash --map build/board.map --json # Сверяет фактические адреса и размеры MAP той же сборки. +``` + +`generate` атомарно отказывается заменять существующий файл. Для осознанной замены используйте `--force`. Утилита не создаёт родительские каталоги молча, не переписывает исходный CMD при проверке и не меняет проект CCS. + +## Подключение карты к проекту + +1. Выберите ровно нужный MCU, `ram`/`flash` и COFF. Сгенерируйте новый CMD и добавьте его в проект вместо прежней карты памяти. Периферийный `DSP2833x_Headers_nonBIOS.cmd` либо соответствующий F281x headers CMD подключается отдельно из TI SDK: генератор не копирует регистры периферии. +2. Добавьте официальный `CodeStartBranch.asm` выбранного семейства, чтобы `codestart` содержал длинную ветвь к C runtime. Минимальная ASM-ветвь тестов проверяет только синтаксис/адреса линкера и не заменяет штатный стартовый код TI. +3. Согласуйте ABI, RTS-библиотеку и параметры всех объектов. Общий проверенный минимум — `--abi=coffabi -v28 --float_support=softlib`. **F2812 не имеет FPU32**. Линковке обычно нужны `--rom_model`, `--stack_size=0x100`, `--heap_size=0x40` и вывод `--map_file=...`. Размеры стека/heap подбираются для приложения; приведённые значения служат примером. Не превышайте 1024 слова M1 выделенного стеку шаблона. +4. Для Flash скопируйте `ramfuncs` из LOAD во Flash в RUN в RAM **до первого вызова** функции из этой секции, в частности `InitFlash`. Проверьте порядок внутри своего `InitSysCtrl`. Генератор объединяет входные секции `ramfuncs` и `.TI.ramfunc` в один выходной блок и создаёт COFF-символы `_RamfuncsLoadStart`, `_RamfuncsLoadEnd`, `_RamfuncsLoadSize`, `_RamfuncsRunStart`. +5. Выполните настоящую TI линковку и проверьте её MAP. После добавления реальных модулей места может не хватить даже при корректной начальной карте; утилита не выбирает автоматически split-секции, trampolines или overlay. + +Пример использования linker-символов из C COFF: + +```c +#include /* Объявляет memcpy; на C28x один char соответствует адресуемому 16-битному слову. */ +extern unsigned int RamfuncsLoadStart, RamfuncsLoadSize, RamfuncsRunStart; /* C-имена соответствуют linker-именам с ведущим подчёркиванием COFF. */ +memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize); /* Адрес символа LoadSize кодирует число копируемых слов; значение по этому адресу не читается. */ +``` + +Эту операцию помещают в стартовую функцию, не в глобальную область C. Допустим и исторический контракт `LOAD_END`: размер вычисляется по разности адресов `LoadEnd` и `LoadStart`. Проверка принимает `LOAD_SIZE` **или** `LOAD_END` вместе с обоими начальными адресами. + +Flash API, обработчики во время erase/program, частоты/тайминги Flash и внешняя SRAM зависят от приложения и платы. Генератор их не добавляет и не запускает erase/program. Области CSM/OTP не получают загружаемых секций и паролей. + +## Что именно проверяется + +Поддерживаются буквальные десятичные/hex `origin`/`length` (`org`/`len`), один регион на строку, PAGE 0/1 и обычные SECTIONS: `> REGION`, `LOAD = REGION`, `RUN = REGION`, `PAGE`, `TYPE`, `LOAD_START/END/SIZE`, `RUN_START/END/SIZE`, выбор входных `*(ramfuncs)`/`*(.TI.ramfunc)`. + +Находятся физические пересечения RAM/Flash между PAGE и зеркалами F28335, выход за известную встроенную память, поглощение BEGIN/CSM/OTP/reset/ADC_cal общим регионом, загрузка обычных секций в резервы/BootROM, ошибочный Flash `codestart`, потеря постоянной Flash LOAD-копии обычных инициализированных секций и отсутствие контракта копирования RAM-функций. Первые `0x50` слов M0 консервативно оставлены загрузчику; при RAM boot F28335 первые два слова выделены BEGIN. + +С `--map` проверяются текстовые таблицы TI `MEMORY CONFIGURATION`/`SECTION ALLOCATION MAP`, соответствие MEMORY текущему CMD, непустые фактические LOAD/RUN, размещение секций внутри регионов, пересечения и значения copy-symbols. Поддержан перенос имени секции и отметка `*` в MAP TI CGT 22.6. Загружаемый Flash `codestart` должен реально занимать два слова. Без MAP анализируются **потенциальные назначения**, а фактические размеры неизвестны. + +Коды завершения: + +| Код | Значение | +|---|---| +| `0` | В поддерживаемой части не найдено нарушений. Это не проверка стартового C/ASM-кода или аппаратуры. | +| `1` | Найдено нарушение карты либо не удалось прочитать/создать файл. | +| `2` | Проверка неполная: неподдерживаемый синтаксис/память/MAP; также обычная ошибка CLI argparse. | + +При наличии и ошибок, и неполных частей возвращается `1`; все причины остаются в отчёте. JSON содержит `scope`, `issues`, `regions`, `sections` и фактические `allocations`. + +`#include`, `#if`, макросы, выражения в MEMORY, `GROUP`/`UNION`, отдельные `LOAD_PAGE`/`RUN_PAGE`, split `>>`, внешние регионы и чужие MAP-форматы явно дают неполную проверку. TI linker с препроцессором остаётся окончательным инструментом. Передавайте предварительно обработанный числовой CMD, если нужно убрать влияние include/условных ветвей; помощник не исполняет их сам. + +Исходный CMD проекта может перечислять внутреннюю Flash, CSM и `codestart`, хотя RAM COFF/SCI8 загружает только RAM, а перечисленные выходные секции пусты. Поэтому без MAP предупреждение о потенциальной загрузке в CSM не доказывает запись этих слов. С MAP пустые CSM/codestart-секции не считаются фактической записью. RAM COFF может запускаться JTAG или boot-таблицей по её entry point без аппаратного Boot-to-SARAM `codestart`; отсутствие такой секции не считается ошибкой RAM-профиля. Сгенерированный RAM-шаблон всё же предоставляет стандартный BEGIN, подтверждённый тестом TI. + +Внешняя SPI EEPROM хранит SCI8 boot-таблицу и **не расширяет RAM процессора**. Переход с AT25256B на M95M02 увеличивает ёмкость носителя, но не устраняет переполнение RAM при укладке `.text`, `.cinit`, `.ebss`. Она не является CPU-addressable MEMORY-регионом. + +## Проверки + +```powershell +python tools/c2000-linker/tests/run_tests.py -v # Выполняет переносимые stdlib-регрессии без установленного SDK. +python tools/c2000-linker/tests/run_tests.py --ti C:/ti/ccs1230/ccs/tools/compiler/ti-cgt-c2000_22.6.0.LTS -v # Дополнительно компилирует и линкует4 настоящих COFF-профиля, без платы. +``` + +Тесты проверяют обе модели и оба режима, пересечения разных PAGE и зеркала, резерв CSM/OTP, copy-symbols и альтернативный LOAD_END, отказ перезаписи и явную неполноту неподдерживаемого входа. TI smoke создаёт `.text`, `.econst`, `.ebss`, обе входные RAM-секции и `codestart`, затем анализирует **настоящий MAP TI**. Временные C/ASM/OBJ/OUT/MAP удаляются вместе с собственным временным каталогом. Сохранённый результат выполненной проверки — `TEST_RESULTS.md`. + +## Первичные источники и происхождение адресов + +- [TI TMS320F2833x datasheet, SPRS439Q](https://www.ti.com/lit/ds/symlink/tms320f28335.pdf): карта F28335, зеркальные L0–L3, Flash, boot entry, CSM и заводской ADC_cal. +- [TI TMS320F281x datasheet, SPRS174V](https://www.ti.com/lit/ds/symlink/tms320f2812.pdf): раздел 9.3, таблица 9-15 и boot modes; отдельный H0, Flash, OTP, BEGIN и CSM F2812. +- [TI C28x Assembly Language Tools, linker](https://downloads.ti.com/docs/esd/SPRU513P/Content/SPRU513P_HTML/linker-description.html): MEMORY/PAGE, SECTIONS, LOAD/RUN и linker-generated copy-symbols. +- [TI Linker Command File Primer](https://software-dl.ti.com/ccs/esd/documents/sdto_cgt_Linker-Command-File-Primer.html): физическая память и логические страницы C28x. +- [TI Running an Application from Internal Flash, SPRA958L](https://www.ti.com/lit/an/spra958l/spra958l.pdf): boot-to-Flash, перенос RAM-функций и стартовая настройка Flash. + +Числа дополнительно сопоставлены с локальными официальными TI примерами `C2000Ware_5_03_00_00/device_support/f2833x/common/cmd/F28335.cmd`, `28335_RAM_lnk.cmd` и `controlSUITE/libs/math/IQmath/v160/examples/cmd/2812_IQmath_lnk.cmd`. Генератор содержит собственную компактную карту на основе документированных аппаратных фактов; не копирует целиком распространяемые TI linker-файлы и не требует этих абсолютных путей у пользователя. diff --git a/tools/c2000-linker/TEST_RESULTS.md b/tools/c2000-linker/TEST_RESULTS.md new file mode 100644 index 0000000..c6f53b5 --- /dev/null +++ b/tools/c2000-linker/TEST_RESULTS.md @@ -0,0 +1,22 @@ +# Выполненная проверка + +Дата: 19.10.2026. Python 3.13; TI C2000 CGT 22.6.0.LTS для Windows. + +Команда: + +```powershell +python tests/run_tests.py --ti C:/ti/ccs1230/ccs/tools/compiler/ti-cgt-c2000_22.6.0.LTS -v # Выполняет переносимые регрессии и четыре настоящие COFF-линковки. +``` + +Результат: **14 тестов PASS**, включая четыре сочетания: + +| MCU | Режим | TI compiler/linker | CMD/MAP helper | +|---|---|---|---| +| TMS320F28335 | RAM | PASS | PASS | +| TMS320F28335 | Flash | PASS | PASS | +| TMS320F2812 | RAM | PASS | PASS | +| TMS320F2812 | Flash | PASS | PASS | + +В каждой линковке использованы `--abi=coffabi -v28 --float_support=softlib`; fixture содержит `.text`, `.econst`, `.ebss`, `ramfuncs`, `.TI.ramfunc` и двухсловный `codestart`. Проверены фактические LOAD/RUN и значения Flash copy-symbols в MAP TI. + +Регрессии Python дополнительно подтвердили пересечение RAM между PAGE, конфликт высокого зеркала F28335, CSM/OTP, альтернативный LOAD_END, защиту существующего файла и неполную проверку неподдерживаемых конструкций. Прошивка в MCU не записывалась; smoke не проверяет стартовый код и периферию конкретной платы. diff --git a/tools/c2000-linker/c2000_linker.py b/tools/c2000-linker/c2000_linker.py new file mode 100644 index 0000000..30ad0e3 --- /dev/null +++ b/tools/c2000-linker/c2000_linker.py @@ -0,0 +1,317 @@ +"""Создаёт и проверяет стартовые карты COFF TMS320F28335/F2812; не заменяет TI linker.""" # Утилита работает офлайн, читает текстовые CMD/MAP и не обращается к устройству. +import argparse # Стандартная библиотека обеспечивает переносимый CLI без пакетов SDK. +from dataclasses import dataclass # Числовые записи отделяют слова C28x от физических октетов файла. +import json # Структурированный отчёт пригоден для CI без разбора русского текста. +from pathlib import Path # Пути не зависят от установленного SDK и рабочего каталога. +import re # Ограниченная грамматика не исполняет макросы или выражения пользовательского CMD. +import sys # Передаёт отдельные коды ошибок и неполной проверки вызывающей сборке. + +@dataclass(frozen=True) # Адреса исходной карты остаются неизменяемыми при проверке. +class Region: # Один MEMORY-регион в 16-битных адресуемых словах C28x. + name: str # Название связывает регион с выходной секцией. + page: int # PAGE разделяет пространство линкера, но не физическую память. + origin: int # Первый адрес слова в интервале. + length: int # Число слов до исключённого правого конца. + +DEVICES = { # Числа сверены с первичными TI datasheet и официальными linker-примерами, указанными в README. + '28335': {'flash': (0x300000, 0x340000), 'begin': 0x33FFF6, 'otp': (0x380400, 0x380800), 'rom': (0x3FE000, 0x400000), 'ram': ((0, 0x800), (0x8000, 0x10000)), 'ram_entry': 0, 'alias': (0x3F8000, 0x3FC000, 0x8000)}, # SPRS439Q: L0–L3 имеют высокое зеркало, Flash содержит 256K слов. + '2812': {'flash': (0x3D8000, 0x3F8000), 'begin': 0x3F7FF6, 'otp': (0x3D7800, 0x3D7C00), 'rom': (0x3FF000, 0x400000), 'ram': ((0, 0x800), (0x8000, 0xA000), (0x3F8000, 0x3FA000)), 'ram_entry': 0x3F8000, 'alias': None}, # SPRS174V: H0 является отдельной RAM8K слов; Flash128K слов. +} # Внешняя SRAM, EEPROM и Flash API зависят от платы и сюда не добавляются. +NUM = r'(?:0[xX][0-9A-Fa-f]+|[0-9]+)' # Принимает только буквальные значения без выполнения C-выражений. +NAME = r'[A-Za-z_.$][\w.$]*' # Обычные имена MEMORY/SECTIONS TI без расширенного GROUP-синтаксиса. + + +def issue(level, code, message): # Формирует единый формат машиночитаемой и русской диагностики. + return {'level': level, 'code': code, 'message': message} # incomplete влияет на код возврата, а не скрывается как справочный текст. + + +def clean_text(text): # Удаляет C-комментарии без изменения номеров строк. + return re.sub(r'/\*.*?\*/|//[^\n]*', lambda m: ''.join('\n' if c == '\n' else ' ' for c in m[0]), text, flags=re.S) # Скобки внутри пояснений не становятся языком linker-файла. + + +def body(text, keyword): # Выделяет MEMORY или SECTIONS по парным скобкам. + match = re.search(r'\b' + keyword + r'\s*\{', text) # Требует фактическую директиву с телом. + if not match: # Отсутствующий блок означает неверный или неполный вход. + raise ValueError('Не найден блок ' + keyword) # Не возвращает пустую карту под видом успешной проверки. + start, depth = match.end(), 1 # Начальная открывающая скобка уже найдена. + for index in range(start, len(text)): # Вложенные тела обычных секций допускаются. + depth += (text[index] == '{') - (text[index] == '}') # Подсчитывает только уже очищенный от комментариев текст. + if not depth: # Нулевой уровень закрывает именно искомую директиву. + return text[start:index] # Сохраняет внутренние тела секций для дальнейшей проверки. + raise ValueError('Незакрытый блок ' + keyword) # Усечённый файл не может дать положительный результат. + + +def parse_cmd(text): # Разбирает числовые регионы и обычные назначения, явно отмечая всё неподдерживаемое. + text, issues = clean_text(text), [] # Синтаксические ограничения входят в общий отчёт. + for line in re.findall(r'^\s*(#[^\n]+)', text, re.M): # TI-препроцессор не воспроизводится средствами Python. + issues.append(issue('incomplete', 'PREPROCESSOR', line.strip() + ': передайте предварительно обработанный CMD TI.')) # include и условные ветки никогда не игнорируются молча. + if any(len(re.findall(r'\b' + word + r'\s*\{', text)) != 1 for word in ('MEMORY', 'SECTIONS')): # Несколько директив нельзя свести к первому блоку без потери физической карты. + issues.append(issue('incomplete', 'MULTIPLE_BLOCKS', 'Поддерживается ровно один MEMORY и один SECTIONS; объедините предварительно обработанный CMD.')) # Не выдаёт первый разобранный блок за проверку всего файла. + memory, section_text = body(text, 'MEMORY'), body(text, 'SECTIONS') # Требует обе основные директивы. + regions, page = [], 0 # MEMORY без PAGE относится к стандартной странице 0. + rule = re.compile(r'(' + NAME + r')\s*(?:\([RWIX]+\))?\s*:\s*(?:origin|org)\s*=\s*(' + NUM + r')\s*,?\s*(?:length|len)\s*=\s*(' + NUM + r')\s*[,;]?\s*$', re.I) # Выражения длины и неизвестные атрибуты дают incomplete. + for raw in memory.splitlines(): # Один числовой MEMORY-регион задаётся одной строкой. + line = raw.strip() # Отступы и пустые комментарии не влияют на смысл. + if not line: # Пропускает только заведомо пустые строки. + continue # Не увеличивает число неподдерживаемых конструкций. + mark = re.fullmatch(r'PAGE\s+([01])\s*:', line, re.I) # Страница учитывается при разрешении имени региона. + if mark: # Переключение действует на следующие объявления. + page = int(mark[1]) # Номер страницы не изменяет физическую адресацию. + continue # PAGE не является MEMORY-регионом. + match = rule.fullmatch(line) # Полное совпадение исключает незаметное отбрасывание выражений. + if match: # Только полностью понятная запись попадает в проверяемую карту. + regions.append(Region(match[1], page, int(match[2], 0), int(match[3], 0))) # Адрес и длина остаются в словах TI. + else: # Даже часть корректного региона не подтверждает всю строку. + issues.append(issue('incomplete', 'MEMORY_SYNTAX', 'Не разобрана строка MEMORY: ' + line)) # Показывает пользователю точную границу анализа. + heads = list(re.finditer(r'(?m)^\s*(' + NAME + r')\s*:', section_text)) # Обычные выходные секции могут содержать точки в имени. + if heads and section_text[:heads[0].start()].strip(): # Непонятный текст до первой обычной секции не принадлежит телу уже распознанного назначения. + issues.append(issue('incomplete', 'SECTION_PREFIX', 'Не разобран префикс SECTIONS перед первым обычным назначением.')) # Не скрывает потерянное назначение .text или неизвестную конструкцию в начале блока. + sections = [] # Результат связывает LOAD/RUN с конкретными регионами. + for index, head in enumerate(heads): # Охватывает все обычные назначения, включая многострочные LOAD/RUN. + text_body = section_text[head.end():heads[index + 1].start() if index + 1 < len(heads) else len(section_text)] # Следующий заголовок завершает текущее назначение. + target = re.search(r'(?)>\s*(' + NAME + r')', text_body) # Простой > задаёт совпадающие адреса хранения и исполнения. + load = re.search(r'\bLOAD\s*=\s*(' + NAME + r')', text_body, re.I) # LOAD указывает место хранения секции. + run = re.search(r'\bRUN\s*=\s*(' + NAME + r')', text_body, re.I) # RUN определяет адрес исполнения копируемого RAM-кода. + pg = re.search(r'\bPAGE\s*=\s*([01])', text_body, re.I) # Без PAGE однозначность проверяется по всем регионам. + typ = re.search(r'\bTYPE\s*=\s*(NOLOAD|DSECT|COPY|NOINIT)', text_body, re.I) # Различает программирование и фиктивное представление ROM. + section = {'name': head[1], 'load': load[1] if load else target[1] if target else None, 'run': run[1] if run else load[1] if load else target[1] if target else None, 'page': int(pg[1]) if pg else None, 'type': typ[1].upper() if typ else '', 'body': text_body.strip()} # Не подставляет предполагаемый регион при неизвестном синтаксисе. + rest = re.sub(r'\b(?:LOAD|RUN)\s*=\s*' + NAME + r'|(?)>\s*' + NAME + r'|\bPAGE\s*=\s*[01]|\bTYPE\s*=\s*(?:NOLOAD|DSECT|COPY|NOINIT)|\b(?:LOAD_START|LOAD_END|LOAD_SIZE|RUN_START|RUN_END|RUN_SIZE|SIZE)\s*\(\s*' + NAME + r'\s*\)|\*\s*\(\s*[.\w]+\s*\)', '', text_body, flags=re.I) # Поддерживает copy-symbols и выбор входных ramfuncs без полного языка TI. + if re.sub(r'[\s{},;]', '', rest) or not section['load']: # Неизвестный остаток запрещает полный успех. + issues.append(issue('incomplete', 'SECTION_SYNTAX', section['name'] + ': назначение разобрано не полностью.')) # Понятные адреса всё ещё можно показать через inspect. + sections.append(section) # Неполный разбор не скрывает подтверждённые ошибки соседних секций. + if not regions or not sections: # Пустой частичный результат не является проверкой linker-карты. + issues.append(issue('incomplete', 'EMPTY_PARSE', 'Не получены MEMORY-регионы или выходные секции.')) # Требует поддерживаемый числовой вход. + if re.search(r'\b(?:GROUP|UNION|LOAD_PAGE|RUN_PAGE)\b|>>', text): # Раздельные страницы LOAD/RUN и overlay требуют полноценного TI linker. + issues.append(issue('incomplete', 'ADVANCED_SYNTAX', 'GROUP/UNION, >> и LOAD_PAGE/RUN_PAGE не поддерживаются.')) # Ограничение явно включено в статус 2. + return regions, sections, issues # Вызывающий код объединяет синтаксические и аппаратные нарушения. + + +def physical(region, device): # Приводит высокое зеркало L0–L3 F28335 к тем же физическим словам. + alias = DEVICES[device]['alias'] # F2812 H0 преобразовывать нельзя: это отдельная RAM. + start = region.origin - alias[0] + alias[2] if alias and alias[0] <= region.origin < region.origin + region.length <= alias[1] else region.origin # Переносит только целиком расположенный в зеркале интервал. + return start, start + region.length # Во всех расчётах правая граница исключена. + + +def inside(start, end, ranges): # Проверяет полное вхождение интервала в один известный аппаратный блок. + return any(left <= start < end <= right for left, right in ranges) # Нулевая длина и выход за конец не принимаются. + + +def reserves(device, boot): # Описывает стандартные резервы без платоспецифичных EEPROM/Flash API. + p, begin = DEVICES[device], DEVICES[device]['begin'] # Для 2812 и 28335 адреса безопасности различаются. + result = [('BOOT_RSVD', 2 if device == '28335' and boot == 'ram' else 0, 0x50), ('CSM_RSVD', begin - 0x76, begin), ('FLASH_BEGIN', begin, begin + 2), ('CSM_PWL', begin + 2, begin + 10), ('OTP', *p['otp']), ('RESET', 0x3FFFC0, 0x400000)] # Первые 80 слов M0 резервируются консервативно; RAM entry28335 занимает только первые 2. + if device == '28335': # У этой модели имеется заводской код калибровки ADC. + result.append(('ADC_CAL', 0x380080, 0x380089)) # Приложение не должно перезаписывать девять слов ADC_cal. + return result # Секции безопасности не получают загружаемых назначений в генераторе. + + +def validate_cmd(regions, sections, device, boot, active_sections=None): # Проверяет физическую память независимо от логических PAGE. + issues, p = [], DEVICES[device] # Все аппаратные пределы берутся из выбранного, а не угаданного MCU. + known = (*p['ram'], p['flash'], p['rom'], p['otp']) + (((0x380080, 0x380089),) if device == '28335' else ()) # Заводской ADC-регион существует только у 28335. + for index, region in enumerate(regions): # Один регион сравнивается со всеми ранее объявленными. + start, end = physical(region, device) # Высокое зеркало и обычная RAM теперь имеют общую координату. + if region.length <= 0 or region.origin + region.length > 0x400000: # Адреса C28x22-битные, а длина должна выделять реальные слова. + issues.append(issue('error', 'REGION_RANGE', region.name + ': недопустимые адрес или длина.')) # Запрещает выход за адресное пространство. + if not inside(start, end, known): # Периферия и XINTF нуждаются в дополнительных данных платы. + issues.append(issue('incomplete', 'UNKNOWN_MEMORY', region.name + ': вне известных блоков RAM/Flash/ROM; внешнюю память и периферию проверьте отдельно.')) # Не объявляет неподтверждённую память конкретной платы безопасной. + for old in regions[:index]: # Отдельные PAGE не исключают физическое пересечение. + left, right = physical(old, device) # Учитывает зеркало второго региона. + if start < right and left < end and inside(max(start, left), min(end, right), (*p['ram'], p['flash'])): # Соседние интервалы разрешены; вложенные ROM-представления не занимают RAM/Flash. + issues.append(issue('error', 'PHYSICAL_OVERLAP', f'{old.name}/PAGE{old.page} и {region.name}/PAGE{region.page}: общая физическая память 0x{max(start, left):X}..0x{min(end, right):X}.')) # Объясняет источник конфликта, а не только номера страниц. + for name, left, right in reserves(device, boot): # Общий FLASH/RAM-регион не должен поглощать резерв безопасности. + special = region.name == name or name == 'FLASH_BEGIN' and region.name == 'BEGIN' and region.origin == p['begin'] and region.length == 2 or name == 'RESET' and region.name in ('RESET', 'VECTORS', 'ROM') # Точные именованные резервы можно описывать без программирования. + if start < right and left < end and not special: # Проверяет также широкие регионы, пока не занятые секциями. + issues.append(issue('error', 'RESERVED_REGION', f'{region.name} захватывает {name}: 0x{left:X}..0x{right:X}.')) # Требует выделить защищённый интервал отдельно. + for section in sections: # Теперь проверяет потенциальные назначения CMD либо только непустые секции переданного MAP. + if active_sections is not None and section['name'] not in active_sections: # Пустая секция CSM/codestart в RAM COFF не означает фактическую запись Flash. + continue # При наличии MAP вывод о загрузке делается только по реально размещённым секциям. + targets = {} # LOAD и RUN остаются разными даже для одинакового адресного пространства. + for key in ('load', 'run'): # Обе стороны должны однозначно ссылаться на MEMORY. + matches = [r for r in regions if r.name == section[key] and (section['page'] is None or r.page == section['page'])] # PAGE разрешает имя, не создавая физическую память. + if len(matches) != 1: # Пропущенное либо неоднозначное назначение не исправляется догадкой. + issues.append(issue('error', 'SECTION_TARGET', f"{section['name']}: {key.upper()}={section[key]} не определён однозначно; проверьте имя и PAGE.")) # Даёт конкретную сторону LOAD/RUN. + else: # Однозначный регион доступен для аппаратных проверок. + targets[key] = matches[0] # Сохраняет назначение без изменения исходной карты. + if section['type'] not in ('DSECT', 'NOLOAD', 'COPY'): # Эти типы не загружают содержимое в ROM/OTP. + for target in set(targets.values()): # Обычный совпадающий LOAD/RUN проверяется один раз. + start, end = physical(target, device) # Зеркала не обходят защиту памяти. + for name, left, right in reserves(device, boot): # Даже именованный резерв нельзя занять обычной секцией. + if start < right and left < end and not (name == 'FLASH_BEGIN' and section['name'] == 'codestart' and boot == 'flash'): # Исключение — аппаратный двухсловный branch Flash. + issues.append(issue('error', 'RESERVED_SECTION', section['name'] + ': загрузка в резерв ' + name)) # CSM/OTP не программируются автоматически. + if inside(start, end, (p['rom'],)): # Таблицы BootROM существуют, но не являются записываемой памятью. + issues.append(issue('error', 'ROM_LOAD', section['name'] + ': BootROM допускается только как NOLOAD/DSECT.')) # Не выпускает загружаемую секцию в ROM. + if boot == 'flash' and section['name'] in ('.text', '.cinit', '.pinit', '.econst', '.switch') and section['type'] not in ('DSECT', 'NOLOAD', 'COPY'): # После холодного Flash reset обычные инициализированные секции должны иметь сохраняемую копию. + if 'load' not in targets or not inside(*physical(targets['load'], device), (p['flash'],)): # RUN в RAM допустим только при явной стороне LOAD во Flash. + issues.append(issue('error', 'FLASH_LOAD', section['name'] + ': Flash boot требует LOAD во внутренней Flash; загружаемая только в RAM секция исчезнет после reset.')) # Не принимает JTAG-образ RAM за автономно запускаемую Flash-прошивку. + if section['name'] == 'codestart' and 'load' in targets: # Проверяет место длинной ветви независимо от имени региона BEGIN. + target, entry = targets['load'], p['begin'] if boot == 'flash' else p['ram_entry'] # RAM boot2812 использует H0; RAM boot28335 — M0. + if target.origin != entry or target.length != 2 or section['load'] != section['run'] or section['type'] in ('DSECT', 'NOLOAD', 'COPY'): # Пустое или копируемое представление не запускается аппаратным boot ROM. + issues.append(issue('error', 'CODESTART', f'codestart должен загружаться в отдельные 2 слова по адресу 0x{entry:X}.')) # Фактическая длина branch дополнительно проверяется MAP. + if section['name'] in ('ramfuncs', '.TI.ramfunc') and boot == 'flash': # Эти функции исполняются из RAM после копирования из Flash. + load_ok = 'load' in targets and inside(*physical(targets['load'], device), (p['flash'],)) # Адрес хранения должен принадлежать Flash выбранного MCU. + run_ok = 'run' in targets and inside(*physical(targets['run'], device), p['ram']) # Адрес исполнения должен принадлежать встроенной RAM. + symbols_ok = all(re.search(r'\b' + op + r'\s*\(', section['body']) for op in ('LOAD_START', 'RUN_START')) and any(re.search(r'\b' + op + r'\s*\(', section['body']) for op in ('LOAD_SIZE', 'LOAD_END')) # Требует минимальные символы адреса источника, назначения и длины memcpy. + if not (load_ok and run_ok and symbols_ok): # Обычное размещение ramfuncs во Flash не считается выполнением условия. + issues.append(issue('error', 'RAMFUNCS_COPY', section['name'] + ': нужны LOAD=Flash, RUN=RAM и LOAD_START/RUN_START и LOAD_SIZE либо LOAD_END.')) # Сам memcpy приложение обязано выполнить до InitFlash. + if boot == 'flash' and not any(s['name'] == 'codestart' for s in sections): # Прямой запуск main отладчиком не заменяет аппаратную точку входа. + issues.append(issue('error', 'NO_CODESTART', 'Нет codestart; добавьте TI CodeStartBranch.asm и двухсловный BEGIN.')) # Подсказывает обязательный стартовый исходник. + if boot == 'flash' and not any(s['name'] in ('ramfuncs', '.TI.ramfunc') for s in sections): # Flash-карта должна описывать место кода настройки Flash в RAM. + issues.append(issue('error', 'NO_RAMFUNCS', 'Нет ramfuncs/.TI.ramfunc с копированием Flash→RAM.')) # Не обещает безопасную InitFlash только по наличию .text. + return issues # Неполнота синтаксиса добавляется отдельно результатом parse_cmd. + + +def generate(device, boot): # Возвращает стартовый CMD COFF без предположений о внешней плате. + p, regions = DEVICES[device], [] # Берёт профиль ровно указанной модели. + regions.append(Region('BEGIN', 0, p['begin'] if boot == 'flash' else p['ram_entry'], 2)) # Два слова оставлены только branch codestart. + if device == '28335': # RAML0–L3 используют только нижний адрес, без одновременного высокоадресного зеркала. + regions.extend((Region('RAM_CODE', 0, 0x8000, 0x1000 if boot == 'flash' else 0x4000), Region('RAM_DATA', 1, 0x9000 if boot == 'flash' else 0xC000, 0x7000 if boot == 'flash' else 0x4000))) # Код и данные физически разделены, а Flash имеет отдельную RAM для RUN. + else: # У 2812 H0 выделяется коду при RAM boot и данным при Flash boot. + regions.extend((Region('RAM_CODE', 0, 0x8000 if boot == 'flash' else 0x3F8002, 0x1000 if boot == 'flash' else 0x1FFE), Region('RAM_DATA', 1, 0x3F8000 if boot == 'flash' else 0x8000, 0x2000))) # H0 не перекрывает L0/L1 и не подменяется XINTF. + regions.extend((Region('RAMM0', 1, 0x50, 0x3B0), Region('RAMM1', 1, 0x400, 0x400))) # Первые 80 слов M0 консервативно зарезервированы для BootROM; M1 предназначен стеку. + if boot == 'flash': # Объединённый Flash-регион заканчивается до CSM_RSVD. + regions.append(Region('FLASH_APP', 0, p['flash'][0], p['begin'] - 0x76 - p['flash'][0])) # Поддерживает доступные секторы без программирования пароля и boot-entry обычными данными. + regions.extend((Region('RESET', 0, 0x3FFFC0, 2), Region('CSM_RSVD', 0, p['begin'] - 0x76, 0x76), Region('CSM_PWL', 0, p['begin'] + 2, 8))) # CSM показан явно, но не получает загружаемых секций. + lines = [f'/* Стартовая карта TMS320F{device}, {boot.upper()}, COFF; все адреса и размеры — слова 16 бит. */', '/* Добавьте TI CodeStartBranch.asm и Headers_nonBIOS.cmd; настройте RTS, стек и копирование RAM-функций по README. */', 'MEMORY /* PAGE0/PAGE1 не являются независимой физической RAM. */', '{ /* Начало встроенной памяти выбранного MCU. */'] # Русские пояснения сопровождают каждую генерируемую строку кода. + for page in (0, 1): # Порядок повторяет обычное оформление примеров TI. + lines.append(f'PAGE {page}: /* Логическая страница линкера; физические интервалы не дублируются. */') # Не разрешает повторно использовать один адрес на другой странице. + for region in (r for r in regions if r.page == page): # Выводит каждый регион один раз. + lines.append(f' {region.name} : origin = 0x{region.origin:06X}, length = 0x{region.length:06X} /* {region.length} слов; аппаратные адреса профиля TI. */') # Значения переносимы между проектами выбранного MCU. + lines.extend(('} /* Конец MEMORY; внешняя память сюда не добавлена. */', 'SECTIONS /* Назначения стандартных COFF-секций. */', '{ /* Начало выходных секций. */', ' codestart : > BEGIN, PAGE = 0 /* Длинный branch из TI CodeStartBranch.asm в _c_int00. */')) # codestart остаётся отдельным от .text. + program = 'FLASH_APP' if boot == 'flash' else 'RAM_CODE' # Инициализированный код хранится в выбранном загрузочном носителе. + for section in ('.text', '.cinit', '.pinit', '.econst', '.switch'): # Имена соответствуют COFF, а не неподдерживаемому EABI. + lines.append(f' {section} : > {program}, PAGE = 0 /* Код, константы или таблицы инициализации COFF. */') # Не создаёт фиктивной адресуемой области EEPROM. + if boot == 'flash': # Исторические и современные RAM-функции входят в одну выходную секцию копирования. + lines.append(' ramfuncs : { *(ramfuncs) *(.TI.ramfunc) } LOAD = FLASH_APP, RUN = RAM_CODE, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), LOAD_SIZE(_RamfuncsLoadSize), RUN_START(_RamfuncsRunStart), PAGE = 0 /* До первого вызова скопируйте LoadSize слов из LoadStart в RunStart. */') # COFF linker-символам с подчёркиванием соответствуют C-имена без него. + else: # При RAM boot JTAG/boot-таблица загружает код сразу по исполняемому адресу. + lines.append(' ramfuncs : { *(ramfuncs) *(.TI.ramfunc) } > RAM_CODE, PAGE = 0 /* Отдельное копирование из внутренней Flash не требуется. */') # Не генерирует вымышленные Flash copy-symbols. + for section in ('.ebss', '.esysmem', '.cio'): # Изменяемые данные обязательно попадают в RAM. + lines.append(f' {section} : > RAM_DATA, PAGE = 1 /* Переменные, динамическая память или служебный буфер COFF. */') # Фактический объём проверяется линкером и MAP. + lines.extend((' .stack : > RAMM1, PAGE = 1 /* Размер --stack_size не должен превышать 1024 слова M1. */', ' .reset : > RESET, PAGE = 0, TYPE = DSECT /* Reset-vector находится в BootROM и не программируется. */', '} /* CSM/OTP намеренно не имеют загружаемых секций. */')) # Генерация никогда не создаёт пароль безопасности. + return '\n'.join(lines) + '\n' # Возвращает UTF-8 текст с конечным переводом строки. + + +def inspect_map(text, regions, sections, device, boot): # Сверяет поддерживаемый текстовый MAP TI с фактическими назначениями CMD. + issues, allocations = [], [] # MAP добавляет размеры секций, которых нет в исходном CMD. + if 'MEMORY CONFIGURATION' not in text or 'SECTION ALLOCATION MAP' not in text: # Не принимает XML/лог или усечённый файл за обычный MAP TI. + return [issue('incomplete', 'MAP_FORMAT', 'Нужен текстовый MAP TI C2000 с MEMORY CONFIGURATION и SECTION ALLOCATION MAP.')], [] # Частичный формат даёт статус 2. + memory = text.split('MEMORY CONFIGURATION', 1)[1].split('SECTION ALLOCATION MAP', 1)[0] # Исключает таблицы входных секций из разбора MEMORY. + map_regions, page = {}, 0 # PAGE участвует в идентификации названия региона. + for line in memory.splitlines(): # Таблица TI задаёт origin/length/used/unused шестнадцатерично. + mark = re.fullmatch(r'\s*PAGE\s+([01]):\s*', line) # Переключает только логическую страницу записи. + if mark: # Новая страница относится к последующим MEMORY-строкам. + page = int(mark[1]) # Физические интервалы будут проверены независимо от PAGE. + match = re.match(r'\s*(' + NAME + r')\s+([\da-fA-F]{8})\s+([\da-fA-F]{8})\s+([\da-fA-F]{8})\s+([\da-fA-F]{8})\b', line) # Не путает заголовки с числовыми строками. + if match: # Только полноценная строка даёт надёжное сравнение с CMD. + map_regions[match[1], page] = tuple(int(match[i], 16) for i in (2, 3, 4, 5)) # Размеры остаются словами C28x. + for region in regions: # Каждый понятный исходный регион должен присутствовать в MAP этой же сборки. + found = map_regions.get((region.name, region.page)) # Не ищет ближайшее совпадение по адресу другой страницы. + if not found or found[:2] != (region.origin, region.length): # Выявляет старый MAP и линковку с другим CMD. + issues.append(issue('error', 'MAP_MEMORY', region.name + ': origin/length/PAGE MAP не совпадают с CMD.')) # Объясняет необходимость передать карту текущей линковки. + table = text.split('SECTION ALLOCATION MAP', 1)[1].split('GLOBAL SYMBOLS', 1)[0] # Глобальные символы не являются отдельными выделениями секций. + table = re.sub(r'(?m)^(' + NAME + r')[ \t]*\n[ \t]*\*?[ \t]+([01])\s+([\da-fA-F]{8})', r'\1 \2 \3', table) # TI переносит длинное имя выходной секции на предыдущую строку. + heads = list(re.finditer(r'(?m)^(' + NAME + r')\s+\*?\s*([01])\s+([\da-fA-F]{8})\s+([\da-fA-F]{8})([^\n]*)', table)) # Строки input objects имеют отступ и не дублируются. + for index, match in enumerate(heads): # Фактические непустые секции проверяются обеими сторонами LOAD/RUN. + name, page, origin, length = match[1], int(match[2]), int(match[3], 16), int(match[4], 16) # Все числовые колонки TI представлены без префикса 0x. + rule = next((s for s in sections if s['name'] == name), None) # Связывает результат линковки с исходным назначением. + if not rule: # MAP может включать дополнительные headers.cmd, не переданные анализатору. + issues.append(issue('incomplete', 'MAP_SECTION', name + ': секция отсутствует в переданном CMD; полный объединённый CMD не проверен.')) # Отсутствие знания явно снижает полноту результата. + continue # Не угадывает назначение периферийных секций. + if not length or rule['type'] in ('DSECT', 'COPY'): # Пустые и фиктивные секции не занимают физические слова приложения. + continue # Не создаёт ложного пересечения ROM-reset с загрузкой. + attrs = match[5] + table[match.end():heads[index + 1].start() if index + 1 < len(heads) else len(table)] # RUN ADDR может быть напечатан на следующей строке атрибутов. + run = re.search(r'RUN\s+ADDR\s*=\s*([\da-fA-F]{8})', attrs) # Адрес исполнения нельзя подменять Flash-адресом хранения. + addresses = [('load', origin), ('run', int(run[1], 16))] if run else [('load', origin)] # Копируемая секция реально занимает два интервала. + if rule['load'] != rule['run'] and not run: # Неподдерживаемое оформление MAP нельзя объявлять полной проверкой RUN. + issues.append(issue('incomplete', 'MAP_RUN', name + ': не найден RUN ADDR для раздельного LOAD/RUN.')) # Показывает предел конкретного MAP-парсера. + for kind, address in addresses: # Каждый интервал должен помещаться в указанном MEMORY-регионе. + target = next((r for r in regions if r.name == rule[kind] and (rule['page'] is None or r.page == rule['page'])), None) # Повторяет однозначное разрешение назначения TI. + if not target or not target.origin <= address < address + length <= target.origin + target.length: # Проверяет конец всей секции, а не только её начало. + issues.append(issue('error', 'MAP_ALLOCATION', f'{name}/{kind}: 0x{address:X}+0x{length:X} вне назначенного MEMORY.')) # Конкретные адрес и размер помогают исправить карту. + current = Region(name + '/' + kind, page, address, length) # Фактическая запись пригодна для общей проверки физического пересечения. + start, end = physical(current, device) # Высокое зеркало F28335 нормализуется как в CMD. + for old in allocations: # PAGE не является исключением из физической проверки. + left, right = physical(old, device) # Оба сравниваемых интервала имеют одинаковую систему адресов. + if start < right and left < end: # Конец, равный началу следующей секции, разрешён. + issues.append(issue('error', 'MAP_OVERLAP', current.name + ' пересекается с ' + old.name)) # Выявляет также конфликт Flash LOAD с другой секцией. + allocations.append(current) # Следующая секция будет сравниваться с этим размещением. + if name == 'codestart' and (origin != (DEVICES[device]['begin'] if boot == 'flash' else DEVICES[device]['ram_entry']) or length != 2): # Реальная ветвь должна занимать два слова в аппаратной точке входа. + issues.append(issue('error', 'MAP_CODESTART', 'Размер/адрес codestart не соответствует выбранному boot mode.')) # Подтверждает то, что невозможно узнать из одного назначения >BEGIN. + if name in ('ramfuncs', '.TI.ramfunc') and boot == 'flash': # Проверяет наличие именно созданных copy-symbols текущей секции. + expected = {'LOAD_START': origin, 'LOAD_END': origin + length, 'LOAD_SIZE': length, 'RUN_START': int(run[1], 16) if run else None} # Символы должны соответствовать фактическим LOAD/RUN, а не старой сборке. + for op, value in expected.items(): # LOAD_END необязателен в пользовательском CMD; генератор всегда его создаёт. + symbol = re.search(r'\b' + op + r'\s*\(\s*(' + NAME + r')\s*\)', rule['body']) # Имя может отличаться от стандартного Ramfuncs. + if symbol: # Проверяет только явно заказанные символы, сохраняя минимальный контракт LOAD_SIZE. + values = re.findall(r'(?m)^\s*(?:(?:[01]|[A-Za-z_]\w*)\s+)?([\da-fA-F]{8})\s+' + re.escape(symbol[1]) + r'\b', text) # TI печатает символы также в нескольких отсортированных таблицах. + if not values or value is None or any(int(item, 16) != value for item in values): # Наличие слова имени само по себе не подтверждает правильный адрес или размер. + issues.append(issue('error', 'MAP_COPY_SYMBOL', symbol[1] + ': значение MAP не соответствует выделенной секции.')) # Не принимает ложные символы копирования. + if boot == 'flash' and not any(r.name == 'codestart/load' for r in allocations): # Flash boot нуждается в реально загружаемой ветви; одно пустое назначение CMD недостаточно. + issues.append(issue('error', 'MAP_NO_CODESTART', 'MAP не содержит непустой codestart для аппаратного Flash boot.')) # Не подтверждает Flash-образ, запускаемый только прямым переходом отладчика. + if not heads: # Пустой результат не подтверждает реальную укладку приложения. + issues.append(issue('incomplete', 'MAP_EMPTY', 'Не распознаны выходные секции текстового MAP TI.')) # Просит поддерживаемый MAP вместо ложного успеха. + return issues, allocations # Возвращает фактические слова также для JSON/inspect. + + +def main(argv=None): # Выполняет только явно выбранное офлайн-действие. + parser = argparse.ArgumentParser(description=__doc__) # Русская справка объясняет применение отдельной утилиты. + sub = parser.add_subparsers(dest='command', required=True) # По умолчанию пользовательские файлы не создаются. + sub.add_parser('profiles', aliases=['list'], help='Список MCU, boot modes и ABI.') # Не требует SDK или проекта. + exp = sub.add_parser('explain', help='Объяснить память и резервы MCU.') # Поясняет единицы и аппаратные границы. + exp.add_argument('--device', choices=DEVICES, required=True, help='MCU:28335 или 2812.') # Не угадывает похожую модель устройства. + gen = sub.add_parser('generate', help='Создать стартовый CMD COFF.') # Единственное действие записи входных файлов. + gen.add_argument('--output', type=Path, required=True, help='Создаваемый .cmd.') # Местоположение задаёт пользователь. + gen.add_argument('--force', action='store_true', help='Явно разрешить замену существующего файла.') # Без ключа файл защищён от перезаписи. + readers = [sub.add_parser(name, help='Показать и проверить понятную часть CMD/MAP.') for name in ('inspect', 'validate')] # Оба режима читают существующие карты без редактирования. + for command in [gen, *readers]: # Аппаратные параметры нужны всем действиям с картой. + command.add_argument('--device', choices=DEVICES, required=True, help='Ожидаемый MCU.') # Выбор устройства определяет карту, CSM и точку boot. + command.add_argument('--boot', choices=('ram', 'flash'), required=True, help='RAM boot/JTAG либо внутренняя Flash.') # EEPROM boot-таблица относится к ram. + for command in readers: # Только режимы проверки принимают исходные CMD/MAP. + command.add_argument('cmd', type=Path, help='Исходный или предварительно обработанный CMD TI.') # include не читаются и не вычисляются Python автоматически. + command.add_argument('--map', type=Path, help='Текстовый MAP той же линковки.') # Даёт фактические размеры и LOAD/RUN после TI linker. + command.add_argument('--json', action='store_true', help='Структурированный JSON UTF-8.') # Отчёт пригоден для непрерывной сборки. + args = parser.parse_args(argv) # Ошибочный CLI получает стандартный ненулевой статус argparse. + if args.command in ('profiles', 'list'): # Каталог не связан с текущим проектом. + print('TMS320F28335 иTMS320F2812: ram/flash, COFF. EABI не поддерживается.') # Не обещает непроверенный ABI. + return 0 # Простой вывод списка не является аппаратной проверкой. + if args.command == 'explain': # Сводка связывает числа с обязательными действиями при старте. + p = DEVICES[args.device] # Выбирает аппаратные диапазоны для понятной человеку таблицы hex-адресов. + print('TMS320F' + args.device + ' / COFF / адреса и размеры в 16-битных словах') # Единицы C28x явно отличаются от обычных октетов файла. + for title, start, end in [('RAM', a, b) for a, b in p['ram']] + [('Flash', *p['flash']), ('Flash BEGIN', p['begin'], p['begin'] + 2), ('CSM reserve', p['begin'] - 0x76, p['begin']), ('CSM password', p['begin'] + 2, p['begin'] + 10), ('OTP', *p['otp'])]: # Выводит только общие встроенные блоки выбранной модели. + print(f'{title:14} 0x{start:06X}..0x{end - 1:06X} {end - start:6} слов') # Включённый конец удобен для сопоставления с таблицей datasheet. + print('TI flags: --abi=coffabi -v28 --float_support=softlib; F2812 не имеет FPU32.') # Стартовый профиль переносится между обеими моделями без аппаратной FPU. + print('Внешняя EEPROM хранит boot-таблицу и не увеличивает RAM; объём RAM проверяйте по MAP.') # Большая M95M02 не устраняет переполнение .text/.ebss в RAM. + print('Адреса и длины — слова 16 бит. PAGE0/PAGE1 физически общие. BEGIN —2 слова. CSM/OTP/BootROM не программируются. Flash ramfuncs копируются до InitFlash. См.README.') # Объясняет назначение резервов и LOAD/RUN. + return 0 # Пользовательская карта в этой команде не проверяется. + try: # Обычные ошибки пути и синтаксиса не скрываются traceback. + if args.command == 'generate': # Выполняет только явно запрошенную запись. + text = generate(args.device, args.boot) # Получает готовый UTF-8 шаблон COFF. + regions, sections, issues = parse_cmd(text) # Проверяет встроенную карту тем же parser, что пользовательскую. + issues += validate_cmd(regions, sections, args.device, args.boot) # Ошибка генератора не должна попасть в проект. + if issues: # Собственный шаблон обязан поддерживаться целиком. + raise ValueError('; '.join(i['message'] for i in issues)) # Не сохраняет сомнительный или частично проверенный CMD. + with args.output.open('w' if args.force else 'x', encoding='utf-8', newline='\n') as stream: # Режим x атомарно защищает существующий файл от случайной замены. + stream.write(text) # Каждая строка CMD сопровождается русским комментарием. + print('Создан ' + str(args.output) + '; добавьте стартовый код и проверьте MAP/README.') # Шаблон не считается готовой прошивкой платы. + return 0 # Генератор не запускает программатор или сторонний процесс. + regions, sections, issues = parse_cmd(args.cmd.read_text(encoding='utf-8-sig')) # Поддерживает пользовательский UTF-8 с BOM без изменения файла. + allocations = [] # Без MAP реальный размер секций неизвестен. + if args.map: # Дополнительная проверка выполняется только по явно переданной карте. + extra, allocations = inspect_map(args.map.read_text(encoding='utf-8-sig'), regions, sections, args.device, args.boot) # Не читает COFF и бинарные прошивки. + issues += extra # Ограничения MAP также участвуют в итоговом статусе. + active = {r.name.rsplit('/', 1)[0] for r in allocations} if args.map else None # Без MAP все назначения потенциальны; с MAP пустые CSM-секции не выдаются за запись Flash. + issues += validate_cmd(regions, sections, args.device, args.boot, active) # Физические MEMORY-пересечения проверяются всегда; фактическая загрузка секций уточняется MAP. + status = 1 if any(i['level'] == 'error' for i in issues) else 2 if issues else 0 # Код 1 — найденное нарушение, код 2 — неполная проверка. + report = {'status': status, 'scope': 'Подмножество CMD; без MAP размеры секций неизвестны. TI linker и стартовый код проверяются отдельно.', 'device': args.device, 'boot': args.boot, 'regions': [r.__dict__ for r in regions], 'sections': sections, 'allocations': [r.__dict__ for r in allocations], 'issues': issues} # Машинный результат не теряет пределы применимости анализа. + if args.json: # JSON не смешивается с обычными строками stdout. + print(json.dumps(report, ensure_ascii=False, indent=2)) # Русские пояснения остаются читаемыми UTF-8. + else: # Человеческий режим показывает карту и все ограничения. + for region in regions: # Страница выводится рядом с физическим адресом для объяснения конфликта. + print(f'{region.name:14} PAGE{region.page} 0x{region.origin:06X}..0x{region.origin + region.length - 1:06X} ({region.length} слов)') # Правая граница включённая только при выводе человеку. + for item in issues: # Неподдерживаемая конструкция не скрывается за успешным частичным разбором. + print(f"{item['level'].upper()} {item['code']}: {item['message']}") # Стабильный код помогает автоматизировать диагностику. + print('Проверенная часть: нарушений не найдено; размеры требуют MAP/TI linker.' if not issues else 'Есть ошибки/непроверенные конструкции; вся карта не подтверждена.') # Не приравнивает статический успех к полной аппаратной проверке. + return status # Возвращает результат без изменения CMD/MAP. + except (OSError, ValueError) as error: # Отсутствующий путь, существующий файл и неверный формат имеют понятный отказ. + print('ОШИБКА: ' + str(error), file=sys.stderr) # stderr не портит структурированный успешный отчёт. + return 1 # Неудача чтения/генерации не может считаться проверкой. + +if __name__ == '__main__': # Импорт в unittest не выполняет CLI и не создаёт файлы. + raise SystemExit(main()) # Передаёт точный статус процессу сборки. diff --git a/tools/c2000-linker/tests/run_tests.py b/tools/c2000-linker/tests/run_tests.py new file mode 100644 index 0000000..3cc8f35 --- /dev/null +++ b/tools/c2000-linker/tests/run_tests.py @@ -0,0 +1,112 @@ +"""Регрессии карт памяти и необязательная реальная COFF-линковка четырёх профилей TI.""" # Проверяет полезные свойства карты, не повторяя реализацию parser. +import argparse # Принимает необязательный путь к установленному TI CGT для smoke. +import contextlib # Перехватывает stdout CLI при проверке отказа перезаписи. +import importlib.util # Импортирует helper относительно каталога теста без установки пакета. +import re # Разбирает контекст диагностической строки MAP при отказе smoke, не меняя рабочий parser. +import io # Сохраняет русскую диагностику CLI в памяти теста. +from pathlib import Path # Временные CMD/MAP не пишутся в пользовательский проект. +import subprocess # Вызывает настоящий TI compiler/linker только по явному параметру --ti. +import sys # Даёт возможность запускать тесты обычным Python3. +import tempfile # Удаляет только собственные временные сборки после тестов. +import unittest # Стандартная библиотека не требует pytest или скачивания зависимостей. +ROOT = Path(__file__).resolve().parents[1] # Находит установленную утилиту независимо от рабочего каталога. +SPEC = importlib.util.spec_from_file_location('c2000_linker', ROOT / 'c2000_linker.py') # Загружает именно проверяемый файл helper. +HELPER = importlib.util.module_from_spec(SPEC) # Создаёт модуль без запуска CLI. +sys.modules[SPEC.name] = HELPER # dataclass находит собственный модуль при аннотировании Region. +SPEC.loader.exec_module(HELPER) # Исполняет только определения функций и числовых профилей. +TI_ROOT = None # Путь compiler задаётся пользователем тестов, не ищется в глобальной системе молча. + + +def checked(text, device='28335', boot='flash'): # Проверяет сгенерированный или намеренно повреждённый CMD реальными функциями helper. + regions, sections, issues = HELPER.parse_cmd(text) # Использует рабочий parser, а не его тестовую копию. + return regions, sections, issues + HELPER.validate_cmd(regions, sections, device, boot) # Сохраняет и неполный синтаксис, и аппаратные нарушения. + + +class MapsTest(unittest.TestCase): # Проверяет границы ответственности и основные причины реальных ошибок linker. + def test_four_profiles(self): # Обе модели и оба boot mode должны генерироваться без неполной проверки. + for device in ('28335', '2812'): # F2812 не наследует адреса Flash или зеркала F28335. + for boot in ('ram', 'flash'): # RAM boot и внутренняя Flash имеют разные BEGIN. + with self.subTest(device=device, boot=boot): # Показывает конкретный аппаратный профиль при регрессии. + regions, sections, issues = checked(HELPER.generate(device, boot), device, boot) # Проверяет готовый текст, включая каждый русский комментарий CMD. + self.assertEqual(issues, []) # Собственные профили обязаны поддерживаться полностью. + self.assertEqual(next(r for r in regions if r.name == 'BEGIN').origin, HELPER.DEVICES[device]['begin' if boot == 'flash' else 'ram_entry']) # BEGIN соответствует первичным адресам TI. + def test_overlap_across_pages(self): # PAGE0/PAGE1 не дают две независимые копии L0. + text = HELPER.generate('28335', 'flash').replace('RAM_DATA : origin = 0x009000', 'RAM_DATA : origin = 0x008000') # Намеренно размещает данные поверх RAM-функций на другой странице. + self.assertIn('PHYSICAL_OVERLAP', [i['code'] for i in checked(text)[2]]) # Ошибка обнаруживается до запуска TI. + def test_high_alias(self): # Высокое зеркало L0–L3 также не добавляет физической RAM. + text = HELPER.generate('28335', 'ram').replace('RAM_DATA : origin = 0x00C000', 'RAM_DATA : origin = 0x3F8000') # Данные используют высокое зеркало того же L0–L3, где лежит код. + self.assertIn('PHYSICAL_OVERLAP', [i['code'] for i in checked(text, boot='ram')[2]]) # Проверка сравнивает физические адреса, а не строки чисел. + def test_flash_reserved(self): # Широкий FLASH_APP не может поглотить CSM_RSVD, BEGIN и пароль. + text = HELPER.generate('2812', 'flash').replace('length = 0x01FF80', 'length = 0x020000') # Расширяет код до физического конца Flash поверх служебных слов. + self.assertIn('RESERVED_REGION', [i['code'] for i in checked(text, '2812')[2]]) # Адреса 2812 сверяются по собственному профилю. + def test_otp_write(self): # Отдельное имя OTP не разрешает программировать его обычной секцией. + text = HELPER.generate('28335', 'flash').replace('PAGE 0:', 'PAGE 0:\n OTP : origin = 0x380400, length = 0x400', 1).replace(' .reset :', ' unsafe : > OTP, PAGE = 0\n .reset :') # Вводит потенциально необратимую загрузку данных в OTP. + self.assertIn('RESERVED_SECTION', [i['code'] for i in checked(text)[2]]) # Наличие резервного MEMORY не делает его записываемой RAM. + def test_flash_text_cannot_load_only_to_ram(self): # Рабочий после JTAG код не обязательно сохраняется при холодном Flash reset. + text = HELPER.generate('28335', 'flash').replace('.text : > FLASH_APP', '.text : > RAM_CODE') # Сохраняет корректные codestart и ramfuncs, но намеренно теряет постоянную копию основного кода. + self.assertIn('FLASH_LOAD', [i['code'] for i in checked(text)[2]]) # Flash-профиль не должен подтверждать такую карту полным успехом. + def test_copy_contract(self): # Flash RAM-функции требуют источника, назначения и количества слов. + text = HELPER.generate('28335', 'flash').replace('LOAD_SIZE(_RamfuncsLoadSize),', '').replace('LOAD_END(_RamfuncsLoadEnd),', '') # Удаляет только размер копирования, сохраняя остальные корректные назначения. + self.assertIn('RAMFUNCS_COPY', [i['code'] for i in checked(text)[2]]) # Отсутствие одного обязательного символа действительно обнаруживается. + def test_copy_end_alternative(self): # Исторический memcpy вправе вычислять размер как LoadEnd-LoadStart. + text = HELPER.generate('28335', 'flash').replace('LOAD_SIZE(_RamfuncsLoadSize),', '') # Оставляет действующие LOAD_END и оба начальных адреса. + self.assertEqual(checked(text)[2], []) # Не требует лишнего LOAD_SIZE у совместимых старых проектов TI. + def test_incomplete_preprocessor(self): # include и выражения не должны исчезать из итогового статуса. + text = '#include "board.cmd"\n' + HELPER.generate('28335', 'ram') # Неизвестный файл мог бы изменить физическую карту. + self.assertIn('PREPROCESSOR', [i['code'] for i in checked(text, boot='ram')[2]]) # Пользователь получает явно неполную проверку. + def test_unknown_syntax(self): # GROUP/UNION и split не интерпретируются ограниченным parser как обычный регион. + text = HELPER.generate('28335', 'ram').replace('.text : > RAM_CODE', '.text : >> RAM_CODE') # Требует поддерживаемого только TI разбиения секции. + self.assertIn('ADVANCED_SYNTAX', [i['code'] for i in checked(text, boot='ram')[2]]) # Поддерживаемая часть карты не даёт ложного полного успеха. + def test_unparsed_extra_blocks(self): # Грамматика не может молча проверить только начало сложного CMD. + text = HELPER.generate('28335', 'ram') # Использует заведомо корректную исходную карту. + extra = text + 'MEMORY { PAGE 1: OTHER : origin = 0x8000, length = 0x100 }' # Второй блок мог бы занять уже используемые физические слова. + self.assertIn('MULTIPLE_BLOCKS', [i['code'] for i in checked(extra, boot='ram')[2]]) # Даже численно понятный первый блок не даёт полного успеха. + prefix = text.replace('{ /* Начало выходных секций. */', '{ BROKEN_DIRECTIVE /* Начало выходных секций. */') # Вставляет неизвестный префикс, который не является телом предыдущей секции. + self.assertIn('SECTION_PREFIX', [i['code'] for i in checked(prefix, boot='ram')[2]]) # Произвольное начальное содержимое явно делает проверку неполной. + def test_no_overwrite(self): # Файл пользователя сохраняется без явно указанного --force. + with tempfile.TemporaryDirectory() as tmp: # Выделяет отдельный безопасный каталог для проверки записи. + target = Path(tmp) / 'board.cmd' # Существующий linker-файл не связан с рабочим проектом. + target.write_text('USER FILE', encoding='utf-8') # Контрольное содержимое должно остаться неизменным. + with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()): # Не засоряет успешный вывод ожидаемой ошибкой CLI. + result = HELPER.main(['generate', '--device', '2812', '--boot', 'ram', '--output', str(target)]) # Проверяет настоящий режим x, а не предварительный exists. + self.assertEqual(result, 1) # Отказ перезаписи имеет ненулевой код. + self.assertEqual(target.read_text(encoding='utf-8'), 'USER FILE') # Пользовательские данные не изменены. + def test_unknown_map(self): # Произвольный лог не считается успешно проверенным MAP. + regions, sections, unused = checked(HELPER.generate('28335', 'ram'), boot='ram') # Даёт анализатору корректный исходный CMD. + issues, allocations = HELPER.inspect_map('not a TI map', regions, sections, '28335', 'ram') # Пробует заведомо чужой текстовый формат. + self.assertEqual(issues[0]['code'], 'MAP_FORMAT') # Отказ объясняет нужный формат TI. + + +class TiSmokeTest(unittest.TestCase): # Тестирует реальную грамматику и MAP TI вместо тестовых выдуманных адресов. + def test_real_ti_four_profiles(self): # Четыре настоящие COFF-сборки выполняются только с указанным установленным CGT. + if TI_ROOT is None: # Обычные stdlib-тесты остаются переносимыми без проприетарного компилятора. + self.skipTest('Для четырёх настоящих TI линковок задайте --ti .') # Пропуск явно виден в отчёте. + compiler = TI_ROOT / 'bin/cl2000.exe' # На Windows smoke использует согласованный пользователем установленный TI CGT. + self.assertTrue(compiler.is_file(), str(compiler)) # Не подменяет отсутствие компилятора успешной проверкой Python. + with tempfile.TemporaryDirectory(prefix='c2000-linker-ti-') as tmp: # Все объектные файлы и MAP находятся только во временном каталоге. + folder = Path(tmp) # Минимальная сборка не зависит от SDK или пользовательского проекта. + source = folder / 'fixture.c' # Исходник содержит типичные секции COFF обоих устройств. + source.write_text('volatile int observed; /* Создаёт изменяемую .ebss для проверки RAM. */\nconst int setting = 17; /* Создаёт .econst с числовой константой без аппаратного адреса. */\n#pragma CODE_SECTION(ram_old, "ramfuncs") /* Проверяет историческое имя секции RAM-кода. */\nint ram_old(void) { return observed + setting; } /* Даёт непустой LOAD/RUN для проверки размера копирования. */\n#pragma CODE_SECTION(ram_new, ".TI.ramfunc") /* Проверяет современную входную секцию в том же копируемом блоке. */\nint ram_new(void) { return observed + 2; } /* Не требует FPU32, аппаратных заголовков или RTS-арифметики. */\nint main(void) { observed = ram_old() + ram_new(); return 0; } /* Только проверяет линковку; этот тест никогда не запускается на MCU. */\n', encoding='utf-8') # Каждая строка fixture имеет осмысленный русский комментарий. + start = folder / 'start.asm' # Собственный минимальный branch исключает зависимость теста от TI SDK. + start.write_text(' .sect "codestart" ; Помещает проверочную двухсловную ветвь в аппаратный BEGIN.\n .global _boot_start ; Задаёт явную точку входа COFF для теста линкера.\n .ref _main ; Объявляет цель из минимального C-файла.\n_boot_start: LB _main ; Длинная ветвь занимает два слова C28x без настройки периферии.\n', encoding='utf-8') # Не выдаёт smoke branch за полноценный CodeStartBranch промышленного приложения. + for device in ('28335', '2812'): # Оба устройства собираются как C28x без FPU32. + for boot in ('ram', 'flash'): # Проверяет отдельный BEGIN, RAM и Flash LOAD/RUN. + with self.subTest(device=device, boot=boot): # Ошибка указывает конкретный профиль. + prefix = folder / (device + '_' + boot) # Разные OUT/MAP исключают использование предыдущей сборки. + cmd = prefix.with_suffix('.cmd') # Выбирает самостоятельную карту для данной линковки. + cmd.write_text(HELPER.generate(device, boot), encoding='utf-8') # В тест идёт именно пользовательский генератор. + subprocess.run([str(compiler), '--abi=coffabi', '-v28', '--float_support=softlib', '--compile_only', str(source), str(start)], cwd=folder, check=True, capture_output=True, text=True) # Настоящий TI компилирует оба fixture без FPU/SDK. + result = subprocess.run([str(compiler), '-v28', '--abi=coffabi', '--run_linker', '--rom_model', '--entry_point=_boot_start', '--stack_size=0x100', '--heap_size=0x40', '--output_file=' + str(prefix.with_suffix('.out')), '--map_file=' + str(prefix.with_suffix('.map')), str(folder / 'fixture.obj'), str(folder / 'start.obj'), str(cmd)], cwd=folder, capture_output=True, text=True) # TI проверяет секции, длины и синтаксис сгенерированной карты. + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) # Любая ошибка linker блокирует подтверждение профиля. + regions, sections, issues = checked(cmd.read_text(encoding='utf-8'), device, boot) # Проверяет ту же карту, что фактически получил TI. + extra, allocations = HELPER.inspect_map(prefix.with_suffix('.map').read_text(encoding='utf-8'), regions, sections, device, boot) # Разбирает настоящий, а не нарисованный под parser MAP. + self.assertEqual(issues + extra, [], str(prefix) + ': ' + str(issues + extra) + '; allocations=' + str([r.name for r in allocations]) + '; codestart=' + str(re.findall(r'codestart[^\n]*\n[^\n]*\n[^\n]*', prefix.with_suffix('.map').read_text(encoding='utf-8')))) # Подтверждает совместимость исходного CMD, LOAD/RUN и реальных copy-symbols TI. + self.assertTrue(allocations) # Пустой MAP-парсер не может дать положительный smoke. + print('TI PASS TMS320F' + device + ' ' + boot + ': COFF, codestart, data, ramfuncs, MAP/copy symbols') # Сохраняет короткое подтверждение каждого реального профиля. + +if __name__ == '__main__': # Импорт теста не запускает компилятор автоматически. + parser = argparse.ArgumentParser(description=__doc__) # Справка описывает явное подключение TI smoke. + parser.add_argument('--ti', type=Path, help='Каталог установленного TI C2000 CGT; включает 4 реальные линковки.') # Не скачивает компилятор и не требует платы. + arguments, unittest_args = parser.parse_known_args() # Допускает обычные флаги unittest вроде-v. + TI_ROOT = arguments.ti.resolve() if arguments.ti else None # Фиксирует согласованный путь перед выполнением тестов. + unittest.main(argv=[sys.argv[0], *unittest_args]) # Возвращает ненулевой код при любой Python/TI регрессии. From 876b58517cfe1df080d1385d24b599c36434fa53 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Oct 2026 14:14:48 +0300 Subject: [PATCH 08/18] =?UTF-8?q?feat(set-protocol):=20=D0=A0=D0=B0=D0=B7?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B8=20GAS=20=D0=B8=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D1=8C=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D1=81=D0=B1=D0=BE=D1=80=20=D1=80=D0=B5=D0=B3=D0=B8?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Сохрани адресацию отдельных регистров GAS 0x3 и выдели слотам тип 0x4 с маской Word0. Добавь единое C-ядро GAS_WATCH2, тонкие Python/JNI-порты и проверки общих эталонных байтов. Совместимость: тип 0x4 больше не обслуживает Modbus Coil. Потребителям PCAN_MSG_MODBUS_COIL и ProtoCanMsgToModbusCoil нужно перейти на GAS_SLOT и отдельный API слотов; регистровый GAS остаётся на 0x3. --- c/set-protocol/CMakeLists.txt | 11 + c/set-protocol/README.md | 9 + c/set-protocol/docs/GAS_SLOT.md | 27 ++ c/set-protocol/docs/GAS_WATCH2.md | 202 ++++++++++ c/set-protocol/docs/GUI_TRENDS.md | 4 + c/set-protocol/docs/legacy/GAS.md | 2 + c/set-protocol/docs/legacy/OAP.md | 8 +- c/set-protocol/docs/legacy/PROTOCOL.md | 11 +- c/set-protocol/include/gui_frame.h | 2 + c/set-protocol/include/pcan_gas.h | 3 +- c/set-protocol/include/pcan_gas_slot.h | 48 +++ c/set-protocol/include/pcan_id.h | 20 +- c/set-protocol/include/pcan_modbus_server.h | 3 +- c/set-protocol/include/protocan_transport.h | 1 + c/set-protocol/include/set_gas_watch.h | 65 +++ c/set-protocol/include/set_invertor_profile.h | 8 + c/set-protocol/include/setprotocol.h | 1 + c/set-protocol/include/setprotocol_abi.h | 1 + c/set-protocol/ports/android/Android.mk | 2 + c/set-protocol/ports/android/gas_slots_jni.c | 42 ++ .../setcorp/setflash/core/ProtoCanCatalog.kt | 2 +- .../kotlin/ru/setcorp/setprotocol/GasSlots.kt | 10 + .../setcorp/setprotocol/NativeSetProtocol.kt | 3 + .../setprotocol/trends/GuiGasWatch2.kt | 73 ++++ .../ports/android/setprotocol_jni.c | 72 ++++ .../ru/setcorp/setprotocol/GasSlotsTest.kt | 34 ++ .../setprotocol/trends/GuiGasWatch2Test.kt | 122 ++++++ c/set-protocol/ports/stm32-bxcan/README.md | 10 +- c/set-protocol/ports/stm32-bxcan/protocan.c | 97 ++--- c/set-protocol/ports/stm32-bxcan/protocan.h | 12 +- c/set-protocol/src/pcan_gas.c | 10 +- c/set-protocol/src/pcan_gas_slot.c | 103 +++++ c/set-protocol/src/pcan_id.c | 10 +- c/set-protocol/src/pcan_modbus_server.c | 22 +- c/set-protocol/src/set_gas_watch.c | 155 ++++++++ .../tests/fixtures/gas-watch-v2.json | 13 + c/set-protocol/tests/test_gas_register.c | 29 ++ c/set-protocol/tests/test_gas_slot.c | 61 +++ c/set-protocol/tests/test_gas_watch.c | 370 ++++++++++++++++++ c/set-protocol/tests/test_modbus_server.c | 16 +- c/set-protocol/tools/build_host.py | 3 + .../protocan/examples/gas-slot-vectors.json | 55 +++ python/logic_analyzer/decoders/set_can.py | 11 +- python/protocan/README.md | 4 + python/protocan/gas_slots.py | 79 ++++ python/protocan/gas_watch.py | 115 ++++++ python/protocan/protocan.py | 44 ++- python/protocan/protocol.py | 2 + .../set_devices/qt_ports/can_frame_builder.py | 6 +- python/tests/test_gas_slots.py | 63 +++ python/tests/test_gas_watch.py | 169 ++++++++ 51 files changed, 2129 insertions(+), 116 deletions(-) create mode 100644 c/set-protocol/docs/GAS_SLOT.md create mode 100644 c/set-protocol/docs/GAS_WATCH2.md create mode 100644 c/set-protocol/include/pcan_gas_slot.h create mode 100644 c/set-protocol/include/set_gas_watch.h create mode 100644 c/set-protocol/include/set_invertor_profile.h create mode 100644 c/set-protocol/ports/android/gas_slots_jni.c create mode 100644 c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/GasSlots.kt create mode 100644 c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/trends/GuiGasWatch2.kt create mode 100644 c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/GasSlotsTest.kt create mode 100644 c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/trends/GuiGasWatch2Test.kt create mode 100644 c/set-protocol/src/pcan_gas_slot.c create mode 100644 c/set-protocol/src/set_gas_watch.c create mode 100644 c/set-protocol/tests/fixtures/gas-watch-v2.json create mode 100644 c/set-protocol/tests/test_gas_register.c create mode 100644 c/set-protocol/tests/test_gas_slot.c create mode 100644 c/set-protocol/tests/test_gas_watch.c create mode 100644 doc/setcan/protocan/examples/gas-slot-vectors.json create mode 100644 python/protocan/gas_slots.py create mode 100644 python/protocan/gas_watch.py create mode 100644 python/tests/test_gas_slots.py create mode 100644 python/tests/test_gas_watch.py diff --git a/c/set-protocol/CMakeLists.txt b/c/set-protocol/CMakeLists.txt index 6a6b56d..e017090 100644 --- a/c/set-protocol/CMakeLists.txt +++ b/c/set-protocol/CMakeLists.txt @@ -20,6 +20,7 @@ set(SETPROTOCOL_V2_SOURCES src/set_telemetry.c src/set_plot.c src/set_trends.c + src/set_gas_watch.c # Собирает единый кодек GAS_WATCH2 и MCU-захват выбранных GAS-слов для static/shared целей. src/set_spectrum.c src/set_signal.c src/set_wavegen.c @@ -37,6 +38,7 @@ set(SETPROTOCOL_LEGACY_SOURCES src/pcan_crc.c src/pcan_frame.c src/pcan_gas.c + src/pcan_gas_slot.c # Собирает GAS SLOT типа 0x4 с Word0-маской и тремя значениями независимо от регистрового GAS 0x3. src/pcan_id.c src/pcan_link.c src/pcan_modbus_server.c @@ -94,6 +96,12 @@ endif() option(SETP_BUILD_TESTS "Build host tests" ON) if(SETP_BUILD_TESTS) enable_testing() + add_executable(test_gas_register tests/test_gas_register.c) # Проверяет запись одной уставки без соседей, границы 0…65535 и изоляцию типа 0x3. + target_link_libraries(test_gas_register PRIVATE setprotocol_static) # Запускает проверки на том же ядре, которое используют прошивки и host-клиенты. + add_test(NAME protocan_gas_register COMMAND test_gas_register) # Отдельный тест защищает восстановленный регистровый контракт. + add_executable(test_gas_slot tests/test_gas_slot.c) # Проверяет MsgType=0x4, маску Word0, сохранение соседей и границы PERIPH. + target_link_libraries(test_gas_slot PRIVATE setprotocol_static) # Использует ту же библиотеку, что MCU и клиенты. + add_test(NAME protocan_gas_slot COMMAND test_gas_slot) # Делает проверку нового формата частью штатного CTest. add_executable(test_emulator_services tests/test_emulator_services.c ports/example-emulator/service.c) target_link_libraries(test_emulator_services PRIVATE setprotocol_static) add_test(NAME emulator_services COMMAND test_emulator_services) @@ -170,6 +178,9 @@ if(SETP_BUILD_TESTS) add_executable(test_trends tests/test_trends.c) target_link_libraries(test_trends PRIVATE setprotocol_static) add_test(NAME shared_trends COMMAND test_trends) + add_executable(test_gas_watch tests/test_gas_watch.c) # Собирает транзакционные проверки конфигурации и эталонных байтов GAS_WATCH2. + target_link_libraries(test_gas_watch PRIVATE setprotocol_static) # Проверяет настоящее общее ядро, а не копию алгоритма в тесте. + add_test(NAME gas_watch_v2 COMMAND test_gas_watch) # Регистрирует новый контракт рядом с неизменёнными legacy-проверками. add_executable(test_spectrum tests/test_spectrum.c) target_link_libraries(test_spectrum PRIVATE setprotocol_static) add_test(NAME shared_spectrum COMMAND test_spectrum) diff --git a/c/set-protocol/README.md b/c/set-protocol/README.md index 170cc1b..0320214 100644 --- a/c/set-protocol/README.md +++ b/c/set-protocol/README.md @@ -1,5 +1,10 @@ # SETProtocol +Пакетный сбор выбранных GAS-регистров: [GAS_WATCH2](docs/GAS_WATCH2.md). +Конфигурация применяется целиком; выборка содержит поколение списка, +номер захвата, время устройства и достоверность каждого слова. Старый GAS_WATCH +сохраняет формат; новые C/ctypes/JNI-адаптеры включаются явно. + `periph28335_eeprom_*` — read-only reader физической EEPROM Бальзам-167 (AT25256B, 32 КиБ), со стабильным C ABI и портом `python/protocan/periph28335_eeprom.py`. Разметка платы задана в @@ -112,3 +117,7 @@ FFI-клиенты подключают `setprotocol_abi.h`. Имена функ [PLOT_PROCESSING.md](docs/PLOT_PROCESSING.md). Генератор сигнала, USB и порты ЦАП F407/G474: [SIGNAL_GENERATOR.md](docs/SIGNAL_GENERATOR.md). + +## GAS: регистры 0x3 и слоты 0x4 + +[Адресация GAS](docs/GAS_SLOT.md): `0x3` — отдельные 16-битные регистры `0…65535`, запись 1…4 слов. `0x4` — слот с Word0-маской и тремя значениями; PERIPH сохраняет 200 слов в 67 слотах `0xMM00…0xMM42`. Формат определяется MsgType, без настройки профиля. diff --git a/c/set-protocol/docs/GAS_SLOT.md b/c/set-protocol/docs/GAS_SLOT.md new file mode 100644 index 0000000..e2274c3 --- /dev/null +++ b/c/set-protocol/docs/GAS_SLOT.md @@ -0,0 +1,27 @@ +# GAS SLOT 0x4: маска в Word0 + +Нормативный контракт: [ОАП](../../../doc/setcan/protocan/OAP.md). GAS `0x3` адресует отдельные 16-битные регистры; GAS SLOT `0x4` использует собственный адрес слота и заменяет прежний Modbus Coil. + +Один кадр: `Word0=маска`, `Word1`, `Word2`, `Word3`; все слова little-endian. В Word0 допустимы только непустые комбинации битов 1…3 (`0x0002…0x000E` с нулевым битом 0). Бит выбирает одноимённое слово. Запись всегда DLC=8; невыбранные значения игнорируются и сохраняются в устройстве. `DLC=0` запрашивает чтение; ответ DLC=8 содержит маску достоверных слов. RTR, standard/error frame, пустой ответ и усечённые данные отвергаются. + +Изменить только Word2 на `0x1234`: payload `04 00 00 00 34 12 00 00`. Полная запись трёх значений использует маску `0x000E`. Word0 — метаданные, не четвёртый регистр. + +## MCU + +`pcan_gas_slot_handle_address(type, id, port, request, response)` обслуживает любой узел и слот 0…65535. Возвращает 1 при ответе, 0 после записи, -1 при отказе. Provider чтения заполняет четыре wire-слова, включая Word0-маску; provider записи сначала проверяет все выбранные права и значения, затем изменяет только отмеченные позиции под общей блокировкой. Кодек не гарантирует транзакционность внешних Flash/callback операций. + +`pcan_gas_slot_handle(mode, ...)` дополнительно проверяет страницу PERIPH. `Slot=(mode<<8)|LocalSlot`, LocalSlot 0…66. Три значения на слот сохраняют 200 слов на mode; в последнем слоте доступны Word1/Word2. `pcan_gas_slot_native(local, word, write, &address)` принимает word 1…3 и переводит `3*local+word-1` в прежние native-сервисы. Нулевая позиция, резерв и запрещённая запись отвергаются. + +Вызывать обработчик из главного цикла/задачи; ISR только принимает кадры. DLC измеряется wire-октетами, в том числе на C28x с 16-битным char. Общий формат не выделяет все 384 КиБ логического пространства в RAM. + +## Python и Android + +`GasSlots.frame(5, 0)` возвращает `(0x11540500, b'')`. `frame(5, 0, [0x0004, 0, 0x1234, 0])` меняет только Word2. `frame_address(7, 14, 65535, [...])` адресует независимый узел и полный 16-битный слот. `decode()` проверяет PERIPH, `decode_address()` — общий формат. Wire-маска и endian формируются единственным C-кодеком. + +Android/JNI: `nativeRequestId`/`nativeDecode` для PERIPH; `nativeAddressId`/`nativeDecodeWords` для общего узла; `nativeEncode` принимает маску и три значения. Пустой запрос возвращает пустой набор значений; ошибка — null. + +В CAN-журнале тип 0x4 выбирается автоматически по MsgType. Параметра `gas_profile` нет; 0x3 всегда отображается как регистры. GAS_WATCH2 и регистровые провайдеры 0x3 сохраняют адреса и ABI. + +## Проверки + +CTest: `protocan_gas_register`, `protocan_gas_slot`, `protocan_modbus_server`; Python: `test_gas_slots.py`; JNI host smoke. Общие эталоны: `doc/setcan/protocan/examples/gas-slot-vectors.json`. Старые узлы Coil 0x4 несовместимы с новым назначением и обновляются согласованно. diff --git a/c/set-protocol/docs/GAS_WATCH2.md b/c/set-protocol/docs/GAS_WATCH2.md new file mode 100644 index 0000000..f3261f7 --- /dev/null +++ b/c/set-protocol/docs/GAS_WATCH2.md @@ -0,0 +1,202 @@ +# GAS_WATCH2: список адресов и пакетная выборка + +> GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Спецификация: `doc/setcan/protocan/OAP.md`; адреса этого документа остаются регистровыми. + +`include/set_gas_watch.h` и `src/set_gas_watch.c` реализуют выбранный клиентом +список GAS-регистров, транзакционную настройку и захват значений в отдельную +структуру. График и архив могут использовать одну готовую выборку. +Ядро — C99, без HAL, часов ОС, heap, глобального состояния и драйверов связи. + +Старые `gui_watch_t`, `GAS_WATCH_SET` / `GAS_WATCH_DATA` и ABI +`set_trend_watch_*` сохраняют сигнатуры и побайтовый формат. +Расширение включается явно и не меняет существующую типизированную +телеметрию `set_telemetry` / SETProtocol v2 `SUBSCRIBE`. + +## Что подключается к МК + +Код `templates` компилируется в прошивку. Она создаёт `set_gas_watch_t` +в собственной RAM, предоставляет `pcan_gas_map_t` и вызывает API из своего +диспетчера команд и таймера. Нового процесса или среды исполнения на МК нет. + +| Компонент | Ответственность | +|---|---| +| `set_gas_watch_t` | Собственная копия списка адресов, период, поколение и расписание | +| `set_gas_watch_sample_t` | Значения, достоверность каждого слова, время и номер захвата | +| `pcan_gas_map_t` | Доступ к RAM/обработчикам источников; GAS-адрес не является указателем MCU | +| Порт платы | Блокировка, локальное время, таймер, диспетчер и очередь передачи | +| Python/JNI/Kotlin | Преобразование моделей и pending/active без второго кодека | +| GUI | Имена, типы, масштаб, цвет, видимость и объединение запросов вкладок | + +Минимальные исходники: `set_gas_watch.c`, `pcan_gas.c`, `pcan_id.c`, +`set_protocol.c`; заголовки берутся из `include`. Полная CMake/NDK/host-сборка +уже включает новый модуль. Состояние и выборка используют ограниченные +массивы; реальные размеры структур определяются `sizeof` на целевом MCU. + +Пример последовательности вызовов в прошивке: + +```c +#include "set_gas_watch.h" /* Подключает список GAS-слов и независимый от транспорта захват. */ +static set_gas_watch_t watch; /* Хранит одну управляемую подписку в RAM платы; память выделяет проект. */ +static set_gas_watch_sample_t sample; /* Сохраняет выборку до завершения работы всех её потребителей. */ +/* При старте сессии: set_gas_watch_init(&watch); память и timer предоставляет прошивка. */ +/* В диспетчере, под общей блокировкой: set_gas_watch_apply(&watch, &map, payload, size). */ +/* При успехе, под той же блокировкой: set_gas_watch_encode_ack(&watch, tx, sizeof(tx)). */ +/* После снятия блокировки: отправить ACK транспортом проекта, при ошибке вернуть NACK/статус. */ +/* В таймере, под общей блокировкой: проверить set_gas_watch_due(&watch, now_ms). */ +/* Когда пора: set_gas_watch_capture(&watch, &map, now_ms, &sample), затем снять блокировку. */ +/* В задаче передачи: set_gas_watch_encode_sample(&sample, tx, sizeof(tx)), затем поставить tx в очередь. */ +``` + +Пример показывает места вызовов; проект предоставляет `map`, `payload`, +буферы, `now_ms`, lock и транспорт. Он обязан проверять результаты API. +Для `[0x0000, 0x0001, 0xFF01]` ядро читает три разрозненных GAS-слова +и формирует один логический пакет, не читая промежуточный диапазон. +Адреса передаются при настройке; DATA содержит значения и метаданные. + +## Настройка и поколения + +Набор ограничен **64 словами по 16 бит**, а не 64 произвольными параметрами. +Многословный параметр занимает несколько позиций. Дубли адресов отклоняются; +владелец подписки объединяет запросы вкладок до отправки. + +`set_gas_watch_request` проверяет модель и строит payload. +`set_gas_watch_apply` проверяет весь пакет и карту: все адреса должны +существовать, разрешать чтение и иметь RAM либо callback чтения. Проверка +не вызывает источники. Отказ сохраняет прежние адреса, период, sequence и +расписание. Частичного принятия нет; коды заданы в `set_gas_watch_result_t`. + +`config_id` — ненулевой 32-битный номер, назначаемый управляющим клиентом. +Любое изменение периода или порядка/состава адресов требует нового поколения. +После первой команды принимается модульная разность `new_id - old_id` +в диапазоне `1..0x7FFFFFFF`. Переход `0xFFFFFFFF → 1` допустим, ноль +зарезервирован. Разрыв между последовательными поколениями меньше `2^31`. +Поколения нельзя переиспользовать, пока в обмене могут оставаться старые пакеты. + +Точный повтор действующего id со всем прежним содержимым успешен и не +сбрасывает захват: потерянный ACK можно запросить повторно. Тот же id +с другим содержимым, старый id и разность `2^31` дают `SET_GAS_WATCH_CONFLICT`. +Остановка — новая конфигурация `period_ms = 0, count = 0`, карта не требуется. +Пустой список с ненулевым периодом и непустой список с нулевым запрещены. + +`set_gas_watch_encode_ack` возвращает полную применённую конфигурацию, +включая адреса. Клиент проверяет её через `set_gas_watch_ack` и заменяет +active только после успеха. Новая команда хранится как pending; DATA +сопоставляются с active. ACK уже заменённого pending отвергается. +Ошибка команды/ACK сохраняет прежний active. + +Один экземпляр обслуживает одного управляющего клиента. Если устройство +сохранило состояние после переподключения, клиент продолжает номера поколений. +`reset()` адаптера очищает только его pending/active, не посылает stop +и не сбрасывает устройство. Проект может явно вызвать `set_gas_watch_init` +при завершении управляющей сессии, разрешив новой сессии произвольный первый id. + +## Захват и синхронизация + +Приложение сериализует все обращения к состоянию, изменения карты, +обновления исходного кэша и захват одним подходящим lock/IRQ-портом. +Транзакционность API означает отсутствие частичной настройки при ошибке; +присваивание C-структуры само по себе не даёт межпоточную атомарность. +Ядро не управляет IRQ и не содержит скрытых ожиданий. + +Под lock выполняются применение конфигурации, подготовка ACK, +проверка `set_gas_watch_due` и `set_gas_watch_capture`. Сам `capture` +допускает явный захват вне расписания и не проверяет due. +После снятия lock приложение кодирует готовую выборку и передаёт её +транспорту. Кодировщик не обращается к источникам. + +При блокировке IRQ callbacks читают только быструю RAM: без запросов +CAN/Modbus, ожидания периферии и выделения памяти. Удалённые источники +обновляют кэш заранее. Общая блокировка согласует чтение кэша, но не +синхронизирует физические измерения нескольких устройств и не определяет +свежесть удалённых данных. + +Отказ отдельного источника даёт `valid = 0, value = 0` и не отменяет выборку. +Корректное нулевое значение имеет `valid = 1`. Повреждённая карта целиком +или остановленная подписка возвращают `false` без изменения состояния и выхода. + +Первый номер выборки нового поколения — 0; далее он увеличивается по +модулю `2^32`. Каждый захват учитывается, даже если транспорт затем его +потерял. Повторная отправка готовой выборки сохраняет тот же номер. +Время передаётся портом **в миллисекундах устройства**, без подмены часами GUI. +Потребитель разворачивает переполнение времени в длинную ось своего сеанса. + +Первый захват разрешён сразу; следующий срок — `now_ms + period_ms`. +После опоздания нет пачки догоняющих выборок. Приложение проверяет таймер +чаще одного раза за `2^31` мс для корректного модульного сравнения u32. + +Изменение GAS и конфигурации не меняет готовую выборку. Приложение хранит +её до окончания чтения всеми потребителями, используя очередь или двойной +буфер при необходимости. Входные/выходные структуры и массивы API не +должны перекрываться в памяти. + +## Wire payload версии 2 + +Числа little-endian, размеры ниже в байтах. Выравнивание C-структур +в обмене не используется. Для GUI protocol v1 добавлены отдельные типы: + +| Тип GUI v1 | Назначение | +|---|---| +| `0x14 GAS_WATCH2_SET` | Настройка и полное эхо принятой конфигурации | +| `0x15 GAS_WATCH2_DATA` | Выборка; внешний sequence равен 0 | + +Внешняя версия остаётся GUI v1. Старые типы `0x12/0x13` не меняются. +Неподдерживаемая команда завершается явным отказом, автоматического fallback нет. +`0x0014 UNSUBSCRIBE` SETProtocol v2 относится к другому кадрированию +и сохраняет смысл. Обёртка нового GAS_WATCH2 для SETProtocol v2 согласуется +отдельно с его существующей типизированной телеметрией. + +Конфигурация и ACK: `12 + 2N` байт, максимум 140. + +| Смещение | Тип | Значение | +|---:|---|---| +| 0 | u16 | версия payload: 2 | +| 2 | u16 | период, мс | +| 4 | u32 | config_id, не ноль | +| 8 | u16 | N, число адресов: 0..64 | +| 10 | u16 | резерв, строго 0 | +| 12 | N × u16 | уникальные GAS-адреса в порядке значений | + +Выборка: `16 + ceil(N/8) + 2N` байт, максимум 152. + +| Смещение | Тип | Значение | +|---:|---|---| +| 0 | u16 | версия payload: 2 | +| 2 | u16 | N, число значений: 1..64 | +| 4 | u32 | config_id | +| 8 | u32 | sequence захвата | +| 12 | u32 | timestamp_ms устройства | +| 16 | ceil(N/8) байт | битовая маска достоверности | +| 16 + ceil(N/8) | N × u16 | сырые значения в порядке списка | + +Канал i соответствует биту `i % 8` байта `i / 8`, младший бит первым. +Неиспользуемые старшие биты последнего байта нулевые. Недостоверные слова +обязательно нулевые: кодировщик нормализует их, декодировщик отвергает +неканонический вход. Ошибки версии, точной длины, id, ожидаемого количества +или вместимости выхода возвращают `-1` без изменения выходных аргументов. +Успешный результат — число слов, включая отмеченные недостоверными. + +Classic CAN требует сегментации логического пакета портом: восемь байт +данных кадра не вмещают всю выборку. Окно Modbus для снимка подключается +отдельным проектным адаптером. + +## Клиенты и проверки + +`python/protocan/gas_watch.py` предоставляет `GasWatchConfig`, +`GasWatchSample`, `NativeGasWatch`; Android-порт — `GuiGasWatch2.kt` и JNI. +Оба используют C request/ack/decode; недостоверный канал представлен +Python `None` / Kotlin `null`. Старый DLL сообщает о необходимости +пересборки нового режима вместо второго кодека на языке GUI. + +Стабильные ABI-символы `set_gas_watch_request`, `set_gas_watch_ack`, +`set_gas_watch_decode` добавлены без изменения версии и прежних символов. +Сборки CMake, прямой host builder и Android NDK включают новый исходник. +Общий эталон — `tests/fixtures/gas-watch-v2.json`. +C-тест `gas_watch_v2` проверяет wire, транзакционность, поколения, +ошибки источников, независимость выборки, bitmap и переполнения. +Python/JVM используют те же байты через настоящие DLL/JNI. + +Это изменение общего ядра и адаптеров в `templates`. Переключение внешних +SETGUI/Android на новую ревизию сабмодуля, объединение подписок вкладок +и подключение к диспетчеру конкретной платы выполняются в этих проектах. +Архивный `c/gas-logger` сохраняет собственный формат истории; его +динамическая перенастройка здесь не включается. diff --git a/c/set-protocol/docs/GUI_TRENDS.md b/c/set-protocol/docs/GUI_TRENDS.md index 2898b89..cf21839 100644 --- a/c/set-protocol/docs/GUI_TRENDS.md +++ b/c/set-protocol/docs/GUI_TRENDS.md @@ -1,5 +1,9 @@ # Общие тренды для Android GUI и SETGUI +Расширенная подписка с подтверждением полного списка, поколением конфигурации +и признаками достоверности: [GAS_WATCH2](GAS_WATCH2.md). Она включается отдельно; +описанный ниже прежний GAS_WATCH и формат настроек сохраняют совместимость. + Модуль задаёт совместимые настройки и числовые источники графиков. Он не рисует экран, не открывает файлы или порты и не управляет прошивкой устройства. diff --git a/c/set-protocol/docs/legacy/GAS.md b/c/set-protocol/docs/legacy/GAS.md index 51207fc..ceed7be 100644 --- a/c/set-protocol/docs/legacy/GAS.md +++ b/c/set-protocol/docs/legacy/GAS.md @@ -1,5 +1,7 @@ # Общее адресное пространство (GAS) +> GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Спецификация: `doc/setcan/protocan/OAP.md`; адреса этого документа остаются регистровыми. + Плоское пространство 16-битных регистров с адресом `0x0000..0xFFFF`. Пространство собирается из **регионов**; регионы не перекрываются и хранятся отсортированными по адресу, поиск — двоичный. diff --git a/c/set-protocol/docs/legacy/OAP.md b/c/set-protocol/docs/legacy/OAP.md index b33a350..34ce935 100644 --- a/c/set-protocol/docs/legacy/OAP.md +++ b/c/set-protocol/docs/legacy/OAP.md @@ -1,14 +1,16 @@ # Общее адресное пространство +> GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Спецификация: `doc/setcan/protocan/OAP.md`; адреса этого документа остаются регистровыми. + Статус: **Stable, данные ведутся в XLSX** Порядок значений: **16-битные регистры, little-endian в CAN payload** Редактируемый источник реестра: -[`Протокол CAN и ОАП.xlsx`](../../Протокол%20CAN%20и%20ОАП.xlsx). +[`Протокол CAN и ОАП.xlsx`](../../../../doc/setcan/Протокол%20CAN%20и%20ОАП.xlsx). Просматриваемая большая таблица находится в -[`Протокол CAN и ОАП.html`](../../Протокол%20CAN%20и%20ОАП.html) и -[`Протокол CAN и ОАП.md`](../../Протокол%20CAN%20и%20ОАП.md). +[`Протокол CAN и ОАП.html`](../../../../doc/setcan/Протокол%20CAN%20и%20ОАП.html) и +[`Протокол CAN и ОАП.md`](../../../../doc/setcan/Протокол%20CAN%20и%20ОАП.md). ## Назначение diff --git a/c/set-protocol/docs/legacy/PROTOCOL.md b/c/set-protocol/docs/legacy/PROTOCOL.md index 5f76f3c..3daef73 100644 --- a/c/set-protocol/docs/legacy/PROTOCOL.md +++ b/c/set-protocol/docs/legacy/PROTOCOL.md @@ -1,7 +1,9 @@ # ProtoCAN — базовый протокол +> GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Полный контракт: [ОАП](../../../../doc/setcan/protocan/OAP.md). Существующие регистровые сервисы сохраняют свои адреса. + Статус: **Stable с зарезервированным загрузочным расширением** -Версия: **1.0** +Версия: **2.1: GAS 0x3 и масочный GAS SLOT 0x4**
Порядок байтов payload: **little-endian**, если явно не указано иное ## Назначение @@ -59,8 +61,8 @@ can_id = | `0x0` | `BROADCAST` | ПМ → все | зависит от команды | stable | | `0x1` | `DISCRETE` | оба | 0…8 | stable | | `0x2` | `ANALOG` | оба | 0…8 | stable | -| `0x3` | `GAS` | оба | 0/2/4/6/8 | stable | -| `0x4` | `MODBUS_COIL` | оба | 0…8 | stable | +| `0x3` | `GAS` | оба | 0/2/4/6/8 | регистры 0…65535 | +| `0x4` | `GAS_SLOT` | оба | 0/8 | Word0 — маска, Word1…Word3 — значения | | `0x5` | `MODBUS_DISCRETE` | оба | 0…8 | stable | | `0x6` | `MODBUS_HOLDING` | оба | 0…8 | stable | | `0x7` | `MODBUS_INPUT` | оба | 0…8 | stable | @@ -82,7 +84,8 @@ can_id = | broadcast | команда `[15:4]`, параметр `[3:0]` | | discrete/analog | подтип `[15:12]`, значение/адрес `[11:0]` | | Modbus | начальный адрес `[15:4]`, количество `[3:0]` | -| GAS | адрес первого 16-битного регистра `[15:0]` | +| GAS 0x3 | адрес первого 16-битного регистра `[15:0]` | +| GAS SLOT 0x4 | адрес слота `[15:0]`; маска — в Word0 payload, значения — Word1…Word3 | | error | дополнительная информация `[15:8]`, код `[7:0]` | | settings | номер сборки `[15:8]`, позиция `[7:0]` | | boot control/status | `SessionID[15:8]`, команда `[7:0]` | diff --git a/c/set-protocol/include/gui_frame.h b/c/set-protocol/include/gui_frame.h index 7b8a784..a0bcbd9 100644 --- a/c/set-protocol/include/gui_frame.h +++ b/c/set-protocol/include/gui_frame.h @@ -61,6 +61,8 @@ extern "C" { #define GUI_MSG_GAS_CATALOG 0x11U #define GUI_MSG_GAS_WATCH_SET 0x12U #define GUI_MSG_GAS_WATCH_DATA 0x13U +#define GUI_MSG_GAS_WATCH2_SET 0x14U /* Новый тип GUI v1 для версионированного полного списка GAS; payload описан в GAS_WATCH2.md. */ +#define GUI_MSG_GAS_WATCH2_DATA 0x15U /* Новый тип GUI v1 для самостоятельной выборки с поколением, временем и маской достоверности. */ #define GUI_MSG_NACK 0x80U #define GUI_MSG_ACK 0x81U #define GUI_MSG_ERROR 0x82U diff --git a/c/set-protocol/include/pcan_gas.h b/c/set-protocol/include/pcan_gas.h index 312e910..b101ba5 100644 --- a/c/set-protocol/include/pcan_gas.h +++ b/c/set-protocol/include/pcan_gas.h @@ -8,6 +8,7 @@ * @file pcan_gas.h * @brief Общее адресное пространство (General Address Space). * + * Тип 0x3 адресует отдельные регистры; независимый тип 0x4 описан в pcan_gas_slot.h. * Плоское пространство 16-битных регистров с адресом 0x0000..0xFFFF, * собранное из регионов. Регион либо ссылается на массив в памяти, * либо обслуживается колбэками - так в карту попадают и обычные @@ -120,7 +121,7 @@ void pcan_gas_regs_to_frame(pcan_frame_t *frame, uint32_t base_id, * * DLC = 0 - запрос на чтение: в rsp кладётся до 4 регистров с адреса * MsgBody, Route переключается на FROM_DEVICE. - * DLC > 0 - запись: регистры пишутся в карту, ответ не формируется. + * DLC = 2/4/6/8 - запись одного/двух/трёх/четырёх регистров; остальные слова не меняются. * * @param[out] rsp кадр ответа; заполняется, только если функция вернула true. * @return true, если ответ нужно передать. diff --git a/c/set-protocol/include/pcan_gas_slot.h b/c/set-protocol/include/pcan_gas_slot.h new file mode 100644 index 0000000..12ce89e --- /dev/null +++ b/c/set-protocol/include/pcan_gas_slot.h @@ -0,0 +1,48 @@ +#ifndef PCAN_GAS_SLOT_H /* Отдельный интерфейс исключает смешение нового номера слота со старым адресом регистра. */ +#define PCAN_GAS_SLOT_H /* Защита допускает включение из общего заголовка и непосредственно из порта MCU. */ +#include /* Фиксированные слова и uint_least8_t доступны также на C28x без восьмибитного char. */ +#include /* NULL используется без зависимости от ОС и динамической памяти. */ +#include /* CHAR_BIT выбирает экспорт host ABI отдельно от 16-битного C28x. */ +#if CHAR_BIT == 8 /* Host/ARM используют существующий экспорт DLL/SO. */ +#include "pcan_abi.h" /* Переиспользуем публичный экспорт единого host-кодека. */ +#elif !defined(PCAN_ABI_API) /* Встроенный C28x статически собирает функции без Windows-атрибутов. */ +#define PCAN_ABI_API /* Не требуем отсутствующий на C28x uint8_t из host ABI. */ +#endif /* Все последующие объявления одинаковы по смыслу на ARM, host и C28x. */ +#ifdef __cplusplus /* C++ и JNI связываются с C99-ядром через стандартные C-имена. */ +extern "C" { /* Начинаем область совместимого C ABI. */ +#endif /* Дальнейшие объявления пригодны также для чистого C. */ +#define PCAN_GAS_SLOT_WORDS 4U /* Восемь октетов кадра содержат четыре wire-слова: маску Word0 и три значения Word1…Word3. */ +#define PCAN_GAS_SLOT_DATA_WORDS 3U /* Два октета маски оставляют шесть октетов для трёх независимых 16-битных значений. */ +#define PCAN_GAS_SLOT_MASK 0x000EU /* Биты 1…3 выбирают одноимённые значения; бит 0 и биты 4…15 зарезервированы. */ +#define PCAN_GAS_SLOT_MODE_COUNT 32U /* Два типа PERIPH по шестнадцать DeviceID дают mode 0…31. */ +#define PCAN_GAS_SLOT_MODE_SLOTS 67U /* Округление 200/3 вверх сохраняет все регистры PERIPH; в последнем слоте действуют два значения. */ +#define PCAN_GAS_SLOT_MODE_WORDS 200U /* Значение измеряется в 16-битных словах, не в байтах MCU. */ +#define PCAN_GAS_SLOT_FLAG_IDE 1U /* Флаг Extended ID совпадает с транспортом pcan_frame; отдельно объявлен для C28x-порта. */ +#define PCAN_GAS_SLOT_FLAG_RTR 2U /* RTR запрещён слотным профилем; запрос чтения использует data frame с DLC=0. */ +#define PCAN_GAS_SLOT_FLAG_ERR 8U /* Ошибочный кадр моста не должен читаться как запрос к данным. */ +typedef int (*pcan_gas_slot_read_fn)(void *, uint16_t, uint16_t[4]); /* Provider возвращает маску достоверных значений в Word0 и три значения; ноль означает успех. */ +typedef int (*pcan_gas_slot_write_fn)(void *, uint16_t, const uint16_t[4]); /* Provider сначала проверяет все выбранные слова, затем меняет только биты 1…3 маски Word0 под общей блокировкой. */ +typedef struct { /* Независимый MCU-кадр не меняет legacy ABI и не требует uint8_t на C28x. */ + uint32_t id; /* Расширенный CAN ID содержит адрес узла и 16-битный номер слота. */ + unsigned flags; /* IDE/RTR/ERR используют документированные значения транспортных флагов. */ + unsigned dlc; /* Длина измеряется в октетах линии, а не в sizeof элементов C28x. */ + uint_least8_t data[8]; /* На C28x октет хранится в 16-битной ячейке; значения строго 0…255. */ +} pcan_gas_slot_frame_t; /* Порт переводит структуру в регистры CAN, не копируя wire-структуру через ABI. */ +typedef struct { /* Один порт соединяет общий обработчик с данными конкретного узла без глобальной памяти. */ + void *context; /* Контекст принадлежит проекту и должен жить дольше обработчика. */ + pcan_gas_slot_read_fn read; /* NULL запрещает чтение; callback получает полный 16-битный адрес слота. */ + pcan_gas_slot_write_fn write; /* NULL запрещает запись; callback не должен менять соседние слоты. */ +} pcan_gas_slot_port_t; /* Размер существующих структур pcan_gas не изменяется. */ +PCAN_ABI_API int32_t pcan_gas_slot_address(unsigned mode, unsigned local); /* Возвращает (mode<<8)|local либо -1 для mode>31 или local>66. */ +PCAN_ABI_API uint32_t pcan_gas_slot_id(unsigned device_type, unsigned device_id, unsigned address, unsigned route); /* Формирует MsgType=0x4 для любого узла и адреса 0…65535 без сужения неверных входов. */ +PCAN_ABI_API uint32_t pcan_gas_slot_request_id(unsigned mode, unsigned local, unsigned route); /* Формирует Extended ID PERIPH с Priority=1 и MsgType=0x4; ноль означает ошибку. */ +PCAN_ABI_API int pcan_gas_slot_encode(const uint16_t *words, unsigned count, uint_least8_t *data); /* Допускает count=0 либо четыре wire-слова с непустой маской в Word0; длина измеряется октетами. */ +PCAN_ABI_API int pcan_gas_slot_decode_words(uint32_t id, unsigned flags, const uint_least8_t *data, unsigned dlc, uint16_t *words); /* Проверяет общий слотный кадр любого узла; возвращает 0/4 либо -1 без изменения выхода при отказе. */ +PCAN_ABI_API int pcan_gas_slot_decode(uint32_t id, unsigned flags, const uint_least8_t *data, unsigned dlc, unsigned *mode, unsigned *local, uint16_t *words); /* Проверяет узел, слот и октеты; возвращает 0/4 либо -1 без изменения выходов. */ +PCAN_ABI_API int pcan_gas_slot_native(unsigned local, unsigned word, unsigned write, uint16_t *address); /* Переводит Word1…Word3 в родной адрес PERIPH; Word0 является маской и не адресует регистр. */ +PCAN_ABI_API int pcan_gas_slot_handle_address(unsigned device_type, unsigned device_id, const pcan_gas_slot_port_t *port, const pcan_gas_slot_frame_t *request, pcan_gas_slot_frame_t *response); /* Обслуживает масочную запись и чтение 0x4 для любого узла; не вызывает Modbus или GAS 0x3. */ +PCAN_ABI_API int pcan_gas_slot_handle(unsigned mode, const pcan_gas_slot_port_t *port, const pcan_gas_slot_frame_t *request, pcan_gas_slot_frame_t *response); /* Возвращает 1 для ответа, 0 после записи, -1 при отказе; не вызывает legacy fallback. */ +#ifdef __cplusplus /* Закрываем C ABI только при включении из C++. */ +} /* Конец объявлений с C-соглашением о связывании. */ +#endif /* Общие защитные символы не зависят от языка порта. */ +#endif /* Завершаем защиту единственного интерфейса слотного профиля GAS. */ diff --git a/c/set-protocol/include/pcan_id.h b/c/set-protocol/include/pcan_id.h index dd88b9e..b4e9e4d 100644 --- a/c/set-protocol/include/pcan_id.h +++ b/c/set-protocol/include/pcan_id.h @@ -46,7 +46,7 @@ typedef enum { PCAN_MSG_DISCRETE = 0x1U, PCAN_MSG_ANALOG = 0x2U, PCAN_MSG_GAS = 0x3U, /**< общее адресное пространство */ - PCAN_MSG_MODBUS_COIL = 0x4U, + PCAN_MSG_GAS_SLOT = 0x4U, /**< Слотный GAS с маской слов; код 0x4 освобождён от Modbus Coil. */ PCAN_MSG_MODBUS_DISCR = 0x5U, PCAN_MSG_MODBUS_HOLDING = 0x6U, PCAN_MSG_MODBUS_INPUT = 0x7U, @@ -57,11 +57,11 @@ typedef enum { /** Разобранный идентификатор. */ typedef struct { uint16_t msg_body; - uint8_t msg_type; /**< pcan_msgtype_t */ - uint8_t device_id; /**< 0..15 */ - uint8_t device_type; /**< 0..7 */ - uint8_t route; - uint8_t priority; + uint_least8_t msg_type; /**< pcan_msgtype_t */ /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ + uint_least8_t device_id; /**< 0..15 */ /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ + uint_least8_t device_type; /**< 0..7 */ /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ + uint_least8_t route; /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ + uint_least8_t priority; /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ } pcan_id_t; uint32_t pcan_id_pack(const pcan_id_t *id); @@ -70,25 +70,25 @@ void pcan_id_unpack(uint32_t raw, pcan_id_t *id); /* --- Раскладки MsgBody ----------------------------------------------------- */ /** BROADCAST: Type[15:4], Body[3:0]. */ -static inline uint16_t pcan_body_broadcast(uint16_t type, uint8_t body) +static inline uint16_t pcan_body_broadcast(uint16_t type, uint_least8_t body) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ { return (uint16_t)(((type & 0x0FFFU) << 4) | (body & 0x0FU)); } /** DISCRETE / ANALOG: Type[15:12], Body[11:0]. */ -static inline uint16_t pcan_body_typed(uint8_t type, uint16_t body) +static inline uint16_t pcan_body_typed(uint_least8_t type, uint16_t body) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ { return (uint16_t)(((uint16_t)(type & 0x0FU) << 12) | (body & 0x0FFFU)); } /** MODBUS: StrAdr[15:4], RegCount[3:0]. */ -static inline uint16_t pcan_body_modbus(uint16_t addr, uint8_t count) +static inline uint16_t pcan_body_modbus(uint16_t addr, uint_least8_t count) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ { return (uint16_t)(((addr & 0x0FFFU) << 4) | (count & 0x0FU)); } /** ERROR: Info[15:8], Code[7:0]. */ -static inline uint16_t pcan_body_error(uint8_t info, uint8_t code) +static inline uint16_t pcan_body_error(uint_least8_t info, uint_least8_t code) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ { return (uint16_t)(((uint16_t)info << 8) | code); } diff --git a/c/set-protocol/include/pcan_modbus_server.h b/c/set-protocol/include/pcan_modbus_server.h index 0552d22..f6874b9 100644 --- a/c/set-protocol/include/pcan_modbus_server.h +++ b/c/set-protocol/include/pcan_modbus_server.h @@ -21,7 +21,6 @@ extern "C" { #endif typedef enum { - PCAN_MODBUS_COIL = 0x4U, PCAN_MODBUS_DISCRETE = 0x5U, PCAN_MODBUS_HOLDING = 0x6U, PCAN_MODBUS_INPUT = 0x7U @@ -54,7 +53,7 @@ bool pcan_modbus_server_init(pcan_modbus_server_t *server, pcan_modbus_read_fn read, pcan_modbus_write_fn write, void *user); -/** Zero DLC reads; data writes COIL/HOLDING. Register words are little-endian. */ +/** DLC=0 читает DISCRETE/HOLDING/INPUT; данные записывают только HOLDING. Тип 0x4 принадлежит GAS SLOT. */ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, const pcan_frame_t *request, pcan_frame_t *response); diff --git a/c/set-protocol/include/protocan_transport.h b/c/set-protocol/include/protocan_transport.h index 34084ae..c07a0ec 100644 --- a/c/set-protocol/include/protocan_transport.h +++ b/c/set-protocol/include/protocan_transport.h @@ -27,6 +27,7 @@ #include "pcan_crc.h" #include "pcan_frame.h" #include "pcan_gas.h" +#include "pcan_gas_slot.h" /* Слотный тип 0x4 имеет маску Word0 и собственный обработчик, регистровый GAS 0x3 сохраняет отдельные адреса слов. */ #include "pcan_id.h" #include "pcan_link.h" #include "pcan_modbus_server.h" diff --git a/c/set-protocol/include/set_gas_watch.h b/c/set-protocol/include/set_gas_watch.h new file mode 100644 index 0000000..ccef471 --- /dev/null +++ b/c/set-protocol/include/set_gas_watch.h @@ -0,0 +1,65 @@ +/* GAS_WATCH2: проверяемый список GAS-слов и независимые от транспорта выборки; формат описан в docs/GAS_WATCH2.md. */ +#ifndef SET_GAS_WATCH_H /* Исключает повторные объявления при подключении ядра несколькими компонентами прошивки. */ +#define SET_GAS_WATCH_H /* Отмечает загрузку публичного контракта расширенной подписки. */ +#include /* Даёт булевы результаты операций без платформенной зависимости. */ +#include "pcan_abi.h" /* Предоставляет фиксированные типы, size_t и экспорт стабильных функций для ctypes/JNI. */ +#include "pcan_gas.h" /* Предоставляет карту 16-битных GAS-регистров и проверяемые операции чтения. */ +#ifdef __cplusplus /* Открывает C ABI для проектов, компилирующих публичный заголовок как C++. */ +extern "C" { /* Запрещает изменение имён экспортируемых функций компилятором C++. */ +#endif /* Завершает условие входа в совместимую с C область объявлений. */ + +#define SET_GAS_WATCH_VERSION 2U /* Версия payload; отличается от версии внешнего кадрирования GUI. */ +#define SET_GAS_WATCH_MAX 64U /* Максимум 16-битных слов в одном списке; многословный параметр занимает несколько позиций. */ +#define SET_GAS_WATCH_CONFIG_HEADER 12U /* Байты version:u16, period:u16, config_id:u32, count:u16, reserved:u16. */ +#define SET_GAS_WATCH_SAMPLE_HEADER 16U /* Байты version:u16, count:u16, config_id:u32, sequence:u32, timestamp_ms:u32. */ +#define SET_GAS_WATCH_CONFIG_MAX (SET_GAS_WATCH_CONFIG_HEADER + 2U * SET_GAS_WATCH_MAX) /* 140 байт с адресами 64 слов. */ +#define SET_GAS_WATCH_SAMPLE_MAX (SET_GAS_WATCH_SAMPLE_HEADER + 8U + 2U * SET_GAS_WATCH_MAX) /* 152 байта: заголовок, 64 бита достоверности и значения. */ + +typedef enum { /* Разделяет неверный payload, ошибки карты и конфликт поколений без строк или исключений. */ + SET_GAS_WATCH_OK = 0, /* Весь список применён либо подтверждён точный повтор действующей конфигурации. */ + SET_GAS_WATCH_INVALID = 1, /* Нарушены версия, длина, указатели, период, уникальность адресов или структура карты. */ + SET_GAS_WATCH_NO_REG = 2, /* Хотя бы один адрес отсутствует в корректной карте; действующий список сохранён. */ + SET_GAS_WATCH_ACCESS = 3, /* Хотя бы один регистр запрещён для чтения либо не имеет источника чтения. */ + SET_GAS_WATCH_CONFLICT = 4 /* Идентификатор устарел либо повторно использован с другим содержимым. */ +} set_gas_watch_result_t; /* Завершает публичный набор детерминированных результатов настройки. */ + +typedef struct { /* Состояние одного прибора и одного управляющего клиента; память принадлежит приложению. */ + uint32_t config_id; /* Ненулевое поколение; новые поколения сравниваются по модульной разности меньше 2^31. */ + uint32_t sequence; /* Номер следующей выборки; первая имеет номер 0, переполнение происходит по модулю 2^32. */ + uint32_t next_ms; /* Срок следующего захвата в миллисекундах локального 32-битного счётчика устройства. */ + uint16_t period_ms; /* Период захвата в миллисекундах; ноль вместе с пустым списком останавливает поток. */ + uint16_t count; /* Число выбранных 16-битных GAS-слов, от 0 до SET_GAS_WATCH_MAX. */ + uint16_t address[SET_GAS_WATCH_MAX]; /* Упорядоченные уникальные GAS-индексы, а не указатели на память MCU. */ + uint8_t scheduled; /* Ноль разрешает первую выборку сразу, единица включает проверку next_ms с переполнением. */ +} set_gas_watch_t; /* Внутренняя структура прошивки не передаётся через wire или языковую границу. */ + +typedef struct { /* Самодостаточная копия одного захвата, пригодная для графика, архива и повторной передачи. */ + uint32_t config_id; /* Связывает позиции значений с подтверждённым списком адресов. */ + uint32_t sequence; /* Номер захвата, позволяющий обнаружить потерю пакета при занятой линии. */ + uint32_t timestamp_ms; /* Время захвата на устройстве; задержка USB/UART не меняет эту метку. */ + uint16_t count; /* Число значений и признаков достоверности в используемой части массивов. */ + uint16_t values[SET_GAS_WATCH_MAX]; /* Сырые слова; при ошибке соответствующего источника сохраняется ноль. */ + uint8_t valid[SET_GAS_WATCH_MAX]; /* Единица означает успешное чтение слова, ноль отличает ошибку от реального нулевого значения. */ +} set_gas_watch_sample_t; /* Приложение хранит выборку до завершения её использования всеми потребителями. */ + +/* Все обращения к состоянию и захвату RAM приложение сериализует своим lock/IRQ-портом; ядро не управляет прерываниями. */ +void set_gas_watch_init(set_gas_watch_t *watch); /* Обнуляет состояние до первой команды; NULL допустим как пустая операция. */ +/* Проверяет весь payload и карту без вызовов источников; ошибка оставляет состояние неизменным. Повтор id+содержимое идемпотентен. */ +int set_gas_watch_apply(set_gas_watch_t *watch, const pcan_gas_map_t *map, const uint8_t *payload, size_t size); /* Пустой stop не требует карты. */ +size_t set_gas_watch_encode_ack(const set_gas_watch_t *watch, uint8_t *out, size_t capacity); /* Возвращает полное эхо применённой конфигурации или 0. */ +bool set_gas_watch_due(const set_gas_watch_t *watch, uint32_t now_ms); /* Проверяет срок с переполнением; период проверок должен быть меньше 2^31 мс. */ +/* Захватывает RAM по явному вызову, без проверки due; источники обязаны быть быстрыми и не выполнять I/O или ожидания. */ +bool set_gas_watch_capture(set_gas_watch_t *watch, const pcan_gas_map_t *map, uint32_t now_ms, set_gas_watch_sample_t *sample); /* Отказ источника отражается valid=0. */ +/* Кодирует только готовую выборку, без обращений к карте и без блокировки источников; приложение вызывает после снятия lock. */ +size_t set_gas_watch_encode_sample(const set_gas_watch_sample_t *sample, uint8_t *out, size_t capacity); /* Неверный аргумент не меняет выходной буфер. */ + +/* Экспортируемый ABI использует скаляры и буферы: ни один клиент не повторяет кодек payload на своём языке. */ +PCAN_ABI_API size_t set_gas_watch_request(uint32_t config_id, uint16_t period_ms, const uint16_t *addresses, size_t count, uint8_t *out, size_t capacity); /* 0 означает отказ без записи. */ +PCAN_ABI_API int set_gas_watch_ack(const uint8_t *payload, size_t size, uint32_t config_id, uint16_t period_ms, const uint16_t *addresses, size_t count); /* 1 подтверждает точное эхо всех адресов. */ +/* Возвращает число слов или -1; до полной проверки payload и ожидаемого поколения не меняет ни один выходной аргумент. */ +PCAN_ABI_API int set_gas_watch_decode(const uint8_t *payload, size_t size, uint32_t expected_config_id, size_t expected_count, uint32_t *sequence, uint32_t *timestamp_ms, uint16_t *values, uint8_t *valid, size_t capacity); /* Метаданные sequence/time могут быть NULL. */ + +#ifdef __cplusplus /* Закрывает только ту область linkage, которую открывали для C++ потребителя. */ +} /* Завершает объявления с C-именами функций. */ +#endif /* Завершает условное закрытие C++ linkage. */ +#endif /* SET_GAS_WATCH_H: завершает защиту публичного заголовка. */ diff --git a/c/set-protocol/include/set_invertor_profile.h b/c/set-protocol/include/set_invertor_profile.h new file mode 100644 index 0000000..f95fb31 --- /dev/null +++ b/c/set-protocol/include/set_invertor_profile.h @@ -0,0 +1,8 @@ +#ifndef SET_INVERTOR_PROFILE_H /* Общий профиль адресации используется прошивкой и клиентами единственного C-ядра Templates. */ +#define SET_INVERTOR_PROFILE_H /* Предотвращаем повторное определение параметров нового устройства. */ +#define SET_INVERTOR_DEVICE_TYPE 7U /* DeviceType 0x7 выбран пользователем; поле ProtoCAN имеет ширину три бита. */ +#define SET_INVERTOR_DEVICE_ID 14U /* DeviceID 0xE свободен по аудиту 23.10.2026; G474 CANdle использует 0xF, F103 KONOR использует 0xD. */ +#define SET_INVERTOR_GAS_SLOT_COUNT 250U /* Пользователь выделил 250 слотов отдельному инвертору, сохранив существующую адресацию PERIPH. */ +#define SET_INVERTOR_GAS_WORDS_PER_SLOT 3U /* Тип 0x4 выделяет Word0 под маску и передаёт три независимых значения Word1…Word3. */ +#define SET_INVERTOR_GAS_WORD_COUNT (SET_INVERTOR_GAS_SLOT_COUNT * SET_INVERTOR_GAS_WORDS_PER_SLOT) /* Выделенные 250 слотов содержат 750 значений; служебная маска не является регистром. */ +#endif /* Этот заголовок задаёт назначение узла без нового кодека или изменения старых CAN ID. */ diff --git a/c/set-protocol/include/setprotocol.h b/c/set-protocol/include/setprotocol.h index 6cf501f..18f86e3 100644 --- a/c/set-protocol/include/setprotocol.h +++ b/c/set-protocol/include/setprotocol.h @@ -31,5 +31,6 @@ #include "protocan_transport.h" #include "gui_frame.h" #include "gui_catalog.h" +#include "set_gas_watch.h" /* Предоставляет новую подписку и независимый захват GAS-слов через общую точку подключения ядра. */ #endif /* SETPROTOCOL_H */ diff --git a/c/set-protocol/include/setprotocol_abi.h b/c/set-protocol/include/setprotocol_abi.h index abb2bc1..c0ae0e2 100644 --- a/c/set-protocol/include/setprotocol_abi.h +++ b/c/set-protocol/include/setprotocol_abi.h @@ -15,6 +15,7 @@ #define SETPROTOCOL_ABI_H #include "pcan_abi.h" +#include "set_gas_watch.h" /* Подключает добавочные стабильные request/ack/decode символы без изменения существующего ABI v1. */ #define SETPROTOCOL_ABI_VERSION PCAN_ABI_VERSION diff --git a/c/set-protocol/ports/android/Android.mk b/c/set-protocol/ports/android/Android.mk index de1ba13..9458a79 100644 --- a/c/set-protocol/ports/android/Android.mk +++ b/c/set-protocol/ports/android/Android.mk @@ -29,6 +29,8 @@ LOCAL_SRC_FILES := \ ../../src/pcan_ring.c \ ../../src/pcan_gas.c \ setprotocol_jni.c +LOCAL_SRC_FILES += ../../src/set_gas_watch.c # Включает общий GAS_WATCH2 в NDK-библиотеку для новых тонких JNI-вызовов. +LOCAL_SRC_FILES += ../../src/pcan_gas_slot.c gas_slots_jni.c # Android собирает общий слотный кодек и тонкую JNI-границу без второго алгоритма. LOCAL_CFLAGS := -std=c99 -Wall -Wextra -Wpedantic -fvisibility=hidden LOCAL_LDLIBS := -llog -lm include $(BUILD_SHARED_LIBRARY) diff --git a/c/set-protocol/ports/android/gas_slots_jni.c b/c/set-protocol/ports/android/gas_slots_jni.c new file mode 100644 index 0000000..fde83cd --- /dev/null +++ b/c/set-protocol/ports/android/gas_slots_jni.c @@ -0,0 +1,42 @@ +#include /* Единственная ответственность JNI — преобразование массивов и скалярных типов JVM. */ +#include "pcan_gas_slot.h" /* Формат ID, слотов и payload реализуется общим C-ядром. */ +JNIEXPORT jlong JNICALL Java_ru_setcorp_setprotocol_GasSlots_nativeRequestId(JNIEnv *env,jobject self,jint mode,jint local,jint route) /* Kotlin и host JVM вызывают одинаковый native-метод. */ +{ /* Начинаем преобразование адресных координат. */ + (void)env;(void)self;if(mode<0 || local<0 || route<0)return 0; /* Не сужаем отрицательные Java-числа в адреса устройств. */ + return (jlong)pcan_gas_slot_request_id((unsigned)mode,(unsigned)local,(unsigned)route); /* Все формулы и пределы проверяются C. */ +} /* Конец построения Extended ID. */ +JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_GasSlots_nativeEncode(JNIEnv *env,jobject self,jintArray input) /* Кодируем Word0-маску и три значения без второго endian-алгоритма на JVM. */ +{ /* NULL означает payload запроса чтения, массив — значения слота. */ + jint source[4];uint16_t words[4];uint_least8_t bytes[8];int i,n; jbyteArray out;(void)self; /* Все буферы имеют фиксированную вместимость одного кадра. */ + if(input==NULL)return (*env)->NewByteArray(env,0); /* Для запроса чтения payload пуст и не требует фиктивных регистров. */ + if((*env)->GetArrayLength(env,input)!=4)return NULL; /* Фиксированные позиции маски и трёх значений требуют четырёх wire-слов даже при частичной записи. */ + (*env)->GetIntArrayRegion(env,input,0,4,source);if((*env)->ExceptionCheck(env))return NULL; /* Не продолжаем JNI-вызовы после ошибки копирования массива. */ + for(i=0;i<4;i++){if(source[i]<0 || source[i]>65535)return NULL;words[i]=(uint16_t)source[i];} /* Сохраняем границы беззнакового 16-битного регистра. */ + n=pcan_gas_slot_encode(words,4U,bytes);if(n<0)return NULL; /* Общий кодек проверяет маску Word0 и формирует восемь wire-октетов. */ + out=(*env)->NewByteArray(env,n);if(out!=NULL)(*env)->SetByteArrayRegion(env,out,0,n,(const jbyte *)bytes);return out; /* Возвращаем готовый payload транспорта JVM/Android. */ +} /* Конец тонкого адаптера записи. */ +JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_GasSlots_nativeDecode(JNIEnv *env,jobject self,jlong id,jint flags,jbyteArray input) /* Декодирование возвращает mode, локальный слот и четыре слова. */ +{ /* Заголовок и содержимое проверяются до создания модели JVM. */ + uint_least8_t bytes[8];uint16_t words[4];unsigned mode,slot;int n,i;jsize length;jint values[6];jintArray out;(void)self; /* Ограниченные массивы не требуют heap внутри ядра. */ + if(id<0 || id>0xFFFFFFFFLL || flags<0 || input==NULL)return NULL; /* Не допускаем сужения 64-битного Long до другого действующего ID. */ + length=(*env)->GetArrayLength(env,input);if(length>8)return NULL; /* Extended Classic CAN не принимает payload CAN FD. */ + if(length>0)(*env)->GetByteArrayRegion(env,input,0,length,(jbyte *)bytes);if((*env)->ExceptionCheck(env))return NULL; /* Передаём исходные октеты C без ручной интерпретации. */ + n=pcan_gas_slot_decode((uint32_t)id,(unsigned)flags,bytes,(unsigned)length,&mode,&slot,words);if(n<0)return NULL; /* Проверяем адрес узла, страницу слота, DLC и направление общей реализацией. */ + values[0]=(jint)mode;values[1]=(jint)slot;for(i=0;iNewIntArray(env,n+2);if(out!=NULL)(*env)->SetIntArrayRegion(env,out,0,n+2,values);return out; /* JVM получает только проверенные скалярные значения. */ +} /* Конец JNI-декодирования без резервной реализации протокола. */ +JNIEXPORT jlong JNICALL Java_ru_setcorp_setprotocol_GasSlots_nativeAddressId(JNIEnv *env, jobject self, jint device_type, jint device_id, jint address, jint route) /* Создаём слотный ID любого узла, не только PERIPH. */ +{ /* JNI проверяет представимость, а ширину полей и номер типа проверяет C. */ + (void)env; (void)self; if (device_type < 0 || device_id < 0 || address < 0 || route < 0) return 0; /* Отрицательные Java Int не превращаются в действительные unsigned-адреса. */ + return (jlong)pcan_gas_slot_id((unsigned)device_type, (unsigned)device_id, (unsigned)address, (unsigned)route); /* Один общий построитель формирует MsgType=0x4 и полный адрес 0…65535. */ +} /* Конец адресного адаптера. */ +JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_GasSlots_nativeDecodeWords(JNIEnv *env, jobject self, jlong id, jint flags, jbyteArray input) /* Возвращаем проверенные wire-слова любого слотного узла. */ +{ /* В этой границе отсутствуют собственные правила маски или порядка октетов. */ + uint_least8_t bytes[8]; uint16_t words[4]; jint values[4]; jsize length; jintArray out; int count, i; (void)self; /* Все буферы ограничены одним classic CAN кадром. */ + if (id < 0 || id > 0xFFFFFFFFLL || flags < 0 || input == NULL) return NULL; /* Проверяем представимость Long и наличие входа до JNI-копирования. */ + length = (*env)->GetArrayLength(env, input); if (length > 8) return NULL; /* Не усекаем данные CAN FD до classic CAN. */ + if (length > 0) (*env)->GetByteArrayRegion(env, input, 0, length, (jbyte *)bytes); if ((*env)->ExceptionCheck(env)) return NULL; /* Сохраняем точные wire-октеты и прекращаем работу при исключении JVM. */ + count = pcan_gas_slot_decode_words((uint32_t)id, (unsigned)flags, bytes, (unsigned)length, words); if (count < 0) return NULL; /* Тип 0x4, маску, DLC и направление проверяет общее C-ядро. */ + for (i = 0; i < count; ++i) values[i] = (jint)words[i]; /* Расширяем проверенные u16 слова без изменения знака или смысла маски. */ + out = (*env)->NewIntArray(env, count); if (out != NULL) (*env)->SetIntArrayRegion(env, out, 0, count, values); return out; /* Публикуем готовый результат, пустой только для корректного запроса чтения. */ +} /* Конец общего JNI-декодера. */ diff --git a/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt b/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt index 00dc1ab..7e367a8 100644 --- a/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt +++ b/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt @@ -11,7 +11,7 @@ enum class ProtoCanMessageType(val code: Int, val title: String) { DISCRETE(0x1, "Discrete"), ANALOG(0x2, "Analog"), GENERAL_ADDRESS_SPACE(0x3, "General Address Space"), - MODBUS_COIL(0x4, "Modbus Coil"), + GAS_SLOT(0x4, "GAS Slot"), // Код 0x4 выбирает слотный GAS с маской, регистровый GAS сохраняет собственный код 0x3. MODBUS_DISCRETE(0x5, "Modbus Discrete"), MODBUS_HOLDING(0x6, "Modbus Holding"), MODBUS_INPUT(0x7, "Modbus Input"), diff --git a/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/GasSlots.kt b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/GasSlots.kt new file mode 100644 index 0000000..c3167b5 --- /dev/null +++ b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/GasSlots.kt @@ -0,0 +1,10 @@ +package ru.setcorp.setprotocol // Размещаем слотный профиль рядом с существующим native-ядром приложения. + +object GasSlots { // Объект не вычисляет адреса и endian самостоятельно, сохраняя единый C-контракт. + init { System.loadLibrary("setprotocol") } // Отсутствие нового ядра проявляется явной ошибкой загрузки. + external fun nativeRequestId(mode: Int, localSlot: Int, route: Int): Long // Ноль означает неверные координаты; допустимый ID формирует C. + external fun nativeEncode(words: IntArray?): ByteArray? // Word0 — непустая маска битов 1…3, Word1…Word3 — значения; null запрашивает чтение. + external fun nativeDecode(canId: Long, flags: Int, payload: ByteArray): IntArray? // Результат PERIPH: mode, слот, маска и три значения; null означает отказ. + external fun nativeAddressId(deviceType: Int, deviceId: Int, address: Int, route: Int): Long // Общий C-построитель поддерживает любой узел и все адреса слота 0…65535. + external fun nativeDecodeWords(canId: Long, flags: Int, payload: ByteArray): IntArray? // Общий C-декодер возвращает маску и три значения любого узла либо пустой массив запроса. +} // Завершаем тонкую привязку без Kotlin-копии wire-протокола. diff --git a/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/NativeSetProtocol.kt b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/NativeSetProtocol.kt index cab62ec..9e050d9 100644 --- a/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/NativeSetProtocol.kt +++ b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/NativeSetProtocol.kt @@ -33,6 +33,9 @@ object NativeSetProtocol { external fun nativeTrendWatchValues(input: ByteArray): IntArray? /** {unsigned timestampMs, word0, ...}. */ external fun nativeTrendWatchDecode(input: ByteArray): LongArray? + external fun nativeGasWatchRequest(configId: Long, period: Int, addresses: IntArray): ByteArray? // Передаёт идентификатор конфигурации u32, период в миллисекундах и адреса u16 общему C-кодеку GAS_WATCH2. + external fun nativeGasWatchAck(input: ByteArray, configId: Long, period: Int, addresses: IntArray): Boolean // Проверяет C-кодеком полное эхо конфигурации, включая порядок всех адресов, до переключения активной подписки. + external fun nativeGasWatchDecode(input: ByteArray, configId: Long, count: Int): LongArray? // Возвращает проверенные C-кодеком sequence и время как положительные u32 в Long, затем слова либо −1 для невалидных каналов. external fun nativePackId( priority: Int, route: Int, diff --git a/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/trends/GuiGasWatch2.kt b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/trends/GuiGasWatch2.kt new file mode 100644 index 0000000..c086fa4 --- /dev/null +++ b/c/set-protocol/ports/android/kotlin/ru/setcorp/setprotocol/trends/GuiGasWatch2.kt @@ -0,0 +1,73 @@ +package ru.setcorp.setprotocol.trends // Размещает независимый от Android UI фасад подписок рядом с существующей поддержкой трендов. + +import java.util.Collections // Предоставляет неизменяемую оболочку коллекций, которую нельзя обойти приведением List к MutableList. +import ru.setcorp.setprotocol.NativeSetProtocol // Подключает единственный C-кодек через тонкие JNI-преобразования без повторного разбора wire-формата в Kotlin. + +object GuiGasWatch2 { // Объединяет проверяемые операции GAS_WATCH2 и модель состояния отдельного подключения. + const val SET = 0x14 // Идентификатор сообщения установки GAS_WATCH2 по согласованному GUI-контракту; содержимое payload формирует только C. + const val DATA = 0x15 // Идентификатор сообщения снимка GAS_WATCH2 по согласованному GUI-контракту; содержимое payload проверяет только C. + + class Config(val configId: Long, val periodMs: Int, addresses: List) { // Хранит неизменяемую конфигурацию: ненулевой u32 идентификатор, период в миллисекундах и упорядоченные адреса слов. + val addresses: List = Collections.unmodifiableList(ArrayList(addresses)) // Копирует внешний список и запрещает последующее изменение уже ожидаемой или активной конфигурации. + init { // Проверяет только границы преобразования JVM-чисел в C-типы; правила количества, дублей и остановки остаются в C-кодеке. + require(configId in 1L..0xFFFFFFFFL) { "Идентификатор конфигурации должен быть ненулевым u32" } // Не допускает потери старших битов или отрицательного Long при передаче идентификатора в uint32_t. + require(periodMs in 0..0xFFFF) { "Период должен помещаться в u16 миллисекунд" } // Сохраняет значение периода без усечения при преобразовании Int в uint16_t. + require(this.addresses.all { it in 0..0xFFFF }) { "Адрес GAS должен помещаться в u16" } // Проверяет каждый адрес до преобразования массива Int в массив 16-битных слов на JNI-границе. + } // Завершает проверки числового представления без добавления собственного кодека. + override fun equals(other: Any?): Boolean = other is Config && configId == other.configId && periodMs == other.periodMs && addresses == other.addresses // Сравнивает полную конфигурацию, чтобы запоздалое подтверждение не подошло другому порядку адресов. + override fun hashCode(): Int = 31 * (31 * configId.hashCode() + periodMs) + addresses.hashCode() // Согласует хеш с теми же тремя полями; множитель 31 служит обычным смешиванием хеша и не относится к протоколу. + } // Завершает модель конфигурации, общую для кодека и состояния подключения. + + class Sample(val configId: Long, val sequence: Long, val timestampMs: Long, values: List) { // Представляет один проверенный снимок с приборным временем в миллисекундах и положительным u32 номером последовательности. + val values: List = Collections.unmodifiableList(ArrayList(values)) // Фиксирует порядок слов активной конфигурации; null явно сохраняет признак невалидного канала вместо подстановки нуля. + } // Завершает неизменяемый снимок, пригодный для графика и записи без дополнительного разбора payload. + + fun request(config: Config): ByteArray { // Формирует payload установки или остановки подписки исключительно общим C-кодеком. + check(NativeSetProtocol.available) { "Общая библиотека SETProtocol недоступна" } // Не допускает скрытого перехода на другой кодек при отсутствии JNI-библиотеки. + return requireNotNull(NativeSetProtocol.nativeGasWatchRequest(config.configId, config.periodMs, config.addresses.toIntArray())) { "Некорректная конфигурация GAS_WATCH2" } // Делегирует C проверку лимита, дублей и согласованности нулевого периода с пустым списком. + } // Возвращает готовые байты без изменения состояния какого-либо подключения. + + fun validateAck(payload: ByteArray, config: Config) { // Проверяет полное эхо ожидаемой конфигурации, не делая выводов по одному количеству каналов. + check(NativeSetProtocol.available) { "Общая библиотека SETProtocol недоступна" } // Требует тот же C-кодек, который сформировал запрос. + require(NativeSetProtocol.nativeGasWatchAck(payload, config.configId, config.periodMs, config.addresses.toIntArray())) { "Подтверждение GAS_WATCH2 не соответствует конфигурации" } // C сравнивает идентификатор, период, число и точную последовательность адресов с ожидаемыми. + } // Завершает проверку ACK без самовольного переключения конфигурации. + + fun decode(payload: ByteArray, config: Config): Sample { // Преобразует только результат C-декодера; схема бинарного пакета в Kotlin отсутствует. + check(NativeSetProtocol.available) { "Общая библиотека SETProtocol недоступна" } // Сохраняет единый источник правил валидации снимков. + val decoded = requireNotNull(NativeSetProtocol.nativeGasWatchDecode(payload, config.configId, config.addresses.size)) { "Снимок GAS_WATCH2 не соответствует активной конфигурации" } // C отклоняет чужой идентификатор, неверное количество, длину, маску валидности и повреждённые поля. + return Sample(config.configId, decoded[0], decoded[1], decoded.drop(2).map { if (it < 0L) null else it.toInt() }) // Два первых элемента JNI-результата содержат sequence и время; −1 остальных элементов переводится в null без повторного wire-декодирования. + } // Возвращает снимок только после успешной проверки общей библиотекой. + + class Session { // Изолирует подтверждённую и ожидающую подписки одного подключения, чтобы разные приборы не делили состояние. + @Volatile var active: Config? = null // Публикует только подтверждённую конфигурацию; volatile обеспечивает видимость чтения с другого потока JVM. + private set // Запрещает внешнему коду обходить проверку полного ACK при изменении активной конфигурации. + @Volatile var pending: Config? = null // Хранит последний успешно построенный запрос отдельно от действующей подписки. + private set // Не позволяет потребителю подменить ожидаемую конфигурацию без вызова request. + + @Synchronized fun request(config: Config): ByteArray { // Сериализует формирование запросов и подтверждения, сохраняя атомарность переходов состояния. + require(active?.let { it.configId != config.configId || it == config } != false) { "Активный идентификатор GAS_WATCH2 уже связан с другой конфигурацией" } // Запрещает присвоить действующему идентификатору иной период или список, сохраняя допустимость идентичного повтора. + require(pending?.let { it.configId != config.configId || it == config } != false) { "Ожидающий идентификатор GAS_WATCH2 уже связан с другой конфигурацией" } // Не допускает неоднозначности одинаковых идентификаторов у двух различающихся ожидающих запросов. + val payload = GuiGasWatch2.request(config) // Сначала получает успешно проверенный C-кодеком payload; ошибка оставляет обе конфигурации неизменными. + pending = config // Запоминает именно последний запрос и оставляет active действующей до получения полного ACK. + return payload // Передаёт вызывающему коду готовый payload для отправки выбранным транспортом. + } // Завершает атомарную постановку ожидающей конфигурации. + + @Synchronized fun validateAck(payload: ByteArray, config: Config) { // Применяет подтверждение только к конфигурации последнего запроса этого подключения. + require(pending == config) { "Получено запоздалое или незапрошенное подтверждение GAS_WATCH2" } // Даже корректный старый ACK не может вернуть уже заменённый ожидающий список. + GuiGasWatch2.validateAck(payload, config) // Проверяет в C полное эхо до каких-либо изменений active или pending. + active = config // Атомарно переключает декодирование входящих снимков на подтверждённый список адресов. + pending = null // Убирает завершённый запрос, чтобы повторный ACK не считался новым подтверждением. + } // Завершает переход к новой активной подписке только после двух проверок ACK. + + @Synchronized fun sample(payload: ByteArray): Sample { // Декодирует снимок по стабильному активному списку даже во время ожидания нового ACK. + val config = checkNotNull(active) { "Нет подтверждённой конфигурации GAS_WATCH2" } // Отклоняет данные до первого подтверждения вместо угадывания адресов по ожидающему запросу. + check(config.periodMs != 0) { "Подписка GAS_WATCH2 остановлена" } // Не принимает запоздалые данные после подтверждённой остановки потока. + return GuiGasWatch2.decode(payload, config) // Делегирует C проверку активного идентификатора и количества каналов вместе с форматом снимка. + } // Возвращает только снимки подтверждённой работающей подписки. + + @Synchronized fun reset() { // Сбрасывает состояние при разрыве связи до повторной настройки нового подключения. + active = null // Не позволяет принять пакет предыдущего соединения до нового подтверждения конфигурации. + pending = null // Не позволяет запоздалому ACK прежнего соединения активировать старый список. + } // Завершает согласованный сброс обоих состояний подключения. + } // Завершает диспетчер одного подключения, не привязанный к UI или конкретному транспорту. +} // Завершает Android-фасад GAS_WATCH2, использующий единственный C-кодек. diff --git a/c/set-protocol/ports/android/setprotocol_jni.c b/c/set-protocol/ports/android/setprotocol_jni.c index 1d9c264..1cd7f44 100644 --- a/c/set-protocol/ports/android/setprotocol_jni.c +++ b/c/set-protocol/ports/android/setprotocol_jni.c @@ -11,6 +11,7 @@ #include "setprotocol_abi.h" #include "set_trends.h" +#include "set_gas_watch.h" /* Подключает единственный кодек GAS_WATCH2 и общие лимиты буферов, чтобы JNI не воспроизводил wire-формат. */ #include "set_spectrum.h" #include "balsam_can.h" #include "periph28335.h" @@ -547,6 +548,77 @@ Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTrendWatchDecode( return result; } +static int gas_watch_copy_addresses(JNIEnv *env, jintArray input, uint16_t *addresses, jsize *count) /* Преобразует JVM IntArray в u16-массив без усечения; протокольные правила проверяет только C-кодек. */ +{ /* Начинает общий для запроса и ACK ограниченный переход между представлениями JNI и C. */ + if (input == NULL) return 0; /* Отклоняет отсутствующий массив до обращения к GetArrayLength, исключая исключение JNI из-за null. */ + *count = (*env)->GetArrayLength(env, input); /* Получает фактическое число адресов из JVM-массива, не доверяя внешнему счётчику. */ + if (*count > (jsize)SET_GAS_WATCH_MAX) return 0; /* Ограничивает копирование общим лимитом 64 слов до заполнения стековых массивов. */ + jint source[SET_GAS_WATCH_MAX]; /* Резервирует исходные знаковые JVM-числа по единственному лимиту из C-заголовка. */ + (*env)->GetIntArrayRegion(env, input, 0, *count, source); /* Копирует JVM-адреса без удержания указателей на управляемую память. */ + if ((*env)->ExceptionCheck(env)) return 0; /* Не использует частично скопированный массив, если JVM сообщила исключение доступа к массиву. */ + for (jsize index = 0; index < *count; ++index) { /* Проверяет каждое число до приведения к беззнаковому 16-битному адресу. */ + if (source[index] < 0 || source[index] > UINT16_MAX) return 0; /* Не позволяет отрицательному или слишком большому Int превратиться в другой действительный GAS-адрес. */ + addresses[index] = (uint16_t)source[index]; /* Сохраняет проверенный адрес без потери битов; порядок остаётся равным порядку конфигурации. */ + } /* Завершает безопасное преобразование адресов без сортировки, удаления дублей или иной протокольной логики. */ + return 1; /* Сообщает вызывающей JNI-функции, что массив готов для проверки общим C-кодеком. */ +} /* Завершает вспомогательное преобразование числовых типов JNI. */ + +JNIEXPORT jbyteArray JNICALL /* Экспортирует JNI-метод, возвращающий готовые байты конфигурации GAS_WATCH2 либо null при отказе. */ +Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeGasWatchRequest( /* Связывает метод с объявлением NativeSetProtocol.nativeGasWatchRequest без регистрации второго кодека. */ + JNIEnv *env, jobject self, jlong config_id, jint period, jintArray input) /* Принимает u32 id в положительном Long, период в миллисекундах и JVM-массив адресов u16. */ +{ /* Начинает тонкий адаптер формирования запроса через общее C-ядро. */ + (void)self; /* Объект Kotlin не содержит данных, необходимых переносимому C-кодеку. */ + if (config_id <= 0 || (uint64_t)config_id > UINT32_MAX || period < 0 || period > UINT16_MAX) return NULL; /* Проверяет границы до приведения Long и Int, исключая потерю битов идентификатора или периода. */ + jsize count = 0; /* Получит число адресов только после проверки фактического JVM-массива. */ + uint16_t addresses[SET_GAS_WATCH_MAX]; /* Выделяет адреса на стеке по общему C-лимиту подписки без динамических выделений. */ + uint8_t output[SET_GAS_WATCH_CONFIG_MAX]; /* Выделяет максимально допустимый payload по C-константе вместо повторного расчёта wire-размеров в адаптере. */ + if (!gas_watch_copy_addresses(env, input, addresses, &count)) return NULL; /* Не передаёт C-кодеку адреса, которые нельзя точно представить как u16. */ + size_t size = set_gas_watch_request((uint32_t)config_id, (uint16_t)period, addresses, (size_t)count, output, sizeof output); /* Единственный C builder проверяет геометрию и создаёт канонический payload конфигурации. */ + return tms_result(env, output, size); /* Копирует результат в ByteArray существующим общим JNI-помощником; нулевая длина C-отказа превращается в null. */ +} /* Завершает запрос без хранения или изменения состояния подписки на JNI-стороне. */ + +JNIEXPORT jboolean JNICALL /* Экспортирует JNI-проверку полного подтверждения конфигурации GAS_WATCH2. */ +Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeGasWatchAck( /* Связывает метод с NativeSetProtocol.nativeGasWatchAck для проверки точного эхо-ответа. */ + JNIEnv *env, jobject self, jbyteArray input, jlong config_id, jint period, jintArray expected) /* Принимает payload ACK и исходные ожидаемые параметры без извлечения полей в JNI. */ +{ /* Начинает адаптер проверки ACK, делегирующий правила общему C-кодеку. */ + (void)self; /* Kotlin-объект служит только точкой вызова и не участвует в сравнении wire-полей. */ + if (input == NULL || config_id <= 0 || (uint64_t)config_id > UINT32_MAX || period < 0 || period > UINT16_MAX) return JNI_FALSE; /* Отбрасывает null и числа, которые были бы усечены при переходе к C-типам. */ + jsize count = 0; /* Получит проверенное количество исходных адресов для полного сравнения ACK в C. */ + uint16_t addresses[SET_GAS_WATCH_MAX]; /* Хранит ожидаемые адреса в том же исходном порядке, которым определяются позиции значений снимка. */ + if (!gas_watch_copy_addresses(env, expected, addresses, &count)) return JNI_FALSE; /* Не сравнивает ACK с недопустимым JVM-массивом или усечёнными адресами. */ + jsize size = (*env)->GetArrayLength(env, input); /* Получает длину ACK для безопасного копирования ограниченного буфера. */ + if (size > (jsize)SET_GAS_WATCH_CONFIG_MAX) return JNI_FALSE; /* Отбрасывает превышение общего максимума до копирования на стек. */ + jbyte payload[SET_GAS_WATCH_CONFIG_MAX]; /* Резервирует payload по общей C-константе; проверка точной длины остаётся в set_gas_watch_ack. */ + (*env)->GetByteArrayRegion(env, input, 0, size, payload); /* Копирует байты ACK без ручного разбора их полей или порядка байтов. */ + if ((*env)->ExceptionCheck(env)) return JNI_FALSE; /* Не вызывает C-кодек, если JVM не смогла полностью скопировать входной массив. */ + return set_gas_watch_ack((const uint8_t *)payload, (size_t)size, (uint32_t)config_id, (uint16_t)period, addresses, (size_t)count) ? JNI_TRUE : JNI_FALSE; /* Проверяет C-кодеком весь echo, включая версию, id, период, количество, reserved и порядок адресов. */ +} /* Завершает проверку ACK без изменения активной или ожидающей конфигурации. */ + +JNIEXPORT jlongArray JNICALL /* Экспортирует JNI-декодер снимка с положительными u32 счётчиками и отдельным маркером невалидного слова. */ +Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeGasWatchDecode( /* Связывает метод с NativeSetProtocol.nativeGasWatchDecode и единственным C-декодером GAS_WATCH2. */ + JNIEnv *env, jobject self, jbyteArray input, jlong config_id, jint expected_count) /* Принимает payload и параметры подтверждённой конфигурации, а не предполагаемые параметры из самого пакета. */ +{ /* Начинает ограниченное преобразование готового C-результата в JVM-массив. */ + (void)self; /* Все параметры ожидаемой подписки переданы явно; объект Kotlin не участвует в C-декодировании. */ + if (input == NULL || config_id <= 0 || (uint64_t)config_id > UINT32_MAX || expected_count < 0 || expected_count > (jint)SET_GAS_WATCH_MAX) return NULL; /* Проверяет null, u32 id и ограниченный count до приведения к C-типам и обращения к стековым буферам. */ + jsize size = (*env)->GetArrayLength(env, input); /* Получает длину входного JVM-массива без чтения каких-либо wire-полей. */ + if (size > (jsize)SET_GAS_WATCH_SAMPLE_MAX) return NULL; /* Гарантирует, что вход помещается в стековый буфер общего максимального размера снимка. */ + jbyte payload[SET_GAS_WATCH_SAMPLE_MAX]; /* Хранит исходный payload до завершения C-проверки версии, длины, id, count и bitmap. */ + uint16_t words[SET_GAS_WATCH_MAX]; /* Принимает от C сырые слова GAS без изменения знакового представления пользовательского параметра. */ + uint8_t valid[SET_GAS_WATCH_MAX]; /* Принимает от C уже проверенные признаки валидности по одному элементу на канал вместо повторного разбора bitmap. */ + uint32_t sequence = 0U, timestamp_ms = 0U; /* Принимает номер снимка и приборное время в миллисекундах как u32 без промежуточного знакового Int. */ + (*env)->GetByteArrayRegion(env, input, 0, size, payload); /* Копирует вход без удержания JVM-памяти и без воспроизведения протокольных смещений в адаптере. */ + if ((*env)->ExceptionCheck(env)) return NULL; /* Не использует частичный вход при исключении копирования JVM-массива. */ + int count = set_gas_watch_decode((const uint8_t *)payload, (size_t)size, (uint32_t)config_id, (size_t)expected_count, &sequence, ×tamp_ms, words, valid, SET_GAS_WATCH_MAX); /* C проверяет принадлежность снимка активной конфигурации и каноничность всего payload, возвращая число слов или −1. */ + if (count < 0) return NULL; /* Не публикует частично заполненные выходные данные после любой ошибки C-декодера. */ + jlong values[2U + SET_GAS_WATCH_MAX]; /* Два первых JVM-элемента принадлежат sequence и времени; остальные ограничены общим максимумом адресов. */ + values[0] = (jlong)sequence; /* Расширяет u32 номер снимка напрямую в положительный Long, включая значения с установленным bit31. */ + values[1] = (jlong)timestamp_ms; /* Расширяет u32 приборное время напрямую в положительный Long без потери старшего бита. */ + for (int index = 0; index < count; ++index) values[index + 2] = valid[index] ? (jlong)words[index] : -1; /* Передаёт валидное u16 слово как 0..65535, а невалидный канал как −1, которое Kotlin преобразует в null. */ + jlongArray result = (*env)->NewLongArray(env, count + 2); /* Создаёт ровно два элемента метаданных и по одному элементу на каждый проверенный канал снимка. */ + if (result != NULL) (*env)->SetLongArrayRegion(env, result, 0, count + 2, values); /* Копирует завершённый результат в управляемую память только после успешной C-проверки. */ + return result; /* Возвращает null при отказе JVM выделить массив и корректный LongArray во всех успешных случаях. */ +} /* Завершает JNI-декодер без второго протокольного алгоритма или собственной таблицы адресов. */ + typedef struct { uint8_t *storage; size_t storage_size; diff --git a/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/GasSlotsTest.kt b/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/GasSlotsTest.kt new file mode 100644 index 0000000..94e2563 --- /dev/null +++ b/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/GasSlotsTest.kt @@ -0,0 +1,34 @@ +package ru.setcorp.setprotocol // Проверяем тонкую Kotlin/JNI-границу общего C-кодека. +import org.junit.Assert.* // Сопоставляем точные CAN ID, wire-октеты и результаты отказа. +import org.junit.Test // Включаем проверки в существующий набор Android host tests. + +class GasSlotsTest { // Номер типа и маска проверяются настоящей shared-библиотекой. + @Test fun identifiersAndMask() { // Проверяем два адресных класса PERIPH и порядок Word0-маски. + val modes = intArrayOf(5, 6, 7, 8, 16, 31) // Номера совпадают с общими нормативными примерами. + val ids = longArrayOf(0x11540500L, 0x11640600L, 0x11740700L, 0x11840800L, 0x12041000L, 0x12F41F41L) // Тип 0x4 заменяет старый Coil без изменения адресов узлов. + val words = intArrayOf(14, 0x1234, 0xABCD, 0xFFFF) // Первое слово является маской, следующие три — независимыми значениями. + val payload = GasSlots.nativeEncode(words)!! // Только C-кодек формирует октеты и проверяет разрешённые биты маски. + assertArrayEquals(byteArrayOf(14, 0, 0x34, 0x12, 0xCD.toByte(), 0xAB.toByte(), 0xFF.toByte(), 0xFF.toByte()), payload) // Проверяем little-endian Word0 и всех трёх значений. + modes.forEachIndexed { index, mode -> // Дополнительно проверяем переход DeviceType после шестнадцати mode. + val slot = if (index == 5) 65 else 0 // Последний полный слот имеет индекс 65, неполный — 66. + assertEquals(ids[index], GasSlots.nativeRequestId(mode, slot, 0)) // Формула и номер типа находятся только в C. + val reply = GasSlots.nativeRequestId(mode, slot, 1) // Направление ответа задаётся явно. + assertArrayEquals(intArrayOf(mode, slot, 14, 0x1234, 0xABCD, 0xFFFF), GasSlots.nativeDecode(reply, 1, payload)) // Результат содержит маску отдельно от трёх значений. + } // Завершаем проверку независимых идентификаторов. + assertEquals(0x17E4FFFFL, GasSlots.nativeAddressId(7, 14, 65535, 0)) // Общий слотный API поддерживает независимый узел и максимальный адрес. + assertArrayEquals(words, GasSlots.nativeDecodeWords(0x1FE4FFFFL, 1, payload)) // Общий декодер не ограничен страницами PERIPH. + } // Конец проверки готовых кадров. + @Test fun invalidFrames() { // Ошибочный слот или маска не должны становиться другой командой. + assertEquals(0L, GasSlots.nativeRequestId(5, 67, 0)) // Значения за последним слотом 66 относятся к резерву. + assertEquals(0L, GasSlots.nativeAddressId(7, 14, 65536, 0)) // Полный адрес проверяется до сужения. + assertNull(GasSlots.nativeEncode(intArrayOf(1, 2, 3))) // Неполный payload не дополняется нулями. + assertNull(GasSlots.nativeEncode(intArrayOf(0, 1, 2, 3))) // Пустая маска запрещена. + assertNull(GasSlots.nativeEncode(intArrayOf(1, 1, 2, 3))) // Бит служебного Word0 не является битом значения. + assertNull(GasSlots.nativeEncode(intArrayOf(14, 1, 2, 65536))) // Число за пределами u16 не усекается. + val payload = GasSlots.nativeEncode(intArrayOf(14, 1, 2, 3))!! // Корректный кадр позволяет отдельно проверить адрес и флаги. + assertNull(GasSlots.nativeDecode(0x19540600L, 1, payload)) // Прибор 5 не обслуживает страницу mode 6. + assertNull(GasSlots.nativeDecode(0x19540500L, 3, payload)) // RTR не является ответом с данными. + assertNull(GasSlots.nativeDecode(0x19540542L, 1, payload)) // Последний слот не содержит Word3. + assertNull(GasSlots.nativeDecodeWords(0x19530500L, 1, payload)) // Тип 0x3 не принимается за слот при совпадении payload. + } // Конец отрицательных и граничных случаев. +} // Конец регрессионной проверки JNI. diff --git a/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/trends/GuiGasWatch2Test.kt b/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/trends/GuiGasWatch2Test.kt new file mode 100644 index 0000000..630bc14 --- /dev/null +++ b/c/set-protocol/ports/android/tests/ru/setcorp/setprotocol/trends/GuiGasWatch2Test.kt @@ -0,0 +1,122 @@ +package ru.setcorp.setprotocol.trends // Размещает проверки Android-фасада рядом с тестами существующих трендов и GAS_WATCH. + +import org.junit.Assert.* // Подключает стандартные утверждения JUnit для проверки состояния, значений и эталонных байтов. +import org.junit.Test // Помечает независимые сценарии, запускаемые на JVM с настоящей JNI-библиотекой. +import ru.setcorp.setprotocol.NativeSetProtocol // Позволяет отдельно проверить защиту числовых преобразований непосредственно на JNI-границе. + +class GuiGasWatch2Test { // Проверяет общий C-кодек через Kotlin/JNI и переходы ожидающей и активной подписок без второго кодека. + private val config = GuiGasWatch2.Config(0x12345678L, 100, listOf(0, 1, 0xFF01)) // Повторяет конфигурацию общего fixture gas-watch-v2.json: три GAS-слова и период 100 миллисекунд. + private val request = hex("0200640078563412030000000000010001ff") // Содержит эталонный payload конфигурации из общего C/Python/Kotlin fixture, включая полный список адресов. + private val payload = hex("0200030078563412fffffffff0ffffff037b00feff0000") // Содержит эталонный снимок: sequence u32 maximum, время 0xFFFFFFF0 мс, два валидных слова и один невалидный канал. + + private fun hex(text: String): ByteArray = text.chunked(2).map { it.toInt(16).toByte() }.toByteArray() // Переводит текст эталонных байтов в массив без знания полей или порядка байтов самого протокола. + private fun fails(action: () -> Unit) = assertTrue(runCatching(action).isFailure) // Проверяет отказ операции независимо от текста локализованной ошибки и не подменяет JNI-результат. + + @Test fun requestAndAckMatchSharedFixture() { // Фиксирует одинаковый wire-контракт Android-порта и общего C fixture. + assertArrayEquals(request, GuiGasWatch2.request(config)) // Сравнивает C-сформированный запрос побайтно с независимым эталоном. + GuiGasWatch2.validateAck(request, config) // Принимает точное полное эхо конфигурации в качестве ACK. + assertEquals(0x14, GuiGasWatch2.SET) // Фиксирует новый идентификатор установки, не затрагивая legacy GAS_WATCH_SET 0x12. + assertEquals(0x15, GuiGasWatch2.DATA) // Фиксирует новый идентификатор данных, не затрагивая legacy GAS_WATCH_DATA 0x13. + } // Завершает проверку эталонного запроса и допустимого подтверждения. + + @Test fun copiedAddressesCannotChangeOutstandingConfiguration() { // Проверяет, что изменение исходного UI-списка не меняет смысл уже сформированного запроса. + val source = mutableListOf(0, 1, 0xFF01) // Создаёт изменяемый список как типичный результат выбора строк таблицы. + val copied = GuiGasWatch2.Config(config.configId, config.periodMs, source) // Сохраняет конфигурацию с защитным копированием списка адресов. + source[0] = 25 // Моделирует последующее редактирование UI после постановки запроса. + assertEquals(config, copied) // Подтверждает неизменность полной конфигурации несмотря на изменение внешнего списка. + assertArrayEquals(request, GuiGasWatch2.request(copied)) // Подтверждает, что C по-прежнему получает исходные адреса fixture. + fails { (copied.addresses as MutableList)[0] = 25 } // Проверяет защиту от обхода read-only List приведением типа во время исполнения JVM. + } // Завершает проверку неизменяемости конфигурации, используемой для сопоставления ACK и данных. + + @Test fun requestRejectsInvalidGeometryWithoutTruncation() { // Проверяет диапазоны JNI и протокольные ограничения через единый C builder. + fails { GuiGasWatch2.Config(0L, 100, listOf(1)) } // Нулевой идентификатор запрещён, чтобы не смешивать неинициализированное состояние с конфигурацией. + fails { GuiGasWatch2.Config(0x100000000L, 100, listOf(1)) } // Значение за пределами u32 не должно усекаться до другого идентификатора. + fails { GuiGasWatch2.Config(1L, -1, listOf(1)) } // Отрицательный период не должен превращаться в большой unsigned u16. + fails { GuiGasWatch2.Config(1L, 100, listOf(0x10000)) } // Адрес за пределами u16 не должен превращаться в адрес ноль. + fails { GuiGasWatch2.request(GuiGasWatch2.Config(1L, 100, listOf(1, 1))) } // Проверяет отказ C от дублирующихся адресов, даже если список помещается в лимит. + fails { GuiGasWatch2.request(GuiGasWatch2.Config(1L, 100, (0..64).toList())) } // Проверяет отказ C от 65 слов при максимуме 64 слова на подписку. + fails { GuiGasWatch2.request(GuiGasWatch2.Config(1L, 0, listOf(1))) } // Остановка с непустым списком должна отклоняться вместо неоднозначного поведения прибора. + fails { GuiGasWatch2.request(GuiGasWatch2.Config(1L, 100, emptyList())) } // Пустая подписка с ненулевым периодом также нарушает общий контракт. + val maximum = GuiGasWatch2.Config(0xFFFFFFFFL, 0xFFFF, (0..63).toList()) // Покрывает допустимые максимальные u32 идентификатор, u16 период и 64 адреса без переполнения JNI. + GuiGasWatch2.validateAck(GuiGasWatch2.request(maximum), maximum) // Проверяет, что предельная допустимая конфигурация проходит C builder и exact ACK. + assertNull(NativeSetProtocol.nativeGasWatchRequest(-1L, 100, intArrayOf(1))) // Проверяет защиту JNI от отрицательного Long даже при обходе Kotlin Config. + assertNull(NativeSetProtocol.nativeGasWatchRequest(0x100000000L, 100, intArrayOf(1))) // Проверяет защиту JNI от усечения старших битов идентификатора. + assertNull(NativeSetProtocol.nativeGasWatchRequest(1L, 0x10000, intArrayOf(1))) // Проверяет защиту JNI от усечения периода при прямом вызове native-метода. + assertNull(NativeSetProtocol.nativeGasWatchRequest(1L, 100, intArrayOf(-1))) // Проверяет защиту JNI от преобразования отрицательного адреса в 0xFFFF. + } // Завершает проверки границ и протокольной геометрии без воспроизведения C-алгоритма. + + @Test fun ackRequiresIdentifierPeriodAndOrderedAddresses() { // Проверяет защиту от ACK чужой подписки с тем же количеством слов. + fails { GuiGasWatch2.validateAck(request, GuiGasWatch2.Config(0x12345679L, 100, config.addresses)) } // Другой идентификатор конфигурации не должен подтверждать ожидаемый запрос. + fails { GuiGasWatch2.validateAck(request, GuiGasWatch2.Config(config.configId, 101, config.addresses)) } // Совпадающие адреса не компенсируют расхождение периода в миллисекундах. + fails { GuiGasWatch2.validateAck(request, GuiGasWatch2.Config(config.configId, 100, listOf(1, 0, 0xFF01))) } // Перестановка адресов при том же количестве должна отклоняться, иначе значения будут подписаны чужими именами. + fails { GuiGasWatch2.validateAck(request.copyOf(request.size - 1), config) } // Усечённое эхо не должно применяться частично. + fails { GuiGasWatch2.validateAck(request + byteArrayOf(0), config) } // Лишний байт должен отклоняться как нарушение точной длины ACK. + } // Завершает проверку полного, а не сокращённого подтверждения. + + @Test fun decodePreservesUnsignedCountersAndInvalidValues() { // Проверяет преобразование C-результата в удобную для графика неизменяемую модель Kotlin. + val sample = GuiGasWatch2.decode(payload, config) // Декодирует реальный fixture через JNI и общее C-ядро. + assertEquals(config.configId, sample.configId) // Сохраняет идентификатор, по которому C проверил принадлежность снимка активной конфигурации. + assertEquals(0xFFFFFFFFL, sample.sequence) // Значение u32 maximum должно остаться положительным Long, а не −1 после знакового Int. + assertEquals(0xFFFFFFF0L, sample.timestampMs) // Приборное время с установленным старшим битом также должно остаться положительным. + assertEquals(listOf(123, 65534, null), sample.values) // Сырые u16 слова сохраняются без потери знака, а невалидный третий канал явно представлен null. + fails { (sample.values as MutableList)[0] = 5 } // Не позволяет потребителю переписать уже переданный другим обработчикам снимок. + } // Завершает проверку JNI-представления счётчиков, слов и валидности. + + @Test fun decodeRejectsStaleAndMalformedPackets() { // Проверяет, что JNI действительно передаёт все проверки формата и конфигурации общему C-декодеру. + fails { GuiGasWatch2.decode(payload, GuiGasWatch2.Config(config.configId + 1L, 100, config.addresses)) } // Старый пакет с прежним id нельзя принять в новую подписку того же размера. + fails { GuiGasWatch2.decode(payload, GuiGasWatch2.Config(config.configId, 100, listOf(0, 1))) } // Совпадающий id не разрешает принять иное количество значений. + fails { GuiGasWatch2.decode(payload.copyOf(payload.size - 1), config) } // Усечённое последнее слово не должно давать частичный снимок. + fails { GuiGasWatch2.decode(payload + byteArrayOf(0), config) } // Лишний байт не должен молча игнорироваться после допустимого пакета. + val dirtyInvalid = payload.copyOf().also { it[it.lastIndex] = 1 } // Нарушает fixture: у невалидного третьего канала wire-значение обязано оставаться нулём. + fails { GuiGasWatch2.decode(dirtyInvalid, config) } // Проверяет C-отказ от неканонического невалидного слова, чтобы не скрывать повреждение payload. + val dirtyPadding = payload.copyOf().also { it[16] = 0x83.toByte() } // Устанавливает bit7 единственного байта bitmap fixture при трёх каналах; этот padding-бит не относится ни к одному слову. + fails { GuiGasWatch2.decode(dirtyPadding, config) } // Проверяет C-отказ от ненулевых неиспользуемых битов валидности. + val wrongVersion = payload.copyOf().also { it[0] = 1 } // Меняет эталонную версию 2 на legacy-значение 1, не меняя остальные байты. + fails { GuiGasWatch2.decode(wrongVersion, config) } // Не позволяет принять другой контракт только из-за совпадения длины пакета. + assertNull(NativeSetProtocol.nativeGasWatchDecode(payload, config.configId, -1)) // Прямой JNI-вызов не должен превращать отрицательный count в большое size_t. + assertNull(NativeSetProtocol.nativeGasWatchDecode(payload, config.configId, 65)) // JNI ограничивает размеры своих стековых массивов до обращения к C-декодеру. + } // Завершает проверку чужих конфигураций, повреждения длины и канонического bitmap. + + @Test fun pendingChangePreservesActiveUntilExactAck() { // Моделирует смену адресов во время продолжающегося потока старой подписки. + val session = GuiGasWatch2.Session() // Создаёт состояние отдельного подключения без заранее активной конфигурации. + fails { session.sample(payload) } // До первого ACK клиент обязан отклонять данные, даже если их формат корректен. + assertArrayEquals(request, session.request(config)) // Ставит первый успешно построенный запрос в pending. + assertNull(session.active) // Один отправленный запрос ещё не означает, что прибор применил подписку. + assertEquals(config, session.pending) // Ожидающая конфигурация точно соответствует выданным байтам запроса. + session.validateAck(request, config) // Активирует первую подписку только после полного ACK. + val next = GuiGasWatch2.Config(config.configId + 1L, 100, listOf(2, 3, 0xFF01)) // Создаёт другую конфигурацию той же ширины для обнаружения ошибки позиционного сопоставления. + val nextRequest = session.request(next) // Ставит новую конфигурацию в pending, не заменяя подтверждённый список. + assertEquals(config, session.active) // До нового ACK продолжает действовать предыдущая подписка. + assertEquals(123, session.sample(payload).values[0]) // Старый корректный пакет продолжает декодироваться по старым адресам во время ожидания. + fails { session.validateAck(request, config) } // Запоздалый ACK первой конфигурации не может подтвердить последний запрос. + fails { session.validateAck(request, next) } // Подстановка ожидаемого объекта не позволяет выдать чужое полное эхо за новый ACK. + assertEquals(config, session.active) // Ошибочные подтверждения не должны сбросить действующую подписку. + assertEquals(next, session.pending) // Ошибочные подтверждения также не должны потерять последний ожидающий запрос. + session.validateAck(nextRequest, next) // Только точное эхо нового запроса переключает активную конфигурацию. + assertEquals(next, session.active) // Подтверждает переход к новому списку адресов. + assertNull(session.pending) // Успешное подтверждение завершает ожидающий запрос. + fails { session.sample(payload) } // Старый пакет того же размера после переключения должен отклоняться по id в C. + fails { session.validateAck(nextRequest, next) } // Повтор уже завершённого ACK не считается новым подтверждением. + } // Завершает проверку согласованного переключения и защиты от запоздалых пакетов. + + @Test fun failedRequestReusedIdStopAndResetKeepStateConsistent() { // Проверяет отказ запросов, идемпотентный повтор, остановку и границу переподключения. + val session = GuiGasWatch2.Session() // Создаёт независимое состояние для сценария ошибок и завершения подписки. + session.request(config) // Готовит первый запрос, который далее будет подтверждён настоящим C-валидатором. + session.validateAck(request, config) // Устанавливает известную действующую конфигурацию. + session.request(config) // Разрешает идентичный повтор запроса с тем же id как идемпотентную операцию. + fails { session.request(GuiGasWatch2.Config(config.configId, 101, config.addresses)) } // Запрещает переиспользовать active или pending id с другим периодом. + fails { session.request(GuiGasWatch2.Config(config.configId + 1L, 100, listOf(1, 1))) } // Ошибка C builder не должна заменить ожидающую конфигурацию некорректным списком. + assertEquals(config, session.active) // После обеих ошибок сохраняется подтверждённая подписка. + assertEquals(config, session.pending) // После обеих ошибок сохраняется последний успешно построенный запрос. + session.validateAck(request, config) // Завершает идемпотентный повтор до отдельного запроса остановки. + val stop = GuiGasWatch2.Config(config.configId + 1L, 0, emptyList()) // Остановка представляется новой конфигурацией с нулевым периодом и пустым списком согласно C-контракту. + val stopRequest = session.request(stop) // Готовит остановку, пока старая подписка ещё активна до ACK. + assertEquals(123, session.sample(payload).values[0]) // Старый поток остаётся допустимым до фактического подтверждения остановки. + session.validateAck(stopRequest, stop) // Применяет остановку только после полного подтверждения прибора. + fails { session.sample(payload) } // После подтверждённой остановки данные не должны попадать в график. + session.reset() // Моделирует разрыв связи, очищая оба состояния перед следующим подключением. + assertNull(session.active) // Следующее соединение не наследует подтверждённый id предыдущего прибора. + assertNull(session.pending) // Следующее соединение не наследует ожидающий ACK предыдущего прибора. + fails { session.validateAck(stopRequest, stop) } // Запоздалое подтверждение до разрыва не может активировать конфигурацию после reset. + } // Завершает сценарий отказов и границы жизненного цикла подключения. +} // Завершает JVM/JNI-проверки общего GAS_WATCH2 без UI-зависимостей. diff --git a/c/set-protocol/ports/stm32-bxcan/README.md b/c/set-protocol/ports/stm32-bxcan/README.md index 5f1dd42..04c89a3 100644 --- a/c/set-protocol/ports/stm32-bxcan/README.md +++ b/c/set-protocol/ports/stm32-bxcan/README.md @@ -34,7 +34,7 @@ c/set-protocol/ Модуль зависит от файлов `main.h` и `can.h`, сгенерированных STM32CubeMX, а также от HAL-драйверов CAN, RTC и TIM. В сборку добавляются -`c/set-protocol/ports/stm32-bxcan/protocan.c` и `c/set-protocol/src/pcan_id.c`. +`c/set-protocol/ports/stm32-bxcan/protocan.c`, `c/set-protocol/src/pcan_id.c` и `c/set-protocol/src/pcan_gas_slot.c`. В include paths добавляются `c/set-protocol/ports/stm32-bxcan`, `c/set-protocol/include` и каталог CubeMX с `main.h`/`can.h`. Если прошивка уже собирает общее ядро SETProtocol, второй раз добавлять @@ -80,7 +80,7 @@ c/set-protocol/ | `0x1` | дискретное (`DISCRETE`) | | `0x2` | аналоговое (`ANALOG`) | | `0x3` | общее адресное пространство | -| `0x4` | Modbus Coil | +| `0x4` | GAS SLOT: Word0-маска и три значения | | `0x5` | Modbus Discrete | | `0x6` | Modbus Holding | | `0x7` | Modbus Input | @@ -600,3 +600,9 @@ CRC32 обнаруживает случайное повреждение, но 7. При необходимости подключить HAL-callback’и вручную. 8. Переопределить нужные `__weak`-обработчики. 9. Вызывать `PROTOCAN_ProcessAllRxMsgs()` в основном цикле. + +## GAS: регистры 0x3 и слоты 0x4 + +[Адресация GAS](../../docs/GAS_SLOT.md): `0x3` — отдельные 16-битные регистры `0…65535`, запись 1…4 слов. `0x4` — слот с Word0-маской и тремя значениями; PERIPH сохраняет 200 слов в 67 слотах `0xMM00…0xMM42`. Формат определяется MsgType, без настройки профиля. + +`PROTOCAN_GAS_SLOT_BIND(&port)` подключает provider типа 0x4 до обработки очереди. `ProtoCanMsgToGasSlot()` вызывает общий адресный обработчик, `PROTOCAN_SEND_GAS_SLOT()` кодирует Word0-маску и три значения. Неподключённый provider возвращает ошибку. Типы Modbus 0x5…0x7 сохраняют прежние номера. diff --git a/c/set-protocol/ports/stm32-bxcan/protocan.c b/c/set-protocol/ports/stm32-bxcan/protocan.c index eef7c68..1bdeca0 100644 --- a/c/set-protocol/ports/stm32-bxcan/protocan.c +++ b/c/set-protocol/ports/stm32-bxcan/protocan.c @@ -170,12 +170,15 @@ void PROTOCAN_LoopProcessRxMsgs(void) { ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_GAS_SLOT) /* Независимый тип 0x4 не должен попадать в обработчик Modbus. */ + { /* Передаём маску и значения общему слотному кодеку из основного цикла. */ + ProtoCanMsgToGasSlot(rxMsg[CurrentStep]); /* ISR только ставит кадр в очередь; provider вызывается здесь. */ + } /* Завершаем обработку слотного сообщения. */ else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_SETTINGS) { PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); } - else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || /* Тип 0x4 передаётся отдельному слотному обработчику, Modbus начинается с 0x5. */ rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) { @@ -226,12 +229,15 @@ PROTOCAN_StatusTypeDef PROTOCAN_ProcessAllRxMsgs(void) { result = ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_GAS_SLOT) /* Независимый тип 0x4 не должен попадать в обработчик Modbus. */ + { /* Передаём маску и значения общему слотному кодеку из основного цикла. */ + result = ProtoCanMsgToGasSlot(rxMsg[CurrentStep]); /* ISR только ставит кадр в очередь; provider вызывается здесь. */ + } /* Завершаем обработку слотного сообщения. */ else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_SETTINGS) { result = PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); } - else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || /* Тип 0x4 передаётся отдельному слотному обработчику, Modbus начинается с 0x5. */ rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) { @@ -283,12 +289,15 @@ PROTOCAN_StatusTypeDef PROTOCAN_ProcessSingleRxMsg(void) { result = ProtoCanMsgToGeneralAddressSpace(rxMsg[CurrentStep]); } + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_GAS_SLOT) /* Независимый тип 0x4 не должен попадать в обработчик Modbus. */ + { /* Передаём маску и значения общему слотному кодеку из основного цикла. */ + result = ProtoCanMsgToGasSlot(rxMsg[CurrentStep]); /* ISR только ставит кадр в очередь; provider вызывается здесь. */ + } /* Завершаем обработку слотного сообщения. */ else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_SETTINGS) { result = PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); } - else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_COIL || - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || /* Тип 0x4 передаётся отдельному слотному обработчику, Modbus начинается с 0x5. */ rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) { @@ -1123,11 +1132,6 @@ PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg _rxMsg) { switch(_rxMsg.eID.Fields.MsgType) { - case PROTOCAN_MSGTYPE_MODBUS_COIL: - { - return ProtoCanMsgToModbusCoil(_rxMsg); - break; - } case PROTOCAN_MSGTYPE_MODBUS_DISCRETE: { return ProtoCanMsgToModbusDiscrete(_rxMsg); @@ -1151,37 +1155,37 @@ PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg _rxMsg) return PROTOCAN_ERROR; } -/** -* @brief __weak Функция отправки ответа на запрос Coil Modbus по CAN. -* Формирует CAN ответ на запрос Coil Modbus и отправляет его. -* @param _rxMsg Структура входящего сообщения RXMsg. -* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). -*/ -__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusCoil(struct RXMsg _rxMsg) -{ - CAN_TxHeaderTypeDef TxHeader; - uint32_t TxMailBox = 0; - uint8_t data[8]; - TxHeader.IDE = CAN_ID_EXT; - TxHeader.TransmitGlobalTime = DISABLE; - TxHeader.RTR = CAN_RTR_DATA; - ProtoCanId_t tmp_eID; - tmp_eID.BitAll = _rxMsg.eID.BitAll; - tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; - TxHeader.ExtId = PROTOCAN_IdPack(&tmp_eID); - TxHeader.DLC = 8; - msgBodyModbusType msg; - msg.Body = _rxMsg.eID.Fields.MsgBody; - data[0] = 'M'; - data[1] = 'C'; - data[2] = ' '; - data[3] = 'S'; - data[4] = msg.Fields.StrAdr; - data[5] = ' '; - data[6] = 'C'; - data[7] = msg.Fields.RegCount; - return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); -} +static const pcan_gas_slot_port_t *gas_slot_port; /* Provider принадлежит приложению; NULL означает, что слотный сервис ещё не подключён. */ +void PROTOCAN_GAS_SLOT_BIND(const pcan_gas_slot_port_t *port) /* Вызывать при инициализации до обработки очереди CAN. */ +{ /* Срок жизни структуры provider должен покрывать всё время работы порта. */ + gas_slot_port = port; /* NULL явно отключает сервис без подстановки фиктивных данных. */ +} /* Конец подключения аппаратно-независимого provider. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_GAS_SLOT(ProtoCanId_t id, uint16_t address, const uint16_t *words, unsigned count) /* Отправляем маску и три значения единственным C-кодеком. */ +{ /* Нулевой count обозначает чтение, четыре wire-слова — масочную запись или ответ. */ + CAN_TxHeaderTypeDef header = {0}; uint32_t mailbox = 0U; uint_least8_t bytes[8]; uint16_t checked[4]; uint8_t data[8] = {0}; int length; unsigned i; /* HAL получает восемь октетов независимо от внутреннего представления общего ядра. */ + id.Fields.MsgType = PROTOCAN_MSGTYPE_GAS_SLOT; id.Fields.MsgBody = address; /* Тип 0x4 и полный 16-битный адрес слота задаются отдельно от карты регистров 0x3. */ + length = pcan_gas_slot_encode(words, count, bytes); /* Проверяем маску Word0 до формирования отправляемого HAL-заголовка. */ + if (_HCAN == NULL || length < 0 || pcan_gas_slot_decode_words(PROTOCAN_IdPack(&id), PCAN_GAS_SLOT_FLAG_IDE, bytes, (unsigned)length, checked) < 0) return PROTOCAN_ERROR; /* Не отправляем неверную маску, пустой ответ или кадр без подготовленного CAN. */ + for (i = 0U; i < (unsigned)length; ++i) data[i] = (uint8_t)bytes[i]; /* Переносим уже закодированные октеты без повторного endian-алгоритма. */ + header.IDE = CAN_ID_EXT; header.ExtId = PROTOCAN_IdPack(&id); header.RTR = CAN_RTR_DATA; header.DLC = (uint32_t)length; header.TransmitGlobalTime = DISABLE; /* Используем extended data frame с DLC ровно 0 либо 8. */ + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &header, data, &mailbox); /* Возвращаем фактический результат постановки кадра в аппаратный TX mailbox. */ +} /* Конец отправки слота через действующий HAL-порт. */ +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToGasSlot(struct RXMsg message) /* При необходимости приложение может переопределить адаптер, сохранив общий wire-контракт. */ +{ /* По умолчанию подключённый provider обрабатывается переносимым C-ядром. */ + pcan_gas_slot_frame_t request = {0}, response; unsigned i; int result; /* Ограничиваем вход одним CAN-кадром и не используем динамическую память. */ + if (gas_slot_port == NULL || message.DLC > 8U) return PROTOCAN_ERROR; /* Не имитируем успешный сервис без реального provider устройства. */ + request.id = PROTOCAN_IdPack(&message.eID); request.dlc = message.DLC; request.flags = (message.info.EXT ? PCAN_GAS_SLOT_FLAG_IDE : 0U) | (message.info.RTR ? PCAN_GAS_SLOT_FLAG_RTR : 0U); /* Сохраняем фактические флаги приёма для проверки общим декодером. */ + for (i = 0U; i < message.DLC; ++i) request.data[i] = message.Data[i]; /* Передаём исходные wire-октеты без извлечения маски в HAL-адаптере. */ + result = pcan_gas_slot_handle_address(CURRENT_TYPE_DEVICE, CURRENT_ID_DEVICE, gas_slot_port, &request, &response); /* Проверяем тип 0x4, адрес своего узла, направление и маску до вызова provider. */ + if (result < 0) return PROTOCAN_ERROR; /* Неверный слот или запрещённая запись не переходят в Modbus или GAS 0x3. */ + if (result == 0) return PROTOCAN_OK; /* Базовый слотный протокол не формирует отдельный ACK записи. */ + message.eID.BitAll = response.id; /* Ответ общего ядра сохраняет адрес узла и меняет Route на FROM_DEVICE. */ + { /* Проверенный ответ переводится в HAL тем же публичным методом отправки. */ + uint16_t words[4]; /* Маска и значения возвращаются общим декодером без второго wire-алгоритма. */ + if (pcan_gas_slot_decode_words(response.id, response.flags, response.data, response.dlc, words) < 0) return PROTOCAN_ERROR; /* Проверяем сформированный ответ перед публикацией в транспорт. */ + return PROTOCAN_SEND_GAS_SLOT(message.eID, (uint16_t)(response.id & 0xFFFFU), words, 4U); /* Отправляем один полный восьмибайтовый слот с маской достоверных значений. */ + } /* Завершаем отправку сформированного ответа. */ +} /* Конец стандартного адаптера слотного GAS. */ /** * @brief __weak Функция отправки ответа на запрос Discrete Modbus по CAN. @@ -1288,8 +1292,8 @@ __weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusInput(struct RXMsg _rxMsg) * @param modbusData Структура с данными Modbus: адрес, количество регистров и сами данные. * @return PROTOCAN_StatusTypeDef Статус операции. * @details - * В зависимости от типа Modbus (coil/discrete или holding/input), формируется - * соответствующий CAN-пакет. Для coil/discrete отправляется один пакет, для holding/input — + * В зависимости от типа Modbus (discrete или holding/input), формируется + * соответствующий CAN-пакет. Для discrete отправляется один пакет, для holding/input — * несколько, по 4 регистра в пакете. В случае ошибок при добавлении сообщения API HAL возвращается ошибка. */ PROTOCAN_StatusTypeDef PROTOCAN_SEND_MODBUS(const ProtoCanId_t id, const struct ProtoCanModbusData modbusData) @@ -1300,7 +1304,7 @@ PROTOCAN_StatusTypeDef PROTOCAN_SEND_MODBUS(const ProtoCanId_t id, const struct CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailBox = 0; uint8_t canData[8]; - if(msgType == PROTOCAN_MSGTYPE_MODBUS_COIL || msgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE) + if(msgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE) /* Битовая ветвь Modbus поддерживает только входы 0x5; 0x4 зарезервирован слотному GAS. */ { // Формируем body msgBodyModbusType body; @@ -1649,7 +1653,8 @@ PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data) data.GeneralAddressSpaceData.Data, data.GeneralAddressSpaceData.RegCount); } - case PROTOCAN_MSGTYPE_MODBUS_COIL: + case PROTOCAN_MSGTYPE_GAS_SLOT: /* Отправка 0x4 использует служебную маску, а не структуру Modbus. */ + return PROTOCAN_SEND_GAS_SLOT(id, data.GasSlotData.Address, data.GasSlotData.Words, data.GasSlotData.Count); /* Count=0 запрашивает чтение; Count=4 передаёт маску и три значения. */ case PROTOCAN_MSGTYPE_MODBUS_DISCRETE: case PROTOCAN_MSGTYPE_MODBUS_HOLDING: case PROTOCAN_MSGTYPE_MODBUS_INPUT: diff --git a/c/set-protocol/ports/stm32-bxcan/protocan.h b/c/set-protocol/ports/stm32-bxcan/protocan.h index 2fac9b8..08636bc 100644 --- a/c/set-protocol/ports/stm32-bxcan/protocan.h +++ b/c/set-protocol/ports/stm32-bxcan/protocan.h @@ -10,6 +10,7 @@ #include "main.h" #include "can.h" #include "pcan_id.h" +#include "pcan_gas_slot.h" /* Общий формат типа 0x4 используется при приёме и отправке масочных слотов без дублирования кодека. */ #define _DEMO @@ -82,7 +83,7 @@ typedef enum { PROTOCAN_MSGTYPE_DISCRETE = 0b0001, /**< Дискретное цифровое сообщение. */ PROTOCAN_MSGTYPE_ANALOG = 0b0010, /**< Аналоговое сообщение. */ PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE = 0b0011, /**< Сообщение общего адресного пространства. */ - PROTOCAN_MSGTYPE_MODBUS_COIL = 0b0100, /**< Сообщение Modbus - Coil. */ + PROTOCAN_MSGTYPE_GAS_SLOT = 0b0100, /**< Слотный GAS: Word0 — маска, Word1…Word3 — значения; прежний код Coil заменён. */ PROTOCAN_MSGTYPE_MODBUS_DISCRETE = 0b0101, /**< Сообщение Modbus - Discrete. */ PROTOCAN_MSGTYPE_MODBUS_HOLDING = 0b0110, /**< Сообщение Modbus - Holding. */ PROTOCAN_MSGTYPE_MODBUS_INPUT = 0b0111, /**< Сообщение Modbus - Input. */ @@ -314,6 +315,11 @@ typedef struct{ uint16_t *Data; /**< Указатель на массив данных. */ unsigned RegCount; /**< Количество регистров. */ } GeneralAddressSpaceData; + struct ProtoCanGasSlotData { /* Отдельная структура исключает смешение номера слота и адреса первого регистра GAS. */ + uint16_t Address; /* Полный 16-битный адрес слота 0…65535. */ + const uint16_t *Words; /* Четыре wire-слова: маска Word0 и значения Word1…Word3. */ + unsigned Count; /* Ноль означает чтение, четыре — маску и три значения; другие размеры отвергает C-кодек. */ + } GasSlotData; /* Член структуры используется только для MsgType=0x4. */ struct ProtoCanModbusData{ uint16_t StrAdr; uint16_t *Data; @@ -422,7 +428,9 @@ PROTOCAN_StatusTypeDef ProtoCanMsgToGeneralAddressSpace(struct RXMsg _rxMsg); PROTOCAN_StatusTypeDef PROTOCAN_RequestError(struct RXMsg _rxMsg); PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg _rxMsg); -PROTOCAN_StatusTypeDef ProtoCanMsgToModbusCoil(struct RXMsg _rxMsg); +void PROTOCAN_GAS_SLOT_BIND(const pcan_gas_slot_port_t *port); /* Подключает долгоживущий provider слотов до обработки очереди; NULL отключает сервис. */ +PROTOCAN_StatusTypeDef ProtoCanMsgToGasSlot(struct RXMsg message); /* Передаёт тип 0x4 общему обработчику с проверкой адреса узла и маски Word0. */ +PROTOCAN_StatusTypeDef PROTOCAN_SEND_GAS_SLOT(ProtoCanId_t id, uint16_t address, const uint16_t *words, unsigned count); /* Отправляет один слот через общий C-кодек, без Modbus-упаковки адреса. */ PROTOCAN_StatusTypeDef ProtoCanMsgToModbusDiscrete(struct RXMsg _rxMsg); PROTOCAN_StatusTypeDef ProtoCanMsgToModbusHolding(struct RXMsg _rxMsg); PROTOCAN_StatusTypeDef ProtoCanMsgToModbusInput(struct RXMsg _rxMsg); diff --git a/c/set-protocol/src/pcan_gas.c b/c/set-protocol/src/pcan_gas.c index 27132b4..1562edb 100644 --- a/c/set-protocol/src/pcan_gas.c +++ b/c/set-protocol/src/pcan_gas.c @@ -139,7 +139,8 @@ uint16_t pcan_gas_write_block(const pcan_gas_map_t *map, uint16_t addr, uint16_t pcan_gas_frame_to_regs(const pcan_frame_t *frame, uint16_t *out, uint16_t max) { - uint16_t n = 0U; + uint16_t n = 0U; /* Счётчик увеличивается только после проверки длины и наличия обоих октетов слова. */ + if (frame == NULL || out == NULL || frame->dlc > PCAN_DATA_MAX || (frame->dlc & 1U) != 0U) return 0U; /* Отвергаем нечётные и превышающие classic CAN длины до доступа к данным. */ for (uint8_t i = 0U; (uint8_t)(i + 1U) < frame->dlc; i = (uint8_t)(i + 2U)) { if (n >= max) { break; @@ -178,9 +179,10 @@ void pcan_gas_regs_to_frame(pcan_frame_t *frame, uint32_t base_id, bool pcan_gas_handle(const pcan_gas_map_t *map, const pcan_frame_t *req, pcan_frame_t *rsp) { - pcan_id_t id; - pcan_id_unpack(req->id, &id); - if (id.msg_type != (uint8_t)PCAN_MSG_GAS) { + pcan_id_t id; /* Адрес регистра и направление проверяются до вызова provider, чтобы ответ не стал записью. */ + if (map == NULL || req == NULL || (req->id & ~PCAN_ID_MASK) != 0U || (req->flags & PCAN_FLAG_IDE) == 0U || (req->flags & (PCAN_FLAG_RTR | PCAN_FLAG_ERR)) != 0U || req->dlc > PCAN_DATA_MAX || (req->dlc & 1U) != 0U) return false; /* Принимаем только extended data frame с целыми 16-битными регистрами. */ + pcan_id_unpack(req->id, &id); /* Разбираем проверенный 29-битный идентификатор единственным общим кодеком. */ + if (id.msg_type != (uint8_t)PCAN_MSG_GAS || id.route != PCAN_ROUTE_FROM_PM || (uint32_t)id.msg_body + req->dlc / 2U > 0x10000UL || (req->dlc == 0U && rsp == NULL)) { /* Тип 0x4, ответы прибора и блоки за адресом 65535 не изменяют карту; чтению нужен выходной кадр. */ return false; } diff --git a/c/set-protocol/src/pcan_gas_slot.c b/c/set-protocol/src/pcan_gas_slot.c new file mode 100644 index 0000000..3df5c9a --- /dev/null +++ b/c/set-protocol/src/pcan_gas_slot.c @@ -0,0 +1,103 @@ +#include "pcan_gas_slot.h" /* Подключаем независимый слотный GAS типа 0x4 с маской в нулевом слове. */ +#include "pcan_id.h" /* Используем единственный общий упаковщик полей 29-битного CAN ID. */ +#include /* Локальный ответ обнуляется до заполнения и публикации вызывающему коду. */ +static unsigned available_mask(unsigned local) /* Вычисляем действующие позиции трёх значений PERIPH, включая неполный последний слот. */ +{ /* Маска не является хранимым регистром и не занимает адрес в карте технологических слов. */ + unsigned word, mask = 0U; /* Биты 1…3 соответствуют одноимённым позициям wire-пакета после маски. */ + for (word = 1U; word <= PCAN_GAS_SLOT_DATA_WORDS; ++word) if (local * PCAN_GAS_SLOT_DATA_WORDS + word - 1U < PCAN_GAS_SLOT_MODE_WORDS) mask |= 1U << word; /* Сохраняем ровно 200 слов без фиктивного 201-го регистра. */ + return mask; /* Для обычного слота получаем 0x000E, для последнего — 0x0006. */ +} /* Завершаем расчёт единственной геометрии PERIPH. */ +int32_t pcan_gas_slot_address(unsigned mode, unsigned local) /* Строим читаемый адрес только для реально выделенной страницы PERIPH. */ +{ /* Остальные 16-битные адреса доступны через общий адресный API отдельного узла. */ + if (mode >= PCAN_GAS_SLOT_MODE_COUNT || local >= PCAN_GAS_SLOT_MODE_SLOTS) return -1; /* Отвергаем чужой mode и резерв страницы до сужения типов. */ + return (int32_t)(((uint32_t)mode << 8) | local); /* Старший октет повторяет mode, младший содержит локальный слот 0…66. */ +} /* Конец проверки координат PERIPH. */ +uint32_t pcan_gas_slot_id(unsigned device_type, unsigned device_id, unsigned address, unsigned route) /* Поддерживаем любой узел ProtoCAN и полный адрес слота 0…65535. */ +{ /* Нулевой результат означает недопустимые поля, а не молчаливое усечение адреса. */ + pcan_id_t id; /* Битовую раскладку идентификатора формирует существующее общее ядро. */ + if (device_type > 7U || device_id > 15U || address > 65535UL || route > 1U) return 0U; /* Проверяем все поля до приведения к их wire-типам. */ + id.priority = PCAN_PRIORITY_STANDARD; id.route = (uint_least8_t)route; /* Обычный приоритет и явное направление сохраняют семантику ProtoCAN. */ + id.device_type = (uint_least8_t)device_type; id.device_id = (uint_least8_t)device_id; /* Не связываем общий слотный сервис исключительно с семейством PERIPH. */ + id.msg_type = PCAN_MSG_GAS_SLOT; id.msg_body = (uint16_t)address; /* Тип 0x4 однозначно отличает слот от адреса отдельного регистра типа 0x3. */ + return pcan_id_pack(&id); /* Публикуем идентификатор после проверки полного диапазона входов. */ +} /* Конец общего адресного построителя. */ +uint32_t pcan_gas_slot_request_id(unsigned mode, unsigned local, unsigned route) /* Сохраняем удобный совместимый вызов для mode PERIPH. */ +{ /* Обёртка добавляет только раскладку mode и не реализует второй кодек. */ + int32_t address = pcan_gas_slot_address(mode, local); /* Проверяем принадлежность слота выделенной странице. */ + return address < 0 ? 0U : pcan_gas_slot_id(1U + mode / 16U, mode % 16U, (unsigned)address, route); /* Обе группы по 16 узлов используют общий конструктор типа 0x4. */ +} /* Конец PERIPH-обёртки построения ID. */ +int pcan_gas_slot_encode(const uint16_t *words, unsigned count, uint_least8_t *data) /* Word0 содержит маску, Word1…Word3 — значения в фиксированных позициях. */ +{ /* Пустой payload означает чтение, полный восьмибайтовый payload — маску и данные. */ + unsigned i; /* Индекс относится к четырём wire-словам, включая служебную маску. */ + if (count == 0U) return 0; /* Запрос чтения не требует массива значений или фиктивной маски. */ + if (count != PCAN_GAS_SLOT_WORDS || words == NULL || data == NULL || words[0] == 0U || (words[0] & ~PCAN_GAS_SLOT_MASK) != 0U) return -1; /* Биты 0 и 4…15 зарезервированы, пустая запись запрещена. */ + for (i = 0U; i < PCAN_GAS_SLOT_WORDS; ++i) { /* Проверенная маска и три значения одинаково упаковываются little-endian. */ + data[2U * i] = (uint_least8_t)(words[i] & 255U); data[2U * i + 1U] = (uint_least8_t)(words[i] >> 8); /* Значения 255 и сдвиг 8 задают октеты линии независимо от ширины char C28x. */ + } /* Все восемь октетов сформированы только после проверки входа. */ + return 8; /* DLC измеряется октетами CAN, а не размером C-массива на wide-char процессоре. */ +} /* Конец единственного кодирования маски и значений. */ +int pcan_gas_slot_decode_words(uint32_t raw, unsigned flags, const uint_least8_t *data, unsigned dlc, uint16_t *words) /* Общая проверка формата не ограничивает узел PERIPH или страницу слота. */ +{ /* Выходные слова остаются неизменными при любой ошибке. */ + pcan_id_t id; unsigned i; uint16_t decoded[PCAN_GAS_SLOT_WORDS]; /* Сначала собираем результат в локальном массиве, чтобы отказ был безопасным. */ + if ((raw & ~PCAN_ID_MASK) != 0U || !(flags & PCAN_GAS_SLOT_FLAG_IDE) || (flags & (PCAN_GAS_SLOT_FLAG_RTR | PCAN_GAS_SLOT_FLAG_ERR)) != 0U) return -1; /* Принимаем только extended data frames classic CAN. */ + if ((dlc != 0U && dlc != 8U) || (dlc == 8U && (data == NULL || words == NULL))) return -1; /* Усечённая маска или часть слота не являются допустимой командой. */ + pcan_id_unpack(raw, &id); /* Все адресные поля извлекаются общим C-кодеком. */ + if (id.msg_type != PCAN_MSG_GAS_SLOT || (dlc == 0U && id.route != PCAN_ROUTE_FROM_PM)) return -1; /* Регистровый GAS 0x3 и пустой ответ не попадают в слотный сервис. */ + if (dlc == 0U) return 0; /* Пустой запрос чтения не изменяет массив значений. */ + for (i = 0U; i < 8U; ++i) if (data[i] > 255U) return -1; /* На C28x запрещаем ненулевые старшие биты каждой ячейки, представляющей wire-октет. */ + for (i = 0U; i < PCAN_GAS_SLOT_WORDS; ++i) decoded[i] = (uint16_t)((uint16_t)data[2U * i] | ((uint16_t)data[2U * i + 1U] << 8)); /* Восстанавливаем четыре слова с явно заданным порядком октетов. */ + if (decoded[0] == 0U || (decoded[0] & ~PCAN_GAS_SLOT_MASK) != 0U) return -1; /* Разрешены только непустые комбинации битов 1, 2 и 3, соответствующие позициям значений. */ + for (i = 0U; i < PCAN_GAS_SLOT_WORDS; ++i) words[i] = decoded[i]; /* Публикуем значения после проверки всей маски. */ + return PCAN_GAS_SLOT_WORDS; /* Четыре возвращённых слова включают Word0 с маской, а не четвёртый регистр. */ +} /* Конец общего декодера любого адреса слота. */ +int pcan_gas_slot_decode(uint32_t raw, unsigned flags, const uint_least8_t *data, unsigned dlc, unsigned *mode, unsigned *local, uint16_t *words) /* Добавляем к общему формату ограничения страницы PERIPH. */ +{ /* При отказе ни координаты, ни значения не меняются. */ + pcan_id_t id; unsigned found_mode, found_local, i; uint16_t decoded[PCAN_GAS_SLOT_WORDS]; int count; /* Подготавливаем промежуточные выходы общей проверки. */ + if (mode == NULL || local == NULL || (dlc != 0U && words == NULL)) return -1; /* Все требуемые выходные указатели проверяются до чтения или публикации данных. */ + count = pcan_gas_slot_decode_words(raw, flags, data, dlc, decoded); if (count < 0) return -1; /* Единственный wire-декодер проверяет тип 0x4, маску, DLC и флаги. */ + pcan_id_unpack(raw, &id); if (id.device_type < 1U || id.device_type > 2U) return -1; /* PERIPH занимает только два существующих класса адресов. */ + found_mode = (unsigned)(id.device_type - 1U) * 16U + id.device_id; found_local = id.msg_body & 255U; /* Номер mode восстанавливается независимо от старшего октета слота. */ + if (pcan_gas_slot_address(found_mode, found_local) != (int32_t)id.msg_body || (count > 0 && (decoded[0] & ~available_mask(found_local)) != 0U)) return -1; /* Отвергаем чужую страницу, резерв и несуществующее третье значение последнего слота. */ + if (count > 0) for (i = 0U; i < PCAN_GAS_SLOT_WORDS; ++i) words[i] = decoded[i]; /* Значения публикуются после проверки геометрии PERIPH. */ + *mode = found_mode; *local = found_local; return count; /* Возвращаем координаты только успешно проверенного кадра. */ +} /* Конец совместимой PERIPH-обёртки декодирования. */ +int pcan_gas_slot_native(unsigned local, unsigned word, unsigned write, uint16_t *address) /* Сопоставляем только значения Word1…Word3 с прежними native-регистрами. */ +{ /* Нулевая позиция является маской и никогда не адресует технологический регистр. */ + unsigned offset; uint16_t native; /* Смещение измеряется в 16-битных словах полезной карты, без служебных масок. */ + if (local >= PCAN_GAS_SLOT_MODE_SLOTS || word == 0U || word > PCAN_GAS_SLOT_DATA_WORDS || write > 1U || address == NULL) return 0; /* Предотвращаем адресацию маски и выход за выделенные позиции. */ + offset = local * PCAN_GAS_SLOT_DATA_WORDS + word - 1U; /* Каждый следующий слот содержит следующие три значения исходной карты из 200 слов. */ + if (offset < 128U) native = (uint16_t)offset; /* Все 128 технологических регистров сохраняют свои native-адреса и смысл. */ + else if (offset < 144U && !write) native = (uint16_t)(0x1000U + offset - 128U); /* Следующие 16 слов читают статус регистратора УМП. */ + else if (offset >= 144U && offset < 156U && !write) native = (uint16_t)(0x1200U + offset - 144U); /* Двенадцать слов паспорта доступны только для чтения. */ + else if (offset >= 156U && offset < 164U) { /* Восемь следующих слов относятся к защите УМП. */ + native = (uint16_t)(0x1300U + offset - 156U); /* Сохраняем исходные адреса 0x1300…0x1307 независимо от границ слота. */ + if (write && native != 0x1302U && native != 0x1303U) return 0; /* Масочная запись допускает только два разрешённых поля защиты. */ + } else if (offset >= 164U && offset < 168U) native = (uint16_t)(0x1000U + offset - 164U); /* Команды регистратора сохраняют собственные native-адреса четырёх слов. */ + else return 0; /* Резерв 168…199 и лишняя позиция 200 не имитируются нулевыми значениями. */ + *address = native; return 1; /* Доступность конкретного сервиса и применение записи проверяет provider устройства. */ +} /* Конец сопоставления без побочных эффектов. */ +int pcan_gas_slot_handle_address(unsigned device_type, unsigned device_id, const pcan_gas_slot_port_t *port, const pcan_gas_slot_frame_t *request, pcan_gas_slot_frame_t *response) /* Обрабатываем любой адресуемый узел ProtoCAN, включая отдельный инвертор. */ +{ /* Provider отвечает за общую проверку и изменение только выбранных маской значений. */ + pcan_id_t id; uint16_t words[PCAN_GAS_SLOT_WORDS]; int count, length; pcan_gas_slot_frame_t out; /* Все рабочие данные локальны и не требуют динамической памяти. */ + if (port == NULL || request == NULL || device_type > 7U || device_id > 15U) return -1; /* Не принимаем отсутствующий порт или усечённый адрес узла. */ + count = pcan_gas_slot_decode_words(request->id, request->flags, request->data, request->dlc, words); if (count < 0) return -1; /* Проверяем полный wire-контракт до обращения к provider. */ + pcan_id_unpack(request->id, &id); /* Направление и адрес проверяем отдельно от декодирования payload. */ + if (id.route != PCAN_ROUTE_FROM_PM || id.device_type != device_type || id.device_id != device_id) return -1; /* Ответы приборов и запросы соседям не исполняются. */ + if (count > 0) return port->write != NULL && port->write(port->context, id.msg_body, words) == 0 ? 0 : -1; /* Единственный callback получает маску Word0 и обязан сохранять невыбранные значения без чтения на хосте. */ + if (response == NULL || port->read == NULL || port->read(port->context, id.msg_body, words) != 0) return -1; /* Ошибка чтения не превращается в успешные нули. */ + memset(&out, 0, sizeof(out)); length = pcan_gas_slot_encode(words, PCAN_GAS_SLOT_WORDS, out.data); if (length < 0) return -1; /* Проверяем маску достоверных значений, которую вернул provider. */ + id.route = PCAN_ROUTE_FROM_DEVICE; out.id = pcan_id_pack(&id); out.flags = PCAN_GAS_SLOT_FLAG_IDE; out.dlc = (unsigned)length; /* Ответ сохраняет полный адрес слота и меняет только направление. */ + *response = out; return 1; /* Публикуем только полностью сформированный ответ. */ +} /* Конец общего обработчика слотов типа 0x4. */ +int pcan_gas_slot_handle(unsigned mode, const pcan_gas_slot_port_t *port, const pcan_gas_slot_frame_t *request, pcan_gas_slot_frame_t *response) /* Сохраняем специализированный вход PERIPH поверх общего обработчика. */ +{ /* Временный ответ защищает выходной кадр от ошибочного provider последнего слота. */ + unsigned found_mode, local; uint16_t words[PCAN_GAS_SLOT_WORDS]; pcan_gas_slot_frame_t out; int result; /* Буферы ограничены одним classic CAN кадром. */ + if (request == NULL || mode >= PCAN_GAS_SLOT_MODE_COUNT || pcan_gas_slot_decode(request->id, request->flags, request->data, request->dlc, &found_mode, &local, words) < 0 || found_mode != mode) return -1; /* Проверяем страницу PERIPH и маску до возможной записи. */ + if (request->dlc == 0U && response == NULL) return -1; /* Не вызываем read-provider, если вызывающая сторона не предоставила место для ответа. */ + result = pcan_gas_slot_handle_address(1U + mode / 16U, mode % 16U, port, request, &out); /* Используем общий обработчик типа 0x4 без второго алгоритма записи. */ + if (result == 1) { /* Дополнительно проверяем маску чтения с учётом неполного последнего слота PERIPH. */ + if (pcan_gas_slot_decode(out.id, out.flags, out.data, out.dlc, &found_mode, &local, words) < 0) return -1; /* Нельзя опубликовать фиктивный 201-й регистр или чужую страницу из ошибочного provider. */ + *response = out; /* Передаём вызывающей стороне только ответ, прошедший обе проверки. */ + } /* Запись возвращает ноль и не изменяет выходной кадр. */ + return result; /* Отрицательный результат означает отказ без автоматического перехода в регистровый GAS. */ +} /* Конец PERIPH-обёртки. */ diff --git a/c/set-protocol/src/pcan_id.c b/c/set-protocol/src/pcan_id.c index 82dbcbb..9f2ae4e 100644 --- a/c/set-protocol/src/pcan_id.c +++ b/c/set-protocol/src/pcan_id.c @@ -19,9 +19,9 @@ void pcan_id_unpack(uint32_t raw, pcan_id_t *id) { raw &= PCAN_ID_MASK; id->msg_body = (uint16_t)(raw & 0xFFFFU); - id->msg_type = (uint8_t)((raw >> 16) & 0xFU); - id->device_id = (uint8_t)((raw >> 20) & 0xFU); - id->device_type = (uint8_t)((raw >> 24) & 0x7U); - id->route = (uint8_t)((raw >> 27) & 0x1U); - id->priority = (uint8_t)((raw >> 28) & 0x1U); + id->msg_type = (uint_least8_t)((raw >> 16) & 0xFU); /* Сужает извлечённое поле к переносимому типу октета, включая C28x с 16-битным char. */ + id->device_id = (uint_least8_t)((raw >> 20) & 0xFU); /* Сужает извлечённое поле к переносимому типу октета, включая C28x с 16-битным char. */ + id->device_type = (uint_least8_t)((raw >> 24) & 0x7U); /* Сужает извлечённое поле к переносимому типу октета, включая C28x с 16-битным char. */ + id->route = (uint_least8_t)((raw >> 27) & 0x1U); /* Сужает извлечённое поле к переносимому типу октета, включая C28x с 16-битным char. */ + id->priority = (uint_least8_t)((raw >> 28) & 0x1U); /* Сужает извлечённое поле к переносимому типу октета, включая C28x с 16-битным char. */ } diff --git a/c/set-protocol/src/pcan_modbus_server.c b/c/set-protocol/src/pcan_modbus_server.c index 46081f6..f0107df 100644 --- a/c/set-protocol/src/pcan_modbus_server.c +++ b/c/set-protocol/src/pcan_modbus_server.c @@ -12,8 +12,8 @@ static bool is_bank(uint8_t value) { - return (value >= (uint8_t)PCAN_MODBUS_COIL) && - (value <= (uint8_t)PCAN_MODBUS_INPUT); + return (value >= (uint8_t)PCAN_MODBUS_DISCRETE) && /* Диапазон Modbus начинается с 0x5: тип 0x4 занят слотным GAS и не должен вызывать Modbus callbacks. */ + (value <= (uint8_t)PCAN_MODBUS_INPUT); /* Сохраняем существующие номера HOLDING=0x6 и INPUT=0x7 без сдвига адресации. */ } bool pcan_modbus_server_init(pcan_modbus_server_t *server, @@ -78,7 +78,7 @@ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, if (request->dlc == 0U) { uint16_t packed = 0U; - if ((bank == PCAN_MODBUS_COIL) || (bank == PCAN_MODBUS_DISCRETE)) { + if (bank == PCAN_MODBUS_DISCRETE) { /* Только тип 0x5 передаёт битовые входы; 0x4 обрабатывается отдельным GAS-кодеком. */ if (count > 16U) { return reject(server); } @@ -115,21 +115,7 @@ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, (server->write == NULL)) { return reject(server); } - if (bank == PCAN_MODBUS_COIL) { - uint16_t bits; - if ((count > 16U) || (request->dlc != 2U)) { - return reject(server); - } - bits = (uint16_t)((uint16_t)request->data[0] | - ((uint16_t)request->data[1] << 8U)); - for (uint8_t index = 0U; index < count; ++index) { - if (!server->write(server->user, bank, - (uint16_t)(address + index), - (uint16_t)((bits >> index) & 1U))) { - return reject(server); - } - } - } else { + { /* После проверки readonly-банков запись возможна только в HOLDING; битовая запись бывшего 0x4 удалена. */ if ((count > 4U) || (request->dlc != (uint8_t)(count * 2U))) { return reject(server); } diff --git a/c/set-protocol/src/set_gas_watch.c b/c/set-protocol/src/set_gas_watch.c new file mode 100644 index 0000000..c2d9692 --- /dev/null +++ b/c/set-protocol/src/set_gas_watch.c @@ -0,0 +1,155 @@ +/* GAS_WATCH2 отделяет настройку списка, согласованный захват RAM и сериализацию готовой выборки. */ +#include "set_gas_watch.h" /* Подключает общий контракт списка, состояния, выборки и стабильного ABI. */ +#include "set_protocol.h" /* Повторно использует единые endian-преобразования SETProtocol вместо отдельного кодека чисел. */ +#include /* Даёт обнуление собственных структур и сравнение канонического подтверждения. */ + +static bool config_valid(uint32_t id, uint16_t period, const uint16_t *addresses, size_t count) /* Проверяет модель до чтения адресов или записи в буфер. */ +{ /* Открывает проверку общих ограничений конфигурации. */ + if (id == 0U || count > SET_GAS_WATCH_MAX || (count > 0U && addresses == NULL) || ((period == 0U) != (count == 0U))) return false; /* Требует ненулевое поколение и однозначную команду stop. */ + for (size_t i = 0U; i < count; ++i) { /* Проверяет каждый адрес только внутри переданной длины списка. */ + for (size_t j = 0U; j < i; ++j) { /* Сравнивает адрес с уже проверенными позициями, сохраняя исходный порядок. */ + if (addresses[i] == addresses[j]) return false; /* Дубли требуют устранения у потребителя, иначе индексный контракт неоднозначен. */ + } /* Завершает проверку совпадений текущего адреса. */ + } /* Завершает проверку всех адресов без выделения памяти. */ + return true; /* Разрешает обработку полностью проверенной модели. */ +} /* Завершает общую проверку ограничений конфигурации. */ + +static bool config_decode(const uint8_t *payload, size_t size, set_gas_watch_t *out) /* Разбирает заявку во временное состояние, не затрагивая действующее. */ +{ /* Открывает проверку бинарного описания списка. */ + if (payload == NULL || size < SET_GAS_WATCH_CONFIG_HEADER || size > SET_GAS_WATCH_CONFIG_MAX) return false; /* Проверяет границы до чтения полей заголовка. */ + if (setp_get_u16(payload) != SET_GAS_WATCH_VERSION || setp_get_u16(payload + 10U) != 0U) return false; /* Версия 2 и нулевой резерв определены контрактом GAS_WATCH2. */ + memset(out, 0, sizeof(*out)); /* Инициализирует также счётчик выборок, расписание и неиспользуемые адреса. */ + out->period_ms = setp_get_u16(payload + 2U); /* Читает период в миллисекундах после двухбайтовой версии. */ + out->config_id = setp_get_u32(payload + 4U); /* Читает 32-битное поколение из байтов 4..7. */ + out->count = setp_get_u16(payload + 8U); /* Читает число 16-битных GAS-слов перед резервом заголовка. */ + if (out->count > SET_GAS_WATCH_MAX || size != SET_GAS_WATCH_CONFIG_HEADER + 2U * (size_t)out->count) return false; /* Запрещает усечённые и дополненные пакеты до обхода адресов. */ + for (size_t i = 0U; i < out->count; ++i) out->address[i] = setp_get_u16(payload + SET_GAS_WATCH_CONFIG_HEADER + 2U * i); /* Декодирует адреса в неизменном порядке, два байта на слово. */ + return config_valid(out->config_id, out->period_ms, out->address, out->count); /* Применяет одинаковые правила к входящему и исходящему спискам. */ +} /* Завершает разбор временной конфигурации. */ + +static bool active(const set_gas_watch_t *watch) /* Ограничивает обращения к массиву рамками настроенной активной подписки. */ +{ /* Открывает проверку минимальных инвариантов состояния. */ + return watch != NULL && watch->config_id != 0U && watch->period_ms != 0U && watch->count > 0U && watch->count <= SET_GAS_WATCH_MAX; /* Остановленная или неинициализированная подписка не выдаёт выборки. */ +} /* Завершает проверку активности. */ + +void set_gas_watch_init(set_gas_watch_t *watch) /* Подготавливает независимый экземпляр для одного управляющего клиента. */ +{ /* Открывает безопасную инициализацию состояния. */ + if (watch != NULL) memset(watch, 0, sizeof(*watch)); /* Нулевое поколение обозначает отсутствие применённой конфигурации. */ +} /* Завершает инициализацию экземпляра. */ + +size_t set_gas_watch_request(uint32_t config_id, uint16_t period_ms, const uint16_t *addresses, size_t count, uint8_t *out, size_t capacity) /* Собирает единственный канонический формат команды и её полного эхо-ответа. */ +{ /* Открывает создание payload конфигурации. */ + if (!config_valid(config_id, period_ms, addresses, count) || out == NULL || capacity < SET_GAS_WATCH_CONFIG_HEADER + 2U * count) return 0U; /* Проверяет всё до первой записи, включая дубли и размер буфера в байтах. */ + setp_put_u16(out, SET_GAS_WATCH_VERSION); /* Записывает версию payload 2 независимо от внешнего транспорта. */ + setp_put_u16(out + 2U, period_ms); /* Кодирует период в миллисекундах в байты 2..3. */ + setp_put_u32(out + 4U, config_id); /* Кодирует ненулевое поколение в байты 4..7. */ + setp_put_u16(out + 8U, (uint16_t)count); /* Сохраняет проверенное число слов в двухбайтовом поле. */ + setp_put_u16(out + 10U, 0U); /* Резерв всегда нулевой, чтобы будущие расширения требовали явного согласования. */ + for (size_t i = 0U; i < count; ++i) setp_put_u16(out + SET_GAS_WATCH_CONFIG_HEADER + 2U * i, addresses[i]); /* Сериализует по два байта на адрес без перестановки списка. */ + return SET_GAS_WATCH_CONFIG_HEADER + 2U * count; /* Возвращает фактический размер payload, а не вместимость буфера. */ +} /* Завершает кодирование команды настройки. */ + +int set_gas_watch_apply(set_gas_watch_t *watch, const pcan_gas_map_t *map, const uint8_t *payload, size_t size) /* Транзакционно заменяет список после всех проверок; вызывающий удерживает общий lock. */ +{ /* Открывает применение новой конфигурации. */ + set_gas_watch_t proposed; /* Держит весь новый список отдельно от состояния, доступного сборщику. */ + if (watch == NULL || !config_decode(payload, size, &proposed)) return SET_GAS_WATCH_INVALID; /* Неверный пакет не меняет действующий список и расписание. */ + if (watch->config_id == proposed.config_id) { /* Обрабатывает повтор команды после потери подтверждения. */ + if (watch->count != proposed.count || watch->period_ms != proposed.period_ms) return SET_GAS_WATCH_CONFLICT; /* Запрещает изменение содержимого под тем же поколением. */ + for (size_t i = 0U; i < proposed.count; ++i) if (watch->address[i] != proposed.address[i]) return SET_GAS_WATCH_CONFLICT; /* Сравнивает также порядок адресов, определяющий смысл позиций. */ + return SET_GAS_WATCH_OK; /* Точный повтор не сбрасывает sequence и срок следующей выборки. */ + } /* Завершает идемпотентный путь повторного запроса. */ + if (watch->config_id != 0U && (uint32_t)(proposed.config_id - watch->config_id) >= 0x80000000UL) return SET_GAS_WATCH_CONFLICT; /* Отклоняет старые поколения по модульному порядку с полуинтервалом 2^31. */ + if (proposed.count > 0U) { /* Команда остановки не зависит от наличия карты или исправности источников. */ + if (!pcan_gas_map_validate(map)) return SET_GAS_WATCH_INVALID; /* Не допускает двоичный поиск по несортированной, перекрытой или повреждённой карте. */ + for (size_t i = 0U; i < proposed.count; ++i) { /* Проверяет доступность каждого выбранного слова до замены состояния. */ + const pcan_gas_region_t *region = pcan_gas_find(map, proposed.address[i]); /* Находит описание региона, не вызывая callback источника. */ + if (region == NULL) return SET_GAS_WATCH_NO_REG; /* Один неизвестный адрес отменяет всю перенастройку без частичной подписки. */ + if ((region->flags & PCAN_GAS_WRONLY) != 0U || (region->read == NULL && region->storage == NULL)) return SET_GAS_WATCH_ACCESS; /* Требует разрешённое чтение и реальный обработчик либо RAM. */ + } /* Завершает проверку полного набора выбранных адресов. */ + } /* Завершает проверку карты для непустой подписки. */ + *watch = proposed; /* Фиксирует целую проверенную конфигурацию; от конкурентного доступа защищает lock приложения. */ + return SET_GAS_WATCH_OK; /* Разрешает отправить полное подтверждение применённого списка. */ +} /* Завершает транзакцию настройки. */ + +size_t set_gas_watch_encode_ack(const set_gas_watch_t *watch, uint8_t *out, size_t capacity) /* Строит эхо из фактически применённого списка, а не из неподтверждённого запроса. */ +{ /* Открывает кодирование подтверждения. */ + if (watch == NULL) return 0U; /* Не читает поля отсутствующего экземпляра. */ + return set_gas_watch_request(watch->config_id, watch->period_ms, watch->address, watch->count, out, capacity); /* Делегирует формат единственному кодировщику конфигурации. */ +} /* Завершает кодирование подтверждения без отдельного wire-формата. */ + +int set_gas_watch_ack(const uint8_t *payload, size_t size, uint32_t config_id, uint16_t period_ms, const uint16_t *addresses, size_t count) /* Проверяет весь список, а не только количество принятых слов. */ +{ /* Открывает host-проверку подтверждения настройки. */ + uint8_t expected[SET_GAS_WATCH_CONFIG_MAX]; /* Ограниченный стековый буфер содержит каноническое представление ожидаемой команды. */ + size_t expected_size = set_gas_watch_request(config_id, period_ms, addresses, count, expected, sizeof(expected)); /* Строит ожидаемый пакет тем же C-кодировщиком. */ + return payload != NULL && expected_size != 0U && size == expected_size && memcmp(payload, expected, size) == 0; /* Принимает только побайтовое совпадение версии, поколения, периода и всех адресов. */ +} /* Завершает точную проверку эхо-ответа. */ + +bool set_gas_watch_due(const set_gas_watch_t *watch, uint32_t now_ms) /* Проверяет расписание захвата относительно локального времени MCU. */ +{ /* Открывает неблокирующую проверку таймера. */ + return active(watch) && (watch->scheduled == 0U || (uint32_t)(now_ms - watch->next_ms) < 0x80000000UL); /* Первая выборка немедленная; полуинтервал 2^31 корректно обрабатывает переполнение u32. */ +} /* Завершает проверку срока без изменения состояния. */ + +bool set_gas_watch_capture(set_gas_watch_t *watch, const pcan_gas_map_t *map, uint32_t now_ms, set_gas_watch_sample_t *sample) /* Снимает согласованный кэш в памяти под lock, предоставленным приложением. */ +{ /* Открывает захват одной самостоятельной выборки. */ + set_gas_watch_sample_t captured; /* Временная выборка не позволяет частично изменить выход при неверных аргументах. */ + if (!active(watch) || sample == NULL || !pcan_gas_map_validate(map)) return false; /* Отклоняет остановленный поток, отсутствующий выход и повреждённую карту. */ + memset(&captured, 0, sizeof(captured)); /* Ошибочные и неиспользуемые позиции заранее получают нулевые значения и признаки. */ + captured.config_id = watch->config_id; /* Закрепляет поколение списка вместе с набором значений. */ + captured.sequence = watch->sequence; /* Первая выборка имеет номер 0; номер увеличивается после успешного захвата структуры. */ + captured.timestamp_ms = now_ms; /* Фиксирует переданное время начала выборки, не время отправки пакета. */ + captured.count = watch->count; /* Закрепляет число позиций независимо от последующей перенастройки. */ + for (size_t i = 0U; i < watch->count; ++i) { /* Читает разрозненные GAS-адреса в согласованном порядке списка. */ + uint16_t value = 0U; /* Не позволяет неуспешному callback протащить мусор или частичное значение. */ + if (pcan_gas_read(map, watch->address[i], &value) == PCAN_GAS_OK) { /* Достоверность означает успешное чтение локального источника, не свежесть удалённого измерения. */ + captured.values[i] = value; /* Копирует прочитанное слово только после подтверждения источником. */ + captured.valid[i] = 1U; /* Отмечает в модели, что слово пригодно для графика и архива. */ + } /* При ошибке источник оставляет и значение, и признак нулевыми. */ + } /* Завершает чтение всех каналов даже при отказе одного из них. */ + *sample = captured; /* Передаёт неизменяемый по отношению к карте снимок приложениям-потребителям. */ + watch->sequence++; /* Учитывает каждый захват, в том числе потерянный позднее из-за занятой линии. */ + watch->next_ms = now_ms + watch->period_ms; /* Планирует следующий захват от текущего времени без пачки догоняющих выборок. */ + watch->scheduled = 1U; /* Включает проверку next_ms после первой выборки. */ + return true; /* Готовая выборка доступна независимо от ошибок отдельных регистров. */ +} /* Завершает захват; транспорт вызывается приложением после снятия lock. */ + +size_t set_gas_watch_encode_sample(const set_gas_watch_sample_t *sample, uint8_t *out, size_t capacity) /* Упаковывает сохранённую выборку без повторных обращений к источникам. */ +{ /* Открывает сериализацию пакета значений. */ + if (sample == NULL || out == NULL || sample->config_id == 0U || sample->count == 0U || sample->count > SET_GAS_WATCH_MAX) return 0U; /* Проверяет модель до вычисления размера и обращения к массивам. */ + size_t mask_size = ((size_t)sample->count + 7U) / 8U; /* Округляет число флагов до байтов, восемь каналов на один байт маски. */ + size_t values_offset = SET_GAS_WATCH_SAMPLE_HEADER + mask_size; /* Значения идут сразу после переменной по длине маски достоверности. */ + size_t total = values_offset + 2U * sample->count; /* Каждое значение занимает два байта без зависимости от выравнивания структур. */ + if (capacity < total) return 0U; /* Недостаточный выходной буфер остаётся полностью неизменным. */ + for (size_t i = 0U; i < sample->count; ++i) if (sample->valid[i] > 1U) return 0U; /* Запрещает неканонические признаки до записи заголовка. */ + setp_put_u16(out, SET_GAS_WATCH_VERSION); /* Сохраняет версию payload 2 в первых двух байтах. */ + setp_put_u16(out + 2U, sample->count); /* Помещает число слов перед поколением конфигурации. */ + setp_put_u32(out + 4U, sample->config_id); /* Позволяет клиенту отклонить пакет предыдущего списка той же длины. */ + setp_put_u32(out + 8U, sample->sequence); /* Номер захвата занимает байты 8..11 и передаётся без знакового преобразования. */ + setp_put_u32(out + 12U, sample->timestamp_ms); /* Время устройства в миллисекундах занимает байты 12..15. */ + memset(out + SET_GAS_WATCH_SAMPLE_HEADER, 0, mask_size); /* Обнуляет также свободные старшие биты последнего байта маски. */ + for (size_t i = 0U; i < sample->count; ++i) { /* Заполняет значения и соответствующие им биты одной позиции списка. */ + if (sample->valid[i] != 0U) out[SET_GAS_WATCH_SAMPLE_HEADER + i / 8U] |= (uint8_t)(1U << (i % 8U)); /* Младший бит байта соответствует первому из восьми каналов. */ + setp_put_u16(out + values_offset + 2U * i, sample->valid[i] != 0U ? sample->values[i] : 0U); /* Недостоверный канал всегда кодируется нулём независимо от содержимого модели. */ + } /* Завершает построение канонического payload выборки. */ + return total; /* Возвращает число готовых к передаче байтов без внешнего кадрирования. */ +} /* Завершает сериализацию самостоятельной выборки. */ + +int set_gas_watch_decode(const uint8_t *payload, size_t size, uint32_t expected_config_id, size_t expected_count, uint32_t *sequence, uint32_t *timestamp_ms, uint16_t *values, uint8_t *valid, size_t capacity) /* Проверяет полный пакет прежде, чем открыть его данным графика или архива. */ +{ /* Открывает стабильный host-декодер payload выборки. */ + if (payload == NULL || size < SET_GAS_WATCH_SAMPLE_HEADER || size > SET_GAS_WATCH_SAMPLE_MAX || expected_config_id == 0U || expected_count == 0U || expected_count > SET_GAS_WATCH_MAX) return -1; /* Исключает неверные границы и отсутствие активной конфигурации до чтения payload. */ + size_t count = setp_get_u16(payload + 2U); /* Читает число слов из проверенного фиксированного заголовка. */ + if (setp_get_u16(payload) != SET_GAS_WATCH_VERSION || setp_get_u32(payload + 4U) != expected_config_id || count != expected_count || count > capacity || values == NULL || valid == NULL) return -1; /* Отбрасывает устаревшую конфигурацию и неподходящие выходные массивы. */ + size_t mask_size = (count + 7U) / 8U; /* Вычисляет единственный допустимый размер маски для ожидаемого числа слов. */ + size_t values_offset = SET_GAS_WATCH_SAMPLE_HEADER + mask_size; /* Находит начало значений после bitmap в байтах. */ + if (size != values_offset + 2U * count) return -1; /* Не принимает ни усечённый пакет, ни добавленные после значений байты. */ + if (count % 8U != 0U && (payload[values_offset - 1U] >> (count % 8U)) != 0U) return -1; /* Требует нулевые неиспользуемые старшие биты маски последнего байта. */ + for (size_t i = 0U; i < count; ++i) { /* Сначала проверяет каноничность всех каналов, ничего не публикуя вызывающему. */ + if ((payload[SET_GAS_WATCH_SAMPLE_HEADER + i / 8U] & (1U << (i % 8U))) == 0U && setp_get_u16(payload + values_offset + 2U * i) != 0U) return -1; /* Ошибочный канал обязан содержать нулевое слово, иначе пакет отвергается целиком. */ + } /* Завершает полную проверку до первой записи в выходные аргументы. */ + for (size_t i = 0U; i < count; ++i) { /* Публикует проверенные значения и их достоверность в одинаковом порядке. */ + values[i] = setp_get_u16(payload + values_offset + 2U * i); /* Копирует сырое 16-битное слово без изменения знаковости. */ + valid[i] = (uint8_t)((payload[SET_GAS_WATCH_SAMPLE_HEADER + i / 8U] >> (i % 8U)) & 1U); /* Раскрывает один бит в 0 или 1 для простого ctypes/JNI ABI. */ + } /* Завершает публикацию массивов после успешной проверки пакета. */ + if (sequence != NULL) *sequence = setp_get_u32(payload + 8U); /* Возвращает номер захвата, если клиент запросил метаданные. */ + if (timestamp_ms != NULL) *timestamp_ms = setp_get_u32(payload + 12U); /* Возвращает приборное время без привязки к часам компьютера. */ + return (int)count; /* Положительный результат сообщает точное число достоверно разобранных позиций, включая помеченные ошибкой. */ +} /* Завершает единый C-декодер для всех языковых портов. */ diff --git a/c/set-protocol/tests/fixtures/gas-watch-v2.json b/c/set-protocol/tests/fixtures/gas-watch-v2.json new file mode 100644 index 0000000..014e37f --- /dev/null +++ b/c/set-protocol/tests/fixtures/gas-watch-v2.json @@ -0,0 +1,13 @@ +{ + "description": "Общие эталонные байты GAS_WATCH2 для C, Python и JVM; порядок адресов сохраняет позиции значений.", + "version": 2, + "config_id": 305419896, + "period_ms": 100, + "addresses": [0, 1, 65281], + "request_hex": "0200640078563412030000000000010001ff", + "sequence": 4294967295, + "timestamp_ms": 4294967280, + "values": [123, 65534, 0], + "valid": [1, 1, 0], + "sample_hex": "0200030078563412fffffffff0ffffff037b00feff0000" +} diff --git a/c/set-protocol/tests/test_gas_register.c b/c/set-protocol/tests/test_gas_register.c new file mode 100644 index 0000000..c81fa6f --- /dev/null +++ b/c/set-protocol/tests/test_gas_register.c @@ -0,0 +1,29 @@ +#include "pcan_gas.h" /* Проверяем фактическую карту отдельных регистров GAS типа 0x3. */ +#include "pcan_id.h" /* Собираем адресуемые запросы общим кодеком идентификатора. */ +#include /* Release-сборка сохраняет проверки и сообщения ошибок. */ +#define CHECK(x) do { if (!(x)) { printf("gas_register:%d: %s\n", __LINE__, #x); return 1; } } while (0) /* Любое нарушение возвращает ненулевой код теста. */ +int main(void) /* Проверяем точечную запись, все допустимые длины и границу полного пространства. */ +{ /* Массивы карты принадлежат тестовому приложению и не требуют выделения всей памяти 0…FFFF. */ + uint16_t low[8] = {100U, 200U, 300U, 400U, 500U, 600U, 700U, 800U}, high[2] = {11U, 22U}; /* Отличающиеся соседние слова обнаруживают лишнюю запись или переход через FFFF. */ + pcan_gas_region_t regions[] = {{0U, 8U, low, NULL, NULL, 0U, NULL, NULL}, {0xFFFEU, 2U, high, NULL, NULL, 0U, NULL, NULL}}; /* Два небольших региона покрывают начало и конец 16-битного пространства. */ + pcan_gas_map_t map = {regions, 2U}; pcan_frame_t request = {0}, response; pcan_id_t id = {1U, PCAN_MSG_GAS, 5U, 1U, PCAN_ROUTE_FROM_PM, PCAN_PRIORITY_STANDARD}; unsigned count, i; /* Запрос адресует второе слово без слота или дополнительного индекса. */ + CHECK(pcan_gas_map_validate(&map)); request.id = pcan_id_pack(&id); request.flags = PCAN_FLAG_IDE; /* Проверяем карту и формируем обычный extended data frame. */ + request.dlc = 2U; request.data[0] = 0x34U; request.data[1] = 0x12U; CHECK(!pcan_gas_handle(&map, &request, &response)); /* Два октета записывают ровно один регистр и не порождают несуществующий ACK. */ + CHECK(low[0] == 100U && low[1] == 0x1234U && low[2] == 300U && low[3] == 400U); /* Соседние уставки остаются прежними без предварительного чтения на клиенте. */ + for (count = 1U; count <= 4U; ++count) { /* Все четыре допустимые длины должны изменять только заданный последовательный диапазон. */ + for (i = 0U; i < 8U; ++i) low[i] = (uint16_t)(100U + i); /* Возвращаем различимые исходные значения перед каждой длиной записи. */ + for (i = 0U; i < count; ++i) { request.data[2U * i] = (uint8_t)(10U + i); request.data[2U * i + 1U] = 0U; } /* Значения 10…13 не совпадают с фоновыми данными карты. */ + request.dlc = (uint8_t)(count * 2U); CHECK(!pcan_gas_handle(&map, &request, &response)); /* DLC определяет один, два, три или четыре слова начиная с MsgBody. */ + for (i = 0U; i < 8U; ++i) CHECK(low[i] == ((i >= 1U && i <= count) ? 9U + i : 100U + i)); /* Любая запись вне выбранного диапазона является ошибкой. */ + } /* Завершаем проверку допустимых коротких и полных payload. */ + for (i = 1U; i <= 9U; i += 2U) { request.dlc = (uint8_t)i; CHECK(!pcan_gas_handle(&map, &request, &response)); CHECK(low[1] == 10U); } /* Нечётный или превышающий восемь октетов payload не записывает даже первый полный регистр. */ + request.dlc = 2U; id.msg_type = PCAN_MSG_GAS_SLOT; request.id = pcan_id_pack(&id); CHECK(!pcan_gas_handle(&map, &request, &response)); CHECK(low[1] == 10U); /* Тип 0x4 изолирован от адресации отдельных регистров. */ + id.msg_type = PCAN_MSG_GAS; id.route = PCAN_ROUTE_FROM_DEVICE; request.id = pcan_id_pack(&id); CHECK(!pcan_gas_handle(&map, &request, &response)); CHECK(low[1] == 10U); /* Ответ прибора не исполняется повторно как запись. */ + id.route = PCAN_ROUTE_FROM_PM; id.msg_body = 0xFFFFU; request.id = pcan_id_pack(&id); request.data[0] = 0x78U; request.data[1] = 0x56U; /* Выбираем максимальный адрес без потери старших битов. */ + CHECK(!pcan_gas_handle(&map, &request, &response)); CHECK(high[0] == 11U && high[1] == 0x5678U); /* Одно слово по адресу FFFF допустимо и не меняет предыдущий регистр. */ + request.dlc = 4U; request.data[0] = 1U; CHECK(!pcan_gas_handle(&map, &request, &response)); CHECK(high[1] == 0x5678U && low[0] == 100U); /* Блок через верхнюю границу отвергается целиком, не оборачиваясь к адресу ноль. */ + request.dlc = 0U; CHECK(pcan_gas_handle(&map, &request, &response)); CHECK(response.dlc == 2U && response.data[0] == 0x78U && response.data[1] == 0x56U); /* Чтение максимального адреса возвращает одно существующее слово. */ + request.dlc = 2U; for (i = 0U; i <= 8U; i += 2U) { request.flags = (uint8_t)(PCAN_FLAG_IDE | i); if (i == 0U || i == 4U || i == 6U) continue; CHECK(!pcan_gas_handle(&map, &request, &response)); CHECK(high[1] == 0x5678U); } /* RTR и ERR не вызывают запись карты. */ + request.flags = 0U; CHECK(!pcan_gas_handle(&map, &request, &response)); CHECK(!pcan_gas_handle(&map, NULL, &response)); /* Стандартный ID и отсутствующий запрос безопасно отвергаются. */ + puts("GAS register addressing: OK"); return 0; /* Подтверждаем успешную проверку всех контрактов отдельного регистра. */ +} /* Конец теста безслотового GAS. */ diff --git a/c/set-protocol/tests/test_gas_slot.c b/c/set-protocol/tests/test_gas_slot.c new file mode 100644 index 0000000..819d9b9 --- /dev/null +++ b/c/set-protocol/tests/test_gas_slot.c @@ -0,0 +1,61 @@ +#include "pcan_gas_slot.h" /* Проверяем реальный публичный кодек и MCU-обработчик слотного GAS. */ +#include "pcan_id.h" /* Независимо проверяем разделение типов 0x3 и 0x4. */ +#include /* Диагностика CHECK работает также в release-сборке без assert. */ +#include /* Сравниваем точные октеты и сохранность невыбранных значений. */ +#define CHECK(x) do { if (!(x)) { printf("gas_slot:%d: %s\n", __LINE__, #x); return 1; } } while (0) /* Ненулевой код делает любое нарушение видимым сборщику тестов. */ +static unsigned reads, writes; /* Счётчики обнаруживают вызов provider для отвергнутого кадра. */ +static uint16_t state[3] = {0x1234U, 0xABCDU, 0xFFFFU}; /* Три независимых значения позволяют проверить, что частичная запись сохраняет соседей. */ +static int read_slot(void *context, uint16_t address, uint16_t words[4]) /* Provider реализует данные, не повторяя формат CAN ID или endian. */ +{ /* Чтение возвращает Word0 с маской достоверности и три фиксированные позиции. */ + unsigned i; (void)context; ++reads; if (address != 0x0500U && address != 0xFFFFU && address != 0x0542U) return 1; /* Только три адреса существуют в тестовом источнике. */ + words[0] = address == 0x0542U ? 0x0006U : PCAN_GAS_SLOT_MASK; /* Последний слот PERIPH содержит два действующих значения, общий адрес FFFF содержит три. */ + for (i = 0U; i < 3U; ++i) words[i + 1U] = state[i]; /* Служебная маска не подменяет первое хранимое значение. */ + return 0; /* Успех сообщается после заполнения всех wire-позиций. */ +} /* Конец источника чтения. */ +static int write_slot(void *context, uint16_t address, const uint16_t words[4]) /* Проверяем рекомендуемый контракт provider с общей предварительной валидацией. */ +{ /* В реальном устройстве обе фазы выполняются под одной блокировкой данных приложения. */ + unsigned i; (void)context; if (address != 0x0500U && address != 0xFFFFU) return 1; /* Несуществующий адрес не изменяет состояние. */ + for (i = 1U; i < 4U; ++i) if ((words[0] & (1U << i)) != 0U && words[i] == 0xDEADU) return 1; /* Отвергаем весь набор до первого изменения выбранных слов. */ + for (i = 1U; i < 4U; ++i) if ((words[0] & (1U << i)) != 0U) state[i - 1U] = words[i]; /* Меняем только отмеченные позиции; остальные остаются текущими значениями устройства. */ + ++writes; return 0; /* Считаем только полностью проверенную и применённую команду. */ +} /* Конец тестового provider записи. */ +int main(void) /* Охватываем wire-контракт, изоляцию типов, масочную запись и все границы адресации. */ +{ /* Все буферы ограничены размером одного classic CAN кадра. */ + unsigned mode, local, i, mask; uint16_t native, words[4] = {0x000EU, 0x1234U, 0xABCDU, 0xFFFFU}, decoded[4]; /* Маска занимает нулевое слово, а не младшие биты адреса. */ + uint_least8_t data[8], expected[8] = {0x0E, 0, 0x34, 0x12, 0xCD, 0xAB, 0xFF, 0xFF}; /* Независимый эталон показывает порядок маски и трёх значений. */ + pcan_gas_slot_port_t port = {NULL, read_slot, write_slot}; pcan_gas_slot_frame_t request = {0}, response; /* Используем тот же входной API, который вызывает прошивка устройства. */ + CHECK(pcan_gas_slot_request_id(5, 0, 0) == 0x11540500UL); CHECK(pcan_gas_slot_request_id(6, 0, 0) == 0x11640600UL); /* В ID заменён только MsgType, адреса узлов PERIPH сохранены. */ + CHECK(pcan_gas_slot_request_id(7, 0, 0) == 0x11740700UL); CHECK(pcan_gas_slot_request_id(8, 0, 0) == 0x11840800UL); /* Проверяем ранее опубликованные адреса соседних mode. */ + CHECK(pcan_gas_slot_request_id(16, 0, 0) == 0x12041000UL); CHECK(pcan_gas_slot_request_id(31, 66, 0) == 0x12F41F42UL); /* Проверяем смену DeviceType и неполный последний слот страницы. */ + CHECK(pcan_gas_slot_address(32, 0) == -1); CHECK(pcan_gas_slot_address(5, 67) == -1); CHECK(pcan_gas_slot_request_id(5, 0, 2) == 0U); /* Резерв, чужой mode и неверный Route не маскируются. */ + CHECK(pcan_gas_slot_encode(words, 4, data) == 8); CHECK(memcmp(data, expected, sizeof(data)) == 0); /* Сопоставляем все восемь wire-октетов, включая маску. */ + CHECK(pcan_gas_slot_decode(0x19540500UL, 1, data, 8, &mode, &local, decoded) == 4); CHECK(mode == 5 && local == 0 && memcmp(words, decoded, sizeof(words)) == 0); /* Обратное преобразование сохраняет маску и значения. */ + CHECK(pcan_gas_slot_encode(words, 3, data) == -1); CHECK(pcan_gas_slot_encode(NULL, 0, NULL) == 0); /* Частичная запись имеет полный payload с маской; чтение остаётся пустым. */ + for (i = 1U; i < 8U; ++i) CHECK(pcan_gas_slot_decode_words(0x11540500UL, 1, data, i, decoded) == -1); /* Ни одна усечённая длина не обращается к provider. */ + for (i = 0U; i < 4U; ++i) { /* Проверяем пустую маску, бит нулевого слова и зарезервированные старшие биты. */ + uint16_t invalid[] = {0U, 1U, 0x10U, 0xFFFFU}; words[0] = invalid[i]; CHECK(pcan_gas_slot_encode(words, 4, data) == -1); /* Недопустимый набор отвергается до изменения выходного буфера. */ + } /* Завершаем проверку каноничности Word0. */ + words[0] = PCAN_GAS_SLOT_MASK; CHECK(pcan_gas_slot_encode(words, 4, data) == 8); /* Восстанавливаем корректный полный набор для последующих проверок. */ + CHECK(pcan_gas_slot_decode_words(0x19530500UL, 1, data, 8, decoded) == -1); /* Тип 0x3 никогда не трактуется как слотный даже при подходящих первых байтах. */ + CHECK(pcan_gas_slot_decode(0x19540600UL, 1, data, 8, &mode, &local, decoded) == -1); /* Устройство mode 5 не обслуживает страницу mode 6. */ + CHECK(pcan_gas_slot_decode(0x19540542UL, 1, data, 8, &mode, &local, decoded) == -1); /* Третье значение последнего слота не существует и не принимается через маску. */ + words[0] = 0x0006U; CHECK(pcan_gas_slot_encode(words, 4, data) == 8); CHECK(pcan_gas_slot_decode(0x19540542UL, 1, data, 8, &mode, &local, decoded) == 4); /* Два действующих значения последнего слота сохраняют допустимость. */ + request.id = 0x11540500UL; request.flags = PCAN_GAS_SLOT_FLAG_IDE; CHECK(pcan_gas_slot_handle(5, &port, &request, &response) == 1); /* Чтение не содержит фиктивной маски в запросе. */ + CHECK(response.id == 0x19540500UL && response.dlc == 8U && reads == 1U); CHECK(memcmp(response.data, expected, sizeof(expected)) == 0); /* Ответ содержит маску достоверности и исходные три значения. */ + for (mask = 2U; mask <= PCAN_GAS_SLOT_MASK; mask += 2U) { /* Все семь непустых комбинаций трёх битов должны сохранять невыбранные позиции. */ + unsigned before = writes; state[0] = 10U; state[1] = 20U; state[2] = 30U; words[0] = (uint16_t)mask; words[1] = 101U; words[2] = 202U; words[3] = 303U; /* Отличающиеся старые и новые значения обнаруживают лишнюю запись соседей. */ + request.dlc = 8U; CHECK(pcan_gas_slot_encode(words, 4, request.data) == 8); CHECK(pcan_gas_slot_handle(5, &port, &request, &response) == 0); /* Одна команда вызывает provider один раз без предварительного чтения слота на хосте. */ + CHECK(writes == before + 1U); CHECK(state[0] == ((mask & 2U) ? 101U : 10U)); CHECK(state[1] == ((mask & 4U) ? 202U : 20U)); CHECK(state[2] == ((mask & 8U) ? 303U : 30U)); /* Проверяем каждую позицию отдельно для всех масок. */ + } /* Конец исчерпывающей проверки выбора трёх значений. */ + words[0] = 6U; words[1] = 7U; words[2] = 0xDEADU; CHECK(pcan_gas_slot_encode(words, 4, request.data) == 8); CHECK(pcan_gas_slot_handle(5, &port, &request, &response) == -1); CHECK(state[0] == 101U && state[1] == 202U); /* Отказ второго выбранного значения не должен менять первое. */ + request.flags = 3U; CHECK(pcan_gas_slot_handle(5, &port, &request, &response) == -1); request.flags = 0U; CHECK(pcan_gas_slot_handle(5, &port, &request, &response) == -1); /* RTR и стандартный ID отвергаются до записи. */ + request.flags = 1U; request.id = 0x19540500UL; CHECK(pcan_gas_slot_handle(5, &port, &request, &response) == -1); /* Ответ прибора не исполняется как команда мастера. */ + CHECK(pcan_gas_slot_id(7, 14, 65535U, 0) == 0x17E4FFFFUL); CHECK(pcan_gas_slot_id(7, 14, 65536UL, 0) == 0U); /* Общий слотный API сохраняет адрес FFFF и отвергает выход за 16 бит. */ + request.id = 0x17E4FFFFUL; request.dlc = 0U; CHECK(pcan_gas_slot_handle_address(7, 14, &port, &request, &response) == 1); CHECK(response.id == 0x1FE4FFFFUL); /* Отдельный инвертор не привязан к геометрии PERIPH. */ + CHECK(pcan_gas_slot_handle_address(7, 13, &port, &request, &response) == -1); /* Соседний узел не обслуживает чужой запрос. */ + CHECK(pcan_gas_slot_native(42, 2, 0, &native) == 1 && native == 127U); CHECK(pcan_gas_slot_native(42, 3, 0, &native) == 1 && native == 0x1000U); /* Граница технологических слов проходит внутри слота и не меняет native-адреса. */ + CHECK(pcan_gas_slot_native(48, 1, 0, &native) == 1 && native == 0x1200U); CHECK(pcan_gas_slot_native(52, 3, 1, &native) == 1 && native == 0x1302U); /* Паспорт и разрешённое поле защиты сохраняют исходное назначение. */ + CHECK(pcan_gas_slot_native(42, 3, 1, &native) == 0); CHECK(pcan_gas_slot_native(52, 1, 1, &native) == 0); CHECK(pcan_gas_slot_native(0, 0, 0, &native) == 0); /* Readonly-слова и служебная маска не записываются как технологические данные. */ + CHECK(pcan_gas_slot_native(56, 1, 0, &native) == 0); CHECK(pcan_gas_slot_native(66, 3, 0, &native) == 0); /* Резерв и лишняя 201-я позиция не становятся фиктивными регистрами. */ + puts("GAS SLOT masks: OK"); return 0; /* Успех означает прохождение всех позитивных, отрицательных и граничных случаев. */ +} /* Конец регрессионного теста масочного слота. */ diff --git a/c/set-protocol/tests/test_gas_watch.c b/c/set-protocol/tests/test_gas_watch.c new file mode 100644 index 0000000..ed2d8d2 --- /dev/null +++ b/c/set-protocol/tests/test_gas_watch.c @@ -0,0 +1,370 @@ +/* Контракт GAS_WATCH2: атомарная подписка, самостоятельный снимок и проверка входящих пакетов. */ +#include /* Целочисленные типы фиксируют размеры полей и переполнение счётчиков протокола. */ +#include /* Диагностика сообщает конкретное нарушенное условие и строку теста. */ +#include /* Побайтовые сравнения проверяют эталонный формат и отсутствие частичных изменений. */ +#include "set_gas_watch.h" /* Проверяем только публичный интерфейс общего ядра и его хостовые функции. */ + +static unsigned failures; /* Число нарушений накапливается, чтобы один запуск показал все независимые ошибки. */ +static void check(int condition, const char *expression, int line) /* Обёртка сохраняет проверки даже при определённом NDEBUG. */ +{ /* Начало общей диагностики проверяемого условия. */ + if (!condition) { /* Записываем только нарушения, чтобы успешный прогон оставался коротким. */ + printf("FAIL gas_watch:%d: %s\n", line, expression); /* Исходная строка позволяет быстро найти нарушенный контракт. */ + ++failures; /* Каждое отдельное нарушение делает итоговый код возврата ненулевым. */ + } /* Завершение обработки одного нарушения. */ +} /* Завершение функции диагностики. */ +#define CHECK(condition) check((condition), #condition, __LINE__) /* Макрос сохраняет выражение и его исходную строку без зависимости от assert. */ + +typedef struct { /* Состояние обработчика позволяет отличить проверку карты от реального чтения. */ + unsigned calls; /* Счётчик фиксирует любое обращение к провайдеру регистра. */ + uint16_t rejected_offset; /* Смещение 0xFFFF означает, что ни один из двух тестовых регистров не отвергается. */ + uint16_t base_value; /* Начальное значение добавляется к смещению, сохраняя различимость соседних каналов. */ +} read_context_t; /* Один экземпляр контекста обслуживает вычисляемый регион карты. */ + +static pcan_gas_status_t read_value(const pcan_gas_region_t *region, uint16_t offset, uint16_t *value) /* Подменяем приборный провайдер воспроизводимым обработчиком. */ +{ /* Начало имитации чтения одного 16-битного регистра. */ + read_context_t *context = (read_context_t *)region->user; /* Контекст берём из публичного пользовательского поля GAS-региона. */ + ++context->calls; /* Считаем в том числе неудачные чтения, чтобы проверить продолжение после ошибки. */ + *value = (uint16_t)(context->base_value + offset); /* Записываем ненулевой результат и при отказе: ядро обязано его обнулить. */ + return offset == context->rejected_offset ? PCAN_GAS_REJECTED : PCAN_GAS_OK; /* Выбранное смещение имитирует недостоверное значение устройства. */ +} /* Завершение подмены чтения. */ + +static pcan_gas_status_t write_value(const pcan_gas_region_t *region, uint16_t offset, uint16_t value) /* Провайдер записи создаёт корректный регион без возможности чтения. */ +{ /* Начало обработчика, используемого только для описания карты. */ + (void)region; /* Тесту достаточно наличия обработчика: состояние региона не изменяем. */ + (void)offset; /* Адрес записи не нужен, потому что операции записи здесь не выполняются. */ + (void)value; /* Значение записи не используется в проверках подписки только на чтение. */ + return PCAN_GAS_OK; /* Наличие рабочего обработчика записи делает регион допустимым для общей карты GAS. */ +} /* Завершение провайдера записи. */ + +static uint16_t storage[] = {123U, 65534U, 456U, 789U}; /* Значения включают отрицательное INT16 в исходном представлении 0xFFFE. */ +static read_context_t context; /* Общий контекст даёт доступ к счётчику обращений из разных сценариев. */ +static const pcan_gas_region_t regions[] = { /* Разрозненные адреса повторяют реальное сочетание памяти и вычисляемых регистров. */ + {0x0000U, 4U, storage, NULL, NULL, PCAN_GAS_RDONLY, NULL, "memory"}, /* Первые четыре адреса доступны напрямую, без обработчиков. */ + {0x0100U, 2U, NULL, read_value, NULL, PCAN_GAS_RDONLY, &context, "provider"}, /* Два вычисляемых канала позволяют отказать первому и успешно прочитать следующий. */ + {0x0200U, 1U, storage, NULL, NULL, PCAN_GAS_WRONLY, NULL, "write-only"}, /* Явный запрет чтения должен отвергаться до сбора выборки. */ + {0x0300U, 1U, NULL, NULL, write_value, 0U, NULL, "writer"}, /* Отсутствие провайдера чтения должно отвергаться и без флага WRONLY. */ + {0xFF01U, 1U, storage + 2U, NULL, NULL, PCAN_GAS_RDONLY, NULL, "uptime"} /* Высокий адрес проверяет отсутствие требований к непрерывности списка. */ +}; /* Конец отсортированной карты без пересечений. */ +static const pcan_gas_map_t map = {regions, 5U}; /* Пять регионов образуют валидную карту для основных сценариев. */ +static const uint16_t reference_addresses[] = {0x0000U, 0x0001U, 0xFF01U}; /* Порядок адресов совпадает с общим JSON-эталоном портов. */ +static const uint8_t reference_config[] = { /* Эталон соответствует tests/fixtures/gas-watch-v2.json и little-endian полям. */ + 0x02U, 0x00U, 0x64U, 0x00U, 0x78U, 0x56U, 0x34U, 0x12U, 0x03U, 0x00U, 0x00U, 0x00U, /* Версия 2, период 100 мс, идентификатор 0x12345678, три адреса и нулевой резерв. */ + 0x00U, 0x00U, 0x01U, 0x00U, 0x01U, 0xFFU /* Адреса 0x0000, 0x0001 и 0xFF01 сохраняют исходный порядок запроса. */ +}; /* Конец эталона запроса, который одновременно является точным ACK. */ +static const uint8_t reference_sample[] = { /* Эталон фиксирует полный диапазон беззнаковых счётчиков и недостоверный третий канал. */ + 0x02U, 0x00U, 0x03U, 0x00U, 0x78U, 0x56U, 0x34U, 0x12U, /* Версия 2, три значения и идентификатор 0x12345678. */ + 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U, 0xFFU, 0xFFU, 0xFFU, /* Номер 0xFFFFFFFF и приборное время 0xFFFFFFF0 мс сохраняются без знакового искажения. */ + 0x03U, 0x7BU, 0x00U, 0xFEU, 0xFFU, 0x00U, 0x00U /* Биты 0 и 1 отмечают достоверность значений 123 и 65534; недостоверное значение передаётся нулём. */ +}; /* Конец эталонной выборки длиной 23 байта. */ + +static void reject_unchanged(set_gas_watch_t *watch, const pcan_gas_map_t *active_map, const uint8_t *payload, size_t size, int expected) /* Общая проверка атомарного отказа на стороне устройства. */ +{ /* Начало вспомогательного сценария ошибочного применения конфигурации. */ + set_gas_watch_t before = *watch; /* Сохраняем весь объект, включая адреса, счётчики и срок очередной выборки. */ + unsigned calls = context.calls; /* Проверка доступности регистров не должна запускать приборные чтения. */ + CHECK(set_gas_watch_apply(watch, active_map, payload, size) == expected); /* Код ошибки отличает формат, отсутствующий адрес, доступ и конфликт идентификатора. */ + CHECK(memcmp(watch, &before, sizeof before) == 0); /* Ошибка любого адреса оставляет подписку целиком прежней. */ + CHECK(context.calls == calls); /* Отклонение запроса не вызывает побочных действий провайдера. */ +} /* Завершение атомарной проверки отказа. */ + +static void test_reference(void) /* Проверяем точные байты обеих сторон контракта на общей эталонной конфигурации. */ +{ /* Начало сценария совместимости wire-формата. */ + set_gas_watch_t watch; /* Устройство хранит подписку в памяти вызывающего приложения. */ + set_gas_watch_sample_t sample; /* Выборка хранится отдельно и не зависит от последующей перенастройки. */ + uint8_t output[SET_GAS_WATCH_SAMPLE_MAX]; /* Размер обеспечивает место для максимально разрешённого пакета. */ + uint16_t values[3] = {0U, 0U, 0U}; /* Декодер получает ровно три ячейки для значений эталона. */ + uint8_t valid[3] = {0U, 0U, 0U}; /* Признаки достоверности возвращаются отдельно от значений. */ + uint32_t sequence = 0U; /* Выходной счётчик должен принять максимальное беззнаковое значение. */ + uint32_t timestamp = 0U; /* Выходная отметка должна сохранить приборные миллисекунды. */ + set_gas_watch_init(&watch); /* Пустое состояние явно инициализируется до первого применения. */ + CHECK(!set_gas_watch_due(&watch, 0U)); /* До настройки устройство не считает сбор активным. */ + CHECK(set_gas_watch_request(0x12345678UL, 100U, reference_addresses, 3U, output, sizeof output) == sizeof reference_config); /* Запрос содержит ровно заголовок 12 байт и три 16-битных адреса. */ + CHECK(memcmp(output, reference_config, sizeof reference_config) == 0); /* Сравнение фиксирует порядок байтов, резерв и порядок адресов. */ + CHECK(set_gas_watch_apply(&watch, &map, output, sizeof reference_config) == SET_GAS_WATCH_OK); /* Полный валидный список принимается одной транзакцией. */ + CHECK(set_gas_watch_encode_ack(&watch, output, sizeof output) == sizeof reference_config); /* Подтверждение возвращает весь принятый список. */ + CHECK(memcmp(output, reference_config, sizeof reference_config) == 0); /* ACK подтверждает адреса точно, а не только совпадение числа каналов. */ + CHECK(set_gas_watch_ack(output, sizeof reference_config, 0x12345678UL, 100U, reference_addresses, 3U) == 1); /* Хост принимает точное подтверждение текущего запроса. */ + CHECK(set_gas_watch_ack(output, sizeof reference_config, 0x12345679UL, 100U, reference_addresses, 3U) == 0); /* Подтверждение предыдущей конфигурации не подтверждает новую. */ + CHECK(set_gas_watch_ack(output, sizeof reference_config, 0x12345678UL, 101U, reference_addresses, 3U) == 0); /* Подтверждённый период тоже является частью конфигурации. */ + const uint16_t reordered[] = {0x0001U, 0x0000U, 0xFF01U}; /* Перестановка сохраняет размер и состав множества, но меняет смысл позиций. */ + CHECK(set_gas_watch_ack(output, sizeof reference_config, 0x12345678UL, 100U, reordered, 3U) == 0); /* ACK обязан подтверждать порядок списка, а не только его множество. */ + CHECK(set_gas_watch_ack(NULL, sizeof reference_config, 0x12345678UL, 100U, reference_addresses, 3U) == 0); /* Нулевой вход ACK безопасно отвергается до сравнения содержимого. */ + CHECK(set_gas_watch_ack(output, sizeof reference_config - 1U, 0x12345678UL, 100U, reference_addresses, 3U) == 0); /* Усечённое подтверждение не подтверждает даже совпадающий префикс. */ + memset(&sample, 0, sizeof sample); /* Обнуляем запасные каналы, чтобы эталон не зависел от содержимого стека. */ + sample.config_id = 0x12345678UL; /* Идентификатор связывает выборку с конкретным списком адресов. */ + sample.sequence = UINT32_MAX; /* Максимальный номер проверяет сохранение всех 32 бит. */ + sample.timestamp_ms = 0xFFFFFFF0UL; /* Время в 16 мс до переполнения проверяет беззнаковую передачу. */ + sample.count = 3U; /* В эталон включены два достоверных и один недостоверный канал. */ + sample.values[0] = 123U; /* Первый регистр передаётся как обычный UINT16. */ + sample.values[1] = 65534U; /* Второй регистр передаётся как сырое слово 0xFFFE без интерпретации типа GUI. */ + sample.values[2] = 0xCAFEU; /* Ненулевое недостоверное значение обязано превратиться в ноль при сериализации. */ + sample.valid[0] = 1U; /* Первый бит маски подтверждает первый канал. */ + sample.valid[1] = 1U; /* Второй бит маски подтверждает второй канал. */ + CHECK(set_gas_watch_encode_sample(&sample, output, sizeof output) == sizeof reference_sample); /* Размер включает заголовок 16 байт, один байт маски и шесть байт значений. */ + CHECK(memcmp(output, reference_sample, sizeof reference_sample) == 0); /* Эталон проверяет каноническое обнуление и отсутствие лишних битов маски. */ + CHECK(sample.values[2] == 0xCAFEU); /* Кодирование не изменяет исходный самостоятельный снимок. */ + CHECK(set_gas_watch_decode(output, sizeof reference_sample, sample.config_id, 3U, &sequence, ×tamp, values, valid, 3U) == 3); /* Хост возвращает число успешно распознанных каналов. */ + CHECK(sequence == UINT32_MAX && timestamp == 0xFFFFFFF0UL); /* Номер и время сохраняются при прохождении через ABI. */ + CHECK(values[0] == 123U && values[1] == 65534U && values[2] == 0U); /* Значения возвращаются в порядке адресов, включая нулевое недостоверное. */ + CHECK(valid[0] == 1U && valid[1] == 1U && valid[2] == 0U); /* Маска распаковывается в отдельные признаки каналов. */ +} /* Завершение проверки эталонных байтов. */ + +static void test_atomic_apply(void) /* Проверяем отказ без частичной замены списка и работу идентификаторов конфигурации. */ +{ /* Начало сценария транзакционной настройки. */ + set_gas_watch_t watch; /* Состояние будет многократно получать ошибочные и корректные запросы. */ + uint8_t payload[SET_GAS_WATCH_CONFIG_MAX + 1U]; /* Дополнительный байт позволяет проверить отказ от лишнего хвоста. */ + uint16_t addresses[] = {0x0000U, 0x0100U}; /* Второй канал принадлежит провайдеру, который нельзя вызывать при настройке. */ + size_t size = set_gas_watch_request(1U, 32U, addresses, 2U, payload, sizeof payload); /* Первая конфигурация запускает два разрозненных регистра с периодом 32 мс. */ + set_gas_watch_init(&watch); /* В исходном состоянии нет принятого идентификатора. */ + context.calls = 0U; /* Счётчик отделяет настройку от всех предыдущих сценариев. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Валидный запрос устанавливает сразу весь список. */ + CHECK(context.calls == 0U); /* Проверка наличия обработчика не должна читать устройство. */ + watch.sequence = 77U; /* Ненулевой номер помогает заметить ошибочный сброс при повторе запроса. */ + watch.next_ms = 12345U; /* Установленный срок должен сохраниться при идемпотентном повторе. */ + watch.scheduled = 1U; /* Состояние уже выполнявшегося сбора не должно превращаться в новый старт. */ + set_gas_watch_t before = watch; /* Копия фиксирует все поля до повторной доставки одного запроса. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Повтор принятой конфигурации является успешным повтором подтверждения. */ + CHECK(memcmp(&watch, &before, sizeof watch) == 0); /* Идемпотентный повтор не меняет номера, расписание и адреса. */ + payload[2] = 33U; /* При прежнем идентификаторе изменяем период с 32 на 33 мс. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_CONFLICT); /* Один идентификатор не может обозначать две разные конфигурации. */ + payload[2] = 32U; /* Восстанавливаем канонический период исходной конфигурации. */ + payload[0] = 3U; /* Неподдерживаемая версия не может интерпретироваться как текущий формат. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_INVALID); /* Неверная версия оставляет рабочий сбор действующим. */ + payload[0] = 2U; /* Возвращаем версию 2 перед проверкой следующего поля. */ + payload[10] = 1U; /* Зарезервированное поле должно оставаться нулевым в версии 2. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_INVALID); /* Неизвестные расширения не принимаются молча. */ + payload[10] = 0U; /* Убираем нарушение резерва для независимой проверки длины. */ + reject_unchanged(&watch, &map, payload, size - 1U, SET_GAS_WATCH_INVALID); /* Оборванный адрес не приводит к усечённой подписке. */ + reject_unchanged(&watch, &map, payload, size + 1U, SET_GAS_WATCH_INVALID); /* Лишний байт исключает неоднозначное принятие пакета. */ + reject_unchanged(&watch, &map, payload, SET_GAS_WATCH_CONFIG_HEADER - 1U, SET_GAS_WATCH_INVALID); /* До чтения полей должен присутствовать весь фиксированный заголовок. */ + reject_unchanged(&watch, &map, payload, sizeof payload, SET_GAS_WATCH_INVALID); /* Пакет больше 140 байт не может содержать допустимую конфигурацию версии 2. */ + reject_unchanged(&watch, &map, NULL, size, SET_GAS_WATCH_INVALID); /* Нулевой указатель с ненулевой длиной обрабатывается безопасно. */ + addresses[1] = 0x0042U; /* Адрес 0x0042 расположен в промежутке между регионами тестовой карты. */ + size = set_gas_watch_request(2U, 32U, addresses, 2U, payload, sizeof payload); /* Новый идентификатор исключает смешение ошибки адреса с конфликтом номера. */ + reject_unchanged(&watch, NULL, payload, size, SET_GAS_WATCH_INVALID); /* Без карты невозможно подтвердить доступность каналов нового списка. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_NO_REG); /* Отсутствующий регистр отвергает весь список. */ + addresses[1] = 0x0200U; /* Этот адрес существует, но помечен как доступный только для записи. */ + size = set_gas_watch_request(2U, 32U, addresses, 2U, payload, sizeof payload); /* Сохраняем корректный wire-формат для проверки прав доступа. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_ACCESS); /* Явный запрет чтения не превращается в постоянно недостоверный канал. */ + addresses[1] = 0x0300U; /* У этого региона есть только провайдер записи без флага WRONLY. */ + size = set_gas_watch_request(2U, 32U, addresses, 2U, payload, sizeof payload); /* Подписка проверяет реальную возможность чтения, а не один флаг. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_ACCESS); /* Отсутствие хранилища и провайдера чтения тоже означает запрет. */ + addresses[1] = 0x0101U; /* Корректная замена сохраняет число каналов, но меняет второй адрес. */ + size = set_gas_watch_request(2U, 32U, addresses, 2U, payload, sizeof payload); /* Новая конфигурация имеет отдельный идентификатор. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Устройство принимает новый список целиком. */ + CHECK(watch.config_id == 2U && watch.address[1] == 0x0101U); /* Равное число каналов не скрывает замену их содержимого. */ + CHECK(watch.sequence == 0U && watch.scheduled == 0U); /* Новый список начинает отдельную последовательность и готов к немедленному сбору. */ + size = set_gas_watch_request(1U, 32U, addresses, 2U, payload, sizeof payload); /* Возвращаем устаревший идентификатор с тем же числом каналов. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_CONFLICT); /* Задержавшийся запрос не откатывает устройство назад. */ + size = set_gas_watch_request(0x80000002UL, 32U, addresses, 2U, payload, sizeof payload); /* Разность ровно половины диапазона uint32 неоднозначна для порядка номеров. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_CONFLICT); /* Граница 2^31 не признаётся более новой конфигурацией. */ + payload[4] = 0U; /* Первые четыре байта идентификатора заменяем нулями для запрещённого номера. */ + payload[5] = 0U; /* Убираем второй байт идентификатора, сохраняя длину и адреса. */ + payload[6] = 0U; /* Убираем третий байт идентификатора без изменения других полей. */ + payload[7] = 0U; /* Завершаем формирование зарезервированного идентификатора 0. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_INVALID); /* Нулевой номер запрещён и не используется как команда обхода порядка. */ + size = set_gas_watch_request(3U, 32U, addresses, 2U, payload, sizeof payload); /* Создаём валидный пакет перед намеренным дублированием адреса на линии. */ + payload[14] = payload[12]; /* Второй адрес получает младший байт первого адреса. */ + payload[15] = payload[13]; /* Второй адрес получает старший байт первого адреса. */ + reject_unchanged(&watch, &map, payload, size, SET_GAS_WATCH_INVALID); /* Дубликаты отвергаются и на устройстве, даже если хостовый builder их запрещает. */ + pcan_gas_region_t overlap[] = {regions[0], regions[0]}; /* Перекрывающиеся регионы создают неоднозначное отображение GAS-адресов. */ + pcan_gas_map_t invalid_map = {overlap, 2U}; /* Некорректная карта не должна обходить проверку через удачный первый поиск. */ + size = set_gas_watch_request(3U, 32U, addresses, 2U, payload, sizeof payload); /* Убираем дубликат из запроса, оставляя единственным нарушением карту. */ + reject_unchanged(&watch, &invalid_map, payload, size, SET_GAS_WATCH_INVALID); /* Применение проверяет целостность карты до принятия подписки. */ + set_gas_watch_init(&watch); /* Новое состояние позволяет отдельно проверить перенос идентификатора через uint32. */ + size = set_gas_watch_request(UINT32_MAX, 32U, addresses, 2U, payload, sizeof payload); /* Любой ненулевой номер разрешён для самой первой конфигурации. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Максимальный номер не отвергается из-за его старшего знакового бита. */ + size = set_gas_watch_request(1U, 32U, addresses, 2U, payload, sizeof payload); /* После максимального номера хост пропускает запрещённый ноль. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Модульное сравнение распознаёт номер 1 как новый после 0xFFFFFFFF. */ +} /* Завершение атомарных и порядковых проверок. */ + +static void test_capture_and_timing(void) /* Проверяем приборное время, единичное чтение и независимость уже полученной выборки. */ +{ /* Начало сценария сбора и сериализации самостоятельного снимка. */ + set_gas_watch_t watch; /* Подписка управляет периодом и последовательностью выборок. */ + set_gas_watch_sample_t sample; /* Снимок принадлежит вызывающему приложению и переживает изменение подписки. */ + uint16_t addresses[] = {0x0100U, 0x0101U, 0x0000U}; /* После отказавшего провайдера остаются ещё два канала для чтения. */ + uint8_t payload[SET_GAS_WATCH_CONFIG_MAX]; /* Буфер переносит только конфигурацию адресов. */ + uint8_t encoded[SET_GAS_WATCH_SAMPLE_MAX]; /* Первый результат кодирования сохраняется для проверки повторной передачи. */ + uint8_t repeated[SET_GAS_WATCH_SAMPLE_MAX]; /* Повторное кодирование обязано совпадать даже после изменений карты. */ + context.calls = 0U; /* Изолируем число приборных обращений текущего сценария. */ + context.base_value = 1000U; /* Вычисляемые значения отличаются от памяти GAS. */ + context.rejected_offset = 0U; /* Первый вычисляемый канал вернёт отказ уже после записи ненулевого результата. */ + set_gas_watch_init(&watch); /* Начинаем без активной подписки и расписания. */ + size_t size = set_gas_watch_request(1U, 32U, addresses, 3U, payload, sizeof payload); /* Три канала должны собираться одним снимком каждые 32 мс. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Проверяем, что наличие провайдера достаточно независимо от его будущего результата. */ + CHECK(context.calls == 0U); /* Настройка не вызывает провайдер даже для заведомо отказавшего чтения. */ + CHECK(set_gas_watch_due(&watch, 0xFFFFFFF0UL)); /* Новый список готов к сбору сразу и около переполнения времени. */ + CHECK(set_gas_watch_capture(&watch, &map, 0xFFFFFFF0UL, &sample)); /* Одна операция фиксирует все каналы и приборную отметку времени. */ + CHECK(context.calls == 2U); /* Оба провайдера прочитаны ровно по одному разу, несмотря на отказ первого. */ + CHECK(sample.config_id == 1U && sample.sequence == 0U && watch.sequence == 1U); /* Первая выборка имеет номер 0, после неё счётчик увеличивается один раз. */ + CHECK(sample.timestamp_ms == 0xFFFFFFF0UL && sample.count == 3U); /* Метка относится ко всей выборке и не подменяется временем отправки. */ + CHECK(sample.valid[0] == 0U && sample.values[0] == 0U); /* Неудачное чтение не выпускает записанное провайдером мусорное значение. */ + CHECK(sample.valid[1] == 1U && sample.values[1] == 1001U); /* Отказ одного адреса не прерывает чтение следующего провайдера. */ + CHECK(sample.valid[2] == 1U && sample.values[2] == storage[0]); /* Последний канал памяти остаётся достоверным после ошибки другого канала. */ + CHECK(watch.scheduled == 1U && watch.next_ms == 16U); /* Прибавление 32 мс к 0xFFFFFFF0 корректно переносит срок в следующий оборот таймера. */ + CHECK(!set_gas_watch_due(&watch, 0xFFFFFFF1UL)); /* Через 1 мс после выборки период ещё не истёк. */ + CHECK(!set_gas_watch_due(&watch, 0U)); /* После переполнения до срока остаётся 16 мс. */ + CHECK(!set_gas_watch_due(&watch, 15U)); /* В последнюю миллисекунду перед сроком чтение ещё не требуется. */ + CHECK(set_gas_watch_due(&watch, 16U)); /* Равенство приборного времени сроку означает готовность новой выборки. */ + watch.sequence = UINT32_MAX; /* Устанавливаем границу, которую нельзя дождаться перебором миллиардов выборок. */ + CHECK(set_gas_watch_capture(&watch, &map, 0U, &sample)); /* Явный сбор разрешён и до очередного срока: due остаётся решением вызывающего кода. */ + CHECK(sample.sequence == UINT32_MAX && watch.sequence == 0U); /* Последовательность переносится через uint32 без потери последнего номера. */ + size_t encoded_size = set_gas_watch_encode_sample(&sample, encoded, sizeof encoded); /* Кодируем зафиксированный снимок до изменения окружения. */ + unsigned calls = context.calls; /* Запоминаем количество чтений, чтобы выявить скрытое перечитывание при сериализации. */ + storage[0] = 999U; /* Модель прибора меняется после фиксации снимка. */ + context.base_value = 2000U; /* Вычисляемый провайдер тоже теперь вернул бы другие значения. */ + size = set_gas_watch_request(2U, 100U, reference_addresses, 3U, payload, sizeof payload); /* Меняем подписку на другой список при сохранении числа каналов. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Перенастройка должна быть независима от уже созданного пакета. */ + CHECK(set_gas_watch_encode_sample(&sample, repeated, sizeof repeated) == encoded_size); /* Повторная передача использует прежний размер самостоятельного снимка. */ + CHECK(memcmp(encoded, repeated, encoded_size) == 0); /* Ни значения карты, ни новые адреса не изменяют старую выборку. */ + CHECK(context.calls == calls); /* Подтверждение настройки и повторное кодирование не читают приборные регистры. */ + pcan_gas_region_t changed_regions[5]; /* Подмена карты моделирует исчезновение или изменение прав после успешной настройки. */ + memcpy(changed_regions, regions, sizeof changed_regions); /* Остальные свойства регионов сохраняются, чтобы карта оставалась структурно корректной. */ + changed_regions[0].flags = PCAN_GAS_WRONLY; /* Выбранные адреса 0 и 1 теперь запрещены для чтения. */ + changed_regions[4].base = 0xFF02U; /* Ранее выбранный адрес 0xFF01 больше не покрывается картой. */ + pcan_gas_map_t changed_map = {changed_regions, 5U}; /* Изменённая карта остаётся отсортированной и без перекрытий. */ + CHECK(set_gas_watch_capture(&watch, &changed_map, 1U, &sample)); /* Потеря отдельных каналов не отменяет номер и время всей выборки. */ + CHECK(sample.valid[0] == 0U && sample.valid[1] == 0U && sample.valid[2] == 0U); /* Изменение прав и исчезновение адреса явно отражаются недостоверностью. */ + CHECK(sample.values[0] == 0U && sample.values[1] == 0U && sample.values[2] == 0U); /* Ни старые значения, ни указатели исчезнувших каналов не попадают в новый пакет. */ + pcan_gas_map_t invalid_map = {NULL, 1U}; /* Ненулевое число регионов без массива является структурной ошибкой карты. */ + set_gas_watch_t before_watch = watch; /* Ошибка всей карты не должна расходовать номер выборки или сдвигать расписание. */ + set_gas_watch_sample_t before_sample = sample; /* Ошибка аргументов не должна повреждать уже полученный снимок. */ + CHECK(!set_gas_watch_capture(&watch, &invalid_map, 2U, &sample)); /* Структурно неверная карта отличается от ошибки отдельного читаемого канала. */ + CHECK(memcmp(&watch, &before_watch, sizeof watch) == 0); /* Состояние подписки полностью сохраняется при невозможности захвата. */ + CHECK(memcmp(&sample, &before_sample, sizeof sample) == 0); /* Выходной снимок полностью сохраняется при невозможности захвата. */ + size = set_gas_watch_request(3U, 0U, NULL, 0U, payload, sizeof payload); /* Остановка выражается пустым списком с периодом 0 мс и новым идентификатором. */ + CHECK(size == SET_GAS_WATCH_CONFIG_HEADER); /* Пакет остановки состоит только из заголовка конфигурации. */ + CHECK(set_gas_watch_apply(&watch, &map, payload, size) == SET_GAS_WATCH_OK); /* Остановка применяется такой же транзакцией, как активная конфигурация. */ + set_gas_watch_sample_t before = sample; /* Сохраняем старую выборку перед попыткой собрать неактивный поток. */ + CHECK(!set_gas_watch_due(&watch, UINT32_MAX)); /* Остановленный поток не становится активным из-за переполнения времени. */ + CHECK(!set_gas_watch_capture(&watch, &map, 1U, &sample)); /* Пустая подписка не создаёт новый пакет. */ + CHECK(memcmp(&sample, &before, sizeof sample) == 0); /* Неудачный сбор сохраняет уже готовую выборку в буфере вызывающего кода. */ + storage[0] = 123U; /* Возвращаем общее значение эталона для независимости следующих сценариев. */ +} /* Завершение проверки снимка и расписания. */ + +static void decode_rejected(const uint8_t *payload, size_t size, uint32_t config_id, size_t count, size_t capacity) /* Проверяем единый контракт отсутствия частичного результата на стороне хоста. */ +{ /* Начало вспомогательной проверки отказа декодера. */ + uint16_t values[SET_GAS_WATCH_MAX]; /* Полный буфер отделяет недостаточную объявленную ёмкость от реального выхода за память. */ + uint8_t valid[SET_GAS_WATCH_MAX]; /* Маска хранится в собственном буфере с отличимым заполнителем. */ + uint16_t before_values[SET_GAS_WATCH_MAX]; /* Копия выявляет изменение любого канала, включая запасные ячейки. */ + uint8_t before_valid[SET_GAS_WATCH_MAX]; /* Копия маски выявляет раннюю запись до полной валидации payload. */ + uint32_t sequence = 0x11223344UL; /* Отличимая исходная последовательность не должна меняться при отказе. */ + uint32_t timestamp = 0x55667788UL; /* Отличимая исходная метка не должна меняться при отказе. */ + memset(values, 0xA5, sizeof values); /* Все значения получают заполнитель, отличный от эталонного payload. */ + memset(valid, 0x5A, sizeof valid); /* Признаки достоверности получают отдельный заполнитель. */ + memcpy(before_values, values, sizeof values); /* Сохраняем массив значений для полного побайтового сравнения. */ + memcpy(before_valid, valid, sizeof valid); /* Сохраняем все ячейки маски до вызова декодера. */ + CHECK(set_gas_watch_decode(payload, size, config_id, count, &sequence, ×tamp, values, valid, capacity) == -1); /* Любая ошибка возвращает единый отрицательный результат. */ + CHECK(sequence == 0x11223344UL && timestamp == 0x55667788UL); /* Скалярные выходы обновляются только после полного принятия пакета. */ + CHECK(memcmp(values, before_values, sizeof values) == 0); /* Декодер не оставляет частично декодированные значения. */ + CHECK(memcmp(valid, before_valid, sizeof valid) == 0); /* Декодер не оставляет частично распакованные признаки. */ +} /* Завершение проверки транзакционного декодирования. */ + +static void test_malformed_and_limits(void) /* Проверяем границы буферов, максимальный список и канонический bitmap. */ +{ /* Начало сценария валидации публичной границы данных. */ + uint8_t payload[SET_GAS_WATCH_SAMPLE_MAX + 1U]; /* Дополнительный байт используется только для проверки лишнего хвоста. */ + uint8_t before[sizeof payload]; /* Заполнитель позволяет доказать отсутствие записи при отказе builder. */ + uint16_t duplicates[] = {1U, 1U}; /* Повтор одного адреса запрещён независимо от его реального существования в карте. */ + memset(payload, 0xA5, sizeof payload); /* Начинаем с различимого содержимого выходного буфера. */ + memcpy(before, payload, sizeof payload); /* Снимок буфера позволит выявить даже частично записанный заголовок. */ + CHECK(set_gas_watch_request(0U, 100U, reference_addresses, 3U, payload, sizeof payload) == 0U); /* Нулевой идентификатор конфигурации запрещён хостовому builder. */ + CHECK(set_gas_watch_request(1U, 0U, reference_addresses, 3U, payload, sizeof payload) == 0U); /* Ненулевой список требует ненулевого периода. */ + CHECK(set_gas_watch_request(1U, 100U, NULL, 0U, payload, sizeof payload) == 0U); /* Пустой список требует нулевого периода и означает остановку. */ + CHECK(set_gas_watch_request(1U, 100U, duplicates, 2U, payload, sizeof payload) == 0U); /* Дубликаты не должны выпускаться builder на линию. */ + CHECK(set_gas_watch_request(1U, 100U, NULL, 3U, payload, sizeof payload) == 0U); /* Ненулевое количество требует доступного массива адресов. */ + CHECK(set_gas_watch_request(1U, 100U, reference_addresses, 65U, payload, sizeof payload) == 0U); /* Проверка предела 64 выполняется до чтения указанного массива. */ + CHECK(set_gas_watch_request(1U, 100U, reference_addresses, 3U, payload, sizeof reference_config - 1U) == 0U); /* Недостаточная ёмкость не допускает усечённого запроса. */ + CHECK(set_gas_watch_request(1U, 100U, reference_addresses, 3U, NULL, sizeof payload) == 0U); /* Нулевой выходной указатель возвращает отказ без записи. */ + CHECK(memcmp(payload, before, sizeof payload) == 0); /* Ни один ошибочный запрос не должен частично менять переданный буфер. */ + memcpy(payload, reference_sample, sizeof reference_sample); /* Берём правильный пакет и независимо повреждаем отдельные части. */ + decode_rejected(payload, sizeof reference_sample, 0x12345679UL, 3U, 3U); /* Задержавшаяся выборка прежнего списка отвергается даже при том же количестве каналов. */ + decode_rejected(payload, sizeof reference_sample, 0x12345678UL, 2U, 3U); /* Число каналов должно совпадать с подтверждённой подпиской. */ + decode_rejected(payload, sizeof reference_sample, 0x12345678UL, 3U, 2U); /* Недостаточное число выходных ячеек не оставляет частичного результата. */ + decode_rejected(NULL, sizeof reference_sample, 0x12345678UL, 3U, 3U); /* Нулевой входной указатель обрабатывается как некорректный пакет. */ + decode_rejected(payload, SET_GAS_WATCH_SAMPLE_HEADER - 1U, 0x12345678UL, 3U, 3U); /* Не хватает даже фиксированного заголовка выборки. */ + decode_rejected(payload, sizeof reference_sample - 1U, 0x12345678UL, 3U, 3U); /* Оборванное последнее значение не может обновить первые каналы. */ + decode_rejected(payload, sizeof reference_sample + 1U, 0x12345678UL, 3U, 3U); /* Избыточный хвост исключает неверную интерпретацию следующего сообщения. */ + payload[0] = 3U; /* Изменяем версию при сохранении всех остальных эталонных полей. */ + decode_rejected(payload, sizeof reference_sample, 0x12345678UL, 3U, 3U); /* Неподдерживаемый формат не обновляет выходы. */ + payload[0] = 2U; /* Возвращаем действующую версию перед повреждением bitmap. */ + payload[16] = 0x83U; /* Бит 7 находится за пределами трёх каналов и обязан быть нулевым. */ + decode_rejected(payload, sizeof reference_sample, 0x12345678UL, 3U, 3U); /* Неиспользуемые биты маски проверяются для канонического представления. */ + payload[16] = 3U; /* Восстанавливаем корректную маску двух достоверных каналов. */ + payload[21] = 1U; /* Третий канал остаётся недостоверным, но его слово становится ненулевым. */ + decode_rejected(payload, sizeof reference_sample, 0x12345678UL, 3U, 3U); /* Неканоническое ненулевое слово недостоверного канала отвергается. */ + payload[21] = 0U; /* Восстанавливаем эталон перед проверкой чрезмерного количества. */ + payload[2] = 65U; /* Заголовок требует больше максимальных 64 каналов. */ + decode_rejected(payload, sizeof reference_sample, 0x12345678UL, 65U, 64U); /* Ограничение количества проверяется до обращения к выходным массивам. */ + uint16_t addresses[SET_GAS_WATCH_MAX]; /* Максимальный список хранит уникальные адреса единого региона. */ + uint16_t words[SET_GAS_WATCH_MAX]; /* Модель карты содержит достаточно реальных слов для всех 64 каналов. */ + for (size_t i = 0U; i < SET_GAS_WATCH_MAX; ++i) { /* Заполняем все разрешённые позиции без фиксации размера в теле цикла. */ + addresses[i] = (uint16_t)i; /* Диапазон 0..63 создаёт уникальный отсортированный список регистров. */ + words[i] = (uint16_t)(1000U + i); /* Ненулевой возрастающий рисунок делает перестановки значений заметными. */ + } /* Завершение подготовки максимального списка. */ + pcan_gas_region_t full_region = {0U, SET_GAS_WATCH_MAX, words, NULL, NULL, PCAN_GAS_RDONLY, NULL, "full"}; /* Один читаемый регион покрывает все 64 адреса. */ + pcan_gas_map_t full_map = {&full_region, 1U}; /* Карта максимального списка остаётся простой и однозначной. */ + set_gas_watch_t watch; /* Состояние максимального потока проверяет размеры публичных структур. */ + set_gas_watch_sample_t sample; /* Выборка должна вместить все значения и признаки без динамической памяти. */ + set_gas_watch_init(&watch); /* Создаём пустое состояние для независимого граничного сценария. */ + size_t config_size = set_gas_watch_request(1U, 1U, addresses, SET_GAS_WATCH_MAX, payload, sizeof payload); /* Минимальный ненулевой период 1 мс остаётся разрешённым. */ + CHECK(config_size == SET_GAS_WATCH_CONFIG_MAX && config_size == 140U); /* Максимальная конфигурация занимает 12 + 64*2 байта. */ + CHECK(set_gas_watch_apply(&watch, &full_map, payload, config_size) == SET_GAS_WATCH_OK); /* Устройство принимает ровно предельные 64 уникальных адреса. */ + CHECK(set_gas_watch_capture(&watch, &full_map, 42U, &sample)); /* Максимальная выборка собирается за один вызов. */ + size_t sample_size = set_gas_watch_encode_sample(&sample, payload, sizeof payload); /* Кодируем весь снимок с восемью байтами bitmap. */ + CHECK(sample_size == SET_GAS_WATCH_SAMPLE_MAX && sample_size == 152U); /* Полный пакет занимает 16 + 8 + 64*2 байта. */ + uint16_t decoded[SET_GAS_WATCH_MAX]; /* Выходные значения хоста имеют ровно предельную ёмкость. */ + uint8_t valid[SET_GAS_WATCH_MAX]; /* Один признак на каждый из 64 каналов проверяет все восемь байтов bitmap. */ + uint32_t sequence = UINT32_MAX; /* Отличимое исходное значение должно замениться нулём первой выборки. */ + uint32_t timestamp = 0U; /* Метка должна получить приборное значение 42 мс. */ + CHECK(set_gas_watch_decode(payload, sample_size, 1U, SET_GAS_WATCH_MAX, &sequence, ×tamp, decoded, valid, SET_GAS_WATCH_MAX) == (int)SET_GAS_WATCH_MAX); /* Декодер принимает предельный размер без усечения. */ + CHECK(sequence == 0U && timestamp == 42U && memcmp(decoded, words, sizeof words) == 0); /* Все значения и скалярные поля максимального пакета сохраняются. */ + for (size_t i = 0U; i < SET_GAS_WATCH_MAX; ++i) { /* Проверяем каждую позицию вместо одной средней маски. */ + CHECK(valid[i] == 1U); /* Читаемый массив делает достоверными все 64 канала, включая последние биты bitmap. */ + } /* Завершение проверки полного bitmap. */ + CHECK(set_gas_watch_decode(payload, sample_size, 1U, SET_GAS_WATCH_MAX, NULL, ×tamp, decoded, valid, SET_GAS_WATCH_MAX) == (int)SET_GAS_WATCH_MAX); /* Вызывающий код может отказаться от получения необязательного счётчика последовательности. */ + CHECK(set_gas_watch_decode(payload, sample_size, 1U, SET_GAS_WATCH_MAX, &sequence, NULL, decoded, valid, SET_GAS_WATCH_MAX) == (int)SET_GAS_WATCH_MAX); /* Вызывающий код может отказаться от получения необязательной отметки времени. */ + CHECK(set_gas_watch_decode(payload, sample_size, 1U, SET_GAS_WATCH_MAX, &sequence, ×tamp, NULL, valid, SET_GAS_WATCH_MAX) == -1); /* Обязательный массив значений проверяется до записи результата. */ + CHECK(set_gas_watch_decode(payload, sample_size, 1U, SET_GAS_WATCH_MAX, &sequence, ×tamp, decoded, NULL, SET_GAS_WATCH_MAX) == -1); /* Обязательный массив достоверности проверяется до записи результата. */ + CHECK(set_gas_watch_encode_sample(&sample, NULL, sizeof payload) == 0U); /* Нулевой буфер сериализации приводит к безопасному отказу. */ + CHECK(set_gas_watch_encode_sample(&sample, payload, sample_size - 1U) == 0U); /* Сериализация никогда не выпускает частичный пакет. */ + CHECK(set_gas_watch_encode_sample(NULL, payload, sizeof payload) == 0U); /* Отсутствующий снимок нельзя заменить чтением какой-либо глобальной карты. */ + CHECK(set_gas_watch_encode_ack(NULL, payload, sizeof payload) == 0U); /* Отсутствующая подписка не образует корректного подтверждения. */ + CHECK(set_gas_watch_encode_ack(&watch, NULL, sizeof payload) == 0U); /* Нулевой буфер ACK безопасно отвергается. */ + CHECK(set_gas_watch_encode_ack(&watch, payload, config_size - 1U) == 0U); /* Подтверждение не сокращается до одного заголовка из-за малого буфера. */ + CHECK(set_gas_watch_apply(NULL, &full_map, payload, config_size) == SET_GAS_WATCH_INVALID); /* Пустой указатель состояния не должен разыменовываться. */ + CHECK(!set_gas_watch_due(NULL, 1U)); /* Запрос расписания без состояния возвращает отсутствие готовности. */ + CHECK(!set_gas_watch_capture(NULL, &full_map, 1U, &sample)); /* Сбор без состояния возвращает отказ. */ + CHECK(!set_gas_watch_capture(&watch, NULL, 1U, &sample)); /* Сбор без карты не обращается к несуществующим провайдерам. */ + CHECK(!set_gas_watch_capture(&watch, &full_map, 1U, NULL)); /* Сбор без выходного снимка не выполняется. */ + set_gas_watch_init(NULL); /* Инициализация проверяется на безопасное поведение с нулевым указателем. */ + sample.valid[0] = 0U; /* Отключаем первый канал, чтобы проверить младший бит первого байта bitmap. */ + sample.valid[7] = 0U; /* Отключаем последний канал первого байта bitmap. */ + sample.valid[8] = 0U; /* Отключаем первый канал второго байта bitmap, проверяя перенос границы восьми каналов. */ + sample.valid[63] = 0U; /* Отключаем последний разрешённый канал в старшем бите восьмого байта. */ + CHECK(set_gas_watch_encode_sample(&sample, payload, sizeof payload) == sample_size); /* Изменение достоверности сохраняет длину максимального пакета. */ + CHECK(payload[16] == 0x7EU && payload[17] == 0xFEU && payload[23] == 0x7FU); /* Раскладка bitmap соответствует индексам 0, 7, 8 и 63 без смещения. */ + CHECK(set_gas_watch_decode(payload, sample_size, 1U, SET_GAS_WATCH_MAX, &sequence, ×tamp, decoded, valid, SET_GAS_WATCH_MAX) == (int)SET_GAS_WATCH_MAX); /* Максимальный пакет с разреженной маской остаётся допустимым. */ + CHECK(decoded[0] == 0U && decoded[7] == 0U && decoded[8] == 0U && decoded[63] == 0U); /* Недостоверные слова принудительно обнуляются на всех проверенных границах маски. */ + CHECK(sample.values[0] == 1000U && sample.values[63] == 1063U); /* Каноническое обнуление относится к wire-пакету и не меняет исходный снимок. */ + memcpy(before, payload, sizeof payload); /* Сохраняем полный выход перед ошибками модели сериализации. */ + sample.valid[63] = 2U; /* Признак достоверности допускает только значения 0 и 1. */ + CHECK(set_gas_watch_encode_sample(&sample, payload, sizeof payload) == 0U); /* Неверный признак в последнем канале проверяется до записи первого байта заголовка. */ + CHECK(memcmp(payload, before, sizeof payload) == 0); /* Поздняя ошибка модели не оставляет частично записанный пакет. */ + sample.valid[63] = 0U; /* Восстанавливаем двоичный признак перед проверкой неверного количества каналов. */ + sample.count = SET_GAS_WATCH_MAX + 1U; /* Число 65 находится за пределами обоих встроенных массивов снимка. */ + CHECK(set_gas_watch_encode_sample(&sample, payload, sizeof payload) == 0U); /* Проверка количества предотвращает выход за границу даже при достаточном output. */ + CHECK(memcmp(payload, before, sizeof payload) == 0); /* Неверное количество тоже не меняет выходной буфер. */ +} /* Завершение проверок некорректных входов и предельных размеров. */ + +int main(void) /* Один независимый исполняемый тест запускается общей системой CTest. */ +{ /* Начало последовательного запуска контрактных сценариев. */ + test_reference(); /* Эталонные байты фиксируют совместимость C, Python и JVM. */ + test_atomic_apply(); /* Ошибки настройки и повторные запросы не должны повреждать подписку. */ + test_capture_and_timing(); /* Снимок и приборный таймер проверяются отдельно от транспорта. */ + test_malformed_and_limits(); /* Входные границы проверяются и на устройстве, и в хостовом ABI. */ + if (failures != 0U) { /* Любое нарушение делает запуск неуспешным для CTest и CI. */ + printf("GAS_WATCH2: %u failures\n", failures); /* Итог сообщает число обнаруженных нарушений контракта. */ + return 1; /* Ненулевой код обозначает, что хотя бы одна контрактная проверка не прошла. */ + } /* Завершение ветки ошибочного результата. */ + puts("GAS_WATCH2 contract tests passed"); /* Краткая строка подтверждает завершение всех сценариев. */ + return 0; /* Нулевой код передаёт общий успех системе сборки. */ +} /* Завершение тестового исполняемого файла. */ diff --git a/c/set-protocol/tests/test_modbus_server.c b/c/set-protocol/tests/test_modbus_server.c index eb264cc..75a86d9 100644 --- a/c/set-protocol/tests/test_modbus_server.c +++ b/c/set-protocol/tests/test_modbus_server.c @@ -12,7 +12,7 @@ static uint16_t holding[32]; static uint16_t input[32]; -static uint16_t coils; +static uint16_t discretes = 0x0014U; /* Входы 2 и 4 установлены для проверки сохранённого битового чтения типа 0x5. */ static bool read_word(void *user, pcan_modbus_bank_t bank, uint16_t address, uint16_t *value) @@ -21,7 +21,7 @@ static bool read_word(void *user, pcan_modbus_bank_t bank, if (address >= 32U) return false; if (bank == PCAN_MODBUS_HOLDING) *value = holding[address]; else if (bank == PCAN_MODBUS_INPUT) *value = input[address]; - else if (bank == PCAN_MODBUS_COIL) *value = (uint16_t)((coils >> address) & 1U); + else if (bank == PCAN_MODBUS_DISCRETE && address < 16U) *value = (uint16_t)((discretes >> address) & 1U); /* Не сдвигаем 16-битное поле на недопустимое число позиций. */ else return false; return true; } @@ -32,10 +32,7 @@ static bool write_word(void *user, pcan_modbus_bank_t bank, (void)user; if (address >= 32U) return false; if (bank == PCAN_MODBUS_HOLDING) holding[address] = value; - else if (bank == PCAN_MODBUS_COIL && address < 16U) { - if (value) coils |= (uint16_t)(1U << address); - else coils &= (uint16_t)~(1U << address); - } else return false; + else return false; /* Битовые входы и новый слотный GAS не записываются через Modbus provider. */ return true; } @@ -84,10 +81,11 @@ int main(void) CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_RESPONSE); CHECK(holding[3] == 0x1122U && holding[4] == 0x3344U); - req = request(PCAN_MODBUS_COIL, 2U, 3U); - req.dlc = 2U; req.data[0] = 0x05U; req.data[1] = 0U; + req = request(PCAN_MODBUS_DISCRETE, 2U, 3U); /* Читаем три входа 2…4 через сохранённый тип 0x5. */ CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_RESPONSE); - CHECK(coils == 0x0014U); + CHECK(rsp.dlc == 2U && rsp.data[0] == 0x05U && rsp.data[1] == 0U); /* Маска прочитанных входов должна сохранять порядок младших битов. */ + req = request(PCAN_MSG_GAS_SLOT, 2U, 3U); /* Передаём бывший номер Coil, теперь занятый независимым GAS SLOT. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_NOT_FOR_US); /* Слотный кадр не должен вызывать Modbus provider и менять его счётчики. */ req = request(PCAN_MODBUS_INPUT, 0U, 5U); CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_HANDLED_NO_RESPONSE); diff --git a/c/set-protocol/tools/build_host.py b/c/set-protocol/tools/build_host.py index 911da88..3c6dcda 100644 --- a/c/set-protocol/tools/build_host.py +++ b/c/set-protocol/tools/build_host.py @@ -27,10 +27,12 @@ SOURCES = [ "set_regmap.c", "set_emu_ump.c", "set_emu_tms.c", "set_emu_igbt.c", "set_emu_server.c", "set_boot.c", "firmware_image.c", "altera_logic.c", "altera_stream.c", + "set_gas_watch.c", # Добавляет общий GAS_WATCH2 в прямые MSVC/CC сборки, чтобы новые ctypes/JNI символы были доступны. "set_protocol.c", "set_can.c", "set_firmware.c", "set_telemetry.c", "set_plot.c", "set_trends.c", "set_spectrum.c", "set_signal.c", "set_wavegen.c", "balsam_can.c", "set_crc.c", "periph28335.c", "tms2812.c", "gui_catalog.c", "gui_frame.c", "pcan_abi.c", "pcan_crc.c", "pcan_frame.c", "pcan_id.c", "pcan_link.c", "pcan_ring.c", "pcan_gas.c", "pcan_modbus_server.c", + "pcan_gas_slot.c", # Собирает единый слотный кодек также при прямой MSVC/CC сборке для ctypes и JNI. ) ] @@ -94,6 +96,7 @@ def main() -> int: SOURCES.extend([ ROOT / "ports" / "android" / "set_plot_jni.c", ROOT / "ports" / "android" / "setprotocol_jni.c", + ROOT / "ports" / "android" / "gas_slots_jni.c", # Даёт host JVM тот же адаптер слотной адресации, который используется Android. ]) output = args.output.resolve() output.parent.mkdir(parents=True, exist_ok=True) diff --git a/doc/setcan/protocan/examples/gas-slot-vectors.json b/doc/setcan/protocan/examples/gas-slot-vectors.json new file mode 100644 index 0000000..3d11862 --- /dev/null +++ b/doc/setcan/protocan/examples/gas-slot-vectors.json @@ -0,0 +1,55 @@ +{ + "profile": "GAS SLOT 0x4 / Word0 mask", + "words": [ + 14, + 4660, + 43981, + 65535 + ], + "payload_hex": "0E003412CDABFFFF", + "vectors": [ + { + "mode": 5, + "local_slot": 0, + "request_id": "0x11540500", + "response_id": "0x19540500" + }, + { + "mode": 6, + "local_slot": 0, + "request_id": "0x11640600", + "response_id": "0x19640600" + }, + { + "mode": 7, + "local_slot": 0, + "request_id": "0x11740700", + "response_id": "0x19740700" + }, + { + "mode": 8, + "local_slot": 0, + "request_id": "0x11840800", + "response_id": "0x19840800" + }, + { + "mode": 16, + "local_slot": 0, + "request_id": "0x12041000", + "response_id": "0x1A041000" + }, + { + "mode": 31, + "local_slot": 66, + "request_id": "0x12F41F42", + "response_id": "0x1AF41F42", + "words": [ + 6, + 4660, + 43981, + 0 + ], + "payload_hex": "06003412CDAB0000" + } + ] +} diff --git a/python/logic_analyzer/decoders/set_can.py b/python/logic_analyzer/decoders/set_can.py index f0d0867..075623c 100644 --- a/python/logic_analyzer/decoders/set_can.py +++ b/python/logic_analyzer/decoders/set_can.py @@ -6,7 +6,7 @@ from .set_uart import number, parse_frame TYPES = {0: 'BROADCAST', 1: 'DISCRETE', 2: 'ANALOG', 3: 'GAS', - 4: 'MODBUS_COIL', 5: 'MODBUS_DISCRETE', 6: 'MODBUS_HOLDING', + 4: 'GAS_SLOT', 5: 'MODBUS_DISCRETE', 6: 'MODBUS_HOLDING', # Тип 0x4 теперь означает масочный слотный GAS, номера остальных Modbus-типов сохранены. 7: 'MODBUS_INPUT', 8: 'ERROR', 9: 'BOOT_CONTROL', 10: 'BOOT_DATA_A', 11: 'BOOT_DATA_B', 12: 'BOOT_STATUS', 13: 'BOOT_DISCOVERY', 15: 'PULSE'} BOOT = dict(enumerate(('IDENTIFY ENTER_BOOT BEGIN_IMAGE BEGIN_COMPAT ERASE VERIFY ' @@ -42,7 +42,14 @@ def legacy(ident, data, profile='protocan'): raise ValueError('Invalid GAS register payload/range') result['registers'] = [(body + i//2, number(data[i:i+2])) for i in range(0, len(data), 2)] text += ' ' + ('READ' if not data else ' '.join('R%04X=%04X' % pair for pair in result['registers'])) - elif 4 <= msg <= 7: + elif msg == 4: # Слотный GAS определяется номером типа, без эвристики по первым байтам данных. + from protocan.gas_slots import GasSlots # Проверку Word0-маски, длины и порядка октетов выполняет единственный C-кодек. + values = GasSlots().decode_address(ident, data) # Не ограничиваем анализатор адресами семейства PERIPH. + result['slot'] = body # Адрес слота отделён от списка обычных регистров GAS 0x3. + result['mask'] = values[0] if values else None # Пустой запрос чтения не содержит фиктивной маски. + result['slot_words'] = [(index, values[index]) for index in range(1, 4) if values and values[0] & (1 << index)] # Публикуем только выбранные или достоверные значения, без служебного Word0. + text += ' slot=%04X' % body + (' READ' if not values else ' mask=%04X' % values[0]) # В логе ясно различаются адрес и маска частичной записи. + elif 5 <= msg <= 7: # Диапазон Modbus больше не включает бывший Coil 0x4. text += ' address=%03X count=%d' % (body >> 4, body & 15) elif msg == 8: text += ' info=%02X code=%02X' % (body >> 8, body & 255) diff --git a/python/protocan/README.md b/python/protocan/README.md index bd9f1b4..b62e697 100644 --- a/python/protocan/README.md +++ b/python/protocan/README.md @@ -55,3 +55,7 @@ assert decode_entry(raw) == entry `SETGUI` (вкладки «Шина CAN» и «Адресное пространство»), `CAN_to_RS485`. Там пакет лежит внутри `gui_desktop/core`, здесь — источник истины. + +## GAS: регистры 0x3 и слоты 0x4 + +[Адресация GAS](../../doc/setcan/protocan/OAP.md): `0x3` — отдельные 16-битные регистры `0…65535`, запись 1…4 слов. `0x4` — слот с Word0-маской и тремя значениями; PERIPH сохраняет 200 слов в 67 слотах `0xMM00…0xMM42`. Формат определяется MsgType, без настройки профиля. diff --git a/python/protocan/gas_slots.py b/python/protocan/gas_slots.py new file mode 100644 index 0000000..e2e19db --- /dev/null +++ b/python/protocan/gas_slots.py @@ -0,0 +1,79 @@ +import ctypes # Передаём построение ID, проверку маски и порядок октетов единственному C-кодеку. +from .native import get_native_core # Используем штатный поиск библиотеки без резервного Python-кодека. + +class GasSlots: # Тип 0x4 содержит Word0 с маской и три значения в фиксированных позициях. + def __init__(self, library=None): # Тест или приложение может передать ту же собранную библиотеку явно. + self.lib = library or get_native_core().lib # Отсутствующее общее ядро проявляется штатной ошибкой загрузки. + self.lib.pcan_gas_slot_request_id.argtypes = [ctypes.c_uint] * 3 # Обёртка PERIPH принимает mode, локальный слот и Route. + self.lib.pcan_gas_slot_request_id.restype = ctypes.c_uint32 # Extended ID возвращается без знакового преобразования. + self.lib.pcan_gas_slot_id.argtypes = [ctypes.c_uint] * 4 # Общий построитель принимает DeviceType, DeviceID, полный адрес и Route. + self.lib.pcan_gas_slot_id.restype = ctypes.c_uint32 # Любой корректный ID типа 0x4 отличен от нулевого маркера ошибки. + self.lib.pcan_gas_slot_encode.argtypes = [ctypes.POINTER(ctypes.c_uint16), ctypes.c_uint, ctypes.POINTER(ctypes.c_uint8)] # Четыре wire-слова включают маску, а не четвёртый регистр. + self.lib.pcan_gas_slot_encode.restype = ctypes.c_int # Кодек возвращает длину 0/8 либо отрицательный отказ. + self.lib.pcan_gas_slot_decode.argtypes = [ctypes.c_uint32, ctypes.c_uint, ctypes.POINTER(ctypes.c_uint8), ctypes.c_uint, ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_uint16)] # PERIPH-декодер дополнительно проверяет принадлежность странице и последний слот. + self.lib.pcan_gas_slot_decode.restype = ctypes.c_int # Результат 0/4 включает маску при наличии данных. + self.lib.pcan_gas_slot_decode_words.argtypes = [ctypes.c_uint32, ctypes.c_uint, ctypes.POINTER(ctypes.c_uint8), ctypes.c_uint, ctypes.POINTER(ctypes.c_uint16)] # Общий декодер поддерживает остальные классы узлов и все 16 бит адреса. + self.lib.pcan_gas_slot_decode_words.restype = ctypes.c_int # Отрицательное значение означает отказ без публикации частичного результата. + + @staticmethod # Проверка представимости Python-чисел не дублирует wire-логику. + def _unsigned(value, maximum): # Проверяем границы до возможного сужения ctypes. + if type(value) is not int or not 0 <= value <= maximum: # bool, дробь и отрицательное число не являются полями протокола. + raise ValueError('Недопустимое целое значение протокола') # Не отправляем усечённое значение к другому адресу. + + def _payload(self, words, route): # Общая упаковка используется адресным и PERIPH-построителями. + values = None if words is None else tuple(words) # Фиксируем входной iterable до преобразования к C-массиву. + if values is not None: # Запись или ответ содержат ровно маску и три значения. + if len(values) != 4: # Позиции не сдвигаются при частичной записи. + raise ValueError('Нужны Word0-маска и три значения Word1…Word3') # Не дополняем отсутствующие позиции нулями неявно. + for value in values: # Все wire-слова имеют одинаковую ширину 16 бит. + self._unsigned(value, 0xFFFF) # Корректные ноль и 65535 остаются допустимыми значениями. + if values is None and route != 0: # Пустой ответ прибора не имеет определённого смысла. + raise ValueError('Ответ должен содержать маску и значения') # Отказ возникает до отправки в транспорт. + source = None if values is None else (ctypes.c_uint16 * 4)(*values) # Маску и значения проверяет C до кодирования. + data = (ctypes.c_uint8 * 8)() # Буфер ограничен одним classic CAN кадром. + length = self.lib.pcan_gas_slot_encode(source, 0 if values is None else 4, data) # Единственный кодек проверяет разрешённые биты маски и порядок октетов. + if length < 0: # Неверная маска не заменяется другой командой. + raise ValueError('Неверная маска GAS SLOT: допустимы непустые биты 1…3') # Бит 0 относится к служебному слову и запрещён. + return bytes(data[:length]) # Возвращаем только готовые wire-октеты. + + def frame(self, mode, slot, words=None, route=0): # Удобная обёртка для 200 регистров каждого mode PERIPH. + for value in (mode, slot, route): # Исключаем переполнение host ABI до вызова C. + self._unsigned(value, 0xFFFFFFFF) # Семантические пределы mode и local проверяет общий построитель. + can_id = self.lib.pcan_gas_slot_request_id(mode, slot, route) # C формирует MsgType=0x4 и HEX-страницу mode. + if can_id == 0: # Не создаём адрес для резерва страницы или неверного направления. + raise ValueError('Неверный mode, слот или направление') # Исходная ошибка не превращается в обращение к соседнему прибору. + payload = self._payload(words, route) # Данные одинаковы для обоих адресных API. + self.decode(can_id, payload) # Дополнительно проверяем маску двух действующих значений последнего слота PERIPH. + return can_id, payload # Транспорт получает готовые CAN ID и данные. + + def frame_address(self, device_type, device_id, address, words=None, route=0): # Полный слотный API для любого узла, включая STM Invertor. + for value in (device_type, device_id, address, route): # Python-числа не должны оборачиваться в C unsigned. + self._unsigned(value, 0xFFFFFFFF) # Конкретную ширину полей идентификатора проверяет C. + can_id = self.lib.pcan_gas_slot_id(device_type, device_id, address, route) # Общий построитель сохраняет все адреса 0…65535. + if can_id == 0: # Нулевой результат означает ошибку адреса узла или слота. + raise ValueError('Неверный адрес узла, слота или направление') # Не скрываем ошибку входа маскированием. + return can_id, self._payload(words, route) # Не привязываем общий формат к странице PERIPH. + + def _input(self, can_id, data, flags): # Проверяем размеры и представимость до создания ctypes-буферов. + self._unsigned(can_id, 0xFFFFFFFF) # C затем проверит фактические 29 бит CAN ID. + self._unsigned(flags, 0xFFFFFFFF) # Флаги IDE/RTR/ERR проверяются общим wire-кодеком. + payload = bytes(data) # Сохраняем точную длину без усечения. + if len(payload) > 8: # CAN FD не включается неявно. + raise ValueError('Classic CAN допускает до восьми октетов') # Лишние октеты остаются видимой ошибкой. + return (ctypes.c_uint8 * len(payload)).from_buffer_copy(payload), len(payload) # Нулевой запрос не требует фиктивных данных. + + def decode(self, can_id, data, flags=1): # Возвращаем mode, локальный слот и wire-слова PERIPH с маской. + raw, length = self._input(can_id, data, flags) # Получаем проверенный ограниченный буфер. + mode, slot, words = ctypes.c_uint(), ctypes.c_uint(), (ctypes.c_uint16 * 4)() # Отдельные выходы сохраняют ширину host ABI. + count = self.lib.pcan_gas_slot_decode(can_id, flags, raw, length, ctypes.byref(mode), ctypes.byref(slot), words) # C проверяет полный формат и геометрию PERIPH. + if count < 0: # Чужая страница или несуществующая позиция не становятся регистрами другого профиля. + raise ValueError('Неверный кадр GAS SLOT PERIPH') # Никакого автоматического перехода к типу 0x3. + return mode.value, slot.value, tuple(words[:count]) # Пустой кортеж означает запрос чтения. + + def decode_address(self, can_id, data, flags=1): # Декодируем маску и три значения любого адресуемого узла. + raw, length = self._input(can_id, data, flags) # Проверяем точную длину до native-вызова. + words = (ctypes.c_uint16 * 4)() # Четыре wire-слова включают служебную маску. + count = self.lib.pcan_gas_slot_decode_words(can_id, flags, raw, length, words) # Общий C-кодек проверяет тип 0x4 и все транспортные условия. + if count < 0: # Ошибка не выдаётся за допустимый пустой слот. + raise ValueError('Неверный кадр GAS SLOT') # Сообщение пригодно для CAN-журнала. + return tuple(words[:count]) # Адрес и класс узла уже доступны вызывающему коду в CAN ID. diff --git a/python/protocan/gas_watch.py b/python/protocan/gas_watch.py new file mode 100644 index 0000000..f6ba056 --- /dev/null +++ b/python/protocan/gas_watch.py @@ -0,0 +1,115 @@ +# Тонкий порт GAS_WATCH2: форматы запросов, подтверждений и выборок проверяет общее C-ядро. +# Python хранит неизменяемые модели и состояние подтверждённой подписки без второго кодека. + +from __future__ import annotations # Откладываем вычисление аннотаций для совместимости с Python 3.8. + +import ctypes # Передаём типизированные буферы единственной реализации протокола в общей библиотеке. +from dataclasses import dataclass # Неизменяемые модели фиксируют порядок адресов и значений одной конфигурации. + +MAX_SIGNALS = 64 # Общий контракт GAS_WATCH2 ограничивает подписку 64 регистрами по 16 бит. +MAX_PAYLOAD_BYTES = 512 # Верхняя граница payload GUI protocol v1 позволяет C выбрать фактическую длину запроса. + + +def _unsigned(value: int, maximum: int, name: str) -> None: # Проверяем представимость Python-числа перед сужением через ctypes. + if type(value) is not int or not 0 <= value <= maximum: # Исключаем bool, дроби и переполнение целевого беззнакового типа. + raise ValueError(f"{name}: требуется целое число от 0 до {maximum}") # Не допускаем незаметного усечения C-аргумента. + + +@dataclass(frozen=True) # Изменение списка после отправки не должно менять смысл ожидаемого подтверждения. +class GasWatchConfig: # Описываем подписку отдельно от её визуального оформления и истории графика. + config_id: int # Ненулевой 32-битный идентификатор связывает выборки с конкретным порядком адресов. + period_ms: int # Беззнаковый 16-битный период задаётся в миллисекундах; ноль используется для отключения. + addresses: tuple[int, ...] # Порядок 16-битных GAS-адресов совпадает с порядком значений в выборке. + + def __post_init__(self) -> None: # Нормализуем коллекцию и защищаем границу Python/C от сужения чисел. + _unsigned(self.config_id, 0xFFFFFFFF, "config_id") # Диапазон соответствует uint32_t в публичном C ABI. + if self.config_id == 0: # Нулевой идентификатор зарезервирован для состояния без установленной подписки. + raise ValueError("config_id должен быть ненулевым") # Не создаём модель, которая не может обозначать конфигурацию. + _unsigned(self.period_ms, 0xFFFF, "period_ms") # Диапазон соответствует uint16_t; логическое сочетание с адресами проверяет C. + addresses = tuple(self.addresses) # Отделяем модель от изменяемого списка, переданного вызывающим приложением. + if len(addresses) > MAX_SIGNALS: # Не передаём C массив сверх согласованного предела подписки. + raise ValueError("GAS_WATCH2 поддерживает не более 64 адресов") # Объясняем ограничение до выделения буфера ctypes. + for address in addresses: # Проверяем каждый элемент до записи в массив uint16_t. + _unsigned(address, 0xFFFF, "address") # GAS использует нулевые 16-битные индексы регистров, без расширенных адресов. + object.__setattr__(self, "addresses", addresses) # Устанавливаем неизменяемую копию внутри frozen dataclass только при создании. + + +@dataclass(frozen=True) # Полученная выборка остаётся стабильной при передаче между рабочим потоком и GUI. +class GasWatchSample: # Возвращаем проверенную модель, а не поля бинарного сообщения. + config_id: int # Идентификатор принадлежит уже подтверждённой конфигурации, проверенной C-декодером. + sequence: int # 32-битный номер выборки позволяет приложению обнаруживать пропуски доставки. + timestamp_ms: int # 32-битная метка устройства передаётся в миллисекундах без подмены временем GUI. + values: tuple[int | None, ...] # None обозначает ошибку источника и отличается от корректного нулевого значения. + + def __post_init__(self) -> None: # Не допускаем сохранения изменяемого списка в публичной frozen-модели. + _unsigned(self.config_id, 0xFFFFFFFF, "config_id") # Сохраняем представимость идентификатора в C uint32_t. + _unsigned(self.sequence, 0xFFFFFFFF, "sequence") # Переполнение счётчика обрабатывается устройством по модулю 2^32. + _unsigned(self.timestamp_ms, 0xFFFFFFFF, "timestamp_ms") # Ограничиваем метку диапазоном миллисекундного uint32_t. + values = tuple(self.values) # Копируем контейнер, чтобы внешний список не изменял уже принятую выборку. + if len(values) > MAX_SIGNALS: # Размер результата должен помещаться в общий предел числа каналов. + raise ValueError("GAS_WATCH2 поддерживает не более 64 значений") # Отвергаем публичную модель с недопустимой геометрией. + for value in values: # Проверяем только модель данных, не выполняя повторного разбора wire-пакета. + if value is not None: # Недоступный источник представляется None и не требует числового преобразования. + _unsigned(value, 0xFFFF, "value") # Достоверное значение регистра сохраняется как беззнаковое 16-битное слово. + object.__setattr__(self, "values", values) # Закрепляем независимый кортеж в неизменяемом экземпляре. + + +class NativeGasWatch: # Управляем ожидаемой и активной подписками поверх единственного C-кодека GAS_WATCH2. + def __init__(self, library: ctypes.CDLL) -> None: # Принимаем уже загруженную общую библиотеку без поиска или fallback. + self.lib = library # Сохраняем владельца C-функций на весь срок жизни адаптера. + try: # Проверяем наличие всей новой возможности до настройки сигнатур ABI. + self._request = library.set_gas_watch_request # C формирует запрос и проверяет допустимость полной конфигурации. + self._ack = library.set_gas_watch_ack # C сравнивает подтверждение со всем запрошенным списком адресов. + self._decode = library.set_gas_watch_decode # C проверяет версию, идентификатор, геометрию и маску достоверности. + except AttributeError as error: # Старая DLL может оставаться пригодной для других возможностей протокола. + raise RuntimeError("Пересоберите SETProtocol с set_gas_watch.c для поддержки GAS_WATCH2") from error # Явно сообщаем о необходимой сборке вместо Python-кодека. + self._request.argtypes = [ctypes.c_uint32, ctypes.c_uint16, ctypes.POINTER(ctypes.c_uint16), ctypes.c_size_t, ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t] # Передаём id, период, адреса и явные размеры входа/выхода по C ABI. + self._request.restype = ctypes.c_size_t # Ноль означает отказ C-валидатора, положительное значение — длину payload. + self._ack.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t, ctypes.c_uint32, ctypes.c_uint16, ctypes.POINTER(ctypes.c_uint16), ctypes.c_size_t] # Сопоставляем байты ACK с полным содержимым ожидаемой конфигурации. + self._ack.restype = ctypes.c_int # Ненулевой результат подтверждает точное принятие подписки устройством. + self._decode.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t, ctypes.c_uint32, ctypes.c_size_t, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint16), ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t] # C получает ожидаемую конфигурацию и отдельные буферы значений и достоверности. + self._decode.restype = ctypes.c_int # Отрицательный результат означает устаревшее либо повреждённое сообщение. + self.reset() # Новый экземпляр не принимает DATA до подтверждения своей первой подписки. + + def reset(self) -> None: # Сбрасываем состояние соединения при переподключении без отправки wire-команд. + self._pending: GasWatchConfig | None = None # Позднее подтверждение предыдущего соединения больше не ожидается. + self._active: GasWatchConfig | None = None # Ранее подтверждённые DATA нельзя привязать к новому соединению автоматически. + + def request(self, config: GasWatchConfig) -> bytes: # Подготавливаем запрос, оставляя старую активную подписку до нового ACK. + if not isinstance(config, GasWatchConfig): # Тонкий порт требует заранее нормализованную модель вместо произвольного объекта. + raise TypeError("Ожидается GasWatchConfig") # Не допускаем обхода проверок представимости аргументов ctypes. + for known in (self._active, self._pending): # Сравниваем идентификатор с ещё значимыми конфигурациями текущего соединения. + if known is not None and known.config_id == config.config_id and known != config: # Один id не может обозначать другой порядок адресов или период. + raise ValueError("Новая конфигурация требует нового config_id") # Иначе C не сможет отличить старые DATA с тем же id и количеством. + addresses = (ctypes.c_uint16 * len(config.addresses))(*config.addresses) # Передаём C непрерывный массив слов без собственного кодирования endian. + output = (ctypes.c_uint8 * MAX_PAYLOAD_BYTES)() # Резервируем транспортный предел; реальную длину определяет C-builder. + size = self._request(config.config_id, config.period_ms, addresses, len(addresses), output, len(output)) # Единственный C-валидатор проверяет дубликаты и сочетание периода с количеством. + if not size: # При ошибке запроса сохраняем предыдущие ожидаемую и активную подписки. + raise ValueError("Недопустимая конфигурация GAS_WATCH2") # Не публикуем частично сформированный payload. + self._pending = config # После успешной сборки ожидаем ACK именно последнего отправляемого запроса. + return bytes(output[:size]) # Копируем готовые байты C без разбора или пересборки полей в Python. + + def validate_ack(self, payload: bytes, config: GasWatchConfig) -> None: # Активируем подписку только после полного подтверждения её содержимого. + if self._pending is None or config != self._pending: # Поздний ACK предыдущего запроса не должен отменять более новую ожидаемую конфигурацию. + raise ValueError("Подтверждение не соответствует ожидаемой конфигурации GAS_WATCH2") # Сохраняем активную подписку при гонке ответов. + data = (ctypes.c_uint8 * len(payload)).from_buffer_copy(payload) # Предоставляем C входные байты без знания их внутреннего расположения. + addresses = (ctypes.c_uint16 * len(config.addresses))(*config.addresses) # Сохраняем исходный порядок для строгой проверки эха в C. + if not self._ack(data, len(data), config.config_id, config.period_ms, addresses, len(addresses)): # Требуем совпадения всей конфигурации, а не одного количества каналов. + raise ValueError("Устройство не подтвердило полную конфигурацию GAS_WATCH2") # Повреждённый или частичный ACK не изменяет состояния подписок. + self._active = config # Только подтверждённая конфигурация определяет допустимые DATA и порядок возвращаемых значений. + self._pending = None # Повторный либо поздний ACK больше не считается ответом на ожидаемую команду. + + def sample(self, payload: bytes) -> GasWatchSample: # Преобразуем проверенную C выборку в неизменяемую модель языка GUI. + config = self._active # Один вызов использует один согласованный снимок ссылки на подтверждённую конфигурацию. + if config is None: # До первого ACK и после reset принадлежность значений неизвестна. + raise RuntimeError("Сначала подтвердите конфигурацию GAS_WATCH2") # Не принимаем неподтверждённые или оставшиеся от прошлого соединения DATA. + data = (ctypes.c_uint8 * len(payload)).from_buffer_copy(payload) # Буфер ctypes передаёт готовый пакет C-декодеру без Python-парсинга. + sequence = ctypes.c_uint32() # C запишет номер выборки только после полной проверки пакета. + timestamp = ctypes.c_uint32() # C вернёт исходную миллисекундную метку устройства. + values = (ctypes.c_uint16 * MAX_SIGNALS)() # Буфер рассчитан на максимальные 64 регистра, согласованные с C-контрактом. + valid = (ctypes.c_uint8 * MAX_SIGNALS)() # C разворачивает wire-маску в отдельный признак достоверности каждого значения. + count = self._decode(data, len(data), config.config_id, len(config.addresses), ctypes.byref(sequence), ctypes.byref(timestamp), values, valid, MAX_SIGNALS) # Проверку id, длины и маски полностью выполняет общее ядро. + if count < 0: # Устаревшие и повреждённые DATA не меняют конфигурацию и не попадают на график. + raise ValueError("Устаревшие или повреждённые данные GAS_WATCH2") # Не возвращаем нулевые значения из неуспешного C-вызова. + words = tuple(values[index] if valid[index] else None for index in range(count)) # Преобразуем результат C в модель, сохраняя различие отсутствующего значения и нуля. + return GasWatchSample(config.config_id, sequence.value, timestamp.value, words) # Закрепляем идентификатор именно той конфигурации, которую подтвердил C-декодер. diff --git a/python/protocan/protocan.py b/python/protocan/protocan.py index 5a31d62..da3383e 100644 --- a/python/protocan/protocan.py +++ b/python/protocan/protocan.py @@ -46,7 +46,7 @@ class MsgType(IntEnum): DISCRETE = 0b0001 ANALOG = 0b0010 GENERAL_ADDRESS_SPACE = 0b0011 - MODBUS_COIL = 0b0100 + GAS_SLOT = 0b0100 # Тип 0x4 однозначно выбирает слотный GAS с маской вместо прежнего Modbus Coil. MODBUS_DISCRETE = 0b0101 MODBUS_HOLDING = 0b0110 MODBUS_INPUT = 0b0111 @@ -115,7 +115,7 @@ MSGTYPE_RU = { MsgType.DISCRETE: "Discrete", MsgType.ANALOG: "Analog", MsgType.GENERAL_ADDRESS_SPACE: "General Address Space", - MsgType.MODBUS_COIL: "Modbus Coil", + MsgType.GAS_SLOT: "GAS Slot", # Отдельное имя показывает, что адрес в Body относится к слоту, а не к Modbus-регистру. MsgType.MODBUS_DISCRETE: "Modbus Discrete", MsgType.MODBUS_HOLDING: "Modbus Holding", MsgType.MODBUS_INPUT: "Modbus Input", @@ -134,14 +134,26 @@ MSGTYPE_RU = { #: но не присваивает приборам имён. DEVICE_TYPE_NAMES = { 0x0: "Верхний уровень", + 0x1: "PERIPH 0–15", # Excel «Интерфейс протокола», C6/F6: первый тип содержит младшие 16 номеров периферии. + 0x2: "PERIPH 16–31", # Excel C7/F7: второй тип продолжает нумерацию, сохраняя четырёхбитный Device ID. 0x6: "Логические анализаторы", } DEVICE_ADDRESS_NAMES = { + (0x1, 0x5): "УМП1", # Excel B50/C50/F50 закрепляет отдельный адрес первого модуля нагрузки. + (0x1, 0x6): "УМП2", # Excel B51/C51/F51 отделяет второй модуль от первого и от задатчика. + (0x1, 0x8): "Задатчик", # Excel B53/C53/F53 задаёт адрес задатчика без сдвига старого CAN Mode на единицу. (0x6, 0xE): "Altera Logic", (0x7, 0xD): "configurator", + (0x7, 0xE): "STM Invertor", # Отдельный ПЧ STM32G474VET6: адрес 7/E проверен по портам Templates; 7/D и 7/F заняты. } + +def periph_address(periph_id: int) -> tuple[int, int]: # Возвращает адрес ProtoCAN для номера из 32 строк обновлённой таблицы PERIPH. + if not 0 <= periph_id < 32: # Число 32 задаёт полный диапазон двух типов по 16 экземпляров; за его пределами адрес не назначается. + raise ValueError("ID PERIPH должен быть в диапазоне 0…31") # Запрещает незаметное оборачивание ошибочного номера на другую плату. + return 1 + periph_id // 16, periph_id % 16 # Старшая группа выбирает Type 1/2, младшие четыре бита — Device ID 0…15. + SETTINGS_RESULT_RU = { SettingsResult.OK: "успех", SettingsResult.INVALID_DLC: "неверный DLC", @@ -408,9 +420,10 @@ def _ascii(data: bytes) -> str: return "".join(chr(b) if 32 <= b < 127 else "." for b in data) -def decode(raw_id: int, data: bytes, ide: bool = True, rtr: bool = False) -> Decoded: +def decode(raw_id: int, data: bytes, ide: bool = True, rtr: bool = False) -> Decoded: # Тип 0x3 всегда адресует регистры, тип 0x4 всегда адресует слоты; настройка профиля не требуется. """Разбирает кадр ProtoCAN в структуру Decoded.""" pid = ProtoCanId.parse(raw_id) + source_data = bytes(data) # Сохраняем фактическую длину кадра до отображения ограниченного classic CAN payload. data = bytes(data[:8]) res = Decoded(id=pid, dlc=len(data), data=data, ide=ide, rtr=rtr) @@ -431,12 +444,27 @@ def decode(raw_id: int, data: bytes, ide: bool = True, rtr: bool = False) -> Dec if rtr: res.warnings.append("Remote frame: полезная нагрузка отсутствует") + if pid.msg_type == MsgType.GAS_SLOT: # Слотный кодек вызывается только для своего типа 0x4, без угадывания по содержимому. + from .gas_slots import GasSlots # Тонкая модель вызывает единственный C-кодек формата и проверок. + try: # Ошибочный слот остаётся видимым в журнале, не превращаясь в регистровый кадр. + values = GasSlots().decode_address(raw_id, source_data, (1 if ide else 0) | (2 if rtr else 0)) # Общий C-кодек проверяет маску и точную длину слота любого узла, включая отдельный инвертор. + except ValueError as error: # Отказ протокола отображаем как ошибку кадра, а не подменяем legacy-декодированием. + res.summary = "GAS SLOT: неверный кадр" # Короткий текст подходит для строки CAN-лога. + res.warnings.append(str(error)) # Подробности доступны в панели выбранного сообщения. + return res # Отвергнутый слот не получает вымышленных адресов регистров. + res.fields.append(("GAS SLOT", "MsgType 0x4")) # Отдельный номер сообщения определяет формат без настройки профиля соединения. + if values: # Запрос чтения не содержит маски или значений. + res.fields.append(("Word0: маска", "0x%04X" % values[0])) # Нулевая позиция отображается как служебная маска, а не как регистр. + for index in range(1, 4): # Три значения имеют фиксированные позиции Word1…Word3 в восьмибайтовом кадре. + if values[0] & (1 << index): # Невыбранные значения не отображаются как записанные или достоверные измерения. + res.fields.append(("Слот 0x%04X, Word%d" % (pid.body, index), "0x%04X (%d)" % (values[index], values[index]))) # Полная координата сохраняет адрес слота и выбранную позицию. + res.summary = "GAS SLOT slot=0x%04X%s" % (pid.body, " mask=0x%04X" % values[0] if values else " (запрос)") # CAN-журнал явно показывает маску частичного изменения. + return res # Не передаём четыре слова старому обработчику адреса первого регистра. handler = { MsgType.BROADCAST: _decode_broadcast, MsgType.DISCRETE: _decode_discrete, MsgType.ANALOG: _decode_analog, MsgType.GENERAL_ADDRESS_SPACE: _decode_gas, - MsgType.MODBUS_COIL: _decode_modbus_bit, MsgType.MODBUS_DISCRETE: _decode_modbus_bit, MsgType.MODBUS_HOLDING: _decode_modbus_reg, MsgType.MODBUS_INPUT: _decode_modbus_reg, @@ -611,6 +639,12 @@ def _decode_gas(res: Decoded) -> None: res.fields.append((" Адрес первого регистра", "0x%04X (%d)" % (start, start))) if res.dlc % 2: res.warnings.append("DLC = %d нечётный: регистры GAS передаются парами байт" % res.dlc) + res.summary = "GAS: неверная длина данных" # Усечённое слово не должно становиться достоверным значением или уставкой в GUI. + return # Не публикуем частичный список регистров повреждённого кадра. + if start + res.dlc // 2 > 0x10000: # Адрес FFFF допустим для одного слова, следующий адрес уже выходит за 16-битное пространство. + res.warnings.append("Диапазон GAS выходит за адрес 0xFFFF") # Не создаём вымышленные адреса 0x10000 и выше. + res.summary = "GAS: неверный диапазон регистров" # Ошибка остаётся видимой в CAN-журнале. + return # Не передаём некорректные значения потребителям трендов или карты данных. vals = regs_le(res.data) if len(vals) > 4: res.warnings.append("В одном кадре GAS не более 4 регистров, получено %d" % len(vals)) @@ -631,7 +665,7 @@ def _decode_gas(res: Decoded) -> None: def _decode_modbus_bit(res: Decoded) -> None: str_adr, reg_count = split_modbus(res.id.body) - kind = "COIL" if res.id.msg_type == MsgType.MODBUS_COIL else "DISCRETE" + kind = "DISCRETE" # После назначения 0x4 слотному GAS битовым Modbus-сообщением остаётся только тип 0x5. res.fields.append((" Modbus.StrAdr", "0x%03X (%d)" % (str_adr, str_adr))) res.fields.append((" Modbus.RegCount", "%d" % reg_count)) expected = reg_count % 8 + 1 diff --git a/python/protocan/protocol.py b/python/protocan/protocol.py index 2b7ae73..c582de2 100644 --- a/python/protocan/protocol.py +++ b/python/protocan/protocol.py @@ -51,6 +51,8 @@ class MessageType(IntEnum): GAS_CATALOG = 0x11 GAS_WATCH_SET = 0x12 GAS_WATCH_DATA = 0x13 + GAS_WATCH2_SET = 0x14 # Новый тип подписки передаёт идентификатор и полный упорядоченный список GAS-регистров, сохраняя старый 0x12. + GAS_WATCH2_DATA = 0x15 # Новый тип выборки связывает значения с конфигурацией и признаками достоверности, сохраняя старый 0x13. SENSOR_SCAN = 0x20 SENSOR_LIST = 0x21 SENSOR_READ = 0x22 diff --git a/python/set_devices/qt_ports/can_frame_builder.py b/python/set_devices/qt_ports/can_frame_builder.py index 0e99116..008428b 100644 --- a/python/set_devices/qt_ports/can_frame_builder.py +++ b/python/set_devices/qt_ports/can_frame_builder.py @@ -128,10 +128,12 @@ class CanFrameFields(QWidget): # Компонент содержит тольк else: # Типы без отдельного подтипа используют Body по собственному назначению. sub_label = "—" # Подпись явно показывает отсутствие подтипа. arg_label = "Body (обычно 0)" # Для PULSE сохраняем исходное описание аргумента. - if msg_type in (pc.MsgType.MODBUS_COIL, pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # Все четыре вида Modbus задают начальный адрес. + if msg_type in (pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # Только сохранённые типы 0x5…0x7 используют Modbus-адрес и количество. arg_label = "StrAdr (0..4095)" # Двенадцатибитный адрес показан в прежних единицах регистров. elif msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE: # GAS использует всё поле Body под адрес. arg_label = "Адрес регистра (0..65535)" # Полный 16-битный диапазон указан в подписи. + elif msg_type == pc.MsgType.GAS_SLOT: # Новый тип 0x4 использует весь Body под номер слота, а не StrAdr/RegCount. + arg_label = "Адрес слота (0..65535), Data: маска + 3 слова" # Напоминаем оператору о Word0 с маской и фиксированных позициях трёх значений. elif msg_type == pc.MsgType.ERROR: # Код ошибки вводится в отдельный байт Body. arg_label = "ErrorCode (0..255)" # Показываем допустимый однобайтовый диапазон. elif settings: # SETTINGS редактируется двухбайтовым компонентом. @@ -146,7 +148,7 @@ class CanFrameFields(QWidget): # Компонент содержит тольк return pc.merge_discrete(pc.DiscreteType[self.sub.currentText()], arg) # Поле собирается общим протокольным модулем. if msg_type == pc.MsgType.ANALOG: # Аналоговое сообщение передаёт SensorID в Body. return pc.merge_analog(pc.AnalogType[self.sub.currentText()], arg) # Существующий кодек задаёт расположение подтипа и SensorID. - if msg_type in (pc.MsgType.MODBUS_COIL, pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # У четырёх видов Modbus одинаковый формат Body. + if msg_type in (pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # Формат Modbus применяется только к трём оставшимся типам 0x5…0x7. return pc.merge_modbus(arg, count) # Адрес и количество объединяются общей функцией протокола. if msg_type == pc.MsgType.ERROR: # Сохраняем существующую категорию ошибки с нулевым кодом источника. return pc.merge_error(0, arg) # Размещение кода ошибки остаётся ответственностью общего ядра. diff --git a/python/tests/test_gas_slots.py b/python/tests/test_gas_slots.py new file mode 100644 index 0000000..cf3aec3 --- /dev/null +++ b/python/tests/test_gas_slots.py @@ -0,0 +1,63 @@ +import json # Общие машинные эталоны независимы от клиентского построителя кадра. +from pathlib import Path # Находим спецификацию относительно репозитория. +import unittest # Проверяем реальные ctypes-привязки без заглушки протокольного ядра. +from protocan.gas_slots import GasSlots # Все правила wire-формата выполняет C, а не тестовая модель. +from protocan import protocan as pc # Проверяем штатный CAN-декодер, который вызывают GUI и журналы. + +class GasSlotTests(unittest.TestCase): # Интеграционные проверки обоих типов GAS и границ адресного API. + def setUp(self): # Каждая проверка использует настоящую собранную shared-библиотеку. + self.codec = GasSlots() # Отсутствующая библиотека не заменяется Python fallback. + + def test_vectors(self): # Проверяем ID, маску и три значения по нормативным независимым байтам. + path = Path(__file__).resolve().parents[2] / 'doc/setcan/protocan/examples/gas-slot-vectors.json' # Те же примеры опубликованы в документации. + vectors = json.loads(path.read_text(encoding='utf-8')) # UTF-8 сохраняет названия и описание профиля. + for item in vectors['vectors']: # Охватываем обе группы адресов и неполный последний слот PERIPH. + words = item.get('words', vectors['words']) # Последний слот имеет только два действующих значения. + expected = item.get('payload_hex', vectors['payload_hex']) # Его отдельный эталон не включает несуществующее третье значение. + can_id, data = self.codec.frame(item['mode'], item['local_slot']) # Пустой запрос не несёт служебной маски. + self.assertEqual((can_id, data), (int(item['request_id'], 16), b'')) # Тип 0x4 и адрес должны совпасть с фиксированным эталоном. + reply, payload = self.codec.frame(item['mode'], item['local_slot'], words, route=1) # Ответ явно содержит маску достоверности. + self.assertEqual(reply, int(item['response_id'], 16)) # Направление не меняет узел или слот. + self.assertEqual(payload.hex().upper(), expected) # Проверяем все восемь октетов, включая расположение Word0. + self.assertEqual(self.codec.decode(reply, payload), (item['mode'], item['local_slot'], tuple(words))) # Полный round-trip сохраняет маску отдельно от трёх значений. + + def test_invalid(self): # Неверные координаты, маски и длины не должны стать другой командой. + for mode, slot in ((32, 0), (5, 67), (-1, 0), (2**32, 0)): # Верхняя граница страницы после маски — LocalSlot 66. + with self.assertRaises(ValueError): self.codec.frame(mode, slot) # Ошибка не маскируется до допустимого адреса. + for payload in (b'\0', b'\0' * 6, b'\0' * 9, b'\0' * 8): # В том числе запрещена полная запись с пустой маской. + with self.assertRaises(ValueError): self.codec.decode(0x19540500, payload) # Точный размер и Word0 проверяет C. + for mask in (0, 1, 0x10, 0xFFFF): # Бит 0 и старшие биты не адресуют данные слота. + with self.assertRaises(ValueError): self.codec.frame(5, 0, [mask, 1, 2, 3]) # Не заменяем отвергнутую маску полной записью. + with self.assertRaises(ValueError): self.codec.frame(5, 66, [14, 1, 2, 3]) # Третье значение неполного слота не существует. + with self.assertRaises(ValueError): self.codec.frame(5, 0, [2, 65536, 0, 0]) # Переполнение u16 не превращается в допустимый ноль. + can_id, payload = self.codec.frame(5, 0, [4, 0, 0x1234, 0], route=1) # Корректный частичный ответ для проверки транспортных флагов. + with self.assertRaises(ValueError): self.codec.decode(can_id, payload, flags=3) # RTR отвергается до обращения к provider. + + def test_types_are_unambiguous(self): # Один и тот же payload получает разный смысл только по номеру типа. + can_id, payload = self.codec.frame(5, 0, [4, 0, 0x1234, 0], route=1) # Word2 выбран, Word1/Word3 передаются в фиксированных позициях и игнорируются. + slot = pc.decode(can_id, payload) # Никакого параметра gas_profile для типа 0x4 больше нет. + self.assertIn('slot=0x0500', slot.summary) # Адрес показывается в единицах слота. + self.assertIn('mask=0x0004', slot.summary) # В CAN-журнале видна частичная запись. + self.assertIsNone(slot.registers) # Старые потребители не получают фиктивный последовательный список регистров. + self.assertTrue(any('Word2' in name for name, value in slot.fields)) # Только выбранная позиция отображается как достоверное значение. + self.assertFalse(any('Word1' in name or 'Word3' in name for name, value in slot.fields)) # Неотмеченные поля не публикуются как измерения. + register = pc.decode(0x19530500, payload) # Тип 0x3 всегда интерпретируется как обычные последовательные слова. + self.assertEqual(register.registers, [(0x0500, 4), (0x0501, 0), (0x0502, 0x1234), (0x0503, 0)]) # Нулевое слово payload не является маской регистрового GAS. + self.assertTrue(pc.decode(can_id, payload + b'\0').warnings) # Девятый октет не теряется до проверки слотного формата. + overflow = pc.decode(0x1953FFFF, b'\x01\x00\x02\x00') # По максимальному адресу нельзя разместить два последовательных регистра. + self.assertTrue(overflow.warnings) # Ошибка диапазона должна быть видна в журнале. + self.assertIsNone(overflow.registers) # Некорректный адрес 0x10000 не становится источником тренда. + + def test_generic_address_and_analyzer(self): # Тип 0x4 должен работать также за пределами PERIPH и его HEX-страниц. + can_id, payload = self.codec.frame_address(7, 14, 0xFFFF, [2, 0x5678, 0xDEAD, 0], route=1) # Неотмеченное значение сохраняется как обычный заполнитель и не является командой записи. + self.assertEqual(can_id, 0x1FE4FFFF) # Полный адрес FFFF принадлежит отдельному инвертору 7/E. + self.assertEqual(self.codec.decode_address(can_id, payload), (2, 0x5678, 0xDEAD, 0)) # Общий декодер проверяет маску, не навязывая страницу mode. + self.assertIn('slot=0xFFFF', pc.decode(can_id, payload).summary) # Штатный GUI-декодер использует общий адресный API. + with self.assertRaises(ValueError): self.codec.frame_address(7, 14, 0x10000) # Не допускаем оборачивания в слот ноль. + from logic_analyzer.decoders.set_can import legacy # Проверяем тот же публичный путь анализа аппаратного захвата. + decoded = legacy(can_id, payload) # Анализатор вызывает общий C-кодек слотного формата. + self.assertEqual(decoded['slot_words'], [(1, 0x5678)]) # Служебная маска и невыбранные слова не становятся данными анализатора. + self.assertNotIn('registers', decoded) # Не смешиваем координаты слота с плоским регистровым адресом. + +if __name__ == '__main__': # Поддерживаем прямой запуск без pytest. + unittest.main() # Любой отказ native-кодека отражается стандартным статусом тестов. diff --git a/python/tests/test_gas_watch.py b/python/tests/test_gas_watch.py new file mode 100644 index 0000000..4b5460a --- /dev/null +++ b/python/tests/test_gas_watch.py @@ -0,0 +1,169 @@ +# Проверяем неизменяемые модели и настоящий C ABI GAS_WATCH2 на общих эталонных байтах. +# Python не подменяет C-кодек: проверки wire-пакетов выполняются только с указанной SETPROTOCOL_LIBRARY. + +import ctypes # Загружаем настоящую общую библиотеку для проверки границы Python/C. +import json # Читаем общий JSON-fixture, используемый также C- и JVM-проверками. +import os # Путь к проверяемой сборке получает тестовый процесс через SETPROTOCOL_LIBRARY. +import unittest # Запускаем воспроизводимые проверки модели, подписок и ошибочных данных. +from dataclasses import FrozenInstanceError # Проверяем запрет изменения уже созданных моделей. +from pathlib import Path # Находим эталон относительно исходников независимо от текущего каталога. + +from protocan.gas_watch import GasWatchConfig, GasWatchSample, NativeGasWatch # Проверяем публичный тонкий порт без доступа к другому Python-кодеку. +from protocan.protocol import MessageType # Проверяем выделение новых типов сообщений без изменения старых значений. + +FIXTURE_PATH = Path(__file__).resolve().parents[2] / "c/set-protocol/tests/fixtures/gas-watch-v2.json" # Общие байты находятся рядом с C-тестами как единый контракт портов. + + +class GasWatchModelTests(unittest.TestCase): # Эти проверки не требуют DLL, поскольку относятся к представлению моделей Python. + def test_models_copy_sequences_and_are_frozen(self): # Изменение исходных списков не должно менять ожидаемый ACK и принятую выборку. + addresses = [0, 1, 0xFF01] # Повторяем три разрозненных адреса из пользовательского примера. + config = GasWatchConfig(1, 100, addresses) # Переданный список должен быть независимо сохранён как кортеж. + addresses[0] = 99 # Моделируем последующее редактирование таблицы сигналов GUI. + self.assertEqual((0, 1, 0xFF01), config.addresses) # Проверяем сохранение исходного порядка подписки. + with self.assertRaises(FrozenInstanceError): # Идентификатор уже сформированной модели нельзя менять на месте. + config.config_id = 2 # Присваивание проверяет защиту frozen dataclass, а не изменение состояния устройства. + values = [0, None, 65535] # Корректный ноль и недостоверное значение должны оставаться различимыми. + sample = GasWatchSample(1, 2, 3, values) # Публичная модель также должна копировать изменяемый контейнер. + values[0] = 5 # Моделируем повторное использование входного списка вызывающим приложением. + self.assertEqual((0, None, 65535), sample.values) # Ранее созданная выборка не должна изменяться вслед за списком. + with self.assertRaises(FrozenInstanceError): # Метка времени проверенной выборки остаётся неизменяемой. + sample.timestamp_ms = 4 # Присваивание должно быть отклонено механизмом dataclass. + + def test_integer_ranges_prevent_ctypes_narrowing(self): # Python обязан отвергать значения, которые ctypes незаметно усекло бы до C-типа. + for config_id in (0, -1, 0x100000000, True, 1.5): # Проверяем нулевой, отрицательный, переполненный и нецелые идентификаторы. + with self.subTest(config_id=config_id), self.assertRaises(ValueError): # Каждый ошибочный id должен отказать до вызова C. + GasWatchConfig(config_id, 100, (0,)) # Остальные поля допустимы и не маскируют проверяемую ошибку. + for period in (-1, 65536, True, 1.5): # Период представляет uint16_t в миллисекундах без преобразования bool и float. + with self.subTest(period=period), self.assertRaises(ValueError): # Проверяем все источники возможного сужения периода. + GasWatchConfig(1, period, (0,)) # Валидный идентификатор и адрес изолируют неверный период. + for address in (-1, 65536, True, 1.5): # GAS-регистр задаётся uint16_t, а не произвольным Python-числом. + with self.subTest(address=address), self.assertRaises(ValueError): # Любой недопустимый элемент массива должен отказать. + GasWatchConfig(1, 100, (address,)) # Один адрес позволяет проверить границу независимо от числа каналов. + with self.assertRaises(ValueError): # Подписка не должна превышать общий предел 64 каналов. + GasWatchConfig(1, 100, tuple(range(65))) # 65 уникальных допустимых адресов изолируют ограничение размера. + with self.assertRaises(ValueError): # Значения публичной модели также не должны выходить за 16 бит. + GasWatchSample(1, 2, 3, (65536,)) # Отдельная ошибочная величина проверяет защиту модели результата. + + def test_old_library_has_explicit_rebuild_error(self): # Устаревшая библиотека должна дать понятную ошибку без Python fallback. + with self.assertRaisesRegex(RuntimeError, "set_gas_watch.c"): # Сообщение должно назвать недостающую реализацию для пересборки. + NativeGasWatch(object()) # Объект без новых ABI-символов воспроизводит отсутствие функции в старой DLL. + + def test_message_types_preserve_legacy_values(self): # Новые wire-типы не должны переопределять существующий GAS_WATCH. + self.assertEqual((0x12, 0x13), (MessageType.GAS_WATCH_SET, MessageType.GAS_WATCH_DATA)) # Сохраняем совместимость старого профиля v1. + self.assertEqual((0x14, 0x15), (MessageType.GAS_WATCH2_SET, MessageType.GAS_WATCH2_DATA)) # Выделенные типы однозначно выбирают новый формат. + + +@unittest.skipUnless(os.environ.get("SETPROTOCOL_LIBRARY"), "Укажите SETPROTOCOL_LIBRARY для проверки настоящего C-ядра") # Без явного пути не подменяем C тестовым Python-кодеком. +class NativeGasWatchTests(unittest.TestCase): # Проверяем реальные builder, ACK-валидатор и DATA-декодер общей библиотеки. + @classmethod # Одну DLL и общий fixture безопасно переиспользуют отдельные экземпляры адаптера каждого теста. + def setUpClass(cls): # Загружаем внешний контракт один раз до тестов C ABI. + cls.library = ctypes.CDLL(os.environ["SETPROTOCOL_LIBRARY"]) # Указанный путь должен вести к сборке с set_gas_watch.c. + cls.fixture = json.loads(FIXTURE_PATH.read_text(encoding="utf-8")) # Эталонные данные читаются в обязательной кодировке UTF-8. + cls.request_bytes = bytes.fromhex(cls.fixture["request_hex"]) # Фиксированные байты отделяют ожидаемый wire-вектор от реализации C. + cls.sample_bytes = bytes.fromhex(cls.fixture["sample_hex"]) # DATA проверяется теми же байтами, что и другие языковые порты. + + def setUp(self): # Изолируем pending и active между независимыми сценариями. + self.core = NativeGasWatch(self.library) # Каждый тест начинает с отсутствующей подтверждённой конфигурацией. + self.config = GasWatchConfig(self.fixture["config_id"], self.fixture["period_ms"], self.fixture["addresses"]) # Сохраняем порядок общих трёх адресов. + + def activate(self): # Повторяем нормальный цикл отправки конфигурации и её точного подтверждения. + payload = self.core.request(self.config) # Запрос формирует настоящий C-builder. + self.core.validate_ack(payload, self.config) # Полное эхо устройства проверяет настоящий C ACK-валидатор. + + def test_shared_fixture_request_ack_and_sample(self): # Основной сценарий фиксирует совместимость байтов и семантику признаков достоверности. + self.assertEqual(self.request_bytes, self.core.request(self.config)) # Сопоставляем результат C-builder с общим независимым эталоном. + with self.assertRaises(RuntimeError): # DATA до ACK не имеет подтверждённого соответствия каналам. + self.core.sample(self.sample_bytes) # Даже корректный пакет должен быть отвергнут до активации конфигурации. + self.core.validate_ack(self.request_bytes, self.config) # Активируем подписку только по полному точному эху. + sample = self.core.sample(self.sample_bytes) # C проверяет config_id, количество, длину, padding и значения invalid-каналов. + expected_values = tuple(value if valid else None for value, valid in zip(self.fixture["values"], self.fixture["valid"])) # Преобразуем семантику fixture, не декодируя wire-пакет. + self.assertEqual(GasWatchSample(self.config.config_id, self.fixture["sequence"], self.fixture["timestamp_ms"], expected_values), sample) # Сверяем всю неизменяемую модель результата. + zero_sample = bytes.fromhex("0200030078563412040302014433221105000000003412") # Фиксированный вектор содержит достоверный ноль, invalid-ноль и слово 0x1234. + self.assertEqual((0, None, 0x1234), self.core.sample(zero_sample).values) # Недостоверное значение не должно превращаться в отображаемый ноль. + + def test_native_request_rejects_duplicates_and_inconsistent_stop(self): # Логические ограничения протокола должны проверяться C, а не вторым валидатором Python. + self.activate() # Действующая подписка нужна для проверки сохранения состояния при отказе builder. + invalid = (GasWatchConfig(2, 100, (0, 0)), GasWatchConfig(2, 0, (0,)), GasWatchConfig(2, 100, ())) # Проверяем дубликаты и оба несовместимых сочетания периода с количеством. + for config in invalid: # Каждая ошибочная конфигурация должна быть отвергнута независимо от предыдущей попытки. + with self.subTest(config=config), self.assertRaises(ValueError): # Отказ C-builder преобразуется в явную ошибку Python. + self.core.request(config) # Никакой неправильный запрос не должен менять активную подписку. + self.assertEqual(self.config.config_id, self.core.sample(self.sample_bytes).config_id) # После отказа прежние подтверждённые DATA продолжают приниматься. + stop = GasWatchConfig(self.config.config_id + 1, 0, ()) # Пустой список с нулевым периодом представляет правильную команду отключения. + self.assertEqual(bytes.fromhex("020000007956341200000000"), self.core.request(stop)) # C-builder должен поддерживать отдельный идентификатор остановки. + self.core.validate_ack(bytes.fromhex("020000007956341200000000"), stop) # Полный ACK пустой конфигурации также должен проходить C-проверку. + + def test_ack_checks_full_configuration_and_preserves_active(self): # Равного количества каналов недостаточно для принятия подтверждения. + self.activate() # Создаём активную подписку, которая должна пережить ошибочный ACK следующей команды. + changed = GasWatchConfig(self.config.config_id + 1, 200, (0xFF01, 1, 0)) # Новый порядок того же числа адресов получает новый идентификатор. + changed_request = self.core.request(changed) # Pending меняется, а действующий профиль остаётся активным до ACK. + self.assertEqual(self.config.config_id, self.core.sample(self.sample_bytes).config_id) # Старые DATA разрешены, пока устройство не подтвердило переключение. + for supplied in (self.config, changed): # Отдельно проверяем поздний ACK и пакет, не соответствующий новой конфигурации. + with self.subTest(supplied=supplied), self.assertRaises(ValueError): # Ни один вариант не должен активировать неподтверждённую подписку. + self.core.validate_ack(self.request_bytes, supplied) # Вариант old отвергает pending-проверка, вариант new — C-сравнение эха. + altered = bytearray(changed_request) # Моделируем ACK с тем же id, периодом и count, но другим порядком адресов. + altered[-2:] = b"\x02\x00" # Меняем один адрес в конце вектора, не затрагивая геометрию ответа. + with self.assertRaises(ValueError): # Полное сравнение адресов должно обнаружить подмену при прежнем количестве каналов. + self.core.validate_ack(bytes(altered), changed) # C проверяет весь список и не разрешает частичную подписку. + self.core.validate_ack(changed_request, changed) # Корректное полное эхо атомарно переводит pending в active. + with self.assertRaises(ValueError): # Пакет прежнего id после успешного переключения становится устаревшим. + self.core.sample(self.sample_bytes) # Количество осталось тем же, поэтому проверка должна опираться на идентификатор. + new_sample = bytes.fromhex("0200030079563412fffffffff0ffffff037b00feff0000") # Фиксированный DATA-вектор относится к новому config_id 0x12345679. + self.assertEqual(changed.config_id, self.core.sample(new_sample).config_id) # Новый подтверждённый id разрешает данные именно новой конфигурации. + + def test_malformed_ack_and_sample_do_not_poison_subscription(self): # Ошибки отдельных пакетов не должны разрушать рабочую подписку. + self.core.request(self.config) # Pending необходим для проверки точного формата первого подтверждения. + for payload in (self.request_bytes[:-1], self.request_bytes + b"\x00"): # Отсечённые и дополненные ACK имеют неправильную длину. + with self.subTest(ack=payload), self.assertRaises(ValueError): # C должен отвергнуть и неполное, и нестрогое эхо. + self.core.validate_ack(payload, self.config) # Pending сохраняется, позволяя принять следующий корректный ACK. + self.core.validate_ack(self.request_bytes, self.config) # Корректное подтверждение после ошибок всё ещё активирует исходную подписку. + malformed = ( # Список фиксированных искажений покрывает геометрию, достоверность и привязку к конфигурации. + self.sample_bytes[:-1], # Отбрасываем последнее слово частично: общая длина больше не соответствует count. + self.sample_bytes + b"\x00", # Лишний байт также нарушает точную геометрию пакета. + bytes.fromhex("0100030078563412fffffffff0ffffff037b00feff0000"), # Версия 1 не должна интерпретироваться как новый формат версии 2. + bytes.fromhex("0200030079563412fffffffff0ffffff037b00feff0000"), # Другой id с прежним count моделирует поздние DATA другой подписки. + bytes.fromhex("0200020078563412fffffffff0ffffff037b00feff"), # Корректная геометрия двух значений не совпадает с тремя ожидаемыми адресами. + bytes.fromhex("0200030078563412fffffffff0ffffff837b00feff0000"), # Старший padding-бит bitmap для трёх каналов обязан быть нулём. + bytes.fromhex("0200030078563412fffffffff0ffffff037b00feff0100"), # Значение invalid-канала обязано быть нулём, иначе данные неоднозначны. + ) # Закрываем перечень независимых отрицательных векторов C-декодера. + for payload in malformed: # Проверяем каждый отказ с тем же неизменным состоянием подписки. + with self.subTest(data=payload), self.assertRaises(ValueError): # Ни один некорректный пакет не должен превращаться в модель. + self.core.sample(payload) # Все проверки структуры пакета выполняются общим C-декодером. + self.assertEqual(self.config.config_id, self.core.sample(self.sample_bytes).config_id) # Следующий корректный пакет доказывает сохранение active после ошибки. + + def test_failed_decode_keeps_all_c_outputs_unchanged(self): # Проверяем обещание ABI не публиковать частичные результаты при ошибке пакета. + data = (ctypes.c_uint8 * len(self.sample_bytes)).from_buffer_copy(self.sample_bytes) # Передаём эталонные байты, изменяя только ожидаемый id C-вызова. + sequence = ctypes.c_uint32(11) # Отличимый sentinel обнаруживает запись счётчика до окончания проверки. + timestamp = ctypes.c_uint32(22) # Независимый sentinel защищает проверку метки времени. + values = (ctypes.c_uint16 * 3)(31, 32, 33) # Отличимые слова обнаруживают частичное заполнение выходного массива. + valid = (ctypes.c_uint8 * 3)(41, 42, 43) # Признаки также не должны перезаписываться при устаревшем id. + result = self.core.lib.set_gas_watch_decode(data, len(data), self.config.config_id + 1, 3, ctypes.byref(sequence), ctypes.byref(timestamp), values, valid, 3) # Проверяем настоящий C ABI без обёртки создания модели. + self.assertEqual(-1, result) # Несовпадающий expected_config_id обязан отвергнуть даже корректно сформированный пакет. + self.assertEqual((11, 22, (31, 32, 33), (41, 42, 43)), (sequence.value, timestamp.value, tuple(values), tuple(valid))) # Каждый выход должен сохранить исходный sentinel. + + def test_pending_replacement_id_reuse_and_reset(self): # Проверяем гонки нескольких запросов и очистку состояния при переподключении. + self.activate() # Ранее подтверждённая конфигурация задаёт исходный active. + changed = GasWatchConfig(self.config.config_id + 1, 100, (1, 0, 0xFF01)) # Первый новый порядок начинает ожидать подтверждение. + self.core.request(changed) # Старый active остаётся доступным, пока новый pending не подтверждён. + newest = GasWatchConfig(self.config.config_id + 2, 100, (0xFF01, 0, 1)) # Следующая команда заменяет ожидаемый список ещё до первого ACK. + newest_request = self.core.request(newest) # Актуальным pending становится только последний запрос. + with self.assertRaises(ValueError): # ACK уже заменённого pending не должен возвращать старое ожидание. + self.core.validate_ack(self.request_bytes, changed) # Проверка pending срабатывает до анализа неподходящего payload. + for reused in (GasWatchConfig(self.config.config_id, 200, self.config.addresses), GasWatchConfig(newest.config_id, 200, newest.addresses)): # Active и pending id нельзя переиспользовать с другим содержимым. + with self.subTest(reused=reused), self.assertRaises(ValueError): # Такая подмена лишила бы DATA возможности определить порядок значений. + self.core.request(reused) # Ошибка не должна уничтожать последний ожидаемый запрос. + self.core.validate_ack(newest_request, newest) # Последний корректный pending всё ещё подтверждается после отвергнутых попыток. + self.core.reset() # Переподключение удаляет как ожидаемую, так и подтверждённую подписку. + with self.assertRaises(RuntimeError): # Старая выборка после reset требует нового цикла подтверждения. + self.core.sample(self.sample_bytes) # Данные прошлого соединения не должны отображаться автоматически. + with self.assertRaises(ValueError): # Ни один ACK прошлого соединения больше не ожидается. + self.core.validate_ack(newest_request, newest) # Reset запрещает позднее восстановление прежнего active. + + def test_maximum_subscription_uses_real_c_builder(self): # Проверяем безопасную передачу полного массива из 64 каналов через ctypes. + config = GasWatchConfig(0xFFFFFFFF, 65535, tuple(range(64))) # Используем максимальные id и период при допустимом числе уникальных адресов. + payload = self.core.request(config) # Размер payload определяет настоящий C-builder в общем транспортном буфере. + self.assertEqual(140, len(payload)) # Версия 2 задаёт 12 байт заголовка и 64 двухбайтных адреса, всего 140 байт. + self.core.validate_ack(payload, config) # Полное эхо максимального массива проверяется без усечения и частичного принятия. + + +if __name__ == "__main__": # Разрешаем запуск этого набора проверок напрямую наряду с unittest discovery. + unittest.main() # Стандартный runner сообщает результаты, ошибки DLL и пропущенные C-проверки. From c6390ae1c9c0b847b2cfa189b8406d337f2072ae Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Oct 2026 14:16:19 +0300 Subject: [PATCH 09/18] =?UTF-8?q?feat(protocan-boot):=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D1=8C=20=D0=BF=D0=BE=D1=80=D1=82=D1=8B=20MCU=20?= =?UTF-8?q?=D0=B8=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D1=8B=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Обеспечь единый процесс обновления для STM32F103/F407/G474 и TMS320F2812/F28335: discovery, служебные ответы, BUSY, тайм-аут сессии и подтверждение приложения. Добавь самостоятельные проекты CCS, аппаратные хранилища и Python-клиент. Совместимость: структуры конфигурации и порта расширены, поэтому потребители должны пересобраться и обнулить новые поля. Для C28x callbacks используют pcan_boot_byte_t; периодический pcan_boot_poll обслуживает discovery и настроенный тайм-аут. --- c/protocan-boot/.gitignore | 8 + c/protocan-boot/CMakeLists.txt | 58 +- c/protocan-boot/README.md | 54 +- c/protocan-boot/docs/BOOTLOADER.md | 20 +- c/protocan-boot/include/pcan_boot.h | 85 +- c/protocan-boot/ports/stm32-common/README.md | 109 + .../ports/stm32-common/boot_native.inc | 127 + .../ports/stm32-common/pcan_boot_stm32.h | 10 + .../ports/stm32-common/pcan_boot_stm32.inc | 167 + c/protocan-boot/ports/stm32f103/README.md | 50 + c/protocan-boot/ports/stm32f103/boot_main.c | 95 + .../ports/stm32f103/boot_profile.h | 17 + .../ports/stm32f103/boot_request.c | 12 + .../ports/stm32f103/pcan_boot_stm32f103.c | 22 + .../ports/stm32f103/pcan_boot_stm32f103.h | 11 + c/protocan-boot/ports/stm32f407/README.md | 51 + .../ports/stm32f407/boot_control_hal.c | 29 + .../ports/stm32f407/boot_control_hal.h | 7 + c/protocan-boot/ports/stm32f407/boot_main.c | 68 + .../ports/stm32f407/boot_profile.h | 8 + .../ports/stm32f407/pcan_boot_stm32f407.c | 28 + .../ports/stm32f407/pcan_boot_stm32f407.h | 11 + .../ports/stm32g474/LICENSE.source.md | 34 + c/protocan-boot/ports/stm32g474/README.md | 63 + .../ports/stm32g474/boot_control.c | 48 + c/protocan-boot/ports/stm32g474/boot_main.c | 66 + .../ports/stm32g474/boot_profile.h | 17 + .../ports/stm32g474/boot_startup.c | 30 + .../ports/stm32g474/pcan_boot_stm32g474.c | 104 + .../ports/stm32g474/pcan_boot_stm32g474.h | 12 + c/protocan-boot/ports/tms320f2812/README.md | 15 + c/protocan-boot/ports/tms320f2812/boot2812.h | 24 + .../ports/tms320f2812/boot_store.c | 105 + c/protocan-boot/ports/tms320f2812/nor_flash.c | 69 + c/protocan-boot/ports/tms320f28335/README.md | 207 + .../ports/tms320f28335/f28335_boot_hw.c | 181 + .../ports/tms320f28335/f28335_boot_platform.h | 18 + .../ports/tms320f28335/f28335_boot_store.c | 254 + .../ports/tms320f28335/f28335_boot_store.h | 55 + .../tms320f28335/f28335_can_application.c | 10 + .../ports/tms320f28335/f28335_can_boot.c | 284 + .../ports/tms320f28335/f28335_can_boot.h | 28 + .../ports/tms320f28335/f28335_flash_app.c | 26 + .../ports/tms320f28335/f28335_flash_app.h | 11 + c/protocan-boot/projects/.gitignore | 4 + c/protocan-boot/projects/README.md | 207 + c/protocan-boot/projects/STM32.md | 69 + c/protocan-boot/projects/build.py | 132 + .../projects/ccs/f2812/.ccsproject | 20 + c/protocan-boot/projects/ccs/f2812/.cproject | 306 + c/protocan-boot/projects/ccs/f2812/.project | 106 + .../projects/ccs/f2812/F2812_CAN_NOR.cmd | 28 + c/protocan-boot/projects/ccs/f2812/board.c | 30 + .../projects/ccs/f2812/boot_store.c | 1 + .../projects/ccs/f2812/codestart.asm | 12 + c/protocan-boot/projects/ccs/f2812/main.c | 114 + .../projects/ccs/f2812/nor_flash.c | 1 + .../projects/ccs/f2812/shared_boot.c | 1 + .../ccs/f2812/targetConfigs/TMS320F2812.ccxml | 12 + .../projects/ccs/f28335/.ccsproject | 20 + c/protocan-boot/projects/ccs/f28335/.cproject | 318 + c/protocan-boot/projects/ccs/f28335/.project | 115 + .../projects/ccs/f28335/F28335_CAN_AB.cmd | 30 + .../projects/ccs/f28335/codestart.asm | 12 + c/protocan-boot/projects/ccs/f28335/main.c | 127 + .../projects/ccs/f28335/shared_boot.c | 5 + .../f28335/targetConfigs/TMS320F28335.ccxml | 54 + c/protocan-boot/src/pcan_boot.c | 234 +- .../tests/f28335_stubs/DSP2833x_Device.h | 13 + c/protocan-boot/tests/f28335_stubs/spise2p.h | 7 + c/protocan-boot/tests/run_tests.py | 32 + .../tests/stm32_stubs/stm32_hal_fake.h | 50 + .../tests/stm32_stubs/stm32f1xx_hal.h | 1 + .../tests/stm32_stubs/stm32f4xx_hal.h | 1 + .../tests/stm32_stubs/stm32g4xx_hal.h | 54 + c/protocan-boot/tests/test_f2812_nor.c | 83 + .../tests/test_f28335_boot_store.c | 118 + c/protocan-boot/tests/test_f28335_can_boot.c | 124 + c/protocan-boot/tests/test_pcan_boot.c | 35 +- c/protocan-boot/tests/test_pcan_busy.c | 22 + c/protocan-boot/tests/test_project_release.py | 66 + c/protocan-boot/tests/test_stm32_ports.c | 259 + c/protocan-boot/vendor/ti/README.md | 20 + .../ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd | 102 + .../f2812/common/include/DSP281x_DefaultIsr.h | 123 + .../f2812/common/include/DSP281x_Examples.h | 88 + .../common/include/DSP281x_GlobalPrototypes.h | 87 + .../include/DSP281x_SWPrioritizedIsrLevels.h | 5881 +++++++++ .../vendor/ti/f2812/include/DSP281x_Adc.h | 224 + .../ti/f2812/include/DSP281x_CpuTimers.h | 184 + .../ti/f2812/include/DSP281x_DefaultIsr.h | 123 + .../vendor/ti/f2812/include/DSP281x_DevEmu.h | 103 + .../vendor/ti/f2812/include/DSP281x_Device.h | 144 + .../vendor/ti/f2812/include/DSP281x_ECan.h | 1163 ++ .../vendor/ti/f2812/include/DSP281x_Ev.h | 654 + .../vendor/ti/f2812/include/DSP281x_Gpio.h | 1034 ++ .../vendor/ti/f2812/include/DSP281x_Mcbsp.h | 777 ++ .../vendor/ti/f2812/include/DSP281x_PieCtrl.h | 153 + .../vendor/ti/f2812/include/DSP281x_PieVect.h | 210 + .../vendor/ti/f2812/include/DSP281x_Sci.h | 233 + .../vendor/ti/f2812/include/DSP281x_Spi.h | 183 + .../vendor/ti/f2812/include/DSP281x_SysCtrl.h | 325 + .../ti/f2812/include/DSP281x_XIntrupt.h | 78 + .../vendor/ti/f2812/include/DSP281x_Xintf.h | 111 + .../ti/f2812/source/DSP281x_CpuTimers.c | 109 + .../f2812/source/DSP281x_GlobalVariableDefs.c | 265 + .../vendor/ti/f2812/source/DSP281x_PieCtrl.c | 84 + .../vendor/ti/f2812/source/DSP281x_SysCtrl.c | 295 + .../ti/f2812/source/DSP281x_usDelay.asm | 71 + .../f28335/cmd/DSP2833x_Headers_nonBIOS.cmd | 240 + .../common/include/DSP2833x_DefaultIsr.h | 236 + .../common/include/DSP2833x_Dma_defines.h | 125 + .../common/include/DSP2833x_EPwm_defines.h | 253 + .../f28335/common/include/DSP2833x_Examples.h | 176 + .../include/DSP2833x_GlobalPrototypes.h | 363 + .../common/include/DSP2833x_I2c_defines.h | 176 + .../include/DSP2833x_SWPrioritizedIsrLevels.h | 10803 ++++++++++++++++ .../ti/f28335/common/include/DSP28x_Project.h | 28 + .../vendor/ti/f28335/include/DSP2833x_Adc.h | 465 + .../ti/f28335/include/DSP2833x_CpuTimers.h | 283 + .../vendor/ti/f28335/include/DSP2833x_DMA.h | 437 + .../ti/f28335/include/DSP2833x_DevEmu.h | 154 + .../ti/f28335/include/DSP2833x_Device.h | 655 + .../vendor/ti/f28335/include/DSP2833x_ECan.h | 2109 +++ .../vendor/ti/f28335/include/DSP2833x_ECap.h | 245 + .../vendor/ti/f28335/include/DSP2833x_EPwm.h | 720 + .../vendor/ti/f28335/include/DSP2833x_EQep.h | 407 + .../vendor/ti/f28335/include/DSP2833x_Gpio.h | 711 + .../vendor/ti/f28335/include/DSP2833x_I2c.h | 319 + .../vendor/ti/f28335/include/DSP2833x_Mcbsp.h | 1299 ++ .../ti/f28335/include/DSP2833x_PieCtrl.h | 260 + .../ti/f28335/include/DSP2833x_PieVect.h | 349 + .../vendor/ti/f28335/include/DSP2833x_Sci.h | 377 + .../vendor/ti/f28335/include/DSP2833x_Spi.h | 292 + .../ti/f28335/include/DSP2833x_SysCtrl.h | 642 + .../ti/f28335/include/DSP2833x_XIntrupt.h | 127 + .../vendor/ti/f28335/include/DSP2833x_Xintf.h | 197 + .../ti/f28335/source/DSP2833x_ADC_cal.asm | 51 + .../ti/f28335/source/DSP2833x_CpuTimers.c | 161 + .../source/DSP2833x_GlobalVariableDefs.c | 746 ++ .../ti/f28335/source/DSP2833x_PieCtrl.c | 121 + .../ti/f28335/source/DSP2833x_SysCtrl.c | 604 + .../ti/f28335/source/DSP2833x_usDelay.asm | 84 + python/protocan/can_boot.py | 104 +- python/protocan/f28335_flash.py | 99 + python/tests/test_can_boot_services.py | 86 + python/tests/test_firmware_clients.py | 5 +- 147 files changed, 42760 insertions(+), 104 deletions(-) create mode 100644 c/protocan-boot/.gitignore create mode 100644 c/protocan-boot/ports/stm32-common/README.md create mode 100644 c/protocan-boot/ports/stm32-common/boot_native.inc create mode 100644 c/protocan-boot/ports/stm32-common/pcan_boot_stm32.h create mode 100644 c/protocan-boot/ports/stm32-common/pcan_boot_stm32.inc create mode 100644 c/protocan-boot/ports/stm32f103/README.md create mode 100644 c/protocan-boot/ports/stm32f103/boot_main.c create mode 100644 c/protocan-boot/ports/stm32f103/boot_profile.h create mode 100644 c/protocan-boot/ports/stm32f103/boot_request.c create mode 100644 c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.c create mode 100644 c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.h create mode 100644 c/protocan-boot/ports/stm32f407/README.md create mode 100644 c/protocan-boot/ports/stm32f407/boot_control_hal.c create mode 100644 c/protocan-boot/ports/stm32f407/boot_control_hal.h create mode 100644 c/protocan-boot/ports/stm32f407/boot_main.c create mode 100644 c/protocan-boot/ports/stm32f407/boot_profile.h create mode 100644 c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.c create mode 100644 c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.h create mode 100644 c/protocan-boot/ports/stm32g474/LICENSE.source.md create mode 100644 c/protocan-boot/ports/stm32g474/README.md create mode 100644 c/protocan-boot/ports/stm32g474/boot_control.c create mode 100644 c/protocan-boot/ports/stm32g474/boot_main.c create mode 100644 c/protocan-boot/ports/stm32g474/boot_profile.h create mode 100644 c/protocan-boot/ports/stm32g474/boot_startup.c create mode 100644 c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.c create mode 100644 c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.h create mode 100644 c/protocan-boot/ports/tms320f2812/README.md create mode 100644 c/protocan-boot/ports/tms320f2812/boot2812.h create mode 100644 c/protocan-boot/ports/tms320f2812/boot_store.c create mode 100644 c/protocan-boot/ports/tms320f2812/nor_flash.c create mode 100644 c/protocan-boot/ports/tms320f28335/README.md create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_platform.h create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_store.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_boot_store.h create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_can_application.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_can_boot.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_can_boot.h create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_flash_app.c create mode 100644 c/protocan-boot/ports/tms320f28335/f28335_flash_app.h create mode 100644 c/protocan-boot/projects/.gitignore create mode 100644 c/protocan-boot/projects/README.md create mode 100644 c/protocan-boot/projects/STM32.md create mode 100644 c/protocan-boot/projects/build.py create mode 100644 c/protocan-boot/projects/ccs/f2812/.ccsproject create mode 100644 c/protocan-boot/projects/ccs/f2812/.cproject create mode 100644 c/protocan-boot/projects/ccs/f2812/.project create mode 100644 c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd create mode 100644 c/protocan-boot/projects/ccs/f2812/board.c create mode 100644 c/protocan-boot/projects/ccs/f2812/boot_store.c create mode 100644 c/protocan-boot/projects/ccs/f2812/codestart.asm create mode 100644 c/protocan-boot/projects/ccs/f2812/main.c create mode 100644 c/protocan-boot/projects/ccs/f2812/nor_flash.c create mode 100644 c/protocan-boot/projects/ccs/f2812/shared_boot.c create mode 100644 c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml create mode 100644 c/protocan-boot/projects/ccs/f28335/.ccsproject create mode 100644 c/protocan-boot/projects/ccs/f28335/.cproject create mode 100644 c/protocan-boot/projects/ccs/f28335/.project create mode 100644 c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd create mode 100644 c/protocan-boot/projects/ccs/f28335/codestart.asm create mode 100644 c/protocan-boot/projects/ccs/f28335/main.c create mode 100644 c/protocan-boot/projects/ccs/f28335/shared_boot.c create mode 100644 c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml create mode 100644 c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h create mode 100644 c/protocan-boot/tests/f28335_stubs/spise2p.h create mode 100644 c/protocan-boot/tests/run_tests.py create mode 100644 c/protocan-boot/tests/stm32_stubs/stm32_hal_fake.h create mode 100644 c/protocan-boot/tests/stm32_stubs/stm32f1xx_hal.h create mode 100644 c/protocan-boot/tests/stm32_stubs/stm32f4xx_hal.h create mode 100644 c/protocan-boot/tests/stm32_stubs/stm32g4xx_hal.h create mode 100644 c/protocan-boot/tests/test_f2812_nor.c create mode 100644 c/protocan-boot/tests/test_f28335_boot_store.c create mode 100644 c/protocan-boot/tests/test_f28335_can_boot.c create mode 100644 c/protocan-boot/tests/test_pcan_busy.c create mode 100644 c/protocan-boot/tests/test_project_release.py create mode 100644 c/protocan-boot/tests/test_stm32_ports.c create mode 100644 c/protocan-boot/vendor/ti/README.md create mode 100644 c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h create mode 100644 c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h create mode 100644 c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm create mode 100644 c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h create mode 100644 c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h create mode 100644 c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c create mode 100644 c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm create mode 100644 python/protocan/f28335_flash.py create mode 100644 python/tests/test_can_boot_services.py diff --git a/c/protocan-boot/.gitignore b/c/protocan-boot/.gitignore new file mode 100644 index 0000000..01b5059 --- /dev/null +++ b/c/protocan-boot/.gitignore @@ -0,0 +1,8 @@ +# Результаты отдельных конфигураций CCS воспроизводятся установленным TI compiler. +/projects/ccs/*/Debug/ +/projects/ccs/*/Release/ +# Служебные локальные настройки IDE и launch не входят в переносимый проект. +/projects/ccs/*/.settings/ +/projects/ccs/*/.launches/ +# Python cache не является исходником общего модуля или проекта. +**/__pycache__/ diff --git a/c/protocan-boot/CMakeLists.txt b/c/protocan-boot/CMakeLists.txt index 47d6c8e..7d253b5 100644 --- a/c/protocan-boot/CMakeLists.txt +++ b/c/protocan-boot/CMakeLists.txt @@ -1,6 +1,6 @@ -# Сборка библиотеки protocan_boot. Состав исходников и публичные include-пути задают -# подключение к проекту потребителя. Файл также собирает и регистрирует хостовые проверки; -# запускать их следует через CTest из каталога сборки. +# Общая C99-библиотека ProtoCAN Boot и аппаратно независимые host-тесты. +# Каждый контроллер сохраняет собственное состояние и отдельный аппаратный порт. +# Дополнительные проекты CCS находятся в projects/ccs и не требуют CMake для TI-сборки. cmake_minimum_required(VERSION 3.13) project(protocan_boot C) @@ -17,10 +17,60 @@ else() target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic) endif() -option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN boot" ON) +option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN Boot" ON) # Не включает host-модели в код MCU. if(PCAN_BOOT_BUILD_TESTS) enable_testing() add_executable(test_pcan_boot tests/test_pcan_boot.c) target_link_libraries(test_pcan_boot PRIVATE protocan_boot) add_test(NAME pcan_boot COMMAND test_pcan_boot) endif() + +if(PCAN_BOOT_BUILD_TESTS) + add_executable(test_f28335_can_boot tests/test_f28335_can_boot.c src/pcan_boot.c ports/tms320f28335/f28335_boot_store.c) + target_compile_definitions(test_f28335_can_boot PRIVATE PCAN_BOOT_WIDE_BYTES) + target_include_directories(test_f28335_can_boot PRIVATE tests/f28335_stubs) + add_test(NAME f28335_can_boot COMMAND test_f28335_can_boot) +endif() + +if(PCAN_BOOT_BUILD_TESTS) + add_executable(test_f28335_application tests/test_f28335_can_boot.c src/pcan_boot.c ports/tms320f28335/f28335_boot_store.c) + target_compile_definitions(test_f28335_application PRIVATE PCAN_BOOT_WIDE_BYTES F28335_BOOT_LOADER=0) + target_include_directories(test_f28335_application PRIVATE tests/f28335_stubs) + add_test(NAME f28335_application COMMAND test_f28335_application) + foreach(width native wide) + add_executable(test_f28335_store_${width} tests/test_f28335_boot_store.c ports/tms320f28335/f28335_boot_store.c) + if(width STREQUAL "wide") + target_compile_definitions(test_f28335_store_${width} PRIVATE PCAN_BOOT_WIDE_BYTES) + endif() + add_test(NAME f28335_store_${width} COMMAND test_f28335_store_${width}) + endforeach() +endif() + +if(PCAN_BOOT_BUILD_TESTS) # Подключает настоящий аппаратно независимый драйвер NOR F2812 и регрессию длительного BUSY. + add_executable(test_f2812_nor tests/test_f2812_nor.c src/pcan_boot.c ports/tms320f2812/nor_flash.c ports/tms320f2812/boot_store.c) # Компилирует production-код вместе с x16 моделью чипа. + target_compile_definitions(test_f2812_nor PRIVATE PCAN_BOOT_WIDE_BYTES BOOT2812_HOST) # Октеты C28x широкие; подменяется только физическая шина памяти. + add_test(NAME f2812_nor COMMAND test_f2812_nor) # Регистрирует проверки CRC, SCI8, границ, manifest и отказов NOR. + add_executable(test_pcan_busy tests/test_pcan_busy.c src/pcan_boot.c) # Использует тот же codec, который обслуживает длинные аппаратные операции. + target_compile_definitions(test_pcan_busy PRIVATE PCAN_BOOT_WIDE_BYTES) # Проверяет wire-статус при 16-битном представлении октета C28x. + add_test(NAME pcan_busy COMMAND test_pcan_busy) # Регистрирует проверку продления session при живом прогрессе erase. +endif() # Включение библиотек без тестов не добавляет host-модель в прошивку. + +if(PCAN_BOOT_BUILD_TESTS) # STM32-порты проверяются с моделью HAL и приватным отображением Flash, без доступа к плате. + foreach(family f103 f407 g474) # Каждый процесс компилирует настоящую реализацию bxCAN/FDCAN одного семейства. + add_executable(test_stm32${family} tests/test_stm32_ports.c ports/stm32${family}/pcan_boot_stm32${family}.c) # Подключает общий сценарий и семейный production-порт. + target_link_libraries(test_stm32${family} PRIVATE protocan_boot) # Использует тот же автомат и CRC, что библиотека устройства. + target_include_directories(test_stm32${family} PRIVATE tests/stm32_stubs) # Только host-цели видят подменённые семейные заголовки HAL. + if(family STREQUAL "f103") # Один сценарий выбирает адреса и аппаратную единицу записи F103. + target_compile_definitions(test_stm32${family} PRIVATE TEST_STM32F103) # F407 использует вторую ветку того же сценария. + endif() # Завершает выбор семейного профиля теста. + if(family STREQUAL "g474") # G474 использует FDCAN, doubleword и обе физические геометрии DBANK. + target_compile_definitions(test_stm32${family} PRIVATE TEST_STM32G474) # Включает G474-модель и проверку старого shifted-DLC HAL. + endif() # Завершает выбор аппаратного профиля G474. + if(MSVC) # Assertions должны исполняться и в Release-конфигурации host-тестов. + target_compile_options(test_stm32${family} PRIVATE /UNDEBUG) # Отменяет NDEBUG, чтобы аппаратные проверки и вызовы не исчезли. + else() # GCC и Clang используют стандартную форму отмены определения макроса. + target_compile_options(test_stm32${family} PRIVATE -UNDEBUG) # Сохраняет проверки границ памяти при любой конфигурации сборки. + endif() # Завершает настройку обязательных assertions. + add_test(NAME stm32${family} COMMAND test_stm32${family}) # Регистрирует регрессию полного обновления и аппаратных отказов. + endforeach() # Завершает регистрацию трёх независимых STM32-портов. +endif() # Без host-тестов CMake по-прежнему собирает только переносимое ядро. diff --git a/c/protocan-boot/README.md b/c/protocan-boot/README.md index 174756f..367e984 100644 --- a/c/protocan-boot/README.md +++ b/c/protocan-boot/README.md @@ -10,12 +10,13 @@ CAN 2.0B и 29-битному ProtoCAN ID. Оно реализует сесси CRC32, проверку совместимости, продолжение по номеру следующего блока и безопасный выбор неактивного слота. -Это не готовый загрузчик конкретного STM32: внутри нет HAL, регистров Flash, -linker script, обработчиков прерываний, криптографии и перехода в приложение. -Эти операции предоставляет проект через таблицу callbacks. +Ядро не содержит HAL или регистров Flash. Готовые аппаратные callbacks для +STM32F103C8, STM32F407VE и STM32G474VE находятся в `ports`; подключение описано ниже. +Linker script, startup, тактирование, GPIO и переход в приложение предоставляет +проект устройства. Криптография в этих single-slot портах не реализована. -Для STM32G474VET6 из `candleLight_fw` задаются `slot_count = 1` и -`max_image_size = 480 * 1024`. В этом режиме запись идёт в единственную +Для [STM32G474VET6 из CANdle_stm32](ports/stm32g474/README.md) задаются +`slot_count = 1` и `max_image_size = 480 * 1024`. В этом режиме запись идёт в единственную область приложения, callback `set_pending_slot` не требуется, а аппаратный rollback недоступен. Значение `slot_count = 0` сохраняет прежний A/B-режим. @@ -97,7 +98,8 @@ typedef struct { } pcan_boot_port_t; ``` -Обязательны `send`, `erase_slot`, `write_slot` и `set_pending_slot`. +Обязательны `send`, `erase_slot`, `write_slot`; в A/B также `set_pending_slot`. +В single-slot этот callback необязателен и может завершать активацию образа. `authorize` проверяет политику до стирания (тип, версия, anti-rollback). `verify_image` выполняет платформенную проверку подписанного контейнера после CRC32. Если callbacks отсутствуют, соответствующие дополнительные проверки @@ -175,5 +177,41 @@ ctest --test-dir build --output-on-failure - включить watchdog и rollback при неподтверждённом запуске; - согласовать фильтры CAN для `MsgType=0x9..0xD`. -Проект пока не подключён ни к одной конкретной плате; это самостоятельный -шаблон для интеграции в будущие загрузчики приборов SET. +Ядро поддерживает платформенные порты; особенности интеграции перечислены ниже. + +## F28335 / большая EEPROM + +[Порт M95M02](ports/tms320f28335/README.md) подключён в `28335_periph`, ветка 167. +Использует отдельный Flash-загрузчик и два слота EEPROM по 130560 байт. +Реализованы readback/CRC, проверка SCI8, журнал метаданных, пробный запуск, +CONFIRM/откат, PING/discovery и сервисный паспорт. Первичная установка Flash- +загрузчика и выбор Flash boot описаны в README порта. + +## STM32 / прошивка по ProtoCAN + +| Порт | Источник профиля | Область приложения | Ёмкость | +|---|---|---|---:| +| [STM32F103C8](ports/stm32f103/README.md) | `KONOR_ds18b20/src/bootloader.c` | `0x08003000..0x08010000` | 52 КиБ | +| [STM32F407VE](ports/stm32f407/README.md) | `climate_control_f407vet6_f4/Bootloader/bootloader_f407.c` | `0x08008000..0x08040000` | 224 КиБ | +| [STM32G474VE](ports/stm32g474/README.md) | `CANdle_stm32/src/boot/g474_can_bootloader.c` | `0x08008000..0x08080000` | 480 КиБ | + +Верхние границы исключены. F103/F407 предоставляют готовые CMSIS `boot_main.c` +для исходных проектов и отдельные reusable HAL-порты. G474 предоставляет +reusable HAL FDCAN/Flash-порт, CAN/UART boot main, startup и вход из приложения. +Общие компоненты и правила подключения описаны в +[`ports/stm32-common`](ports/stm32-common/README.md). Это ProtoCAN Boot v1 по +CAN, с отдельной картой памяти относительно USB SET v2-загрузчиков из `set-protocol`. +Конфигурация задаётся по именам полей и принудительно использует `slot_count=1`. +Образы пишутся в логический слот A; A/B-rollback и постоянные commit-метаданные +отсутствуют. Ограничения запуска после потери питания описаны в общей инструкции. + +Проекты KONOR, climate и CANdle G474 подключены к этим исходникам через свои +submodule `templates`; в старых путях оставлены тонкие include-обёртки. +Состав сборок, разметка SRAM-запросов и результаты проверки перечислены в +[`projects/STM32.md`](projects/STM32.md). + +## Самостоятельные проекты CCS + +Готовые проекты **F28335_CAN_AB** (M95M02) и **F2812_CAN_NOR** (AM29LV800BT), +включая необходимые файлы поддержки TI, находятся в `projects/ccs`. +[Импорт, сборка, карты памяти и установка](projects/README.md). diff --git a/c/protocan-boot/docs/BOOTLOADER.md b/c/protocan-boot/docs/BOOTLOADER.md index f4ccf78..b180cdb 100644 --- a/c/protocan-boot/docs/BOOTLOADER.md +++ b/c/protocan-boot/docs/BOOTLOADER.md @@ -63,6 +63,10 @@ BlockIndex = 0x0000…0xFFFF | `0x09` | `REBOOT` | 0 | отсутствует | активная сессия | | `0x0A` | `ABORT` | 0 | отсутствует | активная сессия | | `0x0B` | `QUERY_PROGRESS` | 0 | отсутствует | активная сессия | +| `0x0C` | `PING` | 0 | отсутствует | любое | +| `0x0D` | `CAPABILITIES` | 0 | отсутствует | любое, при поддержке порта | +| `0x0E` | `DEVICE_NAME` | 1 | номер страницы имени | любое, при поддержке порта | +| `0x0F` | `MEMORY_INFO` | 1 | номер страницы памяти | любое, при поддержке порта | ### `BEGIN_IMAGE` @@ -81,7 +85,8 @@ DATA[4..7] FirmwareVersion, uint32 little-endian ``` До `ERASE` прибор обязан получить обе части метаданных и проверить размер, -тип изделия, аппаратную ревизию, версию и политику anti-rollback. +тип изделия и аппаратную ревизию. Проверка версии/anti-rollback выполняется +только при наличии соответствующей политики платформы (callback authorize). ## `BOOT_STATUS` @@ -181,3 +186,16 @@ Boot metadata должна атомарно хранить: 5. ПМ выполняет `ERASE` и передаёт `BOOT_DATA_A` либо `BOOT_DATA_B`. 6. ПМ выполняет `VERIFY`, затем `COMMIT` и `REBOOT`. 7. Новое приложение после самопроверки выполняет `CONFIRM`. + +## F28335 M95M02 + +Реализованы отдельный Flash-загрузчик, A/B по 130560 байт, журнал, пробный запуск +и откат. Подробная раскладка памяти, сервисных ответов и первичная установка: +[README порта](../ports/tms320f28335/README.md). + +Общий discovery: Route=0, DeviceType=7, DeviceID=15, MsgType=D, Body=0, DLC=0. +Он только запрашивает IDENTIFY; операции изменения всегда адресные. +ENTER_BOOT может отложить ACK до готовности отдельного загрузчика после reset. +CONFIRM с ненулевой session может обрабатываться приложением без ENTER_BOOT. +`pcan_boot_poll` обслуживает задержку discovery и тайм-аут сессии, если он задан +портом. Старым портам с timeout=0 периодический вызов нужен только для discovery. diff --git a/c/protocan-boot/include/pcan_boot.h b/c/protocan-boot/include/pcan_boot.h index 7118b51..534d42c 100644 --- a/c/protocan-boot/include/pcan_boot.h +++ b/c/protocan-boot/include/pcan_boot.h @@ -11,6 +11,13 @@ #include #include +/* C28x has 16-bit addressable chars; wire octets use the low eight bits. */ +#if defined(__TMS320C28XX__) || defined(PCAN_BOOT_WIDE_BYTES) +typedef unsigned int pcan_boot_byte_t; +#else +typedef uint8_t pcan_boot_byte_t; +#endif + #ifdef __cplusplus extern "C" { #endif @@ -41,7 +48,11 @@ typedef enum { PCAN_BOOT_CMD_CONFIRM = 0x08U, PCAN_BOOT_CMD_REBOOT = 0x09U, PCAN_BOOT_CMD_ABORT = 0x0AU, - PCAN_BOOT_CMD_QUERY_PROGRESS = 0x0BU + PCAN_BOOT_CMD_QUERY_PROGRESS = 0x0BU, + PCAN_BOOT_CMD_PING = 0x0CU, + PCAN_BOOT_CMD_CAPABILITIES = 0x0DU, + PCAN_BOOT_CMD_DEVICE_NAME = 0x0EU, + PCAN_BOOT_CMD_MEMORY_INFO = 0x0FU } pcan_boot_command_t; typedef enum { @@ -66,7 +77,8 @@ typedef enum { PCAN_BOOT_STATE_READY_TO_ERASE, PCAN_BOOT_STATE_RECEIVING, PCAN_BOOT_STATE_VERIFIED, - PCAN_BOOT_STATE_FAILED + PCAN_BOOT_STATE_FAILED, + PCAN_BOOT_STATE_COMMITTED } pcan_boot_state_t; typedef struct { @@ -74,36 +86,47 @@ typedef struct { uint32_t image_crc32; uint32_t firmware_version; uint16_t product_type; - uint8_t hardware_revision_min; - uint8_t hardware_revision_max; + pcan_boot_byte_t hardware_revision_min; + pcan_boot_byte_t hardware_revision_max; } pcan_boot_manifest_t; typedef struct { - uint8_t device_type; - uint8_t device_id; + pcan_boot_byte_t device_type; + pcan_boot_byte_t device_id; uint16_t product_type; - uint8_t hardware_revision; + pcan_boot_byte_t hardware_revision; uint32_t firmware_version; - uint8_t active_slot; + pcan_boot_byte_t active_slot; /** 1 for an in-place/single-slot target, 2 for A/B. Zero keeps legacy A/B. */ - uint8_t slot_count; + pcan_boot_byte_t slot_count; /** Writable image capacity. Zero uses PCAN_BOOT_SLOT_SIZE. */ uint32_t max_image_size; - uint8_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */ + pcan_boot_byte_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */ + uint32_t session_timeout_ms; /**< 0 disables timeout for legacy ports. */ } pcan_boot_config_t; typedef struct { - bool (*send)(void *user, uint32_t can_id, const uint8_t *data, uint8_t dlc); - bool (*erase_slot)(void *user, uint8_t slot); - bool (*write_slot)(void *user, uint8_t slot, uint32_t offset, - const uint8_t *data, uint8_t length); + bool (*send)(void *user, uint32_t can_id, const pcan_boot_byte_t *data, pcan_boot_byte_t dlc); + bool (*erase_slot)(void *user, pcan_boot_byte_t slot); + bool (*write_slot)(void *user, pcan_boot_byte_t slot, uint32_t offset, + const pcan_boot_byte_t *data, pcan_boot_byte_t length); bool (*authorize)(void *user, const pcan_boot_manifest_t *manifest); - bool (*verify_image)(void *user, uint8_t slot, + bool (*verify_image)(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest); - bool (*set_pending_slot)(void *user, uint8_t slot, + /** A/B metadata, or optional single-slot activation after verification. */ + bool (*set_pending_slot)(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest); bool (*confirm_running_slot)(void *user); void (*reboot)(void *user); + /** ENTER: 0 ready, 1 deferred ACK after reset, 2 denied. NULL = legacy ready. */ + unsigned int (*enter_boot)(void *user, pcan_boot_byte_t session); + bool (*can_reboot)(void *user); + /** Eight-octet service response, addressed by command + page. */ + bool (*service_info)(void *user, pcan_boot_byte_t command, + pcan_boot_byte_t page, pcan_boot_byte_t *out); + /** Optional precise result, replacing legacy boolean verify_image. */ + pcan_boot_status_t (*verify_status)(void *user, pcan_boot_byte_t slot, + const pcan_boot_manifest_t *manifest); } pcan_boot_port_t; typedef struct { @@ -115,11 +138,13 @@ typedef struct { uint32_t running_crc32; uint32_t bytes_received; uint16_t next_block; - uint8_t session_id; - uint8_t target_slot; - uint8_t last_status; + pcan_boot_byte_t session_id; + pcan_boot_byte_t target_slot; + pcan_boot_byte_t last_status; bool have_image; bool have_compat; + uint32_t now_ms, last_activity_ms, discovery_at; + bool discovery_pending; } pcan_boot_t; /** Инициализирует экземпляр. Все обязательные callbacks должны быть заданы. */ @@ -134,16 +159,22 @@ void pcan_boot_abort(pcan_boot_t *boot); * Возвращает true, если кадр принадлежал загрузочному сервису этого прибора. */ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, - const uint8_t *data, uint8_t dlc); + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc); + +/** Call regularly with a wrapping monotonic millisecond clock. */ +void pcan_boot_poll(pcan_boot_t *boot, uint32_t now_ms); + +uint32_t pcan_boot_crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length); /* Общий потоковый CRC32 для readback аппаратных хранилищ; начальное состояние равно нулю. */ +bool pcan_boot_report_busy(pcan_boot_t *boot, pcan_boot_byte_t command, uint32_t now_ms); /* Долгие аппаратные операции сообщают BUSY тем же codec и той же session, что обычный ответ. */ /** Переносимые операции с 29-битным ProtoCAN ID. */ -uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route, - uint8_t device_type, uint8_t device_id, - uint8_t msg_type, uint16_t msg_body); -uint8_t pcan_boot_id_route(uint32_t can_id); -uint8_t pcan_boot_id_device_type(uint32_t can_id); -uint8_t pcan_boot_id_device_id(uint32_t can_id); -uint8_t pcan_boot_id_msg_type(uint32_t can_id); +uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route, + pcan_boot_byte_t device_type, pcan_boot_byte_t device_id, + pcan_boot_byte_t msg_type, uint16_t msg_body); +pcan_boot_byte_t pcan_boot_id_route(uint32_t can_id); +pcan_boot_byte_t pcan_boot_id_device_type(uint32_t can_id); +pcan_boot_byte_t pcan_boot_id_device_id(uint32_t can_id); +pcan_boot_byte_t pcan_boot_id_msg_type(uint32_t can_id); uint16_t pcan_boot_id_msg_body(uint32_t can_id); #ifdef __cplusplus diff --git a/c/protocan-boot/ports/stm32-common/README.md b/c/protocan-boot/ports/stm32-common/README.md new file mode 100644 index 0000000..8c30bdf --- /dev/null +++ b/c/protocan-boot/ports/stm32-common/README.md @@ -0,0 +1,109 @@ +# STM32: общий слой ProtoCAN Boot v1 + +Порты [F103C8](../stm32f103/README.md), [F407VE](../stm32f407/README.md) и +[G474VE](../stm32g474/README.md) подключают bxCAN/FDCAN и Flash к текущему `pcan_boot`. +F103/F407 предоставляют как лёгкий CMSIS boot main для существующих проектов, +так и независимый HAL-порт. G474 использует HAL FDCAN/Flash. +`pcan_boot_stm32.inc` включается семейным `.c`; отдельно его компилировать не надо. +Сохраните рядом каталоги `stm32-common` и нужного семейства. + +Reusable `pcan_boot_stm32*.c` не содержит `main` или startup. Готовые `boot_main.c` +и вход из приложения находятся в семейных каталогах. Для F103/F407 общая +CMSIS-реализация транспорта, callbacks и безопасного handoff — `boot_native.inc`; +G474 также содержит `boot_startup.c` для исходных Keil/GCC-сборок. +Тактирование платы, linker и привязка USB/CAN-приложения остаются в проектах. + +KONOR, climate и CANdle G474 уже подключены через свои submodule: локальные +boot main/control заменены include-обёртками, состав Keil/CMake обновлён. +UART использует общий `rs485-boot` с сохранением SETGUI v1 wire-протокола. +[Схема подключённых проектов и проверки сборок](../../projects/STM32.md). + +## Подключение reusable HAL-портов F103/F407 + +1. Добавьте в сборку `src/pcan_boot.c` и семейный `pcan_boot_stm32f103.c` + либо `pcan_boot_stm32f407.c`; в include paths — `include`, каталог порта, + CMSIS, HAL и каталог вашего `stm32f1xx_hal_conf.h` / `stm32f4xx_hal_conf.h`. +2. В HAL включите CAN, FLASH, RCC, GPIO и CORTEX. Выполните `HAL_Init`, настройте + тактирование, SysTick и GPIO, вызовите `HAL_CAN_Init` для CAN1. Настройка скорости + шины принадлежит проекту; исходные устройства используют 500 кбит/с. +3. Выделите CAN1, FIFO0 и банки фильтров 0/1 загрузчику. Перед вызовом init CAN + должен находиться в состоянии READY, без чужих активных фильтров. Init настраивает + адресный фильтр и broadcast discovery, затем вызывает `HAL_CAN_Start`. + Оба приоритета ProtoCAN разрешены, standard и remote кадры отвергаются. +4. Не включайте CAN TX/RX IRQ для этого handle и не отправляйте через него кадры + из других контекстов: порт использует опрос и сам читает TXOK до reset. +5. Вызывайте семейный `poll` из основного цикла только после успешного init. + Стирание Flash выполняется синхронно; вызов из IRQ не допускается. +6. Linker приложения, VTOR и переход после reset должны соответствовать карте + выбранного профиля. Изменение адресов требует отдельного согласования + геометрии стирания, linker и host-клиента. + +Пример для F103; `hcan` уже инициализирован проектом: + +```c +#include "pcan_boot_stm32f103.h" /* Подключает HAL-порт и текущий API общего автомата. */ +static pcan_boot_stm32_t updater; /* Сохраняет состояние между итерациями главного цикла. */ +static bool start_updater(CAN_HandleTypeDef *hcan) /* Вызывается после настройки CAN1, clock tree, GPIO и SysTick. */ +{ /* Настройка идентичности прибора не зависит от аппаратной геометрии Flash. */ + pcan_boot_config_t config = {0}; /* Не зависит от порядка полей расширяемого API. */ + config.device_type = 7U; /* Пример: тип 7 должен совпадать с выбранным адресом в клиенте прошивки. */ + config.device_id = 13U; /* Пример: номер 13 повторяет исходный адрес загрузчика KONOR. */ + config.ack_window = 16U; /* Подтверждает каждые 16 CAN-блоков по восемь байт. */ + config.session_timeout_ms = 30000U; /* Пример: 30 секунд без активности прерывают RAM-сессию. */ + return pcan_boot_stm32f103_init(&updater, hcan, &config); /* Настраивает single-slot геометрию, фильтры 0/1 и запускает CAN. */ +} /* После успеха основной цикл регулярно вызывает pcan_boot_stm32f103_poll(&updater). */ +``` + +Product/HW/FW в примере равны нулю; для изделия задайте их явно и согласуйте +с manifest клиента. Порт сохраняет `ack_window` и `session_timeout_ms`, но сам +задаёт `active_slot=0`, `slot_count=1`, `max_image_size` по физическому профилю. +Конфигурацию `config` можно создавать на стеке; состояние `updater` и `hcan` +должно существовать всё время работы загрузчика. + +## Flash, подтверждения и reset + +- Запись последовательная, блоки по восемь байт; неполная аппаратная единица + допустима только в конце образа и дополняется `FF`. CRC учитывает полезную длину. +- HAL-ошибки и readback каждого слова проверяются; после erase/program Flash + снова блокируется, включая обработанные отказы. На F407 перед readback + вызывается `FLASH_FlushCaches`, чтобы соседние записанные слова не читались + из устаревшей строки Flash-кэша; состояние включения кэшей сохраняется HAL. +- VERIFY перечитывает Flash, сравнивает её CRC и проверяет MSP/Thumb reset vector. + Точка входа должна принадлежать фактическому образу, MSP — основной SRAM, + с выравниванием восемь байт. CCM F407 в данном профиле для стека не используется. +- COMMIT повторно проверяет образ и устанавливает признак в RAM. + REBOOT разрешён только в состоянии COMMITTED. Ответ перед reset должен + завершиться с TXOK; отсутствие mailbox, ошибка шины или тайм-аут 100 мс + не вызывают reset. Для этого HAL tick должен работать при ожидании TX. +- BUSY перед стиранием, между секторами F407 и после erase сохраняет активность + сессии. На однобанковой Flash код не исполняется во время аппаратного стирания; + непрерывные ответы в этот интервал не гарантируются. Настройте тайм-аут клиента + больше максимального времени стирания одной аппаратной операции. + +## Запуск приложения и потеря питания + +Порт не меняет Option Bytes, защиту секторов и VDD; F407 требует 2,7..3,6 В +для программирования x32. Переход из работающего приложения в загрузчик, +backup/SRAM-флаг запроса, отключение периферии и безопасная замена MSP +остаются в `main` и startup устройства. + +`*_vectors_valid()` проверяет только векторы и диапазоны. После внешнего reset +этого недостаточно для доказательства целостности образа: RAM-признак COMMIT +потерян, а частично записанное приложение уже может иметь корректные векторы. +Эти профили сохраняют исходную single-slot модель без постоянных метаданных, +rollback, resume после питания и аутентификации. Для защищённого запуска +проекту нужен отдельный постоянный manifest с полной проверкой образа. + +## Проверка + +`python tests/run_tests.py` из корня `protocan-boot` запускает три production-порта +с моделью HAL и Flash, наряду с существующими проверками ядра и TI-портов. +Можно также использовать обычные CMake/CTest: цели `test_stm32f103`, +`test_stm32f407`, `test_stm32g474` работают на Windows и POSIX. + +Проверяются все хвосты CAN-блока, полный ERASE/DATA/VERIFY/COMMIT/REBOOT, +повреждение readback, отказы HAL/TX, фильтрация RX и сохранность памяти +перед приложением и за верхней границей; для G474 проверяются оба DBANK-режима, +переход между банками, запрет swap, ёмкость Flash и старое shifted-DLC HAL. +Эти тесты не заменяют проверку +на реальной плате с её linker, питанием, трансивером и SysTick. diff --git a/c/protocan-boot/ports/stm32-common/boot_native.inc b/c/protocan-boot/ports/stm32-common/boot_native.inc new file mode 100644 index 0000000..ab01725 --- /dev/null +++ b/c/protocan-boot/ports/stm32-common/boot_native.inc @@ -0,0 +1,127 @@ +static __attribute__((naked, noreturn)) void native_enter(uint32_t sp __attribute__((unused)), uint32_t pc __attribute__((unused))) /* Меняет стек без последующего обращения C-кода к старому кадру функции. */ +{ /* AAPCS передаёт новый MSP в r0, Thumb entry в r1; последовательность совместима с GCC и Arm Compiler 6. */ + __asm volatile("msr msp, r0\n" "movs r2, #0\n" "msr control, r2\n" "dsb\n" "isb\n" "cpsie i\n" "bx r1\n"); /* Возвращает привилегированный режим MSP, синхронизирует конвейер и передаёт управление Thumb-вектору. */ +} /* Завершает переход без эпилога C после замены MSP. */ +void SysTick_Handler(void) { ++ticks_ms; } /* Сохраняет миллисекундные часы только в самостоятельной сборке загрузчика. */ +static bool native_vectors_valid(uint32_t size) /* Проверяет начальный стек и reset handler в пределах фактического образа. */ +{ /* До чтения Flash отвергает некорректный размер. */ + const uint32_t *vectors = (const uint32_t *)(uintptr_t)NATIVE_APP_BASE; /* Таблица векторов лежит в начале зарезервированной области приложения. */ + uint32_t sp, pc; /* Хранит начальные значения Cortex-M без невыровненного доступа. */ + if (size < 8U || size > NATIVE_APP_SIZE) return false; /* Для двух векторов нужно минимум восемь байт; верхняя граница профиля исключена. */ + sp = vectors[0]; pc = vectors[1]; /* Читает MSP и Thumb-точку входа только после проверки геометрии. */ + return sp > 0x20000000UL && sp <= NATIVE_RAM_END && (sp & 7U) == 0U && (pc & 1U) != 0U && (pc & ~1UL) >= NATIVE_APP_BASE && (pc & ~1UL) < NATIVE_APP_BASE + size; /* Требует восемь байт выравнивания стека и точку входа внутри выбранной длины приложения. */ +} /* Структурная проверка не заменяет постоянный manifest после отключения питания. */ +static void native_jump(uint32_t address) /* Отключает загрузочную периферию перед запуском приложения либо ROM. */ +{ /* Вызывающий код предварительно проверяет векторы либо использует фиксированный заводской ROM. */ + uint32_t index; /* Перебирает все банки NVIC Cortex-M3/M4 с запасом до восьми банков. */ + const uint32_t *vectors = (const uint32_t *)(uintptr_t)address; /* Сохраняет адрес новой таблицы до отключения прерываний. */ + uint32_t sp = vectors[0], pc = vectors[1]; /* Считывает аргументы перехода, пока C-стек ещё принадлежит загрузчику. */ + __disable_irq(); SysTick->CTRL = 0U; /* Не позволяет SysTick загрузчика вызвать обработчик нового приложения в промежуточном состоянии. */ + native_peripheral_stop(); /* Семейный порт отключает CAN и используемый UART, не трогая резервную память. */ + for (index = 0U; index < 8U; ++index) { NVIC->ICER[index] = 0xFFFFFFFFUL; NVIC->ICPR[index] = 0xFFFFFFFFUL; } /* Сбрасывает enable/pending всех внешних IRQ записью W1C по CMSIS. */ + SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk | SCB_ICSR_PENDSVCLR_Msk; /* Убирает отложенные SysTick и PendSV до смены VTOR. */ + SCB->VTOR = address; /* Согласует векторизацию с linker нового образа. */ + native_enter(sp, pc); /* Передаёт управление без возврата и без обращения к старому C-стеку. */ +} /* Завершает общую процедуру handoff. */ +static bool native_image_valid(uint32_t size, uint32_t crc) /* Проверяет реальную Flash независимо от CRC принятого CAN/UART-потока. */ +{ /* Одно правило проверки используется обоими транспортами KONOR. */ + return native_vectors_valid(size) && pcan_boot_crc32_update(0U, (const uint8_t *)(uintptr_t)NATIVE_APP_BASE, size) == crc; /* Проверяет точную полезную длину, исключая заполнение FF последней аппаратной единицы. */ +} /* Завершает проверку векторов и readback CRC. */ +static bool native_write_bytes(uint32_t image_size, uint32_t offset, const uint8_t *data, uint16_t length) /* Записывает CAN-блок или UART-часть с одной проверкой физической геометрии. */ +{ /* Неполная аппаратная единица разрешена только в самом конце образа. */ + uint32_t done = 0U; bool ok = true; /* Считает полезные байты и сохраняет результат до восстановления блокировки Flash. */ + if (image_size < 8U || image_size > NATIVE_APP_SIZE || data == NULL || length == 0U || offset > image_size || length > image_size - offset || offset % NATIVE_PROGRAM_UNIT != 0U) return false; /* Проверяет диапазоны вычитанием, исключая переполнение и неправильное выравнивание. */ + if (length % NATIVE_PROGRAM_UNIT != 0U && offset + length != image_size) return false; /* Не допускает повторного программирования уже дополненного слова в середине потока. */ + if (!native_unlock()) return false; /* Не изменяет заблокированную или занятую Flash. */ + while (done < length) { /* Делит полезные октеты на аппаратные полуслова F1 или слова F4. */ + uint32_t word = 0xFFFFFFFFUL, count = length - done; /* По умолчанию хвост аппаратной записи остаётся стёртым FF. */ + if (count > NATIVE_PROGRAM_UNIT) count = NATIVE_PROGRAM_UNIT; /* Не копирует больше одной аппаратной единицы за итерацию. */ + (void)memcpy(&word, data + done, count); /* Не читает за фактическим хвостом последнего блока. */ + if (!native_program(NATIVE_APP_BASE + offset + done, word)) { ok = false; break; } /* Проверяет аппаратные флаги и фактический readback каждого записанного слова. */ + done += count; /* Продвигается только на число полезных байтов без дополнения. */ + } /* Завершает программирование текущей части образа. */ + native_lock(); /* Восстанавливает защиту Flash как после успеха, так и после обработанной ошибки. */ + return ok; /* Передаёт отказ общему CAN либо UART-автомату. */ +} /* Завершает общую безопасную запись Flash. */ +static bool native_send(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Передаёт служебный CAN-ответ с ожиданием реального TXOK до reset. */ +{ /* Использует только mailbox 0 выделенного загрузочного CAN1. */ + uint32_t start = ticks_ms, low = 0U, high = 0U; uint8_t index; bool sent; /* Сохраняет начало 100-мс тайм-аута и регистровые слова payload. */ + (void)user; /* Самостоятельный загрузчик содержит один статический экземпляр CAN. */ + if (length > 8U || id > 0x1FFFFFFFUL || (length != 0U && data == NULL)) return false; /* Не допускает чтение за DLC или передачу идентификатора шире 29 бит. */ + while ((CAN1->TSR & CAN_TSR_TME0) == 0U) if ((uint32_t)(ticks_ms - start) >= 100U) return false; /* Ограничивает ожидание свободного mailbox 100 миллисекундами с учётом переполнения часов. */ + for (index = 0U; index < length; ++index) { if (index < 4U) low |= (uint32_t)data[index] << (index * 8U); else high |= (uint32_t)data[index] << ((index - 4U) * 8U); } /* Читает только фактические октеты DLC, оставляя остальные позиции нулевыми. */ + CAN1->TSR = CAN_TSR_RQCP0; /* Сбрасывает прежние TXOK/ошибки mailbox 0 записью W1C. */ + CAN1->sTxMailBox[0].TDTR = length; CAN1->sTxMailBox[0].TDLR = low; CAN1->sTxMailBox[0].TDHR = high; /* Загружает длину и два безопасно сформированных слова данных. */ + CAN1->sTxMailBox[0].TIR = (id << 3U) | CAN_TI0R_IDE | CAN_TI0R_TXRQ; /* Запускает расширенный data-кадр ProtoCAN без remote-флага. */ + while ((CAN1->TSR & CAN_TSR_RQCP0) == 0U) if ((uint32_t)(ticks_ms - start) >= 100U) { CAN1->TSR = CAN_TSR_ABRQ0; return false; } /* Прерывает неподтверждённую передачу и запрещает reset после тайм-аута. */ + sent = (CAN1->TSR & CAN_TSR_TXOK0) != 0U; CAN1->TSR = CAN_TSR_RQCP0; /* Проверяет ACK шины до очистки аппаратного результата. */ + return sent; /* Ядро перезапустит MCU только после успешно отправленного ответа. */ +} /* Завершает синхронную передачу ответа CAN. */ +static bool native_erase_slot(void *user, pcan_boot_byte_t slot) /* Подключает проверенное стирание профиля к текущему ProtoCAN API. */ +{ /* Аппаратная реализация семейства никогда не затрагивает загрузчик или EEPROM-кольцо. */ + bool ok; (void)user; /* Хранит результат до финального обновления времени сессии. */ + if (slot != 0U || boot.manifest.image_size < 8U || boot.manifest.image_size > NATIVE_APP_SIZE) return false; /* Разрешает только логический слот A и полный набор векторов. */ + (void)pcan_boot_report_busy(&boot, PCAN_BOOT_CMD_ERASE, ticks_ms); /* Предупреждает клиента перед синхронным Flash stall. */ + ok = native_erase(boot.manifest.image_size); /* Стирает только реально необходимые страницы или секторы. */ + if (ok) (void)pcan_boot_report_busy(&boot, PCAN_BOOT_CMD_ERASE, ticks_ms); /* Продлевает сессию после завершения длительной аппаратной операции. */ + return ok; /* Сообщает результат стирания общему автомату. */ +} /* Завершает callback стирания CAN. */ +static bool native_write_slot(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Подключает единый Flash writer к последовательным блокам CAN. */ +{ /* Последовательность номеров блоков и максимум DLC уже проверены общим автоматом. */ + (void)user; /* Единственный образ управляется статическим экземпляром загрузчика. */ + return slot == 0U && offset == boot.bytes_received && native_write_bytes(boot.manifest.image_size, offset, data, length); /* Не допускает произвольное смещение даже при прямом вызове callback. */ +} /* Завершает callback записи CAN. */ +static pcan_boot_status_t native_verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest) /* Различает повреждение реальной Flash и неверную таблицу векторов. */ +{ /* Операция не доверяет одному CRC входящего потока. */ + (void)user; /* Использует фиксированную область выбранного семейного профиля. */ + if (slot != 0U || manifest == NULL || !native_vectors_valid(manifest->image_size)) return PCAN_BOOT_STATUS_INVALID_SIZE; /* Отвергает неверный слот, геометрию и точку входа до чтения всего образа. */ + return native_image_valid(manifest->image_size, manifest->image_crc32) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_CRC_ERROR; /* Перечитывает Flash общим CRC32 ProtoCAN. */ +} /* Завершает независимую проверку принятого образа. */ +static bool native_commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest) { return native_verify(user, slot, manifest) == PCAN_BOOT_STATUS_OK; } /* COMMIT повторно проверяет single-slot образ без имитации постоянных метаданных. */ +static bool native_can_reboot(void *user) { (void)user; return boot.state == PCAN_BOOT_STATE_COMMITTED; } /* Протокольный reset разрешён только после VERIFY и COMMIT. */ +static void native_reboot(void *user) { (void)user; NVIC_SystemReset(); } /* Вызывается ядром только после успешного TXOK ответа REBOOT. */ +static bool native_init(void) /* Инициализирует текущий API ядра без позиционных структур старой версии. */ +{ /* Идентичность устройства задаёт профиль либо конфигурация проекта. */ + pcan_boot_config_t config = {0}; pcan_boot_port_t callbacks = {0}; /* Обнуляет необязательные поля и callbacks расширяемого интерфейса. */ + config.device_type = PCAN_BOOT_DEVICE_TYPE; config.device_id = PCAN_BOOT_DEVICE_ID; config.product_type = PCAN_BOOT_PRODUCT_TYPE; /* Сохраняет адрес и Product исходного проекта. */ + config.hardware_revision = PCAN_BOOT_HW_REVISION; config.firmware_version = PCAN_BOOT_FW_VERSION; /* Сохраняет совместимость manifest по HW/FW. */ + config.active_slot = 0U; config.slot_count = 1U; config.max_image_size = NATIVE_APP_SIZE; /* Явно использует single-slot A вместо прежней фиктивной A/B-конфигурации. */ + config.ack_window = PCAN_BOOT_ACK_WINDOW; config.session_timeout_ms = 30000UL; /* Сохраняет исходное окно ACK и прерывает неактивную RAM-сессию через 30 секунд. */ + callbacks.send = native_send; callbacks.erase_slot = native_erase_slot; callbacks.write_slot = native_write_slot; /* Подключает аппаратный транспорт и защищённую область Flash. */ + callbacks.verify_status = native_verify; callbacks.set_pending_slot = native_commit; callbacks.can_reboot = native_can_reboot; callbacks.reboot = native_reboot; /* Подключает readback, COMMIT и согласованную политику reset. */ + return pcan_boot_init(&boot, &config, &callbacks, NULL); /* Проверяет конфигурацию и создаёт единственный экземпляр общего автомата. */ +} /* Завершает настройку ProtoCAN независимо от включения аппаратной шины. */ +static bool native_can_init(void) /* Настраивает выделенный CAN1 и два фильтра для адресных запросов и discovery. */ +{ /* Тактирование GPIO и CAN включает семейная функция; UART во время Flash/CAN init не изменяется. */ + static const uint8_t shifts[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U}; /* RCC кодирует APB1: значения 0..3 без деления, 4..7 дают делители 2,4,8,16. */ + uint32_t clock = SystemCoreClock >> shifts[(RCC->CFGR >> NATIVE_PPRE1_SHIFT) & 7U]; /* Получает действительную частоту APB1 в Гц, без удвоения timer clocks. */ + uint32_t tq, btr = 0U, started, index; bool found = false; /* Сохраняет bit timing, тайм-аут init и индекс фильтра. */ + if (clock % PCAN_BOOT_CAN_BITRATE != 0U) return false; /* Не округляет скорость шины при неподходящем clock tree. */ + for (tq = 18U; tq >= 8U; --tq) { /* Сохраняет диапазон 8..18 time quanta из исходного KONOR. */ + uint32_t divisor = clock / PCAN_BOOT_CAN_BITRATE, prescaler = divisor / tq, ts2 = tq / 5U; /* Выбирает sample point около 80% при допустимом целочисленном делителе. */ + if (divisor % tq == 0U && prescaler >= 1U && prescaler <= 1024U) { btr = ((ts2 - 1U) << 20U) | ((tq - 2U - ts2) << 16U) | (prescaler - 1U); found = true; break; } /* Кодирует BRP/TS1/TS2 с аппаратным смещением минус один и SJW=1 tq. */ + } /* Завершает поиск точной скорости для штатного тактирования F103/F407. */ + if (!found) return false; /* Не включает шину с неизвестными битовыми интервалами. */ + native_gpio_init(); CAN1->MCR = CAN_MCR_INRQ | CAN_MCR_ABOM; started = ticks_ms; /* Включает семейные GPIO и запрашивает init с автоматическим восстановлением bus-off. */ + while ((CAN1->MSR & CAN_MSR_INAK) == 0U) if ((uint32_t)(ticks_ms - started) >= 100U) return false; /* Ограничивает вход в CAN init ста миллисекундами. */ + CAN1->BTR = btr; CAN1->FMR |= CAN_FMR_FINIT; CAN1->FA1R = 0U; CAN1->FS1R |= 3U; CAN1->FM1R &= ~3UL; CAN1->FFA1R &= ~3UL; /* Настраивает только два 32-битных mask-фильтра в FIFO0 и отключает чужие банки загрузчика. */ + for (index = 0U; index < 2U; ++index) { /* Банк 0 принимает собственный адрес, банк 1 — только broadcast discovery. */ + uint32_t id = index == 0U ? pcan_boot_make_id(0U, 0U, PCAN_BOOT_DEVICE_TYPE, PCAN_BOOT_DEVICE_ID, 0U, 0U) : pcan_boot_make_id(0U, 0U, 7U, 15U, PCAN_BOOT_MSG_DISCOVERY, 0U); /* Не маскирует приоритет, сохраняя оба штатных уровня ProtoCAN. */ + uint32_t mask = index == 0U ? 0x0FF00000UL : 0x0FFFFFFFUL; /* Адресный фильтр оставляет MsgType/Body открытыми; discovery сравнивает их точно. */ + CAN1->sFilterRegister[index].FR1 = (id << 3U) | CAN_RI0R_IDE; CAN1->sFilterRegister[index].FR2 = (mask << 3U) | CAN_RI0R_IDE | CAN_RI0R_RTR; /* Исключает standard и remote кадры на аппаратном уровне. */ + } /* Завершает настройку обоих фильтров. */ + CAN1->FA1R |= 3U; CAN1->FMR &= ~CAN_FMR_FINIT; CAN1->MCR &= ~CAN_MCR_INRQ; started = ticks_ms; /* Активирует фильтры и переводит CAN в рабочий режим. */ + while ((CAN1->MSR & CAN_MSR_INAK) != 0U) if ((uint32_t)(ticks_ms - started) >= 100U) return false; /* Отсутствие доступной шины не должно навсегда блокировать обычный запуск приложения. */ + return true; /* Рабочий CAN готов принимать адресные команды и discovery. */ +} /* Завершает общую аппаратную настройку bxCAN. */ +static void native_can_poll(void) /* Обрабатывает не больше трёх кадров — аппаратной глубины FIFO bxCAN. */ +{ /* Длительные операции Flash выполняются только из основного цикла. */ + uint32_t count; pcan_boot_poll(&boot, ticks_ms); /* Обновляет тайм-аут сессии и отложенное discovery независимо от входящих команд. */ + for (count = 0U; count < 3U && (CAN1->RF0R & CAN_RF0R_FMP0) != 0U; ++count) { /* Ограничивает время одного вызова на нагруженной шине. */ + uint32_t rir = CAN1->sFIFOMailBox[0].RIR, low = CAN1->sFIFOMailBox[0].RDLR, high = CAN1->sFIFOMailBox[0].RDHR; /* Сохраняет поля до освобождения аппаратного FIFO. */ + uint8_t dlc = (uint8_t)(CAN1->sFIFOMailBox[0].RDTR & 15U), data[8], index; /* Читает входящий DLC отдельно от фиксированного буфера classic CAN. */ + for (index = 0U; index < 8U; ++index) data[index] = (uint8_t)(index < 4U ? low >> (index * 8U) : high >> ((index - 4U) * 8U)); /* Извлекает октеты без невыровненного чтения аппаратных регистров. */ + CAN1->RF0R |= CAN_RF0R_RFOM0; /* Освобождает обработанный элемент FIFO0 до потенциально долгого erase. */ + if ((rir & CAN_RI0R_IDE) != 0U && (rir & CAN_RI0R_RTR) == 0U && dlc <= 8U) { pcan_boot_poll(&boot, ticks_ms); (void)pcan_boot_process(&boot, (rir >> 3U) & 0x1FFFFFFFUL, data, dlc); } /* Повторно проверяет формат внешнего кадра и вызывает общий автомат. */ + } /* Завершает ограниченный пакет входящих кадров. */ +} /* Завершает обслуживание транспорта и часов ядра. */ diff --git a/c/protocan-boot/ports/stm32-common/pcan_boot_stm32.h b/c/protocan-boot/ports/stm32-common/pcan_boot_stm32.h new file mode 100644 index 0000000..095c3db --- /dev/null +++ b/c/protocan-boot/ports/stm32-common/pcan_boot_stm32.h @@ -0,0 +1,10 @@ +#ifndef PCAN_BOOT_STM32_H /* Защищает общие объявления двух STM32-портов от повторного включения. */ +#define PCAN_BOOT_STM32_H /* Фиксирует включение интерфейса single-slot загрузчика. */ +#include "../../include/pcan_boot.h" /* Использует актуальные именованные поля конфигурации и callbacks ядра. */ +typedef struct { /* Состояние принадлежит одному загрузчику и одному выделенному bxCAN. */ + pcan_boot_t boot; /* Хранит сессию, manifest, CRC потока и состояние общего автомата. */ + void *can; /* Ссылается на CAN_HandleTypeDef bxCAN либо FDCAN_HandleTypeDef G474; время жизни задаёт проект. */ + uint32_t written; /* Следующее допустимое смещение записи, в байтах от начала приложения. */ + bool ready; /* Разрешает reset только после проверки Flash и успешного COMMIT текущего образа. */ +} pcan_boot_stm32_t; /* Не содержит startup, main или обработчиков прерываний проекта. */ +#endif /* Завершает общий интерфейс STM32F103/F407. */ diff --git a/c/protocan-boot/ports/stm32-common/pcan_boot_stm32.inc b/c/protocan-boot/ports/stm32-common/pcan_boot_stm32.inc new file mode 100644 index 0000000..66e3859 --- /dev/null +++ b/c/protocan-boot/ports/stm32-common/pcan_boot_stm32.inc @@ -0,0 +1,167 @@ +static bool send_frame(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) /* Передаёт только объявленные октеты и дожидается физического завершения ACK. */ +{ /* Порт владеет CAN1 без TX IRQ, поэтому флаги завершения не очищаются чужим обработчиком. */ + pcan_boot_stm32_t *port = user; /* Получает состояние выделенного аппаратного порта. */ + CAN_HandleTypeDef *can = port->can; /* Восстанавливает тип handle семейства HAL текущей единицы трансляции. */ + CAN_TxHeaderTypeDef header = {0}; /* Не оставляет мусора в стандартном ID и timestamp-флагах. */ + uint8_t bytes[8] = {0}; /* CAN 2.0 передаёт не больше восьми октетов; короткий payload дополняется безопасными нулями. */ + uint32_t mailbox, mask, started = HAL_GetTick(); /* Запоминает mailbox, его TXOK-флаг и начало тайм-аута в мс. */ + if (dlc > 8U || id > 0x1FFFFFFFUL || (dlc != 0U && data == NULL)) return false; /* Запрещает чтение за payload и идентификатор шире 29 бит. */ + if (dlc != 0U) (void)memcpy(bytes, data, dlc); /* Не читает отсутствующие байты коротких служебных сообщений. */ + while (HAL_CAN_GetTxMailboxesFreeLevel(can) == 0U) { /* Ожидает освобождения аппаратного передатчика. */ + if ((uint32_t)(HAL_GetTick() - started) >= 100U) return false; /* Ограничивает ожидание 100 мс, включая переполнение счётчика времени. */ + } /* Завершает ожидание свободного mailbox. */ + header.ExtId = id; /* Передаёт адресный ProtoCAN ID без преобразования полей. */ + header.IDE = CAN_ID_EXT; /* ProtoCAN использует только расширенные 29-битные идентификаторы. */ + header.RTR = CAN_RTR_DATA; /* Все ответы загрузчика содержат обычные данные, а не remote-запрос. */ + header.DLC = dlc; /* Фиксирует фактическое число объявленных октетов кадра. */ + can->Instance->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2; /* Очищает прежние TXOK/ошибки записью W1C перед новой отправкой; CAN принадлежит только этому порту. */ + if (HAL_CAN_AddTxMessage(can, &header, bytes, &mailbox) != HAL_OK) return false; /* Не считает не поставленный в очередь ответ отправленным. */ + while (HAL_CAN_IsTxMessagePending(can, mailbox) != 0U) { /* Сохраняет CAN до завершения ответа, включая команду REBOOT. */ + if ((uint32_t)(HAL_GetTick() - started) >= 100U) { /* Не зависает навсегда при отсутствии ACK от шины. */ + (void)HAL_CAN_AbortTxRequest(can, mailbox); /* Снимает просроченный запрос передачи перед возвратом ошибки. */ + return false; /* Ядро не выполнит reset после неподтверждённого ответа. */ + } /* Завершает обработку тайм-аута TX. */ + } /* Аппаратная передача завершилась либо была отвергнута CAN. */ + mask = mailbox == CAN_TX_MAILBOX0 ? CAN_TSR_TXOK0 : mailbox == CAN_TX_MAILBOX1 ? CAN_TSR_TXOK1 : CAN_TSR_TXOK2; /* Сопоставляет bitmask mailbox HAL с флагом успешной передачи bxCAN. */ + return (can->Instance->TSR & mask) != 0U; /* Отличает подтверждённый ACK от снятия запроса вследствие ошибки. */ +} /* Завершает синхронный транспорт служебных ответов. */ +bool STM32_BOOT_VECTORS(void) /* Проверяет только структурную корректность таблицы векторов установленного приложения. */ +{ /* Проверка CRC образа выполняется отдельно при VERIFY. */ + const uint32_t *vectors = (const uint32_t *)(uintptr_t)STM32_BOOT_BASE; /* Читает первые два слова из фиксированной области приложения. */ + uint32_t sp = vectors[0], pc = vectors[1]; /* Извлекает начальный стек и Thumb-адрес reset handler. */ + return sp > 0x20000000UL && sp <= STM32_BOOT_RAM_END && (sp & 7U) == 0U && (pc & 1U) != 0U && (pc & ~1UL) >= STM32_BOOT_BASE && (pc & ~1UL) < STM32_BOOT_END; /* Требует доступный стек с выравниванием 8 байт и точку входа внутри приложения. */ +} /* Завершает проверку векторов без изменения MCU. */ +static bool erase_slot(void *user, pcan_boot_byte_t slot) /* Стирает единственную область после проверки manifest общим ядром. */ +{ /* Сохранение старого приложения и rollback в этом профиле отсутствуют. */ + pcan_boot_stm32_t *port = user; /* Получает manifest и состояние активации текущего загрузчика. */ + uint32_t size = port->boot.manifest.image_size; /* Ограничивает стирание фактической длиной образа в байтах. */ + bool ok, locked; /* Сохраняет результаты операции и последующего восстановления защиты Flash. */ + if (slot != 0U || size < 8U || size > STM32_BOOT_END - STM32_BOOT_BASE) return false; /* Не допускает чужой слот, неполные векторы и выход за область приложения. */ + port->ready = false; /* Инвалидирует разрешение reset до первого изменения Flash. */ + port->written = 0U; /* Начинает последовательную запись заново после стирания. */ + (void)pcan_boot_report_busy(&port->boot, PCAN_BOOT_CMD_ERASE, HAL_GetTick()); /* Предупреждает клиента перед синхронным блокированием Flash. */ + if (HAL_FLASH_Unlock() != HAL_OK) return false; /* Не продолжает работу при отказе разблокировки Flash. */ + ok = erase_region(port, size); /* Выполняет семейную операцию по страницам F1 либо секторам F4. */ + locked = HAL_FLASH_Lock() == HAL_OK; /* Восстанавливает защиту Flash и при успехе, и при отказе стирания. */ + if (ok && locked) (void)pcan_boot_report_busy(&port->boot, PCAN_BOOT_CMD_ERASE, HAL_GetTick()); /* Обновляет время после блокировки Flash, чтобы длительное стирание не погасило сессию. */ + return ok && locked; /* Не подтверждает ERASE при любом аппаратном отказе. */ +} /* Завершает callback стирания. */ +static bool write_slot(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Программирует последовательные блоки без пересечения защищённых областей. */ +{ /* Крайний неполный блок дополняется единицами до аппаратной единицы программирования. */ + pcan_boot_stm32_t *port = user; /* Получает длину manifest и ожидаемое следующее смещение. */ + uint32_t done = 0U, size = port->boot.manifest.image_size; /* Считает только полезные байты без дополнения FF. */ + bool ok = true, locked; /* Позволяет гарантированно закрыть Flash после любой ошибки. */ + if (slot != 0U || data == NULL || length == 0U || length > 8U || size < 8U || size > STM32_BOOT_END - STM32_BOOT_BASE || offset != port->written || offset > size || length > size - offset || (offset % STM32_BOOT_UNIT) != 0U) return false; /* Проверяет адреса до сложения, выравнивание и принадлежность текущему образу. */ + if ((length % STM32_BOOT_UNIT) != 0U && offset + length != size) return false; /* Дополнение FF допустимо только у последнего блока; повторная запись слова запрещена. */ + if (HAL_FLASH_Unlock() != HAL_OK) return false; /* Не выполняет запись при заблокированной Flash. */ + while (done < length) { /* Разбивает CAN-блок на аппаратные полуслова F1 либо слова F4. */ + uint32_t value = 0xFFFFFFFFUL, portion = length - done; /* Стертое значение FF заполняет только хвост последней аппаратной записи. */ + uint32_t address = STM32_BOOT_BASE + offset + done; /* Адрес остаётся в заранее проверенной области приложения. */ + HAL_StatusTypeDef status; /* Отделяет аппаратное завершение записи от последующей синхронизации Flash-кэша. */ + if (portion > STM32_BOOT_UNIT) portion = STM32_BOOT_UNIT; /* Ограничивает копирование размером аппаратной записи. */ + (void)memcpy(&value, data + done, portion); /* Не читает за фактическим payload последнего блока. */ + status = HAL_FLASH_Program(STM32_BOOT_PROGRAM, address, value); /* Дожидается завершения программирования выбранной аппаратной единицы. */ + STM32_BOOT_SYNC(); /* На F407 сбрасывает строки Flash-кэша после записи, чтобы readback соседнего слова не получил старое FF. */ + if (status != HAL_OK || memcmp((const void *)(uintptr_t)address, &value, STM32_BOOT_UNIT) != 0) { /* Проверяет результат HAL и чтение записанного значения, включая хвост FF. */ + ok = false; /* Делает частично записанный образ непригодным для VERIFY/COMMIT. */ + break; /* Не продолжает программирование после первого отказа. */ + } /* Завершает проверку результата программирования. */ + done += portion; /* Продвигает полезное смещение без включения дополнения FF в CRC. */ + } /* Завершает аппаратные записи текущего CAN-блока. */ + locked = HAL_FLASH_Lock() == HAL_OK; /* Обязательно восстанавливает аппаратную блокировку Flash. */ + if (ok && locked) port->written += length; /* Подтверждает смещение только после полного успеха и блокировки. */ + return ok && locked; /* Ошибка передаётся общему автомату как FLASH_ERROR. */ +} /* Завершает callback последовательной записи. */ +static pcan_boot_status_t verify_image(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest) /* Перечитывает реальную Flash вместо доверия одному CRC входящего потока. */ +{ /* Проверяет геометрию до доступа к памяти и точный размер переданных данных. */ + pcan_boot_stm32_t *port = user; /* Получает фактический счётчик успешно записанных байтов. */ + const uint8_t *image = (const uint8_t *)(uintptr_t)STM32_BOOT_BASE; /* Отображает фиксированную область приложения в адресное пространство MCU. */ + uint32_t offset, crc = 0U; /* Начинает общий потоковый CRC32 с нуля. */ + if (slot != 0U || manifest == NULL || manifest->image_size < 8U || manifest->image_size > STM32_BOOT_END - STM32_BOOT_BASE || port->written != manifest->image_size) return PCAN_BOOT_STATUS_INVALID_SIZE; /* Не читает произвольную память по недостоверному manifest. */ + for (offset = 0U; offset < manifest->image_size;) { /* Проверяет весь полезный образ ограниченными порциями. */ + uint32_t count = manifest->image_size - offset; /* Вычисляет остаток в байтах без выхода за границу образа. */ + if (count > 1024U) count = 1024U; /* Порция 1 КиБ ограничивает объём одного вызова потокового CRC. */ + crc = pcan_boot_crc32_update(crc, image + offset, count); /* Использует общий полином ProtoCAN и не включает дополнение FF. */ + offset += count; /* Продвигает позицию чтения проверенного образа. */ + } /* Завершает чтение Flash для независимой проверки CRC. */ + if (crc != manifest->image_crc32) return PCAN_BOOT_STATUS_CRC_ERROR; /* Обнаруживает повреждение памяти после успешного приёма CAN. */ + if (!STM32_BOOT_VECTORS() || ((*(const uint32_t *)(const void *)(image + 4U)) & ~1UL) >= STM32_BOOT_BASE + manifest->image_size) return PCAN_BOOT_STATUS_INVALID_SIZE; /* Не принимает reset handler вне фактически загруженного образа. */ + return PCAN_BOOT_STATUS_OK; /* Реальная Flash и векторы соответствуют полученному manifest. */ +} /* Завершает проверку записанного образа. */ +static bool commit_image(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest) /* Активирует только повторно проверенный single-slot образ. */ +{ /* Не имитирует постоянные A/B-метаданные или защиту от потери питания. */ + pcan_boot_stm32_t *port = user; /* Получает RAM-признак успешного COMMIT текущей сессии. */ + port->ready = verify_image(user, slot, manifest) == PCAN_BOOT_STATUS_OK; /* Перечитывает Flash перед разрешением reset. */ + return port->ready; /* Ядро перейдёт в COMMITTED только при успешной проверке. */ +} /* Завершает активацию без записи служебных страниц. */ +static bool can_reboot(void *user) /* Запрещает программный запуск недописанного приложения по команде протокола. */ +{ /* Политика запуска после внешнего reset остаётся обязанностью проекта. */ + pcan_boot_stm32_t *port = user; /* Получает состояние текущей сессии и подтверждение COMMIT. */ + return port->ready && port->boot.state == PCAN_BOOT_STATE_COMMITTED; /* ABORT, новая сессия и ошибки сами по себе не дают права reset. */ +} /* Завершает проверку допустимости протокольного reset. */ +static void reboot(void *user) /* Выполняет reset только после синхронно отправленного ответа ядра. */ +{ /* Повторно проверяет RAM-разрешение непосредственно перед сбросом. */ + if (can_reboot(user)) NVIC_SystemReset(); /* Использует штатный CMSIS reset, оставляя startup и выбор приложения проекту. */ +} /* Завершает callback перезапуска. */ +bool STM32_BOOT_INIT(pcan_boot_stm32_t *port, CAN_HandleTypeDef *can, const pcan_boot_config_t *config) /* Подключает текущий API ядра к выделенным CAN1 и single-slot Flash. */ +{ /* Тактирование, GPIO, bitrate, HAL_Init и SysTick должны быть настроены проектом заранее. */ + pcan_boot_port_t callbacks = {0}; /* Новые необязательные callbacks ядра всегда остаются явно нулевыми. */ + pcan_boot_config_t single; /* Копирует идентичность прибора, переопределяя геометрию профиля. */ + CAN_FilterTypeDef filter = {0}; /* Подготавливает адресный фильтр 0 и discovery-фильтр 1 в FIFO0. */ + uint32_t id, mask; /* Содержит идентификатор и аппаратную маску IDE/RTR сдвига bxCAN. */ + if (port == NULL || can == NULL || config == NULL || can->Instance != CAN1) return false; /* Отклоняет неверные указатели и неподдерживаемый CAN2. */ + single = *config; /* Сохраняет DeviceType/ID, Product, HW, FW, ack_window и тайм-аут сессии проекта. */ + single.active_slot = 0U; /* Single-slot обновление всегда адресует логический слот A. */ + single.slot_count = 1U; /* Исключает старую имитацию single-slot через фиктивный active_slot=1. */ + single.max_image_size = STM32_BOOT_END - STM32_BOOT_BASE; /* Ядро отвергает превышение физической области ещё до erase. */ + callbacks.send = send_frame; /* Подключает синхронную отправку подтверждённых CAN-ответов. */ + callbacks.erase_slot = erase_slot; /* Подключает стирание только области приложения. */ + callbacks.write_slot = write_slot; /* Подключает последовательное программирование с readback каждого слова. */ + callbacks.verify_status = verify_image; /* Возвращает отдельные статусы CRC_ERROR и INVALID_SIZE для Flash/vectors. */ + callbacks.set_pending_slot = commit_image; /* Согласует COMMIT с проверкой реального образа и RAM-признаком активации. */ + callbacks.can_reboot = can_reboot; /* Не позволяет REBOOT обойти проверку завершённого образа. */ + callbacks.reboot = reboot; /* Выполняет CMSIS reset после подтверждения ответа на шине. */ + (void)memset(port, 0, sizeof(*port)); /* Очищает старые счётчики и разрешение активации до настройки сессии. */ + port->can = can; /* Сохраняет заранее инициализированный handle HAL. */ + if (!pcan_boot_init(&port->boot, &single, &callbacks, port)) { port->can = NULL; return false; } /* При ошибке адреса оставляет последующий poll безопасным. */ + id = pcan_boot_make_id(0U, PCAN_BOOT_ROUTE_FROM_PM, single.device_type, single.device_id, 0U, 0U) << 3U; /* Переводит адрес прибора в регистровый формат bxCAN. */ + mask = (0x0FF00000UL << 3U) | 6U; /* Проверяет Route/Type/ID, IDE=1 и RTR=0; приоритет, MsgType и Body остаются открытыми. */ + id |= 4U; /* Устанавливает IDE в бите 2 аппаратного фильтра bxCAN. */ + filter.FilterBank = 0U; /* Выделенный загрузчик использует первый банк фильтров. */ + filter.FilterMode = CAN_FILTERMODE_IDMASK; /* Сравнивает адрес по маске вместо списка отдельных команд. */ + filter.FilterScale = CAN_FILTERSCALE_32BIT; /* Сохраняет все 29 бит расширенного идентификатора. */ + filter.FilterIdHigh = id >> 16U; /* Передаёт HAL старшую половину регистрового идентификатора. */ + filter.FilterIdLow = id & 0xFFFFU; /* Передаёт HAL младшую половину, включая IDE/RTR. */ + filter.FilterMaskIdHigh = mask >> 16U; /* Маскирует адрес прибора и направление обмена. */ + filter.FilterMaskIdLow = mask & 0xFFFFU; /* Отвергает стандартные и remote-кадры до программного разбора. */ + filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; /* Приём выполняется опросом FIFO0 без IRQ. */ + filter.FilterActivation = ENABLE; /* Включает настроенный адресный фильтр. */ + filter.SlaveStartFilterBank = 14U; /* Стандартная граница банков CAN1/CAN2 в HAL; порт не использует CAN2. */ + if (HAL_CAN_ConfigFilter(can, &filter) != HAL_OK) { port->can = NULL; return false; } /* Не запускает загрузчик с неподтверждённой настройкой адресного фильтра. */ + id = (pcan_boot_make_id(0U, PCAN_BOOT_ROUTE_FROM_PM, 7U, 15U, PCAN_BOOT_MSG_DISCOVERY, 0U) << 3U) | 4U; /* Отдельно разрешает штатный broadcast discovery, сохраняя запрет broadcast-записи. */ + mask = (0x0FFFFFFFUL << 3U) | 6U; /* Проверяет всё кроме приоритета, включая MsgType=DISCOVERY и пустой Body. */ + filter.FilterBank = 1U; /* Второй выделенный банк обслуживает только обнаружение устройств. */ + filter.FilterIdHigh = id >> 16U; /* Записывает старшую половину broadcast discovery ID. */ + filter.FilterIdLow = id & 0xFFFFU; /* Записывает младшую половину с IDE=1 и RTR=0. */ + filter.FilterMaskIdHigh = mask >> 16U; /* Ограничивает тип и адрес broadcast запроса. */ + filter.FilterMaskIdLow = mask & 0xFFFFU; /* Ограничивает Body и формат кадра discovery. */ + if (HAL_CAN_ConfigFilter(can, &filter) != HAL_OK || HAL_CAN_Start(can) != HAL_OK) { port->can = NULL; return false; } /* Обезвреживает poll при отказе второго фильтра либо запуска CAN. */ + return true; /* Оба фильтра настроены, CAN успешно вышел из режима init. */ +} /* Завершает настройку одного аппаратного порта. */ +void STM32_BOOT_POLL(pcan_boot_stm32_t *port) /* Обслуживает загрузчик только из основного цикла, где допустимо синхронное стирание. */ +{ /* Вызов из CAN IRQ не допускается из-за длительных операций Flash. */ + CAN_HandleTypeDef *can; /* Получает аппаратный handle после проверки состояния порта. */ + uint32_t count; /* Ограничивает обработку глубиной аппаратного FIFO bxCAN. */ + if (port == NULL || port->can == NULL) return; /* Позволяет безопасно пропустить ещё не настроенный порт. */ + can = port->can; /* Восстанавливает семейный HAL-тип handle. */ + pcan_boot_poll(&port->boot, HAL_GetTick()); /* Обновляет монотонное время и тайм-аут сессии до приёма команд. */ + for (count = 0U; count < 3U && HAL_CAN_GetRxFifoFillLevel(can, CAN_RX_FIFO0) != 0U; ++count) { /* Не позволяет непрерывной нагрузке CAN захватить весь главный цикл. */ + CAN_RxHeaderTypeDef header = {0}; /* Принимает IDE/RTR/DLC независимо от аппаратной настройки фильтра. */ + uint8_t data[8]; /* Выделяет максимальный payload одного classic CAN-кадра. */ + if (HAL_CAN_GetRxMessage(can, CAN_RX_FIFO0, &header, data) != HAL_OK) break; /* Не разбирает неполученный кадр при аппаратной ошибке. */ + if (header.IDE == CAN_ID_EXT && header.RTR == CAN_RTR_DATA && header.DLC <= 8U && header.ExtId <= 0x1FFFFFFFUL) { /* Повторно проверяет внешний ввод до вызова общего decoder. */ + pcan_boot_poll(&port->boot, HAL_GetTick()); /* Учитывает время предыдущего синхронного erase перед следующей командой. */ + (void)pcan_boot_process(&port->boot, header.ExtId, data, (uint8_t)header.DLC); /* Передаёт адресные команды и восьмибайтовые блоки общему автомату. */ + } /* Завершает обработку допустимого формата кадра. */ + } /* Возвращает управление приложению после ограниченного пакета входящих кадров. */ +} /* Завершает обслуживание транспорта и таймеров. */ diff --git a/c/protocan-boot/ports/stm32f103/README.md b/c/protocan-boot/ports/stm32f103/README.md new file mode 100644 index 0000000..75b8262 --- /dev/null +++ b/c/protocan-boot/ports/stm32f103/README.md @@ -0,0 +1,50 @@ +# STM32F103C8: ProtoCAN Boot v1 + +## Подключённый KONOR без HAL + +`boot_main.c` содержит извлечённый CMSIS-загрузчик CAN/UART, `boot_request.c` — +вход из приложения через BKP DR1, `boot_profile.h` — общие адреса и magic. +`KONOR_ds18b20/src/bootloader.c`, `src/boot_control.c`, `inc/boot_control.h` +теперь включают эти файлы из `lib/c/protocan-boot/ports/stm32f103`. +Keil BOOT компилирует общие `pcan_boot.c` и `rs485_boot.c`; локальный `proto.c` +исключён только из загрузчика, приложение продолжает использовать свой parser. +UART BEGIN/DATA/END/STATUS сохраняют SETGUI v1, 512000 бод и PA9/PA10. +Номера блоков, CRC и сессии CAN обслуживает только общий ProtoCAN-автомат. +Оба транспорта используют один Flash writer; одновременная запись блокируется. + +Native вариант не нужно собирать вместе с reusable HAL `.c` ниже. + +## Reusable HAL-порт + +Аппаратный single-slot профиль извлечён из `KONOR_ds18b20/src/bootloader.c`. +Прямые операции с регистрами адаптированы к современному STM32CubeF1 HAL; +UART SETGUI parser исходного проекта в этот CAN-порт не входит. + +| Область | Начало | Конец, исключён | Размер | +|---|---|---|---:| +| Загрузчик | `0x08000000` | `0x08003000` | 12 КиБ | +| Приложение | `0x08003000` | `0x08010000` | 52 КиБ | +| SRAM для MSP | `0x20000000` | `0x20005000` | 20 КиБ | + +MSP может совпадать с верхней границей SRAM, но не с нижней; выравнивание — +восемь байт. Страница Flash — 1024 байта, единица записи — полуслово 16 бит. +Профиль предназначен для штатных 64 КиБ Flash STM32F103C8, без использования +недокументированного расширения памяти. + +Подключайте `pcan_boot_stm32f103.c`, общий `src/pcan_boot.c` и сохраните соседний +каталог `stm32-common`. STM32CubeF1 HAL должен включать CAN и Flash/FlashEx. +Для определения CMSIS обычно используется `STM32F103xB`; физический профиль +этого порта остаётся C8 с 64 КиБ. + +Проект настраивает CAN1 и GPIO: исходная плата использует PA11 RX, PA12 TX, +500 кбит/с, DeviceType=7 / DeviceID=13. Значения адреса задавайте через +`pcan_boot_config_t` и согласуйте с host-клиентом. На стороне Flash всегда +используется логический слот A. + +Вызывайте `pcan_boot_stm32f103_init` после `HAL_CAN_Init`, затем +`pcan_boot_stm32f103_poll` из основного цикла. Linker приложения и VTOR должны +указывать на `0x08003000`. В загрузчике зарезервируйте весь диапазон до этого +адреса и проверьте размер итогового образа по MAP: HAL-сборка может оказаться +крупнее исходного загрузчика с прямым доступом к регистрам. + +[Общая инструкция, пример, ограничения COMMIT и запуска после reset](../stm32-common/README.md). diff --git a/c/protocan-boot/ports/stm32f103/boot_main.c b/c/protocan-boot/ports/stm32f103/boot_main.c new file mode 100644 index 0000000..5b89b95 --- /dev/null +++ b/c/protocan-boot/ports/stm32f103/boot_main.c @@ -0,0 +1,95 @@ +#include "boot_profile.h" /* Сохраняет карту памяти, BKP-запросы и CAN-адрес исходного KONOR. */ +#include "../../include/pcan_boot.h" /* Использует единственную текущую машину состояний ProtoCAN из templates. */ +#include "../../../rs485-boot/include/rs485_boot.h" /* Повторно использует общий SETGUI v1 UART-автомат вместо локальной копии parser/CRC. */ +#include "stm32f10x.h" /* Работает с существующим CMSIS/StdPeriph проекта без добавления HAL. */ +#include /* Предоставляет безопасное копирование коротких хвостов Flash. */ +#define NATIVE_APP_BASE BOOT_APP_ADDRESS /* Выбирает начало приложения после 12 КиБ загрузчика. */ +#define NATIVE_APP_SIZE (BOOT_FLASH_END - BOOT_APP_ADDRESS) /* Ограничивает обновление 52 КиБ штатной Flash C8. */ +#define NATIVE_RAM_END 0x20005000UL /* Начальный MSP допускается до верхней границы 20 КиБ SRAM. */ +#define NATIVE_PROGRAM_UNIT 2U /* Контроллер Flash STM32F103 записывает полуслова по два байта. */ +#define NATIVE_PPRE1_SHIFT 8U /* STM32F1 размещает делитель APB1 в RCC_CFGR[10:8]. */ +static pcan_boot_t boot; static volatile uint32_t ticks_ms; /* Хранит CAN-сессию и монотонный счётчик SysTick загрузчика. */ +static rs485_boot_t uart_boot; /* Хранит UART parser, повторяемую запись блоков и статус общего SETGUI v1-автомата. */ +static bool native_wait(void) /* Ограничивает ожидание Flash и проверяет аппаратные ошибки программирования. */ +{ /* На однобанковой Flash CPU может останавливаться до завершения операции. */ + uint32_t guard = SystemCoreClock; /* Конечный бюджет проверок численно равен HCLK в Гц; это число итераций CPU, а не аппаратный тайм-аут. */ + while ((FLASH->SR & FLASH_SR_BSY) != 0U && guard != 0U) --guard; /* Не продолжает запись до освобождения контроллера Flash. */ + return (FLASH->SR & (FLASH_SR_BSY | FLASH_SR_PGERR | FLASH_SR_WRPRTERR)) == 0U; /* Ошибки записи или защиты делают аппаратную операцию неуспешной. */ +} /* Завершает ожидание Flash с аппаратной проверкой. */ +static bool native_unlock(void) /* Открывает Flash для одной ограниченной операции. */ +{ /* Не меняет Option Bytes или защиту загрузчика. */ + if ((FLASH->SR & FLASH_SR_BSY) != 0U) return false; /* Не посылает ключи занятому контроллеру. */ + FLASH->SR = FLASH_SR_PGERR | FLASH_SR_WRPRTERR | FLASH_SR_EOP; /* Очищает завершение и прежние ошибки записью W1C. */ + if ((FLASH->CR & FLASH_CR_LOCK) != 0U) { FLASH->KEYR = 0x45670123UL; FLASH->KEYR = 0xCDEF89ABUL; } /* Использует обязательную последовательность ключей STM32F1 из RM0008. */ + return (FLASH->CR & FLASH_CR_LOCK) == 0U; /* Проверяет фактическое снятие аппаратной блокировки. */ +} /* Завершает разблокировку без сохранения разрешения между командами. */ +static void native_lock(void) { FLASH->CR = FLASH_CR_LOCK; } /* Снимает PG/PER и восстанавливает LOCK даже после обработанной ошибки. */ +static bool native_program(uint32_t address, uint32_t value) /* Записывает и перечитывает одно выровненное полуслово. */ +{ /* Границы и выравнивание заранее проверяет общий writer. */ + volatile uint16_t *destination = (volatile uint16_t *)(uintptr_t)address; /* Выбирает аппаратную 16-битную операцию F103. */ + FLASH->SR = FLASH_SR_PGERR | FLASH_SR_WRPRTERR | FLASH_SR_EOP; FLASH->CR = FLASH_CR_PG; /* Очищает прежний результат и разрешает программирование полуслова. */ + *destination = (uint16_t)value; /* Передаёт младшие 16 бит, включая FF-дополнение неполного хвоста. */ + if (!native_wait()) return false; /* Не подтверждает запись при BUSY или аппаратной ошибке. */ + FLASH->CR = 0U; return *destination == (uint16_t)value; /* Убирает PG и проверяет реально прочитанное полуслово. */ +} /* Завершает одну аппаратную запись. */ +static bool native_erase(uint32_t size) /* Стирает страницы приложения, не пересекая область загрузчика. */ +{ /* Общая геометрия страницы задаётся единственным профилем F103C8. */ + uint32_t address, end; bool ok = true; /* Хранит исключённый конец стирания и результат до блокировки Flash. */ + if (size < 8U || size > NATIVE_APP_SIZE) return false; /* Не стирает Flash для пустого или слишком большого образа. */ + end = BOOT_APP_ADDRESS + ((size + BOOT_PAGE_SIZE - 1U) & ~(BOOT_PAGE_SIZE - 1U)); /* Округляет конец вверх к странице 1024 байта внутри профиля. */ + if (end > BOOT_FLASH_END || !native_unlock()) return false; /* Проверяет округлённую верхнюю границу до первого стирания. */ + for (address = BOOT_APP_ADDRESS; address < end; address += BOOT_PAGE_SIZE) { /* Обходит только страницы, покрывающие полезный образ. */ + FLASH->SR = FLASH_SR_PGERR | FLASH_SR_WRPRTERR | FLASH_SR_EOP; FLASH->CR = FLASH_CR_PER; FLASH->AR = address; FLASH->CR |= FLASH_CR_STRT; /* Запускает erase одной конкретной страницы вместо mass erase. */ + if (!native_wait()) { ok = false; break; } /* Прекращает стирание на первой аппаратной ошибке. */ + } /* Завершает ограниченный диапазон страниц. */ + native_lock(); return ok; /* Обязательно закрывает Flash после успешного или прерванного erase. */ +} /* Завершает аппаратное стирание F1. */ +static void native_gpio_init(void) /* Сохраняет исходную разводку CAN1 KONOR: PA11 RX и PA12 TX. */ +{ /* UART на PA9/PA10 остаётся независимым загрузочным транспортом. */ + uint32_t value; RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; /* Включает GPIOA, AFIO и CAN1 в соответствующих APB-доменах. */ + value = GPIOA->CRH; value &= ~((0xFUL << 12U) | (0xFUL << 16U)); value |= (0x8UL << 12U) | (0xBUL << 16U); GPIOA->CRH = value; /* Настраивает PA11 как вход с подтяжкой, PA12 как AF push-pull согласно RM0008. */ + GPIOA->BSRR = 1UL << 11U; /* Выбирает подтяжку CAN RX вверх, соответствующую рецессивному состоянию неподключённой линии. */ +} /* Завершает настройку физического CAN-порта. */ +static void native_peripheral_stop(void) { USART1->CR1 = 0U; RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST; } /* Отключает загрузочный USART и сбрасывает CAN перед handoff. */ +#include "../stm32-common/boot_native.inc" /* Подключает общий транспорт, single-slot callbacks, CRC readback и безопасный переход MSP. */ +static bool uart_transmit(void *user, const uint8_t *data, uint16_t length) /* Отправляет кадры SETGUI v1 с ожиданием последнего стоп-бита. */ +{ /* Использует прежнюю скорость USART1 512000 бод без управления RS-485 DE. */ + uint16_t index; (void)user; /* UART-автомат использует единственный статический аппаратный порт. */ + for (index = 0U; index < length; ++index) { while ((USART1->SR & USART_SR_TXE) == 0U) {} USART1->DR = data[index]; } /* Передаёт только объявленные байты полного кадра. */ + while ((USART1->SR & USART_SR_TC) == 0U) {} return true; /* Дожидается физического завершения ответа перед возможным reset. */ +} /* Завершает аппаратную передачу UART. */ +static bool uart_erase(void *user, uint32_t size) { (void)user; return boot.state == PCAN_BOOT_STATE_IDLE && native_erase(size); } /* Не позволяет UART стереть Flash во время открытой CAN-сессии. */ +static bool uart_write(void *user, uint32_t offset, const uint8_t *data, uint16_t length) { (void)user; return native_write_bytes(uart_boot.image_size, offset, data, length); } /* Использует ту же проверку диапазонов и аппаратную запись, что CAN. */ +static bool uart_read(void *user, uint32_t offset, uint8_t *data, uint16_t length) /* Позволяет общему UART-автомату подтвердить повторно присланный блок. */ +{ /* Проверяет размер до сложения адреса, исключая переполнение. */ + (void)user; if (data == NULL || offset > NATIVE_APP_SIZE || length > NATIVE_APP_SIZE - offset) return false; /* Не читает за областью приложения. */ + (void)memcpy(data, (const void *)(uintptr_t)(NATIVE_APP_BASE + offset), length); return true; /* Копирует только объявленный безопасный диапазон Flash. */ +} /* Завершает UART readback для повторов передачи. */ +static bool uart_image_valid(void *user, uint32_t size, uint32_t crc) { (void)user; return native_image_valid(size, crc); } /* Перед END использует тот же CRC Flash и проверку векторов, что CAN VERIFY. */ +static void uart_init(void) /* Инициализирует существующий TTL UART и общий SETGUI v1-автомат. */ +{ /* Локальный Proto parser исходного проекта загрузчику больше не нужен. */ + uint32_t value; rs485_boot_config_t config = {BOOT_APP_ADDRESS, NATIVE_APP_SIZE, RS485_BOOT_MAX_BLOCK}; rs485_boot_port_t callbacks = {0}; /* Сохраняет прежний wire-протокол и предел 504 полезных байта на DATA. */ + RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN; value = GPIOA->CRH; value &= ~((0xFUL << 4U) | (0xFUL << 8U)); value |= (0xBUL << 4U) | (0x4UL << 8U); GPIOA->CRH = value; /* Настраивает PA9 TX AF-PP и PA10 RX floating, как исходный KONOR. */ + USART1->BRR = (SystemCoreClock + 256000UL) / 512000UL; USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; /* При штатном APB2=HCLK сохраняет округлённую скорость 512000 бод, 8-N-1. */ + callbacks.transmit = uart_transmit; callbacks.erase = uart_erase; callbacks.write = uart_write; callbacks.read = uart_read; callbacks.image_valid = uart_image_valid; callbacks.reboot = native_reboot; /* Подключает аппаратные операции к общему UART-автомату. */ + (void)rs485_boot_init(&uart_boot, &config, &callbacks, NULL); /* Инициализирует parser и RAM-сессию отдельного транспорта. */ +} /* Завершает настройку UART без локальной копии codec. */ +static void uart_poll(void) /* Обслуживает UART из главного цикла без прерываний и выделения памяти. */ +{ /* Во время CAN-сессии UART BEGIN отвергается callback стирания. */ + uint32_t status = USART1->SR; uint8_t byte; /* Сохраняет статус до чтения регистра данных. */ + if ((status & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) != 0U) { byte = (uint8_t)USART1->DR; (void)byte; } /* Снимает аппаратные ошибки чтением SR/DR и отбрасывает повреждённый байт. */ + else if ((status & USART_SR_RXNE) != 0U) { byte = (uint8_t)USART1->DR; rs485_boot_feed(&uart_boot, &byte, 1U); } /* Передаёт исправный байт общему parser с прежним кадрированием A5 5A. */ +} /* Завершает неблокирующий приём UART. */ +int main(void) /* Самостоятельная точка входа общего загрузчика KONOR для Keil/GCC. */ +{ /* Тактирование и startup остаются в исходном проекте и выполняются до main. */ + uint16_t request; bool can_ready; /* Хранит одноразовое назначение reset и результат включения CAN. */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN; PWR->CR |= PWR_CR_DBP; request = (uint16_t)BKP->DR1; BKP->DR1 = 0U; /* Потребляет совместимый BKP-запрос ровно один раз. */ + if (request == BOOT_REQUEST_SYSTEM_MAGIC) { /* Сохраняет исходную подготовку периферии перед переходом в заводской UART-загрузчик. */ + __disable_irq(); RCC->APB1RSTR = 0U; RCC->APB2RSTR = 0U; RCC->AHBENR = 0x00000014UL; RCC->APB2ENR = 0U; RCC->APB1ENR = 0U; /* Как исходный KONOR, оставляет только AHB Flash/SRAM и отключает внешнюю APB-периферию перед System Memory. */ + native_jump(0x1FFFF000UL); /* AN2606: фиксированное начало System Memory STM32F103 medium density, дальнейший переход выполняется без доступа к старому MSP. */ + } /* Завершает совместимую ветку заводского загрузчика. */ + if (request != BOOT_REQUEST_FIRMWARE_MAGIC && native_vectors_valid(NATIVE_APP_SIZE)) native_jump(BOOT_APP_ADDRESS); /* Сохраняет немедленный обычный запуск KONOR при допустимых векторах приложения. */ + SystemCoreClockUpdate(); if (SysTick_Config(SystemCoreClock / 1000U) != 0U || !native_init()) for (;;) {} /* Создаёт миллисекундный tick и проверяет текущую конфигурацию ProtoCAN до обработки команд. */ + uart_init(); can_ready = native_can_init(); /* При отказе CAN сохраняет доступный UART-канал восстановления. */ + for (;;) { uart_poll(); if (can_ready && uart_boot.state != RS485_BOOT_RECEIVING) native_can_poll(); } /* Не позволяет двум транспортам одновременно изменять одну область Flash. */ +} /* Завершает самостоятельный загрузчик; управление остаётся в сервисном цикле до успешного обновления. */ diff --git a/c/protocan-boot/ports/stm32f103/boot_profile.h b/c/protocan-boot/ports/stm32f103/boot_profile.h new file mode 100644 index 0000000..0e89187 --- /dev/null +++ b/c/protocan-boot/ports/stm32f103/boot_profile.h @@ -0,0 +1,17 @@ +#ifndef PCAN_BOOT_F103_PROFILE_H /* Согласует загрузчик и приложение KONOR с одной картой памяти. */ +#define PCAN_BOOT_F103_PROFILE_H /* Исключает повторное определение аппаратных констант. */ +#define BOOT_APP_ADDRESS 0x08003000UL /* Приложение KONOR начинается после 12 КиБ защищаемого загрузчика. */ +#define BOOT_FLASH_END 0x08010000UL /* Верхняя исключённая граница штатных 64 КиБ Flash STM32F103C8. */ +#define BOOT_PAGE_SIZE 1024UL /* Средняя плотность STM32F103C8 использует страницы Flash по 1024 байта. */ +#define BOOT_REQUEST_FIRMWARE_MAGIC 0xB007U /* Сохраняет совместимость существующего запроса обновления в BKP DR1. */ +#define BOOT_REQUEST_SYSTEM_MAGIC 0xB315U /* Сохраняет запрос перехода в заводской UART-загрузчик AN3155. */ +#define PCAN_BOOT_DEVICE_TYPE 7U /* Адрес исходного загрузчика KONOR: DeviceType=7. */ +#define PCAN_BOOT_DEVICE_ID 13U /* Адрес исходного загрузчика KONOR: DeviceID=13. */ +#define PCAN_BOOT_PRODUCT_TYPE 0U /* Исходный ProductType KONOR; должен совпадать с manifest клиента. */ +#define PCAN_BOOT_HW_REVISION 0U /* Исходная ревизия платы, согласованная с диапазоном HW manifest. */ +#define PCAN_BOOT_FW_VERSION 0U /* Версия самого загрузчика KONOR; версию приложения сообщает приложение. */ +#define PCAN_BOOT_ACK_WINDOW 16U /* Подтверждает каждые 16 блоков ProtoCAN по восемь байт. */ +#define PCAN_BOOT_CAN_BITRATE 500000UL /* Исходная скорость CAN-загрузчика, бит в секунду. */ +void Boot_RequestFirmware(void); /* Записывает запрос обновления в BKP DR1 и выполняет программный reset. */ +void Boot_RequestSystemMemory(void); /* Записывает запрос AN3155 в BKP DR1 и выполняет программный reset. */ +#endif /* Завершает профиль STM32F103C8 для загрузчика и приложения. */ diff --git a/c/protocan-boot/ports/stm32f103/boot_request.c b/c/protocan-boot/ports/stm32f103/boot_request.c new file mode 100644 index 0000000..af6ce33 --- /dev/null +++ b/c/protocan-boot/ports/stm32f103/boot_request.c @@ -0,0 +1,12 @@ +#include "boot_profile.h" /* Использует ту же карту памяти и magic, что общий загрузчик F103. */ +#include "stm32f10x.h" /* Сохраняет совместимость KONOR с CMSIS/StdPeriph без зависимости от HAL. */ +static void request_boot(uint16_t magic) /* Сохраняет одноразовый запрос через программный reset. */ +{ /* BKP DR1 существует в backup-домене STM32F103 и не требует резервирования основной SRAM. */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN; /* Разрешает тактирование PWR и backup-регистров. */ + PWR->CR |= PWR_CR_DBP; /* Разрешает запись в защищённый backup-домен. */ + BKP->DR1 = magic; /* Записывает совместимый код назначения следующего запуска. */ + __DSB(); /* Гарантирует завершение записи до запроса системного сброса. */ + NVIC_SystemReset(); /* Следующий startup потребляет запрос и выбирает загрузчик. */ +} /* Завершает общую аппаратную последовательность входа. */ +void Boot_RequestFirmware(void) { request_boot(BOOT_REQUEST_FIRMWARE_MAGIC); } /* Сохраняет прежний API приложения KONOR для обновления CAN/UART. */ +void Boot_RequestSystemMemory(void) { request_boot(BOOT_REQUEST_SYSTEM_MAGIC); } /* Сохраняет прежний API меню для заводского UART-загрузчика STM32. */ diff --git a/c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.c b/c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.c new file mode 100644 index 0000000..0159849 --- /dev/null +++ b/c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.c @@ -0,0 +1,22 @@ +#include "pcan_boot_stm32f103.h" /* Подключает HAL STM32F1 и публичный профиль KONOR. */ +#include /* Предоставляет инициализацию структур и чтение невыровненных октетов. */ +#define STM32_BOOT_INIT pcan_boot_stm32f103_init /* Экспортирует семейное имя общей процедуры настройки. */ +#define STM32_BOOT_POLL pcan_boot_stm32f103_poll /* Экспортирует семейное имя обслуживания FIFO и таймеров. */ +#define STM32_BOOT_VECTORS pcan_boot_stm32f103_vectors_valid /* Экспортирует проверку векторов именно этого профиля. */ +#define STM32_BOOT_BASE PCAN_BOOT_F103_APP_ADDRESS /* Сохраняет адрес приложения исходной прошивки KONOR. */ +#define STM32_BOOT_END PCAN_BOOT_F103_FLASH_END /* Ограничивает erase и write штатными 64 КиБ Flash. */ +#define STM32_BOOT_RAM_END 0x20005000UL /* STM32F103C8 имеет 20 КиБ SRAM; MSP может указывать сразу за последним байтом. */ +#define STM32_BOOT_UNIT 2U /* Flash STM32F103 программируется полусловами по два байта. */ +#define STM32_BOOT_PROGRAM FLASH_TYPEPROGRAM_HALFWORD /* Выбирает штатный HAL-режим записи полуслова. */ +#define STM32_BOOT_SYNC() ((void)0) /* F103 не имеет Flash data cache, требующего сброса перед readback. */ +static bool erase_region(pcan_boot_stm32_t *port, uint32_t size) /* Стирает только страницы, покрывающие проверенный размер образа. */ +{ /* Вызывается общим кодом после HAL_FLASH_Unlock и проверки границ. */ + FLASH_EraseInitTypeDef erase = {0}; /* Исключает неопределённые поля семейной структуры HAL. */ + uint32_t error = 0U; /* Получает адрес страницы, на которой HAL обнаружил ошибку. */ + (void)port; /* F1 стирает выбранные страницы одной синхронной операцией HAL. */ + erase.TypeErase = FLASH_TYPEERASE_PAGES; /* Не разрешает массовое стирание, затрагивающее загрузчик. */ + erase.PageAddress = STM32_BOOT_BASE; /* Начинает стирание с первой страницы приложения. */ + erase.NbPages = (size + 1023U) / 1024U; /* Округляет вверх к странице 1 КиБ STM32F103C8, как в исходном KONOR. */ + return HAL_FLASHEx_Erase(&erase, &error) == HAL_OK; /* Прерывает обновление при ошибке или тайм-ауте Flash. */ +} /* Завершает аппаратную реализацию стирания F1. */ +#include "../stm32-common/pcan_boot_stm32.inc" /* Собирает общий transport/readback с геометрией и HAL этого семейства. */ diff --git a/c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.h b/c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.h new file mode 100644 index 0000000..62027b4 --- /dev/null +++ b/c/protocan-boot/ports/stm32f103/pcan_boot_stm32f103.h @@ -0,0 +1,11 @@ +#ifndef PCAN_BOOT_STM32F103_H /* Исключает повторное объявление порта STM32F103C8. */ +#define PCAN_BOOT_STM32F103_H /* Обозначает активный интерфейс аппаратного профиля. */ +#include "stm32f1xx_hal.h" /* Получает тип CAN_HandleTypeDef и драйверы Flash из STM32CubeF1. */ +#include "boot_profile.h" /* Использует ту же аппаратную карту, что подключённый CMSIS-загрузчик KONOR. */ +#include "../stm32-common/pcan_boot_stm32.h" /* Подключает состояние и API переносимого автомата. */ +#define PCAN_BOOT_F103_APP_ADDRESS BOOT_APP_ADDRESS /* Сохраняет публичное HAL-имя адреса приложения без дублирования числа 0x08003000. */ +#define PCAN_BOOT_F103_FLASH_END BOOT_FLASH_END /* Сохраняет публичное HAL-имя верхней границы 64 КиБ Flash из общего профиля. */ +bool pcan_boot_stm32f103_init(pcan_boot_stm32_t *port, CAN_HandleTypeDef *can, const pcan_boot_config_t *config); /* Назначает single-slot callbacks, фильтры 0/1 в FIFO0 и запускает заранее настроенный CAN1. */ +void pcan_boot_stm32f103_poll(pcan_boot_stm32_t *port); /* Обслуживает до трёх кадров FIFO0 и таймеры ядра из основного цикла. */ +bool pcan_boot_stm32f103_vectors_valid(void); /* Проверяет MSP и Thumb-вектор в пределах профиля; CRC установленного образа не подтверждает. */ +#endif /* Завершает интерфейс профиля STM32F103C8. */ diff --git a/c/protocan-boot/ports/stm32f407/README.md b/c/protocan-boot/ports/stm32f407/README.md new file mode 100644 index 0000000..571a93c --- /dev/null +++ b/c/protocan-boot/ports/stm32f407/README.md @@ -0,0 +1,51 @@ +# STM32F407VE: ProtoCAN Boot v1 + +## Подключённый climate + +`boot_main.c` содержит извлечённый CMSIS-загрузчик, `boot_control_hal.c/.h` — +адресный ENTER_BOOT из рабочего приложения. `boot_profile.h` определяет карту +Flash и SRAM-запрос; идентичность прибора остаётся в `pcan_boot_config.h` проекта. +Исходные `Bootloader/bootloader_f407.c`, `Libraries/ProtoCanBoot/Src/pcan_boot.c` +и `Core/Src/can_boot_control.c` стали include-обёртками общего submodule. +Старый include API также перенаправлен в `templates`. + +BOOT linker исключает последние восемь байт SRAM: запрос хранится в +`0x2001FFFC`, а initial stack не может затереть его до main. Приложение climate +уже использует нижние 112 КиБ SRAM и не перекрывает запрос. Обычный reset +сохраняет десятисекундное окно обновления; TX ACK перед REBOOT проверяется. +Native boot main и reusable HAL `.c` ниже — отдельные варианты сборки. + +## Reusable HAL-порт + +Аппаратный single-slot профиль извлечён из +`climate_control_f407vet6_f4/Bootloader/bootloader_f407.c` и +`Libraries/ProtoCanBoot/Inc/pcan_boot_config.h` проекта climate. +Операции с регистрами адаптированы к современному STM32CubeF4 HAL. + +| Область | Начало | Конец, исключён | Размер | +|---|---|---|---:| +| Загрузчик: секторы 0/1 | `0x08000000` | `0x08008000` | 32 КиБ | +| Приложение: секторы 2..5 | `0x08008000` | `0x08040000` | 224 КиБ | +| EEPROM-кольцо: секторы 6/7 | `0x08040000` | `0x08080000` | 256 КиБ | +| Основная SRAM для MSP | `0x20000000` | `0x20020000` | 128 КиБ | + +Размеры стираемых секторов 2/3/4/5: 16/16/64/128 КиБ. Запись выполняется +словами 32 бита, с `FLASH_VOLTAGE_RANGE_3`; VDD платы должно быть 2,7..3,6 В. +Порт не стирает секторы 0/1/6/7. CCM не используется как область допустимого MSP. + +Подключайте `pcan_boot_stm32f407.c`, общий `src/pcan_boot.c` и сохраните соседний +каталог `stm32-common`. В CMSIS выберите `STM32F407xx`, в HAL включите CAN и +Flash/FlashEx. Проект настраивает CAN1, скорость и GPIO: исходная плата использует +PD0 RX, PD1 TX, AF9, 500 кбит/с, DeviceType=7 / DeviceID=3. + +Вызывайте `pcan_boot_stm32f407_init` после `HAL_CAN_Init`, затем +`pcan_boot_stm32f407_poll` из основного цикла. Адрес прибора, Product/HW/FW, +окно ACK и тайм-аут сессии задаются через `pcan_boot_config_t` по именам полей. +Инициализация принудительно задаёт логический слот A и ёмкость 224 КиБ. + +Linker приложения и VTOR должны указывать на `0x08008000`; загрузчик должен +помещаться в 32 КиБ до этого адреса. Это исходная CAN-разметка climate: +USB SET v2-порт F407 из `set-protocol` использует другую карту памяти, +поэтому его linker и готовые USB-образы нельзя подключать без адаптации. + +[Общая инструкция, пример, ограничения COMMIT и запуска после reset](../stm32-common/README.md). diff --git a/c/protocan-boot/ports/stm32f407/boot_control_hal.c b/c/protocan-boot/ports/stm32f407/boot_control_hal.c new file mode 100644 index 0000000..9c7c6ae --- /dev/null +++ b/c/protocan-boot/ports/stm32f407/boot_control_hal.c @@ -0,0 +1,29 @@ +#include "boot_control_hal.h" /* Подключает совместимый API приложения climate. */ +#include "boot_profile.h" /* Получает общий адрес SRAM-запроса и карту Flash. */ +#include "pcan_boot_config.h" /* Идентичность прибора остаётся настройкой проекта, общей для boot и app. */ +HAL_StatusTypeDef CanBootControl_Start(CAN_HandleTypeDef *can) /* Сохраняет прежнюю настройку выделенного CAN приложения. */ +{ /* Новые приложения с DeviceCan используют только Handle и собственные адресные фильтры. */ + CAN_FilterTypeDef filter = {0}; /* Исключает неопределённые поля аппаратной конфигурации. */ + if (can == NULL) return HAL_ERROR; /* Не обращается к отсутствующему HAL handle. */ + filter.FilterBank = 0U; filter.FilterMode = CAN_FILTERMODE_IDMASK; filter.FilterScale = CAN_FILTERSCALE_32BIT; /* Сохраняет широкую фильтрацию старого выделенного канала; адрес проверяется программно. */ + filter.FilterFIFOAssignment = CAN_RX_FIFO0; filter.FilterActivation = ENABLE; filter.SlaveStartFilterBank = 14U; /* Использует FIFO0 и штатное разделение банков CAN1/CAN2. */ + if (HAL_CAN_ConfigFilter(can, &filter) != HAL_OK) return HAL_ERROR; /* Не запускает CAN с неподтверждённым фильтром. */ + return HAL_CAN_Start(can); /* Возвращает вызывающему приложению фактический результат запуска. */ +} /* Завершает совместимую настройку транспорта приложения. */ +void CanBootControl_Poll(CAN_HandleTypeDef *can) /* Поддерживает старые приложения без отдельного распределителя входящих кадров. */ +{ /* Приём ограничен одним кадром, чтобы не блокировать главный цикл. */ + CAN_RxHeaderTypeDef header; uint8_t data[8]; /* Выделяет полный буфер classic CAN независимо от входящего DLC. */ + if (can != NULL && HAL_CAN_GetRxFifoFillLevel(can, CAN_RX_FIFO0) != 0U && HAL_CAN_GetRxMessage(can, CAN_RX_FIFO0, &header, data) == HAL_OK) (void)CanBootControl_Handle(&header, data); /* Передаёт только успешно принятый кадр общему обработчику. */ +} /* Завершает опрос канала совместимости. */ +uint8_t CanBootControl_Handle(const CAN_RxHeaderTypeDef *header, const uint8_t data[8]) /* Запускает обновление только для собственного адреса и ненулевой сессии. */ +{ /* Ответ ENTER_BOOT отправляет уже загрузчик после повторного запроса клиента. */ + uint32_t id; /* Сохраняет проверенный расширенный CAN ID запроса. */ + (void)data; /* ENTER_BOOT не содержит payload и не должен читать входной буфер. */ + if (header == NULL || header->IDE != CAN_ID_EXT || header->RTR != CAN_RTR_DATA || header->DLC != 0U || header->ExtId > 0x1FFFFFFFUL) return 0U; /* Отвергает стандартные, remote и ошибочно дополненные запросы. */ + id = header->ExtId; /* Извлекает идентификатор только после проверки внешнего заголовка. */ + if (((id >> 27U) & 1U) != 0U || ((id >> 24U) & 7U) != PCAN_BOOT_DEVICE_TYPE || ((id >> 20U) & 15U) != PCAN_BOOT_DEVICE_ID || ((id >> 16U) & 15U) != 9U || (id & 255U) != 2U || ((id >> 8U) & 255U) == 0U) return 0U; /* Сопоставляет Route=0, адрес, BOOT_CONTROL=9, ENTER_BOOT=2 и SessionID != 0. */ + *((volatile uint32_t *)(uintptr_t)PCAN_BOOT_REQUEST_ADDRESS) = PCAN_BOOT_REQUEST_MAGIC; /* Сохраняет одноразовый запрос в слове SRAM, исключённом из linker-стека. */ + __DSB(); /* Дожидается записи SRAM перед системным reset. */ + NVIC_SystemReset(); /* Передаёт управление общему загрузчику без подтверждения из приложения. */ + return 1U; /* Позволяет тестовой модели и старому диспетчеру отметить обработанный запрос. */ +} /* Завершает безопасную проверку входа в загрузчик. */ diff --git a/c/protocan-boot/ports/stm32f407/boot_control_hal.h b/c/protocan-boot/ports/stm32f407/boot_control_hal.h new file mode 100644 index 0000000..4de34f5 --- /dev/null +++ b/c/protocan-boot/ports/stm32f407/boot_control_hal.h @@ -0,0 +1,7 @@ +#ifndef PCAN_BOOT_F407_CONTROL_HAL_H /* Защищает совместимый API входа climate в общий загрузчик. */ +#define PCAN_BOOT_F407_CONTROL_HAL_H /* Обозначает включение адаптера рабочего приложения. */ +#include "stm32f4xx_hal.h" /* Приложение climate передаёт штатные заголовки и handle HAL CAN. */ +HAL_StatusTypeDef CanBootControl_Start(CAN_HandleTypeDef *can); /* Сохраняет прежний API выделенного CAN-канала приложения. */ +void CanBootControl_Poll(CAN_HandleTypeDef *can); /* Проверяет один входящий кадр в старых проектах без общего CAN-диспетчера. */ +uint8_t CanBootControl_Handle(const CAN_RxHeaderTypeDef *header, const uint8_t data[8]); /* Обрабатывает адресный ENTER_BOOT из существующего диспетчера DeviceCan. */ +#endif /* Завершает интерфейс адаптера приложения F407. */ diff --git a/c/protocan-boot/ports/stm32f407/boot_main.c b/c/protocan-boot/ports/stm32f407/boot_main.c new file mode 100644 index 0000000..5fb644b --- /dev/null +++ b/c/protocan-boot/ports/stm32f407/boot_main.c @@ -0,0 +1,68 @@ +#include "boot_profile.h" /* Сохраняет карту Flash climate и зарезервированное SRAM-слово запроса. */ +#include "pcan_boot_config.h" /* Идентичность прибора и окно ACK остаются конфигурацией исходного проекта. */ +#include "../../include/pcan_boot.h" /* Подключает единственную текущую state machine ProtoCAN из templates. */ +#include "stm32f407xx.h" /* Сохраняет лёгкую CMSIS-сборку загрузчика без HAL-драйверов. */ +#include /* Предоставляет безопасное формирование слов из коротких хвостов CAN. */ +#define NATIVE_APP_BASE PCAN_BOOT_APP_ADDRESS /* Приложение climate начинается с физического сектора 2. */ +#define NATIVE_APP_SIZE PCAN_BOOT_APP_SIZE /* Ограничивает прошивку секторами 2..5, сохраняя EEPROM-кольцо. */ +#define NATIVE_RAM_END 0x20020000UL /* Физическая верхняя граница 128 КиБ SRAM сохраняет совместимость векторов ранее установленных приложений. */ +#define NATIVE_PROGRAM_UNIT 4U /* F407 программирует слова x32 при VDD 2,7..3,6 В. */ +#define NATIVE_PPRE1_SHIFT 10U /* STM32F4 размещает делитель APB1 в RCC_CFGR[12:10]. */ +#define NATIVE_FLASH_ERRORS (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR) /* Проверяет последовательность, разрядность, выравнивание и аппаратную защиту Flash по RM0090. */ +static pcan_boot_t boot; static volatile uint32_t ticks_ms; /* Хранит единственный автомат CAN и миллисекундные часы загрузчика. */ +static bool native_wait(void) /* Ограничивает аппаратное ожидание Flash без бесконечной блокировки. */ +{ /* Код продолжит исполняться после аппаратного Flash stall на однобанковом F407. */ + uint32_t guard = SystemCoreClock; while ((FLASH->SR & FLASH_SR_BSY) != 0U && guard != 0U) --guard; /* Использует конечный бюджет проверок в единицах итераций текущего CPU. */ + return (FLASH->SR & (FLASH_SR_BSY | NATIVE_FLASH_ERRORS)) == 0U; /* Не подтверждает операцию при BUSY или любой выбранной аппаратной ошибке. */ +} /* Завершает проверку готовности Flash. */ +static bool native_unlock(void) /* Открывает Flash только для текущей операции загрузчика. */ +{ /* Геометрия профиля исключает массовое стирание и запись Option Bytes. */ + if ((FLASH->SR & FLASH_SR_BSY) != 0U) { return false; } FLASH->SR = NATIVE_FLASH_ERRORS; /* Не посылает ключи занятой Flash и очищает предыдущие ошибки W1C. */ + if ((FLASH->CR & FLASH_CR_LOCK) != 0U) { FLASH->KEYR = 0x45670123UL; FLASH->KEYR = 0xCDEF89ABUL; } /* Использует штатную последовательность ключей RM0090. */ + return (FLASH->CR & FLASH_CR_LOCK) == 0U; /* Проверяет фактическое снятие блокировки Flash. */ +} /* Завершает разблокировку контроллера Flash. */ +static void native_lock(void) { FLASH->CR = FLASH_CR_LOCK; } /* Выключает PG/SER и восстанавливает LOCK после успеха и обработанных отказов. */ +static void native_sync_cache(void) /* Убирает устаревшие строки Flash cache перед readback соседнего записанного слова. */ +{ /* Сохраняет исходное включение instruction/data cache и остальные настройки ACR. */ + uint32_t saved = FLASH->ACR; FLASH->ACR = saved & ~(FLASH_ACR_ICEN | FLASH_ACR_DCEN); /* Отключает кэши перед их аппаратным сбросом. */ + FLASH->ACR |= FLASH_ACR_ICRST | FLASH_ACR_DCRST; FLASH->ACR &= ~(FLASH_ACR_ICRST | FLASH_ACR_DCRST); FLASH->ACR = saved; /* Сбрасывает обе cache-памяти и возвращает прежние enable/latency/prefetch настройки. */ + __DSB(); __ISB(); /* Синхронизирует последующие чтения Flash и исполняемый поток после reset кэшей. */ +} /* Завершает синхронизацию Flash cache без HAL. */ +static bool native_program(uint32_t address, uint32_t value) /* Программирует и перечитывает одно слово x32. */ +{ /* Границы и выравнивание проверяет общий writer до вызова. */ + bool ok; FLASH->SR = NATIVE_FLASH_ERRORS; FLASH->CR = FLASH_CR_PG | (2UL << FLASH_CR_PSIZE_Pos); /* Выбирает PSIZE=2, то есть 32-битную запись при VDD 2,7..3,6 В. */ + *(volatile uint32_t *)(uintptr_t)address = value; ok = native_wait(); FLASH->CR &= ~FLASH_CR_PG; native_sync_cache(); /* Дожидается завершения записи и сбрасывает устаревшие строки cache перед чтением. */ + return ok && *(const volatile uint32_t *)(uintptr_t)address == value; /* Проверяет аппаратные флаги и реально прочитанное значение, включая дополнение FF. */ +} /* Завершает одну аппаратную запись F407. */ +static bool native_erase(uint32_t size) /* Стирает только используемые секторы 2..5 приложения climate. */ +{ /* EEPROM-кольцо 6/7 и загрузочные 0/1 не включаются в таблицу разрешённых секторов. */ + static const uint32_t starts[4] = {0x08008000UL, 0x0800C000UL, 0x08010000UL, 0x08020000UL}; /* RM0090: начала секторов 2,3,4,5 объёмом 16,16,64,128 КиБ. */ + uint32_t index; bool ok = true; /* Хранит текущий сектор и результат до восстановления LOCK. */ + if (size < 8U || size > NATIVE_APP_SIZE || !native_unlock()) return false; /* Отвергает неподдерживаемый размер до первого изменения Flash. */ + for (index = 0U; index < 4U && starts[index] < NATIVE_APP_BASE + size; ++index) { /* Не стирает следующий сектор, когда образ заканчивается точно на его границе. */ + (void)pcan_boot_report_busy(&boot, PCAN_BOOT_CMD_ERASE, ticks_ms); FLASH->SR = NATIVE_FLASH_ERRORS; /* Продлевает сессию и сообщает прогресс между длительными стираниями. */ + FLASH->CR = FLASH_CR_SER | (2UL << FLASH_CR_PSIZE_Pos) | ((index + 2U) << FLASH_CR_SNB_Pos); FLASH->CR |= FLASH_CR_STRT; /* Запускает erase конкретного сектора с разрядностью x32. */ + if (!native_wait()) { ok = false; break; } /* Прерывает обновление на первом аппаратном отказе. */ + } /* Завершает обход разрешённых секторов. */ + native_lock(); native_sync_cache(); return ok; /* Восстанавливает LOCK и обновляет cache как после успеха, так и после обработанного отказа. */ +} /* Завершает аппаратное стирание F407. */ +static void native_gpio_init(void) /* Сохраняет исходный CAN1 climate на PD0/PD1 AF9. */ +{ /* Тактирование APB1 определяется общим кодом из фактического RCC_CFGR. */ + RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; /* Разрешает аппаратные такты GPIOD и CAN1. */ + GPIOD->MODER = (GPIOD->MODER & ~15UL) | 10UL; GPIOD->PUPDR = (GPIOD->PUPDR & ~3UL) | 1UL; /* Назначает PD0/PD1 альтернативной функцией и подтягивает RX к рецессивному уровню. */ + GPIOD->OSPEEDR |= 15UL; GPIOD->AFR[0] = (GPIOD->AFR[0] & ~255UL) | 0x99UL; /* Выбирает высокую скорость GPIO и AF9 обоих выводов CAN1 согласно datasheet F407. */ +} /* Завершает настройку физического CAN-порта. */ +static void native_peripheral_stop(void) { RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST; } /* Сбрасывает CAN1 перед handoff без изменения памяти приложения и EEPROM. */ +#include "../stm32-common/boot_native.inc" /* Подключает общий ProtoCAN transport, CRC, callbacks и безопасную замену MSP. */ +int main(void) /* Самостоятельный загрузчик climate, подключаемый тонкой обёрткой исходного проекта. */ +{ /* Сборка PCAN_BOOTLOADER_BUILD сохраняет VTOR startup в начале Flash. */ + bool requested = *(volatile uint32_t *)(uintptr_t)PCAN_BOOT_REQUEST_ADDRESS == PCAN_BOOT_REQUEST_MAGIC; /* Читает запрос из отдельного слова SRAM, не используемого стеком или ZI. */ + *(volatile uint32_t *)(uintptr_t)PCAN_BOOT_REQUEST_ADDRESS = 0U; /* Потребляет запрос ровно один раз до запуска интерфейсов. */ + SystemCoreClockUpdate(); if (SysTick_Config(SystemCoreClock / 1000U) != 0U || !native_init()) for (;;) {} /* Использует фактический HCLK и создаёт millisecond tick до CAN-тайм-аутов. */ + while (!native_can_init()) { if (!requested && native_vectors_valid(NATIVE_APP_SIZE)) native_jump(NATIVE_APP_BASE); native_peripheral_stop(); } /* При недоступной шине сохраняет обычный запуск установленного приложения, а по запросу остаётся восстанавливаемым. */ + if (!requested && native_vectors_valid(NATIVE_APP_SIZE)) { /* Сохраняет исходное десятисекундное окно входа в обновление после обычного reset. */ + uint32_t started = ticks_ms; while ((uint32_t)(ticks_ms - started) < 10000U) { native_can_poll(); if (boot.state != PCAN_BOOT_STATE_IDLE) { requested = true; break; } } /* Обслуживает discovery и команды без ложного входа по одному IDENTIFY. */ + if (!requested) native_jump(NATIVE_APP_BASE); /* Запускает приложение после окна, используя безопасный naked handoff. */ + } /* Завершает политику обычного запуска. */ + for (;;) native_can_poll(); /* Остаётся в общем ProtoCAN-автомате до подтверждённого COMMIT/REBOOT. */ +} /* Завершает самостоятельный CMSIS-загрузчик F407. */ diff --git a/c/protocan-boot/ports/stm32f407/boot_profile.h b/c/protocan-boot/ports/stm32f407/boot_profile.h new file mode 100644 index 0000000..375e750 --- /dev/null +++ b/c/protocan-boot/ports/stm32f407/boot_profile.h @@ -0,0 +1,8 @@ +#ifndef PCAN_BOOT_F407_PROFILE_H /* Согласует нативный загрузчик climate и приложение с общей аппаратной разметкой. */ +#define PCAN_BOOT_F407_PROFILE_H /* Предотвращает повторное объявление адресов и magic. */ +#define PCAN_BOOT_APP_ADDRESS 0x08008000UL /* climate: секторы 0/1 общей ёмкостью 32 КиБ принадлежат загрузчику. */ +#define PCAN_BOOT_FLASH_END 0x08040000UL /* climate: начало EEPROM-кольца в секторе 6 исключено из приложения. */ +#define PCAN_BOOT_APP_SIZE (PCAN_BOOT_FLASH_END - PCAN_BOOT_APP_ADDRESS) /* Разрешённая ёмкость приложения составляет 224 КиБ в секторах 2..5. */ +#define PCAN_BOOT_REQUEST_MAGIC 0x5043414EUL /* Сохраняет совместимый маркер PCAN одноразового запроса обновления. */ +#define PCAN_BOOT_REQUEST_ADDRESS 0x2001FFFCUL /* Последнее слово основной SRAM F407; linker приложения и загрузчика должен исключать эти четыре байта. */ +#endif /* Завершает общую аппаратную часть конфигурации climate. */ diff --git a/c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.c b/c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.c new file mode 100644 index 0000000..748f19b --- /dev/null +++ b/c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.c @@ -0,0 +1,28 @@ +#include "pcan_boot_stm32f407.h" /* Подключает HAL STM32F4 и публичный профиль climate. */ +#include /* Предоставляет инициализацию структур и чтение невыровненных октетов. */ +#define STM32_BOOT_INIT pcan_boot_stm32f407_init /* Экспортирует семейное имя общей процедуры настройки. */ +#define STM32_BOOT_POLL pcan_boot_stm32f407_poll /* Экспортирует семейное имя обслуживания FIFO и таймеров. */ +#define STM32_BOOT_VECTORS pcan_boot_stm32f407_vectors_valid /* Экспортирует проверку векторов именно этого профиля. */ +#define STM32_BOOT_BASE PCAN_BOOT_F407_APP_ADDRESS /* Сохраняет адрес приложения исходного загрузчика climate. */ +#define STM32_BOOT_END PCAN_BOOT_F407_FLASH_END /* Не разрешает запись в EEPROM-кольцо секторов 6 и 7. */ +#define STM32_BOOT_RAM_END 0x20020000UL /* STM32F407VE: верхняя исключённая граница основной SRAM объёмом 128 КиБ. */ +#define STM32_BOOT_UNIT 4U /* Исходный F407-порт использует запись 32-битных слов при VDD 2,7..3,6 В. */ +#define STM32_BOOT_PROGRAM FLASH_TYPEPROGRAM_WORD /* Согласует разрядность программирования с VOLTAGE_RANGE_3. */ +#define STM32_BOOT_SYNC() FLASH_FlushCaches() /* HAL сохраняет состояние cache enable и сбрасывает устаревшие строки перед readback соседних записанных слов. */ +static bool erase_region(pcan_boot_stm32_t *port, uint32_t size) /* Стирает последовательно только используемые секторы приложения. */ +{ /* Общий код уже проверил размер и разблокировал Flash. */ + static const uint32_t starts[] = {0x08008000UL, 0x0800C000UL, 0x08010000UL, 0x08020000UL}; /* RM0090: начала секторов 2..5 размером 16,16,64,128 КиБ. */ + uint32_t index; /* Индекс сектора в разрешённой области приложения. */ + for (index = 0U; index < 4U && starts[index] < STM32_BOOT_BASE + size; ++index) { /* Не стирает следующий сектор, если образ закончился на его границе. */ + FLASH_EraseInitTypeDef erase = {0}; /* Обнуляет все поля аппаратной команды перед выбором сектора. */ + uint32_t error = 0U; /* Получает номер сектора с ошибкой от HAL. */ + (void)pcan_boot_report_busy(&port->boot, PCAN_BOOT_CMD_ERASE, HAL_GetTick()); /* Уведомляет клиента между длительными синхронными стираниями и продлевает сессию. */ + erase.TypeErase = FLASH_TYPEERASE_SECTORS; /* Исключает массовое стирание загрузчика и EEPROM-кольца. */ + erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; /* Требует VDD 2,7..3,6 В для выбранного программирования x32. */ + erase.Sector = FLASH_SECTOR_2 + index; /* Разрешает только физические секторы 2,3,4,5 STM32F407. */ + erase.NbSectors = 1U; /* Между секторами возвращает управление для ответа BUSY. */ + if (HAL_FLASHEx_Erase(&erase, &error) != HAL_OK) return false; /* Прекращает операцию на первой аппаратной ошибке. */ + } /* Завершает обход секторов, покрывающих фактический образ. */ + return true; /* Все выбранные секторы успешно стёрты. */ +} /* Завершает аппаратную реализацию стирания F4. */ +#include "../stm32-common/pcan_boot_stm32.inc" /* Собирает общий transport/readback с геометрией и HAL этого семейства. */ diff --git a/c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.h b/c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.h new file mode 100644 index 0000000..071b9f7 --- /dev/null +++ b/c/protocan-boot/ports/stm32f407/pcan_boot_stm32f407.h @@ -0,0 +1,11 @@ +#ifndef PCAN_BOOT_STM32F407_H /* Исключает повторное объявление порта STM32F407VE. */ +#define PCAN_BOOT_STM32F407_H /* Обозначает активный интерфейс аппаратного профиля. */ +#include "stm32f4xx_hal.h" /* Получает тип CAN_HandleTypeDef и драйверы Flash из STM32CubeF4. */ +#include "boot_profile.h" /* Использует ту же аппаратную карту, что приложение и CMSIS-загрузчик climate. */ +#include "../stm32-common/pcan_boot_stm32.h" /* Подключает состояние и API переносимого автомата. */ +#define PCAN_BOOT_F407_APP_ADDRESS PCAN_BOOT_APP_ADDRESS /* Сохраняет публичное HAL-имя начала приложения без дублирования аппаратного адреса. */ +#define PCAN_BOOT_F407_FLASH_END PCAN_BOOT_FLASH_END /* Сохраняет публичное HAL-имя границы приложения перед EEPROM-кольцом секторов 6/7. */ +bool pcan_boot_stm32f407_init(pcan_boot_stm32_t *port, CAN_HandleTypeDef *can, const pcan_boot_config_t *config); /* Назначает single-slot callbacks, фильтры 0/1 в FIFO0 и запускает заранее настроенный CAN1. */ +void pcan_boot_stm32f407_poll(pcan_boot_stm32_t *port); /* Обслуживает до трёх кадров FIFO0 и таймеры ядра из основного цикла. */ +bool pcan_boot_stm32f407_vectors_valid(void); /* Проверяет MSP и Thumb-вектор в пределах профиля; CRC установленного образа не подтверждает. */ +#endif /* Завершает интерфейс профиля STM32F407VE. */ diff --git a/c/protocan-boot/ports/stm32g474/LICENSE.source.md b/c/protocan-boot/ports/stm32g474/LICENSE.source.md new file mode 100644 index 0000000..6977229 --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/LICENSE.source.md @@ -0,0 +1,34 @@ +# Licenses + +## candleLight Firmware Sources + +The MIT License (MIT) + +Copyright (c) 2016 Hubert Denkmair + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## STM32 HAL +The HAL is distributed under a non-restrictive BSD (Berkeley Software +Distribution) license. + +## STM32 USB Library +Code from the STM32 USB library is licensed +under ST STMicroelectronics +[Ultimate Liberty license SLA0044] (www.st.com/SLA0044) diff --git a/c/protocan-boot/ports/stm32g474/README.md b/c/protocan-boot/ports/stm32g474/README.md new file mode 100644 index 0000000..f672869 --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/README.md @@ -0,0 +1,63 @@ +# STM32G474VET6: ProtoCAN Boot v1 / CANdle + +Исходный проект: `https://git.rd12.ru/setcorp/CANdle_stm32.git`, commit +`61a93c5`. Аппаратный код извлечён из `src/boot/g474_can_bootloader.c`, +`src/can_boot_control.c` и `src/boot/g474_boot_startup.c`; локальная CAN state +machine заменена единым `src/pcan_boot.c`. Лицензия исходного проекта сохранена +в [`LICENSE.source.md`](LICENSE.source.md). + +| Область | Начало | Конец, исключён | Размер | +|---|---|---|---:| +| Загрузчик | `0x08000000` | `0x08008000` | 32 КиБ | +| Single-slot приложение | `0x08008000` | `0x08080000` | 480 КиБ | +| RAM проекта | `0x20000000` | `0x20013FF8` | 80 КиБ − 8 байт | +| Одноразовый запрос CANB | `0x20013FFC` | `0x20014000` | 4 байта | + +`boot_profile.h` содержит единые адреса/magic и совместимый API приложения. +Валидатор векторов допускает прежний MSP вплоть до физической границы +`0x20014000`; новые linker/startup исключают последние восемь байт, чтобы +не затереть запрос до чтения в main. RAM-COMMIT не сохраняется после питания. + +## Состав и подключение + +- `pcan_boot_stm32g474.c/.h` — reusable HAL FDCAN/Flash-порт с single-slot, + независимым CRC readback, doubleword записью и проверкой TXBTO перед reset. +- `boot_main.c` — самостоятельный CAN/UART-загрузчик CANdle, без собственной + реализации wire-протокола; использует `pcan_boot` и общий `rs485-boot`. +- `boot_startup.c` — исходная схема Keil/GCC startup с безопасным initial MSP. +- `boot_control.c` — вход из приложения по адресному ENTER_BOOT или UART BEGIN, + совместимый UART PING/ACK и исходный USART1 IRQ. + +В проекте CANdle старые файлы стали include-обёртками из submodule `templates`. +BOOT Keil и CMake компилируют дополнительно `pcan_boot.c` и +`pcan_boot_stm32g474.c`. Приложение использует общий `boot_control.c` без +подключения загрузочной state machine к USB–CAN приложению. + +Board-проект предоставляет `device.h`, `device_sysclock_config`, +`HAL_FDCAN_MspInit`, CMSIS/HAL и linker. Исходная плата использует CPU 144 МГц, +FDCAN kernel 48 МГц, FDCAN1 PB8/PB9 AF9, classic CAN 500 кбит/с, +DeviceType=7 / DeviceID=15. UART — PA9/PA10 AF7, 512000 бод, TTL без DE. +Для reusable API вызовите `HAL_FDCAN_Init` с двумя extended-фильтрами, +затем `pcan_boot_stm32g474_init`, затем регулярно `poll` из main. +FDCAN и его TX FIFO должны принадлежать этому порту, без конкурирующих TX IRQ. + +## Flash и протокол + +Поддерживается реальная плотность 512 КиБ. DBANK=1 использует два банка по +256 КиБ и страницы 2 КиБ; DBANK=0 — один банк 512 КиБ и страницы 4 КиБ. +Номера страниц считаются отдельно для каждого банка, с проверкой всей +округлённой области до erase. BFB2 и SYSCFG FB_MODE bank swap отвергаются; +Option Bytes не изменяются. Другие плотности требуют собственного профиля. + +Flash программируется doubleword по восемь байт. Неполный doubleword +дополняется FF только в конце образа; повторная запись ECC-слова в середине +потока не допускается. UART использует тот же writer, что CAN DATA. +VERIFY перечитывает Flash, COMMIT повторяет проверку, REBOOT возможен только +после COMMIT и физически подтверждённого TX. Кодирование DLC определяется +константами используемой версии HAL; старый сдвиг 16 и новый сдвиг 0 не смешиваются. + +Стирание синхронное. Клиент должен допускать длительное Flash stall; BUSY до +и после erase поддерживает сессию. Постоянного manifest, A/B-rollback, resume +после питания и аутентификации в исходном single-slot профиле нет. + +[Подключённые проекты и проверки Keil/CMake](../../projects/STM32.md). diff --git a/c/protocan-boot/ports/stm32g474/boot_control.c b/c/protocan-boot/ports/stm32g474/boot_control.c new file mode 100644 index 0000000..c7dd270 --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/boot_control.c @@ -0,0 +1,48 @@ +#include "boot_profile.h" /* Получает единственный источник адресов, magic и функций входа CANdle G474. */ +#include "stm32g4xx.h" /* Использует исходный CMSIS-порт USART/SRAM без зависимости приложения от загрузочного main. */ +static volatile bool request; /* IRQ либо CAN-диспетчер отмечает запрос, который основной цикл может безопасно обработать. */ +static uint8_t frame[28], used; /* Кадр BEGIN содержит 8 байт заголовка, 16 байт payload и 4 байта CRC, всего 28 байт. */ +static uint32_t read32(const uint8_t *data) { return (uint32_t)data[0] | ((uint32_t)data[1] << 8U) | ((uint32_t)data[2] << 16U) | ((uint32_t)data[3] << 24U); } /* Извлекает little-endian CRC без невыровненного чтения. */ +static uint32_t crc32(const uint8_t *data, uint8_t length) /* Малый app-only codec сохраняет отсутствие зависимости приложения от boot-автомата. */ +{ /* Формат PING/BEGIN совпадает с SETGUI v1, исходный полином IEEE отражённый. */ + uint32_t crc = 0xFFFFFFFFUL; uint8_t index, bit; /* Начинает IEEE CRC32 с инверсного состояния, как исходное приложение CANdle. */ + for (index = 0U; index < length; ++index) { crc ^= data[index]; for (bit = 0U; bit < 8U; ++bit) crc = (crc >> 1U) ^ ((crc & 1U) != 0U ? 0xEDB88320UL : 0U); } /* Обрабатывает только проверенные октеты и восемь бит каждого байта. */ + return ~crc; /* Выполняет финальный XOR, совместимый с zlib и загрузчиком SETGUI v1. */ +} /* Завершает совместимый малый CRC приложения. */ +void can_boot_observe(uint32_t id, bool extended, uint8_t dlc) /* Не переводит приложение в обновление по чужому либо невалидному кадру. */ +{ /* Переход откладывается до вызова can_boot_enter из существующего main. */ + if (extended && dlc == 0U && id <= 0x1FFFFFFFUL && ((id >> 27U) & 1U) == 0U && ((id >> 24U) & 7U) == CAN_BOOT_DEVICE_TYPE && ((id >> 20U) & 15U) == CAN_BOOT_DEVICE_ID && ((id >> 16U) & 15U) == 9U && (id & 255U) == 2U && ((id >> 8U) & 255U) != 0U) request = true; /* Требует Route=0, собственный адрес, BOOT_CONTROL/ENTER_BOOT и ненулевую сессию. */ +} /* Завершает наблюдение входящего CAN без чтения отсутствующего payload. */ +bool can_boot_requested(void) { return request; } /* Сохраняет прежний API опроса приложения CANdle. */ +void can_boot_enter(void) { *(volatile uint32_t *)(uintptr_t)CAN_BOOT_REQUEST_ADDRESS = CAN_BOOT_REQUEST_MAGIC; __DSB(); NVIC_SystemReset(); } /* Записывает CANB в зарезервированное SRAM-слово до системного сброса. */ +static void process_frame(void) /* Принимает только проверенные короткие PING и BEGIN приложения. */ +{ /* Полный firmware flow после BEGIN обслуживает уже общий загрузчик из templates. */ + uint8_t payload = frame[7]; uint32_t checksum; /* Размер payload предварительно ограничен шестнадцатью байтами. */ + if (frame[2] != 1U || read32(frame + 8U + payload) != crc32(frame + 2U, (uint8_t)(6U + payload))) { return; } /* Не выполняет reset по кадру другой версии либо повреждённому CRC. */ + if (frame[3] == 0x0BU && payload == 16U) { can_boot_enter(); return; } /* Сохраняет существующий SETGUI FIRMWARE_BEGIN как запрос входа в загрузчик. */ + if (frame[3] == 1U && payload == 0U) { /* PING подтверждает наличие UART приложения без входа в обновление. */ + uint8_t reply[15] = {0xA5U, 0x5AU, 1U, 0x81U, frame[4], frame[5], 0U, 3U, 0U, 0U, 1U}; uint8_t index; /* Формирует прежний ACK PING с номером входящего запроса и трёхбайтовым результатом. */ + checksum = crc32(reply + 2U, 9U); for (index = 0U; index < 4U; ++index) reply[11U + index] = (uint8_t)(checksum >> (index * 8U)); /* Добавляет CRC32 LE после девяти защищаемых байтов ver/header/payload. */ + for (index = 0U; index < sizeof(reply); ++index) { while ((USART1->ISR & USART_ISR_TXE_TXFNF) == 0U) {} USART1->TDR = reply[index]; } /* Отправляет полный совместимый ответ USART1. */ + while ((USART1->ISR & USART_ISR_TC) == 0U) {} USART1->ICR = USART_ICR_TCCF; /* Дожидается последнего стоп-бита и очищает флаг завершения передачи. */ + } /* Остальные сообщения приложения не относятся к входу в boot и игнорируются. */ +} /* Завершает обработку валидного короткого кадра приложения. */ +void can_boot_uart_init(void) /* Сохраняет исходную разводку и IRQ-приём UART CANdle G474. */ +{ /* Этот код компилируется только в работающем приложении с CONFIG_CAN_BOOT_APP. */ + RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN; /* Включает GPIOA и USART1 в соответствующих clock-доменах G474. */ + GPIOA->MODER = (GPIOA->MODER & ~((3UL << 18U) | (3UL << 20U))) | (2UL << 18U) | (2UL << 20U); /* Переводит PA9 и PA10 в режим альтернативной функции. */ + GPIOA->AFR[1] = (GPIOA->AFR[1] & ~((15UL << 4U) | (15UL << 8U))) | (7UL << 4U) | (7UL << 8U); /* Назначает AF7 USART1 TX/RX согласно исходной плате CANdle. */ + USART1->BRR = (SystemCoreClock + 256000UL) / 512000UL; USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE | USART_CR1_UE; /* Сохраняет 512000 бод при исходном APB2=HCLK и приём по RXNE IRQ. */ + NVIC_SetPriority(USART1_IRQn, 2U); NVIC_EnableIRQ(USART1_IRQn); used = 0U; /* Сохраняет приоритет 2 исходного UART и очищает parser перед приёмом. */ +} /* Завершает настройку входа приложения через UART. */ +void can_boot_uart_poll(void) /* Принимает один октет, проверяет длину и синхронизацию до записи в малый буфер. */ +{ /* Длина 28 байт покрывает только PING и BEGIN; больших команд здесь нет. */ + uint32_t status = USART1->ISR; uint8_t byte, total; /* Сохраняет флаги USART до чтения RDR. */ + if ((status & (USART_ISR_ORE | USART_ISR_FE | USART_ISR_NE)) != 0U) { USART1->ICR = USART_ICR_ORECF | USART_ICR_FECF | USART_ICR_NECF; used = 0U; return; } /* Сбрасывает parser после аппаратной потери либо повреждения байта. */ + if ((status & USART_ISR_RXNE_RXFNE) == 0U) { return; } byte = (uint8_t)USART1->RDR; /* Не читает RDR без доступного октета. */ + if (used == 0U && byte != 0xA5U) { return; } if (used == 1U && byte != 0x5AU) { used = byte == 0xA5U ? 1U : 0U; return; } /* Ищет двухбайтовую сигнатуру A5 5A с сохранением возможного начала следующего кадра. */ + frame[used++] = byte; if (used < 8U) { return; } /* Накапливает только ограниченный буфер и ждёт полного восьмибайтового заголовка. */ + if (frame[6] != 0U || frame[7] > 16U) { used = 0U; return; } /* Запрещает длину больше шестнадцати байтов до дальнейшего накопления. */ + total = (uint8_t)(12U + frame[7]); if (used < total) { return; } process_frame(); used = 0U; /* Передаёт полный header/payload/CRC обработчику и начинает следующий короткий кадр. */ +} /* Завершает безопасный parser приложения. */ +void USART1_IRQHandler(void) { can_boot_uart_poll(); } /* Сохраняет прежний экспорт IRQ, используемый startup приложения CANdle. */ diff --git a/c/protocan-boot/ports/stm32g474/boot_main.c b/c/protocan-boot/ports/stm32g474/boot_main.c new file mode 100644 index 0000000..2f8e508 --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/boot_main.c @@ -0,0 +1,66 @@ +#include "pcan_boot_stm32g474.h" /* Подключает FDCAN/Flash порт и единственную ProtoCAN state machine templates. */ +#include "../../../rs485-boot/include/rs485_boot.h" /* Повторно использует общий SETGUI v1 UART updater. */ +#include "device.h" /* Тактирование и GPIO FDCAN остаются аппаратной привязкой исходного board-проекта. */ +#include /* Копирует проверенные диапазоны Flash для повторов UART-блоков. */ +static FDCAN_HandleTypeDef can; static pcan_boot_stm32_t updater; static rs485_boot_t uart_boot; static bool can_started; /* Сохраняет состояния двух транспортов и факт успешного аппаратного запуска FDCAN. */ +static __attribute__((naked, noreturn)) void enter_app(uint32_t sp __attribute__((unused)), uint32_t pc __attribute__((unused))) /* Не обращается к старому C-стеку после замены MSP. */ +{ /* AAPCS передаёт исходный MSP приложения в r0 и Thumb entry в r1. */ + __asm volatile("msr msp, r0\n" "movs r2, #0\n" "msr control, r2\n" "dsb\n" "isb\n" "cpsie i\n" "bx r1\n"); /* Согласует привилегированный режим и конвейер до безвозвратного перехода по новому вектору. */ +} /* Завершает naked handoff без эпилога C. */ +static void jump_app(void) /* Отключает загрузочные интерфейсы перед запуском установленного приложения. */ +{ /* Структурная проверка векторов выполнена вызывающим main. */ + const uint32_t *vectors = (const uint32_t *)(uintptr_t)CAN_BOOT_APP_ADDRESS; uint32_t sp = vectors[0], pc = vectors[1], index; /* Сохраняет новые значения до отключения прерываний и смены стека. */ + __disable_irq(); SysTick->CTRL = 0U; USART1->CR1 = 0U; if (can_started) (void)HAL_FDCAN_Stop(&can); /* Не допускает работы загрузочного UART/CAN и SysTick после handoff. */ + for (index = 0U; index < 8U; ++index) { NVIC->ICER[index] = 0xFFFFFFFFUL; NVIC->ICPR[index] = 0xFFFFFFFFUL; } /* Снимает внешние enable/pending IRQ записью W1C. */ + SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk | SCB_ICSR_PENDSVCLR_Msk; SCB->VTOR = CAN_BOOT_APP_ADDRESS; /* Очищает системные pending IRQ и согласует VTOR с linker приложения. */ + enter_app(sp, pc); /* Передаёт управление без обращения к старому C-стеку. */ +} /* Завершает аппаратную подготовку запуска приложения. */ +static bool uart_transmit(void *user, const uint8_t *data, uint16_t length) /* Передаёт совместимые ответы SETGUI v1 через USART1. */ +{ /* Транспорт TTL не управляет DE внешнего RS-485 трансивера. */ + uint16_t index; (void)user; for (index = 0U; index < length; ++index) { while ((USART1->ISR & USART_ISR_TXE_TXFNF) == 0U) {} USART1->TDR = data[index]; } /* Передаёт полный сформированный кадр без чтения за его длиной. */ + while ((USART1->ISR & USART_ISR_TC) == 0U) {} USART1->ICR = USART_ICR_TCCF; return true; /* Дожидается последнего стоп-бита до возможного reset после END. */ +} /* Завершает синхронную UART передачу. */ +static bool uart_erase(void *user, uint32_t size) { (void)user; return updater.boot.state == PCAN_BOOT_STATE_IDLE && pcan_boot_stm32g474_erase(size); } /* Не позволяет UART стереть Flash при открытой CAN-сессии. */ +static bool uart_write(void *user, uint32_t offset, const uint8_t *data, uint16_t length) { (void)user; return pcan_boot_stm32g474_write(uart_boot.image_size, offset, data, length); } /* Использует тот же doubleword writer, что CAN DATA. */ +static bool uart_read(void *user, uint32_t offset, uint8_t *data, uint16_t length) /* Подтверждает повторы UART-блоков чтением сохранённых данных. */ +{ /* Проверяет размеры вычитанием, чтобы не переполнить адресное сложение. */ + (void)user; if (data == NULL || offset > CAN_BOOT_APP_SIZE || length > CAN_BOOT_APP_SIZE - offset) { return false; } /* Не допускает чтение за пределами 480-КиБ области. */ + (void)memcpy(data, (const void *)(uintptr_t)(CAN_BOOT_APP_ADDRESS + offset), length); return true; /* Возвращает только проверенный диапазон Flash. */ +} /* Завершает readback повторного UART-запроса. */ +static bool uart_valid(void *user, uint32_t size, uint32_t crc) { (void)user; return pcan_boot_stm32g474_image_valid(size, crc); } /* Перед END проверяет векторы и настоящий CRC Flash общим портом. */ +static void uart_reboot(void *user) { (void)user; NVIC_SystemReset(); } /* UART callback вызывается после физически завершённого ответа END. */ +static void uart_init(void) /* Сохраняет исходные PA9/PA10 AF7, 512000 бод и общий SETGUI v1 updater. */ +{ /* Аппаратные частоты уже настроены board-функцией device_sysclock_config. */ + GPIO_InitTypeDef gpio = {0}; rs485_boot_config_t config = {CAN_BOOT_APP_ADDRESS, CAN_BOOT_APP_SIZE, RS485_BOOT_MAX_BLOCK}; rs485_boot_port_t callbacks = {0}; /* Полностью определяет структуры текущих HAL и UART API. */ + __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_USART1_CLK_ENABLE(); gpio.Pin = GPIO_PIN_9 | GPIO_PIN_10; gpio.Mode = GPIO_MODE_AF_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &gpio); /* Назначает исходные TX/RX выводы без изменения CAN PB8/PB9. */ + USART1->BRR = (HAL_RCC_GetPCLK2Freq() + 256000UL) / 512000UL; USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_FIFOEN | USART_CR1_UE; /* Рассчитывает скорость от фактического PCLK2 и включает polling UART с FIFO. */ + callbacks.transmit = uart_transmit; callbacks.erase = uart_erase; callbacks.write = uart_write; callbacks.read = uart_read; callbacks.image_valid = uart_valid; callbacks.reboot = uart_reboot; /* Подключает общий Flash writer и проверку образа вместо локальной реализации UART flow. */ + (void)rs485_boot_init(&uart_boot, &config, &callbacks, NULL); /* Создаёт отдельную RAM-сессию UART с прежним wire-протоколом. */ +} /* Завершает настройку UART восстановления. */ +static bool fdcan_init(void) /* Сохраняет исходные 48 МГц kernel clock и скорость classic CAN 500 кбит/с. */ +{ /* GPIO FDCAN PB8/PB9 AF9 включает board-функция HAL_FDCAN_MspInit. */ + pcan_boot_config_t config = {0}; can.Instance = FDCAN1; can.Init.ClockDivider = FDCAN_CLOCK_DIV1; can.Init.FrameFormat = FDCAN_FRAME_CLASSIC; can.Init.Mode = FDCAN_MODE_NORMAL; can.Init.AutoRetransmission = ENABLE; /* Выбирает единственный выделенный FDCAN1 без CAN FD/BRS и с автоматическим повтором TX. */ + can.Init.NominalPrescaler = 6U; can.Init.NominalSyncJumpWidth = 2U; can.Init.NominalTimeSeg1 = 13U; can.Init.NominalTimeSeg2 = 2U; /* 48 МГц / 6 / (1+13+2) дают ровно 500000 бит/с. */ + can.Init.DataPrescaler = 6U; can.Init.DataSyncJumpWidth = 2U; can.Init.DataTimeSeg1 = 13U; can.Init.DataTimeSeg2 = 2U; /* Полностью инициализирует data timing, хотя в classic режиме он не используется. */ + can.Init.StdFiltersNbr = 0U; can.Init.ExtFiltersNbr = 2U; can.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; /* Выделяет адресный и broadcast-discovery фильтры общему порту. */ + if (HAL_FDCAN_Init(&can) != HAL_OK) { return false; } config.device_type = CAN_BOOT_DEVICE_TYPE; config.device_id = CAN_BOOT_DEVICE_ID; config.ack_window = 16U; config.session_timeout_ms = 30000UL; /* Сохраняет исходный адрес 7:15 и окно ACK, добавляя тайм-аут RAM-сессии 30 секунд. */ + return pcan_boot_stm32g474_init(&updater, &can, &config); /* Инициализирует единую state machine ProtoCAN и проверяет геометрию Flash. */ +} /* Завершает настройку FDCAN без локальной копии CAN-протокола. */ +static void service_interfaces(void) /* Обслуживает оба транспорта без одновременной записи одной Flash-области. */ +{ /* Каждый вызов ограничивает обработку UART шестьюдесятью четырьмя октетами. */ + uint32_t count; for (count = 0U; count < 64U; ++count) { /* Не позволяет постоянному UART-потоку захватить главный цикл целиком. */ + uint32_t status = USART1->ISR; uint8_t byte; if ((status & (USART_ISR_ORE | USART_ISR_FE | USART_ISR_NE)) != 0U) USART1->ICR = USART_ICR_ORECF | USART_ICR_FECF | USART_ICR_NECF; /* Снимает аппаратные ошибки USART перед дальнейшим приёмом. */ + if ((status & USART_ISR_RXNE_RXFNE) == 0U) { break; } byte = (uint8_t)USART1->RDR; rs485_boot_feed(&uart_boot, &byte, 1U); /* Передаёт доступный октет общему UART parser. */ + } /* Завершает ограниченный пакет UART. */ + if (can_started && uart_boot.state != RS485_BOOT_RECEIVING) pcan_boot_stm32g474_poll(&updater); /* Во время записи UART запрещает второй транспорт, в остальных состояниях обслуживает CAN и discovery. */ +} /* Завершает мультиплексирование загрузочных интерфейсов. */ +int main(void) /* Подключает исходный board startup CANdle к общим загрузочным библиотекам templates. */ +{ /* Linker и initial MSP должны исключать последние восемь байт SRAM со словом запроса. */ + bool requested = *(volatile uint32_t *)(uintptr_t)CAN_BOOT_REQUEST_ADDRESS == CAN_BOOT_REQUEST_MAGIC; *(volatile uint32_t *)(uintptr_t)CAN_BOOT_REQUEST_ADDRESS = 0U; /* Потребляет сохранённый запрос CANB до настройки периферии. */ + HAL_Init(); device_sysclock_config(); uart_init(); can_started = fdcan_init(); /* Сохраняет исходную последовательность clock/GPIO/UART/FDCAN и доступность UART при отказе CAN. */ + if (!requested && pcan_boot_stm32g474_vectors_valid(CAN_BOOT_APP_SIZE)) { /* Сохраняет исходное десятисекундное окно входа в обновление. */ + uint32_t started = HAL_GetTick(); while ((uint32_t)(HAL_GetTick() - started) < 10000U) { service_interfaces(); if (updater.boot.state != PCAN_BOOT_STATE_IDLE || uart_boot.state != RS485_BOOT_IDLE) { requested = true; break; } } /* Обслуживает UART/CAN с учётом переполнения tick, без входа в обновление по одному discovery. */ + if (!requested) jump_app(); /* Передаёт управление установленному приложению после окна ожидания. */ + } /* Завершает обычную политику запуска без постоянного manifest. */ + for (;;) service_interfaces(); /* Остаётся доступным для адресного обновления и восстановления через UART. */ +} /* Завершает общий boot main STM32G474VET6. */ diff --git a/c/protocan-boot/ports/stm32g474/boot_profile.h b/c/protocan-boot/ports/stm32g474/boot_profile.h new file mode 100644 index 0000000..319f7cf --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/boot_profile.h @@ -0,0 +1,17 @@ +#ifndef PCAN_BOOT_G474_PROFILE_H /* Согласует приложение CANdle и самостоятельный CAN/UART-загрузчик. */ +#define PCAN_BOOT_G474_PROFILE_H /* Исключает повторное определение общей аппаратной конфигурации. */ +#include /* Объявляет булевы признаки расширенного кадра и запроса обновления. */ +#include /* Объявляет wire-типы CAN ID и DLC публичного приложения. */ +#define CAN_BOOT_APP_ADDRESS 0x08008000UL /* Исходный CANdle G474 резервирует 32 КиБ Flash под загрузчик. */ +#define CAN_BOOT_FLASH_END 0x08080000UL /* Верхняя исключённая граница 512 КиБ Flash STM32G474VET6. */ +#define CAN_BOOT_APP_SIZE (CAN_BOOT_FLASH_END - CAN_BOOT_APP_ADDRESS) /* Единственный слот приложения содержит 480 КиБ. */ +#define CAN_BOOT_REQUEST_ADDRESS 0x20013FFCUL /* Исходный запрос CANB хранится в последнем слове используемых 80 КиБ SRAM; linker исключает последние восемь байт. */ +#define CAN_BOOT_REQUEST_MAGIC 0x43414E42UL /* Сохраняет совместимый маркер CANB для входа из работающего приложения. */ +#define CAN_BOOT_DEVICE_TYPE 7U /* Сохраняет исходный тип устройства CANdle G474 в ProtoCAN. */ +#define CAN_BOOT_DEVICE_ID 15U /* Сохраняет исходный адрес устройства CANdle G474. */ +void can_boot_observe(uint32_t can_id, bool extended, uint8_t dlc); /* Отмечает адресный ENTER_BOOT из общего CAN-диспетчера приложения. */ +bool can_boot_requested(void); /* Возвращает отложенный запрос, чтобы main приложения выполнил reset из безопасного контекста. */ +void can_boot_enter(void); /* Сохраняет одноразовый запрос в SRAM и вызывает системный reset. */ +void can_boot_uart_init(void); /* Настраивает исходный USART1 PA9/PA10, 512000 бод, и приём через IRQ. */ +void can_boot_uart_poll(void); /* Разбирает один байт PING/BEGIN SETGUI v1 в работающем приложении. */ +#endif /* Завершает профиль и совместимый API входа CANdle G474. */ diff --git a/c/protocan-boot/ports/stm32g474/boot_startup.c b/c/protocan-boot/ports/stm32g474/boot_startup.c new file mode 100644 index 0000000..7204d9b --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/boot_startup.c @@ -0,0 +1,30 @@ +#include "boot_profile.h" /* Использует общий адресный профиль CANdle G474 и исключённое слово SRAM-запроса. */ +#include "stm32g4xx.h" /* Получает CMSIS регистры и SystemInit выбранного STM32G474. */ +#include "stm32g4xx_hal.h" /* Связывает SysTick самостоятельного загрузчика с HAL_GetTick. */ +extern uint32_t __StackTop, __data_start, __data_end, __data_source, __bss_start, __bss_end; /* GNU linker задаёт границы runtime-инициализации и вершину отдельного стека. */ +extern int main(void); /* Передаёт управление общему boot main после инициализации C runtime. */ +void SysTick_Handler(void); /* Объявляет публичное имя обработчика до определения, как требует standalone startup. */ +__attribute__((noreturn)) void Reset_Handler(void); /* Объявляет безвозвратную аппаратную точку входа GNU/Keil. */ +static __attribute__((noreturn)) void fault(void) { for (;;) {} } /* Не выполняет произвольный переход при необработанном IRQ либо исключении загрузчика. */ +void SysTick_Handler(void) { HAL_IncTick(); } /* Обеспечивает реальные миллисекундные тайм-ауты UART/FDCAN/HAL. */ +__attribute__((noreturn)) void Reset_Handler(void) /* Сохраняет совместимость исходного startup с Arm Compiler 6 и GNU toolchain. */ +{ /* На Arm Compiler runtime и scatter-loading предоставляет библиотечная функция __main. */ +#if defined(__ARMCC_VERSION) /* Выбирает штатный C runtime Keil, не дублируя ZI/RW инициализацию. */ + extern void __main(void); SystemInit(); __main(); /* Настраивает базовый MCU и запускает runtime перед main. */ +#else /* GNU-вариант использует символы исходного linker script CANdle. */ + uint32_t *source = &__data_source, *destination = &__data_start; /* Сохраняет Flash-источник и SRAM-назначение инициализированных данных. */ + while (destination < &__data_end) *destination++ = *source++; /* Копирует только объявленную секцию data, не затрагивая исключённый SRAM-маркер. */ + for (destination = &__bss_start; destination < &__bss_end; ++destination) *destination = 0U; /* Обнуляет ZI только внутри RAM-региона, согласованного с linker. */ + SystemInit(); (void)main(); /* Запускает базовую конфигурацию MCU и общую загрузочную программу. */ +#endif /* Завершает выбор C runtime для двух поддерживаемых toolchain. */ + for (;;) {} /* Не допускает возврат из main в несуществующий вызывающий код reset. */ +} /* Завершает Reset_Handler самостоятельного загрузчика. */ +typedef void (*vector_t)(void); /* Описывает Thumb-обработчик аппаратного исключения Cortex-M4. */ +static __attribute__((used, section(".vectors"))) const vector_t vectors[118] = { /* Сохраняет таблицу из 118 записей в начале 32-КиБ загрузочной Flash без ненужного внешнего символа. */ +#if defined(__ARMCC_VERSION) /* Keil получает fixed MSP, совпадающий с ARM_LIB_STACK в общем scatter script. */ + (vector_t)0x20013FF8UL, Reset_Handler, fault, fault, /* Резервирует последние восемь байт SRAM, чтобы пролог main не уничтожил маркер CANB до чтения. */ +#else /* GNU linker вычисляет вершину стека по RAM_SIZE, также уменьшенному на восемь байт. */ + (vector_t)&__StackTop, Reset_Handler, fault, fault, /* Использует linker-определение без жёсткого адреса для GNU сборки. */ +#endif /* Завершает выбор совместимого initial MSP. */ + [4 ... 14] = fault, [15] = SysTick_Handler, [16 ... 117] = fault /* Разрешает только SysTick; загрузочные UART/FDCAN обслуживаются опросом. */ +}; /* Завершает извлечённую таблицу векторов CANdle G474. */ diff --git a/c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.c b/c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.c new file mode 100644 index 0000000..6c61357 --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.c @@ -0,0 +1,104 @@ +#include "pcan_boot_stm32g474.h" /* Подключает семейные HAL API, карту памяти и состояние общего автомата. */ +#include /* Предоставляет безопасную упаковку doubleword и коротких CAN-ответов. */ +static const uint32_t dlc_values[9] = {FDCAN_DLC_BYTES_0, FDCAN_DLC_BYTES_1, FDCAN_DLC_BYTES_2, FDCAN_DLC_BYTES_3, FDCAN_DLC_BYTES_4, FDCAN_DLC_BYTES_5, FDCAN_DLC_BYTES_6, FDCAN_DLC_BYTES_7, FDCAN_DLC_BYTES_8}; /* Изолирует различное кодирование DLC в старых и новых версиях HAL, не предполагая сдвиг 0 либо 16. */ +static bool geometry(uint32_t *page_size, uint32_t *bank_size) /* Не позволяет неподдерживаемой геометрии изменить загрузочную область. */ +{ /* Профиль предназначен только для STM32G474VET6 с 512 КиБ Flash. */ + bool dual = (FLASH->OPTR & FLASH_OPTR_DBANK) != 0U; /* DBANK выбирает две страницы по 2 КиБ либо один банк со страницами по 4 КиБ. */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); /* Гарантирует доступность MEMRMP перед проверкой bank swap даже вне board-функции CANdle. */ + if (*(const uint16_t *)(uintptr_t)FLASHSIZE_BASE != 512U || (FLASH->OPTR & FLASH_OPTR_BFB2) != 0U || (SYSCFG->MEMRMP & SYSCFG_MEMRMP_FB_MODE) != 0U) { return false; } /* Требует известную физическую ёмкость и прямое соответствие логических адресов физическим банкам. */ + *page_size = dual ? 2048U : 4096U; *bank_size = dual ? 262144UL : 524288UL; /* RM0440: страницы 2/4 КиБ и банки 256/512 КиБ соответственно режиму DBANK. */ + return true; /* Обе исходные конфигурации DBANK поддерживаются без изменения Option Bytes. */ +} /* Завершает проверку геометрии перед erase и program. */ +bool pcan_boot_stm32g474_vectors_valid(uint32_t size) /* Проверяет только допустимость таблицы векторов. */ +{ /* Используемая SRAM 80 КиБ соответствует исходному linker CANdle G474. */ + const uint32_t *vectors = (const uint32_t *)(uintptr_t)CAN_BOOT_APP_ADDRESS; uint32_t sp, pc; /* Два первых слова содержат MSP и Thumb reset handler. */ + if (size < 8U || size > CAN_BOOT_APP_SIZE) { return false; } sp = vectors[0]; pc = vectors[1]; /* Проверяет размер до чтения аппаратно отображённой Flash. */ + return sp > 0x20000000UL && sp <= 0x20014000UL && (sp & 7U) == 0U && (pc & 1U) != 0U && (pc & ~1UL) >= CAN_BOOT_APP_ADDRESS && (pc & ~1UL) < CAN_BOOT_APP_ADDRESS + size; /* Не принимает стек вне SRAM, невыровненный MSP или reset vector за полезным образом. */ +} /* Завершает структурную проверку без чтения остальной Flash. */ +bool pcan_boot_stm32g474_image_valid(uint32_t size, uint32_t crc) /* Подтверждает реальную Flash перед VERIFY, COMMIT или UART END. */ +{ /* Полезная длина не включает дополнение FF последнего doubleword. */ + return pcan_boot_stm32g474_vectors_valid(size) && pcan_boot_crc32_update(0U, (const uint8_t *)(uintptr_t)CAN_BOOT_APP_ADDRESS, size) == crc; /* Использует общий полином ProtoCAN вместо локальной копии CAN-CRC. */ +} /* Завершает независимую проверку сохранённого образа. */ +bool pcan_boot_stm32g474_erase(uint32_t size) /* Стирает страницы 480-КиБ single-slot области без затрагивания загрузчика. */ +{ /* Bank swap отвергается, а настройки Option Bytes остаются владельцу устройства. */ + uint32_t page_size, bank_size, address, end; bool ok = true; /* Сохраняет аппаратную геометрию и результат до восстановления LOCK. */ + if (size < 8U || size > CAN_BOOT_APP_SIZE || !geometry(&page_size, &bank_size)) { return false; } /* Проверяет полезную длину и физическую карту до разблокировки Flash. */ + end = CAN_BOOT_APP_ADDRESS + ((size + page_size - 1U) & ~(page_size - 1U)); /* Округляет конец вверх к странице текущего DBANK-режима. */ + if (end > CAN_BOOT_FLASH_END || HAL_FLASH_Unlock() != HAL_OK) { return false; } /* Не стирает Flash за физической ёмкостью профиля. */ + for (address = CAN_BOOT_APP_ADDRESS; address < end; address += page_size) { /* Обходит только страницы, покрывающие полезный образ. */ + FLASH_EraseInitTypeDef erase = {0}; uint32_t error = 0U, offset = address - FLASH_BASE; /* Определяет физическое положение страницы относительно начала Flash. */ + erase.TypeErase = FLASH_TYPEERASE_PAGES; erase.Banks = offset >= bank_size ? FLASH_BANK_2 : FLASH_BANK_1; /* Разрешает адресовать второй банк только в поддерживаемой dual-bank карте. */ + erase.Page = (offset % bank_size) / page_size; erase.NbPages = 1U; /* Номер страницы считается отдельно внутри физического банка. */ + if (HAL_FLASHEx_Erase(&erase, &error) != HAL_OK) { ok = false; break; } /* Прерывает стирание при тайм-ауте, защите либо аппаратной ошибке страницы. */ + } /* Завершает ограниченный обход страниц. */ + if (HAL_FLASH_Lock() != HAL_OK) { ok = false; } return ok; /* Обязательно восстанавливает блокировку и не подтверждает отказ LOCK. */ +} /* Завершает стирание с поддержкой single/dual bank STM32G474VE. */ +bool pcan_boot_stm32g474_write(uint32_t image_size, uint32_t offset, const uint8_t *data, uint16_t length) /* Записывает выровненные doubleword без повторного программирования ECC-слова. */ +{ /* Один writer используется обоими загрузочными транспортами. */ + uint32_t page_size, bank_size, done = 0U; bool ok = true; /* Хранит проверенную геометрию и фактическое смещение полезных байтов. */ + if (image_size < 8U || image_size > CAN_BOOT_APP_SIZE || data == NULL || length == 0U || offset > image_size || length > image_size - offset || (offset & 7U) != 0U || !geometry(&page_size, &bank_size)) { return false; } /* Проверяет адреса вычитанием, исключая переполнение и неизвестную физическую геометрию. */ + if ((length & 7U) != 0U && offset + length != image_size) { return false; } /* Неполное 64-битное слово допускается только в конце полезного образа. */ + if (HAL_FLASH_Unlock() != HAL_OK) { return false; } /* Не начинает запись при отказе аппаратной разблокировки. */ + while (done < length) { /* Разбивает UART/CAN payload на аппаратные doubleword по восемь байт. */ + uint64_t value = UINT64_MAX; uint32_t count = length - done, address = CAN_BOOT_APP_ADDRESS + offset + done; /* Значение FF сохраняет незаданные хвостовые октеты стёртыми. */ + if (count > 8U) { count = 8U; } (void)memcpy(&value, data + done, count); /* Не читает за полезной длиной неполного последнего блока. */ + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, value) != HAL_OK || memcmp((const void *)(uintptr_t)address, &value, 8U) != 0) { ok = false; break; } /* HAL G4 синхронизирует Flash cache, а порт проверяет аппаратную запись и весь doubleword readback. */ + done += count; /* Продвигается только на число полезных октетов, не включая FF в CRC. */ + } /* Завершает запись ограниченного payload. */ + if (HAL_FLASH_Lock() != HAL_OK) { ok = false; } return ok; /* Восстанавливает аппаратную блокировку после успеха и отказов записи. */ +} /* Завершает защищённое программирование G474. */ +static bool send_frame(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Подтверждает физическую передачу FDCAN, включая ответ перед reset. */ +{ /* Порт владеет выделенным FDCAN1 без конкурирующих отправителей или TX IRQ. */ + pcan_boot_stm32_t *port = user; FDCAN_HandleTypeDef *can = port->can; FDCAN_TxHeaderTypeDef header = {0}; /* Получает handle и обнуляет все поля аппаратного заголовка. */ + uint8_t bytes[8] = {0}; uint32_t started = HAL_GetTick(), buffer; /* Не позволяет HAL читать за коротким служебным payload. */ + if (length > 8U || id > 0x1FFFFFFFUL || (length != 0U && data == NULL)) { return false; } if (length != 0U) (void)memcpy(bytes, data, length); /* Проверяет внешний размер до копирования в полный classic CAN-буфер. */ + while (HAL_FDCAN_GetTxFifoFreeLevel(can) == 0U) if ((uint32_t)(HAL_GetTick() - started) >= 100U) { return false; } /* Ограничивает ожидание места в TX FIFO ста миллисекундами. */ + header.Identifier = id; header.IdType = FDCAN_EXTENDED_ID; header.TxFrameType = FDCAN_DATA_FRAME; header.DataLength = dlc_values[length]; /* Формирует расширенный адресный кадр с совместимым кодированием DLC текущего HAL. */ + header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; header.BitRateSwitch = FDCAN_BRS_OFF; header.FDFormat = FDCAN_CLASSIC_CAN; header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; /* ProtoCAN Boot использует classic CAN без BRS и не требует отдельного TX Event FIFO. */ + if (HAL_FDCAN_AddMessageToTxFifoQ(can, &header, bytes) != HAL_OK) { return false; } buffer = HAL_FDCAN_GetLatestTxFifoQRequestBuffer(can); /* Запоминает bitmask именно поставленного в очередь TX-буфера. */ + while (HAL_FDCAN_IsTxBufferMessagePending(can, buffer) != 0U) if ((uint32_t)(HAL_GetTick() - started) >= 100U) { (void)HAL_FDCAN_AbortTxRequest(can, buffer); return false; } /* Отменяет неподтверждённый TX вместо перезапуска MCU при отсутствии ACK шины. */ + return buffer != 0U && (can->Instance->TXBTO & buffer) != 0U; /* Отличает завершённую передачу от abort по аппаратному флагу transmission occurred. */ +} /* Завершает надёжную отправку ответа FDCAN. */ +static bool erase_slot(void *user, pcan_boot_byte_t slot) /* Подключает страницу Flash к единственному логическому слоту A. */ +{ /* Разрешение reset сбрасывается до изменения Flash. */ + pcan_boot_stm32_t *port = user; bool ok; if (slot != 0U) { return false; } port->ready = false; port->written = 0U; /* Не допускает A/B-адресацию и прежний COMMIT после начала новой записи. */ + (void)pcan_boot_report_busy(&port->boot, PCAN_BOOT_CMD_ERASE, HAL_GetTick()); ok = pcan_boot_stm32g474_erase(port->boot.manifest.image_size); /* Предупреждает клиента перед синхронным стиранием выбранных страниц. */ + if (ok) { (void)pcan_boot_report_busy(&port->boot, PCAN_BOOT_CMD_ERASE, HAL_GetTick()); } return ok; /* Продлевает сессию после завершения длительной Flash-операции. */ +} /* Завершает callback стирания G474. */ +static bool write_slot(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Подключает защищённый writer к общему CAN-автомату. */ +{ /* Общий автомат проверяет номера восьмибайтовых блоков, порт повторно проверяет фактическое смещение. */ + pcan_boot_stm32_t *port = user; if (slot != 0U || offset != port->written || length > 8U || !pcan_boot_stm32g474_write(port->boot.manifest.image_size, offset, data, length)) { return false; } /* Не подтверждает неправильный слот, порядок или отказ Flash. */ + port->written += length; return true; /* Считает только полностью записанные полезные октеты. */ +} /* Завершает callback записи G474. */ +static pcan_boot_status_t verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest) /* Отличает неверный образ от ошибки readback CRC. */ +{ /* Сохраняет точные статусы текущего общего API. */ + pcan_boot_stm32_t *port = user; if (slot != 0U || manifest == NULL || port->written != manifest->image_size || !pcan_boot_stm32g474_vectors_valid(manifest->image_size)) return PCAN_BOOT_STATUS_INVALID_SIZE; /* Не принимает неполную запись или reset handler вне полезного образа. */ + return pcan_boot_stm32g474_image_valid(manifest->image_size, manifest->image_crc32) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_CRC_ERROR; /* Перечитывает реальную Flash вместо доверия CRC потока. */ +} /* Завершает VERIFY G474. */ +static bool commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *manifest) { pcan_boot_stm32_t *port = user; port->ready = verify(user, slot, manifest) == PCAN_BOOT_STATUS_OK; return port->ready; } /* Активирует проверенный образ только в RAM, без имитации постоянных A/B-метаданных. */ +static bool can_reboot(void *user) { pcan_boot_stm32_t *port = user; return port->ready && port->boot.state == PCAN_BOOT_STATE_COMMITTED; } /* Разрешает протокольный reset только после VERIFY и COMMIT. */ +static void reboot(void *user) { if (can_reboot(user)) NVIC_SystemReset(); } /* Общий автомат вызывает reset только после подтверждённого TX ответа. */ +bool pcan_boot_stm32g474_init(pcan_boot_stm32_t *port, FDCAN_HandleTypeDef *can, const pcan_boot_config_t *config) /* Настраивает current ProtoCAN Boot v1 поверх подготовленного FDCAN1. */ +{ /* GPIO, kernel clock 48 МГц и HAL_FDCAN_Init остаются в board-проекте. */ + pcan_boot_config_t single; pcan_boot_port_t callbacks = {0}; FDCAN_FilterTypeDef filter = {0}; uint32_t page_size, bank_size; /* Подготавливает полностью определённые структуры текущего API и HAL. */ + if (port == NULL || can == NULL || config == NULL || can->Instance != FDCAN1 || can->Init.ExtFiltersNbr < 2U || !geometry(&page_size, &bank_size)) { return false; } /* Не запускает порт без двух выделенных extended-фильтров или поддерживаемой Flash-геометрии. */ + single = *config; single.active_slot = 0U; single.slot_count = 1U; single.max_image_size = CAN_BOOT_APP_SIZE; /* Принудительно сохраняет исходный single-slot профиль 480 КиБ. */ + callbacks.send = send_frame; callbacks.erase_slot = erase_slot; callbacks.write_slot = write_slot; callbacks.verify_status = verify; callbacks.set_pending_slot = commit; callbacks.can_reboot = can_reboot; callbacks.reboot = reboot; /* Подключает Flash, readback и согласованную политику reset к единственному общему автомату. */ + (void)memset(port, 0, sizeof(*port)); port->can = can; if (!pcan_boot_init(&port->boot, &single, &callbacks, port)) { port->can = NULL; return false; } /* Делает неуспешно настроенный порт безопасным для последующего poll. */ + filter.IdType = FDCAN_EXTENDED_ID; filter.FilterIndex = 0U; filter.FilterType = FDCAN_FILTER_MASK; filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* Первый аппаратный фильтр обслуживает все сообщения собственного адреса. */ + filter.FilterID1 = pcan_boot_make_id(0U, 0U, single.device_type, single.device_id, 0U, 0U); filter.FilterID2 = 0x0FF00000UL; /* Не маскирует приоритет; проверяет только Route/Type/ID. */ + if (HAL_FDCAN_ConfigFilter(can, &filter) != HAL_OK) { port->can = NULL; return false; } /* Не использует CAN с неподтверждённым адресным фильтром. */ + filter.FilterIndex = 1U; filter.FilterID1 = pcan_boot_make_id(0U, 0U, 7U, 15U, PCAN_BOOT_MSG_DISCOVERY, 0U); filter.FilterID2 = 0x0FFFFFFFUL; /* Второй фильтр допускает только штатный broadcast discovery, исключая broadcast-запись. */ + if (HAL_FDCAN_ConfigFilter(can, &filter) != HAL_OK || HAL_FDCAN_ConfigGlobalFilter(can, FDCAN_REJECT, FDCAN_REJECT, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE) != HAL_OK || HAL_FDCAN_Start(can) != HAL_OK) { port->can = NULL; return false; } /* Отвергает прочие standard/extended/remote кадры и проверяет аппаратный запуск. */ + return true; /* Flash-профиль, оба фильтра и FDCAN готовы к общему автомату. */ +} /* Завершает инициализацию reusable G474-порта. */ +void pcan_boot_stm32g474_poll(pcan_boot_stm32_t *port) /* Обслуживает транспорт и таймеры ядра из основного цикла. */ +{ /* Не вызывается из IRQ из-за синхронных операций Flash. */ + FDCAN_HandleTypeDef *can; uint32_t count; if (port == NULL || port->can == NULL) { return; } can = port->can; pcan_boot_poll(&port->boot, HAL_GetTick()); /* Проверяет состояние до доступа к handle и обновляет часы без входящего кадра. */ + for (count = 0U; count < 3U && HAL_FDCAN_GetRxFifoFillLevel(can, FDCAN_RX_FIFO0) != 0U; ++count) { /* Ограничивает время обработки нагруженного CAN на одну итерацию main. */ + FDCAN_RxHeaderTypeDef header; uint8_t data[64], length; /* Защищает память даже при ошибочно принятом CAN FD payload до 64 байт. */ + if (HAL_FDCAN_GetRxMessage(can, FDCAN_RX_FIFO0, &header, data) != HAL_OK) break; /* Не декодирует неуспешно принятый аппаратный кадр. */ + for (length = 0U; length <= 8U && header.DataLength != dlc_values[length]; ++length) {} /* Декодирует только classic DLC через значения текущего HAL. */ + if (length <= 8U && header.IdType == FDCAN_EXTENDED_ID && header.RxFrameType == FDCAN_DATA_FRAME && header.FDFormat == FDCAN_CLASSIC_CAN && header.Identifier <= 0x1FFFFFFFUL) { pcan_boot_poll(&port->boot, HAL_GetTick()); (void)pcan_boot_process(&port->boot, header.Identifier, data, length); } /* Проверяет внешний формат и передаёт полный актуальный ProtoCAN flow единому ядру. */ + } /* Завершает ограниченный пакет RX-кадров. */ +} /* Завершает обслуживание reusable G474-порта. */ diff --git a/c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.h b/c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.h new file mode 100644 index 0000000..0824862 --- /dev/null +++ b/c/protocan-boot/ports/stm32g474/pcan_boot_stm32g474.h @@ -0,0 +1,12 @@ +#ifndef PCAN_BOOT_STM32G474_H /* Защищает HAL FDCAN-порт от повторного включения. */ +#define PCAN_BOOT_STM32G474_H /* Обозначает активный интерфейс профиля STM32G474VET6. */ +#include "stm32g4xx_hal.h" /* Подключает реальные типы FDCAN/Flash STM32CubeG4. */ +#include "boot_profile.h" /* Получает аппаратные границы и адрес CAN исходного CANdle G474. */ +#include "../stm32-common/pcan_boot_stm32.h" /* Использует общее состояние single-slot порта и актуальный API ядра. */ +bool pcan_boot_stm32g474_init(pcan_boot_stm32_t *port, FDCAN_HandleTypeDef *can, const pcan_boot_config_t *config); /* Подключает готовый FDCAN1 с двумя extended-фильтрами, запускает адресный ProtoCAN Boot v1. */ +void pcan_boot_stm32g474_poll(pcan_boot_stm32_t *port); /* Обслуживает ограниченный пакет кадров и таймеры ядра из основного цикла. */ +bool pcan_boot_stm32g474_erase(uint32_t size); /* Стирает страницы приложения при поддерживаемой геометрии 512 КиБ и отключённой перестановке банков. */ +bool pcan_boot_stm32g474_write(uint32_t image_size, uint32_t offset, const uint8_t *data, uint16_t length); /* Позволяет CAN и UART использовать один doubleword writer с проверкой полезной длины. */ +bool pcan_boot_stm32g474_image_valid(uint32_t size, uint32_t crc); /* Проверяет readback CRC, MSP и reset vector внутри фактической длины образа. */ +bool pcan_boot_stm32g474_vectors_valid(uint32_t size); /* Проверяет только векторы; не доказывает целостность после внешнего reset. */ +#endif /* Завершает интерфейс G474 single-slot порта. */ diff --git a/c/protocan-boot/ports/tms320f2812/README.md b/c/protocan-boot/ports/tms320f2812/README.md new file mode 100644 index 0000000..5f59dc9 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/README.md @@ -0,0 +1,15 @@ +# F2812 / AM29LV800BT + +Самостоятельный проект, карта NOR, параметры CAN, установка и ограничения +описаны в [общей инструкции CCS](../../projects/README.md). + +- `boot2812.h` — физические CPU word-адреса и отдельная совместимость F2812; +- `nor_flash.c` — x16 AMD driver с ID, ограниченными program/sector erase, + DQ7/DQ5 polling, readback и BUSY; +- `boot_store.c` — упаковка октетов, проверка всей SCI8-таблицы, CRC32, + публикация manifest последними magic-словами, проверенная загрузка RAM; +- `projects/ccs/f2812/board.c` — подтверждённые линии CPLD и XINTF ПМ67; +- `projects/ccs/f2812/main.c` — независимые eCAN/IRQ/очередь/main F2812. + +Протокол и CRC повторно используются из `src/pcan_boot.c`. EEPROM отсутствует; +код F28335 и его A/B-журнал не подключаются к этому проекту. diff --git a/c/protocan-boot/ports/tms320f2812/boot2812.h b/c/protocan-boot/ports/tms320f2812/boot2812.h new file mode 100644 index 0000000..5025d04 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/boot2812.h @@ -0,0 +1,24 @@ +#ifndef BOOT2812_H /* Исключает повторное объявление профиля NOR-загрузчика F2812. */ +#define BOOT2812_H /* Отделяет основной контроллер ПМ67 от периферийного F28335. */ +#include "../../include/pcan_boot.h" /* Использует существующий ProtoCAN codec и представление октетов C28x. */ +#define BOOT2812_NOR_BASE 0x100000UL /* CPU word-адрес AM29LV800BT взят из START_ADR_FLASH действующего flash_tools.h платы. */ +#define BOOT2812_IMAGE_WORD 0x160000UL /* Новый CAN-образ занимает три полных верхних обычных сектора, выше старого образа и данных FPGA. */ +#define BOOT2812_IMAGE_BYTES 0x30000UL /* Три сектора по 0x8000 слов дают 196608 октетов полезного SCI8. */ +#define BOOT2812_META_WORD 0x17E000UL /* Последний top-boot сектор начинается после областей 16K/4K/4K слов и содержит 8192 слова. */ +#define BOOT2812_PRODUCT 0x2812U /* Отдельный Product Type запрещает запись образа F28335 в основной контроллер F2812. */ +#define BOOT2812_DEVICE_TYPE 3U /* Тип загрузчика остаётся в том же адресном классе ProtoCAN, что F28335. */ +#define BOOT2812_DEVICE_ID 6U /* Отдельный ID 6 исключает совпадение с существующим F28335 на адресе 3/7. */ +#define BOOT2812_RECOVERY_MS 3000UL /* После reset загрузчик три секунды принимает ENTER_BOOT до автоматического запуска сохранённого образа. */ +unsigned long Boot2812_Now(void); /* Возвращает монотонные миллисекунды Timer1 для CAN и ограниченных ожиданий NOR. */ +void Boot2812_Busy(void); /* Во время долгого стирания сообщает BUSY через общий codec и обслуживает аппаратный TX ACK. */ +void Boot2812_BoardInit(void); /* Настраивает действующие линии CPLD и XINTF платы ПМ67. */ +bool Boot2812_NorIdentify(void); /* До первого erase требует AMD manufacturer 0001 и top-boot device 22DA. */ +unsigned int Boot2812_NorRead(unsigned long word); /* Читает одно 16-битное слово по CPU-адресу внешней NOR. */ +bool Boot2812_NorProgram(unsigned long word, unsigned int value); /* Программирует только зарезервированные CAN-области и проверяет прочитанный результат. */ +bool Boot2812_NorErase(unsigned long word); /* Принимает только начала трёх секторов образа и одного сектора метаданных. */ +bool Boot2812_Erase(void *user, pcan_boot_byte_t slot); /* Удаляет публикацию до стирания единственного CAN-слота. */ +bool Boot2812_Write(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length); /* Сохраняет октеты ProtoCAN в x16 NOR младшим байтом вперёд. */ +pcan_boot_status_t Boot2812_Verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image); /* Проверяет CRC прочитанной NOR и все CPU-адреса SCI8 до COMMIT. */ +bool Boot2812_Commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image); /* Публикует manifest только после повторной проверки всей внешней Flash. */ +bool Boot2812_Load(uint32_t *entry); /* Читает действующий manifest, проверяет образ и переносит только разрешённую RAM. */ +#endif /* Завершает интерфейс самостоятельного NOR-порта F2812. */ diff --git a/c/protocan-boot/ports/tms320f2812/boot_store.c b/c/protocan-boot/ports/tms320f2812/boot_store.c new file mode 100644 index 0000000..8d9f701 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/boot_store.c @@ -0,0 +1,105 @@ +#include "boot2812.h" /* Использует отдельные адреса и совместимость внешней NOR F2812. */ +static unsigned int octet(uint32_t offset) /* Читает октет файла SCI8 из x16 NOR, где младший октет хранится первым. */ +{ /* Поток CAN остаётся независимым от sizeof(char) на C28x. */ + unsigned int word = Boot2812_NorRead(BOOT2812_IMAGE_WORD + offset / 2UL); /* Преобразует смещение в октетах в CPU word-адрес слота. */ + return (offset & 1UL) ? word >> 8 : word & 255U; /* Передаёт младшие восемь бит октета без знакового расширения. */ +} /* Все дальнейшие поля таблицы собираются из того же порядка октетов. */ +static unsigned int u16(uint32_t offset) /* Восстанавливает слово TI boot table в little endian. */ +{ /* Вызывается только после проверки достаточной длины соответствующего поля. */ + return octet(offset) | (octet(offset + 1UL) << 8); /* Два октета соответствуют одному слову C28x. */ +} /* Завершает чтение длины секции или данных программы. */ +static uint32_t address_at(uint32_t offset) /* Адрес TI SCI8 содержит старшее 16-битное слово перед младшим. */ +{ /* Этот порядок отличается от обычного u32 little endian метаданных ProtoCAN. */ + return ((uint32_t)u16(offset) << 16) | u16(offset + 2UL); /* Внутри каждого слова по-прежнему сохраняется little endian. */ +} /* Возвращает CPU-адрес, измеряемый в словах. */ +static bool allowed(uint32_t first, uint32_t end) /* Разрешает только реальную RAM приложения и исключает RAM работающего загрузчика. */ +{ /* Новое приложение не должно загружать инициализированные секции в L1 или RAM InitFlash до перехода в runtime. */ + return end > first && ((first >= 0x8000UL && end <= 0x8F00UL) || (first >= 0x3F8000UL && end <= 0x3FA000UL) || (first >= 0x80000UL && end <= 0x100000UL)); /* L0 до ramfuncs, полный H0 и внешняя SRAM зоны 2; периферия, NOR, стек и внутренние Flash запрещены. */ +} /* Проверки входа и всех секций выполняются до первой записи приложения в RAM. */ +static bool table(uint32_t size, bool copy, uint32_t *entry) /* Проверяет целиком SCI8 и при повторном проходе переносит данные в RAM. */ +{ /* Устойчивость загрузчика не зависит от адресов, заявленных принимаемым файлом. */ + uint32_t starts[64], ends[64], offset = 22UL, address, end; /* Лимит 64 секции ограничивает стек и число сравнений перекрытий. */ + unsigned int sections = 0U, count, i; bool entry_loaded = false; /* Требует, чтобы точка входа реально находилась среди загружаемых слов. */ + if (size < 24UL || (size & 1UL) || u16(0UL) != 0x08AAU) return false; /* Ключ SCI8 AA08, чётный размер и терминатор обязательны. */ + *entry = address_at(18UL); /* После ключа и восьми резервных слов находится CPU word-адрес C runtime. */ + while (offset + 2UL <= size) { /* Поле count читается только при наличии обоих октетов. */ + count = u16(offset); offset += 2UL; /* Размер секции выражен в 16-битных словах, а не октетах файла. */ + if (!count) return offset == size && entry_loaded; /* Запрещает хвост, незавершённую таблицу и entry вне payload. */ + if (sections == 64U || size - offset < 4UL) return false; /* Не допускает переполнения ограниченных массивов или усечённого адреса. */ + address = address_at(offset); offset += 4UL; end = address + count; /* Восстанавливает исключающую верхнюю границу CPU-диапазона секции. */ + if (!allowed(address, end) || (uint32_t)count * 2UL > size - offset) return false; /* Проверяет адреса и полный payload до обращения к RAM назначения. */ + for (i = 0; i < sections; ++i) if (address < ends[i] && starts[i] < end) return false; /* Даже правильно переданная CRC не разрешает две секции поверх одного слова. */ + starts[sections] = address; ends[sections++] = end; /* Сохраняет уже проверенный диапазон для следующих секций. */ + if (*entry >= address && *entry < end) entry_loaded = true; /* Подтверждает наличие исполняемого слова по адресу входа. */ + if (copy) { /* Этот проход выполняется только после полной read-only проверки всего образа. */ + for (i = 0; i < count; ++i) { /* Переносит ровно заявленные и предварительно проверенные слова секции. */ +#if defined(BOOT2812_HOST) /* Аппаратная модель проверяет тот же диапазон без записи по адресам процесса ПК. */ + extern void NorModel_LoadWord(uint32_t target, unsigned int value); /* Модель сохраняет каждое слово переноса для независимой проверки. */ + NorModel_LoadWord(address + i, u16(offset + (uint32_t)i * 2UL)); /* Подменяет только шину RAM назначения. */ +#else /* На F2812 CPU-адреса уже выражены в 16-битных словах. */ + *(volatile unsigned int *)(address + i) = u16(offset + (uint32_t)i * 2UL); /* Записывает секцию только в разрешённую RAM приложения. */ +#endif /* Завершает аппаратную запись либо её host-модель. */ + } /* Завершает перенос текущей секции. */ + } /* После проверочного прохода RAM остаётся нетронутой. */ + offset += (uint32_t)count * 2UL; /* Пропускает полезные октеты до следующего count. */ + } /* Исчерпание файла без терминатора означает неполный образ. */ + return false; /* Не запускает незавершённую таблицу. */ +} /* Образ с ошибкой не публикуется как запускаемый. */ +bool Boot2812_Erase(void *user, pcan_boot_byte_t slot) /* Реализует single-slot подготовку внешней NOR. */ +{ /* Существующие legacy-образы и FPGA ниже 160000 не входят в новый CAN-раздел. */ + unsigned long sector; (void)user; /* Перебирает только три полных обычных сектора нового образа. */ + if (slot || !Boot2812_NorIdentify() || !Boot2812_NorErase(BOOT2812_META_WORD)) return false; /* Сначала удаляет marker старого CAN-образа; при обрыве стирания сохраняется recovery. */ + for (sector = BOOT2812_IMAGE_WORD; sector < BOOT2812_IMAGE_WORD + BOOT2812_IMAGE_BYTES / 2UL; sector += 0x8000UL) if (!Boot2812_NorErase(sector)) return false; /* Геометрия x16 допускает erase только по границам обычных секторов 32K слов. */ + return true; /* Ядро ProtoCAN разрешает DATA только после полного успешного стирания слота. */ +} /* EEPROM-операции и несуществующий второй слот отсутствуют. */ +bool Boot2812_Write(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Упаковывает поступившие октеты в x16 слова NOR. */ +{ /* В одном вызове записывается не более одного classic CAN кадра. */ + unsigned int i, word; (void)user; /* Счётчик относится к октетам кадра, адрес NOR отдельно делится на два. */ + if (slot || !length || length > 8U || (offset & 1UL) || offset > BOOT2812_IMAGE_BYTES || length > BOOT2812_IMAGE_BYTES - offset) return false; /* Не допускает выхода из слота либо продолжения слова с неверного октета. */ + for (i = 0; i < length; i += 2U) { /* Последовательные 8-октетные блоки начинаются на границе x16 слова. */ + word = (data[i] & 255U) | ((i + 1U < length ? data[i + 1U] & 255U : 255U) << 8); /* Неполное последнее слово сохраняет FF в незанятом старшем октете. */ + if (!Boot2812_NorProgram(BOOT2812_IMAGE_WORD + (offset + i) / 2UL, word)) return false; /* Аппаратный драйвер проверяет и допустимый адрес, и результат записи каждого слова. */ + } /* Завершает сохранение текущего CAN-блока. */ + return true; /* ACK означает проверенную запись, а не только получение кадра. */ +} /* CRC ядра продвигается только после успешного возврата этого callback. */ +pcan_boot_status_t Boot2812_Verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image) /* Перепроверяет CRC непосредственно из сохранённой NOR. */ +{ /* Потоковая CRC при приёме не заменяет аппаратный readback полного файла. */ + uint32_t offset, crc = 0UL, entry; pcan_boot_byte_t bytes[32]; unsigned int count, i; (void)user; /* Небольшой буфер не требует размещать весь образ во внутренней RAM F2812. */ + if (slot || image->image_size < 24UL || image->image_size > BOOT2812_IMAGE_BYTES || (image->image_size & 1UL)) return PCAN_BOOT_STATUS_INVALID_SIZE; /* SCI8 должен целиком помещаться в выделенных трёх секторах и содержать целые слова. */ + if (image->product_type != BOOT2812_PRODUCT || image->hardware_revision_min > 1U || image->hardware_revision_max < 1U) return PCAN_BOOT_STATUS_WRONG_DEVICE; /* Образ F28335 или несовместимого изделия не становится загрузочным. */ + for (offset = 0; offset < image->image_size; offset += count) { /* Проверяет каждый фактически сохранённый октет ровно один раз. */ + count = image->image_size - offset < 32UL ? (unsigned int)(image->image_size - offset) : 32U; /* Последний буфер ограничен реальной длиной без FF-дополнения CAN. */ + for (i = 0; i < count; ++i) bytes[i] = octet(offset + i); /* Читает данные из NOR, а не из приёмной очереди CAN. */ + crc = pcan_boot_crc32_update(crc, bytes, count); /* Использует общий CRC32 ProtoCAN без дублирования полинома в аппаратном порту. */ + Boot2812_Busy(); /* Большой файл сохраняет ответы клиента при длинной проверке на реальном CPU. */ + } /* Завершает вычисление CRC readback. */ + if (crc != image->image_crc32) return PCAN_BOOT_STATUS_CRC_ERROR; /* Различает повреждение памяти и ошибку структуры SCI8. */ + return table(image->image_size, false, &entry) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_INVALID_STATE; /* Все адреса, перекрытия, терминатор и entry проверяются до COMMIT. */ +} /* До успеха verifier никакие слова приложения не переносятся в RAM. */ +bool Boot2812_Commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image) /* Публикует загрузочный manifest последней операцией после readback. */ +{ /* Формат из 12 слов фиксирован и не зависит от sizeof C-структуры. */ + unsigned int words[12], i; /* Два magic-слова, версия формата, размер, CRC, версия FW и контроль manifest. */ + pcan_boot_byte_t bytes[20]; uint32_t crc; /* CRC первых десяти слов защищает размер и контрольную сумму самого образа. */ + if (Boot2812_Verify(user, slot, image) != PCAN_BOOT_STATUS_OK) return false; /* Не публикует файл, испорченный после предыдущего VERIFY. */ + words[0] = 0x2812U; words[1] = 0xCA7EU; words[2] = 1U; words[3] = 0U; /* Magic 2812/CA7E и версия 1 отличают новый CAN manifest от прежних данных платы. */ + words[4] = (unsigned int)(image->image_size & 0xFFFFUL); words[5] = (unsigned int)(image->image_size >> 16); /* Длина выражена октетами и хранится младшим словом первой. */ + words[6] = (unsigned int)(image->image_crc32 & 0xFFFFUL); words[7] = (unsigned int)(image->image_crc32 >> 16); /* Сохраняет точную CRC всего полученного файла. */ + words[8] = (unsigned int)(image->firmware_version & 0xFFFFUL); words[9] = (unsigned int)(image->firmware_version >> 16); /* Версия кандидата не подменяется версией постоянного загрузчика. */ + for (i = 0; i < 10U; ++i) { bytes[2U * i] = words[i] & 255U; bytes[2U * i + 1U] = words[i] >> 8; } /* Wire-представление manifest использует октеты независимо от ширины C28x char. */ + crc = pcan_boot_crc32_update(0UL, bytes, 20U); words[10] = (unsigned int)(crc & 0xFFFFUL); words[11] = (unsigned int)(crc >> 16); /* CRC manifest не позволяет принять частично записанные поля размера и CRC образа. */ + for (i = 2U; i < 12U; ++i) if (!Boot2812_NorProgram(BOOT2812_META_WORD + i, words[i])) return false; /* Сначала записывает все поля, пока оба magic-слова ещё равны FF. */ + if (!Boot2812_NorProgram(BOOT2812_META_WORD + 1UL, words[1])) return false; /* Второе magic-слово фиксируется после полного тела manifest. */ + return Boot2812_NorProgram(BOOT2812_META_WORD, words[0]); /* Первое magic записывается последним: потеря питания раньше оставляет recovery. */ +} /* Повтор COMMIT обрабатывает идемпотентный автомат общего ядра. */ +bool Boot2812_Load(uint32_t *entry) /* Проверяет опубликованный образ после reset перед переносом в RAM приложения. */ +{ /* Пустой или повреждённый manifest оставляет прибор в постоянном CAN recovery. */ + unsigned int words[12], i; pcan_boot_byte_t bytes[20]; uint32_t crc; pcan_boot_manifest_t image; /* Сериализованные поля читаются явно, без memcpy по ABI структуры. */ + for (i = 0; i < 12U; ++i) words[i] = Boot2812_NorRead(BOOT2812_META_WORD + i); /* Читает только фиксированные 24 октета manifest. */ + if (words[0] != 0x2812U || words[1] != 0xCA7EU || words[2] != 1U || words[3]) return false; /* Не интерпретирует старые данные Flash либо неполный commit как запускаемый файл. */ + for (i = 0; i < 10U; ++i) { bytes[2U * i] = words[i] & 255U; bytes[2U * i + 1U] = words[i] >> 8; } /* Восстанавливает то же октетное представление, что защищалось при COMMIT. */ + crc = pcan_boot_crc32_update(0UL, bytes, 20U); /* Проверяет метаданные до использования объявленной ими длины. */ + if (crc != ((uint32_t)words[10] | ((uint32_t)words[11] << 16))) return false; /* Повреждённый размер не может вывести чтение за пределы CAN-слота. */ + image.image_size = (uint32_t)words[4] | ((uint32_t)words[5] << 16); image.image_crc32 = (uint32_t)words[6] | ((uint32_t)words[7] << 16); /* Размер и CRC файла восстанавливаются только после успешной CRC manifest. */ + image.firmware_version = (uint32_t)words[8] | ((uint32_t)words[9] << 16); image.product_type = BOOT2812_PRODUCT; image.hardware_revision_min = image.hardware_revision_max = 1U; /* Профиль образа был проверен до публикации manifest. */ + return Boot2812_Verify(0, 0U, &image) == PCAN_BOOT_STATUS_OK && table(image.image_size, true, entry); /* Сначала полный read-only проход, затем перенос и только после успеха разрешение вызова entry. */ +} /* Не загружает старые flat BIN автоматически: новый проект использует проверяемую SCI8-таблицу. */ diff --git a/c/protocan-boot/ports/tms320f2812/nor_flash.c b/c/protocan-boot/ports/tms320f2812/nor_flash.c new file mode 100644 index 0000000..0b5ff51 --- /dev/null +++ b/c/protocan-boot/ports/tms320f2812/nor_flash.c @@ -0,0 +1,69 @@ +#include "boot2812.h" /* Ограничивает аппаратный драйвер разделами обновления конкретного профиля ПМ67. */ +#if defined(BOOT2812_HOST) /* Host-модель воспроизводит команды NOR без обращения к физическим CPU-адресам. */ +extern unsigned int NorModel_Read(unsigned long word); /* Модель отдаёт данные, ID и аппаратные биты готовности чипа. */ +extern void NorModel_Write(unsigned long word, unsigned int value); /* Модель принимает настоящую последовательность unlock/program/erase драйвера. */ +#define NOR_READ(word) NorModel_Read(word) /* Подменяет только чтение шины, сохраняя алгоритм драйвера. */ +#define NOR_WRITE(word, value) NorModel_Write(word, value) /* Подменяет физическую запись при проверке границ и отказов. */ +#else /* Production использует 16-битную параллельную XINTF-шину. */ +#define NOR_READ(word) (*(volatile unsigned int *)(word)) /* Один CPU-адрес C28x соответствует одному x16 слову AM29LV800BT. */ +#define NOR_WRITE(word, value) (*(volatile unsigned int *)(word) = (value)) /* Volatile сохраняет каждый командный цикл AMD в исходном порядке. */ +#endif /* Завершает выбор физической шины либо модели. */ +static void reset_read(void) /* Выводит чип из autoselect либо неудачной операции в обычный режим чтения. */ +{ /* Reset не стирает слова памяти и допустим по любому адресу чипа. */ + NOR_WRITE(BOOT2812_NOR_BASE, 0x00F0U); /* F0 — Read/Reset из таблицы команд AMD Am29LV800B. */ +} /* Все ошибки возвращают NOR в состояние, пригодное для следующей recovery-сессии. */ +static void unlock(unsigned int command) /* Выполняет общий префикс x16-команд согласно datasheet AMD. */ +{ /* Адреса ниже являются смещениями в словах, а не октетными AAA/555 режима x8. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, 0x00AAU); /* Первый unlock-цикл AA по смещению 555h в режиме x16. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x2AAUL, 0x0055U); /* Второй unlock-цикл 55 по смещению 2AAh. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, command); /* Третий цикл выбирает autoselect, программирование либо начало стирания. */ +} /* Последующий цикл данных или адрес сектора выполняет вызывающая операция. */ +unsigned int Boot2812_NorRead(unsigned long word) /* Читает только физический диапазон установленной NOR ёмкостью 1 МиБ. */ +{ /* Верхняя исключающая граница равна BASE + 512K слов. */ + return word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL ? NOR_READ(word) : 0xFFFFU; /* Вне чипа не создаёт шинного чтения по неизвестному адресу. */ +} /* Возвращает полное x16 слово без перестановки октетов. */ +bool Boot2812_NorIdentify(void) /* Идентификация обязательна перед разрешением изменяющих операций. */ +{ /* Не подменяет top-boot геометрию похожим bottom-boot или NAND-чипом. */ + unsigned int maker, device; /* Хранит два слова autoselect, прежде чем вернуть чип к чтению. */ + reset_read(); unlock(0x0090U); /* 90h включает чтение manufacturer/device ID после обычного unlock. */ + maker = NOR_READ(BOOT2812_NOR_BASE); device = NOR_READ(BOOT2812_NOR_BASE + 1UL); /* AMD: offset 0 содержит 0001, offset 1 — 22DA для Am29LV800BT x16. */ + reset_read(); /* Обычные чтения образа после проверки не должны видеть таблицу autoselect. */ + return maker == 0x0001U && device == 0x22DAU; /* Отличающийся чип получает отказ до первого sector erase. */ +} /* Не выполняет разрушительных пробных записей для определения типа памяти. */ +static bool wait_word(unsigned long word, unsigned int expected, unsigned long timeout) /* Ограничивает DQ7/DQ5 polling временем и числом проходов. */ +{ /* DQ7 отражает готовность программируемого старшего бита; DQ5 требует завершающего повторного чтения. */ + unsigned long started = Boot2812_Now(), budget = 50000000UL; /* Итерационный предел обеспечивает выход даже при остановленном Timer1. */ + unsigned int value; /* Снимок status считывается один раз на основной проход. */ + do { /* Не вызывает никаких функций из программируемой внешней NOR: код загрузчика находится во внутренней Flash. */ + value = NOR_READ(word); /* Читает именно адрес программирования либо начало стираемого сектора. */ + if ((value & 0x0080U) == (expected & 0x0080U)) return NOR_READ(word) == expected; /* После совпадения DQ7 подтверждает все 16 бит результата. */ + if (value & 0x0020U) { /* DQ5 сообщает превышение внутреннего времени алгоритма AMD. */ + if ((NOR_READ(word) & 0x0080U) == (expected & 0x0080U)) return NOR_READ(word) == expected; /* Повтор исключает нормальное завершение операции одновременно с чтением DQ5. */ + break; /* После подтверждённой ошибки больше не ждёт неопределённое время. */ + } /* Завершает трактовку аппаратного статуса текущего прохода. */ + Boot2812_Busy(); /* Долгое стирание продолжает давать клиенту живой ответ и не блокирует CAN ISR. */ + } while (--budget && Boot2812_Now() - started < timeout); /* Беззнаковое вычитание сохраняет корректность при переполнении миллисекунд. */ + reset_read(); /* Отказ возвращает чип в режим чтения перед следующей recovery-попыткой. */ + return false; /* Не сообщает успех по одному окончанию тайм-аута. */ +} /* Завершает ограниченное ожидание аппаратной операции. */ +bool Boot2812_NorProgram(unsigned long word, unsigned int value) /* Программирует только выделенный CAN-образ либо manifest. */ +{ /* Старые данные приложения, FPGA и остальные сектора чипа не входят в разрешённые диапазоны. */ + unsigned int before; /* Предварительное чтение исключает попытку перевода NOR-бита из нуля в единицу. */ + if (!((word >= BOOT2812_IMAGE_WORD && word < BOOT2812_IMAGE_WORD + BOOT2812_IMAGE_BYTES / 2UL) || (word >= BOOT2812_META_WORD && word < BOOT2812_META_WORD + 0x2000UL))) return false; /* Проверяет word-адрес до любого unlock или командного цикла. */ + before = NOR_READ(word); /* Проверяет текущее содержимое перед началом операции. */ + if (before == value) return true; /* Повтор одинакового блока не выполняет лишнее программирование. */ + if ((before & value) != value) return false; /* Бит 0→1 требует отдельного sector erase и не должен маскироваться чтением старого слова. */ + unlock(0x00A0U); NOR_WRITE(word, value); /* A0 запускает word program; следующий цикл содержит адрес и полные 16 бит данных. */ + return wait_word(word, value, 100UL); /* Сто миллисекунд дают ограниченный запас для программирования одного слова. */ +} /* Каждый успех означает фактическое совпадение прочитанного слова. */ +bool Boot2812_NorErase(unsigned long word) /* Не принимает произвольный адрес или команду полного стирания чипа. */ +{ /* Обновление ограничено секторами 12/13/14 и последним top-boot сектором 18. */ + unsigned long i, count = word == BOOT2812_META_WORD ? 0x2000UL : 0x8000UL; /* AM29LV800BT: обычный сектор 32K слов, последний boot-сектор 8K слов. */ + if (!(word == BOOT2812_IMAGE_WORD || word == BOOT2812_IMAGE_WORD + 0x8000UL || word == BOOT2812_IMAGE_WORD + 0x10000UL || word == BOOT2812_META_WORD)) return false; /* Только точные разрешённые начала секторов исключают округление в соседнюю область. */ + unlock(0x0080U); /* 80h начинает шеститактовую последовательность Sector Erase AMD. */ + NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, 0x00AAU); NOR_WRITE(BOOT2812_NOR_BASE + 0x2AAUL, 0x0055U); /* Повторяет вторую unlock-пару перед выбором сектора. */ + NOR_WRITE(word, 0x0030U); /* 30h по sector address выбирает один сектор; команда Chip Erase 10h отсутствует. */ + if (!wait_word(word, 0xFFFFU, 20000UL)) return false; /* Ограничивает ожидание двадцатью секундами с периодическими BUSY-ответами. */ + for (i = 0; i < count; ++i) if (NOR_READ(word + i) != 0xFFFFU) return false; /* Проверяет всю стёртую область, а не только её первое слово. */ + return true; /* Разрешает запись лишь после полного аппаратного readback сектора. */ +} /* При сбое сохранённый manifest уже недействителен, загрузчик остаётся в recovery. */ diff --git a/c/protocan-boot/ports/tms320f28335/README.md b/c/protocan-boot/ports/tms320f28335/README.md new file mode 100644 index 0000000..337d2ec --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/README.md @@ -0,0 +1,207 @@ +# F28335 + M95M02: CAN, отдельный загрузчик и A/B + +Реализация состоит из Flash-загрузчика `projects/ccs/f28335`, переносимого +`f28335_boot_store.c`, аппаратного `f28335_boot_hw.c` и адаптера +`f28335_can_boot.c`. Приложение подключает общий `f28335_can_application.c` +прямой ссылкой linked resource из templates в CCS Debug/Release. +В сборке `EEPROM_M95M02=0` CAN Boot отключён. Для установленной M95M02 — значение 1. + +## Адрес и формат + +Адрес определяется физическим номером **PERIPH 0–31** по новой Excel-таблице: +Type = 1 + PERIPH / 16 (целая часть), Device ID = PERIPH mod 16. +**УМП1 — 1/5, УМП2 — 1/6, задатчик — 1/8**. Product **0x2833**, HW **1** +описывают существующую аппаратную совместимость F28335 и не являются CAN-адресом. +Имена паспорта для назначенных плат — `UMP1`, `UMP2`, `Zadatchik`. +Приложение передаёт Mode в `F28335CanBoot_Init(Mode)`. Загрузчик независимо +читает те же активные низким уровнем GPIO21/20/22/51 с весами 1/2/4/8 и базой 1. +Поэтому существующие перемычки ПМ35 задают номера 1–16; номера 0 и 17–31 +поддерживаются адресным контрактом, но требуют другого источника физического номера. +Общий адрес 3/7 больше не принимается. Чужие адреса отбрасываются аппаратным +mailbox, ISR и ядром до записи EEPROM, включая данные A/B и управляющие команды. +В приложении FW берётся из `firmware_version.h`, формат `major<<24 | minor<<16 | patch`; +для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа +из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT. +CAN **250000 бит/с**, Extended ID, окно **16 блоков по 8 октетов**. +Для задатчика и session=1: ENTER_BOOT `0x11890102`, STATUS `0x198C0102`. + +## Общий запуск Flash и резервной EEPROM + +Сектор A и аппаратный boot `0x33FFF6` принадлежат постоянному загрузчику. +Flash-приложение использует `[0x300000,0x338000)`: первые 16 слов — описание +FAB1, остальные — собственные LOAD-секции. `f28335_flash_app.c` проверяет +magic/version, entry, границы, инверсию entry, маркеры и CRC32 IEEE всего +диапазона после заголовка, включая промежутки, заполненные `0xFFFF`. +Python-контракт `python/protocan/f28335_flash.py` заполняет зарезервированные +32 октета COFF по смещению, подтверждённому TI OFD, после линковки. + +Загрузчик даёт трёхсекундное окно CAN, затем запускает исправную внутреннюю +Flash в приоритете. Отсутствующая/повреждённая Flash ведёт к прежнему выбору +EEPROM A/B с trial/CONFIRM/rollback. ENTER_BOOT удерживает CAN recovery. +Handoff running=`0xFE` обозначает проверенную внутреннюю Flash; 0/1 — EEPROM +A/B, `0xFF` — отсутствие запущенного приложения. Flash-приложение обслуживает +PING и ENTER_BOOT, но не подменяет подтверждение EEPROM-кандидата. +Обновление EEPROM по CAN не меняет приоритет исправной Flash после reset. + +RS Flash должен стирать только B–H, публиковать FAB1 после проверки остальных +данных и запрещать любые адреса сектора A. В SETGUI соответствующие JTAG +маски задаются явными TI `FlashSectorA..H`: A для установки boot, B–H для +приложения. Полное стирание чипа внешним программатором не ограничивается linker. +Старая самостоятельная Flash-сборка с codestart `0x33FFF6` несовместима с этим +размещением и не должна передаваться как обновление приложения. + +Образ — SCI8 BIN (`AA 08`), чётная длина от 24 до **130560 байт** включительно. +Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное +слово, затем младшее; каждое слово little endian. В C28x `char` 16-битный, +поэтому `pcan_boot_byte_t` хранит октет в младших 8 битах. + +## Разметка EEPROM, байтовые адреса + +| Область | Начало | Конец включительно | Размер | +|---|---:|---:|---:| +| Журнал 0 | 0x00000 | 0x000FF | 256 | +| Журнал 1 | 0x00100 | 0x001FF | 256 | +| Slot A | 0x00200 | 0x1FFFF | 130560 | +| Slot B | 0x20000 | 0x3FDFF | 130560 | +| Резерв | 0x3FE00 | 0x3FEFB | 252 | +| Параметры | 0x3FEFC | 0x3FFFD | 258 | +| Последнее слово | 0x3FFFE | 0x3FFFF | 2 | + +В каждой странице журнала первые 64 октета содержат magic `FAB2`, версию 1, +sequence, active/pending/attempted, два manifest, CRC32 первых 56 октетов и +commit marker в октетах 60..63. Сначала обнуляется marker запасной страницы, +затем записывается тело с проверкой чтением, последним — marker. Предыдущая +страница остаётся действующей до полной публикации новой. Выбор sequence +учитывает переполнение u32. После ошибки публикации журнал перечитывается; +ошибка чтения блокирует последующие записи. + +## Сценарий обновления и отката + +1. Приложение принимает ENTER_BOOT, останавливает управление нагрузкой, выставляет 4 мА и выдерживает + секундный STOP, затем сохраняет session в NOINIT RAM 0x50..0x57. Watchdog выполняет reset. + ACK ENTER_BOOT отправляет уже Flash-загрузчик; приложение ничего не стирает. +2. BEGIN_IMAGE/BEGIN_COMPAT проверяют размер, Product, HW и сессию. Неактивный + слот выбирается автоматически; при первом образе это A. ERASE инвалидирует + только его manifest. Полного стирания EEPROM не требуется. +3. Последовательные DATA_A/B записываются с немедленным readback. VERIFY + проверяет потоковый CRC32, CRC32 EEPROM и полную таблицу SCI8. + Разрешена загрузка только в CPU word RAM `[0x8000,0xE000)`: максимум 64 секции, + без пересечений, усечений и хвостовых данных; entry должен попасть в секцию. + Запись в Flash, периферию, стек, RAM загрузчика и handoff запрещена. +4. COMMIT повторно проверяет образ и публикует pending в журнале. Подтверждённый + слот сохраняется. Повтор COMMIT безопасен. REBOOT выполняется после физического + CAN ACK ответа. Потеря ACK/тайм-аут передачи отменяет запрос reset. +5. Перед первым запуском кандидата загрузчик сохраняет attempted=1, затем + проверяет и копирует SCI8 в RAM. Следующий reset без CONFIRM сбрасывает pending + и запускает прежний active. Если прежнего образа нет — остаётся CAN recovery. +6. Новое приложение включает watchdog в начале запуска. До подтверждения + прерывания не кормят watchdog вместо основного цикла. После READY, 100 проходов + main и 5 секунд выполняется автоматический CONFIRM. Неудача сохранения + подтверждения через 10 секунд прекращает кормление watchdog, вызывая откат. + Адресная команда CONFIRM с ненулевой session также разрешена после READY. + CONFIRM в загрузчике и до первого запуска кандидата отклоняется. + +PING, IDENTIFY и паспорт доступны без ENTER_BOOT. QUERY_PROGRESS/ABORT привязаны +к сессии. Сессия в RAM истекает через 30 секунд без подходящих команд/данных. +После reset передачу начинают заново; параметры и подтверждённый образ остаются. +ABORT после COMMIT не отменяет опубликованный pending. Для его пробного запуска +можно открыть новую сессию и отправить REBOOT. Pending запрещено перезаписывать. +Повторы ENTER_BOOT, метаданных, ERASE до первого блока, VERIFY и COMMIT учитывают +потерю ответа. Broadcast никогда не разрешает запись. + +## Сервисные команды + +Запрос: MsgType=9, Body=`session<<8 | command`. IDENTIFY/PING/паспорт не требуют сессии. +Ответ паспорта: MsgType=D, Body=`page<<8 | command`, DLC=8. + +| Код | Имя | DLC запроса | Ответ | +|---:|---|---:|---| +| 01 | IDENTIFY | 0 | Product:u16, HW:u8, protocol:u8, FW:u32; Body=1 | +| 0C | PING | 0 | protocol, state, active, target, session, slot_count, last_status, 0 | +| 0D | CAPABILITIES | 0 | flags:u32, slot_capacity:u32 | +| 0E | DEVICE_NAME | 1 (page) | 8 ASCII-октетов имени; последний фрагмент с NUL | +| 0F | MEMORY_INFO | 1 (page) | Страницы ниже | + +MEMORY_INFO 0: EEPROM bytes:u32, page bytes:u16, mode:u8 (0 app/1 boot), running:u8. +Страница 1: адреса A:u32, B:u32. Страница 2: active, pending, attempted, storage_healthy, +session_timeout_ms:u32. Страница 3: parameters_offset:u32, parameters_bytes:u32. +Слот FF означает отсутствие образа/запущенного приложения. +CAPABILITIES bits 0..11: ping, discovery, identify, name, memory, A/B, confirm, +rollback, separate loader, session timeout, readback, SCI8 validation. +Приложение, запущенное старым SPI ROM без handoff загрузчика, сообщает только +базовые сервисы (0x1F) и отклоняет ENTER_BOOT. + +Обнаружение: MsgType=D, Body=0, DLC=0, Route=0. Адресный запрос или общий +DeviceType=7/DeviceID=15. Ответ IDENTIFY приходит с адреса прибора через +`2*(1+16*DeviceType+DeviceID)` мс. При нескольких одинаковых адресах конфликт +остаётся: каждому физическому устройству нужен уникальный адрес. +Python API: `protocan.can_boot.CanBootServices` — запросы и разбор паспорта; +`CanBootTransfer` — загрузка. Кнопка «Пинг» доступна в режиме ProtoCAN Boot +окна прошивки SETGUI. Для ENTER/VERIFY/COMMIT клиент ждёт до 15 секунд. + +## Аппаратная интеграция + +MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery. +MBOX0..2 сохраняют legacy/UMP, MBOX5 загрузчик не использует. ISR помещает сообщения +в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди. +При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново. +SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес, +разбиение по страницам 256 байт и восстановление конфигурации SPI приложения. +Он работает только при остановленном Timer2. Обычный Seeprom_write приложения +ограничен областью параметров; старый RS EXTEND 0x44 запрещён для A/B. + +Загрузчик исполняется из внутренней Flash A 0x338000..0x33FF7F, entry 0x33FFF6. +Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует +0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации, +0xE000..0xFFFF для .ebss после перехода в C runtime. Linker резервирует +NOINIT handoff в обоих проектах. CAN не содержит операций записи внутренней Flash. + +## Первичная установка + +1. Собрать приложение с EEPROM_M95M02=1 и обновлённым F28335.cmd; получить SCI8 BIN. + Старые BIN/OUT автоматически не заменены. Приложение должно содержать интеграцию + READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом. +2. Собрать отдельный загрузчик TI C2000 COFF compiler: + `python c/protocan-boot/projects/build.py --device f28335 --compiler <путь-к-ti-cgt-c2000>`. + Результат — `projects/ccs/f28335/Debug/F28335_CAN_AB.out` и MAP. +3. Установить обновлённый OUT через JTAG и выбрать аппаратный Flash boot + согласно схеме платы. При переходе с общего адреса 3/7 обновить и приложение, + и загрузчик: старый загрузчик не перейдёт на новый адрес после reset сам. + В SETCAN выбрать «Прошивка → CAN / ProtoCAN Boot → Устройство PERIPH» + и нужное назначение. Не загружать поверх загрузчика старый application OUT с + секцией codestart во Flash. +4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery. + Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и + проверить MEMORY_INFO page 2: pending=FF, active=A. Затем проверить обновление в B. + +Старая SPI-ROM разметка с AA08 по адресу 0 несовместима с новым журналом. +Первое обновление заменяет её; параметры по прежнему адресу сохраняются. +Загрузчик не выполняет скрытую миграцию и не меняет boot pins программно. + +## Проверки и границы проверенного + +`python c/protocan-boot/tests/run_tests.py` (переменная CC — clang/gcc) проверяет +ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом +из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти. +Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B. +Проверка синтаксиса использует настоящие DSP2833x headers. Импорт и сборка TI/CCS, +раскладка MAP и реальные COFF LOAD-адреса проверены; физические CAN/SPI/reset +на плате требуют стендовой проверки. Отдельные проекты и команды сборки описаны +в [инструкции CCS](../../projects/README.md). + +CRC32 защищает от повреждения, криптографической подписи и anti-rollback по +версии в этом порту нет. Удалённый CONFIRM подтверждает готовность приложения, +но не заменяет проверку датчиков/силовой части на стенде. + +Аппаратный формат SPI boot описан в [TI Boot ROM Reference Guide](https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/2742.Boot-ROM.pdf). +В A/B-схеме ROM выбирает Flash, а разбор EEPROM выполняет этот загрузчик. + +Проект предоставляет `f28335_can_application_config.h` в include paths. +Он задаёт `F28335_CAN_BOOT_APPLICATION_ENABLED` (0/1) и при включённом модуле +`F28335_CAN_BOOT_FIRMWARE_VERSION` из версии приложения. В 167 это ручной +`firmware_version.h`; профиль включён только при M95M02 без `FLASH_BOOT`. +Локальный `Source/Internal/can_boot.c` содержит только `F28335Boot_Quiesce` +со штатной остановкой нагрузки. Общие `.c` повторно включать в него не нужно: +они компилируются единственным linked resource общей библиотеки. +Постоянный Flash-загрузчик по-прежнему собирается отдельным проектом +`projects/ccs/f28335` и не линкуется в RAM-приложение. diff --git a/c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c b/c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c new file mode 100644 index 0000000..e3f7aa1 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_boot_hw.c @@ -0,0 +1,181 @@ +/* Shared by the application and the separate Flash bootloader. */ +/* Аппаратный слой: общая RAM между reset, watchdog и SPI EEPROM. + * Один исходник компилируется и в приложение, и в отдельный Flash-загрузчик. + * В отличие от store.c этот файл требует настоящих регистров F28335. */ +#include "DSP2833x_Device.h" +#include "f28335_boot_platform.h" +#include "f28335_can_boot.h" + +/* Must be NOINIT in BOTH linkers, outside ROM scratch and application payload. */ +#pragma DATA_SECTION(boot_handoff,".boot_shared") +/* 8 слов NOINIT по адресу 0x50, одинаково зарезервированных обоими linker-файлами. + * [0..1] magic; [2] запрошенная session; [3] запущенный слот; [4..6] служебные + * поля; [7] XOR-контроль. Это кратковременная передача контекста через watchdog + * reset, а не замена энергонезависимого журнала EEPROM. */ +static volatile unsigned int boot_handoff[8]; +/* Проверяем magic и XOR прежде, чем трактовать RAM как запрос входа в boot. + * После включения питания содержимое NOINIT может быть произвольным. */ +static unsigned int handoff_valid(void) +{ + unsigned int i,sum=0; + for(i=0;i<8;++i) sum^=boot_handoff[i]; + return boot_handoff[0]==0xB283 && boot_handoff[1]==0x4D7C && sum==0xA95B; +} +/* Сначала снимаем признак действительности, затем заполняем поля и контроль. + * Первый magic записываем последним; volatile сохраняет обращения к общей RAM. + * request=0 означает обычный запуск, ненулевая session — явный ENTER_BOOT. */ +static void handoff_set(unsigned int request,unsigned int running) +{ + unsigned int i,sum=0; + boot_handoff[0]=0; boot_handoff[1]=0x4D7C; + boot_handoff[2]=request; boot_handoff[3]=running; + boot_handoff[4]=0xF335; boot_handoff[5]=0x0CCA; boot_handoff[6]=1; + sum=0xB283; + for(i=1;i<7;++i) sum^=boot_handoff[i]; + boot_handoff[7]=sum^0xA95B; + boot_handoff[0]=0xB283; /* publish last */ +} +/* Приложение узнаёт свой слот из handoff, а не предполагает, что оно active: + * во время пробного запуска выполняется pending, active ещё указывает на старый образ. */ +unsigned int F28335Boot_RunningSlot(void) +{ return handoff_valid()?boot_handoff[3]:F28335_AB_NONE; } +unsigned int F28335Boot_RequestedSession(void) +{ return handoff_valid() && boot_handoff[2]<256?boot_handoff[2]:0; } +/* Одновременно публикуем выбранный слот и потребляем запрос ENTER_BOOT: + * он не должен повторяться при следующем обычном reset. */ +void F28335Boot_SetRunning(unsigned int slot) { handoff_set(0,slot); } +/* Timer1 должен давать 1 мс на InterruptCount и в приложении, и в загрузчике. + * Тайм-ауты используют разность unsigned-счётчиков для переноса через wrap. */ +uint32_t F28335Boot_Now(void) { return CpuTimer1.InterruptCount; } +/* Вызвать сразу после InitSysCtrl, который штатно отключает watchdog. + * Сбрасываем разрешение кормления из ISR до полной инициализации CAN-сервиса. + * Для приложения, запущенного нашим загрузчиком, включаем watchdog с делителем. */ +void F28335Boot_StartupWatchdog(void) +{ + F28335CanBoot_EarlyInit(); + if(F28335Boot_RunningSlot()<2) { + EALLOW; SysCtrlRegs.WDKEY=0x55; SysCtrlRegs.WDKEY=0xAA; + SysCtrlRegs.WDCR=0x002F; EDIS; + } +} +/* Платформенный Quiesce останавливает управление выходами перед reset. + * Session сохраняется до включения watchdog; ненулевую session загрузчик + * использует для отложенного ACK ENTER_BOOT. В бесконечном цикле watchdog + * намеренно не обслуживается — выход из функции должен произойти через reset. */ +void F28335Boot_Reset(unsigned int session) +{ + F28335Boot_Quiesce(); + DINT; + handoff_set(session,F28335_AB_NONE); + EALLOW; SysCtrlRegs.WDCR=0x0028; EDIS; + for(;;) { } +} + +/* Main context only. Legacy Timer2 EEPROM driver must be idle/stopped. Save + * its SPI configuration: it changes the character width during transactions. */ +typedef struct { unsigned int ccr,ctl,brr,tx,rx,ct,pri; } boot_spi_saved; +static void spi_cs(unsigned int high) +{ if(high) GpioDataRegs.GPASET.bit.GPIO19=1; else GpioDataRegs.GPACLEAR.bit.GPIO19=1; } +/* Доступ разрешён только из main при остановленном Timer2 старого SPI-драйвера. + * Это проверка занятости в однопоточном приложении, не универсальный mutex. + * Сохраняем режим SPI, поскольку штатный драйвер меняет разрядность передачи. + * CS сначала поднимаем, затем переключаем SPI на 8-битные транзакции. */ +static bool spi_take(boot_spi_saved *s) +{ + volatile unsigned int discard; + if(!CpuTimer2Regs.TCR.bit.TSS) return false; + s->ccr=SpiaRegs.SPICCR.all; s->ctl=SpiaRegs.SPICTL.all; s->brr=SpiaRegs.SPIBRR; + s->tx=SpiaRegs.SPIFFTX.all; s->rx=SpiaRegs.SPIFFRX.all; + s->ct=SpiaRegs.SPIFFCT.all; s->pri=SpiaRegs.SPIPRI.all; + EALLOW; + GpioCtrlRegs.GPAMUX2.bit.GPIO16=1; GpioCtrlRegs.GPAMUX2.bit.GPIO17=1; + GpioCtrlRegs.GPAMUX2.bit.GPIO18=1; GpioCtrlRegs.GPAMUX2.bit.GPIO19=0; + GpioDataRegs.GPASET.bit.GPIO19=1; GpioCtrlRegs.GPADIR.bit.GPIO19=1; + GpioCtrlRegs.GPAQSEL2.bit.GPIO17=3; + EDIS; + SpiaRegs.SPICCR.all=7; SpiaRegs.SPICTL.all=0x0E; /* master, phase=1, IRQ off */ + SpiaRegs.SPIBRR=CLKMULT*6+1; + SpiaRegs.SPIFFTX.all=0x8000; SpiaRegs.SPIFFRX.all=0; SpiaRegs.SPIFFCT.all=0; + SpiaRegs.SPIPRI.all=0x10; SpiaRegs.SPICCR.all=0x87; +/* Снимаем оставшийся RX/INT_FLAG от прежней операции, чтобы первый обмен + * не принял старое содержимое RXBUF за ответ EEPROM. */ + discard=SpiaRegs.SPIRXBUF; (void)discard; + return true; +} +/* Выход и при успехе, и при ошибке: CS не должен остаться активным. + * Настройки возвращаются при удержании SPI в reset; исходный SPISWRESET + * восстанавливается последним, после остальных регистров. */ +static void spi_release(const boot_spi_saved *s) +{ + volatile unsigned int discard; + spi_cs(1); discard=SpiaRegs.SPIRXBUF; (void)discard; + SpiaRegs.SPICCR.all=s->ccr&0x7FU; SpiaRegs.SPICTL.all=s->ctl; + SpiaRegs.SPIBRR=s->brr; SpiaRegs.SPIFFTX.all=s->tx; SpiaRegs.SPIFFRX.all=s->rx; + SpiaRegs.SPIFFCT.all=s->ct; SpiaRegs.SPIPRI.all=s->pri; SpiaRegs.SPICCR.all=s->ccr; +} +/* У F28335 8-битный символ для передачи выравнивается в старшие биты TXBUF. + * Полученный октет читается из младших битов RXBUF. Счётчик budget ограничивает + * ожидание даже при неработающем Timer1; это число итераций, а не миллисекунды. */ +static bool spi_octet(unsigned int tx,unsigned int *rx) +{ + uint32_t budget=100000UL; + SpiaRegs.SPITXBUF=(tx&255U)<<8; + while(!SpiaRegs.SPISTS.bit.INT_FLAG) if(--budget==0) return false; + *rx=SpiaRegs.SPIRXBUF&255U; return true; +} +/* Команда EEPROM и 24-битный байтовый адрес, старший октет адреса первым. + * CS удерживается вызывающей функцией на всю команду и полезные данные. */ +static bool spi_prefix(unsigned int command,uint32_t address) +{ + unsigned int discard; + return spi_octet(command,&discard) && spi_octet((unsigned int)(address>>16),&discard) && + spi_octet((unsigned int)(address>>8),&discard) && spi_octet((unsigned int)address,&discard); +} +/* RDSR (05h): WIP в бите 0 означает незавершённую внутреннюю запись EEPROM. + * Ожидание ограничено и 50 мс, и числом опросов на случай остановки tick. + * После каждого чтения статуса CS снимается, в том числе при ошибке SPI. */ +static bool spi_ready(void) +{ + unsigned int status,discard; uint32_t started=F28335Boot_Now(),budget=20000UL; + do { + spi_cs(0); + if(!spi_octet(5,&discard) || !spi_octet(255,&status)) { spi_cs(1); return false; } + spi_cs(1); + if(!(status&1U)) return true; + } while(--budget && (uint32_t)(F28335Boot_Now()-started)<50UL); + return false; +} +/* Читать разрешено всю физическую EEPROM, включая параметры. Проверка + * через вычитание защищает от переполнения адреса. spi_release обязателен + * после успешного захвата SPI независимо от результата последующего обмена. */ +bool F28335Boot_Read(void *u,uint32_t address,pcan_boot_byte_t *p,unsigned int n) +{ + boot_spi_saved saved; unsigned int i,value; bool ok; (void)u; + if(address>0x40000UL || n>0x40000UL-address || !spi_take(&saved)) return false; + ok=spi_ready(); + spi_cs(0); if(ok) ok=spi_prefix(3,address); + for(i=0;ok && i0x3FE00UL || n>0x3FE00UL-address || !spi_take(&saved)) return false; + ok=spi_ready(); + while(ok && n) { +/* Нельзя пересекать страницу одной командой WRITE: EEPROM может завернуть + * адрес внутри страницы. Для каждого фрагмента заново выдаём WREN (06h), + * WRITE (02h) и ждём снятия WIP. Сравнение readback выполняет верхний слой. */ + chunk=256U-(unsigned int)(address&255U); if(chunk>n) chunk=n; + spi_cs(0); ok=spi_octet(6,&discard); spi_cs(1); /* WREN */ + spi_cs(0); if(ok) ok=spi_prefix(2,address); + for(i=0;ok && i + +/* Формат журнала фиксирован: u32 little endian. Нельзя сохранять C-структуру + * через memcpy: выравнивание и sizeof на C28x отличаются от обычного ПК. */ +static uint32_t bs_get32(const pcan_boot_byte_t *p) +{ return (uint32_t)p[0] | ((uint32_t)p[1]<<8) | ((uint32_t)p[2]<<16) | ((uint32_t)p[3]<<24); } +static void bs_put32(pcan_boot_byte_t *p, uint32_t v) +{ unsigned int i; for(i=0;i<4;++i) p[i]=(pcan_boot_byte_t)((v>>(8*i))&255U); } +/* Потоковый CRC32: первый вызов получает crc=0, следующие — предыдущий результат. + * Внутренняя инверсия позволяет считать один CRC по нескольким порциям EEPROM. + * Маска 255 исключает старшие биты 16-битного представления октета на C28x. + * Это проверка повреждения данных, а не криптографическая подпись. */ +uint32_t f28335_boot_crc(uint32_t crc, const pcan_boot_byte_t *p, unsigned int n) +{ unsigned int i,b; crc=~crc; for(i=0;i>1)^((crc&1U)?0xEDB88320UL:0); } return ~crc; } +static uint32_t bs_base(unsigned int slot) { return slot?F28335_AB_SLOT_B:F28335_AB_SLOT_A; } +/* Принимаем запись только при совпадении magic, версии, marker и CRC. + * Дополнительно проверяем смысл номеров слотов: pending не может быть active. + * Наличие правильного marker без правильного CRC не разрешает запуск. */ +static bool bs_record_valid(const pcan_boot_byte_t *p) +{ + return bs_get32(p)==0x32424146UL && bs_get32(p+4)==1 && + bs_get32(p+60)==0x51AFC03DUL && bs_get32(p+56)==f28335_boot_crc(0,p,56) && + (p[12]<2 || p[12]==F28335_AB_NONE) && + (p[13]<2 || p[13]==F28335_AB_NONE) && p[14]<=1 && + (p[13]==F28335_AB_NONE || p[13]!=p[12]); +} +/* Карта записи, смещения в октетах: + * 0..3 magic FAB2; 4..7 версия; 8..11 sequence; 12 active; 13 pending; + * 14 attempted; 15 резерв; 16..35 manifest A; 36..55 manifest B; + * 56..59 CRC первых 56 октетов; 60..63 marker завершённой публикации. + * Manifest: size, CRC, FW (по u32), Product (u16), HW min/max, 4 октета резерва. */ +static void bs_decode(f28335_boot_store_t *s, const pcan_boot_byte_t *p) +{ + unsigned int i; s->sequence=bs_get32(p+8); s->active=p[12]; + s->pending=p[13]; s->attempted=p[14]; + for(i=0;i<2;++i) { + const pcan_boot_byte_t *q=p+16+i*20; + s->image[i].image_size=bs_get32(q); s->image[i].image_crc32=bs_get32(q+4); + s->image[i].firmware_version=bs_get32(q+8); + s->image[i].product_type=(uint16_t)(q[12]|(q[13]<<8)); + s->image[i].hardware_revision_min=q[14]; s->image[i].hardware_revision_max=q[15]; + } +} +/* Читаем обе копии журнала. Нераспознанная разметка допускает CAN recovery + * с active=NONE; ошибка чтения запрещает запись, поскольку реальный active неизвестен. + * Эта функция не преобразует старый SCI8 по адресу 0 в новую A/B-разметку. */ +bool f28335_boot_open(f28335_boot_store_t *s, const f28335_boot_io_t *io) +{ + pcan_boot_byte_t a[64],b[64]; bool va,vb; + if(!s || !io || !io->read || !io->write) return false; + memset(s,0,sizeof(*s)); s->io=*io; s->active=s->pending=F28335_AB_NONE; + if(!io->read(io->user,0,a,64) || !io->read(io->user,256,b,64)) { s->io_fault=true; return false; } + va=bs_record_valid(a); vb=bs_record_valid(b); + if(!va && !vb) return true; +/* Сравнение sequence по модулю 2^32: разность менее половины диапазона + * считается более новой записью. При равенстве выбирается страница 1. + * Соседние публикации отличаются на единицу, в том числе после переполнения. */ + s->page=vb && (!va || (uint32_t)(bs_get32(b+8)-bs_get32(a+8))<0x80000000UL)?1:0; + bs_decode(s,s->page?b:a); s->valid=true; return true; +} +/* Публикация выполняется в другую страницу, текущую действующую не трогаем. + * Порядок принципиален: обнулить marker -> проверить -> записать тело -> + * проверить тело -> записать marker последним -> проверить всю запись. + * При обрыве питания загрузчик выбирает прежнюю либо полностью новую запись. + * Каждый memcmp учитывает sizeof элемента, поскольку элемент здесь — октет + * протокола, но на C28x занимает адресуемое 16-битное слово. */ +static bool bs_save(f28335_boot_store_t *s) +{ + pcan_boot_byte_t p[64],check[64],invalid[4]={0,0,0,0}; unsigned int i; + unsigned int page=s->valid?(s->page^1U):0; + uint32_t addr=(uint32_t)page*256; + memset(p,0,sizeof(p)); bs_put32(p,0x32424146UL); bs_put32(p+4,1); + bs_put32(p+8,s->sequence+1); p[12]=s->active; p[13]=s->pending; p[14]=s->attempted; + for(i=0;i<2;++i) { + pcan_boot_byte_t *q=p+16+i*20; + bs_put32(q,s->image[i].image_size); bs_put32(q+4,s->image[i].image_crc32); + bs_put32(q+8,s->image[i].firmware_version); + q[12]=s->image[i].product_type&255U; q[13]=(s->image[i].product_type>>8)&255U; + q[14]=s->image[i].hardware_revision_min; q[15]=s->image[i].hardware_revision_max; + } + bs_put32(p+56,f28335_boot_crc(0,p,56)); bs_put32(p+60,0x51AFC03DUL); + /* The old page is never erased. A torn write cannot publish a partial record. */ + if(!s->io.write(s->io.user,addr+60,invalid,4) || + !s->io.read(s->io.user,addr+60,check,4) || memcmp(check,invalid,sizeof(invalid)) || + !s->io.write(s->io.user,addr,p,60) || + !s->io.read(s->io.user,addr,check,60) || memcmp(p,check,60*sizeof(*p)) || + !s->io.write(s->io.user,addr+60,p+60,4) || + !s->io.read(s->io.user,addr,check,64) || memcmp(p,check,sizeof(p))) return false; + s->page=page; s->sequence++; s->valid=true; return true; +} +/* Изменения сначала готовятся в копии состояния next. Рабочее состояние + * заменяем только после публикации. Если запись/контрольное чтение сорвались, + * перечитываем журнал: marker мог успеть записаться до ошибки readback. + * После неудачи чтения io_fault блокирует дальнейшие изменения хранилища. */ +static bool bs_publish(f28335_boot_store_t *s, f28335_boot_store_t *next) +{ + if(bs_save(next)) { *s=*next; return true; } + /* A failed final read may still have committed: reload before any more writes. */ + { f28335_boot_io_t io=s->io; if(!f28335_boot_open(s,&io)) { + s->valid=false; s->io_fault=true; return false; } } + return false; +} +/* Логический ERASE: обнуляем manifest неактивного слота в журнале. + * Саму EEPROM стирать целиком не требуется — каждый байт будет перезаписан. + * Active защищён всегда; наличие pending запрещает начало новой записи, + * пока кандидат не подтверждён либо не снят при следующем выборе загрузки. */ +bool f28335_boot_prepare(f28335_boot_store_t *s, unsigned int slot) +{ + f28335_boot_store_t next=*s; + if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE) return false; + memset(&next.image[slot],0,sizeof(next.image[slot])); + return bs_publish(s,&next); +} +/* Записываем не более одного CAN-блока и немедленно сравниваем прочитанное. + * Проверка n <= capacity-off выполняется после off <= capacity: это исключает + * переполнение суммы off+n и выход из слота в соседний слот или параметры. */ +bool f28335_boot_write(f28335_boot_store_t *s, unsigned int slot, uint32_t off, + const pcan_boot_byte_t *p, unsigned int n) +{ + pcan_boot_byte_t check[8]; + if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE || !n || n>8 || + off>F28335_AB_SLOT_BYTES || n>F28335_AB_SLOT_BYTES-off) return false; + return s->io.write(s->io.user,bs_base(slot)+off,p,n) && + s->io.read(s->io.user,bs_base(slot)+off,check,n) && !memcmp(check,p,n*sizeof(*p)); +} +/* Слово SCI8 занимает два октета файла, младший октет идёт первым. + * Смещение увеличиваем только после успешного чтения; усечённый файл отклоняем. */ +static bool bs_u16(f28335_boot_store_t *s,uint32_t base,uint32_t size,uint32_t *off,uint16_t *v) +{ + pcan_boot_byte_t p[2]; if(*off>size || size-*off<2 || + !s->io.read(s->io.user,base+*off,p,2)) return false; + *v=(uint16_t)(p[0]|(p[1]<<8)); *off+=2; return true; +} +/* Особенность таблицы TI: адрес u32 передаётся старшим словом вперёд, + * при этом внутри каждого слова остаётся little endian. Не заменять на get32. */ +static bool bs_addr(f28335_boot_store_t *s,uint32_t base,uint32_t size,uint32_t *off,uint32_t *v) +{ + uint16_t hi,lo; if(!bs_u16(s,base,size,off,&hi) || !bs_u16(s,base,size,off,&lo)) return false; + *v=((uint32_t)hi<<16)|lo; return true; +} +/* The complete table is validated before any application RAM is written. + * Loader RAM is E000..FFFF and M0/M1. Flash, peripherals and XINTF are forbidden. */ +/* writer=NULL: только разбираем и проверяем таблицу, RAM приложения не меняем. + * writer задан: повторно проверяем таблицу и переносим слова в разрешённую RAM. + * Массивы starts/ends ограничены MAX_SECTIONS; они нужны для обнаружения + * пересекающихся секций, в том числе секций с разным порядком адресов. */ +static bool bs_table(f28335_boot_store_t *s,unsigned int slot,uint32_t size, + f28335_boot_ram_writer writer,void *user,uint32_t *entry) +{ + uint32_t starts[F28335_AB_MAX_SECTIONS],ends[F28335_AB_MAX_SECTIONS]; + uint32_t off=0,addr,end,base=bs_base(slot); unsigned int sections=0,i; + uint16_t count,word; bool entry_loaded=false; + if(!bs_u16(s,base,size,&off,&word) || word!=0x08AA) return false; +/* После ключа AA 08 пропускаем 16 резервных октетов; далее расположен entry. + * Нулевой count завершает таблицу строго на конце файла, без хвостовых данных. */ + off=18; if(!bs_addr(s,base,size,&off,entry)) return false; + for(;;) { + if(!bs_u16(s,base,size,&off,&count)) return false; + if(!count) return off==size && entry_loaded; + if(sections==F28335_AB_MAX_SECTIONS || !bs_addr(s,base,size,&off,&addr)) return false; + end=addr+count; +/* Разрешён только полуинтервал RAM [0x8000,0xE000) в словах CPU. + * Верхняя граница защищает RAM работающего загрузчика; нижняя — стек, + * handoff и регистры. Проверка размера payload использует уже октеты файла. */ + if(addr<0x8000UL || end>0xE000UL || end<=addr || + off>size || (uint32_t)count*2>size-off) return false; + for(i=0;istarts[i]) return false; + starts[sections]=addr; ends[sections++]=end; + if(*entry>=addr && *entry1 || m->image_size<24 || m->image_size>F28335_AB_SLOT_BYTES || + (m->image_size&1) || m->product_type!=0x2833 || + m->hardware_revision_min>1 || m->hardware_revision_max<1) return false; + for(off=0;offimage_size;off+=n) { + n=(m->image_size-off<32)?(unsigned int)(m->image_size-off):32; + if(!s->io.read(s->io.user,bs_base(slot)+off,p,n)) return false; + crc=f28335_boot_crc(crc,p,n); + } + if(crc!=m->image_crc32 || !bs_table(s,slot,m->image_size,0,0,&local_entry)) return false; + if(entry) *entry=local_entry; + return true; +} +/* COMMIT публикует проверенный образ как pending, не меняя active. + * Повторная проверка EEPROM непосредственно перед публикацией не позволяет + * назначить кандидатом образ, испорченный после предыдущего VERIFY. */ +bool f28335_boot_commit(f28335_boot_store_t *s,unsigned int slot,const pcan_boot_manifest_t *m) +{ + f28335_boot_store_t next=*s; + if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE || + !f28335_boot_verify(s,slot,m,0)) return false; + next.image[slot]=*m; next.pending=slot; next.attempted=0; + return bs_publish(s,&next); +} +/* Подтверждать можно только действительно выбранный для пробного запуска слот. + * Требование attempted исключает подтверждение ещё ни разу не запускавшегося + * кандидата. Повтор CONFIRM уже активного слота возвращает успех без записи. */ +bool f28335_boot_confirm(f28335_boot_store_t *s,unsigned int running_slot) +{ + f28335_boot_store_t next=*s; + if(s->io_fault || running_slot>1) return false; + if(s->pending==F28335_AB_NONE) return s->valid && s->active==running_slot; + if(s->pending!=running_slot || !s->attempted) return false; + next.active=running_slot; next.pending=F28335_AB_NONE; next.attempted=0; + return bs_publish(s,&next); +} +/* Выбор выполняется при старте загрузчика. attempted сохраняется ДО перехода + * в приложение: после зависания, watchdog reset или потери питания следующий + * старт уже знает о незавершённой пробе и возвращает прежний active. + * Успех функции с slot=NONE означает recovery, а не разрешение перехода в RAM. */ +bool f28335_boot_select(f28335_boot_store_t *s,unsigned int *slot) +{ + f28335_boot_store_t next=*s; *slot=F28335_AB_NONE; + if(s->io_fault) return false; + if(s->pending!=F28335_AB_NONE) { + if(!s->attempted && f28335_boot_verify(s,s->pending,&s->image[s->pending],0)) { + next.attempted=1; + if(!bs_publish(s,&next)) return false; + *slot=s->pending; return true; + } +/* Кандидат уже запускался без подтверждения либо не прошёл проверку. + * Снимаем pending отдельной публикацией; подтверждённый active остаётся прежним. */ + next.pending=F28335_AB_NONE; next.attempted=0; + if(!bs_publish(s,&next)) return false; + } + if(s->active<2 && f28335_boot_verify(s,s->active,&s->image[s->active],0)) *slot=s->active; + return true; +} +/* Сначала полная проверка CRC и всех адресов без записи, затем перенос слов. + * Платформа вызывает entry только при true; частичная загрузка при ошибке I/O + * не даёт разрешения на запуск приложения. */ +bool f28335_boot_load(f28335_boot_store_t *s,unsigned int slot, + f28335_boot_ram_writer writer,void *user,uint32_t *entry) +{ + return slot<2 && writer && entry && f28335_boot_verify(s,slot,&s->image[slot],entry) && + bs_table(s,slot,s->image[slot].image_size,writer,user,entry); +} diff --git a/c/protocan-boot/ports/tms320f28335/f28335_boot_store.h b/c/protocan-boot/ports/tms320f28335/f28335_boot_store.h new file mode 100644 index 0000000..f5065a9 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_boot_store.h @@ -0,0 +1,55 @@ +#ifndef F28335_BOOT_STORE_H +#define F28335_BOOT_STORE_H +#include "../../include/pcan_boot.h" + +/* All EEPROM offsets/lengths below are OCTETS, CPU destinations are WORDS. */ +/* Физическая EEPROM 256 КиБ: две страницы журнала по 256 октетов, + * два слота по 130560 октетов. С 0x3FE00 начинается резерв, с 0x3FEFC — + * прежняя область параметров. Константы ниже не являются CPU word-адресами. */ +#define F28335_AB_SLOT_BYTES 0x1FE00UL +#define F28335_AB_SLOT_A 0x00200UL +#define F28335_AB_SLOT_B 0x20000UL +#define F28335_AB_PARAMS 0x3FEFCUL +#define F28335_AB_NONE 0xFFU +#define F28335_AB_RECORD 64U +#define F28335_AB_MAX_SECTIONS 64U + +/* Контракт I/O: address и n измеряются в октетах, независимо от sizeof(char). + * true означает, что выполнена вся операция; короткий обмен должен вернуть false. + * Callbacks вызываются синхронно из main, а user передаётся им без изменений. */ +typedef struct { + bool (*read)(void *, uint32_t, pcan_boot_byte_t *, unsigned int); + bool (*write)(void *, uint32_t, const pcan_boot_byte_t *, unsigned int); + void *user; +} f28335_boot_io_t; +typedef struct { + f28335_boot_io_t io; +/* sequence — номер последней публикации; page — выбранная копия журнала. + * active — подтверждённый слот; pending — кандидат; attempted — уже была проба. + * valid показывает наличие распознанной записи, io_fault запрещает изменения + * после ошибки чтения. Отсутствующий слот обозначается NONE, а не нулём. */ + uint32_t sequence; + unsigned int page, active, pending, attempted; + bool valid, io_fault; + pcan_boot_manifest_t image[2]; +} f28335_boot_store_t; + +uint32_t f28335_boot_crc(uint32_t crc, const pcan_boot_byte_t *p, unsigned int n); +bool f28335_boot_open(f28335_boot_store_t *s, const f28335_boot_io_t *io); +/* Blank/unrecognised EEPROM opens successfully with active=NONE. I/O errors fail. */ +bool f28335_boot_prepare(f28335_boot_store_t *s, unsigned int slot); +bool f28335_boot_write(f28335_boot_store_t *s, unsigned int slot, uint32_t offset, + const pcan_boot_byte_t *data, unsigned int n); +bool f28335_boot_verify(f28335_boot_store_t *s, unsigned int slot, + const pcan_boot_manifest_t *m, uint32_t *entry); +bool f28335_boot_commit(f28335_boot_store_t *s, unsigned int slot, + const pcan_boot_manifest_t *m); +bool f28335_boot_confirm(f28335_boot_store_t *s, unsigned int running_slot); +/* Records a trial BEFORE returning it; a second unconfirmed boot rolls back. */ +bool f28335_boot_select(f28335_boot_store_t *s, unsigned int *slot); +/* Запись одного проверенного слова приложения по CPU word-адресу. + * Должна вернуть false при невозможности записи; после отказа запуск запрещён. */ +typedef bool (*f28335_boot_ram_writer)(void *, uint32_t, uint16_t); +bool f28335_boot_load(f28335_boot_store_t *s, unsigned int slot, + f28335_boot_ram_writer write_word, void *user, uint32_t *entry); +#endif diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_application.c b/c/protocan-boot/ports/tms320f28335/f28335_can_application.c new file mode 100644 index 0000000..f7fe30b --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_application.c @@ -0,0 +1,10 @@ +#include "f28335_can_application_config.h" /* Получает от проекта разрешение CAN A/B и версию приложения; этот конфигурационный заголовок должен находиться в include paths CCS. */ +#ifndef F28335_CAN_BOOT_APPLICATION_ENABLED /* Отсутствующее аппаратное решение нельзя трактовать как разрешение записи служебных областей EEPROM. */ +#error "Define F28335_CAN_BOOT_APPLICATION_ENABLED in f28335_can_application_config.h" /* Останавливает сборку до появления приложения с неполной интеграцией загрузчика. */ +#endif /* Завершает проверку обязательного конфигурационного признака проекта. */ +#if F28335_CAN_BOOT_APPLICATION_ENABLED /* Самостоятельный Flash-образ и платы без M95M02 исключают весь CAN A/B-код на этапе компиляции. */ +#include "../../src/pcan_boot.c" /* Компилирует единственный автомат команд ProtoCAN Boot с его штатными сессиями, CRC32 и проверкой последовательности пакетов. */ +#include "f28335_boot_store.c" /* Подключает общий A/B-журнал, readback, проверку SCI8 и выбор подтверждённого слота той же версии templates. */ +#include "f28335_boot_hw.c" /* Предоставляет SPI EEPROM, watchdog и согласованный handoff между приложением и постоянным Flash-загрузчиком. */ +#include "f28335_can_boot.c" /* В режиме приложения обслуживает вход в boot и READY/CONFIRM, сохраняя служебные mailbox 3/4/6 отдельно от технологического CAN. */ +#endif /* Постоянный загрузчик собирается отдельным CCS-проектом templates с F28335_BOOT_LOADER=1, а не этим прикладным модулем. */ diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c new file mode 100644 index 0000000..f02354b --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.c @@ -0,0 +1,284 @@ +/* Separate Flash recovery loader and application service adapter. */ +#include "DSP2833x_Device.h" +#include "f28335_can_boot.h" +#if EEPROM_M95M02 +#include "f28335_boot_platform.h" +#include +/* boot хранит текущую CAN-сессию в RAM, store — прочитанное состояние журнала. + * Сброс сессии не удаляет active/pending из EEPROM. */ +static pcan_boot_t boot; +static f28335_boot_store_t store; +/* Кольцевая очередь: ISR производит кадры, main потребляет. Из 32 элементов + * используется 31, чтобы head==tail однозначно означало пустую очередь. + * Долгие операции SPI запрещены внутри обработчика CAN. */ +static volatile unsigned int head,tail,overflow; +static struct { uint32_t id; unsigned int dlc; pcan_boot_byte_t data[8]; } queue[32]; +/* reset_requested только планирует reset; Service ждёт завершения TX. + * ready сообщает об окончании старта приложения, confirmed — о сохранённом + * подтверждении слота. healthy отражает результат открытия журнала при Init. */ +static unsigned int reset_requested,reset_session,ready,healthy,confirmed; +static uint32_t sent_at,ready_at; +static unsigned int main_passes; +static unsigned int addressed; /* Разрешает обслуживание только после проверки номера PERIPH и установки согласованных фильтров CAN. */ +static int tx_busy,tx_canceling; +/* Один исходящий mailbox исключает перезапись ещё передаваемого ответа. + * MDL содержит первые четыре октета, MDH — следующие четыре, младшим вперёд. + * Запрос CANTRS ещё не означает успешную доставку: CANTA проверяется в Service. + * Аппаратный CAN ACK не является отдельным прикладным подтверждением от ПК. */ +static bool transmit(void *u, uint32_t id, const pcan_boot_byte_t *d, pcan_boot_byte_t n) +{ + unsigned int i; unsigned long lo=0, hi=0; (void)u; + if (tx_busy) return false; + for(i=0;i1) return false; + if(!f28335_boot_confirm(&store,running)) return false; + boot.config.active_slot=running; confirmed=1; return true; +} +static bool can_reboot(void *u) { (void)u; return healthy; } +static void reboot(void *u) { (void)u; reset_session=0; reset_requested=1; } +/* Контракт enter_boot: 0 — загрузчик готов и ядро может отправить ACK; + * 1 — переход отложен, ACK придёт после reset; 2 — вход запрещён. + * Приложение требует handoff нашего загрузчика и подтверждённый текущий слот, + * чтобы не начать обновление из старого SPI-ROM старта или незавершённой пробы. */ +static unsigned int enter(void *u,pcan_boot_byte_t session) +{ + (void)u; + if(!healthy) return 2; + if(F28335_BOOT_LOADER) return 0; + /* No destructive fallback on boards still starting through the SPI ROM. */ + if((F28335Boot_RunningSlot()>1 && F28335Boot_RunningSlot()!=F28335_BOOT_FLASH_SLOT) || !confirmed) return 2; /* Только handoff общего загрузчика разрешает переход из EEPROM либо защищённой внутренней Flash; старый SPI-ROM старт остаётся запрещён. */ + reset_session=session; reset_requested=1; return 1; +} +static void info32(pcan_boot_byte_t *p,uint32_t v) +{ unsigned int i; for(i=0;i<4;++i) p[i]=(pcan_boot_byte_t)((v>>(i*8))&255U); } +/* Паспорт помещается в classic CAN по страницам из восьми октетов. + * NAME возвращает фрагменты строки с завершающим NUL; неизвестная страница + * отклоняется. MEMORY: 0 — ёмкость/страница/режим/running, 1 — базы A/B, + * 2 — active/pending/attempted/healthy/тайм-аут, 3 — область параметров. */ +static bool info(void *u,pcan_boot_byte_t command,pcan_boot_byte_t page,pcan_boot_byte_t *out) +{ + const char *name=boot.config.device_type==1U && boot.config.device_id==8U?"Zadatchik":boot.config.device_type==1U && boot.config.device_id==5U?"UMP1":boot.config.device_type==1U && boot.config.device_id==6U?"UMP2":F28335_CAN_BOOT_DEVICE_NAME; /* Паспорт различает три назначенных Excel устройства; резервные номера сохраняют аппаратное имя. */ + unsigned int i,index,name_size=(unsigned int)strlen(name)+1U; (void)u; /* Длина включает завершающий NUL, чтобы последняя страница имени однозначно завершала чтение. */ + if(command==PCAN_BOOT_CMD_CAPABILITIES && page==0) { + /* bits: ping, discovery, identity, name, memory, A/B, confirm, rollback, + * separate loader, session timeout, readback, SCI8 validation. */ + info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2 || F28335Boot_RunningSlot()==F28335_BOOT_FLASH_SLOT)?0xFFFUL:0x1FUL); /* Flash-приложение с достоверным handoff поддерживает вход в постоянный CAN Boot так же, как подтверждённый EEPROM-образ. */ + info32(out+4,F28335_AB_SLOT_BYTES); return true; + } + if(command==PCAN_BOOT_CMD_DEVICE_NAME) { + if((unsigned int)page*8U>=name_size) return false; /* Страница после конца выбранного имени не является допустимой частью паспорта. */ + for(i=0;i<8;++i) { index=(unsigned int)page*8U+i; + out[i]=index=F28335_CAN_BOOT_PERIPH_COUNT) return; /* Номер вне Excel-диапазона 0–31 не подменяется общим адресом и не открывает запись другой платы. */ + memset(&cfg,0,sizeof(cfg)); memset(&port,0,sizeof(port)); + io.read=F28335Boot_Read; io.write=F28335Boot_Write; io.user=0; + healthy=f28335_boot_open(&store,&io); + cfg.device_type=1U+periph_id/16U; cfg.device_id=periph_id%16U; /* Excel: PERIPH 0–15 → Type 1, 16–31 → Type 2; младшие четыре бита задают Device ID. */ + cfg.product_type=F28335_CAN_BOOT_PRODUCT; cfg.hardware_revision=1; +#if F28335_BOOT_LOADER + cfg.firmware_version=store.active<2?store.image[store.active].firmware_version:0; +#else + cfg.firmware_version=F28335_CAN_BOOT_FIRMWARE_VERSION; +#endif + head=tail=overflow=reset_requested=reset_session=ready=main_passes=0; tx_busy=tx_canceling=0; + confirmed=running==F28335_BOOT_FLASH_SLOT || (healthy && running<2 && store.active==running && store.pending==F28335_AB_NONE); /* Flash уже проверена CRC постоянным boot; пробное подтверждение требуется только EEPROM-кандидату. */ + cfg.active_slot=store.active; + cfg.slot_count=2; cfg.max_image_size=F28335_AB_SLOT_BYTES; cfg.ack_window=16; + cfg.session_timeout_ms=30000UL; + port.send=transmit; port.erase_slot=erase; port.write_slot=write_block; + port.verify_status=verify; port.set_pending_slot=commit; port.reboot=reboot; + port.confirm_running_slot=confirm; port.enter_boot=enter; + port.can_reboot=can_reboot; port.service_info=info; + if(!pcan_boot_init(&boot,&cfg,&port,0)) return; + addressed=1U; /* Дальнейшие ISR, основной цикл и handoff используют только успешно созданную адресную конфигурацию. */ + EALLOW; +/* Меняем только MBOX3/4/6: маска 88=8+16+64. MBOX0..2 — старый обмен, + * MBOX5 — heartbeat. Приём broadcast выделен в отдельный точный mailbox, + * чтобы слишком широкая маска Boot не перехватывала сообщения приложения. + * 72=8+64 — оба RX, 16 — TX. Регистры флагов очищаются записью единицы. */ + ECanaRegs.CANME.all &= ~88UL; + ECanaMboxes.MBOX3.MSGID.all=0xC0000000UL|pcan_boot_make_id(0,0,cfg.device_type,cfg.device_id,0,0); + ECanaLAMRegs.LAM3.all=0x100FFFFFUL; + ECanaMboxes.MBOX3.MSGCTRL.all=8; + /* MBOX5 belongs to the application's heartbeat. MBOX6 is discovery only. */ + ECanaMboxes.MBOX6.MSGID.all=0xC0000000UL|pcan_boot_make_id(0,0,7,15,13,0); + ECanaLAMRegs.LAM6.all=0x10000000UL; /* Ignore priority only. */ + ECanaMboxes.MBOX6.MSGCTRL.all=0; + ECanaRegs.CANMD.all=(ECanaRegs.CANMD.all|72UL)&~16UL; + ECanaRegs.CANRMP.all=72UL; + ECanaRegs.CANMIM.all |=72UL; + ECanaRegs.CANME.all |=88UL; + EDIS; +} +/* ISR только проверяет заголовок и копирует кадр. Чужие адреса и RTR + * отбрасываются до очереди. Глобальный адрес допускается только для discovery; + * DLC и смысл команды окончательно проверит ядро в основном цикле. */ +static void receive_box(volatile struct MBOX *box,uint32_t mask) +{ + unsigned int next=(head+1U)&31U, i; + unsigned long lo, hi; + uint32_t id; unsigned int type; + if(!(ECanaRegs.CANRMP.all&mask)) return; + if(box->MSGCTRL.bit.RTR) { ECanaRegs.CANRMP.all=mask; return; } + id=box->MSGID.all&0x1FFFFFFFUL; + type=pcan_boot_id_msg_type(id); + if(!(box->MSGID.all&0x80000000UL) || pcan_boot_id_route(id)!=0 || + (type!=9 && type!=10 && type!=11 && type!=13) || + !((pcan_boot_id_device_type(id)==boot.config.device_type && /* Сравнивает тип именно этой платы, а не прежнюю общую константу 3. */ + pcan_boot_id_device_id(id)==boot.config.device_id) || /* Отбрасывает команды соседних PERIPH ещё до очереди и любых операций EEPROM. */ + (type==13 && pcan_boot_id_device_type(id)==7 && pcan_boot_id_device_id(id)==15 && + pcan_boot_id_msg_body(id)==0))) { ECanaRegs.CANRMP.all=mask; return; } + if(next==tail) overflow=1; + else { + queue[head].id=box->MSGID.all&0x1FFFFFFFUL; + queue[head].dlc=box->MSGCTRL.bit.DLC; + lo=box->MDL.all; hi=box->MDH.all; + for(i=0;i<4;++i) { queue[head].data[i]=(lo>>(8U*i))&255U; + queue[head].data[i+4]=(hi>>(8U*i))&255U; } + head=next; + } + ECanaRegs.CANRMP.all=mask; +} + +void F28335CanBoot_RxISR(void) +{ + if(!addressed) return; /* Неверный или ещё не настроенный номер PERIPH не должен принимать даже оставшиеся флаги RX. */ + receive_box(&ECanaMboxes.MBOX3,8UL); + receive_box(&ECanaMboxes.MBOX6,64UL); +} +/* Вызывать после инициализации параметров, датчиков и прикладного режима. + * От этого момента отсчитывается интервал наблюдения перед авто-CONFIRM. */ +void F28335CanBoot_Ready(void) +{ ready=1; ready_at=F28335Boot_Now(); } +/* Используется таймерными ISR приложения. Во время пробы кормление watchdog + * должно доказывать выполнение main: работа одного ISR не доказывает готовность. + * Старый старт без handoff сохраняет прежнюю политику watchdog. */ +unsigned int F28335CanBoot_WatchdogAllowed(void) +{ return F28335Boot_RunningSlot()>1 || confirmed; } +/* Неблокирующий диспетчер относительно ожидания CAN: вызывать в каждом проходе main. + * Сами callbacks проверки/записи EEPROM синхронные. Порядок здесь важен: + * проба приложения -> завершение TX -> reset -> poll -> ошибки RX -> один кадр. */ +unsigned int F28335CanBoot_Active(void) { return addressed && (boot.state!=PCAN_BOOT_STATE_IDLE || reset_requested); } /* Открытый ENTER_BOOT удерживает recovery; диагностический PING не меняет приоритет Flash и EEPROM. */ +void F28335CanBoot_Service(void) +{ + uint32_t now=F28335Boot_Now(); + if(!addressed) return; /* Не обслуживает старую RAM-сессию после отказа повторной инициализации адреса. */ + if(!F28335_BOOT_LOADER && ready && !confirmed && healthy && F28335Boot_RunningSlot()<2) { + /* A trial must keep executing main, not merely a timer ISR. */ +/* После 100 проходов main и 5 секунд пробуем сохранить CONFIRM. + * Если до 10 секунд сохранение не удалось, main перестаёт кормить watchdog, + * что позволяет следующему старту откатиться к подтверждённому образу. */ + if((uint32_t)(now-ready_at)<10000UL) ServiceDog(); + if(main_passes<100) ++main_passes; + if(main_passes==100 && (uint32_t)(now-ready_at)>=5000UL) (void)confirm(0); + } + if(tx_busy) { +/* После CANTRR ждём завершения отмены или запоздавшего ACK, прежде чем + * повторно использовать mailbox. reset_requested к этому моменту уже снят, + * поэтому позднее подтверждение не должно перезапустить устройство. */ + if(tx_canceling) { + if(!((ECanaRegs.CANAA.all|ECanaRegs.CANTA.all)&16UL)) return; + ECanaRegs.CANAA.all=16UL; ECanaRegs.CANTA.all=16UL; + tx_busy=tx_canceling=0; + } else if((uint32_t)(now-sent_at)>250UL) { + /* Cancel reset immediately, even if a late CAN ACK races CANTRR. */ + reset_requested=0; pcan_boot_abort(&boot); tail=head; + tx_canceling=1; ECanaRegs.CANTRR.all=16UL; return; + } else if(ECanaRegs.CANTA.all&16UL) { + ECanaRegs.CANTA.all=16UL; tx_busy=0; + } else return; + } + if(reset_requested) { F28335Boot_Reset(reset_session); return; } + pcan_boot_poll(&boot,now); + if(tx_busy) return; +/* После потери кадра нельзя молча продолжать запись: сбрасываем RAM-сессию + * и накопленную очередь. Подтверждённый образ и опубликованный pending сохраняются. */ + if(overflow || (ECanaRegs.CANRML.all&72UL)) { + overflow=0; ECanaRegs.CANRML.all=72UL; + pcan_boot_abort(&boot); tail=head; return; + } + if(tail!=head) { + pcan_boot_process(&boot,queue[tail].id,queue[tail].data,queue[tail].dlc); + tail=(tail+1U)&31U; + } +} +/* Используем session из NOINIT только для нового ENTER_BOOT после reset. + * Это отправка отложенного ACK готовности, а не восстановление принятых блоков + * или CRC незавершённой передачи: данные сессии через reset не сохраняются. */ +void F28335CanBoot_Resume(unsigned int session) +{ + if(addressed && F28335_BOOT_LOADER && session && session<256) /* Восстанавливает только допустимую сессию адресованного загрузчика после reset. */ + (void)pcan_boot_process(&boot,pcan_boot_make_id(1,0, /* ACK относится к тому же физическому PERIPH, который принимал ENTER_BOOT в приложении. */ + boot.config.device_type,boot.config.device_id,9,(session<<8)|2),0,0); /* MsgType 9, команда 2 и исходный SessionID сохраняют протокол handoff. */ +} +#else +void F28335CanBoot_EarlyInit(void) {} +void F28335CanBoot_Init(unsigned int periph_id) { (void)periph_id; } /* Сборка без M95M02 не занимает CAN-адрес и не открывает сервис записи. */ +void F28335CanBoot_RxISR(void) {} +void F28335CanBoot_Service(void) {} +unsigned int F28335CanBoot_Active(void) { return 0U; } /* Профиль без M95M02 не создаёт CAN-сеанс и не удерживает старт общего загрузчика. */ +void F28335CanBoot_Ready(void) {} +unsigned int F28335CanBoot_WatchdogAllowed(void) { return 1; } +void F28335CanBoot_Resume(unsigned int session) { (void)session; } +#endif diff --git a/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h new file mode 100644 index 0000000..59476e8 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_can_boot.h @@ -0,0 +1,28 @@ +#ifndef F28335_CAN_BOOT_H +#define F28335_CAN_BOOT_H +#include "../../include/pcan_boot.h" +/* Приложение задаёт версию из firmware_version.h до подключения этого заголовка. + * Формат поля FW: major[31:24], minor[23:16], patch[15:0]. Ноль — запасное + * значение при отсутствии версии сборки, а не прошитая здесь версия устройства. */ +#ifndef F28335_CAN_BOOT_FIRMWARE_VERSION +#define F28335_CAN_BOOT_FIRMWARE_VERSION 0UL /* Board supplies the build identity. */ +#endif +/* Адрес ProtoCAN состоит из Device Type (3 бита) и Device ID (4 бита). + * ProductType — отдельный код совместимости прошивки; это не CAN ID и не RS-адрес. */ +#define F28335_CAN_BOOT_PERIPH_COUNT 32U /* Лист «Интерфейс протокола», строки 45–76: PERIPH 0–31 занимают два типа по 16 экземпляров. */ +#define F28335_CAN_BOOT_PRODUCT 0x2833U +#define F28335_CAN_BOOT_DEVICE_NAME "F28335-M95M02" +/* Порядок интеграции приложения: + * StartupWatchdog/EarlyInit сразу после InitSysCtrl; Init после настройки + * таймера и EEPROM; Ready после старта прикладных подсистем; Service в main. + * RxISR вызывается из CAN ISR, WatchdogAllowed проверяется перед кормлением + * watchdog таймерным ISR. Resume применяется только отдельным загрузчиком. */ +void F28335CanBoot_Init(unsigned int periph_id); /* Принимает физический номер PERIPH: 5 — УМП1, 6 — УМП2, 8 — задатчик; общий адрес для всех плат исключён. */ +void F28335CanBoot_EarlyInit(void); +void F28335CanBoot_RxISR(void); +void F28335CanBoot_Service(void); +unsigned int F28335CanBoot_Active(void); /* Удерживает загрузчик в CAN recovery после ENTER_BOOT, не запуская приложение по окончании стартового окна. */ +void F28335CanBoot_Ready(void); +void F28335CanBoot_Resume(unsigned int session); +unsigned int F28335CanBoot_WatchdogAllowed(void); +#endif diff --git a/c/protocan-boot/ports/tms320f28335/f28335_flash_app.c b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.c new file mode 100644 index 0000000..ac5dbd5 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.c @@ -0,0 +1,26 @@ +#include "f28335_flash_app.h" /* Использует ту же границу сектора A и формат описания, что сборщик и RS-программатор. */ +bool f28335_flash_app_validate(f28335_flash_read_word_t read_word, void *user, uint32_t *entry) /* Не обращается к EEPROM и подходит для постоянного загрузчика и проверки staging RAM. */ +{ /* Никакие адреса из непроверенного заголовка не используются для чтения до проверки границ. */ + uint16_t header[F28335_FLASH_APP_HEADER_WORDS], word, octet, bit, i; /* Малый локальный буфер хранит 16 слов описания FAB1. */ + uint32_t address, start, end, expected, crc = 0xFFFFFFFFUL, target, inverse; /* CRC32 IEEE начинается со всех единиц и инвертируется после последнего октета. */ + if (!read_word || !entry) return false; /* Отсутствующий источник или выходной указатель не должен вызывать обращение к памяти. */ + for (i = 0; i < F28335_FLASH_APP_HEADER_WORDS; ++i) header[i] = read_word(user, F28335_FLASH_APP_START + i); /* Читает только фиксированное описание в секторе H. */ + if (header[0] != 0x4146U || header[1] != 0x3142U || header[2] != 1U || header[3] != F28335_FLASH_APP_HEADER_WORDS || header[14] != 0x5AA5U || header[15] != 0xA55AU) return false; /* Физические октеты ASCII FAB1, версия 1, размер и два маркера отличают завершённый образ от стёртого либо старого Flash. */ + target = (uint32_t)header[4] | ((uint32_t)header[5] << 16); /* Точка входа хранится младшим 16-битным словом вперёд внутри описания. */ + start = (uint32_t)header[6] | ((uint32_t)header[7] << 16); /* Нижняя граница защищённого CRC диапазона должна начинаться сразу после описания. */ + end = (uint32_t)header[8] | ((uint32_t)header[9] << 16); /* Верхняя граница является исключённым адресом слова, а не длиной в байтах. */ + expected = (uint32_t)header[10] | ((uint32_t)header[11] << 16); /* Сохранённая CRC32 рассчитана по физическим октетам всех слов диапазона. */ + inverse = (uint32_t)header[12] | ((uint32_t)header[13] << 16); /* Инверсия адреса выявляет частичную публикацию управляющих полей. */ + if (start != F28335_FLASH_APP_DATA || end <= start || end > F28335_FLASH_APP_STOP || target < start || target >= end || inverse != ~target) return false; /* Запрещает RAM, сектор загрузчика, пустой код и случайные адреса из повреждённого описания. */ + for (address = start; address < end; ++address) { /* Проверяет также стёртые промежутки между LOAD-секциями, чтобы JTAG и RS давали одинаковое содержимое. */ + word = read_word(user, address); /* Получает одно 16-битное слово из Flash либо из модели staging SCI8. */ + for (i = 0; i < 2U; ++i) { /* Каждый адрес C28x содержит два физических октета: сначала младший, затем старший. */ + octet = (word >> (8U * i)) & 255U; /* Маска отделяет октет независимо от 16-битного char TI. */ + crc ^= octet; /* Добавляет очередной октет в отражённое состояние CRC32 IEEE. */ + for (bit = 0; bit < 8U; ++bit) crc = (crc & 1UL) ? ((crc >> 1) ^ 0xEDB88320UL) : (crc >> 1); /* 0xEDB88320 — отражённый полином IEEE 802.3, совпадающий с zlib.crc32. */ + } /* Завершает обработку обоих октетов текущего слова. */ + } /* Завершает чтение только внутри области приложения ниже сектора A. */ + if ((crc ^ 0xFFFFFFFFUL) != expected) return false; /* Повреждённое или частично записанное приложение остаётся недоступным для запуска. */ + *entry = target; /* Публикует точку старта только после подтверждения всех адресов и данных. */ + return true; /* Разрешает загрузчику запустить именно проверенную Flash-программу. */ +} /* Ошибка никогда не меняет EEPROM, Flash или сохранённый выходной адрес. */ diff --git a/c/protocan-boot/ports/tms320f28335/f28335_flash_app.h b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.h new file mode 100644 index 0000000..94741e3 --- /dev/null +++ b/c/protocan-boot/ports/tms320f28335/f28335_flash_app.h @@ -0,0 +1,11 @@ +#ifndef F28335_FLASH_APP_H /* Защищает общий контракт Flash-приложения от повторного объявления. */ +#define F28335_FLASH_APP_H /* Один заголовок используется загрузчиком, RS-проверкой и host-тестами. */ +#include "../../include/pcan_boot.h" /* Получает переносимые 16- и 32-битные типы и bool для C28x и ПК. */ +#define F28335_FLASH_APP_START 0x300000UL /* Первые 16 слов сектора H содержат описание FAB1, а не аппаратный boot. */ +#define F28335_FLASH_APP_HEADER_WORDS 16U /* Размер описания равен 32 октетам при 16-битном адресуемом слове C28x. */ +#define F28335_FLASH_APP_DATA 0x300010UL /* Код и Flash LOAD-секции следуют после служебного описания. */ +#define F28335_FLASH_APP_STOP 0x338000UL /* Начало сектора A является исключённой границей приложения. */ +#define F28335_BOOT_FLASH_SLOT 0xFEU /* Отдельный handoff отличает внутреннюю Flash от EEPROM A/B и неизвестного SPI-ROM запуска. */ +typedef uint16_t (*f28335_flash_read_word_t)(void *user, uint32_t address); /* Callback читает одно физическое слово без предположения о памяти host-тестов. */ +bool f28335_flash_app_validate(f28335_flash_read_word_t read_word, void *user, uint32_t *entry); /* Проверяет описание, границы и CRC32 до передачи управления приложению. */ +#endif /* Завершает единый контракт защищённой области Flash-приложения. */ diff --git a/c/protocan-boot/projects/.gitignore b/c/protocan-boot/projects/.gitignore new file mode 100644 index 0000000..70afdaf --- /dev/null +++ b/c/protocan-boot/projects/.gitignore @@ -0,0 +1,4 @@ +# Служебные и выходные файлы CCS остаются локальными; исходники проектов хранятся выше этих каталогов. +ccs/*/Debug/ +# Release использует собственные объекты, метаданные и архивы, чтобы не смешивать конфигурации. +ccs/*/Release/ diff --git a/c/protocan-boot/projects/README.md b/c/protocan-boot/projects/README.md new file mode 100644 index 0000000..97e6184 --- /dev/null +++ b/c/protocan-boot/projects/README.md @@ -0,0 +1,207 @@ +# Отдельные проекты CCS: F28335 и F2812 + +Весь комплект находится внутри `templates/c/protocan-boot`: проекты CCS, +исходники загрузчиков, аппаратные порты, linker command files, необходимая +поддержка TI, CLI-сборка, тесты и документация. Зависимости от исходников +`28335_periph` и `BALZAM_167` при сборке отсутствуют. Требуется установленный +TI C2000 compiler с поддержкой **COFF ABI**; проверена версия **22.6.0.LTS**. + +| Проект CCS | Контроллер | Обновляемая память | Схема | +| --- | --- | --- | --- | +| `ccs/f28335` — `F28335_CAN_AB` | TMS320F28335 | M95M02, 256 КиБ | A/B, trial, CONFIRM, rollback | +| `ccs/f2812` — `F2812_CAN_NOR` | TMS320F2812 / ПМ67 | AM29LV800BT-70EI, 1 МиБ, x16 | Один выделенный NOR-слот, проверяемый manifest, CAN recovery | + +F2812 не использует EEPROM. Его карта, GPIO, частота CAN, допустимые адреса +приложения и состояние протокола отделены от F28335. + +## Открытие в Code Composer Studio + +1. **Project → Import CCS Projects**, каталог поиска — `c/protocan-boot/projects/ccs`. +2. Выбрать `F28335_CAN_AB` и `F2812_CAN_NOR`. Оставить проекты в исходном + расположении: **не включать Copy projects into workspace**, поскольку + переносимые ссылки `PCAN_ROOT` ведут к общей библиотеке выше проектов. +3. Выбрать **Debug** либо **Release**, затем **Build Project**. Оба проекта + содержат собственные `.project`, `.cproject`, `.ccsproject`. +4. OUT/MAP появятся в `ccs/<контроллер>//`. + +В `targetConfigs` сохранены существующие конфигурации Sauris SAU510: +F28335 — Iso Plus v.2, F2812 — Iso Plus. Для другого адаптера выбрать свой +Connection в Target Configuration. Компиляция и импорт не подключаются к JTAG +и не программируют плату. + +Для отдельных workspace с ограниченными правами CCS допускает переменную +`TI_APPDATA_DIR` с доступным для записи каталогом. Это служебный cache IDE, +он не относится к исходникам загрузчиков. + +## Сборка без запуска IDE + +Из корня **templates**: + +```powershell +python c/protocan-boot/projects/build.py --device f28335 +python c/protocan-boot/projects/build.py --device f2812 +python c/protocan-boot/projects/build.py --device f28335 --configuration Release +python c/protocan-boot/projects/build.py --device f2812 --configuration Release +``` + +Можно передать `--compiler <каталог-ti-cgt-c2000>` и `--output <каталог>`. +Скрипт читает состав исходников и настройки из этих же CCS-проектов, полностью +пересобирает их и проверяет реальные COFF LOAD-адреса официальным `ofd2000`. +Проверка отклоняет загружаемый RAM-код без Flash LOAD, пересечения, отсутствующие +boot branch/C entry, запись CSM/OTP и посторонних внутренних секторов. +Рядом с OUT сохраняются MAP, `build.log` и manifest с SHA-256. + +Результаты: + +- `ccs/f28335/Debug/F28335_CAN_AB.out`; +- `ccs/f2812/Debug/F2812_CAN_NOR.out`. + +OUT — постоянный загрузчик для первоначальной установки через JTAG во +**внутреннюю Flash** соответствующего TMS. Образ самого приложения передаётся +по CAN в его внешнюю память. Для автоматического запуска должен быть выбран +внутренний Flash boot; у ПМ67 необходимо также учитывать штатную логику CPLD +выбора источника reset/boot из `big_dsp_module` платы. + +## Prebuild/postbuild и копирование в SETGUI + +В `.cproject` обоих проектов настроены **Debug и Release**. Prebuild вызывает +`projects/build.py --step prepare`: сохраняет UTC, Git-ревизию templates, +контроллер, конфигурацию и SHA-256 исходников в +`${BuildDirectory}/generated/canboot_build.json`. Это внешний паспорт сборки +загрузчика; номер версии приложения 167 не изменяется. + +Postbuild вызывает тот же скрипт с `--step postbuild`. Он требует подготовку +той же конфигурации и неизменные исходники, проверяет фактические COFF LOAD-адреса, +C entry и аппаратный boot-переход через TI `ofd2000`, затем сохраняет OUT/MAP, +`.out.manifest.json`, `.out.sha256` и `firmware_identity.json` в локальном архиве +`${BuildDirectory}/firmware/HASH_дата_UTC+3`. Manifest содержит контроллер, +Debug/Release, назначение `canboot`, адреса проверки и SHA-256 точного OUT. +`firmware/latest_build.json` указывает текущие локальную и экспортированную папки. + +Проверенный архив автоматически копируется в SETGUI по следующей схеме: + +```text +SETGUI/..periph_28335/firmware/periph28335/balzam167/canboot/ + 28335/HASH_дата_UTC+3/F28335_CAN_AB.out + 2812/HASH_дата_UTC+3/F2812_CAN_NOR.out +``` + +MAP, manifest, SHA-256 и метаданные лежат рядом с соответствующим OUT. +`..periph_28335` — буквальное имя существующего каталога SETGUI с двумя точками +в начале. Время имени папки берётся из prebuild; `+` после HASH означает изменения +в templates. Debug и Release имеют отдельные BuildDirectory и свои метаданные. + +В **Project Properties → Build → Steps** команды уже заполнены для обеих +конфигураций. Пример для F28335 Debug, каждая команда вводится одной строкой: + +```bat +python "${PROJECT_LOC}/../../build.py" --device f28335 --configuration Debug --compiler "${CG_TOOL_ROOT}" --output "${BuildDirectory}" --step prepare +python "${PROJECT_LOC}/../../build.py" --device f28335 --configuration Debug --compiler "${CG_TOOL_ROOT}" --output "${BuildDirectory}" --step postbuild --export "${PROJECT_LOC}/../../../../../../SETGUI/..periph_28335/firmware/periph28335/balzam167/canboot/28335" +``` + +Для F2812 используются `--device f2812` и конечная папка `2812`; для Release — +`--configuration Release`. При другом расположении SETGUI измените `--export` +в postbuild обеих конфигураций. Все пути с пробелами должны оставаться в кавычках. +CLI-сборка из раздела выше выполняет те же prepare/postbuild и копирует в эти же +каталоги; аргумент `--export <каталог>` переопределяет место копирования. +При ошибке компиляции, проверки OUT, отсутствии MAP или изменении исходников +после prebuild новый комплект в SETGUI не копируется. После изменения исходников +выполните **Rebuild Project**, чтобы обновить и OUT, и подготовку. + +В диалоге SETGUI **Flash JTAG (OUT)** для установки постоянного загрузчика F28335 +выбирайте `canboot/28335/HASH_дата_UTC+3/F28335_CAN_AB.out`. +`F2812_CAN_NOR.out` предназначен для JTAG соответствующего F2812. +Копирование файлов не запускает программирование платы и сетевую публикацию. + +## F28335 / M95M02 + +Проект использует существующий порт и формат журнала без изменения адресов: +**PERIPH 0–31: Type = 1 + PERIPH / 16, Device ID = PERIPH mod 16**. +УМП1 — **1/5**, УМП2 — **1/6**, задатчик — **1/8**. +Product **0x2833**, HW **1**, CAN **250000 бит/с**. Приложение и загрузчик +используют один аппаратный номер платы; прежний общий адрес **3/7** отменён. +Код загрузчика — внутренний сектор A `0x338000..0x33FF7F`, boot — `0x33FFF6`. +Слоты M95M02 имеют по **130560 октетов**, параметры — прежние 258 октетов +по адресу `0x3FEFC`. Приложение загружается в RAM ниже CPU word-адреса `0xE000`. + +После установки постоянного загрузчика новое приложение 167 передаётся +существующим клиентом SETGUI **CAN / ProtoCAN Boot**. Оно обязано содержать +hooks READY/CONFIRM и watchdog: пример интеграции реализован в ветке 167. +Без CONFIRM следующий reset возвращает подтверждённый active. +Полная последовательность — [документация порта F28335](../ports/tms320f28335/README.md). + +## F2812 / AM29LV800BT + +Профиль: **Device Type 3, Device ID 6, Product 0x2812, HW 1, +CAN 250000 бит/с, SYSCLKOUT 150 МГц**. CAN находится на **GPIOF6 TX / GPIOF7 RX**. +F2812 использует программную арифметику `rts2800_ml.lib`; F28335 — FPU32 +и `rts2800_fpu32.lib`. + +Внутренний сектор A загрузчика: `0x3F6000..0x3F7F7F`, boot — `0x3F7FF6`. +Внешняя NOR подключена по **CPU word-адресу `0x100000`**. Новый CAN-раздел +задан явно в `ports/tms320f2812/boot2812.h`: + +| Область | CPU word-адреса включительно | Размер | +| --- | --- | ---: | +| Существующая нижняя область: прежние образы/параметры/FPGA | `0x100000..0x15FFFF` | 768 КиБ | +| Новый SCI8 CAN-образ: обычные сектора 12/13/14 | `0x160000..0x177FFF` | **192 КиБ** | +| Неизменяемые этим загрузчиком top-boot сектора 15/16/17 | `0x178000..0x17DFFF` | 48 КиБ | +| Новый manifest: последний top-boot сектор 18 | `0x17E000..0x17FFFF` | 16 КиБ | + +Это **новое явное размещение CAN-образа**, а не автоматическое определение +свободного места в уже заполненном чипе. Перед первоначальной установкой +согласовать эти два выделенных участка с фактической картой NOR конкретной +платы. В известном исходнике FPGA начинается с `0x130000`, а новый CAN-слот +находится выше; драйвер не изменяет ничего ниже `0x160000` и в секторах 15–17. + +После reset доступно **3 секунды** для ENTER_BOOT. Открытая сессия удерживает +загрузчик; пустой/повреждённый manifest оставляет CAN recovery постоянно. +Для обновления уже работающего приложения нужно войти в это окно после reset; +приложение F2812 само по себе пока не получает обработчик ENTER_BOOT от добавления +отдельного проекта загрузчика. + +Перед записью требуется AMD manufacturer **`0x0001`**, device **`0x22DA`**. +Сначала стирается сектор manifest, затем три сектора образа. Запись проверяет +каждое слово. VERIFY повторно читает NOR, проверяет CRC32, SCI8, entry, +перекрытия и запрещённые назначения. COMMIT повторяет проверку, сохраняет +manifest с собственной CRC, два magic-слова публикуются последними. +Стирание сообщает BUSY каждые 250 мс, продлевая живую сессию. + +Это single-slot схема: при обрыве обновления последнего CAN-образа остаётся +recovery, автоматический A/B rollback для F2812 не заявляется. Полное стирание +NOR, запись внутренней Flash по CAN и программирование FPGA отсутствуют. + +Образ приложения — **TI SCI8 `AA 08`**, максимум **196608 октетов**. Старый +flat BIN основного контроллера автоматически не мигрируется. Допустимый payload: + +- L0 `0x8000..0x8EFF`; +- H0 `0x3F8000..0x3F9FFF`; +- внешняя SRAM zone2 `0x80000..0xFFFFF`. + +Стек M1, L1 `0x9000..0x9FFF`, RAM InitFlash `0x8F00..0x8FFF`, периферия, +внутренняя Flash и NOR не допускаются как назначения SCI8. `.ebss` приложения +может занять L1 после перехода в его C runtime; инициализированный payload +работающую RAM загрузчика перезаписывать не должен. Настройка приложения +F2812/его linker — отдельная от импорта загрузчика операция. + +Геометрия x16, ID и команды AA/55/A0/80/30/F0 взяты из +[оригинального datasheet AMD Am29LV800B](https://cms.nacsemi.com/content/AuthDatasheets/FASLS02690-1.pdf). +Аппаратные GPIO/CPLD и XINTF-тайминги перенесены из действующих +`big_dsp_module.c` / `flash_tools.c` ПМ67, без зависимости от этих файлов при сборке. + +## Проверки + +```powershell +$env:CC = 'C:/msys64/ucrt64/bin/gcc.exe' +python c/protocan-boot/tests/run_tests.py +``` + +Проверяются протокол, CRC, сессии/BUSY, A/B F28335 с trial/rollback/CONFIRM, +NOR F2812 с настоящими AMD command cycles, ID, readback, запрещёнными секторами, +обрывами COMMIT, повреждением CRC/SCI8 и тайм-аутом DQ7. +Вариант с CMake/CTest также поддерживается. + +Подтверждены реальные import/build обоих проектов в CCS 12.3, CLI-сборки +Debug/Release TI 22.6 COFF и проверки секций OUT. Физические JTAG/CAN/XINTF, +режим boot и поведение конкретной платы при отключении питания требуют стенда; +физическое программирование этим комплектом автоматически не выполнялось. diff --git a/c/protocan-boot/projects/STM32.md b/c/protocan-boot/projects/STM32.md new file mode 100644 index 0000000..ba4af27 --- /dev/null +++ b/c/protocan-boot/projects/STM32.md @@ -0,0 +1,69 @@ +# STM32: подключение исходных проектов к templates + +Канонические загрузочные реализации находятся в `c/protocan-boot/ports`. +В проектах сохранены прежние пути файлов, содержащие только include общего +исходника из их submodule. Это сохраняет внешний API и настройки Keil, +не оставляя локальных копий state machine, Flash writer или boot-control. + +| Проект | Submodule | Подключённый порт | Сборки | +|---|---|---|---| +| `KONOR_ds18b20` | `lib` | `stm32f103` CMSIS, BKP request, CAN/UART | Keil app и BOOT | +| `home/climate` | `third_party/templates` | `stm32f407` CMSIS boot, HAL app control | Keil app и BOOT | +| `CANdle_stm32` | `templates` | `stm32g474` HAL FDCAN/Flash, CAN/UART, startup/control | Keil app/BOOT, CMake app/BOOT | + +## Что перенесено + +- Общие `pcan_boot.c/.h` используются через submodule; устаревшая копия + `Libraries/ProtoCanBoot` climate заменена совместимыми include-обёртками. +- F103/F407 CMSIS transport, Flash, CRC readback, безопасный naked handoff, + single-slot callbacks и таймеры используют общий `boot_native.inc`. +- F103 UART firmware flow теперь использует имеющийся общий `rs485-boot`; + приложение KONOR продолжает использовать свой прикладной parser `proto.c`. +- G474 локальная CAN state machine полностью заменена текущим `pcan_boot`. + Единый Flash writer используется CAN/UART; вход из приложения и startup + также принадлежат `templates`. +- Конфигурации ядра заполняются по именам полей. Сохранены исходные Device ID, + скорости CAN/UART, границы Flash и режим одного логического слота A. +- В F407 BOOT и G474 app/BOOT linker исключает последние восемь байт используемой + SRAM, где хранится запрос обновления. Initial MSP G474 согласован с этим. +- В GCC-таблице IRQ G474 размер выведен из самого старшего назначенного IRQ: + прежний предел по USB_LP не вмещал USART1 и ломал CMake app-сборку. + +Clock tree, USB–CAN приложение, трансивер, GPIO board-support, настройки +программирования ST-Link и application linker остаются в исходных проектах. +Нативные `boot_main.c` не нужно компилировать вместе с альтернативным HAL boot +main в одном target. Изменения не прошивают подключённые устройства. + +## Зависимости и публикация + +CANdle получен из `https://git.rd12.ru/setcorp/CANdle_stm32.git`, исходный HEAD +`61a93c5`. Записанный там gitlink `templates` указывает на отсутствующий на +сервере объект `520788491c803e07ba1889e1fa60ed1550afb848`. Для локальной +интеграции submodule переключён на доступный локальный HEAD `templates`, +после чего текущие общие исходники синхронизированы в рабочее дерево. +Рабочие копии submodule KONOR/climate также содержат соответствующие текущие файлы. + +Подключение проверено локально. Для воспроизводимого нового клонирования +потребуется зафиксировать и опубликовать изменения `templates`, затем обновить +gitlinks в исходных проектах на этот доступный commit. Коммиты и push не являются +частью этой локальной интеграции; чужие незавершённые изменения не включались в commit. + +## Проверка + +21 октября 2026 года проверены настоящие Keil/Arm Compiler 6.22 сборки +BOOT и приложения каждого из трёх проектов. Все загрузчики помещаются в +исходные лимиты 12/32/32 КиБ. G474 дополнительно проверен ARM GCC/CMake +для `STM32G474VE_CAN_bootloader` и `STM32G474VE_DevBoard_fw`. + +Включённые в G474 BOOT строгие диагностики Arm Compiler выдают предупреждения +о layout структур, GNU-расширениях и обычном C-доступе к буферам в HAL/общих +модулях; компиляция и линковка завершаются без ошибок. GNU/newlib конфигурация +также сообщает о заглушках syscall при отключённом semihosting. Эти сообщения +не подавлялись общими флагами проекта. + +Host CMake/CTest: 10 тестов, включая три production HAL-порта. G474 проверяется +в DBANK=0 и DBANK=1: весь слот, переход между банками, отказ swap/неверной +плотности, все хвосты DATA, CRC readback, тайм-аут и TX ACK до reset. +Проверки интеграции climate подтверждают реальную цепочку include/Keil и границы +Flash/SRAM. Аппаратное обновление, питание и восстановление после обрыва на +физических платах в эту проверку не входят. diff --git a/c/protocan-boot/projects/build.py b/c/protocan-boot/projects/build.py new file mode 100644 index 0000000..7e24224 --- /dev/null +++ b/c/protocan-boot/projects/build.py @@ -0,0 +1,132 @@ +"""Сборка отдельных CCS-проектов ProtoCAN для F28335/M95M02 и F2812/AM29LV800BT.""" # Требует только Python и установленный TI C2000 COFF compiler. +import argparse # Разбирает выбранный контроллер, конфигурацию и пути toolchain. +import base64 # Читает настоящие программируемые данные COFF из официального OFD XML. +from datetime import datetime, timezone # Фиксирует момент prebuild в UTC; имя архива общий модуль переводит в UTC+3. +import hashlib # Связывает собранный OUT с контрольной суммой в локальном build manifest. +import importlib.util # Подключает общий экспорт firmware-info без копирования его алгоритма архивирования. +import json # Сохраняет точные команды, происхождение исходников и результаты проверки. +from pathlib import Path # Разрешает все зависимости внутри templates относительно расположения проекта. +import subprocess # Вызывает установленный TI compiler без shell-интерполяции аргументов. +import xml.etree.ElementTree as ET # Использует действующие .project/.cproject как источник состава и опций сборки. + +ROOT = Path(__file__).resolve().parents[1] # Корень protocan-boot содержит codec, порты, проекты и vendored TI support. +DEFAULT_COMPILER = Path("C:/ti/ccs1230/ccs/tools/compiler/ti-cgt-c2000_22.6.0.LTS") # Сохраняет проверенную версию установленного C2000 COFF compiler. + + +def settings(device, configuration, compiler): # Читает те же исходники и пути, которые получает импортированный проект CCS. + project = ROOT / "projects/ccs" / device # Каждое семейство контроллера имеет собственный Eclipse projectDescription. + config = next(item for item in ET.parse(project / ".cproject").findall(".//configuration") if item.get("name") == configuration) # Не подменяет Debug настройками Release или другого устройства. + options = {item.get("superClass", "").rsplit(".", 1)[-1]: item for item in config.findall("folderInfo/toolChain/tool/option")} # Собирает только параметры общего folderInfo без переопределений отдельных файлов. + macros = {"${PROJECT_ROOT}": str(project), "${PROJECT_LOC}": str(project), "${CG_TOOL_ROOT}": str(compiler)} # Разрешает только известные пути, не выполняя shell-подстановки. + def values(name): # Возвращает listOptionValue после подстановки локальных макросов CCS. + result = [] # Порядок include paths и библиотек остаётся тем же, что в проекте. + for item in options[name].findall("listOptionValue"): # Обрабатывает каждое явное значение текущей конфигурации. + value = item.get("value", "") # Отсутствующее значение не превращается в имя неизвестного каталога. + for macro, replacement in macros.items(): value = value.replace(macro, replacement) # Ограничивает подстановки определёнными выше путями. + if "${" in value: raise ValueError("Unresolved CCS macro: " + value) # Останавливает сборку вместо поиска случайной зависимости на машине. + result.append(value) # Добавляет параметр в исходном порядке конфигурации CCS. + return result # Возвращает обычные аргументы без скрытых изменений окружения. + sources = sorted(project.glob("*.c")) + sorted(project.glob("*.asm")) # Локальные production-исходники проекта компилируются вместе с аппаратным портом. + commands = sorted(project.glob("*.cmd")) # Каждый проект имеет собственную разметку памяти соответствующего F28xx. + for link in ET.parse(project / ".project").findall(".//linkedResources/link"): # Добавляет только explicit linkedResources из templates. + uri = link.findtext("locationURI", "") # Все общие исходники привязаны к переменной PCAN_ROOT. + if not uri.startswith("PCAN_ROOT/"): raise ValueError("Unsupported linked resource: " + uri) # Не допускает зависимость от старого firmware checkout или абсолютного чужого пути. + path = ROOT / uri.removeprefix("PCAN_ROOT/") # Разрешает vendor и общие исходники внутри переносимого protocan-boot. + if path.suffix.lower() in (".c", ".asm"): sources.append(path) # Заголовки не компилируются самостоятельными единицами трансляции. + elif path.suffix.lower() == ".cmd": commands.append(path) # Подключает оригинальное TI размещение регистров выбранного контроллера. + flags = ["-v28", "-ml", "-mt", "--abi=coffabi", "-O" + options["OPT_LEVEL"].get("value").rsplit(".", 1)[-1], "--opt_for_speed=" + options["OPT_FOR_SPEED"].get("value").rsplit(".", 1)[-1], "--gen_func_subsections=on"] # Повторяет архитектуру COFF, большие адреса, оптимизацию и сборку отдельных функций проекта CCS. + if device == "f28335": flags.append("--float_support=fpu32") # Только F28335 имеет используемый аппаратный FPU32. + flags += ["--include_path=" + value for value in values("INCLUDE_PATH")] + ["--define=" + value for value in values("DEFINE")] # Передаёт конкретные аппаратные заголовки и profile defines без потери различий между контроллерами. + if configuration == "Debug": flags.append("-g") # Debug OUT сохраняет символы для пошагового JTAG-анализа загрузчика. + return project, config.get("artifactName"), flags, sources, commands, values("LIBRARY"), values("SEARCH_PATH") # Возвращает полный воспроизводимый набор исходников и linker inputs. + + +def verify(device, image, compiler): # Проверяет реальные секции OUT после линковки, а не только текст соседнего MAP. + xml = ET.fromstring(subprocess.check_output([str(compiler / "bin/ofd2000.exe"), "-x", str(image)])) # Официальный декодер TI читает COFF текущей завершившейся сборки. + coff = xml.find(".//ti_coff") # Загружать через JTAG разрешено именно executable C2000 COFF. + if coff is None or coff.findtext("file_header/exec") != "true" or coff.findtext("file_header/target_id") != "0x9d": raise ValueError("Expected executable C2000 COFF") # Не подписывает чужой объект, ELF либо незалинкованный файл. + first, end, boot = (0x338000, 0x33FF80, 0x33FFF6) if device == "f28335" else (0x3F6000, 0x3F7F80, 0x3F7FF6) # Адреса внутренних секторов A и аппаратных boot-переходов различаются между F28335/F2812. + loaded = set() # Повторная загрузка одного физического слова из двух секций запрещена. + for section in coff.findall("section"): # Рассматривает только реальные данные секций после линковки. + address = int(section.findtext("virtual_addr", "0"), 0); raw = section.findtext("raw_data") # COFF virtual_addr обозначает LOAD, physical_addr — RUN копируемых ramfuncs. + if raw is None or section.findtext("copy") == "true" or section.findtext("name") == ".adc_cal": continue # Исключает только явные COPY/отладочные секции, BSS без raw_data и заводскую ADC-калибровку; загружаемый RAM-код обязан иметь Flash LOAD. + data = base64.b64decode(raw) # Читает точные октеты программируемого содержимого из COFF, а не считает по объявленному размеру. + if len(data) % 2 or not (first <= address < address + len(data) // 2 <= end or address == boot and len(data) == 4): raise ValueError("Loaded section outside bootloader Flash: " + str(section.findtext("name"))) # Защищает OTP, CSM, внешнюю NOR/EEPROM и остальные внутренние секторы. + for word in range(address, address + len(data) // 2): # Контролирует физические 16-битные слова всех программируемых секций. + if word in loaded: raise ValueError("Overlapping load sections") # Даже совпадающие данные не разрешают неоднозначную разметку OUT. + loaded.add(word) # Фиксирует фактически загружаемый диапазон текущего результата. + entry = int(coff.findtext("optional_file_header/entry_point", "0"), 0) # Извлекает реальную точку входа C runtime из заголовка файла. + if entry not in loaded or boot not in loaded or boot + 1 not in loaded: raise ValueError("Missing loaded C entry or codestart") # JTAG OUT обязан одновременно содержать C startup и аппаратный Flash boot переход. + return {"entry_word": entry, "boot_word": boot, "loaded_words": len(loaded)} # Эти проверенные значения входят в build manifest рядом с SHA-256. + + +def identity_tools(): # CCS и CLI используют общий формат имени папки, manifest и SHA-256 из templates. + spec = importlib.util.spec_from_file_location("canboot_identity", ROOT.parent / "firmware-info/tools/identity.py") # firmware-info расположен рядом с protocan-boot внутри каталога c. + module = importlib.util.module_from_spec(spec) # Загрузка не резервирует версию и не создаёт артефакты приложения 167. + spec.loader.exec_module(module) # Выполняет только объявления общего модуля подготовки и локального экспорта. + return module # Вызывающий получает единую реализацию архивирования без сетевой публикации. + + +def source_hashes(device): # Связывает prebuild и postbuild с исходниками выбранного загрузчика, включая включаемые C-файлы и заголовки. + folders = [ROOT / "include", ROOT / "src", ROOT / "ports" / ("tms320" + device), ROOT / "vendor/ti" / device, ROOT / "projects/ccs" / device] # Общий автомат разделяется, аппаратные файлы второго контроллера в паспорт не попадают. + files = {ROOT / "projects/build.py"} # Изменение самого процесса между подготовкой и копированием требует нового prebuild. + for folder in folders: # Проверяет production-файлы библиотеки, порта, TI support и текущего CCS-проекта. + files.update(path for path in folder.rglob("*") if path.is_file() and path.suffix.lower() in (".c", ".h", ".asm", ".cmd", ".inc") and not {"Debug", "Release", "generated", "firmware"}.intersection(path.relative_to(folder).parts[:-1])) # Исключает результаты сборки; адреса памяти и аппаратные defines входят через CMD/H. + files.update(ROOT / "projects/ccs" / device / name for name in (".project", ".cproject", ".ccsproject")) # Настройки ABI, include paths и список linkedResources тоже должны оставаться неизменными. + return {path.relative_to(ROOT).as_posix(): hashlib.sha256(path.read_bytes()).hexdigest() for path in sorted(files)} # SHA-256 относится к точным байтам каждого исходного файла до компиляции. + + +def prepare(device, configuration, compiler, output): # Prebuild фиксирует происхождение именно той конфигурации, которую затем линкует CCS либо CLI. + project, name, *_ = settings(device, configuration, compiler) # Проверяет наличие выбранного проекта и узнаёт штатное имя OUT. + identity = identity_tools(); source = identity.git_state(ROOT.parents[1]) # Корень templates содержит Git-ревизию самостоятельных CAN boot проектов. + metadata = {"schema": 1, "product": name, "target": "TMS320" + device.upper(), "device": device, "configuration": configuration, "execution": "FLASH", "image_format": "COFF", "purpose": "canboot", "built_at_utc": datetime.now(timezone.utc).replace(microsecond=0).isoformat(), "source": source, "sources": source_hashes(device)} # Внешний паспорт описывает постоянный загрузчик; версию и встроенный паспорт приложения не имитирует. + identity.write_atomic(output / "generated/canboot_build.json", json.dumps(metadata, ensure_ascii=False, indent=2) + "\n") # Отдельный BuildDirectory не позволяет Debug и Release перезаписать подготовку друг друга. + return metadata # Позволяет проверить подготовку без запуска компилятора или доступа к плате. + + +def postbuild(device, configuration, compiler, output, export=None): # Проверяет готовый OUT и копирует только текущий комплект в папку соответствующего контроллера SETGUI. + output = output.resolve(); project, name, *_ = settings(device, configuration, compiler) # Имена OUT/MAP берутся из активной конфигурации CCS, а не из поиска старых сборок. + metadata = json.loads((output / "generated/canboot_build.json").read_text(encoding="utf-8")) # Без успешного prebuild выпуск останавливается до изменения каталога GUI. + if metadata.get("device") != device or metadata.get("configuration") != configuration or metadata.get("sources") != source_hashes(device): # Не допускает паспорт другой конфигурации или изменения исходников после подготовки. + raise ValueError("CAN boot sources/configuration changed: run prebuild and rebuild") # Требует согласованную пересборку вместо копирования неподтверждённого результата. + image = output / (name + ".out"); map_path = image.with_suffix(".map") # Оба файла принадлежат одному штатному результату линковки. + if not map_path.is_file(): raise ValueError("Missing CAN boot MAP: " + str(map_path)) # Неполный комплект не попадает в папку установки через JTAG. + metadata.update(verify(device, image, compiler)) # Повторно проверяет COFF LOAD-адреса, C entry и boot branch перед каждым экспортом из CCS или CLI. + identity = identity_tools(); metadata_path = output / "canboot_build.json" # Сохраняет проверенный внешний паспорт отдельно от исходной записи prebuild. + identity.write_atomic(metadata_path, json.dumps(metadata, ensure_ascii=False, indent=2) + "\n") # Диапазоны Flash и SHA исходников доступны рядом с локальным результатом. + identity.seal(image, metadata_path) # Manifest и SHA-256 рядом с OUT подписывают точные байты файла для JTAG. + destination = export if export is not None else ROOT.parents[2] / "SETGUI/..periph_28335/firmware/periph28335/balzam167/canboot" / device.removeprefix("f") # Сохраняет ожидаемую структуру 167/canboot/28335 и 167/canboot/2812 относительно соседнего SETGUI. + result = identity.archive_build(image, metadata_path, output / "firmware", extra_files=[map_path], export=destination) # Общий архиватор переносит только OUT, MAP, manifest, SHA-256 и метаданные текущего выпуска. + identity.write_atomic(output / "firmware/latest_build.json", json.dumps(result, ensure_ascii=False, indent=2) + "\n") # Указывает точные локальную и скопированную папки последнего успешного выпуска. + return image # Совместимый CLI по-прежнему возвращает путь проверенного OUT для первоначальной установки через JTAG. + + +def build(device, configuration, compiler, output=None, export=None): # Полностью собирает выбранный проект и экспортирует проверенный загрузчик без установки на плату. + compiler = compiler.resolve(); project, name, flags, sources, commands, libraries, searches = settings(device, configuration, compiler) # Использует абсолютный toolchain и актуальную конфигурацию CCS. + output = (output or project / configuration).resolve(); output.mkdir(parents=True, exist_ok=True) # Генерирует результаты только в каталоге выбранной сборки. + prepare(device, configuration, compiler, output) # CLI выполняет тот же prebuild, который настроен в управляемом проекте CCS. + objects = [] # В линковку входят только успешно пересобранные исходники текущего вызова. + with (output / "build.log").open("w", encoding="utf-8") as log: # Журнал содержит полный набор команд и диагностику TI. + def run(command): # Не продолжает сборку после ошибки компилятора или linker. + log.write(json.dumps([str(arg) for arg in command], ensure_ascii=False) + "\n"); log.flush() # Сохраняет команду до запуска процесса без исполнения как shell-кода. + subprocess.run([str(arg) for arg in command], cwd=project, stdout=log, stderr=subprocess.STDOUT, check=True) # Ненулевой статус исключает публикацию ложного успешного результата. + for source in sources: # Все локальные и linked TI-файлы пересобираются для выбранного контроллера. + obj = output / (source.stem + ".obj"); run([compiler / "bin/cl2000.exe", *flags, "-c", "--output_file=" + str(obj), source]); objects.append(obj) # Объекты F2812 soft-float и F28335 FPU32 не смешиваются. + image = output / (name + ".out") # Имя результата совпадает с artifactName импортированного CCS-проекта. + link = [compiler / "bin/cl2000.exe", "-v28", "--abi=coffabi"] + (["--float_support=fpu32"] if device == "f28335" else []) # Linker ABI и FPU точно соответствуют скомпилированным объектам. + run([*link, "-z", "--rom_model", "--entry_point=_c_int00", "--stack_size=0x3f0", "--warn_sections", "--reread_libs", "-m" + str(image.with_suffix(".map")), "-o", image, *["--search_path=" + value for value in searches], *commands, *objects, *["-l" + value for value in libraries]]) # Подключает только собственный linker и оригинальные peripheral sections выбранного MCU. + return postbuild(device, configuration, compiler, output, export) # CCS и CLI проверяют и копируют готовый комплект единственной общей функцией. + + +if __name__ == "__main__": # Импорт для проверки проектов не запускает compiler автоматически. + parser = argparse.ArgumentParser(description=__doc__) # Описывает два самостоятельных проекта и отсутствие программирования платы. + parser.add_argument("--device", choices=("f2812", "f28335"), required=True) # Не допускает случайной сборки для другого контроллера. + parser.add_argument("--configuration", choices=("Debug", "Release"), default="Debug") # Повторяет имена управляемых конфигураций CCS. + parser.add_argument("--compiler", type=Path, default=DEFAULT_COMPILER) # Поддерживает другую установленную версию TI с COFF ABI. + parser.add_argument("--output", type=Path) # Разрешает изолированную проверочную сборку без загрязнения импортированного CCS-проекта. + parser.add_argument("--step", choices=("build", "prepare", "postbuild"), default="build") # CCS запускает подготовку до компиляции и экспорт после своей линковки; CLI по умолчанию выполняет весь цикл. + parser.add_argument("--export", type=Path) # Переопределяет корень архивов 28335 либо 2812 при другом расположении SETGUI. + args = parser.parse_args(); output = (args.output or ROOT / "projects/ccs" / args.device / args.configuration).resolve() # Явный BuildDirectory CCS и CLI используют одинаковый формат результата. + if args.step == "prepare": prepare(args.device, args.configuration, args.compiler, output); print(output / "generated/canboot_build.json") # Фиксирует подготовку и выводит короткий путь к её паспорту без длинного списка SHA исходников. + elif args.step == "postbuild": print(postbuild(args.device, args.configuration, args.compiler, output, args.export)) # Проверяет OUT/MAP активного BuildDirectory и экспортирует один комплект. + else: print(build(args.device, args.configuration, args.compiler, output, args.export)) # Полный CLI-цикл включает те же подготовку и копирование, что CCS. diff --git a/c/protocan-boot/projects/ccs/f2812/.ccsproject b/c/protocan-boot/projects/ccs/f2812/.ccsproject new file mode 100644 index 0000000..335c4fd --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/.ccsproject @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f2812/.cproject b/c/protocan-boot/projects/ccs/f2812/.cproject new file mode 100644 index 0000000..b83628a --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/.cproject @@ -0,0 +1,306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f2812/.project b/c/protocan-boot/projects/ccs/f2812/.project new file mode 100644 index 0000000..49210b8 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/.project @@ -0,0 +1,106 @@ + + + + F2812_CAN_NOR + + Отдельный постоянный загрузчик ProtoCAN для F2812 + + + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + + + + + + + + com.ti.ccstudio.core.ccsNature + + org.eclipse.cdt.core.cnature + + org.eclipse.cdt.core.ccnature + + org.eclipse.cdt.managedbuilder.core.managedBuildNature + + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + + + + ti/DSP281x_CpuTimers.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_CpuTimers.c + + + + + ti/DSP281x_GlobalVariableDefs.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c + + + + + ti/DSP281x_PieCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_PieCtrl.c + + + + + ti/DSP281x_SysCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_SysCtrl.c + + + + + ti/DSP281x_usDelay.asm + + 1 + + PCAN_ROOT/vendor/ti/f2812/source/DSP281x_usDelay.asm + + + + + DSP281x_Headers_nonBIOS.cmd + + 1 + + PCAN_ROOT/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd + + + + + + + + PCAN_ROOT + + $%7BPARENT-3-PROJECT_LOC%7D + + + diff --git a/c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd b/c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd new file mode 100644 index 0000000..d47c8ac --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/F2812_CAN_NOR.cmd @@ -0,0 +1,28 @@ +MEMORY /* Постоянный загрузчик F2812 хранится во внутренней Flash, обновляемые данные — во внешней AM29LV800BT. */ +{ /* Адреса указаны в 16-битных словах C28x, независимо от размера файлов CAN. */ +PAGE 0: /* Исполняемый код и его копируемая RAM-часть. */ + FLASHA : origin = 0x3F6000, length = 0x001F80 /* Сектор A исключает зарезервированные слова CSM в верхних 128 словах. */ + BEGIN : origin = 0x3F7FF6, length = 0x000002 /* Аппаратный Flash boot F2812 начинает длинный переход из двух слов. */ + RAMFUNCS : origin = 0x008F00, length = 0x000100 /* Последние 256 слов L0 содержат InitFlash и исключены из SCI8 payload приложения. */ + RESET : origin = 0x3FFFC0, length = 0x000002 /* ROM reset не программируется при установке загрузчика. */ +PAGE 1: /* Рабочая RAM постоянно работающего загрузчика не должна входить в загружаемый файл. */ + RAMM0 : origin = 0x000050, length = 0x0003B0 /* Исключает первые 80 слов Boot ROM scratch. */ + RAMM1 : origin = 0x000400, length = 0x000400 /* Отдельный стек на 1024 слова совпадает с аппаратным банком M1. */ + RAMDATA : origin = 0x009000, length = 0x001000 /* Банк L1 хранит очередь CAN и состояния загрузчика до перехода в приложение. */ +} /* Верхний H0 и внешняя SRAM остаются доступны payload приложения. */ +SECTIONS /* Ни одна загружаемая секция OUT не записывается во внешнюю NOR автоматически. */ +{ /* Все команды программирования NOR исполняются из внутреннего сектора A. */ + codestart : > BEGIN, PAGE = 0 /* Направляет аппаратный boot в watchdog-safe C startup. */ + .text : > FLASHA, PAGE = 0 /* Размещает общий ProtoCAN, driver NOR и проверку SCI8 в постоянной Flash. */ + .fast_run : > FLASHA, PAGE = 0 /* Штатный DSP281x_usDelay вызывается ещё из InitSysCtrl до копирования ramfuncs, поэтому его LOAD/RUN должны сразу находиться во Flash. */ + .cinit : > FLASHA, PAGE = 0 /* Таблицы ROM-модели инициализируют состояние до main. */ + .pinit : > FLASHA, PAGE = 0 /* Сохраняет стандартный startup для возможных статических конструкторов. */ + .econst : > FLASHA, PAGE = 0 /* Константы не расходуют ограниченную RAM L1. */ + .switch : > FLASHA, PAGE = 0 /* Таблицы switch остаются доступны во время erase внешнего чипа. */ + ramfuncs : LOAD = FLASHA, RUN = RAMFUNCS, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0 /* InitFlash копируется в внутреннюю RAM до изменения таймингов Flash. */ + .stack : > RAMM1, PAGE = 1 /* Стек не пересекает RAM назначения проверяемого образа. */ + .ebss : > RAMDATA, PAGE = 1 /* Состояния очереди и текущей сессии исключены из разрешённых SCI8 адресов. */ + .esysmem : > RAMDATA, PAGE = 1 /* Поддерживает стандартную секцию runtime, хотя алгоритм не требует heap. */ + .fast_vars1 : > RAMDATA, PAGE = 1 /* Подключает штатный HSPCLK выбранного TI SDK без размещения случайной orphan-секции. */ + .reset : > RESET, PAGE = 0, TYPE = DSECT /* Не выдаёт ROM reset за программируемую часть OUT. */ +} /* Не создаёт секции OTP или паролей CSM. */ diff --git a/c/protocan-boot/projects/ccs/f2812/board.c b/c/protocan-boot/projects/ccs/f2812/board.c new file mode 100644 index 0000000..e19e090 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/board.c @@ -0,0 +1,30 @@ +#include "DSP281x_Device.h" /* Использует оригинальные TI определения GPIO и XINTF F2812. */ +#include "../../../ports/tms320f2812/boot2812.h" /* Получает отдельный аппаратный профиль внешней NOR ПМ67. */ +static void operation(unsigned int a, unsigned int b, unsigned int c, unsigned int d) /* Повторяет управляющую защёлку CPLD из big_dsp_module.c штатной платы. */ +{ /* GPIOA13/A14/A15 и GPIOB13 задают код, GPIOB15 формирует строб. */ + EALLOW; /* Разрешает запись системных GPIO платы. */ + GpioDataRegs.GPADAT.bit.GPIOA13 = a; GpioDataRegs.GPADAT.bit.GPIOA14 = b; /* Первые два бита аппаратной команды соответствуют oper_mode1/2. */ + GpioDataRegs.GPADAT.bit.GPIOA15 = c; GpioDataRegs.GPBDAT.bit.GPIOB13 = d; /* Третий и четвёртый биты повторяют штатный write_oper. */ + asm(" NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 0; /* Снимает строб после установки всех четырёх битов команды. */ + asm(" RPT #2 || NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 1; /* Даёт защёлке время установления и формирует активный фронт. */ + asm(" RPT #2 || NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 0; /* Возвращает строб в исходное состояние с выдержкой как в рабочем драйвере. */ + asm(" RPT #2 || NOP"); EDIS; /* Завершает длительность импульса до следующей команды CPLD. */ +} /* Команда не изменяет выбранные аппаратные boot-перемычки контроллера. */ +void Boot2812_BoardInit(void) /* Настраивает подтверждённую схему ПМ67 с AM29LV800BT на XINTF zone6. */ +{ /* Значения линий взяты из setup_oper_line/init_flash/xintf_zone6and7_timing действующего проекта BALZAM_167. */ + EALLOW; /* GPIO mux/direction и XINTF изменяются в разрешённом защищённом контексте. */ + GpioMuxRegs.GPAMUX.bit.C1TRIP_GPIOA13 = 0; GpioMuxRegs.GPAMUX.bit.C2TRIP_GPIOA14 = 0; GpioMuxRegs.GPAMUX.bit.C3TRIP_GPIOA15 = 0; /* Выбирает GPIO для трёх командных линий CPLD вместо функций event manager. */ + GpioMuxRegs.GPBMUX.bit.C4TRIP_GPIOB13 = 0; GpioMuxRegs.GPBMUX.bit.C6TRIP_GPIOB15 = 0; /* Освобождает четвёртый бит команды и строб CPLD. */ + GpioMuxRegs.GPADIR.bit.GPIOA13 = 1; GpioMuxRegs.GPADIR.bit.GPIOA14 = 1; GpioMuxRegs.GPADIR.bit.GPIOA15 = 1; /* Переводит командные линии A в выходы, как рабочий драйвер платы. */ + GpioMuxRegs.GPBDIR.bit.GPIOB13 = 1; GpioMuxRegs.GPBDIR.bit.GPIOB15 = 1; /* Разрешает выдачу четвёртого бита и импульса защёлки. */ + XintfRegs.XINTCNF2.bit.XTIMCLK = 1; XintfRegs.XINTCNF2.bit.WRBUFF = 0; /* XTIMCLK=SYSCLKOUT/2; отключённая буферизация сохраняет порядок unlock-циклов AMD. */ + XintfRegs.XINTCNF2.bit.CLKOFF = 0; XintfRegs.XINTCNF2.bit.CLKMODE = 0; XintfRegs.XINTCNF2.bit.MPNMC = 0; /* Повторяет штатный режим XCLKOUT и микроконтроллерный boot платы. */ + XintfRegs.XTIMING6.bit.XWRLEAD = 3; XintfRegs.XTIMING6.bit.XWRACTIVE = 7; XintfRegs.XTIMING6.bit.XWRTRAIL = 3; /* Времена записи NOR повторяют проверенный flash_tools/init_flash платы в единицах XTIMCLK. */ + XintfRegs.XTIMING6.bit.XRDLEAD = 3; XintfRegs.XTIMING6.bit.XRDACTIVE = 3; XintfRegs.XTIMING6.bit.XRDTRAIL = 3; /* Времена чтения соответствуют штатному профилю AM29LV800BT-70EI. */ + XintfRegs.XTIMING6.bit.X2TIMING = 0; XintfRegs.XTIMING6.bit.USEREADY = 0; XintfRegs.XTIMING6.bit.READYMODE = 0; XintfRegs.XTIMING6.bit.XSIZE = 3; /* Выбирает 16-битную зону без внешнего READY и без дополнительного удвоения тактов. */ + XintfRegs.XTIMING2.bit.XWRLEAD = 3; XintfRegs.XTIMING2.bit.XWRACTIVE = 7; XintfRegs.XTIMING2.bit.XWRTRAIL = 3; /* Консервативный x16 режим внешней SRAM позволяет загружать приложение в zone2. */ + XintfRegs.XTIMING2.bit.XRDLEAD = 3; XintfRegs.XTIMING2.bit.XRDACTIVE = 7; XintfRegs.XTIMING2.bit.XRDTRAIL = 3; /* Удлинённое чтение SRAM не зависит от коротких прикладных таймингов. */ + XintfRegs.XTIMING2.bit.X2TIMING = 0; XintfRegs.XTIMING2.bit.USEREADY = 0; XintfRegs.XTIMING2.bit.READYMODE = 0; XintfRegs.XTIMING2.bit.XSIZE = 3; /* Не включает неподтверждённую линию READY платы. */ + asm(" RPT #7 || NOP"); EDIS; /* Сбрасывает pipeline после изменения XINTF до первого внешнего чтения. */ + operation(1U, 1U, 1U, 1U); operation(1U, 0U, 1U, 0U); operation(0U, 0U, 0U, 0U); /* Штатные select_nothing, select_strob_67_for_flash, select_work_with_flash выбирают CPU-доступ к NOR. */ +} /* Изменение схемы CPLD требует отдельного профиля платы, а не другого размера EEPROM. */ diff --git a/c/protocan-boot/projects/ccs/f2812/boot_store.c b/c/protocan-boot/projects/ccs/f2812/boot_store.c new file mode 100644 index 0000000..e825b09 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/boot_store.c @@ -0,0 +1 @@ +#include "../../../ports/tms320f2812/boot_store.c" /* Подключает проверку SCI8 и публикацию NOR manifest без копирования кода в проект CCS. */ diff --git a/c/protocan-boot/projects/ccs/f2812/codestart.asm b/c/protocan-boot/projects/ccs/f2812/codestart.asm new file mode 100644 index 0000000..b69fe2f --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/codestart.asm @@ -0,0 +1,12 @@ + .ref _c_int00 ; Стандартный COFF startup применяет .cinit и вызывает main после отключения раннего watchdog. + .sect "codestart" ; Boot ROM передаёт управление двухсловному переходу по аппаратному адресу слова 0x33FFF6. + LB flash_boot_start ; Переходит к короткой подготовке C28x во Flash, сохраняя точный размер аппаратного входа два слова. + .text ; Последовательность взята из штатного TI DSP2833x_CodeStartBranch.asm и размещается в секторе основного кода. +flash_boot_start: ; Отключает watchdog до возможной длительной обработки таблиц инициализации C, а не только после входа в main. + SETC OBJMODE ; Выбирает C28x object mode, требуемый стандартным COFF startup процессора F28335. + EALLOW ; Разрешает запись защищённого регистра WDCR перед запуском C runtime. + MOVZ DP, #7029h>>6 ; Адрес слова WDCR=0x7029 из карты F28335; DP выбирает соответствующую страницу по 64 слова. + MOV @7029h, #0068h ; Значение 0x0068 содержит контрольные биты WDCHK=101 и WDDIS=1, как официальный TI startup. + EDIS ; Возвращает защиту системных регистров перед переходом в библиотечную инициализацию. + LB _c_int00 ; Применяет штатную ROM-модель инициализации и затем запускает текущий main 167. + .end ; Завершает модуль, не добавляя произвольных данных рядом с CSM-паролями сектора A. diff --git a/c/protocan-boot/projects/ccs/f2812/main.c b/c/protocan-boot/projects/ccs/f2812/main.c new file mode 100644 index 0000000..880a3f0 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/main.c @@ -0,0 +1,114 @@ +#include "DSP281x_Device.h" /* Использует оригинальные регистры F2812, не подменяя их заголовками F28335. */ +#include "DSP281x_Examples.h" /* Подключает штатные PLL, watchdog, PIE и CpuTimers выбранного TI SDK. */ +#include "../../../ports/tms320f2812/boot2812.h" /* Выбирает отдельные NOR, Product Type и ProtoCAN-адрес F2812. */ +#include /* Инициализирует все состояния независимо от прежнего содержимого .ebss. */ +static pcan_boot_t boot; /* Этот экземпляр относится только к ПМ67/F2812 и не делит состояние с F28335. */ +static volatile unsigned int head, tail, overflow; /* ISR публикует готовые элементы очереди только после заполнения всех полей. */ +static struct { uint32_t id; unsigned int dlc; pcan_boot_byte_t data[8]; } queue[32]; /* Очередь на 31 кадр принимает окно из 16 блоков во время NOR-операций main. */ +static unsigned int tx_busy, reset_requested, operation_active, current_command; /* Отделяет физическое TX ACK, запрос reset и текущую долгую команду. */ +static uint32_t sent_at, busy_at; /* Миллисекундные отметки ограничивают TX и частоту BUSY-ответов. */ +unsigned long Boot2812_Now(void) /* Все тайм-ауты порта работают от одного Timer1. */ +{ /* Прямой счётчик C28x имеет ту же ширину, что uint32_t. */ + return CpuTimer1.InterruptCount; /* Период Timer1 ниже установлен в одну миллисекунду. */ +} /* Беззнаковые разности сохраняют корректность через переполнение. */ +interrupt void boot_tick(void) /* Прямое прерывание Timer1 не обращается к коду приложения. */ +{ /* Долгие erase/verify не должны замораживать часы либо приём CAN. */ + CpuTimer1.InterruptCount++; KickDog(); /* Миллисекундный tick и штатное обслуживание watchdog загрузчика выполняются даже во время polling NOR. */ +} /* Поведение watchdog загружаемого приложения задаёт его собственный startup. */ +static void receive(volatile struct MBOX *box, uint32_t mask) /* Копирует один Extended кадр выделенного mailbox в очередь. */ +{ /* Wire-парсер и запись памяти выполняются позднее общим ядром в main. */ + unsigned int next = (head + 1U) & 31U, i, type; uint32_t id, low, high; /* Индексы кольца ограничены 32 элементами независимо от содержимого CAN. */ + if (!(ECanaRegs.CANRMP.all & mask)) return; /* Не читает старое содержимое mailbox без нового RX-флага. */ + id = box->MSGID.all & 0x1FFFFFFFUL; type = pcan_boot_id_msg_type(id); /* Получает 29-битный ID и тип через общий codec. */ + if ((box->MSGID.all & 0x80000000UL) && !box->MSGCTRL.bit.RTR && pcan_boot_id_route(id) == 0U && (type == 9U || type == 10U || type == 13U) && ((pcan_boot_id_device_type(id) == BOOT2812_DEVICE_TYPE && pcan_boot_id_device_id(id) == BOOT2812_DEVICE_ID) || (type == 13U && pcan_boot_id_device_type(id) == 7U && pcan_boot_id_device_id(id) == 15U && !pcan_boot_id_msg_body(id)))) { /* Допускает только адресный Boot и точное discovery; чужие приборы и RTR не занимают очередь. */ + if (next == tail) overflow = 1U; /* Потеря кадра отменит сессию, а не разрешит незаметно неполный файл. */ + else { /* Сначала формирует весь элемент, затем публикует новый head. */ + queue[head].id = id; queue[head].dlc = box->MSGCTRL.bit.DLC; /* Сохраняет фактические ID и длину для проверок общего ядра. */ + low = box->MDL.all; high = box->MDH.all; /* Два 32-битных снимка не смешивают октеты разных чтений регистров. */ + for (i = 0; i < 4U; ++i) { queue[head].data[i] = (low >> (i * 8U)) & 255U; queue[head].data[i + 4U] = (high >> (i * 8U)) & 255U; } /* DBO=0 передаёт младшие октеты MDL/MDH первыми. */ + head = next; /* Публикация после копирования исключает чтение main частично заполненного элемента. */ + } /* Завершает формирование очередного элемента кольца. */ + } /* Остальные кадры не изменяют никакие состояния протокола. */ + ECanaRegs.CANRMP.all = mask; /* Подтверждает только собственный прочитанный mailbox. */ +} /* В ISR отсутствуют erase, write, CRC и загрузка приложения. */ +interrupt void boot_can_rx(void) /* Использует отдельный аппаратный CAN F2812 на GPIOF6/F7. */ +{ /* Оба служебных RX mailbox относятся к одной линии ECAN0INTA. */ + receive(&ECanaMboxes.MBOX3, 8UL); receive(&ECanaMboxes.MBOX6, 64UL); /* Mailbox 3 принимает адресные кадры, 6 — broadcast discovery. */ + PieCtrlRegs.PIEACK.all = 0x0100U; /* ACK9 открывает группу PIE9 для следующего CAN IRQ. */ +} /* Возвращает управление прерванному main без обращения к прикладным каналам ПМ67. */ +static void tx_poll(void) /* Подтверждает физическую передачу, прежде чем разрешить следующий ответ или reset. */ +{ /* Ошибка шины ограничена четвертью секунды и не приводит к бесконечному ожиданию. */ + if (!tx_busy) return; /* Свободный mailbox не требует чтения старых ACK. */ + if (ECanaRegs.CANTA.all & 16UL) { ECanaRegs.CANTA.all = 16UL; tx_busy = 0U; } /* Снимает только фактический ACK ответа mailbox 4. */ + else if (Boot2812_Now() - sent_at >= 250UL) { /* Истёкшее ожидание не разрешает выполнить ранее заказанный reset. */ + ECanaRegs.CANTRR.all = 16UL; reset_requested = 0U; /* Запрашивает отмену и сохраняет управление recovery-загрузчику. */ + if (ECanaRegs.CANAA.all & 16UL) { ECanaRegs.CANAA.all = 16UL; tx_busy = 0U; } /* Не перезаписывает mailbox до подтверждённого завершения отмены. */ + } /* Поздний ACK после запроса отмены также не восстанавливает сброшенный reset_requested. */ +} /* Состояние передачи не зависит от относительного порядка BUSY и окончательного ответа. */ +static bool transmit(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) /* Реализует физический ответ без дублирования формата ProtoCAN. */ +{ /* Вызывается только из main или синхронного NOR callback, никогда из RX ISR. */ + unsigned int i; uint32_t low = 0UL, high = 0UL, started = Boot2812_Now(), budget = 1000000UL; (void)user; /* Ограничение проходов сохраняет выход при остановленном Timer1. */ + while (tx_busy && --budget && Boot2812_Now() - started < 250UL) tx_poll(); /* Даёт предыдущему BUSY физически уйти, прежде чем отправить окончательный OK. */ + if (tx_busy || dlc > 8U) return false; /* Не теряет неподтверждённый ответ перезаписью регистров. */ + for (i = 0; i < dlc; ++i) { if (i < 4U) low |= (uint32_t)(data[i] & 255U) << (8U * i); else high |= (uint32_t)(data[i] & 255U) << (8U * (i - 4U)); } /* Упаковывает октеты C28x в MDL/MDH при DBO=0. */ + EALLOW; ECanaRegs.CANME.all &= ~16UL; /* Идентификатор TX изменяется только при отключённом mailbox. */ + ECanaMboxes.MBOX4.MSGID.all = 0x80000000UL | id; ECanaMboxes.MBOX4.MSGCTRL.all = dlc; /* IDE=1 включает Extended формат, длина сохраняется из codec. */ + ECanaMboxes.MBOX4.MDL.all = low; ECanaMboxes.MBOX4.MDH.all = high; /* Фиксирует все данные до подачи запроса передачи. */ + ECanaRegs.CANTA.all = 16UL; ECanaRegs.CANAA.all = 16UL; ECanaRegs.CANME.all |= 16UL; ECanaRegs.CANTRS.all = 16UL; EDIS; /* Удаляет старые ACK и запускает один новый аппаратный ответ. */ + sent_at = Boot2812_Now(); tx_busy = 1U; /* Следующий ответ и REBOOT ждут фактический CAN ACK. */ + return true; /* Ядро считает кадр принятым аппаратным передатчиком. */ +} /* Wire-содержимое сформировано только общим ProtoCAN codec. */ +void Boot2812_Busy(void) /* Долгие erase и проверки продолжают сообщать состояние текущей команды. */ +{ /* Функция не извлекает новые команды из очереди и не допускает вложенный процессинг сессии. */ + uint32_t now = Boot2812_Now(); tx_poll(); /* Подтверждает ранее отправленный BUSY по фактическому TX ACK. */ + if (operation_active && !tx_busy && now - busy_at >= 250UL) { busy_at = now; (void)pcan_boot_report_busy(&boot, current_command, now); } /* Ответ каждые 250 мс удерживает клиент живым при секундном стирании NOR. */ +} /* Финальный статус после callback отправит обычное ядро. */ +static void request_reset(void *user) /* Команда REBOOT не сбрасывает аппарат до передачи её статусного ответа. */ +{ /* Аппаратный reset выполнит main после освобождения TX mailbox. */ + (void)user; reset_requested = 1U; /* Не вызывает watchdog непосредственно из callback codec. */ +} /* Потеря TX ACK отменяет этот запрос в tx_poll. */ +static void can_init(void) /* Отдельные clock/GPIO F2812 не используют настройки F28335. */ +{ /* SYSCLKOUT=150 МГц при штатных XCLKIN=30 МГц и PLLCR=10 в включённом TI SDK. */ + EALLOW; GpioMuxRegs.GPFMUX.bit.CANTXA_GPIOF6 = 1; GpioMuxRegs.GPFMUX.bit.CANRXA_GPIOF7 = 1; /* Назначение CAN берётся из оригинального DSP281x_ECan.c. */ + ECanaRegs.CANTIOC.all = 8UL; ECanaRegs.CANRIOC.all = 8UL; ECanaRegs.CANME.all = 0UL; /* Включает CAN-функции и отключает mailbox до полной настройки. */ + ECanaRegs.CANMC.all = 0x3080UL; /* SCB/CCR/ABO выбирают eCAN, режим настройки и автоматическое восстановление шины. */ + while (!ECanaRegs.CANES.bit.CCE) {} /* Ожидает разрешения аппаратуры менять CANBTC. */ + ECanaRegs.CANBTC.all = (29UL << 16) | 0x017AUL; /* F2812: 150 МГц/(BRP+1=30)/(1+16+3 tq)=250000 бит/с, SJW=2 tq. */ + ECanaRegs.CANMC.all &= ~0x1000UL; while (ECanaRegs.CANES.bit.CCE) {} /* Выходит из режима настройки перед включением приёма. */ + ECanaMboxes.MBOX3.MSGID.all = 0xC0000000UL | pcan_boot_make_id(0U, 0U, BOOT2812_DEVICE_TYPE, BOOT2812_DEVICE_ID, 0U, 0U); /* AME/IDE и адресный фильтр отделяют выбранный прибор от остальных узлов CAN. */ + ECanaLAMRegs.LAM3.all = 0x100FFFFFUL; ECanaMboxes.MBOX3.MSGCTRL.all = 8UL; /* Игнорирует priority/type/body при аппаратном отборе; точные типы проверяет ISR/codec. */ + ECanaMboxes.MBOX6.MSGID.all = 0xC0000000UL | pcan_boot_make_id(0U, 0U, 7U, 15U, 13U, 0U); /* Broadcast разрешён только для discovery, а не для стирания/программирования. */ + ECanaLAMRegs.LAM6.all = 0x10000000UL; ECanaMboxes.MBOX6.MSGCTRL.all = 0UL; ECanaMboxes.MBOX4.MSGCTRL.all = 0UL; /* Фильтр discovery игнорирует только priority; зарезервированные биты MSGCTRL очищены. */ + ECanaRegs.CANMD.all = 72UL; ECanaRegs.CANMIL.all = 0UL; ECanaRegs.CANMIM.all = 72UL; /* RX 3/6 и TX4 работают на линии ECAN0INTA; остальных mailbox нет. */ + ECanaRegs.CANRMP.all = 0xFFFFFFFFUL; ECanaRegs.CANRML.all = 0xFFFFFFFFUL; ECanaRegs.CANTA.all = 0xFFFFFFFFUL; /* Удаляет старые флаги перед первым разрешением IRQ. */ + ECanaRegs.CANGIF0.all = 0xFFFFFFFFUL; ECanaRegs.CANGIM.all = 1UL; ECanaRegs.CANME.all = 88UL; /* Включает только три настроенных mailbox и прерывание линии 0. */ + PieVectTable.ECAN0INTA = &boot_can_rx; PieCtrlRegs.PIEIER9.bit.INTx5 = 1; EDIS; IER |= M_INT9; /* Подключает короткий постоянный RX ISR группы PIE9. */ +} /* Конфигурация и состояние ПМ35/F28335 остаются независимыми. */ +void main(void) /* Запускается аппаратным внутренним Flash boot F2812 через 3F7FF6. */ +{ /* Прежний внешний flat-образ не переписывается автоматически и не заменяет проверенную SCI8-таблицу. */ + pcan_boot_config_t config; pcan_boot_port_t port; uint32_t started, entry; unsigned int tried = 0U; /* Небольшие настройки и адрес входа помещаются в постоянный стек M1. */ + InitSysCtrl(); DINT; IER = 0U; IFR = 0U; /* Настраивает PLL=150 МГц и исключает старые IRQ до создания собственных векторов. */ + memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, &RamfuncsLoadEnd - &RamfuncsLoadStart); InitFlash(); /* Штатная InitFlash выполняется из RAM, пока весь остальной код хранится во внутренней Flash A. */ + InitPieCtrl(); InitCpuTimers(); Boot2812_BoardInit(); /* Подготавливает PIE/Timer1 и доступ к подтверждённой AM29LV800BT через CPLD. */ + head = tail = overflow = tx_busy = reset_requested = operation_active = current_command = 0U; sent_at = busy_at = 0UL; /* Явно очищает COFF .ebss и очередь до включения CAN IRQ. */ + memset(&config, 0, sizeof(config)); memset(&port, 0, sizeof(port)); /* Не оставляет неопределённые callbacks нового публичного API. */ + config.device_type = BOOT2812_DEVICE_TYPE; config.device_id = BOOT2812_DEVICE_ID; config.product_type = BOOT2812_PRODUCT; config.hardware_revision = 1U; /* Отдельный адрес 3/6 и Product 2812 отличают основной контроллер от F28335. */ + config.active_slot = 0U; config.slot_count = 1U; config.max_image_size = BOOT2812_IMAGE_BYTES; config.ack_window = 16U; config.session_timeout_ms = 30000UL; /* Single-slot отражает NOR-раздел без ложного обещания A/B-отката. */ + port.send = transmit; port.erase_slot = Boot2812_Erase; port.write_slot = Boot2812_Write; port.verify_status = Boot2812_Verify; port.set_pending_slot = Boot2812_Commit; port.reboot = request_reset; /* Алгоритм ProtoCAN вызывает только аппаратные операции внешней NOR. */ + if (!pcan_boot_init(&boot, &config, &port, 0)) for (;;) {} /* Ошибка конфигурации не разрешает произвольную запись памяти. */ + ConfigCpuTimer(&CpuTimer1, 150.0F, 1000.0F); EALLOW; PieVectTable.XINT13 = &boot_tick; EDIS; /* PLL выбранного TI SDK даёт 150 МГц; 1000 мкс соответствуют миллисекундным тайм-аутам протокола. */ + CpuTimer1Regs.TCR.all = 0x4020U; IER |= M_INT13; can_init(); PieCtrlRegs.PIECRTL.bit.ENPIE = 1; EINT; started = Boot2812_Now(); /* Начинает трёхсекундное окно recovery только после готовности физического CAN. */ + for (;;) { /* Постоянный main обслуживает запись и автоматически запускает только подтверждённый manifest. */ + tx_poll(); pcan_boot_poll(&boot, Boot2812_Now()); KickDog(); /* Тайм-ауты сессии, discovery и watchdog не зависят от очередного окна данных. */ + if (!tx_busy && reset_requested) { DINT; EALLOW; SysCtrlRegs.WDCR = 0x0028U; EDIS; for (;;) {} } /* После физического ACK REBOOT запускает аппаратный watchdog reset без старых ISR. */ + if (overflow || (ECanaRegs.CANRML.all & 72UL)) { overflow = 0U; ECanaRegs.CANRML.all = 72UL; tail = head; pcan_boot_abort(&boot); } /* Потеря mailbox/очереди отменяет сессию и требует передачи заново. */ + if (!tx_busy && tail != head) { /* Обрабатывает один целиком сформированный ISR элемент за проход. */ + current_command = pcan_boot_id_msg_type(queue[tail].id) == 9U ? pcan_boot_id_msg_body(queue[tail].id) & 255U : 0U; operation_active = 1U; /* BUSY содержит именно команду, которая выполняется сейчас. */ + (void)pcan_boot_process(&boot, queue[tail].id, queue[tail].data, queue[tail].dlc); operation_active = 0U; tail = (tail + 1U) & 31U; /* Производственный codec проверяет session/порядок/CRC и вызывает NOR callbacks только в main. */ + } /* Пока TX занят, очередь сохраняет все следующие кадры окна. */ + if (!tried && !tx_busy && boot.state == PCAN_BOOT_STATE_IDLE && Boot2812_Now() - started >= BOOT2812_RECOVERY_MS) { /* ENTER_BOOT удерживает загрузчик; без сессии допускается автоматический запуск сохранённого CAN-образа. */ + tried = 1U; /* Пустой или испорченный manifest не должен проверяться заново на каждом такте main. */ + if (Boot2812_NorIdentify() && Boot2812_Load(&entry)) { DINT; IER = 0U; IFR = 0U; CpuTimer1Regs.TCR.bit.TSS = 1; ECanaRegs.CANMIM.all = 0UL; ((void (*)(void))entry)(); for (;;) {} } /* Запускает только полностью проверенную RAM-таблицу; приложение само создаст свои ISR и C runtime. */ + } /* При отказе остаётся доступен CAN recovery без EEPROM. */ + } /* Ни один путь не исполняет код из стираемой внешней NOR. */ +} /* Завершение загрузчика выполняется только аппаратным reset либо проверенным переходом в приложение. */ diff --git a/c/protocan-boot/projects/ccs/f2812/nor_flash.c b/c/protocan-boot/projects/ccs/f2812/nor_flash.c new file mode 100644 index 0000000..dde47de --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/nor_flash.c @@ -0,0 +1 @@ +#include "../../../ports/tms320f2812/nor_flash.c" /* Собирает канонический драйвер AM29LV800BT из templates, сохраняя hardware callbacks отдельно от протокола. */ diff --git a/c/protocan-boot/projects/ccs/f2812/shared_boot.c b/c/protocan-boot/projects/ccs/f2812/shared_boot.c new file mode 100644 index 0000000..7c877f4 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/shared_boot.c @@ -0,0 +1 @@ +#include "../../../src/pcan_boot.c" /* Подключает общий ProtoCAN codec, сессии и CRC32 без второй реализации протокола. */ diff --git a/c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml b/c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml new file mode 100644 index 0000000..4b062df --- /dev/null +++ b/c/protocan-boot/projects/ccs/f2812/targetConfigs/TMS320F2812.ccxml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f28335/.ccsproject b/c/protocan-boot/projects/ccs/f28335/.ccsproject new file mode 100644 index 0000000..44f2f89 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/.ccsproject @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f28335/.cproject b/c/protocan-boot/projects/ccs/f28335/.cproject new file mode 100644 index 0000000..5c10a85 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/.cproject @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/projects/ccs/f28335/.project b/c/protocan-boot/projects/ccs/f28335/.project new file mode 100644 index 0000000..c1b7273 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/.project @@ -0,0 +1,115 @@ + + + + F28335_CAN_AB + + Отдельный постоянный загрузчик ProtoCAN для F28335 + + + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + + + + + + + + com.ti.ccstudio.core.ccsNature + + org.eclipse.cdt.core.cnature + + org.eclipse.cdt.core.ccnature + + org.eclipse.cdt.managedbuilder.core.managedBuildNature + + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + + + + ti/DSP2833x_ADC_cal.asm + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm + + + + + ti/DSP2833x_CpuTimers.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_CpuTimers.c + + + + + ti/DSP2833x_GlobalVariableDefs.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c + + + + + ti/DSP2833x_PieCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_PieCtrl.c + + + + + ti/DSP2833x_SysCtrl.c + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_SysCtrl.c + + + + + ti/DSP2833x_usDelay.asm + + 1 + + PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_usDelay.asm + + + + + DSP2833x_Headers_nonBIOS.cmd + + 1 + + PCAN_ROOT/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd + + + + + + + + PCAN_ROOT + + $%7BPARENT-3-PROJECT_LOC%7D + + + diff --git a/c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd b/c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd new file mode 100644 index 0000000..161ce61 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/F28335_CAN_AB.cmd @@ -0,0 +1,30 @@ +MEMORY /* Отделяет постоянный загрузчик от адресов RAM payload приложения 167. */ +{ /* Все адреса и длины указаны в 16-битных словах CPU C28x. */ +PAGE 0: /* Исполняемые секции и их Flash LOAD-адреса. */ + FLASHA : origin = 0x338000, length = 0x007F80 /* Сектор A до зарезервированной CSM-области содержит постоянный загрузчик. */ + BEGIN : origin = 0x33FFF6, length = 0x000002 /* Два слова аппаратного Flash boot перехода; пароли CSM не выделяются. */ + RAMFUNCS : origin = 0x00F800, length = 0x000800 /* Верхние 2048 слов RAM загрузчика нужны InitFlash и не входят в SCI8 payload приложения. */ + ADC_CAL : origin = 0x380080, length = 0x000009 /* Заводская калибровка TI используется без записи/стирания. */ + RESET : origin = 0x3FFFC0, length = 0x000002 /* Аппаратный reset находится в ROM и не программируется. */ +PAGE 1: /* Рабочие данные не пересекают код RAM-приложения ниже E000. */ + BOOT_SHARED : origin = 0x000050, length = 0x000008 /* Общие с приложением восемь слов NOINIT handoff после ROM scratch 0..4F. */ + RAMM0 : origin = 0x000058, length = 0x0003A8 /* Малый банк доступен служебным неинициализированным данным. */ + RAMM1 : origin = 0x000400, length = 0x000400 /* Стек на 1024 слова не меняет расположение при переходе в приложение. */ + RAMDATA : origin = 0x00E000, length = 0x001800 /* 6144 слова store/очереди; приложение использует их только после перехода в C startup. */ +} /* Завершает физическую карту постоянного загрузчика. */ +SECTIONS /* Не выделяет ни одного загружаемого слова в RAM приложения. */ +{ /* Инициализированные Flash-секции остаются в секторе A. */ + codestart : > BEGIN, PAGE = 0 /* Аппаратный переход передаёт управление watchdog-safe C startup. */ + .text : > FLASHA, PAGE = 0 /* Весь постоянный алгоритм и библиотеки исполняются из Flash A. */ + .cinit : > FLASHA, PAGE = 0 /* Таблицы ROM-модели подготавливают данные загрузчика до main. */ + .pinit : > FLASHA, PAGE = 0 /* Сохраняет стандартный порядок C runtime, если компилятор создаст эту секцию. */ + .econst : > FLASHA, PAGE = 0 /* Константы протокола и имена сервиса не расходуют рабочую RAM. */ + .switch : > FLASHA, PAGE = 0 /* Таблицы переходов находятся в постоянной области загрузчика. */ + ramfuncs : LOAD = FLASHA, RUN = RAMFUNCS, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0 /* InitFlash копируется до изменения настроек самой Flash. */ + .boot_shared : > BOOT_SHARED, PAGE = 1, TYPE = NOINIT /* Не обнуляет session/slot, полученные через watchdog reset. */ + .stack : > RAMM1, PAGE = 1 /* Стек не пересекает ни handoff, ни загружаемые секции SCI8. */ + .ebss : > RAMDATA, PAGE = 1 /* Размещает очередь, журнал и структуры драйвера вне RAM payload. */ + .esysmem : > RAMDATA, PAGE = 1 /* Поддерживает стандартную секцию runtime без использования heap в алгоритме. */ + .reset : > RESET, PAGE = 0, TYPE = DSECT /* Reset-вектор ROM описывается, но не попадает в программируемый OUT. */ + .adc_cal : > ADC_CAL, PAGE = 0, TYPE = NOLOAD /* Сохраняет заводские данные ADC TI при установке загрузчика. */ +} /* Не создаёт секций CSM, OTP или паролей. */ diff --git a/c/protocan-boot/projects/ccs/f28335/codestart.asm b/c/protocan-boot/projects/ccs/f28335/codestart.asm new file mode 100644 index 0000000..b69fe2f --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/codestart.asm @@ -0,0 +1,12 @@ + .ref _c_int00 ; Стандартный COFF startup применяет .cinit и вызывает main после отключения раннего watchdog. + .sect "codestart" ; Boot ROM передаёт управление двухсловному переходу по аппаратному адресу слова 0x33FFF6. + LB flash_boot_start ; Переходит к короткой подготовке C28x во Flash, сохраняя точный размер аппаратного входа два слова. + .text ; Последовательность взята из штатного TI DSP2833x_CodeStartBranch.asm и размещается в секторе основного кода. +flash_boot_start: ; Отключает watchdog до возможной длительной обработки таблиц инициализации C, а не только после входа в main. + SETC OBJMODE ; Выбирает C28x object mode, требуемый стандартным COFF startup процессора F28335. + EALLOW ; Разрешает запись защищённого регистра WDCR перед запуском C runtime. + MOVZ DP, #7029h>>6 ; Адрес слова WDCR=0x7029 из карты F28335; DP выбирает соответствующую страницу по 64 слова. + MOV @7029h, #0068h ; Значение 0x0068 содержит контрольные биты WDCHK=101 и WDDIS=1, как официальный TI startup. + EDIS ; Возвращает защиту системных регистров перед переходом в библиотечную инициализацию. + LB _c_int00 ; Применяет штатную ROM-модель инициализации и затем запускает текущий main 167. + .end ; Завершает модуль, не добавляя произвольных данных рядом с CSM-паролями сектора A. diff --git a/c/protocan-boot/projects/ccs/f28335/main.c b/c/protocan-boot/projects/ccs/f28335/main.c new file mode 100644 index 0000000..fa829d2 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/main.c @@ -0,0 +1,127 @@ +#include "DSP2833x_Device.h" /* Использует действующую частоту и штатную карту регистров той же платы 167. */ +#include "DSP2833x_Examples.h" /* Предоставляет InitSysCtrl, InitPieCtrl, InitFlash и управление Timer1. */ +#include "../../../ports/tms320f28335/f28335_can_boot.h" /* Подключает адрес, сервисы и очередь существующего загрузчика. */ +#include "../../../ports/tms320f28335/f28335_boot_platform.h" /* Использует общий handoff, SPI и энергонезависимый A/B-журнал. */ +#include /* Копирует ramfuncs до настройки времен доступа Flash. */ +extern Uint16 RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart; /* Адреса LOAD/RUN задаёт отдельный linker загрузчика в словах C28x. */ +static f28335_boot_store_t image_store; /* Журнал загрузки остаётся в RAM E000..FFFF до перехода в приложение. */ +interrupt void boot_tick(void) /* Timer1 продолжает миллисекундные тайм-ауты общего CAN/SPI порта. */ +{ /* Этот ISR принадлежит постоянному загрузчику, а не кандидату приложения. */ + CpuTimer1.InterruptCount++; /* Один тик равен одной миллисекунде согласно ConfigCpuTimer ниже. */ + ServiceDog(); /* Длительные CRC/SPI операции загрузчика не должны сбрасывать аппарат во время обновления. */ +} /* Возвращает управление основному циклу загрузчика. */ +interrupt void boot_can_rx(void) /* CAN IRQ выполняет только короткий перенос принятых кадров в общую очередь. */ +{ /* Запись EEPROM, CRC и публикация pending остаются в главном цикле. */ + F28335CanBoot_RxISR(); /* Читает только выделенные mailbox 3 и 6 существующего адаптера. */ + PieCtrlRegs.PIEACK.all = 0x0100U; /* Бит 8 подтверждает группу PIE9, в которой находится ECAN0INTA. */ +} /* Позволяет принять следующее окно CAN, пока main занят SPI. */ +static void boot_can_init(void) /* Настраивает тот же физический CAN-A и 250 кбит/с, что приложение 167. */ +{ /* Загрузчик не использует прикладные mailbox 0..2 и не меняет адрес общего порта. */ + Uint32 shadow; /* Защищённые eCAN-регистры изменяются только полными 32-битными обращениями. */ + EALLOW; /* Разрешает настройку мультиплексора, eCAN и таблицы векторов. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1; /* GPIO30 служит CANRXA, как в штатном InitCan проекта. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1; /* GPIO31 служит CANTXA того же трансивера. */ + ECanaRegs.CANTIOC.all = 8UL; /* Бит TXFUNC включает функцию CAN у выхода контроллера. */ + ECanaRegs.CANRIOC.all = 8UL; /* Бит RXFUNC включает аппаратный вход CAN. */ + ECanaRegs.CANME.all = 0UL; /* Изменяет mailbox и фильтры только при выключенных ящиках. */ + ECanaRegs.CANMIM.all = 0UL; /* Ни один старый mailbox не должен создавать IRQ во время настройки. */ + ECanaRegs.CANMIL.all = 0UL; /* Направляет служебные mailbox на ECAN0INTA группы PIE9. */ + ECanaRegs.CANMC.all = 0x00003080UL; /* SCB=1 выбирает eCAN, ABO=1 автоматическое восстановление, CCR=1 режим настройки битового времени; SRES остаётся нулём. */ + while (!ECanaRegs.CANES.bit.CCE) {} /* Не пишет CANBTC до аппаратного подтверждения режима настройки. */ + shadow = ((Uint32)(CLKMULT * 3L - 1L) << 16) | 0x0000017AUL; /* BRP=CLKMULT*3-1, SJW=1, TSEG1=15, TSEG2=2 как в приложении: 250000 бит/с при текущем SYSCLKOUT. */ + ECanaRegs.CANBTC.all = shadow; /* Передаёт параметры одним 32-битным обращением к eCAN. */ + ECanaRegs.CANMC.all &= ~0x00001000UL; /* Снимает CCR после настройки тактов CAN. */ + while (ECanaRegs.CANES.bit.CCE) {} /* Ждёт возврата контроллера к обычной работе перед включением фильтров. */ + ECanaRegs.CANTA.all = 0xFFFFFFFFUL; /* Удаляет старые TX ACK, которые не относятся к новой сессии. */ + ECanaRegs.CANRMP.all = 0xFFFFFFFFUL; /* Удаляет старые RX-флаги до включения IRQ. */ + ECanaRegs.CANRML.all = 0xFFFFFFFFUL; /* Начинает контроль потери mailbox с чистого состояния. */ + ECanaRegs.CANGIF0.all = 0xFFFFFFFFUL; /* Снимает накопленные флаги линии CAN0. */ + ECanaRegs.CANGIM.all = 1UL; /* I0EN разрешает mailbox IRQ по линии 0; ошибки не требуют прикладного ISR. */ + PieVectTable.ECAN0INTA = &boot_can_rx; /* Использует постоянный обработчик загрузчика вместо кода RAM-приложения. */ + PieCtrlRegs.PIEIER9.bit.INTx5 = 1; /* Разрешает ECAN0INTA в группе PIE9. */ + EDIS; /* Возвращает защиту аппаратной конфигурации. */ + IER |= M_INT9; /* Разрешает группе CAN доставлять IRQ ядру после общего EINT. */ +} /* Общий порт затем настроит адресные mailbox 3/4/6. */ +static unsigned int boot_periph_id(void) /* Повторяет аппаратное чтение Mode из peripher.c, чтобы после reset адрес загрузчика совпадал с приложением. */ +{ /* Четыре активных низким уровнем перемычки существующей ПМ35 задают номера 1–16. */ + unsigned int periph_id; /* Номер является ID PERIPH из Excel, а не уменьшенным на единицу индексом старого CAN. */ + EALLOW; /* Разрешает настройку только четырёх входов адресных перемычек. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO20=0; /* GPIO20 работает входом адреса с весом 2, как в get_Mode приложения. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO21=0; /* GPIO21 работает входом адреса с весом 1, а не альтернативной периферией. */ + GpioCtrlRegs.GPAMUX2.bit.GPIO22=0; /* GPIO22 работает входом адреса с весом 4. */ + GpioCtrlRegs.GPBMUX2.bit.GPIO51=0; /* GPIO51 работает входом адреса с весом 8. */ + GpioCtrlRegs.GPADIR.bit.GPIO20=0; /* Запрещает выходной драйвер, чтобы загрузчик не воздействовал на перемычку. */ + GpioCtrlRegs.GPADIR.bit.GPIO21=0; /* Оставляет младшую адресную перемычку входом. */ + GpioCtrlRegs.GPADIR.bit.GPIO22=0; /* Оставляет третий разряд аппаратного номера входом. */ + GpioCtrlRegs.GPBDIR.bit.GPIO51=0; /* Оставляет старшую перемычку входом порта B. */ + EDIS; /* Восстанавливает защиту конфигурации GPIO до чтения физического номера. */ + periph_id=1U+!GpioDataRegs.GPADAT.bit.GPIO21; /* Штатный Mode начинается с 1; замкнутая GPIO21 добавляет единицу. */ + periph_id+=2U*!GpioDataRegs.GPADAT.bit.GPIO20; /* Замкнутая GPIO20 добавляет два к номеру платы. */ + periph_id+=4U*!GpioDataRegs.GPADAT.bit.GPIO22; /* Замкнутая GPIO22 добавляет четыре к номеру платы. */ + periph_id+=8U*!GpioDataRegs.GPBDAT.bit.GPIO51; /* Замкнутая GPIO51 добавляет восемь; аппаратный диапазон заканчивается на 16. */ + return periph_id; /* Общий CAN-порт преобразует номер 16 в Type 2 / Device 0 согласно Excel. */ +} /* Приложение и recovery используют один и тот же физический адрес без общего значения 3/7. */ +static bool ram_word(void *user, uint32_t address, uint16_t value) /* Аппаратная запись одного слова уже проверенной таблицы SCI8. */ +{ /* Повторяет нижнюю защиту RAM даже при ошибке вызывающего слоя. */ + (void)user; /* Контекст не нужен для единственной внутренней RAM данного F28335. */ + if (address < 0x8000UL || address >= 0xE000UL) return false; /* Не позволяет таблице затронуть периферию, handoff, стек или RAM загрузчика. */ + *(volatile Uint16 *)address = value; /* Адрес измеряется в 16-битных словах C28x, значение уже декодировано из SCI8. */ + return true; /* Сообщает полную запись слова, а не частичное выполнение секции. */ +} /* После загрузки всех слов общий store вернёт проверенную точку входа. */ +static uint16_t flash_word(void *user, uint32_t address) /* Читает только фиксированный заголовок и проверенный диапазон приложения ниже сектора A. */ +{ /* Загрузчик остаётся во Flash A, поэтому чтение H–B не меняет выполняемый код. */ + (void)user; /* Единственная внутренняя Flash не требует отдельного контекста источника. */ + return *(volatile Uint16 *)address; /* C28x адресует Flash 16-битными словами; разбиение на октеты выполняет общий валидатор CRC. */ +} /* Никакая запись или стирание Flash при выборе источника запуска не выполняется. */ +static void start_application(uint32_t entry, unsigned int source) /* Передаёт управление Flash либо EEPROM только после проверки соответствующего образа. */ +{ /* Останавливает собственные IRQ до C startup приложения, который заново настроит периферию и рабочую RAM. */ + DINT; IER = 0U; IFR = 0U; /* Старые прерывания не должны войти в очередь или стек завершённого загрузчика. */ + CpuTimer1Regs.TCR.bit.TSS = 1; /* Прекращает миллисекундные IRQ до запуска прикладного InitSysCtrl. */ + ECanaRegs.CANMIM.all = 0UL; /* Не доставляет CAN IRQ во время смены векторов приложения. */ + F28335Boot_SetRunning(source); /* Сохраняет достоверный источник: 0/1 для EEPROM A/B либо FE для проверенной Flash. */ + ((void (*)(void))entry)(); /* Вызывает watchdog-safe startup Flash или проверенную точку C runtime RAM-образа. */ + for (;;) {} /* Ошибочный возврат приложения не использует перезаписанное состояние загрузчика. */ +} /* Возврат к boot происходит только аппаратным reset с согласованным handoff. */ +void F28335Boot_Quiesce(void) /* Перед повторным входом загрузчика его собственные IRQ будут отключены общим Reset. */ +{ /* Силовые выходы загрузчик не включает; прикладная остановка выполняется до входа в него. */ + CpuTimer2Regs.TCR.bit.TSS = 1; /* Удерживает старый SPI Timer2 остановленным перед watchdog reset. */ +} /* Общий аппаратный слой сохранит session и включит watchdog. */ +void main(void) /* Постоянный загрузчик запускается аппаратным Flash boot по адресу 33FFF6. */ +{ /* Пустая EEPROM и неподтверждённый кандидат оставляют доступным CAN recovery. */ + f28335_boot_io_t io; /* Доступ к M95M02 предоставляет существующий переносимый SPI-порт. */ + unsigned int slot, session, periph_id; /* Слот, сессия handoff и физический номер PERIPH сохраняются отдельно от адресов памяти. */ + uint32_t entry, started; /* Адрес запуска измеряется словами CPU; started хранит миллисекунды стартового окна CAN. */ + InitSysCtrl(); /* Повторяет PLL и SYSCLKOUT проекта 167, отключая watchdog на раннем старте. */ + DINT; /* Не использует IRQ до настройки таблицы векторов и Timer1. */ + IER = 0U; IFR = 0U; /* Исключает доставку старых прерываний после watchdog reset. */ + memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, &RamfuncsLoadEnd - &RamfuncsLoadStart); /* Переносит InitFlash в RAM до изменения времен доступа Flash. */ + InitFlash(); /* Настраивает доступ к постоянному коду по штатной процедуре TI. */ + InitPieCtrl(); /* Очищает разрешения и флаги всех групп PIE перед установкой двух собственных векторов. */ + InitCpuTimers(); /* Останавливает Timer0/1/2 и сбрасывает их управляющие структуры. */ + ConfigCpuTimer(&CpuTimer1, SYSCLKOUT / 1000000L, 1000UL); /* Период 1000 мкс даёт единый миллисекундный tick для протокола и SPI WIP. */ + EALLOW; PieVectTable.XINT13 = &boot_tick; EDIS; /* Привязывает прямое прерывание Timer1 к постоянному ISR загрузчика. */ + CpuTimer1Regs.TCR.all = 0x4020U; /* Разрешает прерывание Timer1 и запускает счётчик, как приложение 167. */ + IER |= M_INT13; /* Разрешает миллисекундные прерывания ядра. */ + periph_id=boot_periph_id(); /* Читает реальные перемычки до адресных mailbox и до ответа на ENTER_BOOT после reset. */ + boot_can_init(); /* Настраивает трансивер и физическую скорость до общих фильтров и первой передачи. */ + session = F28335Boot_RequestedSession(); /* Потребляет только достоверный запрос приложения с magic и XOR-контролем. */ + F28335CanBoot_Init(periph_id); /* Открывает журнал и адресные Boot mailbox только для физического PERIPH данной платы. */ + PieCtrlRegs.PIECTRL.bit.ENPIE = 1; /* Разрешает таблицу PIE после записи обоих используемых векторов. */ + EINT; /* Приём окна CAN продолжается во время синхронных SPI-транзакций main. */ + if (session) F28335CanBoot_Resume(session); /* Отвечает ENTER_BOOT после reset с той же session и остаётся в recovery. */ + else { /* Обычный reset даёт CAN окно, затем предпочитает проверенную внутреннюю Flash и использует EEPROM как резерв. */ + started = F28335Boot_Now(); /* Отсчитывает три секунды от готового CAN, а не от начала настройки PLL и SPI. */ + while ((uint32_t)(F28335Boot_Now()-started)<3000UL && !F28335CanBoot_Active()) { F28335CanBoot_Service(); ServiceDog(); } /* ENTER_BOOT удерживает recovery; обычный PING не изменяет выбранный источник запуска. */ + F28335CanBoot_Service(); /* Разбирает кадр на границе трёхсекундного окна до последней проверки активного сеанса. */ + if (!F28335CanBoot_Active()) { /* Не запускает основную или резервную программу поверх открытого сеанса CAN Boot. */ + if (f28335_flash_app_validate(flash_word, 0, &entry)) start_application(entry, F28335_BOOT_FLASH_SLOT); /* Flash приоритетна только при правильном FAB1, допустимых адресах и совпавшей CRC всех LOAD-секций. */ + io.read = F28335Boot_Read; io.write = F28335Boot_Write; io.user = 0; /* Передаёт store ту же аппаратную реализацию, что обслуживает CAN. */ + if (f28335_boot_open(&image_store, &io) && f28335_boot_select(&image_store, &slot) && slot < 2U && f28335_boot_load(&image_store, slot, ram_word, 0, &entry)) { /* Проверяет CRC/SCI8, сохраняет attempted до пробного запуска и копирует только допустимую RAM. */ + start_application(entry, slot); /* Резервный EEPROM-образ получает прежние trial/CONFIRM и автоматический откат A/B. */ + } /* При ошибке чтения, CRC, таблицы или журнала не выполняет неизвестный entry. */ + F28335CanBoot_Init(periph_id); /* При переходе в recovery перечитывает журнал, сохраняя прежний физический адрес платы. */ + } /* Открытый CAN-сеанс сохраняет метаданные, выбранный слот и подтверждения без повторного Init. */ + } /* Завершает выбор между адресным входом и обычным запуском приложения. */ + F28335Boot_SetRunning(F28335_AB_NONE); /* Отмечает режим загрузчика, сохраняя уже восстановленную session в RAM автомата. */ + for (;;) { F28335CanBoot_Service(); ServiceDog(); } /* Обслуживает обновления и остаётся доступным при пустой/повреждённой EEPROM. */ +} /* Нормальный выход выполняется только через запуск RAM-приложения либо watchdog reset. */ diff --git a/c/protocan-boot/projects/ccs/f28335/shared_boot.c b/c/protocan-boot/projects/ccs/f28335/shared_boot.c new file mode 100644 index 0000000..733eb5d --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/shared_boot.c @@ -0,0 +1,5 @@ +#include "../../../src/pcan_boot.c" /* Подключает единственный общий автомат ProtoCAN Boot и CRC32. */ +#include "../../../ports/tms320f28335/f28335_boot_store.c" /* Использует проверенный A/B-журнал, readback, SCI8 и откат. */ +#include "../../../ports/tms320f28335/f28335_flash_app.c" /* Проверяет FAB1 и CRC приложения ниже сектора A перед выбором основного Flash либо резервной EEPROM. */ +#include "../../../ports/tms320f28335/f28335_boot_hw.c" /* Подключает те же SPI, watchdog и handoff, что RAM-приложение. */ +#include "../../../ports/tms320f28335/f28335_can_boot.c" /* F28335_BOOT_LOADER=1 разрешает запись слотов только постоянному загрузчику. */ diff --git a/c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml b/c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml new file mode 100644 index 0000000..d074222 --- /dev/null +++ b/c/protocan-boot/projects/ccs/f28335/targetConfigs/TMS320F28335.ccxml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c/protocan-boot/src/pcan_boot.c b/c/protocan-boot/src/pcan_boot.c index 7b92239..e1d3945 100644 --- a/c/protocan-boot/src/pcan_boot.c +++ b/c/protocan-boot/src/pcan_boot.c @@ -1,21 +1,16 @@ -/* - * Автомат адресной загрузки прошивки по ProtoCAN с сессией, контрольной суммой и A/B-слотами. - * Приём блоков, проверка образа и активация разделены на этапы; операции Flash и метаданные - * слотов предоставляет платформа. - */ - -#include "pcan_boot.h" +/* ProtoCAN update state machine; platform owns storage and reset. */ +#include "../include/pcan_boot.h" #include #define PCAN_BOOT_ID_MASK 0x1FFFFFFFUL -static uint16_t get_u16(const uint8_t *p) +static uint16_t get_u16(const pcan_boot_byte_t *p) { return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } -static uint32_t get_u32(const uint8_t *p) +static uint32_t get_u32(const pcan_boot_byte_t *p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8) @@ -23,26 +18,26 @@ static uint32_t get_u32(const uint8_t *p) | ((uint32_t)p[3] << 24); } -static void put_u16(uint8_t *p, uint16_t value) +static void put_u16(pcan_boot_byte_t *p, uint16_t value) { - p[0] = (uint8_t)value; - p[1] = (uint8_t)(value >> 8); + p[0] = (pcan_boot_byte_t)(value & 0xFFU); + p[1] = (pcan_boot_byte_t)((value >> 8) & 0xFFU); } -static void put_u32(uint8_t *p, uint32_t value) +static void put_u32(pcan_boot_byte_t *p, uint32_t value) { - p[0] = (uint8_t)value; - p[1] = (uint8_t)(value >> 8); - p[2] = (uint8_t)(value >> 16); - p[3] = (uint8_t)(value >> 24); + p[0] = (pcan_boot_byte_t)(value & 0xFFU); + p[1] = (pcan_boot_byte_t)((value >> 8) & 0xFFU); + p[2] = (pcan_boot_byte_t)((value >> 16) & 0xFFU); + p[3] = (pcan_boot_byte_t)(value >> 24); } -static uint32_t crc32_update(uint32_t crc, const uint8_t *data, size_t length) +static uint32_t crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length) { size_t i; crc = ~crc; for (i = 0U; i < length; ++i) { - uint8_t bit; + pcan_boot_byte_t bit; crc ^= data[i]; for (bit = 0U; bit < 8U; ++bit) { crc = (crc >> 1) ^ ((crc & 1U) != 0U ? 0xEDB88320UL : 0U); @@ -51,9 +46,9 @@ static uint32_t crc32_update(uint32_t crc, const uint8_t *data, size_t length) return ~crc; } -uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route, - uint8_t device_type, uint8_t device_id, - uint8_t msg_type, uint16_t msg_body) +uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route, + pcan_boot_byte_t device_type, pcan_boot_byte_t device_id, + pcan_boot_byte_t msg_type, uint16_t msg_body) { return ((((uint32_t)priority & 1U) << 28) | (((uint32_t)route & 1U) << 27) @@ -63,14 +58,14 @@ uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route, | msg_body) & PCAN_BOOT_ID_MASK; } -uint8_t pcan_boot_id_route(uint32_t can_id) { return (uint8_t)((can_id >> 27) & 1U); } -uint8_t pcan_boot_id_device_type(uint32_t can_id) { return (uint8_t)((can_id >> 24) & 7U); } -uint8_t pcan_boot_id_device_id(uint32_t can_id) { return (uint8_t)((can_id >> 20) & 15U); } -uint8_t pcan_boot_id_msg_type(uint32_t can_id) { return (uint8_t)((can_id >> 16) & 15U); } +pcan_boot_byte_t pcan_boot_id_route(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 27) & 1U); } +pcan_boot_byte_t pcan_boot_id_device_type(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 24) & 7U); } +pcan_boot_byte_t pcan_boot_id_device_id(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 20) & 15U); } +pcan_boot_byte_t pcan_boot_id_msg_type(uint32_t can_id) { return (pcan_boot_byte_t)((can_id >> 16) & 15U); } uint16_t pcan_boot_id_msg_body(uint32_t can_id) { return (uint16_t)can_id; } -static bool send_frame(pcan_boot_t *boot, uint8_t msg_type, uint16_t body, - const uint8_t *data, uint8_t dlc) +static bool send_frame(pcan_boot_t *boot, pcan_boot_byte_t msg_type, uint16_t body, + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { uint32_t id = pcan_boot_make_id(1U, PCAN_BOOT_ROUTE_FROM_DEVICE, boot->config.device_type, @@ -79,9 +74,12 @@ static bool send_frame(pcan_boot_t *boot, uint8_t msg_type, uint16_t body, return boot->port.send(boot->port_user, id, data, dlc); } -static bool send_status(pcan_boot_t *boot, uint8_t command, uint8_t status) +/* STATUS всегда содержит состояние передачи: status, target_slot, next_block, CRC32. + * CRC здесь относится к уже принятому потоку, а не заменяет проверку EEPROM. + * Номер следующего блока помогает клиенту продолжить обмен после потери ACK. */ +static bool send_status(pcan_boot_t *boot, pcan_boot_byte_t command, pcan_boot_byte_t status) { - uint8_t data[8]; + pcan_boot_byte_t data[8]; uint16_t body = (uint16_t)(((uint16_t)boot->session_id << 8) | command); data[0] = status; data[1] = boot->target_slot; @@ -91,9 +89,22 @@ static bool send_status(pcan_boot_t *boot, uint8_t command, uint8_t status) return send_frame(boot, PCAN_BOOT_MSG_STATUS, body, data, 8U); } +uint32_t pcan_boot_crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length) /* Публичный readback использует тот же полином и отражение, что приём DATA. */ +{ /* Не создаёт второго аппаратно зависимого варианта CRC в портах NOR/EEPROM. */ + return crc32_update(crc, data, length); /* Продолжает ранее полученное состояние либо начинает с нуля. */ +} /* Сохраняет существующую wire-совместимость всех портов. */ +bool pcan_boot_report_busy(pcan_boot_t *boot, pcan_boot_byte_t command, uint32_t now_ms) /* Позволяет синхронному erase отвечать, пока аппаратная операция ещё не завершена. */ +{ /* Порт вызывает функцию только в контексте main с живым экземпляром сессии. */ + if (boot == NULL) return false; /* Не обращается к неинициализированному экземпляру аппаратного порта. */ + boot->now_ms = boot->last_activity_ms = now_ms; /* Продвижение erase/verify считается живой активностью: длинная операция не должна сама истечь по тайм-ауту сессии. */ + return send_status(boot, command, PCAN_BOOT_STATUS_BUSY); /* Номер следующего блока и CRC берутся из настоящего состояния ядра. */ +} /* Окончательный OK/ошибку по завершении callback отправляет обычный автомат. */ + +/* IDENTIFY имеет отдельный тип сообщения DISCOVERY и Body=1. Он доступен + * без открытия сессии, поэтому обнаружение устройства не должно запускать обновление. */ static bool send_identity(pcan_boot_t *boot) { - uint8_t data[8]; + pcan_boot_byte_t data[8]; put_u16(&data[0], boot->config.product_type); data[2] = boot->config.hardware_revision; data[3] = PCAN_BOOT_VERSION; @@ -101,6 +112,9 @@ static bool send_identity(pcan_boot_t *boot) return send_frame(boot, PCAN_BOOT_MSG_DISCOVERY, 1U, data, 8U); } +/* Отменяется только состояние протокола в RAM: manifest, счётчики и session. + * Функция не стирает EEPROM и не снимает ранее опубликованный pending. + * Ответственность за постоянное состояние слотов остаётся у платформы. */ void pcan_boot_abort(pcan_boot_t *boot) { if (boot == NULL) { @@ -118,19 +132,24 @@ void pcan_boot_abort(pcan_boot_t *boot) boot->have_compat = false; } +/* Конфигурация копируется в экземпляр; указатели callbacks остаются привязаны + * к port_user. Значения slot_count=0 и max_image_size=0 сохраняют исторические + * настройки по умолчанию. Для пустого A/B-хранилища допустим active_slot=NONE. */ bool pcan_boot_init(pcan_boot_t *boot, const pcan_boot_config_t *config, const pcan_boot_port_t *port, void *port_user) { - uint8_t slot_count; + pcan_boot_byte_t slot_count; if ((boot == NULL) || (config == NULL) || (port == NULL) || (config->device_type > 7U) || (config->device_id > 15U) - || (config->active_slot > 1U) + || ((config->active_slot > 1U) && (config->active_slot != PCAN_BOOT_SLOT_NONE)) || (port->send == NULL) || (port->erase_slot == NULL) || (port->write_slot == NULL)) { return false; } slot_count = config->slot_count == 0U ? 2U : config->slot_count; - if ((slot_count > 2U) || (config->active_slot >= slot_count) + if ((slot_count > 2U) || ((config->active_slot >= slot_count) && + (config->active_slot != PCAN_BOOT_SLOT_NONE || slot_count != 2U)) + || config->max_image_size > PCAN_BOOT_SLOT_SIZE || ((slot_count == 2U) && (port->set_pending_slot == NULL))) { return false; } @@ -149,7 +168,10 @@ bool pcan_boot_init(pcan_boot_t *boot, const pcan_boot_config_t *config, return true; } -static bool metadata_complete(pcan_boot_t *boot, uint8_t command) +/* BEGIN_IMAGE и BEGIN_COMPAT приходят отдельными кадрами. До получения обоих + * не разрешаем ERASE. Проверяем размер, Product, HW и необязательную политику + * authorize. В A/B выбираем противоположный active слот; для первого образа — A. */ +static bool metadata_complete(pcan_boot_t *boot, pcan_boot_byte_t command) { if (!boot->have_image || !boot->have_compat) { boot->state = PCAN_BOOT_STATE_METADATA; @@ -160,8 +182,11 @@ static bool metadata_complete(pcan_boot_t *boot, uint8_t command) boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_SIZE); } - if ((boot->manifest.product_type != boot->config.product_type) - || (boot->config.hardware_revision < boot->manifest.hardware_revision_min) + if (boot->manifest.product_type != boot->config.product_type) { + boot->state = PCAN_BOOT_STATE_FAILED; + return send_status(boot, command, PCAN_BOOT_STATUS_WRONG_DEVICE); + } + if ((boot->config.hardware_revision < boot->manifest.hardware_revision_min) || (boot->config.hardware_revision > boot->manifest.hardware_revision_max)) { boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_WRONG_HARDWARE); @@ -171,19 +196,51 @@ static bool metadata_complete(pcan_boot_t *boot, uint8_t command) boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_SIGNATURE_ERROR); } - boot->target_slot = boot->config.slot_count == 1U + boot->target_slot = boot->config.active_slot == PCAN_BOOT_SLOT_NONE ? 0U : + boot->config.slot_count == 1U ? boot->config.active_slot - : (uint8_t)(boot->config.active_slot ^ 1U); + : (pcan_boot_byte_t)(boot->config.active_slot ^ 1U); boot->state = PCAN_BOOT_STATE_READY_TO_ERASE; return send_status(boot, command, PCAN_BOOT_STATUS_OK); } +/* Body состоит из session в старшем октете и command в младшем. + * Сначала проверяем DLC, чтобы обработчики не читали отсутствующие данные. + * Идентификация и паспорт не открывают сессию; CONFIRM обрабатывается отдельно, + * поскольку приложение не должно входить в загрузчик ради подтверждения себя. + * Остальные команды изменяют RAM-автомат только в допустимой сессии/состоянии. */ static bool process_control(pcan_boot_t *boot, uint16_t body, - const uint8_t *data, uint8_t dlc) + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { - uint8_t session = (uint8_t)(body >> 8); - uint8_t command = (uint8_t)body; + pcan_boot_byte_t session = (pcan_boot_byte_t)(body >> 8); + pcan_boot_byte_t command = (pcan_boot_byte_t)(body & 0xFFU); + if (dlc != ((command == PCAN_BOOT_CMD_BEGIN_IMAGE || command == PCAN_BOOT_CMD_BEGIN_COMPAT) ? 8U : + (command == PCAN_BOOT_CMD_DEVICE_NAME || command == PCAN_BOOT_CMD_MEMORY_INFO) ? 1U : 0U)) { + return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_SIZE); + } + if (command == PCAN_BOOT_CMD_PING) { + pcan_boot_byte_t reply[8] = {0}; + reply[0] = PCAN_BOOT_VERSION; reply[1] = boot->state; + reply[2] = boot->config.active_slot; reply[3] = boot->target_slot; + reply[4] = boot->session_id; reply[5] = boot->config.slot_count; + reply[6] = boot->last_status; + return send_frame(boot, PCAN_BOOT_MSG_DISCOVERY, command, reply, 8); + } + if (command >= PCAN_BOOT_CMD_CAPABILITIES && command <= PCAN_BOOT_CMD_MEMORY_INFO) { + pcan_boot_byte_t reply[8] = {0}; + pcan_boot_byte_t page = dlc ? data[0] : 0; + if (!boot->port.service_info || !boot->port.service_info(boot->port_user,command,page,reply)) + return send_status(boot,command,PCAN_BOOT_STATUS_INVALID_COMMAND); + return send_frame(boot,PCAN_BOOT_MSG_DISCOVERY,(uint16_t)((page<<8)|command),reply,8); + } + if (command == PCAN_BOOT_CMD_CONFIRM) { + pcan_boot_byte_t saved=boot->session_id; bool sent; + boot->session_id=session; + sent=send_status(boot,command,session && boot->port.confirm_running_slot && + boot->port.confirm_running_slot(boot->port_user) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_INVALID_STATE); + boot->session_id=saved; return sent; + } if (command == PCAN_BOOT_CMD_IDENTIFY) { return send_identity(boot); } @@ -191,8 +248,18 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, if (session == 0U) { return send_status(boot, command, PCAN_BOOT_STATUS_SESSION_ERROR); } + if (boot->state != PCAN_BOOT_STATE_IDLE && boot->session_id != session) + return send_status(boot,command,PCAN_BOOT_STATUS_BUSY); + if (boot->port.enter_boot) { + unsigned int result=boot->port.enter_boot(boot->port_user,session); + if(result==1) return true; + if(result!=0) return send_status(boot,command,PCAN_BOOT_STATUS_INVALID_STATE); + } + if (boot->session_id==session && boot->state!=PCAN_BOOT_STATE_IDLE) + return send_status(boot,command,PCAN_BOOT_STATUS_OK); pcan_boot_abort(boot); boot->session_id = session; + boot->last_activity_ms=boot->now_ms; boot->state = PCAN_BOOT_STATE_METADATA; return send_status(boot, command, PCAN_BOOT_STATUS_OK); } @@ -200,8 +267,11 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_SESSION_ERROR); } + boot->last_activity_ms=boot->now_ms; switch (command) { case PCAN_BOOT_CMD_BEGIN_IMAGE: + if(boot->state==PCAN_BOOT_STATE_READY_TO_ERASE && boot->manifest.image_size==get_u32(data) && + boot->manifest.image_crc32==get_u32(data+4)) return send_status(boot,command,PCAN_BOOT_STATUS_OK); if ((dlc != 8U) || (boot->state != PCAN_BOOT_STATE_METADATA)) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } @@ -211,6 +281,9 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return metadata_complete(boot, command); case PCAN_BOOT_CMD_BEGIN_COMPAT: + if(boot->state==PCAN_BOOT_STATE_READY_TO_ERASE && boot->manifest.product_type==get_u16(data) && + boot->manifest.hardware_revision_min==data[2] && boot->manifest.hardware_revision_max==data[3] && + boot->manifest.firmware_version==get_u32(data+4)) return send_status(boot,command,PCAN_BOOT_STATUS_OK); if ((dlc != 8U) || (boot->state != PCAN_BOOT_STATE_METADATA)) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } @@ -222,6 +295,8 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return metadata_complete(boot, command); case PCAN_BOOT_CMD_ERASE: + if(boot->state==PCAN_BOOT_STATE_RECEIVING && boot->bytes_received==0) + return send_status(boot,command,PCAN_BOOT_STATUS_OK); if (boot->state != PCAN_BOOT_STATE_READY_TO_ERASE) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } @@ -236,6 +311,8 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_VERIFY: + if(boot->state==PCAN_BOOT_STATE_VERIFIED || boot->state==PCAN_BOOT_STATE_COMMITTED) + return send_status(boot,command,PCAN_BOOT_STATUS_OK); if ((boot->state != PCAN_BOOT_STATE_RECEIVING) || (boot->bytes_received != boot->manifest.image_size)) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); @@ -244,7 +321,13 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, boot->state = PCAN_BOOT_STATE_FAILED; return send_status(boot, command, PCAN_BOOT_STATUS_CRC_ERROR); } - if ((boot->port.verify_image != NULL) + if (boot->port.verify_status) { + pcan_boot_status_t status=boot->port.verify_status(boot->port_user,boot->target_slot,&boot->manifest); + if(status!=PCAN_BOOT_STATUS_OK) { + boot->state=PCAN_BOOT_STATE_FAILED; return send_status(boot,command,status); + } + } + if (!boot->port.verify_status && (boot->port.verify_image != NULL) && !boot->port.verify_image(boot->port_user, boot->target_slot, &boot->manifest)) { boot->state = PCAN_BOOT_STATE_FAILED; @@ -254,21 +337,16 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_COMMIT: + if(boot->state==PCAN_BOOT_STATE_COMMITTED) return send_status(boot,command,PCAN_BOOT_STATUS_OK); if (boot->state != PCAN_BOOT_STATE_VERIFIED) { return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); } - if ((boot->config.slot_count == 2U) + if ((boot->port.set_pending_slot != NULL) && !boot->port.set_pending_slot(boot->port_user, boot->target_slot, &boot->manifest)) { return send_status(boot, command, PCAN_BOOT_STATUS_FLASH_ERROR); } - return send_status(boot, command, PCAN_BOOT_STATUS_OK); - - case PCAN_BOOT_CMD_CONFIRM: - if ((boot->port.confirm_running_slot == NULL) - || !boot->port.confirm_running_slot(boot->port_user)) { - return send_status(boot, command, PCAN_BOOT_STATUS_FLASH_ERROR); - } + boot->state=PCAN_BOOT_STATE_COMMITTED; return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_QUERY_PROGRESS: @@ -280,7 +358,9 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, return send_status(boot, command, PCAN_BOOT_STATUS_OK); case PCAN_BOOT_CMD_REBOOT: - (void)send_status(boot, command, PCAN_BOOT_STATUS_OK); + if(!boot->port.reboot || (boot->port.can_reboot && !boot->port.can_reboot(boot->port_user))) + return send_status(boot,command,PCAN_BOOT_STATUS_INVALID_STATE); + if(!send_status(boot,command,PCAN_BOOT_STATUS_OK)) return false; if (boot->port.reboot != NULL) { boot->port.reboot(boot->port_user); } @@ -291,11 +371,16 @@ static bool process_control(pcan_boot_t *boot, uint16_t body, } } -static bool process_data(pcan_boot_t *boot, uint8_t msg_type, uint16_t block, - const uint8_t *data, uint8_t dlc) +/* DATA не содержит session в Body: все 16 бит заняты номером блока. Поэтому + * кадры данных принимаются только в состоянии RECEIVING и для выбранного A/B. + * При неверном номере ничего не записываем и возвращаем ожидаемый next_block. + * Последний кадр дополняется клиентом до 8 октетов, но запись и CRC учитывают + * только оставшиеся октеты image_size. ACK выдаётся на границе окна или в конце. */ +static bool process_data(pcan_boot_t *boot, pcan_boot_byte_t msg_type, uint16_t block, + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { - uint8_t expected_type; - uint8_t write_length; + pcan_boot_byte_t expected_type; + pcan_boot_byte_t write_length; uint32_t remaining; if (boot->state != PCAN_BOOT_STATE_RECEIVING) { @@ -309,8 +394,9 @@ static bool process_data(pcan_boot_t *boot, uint8_t msg_type, uint16_t block, if ((block != boot->next_block) || (dlc != PCAN_BOOT_BLOCK_SIZE)) { return send_status(boot, 0U, PCAN_BOOT_STATUS_SEQUENCE_ERROR); } + boot->last_activity_ms=boot->now_ms; remaining = boot->manifest.image_size - boot->bytes_received; - write_length = remaining < PCAN_BOOT_BLOCK_SIZE ? (uint8_t)remaining + write_length = remaining < PCAN_BOOT_BLOCK_SIZE ? (pcan_boot_byte_t)remaining : PCAN_BOOT_BLOCK_SIZE; if ((write_length == 0U) || !boot->port.write_slot(boot->port_user, boot->target_slot, @@ -329,10 +415,14 @@ static bool process_data(pcan_boot_t *boot, uint8_t msg_type, uint16_t block, return true; } +/* Общая точка входа для одного кадра после аппаратной фильтрации. + * Проверки адреса повторяются программно, чтобы широкая маска CAN не разрешила + * обновление чужого устройства. Broadcast допускается только для DISCOVERY + * с Body=0/DLC=0; ответ откладывается до poll для разведения устройств по времени. */ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, - const uint8_t *data, uint8_t dlc) + const pcan_boot_byte_t *data, pcan_boot_byte_t dlc) { - uint8_t msg_type; + pcan_boot_byte_t msg_type; if ((boot == NULL) || (dlc > 8U) || ((dlc != 0U) && (data == NULL))) { return false; } @@ -340,6 +430,17 @@ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, if ((msg_type < PCAN_BOOT_MSG_CONTROL) || (msg_type > PCAN_BOOT_MSG_DISCOVERY)) { return false; } + if(msg_type==PCAN_BOOT_MSG_DISCOVERY && pcan_boot_id_route(can_id)==0 && + pcan_boot_id_msg_body(can_id)==0 && dlc==0 && + ((pcan_boot_id_device_type(can_id)==7 && pcan_boot_id_device_id(can_id)==15) || + (pcan_boot_id_device_type(can_id)==boot->config.device_type && + pcan_boot_id_device_id(can_id)==boot->config.device_id))) { + if(!boot->discovery_pending) { + boot->discovery_at=boot->now_ms+2U*(1U+16U*boot->config.device_type+boot->config.device_id); + boot->discovery_pending=true; + } + return true; + } if ((pcan_boot_id_route(can_id) != PCAN_BOOT_ROUTE_FROM_PM) || (pcan_boot_id_device_type(can_id) != boot->config.device_type) || (pcan_boot_id_device_id(can_id) != boot->config.device_id)) { @@ -353,3 +454,18 @@ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id, } return false; } + +/* Обслуживание времени не требует входящего кадра. Регулярно вызывать из main + * с монотонным счётчиком миллисекунд: иначе не истечёт сессия и не выйдет discovery. + * При занятом TX discovery остаётся pending до успешного send_identity. + * Вычитание unsigned учитывает переход счётчика через 0xFFFFFFFF. */ +void pcan_boot_poll(pcan_boot_t *boot,uint32_t now_ms) +{ + if(!boot) return; + boot->now_ms=now_ms; + if(boot->config.session_timeout_ms && boot->state!=PCAN_BOOT_STATE_IDLE && + (uint32_t)(now_ms-boot->last_activity_ms)>=boot->config.session_timeout_ms) + pcan_boot_abort(boot); + if(boot->discovery_pending && (uint32_t)(now_ms-boot->discovery_at)<0x80000000UL && send_identity(boot)) + boot->discovery_pending=false; +} diff --git a/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h b/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h new file mode 100644 index 0000000..bd2cf58 --- /dev/null +++ b/c/protocan-boot/tests/f28335_stubs/DSP2833x_Device.h @@ -0,0 +1,13 @@ +#ifndef TEST_DSP_H +#define TEST_DSP_H +#include +#define EALLOW +#define EDIS +struct test_reg { uint32_t all; struct { unsigned DLC, RTR; } bit; }; +struct MBOX { struct test_reg MSGID, MSGCTRL, MDL, MDH; }; +static struct { struct MBOX MBOX3, MBOX4, MBOX6; } ECanaMboxes; +static struct { struct test_reg CANME,CANMD,CANRMP,CANRML,CANMIM,CANTA,CANAA,CANTRS,CANTRR; } ECanaRegs; +static struct { struct test_reg LAM3,LAM6; } ECanaLAMRegs; +static struct { unsigned long InterruptCount; } CpuTimer1; +/* Watchdog/reset моделируются callbacks; неиспользуемая глобальная копия SysCtrlRegs не требуется. */ +#endif diff --git a/c/protocan-boot/tests/f28335_stubs/spise2p.h b/c/protocan-boot/tests/f28335_stubs/spise2p.h new file mode 100644 index 0000000..acb88b5 --- /dev/null +++ b/c/protocan-boot/tests/f28335_stubs/spise2p.h @@ -0,0 +1,7 @@ +#include +#ifndef EEPROM_M95M02 +#define EEPROM_M95M02 1 +#endif +#define BALSAM167_EEPROM_FIRMWARE_BYTES 261884UL +void Seeprom_write(unsigned long word, unsigned int *data, unsigned long bytes); +void Seeprom_read(unsigned long word, unsigned int *data, unsigned long bytes); diff --git a/c/protocan-boot/tests/run_tests.py b/c/protocan-boot/tests/run_tests.py new file mode 100644 index 0000000..48bbe9d --- /dev/null +++ b/c/protocan-boot/tests/run_tests.py @@ -0,0 +1,32 @@ +"""Host regression suite. CC may point to clang/gcc; this does not replace a TI build.""" +import os +from pathlib import Path +import shutil +import subprocess +import tempfile + +root = Path(__file__).resolve().parents[1] +cc = os.environ.get('CC') or shutil.which('clang') or shutil.which('gcc') +if not cc: + raise SystemExit('Set CC to a C99 host compiler') +store = 'ports/tms320f28335/f28335_boot_store.c' +cases = [ + ('core', [], ['src/pcan_boot.c', 'tests/test_pcan_boot.c']), + ('busy', ['-DPCAN_BOOT_WIDE_BYTES'], ['src/pcan_boot.c', 'tests/test_pcan_busy.c']), # Длительный NOR erase с BUSY продлевает session и сохраняет wire-поля ответа. + ('store_native', [], [store, 'tests/test_f28335_boot_store.c']), + ('store_wide', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'tests/test_f28335_boot_store.c']), + ('loader', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), + ('application', ['-DPCAN_BOOT_WIDE_BYTES', '-DF28335_BOOT_LOADER=0'], + [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), + ('f2812_nor', ['-DPCAN_BOOT_WIDE_BYTES', '-DBOOT2812_HOST'], ['src/pcan_boot.c', 'ports/tms320f2812/nor_flash.c', 'ports/tms320f2812/boot_store.c', 'tests/test_f2812_nor.c']), # Проверяет настоящий AMD driver, NOR manifest, SCI8 и восстановление после обрывов записи. + ('stm32f103', ['-DTEST_STM32F103', '-Itests/stm32_stubs'], ['src/pcan_boot.c', 'ports/stm32f103/pcan_boot_stm32f103.c', 'tests/test_stm32_ports.c']), # Проверяет production-порт F103: границы страниц, все хвосты CAN, CRC readback и отказ reset без TX ACK. + ('stm32f407', ['-Itests/stm32_stubs'], ['src/pcan_boot.c', 'ports/stm32f407/pcan_boot_stm32f407.c', 'tests/test_stm32_ports.c']), # Проверяет production-порт F407, включая сохранность загрузчика и EEPROM-кольца секторов 6/7. + ('stm32g474', ['-DTEST_STM32G474', '-Itests/stm32_stubs'], ['src/pcan_boot.c', 'ports/stm32g474/pcan_boot_stm32g474.c', 'tests/test_stm32_ports.c']), # Проверяет FDCAN, обе геометрии DBANK, границу банков и запрет bank swap/ошибочной ёмкости Flash. +] +with tempfile.TemporaryDirectory(prefix='f28335-ab-') as tmp: + for name, defines, sources in cases: + exe = Path(tmp) / (name + '.exe') + subprocess.run([cc, '-std=c99', '-Wall', '-Wextra', '-Werror', '-Wno-misleading-indentation', '-Iinclude', # GCC допускает существующие однострочные циклы старых аппаратных моделей без подавления остальных ошибок. + '-Itests/f28335_stubs', *defines, *sources, '-o', str(exe)], cwd=root, check=True) + sample = os.environ.get('F28335_SAMPLE_IMAGE') if name == 'store_wide' else None + subprocess.run([str(exe), *([sample] if sample else [])], check=True, timeout=30) diff --git a/c/protocan-boot/tests/stm32_stubs/stm32_hal_fake.h b/c/protocan-boot/tests/stm32_stubs/stm32_hal_fake.h new file mode 100644 index 0000000..f548ae1 --- /dev/null +++ b/c/protocan-boot/tests/stm32_stubs/stm32_hal_fake.h @@ -0,0 +1,50 @@ +#ifndef STM32_HAL_FAKE_H /* Изолирует модель HAL от повторного включения семейных обёрток. */ +#define STM32_HAL_FAKE_H /* Включается только host-тестами, без регистров реального устройства. */ +#include /* Определяет типы адресов, таймеров и программируемых значений HAL. */ +typedef enum { HAL_OK = 0, HAL_ERROR = 1 } HAL_StatusTypeDef; /* Модель различает успех и аппаратный отказ. */ +typedef struct { uint32_t TSR; } CAN_TypeDef; /* Хранит только флаги завершения передачи, читаемые production-портом. */ +extern CAN_TypeDef stm32_test_can; /* Единственный экземпляр модели CAN1 принадлежит тестовому процессу. */ +#define CAN1 (&stm32_test_can) /* Заменяет адрес аппаратных регистров безопасным host-объектом. */ +typedef struct { CAN_TypeDef *Instance; } CAN_HandleTypeDef; /* Сохраняет используемое production-кодом поле HAL handle. */ +typedef struct { uint32_t StdId, ExtId, IDE, RTR, DLC, TransmitGlobalTime; } CAN_TxHeaderTypeDef; /* Повторяет поля TX-заголовка современного HAL bxCAN. */ +typedef struct { uint32_t StdId, ExtId, IDE, RTR, DLC; } CAN_RxHeaderTypeDef; /* Повторяет входные поля, проверяемые перед разбором кадра. */ +typedef struct { uint32_t FilterBank, FilterMode, FilterScale, FilterIdHigh, FilterIdLow, FilterMaskIdHigh, FilterMaskIdLow, FilterFIFOAssignment, FilterActivation, SlaveStartFilterBank; } CAN_FilterTypeDef; /* Позволяет проверить реальные маски адреса и broadcast discovery. */ +typedef struct { uint32_t TypeErase, PageAddress, NbPages, VoltageRange, Sector, NbSectors, Banks, Page; } FLASH_EraseInitTypeDef; /* Модель покрывает поля F1/F4/G4, но не подменяет ARM-проверку настоящих заголовков. */ +#define CAN_ID_EXT 4U /* IDE=1 расположен в бите 2 регистрового идентификатора bxCAN. */ +#define CAN_RTR_DATA 0U /* RTR=0 обозначает обычный кадр с данными. */ +#define CAN_TX_MAILBOX0 1U /* HAL кодирует первый mailbox младшим битом маски. */ +#define CAN_TX_MAILBOX1 2U /* HAL кодирует второй mailbox следующим битом маски. */ +#define CAN_TX_MAILBOX2 4U /* HAL кодирует третий mailbox битом 2. */ +#define CAN_TSR_TXOK0 2U /* Успешная передача mailbox 0: TSR bit 1. */ +#define CAN_TSR_TXOK1 512U /* Успешная передача mailbox 1: TSR bit 9. */ +#define CAN_TSR_TXOK2 131072U /* Успешная передача mailbox 2: TSR bit 17. */ +#define CAN_TSR_RQCP0 1U /* W1C подтверждение завершения mailbox 0 расположено в бите 0 TSR. */ +#define CAN_TSR_RQCP1 256U /* W1C подтверждение завершения mailbox 1 расположено в бите 8 TSR. */ +#define CAN_TSR_RQCP2 65536U /* W1C подтверждение завершения mailbox 2 расположено в бите 16 TSR. */ +#define CAN_FILTERMODE_IDMASK 0U /* Фильтр использует аппаратное сравнение по маске. */ +#define CAN_FILTERSCALE_32BIT 1U /* Модель различает полный 32-битный регистровый формат. */ +#define CAN_FILTER_FIFO0 0U /* Фильтры направляются в первый аппаратный FIFO. */ +#define CAN_RX_FIFO0 0U /* Production-порт читает только FIFO0. */ +#define ENABLE 1U /* HAL включает банк фильтра единичным флагом. */ +#define FLASH_TYPEERASE_PAGES 0U /* Семейный тип стирания STM32F1 в тестовом контракте. */ +#define FLASH_TYPEERASE_SECTORS 1U /* Семейный тип стирания STM32F4 в тестовом контракте. */ +#define FLASH_TYPEPROGRAM_HALFWORD 1U /* Выбирает двухбайтовую операцию модели F1. */ +#define FLASH_TYPEPROGRAM_WORD 2U /* Выбирает четырёхбайтовую операцию модели F4. */ +#define FLASH_VOLTAGE_RANGE_3 2U /* Модель проверяет профиль x32 с VDD 2,7..3,6 В. */ +#define FLASH_SECTOR_2 2U /* Начальный разрешённый сектор STM32F407 в профиле climate. */ +uint32_t HAL_GetTick(void); /* Даёт управляемый монотонный таймер для проверки тайм-аутов. */ +uint32_t HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *can); /* Позволяет имитировать постоянно занятый передатчик. */ +HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *can, CAN_TxHeaderTypeDef *header, uint8_t *data, uint32_t *mailbox); /* Сохраняет сформированный production-кодом ответ. */ +uint32_t HAL_CAN_IsTxMessagePending(CAN_HandleTypeDef *can, uint32_t mailbox); /* Позволяет имитировать незавершённую передачу перед reset. */ +HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *can, uint32_t mailbox); /* Фиксирует снятие TX-запроса после тайм-аута. */ +HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *can, CAN_FilterTypeDef *filter); /* Сохраняет оба аппаратных фильтра загрузчика. */ +HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *can); /* Позволяет проверить отказ запуска аппаратного транспорта. */ +uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *can, uint32_t fifo); /* Возвращает число заранее подготовленных входящих кадров. */ +HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *can, uint32_t fifo, CAN_RxHeaderTypeDef *header, uint8_t *data); /* Передаёт production-коду входной заголовок без обхода его проверок. */ +HAL_StatusTypeDef HAL_FLASH_Unlock(void); /* Устанавливает признак разрешённого изменения модели Flash. */ +HAL_StatusTypeDef HAL_FLASH_Lock(void); /* Восстанавливает блокировку после успеха и ошибок. */ +HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *erase, uint32_t *error); /* Стирает настоящую выбранную область host-отображения Flash. */ +HAL_StatusTypeDef HAL_FLASH_Program(uint32_t type, uint32_t address, uint64_t value); /* Программирует модель только в пределах профиля и с правильным выравниванием. */ +void FLASH_FlushCaches(void); /* Фиксирует обязательное обновление представления Flash F407 после записи перед readback. */ +void NVIC_SystemReset(void); /* Записывает факт reset вместо сброса host-процесса. */ +#endif /* Завершает минимальный контракт тестовой HAL-модели. */ diff --git a/c/protocan-boot/tests/stm32_stubs/stm32f1xx_hal.h b/c/protocan-boot/tests/stm32_stubs/stm32f1xx_hal.h new file mode 100644 index 0000000..3847482 --- /dev/null +++ b/c/protocan-boot/tests/stm32_stubs/stm32f1xx_hal.h @@ -0,0 +1 @@ +#include "stm32_hal_fake.h" /* Предоставляет host-модель HAL для production-порта F103. */ diff --git a/c/protocan-boot/tests/stm32_stubs/stm32f4xx_hal.h b/c/protocan-boot/tests/stm32_stubs/stm32f4xx_hal.h new file mode 100644 index 0000000..313b363 --- /dev/null +++ b/c/protocan-boot/tests/stm32_stubs/stm32f4xx_hal.h @@ -0,0 +1 @@ +#include "stm32_hal_fake.h" /* Предоставляет host-модель HAL для production-порта F407. */ diff --git a/c/protocan-boot/tests/stm32_stubs/stm32g4xx_hal.h b/c/protocan-boot/tests/stm32_stubs/stm32g4xx_hal.h new file mode 100644 index 0000000..3547077 --- /dev/null +++ b/c/protocan-boot/tests/stm32_stubs/stm32g4xx_hal.h @@ -0,0 +1,54 @@ +#ifndef STM32_G4_HAL_FAKE_H /* Защищает дополнительные FDCAN/Flash-типы от повторного включения. */ +#define STM32_G4_HAL_FAKE_H /* Обозначает активную host-модель HAL STM32G4. */ +#include "stm32_hal_fake.h" /* Повторно использует таймер, Flash API и host-модель базовых HAL-типов. */ +typedef struct { uint32_t OPTR; } FLASH_TypeDef; /* Моделирует DBANK и запрет BFB2, проверяемые production-портом. */ +typedef struct { uint32_t MEMRMP; } SYSCFG_TypeDef; /* Моделирует запрет программной перестановки физических банков. */ +typedef struct { uint32_t TXBTO; } FDCAN_GlobalTypeDef; /* Моделирует флаг подтверждённой физической передачи TX-буфера. */ +extern FLASH_TypeDef stm32_test_flash; extern SYSCFG_TypeDef stm32_test_syscfg; extern FDCAN_GlobalTypeDef stm32_test_fdcan; extern uint16_t stm32_test_flash_kib; /* Тест управляет независимыми аппаратными регистрами и физической ёмкостью MCU. */ +#define FLASH (&stm32_test_flash) /* Читает Flash geometry из безопасного host-объекта. */ +#define SYSCFG (&stm32_test_syscfg) /* Читает состояние remap из безопасного host-объекта. */ +#define FDCAN1 (&stm32_test_fdcan) /* Единственный выделенный контроллер G474-порта. */ +#define FLASHSIZE_BASE ((uintptr_t)&stm32_test_flash_kib) /* Подменяет аппаратный density-register проверяемым значением в КиБ. */ +#define FLASH_BASE 0x08000000UL /* Сохраняет реальные адреса Cortex-M Flash в host-отображении. */ +#define FLASH_OPTR_DBANK 1U /* Независимый бит режима single/dual bank для геометрической проверки. */ +#define FLASH_OPTR_BFB2 2U /* Независимый бит запрещённого bank boot swap. */ +#define SYSCFG_MEMRMP_FB_MODE 1U /* Независимый бит запрещённого программного bank swap. */ +#define __HAL_RCC_SYSCFG_CLK_ENABLE() ((void)0) /* Host-регистр MEMRMP всегда доступен; реальный порт сам включает его clock. */ +#define FLASH_BANK_1 1U /* Выбирает первый физический Flash-банк в модели HAL. */ +#define FLASH_BANK_2 2U /* Выбирает второй физический Flash-банк в модели HAL. */ +#define FLASH_TYPEPROGRAM_DOUBLEWORD 3U /* Выбирает восьмибайтовую аппаратную запись G474. */ +typedef struct { FDCAN_GlobalTypeDef *Instance; struct { uint32_t ExtFiltersNbr; } Init; } FDCAN_HandleTypeDef; /* Повторяет проверяемый handle и число аппаратных extended-фильтров. */ +typedef struct { uint32_t Identifier, IdType, TxFrameType, DataLength, ErrorStateIndicator, BitRateSwitch, FDFormat, TxEventFifoControl; } FDCAN_TxHeaderTypeDef; /* Позволяет проверить classic extended TX и все используемые поля HAL. */ +typedef struct { uint32_t Identifier, IdType, RxFrameType, DataLength, FDFormat; } FDCAN_RxHeaderTypeDef; /* Позволяет подать неверный DLC, remote либо CAN FD кадр в настоящий RX adapter. */ +typedef struct { uint32_t IdType, FilterIndex, FilterType, FilterConfig, FilterID1, FilterID2; } FDCAN_FilterTypeDef; /* Сохраняет реальные адресные маски production-порта. */ +#define FDCAN_DLC_BYTES_0 (0U << 16U) /* Модель намеренно использует старое кодирование HAL DLC со сдвигом 16, в отличие от проверяемого ARM SDK. */ +#define FDCAN_DLC_BYTES_1 (1U << 16U) /* Один полезный октет в старом HAL-кодировании DLC. */ +#define FDCAN_DLC_BYTES_2 (2U << 16U) /* Два полезных октета в старом HAL-кодировании DLC. */ +#define FDCAN_DLC_BYTES_3 (3U << 16U) /* Три полезных октета в старом HAL-кодировании DLC. */ +#define FDCAN_DLC_BYTES_4 (4U << 16U) /* Четыре полезных октета в старом HAL-кодировании DLC. */ +#define FDCAN_DLC_BYTES_5 (5U << 16U) /* Пять полезных октетов в старом HAL-кодировании DLC. */ +#define FDCAN_DLC_BYTES_6 (6U << 16U) /* Шесть полезных октетов в старом HAL-кодировании DLC. */ +#define FDCAN_DLC_BYTES_7 (7U << 16U) /* Семь полезных октетов в старом HAL-кодировании DLC. */ +#define FDCAN_DLC_BYTES_8 (8U << 16U) /* Восемь полезных октетов в старом HAL-кодировании DLC. */ +#define FDCAN_EXTENDED_ID CAN_ID_EXT /* Объединяет входной формат тестовых сценариев bxCAN и FDCAN без изменения production-кода. */ +#define FDCAN_DATA_FRAME CAN_RTR_DATA /* Сохраняет значение обычного data-кадра для общей модели RX. */ +#define FDCAN_ESI_ACTIVE 0U /* Передатчик модели не находится в пассивном состоянии ошибок. */ +#define FDCAN_BRS_OFF 0U /* ProtoCAN Boot не переключает битовую скорость внутри кадра. */ +#define FDCAN_CLASSIC_CAN 0U /* Выбирает classic CAN вместо CAN FD. */ +#define FDCAN_NO_TX_EVENTS 0U /* Production-порт проверяет TXBTO, не используя отдельную TX Event FIFO. */ +#define FDCAN_FILTER_MASK 0U /* Фильтр сопоставляет ID и аппаратную маску адреса. */ +#define FDCAN_FILTER_TO_RXFIFO0 0U /* Оба разрешённых фильтра направляют сообщения в FIFO0. */ +#define FDCAN_RX_FIFO0 0U /* Загрузчик использует единственную входную FIFO0. */ +#define FDCAN_REJECT 2U /* Неподходящие стандартные и расширенные кадры должны отвергаться. */ +#define FDCAN_REJECT_REMOTE 1U /* Remote-запросы запрещены независимо от совпадения ID. */ +uint32_t HAL_FDCAN_GetTxFifoFreeLevel(const FDCAN_HandleTypeDef *can); /* Моделирует свободный либо постоянно занятый передатчик. */ +HAL_StatusTypeDef HAL_FDCAN_AddMessageToTxFifoQ(FDCAN_HandleTypeDef *can, const FDCAN_TxHeaderTypeDef *header, const uint8_t *data); /* Сохраняет безопасный TX payload и аппаратный результат. */ +uint32_t HAL_FDCAN_GetLatestTxFifoQRequestBuffer(const FDCAN_HandleTypeDef *can); /* Возвращает bitmask последнего поставленного TX-буфера. */ +uint32_t HAL_FDCAN_IsTxBufferMessagePending(const FDCAN_HandleTypeDef *can, uint32_t buffer); /* Удерживает запрос незавершённым для проверки тайм-аута перед reset. */ +HAL_StatusTypeDef HAL_FDCAN_AbortTxRequest(FDCAN_HandleTypeDef *can, uint32_t buffer); /* Фиксирует отмену неподтверждённой передачи. */ +HAL_StatusTypeDef HAL_FDCAN_ConfigFilter(FDCAN_HandleTypeDef *can, const FDCAN_FilterTypeDef *filter); /* Сохраняет два адресных фильтра G474. */ +HAL_StatusTypeDef HAL_FDCAN_ConfigGlobalFilter(FDCAN_HandleTypeDef *can, uint32_t standard, uint32_t extended, uint32_t remote_standard, uint32_t remote_extended); /* Проверяет запрет всех неразрешённых и remote кадров. */ +HAL_StatusTypeDef HAL_FDCAN_Start(FDCAN_HandleTypeDef *can); /* Позволяет имитировать отказ аппаратного старта. */ +uint32_t HAL_FDCAN_GetRxFifoFillLevel(const FDCAN_HandleTypeDef *can, uint32_t fifo); /* Передаёт число подготовленных модельных кадров. */ +HAL_StatusTypeDef HAL_FDCAN_GetRxMessage(FDCAN_HandleTypeDef *can, uint32_t fifo, FDCAN_RxHeaderTypeDef *header, uint8_t *data); /* Подаёт кадр в настоящий production RX adapter с кодированием DLC выбранного HAL. */ +#endif /* Завершает дополнительные типы и API модели G474. */ diff --git a/c/protocan-boot/tests/test_f2812_nor.c b/c/protocan-boot/tests/test_f2812_nor.c new file mode 100644 index 0000000..08ac4ff --- /dev/null +++ b/c/protocan-boot/tests/test_f2812_nor.c @@ -0,0 +1,83 @@ +#include "../ports/tms320f2812/boot2812.h" /* Проверяет реальные callbacks NOR и общий ProtoCAN codec в wide-octet режиме. */ +#include /* Любое нарушение границ, публикации или CRC завершает тест ошибкой. */ +#include /* Модель физической x16 памяти использует ровно 16 бит на слово даже на ПК. */ +#include /* Сообщает результат поведенческих сценариев без физического JTAG. */ +#include /* Подготавливает память и отдельные структуры C-ядра перед серией. */ +static uint16_t memory[0x80000]; /* AM29LV800BT содержит 512K слов x16, то есть 1 МиБ. */ +static unsigned int state, selected, bad_id, erases, programmed, busy_calls, loaded_words, stuck; /* Состояния относятся только к модели командной шины AMD. */ +static long budget = -1; /* Отрицательное значение разрешает записи, ноль моделирует исчезновение питания перед очередным word program. */ +static unsigned long clock_ms; /* Детерминированные часы позволяют проверить ограниченный выход из polling. */ +unsigned long Boot2812_Now(void) { return clock_ms++; } /* Продвигает миллисекунды без зависимости теста от wall clock ПК. */ +void Boot2812_Busy(void) { ++busy_calls; } /* Подтверждает, что длительное ожидание вызывает разрешённый сервис BUSY. */ +void NorModel_LoadWord(uint32_t target, unsigned int value) /* Получает только реальные записи валидатора в разрешённую RAM приложения. */ +{ /* Тестовый образ ниже содержит пять слов H0. */ + assert(target >= 0x3F8000UL && target < 0x3F8005UL); assert(value == 0U); ++loaded_words; /* Неверный адрес либо повреждённый payload не может скрыться в аппаратной заглушке. */ +} /* Запись в адресное пространство процесса ПК отсутствует. */ +unsigned int NorModel_Read(unsigned long word) /* Имитирует обычное чтение либо режим autoselect чипа. */ +{ /* Все обращения обязаны оставаться внутри установленной физической NOR. */ + assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Выход на соседнюю XINTF-память является ошибкой драйвера. */ + if (selected) return word == BOOT2812_NOR_BASE ? (bad_id ? 2U : 1U) : 0x22DAU; /* Модель отличает правильный AMD от неподходящего производителя. */ + if (stuck && word >= BOOT2812_IMAGE_WORD) return 0U; /* DQ7=0/DQ5=0 удерживают erase busy до программного тайм-аута. */ + return memory[word - BOOT2812_NOR_BASE]; /* Возвращает настоящие 16-битные данные модели. */ +} /* Чтение не выполняет скрытых записей и не исправляет повреждённые данные. */ +void NorModel_Write(unsigned long word, unsigned int value) /* Проверяет настоящий unlock state machine драйвера, а не принимает готовые запросы erase. */ +{ /* Командные адреса трактуются как x16 смещения согласно datasheet AMD. */ + assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Любой командный цикл ограничен физическим чипом. */ + if (state == 3U) { /* После A0 следующий цикл обязательно содержит программируемое слово данных. */ + if (budget != 0) { memory[word - BOOT2812_NOR_BASE] &= (uint16_t)value; ++programmed; if (budget > 0) --budget; } /* NOR программирует только переходы 1→0; обрыв питания оставляет прежнее слово. */ + state = 0U; return; /* Программирование одного слова завершает командную последовательность. */ + } /* Значение F0 в payload не должно ошибочно интерпретироваться как отдельная команда Reset. */ + if (value == 0xF0U) { state = selected = 0U; return; } /* Reset возвращает обычное чтение независимо от предыдущей незавершённой команды. */ + if (state == 0U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 1U; } /* Первый unlock-цикл проверяется вместе с адресом. */ + else if (state == 1U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 2U; } /* Второй цикл исключает ошибочную x8 адресацию. */ + else if (state == 2U) { /* Третий цикл выбирает только одну из поддерживаемых безопасных команд. */ + assert(word == BOOT2812_NOR_BASE + 0x555UL); /* Командный регистр находится по x16 смещению 555h. */ + if (value == 0x90U) { selected = 1U; state = 0U; } /* Autoselect не изменяет содержимое памяти. */ + else if (value == 0xA0U) state = 3U; /* Следующий цикл будет word program. */ + else { assert(value == 0x80U); state = 4U; } /* Стирание требует второй unlock-пары, а не одного произвольного слова. */ + } /* Завершает декодирование третьего такта AMD. */ + else if (state == 4U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 5U; } /* Проверяет четвёртый цикл Sector Erase. */ + else if (state == 5U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 6U; } /* Проверяет пятый цикл Sector Erase. */ + else { /* Шестой цикл выбирает только разрешённый отдельный сектор. */ + unsigned long count = word == BOOT2812_META_WORD ? 0x2000UL : 0x8000UL, i; /* Модель различает обычные и последние top-boot сектора. */ + assert(value == 0x30U); assert(word == BOOT2812_META_WORD || word == BOOT2812_IMAGE_WORD || word == BOOT2812_IMAGE_WORD + 0x8000UL || word == BOOT2812_IMAGE_WORD + 0x10000UL); /* Запрещает Chip Erase и любые соседние секторы legacy/FPGA. */ + for (i = 0; i < count; ++i) memory[word - BOOT2812_NOR_BASE + i] = 0xFFFFU; /* Реально стирает все слова выбранного сектора модели. */ + ++erases; state = 0U; /* Сохраняет число аппаратных sector erase для проверки отказов до разрушительных циклов. */ + } /* Завершает разрешённую операцию command bus. */ +} /* Модель не предоставляет драйверу обходного пути прямой записи массива. */ +static pcan_boot_byte_t image[40]; /* Небольшой полный SCI8: заголовок 22, секция 6+10, терминатор 2 октета. */ +static pcan_boot_manifest_t manifest; /* Metadata используют те же размеры и совместимость, что настоящий клиент. */ +static void make_image(void) /* Создаёт независимо определённый SCI8 с entry=3F8000 и пятью нулевыми словами H0. */ +{ /* Нулевой payload облегчает точную проверку каждого перенесённого слова. */ + memset(image, 0, sizeof(image)); image[0] = 0xAAU; image[1] = 8U; image[18] = 0x3FU; image[21] = 0x80U; image[22] = 5U; image[24] = 0x3FU; image[27] = 0x80U; /* Адрес TI передаётся старшим словом вперёд, внутри слова — little endian. */ + memset(&manifest, 0, sizeof(manifest)); manifest.image_size = 40UL; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); /* Начальная CRC вычисляется общим codec по независимому массиву файла. */ + manifest.product_type = BOOT2812_PRODUCT; manifest.hardware_revision_min = manifest.hardware_revision_max = 1U; /* Проверяет исключительно совместимый профиль F2812. */ +} /* Последующие сценарии меняют данные с новой CRC, чтобы отделить ошибки структуры от ошибок передачи. */ +static void save_image(void) /* Заполняет слоты через настоящие production callbacks, а не memcpy в образ. */ +{ /* Каждая порция соответствует одному восьмиоктетному CAN DATA. */ + unsigned int i; assert(Boot2812_Erase(0, 0U)); /* Перед каждой полной передачей удаляет marker и три полных сектора образа. */ + for (i = 0; i < 40U; i += 8U) assert(Boot2812_Write(0, 0U, i, image + i, 8U)); /* Проверяет упаковку октетов и readback каждого x16 слова. */ +} /* Только после завершения записи разрешены VERIFY и COMMIT. */ +int main(void) /* Проверяет драйвер, SCI8, publication и независимость соседних данных платы. */ +{ /* Все операции используют модель, физический CAN/JTAG не открывается. */ + unsigned long i; uint32_t entry; unsigned int before, cut; /* Счётчики контролируют защищённые диапазоны и обрывы manifest. */ + for (i = 0; i < 0x80000UL; ++i) memory[i] = 0x5AA5U; make_image(); /* Заполняет весь чип контрольным значением, включая старые данные и FPGA. */ + bad_id = 1U; before = erases; assert(!Boot2812_Erase(0, 0U) && erases == before); bad_id = 0U; /* Неподходящий производитель блокируется до первого sector erase. */ + assert(!Boot2812_NorErase(0x100000UL) && !Boot2812_NorErase(BOOT2812_IMAGE_WORD + 1UL)); /* Не разрешает старую область либо адрес внутри разрешённого сектора вместо его точного начала. */ + assert(!Boot2812_NorProgram(0x130000UL, 0U)); /* FPGA-образ запрещён даже при ошибочном прямом вызове нижнего драйвера. */ + save_image(); assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_OK); /* Реальный NOR readback и формат SCI8 должны совпасть с входом. */ + assert(!Boot2812_Load(&entry)); assert(Boot2812_Commit(0, 0U, &manifest)); loaded_words = 0U; assert(Boot2812_Load(&entry) && entry == 0x3F8000UL && loaded_words == 5U); /* До COMMIT загрузка запрещена, после него переносятся ровно проверенные слова H0. */ + before = programmed; assert(!Boot2812_NorProgram(BOOT2812_IMAGE_WORD, 0xFFFFU) && programmed == before); /* Перевод 0→1 отклоняется без лишней попытки аппаратного program. */ + for (cut = 0; cut <= 12U; ++cut) { /* Проверяет публикацию при обрыве на каждом месте manifest из двенадцати слов. */ + bool committed; save_image(); budget = (long)cut; committed = Boot2812_Commit(0, 0U, &manifest); budget = -1; /* Останавливает только циклы NOR word program, не подменяя механизм публикации. */ + loaded_words = 0U; assert(Boot2812_Load(&entry) == committed); /* Незавершённая публикация остаётся recovery; полностью опубликованный образ запускается. */ + } /* Предыдущие legacy-данные всё время остаются за пределами разрешённого erase. */ + save_image(); memory[BOOT2812_IMAGE_WORD - BOOT2812_NOR_BASE + 15UL] ^= 1U; assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_CRC_ERROR); /* Порча физической NOR обнаруживается независимо от принятой потоковой CRC. */ + make_image(); image[18] = 0U; image[21] = 0x90U; image[24] = 0U; image[27] = 0x90U; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); save_image(); /* Формирует целостную, но опасную секцию в L1 работающего загрузчика. */ + assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_INVALID_STATE && !Boot2812_Commit(0, 0U, &manifest)); /* Корректная CRC не разрешает перезапись очереди и состояния сессии. */ + make_image(); stuck = 1U; before = busy_calls; assert(!Boot2812_NorErase(BOOT2812_IMAGE_WORD) && busy_calls > before); stuck = 0U; /* Постоянный DQ7 busy даёт ограниченный отказ и вызывает живой сервис BUSY. */ + for (i = 0; i < 0x60000UL; ++i) assert(memory[i] == 0x5AA5U); /* Сохраняет весь нижний участок старого firmware, параметров и FPGA, а не одну контрольную точку. */ + for (i = 0x78000UL; i < 0x7E000UL; ++i) assert(memory[i] == 0x5AA5U); /* Промежуточные top-boot сектора 15/16/17 также не стираются. */ + puts("F2812 NOR: AMD commands, ID, bounds, CRC, SCI8, torn commit, timeout and legacy/FPGA preservation: OK"); /* Перечисляет программно проверенные свойства аппаратного порта. */ + return 0; /* Успех означает завершение всех граничных и отказных сценариев. */ +} /* Политика аппаратного boot/CPLD дополнительно проверяется на реальной плате. */ diff --git a/c/protocan-boot/tests/test_f28335_boot_store.c b/c/protocan-boot/tests/test_f28335_boot_store.c new file mode 100644 index 0000000..7c0fe34 --- /dev/null +++ b/c/protocan-boot/tests/test_f28335_boot_store.c @@ -0,0 +1,118 @@ +#define _CRT_SECURE_NO_WARNINGS +#include "../ports/tms320f28335/f28335_boot_store.h" +#include +#include +#include +static unsigned char eeprom[0x40000],backup[0x40000]; +static long budget=-1; +static int read_fail; +static unsigned written_words; +static bool read_mem(void *u,uint32_t addr,pcan_boot_byte_t *p,unsigned int n) +{ unsigned i; (void)u; assert(addr+n<=sizeof(eeprom)); if(read_fail) return false; + for(i=0;i0) --budget; eeprom[addr+i]=(unsigned char)p[i]; } + return true; } +static f28335_boot_io_t io={read_mem,write_mem,0}; +static pcan_boot_byte_t image[40]; +static pcan_boot_manifest_t manifest; +static void make_image(void) +{ + memset(image,0,sizeof(image)); image[0]=0xAA; image[1]=8; + image[20]=0; image[21]=0x80; /* entry=8000, high-word first */ + image[22]=5; image[26]=0; image[27]=0x80; + image[28]=0x34; image[29]=0x12; + memset(&manifest,0,sizeof(manifest)); manifest.product_type=0x2833; + manifest.hardware_revision_min=manifest.hardware_revision_max=1; + manifest.image_size=40; manifest.image_crc32=f28335_boot_crc(0,image,40); + manifest.firmware_version=0x01010002; +} +static void image_to(f28335_boot_store_t *s,unsigned slot) +{ unsigned i; assert(f28335_boot_prepare(s,slot)); + for(i=0;i<40;i+=8) assert(f28335_boot_write(s,slot,i,image+i,8)); } +static bool ram(void *u,uint32_t address,uint16_t word) +{ (void)u; assert(address==0x8000+written_words); if(!written_words) assert(word==0x1234); + ++written_words; return true; } +static void reopen(f28335_boot_store_t *s) { assert(f28335_boot_open(s,&io)); } +int main(int argc,char **argv) +{ + f28335_boot_store_t s; unsigned slot; uint32_t entry; long cut; + memset(eeprom,0xA5,sizeof(eeprom)); make_image(); reopen(&s); + assert(s.active==255 && !s.valid); assert(f28335_boot_select(&s,&slot) && slot==255); + image_to(&s,0); assert(f28335_boot_verify(&s,0,&manifest,&entry) && entry==0x8000); + assert(f28335_boot_commit(&s,0,&manifest)); + assert(!f28335_boot_confirm(&s,0)); /* Cannot confirm an image not yet started. */ + reopen(&s); assert(f28335_boot_select(&s,&slot) && slot==0 && s.attempted); + assert(f28335_boot_load(&s,slot,ram,0,&entry) && written_words==5); + assert(!f28335_boot_confirm(&s,1)); assert(f28335_boot_confirm(&s,0)); + assert(f28335_boot_confirm(&s,0)); /* idempotent */ + assert(!f28335_boot_prepare(&s,0)); + assert(!f28335_boot_write(&s,0,0,image,8)); + assert(!f28335_boot_write(&s,1,F28335_AB_SLOT_BYTES,image,8)); + image_to(&s,1); memcpy(backup,eeprom,sizeof(eeprom)); + /* Every torn write position in journal publication keeps confirmed A. */ + for(cut=0;cut<=68;++cut) { + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut; + (void)f28335_boot_commit(&s,1,&manifest); budget=-1; reopen(&s); + assert(s.active==0); assert(f28335_boot_verify(&s,0,&s.image[0],0)); + assert(s.pending==255 || s.pending==1); + } + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); assert(f28335_boot_commit(&s,1,&manifest)); + memcpy(backup,eeprom,sizeof(eeprom)); + /* Torn trial bookkeeping must never select an unrecorded trial. */ + for(cut=0;cut<=68;++cut) { + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut; + if(f28335_boot_select(&s,&slot)) { assert(slot==1); assert(s.attempted); } + budget=-1; reopen(&s); assert(s.active==0); + } + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); + assert(f28335_boot_select(&s,&slot) && slot==1); + reopen(&s); assert(f28335_boot_select(&s,&slot) && slot==0 && s.pending==255); + image_to(&s,1); assert(f28335_boot_commit(&s,1,&manifest)); + assert(f28335_boot_select(&s,&slot) && slot==1); + memcpy(backup,eeprom,sizeof(eeprom)); + for(cut=0;cut<=68;++cut) { + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); budget=cut; + (void)f28335_boot_confirm(&s,1); budget=-1; reopen(&s); + assert(s.active==0 || s.active==1); + assert(f28335_boot_select(&s,&slot) && (slot==0 || slot==1)); + } + memcpy(eeprom,backup,sizeof(eeprom)); reopen(&s); assert(f28335_boot_confirm(&s,1)); + /* CRC correct but malicious SCI8 destination and entry are rejected. */ + image_to(&s,0); image[26]=0; image[27]=0xE0; + manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); + image[27]=0x80; image[21]=0x90; manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); + make_image(); image[22]=1; image[30]=1; image[35]=0x80; + manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); /* overlapping sections */ + make_image(); image_to(&s,0); manifest.image_size=38; + manifest.image_crc32=f28335_boot_crc(0,image,38); + assert(!f28335_boot_verify(&s,0,&manifest,0)); /* missing terminator */ + make_image(); image[22]=4; manifest.image_crc32=f28335_boot_crc(0,image,40); + image_to(&s,0); assert(!f28335_boot_verify(&s,0,&manifest,0)); /* trailing octets */ + make_image(); image_to(&s,0); eeprom[F28335_AB_SLOT_A+29]^=1; + assert(!f28335_boot_verify(&s,0,&manifest,0)); + /* Failed EEPROM reads fail closed, including subsequent writes. */ + read_fail=1; assert(!f28335_boot_open(&s,&io)); + assert(!f28335_boot_prepare(&s,0)); assert(!f28335_boot_write(&s,0,0,image,8)); read_fail=0; + for(entry=0x3FE00;entry<0x40000;++entry) assert(eeprom[entry]==0xA5); + if(argc>1) { + FILE *file=fopen(argv[1],"rb"); uint32_t offset,crc=0; + pcan_boot_byte_t bytes[32]; unsigned n; + assert(file); make_image(); + manifest.image_size=(uint32_t)fread(eeprom+F28335_AB_SLOT_A,1,F28335_AB_SLOT_BYTES,file); + assert(!ferror(file) && fgetc(file)==EOF); fclose(file); reopen(&s); + for(offset=0;offset +#include +#include +void ServiceDog(void); +#include "../ports/tms320f28335/f28335_can_boot.c" +static unsigned char memory[0x40000]; +static unsigned int running=255,resets,reset_arg,dog_feeds; +static int fail_write; +static unsigned int write_calls; /* Счётчик аппаратных записей доказывает, что чужие CAN-команды не касаются EEPROM. */ +void ServiceDog(void) { ++dog_feeds; } +bool F28335Boot_Read(void *u,uint32_t a,pcan_boot_byte_t *p,unsigned int n) +{ unsigned i; (void)u; assert(a+n<=sizeof(memory)); for(i=0;i>(i*8))&255; } +static void address_isolation(void) /* Проверяет все 32 назначения Excel, аппаратный RX-фильтр и защиту записи от соседних плат. */ +{ /* Одна модель последовательно представляет каждый физический PERIPH и получает команды всем остальным. */ + unsigned int periph,peer,type,command_id,before=write_calls; /* Сохраняет счётчик записи до проверки, чтобы обнаружить любой побочный эффект чужого кадра. */ + for(periph=0U;periph<32U;++periph) { /* Покрывает обе границы Type 1/2 и все четырёхбитные Device ID. */ + F28335CanBoot_Init(periph); /* Тот же production Init используется RAM-приложением и Flash recovery. */ + assert(addressed && boot.config.device_type==1U+periph/16U && boot.config.device_id==periph%16U); /* Сверяет независимую ожидаемую раскладку Excel со всей конфигурацией устройства. */ + assert((ECanaMboxes.MBOX3.MSGID.all&0x07F00000UL)==((uint32_t)(1U+periph/16U)<<24|((uint32_t)(periph%16U)<<20))); /* Проверяет аппаратный фильтр, а не только программный parser. */ + for(peer=0U;peer<32U;++peer) { /* Включает пары задатчик↔УМП1/УМП2 и совпадающий Device ID в другом Type. */ + if(peer==periph) continue; /* Собственный адрес должен обслуживаться штатными сценариями ниже, поэтому здесь проверяются только чужие. */ + for(type=9U;type<=11U;++type) { /* Проверяет управляющий сервис и оба пространства данных слотов A/B. */ + for(command_id=2U;command_id<=9U;++command_id) { /* ENTER, метаданные, ERASE, VERIFY, COMMIT, CONFIRM и REBOOT должны игнорировать чужой адрес. */ + uint32_t id=pcan_boot_make_id(1,0,1U+peer/16U,peer%16U,type,type==9U?0x100U|command_id:0U); /* Формирует реальный 29-битный запрос соседнему PERIPH с ненулевой сессией. */ + assert(!pcan_boot_process(&boot,id,0,0)); /* Ядро не должно подтверждать или выполнять команду, адресованную другой плате. */ + ECanaRegs.CANRMP.all=8UL; ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|id; /* Моделирует доставку чужого кадра железом вопреки аппаратному фильтру. */ + ECanaMboxes.MBOX3.MSGCTRL.all=0U; ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0U; ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=0U; /* Исключает RTR как причину отказа, проверяя именно адрес. */ + F28335CanBoot_RxISR(); assert(head==0U && tail==0U && !tx_busy); /* Дополнительная ISR-защита не ставит чужую команду в очередь и не отправляет ответ. */ + } /* Завершает проверку изменяющих команд для выбранного пространства MsgType. */ + } /* Завершает проверку данных A/B и управляющего сервиса соседа. */ + } /* Переходит к следующему чужому номеру без перезаписи модели EEPROM. */ + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,7,9,0x102),0,0)); /* Прежний общий адрес 3/7 больше не разрешает вход в загрузчик ни одной платы. */ + } /* Заканчивает проверку уникальности всей таблицы PERIPH. */ + F28335CanBoot_Init(32U); assert(!addressed && !(ECanaRegs.CANME.all&88UL)); /* Недопустимый номер выключает Boot mailbox вместо перехода на общий адрес. */ + F28335CanBoot_Resume(1U); F28335CanBoot_Service(); assert(write_calls==before); /* Неверный адрес и все чужие команды не выполняют ни одной аппаратной записи. */ +} /* Последующие регрессии проверяют успешное обновление задатчика по адресу 1/8. */ +int main(void) +{ + pcan_boot_byte_t image[40]={0xAA,8},meta[8],compat[8]={0x33,0x28,1,1,2,0,1,1}; + unsigned i,slot; pcan_boot_manifest_t m; + memset(memory,0xA5,sizeof(memory)); image[21]=0x80; image[22]=5; image[27]=0x80; + address_isolation(); F28335CanBoot_Init(8U); assert(boot.config.max_image_size==130560 && boot.config.slot_count==2); /* Проверяет изоляцию всей шины перед штатной передачей задатчику. */ + if(!F28335_BOOT_LOADER) { + /* SPI-ROM application without Flash-loader handoff cannot erase anything. */ + command(2,0,0); assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE && !reset_requested); + running=F28335_BOOT_FLASH_SLOT; F28335CanBoot_Init(8U); /* Достоверный handoff постоянного boot разрешает CAN-сервис защищённому Flash-приложению. */ + assert(confirmed && F28335CanBoot_WatchdogAllowed()); /* Flash не выдаётся за неподтверждённый EEPROM-кандидат и сохраняет штатное обслуживание watchdog. */ + command(12,0,0); assert(!F28335CanBoot_Active()); /* Диагностический PING не должен открывать сеанс прошивки или удерживать обычный запуск. */ + command(2,0,0); assert(reset_requested && reset_session==1U && F28335CanBoot_Active()); /* ENTER_BOOT из Flash планирует переход с той же session без прямой записи EEPROM. */ + running=255U; F28335CanBoot_Init(8U); /* Возвращает исходный SPI-ROM сценарий перед прежними тестами trial/CONFIRM и отката. */ + memset(&m,0,sizeof(m));m.image_size=40;m.image_crc32=f28335_boot_crc(0,image,40); + m.product_type=0x2833;m.hardware_revision_min=m.hardware_revision_max=1; + assert(f28335_boot_prepare(&store,0)); + for(i=0;i<40;i+=8)assert(f28335_boot_write(&store,0,i,image+i,8)); + assert(f28335_boot_commit(&store,0,&m)); assert(f28335_boot_select(&store,&slot)); + running=0; F28335CanBoot_Init(8U); /* Пробное приложение сохраняет адрес задатчика после handoff постоянного загрузчика. */ + assert(!F28335CanBoot_WatchdogAllowed()); + command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE); + F28335CanBoot_Ready(); + for(i=0;i<100;++i) F28335CanBoot_Service(); + assert(!confirmed && store.pending==0); + CpuTimer1.InterruptCount=5000; F28335CanBoot_Service(); + assert(confirmed && store.active==0 && dog_feeds); + command(2,0,0); assert(reset_requested && reset_session==1 && boot.state==PCAN_BOOT_STATE_IDLE); + F28335CanBoot_Service();assert(resets==1 && reset_arg==1); + command(1,0,0);assert(ECanaMboxes.MBOX4.MDH.all==0x12345678UL); + } else { + command(2,0,0); put32(meta,40);put32(meta+4,f28335_boot_crc(0,image,40)); + command(3,meta,8);command(4,compat,8);assert(boot.target_slot==0); + command(5,0,0); + for(i=0;i<5;++i) { tx_busy=0; assert(pcan_boot_process(&boot, + pcan_boot_make_id(1,0,1,8,10,i),image+i*8,8)); } /* Данные первого слота передаются только адресу задатчика. */ + command(6,0,0);assert(boot.state==PCAN_BOOT_STATE_VERIFIED); + command(7,0,0);assert(store.pending==0 && boot.state==PCAN_BOOT_STATE_COMMITTED); + command(7,0,0);assert(boot.last_status==0); + command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE); + command(9,0,0);assert(reset_requested);tx_busy=0; + F28335CanBoot_Service();assert(resets==1 && reset_arg==0); + command(10,0,0);command(2,0,0);command(3,meta,8);command(4,compat,8); + command(5,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_FLASH_ERROR); /* Pending is protected. */ + } + command(12,0,0); assert((ECanaMboxes.MBOX4.MSGID.all&65535)==12); + command(13,0,0); assert(ECanaMboxes.MBOX4.MDH.all==130560); + meta[0]=0;command(14,meta,1); assert(ECanaMboxes.MBOX4.MDL.all==0x6164615AUL); /* Первые четыре октета ASCII имени Zadatchik равны «Zada». */ + meta[0]=3;command(15,meta,1);assert(ECanaMboxes.MBOX4.MDL.all==0x3FEFCUL); + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,1,6,9,0x102),0,0)); /* Адрес УМП2 1/6 не должен открывать сессию задатчика 1/8. */ + tx_busy=0; + assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),0,0)); + assert(boot.discovery_pending); pcan_boot_poll(&boot,boot.discovery_at); + assert(!boot.discovery_pending && (ECanaMboxes.MBOX4.MSGID.all&65535)==1); + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x102),0,0)); + head=tail=0; ECanaRegs.CANRMP.all=8; + ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|pcan_boot_make_id(1,0,1,8,9,12); /* Собственный PING задатчика проходит очередь после проверки чужих адресов. */ + ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0; + F28335CanBoot_RxISR(); assert(head==1 && tail==0); + tx_busy=0; F28335CanBoot_Service(); assert(tail==1); + ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=1; F28335CanBoot_RxISR(); assert(head==1); + ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=0; + overflow=1;tx_busy=0;F28335CanBoot_Service();assert(boot.state==PCAN_BOOT_STATE_IDLE); + /* An ACK arriving after cancellation must never execute a queued reset. */ + tx_busy=1;tx_canceling=0;reset_requested=1;sent_at=0; + CpuTimer1.InterruptCount=300;ECanaRegs.CANTA.all=0;ECanaRegs.CANAA.all=0; + F28335CanBoot_Service();assert(!reset_requested && tx_canceling); + ECanaRegs.CANTA.all=16; F28335CanBoot_Service();assert(!tx_busy && resets==1); + for(i=0x3FE00;i<0x40000;++i)assert(memory[i]==0xA5); + puts(F28335_BOOT_LOADER?"F28335 loader CAN services: OK":"F28335 application handoff/confirmation: OK"); + return 0; +} diff --git a/c/protocan-boot/tests/test_pcan_boot.c b/c/protocan-boot/tests/test_pcan_boot.c index d871412..259dcb9 100644 --- a/c/protocan-boot/tests/test_pcan_boot.c +++ b/c/protocan-boot/tests/test_pcan_boot.c @@ -264,7 +264,7 @@ static void test_rejects_wrong_session_and_compatibility(void) data[3] = 3U; put_u32(&data[4], 1U); assert(command(&boot, 7U, PCAN_BOOT_CMD_BEGIN_COMPAT, data, 8U)); - assert(fake.last_data[0] == PCAN_BOOT_STATUS_WRONG_HARDWARE); + assert(fake.last_data[0] == PCAN_BOOT_STATUS_WRONG_DEVICE); assert(boot.state == PCAN_BOOT_STATE_FAILED); } @@ -306,8 +306,41 @@ static void test_single_slot_update(void) assert(memcmp(fake.flash[0], image, sizeof(image)) == 0); } +static void test_services_timeout_and_retries(void) +{ + pcan_boot_t boot; fake_t fake; + uint8_t image[8]={0},compat[8]={0}; unsigned count; + setup(&boot,&fake); boot.config.session_timeout_ms=30000; + pcan_boot_poll(&boot,0xFFFFFF00UL); + assert(command(&boot,7,PCAN_BOOT_CMD_ENTER_BOOT,NULL,0)); + assert(command(&boot,8,PCAN_BOOT_CMD_ENTER_BOOT,NULL,0)); + assert(boot.session_id==7 && fake.last_data[0]==PCAN_BOOT_STATUS_BUSY); + assert(command(&boot,7,PCAN_BOOT_CMD_ERASE,image,1)); + assert(fake.last_data[0]==PCAN_BOOT_STATUS_INVALID_SIZE); + pcan_boot_poll(&boot,29743); assert(boot.state!=PCAN_BOOT_STATE_IDLE); + pcan_boot_poll(&boot,29744); assert(boot.state==PCAN_BOOT_STATE_IDLE); + assert(command(&boot,0,PCAN_BOOT_CMD_PING,NULL,0)); + assert(pcan_boot_id_msg_body(fake.last_id)==12); + count=fake.sends; + assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),NULL,0)); + assert(fake.sends==count); pcan_boot_poll(&boot,boot.discovery_at); + assert(fake.sends==count+1 && pcan_boot_id_msg_body(fake.last_id)==1); + assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x702),NULL,0)); + begin_update(&boot,image,8); + put_u16(compat,boot.manifest.product_type); + compat[2]=boot.manifest.hardware_revision_min; compat[3]=boot.manifest.hardware_revision_max; + put_u32(compat+4,boot.manifest.firmware_version); + assert(command(&boot,7,4,compat,8)); assert(fake.last_data[0]==0); + assert(command(&boot,7,5,NULL,0)); count=fake.erases; + assert(command(&boot,7,5,NULL,0)); assert(fake.erases==count && fake.last_data[0]==0); + assert(pcan_boot_process(&boot,request_id(PCAN_BOOT_MSG_DATA_B,0),image,8)); + assert(command(&boot,7,6,NULL,0)); assert(command(&boot,7,6,NULL,0)); assert(fake.last_data[0]==0); + assert(command(&boot,7,7,NULL,0)); assert(command(&boot,7,7,NULL,0)); assert(fake.last_data[0]==0); +} + int main(void) { + test_services_timeout_and_retries(); test_id_layout(); test_crc32_reference(); test_complete_update(); diff --git a/c/protocan-boot/tests/test_pcan_busy.c b/c/protocan-boot/tests/test_pcan_busy.c new file mode 100644 index 0000000..a7f0b72 --- /dev/null +++ b/c/protocan-boot/tests/test_pcan_busy.c @@ -0,0 +1,22 @@ +#include "../include/pcan_boot.h" /* Проверяет публичный BUSY codec и продление сессии на настоящем ядре. */ +#include /* Несовпадение состояния или wire-полей завершает тест ненулевым результатом. */ +#include /* Инициализирует опциональные поля конфигурации без аппаратных зависимостей. */ +static unsigned int status, body; /* Сохраняет наблюдаемые поля последнего настоящего STATUS кадра. */ +static bool send_frame(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Модель заменяет только физическую отправку CAN. */ +{ /* Содержимое статуса формирует production send_status, а не этот тест. */ + (void)user; assert(length == 8U && pcan_boot_id_msg_type(id) == 12U); status = data[0]; body = pcan_boot_id_msg_body(id); return true; /* Проверяет тип, длину и сохранённую session/command. */ +} /* Передача считается физически принятой аппаратным портом. */ +static bool erase(void *user, pcan_boot_byte_t slot) { (void)user; return slot == 0U; } /* Минимальный single-slot callback удовлетворяет обязательному контракту init. */ +static bool write_data(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) { (void)user; (void)offset; (void)data; return slot == 0U && length <= 8U; } /* Тест не программирует никакое реальное хранилище. */ +int main(void) /* Проверяет, что операция длиннее исходного session timeout остаётся живой при BUSY. */ +{ /* Без этой проверки длительный NOR erase мог бы закончиться уже отменённой сессией. */ + pcan_boot_t boot; pcan_boot_config_t config; pcan_boot_port_t port; /* Использует тот же экземпляр автомата, что аппаратные проекты. */ + memset(&config, 0, sizeof(config)); memset(&port, 0, sizeof(port)); config.slot_count = 1U; config.active_slot = 0U; config.session_timeout_ms = 30000UL; /* Сессия истекает через 30 секунд реального бездействия. */ + port.send = send_frame; port.erase_slot = erase; port.write_slot = write_data; assert(pcan_boot_init(&boot, &config, &port, 0)); /* Не обходит production валидацию обязательных callbacks. */ + assert(pcan_boot_process(&boot, pcan_boot_make_id(1U, 0U, 0U, 0U, 9U, 0x0102U), 0, 0U)); /* Открывает session=1 штатной командой ENTER_BOOT. */ + assert(pcan_boot_report_busy(&boot, 5U, 40000UL) && status == 1U && body == 0x0105U); /* BUSY долгого ERASE содержит исходную session и обновляет часы активности после сорока секунд. */ + pcan_boot_poll(&boot, 69999UL); assert(boot.state == PCAN_BOOT_STATE_METADATA); /* Почти 30 секунд после последнего BUSY ещё не означают тайм-аут. */ + pcan_boot_poll(&boot, 70000UL); assert(boot.state == PCAN_BOOT_STATE_IDLE); /* После полного интервала без прогресса сессия снова отменяется обычным способом. */ + assert(!pcan_boot_report_busy(0, 5U, 0UL)); /* Неинициализированный порт не должен вызывать аппаратный send. */ + return 0; /* Все проверки используют одно производственное ядро и его codec. */ +} /* Криптография и аппаратные сроки конкретной NOR не моделируются этим unit-тестом. */ diff --git a/c/protocan-boot/tests/test_project_release.py b/c/protocan-boot/tests/test_project_release.py new file mode 100644 index 0000000..3387f8d --- /dev/null +++ b/c/protocan-boot/tests/test_project_release.py @@ -0,0 +1,66 @@ +"""Проверки локального экспорта постоянных CAN-загрузчиков из CCS и CLI.""" # Аппаратное программирование и сеть в сценариях не используются. +import hashlib # Сверяет контрольные суммы экспортированных байтов OUT. +import importlib.util # Загружает настоящий сборщик проектов без запуска компиляции. +import json # Проверяет manifest, подготовку и указатель последнего выпуска. +from pathlib import Path # Все результаты проверок находятся во временных каталогах. +import tempfile # Изолирует тесты от пользовательских Debug/Release и SETGUI. +import unittest # Проверки запускаются штатным Python без Qt и дополнительных пакетов. +from unittest.mock import patch # Заменяет только аппаратный OFD-анализ тестового OUT, сохраняя настоящий экспорт и SHA-256. + +SPEC = importlib.util.spec_from_file_location("checked_canboot_projects", Path(__file__).resolve().parents[1] / "projects/build.py") # Выбирает сборщик из того же checkout templates. +BUILD = importlib.util.module_from_spec(SPEC) # Создаёт модуль без вызова CLI и без доступа к плате. +SPEC.loader.exec_module(BUILD) # Выполняет реальные функции prebuild/postbuild, проверяемые ниже. + + +class ProjectReleaseTests(unittest.TestCase): # Проверяет маршруты обоих контроллеров и отказ копирования при неполной или несогласованной сборке. + def test_current_out_map_and_hashes_are_exported_for_both_configurations(self): # Debug/Release F28335/F2812 обязаны экспортировать только свой комплект. + for device in ("f28335", "f2812"): # Покрывает отдельные имена OUT и каталоги двух контроллеров. + for configuration in ("Debug", "Release"): # Проверяет обе конфигурации каждого CCS-проекта. + with self.subTest(device=device, configuration=configuration), tempfile.TemporaryDirectory(prefix="canboot release ") as temporary: # Пробелы в путях проверяют передачу каталогов без shell-подстановок. + output = Path(temporary) / configuration; export = Path(temporary) / "SETGUI/canboot" / device[1:] # Тестовый SETGUI не затрагивает реальные файлы прошивок. + BUILD.prepare(device, configuration, BUILD.DEFAULT_COMPILER, output) # Настоящий prebuild сохраняет ревизию, конфигурацию и SHA исходников. + name = BUILD.settings(device, configuration, BUILD.DEFAULT_COMPILER)[1]; image = output / (name + ".out") # Имя артефакта читается из действующего CCS-проекта. + image.write_bytes(b"current OUT " + device.encode("ascii")); image.with_suffix(".map").write_text("current map", encoding="utf-8") # Создаёт различимые артефакты текущего выбранного контроллера. + (output / "unrelated.out").write_bytes(b"old build") # Старый соседний OUT не должен попасть в экспорт текущего выпуска. + with patch.object(BUILD, "verify", return_value={"entry_word": 1, "boot_word": 2, "loaded_words": 3}): # Модель заменяет лишь TI-декодирование искусственных байтов OUT. + BUILD.postbuild(device, configuration, BUILD.DEFAULT_COMPILER, output, export) # Архивирование, копирование и проверка SHA выполняются настоящим общим кодом. + receipt = json.loads((output / "firmware/latest_build.json").read_text(encoding="utf-8")); copied = Path(receipt["exported_directory"]) # Указатель должен вести на конкретный скопированный выпуск. + self.assertEqual(copied.parent, export) # F28335 и F2812 не смешиваются в одном каталоге контроллера. + self.assertEqual({file.name for file in copied.iterdir()}, {image.name, image.with_suffix(".map").name, image.name + ".manifest.json", image.name + ".sha256", "firmware_identity.json"}) # Экспорт содержит полный текущий комплект без старых OUT или объектных файлов. + self.assertEqual((copied / image.name).read_bytes(), image.read_bytes()) # OUT сохраняется побайтно, включая COFF-символы для JTAG. + manifest = json.loads((copied / (image.name + ".manifest.json")).read_text(encoding="utf-8")) # Проверяет внешний паспорт именно экспортированного файла. + self.assertEqual((manifest["device"], manifest["configuration"], manifest["purpose"]), (device, configuration, "canboot")) # Паспорт сохраняет выбранный контроллер, режим сборки и назначение загрузчика. + self.assertEqual(manifest["sha256"], hashlib.sha256(image.read_bytes()).hexdigest()) # Контрольная сумма относится к точным байтам OUT. + + def test_changed_sources_or_configuration_prevent_export(self): # Несогласованная подготовка не должна выпускать даже формально существующий OUT. + with tempfile.TemporaryDirectory() as temporary: # Изолирует изменение тестовых метаданных от реального prebuild. + output = Path(temporary) / "Debug"; export = Path(temporary) / "SETGUI" # Каталог назначения заранее отсутствует для явной проверки отказа копирования. + BUILD.prepare("f28335", "Debug", BUILD.DEFAULT_COMPILER, output) # Создаёт согласованный паспорт до моделируемого изменения исходников. + with patch.object(BUILD, "source_hashes", return_value={}): # Моделирует изменение дерева после подготовки без записи production-файлов. + with self.assertRaisesRegex(ValueError, "changed"): BUILD.postbuild("f28335", "Debug", BUILD.DEFAULT_COMPILER, output, export) # Несовпадение SHA останавливает выпуск до проверки и копирования OUT. + with self.assertRaisesRegex(ValueError, "changed"): BUILD.postbuild("f28335", "Release", BUILD.DEFAULT_COMPILER, output, export) # Debug-подготовку нельзя выдать за Release даже при одинаковых исходниках. + self.assertFalse(export.exists()) # Ошибочные подготовки не создают папку успешного выпуска в GUI. + + def test_missing_map_or_invalid_coff_prevent_export(self): # Наличие OUT без карты или с запрещёнными LOAD-адресами не разрешает экспорт. + with tempfile.TemporaryDirectory() as temporary: # Тестовые файлы удаляются вместе с изолированным каталогом. + output = Path(temporary) / "Debug"; export = Path(temporary) / "SETGUI" # Не использует аппаратные каталоги реальной установки. + BUILD.prepare("f2812", "Debug", BUILD.DEFAULT_COMPILER, output) # Сохраняет штатные входные данные выбранного F2812. + image = output / "F2812_CAN_NOR.out"; image.write_bytes(b"invalid COFF") # Искусственный OUT не должен считаться проверенным загрузчиком. + with self.assertRaisesRegex(ValueError, "MAP"): BUILD.postbuild("f2812", "Debug", BUILD.DEFAULT_COMPILER, output, export) # Отсутствие карты обнаруживается до запуска OFD. + image.with_suffix(".map").write_text("map", encoding="utf-8") # Дополняет комплект, чтобы отдельно проверить отказ COFF-анализа. + with patch.object(BUILD, "verify", side_effect=ValueError("invalid COFF")): # Моделирует диагностированный TI-декодером неверный образ. + with self.assertRaisesRegex(ValueError, "invalid COFF"): BUILD.postbuild("f2812", "Debug", BUILD.DEFAULT_COMPILER, output, export) # Неверные Flash-данные блокируются до любой публикации файлов. + self.assertFalse(export.exists()) # Ни один путь ошибки не оставляет ложный новый выпуск в SETGUI. + + def test_ccs_steps_match_device_and_configuration(self): # Проверяет все четыре реальные настройки Build Steps, которые вызывает CCS. + for device in ("f28335", "f2812"): # Отдельно проверяет маршруты 28335 и 2812. + for configuration in BUILD.ET.parse(BUILD.ROOT / "projects/ccs" / device / ".cproject").findall(".//configuration"): # Читает действующий XML, включая Debug и Release. + prepare = configuration.get("prebuildStep"); postbuild = configuration.get("postbuildStep") # Извлекает уже раскодированные XML-команды со штатными кавычками. + self.assertIn("--step prepare", prepare); self.assertIn("--step postbuild", postbuild) # Обе фазы обязаны вызывать общий сборщик в соответствующем режиме. + for command in (prepare, postbuild): # Контроллер и конфигурация должны совпадать на обеих фазах. + self.assertIn("--device " + device, command); self.assertIn("--configuration " + configuration.get("name"), command) # Предотвращает случайный паспорт другого проекта либо Debug вместо Release. + self.assertIn("balzam167/canboot/" + device[1:], postbuild) # Конечный каталог соответствует контроллеру постоянного загрузчика. + + +if __name__ == "__main__": # Импорт тестов не запускает их побочным эффектом. + unittest.main() # Поддерживает прямой запуск штатным Python из любого рабочего каталога. diff --git a/c/protocan-boot/tests/test_stm32_ports.c b/c/protocan-boot/tests/test_stm32_ports.c new file mode 100644 index 0000000..119e863 --- /dev/null +++ b/c/protocan-boot/tests/test_stm32_ports.c @@ -0,0 +1,259 @@ +#if defined(_WIN32) /* Windows требует VirtualAlloc для отображения Flash по настоящему адресу MCU. */ +#include /* Предоставляет выделение виртуальной памяти по фиксированному адресу. */ +#else /* POSIX использует аналогичное приватное отображение без файлов устройства. */ +#define _DEFAULT_SOURCE /* Разрешает MAP_ANONYMOUS при строгом режиме C99. */ +#include /* Предоставляет mmap и munmap для модели адресного пространства STM32. */ +#endif /* Завершает выбор host-платформы. */ +#include /* Останавливает проверку на первом нарушении границ или протокольного контракта. */ +#include /* Выводит компактный результат каждого семейного прогона. */ +#include /* Копирует данные модели Flash и сериализованные поля manifest. */ +#if defined(TEST_STM32F103) /* Один сценарий исполняется с настоящим семейным production-портом F1. */ +#include "../ports/stm32f103/pcan_boot_stm32f103.h" /* Подключает API проверяемого профиля STM32F103C8. */ +#define PORT_INIT pcan_boot_stm32f103_init /* Выбирает функцию настройки F103 без копирования сценариев. */ +#define PORT_POLL pcan_boot_stm32f103_poll /* Выбирает основной цикл транспорта F103. */ +#define PORT_VECTORS pcan_boot_stm32f103_vectors_valid /* Выбирает семейную проверку границ SRAM и Flash. */ +#define APP_BASE PCAN_BOOT_F103_APP_ADDRESS /* Берёт исходный адрес KONOR из production-заголовка. */ +#define APP_END PCAN_BOOT_F103_FLASH_END /* Берёт верхнюю границу штатной Flash F103C8. */ +#define RAM_TOP 0x20005000UL /* Тестовый MSP указывает за последним байтом 20 КиБ SRAM F103C8. */ +#define TEST_HANDLE CAN_HandleTypeDef /* F103 использует штатный bxCAN handle HAL. */ +#define TEST_INSTANCE CAN1 /* F103 проверяется с выделенным CAN1. */ +#elif defined(TEST_STM32G474) /* Третий прогон использует production FDCAN/Flash-порт G474. */ +#include "../ports/stm32g474/pcan_boot_stm32g474.h" /* Подключает готовый reusable G474-порт, а не boot main. */ +#define PORT_INIT pcan_boot_stm32g474_init /* Выбирает текущую настройку single-slot FDCAN-порта. */ +#define PORT_POLL pcan_boot_stm32g474_poll /* Выбирает обработку FDCAN FIFO0 и таймеров ядра. */ +#define PORT_VECTORS() pcan_boot_stm32g474_vectors_valid(CAN_BOOT_APP_SIZE) /* Сохраняет смысл структурной проверки всего профиля для общих сценариев. */ +#define APP_BASE CAN_BOOT_APP_ADDRESS /* G474 приложение начинается после исходных 32 КиБ загрузчика. */ +#define APP_END CAN_BOOT_FLASH_END /* Профиль G474 использует оставшиеся 480 КиБ Flash. */ +#define RAM_TOP 0x20014000UL /* Векторы исходного CANdle G474 ограничены основной используемой SRAM 80 КиБ. */ +#define TEST_HANDLE FDCAN_HandleTypeDef /* G474 использует современный FDCAN handle вместо bxCAN. */ +#define TEST_INSTANCE FDCAN1 /* Проверяется только выделенный FDCAN1 исходной платы. */ +#else /* Второй прогон компилирует те же сценарии с настоящим F407-портом. */ +#include "../ports/stm32f407/pcan_boot_stm32f407.h" /* Подключает API профиля climate. */ +#define PORT_INIT pcan_boot_stm32f407_init /* Выбирает функцию настройки F407. */ +#define PORT_POLL pcan_boot_stm32f407_poll /* Выбирает основной цикл транспорта F407. */ +#define PORT_VECTORS pcan_boot_stm32f407_vectors_valid /* Выбирает проверку векторов F407. */ +#define APP_BASE PCAN_BOOT_F407_APP_ADDRESS /* Берёт начало сектора 2 из production-заголовка. */ +#define APP_END PCAN_BOOT_F407_FLASH_END /* Исключает EEPROM-кольцо секторов 6 и 7. */ +#define RAM_TOP 0x20020000UL /* Тестовый MSP указывает за последним байтом основной SRAM F407. */ +#define TEST_HANDLE CAN_HandleTypeDef /* F407 использует штатный bxCAN handle HAL. */ +#define TEST_INSTANCE CAN1 /* F407 проверяется с выделенным CAN1. */ +#endif /* Завершает выбор проверяемой аппаратной реализации. */ +CAN_TypeDef stm32_test_can; /* Эмулирует регистр подтверждения TX, читаемый production-кодом. */ +static uint8_t *flash; /* Ссылается на host-отображение физического диапазона Flash STM32. */ +static uint32_t tick, sends, resets, aborted, erases, writes; /* Считает время и аппаратные эффекты сценария. */ +static bool unlocked, fail_erase, fail_write, corrupt_write, no_mailbox, pending, tx_error, fail_start; /* Управляет воспроизводимыми отказами HAL. */ +static uint8_t last_tx[8], rx_bytes[8]; /* Хранит полный безопасно скопированный TX и единственный входной payload. */ +static CAN_RxHeaderTypeDef rx_header; /* Содержит входной IDE/RTR/DLC для проверок транспортного адаптера. */ +static CAN_FilterTypeDef filters[2]; /* Фиксирует адресный и broadcast-discovery фильтры. */ +static bool have_rx; /* Моделирует наличие одного доступного кадра FIFO0. */ +static bool cache_dirty; /* Фиксирует необходимость синхронизации Flash-кэша F407 после HAL program. */ +#if defined(TEST_STM32G474) /* Расширяет общую модель только для FDCAN/двухбанковой Flash G474. */ +FLASH_TypeDef stm32_test_flash; SYSCFG_TypeDef stm32_test_syscfg; FDCAN_GlobalTypeDef stm32_test_fdcan; uint16_t stm32_test_flash_kib; /* Предоставляет production-коду безопасные регистры геометрии и TX. */ +static bool dual_bank; /* Перебирает оба штатных DBANK-режима одного физического G474VE 512 КиБ. */ +uint32_t HAL_FDCAN_GetTxFifoFreeLevel(const FDCAN_HandleTypeDef *can) { (void)can; return no_mailbox ? 0U : 3U; } /* Воспроизводит ожидание свободного аппаратного TX FIFO. */ +HAL_StatusTypeDef HAL_FDCAN_AddMessageToTxFifoQ(FDCAN_HandleTypeDef *can, const FDCAN_TxHeaderTypeDef *header, const uint8_t *data) /* Проверяет настоящий TX adapter G474 с иным кодированием DLC HAL. */ +{ /* Все восемь доступных байтов payload обязан подготовить production-порт. */ + assert(can->Instance == FDCAN1 && header->IdType == FDCAN_EXTENDED_ID && header->TxFrameType == FDCAN_DATA_FRAME && header->FDFormat == FDCAN_CLASSIC_CAN && header->DataLength <= FDCAN_DLC_BYTES_8); /* Не допускает случайный CAN FD, standard или некорректный DLC. */ + (void)memcpy(last_tx, data, 8U); can->Instance->TXBTO = tx_error ? 0U : 1U; ++sends; return HAL_OK; /* Имитирует отдельный TXBTO и проверяет запрет reset при отсутствии подтверждённой передачи. */ +} /* Завершает модель передачи FDCAN. */ +uint32_t HAL_FDCAN_GetLatestTxFifoQRequestBuffer(const FDCAN_HandleTypeDef *can) { (void)can; return 1U; } /* Выбирает bitmask первого TX-буфера, как реальный API HAL. */ +uint32_t HAL_FDCAN_IsTxBufferMessagePending(const FDCAN_HandleTypeDef *can, uint32_t buffer) { (void)can; assert(buffer == 1U); return pending; } /* Позволяет проверить тайм-аут именно поставленного TX-запроса. */ +HAL_StatusTypeDef HAL_FDCAN_AbortTxRequest(FDCAN_HandleTypeDef *can, uint32_t buffer) { (void)can; assert(buffer == 1U); ++aborted; return HAL_OK; } /* Считает отменённые после тайм-аута кадры. */ +HAL_StatusTypeDef HAL_FDCAN_ConfigFilter(FDCAN_HandleTypeDef *can, const FDCAN_FilterTypeDef *filter) { (void)can; assert(filter->FilterIndex < 2U); filters[filter->FilterIndex].FilterBank = filter->FilterIndex; filters[filter->FilterIndex].FilterMaskIdHigh = (filter->FilterID2 << 3U) >> 16U; return HAL_OK; } /* Сохраняет аппаратные маски адреса и discovery для общих проверок. */ +HAL_StatusTypeDef HAL_FDCAN_ConfigGlobalFilter(FDCAN_HandleTypeDef *can, uint32_t standard, uint32_t extended, uint32_t remote_standard, uint32_t remote_extended) { (void)can; assert(standard == FDCAN_REJECT && extended == FDCAN_REJECT && remote_standard == FDCAN_REJECT_REMOTE && remote_extended == FDCAN_REJECT_REMOTE); return HAL_OK; } /* Не позволяет broad фильтрации обойти проверку адресов и remote-кадров. */ +HAL_StatusTypeDef HAL_FDCAN_Start(FDCAN_HandleTypeDef *can) { (void)can; return fail_start ? HAL_ERROR : HAL_OK; } /* Воспроизводит отказ аппаратного запуска FDCAN. */ +uint32_t HAL_FDCAN_GetRxFifoFillLevel(const FDCAN_HandleTypeDef *can, uint32_t fifo) { (void)can; assert(fifo == FDCAN_RX_FIFO0); return have_rx; } /* Сообщает наличие подготовленного общего тестового RX-кадра. */ +HAL_StatusTypeDef HAL_FDCAN_GetRxMessage(FDCAN_HandleTypeDef *can, uint32_t fifo, FDCAN_RxHeaderTypeDef *header, uint8_t *data) { (void)can; (void)fifo; header->Identifier = rx_header.ExtId; header->IdType = rx_header.IDE; header->RxFrameType = rx_header.RTR; header->DataLength = rx_header.DLC << 16U; header->FDFormat = FDCAN_CLASSIC_CAN; (void)memcpy(data, rx_bytes, 8U); have_rx = false; return HAL_OK; } /* Проверяет decoder старого shifted-DLC HAL на тех же ошибочных входах, что bxCAN. */ +#endif /* Завершает аппаратную модель только для G474. */ +uint32_t HAL_GetTick(void) { return tick++; } /* Продвигает время даже в синхронном ожидании TX для воспроизводимого тайм-аута. */ +uint32_t HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *can) { (void)can; return no_mailbox ? 0U : 3U; } /* Имитирует свободный либо постоянно занятый TX. */ +HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *can, CAN_TxHeaderTypeDef *header, uint8_t *data, uint32_t *mailbox) /* Захватывает ответ и состояние завершения его передачи. */ +{ /* Реальный codec и сборка payload остаются в production-коде. */ + assert(can->Instance == CAN1 && header->IDE == CAN_ID_EXT && header->RTR == CAN_RTR_DATA && header->DLC <= 8U); /* Проверяет аппаратный формат каждого ответа. */ + assert(can->Instance->TSR == (CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2)); /* До передачи порт обязан очистить старые TXOK/ошибки аппаратной записью W1C. */ + (void)memcpy(last_tx, data, sizeof(last_tx)); /* Восемь доступных байтов гарантирует локальный TX-буфер порта. */ + *mailbox = CAN_TX_MAILBOX0; /* Выбирает первый mailbox с известным TXOK-флагом. */ + can->Instance->TSR = tx_error ? 0U : CAN_TSR_TXOK0; /* Различает успешную передачу и снятый без ACK запрос. */ + ++sends; /* Фиксирует факт постановки кадра в передатчик. */ + return HAL_OK; /* Модель успешно приняла параметры аппаратной передачи. */ +} /* Завершает модель отправки кадра. */ +uint32_t HAL_CAN_IsTxMessagePending(CAN_HandleTypeDef *can, uint32_t mailbox) { (void)can; (void)mailbox; return pending; } /* Удерживает TX незавершённым для проверки запрета reset. */ +HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *can, uint32_t mailbox) { (void)can; (void)mailbox; ++aborted; return HAL_OK; } /* Считает отменённые после тайм-аута запросы. */ +HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *can, CAN_FilterTypeDef *filter) { (void)can; assert(filter->FilterBank < 2U); filters[filter->FilterBank] = *filter; return HAL_OK; } /* Проверяет владение только двумя заявленными банками. */ +HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *can) { (void)can; return fail_start ? HAL_ERROR : HAL_OK; } /* Даёт воспроизводимый отказ аппаратного запуска. */ +uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *can, uint32_t fifo) { (void)can; assert(fifo == CAN_RX_FIFO0); return have_rx; } /* Сообщает наличие подготовленного кадра. */ +HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *can, uint32_t fifo, CAN_RxHeaderTypeDef *header, uint8_t *data) { (void)can; (void)fifo; *header = rx_header; (void)memcpy(data, rx_bytes, 8U); have_rx = false; return HAL_OK; } /* Передаёт кадр через настоящий путь RX порта. */ +HAL_StatusTypeDef HAL_FLASH_Unlock(void) { unlocked = true; return HAL_OK; } /* Разрешает последующие модельные erase и program. */ +HAL_StatusTypeDef HAL_FLASH_Lock(void) { unlocked = false; return HAL_OK; } /* Восстанавливает аппаратную блокировку модели. */ +HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *erase, uint32_t *error) /* Моделирует геометрию стирания без изменения самого алгоритма порта. */ +{ /* Любое пересечение загрузчика либо резервной памяти немедленно проваливает тест. */ + uint32_t start, end; /* Вычисляет физический диапазон выбранной операции HAL. */ + assert(unlocked); /* Запрещает erase до аппаратной разблокировки. */ +#if defined(TEST_STM32F103) /* Проверяет 1-КиБ страницы среднего семейства F103. */ + assert(erase->TypeErase == FLASH_TYPEERASE_PAGES && erase->NbPages != 0U); /* Исключает подмену на mass erase. */ + start = erase->PageAddress; end = start + erase->NbPages * 1024U; /* Воспроизводит диапазон HAL page erase в байтах. */ +#elif defined(TEST_STM32G474) /* Проверяет физические страницы обоих банков G474. */ + uint32_t page_size = dual_bank ? 2048U : 4096U, bank_size = dual_bank ? 262144U : 524288U; /* Независимая геометрия по выбранному DBANK-режиму. */ + assert(erase->TypeErase == FLASH_TYPEERASE_PAGES && erase->NbPages == 1U && erase->Banks >= FLASH_BANK_1 && erase->Banks <= (dual_bank ? FLASH_BANK_2 : FLASH_BANK_1)); /* Не допускает второго физического банка в single-bank конфигурации. */ + start = FLASH_BASE + (erase->Banks == FLASH_BANK_2 ? bank_size : 0U) + erase->Page * page_size; end = start + page_size; /* Независимо восстанавливает физический диапазон erase из номера банка и страницы. */ +#else /* Проверяет конкретные секторы STM32F407. */ + static const uint32_t bounds[] = {0x08008000UL, 0x0800C000UL, 0x08010000UL, 0x08020000UL, 0x08040000UL}; /* Независимая карта физических границ секторов 2..5 из исходного climate. */ + assert(erase->TypeErase == FLASH_TYPEERASE_SECTORS && erase->Sector >= 2U && erase->Sector <= 5U && erase->NbSectors == 1U && erase->VoltageRange == FLASH_VOLTAGE_RANGE_3); /* Исключает загрузчик, EEPROM-кольцо и неверную разрядность Flash. */ + start = bounds[erase->Sector - 2U]; end = bounds[erase->Sector - 1U]; /* Определяет полный стираемый сектор по его физическому номеру. */ +#endif /* Завершает проверку геометрии семейства. */ + assert(start >= APP_BASE && end <= APP_END); /* Проверяет границы до обращения к host-памяти. */ + *error = 0U; ++erases; tick += 2000U; /* Воспроизводит длительный erase, превышающий короткий тайм-аут сессии. */ + if (fail_erase) return HAL_ERROR; /* Модель аппаратного отказа не должна оставить Flash разблокированной. */ + (void)memset((void *)(uintptr_t)start, 0xFF, end - start); /* Стирает только разрешённые реальные байты модели. */ + return HAL_OK; /* Выбранные страницы или сектор успешно очищены. */ +} /* Завершает независимую модель аппаратного erase. */ +HAL_StatusTypeDef HAL_FLASH_Program(uint32_t type, uint32_t address, uint64_t value) /* Программирует только выровненную аппаратную единицу. */ +{ /* Чтение результата выполняется настоящим production-кодом через тот же адрес. */ + uint32_t size = type == FLASH_TYPEPROGRAM_HALFWORD ? 2U : 4U; /* Различает аппаратные единицы F103 и F407. */ +#if defined(TEST_STM32G474) /* G474 программируется аппаратными doubleword, а не словами F4. */ + assert(type == FLASH_TYPEPROGRAM_DOUBLEWORD); size = 8U; /* Исключает неверную разрядность записи ECC Flash G474. */ +#endif /* Завершает выбор аппаратной единицы модели программирования. */ + assert(unlocked && address >= APP_BASE && address <= APP_END - size && address % size == 0U); /* Не допускает пересечения Flash-профиля или неверного выравнивания. */ + assert(!cache_dirty); /* Следующая запись не должна скрыть пропущенную синхронизацию предыдущего Flash readback. */ + ++writes; /* Считает обращения к реальному программированию HAL. */ + if (fail_write) return HAL_ERROR; /* Имитирует отказ до изменения данных. */ + (void)memcpy((void *)(uintptr_t)address, &value, size); /* Сохраняет именно аппаратно записанное полуслово либо слово. */ +#if !defined(TEST_STM32F103) && !defined(TEST_STM32G474) /* Только F407 требует явного flush от вызывающего порта; HAL G4 выполняет его внутри Program. */ + cache_dirty = true; /* Следующий readback требует семейного вызова FLASH_FlushCaches. */ +#endif /* Завершает моделирование необходимости синхронизации F407. */ + if (corrupt_write) *(uint8_t *)(uintptr_t)address ^= 1U; /* Вызывает readback-ошибку при формальном успехе HAL. */ + return HAL_OK; /* Даёт production-коду независимо перечитать память. */ +} /* Завершает модель программирования Flash. */ +void FLASH_FlushCaches(void) { cache_dirty = false; } /* Обновляет модель видимости записанных слов F407 перед последующим readback. */ +void NVIC_SystemReset(void) { ++resets; } /* Считает reset только после успешного ACK команды REBOOT. */ +static void put32(uint8_t *out, uint32_t value) /* Сериализует поля образа независимо от host-endian. */ +{ /* ProtoCAN manifest и Cortex-M векторы используют младший байт первым. */ + out[0] = (uint8_t)value; out[1] = (uint8_t)(value >> 8U); out[2] = (uint8_t)(value >> 16U); out[3] = (uint8_t)(value >> 24U); /* Записывает четыре октета little-endian без невыровненного доступа. */ +} /* Завершает тестовую сериализацию 32-битного поля. */ +static bool command(pcan_boot_stm32_t *port, uint8_t cmd, const uint8_t *data, uint8_t dlc) /* Отправляет адресную команду в настоящую state machine. */ +{ /* Сессия 9 и адрес 3:5 являются тестовыми значениями и не задают адрес рабочего устройства. */ + return pcan_boot_process(&port->boot, pcan_boot_make_id(1U, 0U, 3U, 5U, PCAN_BOOT_MSG_CONTROL, (uint16_t)(0x0900U | cmd)), data, dlc); /* Формирует SessionID в старшем октете Body и команду в младшем. */ +} /* Завершает подачу адресной команды. */ +static void setup(pcan_boot_stm32_t *port, TEST_HANDLE *can) /* Подготавливает независимое начальное состояние перед каждым сценарием. */ +{ /* Память вне приложения заполнена сторожевым значением для обнаружения повреждений. */ + pcan_boot_config_t config = {0}; /* Исключает влияние полей новых версий общего API. */ + tick = sends = resets = aborted = erases = writes = 0U; /* Сбрасывает наблюдаемые эффекты предыдущего сценария. */ + unlocked = fail_erase = fail_write = corrupt_write = no_mailbox = pending = tx_error = fail_start = have_rx = false; /* Возвращает все аппаратные отказы в исходное состояние. */ + cache_dirty = false; /* Новая сессия начинается без устаревшего cache-состояния предыдущей проверки. */ + (void)memset(flash, 0xA5, 0x81000U); /* Сторожевое заполнение покрывает все 512 КиБ Flash и сторожевую страницу после физического конца. */ + config.device_type = 3U; config.device_id = 5U; config.ack_window = 1U; config.session_timeout_ms = 1000U; /* Выбирает адрес и сессию короче модельного стирания. */ +#if defined(TEST_STM32G474) /* Подготавливает независимую физическую геометрию G474 для каждого сценария. */ + stm32_test_flash.OPTR = dual_bank ? FLASH_OPTR_DBANK : 0U; stm32_test_syscfg.MEMRMP = 0U; stm32_test_flash_kib = 512U; can->Init.ExtFiltersNbr = 2U; /* Сохраняет выбранный DBANK и выделяет два аппаратных extended-фильтра. */ +#endif /* Завершает подготовку FDCAN/Flash G474. */ + assert(PORT_INIT(port, can, &config)); /* Проверяет настоящую настройку single-slot, callbacks и двух фильтров. */ + assert(port->boot.config.slot_count == 1U && port->boot.config.active_slot == 0U && port->boot.config.max_image_size == APP_END - APP_BASE); /* Исключает возврат старой фиктивной A/B-конфигурации. */ +} /* Завершает подготовку сценария. */ +static void begin(pcan_boot_stm32_t *port, const uint8_t *image, uint32_t size) /* Открывает полную сессию с двумя частями manifest и стиранием. */ +{ /* Все ограничения проверяет общий production-автомат. */ + uint8_t metadata[8] = {0}; /* Product/HW/FW тестового устройства равны нулю. */ + assert(command(port, PCAN_BOOT_CMD_ENTER_BOOT, NULL, 0U)); /* Открывает адресную сессию 9. */ + put32(metadata, size); put32(metadata + 4U, pcan_boot_crc32_update(0U, image, size)); /* Передаёт полезную длину и ожидаемый CRC без хвоста FF. */ + assert(command(port, PCAN_BOOT_CMD_BEGIN_IMAGE, metadata, 8U)); /* Передаёт первую часть manifest. */ + (void)memset(metadata, 0, sizeof(metadata)); /* Очищает поля для части совместимости. */ + assert(command(port, PCAN_BOOT_CMD_BEGIN_COMPAT, metadata, 8U)); /* Передаёт совпадающий Product и диапазон HW. */ + assert(command(port, PCAN_BOOT_CMD_ERASE, NULL, 0U)); /* Вызывает настоящую семейную процедуру стирания. */ + assert(port->boot.state == PCAN_BOOT_STATE_RECEIVING && !unlocked); /* Стирание завершилось и Flash снова защищена. */ + PORT_POLL(port); /* Проверяет, что двухсекундный erase не погасил секундную сессию. */ + assert(port->boot.state == PCAN_BOOT_STATE_RECEIVING); /* Финальное обновление BUSY обязано продлить сессию после Flash stall. */ +} /* Завершает подготовку к передаче блоков образа. */ +static void upload(pcan_boot_stm32_t *port, const uint8_t *image, uint32_t size) /* Передаёт образ через общий decoder восьмибайтовых CAN-блоков. */ +{ /* Последний блок всегда имеет DLC=8, а аппаратный порт получает только полезный остаток. */ + uint32_t offset; /* Считает смещение полезных данных в байтах. */ + for (offset = 0U; offset < size; offset += 8U) { /* Повторяет реальное блочное поведение ProtoCAN Boot. */ + uint8_t block[8]; uint32_t count = size - offset; /* Выделяет полный payload и вычисляет фактический остаток. */ + if (count > 8U) count = 8U; /* Не читает за границей переданного тестового образа. */ + (void)memset(block, 0xFF, 8U); (void)memcpy(block, image + offset, count); /* Формирует wire-дополнение последнего кадра FF. */ + assert(pcan_boot_process(&port->boot, pcan_boot_make_id(1U, 0U, 3U, 5U, PCAN_BOOT_MSG_DATA_A, (uint16_t)(offset / 8U)), block, 8U)); /* Вызывает production-запись выбранного логического слота A. */ + assert(port->boot.state == PCAN_BOOT_STATE_RECEIVING && !unlocked && !cache_dirty); /* Каждый подтверждённый блок обязан оставить Flash защищённой и кэш синхронизированным. */ + } /* Завершает передачу образа. */ +} /* Завершает helper загрузки без обхода протокольной state machine. */ +static void test_update_and_tails(TEST_HANDLE *can) /* Проверяет все возможные остатки аппаратных полуслов/слов и полный COMMIT/REBOOT. */ +{ /* Размеры 16..23 покрывают все восемь вариантов последнего CAN-блока. */ + uint32_t size; /* Перебирает длины полезного образа в байтах. */ + for (size = 16U; size < 24U; ++size) { /* В каждом случае создаёт отдельную сессию обновления. */ + pcan_boot_stm32_t port; uint8_t image[24] = {0}; /* Изолирует состояние и небольшой образ с корректными векторами. */ + setup(&port, can); put32(image, RAM_TOP); put32(image + 4U, APP_BASE + 9U); /* Reset handler указывает внутрь образа, MSP лежит на верхней границе SRAM. */ + begin(&port, image, size); upload(&port, image, size); /* Выполняет реальную последовательность erase и DATA. */ + assert(memcmp((const void *)(uintptr_t)APP_BASE, image, size) == 0 && PORT_VECTORS()); /* Проверяет фактические байты Flash и векторы после программирования. */ + assert(*(uint8_t *)(uintptr_t)(APP_BASE + size) == 0xFFU); /* За полезной длиной остаётся FF, включая дополнение последней аппаратной единицы записи. */ + assert(*(uint8_t *)(uintptr_t)(APP_BASE - 1U) == 0xA5U && *(uint8_t *)(uintptr_t)APP_END == 0xA5U); /* Доказывает сохранность загрузчика и памяти сразу за приложением. */ + assert(command(&port, PCAN_BOOT_CMD_REBOOT, NULL, 0U) && resets == 0U); /* Запрещает reset до VERIFY и COMMIT даже при корректных векторах. */ + assert(command(&port, PCAN_BOOT_CMD_VERIFY, NULL, 0U) && port.boot.state == PCAN_BOOT_STATE_VERIFIED); /* Проверяет CRC именно прочитанной Flash. */ + assert(command(&port, PCAN_BOOT_CMD_COMMIT, NULL, 0U) && port.ready); /* Разрешает активацию проверенного образа. */ + pending = true; assert(!command(&port, PCAN_BOOT_CMD_REBOOT, NULL, 0U) && resets == 0U && aborted == 1U); /* Незавершённый TX ответа не должен вызвать reset. */ + pending = false; tx_error = true; assert(!command(&port, PCAN_BOOT_CMD_REBOOT, NULL, 0U) && resets == 0U); /* Снятый с ошибкой mailbox также не подтверждает отправку ACK. */ + tx_error = false; assert(command(&port, PCAN_BOOT_CMD_REBOOT, NULL, 0U) && resets == 1U); /* Подтверждённый TX допускает ровно один CMSIS reset. */ + } /* Завершает перебор всех хвостов последнего CAN-блока. */ +} /* Завершает основной end-to-end сценарий обновления. */ +static void test_failures_and_transport(TEST_HANDLE *can) /* Проверяет повреждения Flash, пограничные входы и фильтрацию внешних кадров. */ +{ /* Набор ошибок использует те же production-callbacks, что MCU. */ + pcan_boot_stm32_t port; uint8_t image[16] = {0}, one = 0x5AU; uint32_t before; /* Подготавливает минимальный образ и однобайтовый служебный payload. */ + setup(&port, can); put32(image, RAM_TOP); put32(image + 4U, APP_BASE + 9U); begin(&port, image, 16U); upload(&port, image, 16U); /* Записывает корректный образ для независимой проверки повреждения. */ + *(uint8_t *)(uintptr_t)(APP_BASE + 12U) ^= 1U; /* Имитирует повреждение Flash после успешного получения потока. */ + assert(command(&port, PCAN_BOOT_CMD_VERIFY, NULL, 0U) && port.boot.last_status == PCAN_BOOT_STATUS_CRC_ERROR && !port.ready); /* CRC потока остаётся верным, но readback обязан выявить ошибку. */ + setup(&port, can); put32(image + 4U, APP_BASE + 33U); begin(&port, image, 16U); upload(&port, image, 16U); /* Создаёт корректный CRC, но reset handler находится за фактическим образом. */ + assert(PORT_VECTORS() && command(&port, PCAN_BOOT_CMD_VERIFY, NULL, 0U) && port.boot.last_status == PCAN_BOOT_STATUS_INVALID_SIZE); /* Проверка диапазона профиля не заменяет проверку точной длины manifest. */ + put32((uint8_t *)(uintptr_t)APP_BASE, RAM_TOP - 1U); assert(!PORT_VECTORS()); /* Отвергает невыровненный начальный стек внутри допустимой SRAM. */ + put32((uint8_t *)(uintptr_t)APP_BASE, 0x20000000UL); assert(!PORT_VECTORS()); /* Нижняя граница SRAM не оставляет пространства для растущего вниз стека. */ + put32(image + 4U, APP_BASE + 9U); /* Восстанавливает корректную точку входа для следующих независимых проверок. */ + setup(&port, can); begin(&port, image, 16U); corrupt_write = true; /* Имитирует формальный успех HAL при неверном аппаратном readback. */ + assert(!port.boot.port.write_slot(&port, 0U, 0U, image, 8U) && !unlocked && port.written == 0U); /* Не подтверждает ни байта повреждённой записи и блокирует Flash. */ + corrupt_write = false; fail_write = true; assert(!port.boot.port.write_slot(&port, 0U, 0U, image, 8U) && !unlocked); /* При аппаратном отказе записи защита также восстанавливается. */ + fail_write = false; before = writes; /* Начинает проверку входов, которые не должны дойти до HAL. */ + assert(!port.boot.port.write_slot(&port, 1U, 0U, image, 8U) && !port.boot.port.write_slot(&port, 0U, 1U, image, 8U) && !port.boot.port.write_slot(&port, 0U, UINT32_MAX, image, 8U)); /* Отвергает чужой слот, невыровненный адрес и переполнение. */ + assert(!port.boot.port.write_slot(&port, 0U, 0U, image, 3U) && writes == before); /* Не программирует неполное аппаратное слово в середине образа. */ + assert(port.boot.port.send(&port, 1U, &one, 1U) && last_tx[0] == one && last_tx[1] == 0U && last_tx[7] == 0U); /* Короткий payload не читает семь отсутствующих октетов. */ + no_mailbox = true; assert(!port.boot.port.send(&port, 1U, &one, 1U)); no_mailbox = false; /* Ожидание свободного TX ограничено тайм-аутом. */ + fail_erase = true; assert(!port.boot.port.erase_slot(&port, 0U) && !unlocked); fail_erase = false; /* Отказ erase оставляет Flash заблокированной. */ + port.boot.manifest.image_size = APP_END - APP_BASE + 1U; before = erases; assert(!port.boot.port.erase_slot(&port, 0U) && erases == before); /* Превышение области не вызывает ни одной аппаратной операции. */ + setup(&port, can); before = sends; (void)memset(&rx_header, 0, sizeof(rx_header)); rx_header.ExtId = pcan_boot_make_id(1U, 0U, 3U, 5U, PCAN_BOOT_MSG_CONTROL, PCAN_BOOT_CMD_IDENTIFY); /* Готовит валидный адрес при неверном IDE. */ + have_rx = true; PORT_POLL(&port); assert(sends == before); /* Отвергает стандартный CAN-кадр до общего decoder. */ + rx_header.IDE = CAN_ID_EXT; rx_header.RTR = 2U; have_rx = true; PORT_POLL(&port); assert(sends == before); /* Отвергает remote-запрос вместо data-кадра. */ + rx_header.RTR = CAN_RTR_DATA; rx_header.DLC = 9U; have_rx = true; PORT_POLL(&port); assert(sends == before); /* Отвергает DLC больше ёмкости classic CAN. */ + rx_header.DLC = 0U; have_rx = true; PORT_POLL(&port); assert(sends == before + 1U); /* Валидный IDENTIFY проходит через настоящий FIFO adapter. */ + rx_header.ExtId = pcan_boot_make_id(1U, 0U, 7U, 15U, PCAN_BOOT_MSG_DISCOVERY, 0U); have_rx = true; PORT_POLL(&port); tick += 300U; PORT_POLL(&port); assert(sends == before + 2U); /* Broadcast discovery выдаёт отложенный адресный ответ без открытия сессии. */ + assert((filters[0].FilterMaskIdHigh & 0x8000U) == 0U && filters[1].FilterBank == 1U); /* Оба приоритета разрешены, discovery занимает отдельный банк. */ + fail_start = true; assert(!PORT_INIT(&port, can, &port.boot.config)); PORT_POLL(&port); assert(port.can == NULL); /* Отказ инициализации делает последующий poll безопасным. */ +} /* Завершает проверки отказов и транспортных границ. */ +static void test_full_capacity(TEST_HANDLE *can) /* Проверяет округление последней страницы/сектора и запись последнего аппаратного слова. */ +{ /* Полная ёмкость профиля затрагивает все разрешённые сектора, но не следующий. */ + pcan_boot_stm32_t port; uint8_t bytes[8] = {0}; uint32_t size = APP_END - APP_BASE; /* Готовит граничные значения в байтах. */ + setup(&port, can); port.boot.manifest.image_size = size; /* Задаёт максимальную длину без выделения большого wire-образа. */ + assert(port.boot.port.erase_slot(&port, 0U) && !unlocked); /* Стирает все разрешённые страницы или секторы production-алгоритмом. */ + port.written = size - 8U; assert(port.boot.port.write_slot(&port, 0U, size - 8U, bytes, 8U)); /* Проверяет последний допустимый блок точно на верхней границе. */ + assert(*(uint8_t *)(uintptr_t)(APP_BASE - 1U) == 0xA5U && *(uint8_t *)(uintptr_t)APP_END == 0xA5U); /* Не допускает стирания либо программирования соседних защищённых областей. */ +} /* Завершает проверку полного физического диапазона. */ +int main(void) /* Запускает регрессии production-порта в изолированном процессе. */ +{ /* Каждый процесс получает собственное отображение MCU Flash без доступа к устройству. */ + TEST_HANDLE can = {0}; can.Instance = TEST_INSTANCE; /* Подготавливает заранее настроенный HAL handle выделенного CAN1/FDCAN1. */ +#if defined(_WIN32) /* Выделяет фиксированный диапазон виртуальных адресов на Windows. */ + flash = VirtualAlloc((void *)(uintptr_t)0x08000000UL, 0x81000U, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); /* Моделирует 512 КиБ Flash STM32 и одну сторожевую страницу, включая сторожевые области. */ + assert(flash == (void *)(uintptr_t)0x08000000UL); /* Не выполняет тест, если адрес MCU недоступен в host-процессе. */ +#else /* Создаёт эквивалентное анонимное отображение на POSIX. */ + flash = mmap((void *)(uintptr_t)0x08000000UL, 0x81000U, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); /* Использует адрес как подсказку, не заменяя существующие отображения host-процесса. */ + assert(flash == (void *)(uintptr_t)0x08000000UL); /* Не продолжает проверки, если адрес MCU занят или mmap завершился ошибкой. */ +#endif /* Завершает выделение памяти модели. */ +#if defined(TEST_STM32G474) /* Прогоняет общие сценарии в обоих исходных DBANK-режимах G474VE. */ + for (unsigned mode = 0U; mode < 2U; ++mode) { /* Каждый режим независимо проверяет весь 480-КиБ слот и переход между физическими банками. */ + pcan_boot_stm32_t port; uint32_t before; dual_bank = mode != 0U; /* Выбирает single-bank 4 КиБ либо dual-bank 2 КиБ страницы. */ + test_update_and_tails(&can); test_failures_and_transport(&can); test_full_capacity(&can); /* Прогоняет полный flow, аппаратные ошибки, TX/RX и верхнюю границу Flash. */ + setup(&port, &can); port.boot.manifest.image_size = 16U; before = erases; stm32_test_flash.OPTR |= FLASH_OPTR_BFB2; /* Подготавливает опасную перестановку boot-банков. */ + assert(!port.boot.port.erase_slot(&port, 0U) && erases == before); stm32_test_flash.OPTR &= ~FLASH_OPTR_BFB2; /* Запрещённый BFB2 отвергается до HAL erase. */ + stm32_test_syscfg.MEMRMP = SYSCFG_MEMRMP_FB_MODE; assert(!port.boot.port.erase_slot(&port, 0U) && erases == before); stm32_test_syscfg.MEMRMP = 0U; /* Программная перестановка банков также не должна изменить Flash. */ + stm32_test_flash_kib = 256U; assert(!port.boot.port.erase_slot(&port, 0U) && erases == before); /* Профиль VE не должен стирать неизвестную меньшую физическую ёмкость. */ + } /* Завершает независимую проверку обеих аппаратных геометрий. */ +#else /* bxCAN-порты используют одну фиксированную аппаратную геометрию каждый. */ + test_update_and_tails(&can); test_failures_and_transport(&can); test_full_capacity(&can); /* Проверяет нормальный flow, аппаратные отказы и обе границы памяти. */ +#endif /* Завершает семейный набор host-сценариев. */ +#if defined(_WIN32) /* Освобождает всю зарезервированную область Windows. */ + assert(VirtualFree(flash, 0U, MEM_RELEASE)); /* Не оставляет виртуальную память после успешного теста. */ +#else /* Освобождает POSIX-отображение. */ + assert(munmap(flash, 0x81000U) == 0); /* Снимает модель Flash целиком. */ +#endif /* Завершает освобождение host-ресурсов. */ + puts("STM32 ProtoCAN port: OK"); return 0; /* Сообщает успешное завершение семейного прогона без аппаратных заявлений. */ +} /* Завершает host-регрессию реального MCU-порта. */ diff --git a/c/protocan-boot/vendor/ti/README.md b/c/protocan-boot/vendor/ti/README.md new file mode 100644 index 0000000..d16ec89 --- /dev/null +++ b/c/protocan-boot/vendor/ti/README.md @@ -0,0 +1,20 @@ +# Поддержка TI C2000 для самостоятельных проектов + +Здесь сохранён минимальный необходимый набор device headers, peripheral linker, +GlobalVariableDefs, SysCtrl, CpuTimers, PieCtrl и usDelay. Для F28335 также +подключён ADC_cal. Полные исходные copyright/version comments TI сохранены. + +- `f28335`: DSP2833x Header Files/Common Sources **v1.20**, вариант рабочей + платы 167 из `Source/External/v120`. В нём сохранены русские пояснения и + действующие XCLKIN=30 МГц, CLKMULT=2, SYSCLKOUT=60 МГц. +- `f2812`: DSP281x Header Files/Common Sources **v1.20**, вариант рабочей + платы ПМ67 из `22220/ural/TMS_new_bus/Src/v120`. Используется штатный + PLLCR=10 при XCLKIN=30 МГц, SYSCLKOUT=150 МГц. Сохранено исходное имя + регистра `PIECRTL` SDK и секция `.fast_run` у usDelay; linker проекта + размещает её во внутренней Flash для вызовов из раннего InitSysCtrl. + +Это существующая поддержка производителя; код аппаратных портов ProtoCAN +находится отдельно в `ports`, а настройки платы — в проектах CCS. Перенос +исходников TI устраняет зависимость от соседнего checkout конкретной прошивки. +Установленный TI compiler/runtime по-прежнему требуется; `libc`/RTS не +копируются в репозиторий. diff --git a/c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd b/c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd new file mode 100644 index 0000000..0b9ae9c --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd @@ -0,0 +1,102 @@ +/* +// TI File $Revision: /main/4 $ +// Checkin $Date: July 9, 2009 17:39:29 $ +//########################################################################### +// +// FILE: DSP281x_Headers_nonBIOS.cmd +// +// TITLE: DSP281x Peripheral registers linker command file +// +// DESCRIPTION: +// +// This file is for use in Non-BIOS applications. +// +// Linker command file to place the peripheral structures +// used within the DSP28 headerfiles into the correct memory +// mapped locations. +// +// This version of the file includes the PieVectorTable structure. +// For BIOS applications, please use the DSP281x_Headers_BIOS.cmd file +// which does not include the PieVectorTable structure. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### +*/ + +MEMORY +{ + PAGE 0: /* Program Memory */ + + PAGE 1: /* Data Memory */ + + DEV_EMU : origin = 0x000880, length = 0x000180 /* device emulation registers */ + PIE_VECT : origin = 0x000D00, length = 0x000100 /* PIE Vector Table */ + FLASH_REGS : origin = 0x000A80, length = 0x000060 /* FLASH registers */ + CSM : origin = 0x000AE0, length = 0x000010 /* code security module registers */ + XINTF : origin = 0x000B20, length = 0x000020 /* external interface registers */ + CPU_TIMER0 : origin = 0x000C00, length = 0x000008 /* CPU Timer0 registers */ + CPU_TIMER1 : origin = 0x000C08, length = 0x000008 /* CPU Timer1 registers */ + CPU_TIMER2 : origin = 0x000C10, length = 0x000008 /* CPU Timer2 registers */ + PIE_CTRL : origin = 0x000CE0, length = 0x000020 /* PIE control registers */ + ECANA : origin = 0x006000, length = 0x000040 /* eCAN control and status registers */ + ECANA_LAM : origin = 0x006040, length = 0x000040 /* eCAN local acceptance masks */ + ECANA_MOTS : origin = 0x006080, length = 0x000040 /* eCAN message object time stamps */ + ECANA_MOTO : origin = 0x0060C0, length = 0x000040 /* eCAN object time-out registers */ + ECANA_MBOX : origin = 0x006100, length = 0x000100 /* eCAN mailboxes */ + SYSTEM : origin = 0x007010, length = 0x000020 /* System control registers */ + SPIA : origin = 0x007040, length = 0x000010 /* SPI registers */ + SCIA : origin = 0x007050, length = 0x000010 /* SCI-A registers */ + XINTRUPT : origin = 0x007070, length = 0x000010 /* external interrupt registers */ + GPIOMUX : origin = 0x0070C0, length = 0x000020 /* GPIO mux registers */ + GPIODAT : origin = 0x0070E0, length = 0x000020 /* GPIO data registers */ + ADC : origin = 0x007100, length = 0x000020 /* ADC registers */ + EVA : origin = 0x007400, length = 0x000040 /* Event Manager A registers */ + EVB : origin = 0x007500, length = 0x000040 /* Event Manager B registers */ + SCIB : origin = 0x007750, length = 0x000010 /* SCI-B registers */ + MCBSPA : origin = 0x007800, length = 0x000040 /* McBSP registers */ + CSM_PWL : origin = 0x3F7FF8, length = 0x000008 /* Part of FLASHA. CSM password locations. */ +} + + +SECTIONS +{ + PieVectTableFile : > PIE_VECT, PAGE = 1 + +/*** Peripheral Frame 0 Register Structures ***/ + DevEmuRegsFile : > DEV_EMU, PAGE = 1 + FlashRegsFile : > FLASH_REGS, PAGE = 1 + CsmRegsFile : > CSM, PAGE = 1 + XintfRegsFile : > XINTF, PAGE = 1 + CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1 + CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1 + CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1 + PieCtrlRegsFile : > PIE_CTRL, PAGE = 1 + +/*** Peripheral Frame 1 Register Structures ***/ + ECanaRegsFile : > ECANA, PAGE = 1 + ECanaLAMRegsFile : > ECANA_LAM PAGE = 1 + ECanaMboxesFile : > ECANA_MBOX PAGE = 1 + ECanaMOTSRegsFile : > ECANA_MOTS PAGE = 1 + ECanaMOTORegsFile : > ECANA_MOTO PAGE = 1 + +/*** Peripheral Frame 2 Register Structures ***/ + SysCtrlRegsFile : > SYSTEM, PAGE = 1 + SpiaRegsFile : > SPIA, PAGE = 1 + SciaRegsFile : > SCIA, PAGE = 1 + XIntruptRegsFile : > XINTRUPT, PAGE = 1 + GpioMuxRegsFile : > GPIOMUX, PAGE = 1 + GpioDataRegsFile : > GPIODAT PAGE = 1 + AdcRegsFile : > ADC, PAGE = 1 + EvaRegsFile : > EVA, PAGE = 1 + EvbRegsFile : > EVB, PAGE = 1 + ScibRegsFile : > SCIB, PAGE = 1 + McbspaRegsFile : > MCBSPA, PAGE = 1 + +/*** Code Security Module Register Structures ***/ + CsmPwlFile : > CSM_PWL, PAGE = 1 +} + + +/******************* end of file ************************/ diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h new file mode 100644 index 0000000..e617abd --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_DefaultIsr.h @@ -0,0 +1,123 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 15:22:28 $ +//########################################################################### +// +// FILE: DSP281x_DefaultIsr.h +// +// TITLE: DSP281x Devices Default Interrupt Service Routines Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEFAULT_ISR_H +#define DSP281x_DEFAULT_ISR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// Default Interrupt Service Routine Declarations: +// +// The following function prototypes are for the +// default ISR routines used with the default PIE vector table. +// This default vector table is found in the DSP28_PieVect.h +// file. +// + +// Non-Peripheral Interrupts: +interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1 +interrupt void INT14_ISR(void); // CPU-Timer2 +interrupt void DATALOG_ISR(void); // Datalogging interrupt +interrupt void RTOSINT_ISR(void); // RTOS interrupt +interrupt void EMUINT_ISR(void); // Emulation interrupt +interrupt void NMI_ISR(void); // Non-maskable interrupt +interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP +interrupt void USER1_ISR(void); // User Defined trap 1 +interrupt void USER2_ISR(void); // User Defined trap 2 +interrupt void USER3_ISR(void); // User Defined trap 3 +interrupt void USER4_ISR(void); // User Defined trap 4 +interrupt void USER5_ISR(void); // User Defined trap 5 +interrupt void USER6_ISR(void); // User Defined trap 6 +interrupt void USER7_ISR(void); // User Defined trap 7 +interrupt void USER8_ISR(void); // User Defined trap 8 +interrupt void USER9_ISR(void); // User Defined trap 9 +interrupt void USER10_ISR(void); // User Defined trap 10 +interrupt void USER11_ISR(void); // User Defined trap 11 +interrupt void USER12_ISR(void); // User Defined trap 12 + +// Group 1 PIE Interrupt Service Routines: +interrupt void PDPINTA_ISR(void); // EV-A +interrupt void PDPINTB_ISR(void); // EV-B +interrupt void XINT1_ISR(void); +interrupt void XINT2_ISR(void); +interrupt void ADCINT_ISR(void); // ADC +interrupt void TINT0_ISR(void); // Timer 0 +interrupt void WAKEINT_ISR(void); // WD + +// Group 2 PIE Interrupt Service Routines: +interrupt void CMP1INT_ISR(void); // EV-A +interrupt void CMP2INT_ISR(void); // EV-A +interrupt void CMP3INT_ISR(void); // EV-A +interrupt void T1PINT_ISR(void); // EV-A +interrupt void T1CINT_ISR(void); // EV-A +interrupt void T1UFINT_ISR(void); // EV-A +interrupt void T1OFINT_ISR(void); // EV-A + +// Group 3 PIE Interrupt Service Routines: +interrupt void T2PINT_ISR(void); // EV-A +interrupt void T2CINT_ISR(void); // EV-A +interrupt void T2UFINT_ISR(void); // EV-A +interrupt void T2OFINT_ISR(void); // EV-A +interrupt void CAPINT1_ISR(void); // EV-A +interrupt void CAPINT2_ISR(void); // EV-A +interrupt void CAPINT3_ISR(void); // EV-A + +// Group 4 PIE Interrupt Service Routines: +interrupt void CMP4INT_ISR(void); // EV-B +interrupt void CMP5INT_ISR(void); // EV-B +interrupt void CMP6INT_ISR(void); // EV-B +interrupt void T3PINT_ISR(void); // EV-B +interrupt void T3CINT_ISR(void); // EV-B +interrupt void T3UFINT_ISR(void); // EV-B +interrupt void T3OFINT_ISR(void); // EV-B + +// Group 5 PIE Interrupt Service Routines: +interrupt void T4PINT_ISR(void); // EV-B +interrupt void T4CINT_ISR(void); // EV-B +interrupt void T4UFINT_ISR(void); // EV-B +interrupt void T4OFINT_ISR(void); // EV-B +interrupt void CAPINT4_ISR(void); // EV-B +interrupt void CAPINT5_ISR(void); // EV-B +interrupt void CAPINT6_ISR(void); // EV-B + +// Group 6 PIE Interrupt Service Routines: +interrupt void SPIRXINTA_ISR(void); // SPI +interrupt void SPITXINTA_ISR(void); // SPI +interrupt void MRINTA_ISR(void); // McBSP +interrupt void MXINTA_ISR(void); // McBSP + + +// Group 9 PIE Interrupt Service Routines: +interrupt void SCIRXINTA_ISR(void); // SCI-A +interrupt void SCITXINTA_ISR(void); // SCI-A +interrupt void SCIRXINTB_ISR(void); // SCI-B +interrupt void SCITXINTB_ISR(void); // SCI-B +interrupt void ECAN0INTA_ISR(void); // eCAN +interrupt void ECAN1INTA_ISR(void); // eCAN + + +// Catch-all for Reserved Locations For testing purposes: +interrupt void PIE_RESERVED(void); // Reserved for test +interrupt void rsvd_ISR(void); // for test + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEFAULT_ISR_H definition + diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h new file mode 100644 index 0000000..4a8cd6a --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_Examples.h @@ -0,0 +1,88 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: April 25, 2007 11:04:51 $ +//########################################################################### +// +// FILE: DSP281x_Examples.h +// +// TITLE: DSP281x Device Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_EXAMPLES_H +#define DSP281x_EXAMPLES_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*----------------------------------------------------------------------------- + Specify the clock rate of the CPU (SYSCLKOUT) in nS. + + Take into account the input clock frequency and the PLL multiplier + selected in SysCtrl.c (0xA by default). + + Use one of the values provided, or define your own. + The trailing L is required tells the compiler to treat + the number as a 64-bit value. + + Only one statement should be uncommented. + + Example: CLKIN is a 30MHz crystal. + + In SysCtrl.c the user specified PLLCR = 0xA for a + 150Mhz CPU clock (SYSCLKOUT = 150MHz). + + In this case, the CPU_RATE will be 6.667L + Uncomment the line: #define CPU_RATE 6.667L +-----------------------------------------------------------------------------*/ +//#define CPU_RATE 6.667L // for a 150MHz CPU clock speed (SYSCLKOUT) +#define CPU_RATE 7.143L // for a 140MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 8.333L // for a 120MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 10.000L // for a 100MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 13.330L // for a 75MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 20.000L // for a 50MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 33.333L // for a 30MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 41.667L // for a 24MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 50.000L // for a 20MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 66.667L // for a 15MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 100.000L // for a 10MHz CPU clock speed (SYSCLKOUT) + +//---------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- +// Include Example Header Files: +// + +#include "DSP281x_GlobalPrototypes.h" // Prototypes for global functions within the + // .c files. + +#include "DSP281x_SWPrioritizedIsrLevels.h" // Used for Software Prioritization of ISR's + + +// Include files not used with DSP/BIOS +#ifndef DSP28_BIOS +#include "DSP281x_DefaultISR.h" +#endif + + +// DO NOT MODIFY THIS LINE. +#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L) + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_EXAMPELS_H definition + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h new file mode 100644 index 0000000..65bfb6c --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_GlobalPrototypes.h @@ -0,0 +1,87 @@ +// TI File $Revision: /main/7 $ +// Checkin $Date: July 9, 2009 13:14:00 $ +//########################################################################### +// +// FILE: DSP281x_GlobalPrototypes.h +// +// TITLE: Global prototypes for DSP28 Examples +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_GLOBALPROTOTYPES_H +#define DSP281x_GLOBALPROTOTYPES_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/*---- shared global function prototypes -----------------------------------*/ +extern void InitAdc(void); +extern void InitPeripherals(void); +extern void InitECan(void); +extern void InitEv(void); +extern void InitGpio(void); +extern void InitMcbsp(void); +extern void InitPieCtrl(void); +extern void InitPieVectTable(void); +extern void EnableInterrupts(void); +extern void DisableInterrupts(void); +extern void InitSci(void); +extern void InitSpi(void); +extern void InitSysCtrl(void); +extern void InitXintf(void); +extern void InitXIntrupt(void); +extern void InitPll(Uint16 val); +extern void InitPeripheralClocks(void); + +// McBSP functions +// DSP281x_Mcbsp.c +extern void InitMcbspGpio(void); +extern void delay_loop(void); +extern void InitMcbspa8bit(void); +extern void InitMcbspa12bit(void); +extern void InitMcbspa16bit(void); +extern void InitMcbspa20bit(void); +extern void InitMcbspa24bit(void); +extern void InitMcbspa32bit(void); + +// Watchdog functions +// DSP28_SysCtrl.c +extern void KickDog(void); +extern void DisableDog(void); +extern Uint16 CsmUnlock(void); + +// DSP28_DBGIER.asm +extern void SetDBGIER(Uint16 dbgier); + +// DSP281x_usDelay.asm +extern void DSP28x_usDelay(Uint32 Count); + + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results +extern void InitFlash(void); + + +void MemCopy(Uint16 *SourceAddr, Uint16* SourceEndAddr, Uint16* DestAddr); + + +//--------------------------------------------------------------------------- +// External symbols created by the linker cmd file +// DSP28 examples will use these to relocate code from one LOAD location +// in either Flash or XINTF to a different RUN location in internal +// RAM +extern Uint16 RamfuncsLoadStart; +extern Uint16 RamfuncsLoadEnd; +extern Uint16 RamfuncsRunStart; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // - end of DSP281x_GLOBALPROTOTYPES_H + diff --git a/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h new file mode 100644 index 0000000..7495566 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/common/include/DSP281x_SWPrioritizedIsrLevels.h @@ -0,0 +1,5881 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 15:22:36 $ +//########################################################################### +// +// FILE: DSP281x_SWPrioritizedIsrLevels.h +// +// TITLE: DSP28 Devices Software Prioritized Interrupt Service Routine +// Level definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SW_PRIORITZIED_ISR_H +#define DSP281x_SW_PRIORITZIED_ISR_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//------------------------------------------------------------------------------- +// Interrupt Enable Register Allocation For F2810/12 Devices: +//------------------------------------------------------------------------------- +// Interrupts can be enabled/disabled using the CPU interrupt enable register +// (IER) and the PIE interrupt enable registers (PIIER1 to PIEIER12). The table +// below lists the allocation of the various interrupts to these registers: +// +//----------------------------------------------------------------------------------- +// CPU | PIEIER1 to PIEIER12 | +// IER | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +// =====|=========|=========|=========|=========|=========|=========|=======|=======| +// INT1 |PDPINTA |PDPINTB | resvd | XINT1 | XINT2 |ADCINT | TINT0 |WAKEINT| +// | (EV-A) | (EV-B) | | | | | | | +// INT2 |CMP1INT |CMP2INT |CMP3INT |T1PINT |T1CINT |T1UFINT |T1OFINT| resvd | +// | (EV-A) | (EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) | | +// INT3 |T2PINT |T2CINT |T2UFINT |T2OFINT |CAPINT1 |CAPINT2 |CAPINT3| resvd | +// | (EV-A) | (EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) |(EV-A) | | +// INT4 |CMP4INT |CMP5INT |CMP6INT |T3PINT |T3CINT |T3UFINT |T3OFINT| resvd | +// | (EV-B) | (EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) | | +// INT5 |T4PINT |T4CINT |T4UFINT |T4OFINT |CAPINT4 |CAPINT5 |CAPINT6| resvd | +// | (EV-B) | (EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) |(EV-B) | | +// INT6 |SPIRXINTA|SPITXINTA| resvd | resvd | MRINTA | MXINTA | resvd | resvd | +// | (SPI-A) | (SPI-A) | | |(McBSP-A)|(McBSP-A)| | | +// INT7 | resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT8 | resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT9 |SCIRXINTA|SCITXINTA|SCIRXINTB|SCITXINTB|ECAN0INTA|ECAN1INTA| resvd | resvd | +// | (SCI-A) | (SCI-A) |(SCI-B) |(SCI-B) |(ECAN-A) |(ECAN-A) | | | +// INT10| resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT11| resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +// INT12| resvd | resvd | resvd | resvd | resvd | resvd | resvd | resvd | +//------------------------------------------------------------------------------- +// INT13| INT13 +// INT14| INT14 +// INT15| DATALOG +// INT16| RTOSINT +//------------------------------------------------------------------------------- +// +//------------------------------------------------------------------------------- +// Set "Global" Interrupt Priority Level (IER register): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the CPU +// interrupts. This is termed as the "global" priority. The priority level +// must be a number between 1 (highest) to 16 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used. +// +// Note: The priority levels below are used to calculate the IER register +// interrupt masks MINT1 to MINT16. +// +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 16 = lowest priority +#define INT1PL 1 // Group1 Interrupts (PIEIER1) +#define INT2PL 4 // Group2 Interrupts (PIEIER2) +#define INT3PL 2 // Group3 Interrupts (PIEIER3) +#define INT4PL 4 // Group4 Interrupts (PIEIER4) +#define INT5PL 5 // Group5 Interrupts (PIEIER5) +#define INT6PL 3 // Group6 Interrupts (PIEIER6) +#define INT7PL 0 // reserved +#define INT8PL 0 // reserved +#define INT9PL 3 // Group9 Interrupts (PIEIER9) +#define INT10PL 0 // reserved +#define INT11PL 0 // reserved +#define INT12PL 0 // reserved +#define INT13PL 4 // XINT3 +#define INT14PL 4 // INT14 (TINT2) +#define INT15PL 4 // DATALOG +#define INT16PL 4 // RTOSINT + +//------------------------------------------------------------------------------- +// Set "Group" Interrupt Priority Level (PIEIER1 to PIEIER12 registers): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the PIE +// interrupts. This is termed as the "group" priority. The priority level +// must be a number between 1 (highest) to 8 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used: +// +// Note: The priority levels below are used to calculate the following +// PIEIER register interrupt masks: +// MG11 to MG18 +// MG21 to MG28 +// MG31 to MG38 +// MG41 to MG48 +// MG51 to MG58 +// MG61 to MG68 +// MG71 to MG78 +// MG81 to MG88 +// MG91 to MG98 +// MG101 to MG108 +// MG111 to MG118 +// MG121 to MG128 +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 8 = lowest priority +// +#define G11PL 7 // PDPINTA (EV-A) +#define G12PL 6 // PDPINTB (EV-B) +#define G13PL 0 // reserved +#define G14PL 1 // XINT1 (External) +#define G15PL 3 // XINT2 (External) +#define G16PL 2 // ADCINT (ADC) +#define G17PL 1 // TINT0 (CPU Timer 0) +#define G18PL 5 // WAKEINT (WD/LPM) + +#define G21PL 4 // CMP1INT (EV-A) +#define G22PL 3 // CMP2INT (EV-A) +#define G23PL 2 // CMP3INT (EV-A) +#define G24PL 1 // T1PINT (EV-A) +#define G25PL 5 // T1CINT (EV-A) +#define G26PL 6 // T1UFINT (EV-A) +#define G27PL 7 // T1OFINT (EV-A) +#define G28PL 0 // reserved + +#define G31PL 1 // T2PINT (EV-A) +#define G32PL 1 // T2CINT (EV-A) +#define G33PL 1 // T2UFINT (EV-A) +#define G34PL 2 // T2OFINT (EV-A) +#define G35PL 2 // CAPINT1 (EV-A) +#define G36PL 1 // CAPINT2 (EV-A) +#define G37PL 3 // CAPINT3 (EV-A) +#define G38PL 0 // reserved + +#define G41PL 2 // CMP4INT (EV-B) +#define G42PL 1 // CMP5INT (EV-B) +#define G43PL 3 // CMP6INT (EV-B) +#define G44PL 3 // T3PINT (EV-B) +#define G45PL 2 // T3CINT (EV-B) +#define G46PL 2 // T3UFINT (EV-B) +#define G47PL 1 // T3OFINT (EV-B) +#define G48PL 0 // reserved + +#define G51PL 1 // T4PINT (EV-B) +#define G52PL 7 // T4CINT (EV-B) +#define G53PL 2 // T4UFINT (EV-B) +#define G54PL 6 // T4OFINT (EV-B) +#define G55PL 5 // CAPINT4 (EV-B) +#define G56PL 6 // CAPINT5 (EV-B) +#define G57PL 7 // CAPINT6 (EV-B) +#define G58PL 0 // reserved + +#define G61PL 3 // SPIRXINTA (SPI-A) +#define G62PL 1 // SPITXINTA (SPI-A) +#define G63PL 0 // reserved +#define G64PL 0 // reserved +#define G65PL 2 // MRINTA (McBSP-A) +#define G66PL 1 // MXINTA (McBSP-A) +#define G67PL 0 // reserved +#define G68PL 0 // reserved + +#define G71PL 0 // reserved +#define G72PL 0 // reserved +#define G73PL 0 // reserved +#define G74PL 0 // reserved +#define G75PL 0 // reserved +#define G76PL 0 // reserved +#define G77PL 0 // reserved +#define G78PL 0 // reserved + +#define G81PL 0 // reserved +#define G82PL 0 // reserved +#define G83PL 0 // reserved +#define G84PL 0 // reserved +#define G85PL 0 // reserved +#define G86PL 0 // reserved +#define G87PL 0 // reserved +#define G88PL 0 // reserved + +#define G91PL 1 // SCIRXINTA (SCI-A) +#define G92PL 5 // SCITXINTA (SCI-A) +#define G93PL 3 // SCIRXINTB (SCI-B) +#define G94PL 4 // SCITXINTB (SCI-B) +#define G95PL 1 // ECAN0INTA (ECAN-A) +#define G96PL 1 // ECAN1INTA (ECAN-A) +#define G97PL 0 // reserved +#define G98PL 0 // reserved + +#define G101PL 0 // reserved +#define G102PL 0 // reserved +#define G103PL 0 // reserved +#define G104PL 0 // reserved +#define G105PL 0 // reserved +#define G106PL 0 // reserved +#define G107PL 0 // reserved +#define G108PL 0 // reserved + +#define G111PL 0 // reserved +#define G112PL 0 // reserved +#define G113PL 0 // reserved +#define G114PL 0 // reserved +#define G115PL 0 // reserved +#define G116PL 0 // reserved +#define G117PL 0 // reserved +#define G118PL 0 // reserved + +#define G121PL 0 // reserved +#define G122PL 0 // reserved +#define G123PL 0 // reserved +#define G124PL 0 // reserved +#define G125PL 0 // reserved +#define G126PL 0 // reserved +#define G127PL 0 // reserved +#define G128PL 0 // reserved + + +// There should be no need to modify code below this line +//------------------------------------------------------------------------------- +// Automatically generate IER interrupt masks MINT1 to MINT16: +// + +// Beginning of MINT1: +#if (INT1PL == 0) +#define MINT1_1PL ~(1 << 0) +#else +#define MINT1_1PL 0xFFFF +#endif + +#if (INT2PL >= INT1PL) || (INT2PL == 0) +#define MINT1_2PL ~(1 << 1) +#else +#define MINT1_2PL 0xFFFF +#endif + +#if (INT3PL >= INT1PL) || (INT3PL == 0) +#define MINT1_3PL ~(1 << 2) +#else +#define MINT1_3PL 0xFFFF +#endif + +#if (INT4PL >= INT1PL) || (INT4PL == 0) +#define MINT1_4PL ~(1 << 3) +#else +#define MINT1_4PL 0xFFFF +#endif + +#if (INT5PL >= INT1PL) || (INT5PL == 0) +#define MINT1_5PL ~(1 << 4) +#else +#define MINT1_5PL 0xFFFF +#endif + +#if (INT6PL >= INT1PL) || (INT6PL == 0) +#define MINT1_6PL ~(1 << 5) +#else +#define MINT1_6PL 0xFFFF +#endif + +#if (INT7PL >= INT1PL) || (INT7PL == 0) +#define MINT1_7PL ~(1 << 6) +#else +#define MINT1_7PL 0xFFFF +#endif + +#if (INT8PL >= INT1PL) || (INT8PL == 0) +#define MINT1_8PL ~(1 << 7) +#else +#define MINT1_8PL 0xFFFF +#endif + +#if (INT9PL >= INT1PL) || (INT9PL == 0) +#define MINT1_9PL ~(1 << 8) +#else +#define MINT1_9PL 0xFFFF +#endif + +#if (INT10PL >= INT1PL) || (INT10PL == 0) +#define MINT1_10PL ~(1 << 9) +#else +#define MINT1_10PL 0xFFFF +#endif + +#if (INT11PL >= INT1PL) || (INT11PL == 0) +#define MINT1_11PL ~(1 << 10) +#else +#define MINT1_11PL 0xFFFF +#endif + +#if (INT12PL >= INT1PL) || (INT12PL == 0) +#define MINT1_12PL ~(1 << 11) +#else +#define MINT1_12PL 0xFFFF +#endif + +#if (INT13PL >= INT1PL) || (INT13PL == 0) +#define MINT1_13PL ~(1 << 12) +#else +#define MINT1_13PL 0xFFFF +#endif + +#if (INT14PL >= INT1PL) || (INT14PL == 0) +#define MINT1_14PL ~(1 << 13) +#else +#define MINT1_14PL 0xFFFF +#endif + +#if (INT15PL >= INT1PL) || (INT15PL == 0) +#define MINT1_15PL ~(1 << 14) +#else +#define MINT1_15PL 0xFFFF +#endif + +#if (INT16PL >= INT1PL) || (INT16PL == 0) +#define MINT1_16PL ~(1 << 15) +#else +#define MINT1_16PL 0xFFFF +#endif + +#define MINT1 (MINT1_1PL & MINT1_2PL & MINT1_3PL & MINT1_4PL & \ + MINT1_5PL & MINT1_6PL & MINT1_7PL & MINT1_8PL & \ + MINT1_9PL & MINT1_10PL & MINT1_11PL & MINT1_12PL & \ + MINT1_13PL & MINT1_14PL & MINT1_15PL & MINT1_16PL) +// End Of MINT1. + +// Beginning of MINT2: +#if (INT1PL >= INT2PL) || (INT1PL == 0) +#define MINT2_1PL ~(1 << 0) +#else +#define MINT2_1PL 0xFFFF +#endif + +#if (INT2PL == 0) +#define MINT2_2PL ~(1 << 1) +#else +#define MINT2_2PL 0xFFFF +#endif + +#if (INT3PL >= INT2PL) || (INT3PL == 0) +#define MINT2_3PL ~(1 << 2) +#else +#define MINT2_3PL 0xFFFF +#endif + +#if (INT4PL >= INT2PL) || (INT4PL == 0) +#define MINT2_4PL ~(1 << 3) +#else +#define MINT2_4PL 0xFFFF +#endif + +#if (INT5PL >= INT2PL) || (INT5PL == 0) +#define MINT2_5PL ~(1 << 4) +#else +#define MINT2_5PL 0xFFFF +#endif + +#if (INT6PL >= INT2PL) || (INT6PL == 0) +#define MINT2_6PL ~(1 << 5) +#else +#define MINT2_6PL 0xFFFF +#endif + +#if (INT7PL >= INT2PL) || (INT7PL == 0) +#define MINT2_7PL ~(1 << 6) +#else +#define MINT2_7PL 0xFFFF +#endif + +#if (INT8PL >= INT2PL) || (INT8PL == 0) +#define MINT2_8PL ~(1 << 7) +#else +#define MINT2_8PL 0xFFFF +#endif + +#if (INT9PL >= INT2PL) || (INT9PL == 0) +#define MINT2_9PL ~(1 << 8) +#else +#define MINT2_9PL 0xFFFF +#endif + +#if (INT10PL >= INT2PL) || (INT10PL == 0) +#define MINT2_10PL ~(1 << 9) +#else +#define MINT2_10PL 0xFFFF +#endif + +#if (INT11PL >= INT2PL) || (INT11PL == 0) +#define MINT2_11PL ~(1 << 10) +#else +#define MINT2_11PL 0xFFFF +#endif + +#if (INT12PL >= INT2PL) || (INT12PL == 0) +#define MINT2_12PL ~(1 << 11) +#else +#define MINT2_12PL 0xFFFF +#endif + +#if (INT13PL >= INT2PL) || (INT13PL == 0) +#define MINT2_13PL ~(1 << 12) +#else +#define MINT2_13PL 0xFFFF +#endif + +#if (INT14PL >= INT2PL) || (INT14PL == 0) +#define MINT2_14PL ~(1 << 13) +#else +#define MINT2_14PL 0xFFFF +#endif + +#if (INT15PL >= INT2PL) || (INT15PL == 0) +#define MINT2_15PL ~(1 << 14) +#else +#define MINT2_15PL 0xFFFF +#endif + +#if (INT16PL >= INT2PL) || (INT16PL == 0) +#define MINT2_16PL ~(1 << 15) +#else +#define MINT2_16PL 0xFFFF +#endif + +#define MINT2 (MINT2_1PL & MINT2_2PL & MINT2_3PL & MINT2_4PL & \ + MINT2_5PL & MINT2_6PL & MINT2_7PL & MINT2_8PL & \ + MINT2_9PL & MINT2_10PL & MINT2_11PL & MINT2_12PL & \ + MINT2_13PL & MINT2_14PL & MINT2_15PL & MINT2_16PL) +// End Of MINT2. + +// Beginning of MINT3: +#if (INT1PL >= INT3PL) || (INT1PL == 0) +#define MINT3_1PL ~(1 << 0) +#else +#define MINT3_1PL 0xFFFF +#endif + +#if (INT2PL >= INT3PL) || (INT2PL == 0) +#define MINT3_2PL ~(1 << 1) +#else +#define MINT3_2PL 0xFFFF +#endif + +#if (INT3PL == 0) +#define MINT3_3PL ~(1 << 2) +#else +#define MINT3_3PL 0xFFFF +#endif + +#if (INT4PL >= INT3PL) || (INT4PL == 0) +#define MINT3_4PL ~(1 << 3) +#else +#define MINT3_4PL 0xFFFF +#endif + +#if (INT5PL >= INT3PL) || (INT5PL == 0) +#define MINT3_5PL ~(1 << 4) +#else +#define MINT3_5PL 0xFFFF +#endif + +#if (INT6PL >= INT3PL) || (INT6PL == 0) +#define MINT3_6PL ~(1 << 5) +#else +#define MINT3_6PL 0xFFFF +#endif + +#if (INT7PL >= INT3PL) || (INT7PL == 0) +#define MINT3_7PL ~(1 << 6) +#else +#define MINT3_7PL 0xFFFF +#endif + +#if (INT8PL >= INT3PL) || (INT8PL == 0) +#define MINT3_8PL ~(1 << 7) +#else +#define MINT3_8PL 0xFFFF +#endif + +#if (INT9PL >= INT3PL) || (INT9PL == 0) +#define MINT3_9PL ~(1 << 8) +#else +#define MINT3_9PL 0xFFFF +#endif + +#if (INT10PL >= INT3PL) || (INT10PL == 0) +#define MINT3_10PL ~(1 << 9) +#else +#define MINT3_10PL 0xFFFF +#endif + +#if (INT11PL >= INT3PL) || (INT11PL == 0) +#define MINT3_11PL ~(1 << 10) +#else +#define MINT3_11PL 0xFFFF +#endif + +#if (INT12PL >= INT3PL) || (INT12PL == 0) +#define MINT3_12PL ~(1 << 11) +#else +#define MINT3_12PL 0xFFFF +#endif + +#if (INT13PL >= INT3PL) || (INT13PL == 0) +#define MINT3_13PL ~(1 << 12) +#else +#define MINT3_13PL 0xFFFF +#endif + +#if (INT14PL >= INT3PL) || (INT14PL == 0) +#define MINT3_14PL ~(1 << 13) +#else +#define MINT3_14PL 0xFFFF +#endif + +#if (INT15PL >= INT3PL) || (INT15PL == 0) +#define MINT3_15PL ~(1 << 14) +#else +#define MINT3_15PL 0xFFFF +#endif + +#if (INT16PL >= INT3PL) || (INT16PL == 0) +#define MINT3_16PL ~(1 << 15) +#else +#define MINT3_16PL 0xFFFF +#endif + +#define MINT3 (MINT3_1PL & MINT3_2PL & MINT3_3PL & MINT3_4PL & \ + MINT3_5PL & MINT3_6PL & MINT3_7PL & MINT3_8PL & \ + MINT3_9PL & MINT3_10PL & MINT3_11PL & MINT3_12PL & \ + MINT3_13PL & MINT3_14PL & MINT3_15PL & MINT3_16PL) +// End Of MINT3. + +// Beginning of MINT4: +#if (INT1PL >= INT4PL) || (INT1PL == 0) +#define MINT4_1PL ~(1 << 0) +#else +#define MINT4_1PL 0xFFFF +#endif + +#if (INT2PL >= INT4PL) || (INT2PL == 0) +#define MINT4_2PL ~(1 << 1) +#else +#define MINT4_2PL 0xFFFF +#endif + +#if (INT3PL >= INT4PL) || (INT3PL == 0) +#define MINT4_3PL ~(1 << 2) +#else +#define MINT4_3PL 0xFFFF +#endif + +#if (INT4PL == 0) +#define MINT4_4PL ~(1 << 3) +#else +#define MINT4_4PL 0xFFFF +#endif + +#if (INT5PL >= INT4PL) || (INT5PL == 0) +#define MINT4_5PL ~(1 << 4) +#else +#define MINT4_5PL 0xFFFF +#endif + +#if (INT6PL >= INT4PL) || (INT6PL == 0) +#define MINT4_6PL ~(1 << 5) +#else +#define MINT4_6PL 0xFFFF +#endif + +#if (INT7PL >= INT4PL) || (INT7PL == 0) +#define MINT4_7PL ~(1 << 6) +#else +#define MINT4_7PL 0xFFFF +#endif + +#if (INT8PL >= INT4PL) || (INT8PL == 0) +#define MINT4_8PL ~(1 << 7) +#else +#define MINT4_8PL 0xFFFF +#endif + +#if (INT9PL >= INT4PL) || (INT9PL == 0) +#define MINT4_9PL ~(1 << 8) +#else +#define MINT4_9PL 0xFFFF +#endif + +#if (INT10PL >= INT4PL) || (INT10PL == 0) +#define MINT4_10PL ~(1 << 9) +#else +#define MINT4_10PL 0xFFFF +#endif + +#if (INT11PL >= INT4PL) || (INT11PL == 0) +#define MINT4_11PL ~(1 << 10) +#else +#define MINT4_11PL 0xFFFF +#endif + +#if (INT12PL >= INT4PL) || (INT12PL == 0) +#define MINT4_12PL ~(1 << 11) +#else +#define MINT4_12PL 0xFFFF +#endif + +#if (INT13PL >= INT4PL) || (INT13PL == 0) +#define MINT4_13PL ~(1 << 12) +#else +#define MINT4_13PL 0xFFFF +#endif + +#if (INT14PL >= INT4PL) || (INT14PL == 0) +#define MINT4_14PL ~(1 << 13) +#else +#define MINT4_14PL 0xFFFF +#endif + +#if (INT15PL >= INT4PL) || (INT15PL == 0) +#define MINT4_15PL ~(1 << 14) +#else +#define MINT4_15PL 0xFFFF +#endif + +#if (INT16PL >= INT4PL) || (INT16PL == 0) +#define MINT4_16PL ~(1 << 15) +#else +#define MINT4_16PL 0xFFFF +#endif + +#define MINT4 (MINT4_1PL & MINT4_2PL & MINT4_3PL & MINT4_4PL & \ + MINT4_5PL & MINT4_6PL & MINT4_7PL & MINT4_8PL & \ + MINT4_9PL & MINT4_10PL & MINT4_11PL & MINT4_12PL & \ + MINT4_13PL & MINT4_14PL & MINT4_15PL & MINT4_16PL) +// End Of MINT4. + +// Beginning of MINT5: +#if (INT1PL >= INT5PL) || (INT1PL == 0) +#define MINT5_1PL ~(1 << 0) +#else +#define MINT5_1PL 0xFFFF +#endif + +#if (INT2PL >= INT5PL) || (INT2PL == 0) +#define MINT5_2PL ~(1 << 1) +#else +#define MINT5_2PL 0xFFFF +#endif + +#if (INT3PL >= INT5PL) || (INT3PL == 0) +#define MINT5_3PL ~(1 << 2) +#else +#define MINT5_3PL 0xFFFF +#endif + +#if (INT4PL >= INT5PL) || (INT4PL == 0) +#define MINT5_4PL ~(1 << 3) +#else +#define MINT5_4PL 0xFFFF +#endif + +#if (INT5PL == 0) +#define MINT5_5PL ~(1 << 4) +#else +#define MINT5_5PL 0xFFFF +#endif + +#if (INT6PL >= INT5PL) || (INT6PL == 0) +#define MINT5_6PL ~(1 << 5) +#else +#define MINT5_6PL 0xFFFF +#endif + +#if (INT7PL >= INT5PL) || (INT7PL == 0) +#define MINT5_7PL ~(1 << 6) +#else +#define MINT5_7PL 0xFFFF +#endif + +#if (INT8PL >= INT5PL) || (INT8PL == 0) +#define MINT5_8PL ~(1 << 7) +#else +#define MINT5_8PL 0xFFFF +#endif + +#if (INT9PL >= INT5PL) || (INT9PL == 0) +#define MINT5_9PL ~(1 << 8) +#else +#define MINT5_9PL 0xFFFF +#endif + +#if (INT10PL >= INT5PL) || (INT10PL == 0) +#define MINT5_10PL ~(1 << 9) +#else +#define MINT5_10PL 0xFFFF +#endif + +#if (INT11PL >= INT5PL) || (INT11PL == 0) +#define MINT5_11PL ~(1 << 10) +#else +#define MINT5_11PL 0xFFFF +#endif + +#if (INT12PL >= INT5PL) || (INT12PL == 0) +#define MINT5_12PL ~(1 << 11) +#else +#define MINT5_12PL 0xFFFF +#endif + +#if (INT13PL >= INT5PL) || (INT13PL == 0) +#define MINT5_13PL ~(1 << 12) +#else +#define MINT5_13PL 0xFFFF +#endif + +#if (INT14PL >= INT5PL) || (INT14PL == 0) +#define MINT5_14PL ~(1 << 13) +#else +#define MINT5_14PL 0xFFFF +#endif + +#if (INT15PL >= INT5PL) || (INT15PL == 0) +#define MINT5_15PL ~(1 << 14) +#else +#define MINT5_15PL 0xFFFF +#endif + +#if (INT16PL >= INT5PL) || (INT16PL == 0) +#define MINT5_16PL ~(1 << 15) +#else +#define MINT5_16PL 0xFFFF +#endif + +#define MINT5 (MINT5_1PL & MINT5_2PL & MINT5_3PL & MINT5_4PL & \ + MINT5_5PL & MINT5_6PL & MINT5_7PL & MINT5_8PL & \ + MINT5_9PL & MINT5_10PL & MINT5_11PL & MINT5_12PL & \ + MINT5_13PL & MINT5_14PL & MINT5_15PL & MINT5_16PL) +// End Of MINT5. + +// Beginning of MINT6: +#if (INT1PL >= INT6PL) || (INT1PL == 0) +#define MINT6_1PL ~(1 << 0) +#else +#define MINT6_1PL 0xFFFF +#endif + +#if (INT2PL >= INT6PL) || (INT2PL == 0) +#define MINT6_2PL ~(1 << 1) +#else +#define MINT6_2PL 0xFFFF +#endif + +#if (INT3PL >= INT6PL) || (INT3PL == 0) +#define MINT6_3PL ~(1 << 2) +#else +#define MINT6_3PL 0xFFFF +#endif + +#if (INT4PL >= INT6PL) || (INT4PL == 0) +#define MINT6_4PL ~(1 << 3) +#else +#define MINT6_4PL 0xFFFF +#endif + +#if (INT5PL >= INT6PL) || (INT5PL == 0) +#define MINT6_5PL ~(1 << 4) +#else +#define MINT6_5PL 0xFFFF +#endif + +#if (INT6PL == 0) +#define MINT6_6PL ~(1 << 5) +#else +#define MINT6_6PL 0xFFFF +#endif + +#if (INT7PL >= INT6PL) || (INT7PL == 0) +#define MINT6_7PL ~(1 << 6) +#else +#define MINT6_7PL 0xFFFF +#endif + +#if (INT8PL >= INT6PL) || (INT8PL == 0) +#define MINT6_8PL ~(1 << 7) +#else +#define MINT6_8PL 0xFFFF +#endif + +#if (INT9PL >= INT6PL) || (INT9PL == 0) +#define MINT6_9PL ~(1 << 8) +#else +#define MINT6_9PL 0xFFFF +#endif + +#if (INT10PL >= INT6PL) || (INT10PL == 0) +#define MINT6_10PL ~(1 << 9) +#else +#define MINT6_10PL 0xFFFF +#endif + +#if (INT11PL >= INT6PL) || (INT11PL == 0) +#define MINT6_11PL ~(1 << 10) +#else +#define MINT6_11PL 0xFFFF +#endif + +#if (INT12PL >= INT6PL) || (INT12PL == 0) +#define MINT6_12PL ~(1 << 11) +#else +#define MINT6_12PL 0xFFFF +#endif + +#if (INT13PL >= INT6PL) || (INT13PL == 0) +#define MINT6_13PL ~(1 << 12) +#else +#define MINT6_13PL 0xFFFF +#endif + +#if (INT14PL >= INT6PL) || (INT14PL == 0) +#define MINT6_14PL ~(1 << 13) +#else +#define MINT6_14PL 0xFFFF +#endif + +#if (INT15PL >= INT6PL) || (INT15PL == 0) +#define MINT6_15PL ~(1 << 14) +#else +#define MINT6_15PL 0xFFFF +#endif + +#if (INT16PL >= INT6PL) || (INT16PL == 0) +#define MINT6_16PL ~(1 << 15) +#else +#define MINT6_16PL 0xFFFF +#endif + +#define MINT6 (MINT6_1PL & MINT6_2PL & MINT6_3PL & MINT6_4PL & \ + MINT6_5PL & MINT6_6PL & MINT6_7PL & MINT6_8PL & \ + MINT6_9PL & MINT6_10PL & MINT6_11PL & MINT6_12PL & \ + MINT6_13PL & MINT6_14PL & MINT6_15PL & MINT6_16PL) +// End Of MINT6. + +// Beginning of MINT7: +#if (INT1PL >= INT7PL) || (INT1PL == 0) +#define MINT7_1PL ~(1 << 0) +#else +#define MINT7_1PL 0xFFFF +#endif + +#if (INT2PL >= INT7PL) || (INT2PL == 0) +#define MINT7_2PL ~(1 << 1) +#else +#define MINT7_2PL 0xFFFF +#endif + +#if (INT3PL >= INT7PL) || (INT3PL == 0) +#define MINT7_3PL ~(1 << 2) +#else +#define MINT7_3PL 0xFFFF +#endif + +#if (INT4PL >= INT7PL) || (INT4PL == 0) +#define MINT7_4PL ~(1 << 3) +#else +#define MINT7_4PL 0xFFFF +#endif + +#if (INT5PL >= INT7PL) || (INT5PL == 0) +#define MINT7_5PL ~(1 << 4) +#else +#define MINT7_5PL 0xFFFF +#endif + +#if (INT6PL >= INT7PL) || (INT6PL == 0) +#define MINT7_6PL ~(1 << 5) +#else +#define MINT7_6PL 0xFFFF +#endif + +#if (INT7PL == 0) +#define MINT7_7PL ~(1 << 6) +#else +#define MINT7_7PL 0xFFFF +#endif + +#if (INT8PL >= INT7PL) || (INT8PL == 0) +#define MINT7_8PL ~(1 << 7) +#else +#define MINT7_8PL 0xFFFF +#endif + +#if (INT9PL >= INT7PL) || (INT9PL == 0) +#define MINT7_9PL ~(1 << 8) +#else +#define MINT7_9PL 0xFFFF +#endif + +#if (INT10PL >= INT7PL) || (INT10PL == 0) +#define MINT7_10PL ~(1 << 9) +#else +#define MINT7_10PL 0xFFFF +#endif + +#if (INT11PL >= INT7PL) || (INT11PL == 0) +#define MINT7_11PL ~(1 << 10) +#else +#define MINT7_11PL 0xFFFF +#endif + +#if (INT12PL >= INT7PL) || (INT12PL == 0) +#define MINT7_12PL ~(1 << 11) +#else +#define MINT7_12PL 0xFFFF +#endif + +#if (INT13PL >= INT7PL) || (INT13PL == 0) +#define MINT7_13PL ~(1 << 12) +#else +#define MINT7_13PL 0xFFFF +#endif + +#if (INT14PL >= INT7PL) || (INT14PL == 0) +#define MINT7_14PL ~(1 << 13) +#else +#define MINT7_14PL 0xFFFF +#endif + +#if (INT15PL >= INT7PL) || (INT15PL == 0) +#define MINT7_15PL ~(1 << 14) +#else +#define MINT7_15PL 0xFFFF +#endif + +#if (INT16PL >= INT7PL) || (INT16PL == 0) +#define MINT7_16PL ~(1 << 15) +#else +#define MINT7_16PL 0xFFFF +#endif + +#define MINT7 (MINT7_1PL & MINT7_2PL & MINT7_3PL & MINT7_4PL & \ + MINT7_5PL & MINT7_6PL & MINT7_7PL & MINT7_8PL & \ + MINT7_9PL & MINT7_10PL & MINT7_11PL & MINT7_12PL & \ + MINT7_13PL & MINT7_14PL & MINT7_15PL & MINT7_16PL) +// End Of MINT7. + +// Beginning of MINT8: +#if (INT1PL >= INT8PL) || (INT1PL == 0) +#define MINT8_1PL ~(1 << 0) +#else +#define MINT8_1PL 0xFFFF +#endif + +#if (INT2PL >= INT8PL) || (INT2PL == 0) +#define MINT8_2PL ~(1 << 1) +#else +#define MINT8_2PL 0xFFFF +#endif + +#if (INT3PL >= INT8PL) || (INT3PL == 0) +#define MINT8_3PL ~(1 << 2) +#else +#define MINT8_3PL 0xFFFF +#endif + +#if (INT4PL >= INT8PL) || (INT4PL == 0) +#define MINT8_4PL ~(1 << 3) +#else +#define MINT8_4PL 0xFFFF +#endif + +#if (INT5PL >= INT8PL) || (INT5PL == 0) +#define MINT8_5PL ~(1 << 4) +#else +#define MINT8_5PL 0xFFFF +#endif + +#if (INT6PL >= INT8PL) || (INT6PL == 0) +#define MINT8_6PL ~(1 << 5) +#else +#define MINT8_6PL 0xFFFF +#endif + +#if (INT7PL >= INT8PL) || (INT7PL == 0) +#define MINT8_7PL ~(1 << 6) +#else +#define MINT8_7PL 0xFFFF +#endif + +#if (INT8PL == 0) +#define MINT8_8PL ~(1 << 7) +#else +#define MINT8_8PL 0xFFFF +#endif + +#if (INT9PL >= INT8PL) || (INT9PL == 0) +#define MINT8_9PL ~(1 << 8) +#else +#define MINT8_9PL 0xFFFF +#endif + +#if (INT10PL >= INT8PL) || (INT10PL == 0) +#define MINT8_10PL ~(1 << 9) +#else +#define MINT8_10PL 0xFFFF +#endif + +#if (INT11PL >= INT8PL) || (INT11PL == 0) +#define MINT8_11PL ~(1 << 10) +#else +#define MINT8_11PL 0xFFFF +#endif + +#if (INT12PL >= INT8PL) || (INT12PL == 0) +#define MINT8_12PL ~(1 << 11) +#else +#define MINT8_12PL 0xFFFF +#endif + +#if (INT13PL >= INT8PL) || (INT13PL == 0) +#define MINT8_13PL ~(1 << 12) +#else +#define MINT8_13PL 0xFFFF +#endif + +#if (INT14PL >= INT8PL) || (INT14PL == 0) +#define MINT8_14PL ~(1 << 13) +#else +#define MINT8_14PL 0xFFFF +#endif + +#if (INT15PL >= INT8PL) || (INT15PL == 0) +#define MINT8_15PL ~(1 << 14) +#else +#define MINT8_15PL 0xFFFF +#endif + +#if (INT16PL >= INT8PL) || (INT16PL == 0) +#define MINT8_16PL ~(1 << 15) +#else +#define MINT8_16PL 0xFFFF +#endif + +#define MINT8 (MINT8_1PL & MINT8_2PL & MINT8_3PL & MINT8_4PL & \ + MINT8_5PL & MINT8_6PL & MINT8_7PL & MINT8_8PL & \ + MINT8_9PL & MINT8_10PL & MINT8_11PL & MINT8_12PL & \ + MINT8_13PL & MINT8_14PL & MINT8_15PL & MINT8_16PL) +// End Of MINT8. + +// Beginning of MINT9: +#if (INT1PL >= INT9PL) || (INT1PL == 0) +#define MINT9_1PL ~(1 << 0) +#else +#define MINT9_1PL 0xFFFF +#endif + +#if (INT2PL >= INT9PL) || (INT2PL == 0) +#define MINT9_2PL ~(1 << 1) +#else +#define MINT9_2PL 0xFFFF +#endif + +#if (INT3PL >= INT9PL) || (INT3PL == 0) +#define MINT9_3PL ~(1 << 2) +#else +#define MINT9_3PL 0xFFFF +#endif + +#if (INT4PL >= INT9PL) || (INT4PL == 0) +#define MINT9_4PL ~(1 << 3) +#else +#define MINT9_4PL 0xFFFF +#endif + +#if (INT5PL >= INT9PL) || (INT5PL == 0) +#define MINT9_5PL ~(1 << 4) +#else +#define MINT9_5PL 0xFFFF +#endif + +#if (INT6PL >= INT9PL) || (INT6PL == 0) +#define MINT9_6PL ~(1 << 5) +#else +#define MINT9_6PL 0xFFFF +#endif + +#if (INT7PL >= INT9PL) || (INT7PL == 0) +#define MINT9_7PL ~(1 << 6) +#else +#define MINT9_7PL 0xFFFF +#endif + +#if (INT8PL >= INT9PL) || (INT8PL == 0) +#define MINT9_8PL ~(1 << 7) +#else +#define MINT9_8PL 0xFFFF +#endif + +#if (INT9PL == 0) +#define MINT9_9PL ~(1 << 8) +#else +#define MINT9_9PL 0xFFFF +#endif + +#if (INT10PL >= INT9PL) || (INT10PL == 0) +#define MINT9_10PL ~(1 << 9) +#else +#define MINT9_10PL 0xFFFF +#endif + +#if (INT11PL >= INT9PL) || (INT11PL == 0) +#define MINT9_11PL ~(1 << 10) +#else +#define MINT9_11PL 0xFFFF +#endif + +#if (INT12PL >= INT9PL) || (INT12PL == 0) +#define MINT9_12PL ~(1 << 11) +#else +#define MINT9_12PL 0xFFFF +#endif + +#if (INT13PL >= INT9PL) || (INT13PL == 0) +#define MINT9_13PL ~(1 << 12) +#else +#define MINT9_13PL 0xFFFF +#endif + +#if (INT14PL >= INT9PL) || (INT14PL == 0) +#define MINT9_14PL ~(1 << 13) +#else +#define MINT9_14PL 0xFFFF +#endif + +#if (INT15PL >= INT9PL) || (INT15PL == 0) +#define MINT9_15PL ~(1 << 14) +#else +#define MINT9_15PL 0xFFFF +#endif + +#if (INT16PL >= INT9PL) || (INT16PL == 0) +#define MINT9_16PL ~(1 << 15) +#else +#define MINT9_16PL 0xFFFF +#endif + +#define MINT9 (MINT9_1PL & MINT9_2PL & MINT9_3PL & MINT9_4PL & \ + MINT9_5PL & MINT9_6PL & MINT9_7PL & MINT9_8PL & \ + MINT9_9PL & MINT9_10PL & MINT9_11PL & MINT9_12PL & \ + MINT9_13PL & MINT9_14PL & MINT9_15PL & MINT9_16PL) +// End Of MINT9. + +// Beginning of MINT10: +#if (INT1PL >= INT10PL) || (INT1PL == 0) +#define MINT10_1PL ~(1 << 0) +#else +#define MINT10_1PL 0xFFFF +#endif + +#if (INT2PL >= INT10PL) || (INT2PL == 0) +#define MINT10_2PL ~(1 << 1) +#else +#define MINT10_2PL 0xFFFF +#endif + +#if (INT3PL >= INT10PL) || (INT3PL == 0) +#define MINT10_3PL ~(1 << 2) +#else +#define MINT10_3PL 0xFFFF +#endif + +#if (INT4PL >= INT10PL) || (INT4PL == 0) +#define MINT10_4PL ~(1 << 3) +#else +#define MINT10_4PL 0xFFFF +#endif + +#if (INT5PL >= INT10PL) || (INT5PL == 0) +#define MINT10_5PL ~(1 << 4) +#else +#define MINT10_5PL 0xFFFF +#endif + +#if (INT6PL >= INT10PL) || (INT6PL == 0) +#define MINT10_6PL ~(1 << 5) +#else +#define MINT10_6PL 0xFFFF +#endif + +#if (INT7PL >= INT10PL) || (INT7PL == 0) +#define MINT10_7PL ~(1 << 6) +#else +#define MINT10_7PL 0xFFFF +#endif + +#if (INT8PL >= INT10PL) || (INT8PL == 0) +#define MINT10_8PL ~(1 << 7) +#else +#define MINT10_8PL 0xFFFF +#endif + +#if (INT9PL >= INT10PL) || (INT9PL == 0) +#define MINT10_9PL ~(1 << 8) +#else +#define MINT10_9PL 0xFFFF +#endif + +#if (INT10PL == 0) +#define MINT10_10PL ~(1 << 9) +#else +#define MINT10_10PL 0xFFFF +#endif + +#if (INT11PL >= INT10PL) || (INT11PL == 0) +#define MINT10_11PL ~(1 << 10) +#else +#define MINT10_11PL 0xFFFF +#endif + +#if (INT12PL >= INT10PL) || (INT12PL == 0) +#define MINT10_12PL ~(1 << 11) +#else +#define MINT10_12PL 0xFFFF +#endif + +#if (INT13PL >= INT10PL) || (INT13PL == 0) +#define MINT10_13PL ~(1 << 12) +#else +#define MINT10_13PL 0xFFFF +#endif + +#if (INT14PL >= INT10PL) || (INT14PL == 0) +#define MINT10_14PL ~(1 << 13) +#else +#define MINT10_14PL 0xFFFF +#endif + +#if (INT15PL >= INT10PL) || (INT15PL == 0) +#define MINT10_15PL ~(1 << 14) +#else +#define MINT10_15PL 0xFFFF +#endif + +#if (INT16PL >= INT10PL) || (INT16PL == 0) +#define MINT10_16PL ~(1 << 15) +#else +#define MINT10_16PL 0xFFFF +#endif + +#define MINT10 (MINT10_1PL & MINT10_2PL & MINT10_3PL & MINT10_4PL & \ + MINT10_5PL & MINT10_6PL & MINT10_7PL & MINT10_8PL & \ + MINT10_9PL & MINT10_10PL & MINT10_11PL & MINT10_12PL & \ + MINT10_13PL & MINT10_14PL & MINT10_15PL & MINT10_16PL) +// End Of MINT10. + +// Beginning of MINT11: +#if (INT1PL >= INT11PL) || (INT1PL == 0) +#define MINT11_1PL ~(1 << 0) +#else +#define MINT11_1PL 0xFFFF +#endif + +#if (INT2PL >= INT11PL) || (INT2PL == 0) +#define MINT11_2PL ~(1 << 1) +#else +#define MINT11_2PL 0xFFFF +#endif + +#if (INT3PL >= INT11PL) || (INT3PL == 0) +#define MINT11_3PL ~(1 << 2) +#else +#define MINT11_3PL 0xFFFF +#endif + +#if (INT4PL >= INT11PL) || (INT4PL == 0) +#define MINT11_4PL ~(1 << 3) +#else +#define MINT11_4PL 0xFFFF +#endif + +#if (INT5PL >= INT11PL) || (INT5PL == 0) +#define MINT11_5PL ~(1 << 4) +#else +#define MINT11_5PL 0xFFFF +#endif + +#if (INT6PL >= INT11PL) || (INT6PL == 0) +#define MINT11_6PL ~(1 << 5) +#else +#define MINT11_6PL 0xFFFF +#endif + +#if (INT7PL >= INT11PL) || (INT7PL == 0) +#define MINT11_7PL ~(1 << 6) +#else +#define MINT11_7PL 0xFFFF +#endif + +#if (INT8PL >= INT11PL) || (INT8PL == 0) +#define MINT11_8PL ~(1 << 7) +#else +#define MINT11_8PL 0xFFFF +#endif + +#if (INT9PL >= INT11PL) || (INT9PL == 0) +#define MINT11_9PL ~(1 << 8) +#else +#define MINT11_9PL 0xFFFF +#endif + +#if (INT10PL >= INT11PL) || (INT10PL == 0) +#define MINT11_10PL ~(1 << 9) +#else +#define MINT11_10PL 0xFFFF +#endif + +#if (INT11PL == 0) +#define MINT11_11PL ~(1 << 10) +#else +#define MINT11_11PL 0xFFFF +#endif + +#if (INT12PL >= INT11PL) || (INT12PL == 0) +#define MINT11_12PL ~(1 << 11) +#else +#define MINT11_12PL 0xFFFF +#endif + +#if (INT13PL >= INT11PL) || (INT13PL == 0) +#define MINT11_13PL ~(1 << 12) +#else +#define MINT11_13PL 0xFFFF +#endif + +#if (INT14PL >= INT11PL) || (INT14PL == 0) +#define MINT11_14PL ~(1 << 13) +#else +#define MINT11_14PL 0xFFFF +#endif + +#if (INT15PL >= INT11PL) || (INT15PL == 0) +#define MINT11_15PL ~(1 << 14) +#else +#define MINT11_15PL 0xFFFF +#endif + +#if (INT16PL >= INT11PL) || (INT16PL == 0) +#define MINT11_16PL ~(1 << 15) +#else +#define MINT11_16PL 0xFFFF +#endif + +#define MINT11 (MINT11_1PL & MINT11_2PL & MINT11_3PL & MINT11_4PL & \ + MINT11_5PL & MINT11_6PL & MINT11_7PL & MINT11_8PL & \ + MINT11_9PL & MINT11_10PL & MINT11_11PL & MINT11_12PL & \ + MINT11_13PL & MINT11_14PL & MINT11_15PL & MINT11_16PL) +// End Of MINT11. + +// Beginning of MINT12: +#if (INT1PL >= INT12PL) || (INT1PL == 0) +#define MINT12_1PL ~(1 << 0) +#else +#define MINT12_1PL 0xFFFF +#endif + +#if (INT2PL >= INT12PL) || (INT2PL == 0) +#define MINT12_2PL ~(1 << 1) +#else +#define MINT12_2PL 0xFFFF +#endif + +#if (INT3PL >= INT12PL) || (INT3PL == 0) +#define MINT12_3PL ~(1 << 2) +#else +#define MINT12_3PL 0xFFFF +#endif + +#if (INT4PL >= INT12PL) || (INT4PL == 0) +#define MINT12_4PL ~(1 << 3) +#else +#define MINT12_4PL 0xFFFF +#endif + +#if (INT5PL >= INT12PL) || (INT5PL == 0) +#define MINT12_5PL ~(1 << 4) +#else +#define MINT12_5PL 0xFFFF +#endif + +#if (INT6PL >= INT12PL) || (INT6PL == 0) +#define MINT12_6PL ~(1 << 5) +#else +#define MINT12_6PL 0xFFFF +#endif + +#if (INT7PL >= INT12PL) || (INT7PL == 0) +#define MINT12_7PL ~(1 << 6) +#else +#define MINT12_7PL 0xFFFF +#endif + +#if (INT8PL >= INT12PL) || (INT8PL == 0) +#define MINT12_8PL ~(1 << 7) +#else +#define MINT12_8PL 0xFFFF +#endif + +#if (INT9PL >= INT12PL) || (INT9PL == 0) +#define MINT12_9PL ~(1 << 8) +#else +#define MINT12_9PL 0xFFFF +#endif + +#if (INT10PL >= INT12PL) || (INT10PL == 0) +#define MINT12_10PL ~(1 << 9) +#else +#define MINT12_10PL 0xFFFF +#endif + +#if (INT11PL >= INT12PL) || (INT11PL == 0) +#define MINT12_11PL ~(1 << 10) +#else +#define MINT12_11PL 0xFFFF +#endif + +#if (INT12PL == 0) +#define MINT12_12PL ~(1 << 11) +#else +#define MINT12_12PL 0xFFFF +#endif + +#if (INT13PL >= INT12PL) || (INT13PL == 0) +#define MINT12_13PL ~(1 << 12) +#else +#define MINT12_13PL 0xFFFF +#endif + +#if (INT14PL >= INT12PL) || (INT14PL == 0) +#define MINT12_14PL ~(1 << 13) +#else +#define MINT12_14PL 0xFFFF +#endif + +#if (INT15PL >= INT12PL) || (INT15PL == 0) +#define MINT12_15PL ~(1 << 14) +#else +#define MINT12_15PL 0xFFFF +#endif + +#if (INT16PL >= INT12PL) || (INT16PL == 0) +#define MINT12_16PL ~(1 << 15) +#else +#define MINT12_16PL 0xFFFF +#endif + +#define MINT12 (MINT12_1PL & MINT12_2PL & MINT12_3PL & MINT12_4PL & \ + MINT12_5PL & MINT12_6PL & MINT12_7PL & MINT12_8PL & \ + MINT12_9PL & MINT12_10PL & MINT12_11PL & MINT12_12PL & \ + MINT12_13PL & MINT12_14PL & MINT12_15PL & MINT12_16PL) +// End Of MINT12. + +// Beginning of MINT13: +#if (INT1PL >= INT13PL) || (INT1PL == 0) +#define MINT13_1PL ~(1 << 0) +#else +#define MINT13_1PL 0xFFFF +#endif + +#if (INT2PL >= INT13PL) || (INT2PL == 0) +#define MINT13_2PL ~(1 << 1) +#else +#define MINT13_2PL 0xFFFF +#endif + +#if (INT3PL >= INT13PL) || (INT3PL == 0) +#define MINT13_3PL ~(1 << 2) +#else +#define MINT13_3PL 0xFFFF +#endif + +#if (INT4PL >= INT13PL) || (INT4PL == 0) +#define MINT13_4PL ~(1 << 3) +#else +#define MINT13_4PL 0xFFFF +#endif + +#if (INT5PL >= INT13PL) || (INT5PL == 0) +#define MINT13_5PL ~(1 << 4) +#else +#define MINT13_5PL 0xFFFF +#endif + +#if (INT6PL >= INT13PL) || (INT6PL == 0) +#define MINT13_6PL ~(1 << 5) +#else +#define MINT13_6PL 0xFFFF +#endif + +#if (INT7PL >= INT13PL) || (INT7PL == 0) +#define MINT13_7PL ~(1 << 6) +#else +#define MINT13_7PL 0xFFFF +#endif + +#if (INT8PL >= INT13PL) || (INT8PL == 0) +#define MINT13_8PL ~(1 << 7) +#else +#define MINT13_8PL 0xFFFF +#endif + +#if (INT9PL >= INT13PL) || (INT9PL == 0) +#define MINT13_9PL ~(1 << 8) +#else +#define MINT13_9PL 0xFFFF +#endif + +#if (INT10PL >= INT13PL) || (INT10PL == 0) +#define MINT13_10PL ~(1 << 9) +#else +#define MINT13_10PL 0xFFFF +#endif + +#if (INT11PL >= INT13PL) || (INT11PL == 0) +#define MINT13_11PL ~(1 << 10) +#else +#define MINT13_11PL 0xFFFF +#endif + +#define MINT13_12PL ~(1 << 11) + +#if (INT13PL == 0) +#define MINT13_13PL ~(1 << 12) +#else +#define MINT13_13PL 0xFFFF +#endif + +#if (INT14PL >= INT13PL) || (INT14PL == 0) +#define MINT13_14PL ~(1 << 13) +#else +#define MINT13_14PL 0xFFFF +#endif + +#if (INT15PL >= INT13PL) || (INT15PL == 0) +#define MINT13_15PL ~(1 << 14) +#else +#define MINT13_15PL 0xFFFF +#endif + +#if (INT16PL >= INT13PL) || (INT16PL == 0) +#define MINT13_16PL ~(1 << 15) +#else +#define MINT13_16PL 0xFFFF +#endif + +#define MINT13 (MINT13_1PL & MINT13_2PL & MINT13_3PL & MINT13_4PL & \ + MINT13_5PL & MINT13_6PL & MINT13_7PL & MINT13_8PL & \ + MINT13_9PL & MINT13_10PL & MINT13_11PL & MINT13_12PL & \ + MINT13_13PL & MINT13_14PL & MINT13_15PL & MINT13_16PL) +// End Of MINT13. + +// Beginning of MINT14: +#if (INT1PL >= INT14PL) || (INT1PL == 0) +#define MINT14_1PL ~(1 << 0) +#else +#define MINT14_1PL 0xFFFF +#endif + +#if (INT2PL >= INT14PL) || (INT2PL == 0) +#define MINT14_2PL ~(1 << 1) +#else +#define MINT14_2PL 0xFFFF +#endif + +#if (INT3PL >= INT14PL) || (INT3PL == 0) +#define MINT14_3PL ~(1 << 2) +#else +#define MINT14_3PL 0xFFFF +#endif + +#if (INT4PL >= INT14PL) || (INT4PL == 0) +#define MINT14_4PL ~(1 << 3) +#else +#define MINT14_4PL 0xFFFF +#endif + +#if (INT5PL >= INT14PL) || (INT5PL == 0) +#define MINT14_5PL ~(1 << 4) +#else +#define MINT14_5PL 0xFFFF +#endif + +#if (INT6PL >= INT14PL) || (INT6PL == 0) +#define MINT14_6PL ~(1 << 5) +#else +#define MINT14_6PL 0xFFFF +#endif + +#if (INT7PL >= INT14PL) || (INT7PL == 0) +#define MINT14_7PL ~(1 << 6) +#else +#define MINT14_7PL 0xFFFF +#endif + +#if (INT8PL >= INT14PL) || (INT8PL == 0) +#define MINT14_8PL ~(1 << 7) +#else +#define MINT14_8PL 0xFFFF +#endif + +#if (INT9PL >= INT14PL) || (INT9PL == 0) +#define MINT14_9PL ~(1 << 8) +#else +#define MINT14_9PL 0xFFFF +#endif + +#if (INT10PL >= INT14PL) || (INT10PL == 0) +#define MINT14_10PL ~(1 << 9) +#else +#define MINT14_10PL 0xFFFF +#endif + +#if (INT11PL >= INT14PL) || (INT11PL == 0) +#define MINT14_11PL ~(1 << 10) +#else +#define MINT14_11PL 0xFFFF +#endif + +#if (INT12PL >= INT14PL) || (INT12PL == 0) +#define MINT14_12PL ~(1 << 11) +#else +#define MINT14_12PL 0xFFFF +#endif + +#if (INT13PL >= INT14PL) || (INT13PL == 0) +#define MINT14_13PL ~(1 << 12) +#else +#define MINT14_13PL 0xFFFF +#endif + +#define MINT14_14PL ~(1 << 13) + +#if (INT15PL >= INT14PL) || (INT15PL == 0) +#define MINT14_15PL ~(1 << 14) +#else +#define MINT14_15PL 0xFFFF +#endif + +#if (INT16PL >= INT14PL) || (INT16PL == 0) +#define MINT14_16PL ~(1 << 15) +#else +#define MINT14_16PL 0xFFFF +#endif + +#define MINT14 (MINT14_1PL & MINT14_2PL & MINT14_3PL & MINT14_4PL & \ + MINT14_5PL & MINT14_6PL & MINT14_7PL & MINT14_8PL & \ + MINT14_9PL & MINT14_10PL & MINT14_11PL & MINT14_12PL & \ + MINT14_13PL & MINT14_14PL & MINT14_15PL & MINT14_16PL) +// End Of MINT14. + +// Beginning of MINT15: +#if (INT1PL >= INT15PL) || (INT1PL == 0) +#define MINT15_1PL ~(1 << 0) +#else +#define MINT15_1PL 0xFFFF +#endif + +#if (INT2PL >= INT15PL) || (INT2PL == 0) +#define MINT15_2PL ~(1 << 1) +#else +#define MINT15_2PL 0xFFFF +#endif + +#if (INT3PL >= INT15PL) || (INT3PL == 0) +#define MINT15_3PL ~(1 << 2) +#else +#define MINT15_3PL 0xFFFF +#endif + +#if (INT4PL >= INT15PL) || (INT4PL == 0) +#define MINT15_4PL ~(1 << 3) +#else +#define MINT15_4PL 0xFFFF +#endif + +#if (INT5PL >= INT15PL) || (INT5PL == 0) +#define MINT15_5PL ~(1 << 4) +#else +#define MINT15_5PL 0xFFFF +#endif + +#if (INT6PL >= INT15PL) || (INT6PL == 0) +#define MINT15_6PL ~(1 << 5) +#else +#define MINT15_6PL 0xFFFF +#endif + +#if (INT7PL >= INT15PL) || (INT7PL == 0) +#define MINT15_7PL ~(1 << 6) +#else +#define MINT15_7PL 0xFFFF +#endif + +#if (INT8PL >= INT15PL) || (INT8PL == 0) +#define MINT15_8PL ~(1 << 7) +#else +#define MINT15_8PL 0xFFFF +#endif + +#if (INT9PL >= INT15PL) || (INT9PL == 0) +#define MINT15_9PL ~(1 << 8) +#else +#define MINT15_9PL 0xFFFF +#endif + +#if (INT10PL >= INT15PL) || (INT10PL == 0) +#define MINT15_10PL ~(1 << 9) +#else +#define MINT15_10PL 0xFFFF +#endif + +#if (INT11PL >= INT15PL) || (INT11PL == 0) +#define MINT15_11PL ~(1 << 10) +#else +#define MINT15_11PL 0xFFFF +#endif + +#if (INT12PL >= INT15PL) || (INT12PL == 0) +#define MINT15_12PL ~(1 << 11) +#else +#define MINT15_12PL 0xFFFF +#endif + +#if (INT13PL >= INT15PL) || (INT13PL == 0) +#define MINT15_13PL ~(1 << 12) +#else +#define MINT15_13PL 0xFFFF +#endif + +#if (INT14PL >= INT15PL) || (INT14PL == 0) +#define MINT15_14PL ~(1 << 13) +#else +#define MINT15_14PL 0xFFFF +#endif + +#define MINT15_15PL ~(1 << 14) + +#if (INT16PL >= INT15PL) || (INT16PL == 0) +#define MINT15_16PL ~(1 << 15) +#else +#define MINT15_16PL 0xFFFF +#endif + +#define MINT15 (MINT15_1PL & MINT15_2PL & MINT15_3PL & MINT15_4PL & \ + MINT15_5PL & MINT15_6PL & MINT15_7PL & MINT15_8PL & \ + MINT15_9PL & MINT15_10PL & MINT15_11PL & MINT15_12PL & \ + MINT15_13PL & MINT15_14PL & MINT15_15PL & MINT15_16PL) +// End Of MINT15. + +// Beginning of MINT16: +#if (INT1PL >= INT16PL) || (INT1PL == 0) +#define MINT16_1PL ~(1 << 0) +#else +#define MINT16_1PL 0xFFFF +#endif + +#if (INT2PL >= INT16PL) || (INT2PL == 0) +#define MINT16_2PL ~(1 << 1) +#else +#define MINT16_2PL 0xFFFF +#endif + +#if (INT3PL >= INT16PL) || (INT3PL == 0) +#define MINT16_3PL ~(1 << 2) +#else +#define MINT16_3PL 0xFFFF +#endif + +#if (INT4PL >= INT16PL) || (INT4PL == 0) +#define MINT16_4PL ~(1 << 3) +#else +#define MINT16_4PL 0xFFFF +#endif + +#if (INT5PL >= INT16PL) || (INT5PL == 0) +#define MINT16_5PL ~(1 << 4) +#else +#define MINT16_5PL 0xFFFF +#endif + +#if (INT6PL >= INT16PL) || (INT6PL == 0) +#define MINT16_6PL ~(1 << 5) +#else +#define MINT16_6PL 0xFFFF +#endif + +#if (INT7PL >= INT16PL) || (INT7PL == 0) +#define MINT16_7PL ~(1 << 6) +#else +#define MINT16_7PL 0xFFFF +#endif + +#if (INT8PL >= INT16PL) || (INT8PL == 0) +#define MINT16_8PL ~(1 << 7) +#else +#define MINT16_8PL 0xFFFF +#endif + +#if (INT9PL >= INT16PL) || (INT9PL == 0) +#define MINT16_9PL ~(1 << 8) +#else +#define MINT16_9PL 0xFFFF +#endif + +#if (INT10PL >= INT16PL) || (INT10PL == 0) +#define MINT16_10PL ~(1 << 9) +#else +#define MINT16_10PL 0xFFFF +#endif + +#if (INT11PL >= INT16PL) || (INT11PL == 0) +#define MINT16_11PL ~(1 << 10) +#else +#define MINT16_11PL 0xFFFF +#endif + +#if (INT12PL >= INT16PL) || (INT12PL == 0) +#define MINT16_12PL ~(1 << 11) +#else +#define MINT16_12PL 0xFFFF +#endif + +#if (INT13PL >= INT16PL) || (INT13PL == 0) +#define MINT16_13PL ~(1 << 12) +#else +#define MINT16_13PL 0xFFFF +#endif + +#if (INT14PL >= INT16PL) || (INT14PL == 0) +#define MINT16_14PL ~(1 << 13) +#else +#define MINT16_14PL 0xFFFF +#endif + +#if (INT15PL >= INT16PL) || (INT15PL == 0) +#define MINT16_15PL ~(1 << 14) +#else +#define MINT16_15PL 0xFFFF +#endif + +#define MINT16_16PL ~(1 << 15) + +#define MINT16 (MINT16_1PL & MINT16_2PL & MINT16_3PL & MINT16_4PL & \ + MINT16_5PL & MINT16_6PL & MINT16_7PL & MINT16_8PL & \ + MINT16_9PL & MINT16_10PL & MINT16_11PL & MINT16_12PL & \ + MINT16_13PL & MINT16_14PL & MINT16_15PL & MINT16_16PL) +// End Of MINT16. + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG11 to MG18: + +// Beginning of MG11: +#if (G12PL >= G11PL) || (G12PL == 0) +#define MG11_12PL ~(1 << 1) +#else +#define MG11_12PL 0xFFFF +#endif + +#if (G13PL >= G11PL) || (G13PL == 0) +#define MG11_13PL ~(1 << 2) +#else +#define MG11_13PL 0xFFFF +#endif + +#if (G14PL >= G11PL) || (G14PL == 0) +#define MG11_14PL ~(1 << 3) +#else +#define MG11_14PL 0xFFFF +#endif + +#if (G15PL >= G11PL) || (G15PL == 0) +#define MG11_15PL ~(1 << 4) +#else +#define MG11_15PL 0xFFFF +#endif + +#if (G16PL >= G11PL) || (G16PL == 0) +#define MG11_16PL ~(1 << 5) +#else +#define MG11_16PL 0xFFFF +#endif + +#if (G17PL >= G11PL) || (G17PL == 0) +#define MG11_17PL ~(1 << 6) +#else +#define MG11_17PL 0xFFFF +#endif + +#if (G18PL >= G11PL) || (G18PL == 0) +#define MG11_18PL ~(1 << 7) +#else +#define MG11_18PL 0xFFFF +#endif + +#define MG11_11PL 0x00FE +#define MG11 (MG11_11PL & MG11_12PL & MG11_13PL & MG11_14PL & \ + MG11_15PL & MG11_16PL & MG11_17PL & MG11_18PL) +// End of MG11: + +// Beginning of MG12: +#if (G11PL >= G12PL) || (G11PL == 0) +#define MG12_11PL ~(1) +#else +#define MG12_11PL 0xFFFF +#endif +#if (G13PL >= G12PL) || (G13PL == 0) +#define MG12_13PL ~(1 << 2) +#else +#define MG12_13PL 0xFFFF +#endif +#if (G14PL >= G12PL) || (G14PL == 0) +#define MG12_14PL ~(1 << 3) +#else +#define MG12_14PL 0xFFFF +#endif +#if (G15PL >= G12PL) || (G15PL == 0) +#define MG12_15PL ~(1 << 4) +#else +#define MG12_15PL 0xFFFF +#endif +#if (G16PL >= G12PL) || (G16PL == 0) +#define MG12_16PL ~(1 << 5) +#else +#define MG12_16PL 0xFFFF +#endif +#if (G17PL >= G12PL) || (G17PL == 0) +#define MG12_17PL ~(1 << 6) +#else +#define MG12_17PL 0xFFFF +#endif +#if (G18PL >= G12PL) || (G18PL == 0) +#define MG12_18PL ~(1 << 7) +#else +#define MG12_18PL 0xFFFF +#endif +#define MG12_12PL 0x00FD +#define MG12 (MG12_11PL & MG12_12PL & MG12_13PL & MG12_14PL & \ + MG12_15PL & MG12_16PL & MG12_17PL & MG12_18PL) +// End of MG12: + +// Beginning of MG13: +#if (G11PL >= G13PL) || (G11PL == 0) +#define MG13_11PL ~(1) +#else +#define MG13_11PL 0xFFFF +#endif +#if (G12PL >= G13PL) || (G12PL == 0) +#define MG13_12PL ~(1 << 1) +#else +#define MG13_12PL 0xFFFF +#endif +#if (G14PL >= G13PL) || (G14PL == 0) +#define MG13_14PL ~(1 << 3) +#else +#define MG13_14PL 0xFFFF +#endif +#if (G15PL >= G13PL) || (G15PL == 0) +#define MG13_15PL ~(1 << 4) +#else +#define MG13_15PL 0xFFFF +#endif +#if (G16PL >= G13PL) || (G16PL == 0) +#define MG13_16PL ~(1 << 5) +#else +#define MG13_16PL 0xFFFF +#endif +#if (G17PL >= G13PL) || (G17PL == 0) +#define MG13_17PL ~(1 << 6) +#else +#define MG13_17PL 0xFFFF +#endif +#if (G18PL >= G13PL) || (G18PL == 0) +#define MG13_18PL ~(1 << 7) +#else +#define MG13_18PL 0xFFFF +#endif +#define MG13_13PL 0x00FB +#define MG13 (MG13_11PL & MG13_12PL & MG13_13PL & MG13_14PL & \ + MG13_15PL & MG13_16PL & MG13_17PL & MG13_18PL) +// End of MG13: + +// Beginning of MG14: +#if (G11PL >= G14PL) || (G11PL == 0) +#define MG14_11PL ~(1) +#else +#define MG14_11PL 0xFFFF +#endif +#if (G12PL >= G14PL) || (G12PL == 0) +#define MG14_12PL ~(1 << 1) +#else +#define MG14_12PL 0xFFFF +#endif +#if (G13PL >= G14PL) || (G13PL == 0) +#define MG14_13PL ~(1 << 2) +#else +#define MG14_13PL 0xFFFF +#endif +#if (G15PL >= G14PL) || (G15PL == 0) +#define MG14_15PL ~(1 << 4) +#else +#define MG14_15PL 0xFFFF +#endif +#if (G16PL >= G14PL) || (G16PL == 0) +#define MG14_16PL ~(1 << 5) +#else +#define MG14_16PL 0xFFFF +#endif +#if (G17PL >= G14PL) || (G17PL == 0) +#define MG14_17PL ~(1 << 6) +#else +#define MG14_17PL 0xFFFF +#endif +#if (G18PL >= G14PL) || (G18PL == 0) +#define MG14_18PL ~(1 << 7) +#else +#define MG14_18PL 0xFFFF +#endif +#define MG14_14PL 0x00F7 +#define MG14 (MG14_11PL & MG14_12PL & MG14_13PL & MG14_14PL & \ + MG14_15PL & MG14_16PL & MG14_17PL & MG14_18PL) +// End of MG14: + +// Beginning of MG15: +#if (G11PL >= G15PL) || (G11PL == 0) +#define MG15_11PL ~(1) +#else +#define MG15_11PL 0xFFFF +#endif +#if (G12PL >= G15PL) || (G12PL == 0) +#define MG15_12PL ~(1 << 1) +#else +#define MG15_12PL 0xFFFF +#endif +#if (G13PL >= G15PL) || (G13PL == 0) +#define MG15_13PL ~(1 << 2) +#else +#define MG15_13PL 0xFFFF +#endif +#if (G14PL >= G15PL) || (G14PL == 0) +#define MG15_14PL ~(1 << 3) +#else +#define MG15_14PL 0xFFFF +#endif +#if (G16PL >= G15PL) || (G16PL == 0) +#define MG15_16PL ~(1 << 5) +#else +#define MG15_16PL 0xFFFF +#endif +#if (G17PL >= G15PL) || (G17PL == 0) +#define MG15_17PL ~(1 << 6) +#else +#define MG15_17PL 0xFFFF +#endif +#if (G18PL >= G15PL) || (G18PL == 0) +#define MG15_18PL ~(1 << 7) +#else +#define MG15_18PL 0xFFFF +#endif +#define MG15_15PL 0x00EF +#define MG15 (MG15_11PL & MG15_12PL & MG15_13PL & MG15_14PL & \ + MG15_15PL & MG15_16PL & MG15_17PL & MG15_18PL) +// End of MG15: + +// Beginning of MG16: +#if (G11PL >= G16PL) || (G11PL == 0) +#define MG16_11PL ~(1) +#else +#define MG16_11PL 0xFFFF +#endif +#if (G12PL >= G16PL) || (G12PL == 0) +#define MG16_12PL ~(1 << 1) +#else +#define MG16_12PL 0xFFFF +#endif +#if (G13PL >= G16PL) || (G13PL == 0) +#define MG16_13PL ~(1 << 2) +#else +#define MG16_13PL 0xFFFF +#endif +#if (G14PL >= G16PL) || (G14PL == 0) +#define MG16_14PL ~(1 << 3) +#else +#define MG16_14PL 0xFFFF +#endif +#if (G15PL >= G16PL) || (G15PL == 0) +#define MG16_15PL ~(1 << 4) +#else +#define MG16_15PL 0xFFFF +#endif +#if (G17PL >= G16PL) || (G17PL == 0) +#define MG16_17PL ~(1 << 6) +#else +#define MG16_17PL 0xFFFF +#endif +#if (G18PL >= G16PL) || (G18PL == 0) +#define MG16_18PL ~(1 << 7) +#else +#define MG16_18PL 0xFFFF +#endif +#define MG16_16PL 0x00DF +#define MG16 (MG16_11PL & MG16_12PL & MG16_13PL & MG16_14PL & \ + MG16_15PL & MG16_16PL & MG16_17PL & MG16_18PL) +// End of MG16: + +// Beginning of MG17: +#if (G11PL >= G17PL) || (G11PL == 0) +#define MG17_11PL ~(1) +#else +#define MG17_11PL 0xFFFF +#endif +#if (G12PL >= G17PL) || (G12PL == 0) +#define MG17_12PL ~(1 << 1) +#else +#define MG17_12PL 0xFFFF +#endif +#if (G13PL >= G17PL) || (G13PL == 0) +#define MG17_13PL ~(1 << 2) +#else +#define MG17_13PL 0xFFFF +#endif +#if (G14PL >= G17PL) || (G14PL == 0) +#define MG17_14PL ~(1 << 3) +#else +#define MG17_14PL 0xFFFF +#endif +#if (G15PL >= G17PL) || (G15PL == 0) +#define MG17_15PL ~(1 << 4) +#else +#define MG17_15PL 0xFFFF +#endif +#if (G16PL >= G17PL) || (G16PL == 0) +#define MG17_16PL ~(1 << 5) +#else +#define MG17_16PL 0xFFFF +#endif +#if (G18PL >= G17PL) || (G18PL == 0) +#define MG17_18PL ~(1 << 7) +#else +#define MG17_18PL 0xFFFF +#endif +#define MG17_17PL 0x00BF +#define MG17 (MG17_11PL & MG17_12PL & MG17_13PL & MG17_14PL & \ + MG17_15PL & MG17_16PL & MG17_17PL & MG17_18PL) +// End of MG17: + +// Beginning of MG18: +#if (G11PL >= G18PL) || (G11PL == 0) +#define MG18_11PL ~(1) +#else +#define MG18_11PL 0xFFFF +#endif +#if (G12PL >= G18PL) || (G12PL == 0) +#define MG18_12PL ~(1 << 1) +#else +#define MG18_12PL 0xFFFF +#endif +#if (G13PL >= G18PL) || (G13PL == 0) +#define MG18_13PL ~(1 << 2) +#else +#define MG18_13PL 0xFFFF +#endif +#if (G14PL >= G18PL) || (G14PL == 0) +#define MG18_14PL ~(1 << 3) +#else +#define MG18_14PL 0xFFFF +#endif +#if (G15PL >= G18PL) || (G15PL == 0) +#define MG18_15PL ~(1 << 4) +#else +#define MG18_15PL 0xFFFF +#endif +#if (G16PL >= G18PL) || (G16PL == 0) +#define MG18_16PL ~(1 << 5) +#else +#define MG18_16PL 0xFFFF +#endif +#if (G17PL >= G18PL) || (G17PL == 0) +#define MG18_17PL ~(1 << 6) +#else +#define MG18_17PL 0xFFFF +#endif +#define MG18_18PL 0x007F +#define MG18 (MG18_11PL & MG18_12PL & MG18_13PL & MG18_14PL & \ + MG18_15PL & MG18_16PL & MG18_17PL & MG18_18PL) +// End of MG18: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG21 to MG28: +// + +// Beginning of MG21: +#if (G22PL >= G21PL) || (G22PL == 0) +#define MG21_12PL ~(1 << 1) +#else +#define MG21_12PL 0xFFFF +#endif +#if (G23PL >= G21PL) || (G23PL == 0) +#define MG21_13PL ~(1 << 2) +#else +#define MG21_13PL 0xFFFF +#endif +#if (G24PL >= G21PL) || (G24PL == 0) +#define MG21_14PL ~(1 << 3) +#else +#define MG21_14PL 0xFFFF +#endif +#if (G25PL >= G21PL) || (G25PL == 0) +#define MG21_15PL ~(1 << 4) +#else +#define MG21_15PL 0xFFFF +#endif +#if (G26PL >= G21PL) || (G26PL == 0) +#define MG21_16PL ~(1 << 5) +#else +#define MG21_16PL 0xFFFF +#endif +#if (G27PL >= G21PL) || (G27PL == 0) +#define MG21_17PL ~(1 << 6) +#else +#define MG21_17PL 0xFFFF +#endif +#if (G28PL >= G21PL) || (G28PL == 0) +#define MG21_18PL ~(1 << 7) +#else +#define MG21_18PL 0xFFFF +#endif +#define MG21_11PL 0x00FE +#define MG21 (MG21_11PL & MG21_12PL & MG21_13PL & MG21_14PL & \ + MG21_15PL & MG21_16PL & MG21_17PL & MG21_18PL) +// End of MG21: + +// Beginning of MG22: +#if (G21PL >= G22PL) || (G21PL == 0) +#define MG22_11PL ~(1) +#else +#define MG22_11PL 0xFFFF +#endif +#if (G23PL >= G22PL) || (G23PL == 0) +#define MG22_13PL ~(1 << 2) +#else +#define MG22_13PL 0xFFFF +#endif +#if (G24PL >= G22PL) || (G24PL == 0) +#define MG22_14PL ~(1 << 3) +#else +#define MG22_14PL 0xFFFF +#endif +#if (G25PL >= G22PL) || (G25PL == 0) +#define MG22_15PL ~(1 << 4) +#else +#define MG22_15PL 0xFFFF +#endif +#if (G26PL >= G22PL) || (G26PL == 0) +#define MG22_16PL ~(1 << 5) +#else +#define MG22_16PL 0xFFFF +#endif +#if (G27PL >= G22PL) || (G27PL == 0) +#define MG22_17PL ~(1 << 6) +#else +#define MG22_17PL 0xFFFF +#endif +#if (G28PL >= G22PL) || (G28PL == 0) +#define MG22_18PL ~(1 << 7) +#else +#define MG22_18PL 0xFFFF +#endif +#define MG22_12PL 0x00FD +#define MG22 (MG22_11PL & MG22_12PL & MG22_13PL & MG22_14PL & \ + MG22_15PL & MG22_16PL & MG22_17PL & MG22_18PL) +// End of MG22: + +// Beginning of MG23: +#if (G21PL >= G23PL) || (G21PL == 0) +#define MG23_11PL ~(1) +#else +#define MG23_11PL 0xFFFF +#endif +#if (G22PL >= G23PL) || (G22PL == 0) +#define MG23_12PL ~(1 << 1) +#else +#define MG23_12PL 0xFFFF +#endif +#if (G24PL >= G23PL) || (G24PL == 0) +#define MG23_14PL ~(1 << 3) +#else +#define MG23_14PL 0xFFFF +#endif +#if (G25PL >= G23PL) || (G25PL == 0) +#define MG23_15PL ~(1 << 4) +#else +#define MG23_15PL 0xFFFF +#endif +#if (G26PL >= G23PL) || (G26PL == 0) +#define MG23_16PL ~(1 << 5) +#else +#define MG23_16PL 0xFFFF +#endif +#if (G27PL >= G23PL) || (G27PL == 0) +#define MG23_17PL ~(1 << 6) +#else +#define MG23_17PL 0xFFFF +#endif +#if (G28PL >= G23PL) || (G28PL == 0) +#define MG23_18PL ~(1 << 7) +#else +#define MG23_18PL 0xFFFF +#endif +#define MG23_13PL 0x00FB +#define MG23 (MG23_11PL & MG23_12PL & MG23_13PL & MG23_14PL & \ + MG23_15PL & MG23_16PL & MG23_17PL & MG23_18PL) +// End of MG23: + +// Beginning of MG24: +#if (G21PL >= G24PL) || (G21PL == 0) +#define MG24_11PL ~(1) +#else +#define MG24_11PL 0xFFFF +#endif +#if (G22PL >= G24PL) || (G22PL == 0) +#define MG24_12PL ~(1 << 1) +#else +#define MG24_12PL 0xFFFF +#endif +#if (G23PL >= G24PL) || (G23PL == 0) +#define MG24_13PL ~(1 << 2) +#else +#define MG24_13PL 0xFFFF +#endif +#if (G25PL >= G24PL) || (G25PL == 0) +#define MG24_15PL ~(1 << 4) +#else +#define MG24_15PL 0xFFFF +#endif +#if (G26PL >= G24PL) || (G26PL == 0) +#define MG24_16PL ~(1 << 5) +#else +#define MG24_16PL 0xFFFF +#endif +#if (G27PL >= G24PL) || (G27PL == 0) +#define MG24_17PL ~(1 << 6) +#else +#define MG24_17PL 0xFFFF +#endif +#if (G28PL >= G24PL) || (G28PL == 0) +#define MG24_18PL ~(1 << 7) +#else +#define MG24_18PL 0xFFFF +#endif +#define MG24_14PL 0x00F7 +#define MG24 (MG24_11PL & MG24_12PL & MG24_13PL & MG24_14PL & \ + MG24_15PL & MG24_16PL & MG24_17PL & MG24_18PL) +// End of MG24: + +// Beginning of MG25: +#if (G21PL >= G25PL) || (G21PL == 0) +#define MG25_11PL ~(1) +#else +#define MG25_11PL 0xFFFF +#endif +#if (G22PL >= G25PL) || (G22PL == 0) +#define MG25_12PL ~(1 << 1) +#else +#define MG25_12PL 0xFFFF +#endif +#if (G23PL >= G25PL) || (G23PL == 0) +#define MG25_13PL ~(1 << 2) +#else +#define MG25_13PL 0xFFFF +#endif +#if (G24PL >= G25PL) || (G24PL == 0) +#define MG25_14PL ~(1 << 3) +#else +#define MG25_14PL 0xFFFF +#endif +#if (G26PL >= G25PL) || (G26PL == 0) +#define MG25_16PL ~(1 << 5) +#else +#define MG25_16PL 0xFFFF +#endif +#if (G27PL >= G25PL) || (G27PL == 0) +#define MG25_17PL ~(1 << 6) +#else +#define MG25_17PL 0xFFFF +#endif +#if (G28PL >= G25PL) || (G28PL == 0) +#define MG25_18PL ~(1 << 7) +#else +#define MG25_18PL 0xFFFF +#endif +#define MG25_15PL 0x00EF +#define MG25 (MG25_11PL & MG25_12PL & MG25_13PL & MG25_14PL & \ + MG25_15PL & MG25_16PL & MG25_17PL & MG25_18PL) +// End of MG25: + +// Beginning of MG26: +#if (G21PL >= G26PL) || (G21PL == 0) +#define MG26_11PL ~(1) +#else +#define MG26_11PL 0xFFFF +#endif +#if (G22PL >= G26PL) || (G22PL == 0) +#define MG26_12PL ~(1 << 1) +#else +#define MG26_12PL 0xFFFF +#endif +#if (G23PL >= G26PL) || (G23PL == 0) +#define MG26_13PL ~(1 << 2) +#else +#define MG26_13PL 0xFFFF +#endif +#if (G24PL >= G26PL) || (G24PL == 0) +#define MG26_14PL ~(1 << 3) +#else +#define MG26_14PL 0xFFFF +#endif +#if (G25PL >= G26PL) || (G25PL == 0) +#define MG26_15PL ~(1 << 4) +#else +#define MG26_15PL 0xFFFF +#endif +#if (G27PL >= G26PL) || (G27PL == 0) +#define MG26_17PL ~(1 << 6) +#else +#define MG26_17PL 0xFFFF +#endif +#if (G28PL >= G26PL) || (G28PL == 0) +#define MG26_18PL ~(1 << 7) +#else +#define MG26_18PL 0xFFFF +#endif +#define MG26_16PL 0x00DF +#define MG26 (MG26_11PL & MG26_12PL & MG26_13PL & MG26_14PL & \ + MG26_15PL & MG26_16PL & MG26_17PL & MG26_18PL) +// End of MG26: + +// Beginning of MG27: +#if (G21PL >= G27PL) || (G21PL == 0) +#define MG27_11PL ~(1) +#else +#define MG27_11PL 0xFFFF +#endif +#if (G22PL >= G27PL) || (G22PL == 0) +#define MG27_12PL ~(1 << 1) +#else +#define MG27_12PL 0xFFFF +#endif +#if (G23PL >= G27PL) || (G23PL == 0) +#define MG27_13PL ~(1 << 2) +#else +#define MG27_13PL 0xFFFF +#endif +#if (G24PL >= G27PL) || (G24PL == 0) +#define MG27_14PL ~(1 << 3) +#else +#define MG27_14PL 0xFFFF +#endif +#if (G25PL >= G27PL) || (G25PL == 0) +#define MG27_15PL ~(1 << 4) +#else +#define MG27_15PL 0xFFFF +#endif +#if (G26PL >= G27PL) || (G26PL == 0) +#define MG27_16PL ~(1 << 5) +#else +#define MG27_16PL 0xFFFF +#endif +#if (G28PL >= G27PL) || (G28PL == 0) +#define MG27_18PL ~(1 << 7) +#else +#define MG27_18PL 0xFFFF +#endif +#define MG27_17PL 0x00BF +#define MG27 (MG27_11PL & MG27_12PL & MG27_13PL & MG27_14PL & \ + MG27_15PL & MG27_16PL & MG27_17PL & MG27_18PL) +// End of MG27: + +// Beginning of MG28: +#if (G21PL >= G28PL) || (G21PL == 0) +#define MG28_11PL ~(1) +#else +#define MG28_11PL 0xFFFF +#endif +#if (G22PL >= G28PL) || (G22PL == 0) +#define MG28_12PL ~(1 << 1) +#else +#define MG28_12PL 0xFFFF +#endif +#if (G23PL >= G28PL) || (G23PL == 0) +#define MG28_13PL ~(1 << 2) +#else +#define MG28_13PL 0xFFFF +#endif +#if (G24PL >= G28PL) || (G24PL == 0) +#define MG28_14PL ~(1 << 3) +#else +#define MG28_14PL 0xFFFF +#endif +#if (G25PL >= G28PL) || (G25PL == 0) +#define MG28_15PL ~(1 << 4) +#else +#define MG28_15PL 0xFFFF +#endif +#if (G26PL >= G28PL) || (G26PL == 0) +#define MG28_16PL ~(1 << 5) +#else +#define MG28_16PL 0xFFFF +#endif +#if (G27PL >= G28PL) || (G27PL == 0) +#define MG28_17PL ~(1 << 6) +#else +#define MG28_17PL 0xFFFF +#endif +#define MG28_18PL 0x007F +#define MG28 (MG28_11PL & MG28_12PL & MG28_13PL & MG28_14PL & \ + MG28_15PL & MG28_16PL & MG28_17PL & MG28_18PL) +// End of MG28: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG31 to MG38: +// + +// Beginning of MG31: +#if (G32PL >= G31PL) || (G32PL == 0) +#define MG31_12PL ~(1 << 1) +#else +#define MG31_12PL 0xFFFF +#endif +#if (G33PL >= G31PL) || (G33PL == 0) +#define MG31_13PL ~(1 << 2) +#else +#define MG31_13PL 0xFFFF +#endif +#if (G34PL >= G31PL) || (G34PL == 0) +#define MG31_14PL ~(1 << 3) +#else +#define MG31_14PL 0xFFFF +#endif +#if (G35PL >= G31PL) || (G35PL == 0) +#define MG31_15PL ~(1 << 4) +#else +#define MG31_15PL 0xFFFF +#endif +#if (G36PL >= G31PL) || (G36PL == 0) +#define MG31_16PL ~(1 << 5) +#else +#define MG31_16PL 0xFFFF +#endif +#if (G37PL >= G31PL) || (G37PL == 0) +#define MG31_17PL ~(1 << 6) +#else +#define MG31_17PL 0xFFFF +#endif +#if (G38PL >= G31PL) || (G38PL == 0) +#define MG31_18PL ~(1 << 7) +#else +#define MG31_18PL 0xFFFF +#endif +#define MG31_11PL 0x00FE +#define MG31 (MG31_11PL & MG31_12PL & MG31_13PL & MG31_14PL & \ + MG31_15PL & MG31_16PL & MG31_17PL & MG31_18PL) +// End of MG31: + +// Beginning of MG32: +#if (G31PL >= G32PL) || (G31PL == 0) +#define MG32_11PL ~(1) +#else +#define MG32_11PL 0xFFFF +#endif +#if (G33PL >= G32PL) || (G33PL == 0) +#define MG32_13PL ~(1 << 2) +#else +#define MG32_13PL 0xFFFF +#endif +#if (G34PL >= G32PL) || (G34PL == 0) +#define MG32_14PL ~(1 << 3) +#else +#define MG32_14PL 0xFFFF +#endif +#if (G35PL >= G32PL) || (G35PL == 0) +#define MG32_15PL ~(1 << 4) +#else +#define MG32_15PL 0xFFFF +#endif +#if (G36PL >= G32PL) || (G36PL == 0) +#define MG32_16PL ~(1 << 5) +#else +#define MG32_16PL 0xFFFF +#endif +#if (G37PL >= G32PL) || (G37PL == 0) +#define MG32_17PL ~(1 << 6) +#else +#define MG32_17PL 0xFFFF +#endif +#if (G38PL >= G32PL) || (G38PL == 0) +#define MG32_18PL ~(1 << 7) +#else +#define MG32_18PL 0xFFFF +#endif +#define MG32_12PL 0x00FD +#define MG32 (MG32_11PL & MG32_12PL & MG32_13PL & MG32_14PL & \ + MG32_15PL & MG32_16PL & MG32_17PL & MG32_18PL) +// End of MG32: + +// Beginning of MG33: +#if (G31PL >= G33PL) || (G31PL == 0) +#define MG33_11PL ~(1) +#else +#define MG33_11PL 0xFFFF +#endif +#if (G32PL >= G33PL) || (G32PL == 0) +#define MG33_12PL ~(1 << 1) +#else +#define MG33_12PL 0xFFFF +#endif +#if (G34PL >= G33PL) || (G34PL == 0) +#define MG33_14PL ~(1 << 3) +#else +#define MG33_14PL 0xFFFF +#endif +#if (G35PL >= G33PL) || (G35PL == 0) +#define MG33_15PL ~(1 << 4) +#else +#define MG33_15PL 0xFFFF +#endif +#if (G36PL >= G33PL) || (G36PL == 0) +#define MG33_16PL ~(1 << 5) +#else +#define MG33_16PL 0xFFFF +#endif +#if (G37PL >= G33PL) || (G37PL == 0) +#define MG33_17PL ~(1 << 6) +#else +#define MG33_17PL 0xFFFF +#endif +#if (G38PL >= G33PL) || (G38PL == 0) +#define MG33_18PL ~(1 << 7) +#else +#define MG33_18PL 0xFFFF +#endif +#define MG33_13PL 0x00FB +#define MG33 (MG33_11PL & MG33_12PL & MG33_13PL & MG33_14PL & \ + MG33_15PL & MG33_16PL & MG33_17PL & MG33_18PL) +// End of MG33: + +// Beginning of MG34: +#if (G31PL >= G34PL) || (G31PL == 0) +#define MG34_11PL ~(1) +#else +#define MG34_11PL 0xFFFF +#endif +#if (G32PL >= G34PL) || (G32PL == 0) +#define MG34_12PL ~(1 << 1) +#else +#define MG34_12PL 0xFFFF +#endif +#if (G33PL >= G34PL) || (G33PL == 0) +#define MG34_13PL ~(1 << 2) +#else +#define MG34_13PL 0xFFFF +#endif +#if (G35PL >= G34PL) || (G35PL == 0) +#define MG34_15PL ~(1 << 4) +#else +#define MG34_15PL 0xFFFF +#endif +#if (G36PL >= G34PL) || (G36PL == 0) +#define MG34_16PL ~(1 << 5) +#else +#define MG34_16PL 0xFFFF +#endif +#if (G37PL >= G34PL) || (G37PL == 0) +#define MG34_17PL ~(1 << 6) +#else +#define MG34_17PL 0xFFFF +#endif +#if (G38PL >= G34PL) || (G38PL == 0) +#define MG34_18PL ~(1 << 7) +#else +#define MG34_18PL 0xFFFF +#endif +#define MG34_14PL 0x00F7 +#define MG34 (MG34_11PL & MG34_12PL & MG34_13PL & MG34_14PL & \ + MG34_15PL & MG34_16PL & MG34_17PL & MG34_18PL) +// End of MG34: + +// Beginning of MG35: +#if (G31PL >= G35PL) || (G31PL == 0) +#define MG35_11PL ~(1) +#else +#define MG35_11PL 0xFFFF +#endif +#if (G32PL >= G35PL) || (G32PL == 0) +#define MG35_12PL ~(1 << 1) +#else +#define MG35_12PL 0xFFFF +#endif +#if (G33PL >= G35PL) || (G33PL == 0) +#define MG35_13PL ~(1 << 2) +#else +#define MG35_13PL 0xFFFF +#endif +#if (G34PL >= G35PL) || (G34PL == 0) +#define MG35_14PL ~(1 << 3) +#else +#define MG35_14PL 0xFFFF +#endif +#if (G36PL >= G35PL) || (G36PL == 0) +#define MG35_16PL ~(1 << 5) +#else +#define MG35_16PL 0xFFFF +#endif +#if (G37PL >= G35PL) || (G37PL == 0) +#define MG35_17PL ~(1 << 6) +#else +#define MG35_17PL 0xFFFF +#endif +#if (G38PL >= G35PL) || (G38PL == 0) +#define MG35_18PL ~(1 << 7) +#else +#define MG35_18PL 0xFFFF +#endif +#define MG35_15PL 0x00EF +#define MG35 (MG35_11PL & MG35_12PL & MG35_13PL & MG35_14PL & \ + MG35_15PL & MG35_16PL & MG35_17PL & MG35_18PL) +// End of MG35: + +// Beginning of MG36: +#if (G31PL >= G36PL) || (G31PL == 0) +#define MG36_11PL ~(1) +#else +#define MG36_11PL 0xFFFF +#endif +#if (G32PL >= G36PL) || (G32PL == 0) +#define MG36_12PL ~(1 << 1) +#else +#define MG36_12PL 0xFFFF +#endif +#if (G33PL >= G36PL) || (G33PL == 0) +#define MG36_13PL ~(1 << 2) +#else +#define MG36_13PL 0xFFFF +#endif +#if (G34PL >= G36PL) || (G34PL == 0) +#define MG36_14PL ~(1 << 3) +#else +#define MG36_14PL 0xFFFF +#endif +#if (G35PL >= G36PL) || (G35PL == 0) +#define MG36_15PL ~(1 << 4) +#else +#define MG36_15PL 0xFFFF +#endif +#if (G37PL >= G36PL) || (G37PL == 0) +#define MG36_17PL ~(1 << 6) +#else +#define MG36_17PL 0xFFFF +#endif +#if (G38PL >= G36PL) || (G38PL == 0) +#define MG36_18PL ~(1 << 7) +#else +#define MG36_18PL 0xFFFF +#endif +#define MG36_16PL 0x00DF +#define MG36 (MG36_11PL & MG36_12PL & MG36_13PL & MG36_14PL & \ + MG36_15PL & MG36_16PL & MG36_17PL & MG36_18PL) +// End of MG36: + +// Beginning of MG37: +#if (G31PL >= G37PL) || (G31PL == 0) +#define MG37_11PL ~(1) +#else +#define MG37_11PL 0xFFFF +#endif +#if (G32PL >= G37PL) || (G32PL == 0) +#define MG37_12PL ~(1 << 1) +#else +#define MG37_12PL 0xFFFF +#endif +#if (G33PL >= G37PL) || (G33PL == 0) +#define MG37_13PL ~(1 << 2) +#else +#define MG37_13PL 0xFFFF +#endif +#if (G34PL >= G37PL) || (G34PL == 0) +#define MG37_14PL ~(1 << 3) +#else +#define MG37_14PL 0xFFFF +#endif +#if (G35PL >= G37PL) || (G35PL == 0) +#define MG37_15PL ~(1 << 4) +#else +#define MG37_15PL 0xFFFF +#endif +#if (G36PL >= G37PL) || (G36PL == 0) +#define MG37_16PL ~(1 << 5) +#else +#define MG37_16PL 0xFFFF +#endif +#if (G38PL >= G37PL) || (G38PL == 0) +#define MG37_18PL ~(1 << 7) +#else +#define MG37_18PL 0xFFFF +#endif +#define MG37_17PL 0x00BF +#define MG37 (MG37_11PL & MG37_12PL & MG37_13PL & MG37_14PL & \ + MG37_15PL & MG37_16PL & MG37_17PL & MG37_18PL) +// End of MG37: + +// Beginning of MG38: +#if (G31PL >= G38PL) || (G31PL == 0) +#define MG38_11PL ~(1) +#else +#define MG38_11PL 0xFFFF +#endif +#if (G32PL >= G38PL) || (G32PL == 0) +#define MG38_12PL ~(1 << 1) +#else +#define MG38_12PL 0xFFFF +#endif +#if (G33PL >= G38PL) || (G33PL == 0) +#define MG38_13PL ~(1 << 2) +#else +#define MG38_13PL 0xFFFF +#endif +#if (G34PL >= G38PL) || (G34PL == 0) +#define MG38_14PL ~(1 << 3) +#else +#define MG38_14PL 0xFFFF +#endif +#if (G35PL >= G38PL) || (G35PL == 0) +#define MG38_15PL ~(1 << 4) +#else +#define MG38_15PL 0xFFFF +#endif +#if (G36PL >= G38PL) || (G36PL == 0) +#define MG38_16PL ~(1 << 5) +#else +#define MG38_16PL 0xFFFF +#endif +#if (G37PL >= G38PL) || (G37PL == 0) +#define MG38_17PL ~(1 << 6) +#else +#define MG38_17PL 0xFFFF +#endif +#define MG38_18PL 0x007F +#define MG38 (MG38_11PL & MG38_12PL & MG38_13PL & MG38_14PL & \ + MG38_15PL & MG38_16PL & MG38_17PL & MG38_18PL) +// End of MG38: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG41 to MG48: +// + +// Beginning of MG41: +#if (G42PL >= G41PL) || (G42PL == 0) +#define MG41_12PL ~(1 << 1) +#else +#define MG41_12PL 0xFFFF +#endif +#if (G43PL >= G41PL) || (G43PL == 0) +#define MG41_13PL ~(1 << 2) +#else +#define MG41_13PL 0xFFFF +#endif +#if (G44PL >= G41PL) || (G44PL == 0) +#define MG41_14PL ~(1 << 3) +#else +#define MG41_14PL 0xFFFF +#endif +#if (G45PL >= G41PL) || (G45PL == 0) +#define MG41_15PL ~(1 << 4) +#else +#define MG41_15PL 0xFFFF +#endif +#if (G46PL >= G41PL) || (G46PL == 0) +#define MG41_16PL ~(1 << 5) +#else +#define MG41_16PL 0xFFFF +#endif +#if (G47PL >= G41PL) || (G47PL == 0) +#define MG41_17PL ~(1 << 6) +#else +#define MG41_17PL 0xFFFF +#endif +#if (G48PL >= G41PL) || (G48PL == 0) +#define MG41_18PL ~(1 << 7) +#else +#define MG41_18PL 0xFFFF +#endif +#define MG41_11PL 0x00FE +#define MG41 (MG41_11PL & MG41_12PL & MG41_13PL & MG41_14PL & \ + MG41_15PL & MG41_16PL & MG41_17PL & MG41_18PL) +// End of MG41: + +// Beginning of MG42: +#if (G41PL >= G42PL) || (G41PL == 0) +#define MG42_11PL ~(1) +#else +#define MG42_11PL 0xFFFF +#endif +#if (G43PL >= G42PL) || (G43PL == 0) +#define MG42_13PL ~(1 << 2) +#else +#define MG42_13PL 0xFFFF +#endif +#if (G44PL >= G42PL) || (G44PL == 0) +#define MG42_14PL ~(1 << 3) +#else +#define MG42_14PL 0xFFFF +#endif +#if (G45PL >= G42PL) || (G45PL == 0) +#define MG42_15PL ~(1 << 4) +#else +#define MG42_15PL 0xFFFF +#endif +#if (G46PL >= G42PL) || (G46PL == 0) +#define MG42_16PL ~(1 << 5) +#else +#define MG42_16PL 0xFFFF +#endif +#if (G47PL >= G42PL) || (G47PL == 0) +#define MG42_17PL ~(1 << 6) +#else +#define MG42_17PL 0xFFFF +#endif +#if (G48PL >= G42PL) || (G48PL == 0) +#define MG42_18PL ~(1 << 7) +#else +#define MG42_18PL 0xFFFF +#endif +#define MG42_12PL 0x00FD +#define MG42 (MG42_11PL & MG42_12PL & MG42_13PL & MG42_14PL & \ + MG42_15PL & MG42_16PL & MG42_17PL & MG42_18PL) +// End of MG42: + +// Beginning of MG43: +#if (G41PL >= G43PL) || (G41PL == 0) +#define MG43_11PL ~(1) +#else +#define MG43_11PL 0xFFFF +#endif +#if (G42PL >= G43PL) || (G42PL == 0) +#define MG43_12PL ~(1 << 1) +#else +#define MG43_12PL 0xFFFF +#endif +#if (G44PL >= G43PL) || (G44PL == 0) +#define MG43_14PL ~(1 << 3) +#else +#define MG43_14PL 0xFFFF +#endif +#if (G45PL >= G43PL) || (G45PL == 0) +#define MG43_15PL ~(1 << 4) +#else +#define MG43_15PL 0xFFFF +#endif +#if (G46PL >= G43PL) || (G46PL == 0) +#define MG43_16PL ~(1 << 5) +#else +#define MG43_16PL 0xFFFF +#endif +#if (G47PL >= G43PL) || (G47PL == 0) +#define MG43_17PL ~(1 << 6) +#else +#define MG43_17PL 0xFFFF +#endif +#if (G48PL >= G43PL) || (G48PL == 0) +#define MG43_18PL ~(1 << 7) +#else +#define MG43_18PL 0xFFFF +#endif +#define MG43_13PL 0x00FB +#define MG43 (MG43_11PL & MG43_12PL & MG43_13PL & MG43_14PL & \ + MG43_15PL & MG43_16PL & MG43_17PL & MG43_18PL) +// End of MG43: + +// Beginning of MG44: +#if (G41PL >= G44PL) || (G41PL == 0) +#define MG44_11PL ~(1) +#else +#define MG44_11PL 0xFFFF +#endif +#if (G42PL >= G44PL) || (G42PL == 0) +#define MG44_12PL ~(1 << 1) +#else +#define MG44_12PL 0xFFFF +#endif +#if (G43PL >= G44PL) || (G43PL == 0) +#define MG44_13PL ~(1 << 2) +#else +#define MG44_13PL 0xFFFF +#endif +#if (G45PL >= G44PL) || (G45PL == 0) +#define MG44_15PL ~(1 << 4) +#else +#define MG44_15PL 0xFFFF +#endif +#if (G46PL >= G44PL) || (G46PL == 0) +#define MG44_16PL ~(1 << 5) +#else +#define MG44_16PL 0xFFFF +#endif +#if (G47PL >= G44PL) || (G47PL == 0) +#define MG44_17PL ~(1 << 6) +#else +#define MG44_17PL 0xFFFF +#endif +#if (G48PL >= G44PL) || (G48PL == 0) +#define MG44_18PL ~(1 << 7) +#else +#define MG44_18PL 0xFFFF +#endif +#define MG44_14PL 0x00F7 +#define MG44 (MG44_11PL & MG44_12PL & MG44_13PL & MG44_14PL & \ + MG44_15PL & MG44_16PL & MG44_17PL & MG44_18PL) +// End of MG44: + +// Beginning of MG45: +#if (G41PL >= G45PL) || (G41PL == 0) +#define MG45_11PL ~(1) +#else +#define MG45_11PL 0xFFFF +#endif +#if (G42PL >= G45PL) || (G42PL == 0) +#define MG45_12PL ~(1 << 1) +#else +#define MG45_12PL 0xFFFF +#endif +#if (G43PL >= G45PL) || (G43PL == 0) +#define MG45_13PL ~(1 << 2) +#else +#define MG45_13PL 0xFFFF +#endif +#if (G44PL >= G45PL) || (G44PL == 0) +#define MG45_14PL ~(1 << 3) +#else +#define MG45_14PL 0xFFFF +#endif +#if (G46PL >= G45PL) || (G46PL == 0) +#define MG45_16PL ~(1 << 5) +#else +#define MG45_16PL 0xFFFF +#endif +#if (G47PL >= G45PL) || (G47PL == 0) +#define MG45_17PL ~(1 << 6) +#else +#define MG45_17PL 0xFFFF +#endif +#if (G48PL >= G45PL) || (G48PL == 0) +#define MG45_18PL ~(1 << 7) +#else +#define MG45_18PL 0xFFFF +#endif +#define MG45_15PL 0x00EF +#define MG45 (MG45_11PL & MG45_12PL & MG45_13PL & MG45_14PL & \ + MG45_15PL & MG45_16PL & MG45_17PL & MG45_18PL) +// End of MG45: + +// Beginning of MG46: +#if (G41PL >= G46PL) || (G41PL == 0) +#define MG46_11PL ~(1) +#else +#define MG46_11PL 0xFFFF +#endif +#if (G42PL >= G46PL) || (G42PL == 0) +#define MG46_12PL ~(1 << 1) +#else +#define MG46_12PL 0xFFFF +#endif +#if (G43PL >= G46PL) || (G43PL == 0) +#define MG46_13PL ~(1 << 2) +#else +#define MG46_13PL 0xFFFF +#endif +#if (G44PL >= G46PL) || (G44PL == 0) +#define MG46_14PL ~(1 << 3) +#else +#define MG46_14PL 0xFFFF +#endif +#if (G45PL >= G46PL) || (G45PL == 0) +#define MG46_15PL ~(1 << 4) +#else +#define MG46_15PL 0xFFFF +#endif +#if (G47PL >= G46PL) || (G47PL == 0) +#define MG46_17PL ~(1 << 6) +#else +#define MG46_17PL 0xFFFF +#endif +#if (G48PL >= G46PL) || (G48PL == 0) +#define MG46_18PL ~(1 << 7) +#else +#define MG46_18PL 0xFFFF +#endif +#define MG46_16PL 0x00DF +#define MG46 (MG46_11PL & MG46_12PL & MG46_13PL & MG46_14PL & \ + MG46_15PL & MG46_16PL & MG46_17PL & MG46_18PL) +// End of MG46: + +// Beginning of MG47: +#if (G41PL >= G47PL) || (G41PL == 0) +#define MG47_11PL ~(1) +#else +#define MG47_11PL 0xFFFF +#endif +#if (G42PL >= G47PL) || (G42PL == 0) +#define MG47_12PL ~(1 << 1) +#else +#define MG47_12PL 0xFFFF +#endif +#if (G43PL >= G47PL) || (G43PL == 0) +#define MG47_13PL ~(1 << 2) +#else +#define MG47_13PL 0xFFFF +#endif +#if (G44PL >= G47PL) || (G44PL == 0) +#define MG47_14PL ~(1 << 3) +#else +#define MG47_14PL 0xFFFF +#endif +#if (G45PL >= G47PL) || (G45PL == 0) +#define MG47_15PL ~(1 << 4) +#else +#define MG47_15PL 0xFFFF +#endif +#if (G46PL >= G47PL) || (G46PL == 0) +#define MG47_16PL ~(1 << 5) +#else +#define MG47_16PL 0xFFFF +#endif +#if (G48PL >= G47PL) || (G48PL == 0) +#define MG47_18PL ~(1 << 7) +#else +#define MG47_18PL 0xFFFF +#endif +#define MG47_17PL 0x00BF +#define MG47 (MG47_11PL & MG47_12PL & MG47_13PL & MG47_14PL & \ + MG47_15PL & MG47_16PL & MG47_17PL & MG47_18PL) +// End of MG47: + +// Beginning of MG48: +#if (G41PL >= G48PL) || (G41PL == 0) +#define MG48_11PL ~(1) +#else +#define MG48_11PL 0xFFFF +#endif +#if (G42PL >= G48PL) || (G42PL == 0) +#define MG48_12PL ~(1 << 1) +#else +#define MG48_12PL 0xFFFF +#endif +#if (G43PL >= G48PL) || (G43PL == 0) +#define MG48_13PL ~(1 << 2) +#else +#define MG48_13PL 0xFFFF +#endif +#if (G44PL >= G48PL) || (G44PL == 0) +#define MG48_14PL ~(1 << 3) +#else +#define MG48_14PL 0xFFFF +#endif +#if (G45PL >= G48PL) || (G45PL == 0) +#define MG48_15PL ~(1 << 4) +#else +#define MG48_15PL 0xFFFF +#endif +#if (G46PL >= G48PL) || (G46PL == 0) +#define MG48_16PL ~(1 << 5) +#else +#define MG48_16PL 0xFFFF +#endif +#if (G47PL >= G48PL) || (G47PL == 0) +#define MG48_17PL ~(1 << 6) +#else +#define MG48_17PL 0xFFFF +#endif +#define MG48_18PL 0x007F +#define MG48 (MG48_11PL & MG48_12PL & MG48_13PL & MG48_14PL & \ + MG48_15PL & MG48_16PL & MG48_17PL & MG48_18PL) +// End of MG48: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG51 to MG58: +// + +// Beginning of MG51: +#if (G52PL >= G51PL) || (G52PL == 0) +#define MG51_12PL ~(1 << 1) +#else +#define MG51_12PL 0xFFFF +#endif +#if (G53PL >= G51PL) || (G53PL == 0) +#define MG51_13PL ~(1 << 2) +#else +#define MG51_13PL 0xFFFF +#endif +#if (G54PL >= G51PL) || (G54PL == 0) +#define MG51_14PL ~(1 << 3) +#else +#define MG51_14PL 0xFFFF +#endif +#if (G55PL >= G51PL) || (G55PL == 0) +#define MG51_15PL ~(1 << 4) +#else +#define MG51_15PL 0xFFFF +#endif +#if (G56PL >= G51PL) || (G56PL == 0) +#define MG51_16PL ~(1 << 5) +#else +#define MG51_16PL 0xFFFF +#endif +#if (G57PL >= G51PL) || (G57PL == 0) +#define MG51_17PL ~(1 << 6) +#else +#define MG51_17PL 0xFFFF +#endif +#if (G58PL >= G51PL) || (G58PL == 0) +#define MG51_18PL ~(1 << 7) +#else +#define MG51_18PL 0xFFFF +#endif +#define MG51_11PL 0x00FE +#define MG51 (MG51_11PL & MG51_12PL & MG51_13PL & MG51_14PL & \ + MG51_15PL & MG51_16PL & MG51_17PL & MG51_18PL) +// End of MG51: + +// Beginning of MG52: +#if (G51PL >= G52PL) || (G51PL == 0) +#define MG52_11PL ~(1) +#else +#define MG52_11PL 0xFFFF +#endif +#if (G53PL >= G52PL) || (G53PL == 0) +#define MG52_13PL ~(1 << 2) +#else +#define MG52_13PL 0xFFFF +#endif +#if (G54PL >= G52PL) || (G54PL == 0) +#define MG52_14PL ~(1 << 3) +#else +#define MG52_14PL 0xFFFF +#endif +#if (G55PL >= G52PL) || (G55PL == 0) +#define MG52_15PL ~(1 << 4) +#else +#define MG52_15PL 0xFFFF +#endif +#if (G56PL >= G52PL) || (G56PL == 0) +#define MG52_16PL ~(1 << 5) +#else +#define MG52_16PL 0xFFFF +#endif +#if (G57PL >= G52PL) || (G57PL == 0) +#define MG52_17PL ~(1 << 6) +#else +#define MG52_17PL 0xFFFF +#endif +#if (G58PL >= G52PL) || (G58PL == 0) +#define MG52_18PL ~(1 << 7) +#else +#define MG52_18PL 0xFFFF +#endif +#define MG52_12PL 0x00FD +#define MG52 (MG52_11PL & MG52_12PL & MG52_13PL & MG52_14PL & \ + MG52_15PL & MG52_16PL & MG52_17PL & MG52_18PL) +// End of MG52: + +// Beginning of MG53: +#if (G51PL >= G53PL) || (G51PL == 0) +#define MG53_11PL ~(1) +#else +#define MG53_11PL 0xFFFF +#endif +#if (G52PL >= G53PL) || (G52PL == 0) +#define MG53_12PL ~(1 << 1) +#else +#define MG53_12PL 0xFFFF +#endif +#if (G54PL >= G53PL) || (G54PL == 0) +#define MG53_14PL ~(1 << 3) +#else +#define MG53_14PL 0xFFFF +#endif +#if (G55PL >= G53PL) || (G55PL == 0) +#define MG53_15PL ~(1 << 4) +#else +#define MG53_15PL 0xFFFF +#endif +#if (G56PL >= G53PL) || (G56PL == 0) +#define MG53_16PL ~(1 << 5) +#else +#define MG53_16PL 0xFFFF +#endif +#if (G57PL >= G53PL) || (G57PL == 0) +#define MG53_17PL ~(1 << 6) +#else +#define MG53_17PL 0xFFFF +#endif +#if (G58PL >= G53PL) || (G58PL == 0) +#define MG53_18PL ~(1 << 7) +#else +#define MG53_18PL 0xFFFF +#endif +#define MG53_13PL 0x00FB +#define MG53 (MG53_11PL & MG53_12PL & MG53_13PL & MG53_14PL & \ + MG53_15PL & MG53_16PL & MG53_17PL & MG53_18PL) +// End of MG53: + +// Beginning of MG54: +#if (G51PL >= G54PL) || (G51PL == 0) +#define MG54_11PL ~(1) +#else +#define MG54_11PL 0xFFFF +#endif +#if (G52PL >= G54PL) || (G52PL == 0) +#define MG54_12PL ~(1 << 1) +#else +#define MG54_12PL 0xFFFF +#endif +#if (G53PL >= G54PL) || (G53PL == 0) +#define MG54_13PL ~(1 << 2) +#else +#define MG54_13PL 0xFFFF +#endif +#if (G55PL >= G54PL) || (G55PL == 0) +#define MG54_15PL ~(1 << 4) +#else +#define MG54_15PL 0xFFFF +#endif +#if (G56PL >= G54PL) || (G56PL == 0) +#define MG54_16PL ~(1 << 5) +#else +#define MG54_16PL 0xFFFF +#endif +#if (G57PL >= G54PL) || (G57PL == 0) +#define MG54_17PL ~(1 << 6) +#else +#define MG54_17PL 0xFFFF +#endif +#if (G58PL >= G54PL) || (G58PL == 0) +#define MG54_18PL ~(1 << 7) +#else +#define MG54_18PL 0xFFFF +#endif +#define MG54_14PL 0x00F7 +#define MG54 (MG54_11PL & MG54_12PL & MG54_13PL & MG54_14PL & \ + MG54_15PL & MG54_16PL & MG54_17PL & MG54_18PL) +// End of MG54: + +// Beginning of MG55: +#if (G51PL >= G55PL) || (G51PL == 0) +#define MG55_11PL ~(1) +#else +#define MG55_11PL 0xFFFF +#endif +#if (G52PL >= G55PL) || (G52PL == 0) +#define MG55_12PL ~(1 << 1) +#else +#define MG55_12PL 0xFFFF +#endif +#if (G53PL >= G55PL) || (G53PL == 0) +#define MG55_13PL ~(1 << 2) +#else +#define MG55_13PL 0xFFFF +#endif +#if (G54PL >= G55PL) || (G54PL == 0) +#define MG55_14PL ~(1 << 3) +#else +#define MG55_14PL 0xFFFF +#endif +#if (G56PL >= G55PL) || (G56PL == 0) +#define MG55_16PL ~(1 << 5) +#else +#define MG55_16PL 0xFFFF +#endif +#if (G57PL >= G55PL) || (G57PL == 0) +#define MG55_17PL ~(1 << 6) +#else +#define MG55_17PL 0xFFFF +#endif +#if (G58PL >= G55PL) || (G58PL == 0) +#define MG55_18PL ~(1 << 7) +#else +#define MG55_18PL 0xFFFF +#endif +#define MG55_15PL 0x00EF +#define MG55 (MG55_11PL & MG55_12PL & MG55_13PL & MG55_14PL & \ + MG55_15PL & MG55_16PL & MG55_17PL & MG55_18PL) +// End of MG55: + +// Beginning of MG56: +#if (G51PL >= G56PL) || (G51PL == 0) +#define MG56_11PL ~(1) +#else +#define MG56_11PL 0xFFFF +#endif +#if (G52PL >= G56PL) || (G52PL == 0) +#define MG56_12PL ~(1 << 1) +#else +#define MG56_12PL 0xFFFF +#endif +#if (G53PL >= G56PL) || (G53PL == 0) +#define MG56_13PL ~(1 << 2) +#else +#define MG56_13PL 0xFFFF +#endif +#if (G54PL >= G56PL) || (G54PL == 0) +#define MG56_14PL ~(1 << 3) +#else +#define MG56_14PL 0xFFFF +#endif +#if (G55PL >= G56PL) || (G55PL == 0) +#define MG56_15PL ~(1 << 4) +#else +#define MG56_15PL 0xFFFF +#endif +#if (G57PL >= G56PL) || (G57PL == 0) +#define MG56_17PL ~(1 << 6) +#else +#define MG56_17PL 0xFFFF +#endif +#if (G58PL >= G56PL) || (G58PL == 0) +#define MG56_18PL ~(1 << 7) +#else +#define MG56_18PL 0xFFFF +#endif +#define MG56_16PL 0x00DF +#define MG56 (MG56_11PL & MG56_12PL & MG56_13PL & MG56_14PL & \ + MG56_15PL & MG56_16PL & MG56_17PL & MG56_18PL) +// End of MG56: + +// Beginning of MG57: +#if (G51PL >= G57PL) || (G51PL == 0) +#define MG57_11PL ~(1) +#else +#define MG57_11PL 0xFFFF +#endif +#if (G52PL >= G57PL) || (G52PL == 0) +#define MG57_12PL ~(1 << 1) +#else +#define MG57_12PL 0xFFFF +#endif +#if (G53PL >= G57PL) || (G53PL == 0) +#define MG57_13PL ~(1 << 2) +#else +#define MG57_13PL 0xFFFF +#endif +#if (G54PL >= G57PL) || (G54PL == 0) +#define MG57_14PL ~(1 << 3) +#else +#define MG57_14PL 0xFFFF +#endif +#if (G55PL >= G57PL) || (G55PL == 0) +#define MG57_15PL ~(1 << 4) +#else +#define MG57_15PL 0xFFFF +#endif +#if (G56PL >= G57PL) || (G56PL == 0) +#define MG57_16PL ~(1 << 5) +#else +#define MG57_16PL 0xFFFF +#endif +#if (G58PL >= G57PL) || (G58PL == 0) +#define MG57_18PL ~(1 << 7) +#else +#define MG57_18PL 0xFFFF +#endif +#define MG57_17PL 0x00BF +#define MG57 (MG57_11PL & MG57_12PL & MG57_13PL & MG57_14PL & \ + MG57_15PL & MG57_16PL & MG57_17PL & MG57_18PL) +// End of MG57: + +// Beginning of MG58: +#if (G51PL >= G58PL) || (G51PL == 0) +#define MG58_11PL ~(1) +#else +#define MG58_11PL 0xFFFF +#endif +#if (G52PL >= G58PL) || (G52PL == 0) +#define MG58_12PL ~(1 << 1) +#else +#define MG58_12PL 0xFFFF +#endif +#if (G53PL >= G58PL) || (G53PL == 0) +#define MG58_13PL ~(1 << 2) +#else +#define MG58_13PL 0xFFFF +#endif +#if (G54PL >= G58PL) || (G54PL == 0) +#define MG58_14PL ~(1 << 3) +#else +#define MG58_14PL 0xFFFF +#endif +#if (G55PL >= G58PL) || (G55PL == 0) +#define MG58_15PL ~(1 << 4) +#else +#define MG58_15PL 0xFFFF +#endif +#if (G56PL >= G58PL) || (G56PL == 0) +#define MG58_16PL ~(1 << 5) +#else +#define MG58_16PL 0xFFFF +#endif +#if (G57PL >= G58PL) || (G57PL == 0) +#define MG58_17PL ~(1 << 6) +#else +#define MG58_17PL 0xFFFF +#endif +#define MG58_18PL 0x007F +#define MG58 (MG58_11PL & MG58_12PL & MG58_13PL & MG58_14PL & \ + MG58_15PL & MG58_16PL & MG58_17PL & MG58_18PL) +// End of MG58: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG61 to MG68: +// + +// Beginning of MG61: +#if (G62PL >= G61PL) || (G62PL == 0) +#define MG61_12PL ~(1 << 1) +#else +#define MG61_12PL 0xFFFF +#endif +#if (G63PL >= G61PL) || (G63PL == 0) +#define MG61_13PL ~(1 << 2) +#else +#define MG61_13PL 0xFFFF +#endif +#if (G64PL >= G61PL) || (G64PL == 0) +#define MG61_14PL ~(1 << 3) +#else +#define MG61_14PL 0xFFFF +#endif +#if (G65PL >= G61PL) || (G65PL == 0) +#define MG61_15PL ~(1 << 4) +#else +#define MG61_15PL 0xFFFF +#endif +#if (G66PL >= G61PL) || (G66PL == 0) +#define MG61_16PL ~(1 << 5) +#else +#define MG61_16PL 0xFFFF +#endif +#if (G67PL >= G61PL) || (G67PL == 0) +#define MG61_17PL ~(1 << 6) +#else +#define MG61_17PL 0xFFFF +#endif +#if (G68PL >= G61PL) || (G68PL == 0) +#define MG61_18PL ~(1 << 7) +#else +#define MG61_18PL 0xFFFF +#endif +#define MG61_11PL 0x00FE +#define MG61 (MG61_11PL & MG61_12PL & MG61_13PL & MG61_14PL & \ + MG61_15PL & MG61_16PL & MG61_17PL & MG61_18PL) +// End of MG61: + +// Beginning of MG62: +#if (G61PL >= G62PL) || (G61PL == 0) +#define MG62_11PL ~(1) +#else +#define MG62_11PL 0xFFFF +#endif +#if (G63PL >= G62PL) || (G63PL == 0) +#define MG62_13PL ~(1 << 2) +#else +#define MG62_13PL 0xFFFF +#endif +#if (G64PL >= G62PL) || (G64PL == 0) +#define MG62_14PL ~(1 << 3) +#else +#define MG62_14PL 0xFFFF +#endif +#if (G65PL >= G62PL) || (G65PL == 0) +#define MG62_15PL ~(1 << 4) +#else +#define MG62_15PL 0xFFFF +#endif +#if (G66PL >= G62PL) || (G66PL == 0) +#define MG62_16PL ~(1 << 5) +#else +#define MG62_16PL 0xFFFF +#endif +#if (G67PL >= G62PL) || (G67PL == 0) +#define MG62_17PL ~(1 << 6) +#else +#define MG62_17PL 0xFFFF +#endif +#if (G68PL >= G62PL) || (G68PL == 0) +#define MG62_18PL ~(1 << 7) +#else +#define MG62_18PL 0xFFFF +#endif +#define MG62_12PL 0x00FD +#define MG62 (MG62_11PL & MG62_12PL & MG62_13PL & MG62_14PL & \ + MG62_15PL & MG62_16PL & MG62_17PL & MG62_18PL) +// End of MG62: + +// Beginning of MG63: +#if (G61PL >= G63PL) || (G61PL == 0) +#define MG63_11PL ~(1) +#else +#define MG63_11PL 0xFFFF +#endif +#if (G62PL >= G63PL) || (G62PL == 0) +#define MG63_12PL ~(1 << 1) +#else +#define MG63_12PL 0xFFFF +#endif +#if (G64PL >= G63PL) || (G64PL == 0) +#define MG63_14PL ~(1 << 3) +#else +#define MG63_14PL 0xFFFF +#endif +#if (G65PL >= G63PL) || (G65PL == 0) +#define MG63_15PL ~(1 << 4) +#else +#define MG63_15PL 0xFFFF +#endif +#if (G66PL >= G63PL) || (G66PL == 0) +#define MG63_16PL ~(1 << 5) +#else +#define MG63_16PL 0xFFFF +#endif +#if (G67PL >= G63PL) || (G67PL == 0) +#define MG63_17PL ~(1 << 6) +#else +#define MG63_17PL 0xFFFF +#endif +#if (G68PL >= G63PL) || (G68PL == 0) +#define MG63_18PL ~(1 << 7) +#else +#define MG63_18PL 0xFFFF +#endif +#define MG63_13PL 0x00FB +#define MG63 (MG63_11PL & MG63_12PL & MG63_13PL & MG63_14PL & \ + MG63_15PL & MG63_16PL & MG63_17PL & MG63_18PL) +// End of MG63: + +// Beginning of MG64: +#if (G61PL >= G64PL) || (G61PL == 0) +#define MG64_11PL ~(1) +#else +#define MG64_11PL 0xFFFF +#endif +#if (G62PL >= G64PL) || (G62PL == 0) +#define MG64_12PL ~(1 << 1) +#else +#define MG64_12PL 0xFFFF +#endif +#if (G63PL >= G64PL) || (G63PL == 0) +#define MG64_13PL ~(1 << 2) +#else +#define MG64_13PL 0xFFFF +#endif +#if (G65PL >= G64PL) || (G65PL == 0) +#define MG64_15PL ~(1 << 4) +#else +#define MG64_15PL 0xFFFF +#endif +#if (G66PL >= G64PL) || (G66PL == 0) +#define MG64_16PL ~(1 << 5) +#else +#define MG64_16PL 0xFFFF +#endif +#if (G67PL >= G64PL) || (G67PL == 0) +#define MG64_17PL ~(1 << 6) +#else +#define MG64_17PL 0xFFFF +#endif +#if (G68PL >= G64PL) || (G68PL == 0) +#define MG64_18PL ~(1 << 7) +#else +#define MG64_18PL 0xFFFF +#endif +#define MG64_14PL 0x00F7 +#define MG64 (MG64_11PL & MG64_12PL & MG64_13PL & MG64_14PL & \ + MG64_15PL & MG64_16PL & MG64_17PL & MG64_18PL) +// End of MG64: + +// Beginning of MG65: +#if (G61PL >= G65PL) || (G61PL == 0) +#define MG65_11PL ~(1) +#else +#define MG65_11PL 0xFFFF +#endif +#if (G62PL >= G65PL) || (G62PL == 0) +#define MG65_12PL ~(1 << 1) +#else +#define MG65_12PL 0xFFFF +#endif +#if (G63PL >= G65PL) || (G63PL == 0) +#define MG65_13PL ~(1 << 2) +#else +#define MG65_13PL 0xFFFF +#endif +#if (G64PL >= G65PL) || (G64PL == 0) +#define MG65_14PL ~(1 << 3) +#else +#define MG65_14PL 0xFFFF +#endif +#if (G66PL >= G65PL) || (G66PL == 0) +#define MG65_16PL ~(1 << 5) +#else +#define MG65_16PL 0xFFFF +#endif +#if (G67PL >= G65PL) || (G67PL == 0) +#define MG65_17PL ~(1 << 6) +#else +#define MG65_17PL 0xFFFF +#endif +#if (G68PL >= G65PL) || (G68PL == 0) +#define MG65_18PL ~(1 << 7) +#else +#define MG65_18PL 0xFFFF +#endif +#define MG65_15PL 0x00EF +#define MG65 (MG65_11PL & MG65_12PL & MG65_13PL & MG65_14PL & \ + MG65_15PL & MG65_16PL & MG65_17PL & MG65_18PL) +// End of MG65: + +// Beginning of MG66: +#if (G61PL >= G66PL) || (G61PL == 0) +#define MG66_11PL ~(1) +#else +#define MG66_11PL 0xFFFF +#endif +#if (G62PL >= G66PL) || (G62PL == 0) +#define MG66_12PL ~(1 << 1) +#else +#define MG66_12PL 0xFFFF +#endif +#if (G63PL >= G66PL) || (G63PL == 0) +#define MG66_13PL ~(1 << 2) +#else +#define MG66_13PL 0xFFFF +#endif +#if (G64PL >= G66PL) || (G64PL == 0) +#define MG66_14PL ~(1 << 3) +#else +#define MG66_14PL 0xFFFF +#endif +#if (G65PL >= G66PL) || (G65PL == 0) +#define MG66_15PL ~(1 << 4) +#else +#define MG66_15PL 0xFFFF +#endif +#if (G67PL >= G66PL) || (G67PL == 0) +#define MG66_17PL ~(1 << 6) +#else +#define MG66_17PL 0xFFFF +#endif +#if (G68PL >= G66PL) || (G68PL == 0) +#define MG66_18PL ~(1 << 7) +#else +#define MG66_18PL 0xFFFF +#endif +#define MG66_16PL 0x00DF +#define MG66 (MG66_11PL & MG66_12PL & MG66_13PL & MG66_14PL & \ + MG66_15PL & MG66_16PL & MG66_17PL & MG66_18PL) +// End of MG66: + +// Beginning of MG67: +#if (G61PL >= G67PL) || (G61PL == 0) +#define MG67_11PL ~(1) +#else +#define MG67_11PL 0xFFFF +#endif +#if (G62PL >= G67PL) || (G62PL == 0) +#define MG67_12PL ~(1 << 1) +#else +#define MG67_12PL 0xFFFF +#endif +#if (G63PL >= G67PL) || (G63PL == 0) +#define MG67_13PL ~(1 << 2) +#else +#define MG67_13PL 0xFFFF +#endif +#if (G64PL >= G67PL) || (G64PL == 0) +#define MG67_14PL ~(1 << 3) +#else +#define MG67_14PL 0xFFFF +#endif +#if (G65PL >= G67PL) || (G65PL == 0) +#define MG67_15PL ~(1 << 4) +#else +#define MG67_15PL 0xFFFF +#endif +#if (G66PL >= G67PL) || (G66PL == 0) +#define MG67_16PL ~(1 << 5) +#else +#define MG67_16PL 0xFFFF +#endif +#if (G68PL >= G67PL) || (G68PL == 0) +#define MG67_18PL ~(1 << 7) +#else +#define MG67_18PL 0xFFFF +#endif +#define MG67_17PL 0x00BF +#define MG67 (MG67_11PL & MG67_12PL & MG67_13PL & MG67_14PL & \ + MG67_15PL & MG67_16PL & MG67_17PL & MG67_18PL) +// End of MG67: + +// Beginning of MG68: +#if (G61PL >= G68PL) || (G61PL == 0) +#define MG68_11PL ~(1) +#else +#define MG68_11PL 0xFFFF +#endif +#if (G62PL >= G68PL) || (G62PL == 0) +#define MG68_12PL ~(1 << 1) +#else +#define MG68_12PL 0xFFFF +#endif +#if (G63PL >= G68PL) || (G63PL == 0) +#define MG68_13PL ~(1 << 2) +#else +#define MG68_13PL 0xFFFF +#endif +#if (G64PL >= G68PL) || (G64PL == 0) +#define MG68_14PL ~(1 << 3) +#else +#define MG68_14PL 0xFFFF +#endif +#if (G65PL >= G68PL) || (G65PL == 0) +#define MG68_15PL ~(1 << 4) +#else +#define MG68_15PL 0xFFFF +#endif +#if (G66PL >= G68PL) || (G66PL == 0) +#define MG68_16PL ~(1 << 5) +#else +#define MG68_16PL 0xFFFF +#endif +#if (G67PL >= G68PL) || (G67PL == 0) +#define MG68_17PL ~(1 << 6) +#else +#define MG68_17PL 0xFFFF +#endif +#define MG68_18PL 0x007F +#define MG68 (MG68_11PL & MG68_12PL & MG68_13PL & MG68_14PL & \ + MG68_15PL & MG68_16PL & MG68_17PL & MG68_18PL) +// End of MG68: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG71 to MG78: +// + +// Beginning of MG71: +#if (G72PL >= G71PL) || (G72PL == 0) +#define MG71_12PL ~(1 << 1) +#else +#define MG71_12PL 0xFFFF +#endif +#if (G73PL >= G71PL) || (G73PL == 0) +#define MG71_13PL ~(1 << 2) +#else +#define MG71_13PL 0xFFFF +#endif +#if (G74PL >= G71PL) || (G74PL == 0) +#define MG71_14PL ~(1 << 3) +#else +#define MG71_14PL 0xFFFF +#endif +#if (G75PL >= G71PL) || (G75PL == 0) +#define MG71_15PL ~(1 << 4) +#else +#define MG71_15PL 0xFFFF +#endif +#if (G76PL >= G71PL) || (G76PL == 0) +#define MG71_16PL ~(1 << 5) +#else +#define MG71_16PL 0xFFFF +#endif +#if (G77PL >= G71PL) || (G77PL == 0) +#define MG71_17PL ~(1 << 6) +#else +#define MG71_17PL 0xFFFF +#endif +#if (G78PL >= G71PL) || (G78PL == 0) +#define MG71_18PL ~(1 << 7) +#else +#define MG71_18PL 0xFFFF +#endif +#define MG71_11PL 0x00FE +#define MG71 (MG71_11PL & MG71_12PL & MG71_13PL & MG71_14PL & \ + MG71_15PL & MG71_16PL & MG71_17PL & MG71_18PL) +// End of MG71: + +// Beginning of MG72: +#if (G71PL >= G72PL) || (G71PL == 0) +#define MG72_11PL ~(1) +#else +#define MG72_11PL 0xFFFF +#endif +#if (G73PL >= G72PL) || (G73PL == 0) +#define MG72_13PL ~(1 << 2) +#else +#define MG72_13PL 0xFFFF +#endif +#if (G74PL >= G72PL) || (G74PL == 0) +#define MG72_14PL ~(1 << 3) +#else +#define MG72_14PL 0xFFFF +#endif +#if (G75PL >= G72PL) || (G75PL == 0) +#define MG72_15PL ~(1 << 4) +#else +#define MG72_15PL 0xFFFF +#endif +#if (G76PL >= G72PL) || (G76PL == 0) +#define MG72_16PL ~(1 << 5) +#else +#define MG72_16PL 0xFFFF +#endif +#if (G77PL >= G72PL) || (G77PL == 0) +#define MG72_17PL ~(1 << 6) +#else +#define MG72_17PL 0xFFFF +#endif +#if (G78PL >= G72PL) || (G78PL == 0) +#define MG72_18PL ~(1 << 7) +#else +#define MG72_18PL 0xFFFF +#endif +#define MG72_12PL 0x00FD +#define MG72 (MG72_11PL & MG72_12PL & MG72_13PL & MG72_14PL & \ + MG72_15PL & MG72_16PL & MG72_17PL & MG72_18PL) +// End of MG72: + +// Beginning of MG73: +#if (G71PL >= G73PL) || (G71PL == 0) +#define MG73_11PL ~(1) +#else +#define MG73_11PL 0xFFFF +#endif +#if (G72PL >= G73PL) || (G72PL == 0) +#define MG73_12PL ~(1 << 1) +#else +#define MG73_12PL 0xFFFF +#endif +#if (G74PL >= G73PL) || (G74PL == 0) +#define MG73_14PL ~(1 << 3) +#else +#define MG73_14PL 0xFFFF +#endif +#if (G75PL >= G73PL) || (G75PL == 0) +#define MG73_15PL ~(1 << 4) +#else +#define MG73_15PL 0xFFFF +#endif +#if (G76PL >= G73PL) || (G76PL == 0) +#define MG73_16PL ~(1 << 5) +#else +#define MG73_16PL 0xFFFF +#endif +#if (G77PL >= G73PL) || (G77PL == 0) +#define MG73_17PL ~(1 << 6) +#else +#define MG73_17PL 0xFFFF +#endif +#if (G78PL >= G73PL) || (G78PL == 0) +#define MG73_18PL ~(1 << 7) +#else +#define MG73_18PL 0xFFFF +#endif +#define MG73_13PL 0x00FB +#define MG73 (MG73_11PL & MG73_12PL & MG73_13PL & MG73_14PL & \ + MG73_15PL & MG73_16PL & MG73_17PL & MG73_18PL) +// End of MG73: + +// Beginning of MG74: +#if (G71PL >= G74PL) || (G71PL == 0) +#define MG74_11PL ~(1) +#else +#define MG74_11PL 0xFFFF +#endif +#if (G72PL >= G74PL) || (G72PL == 0) +#define MG74_12PL ~(1 << 1) +#else +#define MG74_12PL 0xFFFF +#endif +#if (G73PL >= G74PL) || (G73PL == 0) +#define MG74_13PL ~(1 << 2) +#else +#define MG74_13PL 0xFFFF +#endif +#if (G75PL >= G74PL) || (G75PL == 0) +#define MG74_15PL ~(1 << 4) +#else +#define MG74_15PL 0xFFFF +#endif +#if (G76PL >= G74PL) || (G76PL == 0) +#define MG74_16PL ~(1 << 5) +#else +#define MG74_16PL 0xFFFF +#endif +#if (G77PL >= G74PL) || (G77PL == 0) +#define MG74_17PL ~(1 << 6) +#else +#define MG74_17PL 0xFFFF +#endif +#if (G78PL >= G74PL) || (G78PL == 0) +#define MG74_18PL ~(1 << 7) +#else +#define MG74_18PL 0xFFFF +#endif +#define MG74_14PL 0x00F7 +#define MG74 (MG74_11PL & MG74_12PL & MG74_13PL & MG74_14PL & \ + MG74_15PL & MG74_16PL & MG74_17PL & MG74_18PL) +// End of MG74: + +// Beginning of MG75: +#if (G71PL >= G75PL) || (G71PL == 0) +#define MG75_11PL ~(1) +#else +#define MG75_11PL 0xFFFF +#endif +#if (G72PL >= G75PL) || (G72PL == 0) +#define MG75_12PL ~(1 << 1) +#else +#define MG75_12PL 0xFFFF +#endif +#if (G73PL >= G75PL) || (G73PL == 0) +#define MG75_13PL ~(1 << 2) +#else +#define MG75_13PL 0xFFFF +#endif +#if (G74PL >= G75PL) || (G74PL == 0) +#define MG75_14PL ~(1 << 3) +#else +#define MG75_14PL 0xFFFF +#endif +#if (G76PL >= G75PL) || (G76PL == 0) +#define MG75_16PL ~(1 << 5) +#else +#define MG75_16PL 0xFFFF +#endif +#if (G77PL >= G75PL) || (G77PL == 0) +#define MG75_17PL ~(1 << 6) +#else +#define MG75_17PL 0xFFFF +#endif +#if (G78PL >= G75PL) || (G78PL == 0) +#define MG75_18PL ~(1 << 7) +#else +#define MG75_18PL 0xFFFF +#endif +#define MG75_15PL 0x00EF +#define MG75 (MG75_11PL & MG75_12PL & MG75_13PL & MG75_14PL & \ + MG75_15PL & MG75_16PL & MG75_17PL & MG75_18PL) +// End of MG75: + +// Beginning of MG76: +#if (G71PL >= G76PL) || (G71PL == 0) +#define MG76_11PL ~(1) +#else +#define MG76_11PL 0xFFFF +#endif +#if (G72PL >= G76PL) || (G72PL == 0) +#define MG76_12PL ~(1 << 1) +#else +#define MG76_12PL 0xFFFF +#endif +#if (G73PL >= G76PL) || (G73PL == 0) +#define MG76_13PL ~(1 << 2) +#else +#define MG76_13PL 0xFFFF +#endif +#if (G74PL >= G76PL) || (G74PL == 0) +#define MG76_14PL ~(1 << 3) +#else +#define MG76_14PL 0xFFFF +#endif +#if (G75PL >= G76PL) || (G75PL == 0) +#define MG76_15PL ~(1 << 4) +#else +#define MG76_15PL 0xFFFF +#endif +#if (G77PL >= G76PL) || (G77PL == 0) +#define MG76_17PL ~(1 << 6) +#else +#define MG76_17PL 0xFFFF +#endif +#if (G78PL >= G76PL) || (G78PL == 0) +#define MG76_18PL ~(1 << 7) +#else +#define MG76_18PL 0xFFFF +#endif +#define MG76_16PL 0x00DF +#define MG76 (MG76_11PL & MG76_12PL & MG76_13PL & MG76_14PL & \ + MG76_15PL & MG76_16PL & MG76_17PL & MG76_18PL) +// End of MG76: + +// Beginning of MG77: +#if (G71PL >= G77PL) || (G71PL == 0) +#define MG77_11PL ~(1) +#else +#define MG77_11PL 0xFFFF +#endif +#if (G72PL >= G77PL) || (G72PL == 0) +#define MG77_12PL ~(1 << 1) +#else +#define MG77_12PL 0xFFFF +#endif +#if (G73PL >= G77PL) || (G73PL == 0) +#define MG77_13PL ~(1 << 2) +#else +#define MG77_13PL 0xFFFF +#endif +#if (G74PL >= G77PL) || (G74PL == 0) +#define MG77_14PL ~(1 << 3) +#else +#define MG77_14PL 0xFFFF +#endif +#if (G75PL >= G77PL) || (G75PL == 0) +#define MG77_15PL ~(1 << 4) +#else +#define MG77_15PL 0xFFFF +#endif +#if (G76PL >= G77PL) || (G76PL == 0) +#define MG77_16PL ~(1 << 5) +#else +#define MG77_16PL 0xFFFF +#endif +#if (G78PL >= G77PL) || (G78PL == 0) +#define MG77_18PL ~(1 << 7) +#else +#define MG77_18PL 0xFFFF +#endif +#define MG77_17PL 0x00BF +#define MG77 (MG77_11PL & MG77_12PL & MG77_13PL & MG77_14PL & \ + MG77_15PL & MG77_16PL & MG77_17PL & MG77_18PL) +// End of MG77: + +// Beginning of MG78: +#if (G71PL >= G78PL) || (G71PL == 0) +#define MG78_11PL ~(1) +#else +#define MG78_11PL 0xFFFF +#endif +#if (G72PL >= G78PL) || (G72PL == 0) +#define MG78_12PL ~(1 << 1) +#else +#define MG78_12PL 0xFFFF +#endif +#if (G73PL >= G78PL) || (G73PL == 0) +#define MG78_13PL ~(1 << 2) +#else +#define MG78_13PL 0xFFFF +#endif +#if (G74PL >= G78PL) || (G74PL == 0) +#define MG78_14PL ~(1 << 3) +#else +#define MG78_14PL 0xFFFF +#endif +#if (G75PL >= G78PL) || (G75PL == 0) +#define MG78_15PL ~(1 << 4) +#else +#define MG78_15PL 0xFFFF +#endif +#if (G76PL >= G78PL) || (G76PL == 0) +#define MG78_16PL ~(1 << 5) +#else +#define MG78_16PL 0xFFFF +#endif +#if (G77PL >= G78PL) || (G77PL == 0) +#define MG78_17PL ~(1 << 6) +#else +#define MG78_17PL 0xFFFF +#endif +#define MG78_18PL 0x007F +#define MG78 (MG78_11PL & MG78_12PL & MG78_13PL & MG78_14PL & \ + MG78_15PL & MG78_16PL & MG78_17PL & MG78_18PL) +// End of MG78: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG81 to MG88: +// + +// Beginning of MG81: +#if (G82PL >= G81PL) || (G82PL == 0) +#define MG81_12PL ~(1 << 1) +#else +#define MG81_12PL 0xFFFF +#endif +#if (G83PL >= G81PL) || (G83PL == 0) +#define MG81_13PL ~(1 << 2) +#else +#define MG81_13PL 0xFFFF +#endif +#if (G84PL >= G81PL) || (G84PL == 0) +#define MG81_14PL ~(1 << 3) +#else +#define MG81_14PL 0xFFFF +#endif +#if (G85PL >= G81PL) || (G85PL == 0) +#define MG81_15PL ~(1 << 4) +#else +#define MG81_15PL 0xFFFF +#endif +#if (G86PL >= G81PL) || (G86PL == 0) +#define MG81_16PL ~(1 << 5) +#else +#define MG81_16PL 0xFFFF +#endif +#if (G87PL >= G81PL) || (G87PL == 0) +#define MG81_17PL ~(1 << 6) +#else +#define MG81_17PL 0xFFFF +#endif +#if (G88PL >= G81PL) || (G88PL == 0) +#define MG81_18PL ~(1 << 7) +#else +#define MG81_18PL 0xFFFF +#endif +#define MG81_11PL 0x00FE +#define MG81 (MG81_11PL & MG81_12PL & MG81_13PL & MG81_14PL & \ + MG81_15PL & MG81_16PL & MG81_17PL & MG81_18PL) +// End of MG81: + +// Beginning of MG82: +#if (G81PL >= G82PL) || (G81PL == 0) +#define MG82_11PL ~(1) +#else +#define MG82_11PL 0xFFFF +#endif +#if (G83PL >= G82PL) || (G83PL == 0) +#define MG82_13PL ~(1 << 2) +#else +#define MG82_13PL 0xFFFF +#endif +#if (G84PL >= G82PL) || (G84PL == 0) +#define MG82_14PL ~(1 << 3) +#else +#define MG82_14PL 0xFFFF +#endif +#if (G85PL >= G82PL) || (G85PL == 0) +#define MG82_15PL ~(1 << 4) +#else +#define MG82_15PL 0xFFFF +#endif +#if (G86PL >= G82PL) || (G86PL == 0) +#define MG82_16PL ~(1 << 5) +#else +#define MG82_16PL 0xFFFF +#endif +#if (G87PL >= G82PL) || (G87PL == 0) +#define MG82_17PL ~(1 << 6) +#else +#define MG82_17PL 0xFFFF +#endif +#if (G88PL >= G82PL) || (G88PL == 0) +#define MG82_18PL ~(1 << 7) +#else +#define MG82_18PL 0xFFFF +#endif +#define MG82_12PL 0x00FD +#define MG82 (MG82_11PL & MG82_12PL & MG82_13PL & MG82_14PL & \ + MG82_15PL & MG82_16PL & MG82_17PL & MG82_18PL) +// End of MG82: + +// Beginning of MG83: +#if (G81PL >= G83PL) || (G81PL == 0) +#define MG83_11PL ~(1) +#else +#define MG83_11PL 0xFFFF +#endif +#if (G82PL >= G83PL) || (G82PL == 0) +#define MG83_12PL ~(1 << 1) +#else +#define MG83_12PL 0xFFFF +#endif +#if (G84PL >= G83PL) || (G84PL == 0) +#define MG83_14PL ~(1 << 3) +#else +#define MG83_14PL 0xFFFF +#endif +#if (G85PL >= G83PL) || (G85PL == 0) +#define MG83_15PL ~(1 << 4) +#else +#define MG83_15PL 0xFFFF +#endif +#if (G86PL >= G83PL) || (G86PL == 0) +#define MG83_16PL ~(1 << 5) +#else +#define MG83_16PL 0xFFFF +#endif +#if (G87PL >= G83PL) || (G87PL == 0) +#define MG83_17PL ~(1 << 6) +#else +#define MG83_17PL 0xFFFF +#endif +#if (G88PL >= G83PL) || (G88PL == 0) +#define MG83_18PL ~(1 << 7) +#else +#define MG83_18PL 0xFFFF +#endif +#define MG83_13PL 0x00FB +#define MG83 (MG83_11PL & MG83_12PL & MG83_13PL & MG83_14PL & \ + MG83_15PL & MG83_16PL & MG83_17PL & MG83_18PL) +// End of MG83: + +// Beginning of MG84: +#if (G81PL >= G84PL) || (G81PL == 0) +#define MG84_11PL ~(1) +#else +#define MG84_11PL 0xFFFF +#endif +#if (G82PL >= G84PL) || (G82PL == 0) +#define MG84_12PL ~(1 << 1) +#else +#define MG84_12PL 0xFFFF +#endif +#if (G83PL >= G84PL) || (G83PL == 0) +#define MG84_13PL ~(1 << 2) +#else +#define MG84_13PL 0xFFFF +#endif +#if (G85PL >= G84PL) || (G85PL == 0) +#define MG84_15PL ~(1 << 4) +#else +#define MG84_15PL 0xFFFF +#endif +#if (G86PL >= G84PL) || (G86PL == 0) +#define MG84_16PL ~(1 << 5) +#else +#define MG84_16PL 0xFFFF +#endif +#if (G87PL >= G84PL) || (G87PL == 0) +#define MG84_17PL ~(1 << 6) +#else +#define MG84_17PL 0xFFFF +#endif +#if (G88PL >= G84PL) || (G88PL == 0) +#define MG84_18PL ~(1 << 7) +#else +#define MG84_18PL 0xFFFF +#endif +#define MG84_14PL 0x00F7 +#define MG84 (MG84_11PL & MG84_12PL & MG84_13PL & MG84_14PL & \ + MG84_15PL & MG84_16PL & MG84_17PL & MG84_18PL) +// End of MG84: + +// Beginning of MG85: +#if (G81PL >= G85PL) || (G81PL == 0) +#define MG85_11PL ~(1) +#else +#define MG85_11PL 0xFFFF +#endif +#if (G82PL >= G85PL) || (G82PL == 0) +#define MG85_12PL ~(1 << 1) +#else +#define MG85_12PL 0xFFFF +#endif +#if (G83PL >= G85PL) || (G83PL == 0) +#define MG85_13PL ~(1 << 2) +#else +#define MG85_13PL 0xFFFF +#endif +#if (G84PL >= G85PL) || (G84PL == 0) +#define MG85_14PL ~(1 << 3) +#else +#define MG85_14PL 0xFFFF +#endif +#if (G86PL >= G85PL) || (G86PL == 0) +#define MG85_16PL ~(1 << 5) +#else +#define MG85_16PL 0xFFFF +#endif +#if (G87PL >= G85PL) || (G87PL == 0) +#define MG85_17PL ~(1 << 6) +#else +#define MG85_17PL 0xFFFF +#endif +#if (G88PL >= G85PL) || (G88PL == 0) +#define MG85_18PL ~(1 << 7) +#else +#define MG85_18PL 0xFFFF +#endif +#define MG85_15PL 0x00EF +#define MG85 (MG85_11PL & MG85_12PL & MG85_13PL & MG85_14PL & \ + MG85_15PL & MG85_16PL & MG85_17PL & MG85_18PL) +// End of MG85: + +// Beginning of MG86: +#if (G81PL >= G86PL) || (G81PL == 0) +#define MG86_11PL ~(1) +#else +#define MG86_11PL 0xFFFF +#endif +#if (G82PL >= G86PL) || (G82PL == 0) +#define MG86_12PL ~(1 << 1) +#else +#define MG86_12PL 0xFFFF +#endif +#if (G83PL >= G86PL) || (G83PL == 0) +#define MG86_13PL ~(1 << 2) +#else +#define MG86_13PL 0xFFFF +#endif +#if (G84PL >= G86PL) || (G84PL == 0) +#define MG86_14PL ~(1 << 3) +#else +#define MG86_14PL 0xFFFF +#endif +#if (G85PL >= G86PL) || (G85PL == 0) +#define MG86_15PL ~(1 << 4) +#else +#define MG86_15PL 0xFFFF +#endif +#if (G87PL >= G86PL) || (G87PL == 0) +#define MG86_17PL ~(1 << 6) +#else +#define MG86_17PL 0xFFFF +#endif +#if (G88PL >= G86PL) || (G88PL == 0) +#define MG86_18PL ~(1 << 7) +#else +#define MG86_18PL 0xFFFF +#endif +#define MG86_16PL 0x00DF +#define MG86 (MG86_11PL & MG86_12PL & MG86_13PL & MG86_14PL & \ + MG86_15PL & MG86_16PL & MG86_17PL & MG86_18PL) +// End of MG86: + +// Beginning of MG87: +#if (G81PL >= G87PL) || (G81PL == 0) +#define MG87_11PL ~(1) +#else +#define MG87_11PL 0xFFFF +#endif +#if (G82PL >= G87PL) || (G82PL == 0) +#define MG87_12PL ~(1 << 1) +#else +#define MG87_12PL 0xFFFF +#endif +#if (G83PL >= G87PL) || (G83PL == 0) +#define MG87_13PL ~(1 << 2) +#else +#define MG87_13PL 0xFFFF +#endif +#if (G84PL >= G87PL) || (G84PL == 0) +#define MG87_14PL ~(1 << 3) +#else +#define MG87_14PL 0xFFFF +#endif +#if (G85PL >= G87PL) || (G85PL == 0) +#define MG87_15PL ~(1 << 4) +#else +#define MG87_15PL 0xFFFF +#endif +#if (G86PL >= G87PL) || (G86PL == 0) +#define MG87_16PL ~(1 << 5) +#else +#define MG87_16PL 0xFFFF +#endif +#if (G88PL >= G87PL) || (G88PL == 0) +#define MG87_18PL ~(1 << 7) +#else +#define MG87_18PL 0xFFFF +#endif +#define MG87_17PL 0x00BF +#define MG87 (MG87_11PL & MG87_12PL & MG87_13PL & MG87_14PL & \ + MG87_15PL & MG87_16PL & MG87_17PL & MG87_18PL) +// End of MG87: + +// Beginning of MG88: +#if (G81PL >= G88PL) || (G81PL == 0) +#define MG88_11PL ~(1) +#else +#define MG88_11PL 0xFFFF +#endif +#if (G82PL >= G88PL) || (G82PL == 0) +#define MG88_12PL ~(1 << 1) +#else +#define MG88_12PL 0xFFFF +#endif +#if (G83PL >= G88PL) || (G83PL == 0) +#define MG88_13PL ~(1 << 2) +#else +#define MG88_13PL 0xFFFF +#endif +#if (G84PL >= G88PL) || (G84PL == 0) +#define MG88_14PL ~(1 << 3) +#else +#define MG88_14PL 0xFFFF +#endif +#if (G85PL >= G88PL) || (G85PL == 0) +#define MG88_15PL ~(1 << 4) +#else +#define MG88_15PL 0xFFFF +#endif +#if (G86PL >= G88PL) || (G86PL == 0) +#define MG88_16PL ~(1 << 5) +#else +#define MG88_16PL 0xFFFF +#endif +#if (G87PL >= G88PL) || (G87PL == 0) +#define MG88_17PL ~(1 << 6) +#else +#define MG88_17PL 0xFFFF +#endif +#define MG88_18PL 0x007F +#define MG88 (MG88_11PL & MG88_12PL & MG88_13PL & MG88_14PL & \ + MG88_15PL & MG88_16PL & MG88_17PL & MG88_18PL) +// End of MG88: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG91 to MG98: +// + +// Beginning of MG91: +#if (G92PL >= G91PL) || (G92PL == 0) +#define MG91_12PL ~(1 << 1) +#else +#define MG91_12PL 0xFFFF +#endif +#if (G93PL >= G91PL) || (G93PL == 0) +#define MG91_13PL ~(1 << 2) +#else +#define MG91_13PL 0xFFFF +#endif +#if (G94PL >= G91PL) || (G94PL == 0) +#define MG91_14PL ~(1 << 3) +#else +#define MG91_14PL 0xFFFF +#endif +#if (G95PL >= G91PL) || (G95PL == 0) +#define MG91_15PL ~(1 << 4) +#else +#define MG91_15PL 0xFFFF +#endif +#if (G96PL >= G91PL) || (G96PL == 0) +#define MG91_16PL ~(1 << 5) +#else +#define MG91_16PL 0xFFFF +#endif +#if (G97PL >= G91PL) || (G97PL == 0) +#define MG91_17PL ~(1 << 6) +#else +#define MG91_17PL 0xFFFF +#endif +#if (G98PL >= G91PL) || (G98PL == 0) +#define MG91_18PL ~(1 << 7) +#else +#define MG91_18PL 0xFFFF +#endif +#define MG91_11PL 0x00FE +#define MG91 (MG91_11PL & MG91_12PL & MG91_13PL & MG91_14PL & \ + MG91_15PL & MG91_16PL & MG91_17PL & MG91_18PL) +// End of MG91: + +// Beginning of MG92: +#if (G91PL >= G92PL) || (G91PL == 0) +#define MG92_11PL ~(1) +#else +#define MG92_11PL 0xFFFF +#endif +#if (G93PL >= G92PL) || (G93PL == 0) +#define MG92_13PL ~(1 << 2) +#else +#define MG92_13PL 0xFFFF +#endif +#if (G94PL >= G92PL) || (G94PL == 0) +#define MG92_14PL ~(1 << 3) +#else +#define MG92_14PL 0xFFFF +#endif +#if (G95PL >= G92PL) || (G95PL == 0) +#define MG92_15PL ~(1 << 4) +#else +#define MG92_15PL 0xFFFF +#endif +#if (G96PL >= G92PL) || (G96PL == 0) +#define MG92_16PL ~(1 << 5) +#else +#define MG92_16PL 0xFFFF +#endif +#if (G97PL >= G92PL) || (G97PL == 0) +#define MG92_17PL ~(1 << 6) +#else +#define MG92_17PL 0xFFFF +#endif +#if (G98PL >= G92PL) || (G98PL == 0) +#define MG92_18PL ~(1 << 7) +#else +#define MG92_18PL 0xFFFF +#endif +#define MG92_12PL 0x00FD +#define MG92 (MG92_11PL & MG92_12PL & MG92_13PL & MG92_14PL & \ + MG92_15PL & MG92_16PL & MG92_17PL & MG92_18PL) +// End of MG92: + +// Beginning of MG93: +#if (G91PL >= G93PL) || (G91PL == 0) +#define MG93_11PL ~(1) +#else +#define MG93_11PL 0xFFFF +#endif +#if (G92PL >= G93PL) || (G92PL == 0) +#define MG93_12PL ~(1 << 1) +#else +#define MG93_12PL 0xFFFF +#endif +#if (G94PL >= G93PL) || (G94PL == 0) +#define MG93_14PL ~(1 << 3) +#else +#define MG93_14PL 0xFFFF +#endif +#if (G95PL >= G93PL) || (G95PL == 0) +#define MG93_15PL ~(1 << 4) +#else +#define MG93_15PL 0xFFFF +#endif +#if (G96PL >= G93PL) || (G96PL == 0) +#define MG93_16PL ~(1 << 5) +#else +#define MG93_16PL 0xFFFF +#endif +#if (G97PL >= G93PL) || (G97PL == 0) +#define MG93_17PL ~(1 << 6) +#else +#define MG93_17PL 0xFFFF +#endif +#if (G98PL >= G93PL) || (G98PL == 0) +#define MG93_18PL ~(1 << 7) +#else +#define MG93_18PL 0xFFFF +#endif +#define MG93_13PL 0x00FB +#define MG93 (MG93_11PL & MG93_12PL & MG93_13PL & MG93_14PL & \ + MG93_15PL & MG93_16PL & MG93_17PL & MG93_18PL) +// End of MG93: + +// Beginning of MG94: +#if (G91PL >= G94PL) || (G91PL == 0) +#define MG94_11PL ~(1) +#else +#define MG94_11PL 0xFFFF +#endif +#if (G92PL >= G94PL) || (G92PL == 0) +#define MG94_12PL ~(1 << 1) +#else +#define MG94_12PL 0xFFFF +#endif +#if (G93PL >= G94PL) || (G93PL == 0) +#define MG94_13PL ~(1 << 2) +#else +#define MG94_13PL 0xFFFF +#endif +#if (G95PL >= G94PL) || (G95PL == 0) +#define MG94_15PL ~(1 << 4) +#else +#define MG94_15PL 0xFFFF +#endif +#if (G96PL >= G94PL) || (G96PL == 0) +#define MG94_16PL ~(1 << 5) +#else +#define MG94_16PL 0xFFFF +#endif +#if (G97PL >= G94PL) || (G97PL == 0) +#define MG94_17PL ~(1 << 6) +#else +#define MG94_17PL 0xFFFF +#endif +#if (G98PL >= G94PL) || (G98PL == 0) +#define MG94_18PL ~(1 << 7) +#else +#define MG94_18PL 0xFFFF +#endif +#define MG94_14PL 0x00F7 +#define MG94 (MG94_11PL & MG94_12PL & MG94_13PL & MG94_14PL & \ + MG94_15PL & MG94_16PL & MG94_17PL & MG94_18PL) +// End of MG94: + +// Beginning of MG95: +#if (G91PL >= G95PL) || (G91PL == 0) +#define MG95_11PL ~(1) +#else +#define MG95_11PL 0xFFFF +#endif +#if (G92PL >= G95PL) || (G92PL == 0) +#define MG95_12PL ~(1 << 1) +#else +#define MG95_12PL 0xFFFF +#endif +#if (G93PL >= G95PL) || (G93PL == 0) +#define MG95_13PL ~(1 << 2) +#else +#define MG95_13PL 0xFFFF +#endif +#if (G94PL >= G95PL) || (G94PL == 0) +#define MG95_14PL ~(1 << 3) +#else +#define MG95_14PL 0xFFFF +#endif +#if (G96PL >= G95PL) || (G96PL == 0) +#define MG95_16PL ~(1 << 5) +#else +#define MG95_16PL 0xFFFF +#endif +#if (G97PL >= G95PL) || (G97PL == 0) +#define MG95_17PL ~(1 << 6) +#else +#define MG95_17PL 0xFFFF +#endif +#if (G98PL >= G95PL) || (G98PL == 0) +#define MG95_18PL ~(1 << 7) +#else +#define MG95_18PL 0xFFFF +#endif +#define MG95_15PL 0x00EF +#define MG95 (MG95_11PL & MG95_12PL & MG95_13PL & MG95_14PL & \ + MG95_15PL & MG95_16PL & MG95_17PL & MG95_18PL) +// End of MG95: + +// Beginning of MG96: +#if (G91PL >= G96PL) || (G91PL == 0) +#define MG96_11PL ~(1) +#else +#define MG96_11PL 0xFFFF +#endif +#if (G92PL >= G96PL) || (G92PL == 0) +#define MG96_12PL ~(1 << 1) +#else +#define MG96_12PL 0xFFFF +#endif +#if (G93PL >= G96PL) || (G93PL == 0) +#define MG96_13PL ~(1 << 2) +#else +#define MG96_13PL 0xFFFF +#endif +#if (G94PL >= G96PL) || (G94PL == 0) +#define MG96_14PL ~(1 << 3) +#else +#define MG96_14PL 0xFFFF +#endif +#if (G95PL >= G96PL) || (G95PL == 0) +#define MG96_15PL ~(1 << 4) +#else +#define MG96_15PL 0xFFFF +#endif +#if (G97PL >= G96PL) || (G97PL == 0) +#define MG96_17PL ~(1 << 6) +#else +#define MG96_17PL 0xFFFF +#endif +#if (G98PL >= G96PL) || (G98PL == 0) +#define MG96_18PL ~(1 << 7) +#else +#define MG96_18PL 0xFFFF +#endif +#define MG96_16PL 0x00DF +#define MG96 (MG96_11PL & MG96_12PL & MG96_13PL & MG96_14PL & \ + MG96_15PL & MG96_16PL & MG96_17PL & MG96_18PL) +// End of MG96: + +// Beginning of MG97: +#if (G91PL >= G97PL) || (G91PL == 0) +#define MG97_11PL ~(1) +#else +#define MG97_11PL 0xFFFF +#endif +#if (G92PL >= G97PL) || (G92PL == 0) +#define MG97_12PL ~(1 << 1) +#else +#define MG97_12PL 0xFFFF +#endif +#if (G93PL >= G97PL) || (G93PL == 0) +#define MG97_13PL ~(1 << 2) +#else +#define MG97_13PL 0xFFFF +#endif +#if (G94PL >= G97PL) || (G94PL == 0) +#define MG97_14PL ~(1 << 3) +#else +#define MG97_14PL 0xFFFF +#endif +#if (G95PL >= G97PL) || (G95PL == 0) +#define MG97_15PL ~(1 << 4) +#else +#define MG97_15PL 0xFFFF +#endif +#if (G96PL >= G97PL) || (G96PL == 0) +#define MG97_16PL ~(1 << 5) +#else +#define MG97_16PL 0xFFFF +#endif +#if (G98PL >= G97PL) || (G98PL == 0) +#define MG97_18PL ~(1 << 7) +#else +#define MG97_18PL 0xFFFF +#endif +#define MG97_17PL 0x00BF +#define MG97 (MG97_11PL & MG97_12PL & MG97_13PL & MG97_14PL & \ + MG97_15PL & MG97_16PL & MG97_17PL & MG97_18PL) +// End of MG97: + +// Beginning of MG98: +#if (G91PL >= G98PL) || (G91PL == 0) +#define MG98_11PL ~(1) +#else +#define MG98_11PL 0xFFFF +#endif +#if (G92PL >= G98PL) || (G92PL == 0) +#define MG98_12PL ~(1 << 1) +#else +#define MG98_12PL 0xFFFF +#endif +#if (G93PL >= G98PL) || (G93PL == 0) +#define MG98_13PL ~(1 << 2) +#else +#define MG98_13PL 0xFFFF +#endif +#if (G94PL >= G98PL) || (G94PL == 0) +#define MG98_14PL ~(1 << 3) +#else +#define MG98_14PL 0xFFFF +#endif +#if (G95PL >= G98PL) || (G95PL == 0) +#define MG98_15PL ~(1 << 4) +#else +#define MG98_15PL 0xFFFF +#endif +#if (G96PL >= G98PL) || (G96PL == 0) +#define MG98_16PL ~(1 << 5) +#else +#define MG98_16PL 0xFFFF +#endif +#if (G97PL >= G98PL) || (G97PL == 0) +#define MG98_17PL ~(1 << 6) +#else +#define MG98_17PL 0xFFFF +#endif +#define MG98_18PL 0x007F +#define MG98 (MG98_11PL & MG98_12PL & MG98_13PL & MG98_14PL & \ + MG98_15PL & MG98_16PL & MG98_17PL & MG98_18PL) +// End of MG98: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG101 to MG108: +// + +// Beginning of MG101: +#if (G102PL >= G101PL) || (G102PL == 0) +#define MG101_12PL ~(1 << 1) +#else +#define MG101_12PL 0xFFFF +#endif +#if (G103PL >= G101PL) || (G103PL == 0) +#define MG101_13PL ~(1 << 2) +#else +#define MG101_13PL 0xFFFF +#endif +#if (G104PL >= G101PL) || (G104PL == 0) +#define MG101_14PL ~(1 << 3) +#else +#define MG101_14PL 0xFFFF +#endif +#if (G105PL >= G101PL) || (G105PL == 0) +#define MG101_15PL ~(1 << 4) +#else +#define MG101_15PL 0xFFFF +#endif +#if (G106PL >= G101PL) || (G106PL == 0) +#define MG101_16PL ~(1 << 5) +#else +#define MG101_16PL 0xFFFF +#endif +#if (G107PL >= G101PL) || (G107PL == 0) +#define MG101_17PL ~(1 << 6) +#else +#define MG101_17PL 0xFFFF +#endif +#if (G108PL >= G101PL) || (G108PL == 0) +#define MG101_18PL ~(1 << 7) +#else +#define MG101_18PL 0xFFFF +#endif +#define MG101_11PL 0x00FE +#define MG101 (MG101_11PL & MG101_12PL & MG101_13PL & MG101_14PL & \ + MG101_15PL & MG101_16PL & MG101_17PL & MG101_18PL) +// End of MG101: + +// Beginning of MG102: +#if (G101PL >= G102PL) || (G101PL == 0) +#define MG102_11PL ~(1) +#else +#define MG102_11PL 0xFFFF +#endif +#if (G103PL >= G102PL) || (G103PL == 0) +#define MG102_13PL ~(1 << 2) +#else +#define MG102_13PL 0xFFFF +#endif +#if (G104PL >= G102PL) || (G104PL == 0) +#define MG102_14PL ~(1 << 3) +#else +#define MG102_14PL 0xFFFF +#endif +#if (G105PL >= G102PL) || (G105PL == 0) +#define MG102_15PL ~(1 << 4) +#else +#define MG102_15PL 0xFFFF +#endif +#if (G106PL >= G102PL) || (G106PL == 0) +#define MG102_16PL ~(1 << 5) +#else +#define MG102_16PL 0xFFFF +#endif +#if (G107PL >= G102PL) || (G107PL == 0) +#define MG102_17PL ~(1 << 6) +#else +#define MG102_17PL 0xFFFF +#endif +#if (G108PL >= G102PL) || (G108PL == 0) +#define MG102_18PL ~(1 << 7) +#else +#define MG102_18PL 0xFFFF +#endif +#define MG102_12PL 0x00FD +#define MG102 (MG102_11PL & MG102_12PL & MG102_13PL & MG102_14PL & \ + MG102_15PL & MG102_16PL & MG102_17PL & MG102_18PL) +// End of MG102: + +// Beginning of MG103: +#if (G101PL >= G103PL) || (G101PL == 0) +#define MG103_11PL ~(1) +#else +#define MG103_11PL 0xFFFF +#endif +#if (G102PL >= G103PL) || (G102PL == 0) +#define MG103_12PL ~(1 << 1) +#else +#define MG103_12PL 0xFFFF +#endif +#if (G104PL >= G103PL) || (G104PL == 0) +#define MG103_14PL ~(1 << 3) +#else +#define MG103_14PL 0xFFFF +#endif +#if (G105PL >= G103PL) || (G105PL == 0) +#define MG103_15PL ~(1 << 4) +#else +#define MG103_15PL 0xFFFF +#endif +#if (G106PL >= G103PL) || (G106PL == 0) +#define MG103_16PL ~(1 << 5) +#else +#define MG103_16PL 0xFFFF +#endif +#if (G107PL >= G103PL) || (G107PL == 0) +#define MG103_17PL ~(1 << 6) +#else +#define MG103_17PL 0xFFFF +#endif +#if (G108PL >= G103PL) || (G108PL == 0) +#define MG103_18PL ~(1 << 7) +#else +#define MG103_18PL 0xFFFF +#endif +#define MG103_13PL 0x00FB +#define MG103 (MG103_11PL & MG103_12PL & MG103_13PL & MG103_14PL & \ + MG103_15PL & MG103_16PL & MG103_17PL & MG103_18PL) +// End of MG103: + +// Beginning of MG104: +#if (G101PL >= G104PL) || (G101PL == 0) +#define MG104_11PL ~(1) +#else +#define MG104_11PL 0xFFFF +#endif +#if (G102PL >= G104PL) || (G102PL == 0) +#define MG104_12PL ~(1 << 1) +#else +#define MG104_12PL 0xFFFF +#endif +#if (G103PL >= G104PL) || (G103PL == 0) +#define MG104_13PL ~(1 << 2) +#else +#define MG104_13PL 0xFFFF +#endif +#if (G105PL >= G104PL) || (G105PL == 0) +#define MG104_15PL ~(1 << 4) +#else +#define MG104_15PL 0xFFFF +#endif +#if (G106PL >= G104PL) || (G106PL == 0) +#define MG104_16PL ~(1 << 5) +#else +#define MG104_16PL 0xFFFF +#endif +#if (G107PL >= G104PL) || (G107PL == 0) +#define MG104_17PL ~(1 << 6) +#else +#define MG104_17PL 0xFFFF +#endif +#if (G108PL >= G104PL) || (G108PL == 0) +#define MG104_18PL ~(1 << 7) +#else +#define MG104_18PL 0xFFFF +#endif +#define MG104_14PL 0x00F7 +#define MG104 (MG104_11PL & MG104_12PL & MG104_13PL & MG104_14PL & \ + MG104_15PL & MG104_16PL & MG104_17PL & MG104_18PL) +// End of MG104: + +// Beginning of MG105: +#if (G101PL >= G105PL) || (G101PL == 0) +#define MG105_11PL ~(1) +#else +#define MG105_11PL 0xFFFF +#endif +#if (G102PL >= G105PL) || (G102PL == 0) +#define MG105_12PL ~(1 << 1) +#else +#define MG105_12PL 0xFFFF +#endif +#if (G103PL >= G105PL) || (G103PL == 0) +#define MG105_13PL ~(1 << 2) +#else +#define MG105_13PL 0xFFFF +#endif +#if (G104PL >= G105PL) || (G104PL == 0) +#define MG105_14PL ~(1 << 3) +#else +#define MG105_14PL 0xFFFF +#endif +#if (G106PL >= G105PL) || (G106PL == 0) +#define MG105_16PL ~(1 << 5) +#else +#define MG105_16PL 0xFFFF +#endif +#if (G107PL >= G105PL) || (G107PL == 0) +#define MG105_17PL ~(1 << 6) +#else +#define MG105_17PL 0xFFFF +#endif +#if (G108PL >= G105PL) || (G108PL == 0) +#define MG105_18PL ~(1 << 7) +#else +#define MG105_18PL 0xFFFF +#endif +#define MG105_15PL 0x00EF +#define MG105 (MG105_11PL & MG105_12PL & MG105_13PL & MG105_14PL & \ + MG105_15PL & MG105_16PL & MG105_17PL & MG105_18PL) +// End of MG105: + +// Beginning of MG106: +#if (G101PL >= G106PL) || (G101PL == 0) +#define MG106_11PL ~(1) +#else +#define MG106_11PL 0xFFFF +#endif +#if (G102PL >= G106PL) || (G102PL == 0) +#define MG106_12PL ~(1 << 1) +#else +#define MG106_12PL 0xFFFF +#endif +#if (G103PL >= G106PL) || (G103PL == 0) +#define MG106_13PL ~(1 << 2) +#else +#define MG106_13PL 0xFFFF +#endif +#if (G104PL >= G106PL) || (G104PL == 0) +#define MG106_14PL ~(1 << 3) +#else +#define MG106_14PL 0xFFFF +#endif +#if (G105PL >= G106PL) || (G105PL == 0) +#define MG106_15PL ~(1 << 4) +#else +#define MG106_15PL 0xFFFF +#endif +#if (G107PL >= G106PL) || (G107PL == 0) +#define MG106_17PL ~(1 << 6) +#else +#define MG106_17PL 0xFFFF +#endif +#if (G108PL >= G106PL) || (G108PL == 0) +#define MG106_18PL ~(1 << 7) +#else +#define MG106_18PL 0xFFFF +#endif +#define MG106_16PL 0x00DF +#define MG106 (MG106_11PL & MG106_12PL & MG106_13PL & MG106_14PL & \ + MG106_15PL & MG106_16PL & MG106_17PL & MG106_18PL) +// End of MG106: + +// Beginning of MG107: +#if (G101PL >= G107PL) || (G101PL == 0) +#define MG107_11PL ~(1) +#else +#define MG107_11PL 0xFFFF +#endif +#if (G102PL >= G107PL) || (G102PL == 0) +#define MG107_12PL ~(1 << 1) +#else +#define MG107_12PL 0xFFFF +#endif +#if (G103PL >= G107PL) || (G103PL == 0) +#define MG107_13PL ~(1 << 2) +#else +#define MG107_13PL 0xFFFF +#endif +#if (G104PL >= G107PL) || (G104PL == 0) +#define MG107_14PL ~(1 << 3) +#else +#define MG107_14PL 0xFFFF +#endif +#if (G105PL >= G107PL) || (G105PL == 0) +#define MG107_15PL ~(1 << 4) +#else +#define MG107_15PL 0xFFFF +#endif +#if (G106PL >= G107PL) || (G106PL == 0) +#define MG107_16PL ~(1 << 5) +#else +#define MG107_16PL 0xFFFF +#endif +#if (G108PL >= G107PL) || (G108PL == 0) +#define MG107_18PL ~(1 << 7) +#else +#define MG107_18PL 0xFFFF +#endif +#define MG107_17PL 0x00BF +#define MG107 (MG107_11PL & MG107_12PL & MG107_13PL & MG107_14PL & \ + MG107_15PL & MG107_16PL & MG107_17PL & MG107_18PL) +// End of MG107: + +// Beginning of MG108: +#if (G101PL >= G108PL) || (G101PL == 0) +#define MG108_11PL ~(1) +#else +#define MG108_11PL 0xFFFF +#endif +#if (G102PL >= G108PL) || (G102PL == 0) +#define MG108_12PL ~(1 << 1) +#else +#define MG108_12PL 0xFFFF +#endif +#if (G103PL >= G108PL) || (G103PL == 0) +#define MG108_13PL ~(1 << 2) +#else +#define MG108_13PL 0xFFFF +#endif +#if (G104PL >= G108PL) || (G104PL == 0) +#define MG108_14PL ~(1 << 3) +#else +#define MG108_14PL 0xFFFF +#endif +#if (G105PL >= G108PL) || (G105PL == 0) +#define MG108_15PL ~(1 << 4) +#else +#define MG108_15PL 0xFFFF +#endif +#if (G106PL >= G108PL) || (G106PL == 0) +#define MG108_16PL ~(1 << 5) +#else +#define MG108_16PL 0xFFFF +#endif +#if (G107PL >= G108PL) || (G107PL == 0) +#define MG108_17PL ~(1 << 6) +#else +#define MG108_17PL 0xFFFF +#endif +#define MG108_18PL 0x007F +#define MG108 (MG108_11PL & MG108_12PL & MG108_13PL & MG108_14PL & \ + MG108_15PL & MG108_16PL & MG108_17PL & MG108_18PL) +// End of MG108: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG111 to MG118: +// + +// Beginning of MG111: +#if (G112PL >= G111PL) || (G112PL == 0) +#define MG111_12PL ~(1 << 1) +#else +#define MG111_12PL 0xFFFF +#endif +#if (G113PL >= G111PL) || (G113PL == 0) +#define MG111_13PL ~(1 << 2) +#else +#define MG111_13PL 0xFFFF +#endif +#if (G114PL >= G111PL) || (G114PL == 0) +#define MG111_14PL ~(1 << 3) +#else +#define MG111_14PL 0xFFFF +#endif +#if (G115PL >= G111PL) || (G115PL == 0) +#define MG111_15PL ~(1 << 4) +#else +#define MG111_15PL 0xFFFF +#endif +#if (G116PL >= G111PL) || (G116PL == 0) +#define MG111_16PL ~(1 << 5) +#else +#define MG111_16PL 0xFFFF +#endif +#if (G117PL >= G111PL) || (G117PL == 0) +#define MG111_17PL ~(1 << 6) +#else +#define MG111_17PL 0xFFFF +#endif +#if (G118PL >= G111PL) || (G118PL == 0) +#define MG111_18PL ~(1 << 7) +#else +#define MG111_18PL 0xFFFF +#endif +#define MG111_11PL 0x00FE +#define MG111 (MG111_11PL & MG111_12PL & MG111_13PL & MG111_14PL & \ + MG111_15PL & MG111_16PL & MG111_17PL & MG111_18PL) +// End of MG111: + +// Beginning of MG112: +#if (G111PL >= G112PL) || (G111PL == 0) +#define MG112_11PL ~(1) +#else +#define MG112_11PL 0xFFFF +#endif +#if (G113PL >= G112PL) || (G113PL == 0) +#define MG112_13PL ~(1 << 2) +#else +#define MG112_13PL 0xFFFF +#endif +#if (G114PL >= G112PL) || (G114PL == 0) +#define MG112_14PL ~(1 << 3) +#else +#define MG112_14PL 0xFFFF +#endif +#if (G115PL >= G112PL) || (G115PL == 0) +#define MG112_15PL ~(1 << 4) +#else +#define MG112_15PL 0xFFFF +#endif +#if (G116PL >= G112PL) || (G116PL == 0) +#define MG112_16PL ~(1 << 5) +#else +#define MG112_16PL 0xFFFF +#endif +#if (G117PL >= G112PL) || (G117PL == 0) +#define MG112_17PL ~(1 << 6) +#else +#define MG112_17PL 0xFFFF +#endif +#if (G118PL >= G112PL) || (G118PL == 0) +#define MG112_18PL ~(1 << 7) +#else +#define MG112_18PL 0xFFFF +#endif +#define MG112_12PL 0x00FD +#define MG112 (MG112_11PL & MG112_12PL & MG112_13PL & MG112_14PL & \ + MG112_15PL & MG112_16PL & MG112_17PL & MG112_18PL) +// End of MG112: + +// Beginning of MG113: +#if (G111PL >= G113PL) || (G111PL == 0) +#define MG113_11PL ~(1) +#else +#define MG113_11PL 0xFFFF +#endif +#if (G112PL >= G113PL) || (G112PL == 0) +#define MG113_12PL ~(1 << 1) +#else +#define MG113_12PL 0xFFFF +#endif +#if (G114PL >= G113PL) || (G114PL == 0) +#define MG113_14PL ~(1 << 3) +#else +#define MG113_14PL 0xFFFF +#endif +#if (G115PL >= G113PL) || (G115PL == 0) +#define MG113_15PL ~(1 << 4) +#else +#define MG113_15PL 0xFFFF +#endif +#if (G116PL >= G113PL) || (G116PL == 0) +#define MG113_16PL ~(1 << 5) +#else +#define MG113_16PL 0xFFFF +#endif +#if (G117PL >= G113PL) || (G117PL == 0) +#define MG113_17PL ~(1 << 6) +#else +#define MG113_17PL 0xFFFF +#endif +#if (G118PL >= G113PL) || (G118PL == 0) +#define MG113_18PL ~(1 << 7) +#else +#define MG113_18PL 0xFFFF +#endif +#define MG113_13PL 0x00FB +#define MG113 (MG113_11PL & MG113_12PL & MG113_13PL & MG113_14PL & \ + MG113_15PL & MG113_16PL & MG113_17PL & MG113_18PL) +// End of MG113: + +// Beginning of MG114: +#if (G111PL >= G114PL) || (G111PL == 0) +#define MG114_11PL ~(1) +#else +#define MG114_11PL 0xFFFF +#endif +#if (G112PL >= G114PL) || (G112PL == 0) +#define MG114_12PL ~(1 << 1) +#else +#define MG114_12PL 0xFFFF +#endif +#if (G113PL >= G114PL) || (G113PL == 0) +#define MG114_13PL ~(1 << 2) +#else +#define MG114_13PL 0xFFFF +#endif +#if (G115PL >= G114PL) || (G115PL == 0) +#define MG114_15PL ~(1 << 4) +#else +#define MG114_15PL 0xFFFF +#endif +#if (G116PL >= G114PL) || (G116PL == 0) +#define MG114_16PL ~(1 << 5) +#else +#define MG114_16PL 0xFFFF +#endif +#if (G117PL >= G114PL) || (G117PL == 0) +#define MG114_17PL ~(1 << 6) +#else +#define MG114_17PL 0xFFFF +#endif +#if (G118PL >= G114PL) || (G118PL == 0) +#define MG114_18PL ~(1 << 7) +#else +#define MG114_18PL 0xFFFF +#endif +#define MG114_14PL 0x00F7 +#define MG114 (MG114_11PL & MG114_12PL & MG114_13PL & MG114_14PL & \ + MG114_15PL & MG114_16PL & MG114_17PL & MG114_18PL) +// End of MG114: + +// Beginning of MG115: +#if (G111PL >= G115PL) || (G111PL == 0) +#define MG115_11PL ~(1) +#else +#define MG115_11PL 0xFFFF +#endif +#if (G112PL >= G115PL) || (G112PL == 0) +#define MG115_12PL ~(1 << 1) +#else +#define MG115_12PL 0xFFFF +#endif +#if (G113PL >= G115PL) || (G113PL == 0) +#define MG115_13PL ~(1 << 2) +#else +#define MG115_13PL 0xFFFF +#endif +#if (G114PL >= G115PL) || (G114PL == 0) +#define MG115_14PL ~(1 << 3) +#else +#define MG115_14PL 0xFFFF +#endif +#if (G116PL >= G115PL) || (G116PL == 0) +#define MG115_16PL ~(1 << 5) +#else +#define MG115_16PL 0xFFFF +#endif +#if (G117PL >= G115PL) || (G117PL == 0) +#define MG115_17PL ~(1 << 6) +#else +#define MG115_17PL 0xFFFF +#endif +#if (G118PL >= G115PL) || (G118PL == 0) +#define MG115_18PL ~(1 << 7) +#else +#define MG115_18PL 0xFFFF +#endif +#define MG115_15PL 0x00EF +#define MG115 (MG115_11PL & MG115_12PL & MG115_13PL & MG115_14PL & \ + MG115_15PL & MG115_16PL & MG115_17PL & MG115_18PL) +// End of MG115: + +// Beginning of MG116: +#if (G111PL >= G116PL) || (G111PL == 0) +#define MG116_11PL ~(1) +#else +#define MG116_11PL 0xFFFF +#endif +#if (G112PL >= G116PL) || (G112PL == 0) +#define MG116_12PL ~(1 << 1) +#else +#define MG116_12PL 0xFFFF +#endif +#if (G113PL >= G116PL) || (G113PL == 0) +#define MG116_13PL ~(1 << 2) +#else +#define MG116_13PL 0xFFFF +#endif +#if (G114PL >= G116PL) || (G114PL == 0) +#define MG116_14PL ~(1 << 3) +#else +#define MG116_14PL 0xFFFF +#endif +#if (G115PL >= G116PL) || (G115PL == 0) +#define MG116_15PL ~(1 << 4) +#else +#define MG116_15PL 0xFFFF +#endif +#if (G117PL >= G116PL) || (G117PL == 0) +#define MG116_17PL ~(1 << 6) +#else +#define MG116_17PL 0xFFFF +#endif +#if (G118PL >= G116PL) || (G118PL == 0) +#define MG116_18PL ~(1 << 7) +#else +#define MG116_18PL 0xFFFF +#endif +#define MG116_16PL 0x00DF +#define MG116 (MG116_11PL & MG116_12PL & MG116_13PL & MG116_14PL & \ + MG116_15PL & MG116_16PL & MG116_17PL & MG116_18PL) +// End of MG116: + +// Beginning of MG117: +#if (G111PL >= G117PL) || (G111PL == 0) +#define MG117_11PL ~(1) +#else +#define MG117_11PL 0xFFFF +#endif +#if (G112PL >= G117PL) || (G112PL == 0) +#define MG117_12PL ~(1 << 1) +#else +#define MG117_12PL 0xFFFF +#endif +#if (G113PL >= G117PL) || (G113PL == 0) +#define MG117_13PL ~(1 << 2) +#else +#define MG117_13PL 0xFFFF +#endif +#if (G114PL >= G117PL) || (G114PL == 0) +#define MG117_14PL ~(1 << 3) +#else +#define MG117_14PL 0xFFFF +#endif +#if (G115PL >= G117PL) || (G115PL == 0) +#define MG117_15PL ~(1 << 4) +#else +#define MG117_15PL 0xFFFF +#endif +#if (G116PL >= G117PL) || (G116PL == 0) +#define MG117_16PL ~(1 << 5) +#else +#define MG117_16PL 0xFFFF +#endif +#if (G118PL >= G117PL) || (G118PL == 0) +#define MG117_18PL ~(1 << 7) +#else +#define MG117_18PL 0xFFFF +#endif +#define MG117_17PL 0x00BF +#define MG117 (MG117_11PL & MG117_12PL & MG117_13PL & MG117_14PL & \ + MG117_15PL & MG117_16PL & MG117_17PL & MG117_18PL) +// End of MG117: + +// Beginning of MG118: +#if (G111PL >= G118PL) || (G111PL == 0) +#define MG118_11PL ~(1) +#else +#define MG118_11PL 0xFFFF +#endif +#if (G112PL >= G118PL) || (G112PL == 0) +#define MG118_12PL ~(1 << 1) +#else +#define MG118_12PL 0xFFFF +#endif +#if (G113PL >= G118PL) || (G113PL == 0) +#define MG118_13PL ~(1 << 2) +#else +#define MG118_13PL 0xFFFF +#endif +#if (G114PL >= G118PL) || (G114PL == 0) +#define MG118_14PL ~(1 << 3) +#else +#define MG118_14PL 0xFFFF +#endif +#if (G115PL >= G118PL) || (G115PL == 0) +#define MG118_15PL ~(1 << 4) +#else +#define MG118_15PL 0xFFFF +#endif +#if (G116PL >= G118PL) || (G116PL == 0) +#define MG118_16PL ~(1 << 5) +#else +#define MG118_16PL 0xFFFF +#endif +#if (G117PL >= G118PL) || (G117PL == 0) +#define MG118_17PL ~(1 << 6) +#else +#define MG118_17PL 0xFFFF +#endif +#define MG118_18PL 0x007F +#define MG118 (MG118_11PL & MG118_12PL & MG118_13PL & MG118_14PL & \ + MG118_15PL & MG118_16PL & MG118_17PL & MG118_18PL) +// End of MG118: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG121 to MG128: +// + +// Beginning of MG121: +#if (G122PL >= G121PL) || (G122PL == 0) +#define MG121_12PL ~(1 << 1) +#else +#define MG121_12PL 0xFFFF +#endif +#if (G123PL >= G121PL) || (G123PL == 0) +#define MG121_13PL ~(1 << 2) +#else +#define MG121_13PL 0xFFFF +#endif +#if (G124PL >= G121PL) || (G124PL == 0) +#define MG121_14PL ~(1 << 3) +#else +#define MG121_14PL 0xFFFF +#endif +#if (G125PL >= G121PL) || (G125PL == 0) +#define MG121_15PL ~(1 << 4) +#else +#define MG121_15PL 0xFFFF +#endif +#if (G126PL >= G121PL) || (G126PL == 0) +#define MG121_16PL ~(1 << 5) +#else +#define MG121_16PL 0xFFFF +#endif +#if (G127PL >= G121PL) || (G127PL == 0) +#define MG121_17PL ~(1 << 6) +#else +#define MG121_17PL 0xFFFF +#endif +#if (G128PL >= G121PL) || (G128PL == 0) +#define MG121_18PL ~(1 << 7) +#else +#define MG121_18PL 0xFFFF +#endif +#define MG121_11PL 0x00FE +#define MG121 (MG121_11PL & MG121_12PL & MG121_13PL & MG121_14PL & \ + MG121_15PL & MG121_16PL & MG121_17PL & MG121_18PL) +// End of MG121: + +// Beginning of MG121: +#if (G121PL >= G122PL) || (G121PL == 0) +#define MG122_11PL ~(1) +#else +#define MG122_11PL 0xFFFF +#endif +#if (G123PL >= G122PL) || (G123PL == 0) +#define MG122_13PL ~(1 << 2) +#else +#define MG122_13PL 0xFFFF +#endif +#if (G124PL >= G122PL) || (G124PL == 0) +#define MG122_14PL ~(1 << 3) +#else +#define MG122_14PL 0xFFFF +#endif +#if (G125PL >= G122PL) || (G125PL == 0) +#define MG122_15PL ~(1 << 4) +#else +#define MG122_15PL 0xFFFF +#endif +#if (G126PL >= G122PL) || (G126PL == 0) +#define MG122_16PL ~(1 << 5) +#else +#define MG122_16PL 0xFFFF +#endif +#if (G127PL >= G122PL) || (G127PL == 0) +#define MG122_17PL ~(1 << 6) +#else +#define MG122_17PL 0xFFFF +#endif +#if (G128PL >= G122PL) || (G128PL == 0) +#define MG122_18PL ~(1 << 7) +#else +#define MG122_18PL 0xFFFF +#endif +#define MG122_12PL 0x00FD +#define MG122 (MG122_11PL & MG122_12PL & MG122_13PL & MG122_14PL & \ + MG122_15PL & MG122_16PL & MG122_17PL & MG122_18PL) +// End of MG122: + +// Beginning of MG123: +#if (G121PL >= G123PL) || (G121PL == 0) +#define MG123_11PL ~(1) +#else +#define MG123_11PL 0xFFFF +#endif +#if (G122PL >= G123PL) || (G122PL == 0) +#define MG123_12PL ~(1 << 1) +#else +#define MG123_12PL 0xFFFF +#endif +#if (G124PL >= G123PL) || (G124PL == 0) +#define MG123_14PL ~(1 << 3) +#else +#define MG123_14PL 0xFFFF +#endif +#if (G125PL >= G123PL) || (G125PL == 0) +#define MG123_15PL ~(1 << 4) +#else +#define MG123_15PL 0xFFFF +#endif +#if (G126PL >= G123PL) || (G126PL == 0) +#define MG123_16PL ~(1 << 5) +#else +#define MG123_16PL 0xFFFF +#endif +#if (G127PL >= G123PL) || (G127PL == 0) +#define MG123_17PL ~(1 << 6) +#else +#define MG123_17PL 0xFFFF +#endif +#if (G128PL >= G123PL) || (G128PL == 0) +#define MG123_18PL ~(1 << 7) +#else +#define MG123_18PL 0xFFFF +#endif +#define MG123_13PL 0x00FB +#define MG123 (MG123_11PL & MG123_12PL & MG123_13PL & MG123_14PL & \ + MG123_15PL & MG123_16PL & MG123_17PL & MG123_18PL) +// End of MG123: + +// Beginning of MG124: +#if (G121PL >= G124PL) || (G121PL == 0) +#define MG124_11PL ~(1) +#else +#define MG124_11PL 0xFFFF +#endif +#if (G122PL >= G124PL) || (G122PL == 0) +#define MG124_12PL ~(1 << 1) +#else +#define MG124_12PL 0xFFFF +#endif +#if (G123PL >= G124PL) || (G123PL == 0) +#define MG124_13PL ~(1 << 2) +#else +#define MG124_13PL 0xFFFF +#endif +#if (G125PL >= G124PL) || (G125PL == 0) +#define MG124_15PL ~(1 << 4) +#else +#define MG124_15PL 0xFFFF +#endif +#if (G126PL >= G124PL) || (G126PL == 0) +#define MG124_16PL ~(1 << 5) +#else +#define MG124_16PL 0xFFFF +#endif +#if (G127PL >= G124PL) || (G127PL == 0) +#define MG124_17PL ~(1 << 6) +#else +#define MG124_17PL 0xFFFF +#endif +#if (G128PL >= G124PL) || (G128PL == 0) +#define MG124_18PL ~(1 << 7) +#else +#define MG124_18PL 0xFFFF +#endif +#define MG124_14PL 0x00F7 +#define MG124 (MG124_11PL & MG124_12PL & MG124_13PL & MG124_14PL & \ + MG124_15PL & MG124_16PL & MG124_17PL & MG124_18PL) +// End of MG124: + +// Beginning of MG125: +#if (G121PL >= G125PL) || (G121PL == 0) +#define MG125_11PL ~(1) +#else +#define MG125_11PL 0xFFFF +#endif +#if (G122PL >= G125PL) || (G122PL == 0) +#define MG125_12PL ~(1 << 1) +#else +#define MG125_12PL 0xFFFF +#endif +#if (G123PL >= G125PL) || (G123PL == 0) +#define MG125_13PL ~(1 << 2) +#else +#define MG125_13PL 0xFFFF +#endif +#if (G124PL >= G125PL) || (G124PL == 0) +#define MG125_14PL ~(1 << 3) +#else +#define MG125_14PL 0xFFFF +#endif +#if (G126PL >= G125PL) || (G126PL == 0) +#define MG125_16PL ~(1 << 5) +#else +#define MG125_16PL 0xFFFF +#endif +#if (G127PL >= G125PL) || (G127PL == 0) +#define MG125_17PL ~(1 << 6) +#else +#define MG125_17PL 0xFFFF +#endif +#if (G128PL >= G125PL) || (G128PL == 0) +#define MG125_18PL ~(1 << 7) +#else +#define MG125_18PL 0xFFFF +#endif +#define MG125_15PL 0x00EF +#define MG125 (MG125_11PL & MG125_12PL & MG125_13PL & MG125_14PL & \ + MG125_15PL & MG125_16PL & MG125_17PL & MG125_18PL) +// End of MG125: + +// Beginning of MG126: +#if (G121PL >= G126PL) || (G121PL == 0) +#define MG126_11PL ~(1) +#else +#define MG126_11PL 0xFFFF +#endif +#if (G122PL >= G126PL) || (G122PL == 0) +#define MG126_12PL ~(1 << 1) +#else +#define MG126_12PL 0xFFFF +#endif +#if (G123PL >= G126PL) || (G123PL == 0) +#define MG126_13PL ~(1 << 2) +#else +#define MG126_13PL 0xFFFF +#endif +#if (G124PL >= G126PL) || (G124PL == 0) +#define MG126_14PL ~(1 << 3) +#else +#define MG126_14PL 0xFFFF +#endif +#if (G125PL >= G126PL) || (G125PL == 0) +#define MG126_15PL ~(1 << 4) +#else +#define MG126_15PL 0xFFFF +#endif +#if (G127PL >= G126PL) || (G127PL == 0) +#define MG126_17PL ~(1 << 6) +#else +#define MG126_17PL 0xFFFF +#endif +#if (G128PL >= G126PL) || (G128PL == 0) +#define MG126_18PL ~(1 << 7) +#else +#define MG126_18PL 0xFFFF +#endif +#define MG126_16PL 0x00DF +#define MG126 (MG126_11PL & MG126_12PL & MG126_13PL & MG126_14PL & \ + MG126_15PL & MG126_16PL & MG126_17PL & MG126_18PL) +// End of MG126: + +// Beginning of MG127: +#if (G121PL >= G127PL) || (G121PL == 0) +#define MG127_11PL ~(1) +#else +#define MG127_11PL 0xFFFF +#endif +#if (G122PL >= G127PL) || (G122PL == 0) +#define MG127_12PL ~(1 << 1) +#else +#define MG127_12PL 0xFFFF +#endif +#if (G123PL >= G127PL) || (G123PL == 0) +#define MG127_13PL ~(1 << 2) +#else +#define MG127_13PL 0xFFFF +#endif +#if (G124PL >= G127PL) || (G124PL == 0) +#define MG127_14PL ~(1 << 3) +#else +#define MG127_14PL 0xFFFF +#endif +#if (G125PL >= G127PL) || (G125PL == 0) +#define MG127_15PL ~(1 << 4) +#else +#define MG127_15PL 0xFFFF +#endif +#if (G126PL >= G127PL) || (G126PL == 0) +#define MG127_16PL ~(1 << 5) +#else +#define MG127_16PL 0xFFFF +#endif +#if (G128PL >= G127PL) || (G128PL == 0) +#define MG127_18PL ~(1 << 7) +#else +#define MG127_18PL 0xFFFF +#endif +#define MG127_17PL 0x00BF +#define MG127 (MG127_11PL & MG127_12PL & MG127_13PL & MG127_14PL & \ + MG127_15PL & MG127_16PL & MG127_17PL & MG127_18PL) +// End of MG127: + +// Beginning of MG128: +#if (G121PL >= G128PL) || (G121PL == 0) +#define MG128_11PL ~(1) +#else +#define MG128_11PL 0xFFFF +#endif +#if (G122PL >= G128PL) || (G122PL == 0) +#define MG128_12PL ~(1 << 1) +#else +#define MG128_12PL 0xFFFF +#endif +#if (G123PL >= G128PL) || (G123PL == 0) +#define MG128_13PL ~(1 << 2) +#else +#define MG128_13PL 0xFFFF +#endif +#if (G124PL >= G128PL) || (G124PL == 0) +#define MG128_14PL ~(1 << 3) +#else +#define MG128_14PL 0xFFFF +#endif +#if (G125PL >= G128PL) || (G125PL == 0) +#define MG128_15PL ~(1 << 4) +#else +#define MG128_15PL 0xFFFF +#endif +#if (G126PL >= G128PL) || (G126PL == 0) +#define MG128_16PL ~(1 << 5) +#else +#define MG128_16PL 0xFFFF +#endif +#if (G127PL >= G128PL) || (G127PL == 0) +#define MG128_17PL ~(1 << 6) +#else +#define MG128_17PL 0xFFFF +#endif +#define MG128_18PL 0x007F +#define MG128 (MG128_11PL & MG128_12PL & MG128_13PL & MG128_14PL & \ + MG128_15PL & MG128_16PL & MG128_17PL & MG128_18PL) +// End of MG128: + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // eof + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h new file mode 100644 index 0000000..e6b5e40 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Adc.h @@ -0,0 +1,224 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 19, 2007 15:09:18 $ +//########################################################################### +// +// FILE: DSP281x_Adc.h +// +// TITLE: DSP281x Device ADC Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + + +#ifndef DSP281x_ADC_H +#define DSP281x_ADC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// ADC Individual Register Bit Definitions: + +struct ADCTRL1_BITS { // bits description + Uint16 rsvd1:4; // 3:0 reserved + Uint16 SEQ_CASC:1; // 4 Cascaded sequencer mode + Uint16 SEQ_OVRD:1; // 5 Sequencer override + Uint16 CONT_RUN:1; // 6 Continuous run + Uint16 CPS:1; // 7 ADC core clock pre-scalar + Uint16 ACQ_PS:4; // 11:8 Acquisition window size + Uint16 SUSMOD:2; // 13:12 Emulation suspend mode + Uint16 RESET:1; // 14 ADC reset + Uint16 rsvd2:1; // 15 reserved +}; + + +union ADCTRL1_REG { + Uint16 all; + struct ADCTRL1_BITS bit; +}; + + +struct ADCTRL2_BITS { // bits description + Uint16 EVB_SOC_SEQ2:1; // 0 Event manager B SOC mask for SEQ2 + Uint16 rsvd1:1; // 1 reserved + Uint16 INT_MOD_SEQ2:1; // 2 SEQ2 Interrupt mode + Uint16 INT_ENA_SEQ2:1; // 3 SEQ2 Interrupt enable + Uint16 rsvd2:1; // 4 reserved + Uint16 SOC_SEQ2:1; // 5 Start of conversion for SEQ2 + Uint16 RST_SEQ2:1; // 6 Reset SEQ2 + Uint16 EXT_SOC_SEQ1:1; // 7 External start of conversion for SEQ1 + Uint16 EVA_SOC_SEQ1:1; // 8 Event manager A SOC mask for SEQ1 + Uint16 rsvd3:1; // 9 reserved + Uint16 INT_MOD_SEQ1:1; // 10 SEQ1 Interrupt mode + Uint16 INT_ENA_SEQ1:1; // 11 SEQ1 Interrupt enable + Uint16 rsvd4:1; // 12 reserved + Uint16 SOC_SEQ1:1; // 13 Start of conversion trigger for SEQ1 + Uint16 RST_SEQ1:1; // 14 Restart sequencer 1 + Uint16 EVB_SOC_SEQ:1; // 15 EVB SOC enable +}; + + +union ADCTRL2_REG { + Uint16 all; + struct ADCTRL2_BITS bit; +}; + + +struct ADCASEQSR_BITS { // bits description + Uint16 SEQ1_STATE:4; // 3:0 SEQ1 state + Uint16 SEQ2_STATE:3; // 6:4 SEQ2 state + Uint16 rsvd1:1; // 7 reserved + Uint16 SEQ_CNTR:4; // 11:8 Sequencing counter status + Uint16 rsvd2:4; // 15:12 reserved +}; + +union ADCASEQSR_REG { + Uint16 all; + struct ADCASEQSR_BITS bit; +}; + + +struct ADCMAXCONV_BITS { // bits description + Uint16 MAX_CONV1:4; // 3:0 Max number of conversions + Uint16 MAX_CONV2:3; // 6:4 Max number of conversions + Uint16 rsvd1:9; // 15:7 reserved +}; + +union ADCMAXCONV_REG { + Uint16 all; + struct ADCMAXCONV_BITS bit; +}; + + +struct ADCCHSELSEQ1_BITS { // bits description + Uint16 CONV00:4; // 3:0 Conversion selection 00 + Uint16 CONV01:4; // 7:4 Conversion selection 01 + Uint16 CONV02:4; // 11:8 Conversion selection 02 + Uint16 CONV03:4; // 15:12 Conversion selection 03 +}; + +union ADCCHSELSEQ1_REG{ + Uint16 all; + struct ADCCHSELSEQ1_BITS bit; +}; + +struct ADCCHSELSEQ2_BITS { // bits description + Uint16 CONV04:4; // 3:0 Conversion selection 04 + Uint16 CONV05:4; // 7:4 Conversion selection 05 + Uint16 CONV06:4; // 11:8 Conversion selection 06 + Uint16 CONV07:4; // 15:12 Conversion selection 07 +}; + +union ADCCHSELSEQ2_REG{ + Uint16 all; + struct ADCCHSELSEQ2_BITS bit; +}; + +struct ADCCHSELSEQ3_BITS { // bits description + Uint16 CONV08:4; // 3:0 Conversion selection 08 + Uint16 CONV09:4; // 7:4 Conversion selection 09 + Uint16 CONV10:4; // 11:8 Conversion selection 10 + Uint16 CONV11:4; // 15:12 Conversion selection 11 +}; + +union ADCCHSELSEQ3_REG{ + Uint16 all; + struct ADCCHSELSEQ3_BITS bit; +}; + +struct ADCCHSELSEQ4_BITS { // bits description + Uint16 CONV12:4; // 3:0 Conversion selection 12 + Uint16 CONV13:4; // 7:4 Conversion selection 13 + Uint16 CONV14:4; // 11:8 Conversion selection 14 + Uint16 CONV15:4; // 15:12 Conversion selection 15 +}; + +union ADCCHSELSEQ4_REG { + Uint16 all; + struct ADCCHSELSEQ4_BITS bit; +}; + +struct ADCTRL3_BITS { // bits description + Uint16 SMODE_SEL:1; // 0 Sampling mode select + Uint16 ADCCLKPS:4; // 4:1 ADC core clock divider + Uint16 ADCPWDN:1; // 5 ADC powerdown + Uint16 ADCBGRFDN:2; // 7:6 ADC bandgap/ref power down + Uint16 ADCEXTREF:1; // 8 ADC external reference + Uint16 rsvd1:7; // 15:9 reserved +}; + +union ADCTRL3_REG { + Uint16 all; + struct ADCTRL3_BITS bit; +}; + + +struct ADCST_BITS { // bits description + Uint16 INT_SEQ1:1; // 0 SEQ1 Interrupt flag + Uint16 INT_SEQ2:1; // 1 SEQ2 Interrupt flag + Uint16 SEQ1_BSY:1; // 2 SEQ1 busy status + Uint16 SEQ2_BSY:1; // 3 SEQ2 busy status + Uint16 INT_SEQ1_CLR:1; // 4 SEQ1 Interrupt clear + Uint16 INT_SEQ2_CLR:1; // 5 SEQ2 Interrupt clear + Uint16 EOS_BUF1:1; // 6 End of sequence buffer1 + Uint16 EOS_BUF2:1; // 7 End of sequence buffer2 + Uint16 rsvd1:8; // 15:8 reserved +}; + + +union ADCST_REG { + Uint16 all; + struct ADCST_BITS bit; +}; + + +struct ADC_REGS { + union ADCTRL1_REG ADCTRL1; // ADC Control 1 + union ADCTRL2_REG ADCTRL2; // ADC Control 2 + union ADCMAXCONV_REG ADCMAXCONV; // Max conversions + union ADCCHSELSEQ1_REG ADCCHSELSEQ1; // Channel select sequencing control 1 + union ADCCHSELSEQ2_REG ADCCHSELSEQ2; // Channel select sequencing control 2 + union ADCCHSELSEQ3_REG ADCCHSELSEQ3; // Channel select sequencing control 3 + union ADCCHSELSEQ4_REG ADCCHSELSEQ4; // Channel select sequencing control 4 + union ADCASEQSR_REG ADCASEQSR; // Autosequence status register + Uint16 ADCRESULT0; // Conversion Result Buffer 0 + Uint16 ADCRESULT1; // Conversion Result Buffer 1 + Uint16 ADCRESULT2; // Conversion Result Buffer 2 + Uint16 ADCRESULT3; // Conversion Result Buffer 3 + Uint16 ADCRESULT4; // Conversion Result Buffer 4 + Uint16 ADCRESULT5; // Conversion Result Buffer 5 + Uint16 ADCRESULT6; // Conversion Result Buffer 6 + Uint16 ADCRESULT7; // Conversion Result Buffer 7 + Uint16 ADCRESULT8; // Conversion Result Buffer 8 + Uint16 ADCRESULT9; // Conversion Result Buffer 9 + Uint16 ADCRESULT10; // Conversion Result Buffer 10 + Uint16 ADCRESULT11; // Conversion Result Buffer 11 + Uint16 ADCRESULT12; // Conversion Result Buffer 12 + Uint16 ADCRESULT13; // Conversion Result Buffer 13 + Uint16 ADCRESULT14; // Conversion Result Buffer 14 + Uint16 ADCRESULT15; // Conversion Result Buffer 15 + union ADCTRL3_REG ADCTRL3; // ADC Control 3 + union ADCST_REG ADCST; // ADC Status Register +}; + + +//--------------------------------------------------------------------------- +// ADC External References & Function Declarations: +// +extern volatile struct ADC_REGS AdcRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + + +#endif // end of DSP281x_ADC_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h new file mode 100644 index 0000000..ffe1784 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_CpuTimers.h @@ -0,0 +1,184 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: July 9, 2009 17:08:54 $ +//########################################################################### +// +// FILE: DSP281x_CpuTimers.h +// +// TITLE: DSP281x CPU 32-bit Timers Register Definitions. +// +// NOTES: CpuTimer2 is reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use this timer in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_CPU_TIMERS_H +#define DSP281x_CPU_TIMERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// CPU Timer Register Bit Definitions: +// +// +// TCR: Control register bit definitions: +struct TCR_BITS { // bits description + Uint16 rsvd1:4; // 3:0 reserved + Uint16 TSS:1; // 4 Timer Start/Stop + Uint16 TRB:1; // 5 Timer reload + Uint16 rsvd2:4; // 9:6 reserved + Uint16 SOFT:1; // 10 Emulation modes + Uint16 FREE:1; // 11 + Uint16 rsvd3:2; // 12:13 reserved + Uint16 TIE:1; // 14 Output enable + Uint16 TIF:1; // 15 Interrupt flag +}; + +union TCR_REG { + Uint16 all; + struct TCR_BITS bit; +}; + +// TPR: Pre-scale low bit definitions: +struct TPR_BITS { // bits description + Uint16 TDDR:8; // 7:0 Divide-down low + Uint16 PSC:8; // 15:8 Prescale counter low +}; + +union TPR_REG { + Uint16 all; + struct TPR_BITS bit; +}; + +// TPRH: Pre-scale high bit definitions: +struct TPRH_BITS { // bits description + Uint16 TDDRH:8; // 7:0 Divide-down high + Uint16 PSCH:8; // 15:8 Prescale counter high +}; + +union TPRH_REG { + Uint16 all; + struct TPRH_BITS bit; +}; + +// TIM, TIMH: Timer register definitions: +struct TIM_REG { + Uint16 LSW; + Uint16 MSW; +}; + +union TIM_GROUP { + Uint32 all; + struct TIM_REG half; +}; + +// PRD, PRDH: Period register definitions: +struct PRD_REG { + Uint16 LSW; + Uint16 MSW; +}; + +union PRD_GROUP { + Uint32 all; + struct PRD_REG half; +}; + +//--------------------------------------------------------------------------- +// CPU Timer Register File: +// +struct CPUTIMER_REGS { + union TIM_GROUP TIM; // Timer counter register + union PRD_GROUP PRD; // Period register + union TCR_REG TCR; // Timer control register + Uint16 rsvd1; // reserved + union TPR_REG TPR; // Timer pre-scale low + union TPRH_REG TPRH; // Timer pre-scale high +}; + +//--------------------------------------------------------------------------- +// CPU Timer Support Variables: +// +struct CPUTIMER_VARS { + volatile struct CPUTIMER_REGS *RegsAddr; + Uint32 InterruptCount; + float CPUFreqInMHz; + float PeriodInUSec; +}; + +//--------------------------------------------------------------------------- +// Function prototypes and external definitions: +// +void InitCpuTimers(void); +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period); + +extern volatile struct CPUTIMER_REGS CpuTimer0Regs; +extern struct CPUTIMER_VARS CpuTimer0; + +// CpuTimer2 is reserved when using DSP BIOS & other RTOS +extern volatile struct CPUTIMER_REGS CpuTimer1Regs; +extern volatile struct CPUTIMER_REGS CpuTimer2Regs; + +extern struct CPUTIMER_VARS CpuTimer1; +extern struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// Usefull Timer Operations: +// +// Start Timer: +#define StartCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 0 + +// Stop Timer: +#define StopCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +#define ReloadCpuTimer0() CpuTimer0Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +#define ReadCpuTimer0Counter() CpuTimer0Regs.TIM.all + +// Read 32-Bit Period Value: +#define ReadCpuTimer0Period() CpuTimer0Regs.PRD.all + +// CpuTimer2 is reserved by DSP BIOS & other RTOS +// Do not use this timer if you ever plan on integrating +// DSP-BIOS or another realtime OS. + +// Start Timer: +#define StartCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 0 +#define StartCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 0 + +// Stop Timer: +#define StopCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 1 +#define StopCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +#define ReloadCpuTimer1() CpuTimer1Regs.TCR.bit.TRB = 1 +#define ReloadCpuTimer2() CpuTimer2Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +#define ReadCpuTimer1Counter() CpuTimer1Regs.TIM.all +#define ReadCpuTimer2Counter() CpuTimer2Regs.TIM.all + +// Read 32-Bit Period Value: +#define ReadCpuTimer1Period() CpuTimer1Regs.PRD.all +#define ReadCpuTimer2Period() CpuTimer2Regs.PRD.all + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_CPU_TIMERS_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h new file mode 100644 index 0000000..e55f671 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DefaultIsr.h @@ -0,0 +1,123 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:38 $ +//########################################################################### +// +// FILE: DSP281x_DefaultIsr.h +// +// TITLE: DSP281x Devices Default Interrupt Service Routines Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEFAULT_ISR_H +#define DSP281x_DEFAULT_ISR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// Default Interrupt Service Routine Declarations: +// +// The following function prototypes are for the +// default ISR routines used with the default PIE vector table. +// This default vector table is found in the DSP281x_PieVect.h +// file. +// + +// Non-Peripheral Interrupts: +interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1 +interrupt void INT14_ISR(void); // CPU-Timer2 +interrupt void DATALOG_ISR(void); // Datalogging interrupt +interrupt void RTOSINT_ISR(void); // RTOS interrupt +interrupt void EMUINT_ISR(void); // Emulation interrupt +interrupt void NMI_ISR(void); // Non-maskable interrupt +interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP +interrupt void USER1_ISR(void); // User Defined trap 1 +interrupt void USER2_ISR(void); // User Defined trap 2 +interrupt void USER3_ISR(void); // User Defined trap 3 +interrupt void USER4_ISR(void); // User Defined trap 4 +interrupt void USER5_ISR(void); // User Defined trap 5 +interrupt void USER6_ISR(void); // User Defined trap 6 +interrupt void USER7_ISR(void); // User Defined trap 7 +interrupt void USER8_ISR(void); // User Defined trap 8 +interrupt void USER9_ISR(void); // User Defined trap 9 +interrupt void USER10_ISR(void); // User Defined trap 10 +interrupt void USER11_ISR(void); // User Defined trap 11 +interrupt void USER12_ISR(void); // User Defined trap 12 + +// Group 1 PIE Interrupt Service Routines: +interrupt void PDPINTA_ISR(void); // EV-A +interrupt void PDPINTB_ISR(void); // EV-B +interrupt void XINT1_ISR(void); +interrupt void XINT2_ISR(void); +interrupt void ADCINT_ISR(void); // ADC +interrupt void TINT0_ISR(void); // Timer 0 +interrupt void WAKEINT_ISR(void); // WD + +// Group 2 PIE Interrupt Service Routines: +interrupt void CMP1INT_ISR(void); // EV-A +interrupt void CMP2INT_ISR(void); // EV-A +interrupt void CMP3INT_ISR(void); // EV-A +interrupt void T1PINT_ISR(void); // EV-A +interrupt void T1CINT_ISR(void); // EV-A +interrupt void T1UFINT_ISR(void); // EV-A +interrupt void T1OFINT_ISR(void); // EV-A + +// Group 3 PIE Interrupt Service Routines: +interrupt void T2PINT_ISR(void); // EV-A +interrupt void T2CINT_ISR(void); // EV-A +interrupt void T2UFINT_ISR(void); // EV-A +interrupt void T2OFINT_ISR(void); // EV-A +interrupt void CAPINT1_ISR(void); // EV-A +interrupt void CAPINT2_ISR(void); // EV-A +interrupt void CAPINT3_ISR(void); // EV-A + +// Group 4 PIE Interrupt Service Routines: +interrupt void CMP4INT_ISR(void); // EV-B +interrupt void CMP5INT_ISR(void); // EV-B +interrupt void CMP6INT_ISR(void); // EV-B +interrupt void T3PINT_ISR(void); // EV-B +interrupt void T3CINT_ISR(void); // EV-B +interrupt void T3UFINT_ISR(void); // EV-B +interrupt void T3OFINT_ISR(void); // EV-B + +// Group 5 PIE Interrupt Service Routines: +interrupt void T4PINT_ISR(void); // EV-B +interrupt void T4CINT_ISR(void); // EV-B +interrupt void T4UFINT_ISR(void); // EV-B +interrupt void T4OFINT_ISR(void); // EV-B +interrupt void CAPINT4_ISR(void); // EV-B +interrupt void CAPINT5_ISR(void); // EV-B +interrupt void CAPINT6_ISR(void); // EV-B + +// Group 6 PIE Interrupt Service Routines: +interrupt void SPIRXINTA_ISR(void); // SPI +interrupt void SPITXINTA_ISR(void); // SPI +interrupt void MRINTA_ISR(void); // McBSP +interrupt void MXINTA_ISR(void); // McBSP + + +// Group 9 PIE Interrupt Service Routines: +interrupt void SCIRXINTA_ISR(void); // SCI-A +interrupt void SCITXINTA_ISR(void); // SCI-A +interrupt void SCIRXINTB_ISR(void); // SCI-B +interrupt void SCITXINTB_ISR(void); // SCI-B +interrupt void ECAN0INTA_ISR(void); // eCAN +interrupt void ECAN1INTA_ISR(void); // eCAN + + +// Catch-all for Reserved Locations For testing purposes: +interrupt void PIE_RESERVED(void); // Reserved for test +interrupt void rsvd_ISR(void); // for test + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEFAULT_ISR_H definition + diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h new file mode 100644 index 0000000..af37f2e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_DevEmu.h @@ -0,0 +1,103 @@ +//########################################################################### +// +// FILE: DSP281x_DevEmu.h +// +// TITLE: DSP281x Device Emulation Register Definitions. +// +//########################################################################### +// +// Ver | dd mmm yyyy | Who | Description of changes +// =====|=============|======|=============================================== +// 1.00| 11 Sep 2003 | L.H. | Changes since previous version (v.58 Alpha) +// | | | As of Rev C silicon, DEVICEID is a 16-bit +// | | | register +// | | | Commented out the DFT test registers. These +// | | | are not needed as of Rev C silicon. +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEV_EMU_H +#define DSP281x_DEV_EMU_H + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// Device Emulation Register Bit Definitions: +// +// Device Configuration Register Bit Definitions +struct DEVICECNF_BITS { // bits description + Uint16 rsvd1:3; // 2:0 reserved + Uint16 VMAPS:1; // 3 VMAP Status + Uint16 rsvd2:1; // 4 reserved + Uint16 XRSn:1; // 5 XRSn Signal Status + Uint16 rsvd3:10; // 15:6 + Uint16 rsvd4:3; // 18:6 + Uint16 ENPROT:1; // 19 Enable/Disable pipeline protection + Uint16 rsvd5:12; // 31:20 reserved +}; + +union DEVICECNF_REG { + Uint32 all; + struct DEVICECNF_BITS bit; +}; + + +// Device ID Register Bit Definitions +struct DEVICEID_BITS { // bits description + Uint16 REVID:16; // 15:0 Silicon revision +}; + +union DEVICEID_REG { + Uint16 all; + struct DEVICEID_BITS bit; +}; + +// PARTID Register Bit Definitions +struct PARTID_BITS { // bits description + Uint16 PARTNO:8; // 7:0 Part Number + Uint16 PARTTYPE:8; // 15:8 Part Type +}; + +union PARTID_REG { + Uint16 all; + struct PARTID_BITS bit; +}; + +struct DEV_EMU_REGS { + union DEVICECNF_REG DEVICECNF; // device configuration + union PARTID_REG PARTID; // Part ID + union DEVICEID_REG DEVICEID; // Device ID + Uint16 PROTSTART; // Write-Read protection start + Uint16 PROTRANGE; // Write-Read protection range + Uint16 rsvd2[202]; +// These registers are no longer needed for Rev C and beyond +// Uint16 M0RAMDFT; +// Uint16 M1RAMDFT; +// Uint16 L0RAMDFT; +// Uint16 L1RAMDFT; +// Uint16 H0RAMDFT; +}; + +#define REVID DEVICEID // REVID replaces DEVICEID starting 281x header files v1.10 + // use #define to maintain code compatibility with v1.00 and older + + + +//--------------------------------------------------------------------------- +// Device Emulation Register References & Function Declarations: +// +extern volatile struct DEV_EMU_REGS DevEmuRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEV_EMU_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h new file mode 100644 index 0000000..e664028 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Device.h @@ -0,0 +1,144 @@ +// TI File $Revision: /main/5 $ +// Checkin $Date: December 17, 2007 13:36:09 $ +//########################################################################### +// +// FILE: DSP281x_Device.h +// +// TITLE: DSP281x Device Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_DEVICE_H +#define DSP281x_DEVICE_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define TARGET 1 +//--------------------------------------------------------------------------- +// User To Select Target Device: + +#define DSP28_F2812 TARGET +#define DSP28_F2811 0 +#define DSP28_F2810 0 + +//--------------------------------------------------------------------------- +// Common CPU Definitions: +// + +extern cregister volatile unsigned int IFR; +extern cregister volatile unsigned int IER; + +#define EINT asm(" clrc INTM") +#define DINT asm(" setc INTM") +#define ERTM asm(" clrc DBGM") +#define DRTM asm(" setc DBGM") +#define EALLOW asm(" EALLOW") +#define EDIS asm(" EDIS") +#define ESTOP0 asm(" ESTOP0") + +#define M_INT1 0x0001 +#define M_INT2 0x0002 +#define M_INT3 0x0004 +#define M_INT4 0x0008 +#define M_INT5 0x0010 +#define M_INT6 0x0020 +#define M_INT7 0x0040 +#define M_INT8 0x0080 +#define M_INT9 0x0100 +#define M_INT10 0x0200 +#define M_INT11 0x0400 +#define M_INT12 0x0800 +#define M_INT13 0x1000 +#define M_INT14 0x2000 +#define M_DLOG 0x4000 +#define M_RTOS 0x8000 + +#define BIT0 0x0001 +#define BIT1 0x0002 +#define BIT2 0x0004 +#define BIT3 0x0008 +#define BIT4 0x0010 +#define BIT5 0x0020 +#define BIT6 0x0040 +#define BIT7 0x0080 +#define BIT8 0x0100 +#define BIT9 0x0200 +#define BIT10 0x0400 +#define BIT11 0x0800 +#define BIT12 0x1000 +#define BIT13 0x2000 +#define BIT14 0x4000 +#define BIT15 0x8000 + +#ifndef NULL + #define NULL 0 +#endif + + +//--------------------------------------------------------------------------- +// For Portability, User Is Recommended To Use Following Data Type Size +// Definitions For 16-bit and 32-Bit Signed/Unsigned Integers: +// + +#ifndef DSP28_DATA_TYPES +#define DSP28_DATA_TYPES +typedef int int16; +typedef long int32; +typedef long long int64; +typedef unsigned int Uint16; +typedef unsigned long Uint32; +typedef unsigned long long Uint64; +typedef float float32; +typedef long double float64; +#endif + +#define LOWORD(l)((short int)( (long int)(l) &0xFFFF)) +#define HIWORD(l)((short int)(((long int)(l)>>16)&0xFFFF)) + +#define LOBYTE(w)((char)( (short int)(w) &0xFF)) +#define HIBYTE(w)((char)(((short int)(w)>>8)&0xFF)) + +#define BYTE3(l)((char)(((long int)(l)>>24)&0xFF)) +#define BYTE2(l)((char)(((long int)(l)>>16)&0xFF)) +#define BYTE1(l)((char)(((long int)(l)>> 8)&0xFF)) +#define BYTE0(l)((char)( (long int)(l) &0xFF)) + +//--------------------------------------------------------------------------- +// Include All Peripheral Header Files: +// + +#include "DSP281x_SysCtrl.h" // System Control/Power Modes +#include "DSP281x_DevEmu.h" // Device Emulation Registers +#include "DSP281x_Xintf.h" // External Interface Registers +#include "DSP281x_CpuTimers.h" // 32-bit CPU Timers +#include "DSP281x_PieCtrl.h" // PIE Control Registers +#include "DSP281x_PieVect.h" // PIE Vector Table +#include "DSP281x_Spi.h" // SPI Registers +#include "DSP281x_Sci.h" // SCI Registers +#include "DSP281x_Mcbsp.h" // McBSP Registers +#include "DSP281x_ECan.h" // Enhanced eCAN Registers +#include "DSP281x_Gpio.h" // General Purpose I/O Registers +#include "DSP281x_Ev.h" // Event Manager Registers +#include "DSP281x_Adc.h" // ADC Registers +#include "DSP281x_XIntrupt.h" // External Interrupts + +#define XCLKIN 24000000 // external oscillator frequency +extern float SYSCLKOUT, LSPCLK, HSPCLK; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_DEVICE_H definition + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h new file mode 100644 index 0000000..7f26fc5 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_ECan.h @@ -0,0 +1,1163 @@ +//########################################################################### +// +// FILE: DSP281x_ECan.h +// +// TITLE: DSP281x Device eCAN Register Definitions. +// +//########################################################################### +// +// Ver | dd mmm yyyy | Who | Description of changes +// =====|=============|======|=============================================== +// 1.00a| 07/21/2004 | H.J. |(i) Support for errata (as explained in SPRZ193E and above) incorporated +// |(ii) Changed the byte ordering to make it easy to use with the +// | default value of DBO bit (0). + +//########################################################################### + +#ifndef DSP281x_ECAN_H +#define DSP281x_ECAN_H + +/* These 2 lines have been added to support the C callable assembly workaround */ +/* This is to support the workaround for errata (as explained in SPRZ193E and above) */ + +extern void CanDoubleRead(Uint32 *StorePtr, volatile Uint32 *RegPtr); +extern void CanDoubleWrite(volatile Uint32 *RegPtr, Uint32 *LoadPtr); + +#ifdef __cplusplus +extern "C" { +#endif + + +/* --------------------------------------------------- */ +/* eCAN Control & Status Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Mailbox enable register (CANME) bit definitions */ +struct CANME_BITS { // bit description + Uint16 ME0:1; // 0 Enable Mailbox 0 + Uint16 ME1:1; // 1 Enable Mailbox 1 + Uint16 ME2:1; // 2 Enable Mailbox 2 + Uint16 ME3:1; // 3 Enable Mailbox 3 + Uint16 ME4:1; // 4 Enable Mailbox 4 + Uint16 ME5:1; // 5 Enable Mailbox 5 + Uint16 ME6:1; // 6 Enable Mailbox 6 + Uint16 ME7:1; // 7 Enable Mailbox 7 + Uint16 ME8:1; // 8 Enable Mailbox 8 + Uint16 ME9:1; // 9 Enable Mailbox 9 + Uint16 ME10:1; // 10 Enable Mailbox 10 + Uint16 ME11:1; // 11 Enable Mailbox 11 + Uint16 ME12:1; // 12 Enable Mailbox 12 + Uint16 ME13:1; // 13 Enable Mailbox 13 + Uint16 ME14:1; // 14 Enable Mailbox 14 + Uint16 ME15:1; // 15 Enable Mailbox 15 + Uint16 ME16:1; // 16 Enable Mailbox 16 + Uint16 ME17:1; // 17 Enable Mailbox 17 + Uint16 ME18:1; // 18 Enable Mailbox 18 + Uint16 ME19:1; // 19 Enable Mailbox 19 + Uint16 ME20:1; // 20 Enable Mailbox 20 + Uint16 ME21:1; // 21 Enable Mailbox 21 + Uint16 ME22:1; // 22 Enable Mailbox 22 + Uint16 ME23:1; // 23 Enable Mailbox 23 + Uint16 ME24:1; // 24 Enable Mailbox 24 + Uint16 ME25:1; // 25 Enable Mailbox 25 + Uint16 ME26:1; // 26 Enable Mailbox 26 + Uint16 ME27:1; // 27 Enable Mailbox 27 + Uint16 ME28:1; // 28 Enable Mailbox 28 + Uint16 ME29:1; // 29 Enable Mailbox 29 + Uint16 ME30:1; // 30 Enable Mailbox 30 + Uint16 ME31:1; // 31 Enable Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANME_REG { + Uint32 all; + struct CANME_BITS bit; +}; + +/* eCAN Mailbox direction register (CANMD) bit definitions */ +struct CANMD_BITS { // bit description + Uint16 MD0:1; // 0 0 -> Tx 1 -> Rx + Uint16 MD1:1; // 1 0 -> Tx 1 -> Rx + Uint16 MD2:1; // 2 0 -> Tx 1 -> Rx + Uint16 MD3:1; // 3 0 -> Tx 1 -> Rx + Uint16 MD4:1; // 4 0 -> Tx 1 -> Rx + Uint16 MD5:1; // 5 0 -> Tx 1 -> Rx + Uint16 MD6:1; // 6 0 -> Tx 1 -> Rx + Uint16 MD7:1; // 7 0 -> Tx 1 -> Rx + Uint16 MD8:1; // 8 0 -> Tx 1 -> Rx + Uint16 MD9:1; // 9 0 -> Tx 1 -> Rx + Uint16 MD10:1; // 10 0 -> Tx 1 -> Rx + Uint16 MD11:1; // 11 0 -> Tx 1 -> Rx + Uint16 MD12:1; // 12 0 -> Tx 1 -> Rx + Uint16 MD13:1; // 13 0 -> Tx 1 -> Rx + Uint16 MD14:1; // 14 0 -> Tx 1 -> Rx + Uint16 MD15:1; // 15 0 -> Tx 1 -> Rx + Uint16 MD16:1; // 16 0 -> Tx 1 -> Rx + Uint16 MD17:1; // 17 0 -> Tx 1 -> Rx + Uint16 MD18:1; // 18 0 -> Tx 1 -> Rx + Uint16 MD19:1; // 19 0 -> Tx 1 -> Rx + Uint16 MD20:1; // 20 0 -> Tx 1 -> Rx + Uint16 MD21:1; // 21 0 -> Tx 1 -> Rx + Uint16 MD22:1; // 22 0 -> Tx 1 -> Rx + Uint16 MD23:1; // 23 0 -> Tx 1 -> Rx + Uint16 MD24:1; // 24 0 -> Tx 1 -> Rx + Uint16 MD25:1; // 25 0 -> Tx 1 -> Rx + Uint16 MD26:1; // 26 0 -> Tx 1 -> Rx + Uint16 MD27:1; // 27 0 -> Tx 1 -> Rx + Uint16 MD28:1; // 28 0 -> Tx 1 -> Rx + Uint16 MD29:1; // 29 0 -> Tx 1 -> Rx + Uint16 MD30:1; // 30 0 -> Tx 1 -> Rx + Uint16 MD31:1; // 31 0 -> Tx 1 -> Rx + +}; + +/* Allow access to the bit fields or entire register */ +union CANMD_REG { + Uint32 all; + struct CANMD_BITS bit; +}; + +/* eCAN Transmit Request Set register (CANTRS) bit definitions */ +struct CANTRS_BITS { // bit description + Uint16 TRS0:1; // 0 TRS for Mailbox 0 + Uint16 TRS1:1; // 1 TRS for Mailbox 1 + Uint16 TRS2:1; // 2 TRS for Mailbox 2 + Uint16 TRS3:1; // 3 TRS for Mailbox 3 + Uint16 TRS4:1; // 4 TRS for Mailbox 4 + Uint16 TRS5:1; // 5 TRS for Mailbox 5 + Uint16 TRS6:1; // 6 TRS for Mailbox 6 + Uint16 TRS7:1; // 7 TRS for Mailbox 7 + Uint16 TRS8:1; // 8 TRS for Mailbox 8 + Uint16 TRS9:1; // 9 TRS for Mailbox 9 + Uint16 TRS10:1; // 10 TRS for Mailbox 10 + Uint16 TRS11:1; // 11 TRS for Mailbox 11 + Uint16 TRS12:1; // 12 TRS for Mailbox 12 + Uint16 TRS13:1; // 13 TRS for Mailbox 13 + Uint16 TRS14:1; // 14 TRS for Mailbox 14 + Uint16 TRS15:1; // 15 TRS for Mailbox 15 + Uint16 TRS16:1; // 16 TRS for Mailbox 16 + Uint16 TRS17:1; // 17 TRS for Mailbox 17 + Uint16 TRS18:1; // 18 TRS for Mailbox 18 + Uint16 TRS19:1; // 19 TRS for Mailbox 19 + Uint16 TRS20:1; // 20 TRS for Mailbox 20 + Uint16 TRS21:1; // 21 TRS for Mailbox 21 + Uint16 TRS22:1; // 22 TRS for Mailbox 22 + Uint16 TRS23:1; // 23 TRS for Mailbox 23 + Uint16 TRS24:1; // 24 TRS for Mailbox 24 + Uint16 TRS25:1; // 25 TRS for Mailbox 25 + Uint16 TRS26:1; // 26 TRS for Mailbox 26 + Uint16 TRS27:1; // 27 TRS for Mailbox 27 + Uint16 TRS28:1; // 28 TRS for Mailbox 28 + Uint16 TRS29:1; // 29 TRS for Mailbox 29 + Uint16 TRS30:1; // 30 TRS for Mailbox 30 + Uint16 TRS31:1; // 31 TRS for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTRS_REG { + Uint32 all; + struct CANTRS_BITS bit; +}; + +/* eCAN Transmit Request Reset register (CANTRR) bit definitions */ +struct CANTRR_BITS { // bit description + Uint16 TRR0:1; // 0 TRR for Mailbox 0 + Uint16 TRR1:1; // 1 TRR for Mailbox 1 + Uint16 TRR2:1; // 2 TRR for Mailbox 2 + Uint16 TRR3:1; // 3 TRR for Mailbox 3 + Uint16 TRR4:1; // 4 TRR for Mailbox 4 + Uint16 TRR5:1; // 5 TRR for Mailbox 5 + Uint16 TRR6:1; // 6 TRR for Mailbox 6 + Uint16 TRR7:1; // 7 TRR for Mailbox 7 + Uint16 TRR8:1; // 8 TRR for Mailbox 8 + Uint16 TRR9:1; // 9 TRR for Mailbox 9 + Uint16 TRR10:1; // 10 TRR for Mailbox 10 + Uint16 TRR11:1; // 11 TRR for Mailbox 11 + Uint16 TRR12:1; // 12 TRR for Mailbox 12 + Uint16 TRR13:1; // 13 TRR for Mailbox 13 + Uint16 TRR14:1; // 14 TRR for Mailbox 14 + Uint16 TRR15:1; // 15 TRR for Mailbox 15 + Uint16 TRR16:1; // 16 TRR for Mailbox 16 + Uint16 TRR17:1; // 17 TRR for Mailbox 17 + Uint16 TRR18:1; // 18 TRR for Mailbox 18 + Uint16 TRR19:1; // 19 TRR for Mailbox 19 + Uint16 TRR20:1; // 20 TRR for Mailbox 20 + Uint16 TRR21:1; // 21 TRR for Mailbox 21 + Uint16 TRR22:1; // 22 TRR for Mailbox 22 + Uint16 TRR23:1; // 23 TRR for Mailbox 23 + Uint16 TRR24:1; // 24 TRR for Mailbox 24 + Uint16 TRR25:1; // 25 TRR for Mailbox 25 + Uint16 TRR26:1; // 26 TRR for Mailbox 26 + Uint16 TRR27:1; // 27 TRR for Mailbox 27 + Uint16 TRR28:1; // 28 TRR for Mailbox 28 + Uint16 TRR29:1; // 29 TRR for Mailbox 29 + Uint16 TRR30:1; // 30 TRR for Mailbox 30 + Uint16 TRR31:1; // 31 TRR for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTRR_REG { + Uint32 all; + struct CANTRR_BITS bit; +}; + +/* eCAN Transmit Acknowledge register (CANTA) bit definitions */ +struct CANTA_BITS { // bit description + Uint16 TA0:1; // 0 TA for Mailbox 0 + Uint16 TA1:1; // 1 TA for Mailbox 1 + Uint16 TA2:1; // 2 TA for Mailbox 2 + Uint16 TA3:1; // 3 TA for Mailbox 3 + Uint16 TA4:1; // 4 TA for Mailbox 4 + Uint16 TA5:1; // 5 TA for Mailbox 5 + Uint16 TA6:1; // 6 TA for Mailbox 6 + Uint16 TA7:1; // 7 TA for Mailbox 7 + Uint16 TA8:1; // 8 TA for Mailbox 8 + Uint16 TA9:1; // 9 TA for Mailbox 9 + Uint16 TA10:1; // 10 TA for Mailbox 10 + Uint16 TA11:1; // 11 TA for Mailbox 11 + Uint16 TA12:1; // 12 TA for Mailbox 12 + Uint16 TA13:1; // 13 TA for Mailbox 13 + Uint16 TA14:1; // 14 TA for Mailbox 14 + Uint16 TA15:1; // 15 TA for Mailbox 15 + Uint16 TA16:1; // 16 TA for Mailbox 16 + Uint16 TA17:1; // 17 TA for Mailbox 17 + Uint16 TA18:1; // 18 TA for Mailbox 18 + Uint16 TA19:1; // 19 TA for Mailbox 19 + Uint16 TA20:1; // 20 TA for Mailbox 20 + Uint16 TA21:1; // 21 TA for Mailbox 21 + Uint16 TA22:1; // 22 TA for Mailbox 22 + Uint16 TA23:1; // 23 TA for Mailbox 23 + Uint16 TA24:1; // 24 TA for Mailbox 24 + Uint16 TA25:1; // 25 TA for Mailbox 25 + Uint16 TA26:1; // 26 TA for Mailbox 26 + Uint16 TA27:1; // 27 TA for Mailbox 27 + Uint16 TA28:1; // 28 TA for Mailbox 28 + Uint16 TA29:1; // 29 TA for Mailbox 29 + Uint16 TA30:1; // 30 TA for Mailbox 30 + Uint16 TA31:1; // 31 TA for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTA_REG { + Uint32 all; + struct CANTA_BITS bit; +}; + +/* eCAN Transmit Abort Acknowledge register (CANAA) bit definitions */ +struct CANAA_BITS { // bit description + Uint16 AA0:1; // 0 AA for Mailbox 0 + Uint16 AA1:1; // 1 AA for Mailbox 1 + Uint16 AA2:1; // 2 AA for Mailbox 2 + Uint16 AA3:1; // 3 AA for Mailbox 3 + Uint16 AA4:1; // 4 AA for Mailbox 4 + Uint16 AA5:1; // 5 AA for Mailbox 5 + Uint16 AA6:1; // 6 AA for Mailbox 6 + Uint16 AA7:1; // 7 AA for Mailbox 7 + Uint16 AA8:1; // 8 AA for Mailbox 8 + Uint16 AA9:1; // 9 AA for Mailbox 9 + Uint16 AA10:1; // 10 AA for Mailbox 10 + Uint16 AA11:1; // 11 AA for Mailbox 11 + Uint16 AA12:1; // 12 AA for Mailbox 12 + Uint16 AA13:1; // 13 AA for Mailbox 13 + Uint16 AA14:1; // 14 AA for Mailbox 14 + Uint16 AA15:1; // 15 AA for Mailbox 15 + Uint16 AA16:1; // 16 AA for Mailbox 16 + Uint16 AA17:1; // 17 AA for Mailbox 17 + Uint16 AA18:1; // 18 AA for Mailbox 18 + Uint16 AA19:1; // 19 AA for Mailbox 19 + Uint16 AA20:1; // 20 AA for Mailbox 20 + Uint16 AA21:1; // 21 AA for Mailbox 21 + Uint16 AA22:1; // 22 AA for Mailbox 22 + Uint16 AA23:1; // 23 AA for Mailbox 23 + Uint16 AA24:1; // 24 AA for Mailbox 24 + Uint16 AA25:1; // 25 AA for Mailbox 25 + Uint16 AA26:1; // 26 AA for Mailbox 26 + Uint16 AA27:1; // 27 AA for Mailbox 27 + Uint16 AA28:1; // 28 AA for Mailbox 28 + Uint16 AA29:1; // 29 AA for Mailbox 29 + Uint16 AA30:1; // 30 AA for Mailbox 30 + Uint16 AA31:1; // 31 AA for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANAA_REG { + Uint32 all; + struct CANAA_BITS bit; +}; + +/* eCAN Received Message Pending register (CANRMP) bit definitions */ +struct CANRMP_BITS { // bit description + Uint16 RMP0:1; // 0 RMP for Mailbox 0 + Uint16 RMP1:1; // 1 RMP for Mailbox 1 + Uint16 RMP2:1; // 2 RMP for Mailbox 2 + Uint16 RMP3:1; // 3 RMP for Mailbox 3 + Uint16 RMP4:1; // 4 RMP for Mailbox 4 + Uint16 RMP5:1; // 5 RMP for Mailbox 5 + Uint16 RMP6:1; // 6 RMP for Mailbox 6 + Uint16 RMP7:1; // 7 RMP for Mailbox 7 + Uint16 RMP8:1; // 8 RMP for Mailbox 8 + Uint16 RMP9:1; // 9 RMP for Mailbox 9 + Uint16 RMP10:1; // 10 RMP for Mailbox 10 + Uint16 RMP11:1; // 11 RMP for Mailbox 11 + Uint16 RMP12:1; // 12 RMP for Mailbox 12 + Uint16 RMP13:1; // 13 RMP for Mailbox 13 + Uint16 RMP14:1; // 14 RMP for Mailbox 14 + Uint16 RMP15:1; // 15 RMP for Mailbox 15 + Uint16 RMP16:1; // 16 RMP for Mailbox 16 + Uint16 RMP17:1; // 17 RMP for Mailbox 17 + Uint16 RMP18:1; // 18 RMP for Mailbox 18 + Uint16 RMP19:1; // 19 RMP for Mailbox 19 + Uint16 RMP20:1; // 20 RMP for Mailbox 20 + Uint16 RMP21:1; // 21 RMP for Mailbox 21 + Uint16 RMP22:1; // 22 RMP for Mailbox 22 + Uint16 RMP23:1; // 23 RMP for Mailbox 23 + Uint16 RMP24:1; // 24 RMP for Mailbox 24 + Uint16 RMP25:1; // 25 RMP for Mailbox 25 + Uint16 RMP26:1; // 26 RMP for Mailbox 26 + Uint16 RMP27:1; // 27 RMP for Mailbox 27 + Uint16 RMP28:1; // 28 RMP for Mailbox 28 + Uint16 RMP29:1; // 29 RMP for Mailbox 29 + Uint16 RMP30:1; // 30 RMP for Mailbox 30 + Uint16 RMP31:1; // 31 RMP for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANRMP_REG { + Uint32 all; + struct CANRMP_BITS bit; +}; + +/* eCAN Received Message Lost register (CANRML) bit definitions */ +struct CANRML_BITS { // bit description + Uint16 RML0:1; // 0 RML for Mailbox 0 + Uint16 RML1:1; // 1 RML for Mailbox 1 + Uint16 RML2:1; // 2 RML for Mailbox 2 + Uint16 RML3:1; // 3 RML for Mailbox 3 + Uint16 RML4:1; // 4 RML for Mailbox 4 + Uint16 RML5:1; // 5 RML for Mailbox 5 + Uint16 RML6:1; // 6 RML for Mailbox 6 + Uint16 RML7:1; // 7 RML for Mailbox 7 + Uint16 RML8:1; // 8 RML for Mailbox 8 + Uint16 RML9:1; // 9 RML for Mailbox 9 + Uint16 RML10:1; // 10 RML for Mailbox 10 + Uint16 RML11:1; // 11 RML for Mailbox 11 + Uint16 RML12:1; // 12 RML for Mailbox 12 + Uint16 RML13:1; // 13 RML for Mailbox 13 + Uint16 RML14:1; // 14 RML for Mailbox 14 + Uint16 RML15:1; // 15 RML for Mailbox 15 + Uint16 RML16:1; // 16 RML for Mailbox 16 + Uint16 RML17:1; // 17 RML for Mailbox 17 + Uint16 RML18:1; // 18 RML for Mailbox 18 + Uint16 RML19:1; // 19 RML for Mailbox 19 + Uint16 RML20:1; // 20 RML for Mailbox 20 + Uint16 RML21:1; // 21 RML for Mailbox 21 + Uint16 RML22:1; // 22 RML for Mailbox 22 + Uint16 RML23:1; // 23 RML for Mailbox 23 + Uint16 RML24:1; // 24 RML for Mailbox 24 + Uint16 RML25:1; // 25 RML for Mailbox 25 + Uint16 RML26:1; // 26 RML for Mailbox 26 + Uint16 RML27:1; // 27 RML for Mailbox 27 + Uint16 RML28:1; // 28 RML for Mailbox 28 + Uint16 RML29:1; // 29 RML for Mailbox 29 + Uint16 RML30:1; // 30 RML for Mailbox 30 + Uint16 RML31:1; // 31 RML for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANRML_REG { + Uint32 all; + struct CANRML_BITS bit; +}; + +/* eCAN Remote Frame Pending register (CANRFP) bit definitions */ +struct CANRFP_BITS { // bit description + Uint16 RFP0:1; // 0 RFP for Mailbox 0 + Uint16 RFP1:1; // 1 RFP for Mailbox 1 + Uint16 RFP2:1; // 2 RFP for Mailbox 2 + Uint16 RFP3:1; // 3 RFP for Mailbox 3 + Uint16 RFP4:1; // 4 RFP for Mailbox 4 + Uint16 RFP5:1; // 5 RFP for Mailbox 5 + Uint16 RFP6:1; // 6 RFP for Mailbox 6 + Uint16 RFP7:1; // 7 RFP for Mailbox 7 + Uint16 RFP8:1; // 8 RFP for Mailbox 8 + Uint16 RFP9:1; // 9 RFP for Mailbox 9 + Uint16 RFP10:1; // 10 RFP for Mailbox 10 + Uint16 RFP11:1; // 11 RFP for Mailbox 11 + Uint16 RFP12:1; // 12 RFP for Mailbox 12 + Uint16 RFP13:1; // 13 RFP for Mailbox 13 + Uint16 RFP14:1; // 14 RFP for Mailbox 14 + Uint16 RFP15:1; // 15 RFP for Mailbox 15 + Uint16 RFP16:1; // 16 RFP for Mailbox 16 + Uint16 RFP17:1; // 17 RFP for Mailbox 17 + Uint16 RFP18:1; // 18 RFP for Mailbox 18 + Uint16 RFP19:1; // 19 RFP for Mailbox 19 + Uint16 RFP20:1; // 20 RFP for Mailbox 20 + Uint16 RFP21:1; // 21 RFP for Mailbox 21 + Uint16 RFP22:1; // 22 RFP for Mailbox 22 + Uint16 RFP23:1; // 23 RFP for Mailbox 23 + Uint16 RFP24:1; // 24 RFP for Mailbox 24 + Uint16 RFP25:1; // 25 RFP for Mailbox 25 + Uint16 RFP26:1; // 26 RFP for Mailbox 26 + Uint16 RFP27:1; // 27 RFP for Mailbox 27 + Uint16 RFP28:1; // 28 RFP for Mailbox 28 + Uint16 RFP29:1; // 29 RFP for Mailbox 29 + Uint16 RFP30:1; // 30 RFP for Mailbox 30 + Uint16 RFP31:1; // 31 RFP for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANRFP_REG { + Uint32 all; + struct CANRFP_BITS bit; +}; + +/* eCAN Global Acceptance Mask register (CANGAM) bit definitions */ +struct CANGAM_BITS { // bits description + Uint16 GAM150:16; // 15:0 Global acceptance mask bits 0-15 + Uint16 GAM2816:13; // 28:16 Global acceptance mask bits 16-28 + Uint16 rsvd:2; // 30:29 reserved + Uint16 AMI:1; // 31 AMI bit +}; + +/* Allow access to the bit fields or entire register */ +union CANGAM_REG { + Uint32 all; + struct CANGAM_BITS bit; +}; + + +/* eCAN Master Control register (CANMC) bit definitions */ +struct CANMC_BITS { // bits description + Uint16 MBNR:5; // 4:0 MBX # for CDR bit + Uint16 SRES:1; // 5 Soft reset + Uint16 STM:1; // 6 Self-test mode + Uint16 ABO:1; // 7 Auto bus-on + Uint16 CDR:1; // 8 Change data request + Uint16 WUBA:1; // 9 Wake-up on bus activity + Uint16 DBO:1; // 10 Data-byte order + Uint16 PDR:1; // 11 Power-down mode request + Uint16 CCR:1; // 12 Change configuration request + Uint16 SCB:1; // 13 SCC compatibility bit + Uint16 TCC:1; // 14 TSC MSB clear bit + Uint16 MBCC:1; // 15 TSC clear bit thru mailbox 16 + Uint16 SUSP:1; // 16 SUSPEND free/soft bit + Uint16 rsvd:15; // 31:17 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANMC_REG { + Uint32 all; + struct CANMC_BITS bit; +}; + +/* eCAN Bit -timing configuration register (CANBTC) bit definitions */ +struct CANBTC_BITS { // bits description + Uint16 TSEG2REG:3; // 2:0 TSEG2 register value + Uint16 TSEG1REG:4; // 6:3 TSEG1 register value + Uint16 SAM:1; // 7 Sample-point setting + Uint16 SJWREG:2; // 9:8 Synchroniztion Jump Width register value + Uint16 rsvd1:6; // 15:10 reserved + Uint16 BRPREG:8; // 23:16 Baudrate prescaler register value + Uint16 rsvd2:8; // 31:24 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANBTC_REG { + Uint32 all; + struct CANBTC_BITS bit; +}; + +/* eCAN Error & Status register (CANES) bit definitions */ +struct CANES_BITS { // bits description + Uint16 TM:1; // 0 Transmit Mode + Uint16 RM:1; // 1 Receive Mode + Uint16 rsvd1:1; // 2 reserved + Uint16 PDA:1; // 3 Power-down acknowledge + Uint16 CCE:1; // 4 Change Configuration Enable + Uint16 SMA:1; // 5 Suspend Mode Acknowledge + Uint16 rsvd2:10; // 15:6 reserved + Uint16 EW:1; // 16 Warning status + Uint16 EP:1; // 17 Error Passive status + Uint16 BO:1; // 18 Bus-off status + Uint16 ACKE:1; // 19 Acknowledge error + Uint16 SE:1; // 20 Stuff error + Uint16 CRCE:1; // 21 CRC error + Uint16 SA1:1; // 22 Stuck at Dominant error + Uint16 BE:1; // 23 Bit error + Uint16 FE:1; // 24 Framing error + Uint16 rsvd3:7; // 31:25 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANES_REG { + Uint32 all; + struct CANES_BITS bit; +}; + + +/* eCAN Transmit Error Counter register (CANTEC) bit definitions */ +struct CANTEC_BITS { // bits description + Uint16 TEC:8; // 7:0 TEC + Uint16 rsvd1:8; // 15:8 reserved + Uint16 rsvd2:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANTEC_REG { + Uint32 all; + struct CANTEC_BITS bit; +}; + +/* eCAN Receive Error Counter register (CANREC) bit definitions */ +struct CANREC_BITS { // bits description + Uint16 REC:8; // 7:0 REC + Uint16 rsvd1:8; // 15:8 reserved + Uint16 rsvd2:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANREC_REG { + Uint32 all; + struct CANREC_BITS bit; +}; + +/* eCAN Global Interrupt Flag 0 (CANGIF0) bit definitions */ +struct CANGIF0_BITS { // bits description + Uint16 MIV0:5; // 4:0 Mailbox Interrupt Vector + Uint16 rsvd1:3; // 7:5 reserved + Uint16 WLIF0:1; // 8 Warning level interrupt flag + Uint16 EPIF0:1; // 9 Error-passive interrupt flag + Uint16 BOIF0:1; // 10 Bus-off interrupt flag + Uint16 RMLIF0:1; // 11 Received message lost interrupt flag + Uint16 WUIF0:1; // 12 Wakeup interrupt flag + Uint16 WDIF0:1; // 13 Write denied interrupt flag + Uint16 AAIF0:1; // 14 Abort Ack interrupt flag + Uint16 GMIF0:1; // 15 Global MBX interrupt flag + Uint16 TCOF0:1; // 16 TSC Overflow flag + Uint16 MTOF0:1; // 17 Mailbox Timeout flag + Uint16 rsvd2:14; // 31:18 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANGIF0_REG { + Uint32 all; + struct CANGIF0_BITS bit; +}; + +/* eCAN Global Interrupt Mask register (CANGIM) bit definitions */ +struct CANGIM_BITS { // bits description + Uint16 I0EN:1; // 0 Interrupt 0 enable + Uint16 I1EN:1; // 1 Interrupt 1 enable + Uint16 GIL:1; // 2 Global Interrupt Level + Uint16 rsvd1:5; // 7:3 reserved + Uint16 WLIM:1; // 8 Warning level interrupt mask + Uint16 EPIM:1; // 9 Error-passive interrupt mask + Uint16 BOIM:1; // 10 Bus-off interrupt mask + Uint16 RMLIM:1; // 11 Received message lost interrupt mask + Uint16 WUIM:1; // 12 Wakeup interrupt mask + Uint16 WDIM:1; // 13 Write denied interrupt mask + Uint16 AAIM:1; // 14 Abort Ack interrupt mask + Uint16 rsvd2:1; // 15 reserved + Uint16 TCOM:1; // 16 TSC overflow interrupt mask + Uint16 MTOM:1; // 17 MBX Timeout interrupt mask + Uint16 rsvd3:14; // 31:18 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANGIM_REG { + Uint32 all; + struct CANGIM_BITS bit; +}; + + +/* eCAN Global Interrupt Flag 1 (eCANGIF1) bit definitions */ +struct CANGIF1_BITS { // bits description + Uint16 MIV1:5; // 4:0 Mailbox Interrupt Vector + Uint16 rsvd1:3; // 7:5 reserved + Uint16 WLIF1:1; // 8 Warning level interrupt flag + Uint16 EPIF1:1; // 9 Error-passive interrupt flag + Uint16 BOIF1:1; // 10 Bus-off interrupt flag + Uint16 RMLIF1:1; // 11 Received message lost interrupt flag + Uint16 WUIF1:1; // 12 Wakeup interrupt flag + Uint16 WDIF1:1; // 13 Write denied interrupt flag + Uint16 AAIF1:1; // 14 Abort Ack interrupt flag + Uint16 GMIF1:1; // 15 Global MBX interrupt flag + Uint16 TCOF1:1; // 16 TSC Overflow flag + Uint16 MTOF1:1; // 17 Mailbox Timeout flag + Uint16 rsvd2:14; // 31:18 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANGIF1_REG { + Uint32 all; + struct CANGIF1_BITS bit; +}; + + +/* eCAN Mailbox Interrupt Mask register (CANMIM) bit definitions */ +struct CANMIM_BITS { // bit description + Uint16 MIM0:1; // 0 MIM for Mailbox 0 + Uint16 MIM1:1; // 1 MIM for Mailbox 1 + Uint16 MIM2:1; // 2 MIM for Mailbox 2 + Uint16 MIM3:1; // 3 MIM for Mailbox 3 + Uint16 MIM4:1; // 4 MIM for Mailbox 4 + Uint16 MIM5:1; // 5 MIM for Mailbox 5 + Uint16 MIM6:1; // 6 MIM for Mailbox 6 + Uint16 MIM7:1; // 7 MIM for Mailbox 7 + Uint16 MIM8:1; // 8 MIM for Mailbox 8 + Uint16 MIM9:1; // 9 MIM for Mailbox 9 + Uint16 MIM10:1; // 10 MIM for Mailbox 10 + Uint16 MIM11:1; // 11 MIM for Mailbox 11 + Uint16 MIM12:1; // 12 MIM for Mailbox 12 + Uint16 MIM13:1; // 13 MIM for Mailbox 13 + Uint16 MIM14:1; // 14 MIM for Mailbox 14 + Uint16 MIM15:1; // 15 MIM for Mailbox 15 + Uint16 MIM16:1; // 16 MIM for Mailbox 16 + Uint16 MIM17:1; // 17 MIM for Mailbox 17 + Uint16 MIM18:1; // 18 MIM for Mailbox 18 + Uint16 MIM19:1; // 19 MIM for Mailbox 19 + Uint16 MIM20:1; // 20 MIM for Mailbox 20 + Uint16 MIM21:1; // 21 MIM for Mailbox 21 + Uint16 MIM22:1; // 22 MIM for Mailbox 22 + Uint16 MIM23:1; // 23 MIM for Mailbox 23 + Uint16 MIM24:1; // 24 MIM for Mailbox 24 + Uint16 MIM25:1; // 25 MIM for Mailbox 25 + Uint16 MIM26:1; // 26 MIM for Mailbox 26 + Uint16 MIM27:1; // 27 MIM for Mailbox 27 + Uint16 MIM28:1; // 28 MIM for Mailbox 28 + Uint16 MIM29:1; // 29 MIM for Mailbox 29 + Uint16 MIM30:1; // 30 MIM for Mailbox 30 + Uint16 MIM31:1; // 31 MIM for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANMIM_REG { + Uint32 all; + struct CANMIM_BITS bit; +}; + +/* eCAN Mailbox Interrupt Level register (CANMIL) bit definitions */ +struct CANMIL_BITS { // bit description + Uint16 MIL0:1; // 0 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL1:1; // 1 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL2:1; // 2 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL3:1; // 3 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL4:1; // 4 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL5:1; // 5 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL6:1; // 6 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL7:1; // 7 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL8:1; // 8 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL9:1; // 9 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL10:1; // 10 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL11:1; // 11 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL12:1; // 12 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL13:1; // 13 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL14:1; // 14 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL15:1; // 15 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL16:1; // 16 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL17:1; // 17 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL18:1; // 18 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL19:1; // 19 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL20:1; // 20 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL21:1; // 21 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL22:1; // 22 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL23:1; // 23 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL24:1; // 24 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL25:1; // 25 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL26:1; // 26 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL27:1; // 27 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL28:1; // 28 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL29:1; // 29 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL30:1; // 30 0 -> Int 9.5 1 -> Int 9.6 + Uint16 MIL31:1; // 31 0 -> Int 9.5 1 -> Int 9.6 + +}; + +/* Allow access to the bit fields or entire register */ +union CANMIL_REG { + Uint32 all; + struct CANMIL_BITS bit; +}; + + +/* eCAN Overwrite Protection Control register (CANOPC) bit definitions */ +struct CANOPC_BITS { // bit description + Uint16 OPC0:1; // 0 OPC for Mailbox 0 + Uint16 OPC1:1; // 1 OPC for Mailbox 1 + Uint16 OPC2:1; // 2 OPC for Mailbox 2 + Uint16 OPC3:1; // 3 OPC for Mailbox 3 + Uint16 OPC4:1; // 4 OPC for Mailbox 4 + Uint16 OPC5:1; // 5 OPC for Mailbox 5 + Uint16 OPC6:1; // 6 OPC for Mailbox 6 + Uint16 OPC7:1; // 7 OPC for Mailbox 7 + Uint16 OPC8:1; // 8 OPC for Mailbox 8 + Uint16 OPC9:1; // 9 OPC for Mailbox 9 + Uint16 OPC10:1; // 10 OPC for Mailbox 10 + Uint16 OPC11:1; // 11 OPC for Mailbox 11 + Uint16 OPC12:1; // 12 OPC for Mailbox 12 + Uint16 OPC13:1; // 13 OPC for Mailbox 13 + Uint16 OPC14:1; // 14 OPC for Mailbox 14 + Uint16 OPC15:1; // 15 OPC for Mailbox 15 + Uint16 OPC16:1; // 16 OPC for Mailbox 16 + Uint16 OPC17:1; // 17 OPC for Mailbox 17 + Uint16 OPC18:1; // 18 OPC for Mailbox 18 + Uint16 OPC19:1; // 19 OPC for Mailbox 19 + Uint16 OPC20:1; // 20 OPC for Mailbox 20 + Uint16 OPC21:1; // 21 OPC for Mailbox 21 + Uint16 OPC22:1; // 22 OPC for Mailbox 22 + Uint16 OPC23:1; // 23 OPC for Mailbox 23 + Uint16 OPC24:1; // 24 OPC for Mailbox 24 + Uint16 OPC25:1; // 25 OPC for Mailbox 25 + Uint16 OPC26:1; // 26 OPC for Mailbox 26 + Uint16 OPC27:1; // 27 OPC for Mailbox 27 + Uint16 OPC28:1; // 28 OPC for Mailbox 28 + Uint16 OPC29:1; // 29 OPC for Mailbox 29 + Uint16 OPC30:1; // 30 OPC for Mailbox 30 + Uint16 OPC31:1; // 31 OPC for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANOPC_REG { + Uint32 all; + struct CANOPC_BITS bit; +}; + + +/* eCAN TX I/O Control Register (CANTIOC) bit definitions */ +struct CANTIOC_BITS { // bits description + Uint16 rsvd1:3; // 2:0 reserved + Uint16 TXFUNC:1; // 3 TXFUNC + Uint16 rsvd2:12; // 15:4 reserved + Uint16 rsvd3:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANTIOC_REG { + Uint32 all; + struct CANTIOC_BITS bit; +}; + +/* eCAN RX I/O Control Register (CANRIOC) bit definitions */ +struct CANRIOC_BITS { // bits description + Uint16 rsvd1:3; // 2:0 reserved + Uint16 RXFUNC:1; // 3 RXFUNC + Uint16 rsvd2:12; // 15:4 reserved + Uint16 rsvd3:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANRIOC_REG { + Uint32 all; + struct CANRIOC_BITS bit; +}; + + +/* eCAN Time-out Control register (CANTOC) bit definitions */ +struct CANTOC_BITS { // bit description + Uint16 TOC0:1; // 0 TOC for Mailbox 0 + Uint16 TOC1:1; // 1 TOC for Mailbox 1 + Uint16 TOC2:1; // 2 TOC for Mailbox 2 + Uint16 TOC3:1; // 3 TOC for Mailbox 3 + Uint16 TOC4:1; // 4 TOC for Mailbox 4 + Uint16 TOC5:1; // 5 TOC for Mailbox 5 + Uint16 TOC6:1; // 6 TOC for Mailbox 6 + Uint16 TOC7:1; // 7 TOC for Mailbox 7 + Uint16 TOC8:1; // 8 TOC for Mailbox 8 + Uint16 TOC9:1; // 9 TOC for Mailbox 9 + Uint16 TOC10:1; // 10 TOC for Mailbox 10 + Uint16 TOC11:1; // 11 TOC for Mailbox 11 + Uint16 TOC12:1; // 12 TOC for Mailbox 12 + Uint16 TOC13:1; // 13 TOC for Mailbox 13 + Uint16 TOC14:1; // 14 TOC for Mailbox 14 + Uint16 TOC15:1; // 15 TOC for Mailbox 15 + Uint16 TOC16:1; // 16 TOC for Mailbox 16 + Uint16 TOC17:1; // 17 TOC for Mailbox 17 + Uint16 TOC18:1; // 18 TOC for Mailbox 18 + Uint16 TOC19:1; // 19 TOC for Mailbox 19 + Uint16 TOC20:1; // 20 TOC for Mailbox 20 + Uint16 TOC21:1; // 21 TOC for Mailbox 21 + Uint16 TOC22:1; // 22 TOC for Mailbox 22 + Uint16 TOC23:1; // 23 TOC for Mailbox 23 + Uint16 TOC24:1; // 24 TOC for Mailbox 24 + Uint16 TOC25:1; // 25 TOC for Mailbox 25 + Uint16 TOC26:1; // 26 TOC for Mailbox 26 + Uint16 TOC27:1; // 27 TOC for Mailbox 27 + Uint16 TOC28:1; // 28 TOC for Mailbox 28 + Uint16 TOC29:1; // 29 TOC for Mailbox 29 + Uint16 TOC30:1; // 30 TOC for Mailbox 30 + Uint16 TOC31:1; // 31 TOC for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTOC_REG { + Uint32 all; + struct CANTOC_BITS bit; +}; + + +/* eCAN Time-out Status register (CANTOS) bit definitions */ +struct CANTOS_BITS { // bit description + Uint16 TOS0:1; // 0 TOS for Mailbox 0 + Uint16 TOS1:1; // 1 TOS for Mailbox 1 + Uint16 TOS2:1; // 2 TOS for Mailbox 2 + Uint16 TOS3:1; // 3 TOS for Mailbox 3 + Uint16 TOS4:1; // 4 TOS for Mailbox 4 + Uint16 TOS5:1; // 5 TOS for Mailbox 5 + Uint16 TOS6:1; // 6 TOS for Mailbox 6 + Uint16 TOS7:1; // 7 TOS for Mailbox 7 + Uint16 TOS8:1; // 8 TOS for Mailbox 8 + Uint16 TOS9:1; // 9 TOS for Mailbox 9 + Uint16 TOS10:1; // 10 TOS for Mailbox 10 + Uint16 TOS11:1; // 11 TOS for Mailbox 11 + Uint16 TOS12:1; // 12 TOS for Mailbox 12 + Uint16 TOS13:1; // 13 TOS for Mailbox 13 + Uint16 TOS14:1; // 14 TOS for Mailbox 14 + Uint16 TOS15:1; // 15 TOS for Mailbox 15 + Uint16 TOS16:1; // 16 TOS for Mailbox 16 + Uint16 TOS17:1; // 17 TOS for Mailbox 17 + Uint16 TOS18:1; // 18 TOS for Mailbox 18 + Uint16 TOS19:1; // 19 TOS for Mailbox 19 + Uint16 TOS20:1; // 20 TOS for Mailbox 20 + Uint16 TOS21:1; // 21 TOS for Mailbox 21 + Uint16 TOS22:1; // 22 TOS for Mailbox 22 + Uint16 TOS23:1; // 23 TOS for Mailbox 23 + Uint16 TOS24:1; // 24 TOS for Mailbox 24 + Uint16 TOS25:1; // 25 TOS for Mailbox 25 + Uint16 TOS26:1; // 26 TOS for Mailbox 26 + Uint16 TOS27:1; // 27 TOS for Mailbox 27 + Uint16 TOS28:1; // 28 TOS for Mailbox 28 + Uint16 TOS29:1; // 29 TOS for Mailbox 29 + Uint16 TOS30:1; // 30 TOS for Mailbox 30 + Uint16 TOS31:1; // 31 TOS for Mailbox 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANTOS_REG { + Uint32 all; + struct CANTOS_BITS bit; +}; + +/**************************************/ +/* eCAN Control & Status register file */ +/**************************************/ + +struct ECAN_REGS { + union CANME_REG CANME; // Mailbox Enable + union CANMD_REG CANMD; // Mailbox Direction + union CANTRS_REG CANTRS; // Transmit Request Set + union CANTRR_REG CANTRR; // Transmit Request Reset + union CANTA_REG CANTA; // Transmit Acknowledge + union CANAA_REG CANAA; // Abort Acknowledge + union CANRMP_REG CANRMP; // Received Message Pending + union CANRML_REG CANRML; // Received Message Lost + union CANRFP_REG CANRFP; // Remote Frame Pending + union CANGAM_REG CANGAM; // Global Acceptance Mask + union CANMC_REG CANMC; // Master Control + union CANBTC_REG CANBTC; // Bit Timing + union CANES_REG CANES; // Error Status + union CANTEC_REG CANTEC; // Transmit Error Counter + union CANREC_REG CANREC; // Receive Error Counter + union CANGIF0_REG CANGIF0; // Global Interrupt Flag 0 + union CANGIM_REG CANGIM; // Global Interrupt Mask 0 + union CANGIF1_REG CANGIF1; // Global Interrupt Flag 1 + union CANMIM_REG CANMIM; // Mailbox Interrupt Mask + union CANMIL_REG CANMIL; // Mailbox Interrupt Level + union CANOPC_REG CANOPC; // Overwrite Protection Control + union CANTIOC_REG CANTIOC; // TX I/O Control + union CANRIOC_REG CANRIOC; // RX I/O Control + Uint32 CANTSC; // Time-stamp counter + union CANTOC_REG CANTOC; // Time-out Control + union CANTOS_REG CANTOS; // Time-out Status + +}; + +/* --------------------------------------------------- */ +/* eCAN Mailbox Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Message ID (MSGID) bit definitions */ +struct CANMSGID_BITS { // bits description + Uint16 EXTMSGID_L:16; // 0:15 + Uint16 EXTMSGID_H:2; // 16:17 + Uint16 STDMSGID:11; // 18:28 + Uint16 AAM:1; // 29 + Uint16 AME:1; // 30 + Uint16 IDE:1; // 31 + +}; + +/* Allow access to the bit fields or entire register */ +union CANMSGID_REG { + Uint32 all; + struct CANMSGID_BITS bit; +}; + +/* eCAN Message Control Field (MSGCTRL) bit definitions */ +struct CANMSGCTRL_BITS { // bits description + Uint16 DLC:4; // 0:3 + Uint16 RTR:1; // 4 + Uint16 rsvd1:3; // 7:5 reserved + Uint16 TPL:5; // 12:8 + Uint16 rsvd2:3; // 15:13 reserved + Uint16 rsvd3:16; // 31:16 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CANMSGCTRL_REG { + Uint32 all; + struct CANMSGCTRL_BITS bit; +}; + +/* eCAN Message Data Register low (MDR_L) word definitions */ +struct CANMDL_WORDS { // bits description + Uint16 LOW_WORD:16; // 0:15 + Uint16 HI_WORD:16; // 31:16 +}; + +/* eCAN Message Data Register low (MDR_L) byte definitions */ +struct CANMDL_BYTES { // bits description + Uint16 BYTE3:8; // 31:24 + Uint16 BYTE2:8; // 23:16 + Uint16 BYTE1:8; // 15:8 + Uint16 BYTE0:8; // 7:0 +}; + + +/* Allow access to the bit fields or entire register */ + +union CANMDL_REG { + Uint32 all; + struct CANMDL_WORDS word; + struct CANMDL_BYTES byte; +}; + + + +/* eCAN Message Data Register high (MDR_H) word definitions */ +struct CANMDH_WORDS { // bits description + Uint16 LOW_WORD:16; // 0:15 + Uint16 HI_WORD:16; // 31:16 +}; + +/* eCAN Message Data Register low (MDR_H) byte definitions */ +struct CANMDH_BYTES { // bits description + Uint16 BYTE7:8; // 63:56 + Uint16 BYTE6:8; // 55:48 + Uint16 BYTE5:8; // 47:40 + Uint16 BYTE4:8; // 39:32 +}; + +/* Allow access to the bit fields or entire register */ +union CANMDH_REG { + Uint32 all; + struct CANMDH_WORDS word; + struct CANMDH_BYTES byte; +}; + + +struct MBOX { + union CANMSGID_REG MSGID; + union CANMSGCTRL_REG MSGCTRL; + union CANMDL_REG MDL; + union CANMDH_REG MDH; +}; + +/**************************************/ +/* eCAN Mailboxes */ +/**************************************/ + +struct ECAN_MBOXES { + struct MBOX MBOX0; + struct MBOX MBOX1; + struct MBOX MBOX2; + struct MBOX MBOX3; + struct MBOX MBOX4; + struct MBOX MBOX5; + struct MBOX MBOX6; + struct MBOX MBOX7; + struct MBOX MBOX8; + struct MBOX MBOX9; + struct MBOX MBOX10; + struct MBOX MBOX11; + struct MBOX MBOX12; + struct MBOX MBOX13; + struct MBOX MBOX14; + struct MBOX MBOX15; + struct MBOX MBOX16; + struct MBOX MBOX17; + struct MBOX MBOX18; + struct MBOX MBOX19; + struct MBOX MBOX20; + struct MBOX MBOX21; + struct MBOX MBOX22; + struct MBOX MBOX23; + struct MBOX MBOX24; + struct MBOX MBOX25; + struct MBOX MBOX26; + struct MBOX MBOX27; + struct MBOX MBOX28; + struct MBOX MBOX29; + struct MBOX MBOX30; + struct MBOX MBOX31; +}; + +/* eCAN Local Acceptance Mask (LAM) bit definitions */ +struct CANLAM_BITS { // bits description + Uint16 LAM_L:16; // 0:15 + Uint16 LAM_H:13; // 16:28 + Uint16 rsvd1:2; // 29:30 reserved + Uint16 LAMI:1; // 31 +}; + +/* Allow access to the bit fields or entire register */ +union CANLAM_REG { + Uint32 all; + struct CANLAM_BITS bit; +}; + + +/**************************************/ +/* eCAN Local Acceptance Masks */ +/**************************************/ + +/* eCAN LAM File */ +struct LAM_REGS { + union CANLAM_REG LAM0; + union CANLAM_REG LAM1; + union CANLAM_REG LAM2; + union CANLAM_REG LAM3; + union CANLAM_REG LAM4; + union CANLAM_REG LAM5; + union CANLAM_REG LAM6; + union CANLAM_REG LAM7; + union CANLAM_REG LAM8; + union CANLAM_REG LAM9; + union CANLAM_REG LAM10; + union CANLAM_REG LAM11; + union CANLAM_REG LAM12; + union CANLAM_REG LAM13; + union CANLAM_REG LAM14; + union CANLAM_REG LAM15; + union CANLAM_REG LAM16; + union CANLAM_REG LAM17; + union CANLAM_REG LAM18; + union CANLAM_REG LAM19; + union CANLAM_REG LAM20; + union CANLAM_REG LAM21; + union CANLAM_REG LAM22; + union CANLAM_REG LAM23; + union CANLAM_REG LAM24; + union CANLAM_REG LAM25; + union CANLAM_REG LAM26; + union CANLAM_REG LAM27; + union CANLAM_REG LAM28; + union CANLAM_REG LAM29; + union CANLAM_REG LAM30; + union CANLAM_REG LAM31; +}; + +/* Mailbox MOTS File */ + +struct MOTS_REGS { + Uint32 MOTS0; + Uint32 MOTS1; + Uint32 MOTS2; + Uint32 MOTS3; + Uint32 MOTS4; + Uint32 MOTS5; + Uint32 MOTS6; + Uint32 MOTS7; + Uint32 MOTS8; + Uint32 MOTS9; + Uint32 MOTS10; + Uint32 MOTS11; + Uint32 MOTS12; + Uint32 MOTS13; + Uint32 MOTS14; + Uint32 MOTS15; + Uint32 MOTS16; + Uint32 MOTS17; + Uint32 MOTS18; + Uint32 MOTS19; + Uint32 MOTS20; + Uint32 MOTS21; + Uint32 MOTS22; + Uint32 MOTS23; + Uint32 MOTS24; + Uint32 MOTS25; + Uint32 MOTS26; + Uint32 MOTS27; + Uint32 MOTS28; + Uint32 MOTS29; + Uint32 MOTS30; + Uint32 MOTS31; +}; + +/* Mailbox MOTO File */ + +struct MOTO_REGS { + Uint32 MOTO0; + Uint32 MOTO1; + Uint32 MOTO2; + Uint32 MOTO3; + Uint32 MOTO4; + Uint32 MOTO5; + Uint32 MOTO6; + Uint32 MOTO7; + Uint32 MOTO8; + Uint32 MOTO9; + Uint32 MOTO10; + Uint32 MOTO11; + Uint32 MOTO12; + Uint32 MOTO13; + Uint32 MOTO14; + Uint32 MOTO15; + Uint32 MOTO16; + Uint32 MOTO17; + Uint32 MOTO18; + Uint32 MOTO19; + Uint32 MOTO20; + Uint32 MOTO21; + Uint32 MOTO22; + Uint32 MOTO23; + Uint32 MOTO24; + Uint32 MOTO25; + Uint32 MOTO26; + Uint32 MOTO27; + Uint32 MOTO28; + Uint32 MOTO29; + Uint32 MOTO30; + Uint32 MOTO31; +}; + + +//--------------------------------------------------------------------------- +// eCAN External References & Function Declarations: +// +extern volatile struct ECAN_REGS ECanaRegs; +extern volatile struct ECAN_MBOXES ECanaMboxes; +extern volatile struct LAM_REGS ECanaLAMRegs; +extern volatile struct MOTO_REGS ECanaMOTORegs; +extern volatile struct MOTS_REGS ECanaMOTSRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_ECAN.H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h new file mode 100644 index 0000000..092a5fd --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Ev.h @@ -0,0 +1,654 @@ +// TI File $Revision: /main/4 $ +// Checkin $Date: June 22, 2007 09:30:33 $ +//########################################################################### +// +// FILE: DSP281x_Ev.h +// +// TITLE: DSP281x Device Event Manager Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_EV_H +#define DSP281x_EV_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "DSP281x_Device.h" +/* --------------------------------------------------- */ +/* F2810/12 Event Manager (EV) GP Timer Registers */ +/* */ +/* ----------------------------------------------------*/ + +/* Overall Timer Control Register */ + +struct GPTCONA_BITS { + Uint16 T1PIN:2; // 1:0 Polarity of GP timer 1 compare + Uint16 T2PIN:2; // 3:2 Polarity of GP timer 2 compare + Uint16 T1CMPOE:1; // 4 Timer1 compare output + Uint16 T2CMPOE:1; // 5 Timer2 compare output + Uint16 TCMPOE:1; // 6 Compare output enable + Uint16 T1TOADC:2; // 8:7 Start ADC with timer 1 event + Uint16 T2TOADC:2; // 10:9 Start ADC with timer 2 event + Uint16 T1CTRIPE:1; // 11 Enable Timer 1 compare trip + Uint16 T2CTRIPE:1; // 12 Enable Timer 2 compare trip + Uint16 T1STAT:1; // 13 GP Timer 1 status (read only) + Uint16 T2STAT:1; // 14 GP Timer 2 status (read only) + Uint16 rsvd:1; // 15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union GPTCONA_REG { + Uint16 all; + struct GPTCONA_BITS bit; +}; + +struct GPTCONB_BITS { + Uint16 T3PIN:2; // 1:0 Polarity of GP timer 3 compare + Uint16 T4PIN:2; // 3:2 Polarity of GP timer 4 compare + Uint16 T3CMPOE:1; // 4 Timer3 compare output + Uint16 T4CMPOE:1; // 5 Timer4 compare output + Uint16 TCMPOE:1; // 6 Compare output enable + Uint16 T3TOADC:2; // 8:7 Start ADC with timer 3 event + Uint16 T4TOADC:2; // 10:9 Start ADC with timer 4 event + Uint16 T3CTRIPE:1; // 11 Timer 3 trip enable + Uint16 T4CTRIPE:1; // 12 Timer 4 trip enable + Uint16 T3STAT:1; // 13 GP Timer 3 status (read only) + Uint16 T4STAT:1; // 14 GP Timer 4 status (read only) + Uint16 rsvd2:1; // 15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union GPTCONB_REG { + Uint16 all; + struct GPTCONB_BITS bit; +}; + +/* Timer 1 Control Register bit defintions */ +struct T1CON_BITS { + Uint16 rsvd1:1; // 0 reserved + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 rsvd2:1; // 7 reserved + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T1CON_REG { + Uint16 all; + struct T1CON_BITS bit; +}; + + +/* Timer 2 Control Register bit defintions */ +struct T2CON_BITS { + Uint16 SET1PR:1; // 0 Period register select + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 T2SWT1:1; // 7 Start GP timer 2 with GP timer 1's enable + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T2CON_REG { + Uint16 all; + struct T2CON_BITS bit; +}; + +/* Timer 3 Control Register bit defintions */ +struct T3CON_BITS { + Uint16 rsvd1:1; // 0 reserved + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 rsvd2:1; // 7 reserved + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T3CON_REG { + Uint16 all; + struct T3CON_BITS bit; +}; + +/* Timer 4 Control Register bit defintions */ +struct T4CON_BITS { + Uint16 SET3PR:1; // 0 Period register select + Uint16 TECMPR:1; // 1 Timer compare enable + Uint16 TCLD10:2; // 3:2 Timer copare register reload + Uint16 TCLKS10:2; // 5:4 Clock source select + Uint16 TENABLE:1; // 6 Timer enable + Uint16 T4SWT3:1; // 7 Start GP timer 2 with GP timer 1's enable + Uint16 TPS:3; // 10:8 Input clock prescaler + Uint16 TMODE:2; // 12:11 Count mode selection + Uint16 rsvd:1; // 13 reserved + Uint16 SOFT:1; // 14 Soft emulation control + Uint16 FREE:1; // 15 Free emulation control +}; + +/* Allow access to the bit fields or entire register */ +union T4CON_REG { + Uint16 all; + struct T4CON_BITS bit; +}; + + +struct EXTCONA_BITS { + Uint16 INDCOE:1; // 0 Independant compare output + Uint16 QEPIQUAL:1; // 1 QEP/CAP3 Index Qual Mode + Uint16 QEPIE:1; // 2 QEP index enable + Uint16 EVSOCE:1; // 3 EvA start of conversion output enable + Uint16 rsvd:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EXTCONA_REG { + Uint16 all; + struct EXTCONA_BITS bit; +}; + + +struct EXTCONB_BITS { + Uint16 INDCOE:1; // 0 Independant compare output + Uint16 QEPIQUAL:1; // 1 QEP/CAP3 Index Qual Mode + Uint16 QEPIE:1; // 2 QEP index enable + Uint16 EVSOCE:1; // 3 EvB start of conversion output enable + Uint16 rsvd:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EXTCONB_REG { + Uint16 all; + struct EXTCONA_BITS bit; +}; + + + +/* Compare Control Register */ +struct COMCONA_BITS { + Uint16 C1TRIPE:1; // 0 C1TRIP enable + Uint16 C2TRIPE:1; // 1 C2TRIP enable + Uint16 C3TRIPE:1; // 2 C3TRIP eanble + Uint16 rsvd:2; // 4:3 reserved + Uint16 FCMP1OE:1; // 5 Full compare 1 output enable + Uint16 FCMP2OE:1; // 6 Full compare 2 output enable + Uint16 FCMP3OE:1; // 7 Full compare 3 output enable + Uint16 PDPINTASTATUS:1;// 8 Current status of the PDPINTA pin + Uint16 FCOMPOE:1; // 9 Compare output enable + Uint16 ACTRLD:2; // 11:10 Action control register reload + Uint16 SVENABLE:1; // 12 Space vector PWM Mode enable + Uint16 CLD:2; // 14:13 Compare register reload condition + Uint16 CENABLE:1; // 15 Compare enable +}; + +/* Allow access to the bit fields or entire register */ +union COMCONA_REG { + Uint16 all; + struct COMCONA_BITS bit; +}; + +struct COMCONB_BITS { + Uint16 C4TRIPE:1; // 0 C4TRIP enable + Uint16 C5TRIPE:1; // 1 C5TRIP enable + Uint16 C6TRIPE:1; // 2 C6TRIP eanble + Uint16 rsvd:2; // 4:3 reserved + Uint16 FCMP4OE:1; // 5 Full compare 4 output enable + Uint16 FCMP5OE:1; // 6 Full compare 5 output enable + Uint16 FCMP6OE:1; // 7 Full compare 6 output enable + Uint16 PDPINTBSTATUS:1;// 8 Current status of the PDPINTB pin + Uint16 FCOMPOE:1; // 9 Compare output enable + Uint16 ACTRLD:2; // 11:10 Action control register reload + Uint16 SVENABLE:1; // 12 Space vector PWM Mode enable + Uint16 CLD:2; // 14:13 Compare register reload condition + Uint16 CENABLE:1; // 15 Compare enable +}; + +/* Allow access to the bit fields or entire register */ +union COMCONB_REG { + Uint16 all; + struct COMCONB_BITS bit; +}; + +/* Compare Action Control Register bit definitions */ + +struct ACTRA_BITS { + Uint16 CMP1ACT:2; // 1:0 Action on compare output pin 1 CMP1 + Uint16 CMP2ACT:2; // 3:2 Action on compare output pin 2 CMP2 + Uint16 CMP3ACT:2; // 5:4 Action on compare output pin 3 CMP3 + Uint16 CMP4ACT:2; // 7:6 Action on compare output pin 4 CMP4 + Uint16 CMP5ACT:2; // 9:8 Action on compare output pin 5 CMP5 + Uint16 CMP6ACT:2; // 11:10 Action on compare output pin 6 CMP6 + Uint16 D:3; // 14:12 Basic vector bits + Uint16 SVRDIR:1; // 15 Space vecor PWM rotation dir +}; + +/* Allow access to the bit fields or entire register */ +union ACTRA_REG { + Uint16 all; + struct ACTRA_BITS bit; +}; + +struct ACTRB_BITS { + Uint16 CMP7ACT:2; // 1:0 Action on compare output pin 7 CMP7 + Uint16 CMP8ACT:2; // 3:2 Action on compare output pin 8 CMP8 + Uint16 CMP9ACT:2; // 5:4 Action on compare output pin 9 CMP9 + Uint16 CMP10ACT:2; // 7:6 Action on compare output pin 10 CMP10 + Uint16 CMP11ACT:2; // 9:8 Action on compare output pin 11 CMP11 + Uint16 CMP12ACT:2; // 11:10 Action on compare output pin 12 CMP12 + Uint16 D:3; // 14:12 Basic vector bits + Uint16 SVRDIR:1; // 15 Space vecor PWM rotation dir +}; + +/* Allow access to the bit fields or entire register */ +union ACTRB_REG { + Uint16 all; + struct ACTRB_BITS bit; +}; + +/* Dead-Band Timer Control register bit definitions */ +struct DBTCON_BITS { + Uint16 rsvd1:2; // 1:0 reserved + Uint16 DBTPS:3; // 4:2 Dead-Band timer prescaler + Uint16 EDBT1:1; // 5 Dead-Band timer 1 enable + Uint16 EDBT2:1; // 6 Dead-Band timer 2 enable + Uint16 EDBT3:1; // 7 Dead-Band timer 3 enable + Uint16 DBT:4; // 11:8 Dead-Band timer period + Uint16 rsvd2:4; // 15:12 reserved +}; + +/* Allow access to the bit fields or entire register */ +union DBTCON_REG { + Uint16 all; + struct DBTCON_BITS bit; +}; + + +/* Capture Control register bit definitions */ +struct CAPCONA_BITS { + Uint16 rsvd1:2; // 1:0 reserved + Uint16 CAP3EDGE:2; // 3:2 Edge Detection for Unit 3 + Uint16 CAP2EDGE:2; // 5:4 Edge Detection for Unit 2 + Uint16 CAP1EDGE:2; // 7:6 Edge Detection for Unit 1 + Uint16 CAP3TOADC:1; // 8 Unit 3 starts the ADC + Uint16 CAP12TSEL:1; // 9 GP Timer selection for Units 1 and 2 + Uint16 CAP3TSEL:1; // 10 GP Timer selection for Unit 3 + Uint16 rsvd2:1; // 11 reserved + Uint16 CAP3EN:1; // 12 Capture Unit 3 enable + Uint16 CAP12EN:2; // 14:13 Capture Unit 1 and 2 enable + Uint16 CAPRES:1; // 15 Capture reset (always reads 0) +}; + +/* Allow access to the bit fields or entire register */ +union CAPCONA_REG { + Uint16 all; + struct CAPCONA_BITS bit; +}; + + +/* Control register bit definitions */ +struct CAPCONB_BITS { + Uint16 rsvd1:2; // 1:0 reserved + Uint16 CAP6EDGE:2; // 3:2 Edge Detection for Unit 6 + Uint16 CAP5EDGE:2; // 5:4 Edge Detection for Unit 5 + Uint16 CAP4EDGE:2; // 7:6 Edge Detection for Unit 4 + Uint16 CAP6TOADC:1; // 8 Unit 6 starts the ADC + Uint16 CAP45TSEL:1; // 9 GP Timer selection for Units 4 and 5 + Uint16 CAP6TSEL:1; // 10 GP Timer selection for Unit 6 + Uint16 rsvd2:1; // 11 reserved + Uint16 CAP6EN:1; // 12 Capture Unit 6 control + Uint16 CAP45EN:2; // 14:13 Capture Unit 4 and 5 control + Uint16 CAPRES:1; // 15 Capture reset (always reads 0) +}; + +/* Allow access to the bit fields or entire register */ +union CAPCONB_REG { + Uint16 all; + struct CAPCONB_BITS bit; +}; + +/* Capture FIFO Status Register bit definitions */ +struct CAPFIFOA_BITS { + Uint16 rsvd1:8; // 7:0 reserved + Uint16 CAP1FIFO:2; // 9:8 CAP1 FIFO status + Uint16 CAP2FIFO:2; // 11:10 CAP2 FIFO status + Uint16 CAP3FIFO:2; // 13:12 CAP2 FIFO status + Uint16 rsvd2:2; // 15:14 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CAPFIFOA_REG { + Uint16 all; + struct CAPFIFOA_BITS bit; +}; + +/* Capture FIFO Status Register bit definitions */ +struct CAPFIFOB_BITS { + Uint16 rsvd1:8; // 7:0 reserved + Uint16 CAP4FIFO:2; // 9:8 CAP4 FIFO status + Uint16 CAP5FIFO:2; // 11:10 CAP5 FIFO status + Uint16 CAP6FIFO:2; // 13:12 CAP6 FIFO status + Uint16 rsvd2:2; // 15:14 reserved +}; + +/* Allow access to the bit fields or entire register */ +union CAPFIFOB_REG { + Uint16 all; + struct CAPFIFOB_BITS bit; +}; + +/* Interrupt Mask Register bit definitions */ +struct EVAIMRA_BITS { + Uint16 PDPINTA:1; // 0 Enable PDPINTA + Uint16 CMP1INT:1; // 1 Enable + Uint16 CMP2INT:1; // 2 Enable + Uint16 CMP3INT:1; // 3 Enable + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T1PINT:1; // 7 Enable + Uint16 T1CINT:1; // 8 Enable + Uint16 T1UFINT:1; // 9 Enable + Uint16 T1OFINT:1; // 10 Enable + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIMRA_REG { + Uint16 all; + struct EVAIMRA_BITS bit; +}; + +/* Interrupt Mask Register bit definitions */ +struct EVBIMRA_BITS { + Uint16 PDPINTB:1; // 0 Enable PDPINTB + Uint16 CMP4INT:1; // 1 Enable + Uint16 CMP5INT:1; // 2 Enable + Uint16 CMP6INT:1; // 3 Enable + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T3PINT:1; // 7 Enable + Uint16 T3CINT:1; // 8 Enable + Uint16 T3UFINT:1; // 9 Enable + Uint16 T3OFINT:1; // 10 Enable + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIMRA_REG { + Uint16 all; + struct EVBIMRA_BITS bit; +}; + +struct EVAIMRB_BITS { + Uint16 T2PINT:1; // 0 Enable + Uint16 T2CINT:1; // 1 Enable + Uint16 T2UFINT:1; // 2 Enable + Uint16 T2OFINT:1; // 3 Enable + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIMRB_REG { + Uint16 all; + struct EVAIMRB_BITS bit; +}; + +struct EVBIMRB_BITS { + Uint16 T4PINT:1; // 0 Enable + Uint16 T4CINT:1; // 1 Enable + Uint16 T4UFINT:1; // 2 Enable + Uint16 T4OFINT:1; // 3 Enable + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIMRB_REG { + Uint16 all; + struct EVBIMRB_BITS bit; +}; + +struct EVAIMRC_BITS { + Uint16 CAP1INT:1; // 0 Enable + Uint16 CAP2INT:1; // 1 Enable + Uint16 CAP3INT:1; // 2 Enable + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIMRC_REG { + Uint16 all; + struct EVAIMRC_BITS bit; +}; + +struct EVBIMRC_BITS { + Uint16 CAP4INT:1; // 0 Enable + Uint16 CAP5INT:1; // 1 Enable + Uint16 CAP6INT:1; // 2 Enable + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIMRC_REG { + Uint16 all; + struct EVBIMRC_BITS bit; +}; + +/* Interrupt Flag Register bit definitions */ +struct EVAIFRA_BITS { + Uint16 PDPINTA:1; // 0 Flag PDPINTA + Uint16 CMP1INT:1; // 1 Flag + Uint16 CMP2INT:1; // 2 Flag + Uint16 CMP3INT:1; // 3 Flag + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T1PINT:1; // 7 Flag + Uint16 T1CINT:1; // 8 Flag + Uint16 T1UFINT:1; // 9 Flag + Uint16 T1OFINT:1; // 10 Flag + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIFRA_REG { + Uint16 all; + struct EVAIMRA_BITS bit; +}; + +/* Interrupt Mask Register bit definitions */ +struct EVBIFRA_BITS { + Uint16 PDPINTB:1; // 0 Flag PDPINTB + Uint16 CMP4INT:1; // 1 Flag + Uint16 CMP5INT:1; // 2 Flag + Uint16 CMP6INT:1; // 3 Flag + Uint16 rsvd1:3; // 6:4 reserved + Uint16 T3PINT:1; // 7 Flag + Uint16 T3CINT:1; // 8 Flag + Uint16 T3UFINT:1; // 9 Flag + Uint16 T3OFINT:1; // 10 Flag + Uint16 rsvd2:5; // 15:11 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIFRA_REG { + Uint16 all; + struct EVBIFRA_BITS bit; +}; + +struct EVAIFRB_BITS { + Uint16 T2PINT:1; // 0 Flag + Uint16 T2CINT:1; // 1 Flag + Uint16 T2UFINT:1; // 2 Flag + Uint16 T2OFINT:1; // 3 Flag + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIFRB_REG { + Uint16 all; + struct EVAIFRB_BITS bit; +}; + +struct EVBIFRB_BITS { + Uint16 T4PINT:1; // 0 Flag + Uint16 T4CINT:1; // 1 Flag + Uint16 T4UFINT:1; // 2 Flag + Uint16 T4OFINT:1; // 3 Flag + Uint16 rsvd1:12; // 15:4 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIFRB_REG { + Uint16 all; + struct EVBIFRB_BITS bit; +}; + +struct EVAIFRC_BITS { + Uint16 CAP1INT:1; // 0 Flag + Uint16 CAP2INT:1; // 1 Flag + Uint16 CAP3INT:1; // 2 Flag + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVAIFRC_REG { + Uint16 all; + struct EVAIFRC_BITS bit; +}; + +struct EVBIFRC_BITS { + Uint16 CAP4INT:1; // 0 Flag + Uint16 CAP5INT:1; // 1 Flag + Uint16 CAP6INT:1; // 2 Flag + Uint16 rsvd1:13; // 15:3 reserved +}; + +/* Allow access to the bit fields or entire register */ +union EVBIFRC_REG { + Uint16 all; + struct EVBIFRC_BITS bit; +}; + +/* EVA Register File */ + +struct EVA_REGS { + union GPTCONA_REG GPTCONA; //0x7400 + Uint16 T1CNT; //0x7401 + Uint16 T1CMPR; //0x7402 + Uint16 T1PR; //0x7403 + union T1CON_REG T1CON; //0x7404 + Uint16 T2CNT; //0x7405 + Uint16 T2CMPR; //0x7406 + Uint16 T2PR; //0x7407 + union T2CON_REG T2CON; //0x7408 + union EXTCONA_REG EXTCONA; //0x7409 + Uint16 rsvd1[7]; //0x740A-10 + union COMCONA_REG COMCONA; //0x7411 + Uint16 rsvd2; //0x7412 + union ACTRA_REG ACTRA; //0x7413 + Uint16 rsvd3; //0x7414 + union DBTCON_REG DBTCONA; //0x7415 + Uint16 rsvd4; //0x7416 + Uint16 CMPR1; //0x7417 + Uint16 CMPR2; //0x7418 + Uint16 CMPR3; //0x7419 + Uint16 rsvd5[6]; //0x741A-F + union CAPCONA_REG CAPCONA; //0x7420 + Uint16 rsvd6; //0x7421 + union CAPFIFOA_REG CAPFIFOA; //0x7422 + Uint16 CAP1FIFO; //0x7423 + Uint16 CAP2FIFO; //0x7424 + Uint16 CAP3FIFO; //0x7425 + Uint16 rsvd7; //0x7426 + Uint16 CAP1FBOT; //0x7427 + Uint16 CAP2FBOT; //0x7428 + Uint16 CAP3FBOT; //0x7429 + Uint16 rsvd8[2]; //0x742A-B + union EVAIMRA_REG EVAIMRA; //0x742C + union EVAIMRB_REG EVAIMRB; //0x742D + union EVAIMRC_REG EVAIMRC; //0x742E + union EVAIFRA_REG EVAIFRA; //0x742F + union EVAIFRB_REG EVAIFRB; //0x7430 + union EVAIFRC_REG EVAIFRC; //0x7431 +}; + + +/* EVB Register File */ + +struct EVB_REGS { + union GPTCONB_REG GPTCONB; //0x7500 + Uint16 T3CNT; //0x7501 + Uint16 T3CMPR; //0x7502 + Uint16 T3PR; //0x7503 + union T3CON_REG T3CON; //0x7504 + Uint16 T4CNT; //0x7505 + Uint16 T4CMPR; //0x7506 + Uint16 T4PR; //0x7507 + union T4CON_REG T4CON; //0x7508 + union EXTCONB_REG EXTCONB; //0x7509 + Uint16 rsvd1[7]; //0x750A-10 + union COMCONB_REG COMCONB; //0x7511 + Uint16 rsvd2; //0x7512 + union ACTRB_REG ACTRB; //0x7513 + Uint16 rsvd3; //0x7514 + union DBTCON_REG DBTCONB; //0x7515 + Uint16 rsvd4; //0x7516 + Uint16 CMPR4; //0x7517 + Uint16 CMPR5; //0x7518 + Uint16 CMPR6; //0x7519 + Uint16 rsvd5[6]; //0x751A-F + union CAPCONB_REG CAPCONB; //0x7520 + Uint16 rsvd6; //0x7521 + union CAPFIFOB_REG CAPFIFOB; //0x7522 + Uint16 CAP4FIFO; //0x7523 + Uint16 CAP5FIFO; //0x7524 + Uint16 CAP6FIFO; //0x7525 + Uint16 rsvd7; //0x7526 + Uint16 CAP4FBOT; //0x7527 + Uint16 CAP5FBOT; //0x7528 + Uint16 CAP6FBOT; //0x7529 + Uint16 rsvd8[2]; //0x752A-B + union EVBIMRA_REG EVBIMRA; //0x752C + union EVBIMRB_REG EVBIMRB; //0x752D + union EVBIMRC_REG EVBIMRC; //0x752E + union EVBIFRA_REG EVBIFRA; //0x752F + union EVBIFRB_REG EVBIFRB; //0x7530 + union EVBIFRC_REG EVBIFRC; //0x7531 +}; + + + +//--------------------------------------------------------------------------- +// Function prototypes and external definitions: +// + +extern volatile struct EVA_REGS EvaRegs; +extern volatile struct EVB_REGS EvbRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_EV.H definition + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h new file mode 100644 index 0000000..fb3d751 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Gpio.h @@ -0,0 +1,1034 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:26 $ +//########################################################################### +// +// FILE: DSP281x_Gpio.h +// +// TITLE: DSP281x General Purpose I/O Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_GPIO_H +#define DSP281x_GPIO_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//---------------------------------------------------- +// General purpose I/O (GPIO) Register Bit Definitions + +//---------------------------------------------------- +// GPIO A mux control register bit definitions */ +// +// +struct GPAMUX_BITS { // bits description + Uint16 PWM1_GPIOA0:1; // 0 + Uint16 PWM2_GPIOA1:1; // 1 + Uint16 PWM3_GPIOA2:1; // 2 + Uint16 PWM4_GPIOA3:1; // 3 + Uint16 PWM5_GPIOA4:1; // 4 + Uint16 PWM6_GPIOA5:1; // 5 + Uint16 T1PWM_GPIOA6:1; // 6 + Uint16 T2PWM_GPIOA7:1; // 7 + Uint16 CAP1Q1_GPIOA8:1; // 8 + Uint16 CAP2Q2_GPIOA9:1; // 9 + Uint16 CAP3QI1_GPIOA10:1; // 10 + Uint16 TDIRA_GPIOA11:1; // 11 + Uint16 TCLKINA_GPIOA12:1; // 12 + Uint16 C1TRIP_GPIOA13:1; // 13 + Uint16 C2TRIP_GPIOA14:1; // 14 + Uint16 C3TRIP_GPIOA15:1; // 15 + +}; + +union GPAMUX_REG { + Uint16 all; + struct GPAMUX_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO A Direction control register bit definitions +// +// +struct GPADIR_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPADIR_REG { + Uint16 all; + struct GPADIR_BITS bit; +}; + +//---------------------------------- +// GPA Qualregister bit definitions +// +// + +struct GPAQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPAQUAL_REG { + Uint16 all; + struct GPAQUAL_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO A Data register bit definitions +// +// +struct GPADAT_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPADAT_REG { + Uint16 all; + struct GPADAT_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO A Data set bit definitions +// +// +struct GPASET_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPASET_REG { + Uint16 all; + struct GPASET_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO A Data clear register bit definitions +// +// +struct GPACLEAR_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPACLEAR_REG { + Uint16 all; + struct GPACLEAR_BITS bit; +}; + +//--------------------------------------------------------------------------------------- +// GPIO A Data toggle register bit definitions +// +// +struct GPATOGGLE_BITS { // bits description + Uint16 GPIOA0:1; // 0 + Uint16 GPIOA1:1; // 1 + Uint16 GPIOA2:1; // 2 + Uint16 GPIOA3:1; // 3 + Uint16 GPIOA4:1; // 4 + Uint16 GPIOA5:1; // 5 + Uint16 GPIOA6:1; // 6 + Uint16 GPIOA7:1; // 7 + Uint16 GPIOA8:1; // 8 + Uint16 GPIOA9:1; // 9 + Uint16 GPIOA10:1; // 10 + Uint16 GPIOA11:1; // 11 + Uint16 GPIOA12:1; // 12 + Uint16 GPIOA13:1; // 13 + Uint16 GPIOA14:1; // 14 + Uint16 GPIOA15:1; // 15 + +}; + +union GPATOGGLE_REG { + Uint16 all; + struct GPATOGGLE_BITS bit; +}; + + + +//--------------------------------------------------------------------------------- +// GPIO B mux control register bit definitions +// +// +struct GPBMUX_BITS { // bits description + Uint16 PWM7_GPIOB0:1; // 0 + Uint16 PWM8_GPIOB1:1; // 1 + Uint16 PWM9_GPIOB2:1; // 2 + Uint16 PWM10_GPIOB3:1; // 3 + Uint16 PWM11_GPIOB4:1; // 4 + Uint16 PWM12_GPIOB5:1; // 5 + Uint16 T3PWM_GPIOB6:1; // 6 + Uint16 T4PWM_GPIOB7:1; // 7 + Uint16 CAP4Q1_GPIOB8:1; // 8 + Uint16 CAP5Q2_GPIOB9:1; // 9 + Uint16 CAP6QI2_GPIOB10:1; // 10 + Uint16 TDIRB_GPIOB11:1; // 11 + Uint16 TCLKINB_GPIOB12:1; // 12 + Uint16 C4TRIP_GPIOB13:1; // 13 + Uint16 C5TRIP_GPIOB14:1; // 14 + Uint16 C6TRIP_GPIOB15:1; // 15 + +}; + +union GPBMUX_REG { + Uint16 all; + struct GPBMUX_BITS bit; +}; + +//--------------------------------------------------------------------------------------- +// GPIO B Direction control register bit definitions +// +// +struct GPBDIR_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBDIR_REG { + Uint16 all; + struct GPBDIR_BITS bit; +}; + +//----------------------------------- +// GPB Qualregister bit definitions +// +// + +struct GPBQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPBQUAL_REG { + Uint16 all; + struct GPBQUAL_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO B data register bit definitions +// +// +struct GPBDAT_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBDAT_REG { + Uint16 all; + struct GPBDAT_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO B data set register bit definitions +// +// +struct GPBSET_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + + +union GPBSET_REG { + Uint16 all; + struct GPBSET_BITS bit; +}; + + +//--------------------------------------------------------------------------------------- +// GPIO B data clear register bit definitions +// +// +struct GPBCLEAR_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBCLEAR_REG { + Uint16 all; + struct GPBCLEAR_BITS bit; +}; + + + +//--------------------------------------------------------------------------------------- +// GPIO B data toggle register bit definitions +// +// +struct GPBTOGGLE_BITS { // bits description + Uint16 GPIOB0:1; // 0 + Uint16 GPIOB1:1; // 1 + Uint16 GPIOB2:1; // 2 + Uint16 GPIOB3:1; // 3 + Uint16 GPIOB4:1; // 4 + Uint16 GPIOB5:1; // 5 + Uint16 GPIOB6:1; // 6 + Uint16 GPIOB7:1; // 7 + Uint16 GPIOB8:1; // 8 + Uint16 GPIOB9:1; // 9 + Uint16 GPIOB10:1; // 10 + Uint16 GPIOB11:1; // 11 + Uint16 GPIOB12:1; // 12 + Uint16 GPIOB13:1; // 13 + Uint16 GPIOB14:1; // 14 + Uint16 GPIOB15:1; // 15 + +}; + +union GPBTOGGLE_REG { + Uint16 all; + struct GPBTOGGLE_BITS bit; +}; + + +//--------------------------------------------------------------------------------- +// GPIO D mux control register bit definitions +// +// +struct GPDMUX_BITS { // bits description + Uint16 T1CTRIP_PDPA_GPIOD0:1; // 0 + Uint16 T2CTRIP_SOCA_GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 T3CTRIP_PDPB_GPIOD5:1; // 5 + Uint16 T4CTRIP_SOCB_GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 + +}; + +union GPDMUX_REG { + Uint16 all; + struct GPDMUX_BITS bit; +}; + +//---------------------------------------------------- +// GPIO D Direction control register bit definitions +// +// +struct GPDDIR_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDDIR_REG { + Uint16 all; + struct GPDDIR_BITS bit; +}; + + +//---------------------------------------------------- +// GPIO D data register bit definitions +// +// +struct GPDDAT_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDDAT_REG { + Uint16 all; + struct GPDDAT_BITS bit; +}; + + +//---------------------------------------------------- +// GPIO D data set register bit definitions +// +// +struct GPDSET_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDSET_REG { + Uint16 all; + struct GPDSET_BITS bit; +}; + + +//---------------------------------------------------- +// GPIO D data clear register bit definitions +// +// +struct GPDCLEAR_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDCLEAR_REG { + Uint16 all; + struct GPDCLEAR_BITS bit; +}; + + + +//---------------------------------------------------- +// GPIO D data toggle register bit definitions +// +// +struct GPDTOGGLE_BITS { // bits description + Uint16 GPIOD0:1; // 0 + Uint16 GPIOD1:1; // 1 + Uint16 rsvd1:3; // 4:2 + Uint16 GPIOD5:1; // 5 + Uint16 GPIOD6:1; // 6 + Uint16 rsvd2:9; // 15:7 +}; + +union GPDTOGGLE_REG { + Uint16 all; + struct GPDTOGGLE_BITS bit; +}; + + + +//---------------------------------- +// GPIOD Qualregister bit definitions +// +// +struct GPDQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPDQUAL_REG { + Uint16 all; + struct GPDQUAL_BITS bit; +}; + + +//--------------------------------------------- +// GPIO E mux control register bit definitions +// +// +struct GPEMUX_BITS { // bits description + Uint16 XINT1_XBIO_GPIOE0:1; // 0 + Uint16 XINT2_ADCSOC_GPIOE1:1; // 1 + Uint16 XNMI_XINT13_GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 + +}; + +union GPEMUX_REG { + Uint16 all; + struct GPEMUX_BITS bit; +}; + +//--------------------------------------------------- +// GPIO E Direction control register bit definitions +// +// +struct GPEDIR_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPEDIR_REG { + Uint16 all; + struct GPEDIR_BITS bit; +}; + +//--------------------------------------------------- +// GPIO E data register bit definitions +// +// +struct GPEDAT_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPEDAT_REG { + Uint16 all; + struct GPEDAT_BITS bit; +}; + + + +//--------------------------------------------------- +// GPIO E data set register bit definitions +// +// +struct GPESET_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPESET_REG { + Uint16 all; + struct GPESET_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO E data clear register bit definitions +// +// +struct GPECLEAR_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPECLEAR_REG { + Uint16 all; + struct GPECLEAR_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO E data toggle register bit definitions +// +// +struct GPETOGGLE_BITS { // bits description + Uint16 GPIOE0:1; // 0 + Uint16 GPIOE1:1; // 1 + Uint16 GPIOE2:1; // 2 + Uint16 rsvd1:12; // 15:3 +}; + +union GPETOGGLE_REG { + Uint16 all; + struct GPETOGGLE_BITS bit; +}; + + + +//----------------------------------- +// GPIOE Qualregister bit definitions +// +// +struct GPEQUAL_BITS { // bits description + Uint16 QUALPRD:8; // 0:7 Qualification Sampling Period + Uint16 rsvd1:8; // 15:8 reserved +}; + +union GPEQUAL_REG { + Uint16 all; + struct GPEQUAL_BITS bit; +}; + + +//---------------------------------------------- +// GPIO F mux control register bit definitions +// +// +struct GPFMUX_BITS { // bits description + Uint16 SPISIMOA_GPIOF0:1; // 0 + Uint16 SPISOMIA_GPIOF1:1; // 1 + Uint16 SPICLKA_GPIOF2:1; // 2 + Uint16 SPISTEA_GPIOF3:1; // 3 + Uint16 SCITXDA_GPIOF4:1; // 4 + Uint16 SCIRXDA_GPIOF5:1; // 5 + Uint16 CANTXA_GPIOF6:1; // 6 + Uint16 CANRXA_GPIOF7:1; // 7 + Uint16 MCLKXA_GPIOF8:1; // 8 + Uint16 MCLKRA_GPIOF9:1; // 9 + Uint16 MFSXA_GPIOF10:1; // 10 + Uint16 MFSRA_GPIOF11:1; // 11 + Uint16 MDXA_GPIOF12:1; // 12 + Uint16 MDRA_GPIOF13:1; // 13 + Uint16 XF_GPIOF14:1; // 14 + Uint16 spare_GPIOF15:1; // 15 + +}; + +/* Allow access to the bit fields or entire register */ +union GPFMUX_REG { + Uint16 all; + struct GPFMUX_BITS bit; +}; + +//--------------------------------------------------- +// GPIO F Direction control register bit definitions +// +// + +struct GPFDIR_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFDIR_REG { + Uint16 all; + struct GPFDIR_BITS bit; +}; + +//--------------------------------------------------- +// GPIO F data register bit definitions +// +// + +struct GPFDAT_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFDAT_REG { + Uint16 all; + struct GPFDAT_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO F data set register bit definitions +// +// + +struct GPFSET_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFSET_REG { + Uint16 all; + struct GPFSET_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO F data clear register bit definitions +// +// + +struct GPFCLEAR_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFCLEAR_REG { + Uint16 all; + struct GPFCLEAR_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO F data toggle register bit definitions +// +// + +struct GPFTOGGLE_BITS { // bits description + Uint16 GPIOF0:1; // 0 + Uint16 GPIOF1:1; // 1 + Uint16 GPIOF2:1; // 2 + Uint16 GPIOF3:1; // 3 + Uint16 GPIOF4:1; // 4 + Uint16 GPIOF5:1; // 5 + Uint16 GPIOF6:1; // 6 + Uint16 GPIOF7:1; // 7 + Uint16 GPIOF8:1; // 8 + Uint16 GPIOF9:1; // 9 + Uint16 GPIOF10:1; // 10 + Uint16 GPIOF11:1; // 11 + Uint16 GPIOF12:1; // 12 + Uint16 GPIOF13:1; // 13 + Uint16 GPIOF14:1; // 14 + Uint16 GPIOF15:1; // 15 + +}; + +union GPFTOGGLE_REG { + Uint16 all; + struct GPFTOGGLE_BITS bit; +}; + +//---------------------------------------------- +// GPIO G mux control register bit definitions +// +// +struct GPGMUX_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 SCITXDB_GPIOG4:1; // 4 + Uint16 SCIRXDB_GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + + +/* Allow access to the bit fields or entire register */ +union GPGMUX_REG { + Uint16 all; + struct GPGMUX_BITS bit; +}; + +//--------------------------------------------------- +// GPIO G Direction control register bit definitions +// +// + +struct GPGDIR_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGDIR_REG { + Uint16 all; + struct GPGDIR_BITS bit; +}; + +//--------------------------------------------------- +// GPIO G data register bit definitions +// +// + +struct GPGDAT_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGDAT_REG { + Uint16 all; + struct GPGDAT_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO G data set register bit definitions +// +// + +struct GPGSET_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGSET_REG { + Uint16 all; + struct GPGSET_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO G data clear register bit definitions +// +// + +struct GPGCLEAR_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGCLEAR_REG { + Uint16 all; + struct GPGCLEAR_BITS bit; +}; + + +//--------------------------------------------------- +// GPIO G data toggle register bit definitions +// +// + +struct GPGTOGGLE_BITS { // bits description + Uint16 rsvd1:4; // 3:0 + Uint16 GPIOG4:1; // 4 + Uint16 GPIOG5:1; // 5 + Uint16 rsvd2:10; // 15:6 + +}; + +union GPGTOGGLE_REG { + Uint16 all; + struct GPGTOGGLE_BITS bit; +}; + + +struct GPIO_MUX_REGS { + union GPAMUX_REG GPAMUX; + union GPADIR_REG GPADIR; + union GPAQUAL_REG GPAQUAL; + Uint16 rsvd1; + union GPBMUX_REG GPBMUX; + union GPBDIR_REG GPBDIR; + union GPBQUAL_REG GPBQUAL; + Uint16 rsvd2[5]; + union GPDMUX_REG GPDMUX; + union GPDDIR_REG GPDDIR; + union GPDQUAL_REG GPDQUAL; + Uint16 rsvd3; + union GPEMUX_REG GPEMUX; + union GPEDIR_REG GPEDIR; + union GPEQUAL_REG GPEQUAL; + Uint16 rsvd4; + union GPFMUX_REG GPFMUX; + union GPFDIR_REG GPFDIR; + Uint16 rsvd5[2]; + union GPGMUX_REG GPGMUX; + union GPGDIR_REG GPGDIR; + Uint16 rsvd6[6]; +}; + +struct GPIO_DATA_REGS { + union GPADAT_REG GPADAT; + union GPASET_REG GPASET; + union GPACLEAR_REG GPACLEAR; + union GPATOGGLE_REG GPATOGGLE; + union GPBDAT_REG GPBDAT; + union GPBSET_REG GPBSET; + union GPBCLEAR_REG GPBCLEAR; + union GPBTOGGLE_REG GPBTOGGLE; + Uint16 rsvd1[4]; + union GPDDAT_REG GPDDAT; + union GPDSET_REG GPDSET; + union GPDCLEAR_REG GPDCLEAR; + union GPDTOGGLE_REG GPDTOGGLE; + union GPEDAT_REG GPEDAT; + union GPESET_REG GPESET; + union GPECLEAR_REG GPECLEAR; + union GPETOGGLE_REG GPETOGGLE; + union GPFDAT_REG GPFDAT; + union GPFSET_REG GPFSET; + union GPFCLEAR_REG GPFCLEAR; + union GPFTOGGLE_REG GPFTOGGLE; + union GPGDAT_REG GPGDAT; + union GPGSET_REG GPGSET; + union GPGCLEAR_REG GPGCLEAR; + union GPGTOGGLE_REG GPGTOGGLE; + Uint16 rsvd2[4]; +}; + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +extern volatile struct GPIO_MUX_REGS GpioMuxRegs; +extern volatile struct GPIO_DATA_REGS GpioDataRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_GPIO_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h new file mode 100644 index 0000000..559d96d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Mcbsp.h @@ -0,0 +1,777 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:24 $ +//########################################################################### +// +// FILE: DSP281x_Mcbsp.h +// +// TITLE: DSP281x Device McBSP Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_MCBSP_H +#define DSP281x_MCBSP_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// McBSP Individual Register Bit Definitions: +// +// McBSP DRR2 register bit definitions: +struct DRR2_BITS { // bit description + Uint16 HWLB:8; // 16:23 High word low byte + Uint16 HWHB:8; // 24:31 High word high byte +}; + +union DRR2_REG { + Uint16 all; + struct DRR2_BITS bit; +}; + +// McBSP DRR1 register bit definitions: +struct DRR1_BITS { // bit description + Uint16 LWLB:8; // 16:23 Low word low byte + Uint16 LWHB:8; // 24:31 low word high byte +}; + +union DRR1_REG { + Uint16 all; + struct DRR1_BITS bit; +}; + +// McBSP DXR2 register bit definitions: +struct DXR2_BITS { // bit description + Uint16 HWLB:8; // 16:23 High word low byte + Uint16 HWHB:8; // 24:31 High word high byte +}; + +union DXR2_REG { + Uint16 all; + struct DXR2_BITS bit; +}; + +// McBSP DXR1 register bit definitions: +struct DXR1_BITS { // bit description + Uint16 LWLB:8; // 16:23 Low word low byte + Uint16 LWHB:8; // 24:31 low word high byte +}; + +union DXR1_REG { + Uint16 all; + struct DXR1_BITS bit; +}; + +// SPCR2 control register bit definitions: +struct SPCR2_BITS { // bit description + Uint16 XRST:1; // 0 transmit reset + Uint16 XRDY:1; // 1 transmit ready + Uint16 XEMPTY:1; // 2 Transmit empty + Uint16 XSYNCERR:1; // 3 Transmit syn errorINT flag + Uint16 XINTM:2; // 5:4 Transmit interrupt types + Uint16 GRST:1; // 6 CLKG reset + Uint16 FRST:1; // 7 Frame sync reset + Uint16 SOFT:1; // 8 SOFT bit + Uint16 FREE:1; // 9 FREE bit + Uint16 rsvd:6; // 15:10 reserved +}; + +union SPCR2_REG { + Uint16 all; + struct SPCR2_BITS bit; +}; + +// SPCR1 control register bit definitions: +struct SPCR1_BITS { // bit description + Uint16 RRST:1; // 0 Receive reset + Uint16 RRDY:1; // 1 Receive ready + Uint16 RFULL:1; // 2 Receive full + Uint16 RSYNCERR:1; // 7 Receive syn error + Uint16 RINTM:2; // 5:4 Receive interrupt types + Uint16 ABIS:1; // 6 ABIS mode select + Uint16 DXENA:1; // 7 DX hi-z enable + Uint16 rsvd:3; // 10:8 reserved + Uint16 CLKSTP:2; // 12:11 CLKSTOP mode bit + Uint16 RJUST:2; // 13:14 Right justified + Uint16 DLB:1; // 15 Digital loop back +}; + +union SPCR1_REG { + Uint16 all; + struct SPCR1_BITS bit; +}; + +// RCR2 control register bit definitions: +struct RCR2_BITS { // bit description + Uint16 RDATDLY:2; // 1:0 Receive data delay + Uint16 RFIG:1; // 2 Receive frame sync ignore + Uint16 RCOMPAND:2; // 4:3 Receive Companding Mode selects + Uint16 RWDLEN2:3; // 7:5 Receive word length + Uint16 RFRLEN2:7; // 14:8 Receive Frame sync + Uint16 RPHASE:1; // 15 Receive Phase +}; + +union RCR2_REG { + Uint16 all; + struct RCR2_BITS bit; +}; + +// RCR1 control register bit definitions: +struct RCR1_BITS { // bit description + Uint16 rsvd1:5; // 4:0 reserved + Uint16 RWDLEN1:3; // 7:5 Receive word length + Uint16 RFRLEN1:7; // 14:8 Receive frame length + Uint16 rsvd2:1; // 15 reserved +}; + +union RCR1_REG { + Uint16 all; + struct RCR1_BITS bit; +}; + +// XCR2 control register bit definitions: + +struct XCR2_BITS { // bit description + Uint16 XDATDLY:2; // 1:0 Transmit data delay + Uint16 XFIG:1; // 2 Transmit frame sync ignore + Uint16 XCOMPAND:2; // 4:3 Transmit Companding Mode selects + Uint16 XWDLEN2:3; // 7:5 Transmit word length + Uint16 XFRLEN2:7; // 14:8 Transmit Frame sync + Uint16 XPHASE:1; // 15 Transmit Phase +}; + +union XCR2_REG { + Uint16 all; + struct XCR2_BITS bit; +}; + +// XCR1 control register bit definitions: +struct XCR1_BITS { // bit description + Uint16 rsvd1:5; // 4:0 reserved + Uint16 XWDLEN1:3; // 7:5 Transmit word length + Uint16 XFRLEN1:7; // 14:8 Transmit frame length + Uint16 rsvd2:1; // 15 reserved +}; + +union XCR1_REG { + Uint16 all; + struct XCR1_BITS bit; +}; + +// SRGR2 Sample rate generator control register bit definitions: +struct SRGR2_BITS { // bit description + Uint16 FPER:12; // 11:0 Frame period + Uint16 FSGM:1; // 12 Frame sync generator mode + Uint16 CLKSM:1; // 13 Sample rate generator mode + Uint16 rsvd:1; // 14 reserved + Uint16 GSYNC:1; // 15 CLKG sync +}; + +union SRGR2_REG { + Uint16 all; + struct SRGR2_BITS bit; +}; + +// SRGR1 control register bit definitions: +struct SRGR1_BITS { // bit description + Uint16 CLKGDV:8; // 7:0 CLKG divider + Uint16 FWID:8; // 15:8 Frame width +}; + +union SRGR1_REG { + Uint16 all; + struct SRGR1_BITS bit; +}; + +// MCR2 Multichannel control register bit definitions: +struct MCR2_BITS { // bit description + Uint16 XMCM:2; // 1:0 Transmit multichannel mode + Uint16 XCBLK:3; // 2:4 Transmit current block + Uint16 XPABLK:2; // 5:6 Transmit partition A Block + Uint16 XPBBLK:2; // 7:8 Transmit partition B Block + Uint16 XMCME:1; // 9 Transmit multi-channel enhance mode + Uint16 rsvd:6; // 15:10 reserved +}; + +union MCR2_REG { + Uint16 all; + struct MCR2_BITS bit; +}; + +// MCR1 Multichannel control register bit definitions: +struct MCR1_BITS { // bit description + Uint16 RMCM:1; // 0 Receive multichannel mode + Uint16 rsvd:1; // 1 reserved + Uint16 RCBLK:3; // 4:2 Receive current block + Uint16 RPABLK:2; // 6:5 Receive partition A Block + Uint16 RPBBLK:2; // 7:8 Receive partition B Block + Uint16 RMCME:1; // 9 Receive multi-channel enhance mode + Uint16 rsvd1:6; // 15:10 reserved +}; + +union MCR1_REG { + Uint16 all; + struct MCR1_BITS bit; +}; + +// RCERA control register bit definitions: +struct RCERA_BITS { // bit description + Uint16 RCEA0:1; // 0 Receive Channel enable bit + Uint16 RCEA1:1; // 1 Receive Channel enable bit + Uint16 RCEA2:1; // 2 Receive Channel enable bit + Uint16 RCEA3:1; // 3 Receive Channel enable bit + Uint16 RCEA4:1; // 4 Receive Channel enable bit + Uint16 RCEA5:1; // 5 Receive Channel enable bit + Uint16 RCEA6:1; // 6 Receive Channel enable bit + Uint16 RCEA7:1; // 7 Receive Channel enable bit + Uint16 RCEA8:1; // 8 Receive Channel enable bit + Uint16 RCEA9:1; // 9 Receive Channel enable bit + Uint16 RCEA10:1; // 10 Receive Channel enable bit + Uint16 RCEA11:1; // 11 Receive Channel enable bit + Uint16 RCEA12:1; // 12 Receive Channel enable bit + Uint16 RCEA13:1; // 13 Receive Channel enable bit + Uint16 RCEA14:1; // 14 Receive Channel enable bit + Uint16 RCEA15:1; // 15 Receive Channel enable bit +}; + +union RCERA_REG { + Uint16 all; + struct RCERA_BITS bit; +}; + +// RCERB control register bit definitions: +struct RCERB_BITS { // bit description + Uint16 RCEB0:1; // 0 Receive Channel enable bit + Uint16 RCEB1:1; // 1 Receive Channel enable bit + Uint16 RCEB2:1; // 2 Receive Channel enable bit + Uint16 RCEB3:1; // 3 Receive Channel enable bit + Uint16 RCEB4:1; // 4 Receive Channel enable bit + Uint16 RCEB5:1; // 5 Receive Channel enable bit + Uint16 RCEB6:1; // 6 Receive Channel enable bit + Uint16 RCEB7:1; // 7 Receive Channel enable bit + Uint16 RCEB8:1; // 8 Receive Channel enable bit + Uint16 RCEB9:1; // 9 Receive Channel enable bit + Uint16 RCEB10:1; // 10 Receive Channel enable bit + Uint16 RCEB11:1; // 11 Receive Channel enable bit + Uint16 RCEB12:1; // 12 Receive Channel enable bit + Uint16 RCEB13:1; // 13 Receive Channel enable bit + Uint16 RCEB14:1; // 14 Receive Channel enable bit + Uint16 RCEB15:1; // 15 Receive Channel enable bit +}; + +union RCERB_REG { + Uint16 all; + struct RCERB_BITS bit; +}; + +// XCERA control register bit definitions: +struct XCERA_BITS { // bit description + Uint16 XCERA0:1; // 0 Receive Channel enable bit + Uint16 XCERA1:1; // 1 Receive Channel enable bit + Uint16 XCERA2:1; // 2 Receive Channel enable bit + Uint16 XCERA3:1; // 3 Receive Channel enable bit + Uint16 XCERA4:1; // 4 Receive Channel enable bit + Uint16 XCERA5:1; // 5 Receive Channel enable bit + Uint16 XCERA6:1; // 6 Receive Channel enable bit + Uint16 XCERA7:1; // 7 Receive Channel enable bit + Uint16 XCERA8:1; // 8 Receive Channel enable bit + Uint16 XCERA9:1; // 9 Receive Channel enable bit + Uint16 XCERA10:1; // 10 Receive Channel enable bit + Uint16 XCERA11:1; // 11 Receive Channel enable bit + Uint16 XCERA12:1; // 12 Receive Channel enable bit + Uint16 XCERA13:1; // 13 Receive Channel enable bit + Uint16 XCERA14:1; // 14 Receive Channel enable bit + Uint16 XCERA15:1; // 15 Receive Channel enable bit +}; + +union XCERA_REG { + Uint16 all; + struct XCERA_BITS bit; +}; + +// XCERB control register bit definitions: +struct XCERB_BITS { // bit description + Uint16 XCERB0:1; // 0 Receive Channel enable bit + Uint16 XCERB1:1; // 1 Receive Channel enable bit + Uint16 XCERB2:1; // 2 Receive Channel enable bit + Uint16 XCERB3:1; // 3 Receive Channel enable bit + Uint16 XCERB4:1; // 4 Receive Channel enable bit + Uint16 XCERB5:1; // 5 Receive Channel enable bit + Uint16 XCERB6:1; // 6 Receive Channel enable bit + Uint16 XCERB7:1; // 7 Receive Channel enable bit + Uint16 XCERB8:1; // 8 Receive Channel enable bit + Uint16 XCERB9:1; // 9 Receive Channel enable bit + Uint16 XCERB10:1; // 10 Receive Channel enable bit + Uint16 XCERB11:1; // 11 Receive Channel enable bit + Uint16 XCERB12:1; // 12 Receive Channel enable bit + Uint16 XCERB13:1; // 13 Receive Channel enable bit + Uint16 XCERB14:1; // 14 Receive Channel enable bit + Uint16 XCERB15:1; // 15 Receive Channel enable bit +}; + +union XCERB_REG { + Uint16 all; + struct XCERB_BITS bit; +}; + +// PCR control register bit definitions: +struct PCR_BITS { // bit description + Uint16 CLKRP:1; // 0 Receive Clock polarity + Uint16 CLKXP:1; // 1 Transmit clock polarity + Uint16 FSRP:1; // 2 Receive Frame synchronization polarity + Uint16 FSXP:1; // 3 Transmit Frame synchronization polarity + Uint16 DR_STAT:1; // 4 DR pin status - reserved for this McBSP + Uint16 DX_STAT:1; // 5 DX pin status - reserved for this McBSP + Uint16 CLKS_STAT:1; // 6 CLKS pin status - reserved for 28x -McBSP + Uint16 SCLKME:1; // 7 Enhanced sample clock mode selection bit. + Uint16 CLKRM:1; // 8 Receiver Clock Mode + Uint16 CLKXM:1; // 9 Transmitter Clock Mode. + Uint16 FSRM:1; // 10 Receive Frame Synchronization Mode + Uint16 FSXM:1; // 11 Transmit Frame Synchronization Mode + Uint16 RIOEN:1; // 12 General Purpose I/O Mode - reserved in this 28x-McBSP + Uint16 XIOEN:1; // 13 General Purpose I/O Mode - reserved in this 28x-McBSP + Uint16 IDEL_EN:1; // 14 reserved in this 28x-McBSP + Uint16 rsvd:1 ; // 15 reserved +}; + +union PCR_REG { + Uint16 all; + struct PCR_BITS bit; +}; + +// RCERC control register bit definitions: +struct RCERC_BITS { // bit description + Uint16 RCEC0:1; // 0 Receive Channel enable bit + Uint16 RCEC1:1; // 1 Receive Channel enable bit + Uint16 RCEC2:1; // 2 Receive Channel enable bit + Uint16 RCEC3:1; // 3 Receive Channel enable bit + Uint16 RCEC4:1; // 4 Receive Channel enable bit + Uint16 RCEC5:1; // 5 Receive Channel enable bit + Uint16 RCEC6:1; // 6 Receive Channel enable bit + Uint16 RCEC7:1; // 7 Receive Channel enable bit + Uint16 RCEC8:1; // 8 Receive Channel enable bit + Uint16 RCEC9:1; // 9 Receive Channel enable bit + Uint16 RCEC10:1; // 10 Receive Channel enable bit + Uint16 RCEC11:1; // 11 Receive Channel enable bit + Uint16 RCEC12:1; // 12 Receive Channel enable bit + Uint16 RCEC13:1; // 13 Receive Channel enable bit + Uint16 RCEC14:1; // 14 Receive Channel enable bit + Uint16 RCEC15:1; // 15 Receive Channel enable bit +}; + +union RCERC_REG { + Uint16 all; + struct RCERC_BITS bit; +}; + +// RCERD control register bit definitions: +struct RCERD_BITS { // bit description + Uint16 RCED0:1; // 0 Receive Channel enable bit + Uint16 RCED1:1; // 1 Receive Channel enable bit + Uint16 RCED2:1; // 2 Receive Channel enable bit + Uint16 RCED3:1; // 3 Receive Channel enable bit + Uint16 RCED4:1; // 4 Receive Channel enable bit + Uint16 RCED5:1; // 5 Receive Channel enable bit + Uint16 RCED6:1; // 6 Receive Channel enable bit + Uint16 RCED7:1; // 7 Receive Channel enable bit + Uint16 RCED8:1; // 8 Receive Channel enable bit + Uint16 RCED9:1; // 9 Receive Channel enable bit + Uint16 RCED10:1; // 10 Receive Channel enable bit + Uint16 RCED11:1; // 11 Receive Channel enable bit + Uint16 RCED12:1; // 12 Receive Channel enable bit + Uint16 RCED13:1; // 13 Receive Channel enable bit + Uint16 RCED14:1; // 14 Receive Channel enable bit + Uint16 RCED15:1; // 15 Receive Channel enable bit +}; + +union RCERD_REG { + Uint16 all; + struct RCERD_BITS bit; +}; + +// XCERC control register bit definitions: +struct XCERC_BITS { // bit description + Uint16 XCERC0:1; // 0 Receive Channel enable bit + Uint16 XCERC1:1; // 1 Receive Channel enable bit + Uint16 XCERC2:1; // 2 Receive Channel enable bit + Uint16 XCERC3:1; // 3 Receive Channel enable bit + Uint16 XCERC4:1; // 4 Receive Channel enable bit + Uint16 XCERC5:1; // 5 Receive Channel enable bit + Uint16 XCERC6:1; // 6 Receive Channel enable bit + Uint16 XCERC7:1; // 7 Receive Channel enable bit + Uint16 XCERC8:1; // 8 Receive Channel enable bit + Uint16 XCERC9:1; // 9 Receive Channel enable bit + Uint16 XCERC10:1; // 10 Receive Channel enable bit + Uint16 XCERC11:1; // 11 Receive Channel enable bit + Uint16 XCERC12:1; // 12 Receive Channel enable bit + Uint16 XCERC13:1; // 13 Receive Channel enable bit + Uint16 XCERC14:1; // 14 Receive Channel enable bit + Uint16 XCERC15:1; // 15 Receive Channel enable bit +}; + +union XCERC_REG { + Uint16 all; + struct XCERC_BITS bit; +}; + +// XCERD control register bit definitions: +struct XCERD_BITS { // bit description + Uint16 XCERD0:1; // 0 Receive Channel enable bit + Uint16 XCERD1:1; // 1 Receive Channel enable bit + Uint16 XCERD2:1; // 2 Receive Channel enable bit + Uint16 XCERD3:1; // 3 Receive Channel enable bit + Uint16 XCERD4:1; // 4 Receive Channel enable bit + Uint16 XCERD5:1; // 5 Receive Channel enable bit + Uint16 XCERD6:1; // 6 Receive Channel enable bit + Uint16 XCERD7:1; // 7 Receive Channel enable bit + Uint16 XCERD8:1; // 8 Receive Channel enable bit + Uint16 XCERD9:1; // 9 Receive Channel enable bit + Uint16 XCERD10:1; // 10 Receive Channel enable bit + Uint16 XCERD11:1; // 11 Receive Channel enable bit + Uint16 XCERD12:1; // 12 Receive Channel enable bit + Uint16 XCERD13:1; // 13 Receive Channel enable bit + Uint16 XCERD14:1; // 14 Receive Channel enable bit + Uint16 XCERD15:1; // 15 Receive Channel enable bit +}; + +union XCERD_REG { + Uint16 all; + struct XCERD_BITS bit; +}; + +// RCERE control register bit definitions: +struct RCERE_BITS { // bit description + Uint16 RCEE0:1; // 0 Receive Channel enable bit + Uint16 RCEE1:1; // 1 Receive Channel enable bit + Uint16 RCEE2:1; // 2 Receive Channel enable bit + Uint16 RCEE3:1; // 3 Receive Channel enable bit + Uint16 RCEE4:1; // 4 Receive Channel enable bit + Uint16 RCEE5:1; // 5 Receive Channel enable bit + Uint16 RCEE6:1; // 6 Receive Channel enable bit + Uint16 RCEE7:1; // 7 Receive Channel enable bit + Uint16 RCEE8:1; // 8 Receive Channel enable bit + Uint16 RCEE9:1; // 9 Receive Channel enable bit + Uint16 RCEE10:1; // 10 Receive Channel enable bit + Uint16 RCEE11:1; // 11 Receive Channel enable bit + Uint16 RCEE12:1; // 12 Receive Channel enable bit + Uint16 RCEE13:1; // 13 Receive Channel enable bit + Uint16 RCEE14:1; // 14 Receive Channel enable bit + Uint16 RCEE15:1; // 15 Receive Channel enable bit +}; + +union RCERE_REG { + Uint16 all; + struct RCERE_BITS bit; +}; + +// RCERF control register bit definitions: +struct RCERF_BITS { // bit description + Uint16 RCEF0:1; // 0 Receive Channel enable bit + Uint16 RCEF1:1; // 1 Receive Channel enable bit + Uint16 RCEF2:1; // 2 Receive Channel enable bit + Uint16 RCEF3:1; // 3 Receive Channel enable bit + Uint16 RCEF4:1; // 4 Receive Channel enable bit + Uint16 RCEF5:1; // 5 Receive Channel enable bit + Uint16 RCEF6:1; // 6 Receive Channel enable bit + Uint16 RCEF7:1; // 7 Receive Channel enable bit + Uint16 RCEF8:1; // 8 Receive Channel enable bit + Uint16 RCEF9:1; // 9 Receive Channel enable bit + Uint16 RCEF10:1; // 10 Receive Channel enable bit + Uint16 RCEF11:1; // 11 Receive Channel enable bit + Uint16 RCEF12:1; // 12 Receive Channel enable bit + Uint16 RCEF13:1; // 13 Receive Channel enable bit + Uint16 RCEF14:1; // 14 Receive Channel enable bit + Uint16 RCEF15:1; // 15 Receive Channel enable bit +}; + +union RCERF_REG { + Uint16 all; + struct RCERF_BITS bit; +}; + +// XCERE control register bit definitions: +struct XCERE_BITS { // bit description + Uint16 XCERE0:1; // 0 Receive Channel enable bit + Uint16 XCERE1:1; // 1 Receive Channel enable bit + Uint16 XCERE2:1; // 2 Receive Channel enable bit + Uint16 XCERE3:1; // 3 Receive Channel enable bit + Uint16 XCERE4:1; // 4 Receive Channel enable bit + Uint16 XCERE5:1; // 5 Receive Channel enable bit + Uint16 XCERE6:1; // 6 Receive Channel enable bit + Uint16 XCERE7:1; // 7 Receive Channel enable bit + Uint16 XCERE8:1; // 8 Receive Channel enable bit + Uint16 XCERE9:1; // 9 Receive Channel enable bit + Uint16 XCERE10:1; // 10 Receive Channel enable bit + Uint16 XCERE11:1; // 11 Receive Channel enable bit + Uint16 XCERE12:1; // 12 Receive Channel enable bit + Uint16 XCERE13:1; // 13 Receive Channel enable bit + Uint16 XCERE14:1; // 14 Receive Channel enable bit + Uint16 XCERE15:1; // 15 Receive Channel enable bit +}; + +union XCERE_REG { + Uint16 all; + struct XCERE_BITS bit; +}; + +// XCERF control register bit definitions: +struct XCERF_BITS { // bit description + Uint16 XCERF0:1; // 0 Receive Channel enable bit + Uint16 XCERF1:1; // 1 Receive Channel enable bit + Uint16 XCERF2:1; // 2 Receive Channel enable bit + Uint16 XCERF3:1; // 3 Receive Channel enable bit + Uint16 XCERF4:1; // 4 Receive Channel enable bit + Uint16 XCERF5:1; // 5 Receive Channel enable bit + Uint16 XCERF6:1; // 6 Receive Channel enable bit + Uint16 XCERF7:1; // 7 Receive Channel enable bit + Uint16 XCERF8:1; // 8 Receive Channel enable bit + Uint16 XCERF9:1; // 9 Receive Channel enable bit + Uint16 XCERF10:1; // 10 Receive Channel enable bit + Uint16 XCERF11:1; // 11 Receive Channel enable bit + Uint16 XCERF12:1; // 12 Receive Channel enable bit + Uint16 XCERF13:1; // 13 Receive Channel enable bit + Uint16 XCERF14:1; // 14 Receive Channel enable bit + Uint16 XCERF15:1; // 15 Receive Channel enable bit +}; + +union XCERF_REG { + Uint16 all; + struct XCERF_BITS bit; +}; + +// RCERG control register bit definitions: +struct RCERG_BITS { // bit description + Uint16 RCEG0:1; // 0 Receive Channel enable bit + Uint16 RCEG1:1; // 1 Receive Channel enable bit + Uint16 RCEG2:1; // 2 Receive Channel enable bit + Uint16 RCEG3:1; // 3 Receive Channel enable bit + Uint16 RCEG4:1; // 4 Receive Channel enable bit + Uint16 RCEG5:1; // 5 Receive Channel enable bit + Uint16 RCEG6:1; // 6 Receive Channel enable bit + Uint16 RCEG7:1; // 7 Receive Channel enable bit + Uint16 RCEG8:1; // 8 Receive Channel enable bit + Uint16 RCEG9:1; // 9 Receive Channel enable bit + Uint16 RCEG10:1; // 10 Receive Channel enable bit + Uint16 RCEG11:1; // 11 Receive Channel enable bit + Uint16 RCEG12:1; // 12 Receive Channel enable bit + Uint16 RCEG13:1; // 13 Receive Channel enable bit + Uint16 RCEG14:1; // 14 Receive Channel enable bit + Uint16 RCEG15:1; // 15 Receive Channel enable bit +}; + +union RCERG_REG { + Uint16 all; + struct RCERG_BITS bit; +}; + +// RCERH control register bit definitions: +struct RCERH_BITS { // bit description + Uint16 RCEH0:1; // 0 Receive Channel enable bit + Uint16 RCEH1:1; // 1 Receive Channel enable bit + Uint16 RCEH2:1; // 2 Receive Channel enable bit + Uint16 RCEH3:1; // 3 Receive Channel enable bit + Uint16 RCEH4:1; // 4 Receive Channel enable bit + Uint16 RCEH5:1; // 5 Receive Channel enable bit + Uint16 RCEH6:1; // 6 Receive Channel enable bit + Uint16 RCEH7:1; // 7 Receive Channel enable bit + Uint16 RCEH8:1; // 8 Receive Channel enable bit + Uint16 RCEH9:1; // 9 Receive Channel enable bit + Uint16 RCEH10:1; // 10 Receive Channel enable bit + Uint16 RCEH11:1; // 11 Receive Channel enable bit + Uint16 RCEH12:1; // 12 Receive Channel enable bit + Uint16 RCEH13:1; // 13 Receive Channel enable bit + Uint16 RCEH14:1; // 14 Receive Channel enable bit + Uint16 RCEH15:1; // 15 Receive Channel enable bit +}; + +union RCERH_REG { + Uint16 all; + struct RCERH_BITS bit; +}; + +// XCERG control register bit definitions: +struct XCERG_BITS { // bit description + Uint16 XCERG0:1; // 0 Receive Channel enable bit + Uint16 XCERG1:1; // 1 Receive Channel enable bit + Uint16 XCERG2:1; // 2 Receive Channel enable bit + Uint16 XCERG3:1; // 3 Receive Channel enable bit + Uint16 XCERG4:1; // 4 Receive Channel enable bit + Uint16 XCERG5:1; // 5 Receive Channel enable bit + Uint16 XCERG6:1; // 6 Receive Channel enable bit + Uint16 XCERG7:1; // 7 Receive Channel enable bit + Uint16 XCERG8:1; // 8 Receive Channel enable bit + Uint16 XCERG9:1; // 9 Receive Channel enable bit + Uint16 XCERG10:1; // 10 Receive Channel enable bit + Uint16 XCERG11:1; // 11 Receive Channel enable bit + Uint16 XCERG12:1; // 12 Receive Channel enable bit + Uint16 XCERG13:1; // 13 Receive Channel enable bit + Uint16 XCERG14:1; // 14 Receive Channel enable bit + Uint16 XCERG15:1; // 15 Receive Channel enable bit +}; + +union XCERG_REG { + Uint16 all; + struct XCERG_BITS bit; +}; + +// XCERH control register bit definitions: +struct XCERH_BITS { // bit description + Uint16 XCEH0:1; // 0 Receive Channel enable bit + Uint16 XCEH1:1; // 1 Receive Channel enable bit + Uint16 XCEH2:1; // 2 Receive Channel enable bit + Uint16 XCEH3:1; // 3 Receive Channel enable bit + Uint16 XCEH4:1; // 4 Receive Channel enable bit + Uint16 XCEH5:1; // 5 Receive Channel enable bit + Uint16 XCEH6:1; // 6 Receive Channel enable bit + Uint16 XCEH7:1; // 7 Receive Channel enable bit + Uint16 XCEH8:1; // 8 Receive Channel enable bit + Uint16 XCEH9:1; // 9 Receive Channel enable bit + Uint16 XCEH10:1; // 10 Receive Channel enable bit + Uint16 XCEH11:1; // 11 Receive Channel enable bit + Uint16 XCEH12:1; // 12 Receive Channel enable bit + Uint16 XCEH13:1; // 13 Receive Channel enable bit + Uint16 XCEH14:1; // 14 Receive Channel enable bit + Uint16 XCEH15:1; // 15 Receive Channel enable bit +}; + +union XCERH_REG { + Uint16 all; + struct XCERH_BITS bit; +}; + +// McBSP FIFO Transmit register bit definitions: +struct MFFTX_BITS { // bit description + Uint16 TXFFIL:5; // 4:0 Interrupt level + Uint16 TXFFIENA:1; // 5 Interrupt enable + Uint16 TXFFINT_CLEAR:1; // 6 Clear INT flag + Uint16 TXFFINT_FLAG:1; // 7 INT flag + Uint16 TXFFST:5; // 12:8 FIFO status + Uint16 TXFIFO_RESET:1; // 13 FIFO reset + Uint16 MFFENA:1; // 14 Enhancement enable + Uint16 rsvd:1; // 15 reserved +}; + +union MFFTX_REG { + Uint16 all; + struct MFFTX_BITS bit; +}; + +// McBSP FIFO recieve register bit definitions: +struct MFFRX_BITS { // bits description + Uint16 RXFFIL:5; // 4:0 Interrupt level + Uint16 RXFFIENA:1; // 5 Interrupt enable + Uint16 RXFFINT_CLEAR:1; // 6 Clear INT flag + Uint16 RXFFINT_FLAG:1; // 7 INT flag + Uint16 RXFFST:5; // 12:8 FIFO status + Uint16 RXFIFO_RESET:1; // 13 FIFO reset + Uint16 RXFFOVF_CLEAR:1; // 14 Clear overflow + Uint16 RXFFOVF_FLAG:1; // 15 FIFO overflow +}; + +union MFFRX_REG { + Uint16 all; + struct MFFRX_BITS bit; +}; + +// McBSP FIFO control register bit definitions: +struct MFFCT_BITS { // bits description + Uint16 FFTXTXDLY:8; // 7:0 FIFO transmit delay + Uint16 rsvd:7; // 15:7 reserved + Uint16 IACKM:1; // 15 is IACK mode enable bit +}; + +union MFFCT_REG { + Uint16 all; + struct MFFCT_BITS bit; +}; + +// McBSP FIFO INTERRUPT control register bit definitions: +struct MFFINT_BITS { // bits description + Uint16 XINT:1; // 0 XINT interrupt enable + Uint16 XEVTA:1; // 1 XEVTA interrupt enable + Uint16 RINT:1; // 2 RINT interrupt enable + Uint16 REVTA:1; // 3 REVTA interrupt enable + Uint16 rsvd:12; // 15:4 reserved +}; + +union MFFINT_REG { + Uint16 all; + struct MFFINT_BITS bit; +}; + +// McBSP FIFO INTERRUPT status register bit definitions: +struct MFFST_BITS { // bits description + Uint16 EOBX:1; // 0 EOBX flag + Uint16 FSX:1; // 1 FSX flag + Uint16 EOBR:1; // 2 EOBR flag + Uint16 FSR:1; // 3 FSR flag + Uint16 rsvd:12; // 15:4 reserved +}; + +union MFFST_REG { + Uint16 all; + struct MFFST_BITS bit; +}; + + +//--------------------------------------------------------------------------- +// McBSP Register File: +// +struct MCBSP_REGS { + union DRR2_REG DRR2; // 0x7800, MCBSP Data receive register bits 31-16 + union DRR1_REG DRR1; // 0x7801, MCBSP Data receive register bits 15-0 + union DXR2_REG DXR2; // 0x7802, MCBSP Data transmit register bits 31-16 + union DXR1_REG DXR1; // 0x7803, MCBSP Data transmit register bits 15-0 + union SPCR2_REG SPCR2; // 0x7804, MCBSP control register bits 31-16 + union SPCR1_REG SPCR1; // 0x7805, MCBSP control register bits 15-0 + union RCR2_REG RCR2; // 0x7806, MCBSP receive control register bits 31-16 + union RCR1_REG RCR1; // 0x7807, MCBSP receive control register bits 15-0 + union XCR2_REG XCR2; // 0x7808, MCBSP transmit control register bits 31-16 + union XCR1_REG XCR1; // 0x7809, MCBSP transmit control register bits 15-0 + union SRGR2_REG SRGR2; // 0x7810, MCBSP sample rate gen register bits 31-16 + union SRGR1_REG SRGR1; // 0x7811, MCBSP sample rate gen register bits 15-0 + union MCR2_REG MCR2; // 0x7812, MCBSP multichannel register bits 31-16 + union MCR1_REG MCR1; // 0x7813, MCBSP multichannel register bits 15-0 + union RCERA_REG RCERA; // 0x7814, MCBSP Receive channel enable partition A + union RCERB_REG RCERB; // 0x7815, MCBSP Receive channel enable partition B + union XCERA_REG XCERA; // 0x7816, MCBSP Transmit channel enable partition A + union XCERB_REG XCERB; // 0x7817, MCBSP Transmit channel enable partition B + union PCR_REG PCR; // 0x7818, MCBSP Pin control register bits 15-0 + union RCERC_REG RCERC; // 0x7819, MCBSP Receive channel enable partition C + union RCERD_REG RCERD; // 0x7820, MCBSP Receive channel enable partition D + union XCERC_REG XCERC; // 0x7821, MCBSP Transmit channel enable partition C + union XCERD_REG XCERD; // 0x7823, MCBSP Transmit channel enable partition D + union RCERE_REG RCERE; // 0x7824, MCBSP Receive channel enable partition E + union RCERF_REG RCERF; // 0x7825, MCBSP Receive channel enable partition F + union XCERE_REG XCERE; // 0x7826, MCBSP Transmit channel enable partition E + union XCERF_REG XCERF; // 0x7827, MCBSP Transmit channel enable partition F + union RCERG_REG RCERG; // 0x7828, MCBSP Receive channel enable partition G + union RCERH_REG RCERH; // 0x7829, MCBSP Receive channel enable partition H + union XCERG_REG XCERG; // 0x7830, MCBSP Transmit channel enable partition G + union XCERH_REG XCERH; // 0x7831, MCBSP Transmit channel enable partition H + Uint16 rsvd1; // 0x7832, reserved + union MFFTX_REG MFFTX; // 0x7833, MCBSP Transmit FIFO register bits + union MFFRX_REG MFFRX; // 0x7834, MCBSP Receive FIFO register bits + union MFFCT_REG MFFCT; // 0x7835, MCBSP FIFO control register bits + union MFFINT_REG MFFINT; // 0x7836, MCBSP Interrupt register bits + union MFFST_REG MFFST; // 0x7837, MCBSP Status register bits +}; + +//--------------------------------------------------------------------------- +// McBSP External References & Function Declarations: +// +extern volatile struct MCBSP_REGS McbspaRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_MCBSP_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h new file mode 100644 index 0000000..512b29a --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieCtrl.h @@ -0,0 +1,153 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:22 $ +//########################################################################### +// +// FILE: DSP281x_PieCtrl.h +// +// TITLE: DSP281x Device PIE Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + + +#ifndef DSP281x_PIE_CTRL_H +#define DSP281x_PIE_CTRL_H + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// PIE Control Register Bit Definitions: +// +// PIECTRL: Register bit definitions: +struct PIECTRL_BITS { // bits description + Uint16 ENPIE:1; // 0 Enable PIE block + Uint16 PIEVECT:15; // 15:1 Fetched vector address +}; + +union PIECTRL_REG { + Uint16 all; + struct PIECTRL_BITS bit; +}; + +// PIEIER: Register bit definitions: +struct PIEIER_BITS { // bits description + Uint16 INTx1:1; // 0 INTx.1 + Uint16 INTx2:1; // 1 INTx.2 + Uint16 INTx3:1; // 2 INTx.3 + Uint16 INTx4:1; // 3 INTx.4 + Uint16 INTx5:1; // 4 INTx.5 + Uint16 INTx6:1; // 5 INTx.6 + Uint16 INTx7:1; // 6 INTx.7 + Uint16 INTx8:1; // 7 INTx.8 + Uint16 rsvd:8; // 15:8 reserved +}; + +union PIEIER_REG { + Uint16 all; + struct PIEIER_BITS bit; +}; + +// PIEIFR: Register bit definitions: +struct PIEIFR_BITS { // bits description + Uint16 INTx1:1; // 0 INTx.1 + Uint16 INTx2:1; // 1 INTx.2 + Uint16 INTx3:1; // 2 INTx.3 + Uint16 INTx4:1; // 3 INTx.4 + Uint16 INTx5:1; // 4 INTx.5 + Uint16 INTx6:1; // 5 INTx.6 + Uint16 INTx7:1; // 6 INTx.7 + Uint16 INTx8:1; // 7 INTx.8 + Uint16 rsvd:8; // 15:8 reserved +}; + +union PIEIFR_REG { + Uint16 all; + struct PIEIFR_BITS bit; +}; + +// PIEACK: Register bit definitions: +struct PIEACK_BITS { // bits description + Uint16 ACK1:1; // 0 Acknowledge PIE interrupt group 1 + Uint16 ACK2:1; // 1 Acknowledge PIE interrupt group 2 + Uint16 ACK3:1; // 2 Acknowledge PIE interrupt group 3 + Uint16 ACK4:1; // 3 Acknowledge PIE interrupt group 4 + Uint16 ACK5:1; // 4 Acknowledge PIE interrupt group 5 + Uint16 ACK6:1; // 5 Acknowledge PIE interrupt group 6 + Uint16 ACK7:1; // 6 Acknowledge PIE interrupt group 7 + Uint16 ACK8:1; // 7 Acknowledge PIE interrupt group 8 + Uint16 ACK9:1; // 8 Acknowledge PIE interrupt group 9 + Uint16 ACK10:1; // 9 Acknowledge PIE interrupt group 10 + Uint16 ACK11:1; // 10 Acknowledge PIE interrupt group 11 + Uint16 ACK12:1; // 11 Acknowledge PIE interrupt group 12 + Uint16 rsvd:4; // 15:12 reserved +}; + +union PIEACK_REG { + Uint16 all; + struct PIEACK_BITS bit; +}; + +//--------------------------------------------------------------------------- +// PIE Control Register File: +// +struct PIE_CTRL_REGS { + union PIECTRL_REG PIECRTL; // PIE control register + union PIEACK_REG PIEACK; // PIE acknowledge + union PIEIER_REG PIEIER1; // PIE INT1 IER register + union PIEIFR_REG PIEIFR1; // PIE INT1 IFR register + union PIEIER_REG PIEIER2; // PIE INT2 IER register + union PIEIFR_REG PIEIFR2; // PIE INT2 IFR register + union PIEIER_REG PIEIER3; // PIE INT3 IER register + union PIEIFR_REG PIEIFR3; // PIE INT3 IFR register + union PIEIER_REG PIEIER4; // PIE INT4 IER register + union PIEIFR_REG PIEIFR4; // PIE INT4 IFR register + union PIEIER_REG PIEIER5; // PIE INT5 IER register + union PIEIFR_REG PIEIFR5; // PIE INT5 IFR register + union PIEIER_REG PIEIER6; // PIE INT6 IER register + union PIEIFR_REG PIEIFR6; // PIE INT6 IFR register + union PIEIER_REG PIEIER7; // PIE INT7 IER register + union PIEIFR_REG PIEIFR7; // PIE INT7 IFR register + union PIEIER_REG PIEIER8; // PIE INT8 IER register + union PIEIFR_REG PIEIFR8; // PIE INT8 IFR register + union PIEIER_REG PIEIER9; // PIE INT9 IER register + union PIEIFR_REG PIEIFR9; // PIE INT9 IFR register + union PIEIER_REG PIEIER10; // PIE INT10 IER register + union PIEIFR_REG PIEIFR10; // PIE INT10 IFR register + union PIEIER_REG PIEIER11; // PIE INT11 IER register + union PIEIFR_REG PIEIFR11; // PIE INT11 IFR register + union PIEIER_REG PIEIER12; // PIE INT12 IER register + union PIEIFR_REG PIEIFR12; // PIE INT12 IFR register +}; + +#define PIEACK_GROUP1 0x0001; +#define PIEACK_GROUP2 0x0002; +#define PIEACK_GROUP3 0x0004; +#define PIEACK_GROUP4 0x0008; +#define PIEACK_GROUP5 0x0010; +#define PIEACK_GROUP6 0x0020; +#define PIEACK_GROUP7 0x0040; +#define PIEACK_GROUP8 0x0080; +#define PIEACK_GROUP9 0x0100; +#define PIEACK_GROUP10 0x0200; +#define PIEACK_GROUP11 0x0400; +#define PIEACK_GROUP12 0x0800; + +//--------------------------------------------------------------------------- +// PIE Control Registers External References & Function Declarations: +// +extern volatile struct PIE_CTRL_REGS PieCtrlRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_PIE_CTRL_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h new file mode 100644 index 0000000..ec34743 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_PieVect.h @@ -0,0 +1,210 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:21 $ +//########################################################################### +// +// FILE: DSP281x_PieVect.h +// +// TITLE: DSP281x Devices PIE Vector Table Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_PIE_VECT_H +#define DSP281x_PIE_VECT_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table Definition: +// +// Create a user type called PINT (pointer to interrupt): + +typedef interrupt void(*PINT)(void); + +// Define Vector Table: +struct PIE_VECT_TABLE { + +// Reset is never fetched from this table. +// It will always be fetched from 0x3FFFC0 in either +// boot ROM or XINTF Zone 7 depending on the state of +// the XMP/MC input signal. On the F2810 it is always +// fetched from boot ROM. + + PINT PIE1_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE2_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE3_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE4_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE5_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE6_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE7_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE8_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE9_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE10_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE11_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE12_RESERVED; // @suppress("Type cannot be resolved") + PINT PIE13_RESERVED; // @suppress("Type cannot be resolved") + +// Non-Peripheral Interrupts: + PINT XINT13; // XINT13 // @suppress("Type cannot be resolved") + PINT TINT2; // CPU-Timer2 // @suppress("Type cannot be resolved") + PINT DATALOG; // Datalogging interrupt // @suppress("Type cannot be resolved") + PINT RTOSINT; // RTOS interrupt // @suppress("Type cannot be resolved") + PINT EMUINT; // Emulation interrupt // @suppress("Type cannot be resolved") + PINT XNMI; // Non-maskable interrupt // @suppress("Type cannot be resolved") + PINT ILLEGAL; // Illegal operation TRAP // @suppress("Type cannot be resolved") + PINT USER1; // User Defined trap 1 // @suppress("Type cannot be resolved") + PINT USER2; // User Defined trap 2 // @suppress("Type cannot be resolved") + PINT USER3; // User Defined trap 3 // @suppress("Type cannot be resolved") + PINT USER4; // User Defined trap 4 // @suppress("Type cannot be resolved") + PINT USER5; // User Defined trap 5 // @suppress("Type cannot be resolved") + PINT USER6; // User Defined trap 6 // @suppress("Type cannot be resolved") + PINT USER7; // User Defined trap 7 // @suppress("Type cannot be resolved") + PINT USER8; // User Defined trap 8 // @suppress("Type cannot be resolved") + PINT USER9; // User Defined trap 9 // @suppress("Type cannot be resolved") + PINT USER10; // User Defined trap 10 // @suppress("Type cannot be resolved") + PINT USER11; // User Defined trap 11 // @suppress("Type cannot be resolved") + PINT USER12; // User Defined trap 12 // @suppress("Type cannot be resolved") + +// Group 1 PIE Peripheral Vectors: + PINT PDPINTA; // EV-A // @suppress("Type cannot be resolved") + PINT PDPINTB; // EV-B // @suppress("Type cannot be resolved") + PINT rsvd1_3; // @suppress("Type cannot be resolved") + PINT XINT1; // @suppress("Type cannot be resolved") + PINT XINT2; // @suppress("Type cannot be resolved") + PINT ADCINT; // ADC // @suppress("Type cannot be resolved") + PINT TINT0; // Timer 0 // @suppress("Type cannot be resolved") + PINT WAKEINT; // WD // @suppress("Type cannot be resolved") + +// Group 2 PIE Peripheral Vectors: + PINT CMP1INT; // EV-A // @suppress("Type cannot be resolved") + PINT CMP2INT; // EV-A // @suppress("Type cannot be resolved") + PINT CMP3INT; // EV-A // @suppress("Type cannot be resolved") + PINT T1PINT; // EV-A // @suppress("Type cannot be resolved") + PINT T1CINT; // EV-A // @suppress("Type cannot be resolved") + PINT T1UFINT; // EV-A // @suppress("Type cannot be resolved") + PINT T1OFINT; // EV-A // @suppress("Type cannot be resolved") + PINT rsvd2_8; // @suppress("Type cannot be resolved") + +// Group 3 PIE Peripheral Vectors: + PINT T2PINT; // EV-A // @suppress("Type cannot be resolved") + PINT T2CINT; // EV-A // @suppress("Type cannot be resolved") + PINT T2UFINT; // EV-A // @suppress("Type cannot be resolved") + PINT T2OFINT; // EV-A // @suppress("Type cannot be resolved") + PINT CAPINT1; // EV-A // @suppress("Type cannot be resolved") + PINT CAPINT2; // EV-A // @suppress("Type cannot be resolved") + PINT CAPINT3; // EV-A // @suppress("Type cannot be resolved") + PINT rsvd3_8; // @suppress("Type cannot be resolved") + +// Group 4 PIE Peripheral Vectors: + PINT CMP4INT; // EV-B // @suppress("Type cannot be resolved") + PINT CMP5INT; // EV-B // @suppress("Type cannot be resolved") + PINT CMP6INT; // EV-B // @suppress("Type cannot be resolved") + PINT T3PINT; // EV-B // @suppress("Type cannot be resolved") + PINT T3CINT; // EV-B // @suppress("Type cannot be resolved") + PINT T3UFINT; // EV-B // @suppress("Type cannot be resolved") + PINT T3OFINT; // EV-B // @suppress("Type cannot be resolved") + PINT rsvd4_8; // @suppress("Type cannot be resolved") + +// Group 5 PIE Peripheral Vectors: + PINT T4PINT; // EV-B // @suppress("Type cannot be resolved") + PINT T4CINT; // EV-B // @suppress("Type cannot be resolved") + PINT T4UFINT; // EV-B // @suppress("Type cannot be resolved") + PINT T4OFINT; // EV-B // @suppress("Type cannot be resolved") + PINT CAPINT4; // EV-B // @suppress("Type cannot be resolved") + PINT CAPINT5; // EV-B // @suppress("Type cannot be resolved") + PINT CAPINT6; // EV-B // @suppress("Type cannot be resolved") + PINT rsvd5_8; // @suppress("Type cannot be resolved") + +// Group 6 PIE Peripheral Vectors: + PINT SPIRXINTA; // SPI-A // @suppress("Type cannot be resolved") + PINT SPITXINTA; // SPI-A // @suppress("Type cannot be resolved") + PINT rsvd6_3; // @suppress("Type cannot be resolved") + PINT rsvd6_4; // @suppress("Type cannot be resolved") + PINT MRINTA; // McBSP-A // @suppress("Type cannot be resolved") + PINT MXINTA; // McBSP-A // @suppress("Type cannot be resolved") + PINT rsvd6_7; // @suppress("Type cannot be resolved") + PINT rsvd6_8; // @suppress("Type cannot be resolved") + +// Group 7 PIE Peripheral Vectors: + PINT rsvd7_1; // @suppress("Type cannot be resolved") + PINT rsvd7_2; // @suppress("Type cannot be resolved") + PINT rsvd7_3; // @suppress("Type cannot be resolved") + PINT rsvd7_4; // @suppress("Type cannot be resolved") + PINT rsvd7_5; // @suppress("Type cannot be resolved") + PINT rsvd7_6; // @suppress("Type cannot be resolved") + PINT rsvd7_7; // @suppress("Type cannot be resolved") + PINT rsvd7_8; // @suppress("Type cannot be resolved") + +// Group 8 PIE Peripheral Vectors: + PINT rsvd8_1; // @suppress("Type cannot be resolved") + PINT rsvd8_2; // @suppress("Type cannot be resolved") + PINT rsvd8_3; // @suppress("Type cannot be resolved") + PINT rsvd8_4; // @suppress("Type cannot be resolved") + PINT rsvd8_5; // @suppress("Type cannot be resolved") + PINT rsvd8_6; // @suppress("Type cannot be resolved") + PINT rsvd8_7; // @suppress("Type cannot be resolved") + PINT rsvd8_8; // @suppress("Type cannot be resolved") + +// Group 9 PIE Peripheral Vectors: + PINT RXAINT; // SCI-A // @suppress("Type cannot be resolved") + PINT TXAINT; // SCI-A // @suppress("Type cannot be resolved") + PINT RXBINT; // SCI-B // @suppress("Type cannot be resolved") + PINT TXBINT; // SCI-B // @suppress("Type cannot be resolved") + PINT ECAN0INTA; // eCAN // @suppress("Type cannot be resolved") + PINT ECAN1INTA; // eCAN // @suppress("Type cannot be resolved") + PINT rsvd9_7; // @suppress("Type cannot be resolved") + PINT rsvd9_8; // @suppress("Type cannot be resolved") + +// Group 10 PIE Peripheral Vectors: + PINT rsvd10_1; // @suppress("Type cannot be resolved") + PINT rsvd10_2; // @suppress("Type cannot be resolved") + PINT rsvd10_3; // @suppress("Type cannot be resolved") + PINT rsvd10_4; // @suppress("Type cannot be resolved") + PINT rsvd10_5; // @suppress("Type cannot be resolved") + PINT rsvd10_6; // @suppress("Type cannot be resolved") + PINT rsvd10_7; // @suppress("Type cannot be resolved") + PINT rsvd10_8; // @suppress("Type cannot be resolved") + +// Group 11 PIE Peripheral Vectors: + PINT rsvd11_1; // @suppress("Type cannot be resolved") + PINT rsvd11_2; // @suppress("Type cannot be resolved") + PINT rsvd11_3; // @suppress("Type cannot be resolved") + PINT rsvd11_4; // @suppress("Type cannot be resolved") + PINT rsvd11_5; // @suppress("Type cannot be resolved") + PINT rsvd11_6; // @suppress("Type cannot be resolved") + PINT rsvd11_7; // @suppress("Type cannot be resolved") + PINT rsvd11_8; // @suppress("Type cannot be resolved") + +// Group 12 PIE Peripheral Vectors: + PINT rsvd12_1; // @suppress("Type cannot be resolved") + PINT rsvd12_2; // @suppress("Type cannot be resolved") + PINT rsvd12_3; // @suppress("Type cannot be resolved") + PINT rsvd12_4; // @suppress("Type cannot be resolved") + PINT rsvd12_5; // @suppress("Type cannot be resolved") + PINT rsvd12_6; // @suppress("Type cannot be resolved") + PINT rsvd12_7; // @suppress("Type cannot be resolved") + PINT rsvd12_8; // @suppress("Type cannot be resolved") +}; + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table External References & Function Declarations: +// +extern struct PIE_VECT_TABLE PieVectTable; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_PIE_VECT_H definition + +//=========================================================================== +// No more. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h new file mode 100644 index 0000000..2a86da0 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Sci.h @@ -0,0 +1,233 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:19 $ +//########################################################################### +// +// FILE: DSP281x_Sci.h +// +// TITLE: DSP281x Device SCI Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SCI_H +#define DSP281x_SCI_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- +// SCI Individual Register Bit Definitions + +//---------------------------------------------------------- +// SCICCR communication control register bit definitions: +// + +struct SCICCR_BITS { // bit description + Uint16 SCICHAR:3; // 2:0 Character length control + Uint16 ADDRIDLE_MODE:1; // 3 ADDR/IDLE Mode control + Uint16 LOOPBKENA:1; // 4 Loop Back enable + Uint16 PARITYENA:1; // 5 Parity enable + Uint16 PARITY:1; // 6 Even or Odd Parity + Uint16 STOPBITS:1; // 7 Number of Stop Bits + Uint16 rsvd1:8; // 15:8 reserved +}; + + +union SCICCR_REG { + Uint16 all; + struct SCICCR_BITS bit; +}; + +//------------------------------------------- +// SCICTL1 control register 1 bit definitions: +// + +struct SCICTL1_BITS { // bit description + Uint16 RXENA:1; // 0 SCI receiver enable + Uint16 TXENA:1; // 1 SCI transmitter enable + Uint16 SLEEP:1; // 2 SCI sleep + Uint16 TXWAKE:1; // 3 Transmitter wakeup method + Uint16 rsvd:1; // 4 reserved + Uint16 SWRESET:1; // 5 Software reset + Uint16 RXERRINTENA:1; // 6 Recieve interrupt enable + Uint16 rsvd1:9; // 15:7 reserved + +}; + +union SCICTL1_REG { + Uint16 all; + struct SCICTL1_BITS bit; +}; + +//--------------------------------------------- +// SCICTL2 control register 2 bit definitions: +// + +struct SCICTL2_BITS { // bit description + Uint16 TXINTENA:1; // 0 Transmit interrupt enable + Uint16 RXBKINTENA:1; // 1 Receiver-buffer break enable + Uint16 rsvd:4; // 5:2 reserved + Uint16 TXEMPTY:1; // 6 Transmitter empty flag + Uint16 TXRDY:1; // 7 Transmitter ready flag + Uint16 rsvd1:8; // 15:8 reserved + +}; + +union SCICTL2_REG { + Uint16 all; + struct SCICTL2_BITS bit; +}; + +//--------------------------------------------------- +// SCIRXST Receiver status register bit definitions: +// + +struct SCIRXST_BITS { // bit description + Uint16 rsvd:1; // 0 reserved + Uint16 RXWAKE:1; // 1 Receiver wakeup detect flag + Uint16 PE:1; // 2 Parity error flag + Uint16 OE:1; // 3 Overrun error flag + Uint16 FE:1; // 4 Framing error flag + Uint16 BRKDT:1; // 5 Break-detect flag + Uint16 RXRDY:1; // 6 Receiver ready flag + Uint16 RXERROR:1; // 7 Receiver error flag + +}; + +union SCIRXST_REG { + Uint16 all; + struct SCIRXST_BITS bit; +}; + +//---------------------------------------------------- +// SCIRXBUF Receiver Data Buffer with FIFO bit definitions: +// + +struct SCIRXBUF_BITS { // bits description + Uint16 RXDT:8; // 7:0 Receive word + Uint16 rsvd:6; // 13:8 reserved + Uint16 SCIFFPE:1; // 14 SCI PE error in FIFO mode + Uint16 SCIFFFE:1; // 15 SCI FE error in FIFO mode +}; + +union SCIRXBUF_REG { + Uint16 all; + struct SCIRXBUF_BITS bit; +}; + +//-------------------------------------------------- +// SCIPRI Priority control register bit definitions: +// +// + +struct SCIPRI_BITS { // bit description + Uint16 rsvd:3; // 2:0 reserved + Uint16 FREE:1; // 3 Free emulation suspend mode + Uint16 SOFT:1; // 4 Soft emulation suspend mode + Uint16 rsvd1:3; // 7:5 reserved +}; + +union SCIPRI_REG { + Uint16 all; + struct SCIPRI_BITS bit; +}; + +//------------------------------------------------- +// SCI FIFO Transmit register bit definitions: +// +// + +struct SCIFFTX_BITS { // bit description + Uint16 TXFFILIL:5; // 4:0 Interrupt level + Uint16 TXFFIENA:1; // 5 Interrupt enable + Uint16 TXINTCLR:1; // 6 Clear INT flag + Uint16 TXFFINT:1; // 7 INT flag + Uint16 TXFFST:5; // 12:8 FIFO status + Uint16 TXFIFOXRESET:1; // 13 FIFO reset + Uint16 SCIFFENA:1; // 14 Enhancement enable + Uint16 SCIRST:1; // 15 SCI reset rx/tx channels + +}; + +union SCIFFTX_REG { + Uint16 all; + struct SCIFFTX_BITS bit; +}; + +//------------------------------------------------ +// SCI FIFO recieve register bit definitions: +// +// + +struct SCIFFRX_BITS { // bits description + Uint16 RXFFIL:5; // 4:0 Interrupt level + Uint16 RXFFIENA:1; // 5 Interrupt enable + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + Uint16 RXFFINT:1; // 7 INT flag + Uint16 RXFIFST:5; // 12:8 FIFO status + Uint16 RXFIFORESET:1; // 13 FIFO reset + Uint16 RXFFOVRCLR:1; // 14 Clear overflow + Uint16 RXFFOVF:1; // 15 FIFO overflow + +}; + +union SCIFFRX_REG { + Uint16 all; + struct SCIFFRX_BITS bit; +}; + +// SCI FIFO control register bit definitions: +struct SCIFFCT_BITS { // bits description + Uint16 FFTXDLY:8; // 7:0 FIFO transmit delay + Uint16 rsvd:5; // 12:8 reserved + Uint16 CDC:1; // 13 Auto baud mode enable + Uint16 ABDCLR:1; // 14 Auto baud clear + Uint16 ABD:1; // 15 Auto baud detect +}; + +union SCIFFCT_REG { + Uint16 all; + struct SCIFFCT_BITS bit; +}; + +//--------------------------------------------------------------------------- +// SCI Register File: +// +struct SCI_REGS { + union SCICCR_REG SCICCR; // Communications control register + union SCICTL1_REG SCICTL1; // Control register 1 + Uint16 SCIHBAUD; // Baud rate (high) register + Uint16 SCILBAUD; // Baud rate (low) register + union SCICTL2_REG SCICTL2; // Control register 2 + union SCIRXST_REG SCIRXST; // Recieve status register + Uint16 SCIRXEMU; // Recieve emulation buffer register + union SCIRXBUF_REG SCIRXBUF; // Recieve data buffer + Uint16 rsvd1; // reserved + Uint16 SCITXBUF; // Transmit data buffer + union SCIFFTX_REG SCIFFTX; // FIFO transmit register + union SCIFFRX_REG SCIFFRX; // FIFO recieve register + union SCIFFCT_REG SCIFFCT; // FIFO control register + Uint16 rsvd2; // reserved + Uint16 rsvd3; // reserved + union SCIPRI_REG SCIPRI; // FIFO Priority control +}; + +//--------------------------------------------------------------------------- +// SCI External References & Function Declarations: +// +extern volatile struct SCI_REGS SciaRegs; +extern volatile struct SCI_REGS ScibRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_SCI_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h new file mode 100644 index 0000000..a5c29ab --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Spi.h @@ -0,0 +1,183 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:16 $ +//########################################################################### +// +// FILE: DSP281x_Spi.h +// +// TITLE: DSP281x Device SPI Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SPI_H +#define DSP281x_SPI_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// SPI Individual Register Bit Definitions: +// +// SPI FIFO Transmit register bit definitions: +struct SPIFFTX_BITS { // bit description + Uint16 TXFFIL:5; // 4:0 Interrupt level + Uint16 TXFFIENA:1; // 5 Interrupt enable + Uint16 TXFFINTCLR:1; // 6 Clear INT flag + Uint16 TXFFINT:1; // 7 INT flag + Uint16 TXFFST:5; // 12:8 FIFO status + Uint16 TXFIFO:1; // 13 FIFO reset + Uint16 SPIFFENA:1; // 14 Enhancement enable + Uint16 SPIRST:1; // 15 Reset SPI +}; + +union SPIFFTX_REG { + Uint16 all; + struct SPIFFTX_BITS bit; +}; + +//-------------------------------------------- +// SPI FIFO recieve register bit definitions: +// +// +struct SPIFFRX_BITS { // bits description + Uint16 RXFFIL:5; // 4:0 Interrupt level + Uint16 RXFFIENA:1; // 5 Interrupt enable + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + Uint16 RXFFINT:1; // 7 INT flag + Uint16 RXFFST:5; // 12:8 FIFO status + Uint16 RXFIFORESET:1; // 13 FIFO reset + Uint16 RXFFOVFCLR:1; // 14 Clear overflow + Uint16 RXFFOVF:1; // 15 FIFO overflow + +}; + +union SPIFFRX_REG { + Uint16 all; + struct SPIFFRX_BITS bit; +}; + +//-------------------------------------------- +// SPI FIFO control register bit definitions: +// +// +struct SPIFFCT_BITS { // bits description + Uint16 TXDLY:8; // 7:0 FIFO transmit delay + Uint16 rsvd:8; // 15:8 reserved +}; + +union SPIFFCT_REG { + Uint16 all; + struct SPIFFCT_BITS bit; +}; + +//--------------------------------------------- +// SPI configuration register bit definitions: +// +// +struct SPICCR_BITS { // bits description + Uint16 SPICHAR:4; // 3:0 Character length control + Uint16 SPILBK:1; // 4 Loop-back enable/disable + Uint16 rsvd1:1; // 5 reserved + Uint16 CLKPOLARITY:1; // 6 Clock polarity + Uint16 SPISWRESET:1; // 7 SPI SW Reset + Uint16 rsvd2:8; // 15:8 reserved +}; + +union SPICCR_REG { + Uint16 all; + struct SPICCR_BITS bit; +}; + +//------------------------------------------------- +// SPI operation control register bit definitions: +// +// +struct SPICTL_BITS { // bits description + Uint16 SPIINTENA:1; // 0 Interrupt enable + Uint16 TALK:1; // 1 Master/Slave transmit enable + Uint16 MASTER_SLAVE:1; // 2 Network control mode + Uint16 CLK_PHASE:1; // 3 Clock phase select + Uint16 OVERRUNINTENA:1; // 4 Overrun interrupt enable + Uint16 rsvd:11; // 15:5 reserved +}; + +union SPICTL_REG { + Uint16 all; + struct SPICTL_BITS bit; +}; + +//-------------------------------------- +// SPI status register bit definitions: +// +// +struct SPISTS_BITS { // bits description + Uint16 rsvd1:5; // 4:0 reserved + Uint16 BUFFULL_FLAG:1; // 5 SPI transmit buffer full flag + Uint16 INT_FLAG:1; // 6 SPI interrupt flag + Uint16 OVERRUN_FLAG:1; // 7 SPI reciever overrun flag + Uint16 rsvd2:8; // 15:8 reserved +}; + +union SPISTS_REG { + Uint16 all; + struct SPISTS_BITS bit; +}; + +//------------------------------------------------ +// SPI priority control register bit definitions: +// +// +struct SPIPRI_BITS { // bits description + Uint16 rsvd1:4; // 3:0 reserved + Uint16 FREE:1; // 4 Free emulation mode control + Uint16 SOFT:1; // 5 Soft emulation mode control + Uint16 PRIORITY:1; // 6 Interrupt priority select + Uint16 rsvd2:9; // 15:7 reserved +}; + +union SPIPRI_REG { + Uint16 all; + struct SPIPRI_BITS bit; +}; + +//--------------------------------------------------------------------------- +// SPI Register File: +// +struct SPI_REGS { + union SPICCR_REG SPICCR; // Configuration register + union SPICTL_REG SPICTL; // Operation control register + union SPISTS_REG SPISTS; // Status register + Uint16 rsvd1; // reserved + Uint16 SPIBRR; // Baud Rate + Uint16 rsvd2; // reserved + Uint16 SPIRXEMU; // Emulation buffer + Uint16 SPIRXBUF; // Serial input buffer + Uint16 SPITXBUF; // Serial output buffer + Uint16 SPIDAT; // Serial data + union SPIFFTX_REG SPIFFTX; // FIFO transmit register + union SPIFFRX_REG SPIFFRX; // FIFO recieve register + union SPIFFCT_REG SPIFFCT; // FIFO control register + Uint16 rsvd3[2]; // reserved + union SPIPRI_REG SPIPRI; // FIFO Priority control +}; + +//--------------------------------------------------------------------------- +// SPI External References & Function Declarations: +// +extern volatile struct SPI_REGS SpiaRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_SPI_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h new file mode 100644 index 0000000..6700f62 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_SysCtrl.h @@ -0,0 +1,325 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 16, 2007 13:58:47 $ +//########################################################################### +// +// FILE: DSP281x_SysCtrl.h +// +// TITLE: DSP281x Device System Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_SYS_CTRL_H +#define DSP281x_SYS_CTRL_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +//--------------------------------------------------------------------------- +// System Control Individual Register Bit Definitions: +// +// High speed peripheral clock register bit definitions: +struct HISPCP_BITS { // bits description + Uint16 HSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + Uint16 rsvd1:13; // 15:3 reserved +}; + +union HISPCP_REG { + Uint16 all; + struct HISPCP_BITS bit; +}; + +// Low speed peripheral clock register bit definitions: +struct LOSPCP_BITS { // bits description + Uint16 LSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + Uint16 rsvd1:13; // 15:3 reserved +}; + +union LOSPCP_REG { + Uint16 all; + struct LOSPCP_BITS bit; +}; + +// Peripheral clock control register bit definitions: +struct PCLKCR_BITS { // bits description + Uint16 EVAENCLK:1; // 0 Enable high speed clk to EV-A + Uint16 EVBENCLK:1; // 1 Enable high speed clk to EV-B + Uint16 rsvd1:1; // 2 + Uint16 ADCENCLK:1; // 3 Enable high speed clk to ADC + Uint16 rsvd2:4; // 7:4 reserved + Uint16 SPIENCLK:1; // 8 Enable low speed clk to SPI + Uint16 rsvd3:1; // 9 reserved + Uint16 SCIAENCLK:1; // 10 Enable low speed clk to SCI-A + Uint16 SCIBENCLK:1; // 11 Enable low speed clk to SCI-B + Uint16 MCBSPENCLK:1; // 12 Enable low speed clk to McBSP + Uint16 rsvd4:1; // 13 reserved + Uint16 ECANENCLK:1; // 14 Enable system clk to eCAN +}; + +union PCLKCR_REG { + Uint16 all; + struct PCLKCR_BITS bit; +}; + +// PLL control register bit definitions: +struct PLLCR_BITS { // bits description + Uint16 DIV:4; // 3:0 Set clock ratio for the PLL + Uint16 rsvd1:12; // 15:4 reserved +}; + +union PLLCR_REG { + Uint16 all; + struct PLLCR_BITS bit; +}; + +// Low Power Mode 0 control register bit definitions: +struct LPMCR0_BITS { // bits description + Uint16 LPM:2; // 1:0 Set the low power mode + Uint16 QUALSTDBY:6; // 7:2 Qualification + Uint16 rsvd1:8; // 15:8 reserved +}; + +union LPMCR0_REG { + Uint16 all; + struct LPMCR0_BITS bit; +}; + +// Low Power Mode 1 control register bit definitions: +struct LPMCR1_BITS { // bits description + Uint16 XINT1:1; // 0 Enable XINT1 to wake the device from standby + Uint16 XNMI:1; // 1 Enable XMNI to wake the device from standby + Uint16 WDINT:1; // 2 Enable watchdog interrupt to wake the device from standby + Uint16 T1CTRIP:1; // 3 Enable T1CTRIP to wake the device from standby + Uint16 T2CTRIP:1; // 4 Enable T2CTRIP to wake the device from standby + Uint16 T3CTRIP:1; // 5 Enable T3CTRIP to wake the device from standby + Uint16 T4CTRIP:1; // 6 Enable T4CTRIP to wake the device from standby + Uint16 C1TRIP:1; // 7 Enable C1TRIP to wake the device from standby + Uint16 C2TRIP:1; // 8 Enable C2TRIP to wake the device from standby + Uint16 C3TRIP:1; // 9 Enable C3TRIP to wake the device from standby + Uint16 C4TRIP:1; // 10 Enable C4TRIP to wake the device from standby + Uint16 C5TRIP:1; // 11 Enable C5TRIP to wake the device from standby + Uint16 C6TRIP:1; // 12 Enable C6TRIP to wake the device from standby + Uint16 SCIRXA:1; // 13 Enable SCIRXA to wake the device from standby + Uint16 SCIRXB:1; // 14 Enable SCIRXB to wake the device from standby + Uint16 CANRX:1; // 15 Enable CANRX to wake the device from standby +}; + +union LPMCR1_REG { + Uint16 all; + struct LPMCR1_BITS bit; +}; + +//--------------------------------------------------------------------------- +// System Control Register File: +// +struct SYS_CTRL_REGS { + Uint16 rsvd1[10]; // 0-9 + union HISPCP_REG HISPCP; // 10: High-speed peripheral clock pre-scaler + union LOSPCP_REG LOSPCP; // 11: Low-speed peripheral clock pre-scaler + union PCLKCR_REG PCLKCR; // 12: Peripheral clock control register + Uint16 rsvd2; // 13: reserved + union LPMCR0_REG LPMCR0; // 14: Low-power mode control register 0 + union LPMCR1_REG LPMCR1; // 15: Low-power mode control register 1 + Uint16 rsvd3; // 16: reserved + union PLLCR_REG PLLCR; // 17: PLL control register + // No bit definitions are defined for SCSR because + // a read-modify-write instruction can clear the WDOVERRIDE bit + Uint16 SCSR; // 18: System control and status register + Uint16 WDCNTR; // 19: WD counter register + Uint16 rsvd4; // 20 + Uint16 WDKEY; // 21: WD reset key register + Uint16 rsvd5[3]; // 22-24 + // No bit definitions are defined for WDCR because + // the proper value must be written to the WDCHK field + // whenever writing to this register. + Uint16 WDCR; // 25: WD timer control register + Uint16 rsvd6[6]; // 26-31 +}; + + +/* --------------------------------------------------- */ +/* CSM Registers */ +/* */ +/* ----------------------------------------------------*/ + +/* CSM Status & Control register bit definitions */ +struct CSMSCR_BITS { // bit description + Uint16 SECURE:1; // 0 Secure flag + Uint16 rsvd1:14; // 14-1 reserved + Uint16 FORCESEC:1; // 15 Force Secure control bit + +}; + +/* Allow access to the bit fields or entire register */ +union CSMSCR_REG { + Uint16 all; + struct CSMSCR_BITS bit; +}; + +/* CSM Register File */ +struct CSM_REGS { + Uint16 KEY0; // KEY reg bits 15-0 + Uint16 KEY1; // KEY reg bits 31-16 + Uint16 KEY2; // KEY reg bits 47-32 + Uint16 KEY3; // KEY reg bits 63-48 + Uint16 KEY4; // KEY reg bits 79-64 + Uint16 KEY5; // KEY reg bits 95-80 + Uint16 KEY6; // KEY reg bits 111-96 + Uint16 KEY7; // KEY reg bits 127-112 + Uint16 rsvd1; // reserved + Uint16 rsvd2; // reserved + Uint16 rsvd3; // reserved + Uint16 rsvd4; // reserved + Uint16 rsvd5; // reserved + Uint16 rsvd6; // reserved + Uint16 rsvd7; // reserved + union CSMSCR_REG CSMSCR; // CSM Status & Control register +}; + +/* Password locations */ +struct CSM_PWL { + Uint16 PSWD0; // PSWD bits 15-0 + Uint16 PSWD1; // PSWD bits 31-16 + Uint16 PSWD2; // PSWD bits 47-32 + Uint16 PSWD3; // PSWD bits 63-48 + Uint16 PSWD4; // PSWD bits 79-64 + Uint16 PSWD5; // PSWD bits 95-80 + Uint16 PSWD6; // PSWD bits 111-96 + Uint16 PSWD7; // PSWD bits 127-112 +}; + + + +/* Flash Registers */ + +#define FLASH_SLEEP 0x0000; +#define FLASH_STANDBY 0x0001; +#define FLASH_ACTIVE 0x0003; + + +/* Flash Option Register bit definitions */ +struct FOPT_BITS { // bit description + Uint16 ENPIPE:1; // 0 Enable Pipeline Mode + Uint16 rsvd:15; // 1-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FOPT_REG { + Uint16 all; + struct FOPT_BITS bit; +}; + +/* Flash Power Modes Register bit definitions */ +struct FPWR_BITS { // bit description + Uint16 PWR:2; // 0-1 Power Mode bits + Uint16 rsvd:14; // 2-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FPWR_REG { + Uint16 all; + struct FPWR_BITS bit; +}; + + +/* Flash Status Register bit definitions */ +struct FSTATUS_BITS { // bit description + Uint16 PWRS:2; // 0-1 Power Mode Status bits + Uint16 STDBYWAITS:1; // 2 Bank/Pump Sleep to Standby Wait Counter Status bits + Uint16 ACTIVEWAITS:1; // 3 Bank/Pump Standby to Active Wait Counter Status bits + Uint16 rsvd1:4; // 4-7 reserved + Uint16 V3STAT:1; // 8 VDD3V Status Latch bit + Uint16 rsvd2:7; // 9-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FSTATUS_REG { + Uint16 all; + struct FSTATUS_BITS bit; +}; + +/* Flash Sleep to Standby Wait Counter Register bit definitions */ +struct FSTDBYWAIT_BITS { // bit description + Uint16 STDBYWAIT:9; // 0-8 Bank/Pump Sleep to Standby Wait Count bits + Uint16 rsvd:7; // 9-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FSTDBYWAIT_REG { + Uint16 all; + struct FSTDBYWAIT_BITS bit; +}; + +/* Flash Standby to Active Wait Counter Register bit definitions */ +struct FACTIVEWAIT_BITS { // bit description + Uint16 ACTIVEWAIT:9; // 0-8 Bank/Pump Standby to Active Wait Count bits + Uint16 rsvd:7; // 9-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FACTIVEWAIT_REG { + Uint16 all; + struct FACTIVEWAIT_BITS bit; +}; + +/* Bank Read Access Wait State Register bit definitions */ +struct FBANKWAIT_BITS { // bit description + Uint16 RANDWAIT:4; // 0-3 Flash Random Read Wait State bits + Uint16 rsvd1:4; // 4-7 reserved + Uint16 PAGEWAIT:4; // 8-11 Flash Paged Read Wait State bits + Uint16 rsvd2:4; // 12-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FBANKWAIT_REG { + Uint16 all; + struct FBANKWAIT_BITS bit; +}; + +/* OTP Read Access Wait State Register bit definitions */ +struct FOTPWAIT_BITS { // bit description + Uint16 OTPWAIT:5; // 0-4 OTP Read Wait State bits + Uint16 rsvd:11; // 5-15 reserved +}; + +/* Allow access to the bit fields or entire register */ +union FOTPWAIT_REG { + Uint16 all; + struct FOTPWAIT_BITS bit; +}; + + +struct FLASH_REGS { + union FOPT_REG FOPT; // Option Register + Uint16 rsvd1; // reserved + union FPWR_REG FPWR; // Power Modes Register + union FSTATUS_REG FSTATUS; // Status Register + union FSTDBYWAIT_REG FSTDBYWAIT; // Pump/Bank Sleep to Standby Wait State Register + union FACTIVEWAIT_REG FACTIVEWAIT; // Pump/Bank Standby to Active Wait State Register + union FBANKWAIT_REG FBANKWAIT; // Bank Read Access Wait State Register + union FOTPWAIT_REG FOTPWAIT; // OTP Read Access Wait State Register +}; + +//--------------------------------------------------------------------------- +// System Control External References & Function Declarations: +// +extern volatile struct SYS_CTRL_REGS SysCtrlRegs; +extern volatile struct CSM_REGS CsmRegs; +extern volatile struct CSM_PWL CsmPwl; +extern volatile struct FLASH_REGS FlashRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_SYS_CTRL_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h new file mode 100644 index 0000000..7cb66d7 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_XIntrupt.h @@ -0,0 +1,78 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 28, 2005 14:57:07 $ +//########################################################################### +// +// FILE: DSP281x_XIntrupt.h +// +// TITLE: DSP281x Device External Interrupt Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_XINTRUPT_H +#define DSP281x_XINTRUPT_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------------- + +struct XINTCR_BITS { + Uint16 ENABLE:1; // 0 enable/disable + Uint16 rsvd1:1; // 1 reserved + Uint16 POLARITY:1; // 2 pos/neg triggered + Uint16 rsvd2:12; // 15:3 reserved +}; + +union XINTCR_REG { + Uint16 all; + struct XINTCR_BITS bit; +}; + +struct XNMICR_BITS { + Uint16 ENABLE:1; // 0 enable/disable + Uint16 SELECT:1; // 1 Timer 1 or XNMI connected to INT13 + Uint16 POLARITY:1; // 2 pos/neg triggered + Uint16 rsvd2:12; // 15:3 reserved +}; + +union XNMICR_REG { + Uint16 all; + struct XNMICR_BITS bit; +}; + + + + +//--------------------------------------------------------------------------- +// External Interrupt Register File: +// +struct XINTRUPT_REGS { + union XINTCR_REG XINT1CR; + union XINTCR_REG XINT2CR; + Uint16 rsvd1[5]; + union XNMICR_REG XNMICR; + Uint16 XINT1CTR; + Uint16 XINT2CTR; + Uint16 rsvd[5]; + Uint16 XNMICTR; +}; + +//--------------------------------------------------------------------------- +// External Interrupt References & Function Declarations: +// +extern volatile struct XINTRUPT_REGS XIntruptRegs; + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_XINTF_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h new file mode 100644 index 0000000..b394f72 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/include/DSP281x_Xintf.h @@ -0,0 +1,111 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 20, 2007 16:30:14 $ +//########################################################################### +// +// FILE: DSP281x_Xintf.h +// +// TITLE: DSP281x Device External Interface Register Definitions. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#ifndef DSP281x_XINTF_H +#define DSP281x_XINTF_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +// XINTF timing register bit definitions: +struct XTIMING_BITS { // bits description + Uint16 XWRTRAIL:2; // 1:0 Write access trail timing + Uint16 XWRACTIVE:3; // 4:2 Write access active timing + Uint16 XWRLEAD:2; // 6:5 Write access lead timing + Uint16 XRDTRAIL:2; // 8:7 Read access trail timing + Uint16 XRDACTIVE:3; // 11:9 Read access active timing + Uint16 XRDLEAD:2; // 13:12 Read access lead timing + Uint16 USEREADY:1; // 14 Extend access using HW waitstates + Uint16 READYMODE:1; // 15 Ready mode + Uint16 XSIZE:2; // 17:16 XINTF bus width - must be written as 11b + Uint16 rsvd1:4; // 21:18 reserved + Uint16 X2TIMING:1; // 22 Double lead/active/trail timing + Uint16 rsvd3:9; // 31:23 reserved +}; + +union XTIMING_REG { + Uint32 all; + struct XTIMING_BITS bit; +}; + +// XINTF control register bit definitions: +struct XINTCNF2_BITS { // bits description + Uint16 WRBUFF:2; // 1:0 Write buffer depth + Uint16 CLKMODE:1; // 2 Ratio for XCLKOUT with respect to XTIMCLK + Uint16 CLKOFF:1; // 3 Disable XCLKOUT + Uint16 rsvd1:2; // 5:4 reserved + Uint16 WLEVEL:2; // 7:6 Current level of the write buffer + Uint16 MPNMC:1; // 8 Micro-processor/micro-computer mode + Uint16 HOLD:1; // 9 Hold enable/disable + Uint16 HOLDS:1; // 10 Current state of HOLDn input + Uint16 HOLDAS:1; // 11 Current state of HOLDAn output + Uint16 rsvd2:4; // 15:12 reserved + Uint16 XTIMCLK:3; // 18:16 Ratio for XTIMCLK + Uint16 rsvd3:13; // 31:19 reserved +}; + +union XINTCNF2_REG { + Uint32 all; + struct XINTCNF2_BITS bit; +}; + +// XINTF bank switching register bit definitions: +struct XBANK_BITS { // bits description + Uint16 BANK:3; // 2:0 Zone for which banking is enabled + Uint16 BCYC:3; // 5:3 XTIMCLK cycles to add + Uint16 rsvd:10; // 15:6 reserved +}; + +union XBANK_REG { + Uint16 all; + struct XBANK_BITS bit; +}; + + +//--------------------------------------------------------------------------- +// XINTF Register File: +// +struct XINTF_REGS { + union XTIMING_REG XTIMING0; + union XTIMING_REG XTIMING1; + union XTIMING_REG XTIMING2; + Uint32 rsvd1[3]; + union XTIMING_REG XTIMING6; + union XTIMING_REG XTIMING7; + Uint32 rsvd2[2]; + union XINTCNF2_REG XINTCNF2; + Uint32 rsvd3; + union XBANK_REG XBANK; + Uint16 rsvd4; + Uint16 XREVISION; + Uint16 rsvd5[5]; +}; + +//--------------------------------------------------------------------------- +// XINTF External References & Function Declarations: +// +extern volatile struct XINTF_REGS XintfRegs; + + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif // end of DSP281x_XINTF_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c new file mode 100644 index 0000000..63bdc48 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_CpuTimers.c @@ -0,0 +1,109 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: July 9, 2009 10:51:58 $ +//########################################################################### +// +// FILE: DSP281x_CpuTimers.c +// +// TITLE: CPU 32-bit Timers Initialization & Support Functions. +// +// NOTES: CpuTimer2 is reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use these this timer in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // Headerfile Include File +#include "DSP281x_Examples.h" // Examples Include File +#include "DSP281x_CpuTimers.h" +struct CPUTIMER_VARS CpuTimer0; + +// When using DSP BIOS & other RTOS, comment out CPU Timer 2 code. +struct CPUTIMER_VARS CpuTimer1; +struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// InitCpuTimers: +//--------------------------------------------------------------------------- +// This function initializes all three CPU timers to a known state. +// +void InitCpuTimers(void) +{ + // CPU Timer 0 + // Initialize address pointers to respective timer registers: + CpuTimer0.RegsAddr = &CpuTimer0Regs; + // Initialize timer period to maximum: + CpuTimer0Regs.PRD.all = 0xFFFFFFFF; + // Initialize pre-scale counter to divide by 1 (SYSCLKOUT): + CpuTimer0Regs.TPR.all = 0; + CpuTimer0Regs.TPRH.all = 0; + // Make sure timer is stopped: + CpuTimer0Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + CpuTimer0Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + CpuTimer0.InterruptCount = 0; + + +// CpuTimer2 is reserved for DSP BIOS & other RTOS +// Do not use this timer if you ever plan on integrating +// DSP-BIOS or another realtime OS. + + // Initialize address pointers to respective timer registers: + CpuTimer1.RegsAddr = &CpuTimer1Regs; + CpuTimer2.RegsAddr = &CpuTimer2Regs; + // Initialize timer period to maximum: + CpuTimer1Regs.PRD.all = 0xFFFFFFFF; + CpuTimer2Regs.PRD.all = 0xFFFFFFFF; + // Make sure timers are stopped: + CpuTimer1Regs.TCR.bit.TSS = 1; + CpuTimer2Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + CpuTimer1Regs.TCR.bit.TRB = 1; + CpuTimer2Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + CpuTimer1.InterruptCount = 0; + CpuTimer2.InterruptCount = 0; + +} + +//--------------------------------------------------------------------------- +// ConfigCpuTimer: +//--------------------------------------------------------------------------- +// This function initializes the selected timer to the period specified +// by the "Freq" and "Period" parameters. The "Freq" is entered as "MHz" +// and the period in "uSeconds". The timer is held in the stopped state +// after configuration. +// +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period) +{ + Uint32 temp; + + // Initialize timer period: + Timer->CPUFreqInMHz = Freq; + Timer->PeriodInUSec = Period; + temp = (long) (Freq * Period); + Timer->RegsAddr->PRD.all = temp; + + // Set pre-scale counter to divide by 1 (SYSCLKOUT): + Timer->RegsAddr->TPR.all = 0; + Timer->RegsAddr->TPRH.all = 0; + + // Initialize timer control register: + Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 = Start/Restart Timer + Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer + Timer->RegsAddr->TCR.bit.SOFT = 1; + Timer->RegsAddr->TCR.bit.FREE = 1; // Timer Free Run + Timer->RegsAddr->TCR.bit.TIE = 1; // 0 = Disable/ 1 = Enable Timer Interrupt + + // Reset interrupt counter: + Timer->InterruptCount = 0; +} + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c new file mode 100644 index 0000000..cdd93b0 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c @@ -0,0 +1,265 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: July 9, 2009 17:28:45 $ +//########################################################################### +// +// FILE: DSP281x_GlobalVariableDefs.c +// +// TITLE: DSP281x Global Variables and Data Section Pragmas. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // DSP281x Headerfile Include File + +//--------------------------------------------------------------------------- +// Define Global Peripheral Variables: +// + +#ifdef __cplusplus +#pragma DATA_SECTION("AdcRegsFile") +#else +#pragma DATA_SECTION(AdcRegs,"AdcRegsFile"); +#endif +volatile struct ADC_REGS AdcRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("CpuTimer0RegsFile") +#else +#pragma DATA_SECTION(CpuTimer0Regs,"CpuTimer0RegsFile"); +#endif +volatile struct CPUTIMER_REGS CpuTimer0Regs; +//---------------------------------------- + +#ifdef __cplusplus +#pragma DATA_SECTION("CpuTimer1RegsFile") +#else +#pragma DATA_SECTION(CpuTimer1Regs,"CpuTimer1RegsFile"); +#endif +volatile struct CPUTIMER_REGS CpuTimer1Regs; +//---------------------------------------- + +#ifdef __cplusplus +#pragma DATA_SECTION("CpuTimer2RegsFile") +#else +#pragma DATA_SECTION(CpuTimer2Regs,"CpuTimer2RegsFile"); +#endif +volatile struct CPUTIMER_REGS CpuTimer2Regs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaRegsFile") +#else +#pragma DATA_SECTION(ECanaRegs,"ECanaRegsFile"); +#endif +volatile struct ECAN_REGS ECanaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaMboxesFile") +#else +#pragma DATA_SECTION(ECanaMboxes,"ECanaMboxesFile"); +#endif +volatile struct ECAN_MBOXES ECanaMboxes; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaLAMRegsFile") +#else +#pragma DATA_SECTION(ECanaLAMRegs,"ECanaLAMRegsFile"); +#endif +volatile struct LAM_REGS ECanaLAMRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaMOTSRegsFile") +#else +#pragma DATA_SECTION(ECanaMOTSRegs,"ECanaMOTSRegsFile"); +#endif +volatile struct MOTS_REGS ECanaMOTSRegs; + + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ECanaMOTORegsFile") +#else +#pragma DATA_SECTION(ECanaMOTORegs,"ECanaMOTORegsFile"); +#endif +volatile struct MOTO_REGS ECanaMOTORegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("EvaRegsFile") +#else +#pragma DATA_SECTION(EvaRegs,"EvaRegsFile"); +#endif +volatile struct EVA_REGS EvaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("EvbRegsFile") +#else +#pragma DATA_SECTION(EvbRegs,"EvbRegsFile"); +#endif +volatile struct EVB_REGS EvbRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("GpioDataRegsFile") +#else +#pragma DATA_SECTION(GpioDataRegs,"GpioDataRegsFile"); +#endif +volatile struct GPIO_DATA_REGS GpioDataRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("GpioMuxRegsFile") +#else +#pragma DATA_SECTION(GpioMuxRegs,"GpioMuxRegsFile"); +#endif +volatile struct GPIO_MUX_REGS GpioMuxRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("McbspaRegsFile") +#else +#pragma DATA_SECTION(McbspaRegs,"McbspaRegsFile"); +#endif +volatile struct MCBSP_REGS McbspaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("PieCtrlRegsFile") +#else +#pragma DATA_SECTION(PieCtrlRegs,"PieCtrlRegsFile"); +#endif +volatile struct PIE_CTRL_REGS PieCtrlRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("PieVectTableFile") +#else +#pragma DATA_SECTION(PieVectTable,"PieVectTableFile"); +#endif +struct PIE_VECT_TABLE PieVectTable; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("SciaRegsFile") +#else +#pragma DATA_SECTION(SciaRegs,"SciaRegsFile"); +#endif +volatile struct SCI_REGS SciaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("ScibRegsFile") +#else +#pragma DATA_SECTION(ScibRegs,"ScibRegsFile"); +#endif +volatile struct SCI_REGS ScibRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("SpiaRegsFile") +#else +#pragma DATA_SECTION(SpiaRegs,"SpiaRegsFile"); +#endif +volatile struct SPI_REGS SpiaRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("SysCtrlRegsFile") +#else +#pragma DATA_SECTION(SysCtrlRegs,"SysCtrlRegsFile"); +#endif +volatile struct SYS_CTRL_REGS SysCtrlRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("DevEmuRegsFile") +#else +#pragma DATA_SECTION(DevEmuRegs,"DevEmuRegsFile"); +#endif +volatile struct DEV_EMU_REGS DevEmuRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("CsmRegsFile") +#else +#pragma DATA_SECTION(CsmRegs,"CsmRegsFile"); +#endif +volatile struct CSM_REGS CsmRegs; + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("CsmPwlFile") +#else +#pragma DATA_SECTION(CsmPwl,"CsmPwlFile"); +#endif +volatile struct CSM_PWL CsmPwl; + + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("FlashRegsFile") +#else +#pragma DATA_SECTION(FlashRegs,"FlashRegsFile"); +#endif +volatile struct FLASH_REGS FlashRegs; + +#if DSP28_F2812 +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("XintfRegsFile") +#else +#pragma DATA_SECTION(XintfRegs,"XintfRegsFile"); +#endif +volatile struct XINTF_REGS XintfRegs; +#endif + +//---------------------------------------- +#ifdef __cplusplus +#pragma DATA_SECTION("XIntruptRegsFile") +#else +#pragma DATA_SECTION(XIntruptRegs,"XIntruptRegsFile"); +#endif +volatile struct XINTRUPT_REGS XIntruptRegs; + + + +// The following are provided to support alternate notation +// that was used in an early version of the header files + +#define ADCRegs AdcRegs +#define CPUTimer0Regs CpuTimer0Regs +#define CPUTimer1Regs CpuTimer1Regs +#define CPUTimer2Regs CpuTimer2Regs +#define ECANARegs ECanaRegs +#define ECANAMboxes ECanaMboxes +#define EVARegs EvaRegs +#define GPIODataRegs GpioDataRegs +#define GPIOMuxRegs GpioMuxRegs +#define MCBSPARegs McbspaRegs +#define PIECtrlRegs PieCtrlRegs +#define PIEVectTable PieVectTable +#define SCIARegs SciaRegs +#define SCIBRegs ScibRegs +#define SYSCtrlRegs SysCtrlRegs +#define DEVEmuRegs DevEmuRegs +#define CSMRegs CsmRegs +#define CSMPwl CsmPwl +#define FLASHRegs FlashRegs +#define XINTFRegs XintfRegs +#define XINTRUPTRegs XIntruptRegs + + + + + + + + + diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c new file mode 100644 index 0000000..8d38af6 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_PieCtrl.c @@ -0,0 +1,84 @@ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 29, 2005 11:09:05 $ +//########################################################################### +// +// FILE: DSP281x_PieCtrl.c +// +// TITLE: DSP281x Device PIE Control Register Initialization Functions. +// + +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // DSP281x Headerfile Include File +#include "DSP281x_Examples.h" // DSP281x Examples Include File + +//--------------------------------------------------------------------------- +// InitPieCtrl: +//--------------------------------------------------------------------------- +// This function initializes the PIE control registers to a known state. +// +void InitPieCtrl(void) +{ + // Disable Interrupts at the CPU level: + DINT; + + // Disable the PIE + PieCtrlRegs.PIECRTL.bit.ENPIE = 0; + + // Clear all PIEIER registers: + PieCtrlRegs.PIEIER1.all = 0; + PieCtrlRegs.PIEIER2.all = 0; + PieCtrlRegs.PIEIER3.all = 0; + PieCtrlRegs.PIEIER4.all = 0; + PieCtrlRegs.PIEIER5.all = 0; + PieCtrlRegs.PIEIER6.all = 0; + PieCtrlRegs.PIEIER7.all = 0; + PieCtrlRegs.PIEIER8.all = 0; + PieCtrlRegs.PIEIER9.all = 0; + PieCtrlRegs.PIEIER10.all = 0; + PieCtrlRegs.PIEIER11.all = 0; + PieCtrlRegs.PIEIER12.all = 0; + + // Clear all PIEIFR registers: + PieCtrlRegs.PIEIFR1.all = 0; + PieCtrlRegs.PIEIFR2.all = 0; + PieCtrlRegs.PIEIFR3.all = 0; + PieCtrlRegs.PIEIFR4.all = 0; + PieCtrlRegs.PIEIFR5.all = 0; + PieCtrlRegs.PIEIFR6.all = 0; + PieCtrlRegs.PIEIFR7.all = 0; + PieCtrlRegs.PIEIFR8.all = 0; + PieCtrlRegs.PIEIFR9.all = 0; + PieCtrlRegs.PIEIFR10.all = 0; + PieCtrlRegs.PIEIFR11.all = 0; + PieCtrlRegs.PIEIFR12.all = 0; + + +} + +//--------------------------------------------------------------------------- +// EnableInterrupts: +//--------------------------------------------------------------------------- +// This function enables the PIE module and CPU interrupts +// +void EnableInterrupts() +{ + + // Enable the PIE + PieCtrlRegs.PIECRTL.bit.ENPIE = 1; + + // Enables PIE to drive a pulse into the CPU + PieCtrlRegs.PIEACK.all = 0xFFFF; + + // Enable Interrupts at the CPU level + EINT; + +} + + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c new file mode 100644 index 0000000..9db37eb --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_SysCtrl.c @@ -0,0 +1,295 @@ +// TI File $Revision: /main/3 $ +// Checkin $Date: April 4, 2007 13:20:29 $ +//########################################################################### +// +// FILE: DSP281x_SysCtrl.c +// +// TITLE: DSP281x Device System Control Initialization & Support Functions. +// +// DESCRIPTION: +// +// Example initialization of system resources. +// +//########################################################################### +// $TI Release: DSP281x C/C++ Header Files V1.20 $ +// $Release Date: July 27, 2009 $ +//########################################################################### + +#include "DSP281x_Device.h" // DSP281x Headerfile Include File +#include "DSP281x_Examples.h" // DSP281x Examples Include File + +// Functions that will be run from RAM need to be assigned to +// a different section. This section will then be mapped to a load and +// run address using the linker cmd file. + +#pragma CODE_SECTION(InitFlash, "ramfuncs"); + +#pragma DATA_SECTION(HSPCLK,".fast_vars1"); +float SYSCLKOUT, LSPCLK, HSPCLK; + +//--------------------------------------------------------------------------- +// InitSysCtrl: +//--------------------------------------------------------------------------- +// This function initializes the System Control registers to a known state. +// - Disables the watchdog +// - Set the PLLCR for proper SYSCLKOUT frequency +// - Set the pre-scaler for the high and low frequency peripheral clocks +// - Enable the clocks to the peripherals + +void InitSysCtrl(void) +{ + +// On F2812/F2810 TMX samples prior to rev C this initialization was +// required. For Rev C and after this is no longer required +/* + EALLOW; + DevEmuRegs.M0RAMDFT = 0x0300; + DevEmuRegs.M1RAMDFT = 0x0300; + DevEmuRegs.L0RAMDFT = 0x0300; + DevEmuRegs.L1RAMDFT = 0x0300; + DevEmuRegs.H0RAMDFT = 0x0300; + EDIS; +*/ + // Disable the watchdog + DisableDog(); + + // Initialize the PLLCR to 0xA + InitPll(0xA); + + // Initialize the peripheral clocks + InitPeripheralClocks(); +} + + +//--------------------------------------------------------------------------- +// Example: InitFlash: +//--------------------------------------------------------------------------- +// This function initializes the Flash Control registers + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results + +void InitFlash(void) +{ + + + + EALLOW; + //Enable Flash Pipeline mode to improve performance + //of code executed from Flash. + FlashRegs.FOPT.bit.ENPIPE = 1; + + // CAUTION + //Minimum waitstates required for the flash operating + //at a given CPU rate must be characterized by TI. + //Refer to the datasheet for the latest information. + + //Set the Random Waitstate for the Flash + FlashRegs.FBANKWAIT.bit.RANDWAIT = 5; + + //Set the Paged Waitstate for the Flash + FlashRegs.FBANKWAIT.bit.PAGEWAIT = 5; + + // CAUTION + //Minimum cycles required to move between power states + //at a given CPU rate must be characterized by TI. + //Refer to the datasheet for the latest information. + + //For now use the default count + //Set number of cycles to transition from sleep to standby + FlashRegs.FSTDBYWAIT.bit.STDBYWAIT = 0x01FF; + + //Set number of cycles to transition from standby to active + FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT = 0x01FF; + +// new add!!! + + FlashRegs.FPWR.bit.PWR = 3; // Pump and bank set to active mode + FlashRegs.FSTATUS.bit.V3STAT = 1; // Clear the 3VSTAT bit + FlashRegs.FOTPWAIT.bit.OTPWAIT = 8; // OTP waitstates + +///////// + + EDIS; + + //Force a pipeline flush to ensure that the write to + //the last register configured occurs before returning. + + asm(" RPT #7 || NOP"); +} + + +//--------------------------------------------------------------------------- +// Example: KickDog: +//--------------------------------------------------------------------------- +// This function resets the watchdog timer. +// Enable this function for using KickDog in the application + +void KickDog(void) +{ + EALLOW; + SysCtrlRegs.WDKEY = 0x0055; + SysCtrlRegs.WDKEY = 0x00AA; + EDIS; +} + +//--------------------------------------------------------------------------- +// Example: DisableDog: +//--------------------------------------------------------------------------- +// This function disables the watchdog timer. + +void DisableDog(void) +{ + EALLOW; + SysCtrlRegs.WDCR= 0x0068; + EDIS; +} + +//--------------------------------------------------------------------------- +// Example: InitPll: +//--------------------------------------------------------------------------- +// This function initializes the PLLCR register. + +void InitPll(Uint16 val) +{ + float Val; + volatile Uint16 iVol; + + Val = (val)?val:1; + Val = XCLKIN * (Val / 2); + SYSCLKOUT = Val; + + + + if (SysCtrlRegs.PLLCR.bit.DIV != val) + { + EALLOW; + SysCtrlRegs.PLLCR.bit.DIV = val; + EDIS; + + // Optional: Wait for PLL to lock. + // During this time the CPU will switch to OSCCLK/2 until the PLL is + // stable. Once the PLL is stable the CPU will switch to the new PLL value. + // + // This switch time is 131072 CLKIN cycles as of Rev C silicon. + // + // Code is not required to sit and wait for the PLL to lock. + // However, if the code does anything that is timing critical, + // and requires the correct clock be locked, then it is best to + // wait until this switching has completed. + + // If this function is run from waitstated memory, then the loop count can + // be reduced as long as the minimum switch time is still met. + + // iVol is volatile so the compiler will not optimize this loop out + // + // The watchdog should be disabled before this loop, or fed within + // the loop. + + DisableDog(); + + // Wait lock cycles. + // Note, This loop is tuned to 0-waitstate RAM memory. If this + // function is run from wait-stated memory such as Flash or XINTF, + // then the number of times through the loop can be reduced + // accordingly. + for(iVol= 0; iVol< ( (131072/2)/12 ); iVol++) + { + + } + } +} + +//-------------------------------------------------------------------------- +// Example: InitPeripheralClocks: +//--------------------------------------------------------------------------- +// This function initializes the clocks to the peripheral modules. +// First the high and low clock prescalers are set +// Second the clocks are enabled to each peripheral. +// To reduce power, leave clocks to unused peripherals disabled +// Note: If a peripherals clock is not enabled then you cannot +// read or write to the registers for that peripheral + +void InitPeripheralClocks(void) +{ + float Val; + + EALLOW; +// HISPCP/LOSPCP prescale register settings, normally it will be set to default values + SysCtrlRegs.HISPCP.all = 0x002;//0x0002; + SysCtrlRegs.LOSPCP.all = 0x0000;//0x4 + + + Val = (SysCtrlRegs.HISPCP.all)? + SysCtrlRegs.HISPCP.all*2 : 1; + Val = SYSCLKOUT / Val; + + HSPCLK = Val; + + Val = (SysCtrlRegs.LOSPCP.all)? + SysCtrlRegs.LOSPCP.all*2 : 1; + Val = SYSCLKOUT / Val; + LSPCLK = Val; + +// Peripheral clock enables set for the selected peripherals. + SysCtrlRegs.PCLKCR.bit.EVAENCLK=1; + SysCtrlRegs.PCLKCR.bit.EVBENCLK=1; + SysCtrlRegs.PCLKCR.bit.SCIAENCLK=1; + SysCtrlRegs.PCLKCR.bit.SCIBENCLK=1; + SysCtrlRegs.PCLKCR.bit.MCBSPENCLK=1; + SysCtrlRegs.PCLKCR.bit.SPIENCLK=1; + SysCtrlRegs.PCLKCR.bit.ECANENCLK=1; + SysCtrlRegs.PCLKCR.bit.ADCENCLK=1; + EDIS; +} + +//--------------------------------------------------------------------------- +// Example: CsmUnlock: +//--------------------------------------------------------------------------- +// This function unlocks the CSM. User must replace 0xFFFF's with current +// password for the DSP. Returns 1 if unlock is successful. + +#define STATUS_FAIL 0 +#define STATUS_SUCCESS 1 + +Uint16 CsmUnlock() +{ + volatile Uint16 temp; + + // Load the key registers with the current password. The 0xFFFF's are dummy + // passwords. User should replace them with the correct password for the DSP. + + EALLOW; + CsmRegs.KEY0 = 0xFFFF; + CsmRegs.KEY1 = 0xFFFF; + CsmRegs.KEY2 = 0xFFFF; + CsmRegs.KEY3 = 0xFFFF; + CsmRegs.KEY4 = 0xFFFF; + CsmRegs.KEY5 = 0xFFFF; + CsmRegs.KEY6 = 0xFFFF; + CsmRegs.KEY7 = 0xFFFF; + EDIS; + + // Perform a dummy read of the password locations + // if they match the key values, the CSM will unlock + + temp = CsmPwl.PSWD0; + temp = CsmPwl.PSWD1; + temp = CsmPwl.PSWD2; + temp = CsmPwl.PSWD3; + temp = CsmPwl.PSWD4; + temp = CsmPwl.PSWD5; + temp = CsmPwl.PSWD6; + temp = CsmPwl.PSWD7; + + // If the CSM unlocked, return succes, otherwise return + // failure. + if (CsmRegs.CSMSCR.bit.SECURE == 0) return STATUS_SUCCESS; + else return STATUS_FAIL; + +} + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm new file mode 100644 index 0000000..e1b644e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f2812/source/DSP281x_usDelay.asm @@ -0,0 +1,71 @@ +;// TI File $Revision: /main/2 $ +;// Checkin $Date: April 29, 2005 11:01:42 $ +;//########################################################################### +;// +;// FILE: DSP281x_usDelay.asm +;// +;// TITLE: Simple delay function +;// +;// DESCRIPTION: +;// +;// This is a simple delay function that can be used to insert a specified +;// delay into code. +;// +;// This function is only accurate if executed from internal zero-waitstate +;// SARAM. If it is executed from waitstate memory then the delay will be +;// longer then specified. +;// +;// To use this function: +;// +;// 1 - update the CPU clock speed in the DSP281x_Examples.h +;// file. For example: +;// #define CPU_CLOCK_SPEED 6.6667L // for a 150MHz CPU clock speed +;// +;// 2 - Call this function by using the DELAY_US(A) macro +;// that is defined in the DSP28_Device.h file. This macro +;// will convert the number of microseconds specified +;// into a loop count for use with this function. +;// This count will be based on the CPU frequency you specify. +;// +;// 3 - For the most accurate delay +;// - Execute this function in 0 waitstate RAM. +;// - Disable interrupts before calling the function +;// If you do not disable interrupts, then think of +;// this as an "at least" delay function as the actual +;// delay may be longer. +;// +;// The C assembly call from the DELAY_US(time) macro will +;// look as follows: +;// +;// extern void Delay(long LoopCount); +;// +;// MOV AL,#LowLoopCount +;// MOV AH,#HighLoopCount +;// LCR _Delay +;// +;// Or as follows (if count is less then 16-bits): +;// +;// MOV ACC,#LoopCount +;// LCR _Delay +;// +;// +;//########################################################################### +;// $TI Release: DSP281x C/C++ Header Files V1.20 $ +;// $Release Date: July 27, 2009 $ +;//########################################################################### + .def _DSP28x_usDelay + .sect ".fast_run" + + .global __DSP28x_usDelay +_DSP28x_usDelay: + SUB ACC,#1 + BF _DSP28x_usDelay,GEQ ;; Loop if ACC >= 0 + LRETR + +;There is a 9/10 cycle overhead and each loop +;takes five cycles. The LoopCount is given by +;the following formula: +; DELAY_CPU_CYCLES = 9 + 5*LoopCount +; LoopCount = (DELAY_CPU_CYCLES - 9) / 5 +; The macro DELAY_US(A) performs this calculation for you +;================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd b/c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd new file mode 100644 index 0000000..d16ae33 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd @@ -0,0 +1,240 @@ +/* Поставляемое TI описание Headers_nonBIOS для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +/* +// TI File $Revision: /main/8 $ +// Checkin $Date: June 2, 2008 11:12:24 $ +//########################################################################### +// +// FILE: DSP2833x_Headers_nonBIOS.cmd +// +// TITLE: DSP2833x Peripheral registers linker command file +// +// DESCRIPTION: +// +// This file is for use in Non-BIOS applications. +// +// Linker command file to place the peripheral structures +// used within the DSP2833x headerfiles into the correct memory +// mapped locations. +// +// This version of the file includes the PieVectorTable structure. +// For BIOS applications, please use the DSP2833x_Headers_BIOS.cmd file +// which does not include the PieVectorTable structure. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### +*/ + +/* Начинает описание физических блоков памяти для линкера. */ +MEMORY +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + PAGE 0: /* Program Memory */ /* Выбирает страницу адресного пространства линкера: 0 — программа, 1 — данные. */ + + PAGE 1: /* Data Memory */ /* Выбирает страницу адресного пространства линкера: 0 — программа, 1 — данные. */ + + DEV_EMU : origin = 0x000880, length = 0x000180 /* device emulation registers */ /* Записывает origin значением 0x000880, length = 0x000180; данные origin. */ + FLASH_REGS : origin = 0x000A80, length = 0x000060 /* FLASH registers */ /* Записывает origin значением 0x000A80, length = 0x000060; данные origin. */ + CSM : origin = 0x000AE0, length = 0x000010 /* code security module registers */ /* Записывает origin значением 0x000AE0, length = 0x000010; данные origin. */ + + ADC_MIRROR : origin = 0x000B00, length = 0x000010 /* ADC Results register mirror */ /* Записывает origin значением 0x000B00, length = 0x000010; данные origin. */ + + XINTF : origin = 0x000B20, length = 0x000020 /* external interface registers */ /* Записывает origin значением 0x000B20, length = 0x000020; данные origin. */ + + CPU_TIMER0 : origin = 0x000C00, length = 0x000008 /* CPU Timer0 registers */ /* Записывает origin значением 0x000C00, length = 0x000008; данные origin. */ + CPU_TIMER1 : origin = 0x000C08, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ /* Записывает origin значением 0x000C08, length = 0x000008; данные origin. */ + CPU_TIMER2 : origin = 0x000C10, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ /* Записывает origin значением 0x000C10, length = 0x000008; данные origin. */ + + PIE_CTRL : origin = 0x000CE0, length = 0x000020 /* PIE control registers */ /* Записывает origin значением 0x000CE0, length = 0x000020; данные origin. */ + PIE_VECT : origin = 0x000D00, length = 0x000100 /* PIE Vector Table */ /* Записывает origin значением 0x000D00, length = 0x000100; данные origin. */ + + DMA : origin = 0x001000, length = 0x000200 /* DMA registers */ /* Записывает origin значением 0x001000, length = 0x000200; данные origin. */ + + MCBSPA : origin = 0x005000, length = 0x000040 /* McBSP-A registers */ /* Записывает origin значением 0x005000, length = 0x000040; данные origin. */ + MCBSPB : origin = 0x005040, length = 0x000040 /* McBSP-B registers */ /* Записывает origin значением 0x005040, length = 0x000040; данные origin. */ + + ECANA : origin = 0x006000, length = 0x000040 /* eCAN-A control and status registers */ /* Записывает origin значением 0x006000, length = 0x000040; данные origin. */ + ECANA_LAM : origin = 0x006040, length = 0x000040 /* eCAN-A local acceptance masks */ /* Записывает origin значением 0x006040, length = 0x000040; данные origin. */ + ECANA_MOTS : origin = 0x006080, length = 0x000040 /* eCAN-A message object time stamps */ /* Записывает origin значением 0x006080, length = 0x000040; данные origin. */ + ECANA_MOTO : origin = 0x0060C0, length = 0x000040 /* eCAN-A object time-out registers */ /* Записывает origin значением 0x0060C0, length = 0x000040; данные origin. */ + ECANA_MBOX : origin = 0x006100, length = 0x000100 /* eCAN-A mailboxes */ /* Записывает origin значением 0x006100, length = 0x000100; данные origin. */ + + ECANB : origin = 0x006200, length = 0x000040 /* eCAN-B control and status registers */ /* Записывает origin значением 0x006200, length = 0x000040; данные origin. */ + ECANB_LAM : origin = 0x006240, length = 0x000040 /* eCAN-B local acceptance masks */ /* Записывает origin значением 0x006240, length = 0x000040; данные origin. */ + ECANB_MOTS : origin = 0x006280, length = 0x000040 /* eCAN-B message object time stamps */ /* Записывает origin значением 0x006280, length = 0x000040; данные origin. */ + ECANB_MOTO : origin = 0x0062C0, length = 0x000040 /* eCAN-B object time-out registers */ /* Записывает origin значением 0x0062C0, length = 0x000040; данные origin. */ + ECANB_MBOX : origin = 0x006300, length = 0x000100 /* eCAN-B mailboxes */ /* Записывает origin значением 0x006300, length = 0x000100; данные origin. */ + + EPWM1 : origin = 0x006800, length = 0x000022 /* Enhanced PWM 1 registers */ /* Записывает origin значением 0x006800, length = 0x000022; данные origin. */ + EPWM2 : origin = 0x006840, length = 0x000022 /* Enhanced PWM 2 registers */ /* Записывает origin значением 0x006840, length = 0x000022; данные origin. */ + EPWM3 : origin = 0x006880, length = 0x000022 /* Enhanced PWM 3 registers */ /* Записывает origin значением 0x006880, length = 0x000022; данные origin. */ + EPWM4 : origin = 0x0068C0, length = 0x000022 /* Enhanced PWM 4 registers */ /* Записывает origin значением 0x0068C0, length = 0x000022; данные origin. */ + EPWM5 : origin = 0x006900, length = 0x000022 /* Enhanced PWM 5 registers */ /* Записывает origin значением 0x006900, length = 0x000022; данные origin. */ + EPWM6 : origin = 0x006940, length = 0x000022 /* Enhanced PWM 6 registers */ /* Записывает origin значением 0x006940, length = 0x000022; данные origin. */ + + ECAP1 : origin = 0x006A00, length = 0x000020 /* Enhanced Capture 1 registers */ /* Записывает origin значением 0x006A00, length = 0x000020; данные origin. */ + ECAP2 : origin = 0x006A20, length = 0x000020 /* Enhanced Capture 2 registers */ /* Записывает origin значением 0x006A20, length = 0x000020; данные origin. */ + ECAP3 : origin = 0x006A40, length = 0x000020 /* Enhanced Capture 3 registers */ /* Записывает origin значением 0x006A40, length = 0x000020; данные origin. */ + ECAP4 : origin = 0x006A60, length = 0x000020 /* Enhanced Capture 4 registers */ /* Записывает origin значением 0x006A60, length = 0x000020; данные origin. */ + ECAP5 : origin = 0x006A80, length = 0x000020 /* Enhanced Capture 5 registers */ /* Записывает origin значением 0x006A80, length = 0x000020; данные origin. */ + ECAP6 : origin = 0x006AA0, length = 0x000020 /* Enhanced Capture 6 registers */ /* Записывает origin значением 0x006AA0, length = 0x000020; данные origin. */ + + EQEP1 : origin = 0x006B00, length = 0x000040 /* Enhanced QEP 1 registers */ /* Записывает origin значением 0x006B00, length = 0x000040; данные origin. */ + EQEP2 : origin = 0x006B40, length = 0x000040 /* Enhanced QEP 2 registers */ /* Записывает origin значением 0x006B40, length = 0x000040; данные origin. */ + + GPIOCTRL : origin = 0x006F80, length = 0x000040 /* GPIO control registers */ /* Записывает origin значением 0x006F80, length = 0x000040; данные origin. */ + GPIODAT : origin = 0x006FC0, length = 0x000020 /* GPIO data registers */ /* Записывает origin значением 0x006FC0, length = 0x000020; данные origin. */ + GPIOINT : origin = 0x006FE0, length = 0x000020 /* GPIO interrupt/LPM registers */ /* Записывает origin значением 0x006FE0, length = 0x000020; данные origin. */ + + SYSTEM : origin = 0x007010, length = 0x000020 /* System control registers */ /* Записывает origin значением 0x007010, length = 0x000020; данные origin. */ + SPIA : origin = 0x007040, length = 0x000010 /* SPI-A registers */ /* Записывает origin значением 0x007040, length = 0x000010; данные origin. */ + SCIA : origin = 0x007050, length = 0x000010 /* SCI-A registers */ /* Записывает origin значением 0x007050, length = 0x000010; данные origin. */ + XINTRUPT : origin = 0x007070, length = 0x000010 /* external interrupt registers */ /* Записывает origin значением 0x007070, length = 0x000010; данные origin. */ + + ADC : origin = 0x007100, length = 0x000020 /* ADC registers */ /* Записывает origin значением 0x007100, length = 0x000020; данные origin. */ + + SCIB : origin = 0x007750, length = 0x000010 /* SCI-B registers */ /* Записывает origin значением 0x007750, length = 0x000010; данные origin. */ + + SCIC : origin = 0x007770, length = 0x000010 /* SCI-C registers */ /* Записывает origin значением 0x007770, length = 0x000010; данные origin. */ + + I2CA : origin = 0x007900, length = 0x000040 /* I2C-A registers */ /* Записывает origin значением 0x007900, length = 0x000040; данные origin. */ + + CSM_PWL : origin = 0x33FFF8, length = 0x000008 /* Part of FLASHA. CSM password locations. */ /* Записывает origin значением 0x33FFF8, length = 0x000008; данные origin. */ + + PARTID : origin = 0x380090, length = 0x000001 /* Part ID register location */ /* Записывает origin значением 0x380090, length = 0x000001; данные origin. */ +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +/* Начинает описание размещения секций объектных файлов для линкера. */ +SECTIONS +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Записывает PAGE значением 1; данные PAGE. */ + PieVectTableFile : > PIE_VECT, PAGE = 1 + +/*** Peripheral Frame 0 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + DevEmuRegsFile : > DEV_EMU, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + FlashRegsFile : > FLASH_REGS, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CsmRegsFile : > CSM, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + AdcMirrorFile : > ADC_MIRROR, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + XintfRegsFile : > XINTF, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + PieCtrlRegsFile : > PIE_CTRL, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + DmaRegsFile : > DMA, PAGE = 1 + +/*** Peripheral Frame 3 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + McbspaRegsFile : > MCBSPA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + McbspbRegsFile : > MCBSPB, PAGE = 1 + +/*** Peripheral Frame 1 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaRegsFile : > ECANA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaLAMRegsFile : > ECANA_LAM PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaMboxesFile : > ECANA_MBOX PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaMOTSRegsFile : > ECANA_MOTS PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanaMOTORegsFile : > ECANA_MOTO PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbRegsFile : > ECANB, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbLAMRegsFile : > ECANB_LAM PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbMboxesFile : > ECANB_MBOX PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbMOTSRegsFile : > ECANB_MOTS PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECanbMOTORegsFile : > ECANB_MOTO PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm1RegsFile : > EPWM1 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm2RegsFile : > EPWM2 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm3RegsFile : > EPWM3 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm4RegsFile : > EPWM4 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm5RegsFile : > EPWM5 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EPwm6RegsFile : > EPWM6 PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + ECap1RegsFile : > ECAP1 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap2RegsFile : > ECAP2 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap3RegsFile : > ECAP3 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap4RegsFile : > ECAP4 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap5RegsFile : > ECAP5 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ECap6RegsFile : > ECAP6 PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + EQep1RegsFile : > EQEP1 PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + EQep2RegsFile : > EQEP2 PAGE = 1 + + /* Записывает PAGE значением 1; данные PAGE. */ + GpioCtrlRegsFile : > GPIOCTRL PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + GpioDataRegsFile : > GPIODAT PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + GpioIntRegsFile : > GPIOINT PAGE = 1 + +/*** Peripheral Frame 2 Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + SysCtrlRegsFile : > SYSTEM, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + SpiaRegsFile : > SPIA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + SciaRegsFile : > SCIA, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + XIntruptRegsFile : > XINTRUPT, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + AdcRegsFile : > ADC, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ScibRegsFile : > SCIB, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + ScicRegsFile : > SCIC, PAGE = 1 + /* Записывает PAGE значением 1; данные PAGE. */ + I2caRegsFile : > I2CA, PAGE = 1 + +/*** Code Security Module Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + CsmPwlFile : > CSM_PWL, PAGE = 1 + +/*** Device Part ID Register Structures ***/ + /* Записывает PAGE значением 1; данные PAGE. */ + PartIdRegsFile : > PARTID, PAGE = 1 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +/* +//=========================================================================== +// End of file. +//=========================================================================== +*/ diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h new file mode 100644 index 0000000..648872d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_DefaultIsr.h @@ -0,0 +1,236 @@ +/* Поставляемое TI описание DefaultIsr для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:45:37 $ +//########################################################################### +// +// FILE: DSP2833x_DefaultIsr.h +// +// TITLE: DSP2833x Devices Default Interrupt Service Routines Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DEFAULT_ISR_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DEFAULT_ISR_H +/* Определяет защитный символ или переключатель DSP2833x_DEFAULT_ISR_H для последующей компиляции. */ +#define DSP2833x_DEFAULT_ISR_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// Default Interrupt Service Routine Declarations: +// +// The following function prototypes are for the +// default ISR routines used with the default PIE vector table. +// This default vector table is found in the DSP2833x_PieVect.h +// file. +// + +// Non-Peripheral Interrupts: +/* Объявляет обработчик INT13_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1 +/* Объявляет обработчик INT14_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void INT14_ISR(void); // CPU-Timer2 +/* Объявляет обработчик DATALOG_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DATALOG_ISR(void); // Datalogging interrupt +/* Объявляет обработчик RTOSINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void RTOSINT_ISR(void); // RTOS interrupt +/* Объявляет обработчик EMUINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EMUINT_ISR(void); // Emulation interrupt +/* Объявляет обработчик NMI_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void NMI_ISR(void); // Non-maskable interrupt +/* Объявляет обработчик ILLEGAL_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP +/* Объявляет обработчик USER1_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER1_ISR(void); // User Defined trap 1 +/* Объявляет обработчик USER2_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER2_ISR(void); // User Defined trap 2 +/* Объявляет обработчик USER3_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER3_ISR(void); // User Defined trap 3 +/* Объявляет обработчик USER4_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER4_ISR(void); // User Defined trap 4 +/* Объявляет обработчик USER5_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER5_ISR(void); // User Defined trap 5 +/* Объявляет обработчик USER6_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER6_ISR(void); // User Defined trap 6 +/* Объявляет обработчик USER7_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER7_ISR(void); // User Defined trap 7 +/* Объявляет обработчик USER8_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER8_ISR(void); // User Defined trap 8 +/* Объявляет обработчик USER9_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER9_ISR(void); // User Defined trap 9 +/* Объявляет обработчик USER10_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER10_ISR(void); // User Defined trap 10 +/* Объявляет обработчик USER11_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER11_ISR(void); // User Defined trap 11 +/* Объявляет обработчик USER12_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void USER12_ISR(void); // User Defined trap 12 + +// Group 1 PIE Interrupt Service Routines: +/* Объявляет обработчик SEQ1INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SEQ1INT_ISR(void); // ADC Sequencer 1 ISR +/* Объявляет обработчик SEQ2INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SEQ2INT_ISR(void); // ADC Sequencer 2 ISR +/* Объявляет обработчик XINT1_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT1_ISR(void); // External interrupt 1 +/* Объявляет обработчик XINT2_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT2_ISR(void); // External interrupt 2 +/* Объявляет обработчик ADCINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ADCINT_ISR(void); // ADC +/* Объявляет обработчик TINT0_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void TINT0_ISR(void); // Timer 0 +/* Объявляет обработчик WAKEINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void WAKEINT_ISR(void); // WD + +// Group 2 PIE Interrupt Service Routines: +/* Объявляет обработчик EPWM1_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM1_TZINT_ISR(void); // EPWM-1 +/* Объявляет обработчик EPWM2_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM2_TZINT_ISR(void); // EPWM-2 +/* Объявляет обработчик EPWM3_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM3_TZINT_ISR(void); // EPWM-3 +/* Объявляет обработчик EPWM4_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM4_TZINT_ISR(void); // EPWM-4 +/* Объявляет обработчик EPWM5_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM5_TZINT_ISR(void); // EPWM-5 +/* Объявляет обработчик EPWM6_TZINT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM6_TZINT_ISR(void); // EPWM-6 + +// Group 3 PIE Interrupt Service Routines: +/* Объявляет обработчик EPWM1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM1_INT_ISR(void); // EPWM-1 +/* Объявляет обработчик EPWM2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM2_INT_ISR(void); // EPWM-2 +/* Объявляет обработчик EPWM3_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM3_INT_ISR(void); // EPWM-3 +/* Объявляет обработчик EPWM4_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM4_INT_ISR(void); // EPWM-4 +/* Объявляет обработчик EPWM5_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM5_INT_ISR(void); // EPWM-5 +/* Объявляет обработчик EPWM6_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EPWM6_INT_ISR(void); // EPWM-6 + +// Group 4 PIE Interrupt Service Routines: +/* Объявляет обработчик ECAP1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP1_INT_ISR(void); // ECAP-1 +/* Объявляет обработчик ECAP2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP2_INT_ISR(void); // ECAP-2 +/* Объявляет обработчик ECAP3_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP3_INT_ISR(void); // ECAP-3 +/* Объявляет обработчик ECAP4_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP4_INT_ISR(void); // ECAP-4 +/* Объявляет обработчик ECAP5_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP5_INT_ISR(void); // ECAP-5 +/* Объявляет обработчик ECAP6_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAP6_INT_ISR(void); // ECAP-6 + +// Group 5 PIE Interrupt Service Routines: +/* Объявляет обработчик EQEP1_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EQEP1_INT_ISR(void); // EQEP-1 +/* Объявляет обработчик EQEP2_INT_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void EQEP2_INT_ISR(void); // EQEP-2 + +// Group 6 PIE Interrupt Service Routines: +/* Объявляет обработчик SPIRXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SPIRXINTA_ISR(void); // SPI-A +/* Объявляет обработчик SPITXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SPITXINTA_ISR(void); // SPI-A +/* Объявляет обработчик MRINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MRINTA_ISR(void); // McBSP-A +/* Объявляет обработчик MXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MXINTA_ISR(void); // McBSP-A +/* Объявляет обработчик MRINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MRINTB_ISR(void); // McBSP-B +/* Объявляет обработчик MXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void MXINTB_ISR(void); // McBSP-B + +// Group 7 PIE Interrupt Service Routines: +/* Объявляет обработчик DINTCH1_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH1_ISR(void); // DMA-Channel 1 +/* Объявляет обработчик DINTCH2_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH2_ISR(void); // DMA-Channel 2 +/* Объявляет обработчик DINTCH3_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH3_ISR(void); // DMA-Channel 3 +/* Объявляет обработчик DINTCH4_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH4_ISR(void); // DMA-Channel 4 +/* Объявляет обработчик DINTCH5_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH5_ISR(void); // DMA-Channel 5 +/* Объявляет обработчик DINTCH6_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void DINTCH6_ISR(void); // DMA-Channel 6 + +// Group 8 PIE Interrupt Service Routines: +/* Объявляет обработчик I2CINT1A_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void I2CINT1A_ISR(void); // I2C-A +/* Объявляет обработчик I2CINT2A_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void I2CINT2A_ISR(void); // I2C-A +/* Объявляет обработчик SCIRXINTC_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCIRXINTC_ISR(void); // SCI-C +/* Объявляет обработчик SCITXINTC_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCITXINTC_ISR(void); // SCI-C + +// Group 9 PIE Interrupt Service Routines: +/* Объявляет обработчик SCIRXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCIRXINTA_ISR(void); // SCI-A +/* Объявляет обработчик SCITXINTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCITXINTA_ISR(void); // SCI-A +/* Объявляет обработчик SCIRXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCIRXINTB_ISR(void); // SCI-B +/* Объявляет обработчик SCITXINTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void SCITXINTB_ISR(void); // SCI-B +/* Объявляет обработчик ECAN0INTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN0INTA_ISR(void); // eCAN-A +/* Объявляет обработчик ECAN1INTA_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN1INTA_ISR(void); // eCAN-A +/* Объявляет обработчик ECAN0INTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN0INTB_ISR(void); // eCAN-B +/* Объявляет обработчик ECAN1INTB_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void ECAN1INTB_ISR(void); // eCAN-B + +// Group 10 PIE Interrupt Service Routines: + +// Group 11 PIE Interrupt Service Routines: + +// Group 12 PIE Interrupt Service Routines: +/* Объявляет обработчик XINT3_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT3_ISR(void); // External interrupt 3 +/* Объявляет обработчик XINT4_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT4_ISR(void); // External interrupt 4 +/* Объявляет обработчик XINT5_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT5_ISR(void); // External interrupt 5 +/* Объявляет обработчик XINT6_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT6_ISR(void); // External interrupt 6 +/* Объявляет обработчик XINT7_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void XINT7_ISR(void); // External interrupt 7 +/* Объявляет обработчик LVF_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void LVF_ISR(void); // Latched overflow flag +/* Объявляет обработчик LUF_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void LUF_ISR(void); // Latched underflow flag + +// Catch-all for Reserved Locations For testing purposes: +/* Объявляет интерфейс функции PIE_RESERVED; реализация вызывается через этот прототип. */ +interrupt void PIE_RESERVED(void); // Reserved for test +/* Объявляет обработчик rsvd_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void rsvd_ISR(void); // for test +/* Объявляет обработчик INT_NOTUSED_ISR; обслуживает источник прерывания и его аппаратные флаги. */ +interrupt void INT_NOTUSED_ISR(void); // for unused interrupts + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DEFAULT_ISR_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h new file mode 100644 index 0000000..a327969 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Dma_defines.h @@ -0,0 +1,125 @@ +/* Поставляемое TI описание Dma_defines для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: August 14, 2007 16:32:29 $ +//########################################################################### +// +// FILE: DSP2833x_Dma_defines.h +// +// TITLE: #defines used in DMA examples +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DMA_DEFINES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DMA_DEFINES_H +/* Определяет защитный символ или переключатель DSP2833x_DMA_DEFINES_H для последующей компиляции. */ +#define DSP2833x_DMA_DEFINES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +// MODE +//========================== +// PERINTSEL bits +/* Задаёт DMA_SEQ1INT = 1; DMA 1 INT. */ +#define DMA_SEQ1INT 1 +/* Задаёт DMA_SEQ2INT = 2; DMA 2 INT. */ +#define DMA_SEQ2INT 2 +/* Задаёт DMA_XINT1 = 3; DMA 1. */ +#define DMA_XINT1 3 +/* Задаёт DMA_XINT2 = 4; DMA 2. */ +#define DMA_XINT2 4 +/* Задаёт DMA_XINT3 = 5; DMA 3. */ +#define DMA_XINT3 5 +/* Задаёт DMA_XINT4 = 6; DMA 4. */ +#define DMA_XINT4 6 +/* Задаёт DMA_XINT5 = 7; DMA 5. */ +#define DMA_XINT5 7 +/* Задаёт DMA_XINT6 = 8; DMA 6. */ +#define DMA_XINT6 8 +/* Задаёт DMA_XINT7 = 9; DMA 7. */ +#define DMA_XINT7 9 +/* Задаёт DMA_XINT13 = 10; DMA 13. */ +#define DMA_XINT13 10 +/* Задаёт DMA_TINT0 = 11; DMA 0. */ +#define DMA_TINT0 11 +/* Задаёт DMA_TINT1 = 12; DMA 1. */ +#define DMA_TINT1 12 +/* Задаёт DMA_TINT2 = 13; DMA 2. */ +#define DMA_TINT2 13 +/* Задаёт DMA_MXEVTA = 14; DMA MXEVTA. */ +#define DMA_MXEVTA 14 +/* Задаёт DMA_MREVTA = 15; DMA MREVTA. */ +#define DMA_MREVTA 15 +/* Задаёт DMA_MXREVTB = 16; DMA MXREVTB. */ +#define DMA_MXREVTB 16 +/* Задаёт DMA_MREVTB = 17; DMA MREVTB. */ +#define DMA_MREVTB 17 +// OVERINTE bit +/* Задаёт OVRFLOW_DISABLE = 0x0; OVRFLOW запрет. */ +#define OVRFLOW_DISABLE 0x0 +/* Задаёт OVEFLOW_ENABLE = 0x1; OVEFLOW разрешение. */ +#define OVEFLOW_ENABLE 0x1 +// PERINTE bit +/* Задаёт PERINT_DISABLE = 0x0; PERINT запрет. */ +#define PERINT_DISABLE 0x0 +/* Задаёт PERINT_ENABLE = 0x1; PERINT разрешение. */ +#define PERINT_ENABLE 0x1 +// CHINTMODE bits +/* Задаёт CHINT_BEGIN = 0x0; данные CHINT_BEGIN. */ +#define CHINT_BEGIN 0x0 +/* Задаёт CHINT_END = 0x1; данные CHINT_END. */ +#define CHINT_END 0x1 +// ONESHOT bits +/* Задаёт ONESHOT_DISABLE = 0x0; ONESHOT запрет. */ +#define ONESHOT_DISABLE 0x0 +/* Задаёт ONESHOT_ENABLE = 0x1; ONESHOT разрешение. */ +#define ONESHOT_ENABLE 0x1 +// CONTINOUS bit +/* Задаёт CONT_DISABLE = 0x0; CONT запрет. */ +#define CONT_DISABLE 0x0 +/* Задаёт CONT_ENABLE = 0x1; CONT разрешение. */ +#define CONT_ENABLE 0x1 +// SYNCE bit +/* Задаёт SYNC_DISABLE = 0x0; синхронизация запрет. */ +#define SYNC_DISABLE 0x0 +/* Задаёт SYNC_ENABLE = 0x1; синхронизация разрешение. */ +#define SYNC_ENABLE 0x1 +// SYNCSEL bit +/* Задаёт SYNC_SRC = 0x0; синхронизация SRC. */ +#define SYNC_SRC 0x0 +/* Задаёт SYNC_DST = 0x1; синхронизация DST. */ +#define SYNC_DST 0x1 +// DATASIZE bit +/* Задаёт SIXTEEN_BIT = 0x0; SIXTEEN бит. */ +#define SIXTEEN_BIT 0x0 +/* Задаёт THIRTYTWO_BIT = 0x1; THIRTYTWO бит. */ +#define THIRTYTWO_BIT 0x1 +// CHINTE bit +/* Задаёт CHINT_DISABLE = 0x0; CHINT запрет. */ +#define CHINT_DISABLE 0x0 +/* Задаёт CHINT_ENABLE = 0x1; CHINT разрешение. */ +#define CHINT_ENABLE 0x1 + + + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // - end of DSP2833x_EPWM_DEFINES_H + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h new file mode 100644 index 0000000..0084f16 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_EPwm_defines.h @@ -0,0 +1,253 @@ +/* Поставляемое TI описание EPwm_defines для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:45:39 $ +//########################################################################### +// +// FILE: DSP2833x_EPwm_defines.h +// +// TITLE: #defines used in ePWM examples examples +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EPWM_DEFINES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EPWM_DEFINES_H +/* Определяет защитный символ или переключатель DSP2833x_EPWM_DEFINES_H для последующей компиляции. */ +#define DSP2833x_EPWM_DEFINES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +// TBCTL (Time-Base Control) +//========================== +// CTRMODE bits +/* Задаёт TB_COUNT_UP = 0x0; TB число UP. */ +#define TB_COUNT_UP 0x0 +/* Задаёт TB_COUNT_DOWN = 0x1; TB число DOWN. */ +#define TB_COUNT_DOWN 0x1 +/* Задаёт TB_COUNT_UPDOWN = 0x2; TB число UPDOWN. */ +#define TB_COUNT_UPDOWN 0x2 +/* Задаёт TB_FREEZE = 0x3; данные TB_FREEZE. */ +#define TB_FREEZE 0x3 +// PHSEN bit +/* Задаёт TB_DISABLE = 0x0; TB запрет. */ +#define TB_DISABLE 0x0 +/* Задаёт TB_ENABLE = 0x1; TB разрешение. */ +#define TB_ENABLE 0x1 +// PRDLD bit +/* Задаёт TB_SHADOW = 0x0; данные TB_SHADOW. */ +#define TB_SHADOW 0x0 +/* Задаёт TB_IMMEDIATE = 0x1; данные TB_IMMEDIATE. */ +#define TB_IMMEDIATE 0x1 +// SYNCOSEL bits +/* Задаёт TB_SYNC_IN = 0x0; TB синхронизация IN. */ +#define TB_SYNC_IN 0x0 +/* Задаёт TB_CTR_ZERO = 0x1; данные TB_CTR_ZERO. */ +#define TB_CTR_ZERO 0x1 +/* Задаёт TB_CTR_CMPB = 0x2; данные TB_CTR_CMPB. */ +#define TB_CTR_CMPB 0x2 +/* Задаёт TB_SYNC_DISABLE = 0x3; TB синхронизация запрет. */ +#define TB_SYNC_DISABLE 0x3 +// HSPCLKDIV and CLKDIV bits +/* Задаёт TB_DIV1 = 0x0; данные TB_DIV1. */ +#define TB_DIV1 0x0 +/* Задаёт TB_DIV2 = 0x1; данные TB_DIV2. */ +#define TB_DIV2 0x1 +/* Задаёт TB_DIV4 = 0x2; данные TB_DIV4. */ +#define TB_DIV4 0x2 +// PHSDIR bit +/* Задаёт TB_DOWN = 0x0; данные TB_DOWN. */ +#define TB_DOWN 0x0 +/* Задаёт TB_UP = 0x1; данные TB_UP. */ +#define TB_UP 0x1 + +// CMPCTL (Compare Control) +//========================== +// LOADAMODE and LOADBMODE bits +/* Задаёт CC_CTR_ZERO = 0x0; данные CC_CTR_ZERO. */ +#define CC_CTR_ZERO 0x0 +/* Задаёт CC_CTR_PRD = 0x1; данные CC_CTR_PRD. */ +#define CC_CTR_PRD 0x1 +/* Задаёт CC_CTR_ZERO_PRD = 0x2; данные CC_CTR_ZERO_PRD. */ +#define CC_CTR_ZERO_PRD 0x2 +/* Задаёт CC_LD_DISABLE = 0x3; CC LD запрет. */ +#define CC_LD_DISABLE 0x3 +// SHDWAMODE and SHDWBMODE bits +/* Задаёт CC_SHADOW = 0x0; данные CC_SHADOW. */ +#define CC_SHADOW 0x0 +/* Задаёт CC_IMMEDIATE = 0x1; данные CC_IMMEDIATE. */ +#define CC_IMMEDIATE 0x1 + +// AQCTLA and AQCTLB (Action Qualifier Control) +//============================================= +// ZRO, PRD, CAU, CAD, CBU, CBD bits +/* Задаёт AQ_NO_ACTION = 0x0; данные AQ_NO_ACTION. */ +#define AQ_NO_ACTION 0x0 +/* Задаёт AQ_CLEAR = 0x1; AQ очистка. */ +#define AQ_CLEAR 0x1 +/* Задаёт AQ_SET = 0x2; AQ установка. */ +#define AQ_SET 0x2 +/* Задаёт AQ_TOGGLE = 0x3; данные AQ_TOGGLE. */ +#define AQ_TOGGLE 0x3 + +// DBCTL (Dead-Band Control) +//========================== +// OUT MODE bits +/* Задаёт DB_DISABLE = 0x0; DB запрет. */ +#define DB_DISABLE 0x0 +/* Задаёт DBA_ENABLE = 0x1; DBA разрешение. */ +#define DBA_ENABLE 0x1 +/* Задаёт DBB_ENABLE = 0x2; DBB разрешение. */ +#define DBB_ENABLE 0x2 +/* Задаёт DB_FULL_ENABLE = 0x3; DB FULL разрешение. */ +#define DB_FULL_ENABLE 0x3 +// POLSEL bits +/* Задаёт DB_ACTV_HI = 0x0; данные DB_ACTV_HI. */ +#define DB_ACTV_HI 0x0 +/* Задаёт DB_ACTV_LOC = 0x1; данные DB_ACTV_LOC. */ +#define DB_ACTV_LOC 0x1 +/* Задаёт DB_ACTV_HIC = 0x2; данные DB_ACTV_HIC. */ +#define DB_ACTV_HIC 0x2 +/* Задаёт DB_ACTV_LO = 0x3; данные DB_ACTV_LO. */ +#define DB_ACTV_LO 0x3 +// IN MODE +/* Задаёт DBA_ALL = 0x0; данные DBA_ALL. */ +#define DBA_ALL 0x0 +/* Задаёт DBB_RED_DBA_FED = 0x1; данные DBB_RED_DBA_FED. */ +#define DBB_RED_DBA_FED 0x1 +/* Задаёт DBA_RED_DBB_FED = 0x2; данные DBA_RED_DBB_FED. */ +#define DBA_RED_DBB_FED 0x2 +/* Задаёт DBB_ALL = 0x3; данные DBB_ALL. */ +#define DBB_ALL 0x3 + +// CHPCTL (chopper control) +//========================== +// CHPEN bit +/* Задаёт CHP_DISABLE = 0x0; CHP запрет. */ +#define CHP_DISABLE 0x0 +/* Задаёт CHP_ENABLE = 0x1; CHP разрешение. */ +#define CHP_ENABLE 0x1 +// CHPFREQ bits +/* Задаёт CHP_DIV1 = 0x0; данные CHP_DIV1. */ +#define CHP_DIV1 0x0 +/* Задаёт CHP_DIV2 = 0x1; данные CHP_DIV2. */ +#define CHP_DIV2 0x1 +/* Задаёт CHP_DIV3 = 0x2; данные CHP_DIV3. */ +#define CHP_DIV3 0x2 +/* Задаёт CHP_DIV4 = 0x3; данные CHP_DIV4. */ +#define CHP_DIV4 0x3 +/* Задаёт CHP_DIV5 = 0x4; данные CHP_DIV5. */ +#define CHP_DIV5 0x4 +/* Задаёт CHP_DIV6 = 0x5; данные CHP_DIV6. */ +#define CHP_DIV6 0x5 +/* Задаёт CHP_DIV7 = 0x6; данные CHP_DIV7. */ +#define CHP_DIV7 0x6 +/* Задаёт CHP_DIV8 = 0x7; данные CHP_DIV8. */ +#define CHP_DIV8 0x7 +// CHPDUTY bits +/* Задаёт CHP1_8TH = 0x0; данные CHP1_8TH. */ +#define CHP1_8TH 0x0 +/* Задаёт CHP2_8TH = 0x1; данные CHP2_8TH. */ +#define CHP2_8TH 0x1 +/* Задаёт CHP3_8TH = 0x2; данные CHP3_8TH. */ +#define CHP3_8TH 0x2 +/* Задаёт CHP4_8TH = 0x3; данные CHP4_8TH. */ +#define CHP4_8TH 0x3 +/* Задаёт CHP5_8TH = 0x4; данные CHP5_8TH. */ +#define CHP5_8TH 0x4 +/* Задаёт CHP6_8TH = 0x5; данные CHP6_8TH. */ +#define CHP6_8TH 0x5 +/* Задаёт CHP7_8TH = 0x6; данные CHP7_8TH. */ +#define CHP7_8TH 0x6 + +// TZSEL (Trip Zone Select) +//========================== +// CBCn and OSHTn bits +/* Задаёт TZ_DISABLE = 0x0; TZ запрет. */ +#define TZ_DISABLE 0x0 +/* Задаёт TZ_ENABLE = 0x1; TZ разрешение. */ +#define TZ_ENABLE 0x1 + +// TZCTL (Trip Zone Control) +//========================== +// TZA and TZB bits +/* Задаёт TZ_HIZ = 0x0; данные TZ_HIZ. */ +#define TZ_HIZ 0x0 +/* Задаёт TZ_FORCE_HI = 0x1; TZ принудительная установка HI. */ +#define TZ_FORCE_HI 0x1 +/* Задаёт TZ_FORCE_LO = 0x2; TZ принудительная установка LO. */ +#define TZ_FORCE_LO 0x2 +/* Задаёт TZ_NO_CHANGE = 0x3; данные TZ_NO_CHANGE. */ +#define TZ_NO_CHANGE 0x3 + +// ETSEL (Event Trigger Select) +//============================= +/* Задаёт ET_CTR_ZERO = 0x1; данные ET_CTR_ZERO. */ +#define ET_CTR_ZERO 0x1 +/* Задаёт ET_CTR_PRD = 0x2; данные ET_CTR_PRD. */ +#define ET_CTR_PRD 0x2 +/* Задаёт ET_CTRU_CMPA = 0x4; данные ET_CTRU_CMPA. */ +#define ET_CTRU_CMPA 0x4 +/* Задаёт ET_CTRD_CMPA = 0x5; данные ET_CTRD_CMPA. */ +#define ET_CTRD_CMPA 0x5 +/* Задаёт ET_CTRU_CMPB = 0x6; данные ET_CTRU_CMPB. */ +#define ET_CTRU_CMPB 0x6 +/* Задаёт ET_CTRD_CMPB = 0x7; данные ET_CTRD_CMPB. */ +#define ET_CTRD_CMPB 0x7 + +// ETPS (Event Trigger Pre-scale) +//=============================== +// INTPRD, SOCAPRD, SOCBPRD bits +/* Задаёт ET_DISABLE = 0x0; ET запрет. */ +#define ET_DISABLE 0x0 +/* Задаёт ET_1ST = 0x1; данные ET_1ST. */ +#define ET_1ST 0x1 +/* Задаёт ET_2ND = 0x2; данные ET_2ND. */ +#define ET_2ND 0x2 +/* Задаёт ET_3RD = 0x3; данные ET_3RD. */ +#define ET_3RD 0x3 + + +//-------------------------------- +// HRPWM (High Resolution PWM) +//================================ +// HRCNFG +/* Задаёт HR_Disable = 0x0; HR запрет. */ +#define HR_Disable 0x0 +/* Задаёт HR_REP = 0x1; данные HR_REP. */ +#define HR_REP 0x1 +/* Задаёт HR_FEP = 0x2; данные HR_FEP. */ +#define HR_FEP 0x2 +/* Задаёт HR_BEP = 0x3; данные HR_BEP. */ +#define HR_BEP 0x3 + +/* Задаёт HR_CMP = 0x0; данные HR_CMP. */ +#define HR_CMP 0x0 +/* Задаёт HR_PHS = 0x1; данные HR_PHS. */ +#define HR_PHS 0x1 + +/* Задаёт HR_CTR_ZERO = 0x0; данные HR_CTR_ZERO. */ +#define HR_CTR_ZERO 0x0 +/* Задаёт HR_CTR_PRD = 0x1; данные HR_CTR_PRD. */ +#define HR_CTR_PRD 0x1 + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // - end of DSP2833x_EPWM_DEFINES_H + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h new file mode 100644 index 0000000..eaa6500 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_Examples.h @@ -0,0 +1,176 @@ +/* Поставляемое TI описание Examples для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/9 $ +// Checkin $Date: July 2, 2008 14:31:12 $ +//########################################################################### +// +// FILE: DSP2833x_Examples.h +// +// TITLE: DSP2833x Device Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EXAMPLES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EXAMPLES_H +/* Определяет защитный символ или переключатель DSP2833x_EXAMPLES_H для последующей компиляции. */ +#define DSP2833x_EXAMPLES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +/*----------------------------------------------------------------------------- + Specify the PLL control register (PLLCR) and divide select (DIVSEL) value. +-----------------------------------------------------------------------------*/ +//#define DSP28_DIVSEL 0 // Enable /4 for SYSCLKOUT +//#define DSP28_DIVSEL 1 // Enable /4 for SYSCKOUT +/* Задаёт DSP28_DIVSEL = 2; данные DSP28_DIVSEL. */ +#define DSP28_DIVSEL 2 // Enable /2 for SYSCLKOUT +//#define DSP28_DIVSEL 3 // Enable /1 for SYSCLKOUT + +/* Задаёт DSP28_PLLCR = CLKMULT*2; данные DSP28_PLLCR. */ +#define DSP28_PLLCR CLKMULT*2 + +//#define DSP28_PLLCR 10 +//#define DSP28_PLLCR 9 +//#define DSP28_PLLCR 8 +//#define DSP28_PLLCR 7 +//#define DSP28_PLLCR 6 +//#define DSP28_PLLCR 5 +//#define DSP28_PLLCR 4 +//#define DSP28_PLLCR 3 +//#define DSP28_PLLCR 2 +//#define DSP28_PLLCR 1 +//#define DSP28_PLLCR 0 // PLL is bypassed in this mode +//---------------------------------------------------------------------------- + + +/*----------------------------------------------------------------------------- + Specify the clock rate of the CPU (SYSCLKOUT) in nS. + + Take into account the input clock frequency and the PLL multiplier + selected in step 1. + + Use one of the values provided, or define your own. + The trailing L is required tells the compiler to treat + the number as a 64-bit value. + + Only one statement should be uncommented. + + Example 1:150 MHz devices: + CLKIN is a 30MHz crystal. + + In step 1 the user specified PLLCR = 0xA for a + 150Mhz CPU clock (SYSCLKOUT = 150MHz). + + In this case, the CPU_RATE will be 6.667L + Uncomment the line: #define CPU_RATE 6.667L + + Example 2: 100 MHz devices: + CLKIN is a 20MHz crystal. + + In step 1 the user specified PLLCR = 0xA for a + 100Mhz CPU clock (SYSCLKOUT = 100MHz). + + In this case, the CPU_RATE will be 10.000L + Uncomment the line: #define CPU_RATE 10.000L +-----------------------------------------------------------------------------*/ +/* Задаёт CPU_RATE = 6.667L; данные CPU_RATE. */ +#define CPU_RATE 6.667L // for a 150MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 7.143L // for a 140MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 8.333L // for a 120MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 10.000L // for a 100MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 13.330L // for a 75MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 20.000L // for a 50MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 33.333L // for a 30MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 41.667L // for a 24MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 50.000L // for a 20MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 66.667L // for a 15MHz CPU clock speed (SYSCLKOUT) +//#define CPU_RATE 100.000L // for a 10MHz CPU clock speed (SYSCLKOUT) + +//---------------------------------------------------------------------------- + +/*----------------------------------------------------------------------------- + Target device (in DSP2833x_Device.h) determines CPU frequency + (for examples) - either 150 MHz (for 28335 and 28334) or 100 MHz + (for 28332). User does not have to change anything here. +-----------------------------------------------------------------------------*/ +/* Условие компиляции DSP28_28332: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28332 // DSP28_28332 device only + /* Задаёт CPU_FRQ_100MHZ = 1; данные CPU_FRQ_100MHZ. */ + #define CPU_FRQ_100MHZ 1 // 100 Mhz CPU Freq (20 MHz input freq) + /* Задаёт CPU_FRQ_150MHZ = 0; данные CPU_FRQ_150MHZ. */ + #define CPU_FRQ_150MHZ 0 +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else + /* Задаёт CPU_FRQ_100MHZ = 0; данные CPU_FRQ_100MHZ. */ + #define CPU_FRQ_100MHZ 0 // DSP28_28335||DSP28_28334 + /* Задаёт CPU_FRQ_150MHZ = 1; данные CPU_FRQ_150MHZ. */ + #define CPU_FRQ_150MHZ 1 // 150 MHz CPU Freq (30 MHz input freq) by DEFAULT +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// Include Example Header Files: +// + +/* Подключает "DSP2833x_GlobalPrototypes.h": поставляемое TI описание GlobalPrototypes для семейства C2833x. */ +#include "DSP2833x_GlobalPrototypes.h" // Prototypes for global functions within the + // .c files. + +/* Подключает "DSP2833x_ePwm_defines.h": поставляемое TI описание ePwm_defines для семейства C2833x. */ +#include "DSP2833x_ePwm_defines.h" // Macros used for PWM examples. +/* Подключает "DSP2833x_Dma_defines.h": поставляемое TI описание Dma_defines для семейства C2833x. */ +#include "DSP2833x_Dma_defines.h" // Macros used for DMA examples. +/* Подключает "DSP2833x_I2C_defines.h": поставляемое TI описание I2C_defines для семейства C2833x. */ +#include "DSP2833x_I2C_defines.h" // Macros used for I2C examples. + +/* Задаёт PARTNO_28335 = 0xEF; данные PARTNO_28335. */ +#define PARTNO_28335 0xEF +/* Задаёт PARTNO_28334 = 0xEE; данные PARTNO_28334. */ +#define PARTNO_28334 0xEE +/* Задаёт PARTNO_28332 = 0xED; данные PARTNO_28332. */ +#define PARTNO_28332 0xED +/* Задаёт PARTNO_28235 = 0xE8; данные PARTNO_28235. */ +#define PARTNO_28235 0xE8 +/* Задаёт PARTNO_28234 = 0xE7; данные PARTNO_28234. */ +#define PARTNO_28234 0xE7 +/* Задаёт PARTNO_28232 = 0xE6; данные PARTNO_28232. */ +#define PARTNO_28232 0xE6 + + +// Include files not used with DSP/BIOS +/* Начинает условие: DSP28_BIOS ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP28_BIOS +/* Подключает "DSP2833x_DefaultISR.h": поставляемое TI описание DefaultISR для семейства C2833x. */ +#include "DSP2833x_DefaultISR.h" +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +// DO NOT MODIFY THIS LINE. +/* Задаёт DELAY_US = DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L); данные DELAY_US. */ +#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L) + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_EXAMPLES_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h new file mode 100644 index 0000000..4cd293d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_GlobalPrototypes.h @@ -0,0 +1,363 @@ +/* Поставляемое TI описание GlobalPrototypes для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/11 $ +// Checkin $Date: May 12, 2008 14:30:08 $ +//########################################################################### +// +// FILE: DSP2833x_GlobalPrototypes.h +// +// TITLE: Global prototypes for DSP2833x Examples +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_GLOBALPROTOTYPES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_GLOBALPROTOTYPES_H +/* Определяет защитный символ или переключатель DSP2833x_GLOBALPROTOTYPES_H для последующей компиляции. */ +#define DSP2833x_GLOBALPROTOTYPES_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/*---- shared global function prototypes -----------------------------------*/ +/* Объявляет интерфейс функции InitAdc; реализация вызывается через этот прототип. */ +extern void InitAdc(void); + +/* Объявляет интерфейс функции DMAInitialize; реализация вызывается через этот прототип. */ +extern void DMAInitialize(void); +// DMA Channel 1 +/* Объявляет интерфейс функции DMACH1AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH1AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH1BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH1BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH1TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH1TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH1WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH1WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH1ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH1ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH1; реализация вызывается через этот прототип. */ +extern void StartDMACH1(void); +// DMA Channel 2 +/* Объявляет интерфейс функции DMACH2AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH2AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH2BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH2BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH2TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH2TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH2WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH2WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH2ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH2ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH2; реализация вызывается через этот прототип. */ +extern void StartDMACH2(void); +// DMA Channel 3 +/* Объявляет интерфейс функции DMACH3AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH3AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH3BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH3BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH3TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH3TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH3WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH3WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH3ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH3ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH3; реализация вызывается через этот прототип. */ +extern void StartDMACH3(void); +// DMA Channel 4 +/* Объявляет интерфейс функции DMACH4AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH4AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH4BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH4BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH4TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH4TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH4WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH4WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH4ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH4ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH4; реализация вызывается через этот прототип. */ +extern void StartDMACH4(void); +// DMA Channel 5 +/* Объявляет интерфейс функции DMACH5AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH5AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH5BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH5BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH5TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH5TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH5WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH5WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH5ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH5ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH5; реализация вызывается через этот прототип. */ +extern void StartDMACH5(void); +// DMA Channel 6 +/* Объявляет интерфейс функции DMACH6AddrConfig; реализация вызывается через этот прототип. */ +extern void DMACH6AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source); +/* Объявляет интерфейс функции DMACH6BurstConfig; реализация вызывается через этот прототип. */ +extern void DMACH6BurstConfig(Uint16 bsize,Uint16 srcbstep, int16 desbstep); +/* Объявляет интерфейс функции DMACH6TransferConfig; реализация вызывается через этот прототип. */ +extern void DMACH6TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep); +/* Объявляет интерфейс функции DMACH6WrapConfig; реализация вызывается через этот прототип. */ +extern void DMACH6WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep); +/* Объявляет интерфейс функции DMACH6ModeConfig; реализация вызывается через этот прототип. */ +extern void DMACH6ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte); +/* Объявляет интерфейс функции StartDMACH6; реализация вызывается через этот прототип. */ +extern void StartDMACH6(void); + +/* Объявляет интерфейс функции InitPeripherals; реализация вызывается через этот прототип. */ +extern void InitPeripherals(void); +/* Условие компиляции DSP28_ECANA: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECANA +/* Объявляет интерфейс функции InitECan; реализация вызывается через этот прототип. */ +extern void InitECan(void); +/* Объявляет интерфейс функции InitECana; реализация вызывается через этот прототип. */ +extern void InitECana(void); +/* Объявляет интерфейс функции InitECanGpio; реализация вызывается через этот прототип. */ +extern void InitECanGpio(void); +/* Объявляет интерфейс функции InitECanaGpio; реализация вызывается через этот прототип. */ +extern void InitECanaGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECANA +/* Условие компиляции DSP28_ECANB: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECANB +/* Объявляет интерфейс функции InitECanb; реализация вызывается через этот прототип. */ +extern void InitECanb(void); +/* Объявляет интерфейс функции InitECanbGpio; реализация вызывается через этот прототип. */ +extern void InitECanbGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECANB +/* Объявляет интерфейс функции InitECap; реализация вызывается через этот прототип. */ +extern void InitECap(void); +/* Объявляет интерфейс функции InitECapGpio; реализация вызывается через этот прототип. */ +extern void InitECapGpio(void); +/* Объявляет интерфейс функции InitECap1Gpio; реализация вызывается через этот прототип. */ +extern void InitECap1Gpio(void); +/* Объявляет интерфейс функции InitECap2Gpio; реализация вызывается через этот прототип. */ +extern void InitECap2Gpio(void); +/* Условие компиляции DSP28_ECAP3: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP3 +/* Объявляет интерфейс функции InitECap3Gpio; реализация вызывается через этот прототип. */ +extern void InitECap3Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP3 +/* Условие компиляции DSP28_ECAP4: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP4 +/* Объявляет интерфейс функции InitECap4Gpio; реализация вызывается через этот прототип. */ +extern void InitECap4Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP4 +/* Условие компиляции DSP28_ECAP5: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP5 +/* Объявляет интерфейс функции InitECap5Gpio; реализация вызывается через этот прототип. */ +extern void InitECap5Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP5 +/* Условие компиляции DSP28_ECAP6: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_ECAP6 +/* Объявляет интерфейс функции InitECap6Gpio; реализация вызывается через этот прототип. */ +extern void InitECap6Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_ECAP6 +/* Объявляет интерфейс функции InitEPwm; реализация вызывается через этот прототип. */ +extern void InitEPwm(void); +/* Объявляет интерфейс функции InitEPwmGpio; реализация вызывается через этот прототип. */ +extern void InitEPwmGpio(void); +/* Объявляет интерфейс функции InitEPwm1Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm1Gpio(void); +/* Объявляет интерфейс функции InitEPwm2Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm2Gpio(void); +/* Объявляет интерфейс функции InitEPwm3Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm3Gpio(void); +/* Условие компиляции DSP28_EPWM4: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EPWM4 +/* Объявляет интерфейс функции InitEPwm4Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm4Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EPWM4 +/* Условие компиляции DSP28_EPWM5: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EPWM5 +/* Объявляет интерфейс функции InitEPwm5Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm5Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EPWM5 +/* Условие компиляции DSP28_EPWM6: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EPWM6 +/* Объявляет интерфейс функции InitEPwm6Gpio; реализация вызывается через этот прототип. */ +extern void InitEPwm6Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EPWM6 +/* Условие компиляции DSP28_EQEP1: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EQEP1 +/* Объявляет интерфейс функции InitEQep; реализация вызывается через этот прототип. */ +extern void InitEQep(void); +/* Объявляет интерфейс функции InitEQepGpio; реализация вызывается через этот прототип. */ +extern void InitEQepGpio(void); +/* Объявляет интерфейс функции InitEQep1Gpio; реализация вызывается через этот прототип. */ +extern void InitEQep1Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // if DSP28_EQEP1 +/* Условие компиляции DSP28_EQEP2: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_EQEP2 +/* Объявляет интерфейс функции InitEQep2Gpio; реализация вызывается через этот прототип. */ +extern void InitEQep2Gpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_EQEP2 +/* Объявляет интерфейс функции InitGpio; реализация вызывается через этот прототип. */ +extern void InitGpio(void); +/* Объявляет интерфейс функции InitI2CGpio; реализация вызывается через этот прототип. */ +extern void InitI2CGpio(void); + +/* Объявляет интерфейс функции InitMcbsp; реализация вызывается через этот прототип. */ +extern void InitMcbsp(void); +/* Объявляет интерфейс функции InitMcbspa; реализация вызывается через этот прототип. */ +extern void InitMcbspa(void); +/* Объявляет интерфейс функции delay_loop; реализация вызывается через этот прототип. */ +extern void delay_loop(void); +/* Объявляет интерфейс функции InitMcbspaGpio; реализация вызывается через этот прототип. */ +extern void InitMcbspaGpio(void); +/* Объявляет интерфейс функции InitMcbspa8bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa8bit(void); +/* Объявляет интерфейс функции InitMcbspa12bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa12bit(void); +/* Объявляет интерфейс функции InitMcbspa16bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa16bit(void); +/* Объявляет интерфейс функции InitMcbspa20bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa20bit(void); +/* Объявляет интерфейс функции InitMcbspa24bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa24bit(void); +/* Объявляет интерфейс функции InitMcbspa32bit; реализация вызывается через этот прототип. */ +extern void InitMcbspa32bit(void); +/* Условие компиляции DSP28_MCBSPB: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_MCBSPB +/* Объявляет интерфейс функции InitMcbspb; реализация вызывается через этот прототип. */ +extern void InitMcbspb(void); +/* Объявляет интерфейс функции InitMcbspbGpio; реализация вызывается через этот прототип. */ +extern void InitMcbspbGpio(void); +/* Объявляет интерфейс функции InitMcbspb8bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb8bit(void); +/* Объявляет интерфейс функции InitMcbspb12bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb12bit(void); +/* Объявляет интерфейс функции InitMcbspb16bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb16bit(void); +/* Объявляет интерфейс функции InitMcbspb20bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb20bit(void); +/* Объявляет интерфейс функции InitMcbspb24bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb24bit(void); +/* Объявляет интерфейс функции InitMcbspb32bit; реализация вызывается через этот прототип. */ +extern void InitMcbspb32bit(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_MCBSPB + +/* Объявляет интерфейс функции InitPieCtrl; реализация вызывается через этот прототип. */ +extern void InitPieCtrl(void); +/* Объявляет интерфейс функции InitPieVectTable; реализация вызывается через этот прототип. */ +extern void InitPieVectTable(void); + +/* Объявляет интерфейс функции InitSci; реализация вызывается через этот прототип. */ +extern void InitSci(void); +/* Объявляет интерфейс функции InitSciGpio; реализация вызывается через этот прототип. */ +extern void InitSciGpio(void); +/* Объявляет интерфейс функции InitSciaGpio; реализация вызывается через этот прототип. */ +extern void InitSciaGpio(void); +/* Условие компиляции DSP28_SCIB: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_SCIB +/* Объявляет интерфейс функции InitScibGpio; реализация вызывается через этот прототип. */ +extern void InitScibGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // endif DSP28_SCIB +/* Условие компиляции DSP28_SCIC: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_SCIC +/* Объявляет интерфейс функции InitScicGpio; реализация вызывается через этот прототип. */ +extern void InitScicGpio(void); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Объявляет интерфейс функции InitSpi; реализация вызывается через этот прототип. */ +extern void InitSpi(void); +/* Объявляет интерфейс функции InitSpiGpio; реализация вызывается через этот прототип. */ +extern void InitSpiGpio(void); +/* Объявляет интерфейс функции InitSpiaGpio; реализация вызывается через этот прототип. */ +extern void InitSpiaGpio(void); +/* Объявляет интерфейс функции InitSysCtrl; реализация вызывается через этот прототип. */ +extern void InitSysCtrl(void); +/* Объявляет интерфейс функции InitTzGpio; реализация вызывается через этот прототип. */ +extern void InitTzGpio(void); +/* Объявляет интерфейс функции InitXIntrupt; реализация вызывается через этот прототип. */ +extern void InitXIntrupt(void); +/* Объявляет интерфейс функции XintfInit; реализация вызывается через этот прототип. */ +extern void XintfInit(void); +/* Объявляет интерфейс функции InitXintf16Gpio; реализация вызывается через этот прототип. */ +extern void InitXintf16Gpio(); +/* Объявляет интерфейс функции InitXintf32Gpio; реализация вызывается через этот прототип. */ +extern void InitXintf32Gpio(); +/* Объявляет интерфейс функции InitPll; реализация вызывается через этот прототип. */ +extern void InitPll(Uint16 pllcr, Uint16 clkindiv); +/* Объявляет интерфейс функции InitPeripheralClocks; реализация вызывается через этот прототип. */ +extern void InitPeripheralClocks(void); +/* Объявляет интерфейс функции EnableInterrupts; реализация вызывается через этот прототип. */ +extern void EnableInterrupts(void); +/* Объявляет интерфейс функции DSP28x_usDelay; реализация вызывается через этот прототип. */ +extern void DSP28x_usDelay(Uint32 Count); +/* Объявляет интерфейс функции ADC_cal; реализация вызывается через этот прототип. */ +extern void ADC_cal (void); +/* Задаёт KickDog = ServiceDog; данные KickDog. */ +#define KickDog ServiceDog // For compatiblity with previous versions +/* Объявляет интерфейс функции ServiceDog; реализация вызывается через этот прототип. */ +extern void ServiceDog(void); +/* Объявляет интерфейс функции DisableDog; реализация вызывается через этот прототип. */ +extern void DisableDog(void); +/* Объявляет интерфейс функции CsmUnlock; реализация вызывается через этот прототип. */ +extern Uint16 CsmUnlock(void); + +// DSP28_DBGIER.asm +/* Объявляет интерфейс функции SetDBGIER; реализация вызывается через этот прототип. */ +extern void SetDBGIER(Uint16 dbgier); + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results +/* Объявляет интерфейс функции InitFlash; реализация вызывается через этот прототип. */ +extern void InitFlash(void); + + +/* Объявляет интерфейс функции MemCopy; реализация вызывается через этот прототип. */ +void MemCopy(Uint16 *SourceAddr, Uint16* SourceEndAddr, Uint16* DestAddr); + + +//--------------------------------------------------------------------------- +// External symbols created by the linker cmd file +// DSP28 examples will use these to relocate code from one LOAD location +// in either Flash or XINTF to a different RUN location in internal +// RAM +/* Объявляет RamfuncsLoadStart — данные RamfuncsLoadStart. Память определена в другом модуле. */ +extern Uint16 RamfuncsLoadStart; +/* Объявляет RamfuncsLoadEnd — данные RamfuncsLoadEnd. Память определена в другом модуле. */ +extern Uint16 RamfuncsLoadEnd; +/* Объявляет RamfuncsRunStart — данные RamfuncsRunStart. Память определена в другом модуле. */ +extern Uint16 RamfuncsRunStart; + +/* Объявляет XintffuncsLoadStart — данные XintffuncsLoadStart. Память определена в другом модуле. */ +extern Uint16 XintffuncsLoadStart; +/* Объявляет XintffuncsLoadEnd — данные XintffuncsLoadEnd. Память определена в другом модуле. */ +extern Uint16 XintffuncsLoadEnd; +/* Объявляет XintffuncsRunStart — данные XintffuncsRunStart. Память определена в другом модуле. */ +extern Uint16 XintffuncsRunStart; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // - end of DSP2833x_GLOBALPROTOTYPES_H + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h new file mode 100644 index 0000000..6dfd58d --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_I2c_defines.h @@ -0,0 +1,176 @@ +/* Поставляемое TI описание I2c_defines для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 16, 2008 17:16:47 $ +//########################################################################### +// +// FILE: DSP2833x_I2cExample.h +// +// TITLE: 2833x I2C Example Code Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_I2C_DEFINES_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_I2C_DEFINES_H +/* Определяет защитный символ или переключатель DSP2833x_I2C_DEFINES_H для последующей компиляции. */ +#define DSP2833x_I2C_DEFINES_H + +//-------------------------------------------- +// Defines +//-------------------------------------------- + +// Error Messages +/* Задаёт I2C_ERROR = 0xFFFF; 2 C ошибка. */ +#define I2C_ERROR 0xFFFF +/* Задаёт I2C_ARB_LOST_ERROR = 0x0001; 2 C ARB LOST ошибка. */ +#define I2C_ARB_LOST_ERROR 0x0001 +/* Задаёт I2C_NACK_ERROR = 0x0002; 2 C NACK ошибка. */ +#define I2C_NACK_ERROR 0x0002 +/* Задаёт I2C_BUS_BUSY_ERROR = 0x1000; 2 C BUS BUSY ошибка. */ +#define I2C_BUS_BUSY_ERROR 0x1000 +/* Задаёт I2C_STP_NOT_READY_ERROR = 0x5555; 2 C STP NOT READY ошибка. */ +#define I2C_STP_NOT_READY_ERROR 0x5555 +/* Задаёт I2C_NO_FLAGS = 0xAAAA; 2 C NO флаги. */ +#define I2C_NO_FLAGS 0xAAAA +/* Задаёт I2C_SUCCESS = 0x0000; данные I2C_SUCCESS. */ +#define I2C_SUCCESS 0x0000 + +// Clear Status Flags +/* Задаёт I2C_CLR_AL_BIT = 0x0001; 2 C CLR AL бит. */ +#define I2C_CLR_AL_BIT 0x0001 +/* Задаёт I2C_CLR_NACK_BIT = 0x0002; 2 C CLR NACK бит. */ +#define I2C_CLR_NACK_BIT 0x0002 +/* Задаёт I2C_CLR_ARDY_BIT = 0x0004; 2 C CLR ARDY бит. */ +#define I2C_CLR_ARDY_BIT 0x0004 +/* Задаёт I2C_CLR_RRDY_BIT = 0x0008; 2 C CLR RRDY бит. */ +#define I2C_CLR_RRDY_BIT 0x0008 +/* Задаёт I2C_CLR_SCD_BIT = 0x0020; 2 C CLR SCD бит. */ +#define I2C_CLR_SCD_BIT 0x0020 + +// Interrupt Source Messages +/* Задаёт I2C_NO_ISRC = 0x0000; данные I2C_NO_ISRC. */ +#define I2C_NO_ISRC 0x0000 +/* Задаёт I2C_ARB_ISRC = 0x0001; данные I2C_ARB_ISRC. */ +#define I2C_ARB_ISRC 0x0001 +/* Задаёт I2C_NACK_ISRC = 0x0002; данные I2C_NACK_ISRC. */ +#define I2C_NACK_ISRC 0x0002 +/* Задаёт I2C_ARDY_ISRC = 0x0003; данные I2C_ARDY_ISRC. */ +#define I2C_ARDY_ISRC 0x0003 +/* Задаёт I2C_RX_ISRC = 0x0004; данные I2C_RX_ISRC. */ +#define I2C_RX_ISRC 0x0004 +/* Задаёт I2C_TX_ISRC = 0x0005; данные I2C_TX_ISRC. */ +#define I2C_TX_ISRC 0x0005 +/* Задаёт I2C_SCD_ISRC = 0x0006; данные I2C_SCD_ISRC. */ +#define I2C_SCD_ISRC 0x0006 +/* Задаёт I2C_AAS_ISRC = 0x0007; данные I2C_AAS_ISRC. */ +#define I2C_AAS_ISRC 0x0007 + +// I2CMSG structure defines +/* Задаёт I2C_NO_STOP = 0; данные I2C_NO_STOP. */ +#define I2C_NO_STOP 0 +/* Задаёт I2C_YES_STOP = 1; данные I2C_YES_STOP. */ +#define I2C_YES_STOP 1 +/* Задаёт I2C_RECEIVE = 0; 2 C приём. */ +#define I2C_RECEIVE 0 +/* Задаёт I2C_TRANSMIT = 1; 2 C передача. */ +#define I2C_TRANSMIT 1 +/* Задаёт I2C_MAX_BUFFER_SIZE = 16; 2 C MAX буфер размер. */ +#define I2C_MAX_BUFFER_SIZE 16 + +// I2C Slave State defines +/* Задаёт I2C_NOTSLAVE = 0; данные I2C_NOTSLAVE. */ +#define I2C_NOTSLAVE 0 +/* Задаёт I2C_ADDR_AS_SLAVE = 1; данные I2C_ADDR_AS_SLAVE. */ +#define I2C_ADDR_AS_SLAVE 1 +/* Задаёт I2C_ST_MSG_READY = 2; данные I2C_ST_MSG_READY. */ +#define I2C_ST_MSG_READY 2 + +// I2C Slave Receiver messages defines +/* Задаёт I2C_SND_MSG1 = 1; данные I2C_SND_MSG1. */ +#define I2C_SND_MSG1 1 +/* Задаёт I2C_SND_MSG2 = 2; данные I2C_SND_MSG2. */ +#define I2C_SND_MSG2 2 + +// I2C State defines +/* Задаёт I2C_IDLE = 0; данные I2C_IDLE. */ +#define I2C_IDLE 0 +/* Задаёт I2C_SLAVE_RECEIVER = 1; данные I2C_SLAVE_RECEIVER. */ +#define I2C_SLAVE_RECEIVER 1 +/* Задаёт I2C_SLAVE_TRANSMITTER = 2; данные I2C_SLAVE_TRANSMITTER. */ +#define I2C_SLAVE_TRANSMITTER 2 +/* Задаёт I2C_MASTER_RECEIVER = 3; данные I2C_MASTER_RECEIVER. */ +#define I2C_MASTER_RECEIVER 3 +/* Задаёт I2C_MASTER_TRANSMITTER = 4; данные I2C_MASTER_TRANSMITTER. */ +#define I2C_MASTER_TRANSMITTER 4 + +// I2C Message Commands for I2CMSG struct +/* Задаёт I2C_MSGSTAT_INACTIVE = 0x0000; данные I2C_MSGSTAT_INACTIVE. */ +#define I2C_MSGSTAT_INACTIVE 0x0000 +/* Задаёт I2C_MSGSTAT_SEND_WITHSTOP = 0x0010; данные I2C_MSGSTAT_SEND_WITHSTOP. */ +#define I2C_MSGSTAT_SEND_WITHSTOP 0x0010 +/* Задаёт I2C_MSGSTAT_WRITE_BUSY = 0x0011; 2 C MSGSTAT запись BUSY. */ +#define I2C_MSGSTAT_WRITE_BUSY 0x0011 +/* Задаёт I2C_MSGSTAT_SEND_NOSTOP = 0x0020; данные I2C_MSGSTAT_SEND_NOSTOP. */ +#define I2C_MSGSTAT_SEND_NOSTOP 0x0020 +/* Задаёт I2C_MSGSTAT_SEND_NOSTOP_BUSY = 0x0021; данные I2C_MSGSTAT_SEND_NOSTOP_BUSY. */ +#define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021 +/* Задаёт I2C_MSGSTAT_RESTART = 0x0022; данные I2C_MSGSTAT_RESTART. */ +#define I2C_MSGSTAT_RESTART 0x0022 +/* Задаёт I2C_MSGSTAT_READ_BUSY = 0x0023; 2 C MSGSTAT чтение BUSY. */ +#define I2C_MSGSTAT_READ_BUSY 0x0023 + +// Generic defines +/* Задаёт I2C_TRUE = 1; данные I2C_TRUE. */ +#define I2C_TRUE 1 +/* Задаёт I2C_FALSE = 0; данные I2C_FALSE. */ +#define I2C_FALSE 0 +/* Задаёт I2C_YES = 1; данные I2C_YES. */ +#define I2C_YES 1 +/* Задаёт I2C_NO = 0; данные I2C_NO. */ +#define I2C_NO 0 +/* Задаёт I2C_DUMMY_BYTE = 0; данные I2C_DUMMY_BYTE. */ +#define I2C_DUMMY_BYTE 0 + + +//-------------------------------------------- +// Structures +//-------------------------------------------- + +// I2C Message Structure +/* Описывает структуру I2CMSG; порядок полей определяет расположение данных. */ +struct I2CMSG { + /* Объявляет MsgStatus — Msg состояние. */ + Uint16 MsgStatus; // Word stating what state msg is in: + // I2C_MSGCMD_INACTIVE = do not send msg + // I2C_MSGCMD_BUSY = msg start has been sent, + // awaiting stop + // I2C_MSGCMD_SEND_WITHSTOP = command to send + // master trans msg complete with a stop bit + // I2C_MSGCMD_SEND_NOSTOP = command to send + // master trans msg without the stop bit + // I2C_MSGCMD_RESTART = command to send a restart + // as a master receiver with a stop bit + /* Объявляет SlaveAddress — Slave адрес. */ + Uint16 SlaveAddress; // I2C address of slave msg is intended for + /* Объявляет NumOfBytes — данные NumOfBytes. */ + Uint16 NumOfBytes; // Num of valid bytes in (or to be put in MsgBuffer) + /* Объявляет MemoryHighAddr — данные MemoryHighAddr. */ + Uint16 MemoryHighAddr; // EEPROM address of data associated with msg (high byte) + /* Объявляет MemoryLowAddr — данные MemoryLowAddr. */ + Uint16 MemoryLowAddr; // EEPROM address of data associated with msg (low byte) + /* Объявляет MsgBuffer — Msg буфер. */ + Uint16 MsgBuffer[I2C_MAX_BUFFER_SIZE]; // Array holding msg data - max that + // MAX_BUFFER_SIZE can be is 16 due to + // the FIFO's +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_I2C_DEFINES_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h new file mode 100644 index 0000000..67fb657 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP2833x_SWPrioritizedIsrLevels.h @@ -0,0 +1,10803 @@ +/* Поставляемое TI описание SWPrioritizedIsrLevels для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: April 4, 2007 14:25:21 $ +//########################################################################### +// +// FILE: DSP2833x_SWPrioritizedIsrLevels.h +// +// TITLE: DSP28 Devices Software Prioritized Interrupt Service Routine +// Level definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SW_PRIORITZIED_ISR_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SW_PRIORITZIED_ISR_H +/* Определяет защитный символ или переключатель DSP2833x_SW_PRIORITZIED_ISR_H для последующей компиляции. */ +#define DSP2833x_SW_PRIORITZIED_ISR_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//------------------------------------------------------------------------------- +// Interrupt Enable Register Allocation For 2833x Devices: +//------------------------------------------------------------------------------- +// Interrupts can be enabled/disabled using the CPU interrupt enable register +// (IER) and the PIE interrupt enable registers (PIEIER1 to PIEIER12). +//------------------------------------------------------------------------------- +//------------------------------------------------------------------------------- +// Set "Global" Interrupt Priority Level (IER register): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the CPU +// interrupts. This is termed as the "global" priority. The priority level +// must be a number between 1 (highest) to 16 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used. +// +// Note: The priority levels below are used to calculate the IER register +// interrupt masks MINT1 to MINT16. +// +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 16 = lowest priority +/* Задаёт INT1PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT1PL 2 // Group1 Interrupts (PIEIER1) +/* Задаёт INT2PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT2PL 0 // Group2 Interrupts (PIEIER2) +/* Задаёт INT3PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT3PL 4 // Group3 Interrupts (PIEIER3) +/* Задаёт INT4PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT4PL 2 // Group4 Interrupts (PIEIER4) +/* Задаёт INT5PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT5PL 2 // Group5 Interrupts (PIEIER5) +/* Задаёт INT6PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT6PL 3 // Group6 Interrupts (PIEIER6) +/* Задаёт INT7PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT7PL 0 // reserved +/* Задаёт INT8PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT8PL 0 // reserved +/* Задаёт INT9PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT9PL 1 // Group9 Interrupts (PIEIER9) +/* Задаёт INT10PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT10PL 0 // reserved +/* Задаёт INT11PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT11PL 0 // reserved +/* Задаёт INT12PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT12PL 0 // reserved +/* Задаёт INT13PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT13PL 4 // XINT13 +/* Задаёт INT14PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT14PL 4 // INT14 (TINT2) +/* Задаёт INT15PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT15PL 4 // DATALOG +/* Задаёт INT16PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define INT16PL 4 // RTOSINT + +//------------------------------------------------------------------------------- +// Set "Group" Interrupt Priority Level (PIEIER1 to PIEIER12 registers): +//------------------------------------------------------------------------------- +// The user must set the appropriate priority level for each of the PIE +// interrupts. This is termed as the "group" priority. The priority level +// must be a number between 1 (highest) to 8 (lowest). A value of 0 must +// be entered for reserved interrupts or interrupts that are not used. This +// will also reduce code size by not including ISR's that are not used: +// +// Note: The priority levels below are used to calculate the following +// PIEIER register interrupt masks: +// MG11 to MG18 +// MG21 to MG28 +// MG31 to MG38 +// MG41 to MG48 +// MG51 to MG58 +// MG61 to MG68 +// MG71 to MG78 +// MG81 to MG88 +// MG91 to MG98 +// MG101 to MG108 +// MG111 to MG118 +// MG121 to MG128 +// +// Note: The priority levels shown here may not make sense in a +// real application. This is for demonstration purposes only!!! +// +// The user should change these to values that make sense for +// their application. +// +// 0 = not used +// 1 = highest priority +// ... +// 8 = lowest priority +// +/* Задаёт G11PL = 7; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G11PL 7 // SEQ1INT (ADC) +/* Задаёт G12PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G12PL 6 // SEQ2INT (ADC) +/* Задаёт G13PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G13PL 0 // reserved +/* Задаёт G14PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G14PL 1 // XINT1 (External) +/* Задаёт G15PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G15PL 3 // XINT2 (External) +/* Задаёт G16PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G16PL 2 // ADCINT (ADC) +/* Задаёт G17PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G17PL 1 // TINT0 (CPU Timer 0) +/* Задаёт G18PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G18PL 5 // WAKEINT (WD/LPM) + +/* Задаёт G21PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G21PL 4 // EPWM1_TZINT (ePWM1 Trip) +/* Задаёт G22PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G22PL 3 // EPWM2_TZINT (ePWM2 Trip) +/* Задаёт G23PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G23PL 2 // EPWM3_TZINT (ePWM3 Trip) +/* Задаёт G24PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G24PL 1 // EPWM4_TZINT (ePWM4 Trip) +/* Задаёт G25PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G25PL 5 // EPWM5_TZINT (ePWM5 Trip) +/* Задаёт G26PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G26PL 6 // EPWM6_TZINT (ePWM6 Trip) +/* Задаёт G27PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G27PL 0 // reserved +/* Задаёт G28PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G28PL 0 // reserved + +/* Задаёт G31PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G31PL 4 // EPWM1_INT (ePWM1 Int) +/* Задаёт G32PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G32PL 1 // EPWM2_INT (ePWM2 Int) +/* Задаёт G33PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G33PL 1 // EPWM3_INT (ePWM3 Int) +/* Задаёт G34PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G34PL 2 // EPWM4_INT (ePWM4 Int) +/* Задаёт G35PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G35PL 2 // EPWM5_INT (ePWM5 Int) +/* Задаёт G36PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G36PL 1 // EPWM6_INT (ePWM6 Int) +/* Задаёт G37PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G37PL 0 // reserved +/* Задаёт G38PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G38PL 0 // reserved + +/* Задаёт G41PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G41PL 2 // ECAP1_INT (eCAP1 Int) +/* Задаёт G42PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G42PL 1 // ECAP2_INT (eCAP2 Int) +/* Задаёт G43PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G43PL 3 // ECAP3_INT (eCAP3 Int) +/* Задаёт G44PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G44PL 3 // ECAP4_INT (eCAP4 Int) +/* Задаёт G45PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G45PL 5 // ECAP5_INT (eCAP5 Int) +/* Задаёт G46PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G46PL 5 // ECAP6_INT (eCAP6 Int) +/* Задаёт G47PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G47PL 0 // reserved +/* Задаёт G48PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G48PL 0 // reserved + +/* Задаёт G51PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G51PL 2 // EQEP1_INT (eQEP1 Int) +/* Задаёт G52PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G52PL 1 // EQEP2_INT (eQEP2 Int) +/* Задаёт G53PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G53PL 0 // reserved +/* Задаёт G54PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G54PL 0 // reserved +/* Задаёт G55PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G55PL 0 // reserved +/* Задаёт G56PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G56PL 0 // reserved +/* Задаёт G57PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G57PL 0 // reserved +/* Задаёт G58PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G58PL 0 // reserved + +/* Задаёт G61PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G61PL 3 // SPIRXINTA (SPI-A) +/* Задаёт G62PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G62PL 1 // SPITXINTA (SPI-A) +/* Задаёт G63PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G63PL 4 // MRINTB (McBSP-B) +/* Задаёт G64PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G64PL 6 // MXINTB (McBSP-B) +/* Задаёт G65PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G65PL 2 // MRINTA (McBSP-A) +/* Задаёт G66PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G66PL 1 // MXINTA (McBSP-A) +/* Задаёт G67PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G67PL 0 // reserved +/* Задаёт G68PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G68PL 0 // reserved + +/* Задаёт G71PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G71PL 5 // DINTCH1 (DMA) +/* Задаёт G72PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G72PL 4 // DINTCH2 (DMA) +/* Задаёт G73PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G73PL 4 // DINTCH3 (DMA) +/* Задаёт G74PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G74PL 2 // DINTCH4 (DMA) +/* Задаёт G75PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G75PL 3 // DINTCH5 (DMA) +/* Задаёт G76PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G76PL 1 // DINTCH6 (DMA) +/* Задаёт G77PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G77PL 0 // reserved +/* Задаёт G78PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G78PL 0 // reserved + +/* Задаёт G81PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G81PL 1 // I2CINT1A (I2C-A) +/* Задаёт G82PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G82PL 2 // I2CINT2A (I2C-A) +/* Задаёт G83PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G83PL 0 // reserved +/* Задаёт G84PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G84PL 0 // reserved +/* Задаёт G85PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G85PL 4 // SCIRXINTC (SCI-C) +/* Задаёт G86PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G86PL 3 // SCITXINTC (SCI-C) +/* Задаёт G87PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G87PL 0 // reserved +/* Задаёт G88PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G88PL 0 // reserved + +/* Задаёт G91PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G91PL 1 // SCIRXINTA (SCI-A) +/* Задаёт G92PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G92PL 5 // SCITXINTA (SCI-A) +/* Задаёт G93PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G93PL 3 // SCIRXINTB (SCI-B) +/* Задаёт G94PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G94PL 4 // SCITXINTB (SCI-B) +/* Задаёт G95PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G95PL 1 // ECAN0INTA (ECAN-A) +/* Задаёт G96PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G96PL 1 // ECAN1INTA (ECAN-A) +/* Задаёт G97PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G97PL 2 // ECAN0INTB (ECAN-B) +/* Задаёт G98PL = 4; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G98PL 4 // ECAN1INTB (ECAN-B) + +/* Задаёт G101PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G101PL 0 // reserved +/* Задаёт G102PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G102PL 0 // reserved +/* Задаёт G103PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G103PL 0 // reserved +/* Задаёт G104PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G104PL 0 // reserved +/* Задаёт G105PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G105PL 0 // reserved +/* Задаёт G106PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G106PL 0 // reserved +/* Задаёт G107PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G107PL 0 // reserved +/* Задаёт G108PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G108PL 0 // reserved + +/* Задаёт G111PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G111PL 0 // reserved +/* Задаёт G112PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G112PL 0 // reserved +/* Задаёт G113PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G113PL 0 // reserved +/* Задаёт G114PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G114PL 0 // reserved +/* Задаёт G115PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G115PL 0 // reserved +/* Задаёт G116PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G116PL 0 // reserved +/* Задаёт G117PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G117PL 0 // reserved +/* Задаёт G118PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G118PL 0 // reserved + +/* Задаёт G121PL = 5; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G121PL 5 // XINT3 (External) +/* Задаёт G122PL = 3; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G122PL 3 // XINT4 (External) +/* Задаёт G123PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G123PL 2 // XINT5 (External) +/* Задаёт G124PL = 2; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G124PL 2 // XINT6 (External) +/* Задаёт G125PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G125PL 1 // XINT7 (External) +/* Задаёт G126PL = 0; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G126PL 0 // reserved +/* Задаёт G127PL = 6; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G127PL 6 // LVF (FPA32) +/* Задаёт G128PL = 1; уровень приоритета; 0 отключает источник, меньшее ненулевое число означает более высокий приоритет. */ +#define G128PL 1 // LUF (FPA32) + + +// There should be no need to modify code below this line +//------------------------------------------------------------------------------- +// Automatically generate IER interrupt masks MINT1 to MINT16: +// + +// Beginning of MINT1: +/* Условие компиляции (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL == 0) +/* Задаёт MINT1_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 1_1PL. */ +#define MINT1_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_1PL. */ +#define MINT1_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT1PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT1PL) || (INT2PL == 0) +/* Задаёт MINT1_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 1_2PL. */ +#define MINT1_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_2PL. */ +#define MINT1_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT1PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT1PL) || (INT3PL == 0) +/* Задаёт MINT1_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 1_3PL. */ +#define MINT1_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_3PL. */ +#define MINT1_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT1PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT1PL) || (INT4PL == 0) +/* Задаёт MINT1_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 1_4PL. */ +#define MINT1_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_4PL. */ +#define MINT1_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT1PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT1PL) || (INT5PL == 0) +/* Задаёт MINT1_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 1_5PL. */ +#define MINT1_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_5PL. */ +#define MINT1_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT1PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT1PL) || (INT6PL == 0) +/* Задаёт MINT1_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 1_6PL. */ +#define MINT1_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_6PL. */ +#define MINT1_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT1PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT1PL) || (INT7PL == 0) +/* Задаёт MINT1_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 1_7PL. */ +#define MINT1_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_7PL. */ +#define MINT1_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT1PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT1PL) || (INT8PL == 0) +/* Задаёт MINT1_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 1_8PL. */ +#define MINT1_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_8PL. */ +#define MINT1_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT1PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT1PL) || (INT9PL == 0) +/* Задаёт MINT1_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 1_9PL. */ +#define MINT1_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_9PL. */ +#define MINT1_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT1PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT1PL) || (INT10PL == 0) +/* Задаёт MINT1_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 1_10PL. */ +#define MINT1_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_10PL. */ +#define MINT1_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT1PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT1PL) || (INT11PL == 0) +/* Задаёт MINT1_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 1_11PL. */ +#define MINT1_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_11PL. */ +#define MINT1_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT1PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT1PL) || (INT12PL == 0) +/* Задаёт MINT1_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 1_12PL. */ +#define MINT1_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_12PL. */ +#define MINT1_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT1PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT1PL) || (INT13PL == 0) +/* Задаёт MINT1_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 1_13PL. */ +#define MINT1_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_13PL. */ +#define MINT1_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT1PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT1PL) || (INT14PL == 0) +/* Задаёт MINT1_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 1_14PL. */ +#define MINT1_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_14PL. */ +#define MINT1_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT1PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT1PL) || (INT15PL == 0) +/* Задаёт MINT1_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 1_15PL. */ +#define MINT1_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_15PL. */ +#define MINT1_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT1PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT1PL) || (INT16PL == 0) +/* Задаёт MINT1_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 1_16PL. */ +#define MINT1_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT1_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 1_16PL. */ +#define MINT1_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT1 = (MINT1_1PL & MINT1_2PL & MINT1_3PL & MINT1_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 1. */ +#define MINT1 (MINT1_1PL & MINT1_2PL & MINT1_3PL & MINT1_4PL & \ + MINT1_5PL & MINT1_6PL & MINT1_7PL & MINT1_8PL & /* Продолжает список аргументов, полей или выражение MINT1_5PL & MINT1_6PL & MINT1_7PL & MINT1_8PL &; порядок элементов сохраняется. */ \ + MINT1_9PL & MINT1_10PL & MINT1_11PL & MINT1_12PL & /* Продолжает список аргументов, полей или выражение MINT1_9PL & MINT1_10PL & MINT1_11PL & MINT1_12PL &; порядок элементов сохраняется. */ \ + MINT1_13PL & MINT1_14PL & MINT1_15PL & MINT1_16PL) /* Продолжает список аргументов, полей или выражение MINT1_13PL & MINT1_14PL & MINT1_15PL & MINT1_16PL); порядок элементов сохраняется. */ +// End Of MINT1. + +// Beginning of MINT2: +/* Условие компиляции (INT1PL >= INT2PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT2PL) || (INT1PL == 0) +/* Задаёт MINT2_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 2_1PL. */ +#define MINT2_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_1PL. */ +#define MINT2_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL == 0) +/* Задаёт MINT2_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 2_2PL. */ +#define MINT2_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_2PL. */ +#define MINT2_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT2PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT2PL) || (INT3PL == 0) +/* Задаёт MINT2_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 2_3PL. */ +#define MINT2_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_3PL. */ +#define MINT2_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT2PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT2PL) || (INT4PL == 0) +/* Задаёт MINT2_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 2_4PL. */ +#define MINT2_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_4PL. */ +#define MINT2_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT2PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT2PL) || (INT5PL == 0) +/* Задаёт MINT2_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 2_5PL. */ +#define MINT2_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_5PL. */ +#define MINT2_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT2PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT2PL) || (INT6PL == 0) +/* Задаёт MINT2_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 2_6PL. */ +#define MINT2_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_6PL. */ +#define MINT2_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT2PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT2PL) || (INT7PL == 0) +/* Задаёт MINT2_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 2_7PL. */ +#define MINT2_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_7PL. */ +#define MINT2_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT2PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT2PL) || (INT8PL == 0) +/* Задаёт MINT2_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 2_8PL. */ +#define MINT2_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_8PL. */ +#define MINT2_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT2PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT2PL) || (INT9PL == 0) +/* Задаёт MINT2_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 2_9PL. */ +#define MINT2_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_9PL. */ +#define MINT2_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT2PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT2PL) || (INT10PL == 0) +/* Задаёт MINT2_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 2_10PL. */ +#define MINT2_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_10PL. */ +#define MINT2_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT2PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT2PL) || (INT11PL == 0) +/* Задаёт MINT2_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 2_11PL. */ +#define MINT2_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_11PL. */ +#define MINT2_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT2PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT2PL) || (INT12PL == 0) +/* Задаёт MINT2_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 2_12PL. */ +#define MINT2_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_12PL. */ +#define MINT2_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT2PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT2PL) || (INT13PL == 0) +/* Задаёт MINT2_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 2_13PL. */ +#define MINT2_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_13PL. */ +#define MINT2_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT2PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT2PL) || (INT14PL == 0) +/* Задаёт MINT2_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 2_14PL. */ +#define MINT2_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_14PL. */ +#define MINT2_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT2PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT2PL) || (INT15PL == 0) +/* Задаёт MINT2_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 2_15PL. */ +#define MINT2_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_15PL. */ +#define MINT2_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT2PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT2PL) || (INT16PL == 0) +/* Задаёт MINT2_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 2_16PL. */ +#define MINT2_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT2_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 2_16PL. */ +#define MINT2_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT2 = (MINT2_1PL & MINT2_2PL & MINT2_3PL & MINT2_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 2. */ +#define MINT2 (MINT2_1PL & MINT2_2PL & MINT2_3PL & MINT2_4PL & \ + MINT2_5PL & MINT2_6PL & MINT2_7PL & MINT2_8PL & /* Продолжает список аргументов, полей или выражение MINT2_5PL & MINT2_6PL & MINT2_7PL & MINT2_8PL &; порядок элементов сохраняется. */ \ + MINT2_9PL & MINT2_10PL & MINT2_11PL & MINT2_12PL & /* Продолжает список аргументов, полей или выражение MINT2_9PL & MINT2_10PL & MINT2_11PL & MINT2_12PL &; порядок элементов сохраняется. */ \ + MINT2_13PL & MINT2_14PL & MINT2_15PL & MINT2_16PL) /* Продолжает список аргументов, полей или выражение MINT2_13PL & MINT2_14PL & MINT2_15PL & MINT2_16PL); порядок элементов сохраняется. */ +// End Of MINT2. + +// Beginning of MINT3: +/* Условие компиляции (INT1PL >= INT3PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT3PL) || (INT1PL == 0) +/* Задаёт MINT3_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 3_1PL. */ +#define MINT3_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_1PL. */ +#define MINT3_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT3PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT3PL) || (INT2PL == 0) +/* Задаёт MINT3_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 3_2PL. */ +#define MINT3_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_2PL. */ +#define MINT3_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL == 0) +/* Задаёт MINT3_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 3_3PL. */ +#define MINT3_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_3PL. */ +#define MINT3_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT3PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT3PL) || (INT4PL == 0) +/* Задаёт MINT3_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 3_4PL. */ +#define MINT3_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_4PL. */ +#define MINT3_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT3PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT3PL) || (INT5PL == 0) +/* Задаёт MINT3_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 3_5PL. */ +#define MINT3_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_5PL. */ +#define MINT3_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT3PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT3PL) || (INT6PL == 0) +/* Задаёт MINT3_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 3_6PL. */ +#define MINT3_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_6PL. */ +#define MINT3_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT3PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT3PL) || (INT7PL == 0) +/* Задаёт MINT3_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 3_7PL. */ +#define MINT3_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_7PL. */ +#define MINT3_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT3PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT3PL) || (INT8PL == 0) +/* Задаёт MINT3_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 3_8PL. */ +#define MINT3_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_8PL. */ +#define MINT3_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT3PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT3PL) || (INT9PL == 0) +/* Задаёт MINT3_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 3_9PL. */ +#define MINT3_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_9PL. */ +#define MINT3_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT3PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT3PL) || (INT10PL == 0) +/* Задаёт MINT3_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 3_10PL. */ +#define MINT3_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_10PL. */ +#define MINT3_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT3PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT3PL) || (INT11PL == 0) +/* Задаёт MINT3_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 3_11PL. */ +#define MINT3_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_11PL. */ +#define MINT3_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT3PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT3PL) || (INT12PL == 0) +/* Задаёт MINT3_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 3_12PL. */ +#define MINT3_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_12PL. */ +#define MINT3_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT3PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT3PL) || (INT13PL == 0) +/* Задаёт MINT3_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 3_13PL. */ +#define MINT3_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_13PL. */ +#define MINT3_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT3PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT3PL) || (INT14PL == 0) +/* Задаёт MINT3_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 3_14PL. */ +#define MINT3_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_14PL. */ +#define MINT3_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT3PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT3PL) || (INT15PL == 0) +/* Задаёт MINT3_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 3_15PL. */ +#define MINT3_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_15PL. */ +#define MINT3_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT3PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT3PL) || (INT16PL == 0) +/* Задаёт MINT3_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 3_16PL. */ +#define MINT3_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT3_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 3_16PL. */ +#define MINT3_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT3 = (MINT3_1PL & MINT3_2PL & MINT3_3PL & MINT3_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 3. */ +#define MINT3 (MINT3_1PL & MINT3_2PL & MINT3_3PL & MINT3_4PL & \ + MINT3_5PL & MINT3_6PL & MINT3_7PL & MINT3_8PL & /* Продолжает список аргументов, полей или выражение MINT3_5PL & MINT3_6PL & MINT3_7PL & MINT3_8PL &; порядок элементов сохраняется. */ \ + MINT3_9PL & MINT3_10PL & MINT3_11PL & MINT3_12PL & /* Продолжает список аргументов, полей или выражение MINT3_9PL & MINT3_10PL & MINT3_11PL & MINT3_12PL &; порядок элементов сохраняется. */ \ + MINT3_13PL & MINT3_14PL & MINT3_15PL & MINT3_16PL) /* Продолжает список аргументов, полей или выражение MINT3_13PL & MINT3_14PL & MINT3_15PL & MINT3_16PL); порядок элементов сохраняется. */ +// End Of MINT3. + +// Beginning of MINT4: +/* Условие компиляции (INT1PL >= INT4PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT4PL) || (INT1PL == 0) +/* Задаёт MINT4_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 4_1PL. */ +#define MINT4_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_1PL. */ +#define MINT4_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT4PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT4PL) || (INT2PL == 0) +/* Задаёт MINT4_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 4_2PL. */ +#define MINT4_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_2PL. */ +#define MINT4_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT4PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT4PL) || (INT3PL == 0) +/* Задаёт MINT4_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 4_3PL. */ +#define MINT4_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_3PL. */ +#define MINT4_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL == 0) +/* Задаёт MINT4_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 4_4PL. */ +#define MINT4_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_4PL. */ +#define MINT4_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT4PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT4PL) || (INT5PL == 0) +/* Задаёт MINT4_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 4_5PL. */ +#define MINT4_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_5PL. */ +#define MINT4_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT4PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT4PL) || (INT6PL == 0) +/* Задаёт MINT4_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 4_6PL. */ +#define MINT4_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_6PL. */ +#define MINT4_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT4PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT4PL) || (INT7PL == 0) +/* Задаёт MINT4_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 4_7PL. */ +#define MINT4_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_7PL. */ +#define MINT4_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT4PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT4PL) || (INT8PL == 0) +/* Задаёт MINT4_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 4_8PL. */ +#define MINT4_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_8PL. */ +#define MINT4_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT4PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT4PL) || (INT9PL == 0) +/* Задаёт MINT4_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 4_9PL. */ +#define MINT4_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_9PL. */ +#define MINT4_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT4PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT4PL) || (INT10PL == 0) +/* Задаёт MINT4_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 4_10PL. */ +#define MINT4_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_10PL. */ +#define MINT4_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT4PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT4PL) || (INT11PL == 0) +/* Задаёт MINT4_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 4_11PL. */ +#define MINT4_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_11PL. */ +#define MINT4_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT4PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT4PL) || (INT12PL == 0) +/* Задаёт MINT4_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 4_12PL. */ +#define MINT4_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_12PL. */ +#define MINT4_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT4PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT4PL) || (INT13PL == 0) +/* Задаёт MINT4_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 4_13PL. */ +#define MINT4_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_13PL. */ +#define MINT4_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT4PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT4PL) || (INT14PL == 0) +/* Задаёт MINT4_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 4_14PL. */ +#define MINT4_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_14PL. */ +#define MINT4_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT4PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT4PL) || (INT15PL == 0) +/* Задаёт MINT4_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 4_15PL. */ +#define MINT4_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_15PL. */ +#define MINT4_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT4PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT4PL) || (INT16PL == 0) +/* Задаёт MINT4_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 4_16PL. */ +#define MINT4_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT4_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 4_16PL. */ +#define MINT4_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT4 = (MINT4_1PL & MINT4_2PL & MINT4_3PL & MINT4_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 4. */ +#define MINT4 (MINT4_1PL & MINT4_2PL & MINT4_3PL & MINT4_4PL & \ + MINT4_5PL & MINT4_6PL & MINT4_7PL & MINT4_8PL & /* Продолжает список аргументов, полей или выражение MINT4_5PL & MINT4_6PL & MINT4_7PL & MINT4_8PL &; порядок элементов сохраняется. */ \ + MINT4_9PL & MINT4_10PL & MINT4_11PL & MINT4_12PL & /* Продолжает список аргументов, полей или выражение MINT4_9PL & MINT4_10PL & MINT4_11PL & MINT4_12PL &; порядок элементов сохраняется. */ \ + MINT4_13PL & MINT4_14PL & MINT4_15PL & MINT4_16PL) /* Продолжает список аргументов, полей или выражение MINT4_13PL & MINT4_14PL & MINT4_15PL & MINT4_16PL); порядок элементов сохраняется. */ +// End Of MINT4. + +// Beginning of MINT5: +/* Условие компиляции (INT1PL >= INT5PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT5PL) || (INT1PL == 0) +/* Задаёт MINT5_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 5_1PL. */ +#define MINT5_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_1PL. */ +#define MINT5_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT5PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT5PL) || (INT2PL == 0) +/* Задаёт MINT5_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 5_2PL. */ +#define MINT5_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_2PL. */ +#define MINT5_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT5PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT5PL) || (INT3PL == 0) +/* Задаёт MINT5_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 5_3PL. */ +#define MINT5_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_3PL. */ +#define MINT5_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT5PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT5PL) || (INT4PL == 0) +/* Задаёт MINT5_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 5_4PL. */ +#define MINT5_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_4PL. */ +#define MINT5_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL == 0) +/* Задаёт MINT5_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 5_5PL. */ +#define MINT5_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_5PL. */ +#define MINT5_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT5PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT5PL) || (INT6PL == 0) +/* Задаёт MINT5_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 5_6PL. */ +#define MINT5_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_6PL. */ +#define MINT5_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT5PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT5PL) || (INT7PL == 0) +/* Задаёт MINT5_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 5_7PL. */ +#define MINT5_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_7PL. */ +#define MINT5_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT5PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT5PL) || (INT8PL == 0) +/* Задаёт MINT5_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 5_8PL. */ +#define MINT5_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_8PL. */ +#define MINT5_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT5PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT5PL) || (INT9PL == 0) +/* Задаёт MINT5_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 5_9PL. */ +#define MINT5_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_9PL. */ +#define MINT5_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT5PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT5PL) || (INT10PL == 0) +/* Задаёт MINT5_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 5_10PL. */ +#define MINT5_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_10PL. */ +#define MINT5_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT5PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT5PL) || (INT11PL == 0) +/* Задаёт MINT5_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 5_11PL. */ +#define MINT5_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_11PL. */ +#define MINT5_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT5PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT5PL) || (INT12PL == 0) +/* Задаёт MINT5_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 5_12PL. */ +#define MINT5_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_12PL. */ +#define MINT5_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT5PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT5PL) || (INT13PL == 0) +/* Задаёт MINT5_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 5_13PL. */ +#define MINT5_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_13PL. */ +#define MINT5_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT5PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT5PL) || (INT14PL == 0) +/* Задаёт MINT5_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 5_14PL. */ +#define MINT5_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_14PL. */ +#define MINT5_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT5PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT5PL) || (INT15PL == 0) +/* Задаёт MINT5_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 5_15PL. */ +#define MINT5_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_15PL. */ +#define MINT5_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT5PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT5PL) || (INT16PL == 0) +/* Задаёт MINT5_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 5_16PL. */ +#define MINT5_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT5_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 5_16PL. */ +#define MINT5_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT5 = (MINT5_1PL & MINT5_2PL & MINT5_3PL & MINT5_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 5. */ +#define MINT5 (MINT5_1PL & MINT5_2PL & MINT5_3PL & MINT5_4PL & \ + MINT5_5PL & MINT5_6PL & MINT5_7PL & MINT5_8PL & /* Продолжает список аргументов, полей или выражение MINT5_5PL & MINT5_6PL & MINT5_7PL & MINT5_8PL &; порядок элементов сохраняется. */ \ + MINT5_9PL & MINT5_10PL & MINT5_11PL & MINT5_12PL & /* Продолжает список аргументов, полей или выражение MINT5_9PL & MINT5_10PL & MINT5_11PL & MINT5_12PL &; порядок элементов сохраняется. */ \ + MINT5_13PL & MINT5_14PL & MINT5_15PL & MINT5_16PL) /* Продолжает список аргументов, полей или выражение MINT5_13PL & MINT5_14PL & MINT5_15PL & MINT5_16PL); порядок элементов сохраняется. */ +// End Of MINT5. + +// Beginning of MINT6: +/* Условие компиляции (INT1PL >= INT6PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT6PL) || (INT1PL == 0) +/* Задаёт MINT6_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 6_1PL. */ +#define MINT6_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_1PL. */ +#define MINT6_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT6PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT6PL) || (INT2PL == 0) +/* Задаёт MINT6_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 6_2PL. */ +#define MINT6_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_2PL. */ +#define MINT6_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT6PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT6PL) || (INT3PL == 0) +/* Задаёт MINT6_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 6_3PL. */ +#define MINT6_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_3PL. */ +#define MINT6_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT6PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT6PL) || (INT4PL == 0) +/* Задаёт MINT6_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 6_4PL. */ +#define MINT6_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_4PL. */ +#define MINT6_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT6PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT6PL) || (INT5PL == 0) +/* Задаёт MINT6_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 6_5PL. */ +#define MINT6_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_5PL. */ +#define MINT6_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL == 0) +/* Задаёт MINT6_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 6_6PL. */ +#define MINT6_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_6PL. */ +#define MINT6_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT6PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT6PL) || (INT7PL == 0) +/* Задаёт MINT6_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 6_7PL. */ +#define MINT6_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_7PL. */ +#define MINT6_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT6PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT6PL) || (INT8PL == 0) +/* Задаёт MINT6_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 6_8PL. */ +#define MINT6_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_8PL. */ +#define MINT6_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT6PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT6PL) || (INT9PL == 0) +/* Задаёт MINT6_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 6_9PL. */ +#define MINT6_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_9PL. */ +#define MINT6_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT6PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT6PL) || (INT10PL == 0) +/* Задаёт MINT6_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 6_10PL. */ +#define MINT6_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_10PL. */ +#define MINT6_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT6PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT6PL) || (INT11PL == 0) +/* Задаёт MINT6_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 6_11PL. */ +#define MINT6_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_11PL. */ +#define MINT6_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT6PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT6PL) || (INT12PL == 0) +/* Задаёт MINT6_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 6_12PL. */ +#define MINT6_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_12PL. */ +#define MINT6_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT6PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT6PL) || (INT13PL == 0) +/* Задаёт MINT6_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 6_13PL. */ +#define MINT6_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_13PL. */ +#define MINT6_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT6PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT6PL) || (INT14PL == 0) +/* Задаёт MINT6_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 6_14PL. */ +#define MINT6_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_14PL. */ +#define MINT6_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT6PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT6PL) || (INT15PL == 0) +/* Задаёт MINT6_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 6_15PL. */ +#define MINT6_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_15PL. */ +#define MINT6_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT6PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT6PL) || (INT16PL == 0) +/* Задаёт MINT6_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 6_16PL. */ +#define MINT6_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT6_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 6_16PL. */ +#define MINT6_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT6 = (MINT6_1PL & MINT6_2PL & MINT6_3PL & MINT6_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 6. */ +#define MINT6 (MINT6_1PL & MINT6_2PL & MINT6_3PL & MINT6_4PL & \ + MINT6_5PL & MINT6_6PL & MINT6_7PL & MINT6_8PL & /* Продолжает список аргументов, полей или выражение MINT6_5PL & MINT6_6PL & MINT6_7PL & MINT6_8PL &; порядок элементов сохраняется. */ \ + MINT6_9PL & MINT6_10PL & MINT6_11PL & MINT6_12PL & /* Продолжает список аргументов, полей или выражение MINT6_9PL & MINT6_10PL & MINT6_11PL & MINT6_12PL &; порядок элементов сохраняется. */ \ + MINT6_13PL & MINT6_14PL & MINT6_15PL & MINT6_16PL) /* Продолжает список аргументов, полей или выражение MINT6_13PL & MINT6_14PL & MINT6_15PL & MINT6_16PL); порядок элементов сохраняется. */ +// End Of MINT6. + +// Beginning of MINT7: +/* Условие компиляции (INT1PL >= INT7PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT7PL) || (INT1PL == 0) +/* Задаёт MINT7_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 7_1PL. */ +#define MINT7_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_1PL. */ +#define MINT7_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT7PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT7PL) || (INT2PL == 0) +/* Задаёт MINT7_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 7_2PL. */ +#define MINT7_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_2PL. */ +#define MINT7_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT7PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT7PL) || (INT3PL == 0) +/* Задаёт MINT7_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 7_3PL. */ +#define MINT7_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_3PL. */ +#define MINT7_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT7PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT7PL) || (INT4PL == 0) +/* Задаёт MINT7_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 7_4PL. */ +#define MINT7_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_4PL. */ +#define MINT7_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT7PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT7PL) || (INT5PL == 0) +/* Задаёт MINT7_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 7_5PL. */ +#define MINT7_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_5PL. */ +#define MINT7_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT7PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT7PL) || (INT6PL == 0) +/* Задаёт MINT7_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 7_6PL. */ +#define MINT7_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_6PL. */ +#define MINT7_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL == 0) +/* Задаёт MINT7_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 7_7PL. */ +#define MINT7_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_7PL. */ +#define MINT7_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT7PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT7PL) || (INT8PL == 0) +/* Задаёт MINT7_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 7_8PL. */ +#define MINT7_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_8PL. */ +#define MINT7_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT7PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT7PL) || (INT9PL == 0) +/* Задаёт MINT7_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 7_9PL. */ +#define MINT7_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_9PL. */ +#define MINT7_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT7PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT7PL) || (INT10PL == 0) +/* Задаёт MINT7_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 7_10PL. */ +#define MINT7_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_10PL. */ +#define MINT7_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT7PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT7PL) || (INT11PL == 0) +/* Задаёт MINT7_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 7_11PL. */ +#define MINT7_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_11PL. */ +#define MINT7_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT7PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT7PL) || (INT12PL == 0) +/* Задаёт MINT7_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 7_12PL. */ +#define MINT7_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_12PL. */ +#define MINT7_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT7PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT7PL) || (INT13PL == 0) +/* Задаёт MINT7_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 7_13PL. */ +#define MINT7_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_13PL. */ +#define MINT7_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT7PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT7PL) || (INT14PL == 0) +/* Задаёт MINT7_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 7_14PL. */ +#define MINT7_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_14PL. */ +#define MINT7_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT7PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT7PL) || (INT15PL == 0) +/* Задаёт MINT7_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 7_15PL. */ +#define MINT7_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_15PL. */ +#define MINT7_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT7PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT7PL) || (INT16PL == 0) +/* Задаёт MINT7_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 7_16PL. */ +#define MINT7_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT7_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 7_16PL. */ +#define MINT7_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT7 = (MINT7_1PL & MINT7_2PL & MINT7_3PL & MINT7_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 7. */ +#define MINT7 (MINT7_1PL & MINT7_2PL & MINT7_3PL & MINT7_4PL & \ + MINT7_5PL & MINT7_6PL & MINT7_7PL & MINT7_8PL & /* Продолжает список аргументов, полей или выражение MINT7_5PL & MINT7_6PL & MINT7_7PL & MINT7_8PL &; порядок элементов сохраняется. */ \ + MINT7_9PL & MINT7_10PL & MINT7_11PL & MINT7_12PL & /* Продолжает список аргументов, полей или выражение MINT7_9PL & MINT7_10PL & MINT7_11PL & MINT7_12PL &; порядок элементов сохраняется. */ \ + MINT7_13PL & MINT7_14PL & MINT7_15PL & MINT7_16PL) /* Продолжает список аргументов, полей или выражение MINT7_13PL & MINT7_14PL & MINT7_15PL & MINT7_16PL); порядок элементов сохраняется. */ +// End Of MINT7. + +// Beginning of MINT8: +/* Условие компиляции (INT1PL >= INT8PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT8PL) || (INT1PL == 0) +/* Задаёт MINT8_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 8_1PL. */ +#define MINT8_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_1PL. */ +#define MINT8_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT8PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT8PL) || (INT2PL == 0) +/* Задаёт MINT8_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 8_2PL. */ +#define MINT8_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_2PL. */ +#define MINT8_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT8PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT8PL) || (INT3PL == 0) +/* Задаёт MINT8_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 8_3PL. */ +#define MINT8_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_3PL. */ +#define MINT8_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT8PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT8PL) || (INT4PL == 0) +/* Задаёт MINT8_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 8_4PL. */ +#define MINT8_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_4PL. */ +#define MINT8_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT8PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT8PL) || (INT5PL == 0) +/* Задаёт MINT8_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 8_5PL. */ +#define MINT8_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_5PL. */ +#define MINT8_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT8PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT8PL) || (INT6PL == 0) +/* Задаёт MINT8_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 8_6PL. */ +#define MINT8_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_6PL. */ +#define MINT8_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT8PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT8PL) || (INT7PL == 0) +/* Задаёт MINT8_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 8_7PL. */ +#define MINT8_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_7PL. */ +#define MINT8_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL == 0) +/* Задаёт MINT8_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 8_8PL. */ +#define MINT8_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_8PL. */ +#define MINT8_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT8PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT8PL) || (INT9PL == 0) +/* Задаёт MINT8_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 8_9PL. */ +#define MINT8_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_9PL. */ +#define MINT8_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT8PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT8PL) || (INT10PL == 0) +/* Задаёт MINT8_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 8_10PL. */ +#define MINT8_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_10PL. */ +#define MINT8_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT8PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT8PL) || (INT11PL == 0) +/* Задаёт MINT8_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 8_11PL. */ +#define MINT8_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_11PL. */ +#define MINT8_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT8PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT8PL) || (INT12PL == 0) +/* Задаёт MINT8_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 8_12PL. */ +#define MINT8_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_12PL. */ +#define MINT8_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT8PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT8PL) || (INT13PL == 0) +/* Задаёт MINT8_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 8_13PL. */ +#define MINT8_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_13PL. */ +#define MINT8_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT8PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT8PL) || (INT14PL == 0) +/* Задаёт MINT8_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 8_14PL. */ +#define MINT8_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_14PL. */ +#define MINT8_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT8PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT8PL) || (INT15PL == 0) +/* Задаёт MINT8_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 8_15PL. */ +#define MINT8_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_15PL. */ +#define MINT8_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT8PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT8PL) || (INT16PL == 0) +/* Задаёт MINT8_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 8_16PL. */ +#define MINT8_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT8_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 8_16PL. */ +#define MINT8_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT8 = (MINT8_1PL & MINT8_2PL & MINT8_3PL & MINT8_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 8. */ +#define MINT8 (MINT8_1PL & MINT8_2PL & MINT8_3PL & MINT8_4PL & \ + MINT8_5PL & MINT8_6PL & MINT8_7PL & MINT8_8PL & /* Продолжает список аргументов, полей или выражение MINT8_5PL & MINT8_6PL & MINT8_7PL & MINT8_8PL &; порядок элементов сохраняется. */ \ + MINT8_9PL & MINT8_10PL & MINT8_11PL & MINT8_12PL & /* Продолжает список аргументов, полей или выражение MINT8_9PL & MINT8_10PL & MINT8_11PL & MINT8_12PL &; порядок элементов сохраняется. */ \ + MINT8_13PL & MINT8_14PL & MINT8_15PL & MINT8_16PL) /* Продолжает список аргументов, полей или выражение MINT8_13PL & MINT8_14PL & MINT8_15PL & MINT8_16PL); порядок элементов сохраняется. */ +// End Of MINT8. + +// Beginning of MINT9: +/* Условие компиляции (INT1PL >= INT9PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT9PL) || (INT1PL == 0) +/* Задаёт MINT9_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 9_1PL. */ +#define MINT9_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_1PL. */ +#define MINT9_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT9PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT9PL) || (INT2PL == 0) +/* Задаёт MINT9_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 9_2PL. */ +#define MINT9_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_2PL. */ +#define MINT9_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT9PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT9PL) || (INT3PL == 0) +/* Задаёт MINT9_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 9_3PL. */ +#define MINT9_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_3PL. */ +#define MINT9_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT9PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT9PL) || (INT4PL == 0) +/* Задаёт MINT9_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 9_4PL. */ +#define MINT9_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_4PL. */ +#define MINT9_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT9PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT9PL) || (INT5PL == 0) +/* Задаёт MINT9_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 9_5PL. */ +#define MINT9_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_5PL. */ +#define MINT9_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT9PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT9PL) || (INT6PL == 0) +/* Задаёт MINT9_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 9_6PL. */ +#define MINT9_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_6PL. */ +#define MINT9_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT9PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT9PL) || (INT7PL == 0) +/* Задаёт MINT9_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 9_7PL. */ +#define MINT9_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_7PL. */ +#define MINT9_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT9PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT9PL) || (INT8PL == 0) +/* Задаёт MINT9_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 9_8PL. */ +#define MINT9_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_8PL. */ +#define MINT9_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL == 0) +/* Задаёт MINT9_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 9_9PL. */ +#define MINT9_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_9PL. */ +#define MINT9_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT9PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT9PL) || (INT10PL == 0) +/* Задаёт MINT9_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 9_10PL. */ +#define MINT9_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_10PL. */ +#define MINT9_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT9PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT9PL) || (INT11PL == 0) +/* Задаёт MINT9_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 9_11PL. */ +#define MINT9_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_11PL. */ +#define MINT9_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT9PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT9PL) || (INT12PL == 0) +/* Задаёт MINT9_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 9_12PL. */ +#define MINT9_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_12PL. */ +#define MINT9_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT9PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT9PL) || (INT13PL == 0) +/* Задаёт MINT9_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 9_13PL. */ +#define MINT9_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_13PL. */ +#define MINT9_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT9PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT9PL) || (INT14PL == 0) +/* Задаёт MINT9_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 9_14PL. */ +#define MINT9_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_14PL. */ +#define MINT9_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT9PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT9PL) || (INT15PL == 0) +/* Задаёт MINT9_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 9_15PL. */ +#define MINT9_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_15PL. */ +#define MINT9_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT9PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT9PL) || (INT16PL == 0) +/* Задаёт MINT9_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 9_16PL. */ +#define MINT9_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT9_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 9_16PL. */ +#define MINT9_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT9 = (MINT9_1PL & MINT9_2PL & MINT9_3PL & MINT9_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 9. */ +#define MINT9 (MINT9_1PL & MINT9_2PL & MINT9_3PL & MINT9_4PL & \ + MINT9_5PL & MINT9_6PL & MINT9_7PL & MINT9_8PL & /* Продолжает список аргументов, полей или выражение MINT9_5PL & MINT9_6PL & MINT9_7PL & MINT9_8PL &; порядок элементов сохраняется. */ \ + MINT9_9PL & MINT9_10PL & MINT9_11PL & MINT9_12PL & /* Продолжает список аргументов, полей или выражение MINT9_9PL & MINT9_10PL & MINT9_11PL & MINT9_12PL &; порядок элементов сохраняется. */ \ + MINT9_13PL & MINT9_14PL & MINT9_15PL & MINT9_16PL) /* Продолжает список аргументов, полей или выражение MINT9_13PL & MINT9_14PL & MINT9_15PL & MINT9_16PL); порядок элементов сохраняется. */ +// End Of MINT9. + +// Beginning of MINT10: +/* Условие компиляции (INT1PL >= INT10PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT10PL) || (INT1PL == 0) +/* Задаёт MINT10_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 10_1PL. */ +#define MINT10_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_1PL. */ +#define MINT10_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT10PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT10PL) || (INT2PL == 0) +/* Задаёт MINT10_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 10_2PL. */ +#define MINT10_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_2PL. */ +#define MINT10_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT10PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT10PL) || (INT3PL == 0) +/* Задаёт MINT10_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 10_3PL. */ +#define MINT10_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_3PL. */ +#define MINT10_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT10PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT10PL) || (INT4PL == 0) +/* Задаёт MINT10_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 10_4PL. */ +#define MINT10_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_4PL. */ +#define MINT10_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT10PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT10PL) || (INT5PL == 0) +/* Задаёт MINT10_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 10_5PL. */ +#define MINT10_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_5PL. */ +#define MINT10_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT10PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT10PL) || (INT6PL == 0) +/* Задаёт MINT10_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 10_6PL. */ +#define MINT10_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_6PL. */ +#define MINT10_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT10PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT10PL) || (INT7PL == 0) +/* Задаёт MINT10_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 10_7PL. */ +#define MINT10_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_7PL. */ +#define MINT10_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT10PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT10PL) || (INT8PL == 0) +/* Задаёт MINT10_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 10_8PL. */ +#define MINT10_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_8PL. */ +#define MINT10_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT10PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT10PL) || (INT9PL == 0) +/* Задаёт MINT10_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 10_9PL. */ +#define MINT10_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_9PL. */ +#define MINT10_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL == 0) +/* Задаёт MINT10_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 10_10PL. */ +#define MINT10_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_10PL. */ +#define MINT10_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT10PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT10PL) || (INT11PL == 0) +/* Задаёт MINT10_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 10_11PL. */ +#define MINT10_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_11PL. */ +#define MINT10_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT10PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT10PL) || (INT12PL == 0) +/* Задаёт MINT10_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 10_12PL. */ +#define MINT10_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_12PL. */ +#define MINT10_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT10PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT10PL) || (INT13PL == 0) +/* Задаёт MINT10_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 10_13PL. */ +#define MINT10_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_13PL. */ +#define MINT10_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT10PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT10PL) || (INT14PL == 0) +/* Задаёт MINT10_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 10_14PL. */ +#define MINT10_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_14PL. */ +#define MINT10_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT10PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT10PL) || (INT15PL == 0) +/* Задаёт MINT10_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 10_15PL. */ +#define MINT10_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_15PL. */ +#define MINT10_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT10PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT10PL) || (INT16PL == 0) +/* Задаёт MINT10_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 10_16PL. */ +#define MINT10_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT10_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 10_16PL. */ +#define MINT10_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT10 = (MINT10_1PL & MINT10_2PL & MINT10_3PL & MINT10_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 10. */ +#define MINT10 (MINT10_1PL & MINT10_2PL & MINT10_3PL & MINT10_4PL & \ + MINT10_5PL & MINT10_6PL & MINT10_7PL & MINT10_8PL & /* Продолжает список аргументов, полей или выражение MINT10_5PL & MINT10_6PL & MINT10_7PL & MINT10_8PL &; порядок элементов сохраняется. */ \ + MINT10_9PL & MINT10_10PL & MINT10_11PL & MINT10_12PL & /* Продолжает список аргументов, полей или выражение MINT10_9PL & MINT10_10PL & MINT10_11PL & MINT10_12PL &; порядок элементов сохраняется. */ \ + MINT10_13PL & MINT10_14PL & MINT10_15PL & MINT10_16PL) /* Продолжает список аргументов, полей или выражение MINT10_13PL & MINT10_14PL & MINT10_15PL & MINT10_16PL); порядок элементов сохраняется. */ +// End Of MINT10. + +// Beginning of MINT11: +/* Условие компиляции (INT1PL >= INT11PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT11PL) || (INT1PL == 0) +/* Задаёт MINT11_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 11_1PL. */ +#define MINT11_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_1PL. */ +#define MINT11_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT11PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT11PL) || (INT2PL == 0) +/* Задаёт MINT11_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 11_2PL. */ +#define MINT11_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_2PL. */ +#define MINT11_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT11PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT11PL) || (INT3PL == 0) +/* Задаёт MINT11_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 11_3PL. */ +#define MINT11_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_3PL. */ +#define MINT11_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT11PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT11PL) || (INT4PL == 0) +/* Задаёт MINT11_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 11_4PL. */ +#define MINT11_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_4PL. */ +#define MINT11_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT11PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT11PL) || (INT5PL == 0) +/* Задаёт MINT11_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 11_5PL. */ +#define MINT11_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_5PL. */ +#define MINT11_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT11PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT11PL) || (INT6PL == 0) +/* Задаёт MINT11_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 11_6PL. */ +#define MINT11_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_6PL. */ +#define MINT11_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT11PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT11PL) || (INT7PL == 0) +/* Задаёт MINT11_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 11_7PL. */ +#define MINT11_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_7PL. */ +#define MINT11_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT11PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT11PL) || (INT8PL == 0) +/* Задаёт MINT11_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 11_8PL. */ +#define MINT11_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_8PL. */ +#define MINT11_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT11PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT11PL) || (INT9PL == 0) +/* Задаёт MINT11_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 11_9PL. */ +#define MINT11_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_9PL. */ +#define MINT11_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT11PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT11PL) || (INT10PL == 0) +/* Задаёт MINT11_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 11_10PL. */ +#define MINT11_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_10PL. */ +#define MINT11_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL == 0) +/* Задаёт MINT11_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 11_11PL. */ +#define MINT11_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_11PL. */ +#define MINT11_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT11PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT11PL) || (INT12PL == 0) +/* Задаёт MINT11_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 11_12PL. */ +#define MINT11_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_12PL. */ +#define MINT11_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT11PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT11PL) || (INT13PL == 0) +/* Задаёт MINT11_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 11_13PL. */ +#define MINT11_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_13PL. */ +#define MINT11_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT11PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT11PL) || (INT14PL == 0) +/* Задаёт MINT11_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 11_14PL. */ +#define MINT11_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_14PL. */ +#define MINT11_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT11PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT11PL) || (INT15PL == 0) +/* Задаёт MINT11_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 11_15PL. */ +#define MINT11_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_15PL. */ +#define MINT11_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT11PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT11PL) || (INT16PL == 0) +/* Задаёт MINT11_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 11_16PL. */ +#define MINT11_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT11_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 11_16PL. */ +#define MINT11_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT11 = (MINT11_1PL & MINT11_2PL & MINT11_3PL & MINT11_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 11. */ +#define MINT11 (MINT11_1PL & MINT11_2PL & MINT11_3PL & MINT11_4PL & \ + MINT11_5PL & MINT11_6PL & MINT11_7PL & MINT11_8PL & /* Продолжает список аргументов, полей или выражение MINT11_5PL & MINT11_6PL & MINT11_7PL & MINT11_8PL &; порядок элементов сохраняется. */ \ + MINT11_9PL & MINT11_10PL & MINT11_11PL & MINT11_12PL & /* Продолжает список аргументов, полей или выражение MINT11_9PL & MINT11_10PL & MINT11_11PL & MINT11_12PL &; порядок элементов сохраняется. */ \ + MINT11_13PL & MINT11_14PL & MINT11_15PL & MINT11_16PL) /* Продолжает список аргументов, полей или выражение MINT11_13PL & MINT11_14PL & MINT11_15PL & MINT11_16PL); порядок элементов сохраняется. */ +// End Of MINT11. + +// Beginning of MINT12: +/* Условие компиляции (INT1PL >= INT12PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT12PL) || (INT1PL == 0) +/* Задаёт MINT12_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 12_1PL. */ +#define MINT12_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_1PL. */ +#define MINT12_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT12PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT12PL) || (INT2PL == 0) +/* Задаёт MINT12_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 12_2PL. */ +#define MINT12_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_2PL. */ +#define MINT12_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT12PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT12PL) || (INT3PL == 0) +/* Задаёт MINT12_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 12_3PL. */ +#define MINT12_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_3PL. */ +#define MINT12_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT12PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT12PL) || (INT4PL == 0) +/* Задаёт MINT12_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 12_4PL. */ +#define MINT12_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_4PL. */ +#define MINT12_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT12PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT12PL) || (INT5PL == 0) +/* Задаёт MINT12_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 12_5PL. */ +#define MINT12_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_5PL. */ +#define MINT12_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT12PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT12PL) || (INT6PL == 0) +/* Задаёт MINT12_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 12_6PL. */ +#define MINT12_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_6PL. */ +#define MINT12_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT12PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT12PL) || (INT7PL == 0) +/* Задаёт MINT12_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 12_7PL. */ +#define MINT12_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_7PL. */ +#define MINT12_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT12PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT12PL) || (INT8PL == 0) +/* Задаёт MINT12_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 12_8PL. */ +#define MINT12_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_8PL. */ +#define MINT12_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT12PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT12PL) || (INT9PL == 0) +/* Задаёт MINT12_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 12_9PL. */ +#define MINT12_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_9PL. */ +#define MINT12_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT12PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT12PL) || (INT10PL == 0) +/* Задаёт MINT12_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 12_10PL. */ +#define MINT12_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_10PL. */ +#define MINT12_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT12PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT12PL) || (INT11PL == 0) +/* Задаёт MINT12_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 12_11PL. */ +#define MINT12_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_11PL. */ +#define MINT12_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL == 0) +/* Задаёт MINT12_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 12_12PL. */ +#define MINT12_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_12PL. */ +#define MINT12_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT12PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT12PL) || (INT13PL == 0) +/* Задаёт MINT12_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 12_13PL. */ +#define MINT12_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_13PL. */ +#define MINT12_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT12PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT12PL) || (INT14PL == 0) +/* Задаёт MINT12_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 12_14PL. */ +#define MINT12_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_14PL. */ +#define MINT12_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT12PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT12PL) || (INT15PL == 0) +/* Задаёт MINT12_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 12_15PL. */ +#define MINT12_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_15PL. */ +#define MINT12_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT12PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT12PL) || (INT16PL == 0) +/* Задаёт MINT12_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 12_16PL. */ +#define MINT12_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT12_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 12_16PL. */ +#define MINT12_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT12 = (MINT12_1PL & MINT12_2PL & MINT12_3PL & MINT12_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 12. */ +#define MINT12 (MINT12_1PL & MINT12_2PL & MINT12_3PL & MINT12_4PL & \ + MINT12_5PL & MINT12_6PL & MINT12_7PL & MINT12_8PL & /* Продолжает список аргументов, полей или выражение MINT12_5PL & MINT12_6PL & MINT12_7PL & MINT12_8PL &; порядок элементов сохраняется. */ \ + MINT12_9PL & MINT12_10PL & MINT12_11PL & MINT12_12PL & /* Продолжает список аргументов, полей или выражение MINT12_9PL & MINT12_10PL & MINT12_11PL & MINT12_12PL &; порядок элементов сохраняется. */ \ + MINT12_13PL & MINT12_14PL & MINT12_15PL & MINT12_16PL) /* Продолжает список аргументов, полей или выражение MINT12_13PL & MINT12_14PL & MINT12_15PL & MINT12_16PL); порядок элементов сохраняется. */ +// End Of MINT12. + +// Beginning of MINT13: +/* Условие компиляции (INT1PL >= INT13PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT13PL) || (INT1PL == 0) +/* Задаёт MINT13_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 13_1PL. */ +#define MINT13_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_1PL. */ +#define MINT13_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT13PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT13PL) || (INT2PL == 0) +/* Задаёт MINT13_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 13_2PL. */ +#define MINT13_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_2PL. */ +#define MINT13_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT13PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT13PL) || (INT3PL == 0) +/* Задаёт MINT13_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 13_3PL. */ +#define MINT13_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_3PL. */ +#define MINT13_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT13PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT13PL) || (INT4PL == 0) +/* Задаёт MINT13_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 13_4PL. */ +#define MINT13_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_4PL. */ +#define MINT13_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT13PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT13PL) || (INT5PL == 0) +/* Задаёт MINT13_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 13_5PL. */ +#define MINT13_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_5PL. */ +#define MINT13_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT13PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT13PL) || (INT6PL == 0) +/* Задаёт MINT13_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 13_6PL. */ +#define MINT13_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_6PL. */ +#define MINT13_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT13PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT13PL) || (INT7PL == 0) +/* Задаёт MINT13_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 13_7PL. */ +#define MINT13_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_7PL. */ +#define MINT13_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT13PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT13PL) || (INT8PL == 0) +/* Задаёт MINT13_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 13_8PL. */ +#define MINT13_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_8PL. */ +#define MINT13_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT13PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT13PL) || (INT9PL == 0) +/* Задаёт MINT13_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 13_9PL. */ +#define MINT13_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_9PL. */ +#define MINT13_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT13PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT13PL) || (INT10PL == 0) +/* Задаёт MINT13_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 13_10PL. */ +#define MINT13_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_10PL. */ +#define MINT13_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT13PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT13PL) || (INT11PL == 0) +/* Задаёт MINT13_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 13_11PL. */ +#define MINT13_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_11PL. */ +#define MINT13_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT13_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 13_12PL. */ +#define MINT13_12PL ~(1 << 11) + +/* Условие компиляции (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL == 0) +/* Задаёт MINT13_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 13_13PL. */ +#define MINT13_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_13PL. */ +#define MINT13_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT13PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT13PL) || (INT14PL == 0) +/* Задаёт MINT13_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 13_14PL. */ +#define MINT13_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_14PL. */ +#define MINT13_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT13PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT13PL) || (INT15PL == 0) +/* Задаёт MINT13_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 13_15PL. */ +#define MINT13_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_15PL. */ +#define MINT13_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT13PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT13PL) || (INT16PL == 0) +/* Задаёт MINT13_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 13_16PL. */ +#define MINT13_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT13_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 13_16PL. */ +#define MINT13_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT13 = (MINT13_1PL & MINT13_2PL & MINT13_3PL & MINT13_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 13. */ +#define MINT13 (MINT13_1PL & MINT13_2PL & MINT13_3PL & MINT13_4PL & \ + MINT13_5PL & MINT13_6PL & MINT13_7PL & MINT13_8PL & /* Продолжает список аргументов, полей или выражение MINT13_5PL & MINT13_6PL & MINT13_7PL & MINT13_8PL &; порядок элементов сохраняется. */ \ + MINT13_9PL & MINT13_10PL & MINT13_11PL & MINT13_12PL & /* Продолжает список аргументов, полей или выражение MINT13_9PL & MINT13_10PL & MINT13_11PL & MINT13_12PL &; порядок элементов сохраняется. */ \ + MINT13_13PL & MINT13_14PL & MINT13_15PL & MINT13_16PL) /* Продолжает список аргументов, полей или выражение MINT13_13PL & MINT13_14PL & MINT13_15PL & MINT13_16PL); порядок элементов сохраняется. */ +// End Of MINT13. + +// Beginning of MINT14: +/* Условие компиляции (INT1PL >= INT14PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT14PL) || (INT1PL == 0) +/* Задаёт MINT14_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 14_1PL. */ +#define MINT14_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_1PL. */ +#define MINT14_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT14PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT14PL) || (INT2PL == 0) +/* Задаёт MINT14_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 14_2PL. */ +#define MINT14_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_2PL. */ +#define MINT14_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT14PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT14PL) || (INT3PL == 0) +/* Задаёт MINT14_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 14_3PL. */ +#define MINT14_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_3PL. */ +#define MINT14_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT14PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT14PL) || (INT4PL == 0) +/* Задаёт MINT14_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 14_4PL. */ +#define MINT14_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_4PL. */ +#define MINT14_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT14PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT14PL) || (INT5PL == 0) +/* Задаёт MINT14_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 14_5PL. */ +#define MINT14_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_5PL. */ +#define MINT14_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT14PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT14PL) || (INT6PL == 0) +/* Задаёт MINT14_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 14_6PL. */ +#define MINT14_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_6PL. */ +#define MINT14_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT14PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT14PL) || (INT7PL == 0) +/* Задаёт MINT14_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 14_7PL. */ +#define MINT14_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_7PL. */ +#define MINT14_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT14PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT14PL) || (INT8PL == 0) +/* Задаёт MINT14_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 14_8PL. */ +#define MINT14_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_8PL. */ +#define MINT14_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT14PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT14PL) || (INT9PL == 0) +/* Задаёт MINT14_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 14_9PL. */ +#define MINT14_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_9PL. */ +#define MINT14_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT14PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT14PL) || (INT10PL == 0) +/* Задаёт MINT14_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 14_10PL. */ +#define MINT14_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_10PL. */ +#define MINT14_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT14PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT14PL) || (INT11PL == 0) +/* Задаёт MINT14_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 14_11PL. */ +#define MINT14_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_11PL. */ +#define MINT14_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT14PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT14PL) || (INT12PL == 0) +/* Задаёт MINT14_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 14_12PL. */ +#define MINT14_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_12PL. */ +#define MINT14_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT14PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT14PL) || (INT13PL == 0) +/* Задаёт MINT14_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 14_13PL. */ +#define MINT14_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_13PL. */ +#define MINT14_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT14_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 14_14PL. */ +#define MINT14_14PL ~(1 << 13) + +/* Условие компиляции (INT15PL >= INT14PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT14PL) || (INT15PL == 0) +/* Задаёт MINT14_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 14_15PL. */ +#define MINT14_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_15PL. */ +#define MINT14_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT16PL >= INT14PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT14PL) || (INT16PL == 0) +/* Задаёт MINT14_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 14_16PL. */ +#define MINT14_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT14_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 14_16PL. */ +#define MINT14_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT14 = (MINT14_1PL & MINT14_2PL & MINT14_3PL & MINT14_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 14. */ +#define MINT14 (MINT14_1PL & MINT14_2PL & MINT14_3PL & MINT14_4PL & \ + MINT14_5PL & MINT14_6PL & MINT14_7PL & MINT14_8PL & /* Продолжает список аргументов, полей или выражение MINT14_5PL & MINT14_6PL & MINT14_7PL & MINT14_8PL &; порядок элементов сохраняется. */ \ + MINT14_9PL & MINT14_10PL & MINT14_11PL & MINT14_12PL & /* Продолжает список аргументов, полей или выражение MINT14_9PL & MINT14_10PL & MINT14_11PL & MINT14_12PL &; порядок элементов сохраняется. */ \ + MINT14_13PL & MINT14_14PL & MINT14_15PL & MINT14_16PL) /* Продолжает список аргументов, полей или выражение MINT14_13PL & MINT14_14PL & MINT14_15PL & MINT14_16PL); порядок элементов сохраняется. */ +// End Of MINT14. + +// Beginning of MINT15: +/* Условие компиляции (INT1PL >= INT15PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT15PL) || (INT1PL == 0) +/* Задаёт MINT15_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 15_1PL. */ +#define MINT15_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_1PL. */ +#define MINT15_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT15PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT15PL) || (INT2PL == 0) +/* Задаёт MINT15_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 15_2PL. */ +#define MINT15_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_2PL. */ +#define MINT15_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT15PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT15PL) || (INT3PL == 0) +/* Задаёт MINT15_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 15_3PL. */ +#define MINT15_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_3PL. */ +#define MINT15_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT15PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT15PL) || (INT4PL == 0) +/* Задаёт MINT15_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 15_4PL. */ +#define MINT15_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_4PL. */ +#define MINT15_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT15PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT15PL) || (INT5PL == 0) +/* Задаёт MINT15_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 15_5PL. */ +#define MINT15_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_5PL. */ +#define MINT15_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT15PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT15PL) || (INT6PL == 0) +/* Задаёт MINT15_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 15_6PL. */ +#define MINT15_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_6PL. */ +#define MINT15_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT15PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT15PL) || (INT7PL == 0) +/* Задаёт MINT15_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 15_7PL. */ +#define MINT15_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_7PL. */ +#define MINT15_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT15PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT15PL) || (INT8PL == 0) +/* Задаёт MINT15_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 15_8PL. */ +#define MINT15_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_8PL. */ +#define MINT15_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT15PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT15PL) || (INT9PL == 0) +/* Задаёт MINT15_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 15_9PL. */ +#define MINT15_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_9PL. */ +#define MINT15_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT15PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT15PL) || (INT10PL == 0) +/* Задаёт MINT15_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 15_10PL. */ +#define MINT15_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_10PL. */ +#define MINT15_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT15PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT15PL) || (INT11PL == 0) +/* Задаёт MINT15_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 15_11PL. */ +#define MINT15_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_11PL. */ +#define MINT15_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT15PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT15PL) || (INT12PL == 0) +/* Задаёт MINT15_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 15_12PL. */ +#define MINT15_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_12PL. */ +#define MINT15_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT15PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT15PL) || (INT13PL == 0) +/* Задаёт MINT15_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 15_13PL. */ +#define MINT15_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_13PL. */ +#define MINT15_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT15PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT15PL) || (INT14PL == 0) +/* Задаёт MINT15_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 15_14PL. */ +#define MINT15_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_14PL. */ +#define MINT15_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT15_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 15_15PL. */ +#define MINT15_15PL ~(1 << 14) + +/* Условие компиляции (INT16PL >= INT15PL) или (INT16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT16PL >= INT15PL) || (INT16PL == 0) +/* Задаёт MINT15_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 15_16PL. */ +#define MINT15_16PL ~(1 << 15) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT15_16PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 15_16PL. */ +#define MINT15_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT15 = (MINT15_1PL & MINT15_2PL & MINT15_3PL & MINT15_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 15. */ +#define MINT15 (MINT15_1PL & MINT15_2PL & MINT15_3PL & MINT15_4PL & \ + MINT15_5PL & MINT15_6PL & MINT15_7PL & MINT15_8PL & /* Продолжает список аргументов, полей или выражение MINT15_5PL & MINT15_6PL & MINT15_7PL & MINT15_8PL &; порядок элементов сохраняется. */ \ + MINT15_9PL & MINT15_10PL & MINT15_11PL & MINT15_12PL & /* Продолжает список аргументов, полей или выражение MINT15_9PL & MINT15_10PL & MINT15_11PL & MINT15_12PL &; порядок элементов сохраняется. */ \ + MINT15_13PL & MINT15_14PL & MINT15_15PL & MINT15_16PL) /* Продолжает список аргументов, полей или выражение MINT15_13PL & MINT15_14PL & MINT15_15PL & MINT15_16PL); порядок элементов сохраняется. */ +// End Of MINT15. + +// Beginning of MINT16: +/* Условие компиляции (INT1PL >= INT16PL) или (INT1PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT1PL >= INT16PL) || (INT1PL == 0) +/* Задаёт MINT16_1PL = ~(1 << 0); маска разрешённых прерываний ядра для приоритетного обработчика 16_1PL. */ +#define MINT16_1PL ~(1 << 0) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_1PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_1PL. */ +#define MINT16_1PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT2PL >= INT16PL) или (INT2PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT2PL >= INT16PL) || (INT2PL == 0) +/* Задаёт MINT16_2PL = ~(1 << 1); маска разрешённых прерываний ядра для приоритетного обработчика 16_2PL. */ +#define MINT16_2PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_2PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_2PL. */ +#define MINT16_2PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT3PL >= INT16PL) или (INT3PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT3PL >= INT16PL) || (INT3PL == 0) +/* Задаёт MINT16_3PL = ~(1 << 2); маска разрешённых прерываний ядра для приоритетного обработчика 16_3PL. */ +#define MINT16_3PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_3PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_3PL. */ +#define MINT16_3PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT4PL >= INT16PL) или (INT4PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT4PL >= INT16PL) || (INT4PL == 0) +/* Задаёт MINT16_4PL = ~(1 << 3); маска разрешённых прерываний ядра для приоритетного обработчика 16_4PL. */ +#define MINT16_4PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_4PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_4PL. */ +#define MINT16_4PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT5PL >= INT16PL) или (INT5PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT5PL >= INT16PL) || (INT5PL == 0) +/* Задаёт MINT16_5PL = ~(1 << 4); маска разрешённых прерываний ядра для приоритетного обработчика 16_5PL. */ +#define MINT16_5PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_5PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_5PL. */ +#define MINT16_5PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT6PL >= INT16PL) или (INT6PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT6PL >= INT16PL) || (INT6PL == 0) +/* Задаёт MINT16_6PL = ~(1 << 5); маска разрешённых прерываний ядра для приоритетного обработчика 16_6PL. */ +#define MINT16_6PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_6PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_6PL. */ +#define MINT16_6PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT7PL >= INT16PL) или (INT7PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT7PL >= INT16PL) || (INT7PL == 0) +/* Задаёт MINT16_7PL = ~(1 << 6); маска разрешённых прерываний ядра для приоритетного обработчика 16_7PL. */ +#define MINT16_7PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_7PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_7PL. */ +#define MINT16_7PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT8PL >= INT16PL) или (INT8PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT8PL >= INT16PL) || (INT8PL == 0) +/* Задаёт MINT16_8PL = ~(1 << 7); маска разрешённых прерываний ядра для приоритетного обработчика 16_8PL. */ +#define MINT16_8PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_8PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_8PL. */ +#define MINT16_8PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT9PL >= INT16PL) или (INT9PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT9PL >= INT16PL) || (INT9PL == 0) +/* Задаёт MINT16_9PL = ~(1 << 8); маска разрешённых прерываний ядра для приоритетного обработчика 16_9PL. */ +#define MINT16_9PL ~(1 << 8) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_9PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_9PL. */ +#define MINT16_9PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT10PL >= INT16PL) или (INT10PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT10PL >= INT16PL) || (INT10PL == 0) +/* Задаёт MINT16_10PL = ~(1 << 9); маска разрешённых прерываний ядра для приоритетного обработчика 16_10PL. */ +#define MINT16_10PL ~(1 << 9) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_10PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_10PL. */ +#define MINT16_10PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT11PL >= INT16PL) или (INT11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT11PL >= INT16PL) || (INT11PL == 0) +/* Задаёт MINT16_11PL = ~(1 << 10); маска разрешённых прерываний ядра для приоритетного обработчика 16_11PL. */ +#define MINT16_11PL ~(1 << 10) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_11PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_11PL. */ +#define MINT16_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT12PL >= INT16PL) или (INT12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT12PL >= INT16PL) || (INT12PL == 0) +/* Задаёт MINT16_12PL = ~(1 << 11); маска разрешённых прерываний ядра для приоритетного обработчика 16_12PL. */ +#define MINT16_12PL ~(1 << 11) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_12PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_12PL. */ +#define MINT16_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT13PL >= INT16PL) или (INT13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT13PL >= INT16PL) || (INT13PL == 0) +/* Задаёт MINT16_13PL = ~(1 << 12); маска разрешённых прерываний ядра для приоритетного обработчика 16_13PL. */ +#define MINT16_13PL ~(1 << 12) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_13PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_13PL. */ +#define MINT16_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT14PL >= INT16PL) или (INT14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT14PL >= INT16PL) || (INT14PL == 0) +/* Задаёт MINT16_14PL = ~(1 << 13); маска разрешённых прерываний ядра для приоритетного обработчика 16_14PL. */ +#define MINT16_14PL ~(1 << 13) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_14PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_14PL. */ +#define MINT16_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (INT15PL >= INT16PL) или (INT15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (INT15PL >= INT16PL) || (INT15PL == 0) +/* Задаёт MINT16_15PL = ~(1 << 14); маска разрешённых прерываний ядра для приоритетного обработчика 16_15PL. */ +#define MINT16_15PL ~(1 << 14) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MINT16_15PL = 0xFFFF; маска разрешённых прерываний ядра для приоритетного обработчика 16_15PL. */ +#define MINT16_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MINT16_16PL = ~(1 << 15); маска разрешённых прерываний ядра для приоритетного обработчика 16_16PL. */ +#define MINT16_16PL ~(1 << 15) + +/* Задаёт MINT16 = (MINT16_1PL & MINT16_2PL & MINT16_3PL & MINT16_4PL &; маска разрешённых прерываний ядра для приоритетного обработчика 16. */ +#define MINT16 (MINT16_1PL & MINT16_2PL & MINT16_3PL & MINT16_4PL & \ + MINT16_5PL & MINT16_6PL & MINT16_7PL & MINT16_8PL & /* Продолжает список аргументов, полей или выражение MINT16_5PL & MINT16_6PL & MINT16_7PL & MINT16_8PL &; порядок элементов сохраняется. */ \ + MINT16_9PL & MINT16_10PL & MINT16_11PL & MINT16_12PL & /* Продолжает список аргументов, полей или выражение MINT16_9PL & MINT16_10PL & MINT16_11PL & MINT16_12PL &; порядок элементов сохраняется. */ \ + MINT16_13PL & MINT16_14PL & MINT16_15PL & MINT16_16PL) /* Продолжает список аргументов, полей или выражение MINT16_13PL & MINT16_14PL & MINT16_15PL & MINT16_16PL); порядок элементов сохраняется. */ +// End Of MINT16. + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG11 to MG18: + +// Beginning of MG11: +/* Условие компиляции (G12PL >= G11PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G11PL) || (G12PL == 0) +/* Задаёт MG11_12PL = ~(1 << 1); данные MG11_12PL. */ +#define MG11_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_12PL = 0xFFFF; данные MG11_12PL. */ +#define MG11_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G13PL >= G11PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G11PL) || (G13PL == 0) +/* Задаёт MG11_13PL = ~(1 << 2); данные MG11_13PL. */ +#define MG11_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_13PL = 0xFFFF; данные MG11_13PL. */ +#define MG11_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G14PL >= G11PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G11PL) || (G14PL == 0) +/* Задаёт MG11_14PL = ~(1 << 3); данные MG11_14PL. */ +#define MG11_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_14PL = 0xFFFF; данные MG11_14PL. */ +#define MG11_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G15PL >= G11PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G11PL) || (G15PL == 0) +/* Задаёт MG11_15PL = ~(1 << 4); данные MG11_15PL. */ +#define MG11_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_15PL = 0xFFFF; данные MG11_15PL. */ +#define MG11_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G16PL >= G11PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G11PL) || (G16PL == 0) +/* Задаёт MG11_16PL = ~(1 << 5); данные MG11_16PL. */ +#define MG11_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_16PL = 0xFFFF; данные MG11_16PL. */ +#define MG11_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G17PL >= G11PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G11PL) || (G17PL == 0) +/* Задаёт MG11_17PL = ~(1 << 6); данные MG11_17PL. */ +#define MG11_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_17PL = 0xFFFF; данные MG11_17PL. */ +#define MG11_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции (G18PL >= G11PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G11PL) || (G18PL == 0) +/* Задаёт MG11_18PL = ~(1 << 7); данные MG11_18PL. */ +#define MG11_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG11_18PL = 0xFFFF; данные MG11_18PL. */ +#define MG11_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Задаёт MG11_11PL = 0x00FE; данные MG11_11PL. */ +#define MG11_11PL 0x00FE +/* Задаёт MG11 = (MG11_11PL & MG11_12PL & MG11_13PL & MG11_14PL &; маска разрешённых прерываний внутри группы PIE 11. */ +#define MG11 (MG11_11PL & MG11_12PL & MG11_13PL & MG11_14PL & \ + MG11_15PL & MG11_16PL & MG11_17PL & MG11_18PL) /* Продолжает список аргументов, полей или выражение MG11_15PL & MG11_16PL & MG11_17PL & MG11_18PL); порядок элементов сохраняется. */ +// End of MG11: + +// Beginning of MG12: +/* Условие компиляции (G11PL >= G12PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G12PL) || (G11PL == 0) +/* Задаёт MG12_11PL = ~(1); данные MG12_11PL. */ +#define MG12_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_11PL = 0xFFFF; данные MG12_11PL. */ +#define MG12_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G12PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G12PL) || (G13PL == 0) +/* Задаёт MG12_13PL = ~(1 << 2); данные MG12_13PL. */ +#define MG12_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_13PL = 0xFFFF; данные MG12_13PL. */ +#define MG12_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G12PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G12PL) || (G14PL == 0) +/* Задаёт MG12_14PL = ~(1 << 3); данные MG12_14PL. */ +#define MG12_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_14PL = 0xFFFF; данные MG12_14PL. */ +#define MG12_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G12PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G12PL) || (G15PL == 0) +/* Задаёт MG12_15PL = ~(1 << 4); данные MG12_15PL. */ +#define MG12_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_15PL = 0xFFFF; данные MG12_15PL. */ +#define MG12_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G12PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G12PL) || (G16PL == 0) +/* Задаёт MG12_16PL = ~(1 << 5); данные MG12_16PL. */ +#define MG12_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_16PL = 0xFFFF; данные MG12_16PL. */ +#define MG12_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G12PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G12PL) || (G17PL == 0) +/* Задаёт MG12_17PL = ~(1 << 6); данные MG12_17PL. */ +#define MG12_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_17PL = 0xFFFF; данные MG12_17PL. */ +#define MG12_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G12PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G12PL) || (G18PL == 0) +/* Задаёт MG12_18PL = ~(1 << 7); данные MG12_18PL. */ +#define MG12_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG12_18PL = 0xFFFF; данные MG12_18PL. */ +#define MG12_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG12_12PL = 0x00FD; данные MG12_12PL. */ +#define MG12_12PL 0x00FD +/* Задаёт MG12 = (MG12_11PL & MG12_12PL & MG12_13PL & MG12_14PL &; маска разрешённых прерываний внутри группы PIE 12. */ +#define MG12 (MG12_11PL & MG12_12PL & MG12_13PL & MG12_14PL & \ + MG12_15PL & MG12_16PL & MG12_17PL & MG12_18PL) /* Продолжает список аргументов, полей или выражение MG12_15PL & MG12_16PL & MG12_17PL & MG12_18PL); порядок элементов сохраняется. */ +// End of MG12: + +// Beginning of MG13: +/* Условие компиляции (G11PL >= G13PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G13PL) || (G11PL == 0) +/* Задаёт MG13_11PL = ~(1); данные MG13_11PL. */ +#define MG13_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_11PL = 0xFFFF; данные MG13_11PL. */ +#define MG13_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G13PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G13PL) || (G12PL == 0) +/* Задаёт MG13_12PL = ~(1 << 1); данные MG13_12PL. */ +#define MG13_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_12PL = 0xFFFF; данные MG13_12PL. */ +#define MG13_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G13PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G13PL) || (G14PL == 0) +/* Задаёт MG13_14PL = ~(1 << 3); данные MG13_14PL. */ +#define MG13_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_14PL = 0xFFFF; данные MG13_14PL. */ +#define MG13_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G13PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G13PL) || (G15PL == 0) +/* Задаёт MG13_15PL = ~(1 << 4); данные MG13_15PL. */ +#define MG13_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_15PL = 0xFFFF; данные MG13_15PL. */ +#define MG13_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G13PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G13PL) || (G16PL == 0) +/* Задаёт MG13_16PL = ~(1 << 5); данные MG13_16PL. */ +#define MG13_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_16PL = 0xFFFF; данные MG13_16PL. */ +#define MG13_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G13PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G13PL) || (G17PL == 0) +/* Задаёт MG13_17PL = ~(1 << 6); данные MG13_17PL. */ +#define MG13_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_17PL = 0xFFFF; данные MG13_17PL. */ +#define MG13_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G13PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G13PL) || (G18PL == 0) +/* Задаёт MG13_18PL = ~(1 << 7); данные MG13_18PL. */ +#define MG13_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG13_18PL = 0xFFFF; данные MG13_18PL. */ +#define MG13_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG13_13PL = 0x00FB; данные MG13_13PL. */ +#define MG13_13PL 0x00FB +/* Задаёт MG13 = (MG13_11PL & MG13_12PL & MG13_13PL & MG13_14PL &; маска разрешённых прерываний внутри группы PIE 13. */ +#define MG13 (MG13_11PL & MG13_12PL & MG13_13PL & MG13_14PL & \ + MG13_15PL & MG13_16PL & MG13_17PL & MG13_18PL) /* Продолжает список аргументов, полей или выражение MG13_15PL & MG13_16PL & MG13_17PL & MG13_18PL); порядок элементов сохраняется. */ +// End of MG13: + +// Beginning of MG14: +/* Условие компиляции (G11PL >= G14PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G14PL) || (G11PL == 0) +/* Задаёт MG14_11PL = ~(1); данные MG14_11PL. */ +#define MG14_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_11PL = 0xFFFF; данные MG14_11PL. */ +#define MG14_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G14PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G14PL) || (G12PL == 0) +/* Задаёт MG14_12PL = ~(1 << 1); данные MG14_12PL. */ +#define MG14_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_12PL = 0xFFFF; данные MG14_12PL. */ +#define MG14_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G14PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G14PL) || (G13PL == 0) +/* Задаёт MG14_13PL = ~(1 << 2); данные MG14_13PL. */ +#define MG14_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_13PL = 0xFFFF; данные MG14_13PL. */ +#define MG14_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G14PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G14PL) || (G15PL == 0) +/* Задаёт MG14_15PL = ~(1 << 4); данные MG14_15PL. */ +#define MG14_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_15PL = 0xFFFF; данные MG14_15PL. */ +#define MG14_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G14PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G14PL) || (G16PL == 0) +/* Задаёт MG14_16PL = ~(1 << 5); данные MG14_16PL. */ +#define MG14_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_16PL = 0xFFFF; данные MG14_16PL. */ +#define MG14_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G14PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G14PL) || (G17PL == 0) +/* Задаёт MG14_17PL = ~(1 << 6); данные MG14_17PL. */ +#define MG14_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_17PL = 0xFFFF; данные MG14_17PL. */ +#define MG14_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G14PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G14PL) || (G18PL == 0) +/* Задаёт MG14_18PL = ~(1 << 7); данные MG14_18PL. */ +#define MG14_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG14_18PL = 0xFFFF; данные MG14_18PL. */ +#define MG14_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG14_14PL = 0x00F7; данные MG14_14PL. */ +#define MG14_14PL 0x00F7 +/* Задаёт MG14 = (MG14_11PL & MG14_12PL & MG14_13PL & MG14_14PL &; маска разрешённых прерываний внутри группы PIE 14. */ +#define MG14 (MG14_11PL & MG14_12PL & MG14_13PL & MG14_14PL & \ + MG14_15PL & MG14_16PL & MG14_17PL & MG14_18PL) /* Продолжает список аргументов, полей или выражение MG14_15PL & MG14_16PL & MG14_17PL & MG14_18PL); порядок элементов сохраняется. */ +// End of MG14: + +// Beginning of MG15: +/* Условие компиляции (G11PL >= G15PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G15PL) || (G11PL == 0) +/* Задаёт MG15_11PL = ~(1); данные MG15_11PL. */ +#define MG15_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_11PL = 0xFFFF; данные MG15_11PL. */ +#define MG15_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G15PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G15PL) || (G12PL == 0) +/* Задаёт MG15_12PL = ~(1 << 1); данные MG15_12PL. */ +#define MG15_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_12PL = 0xFFFF; данные MG15_12PL. */ +#define MG15_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G15PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G15PL) || (G13PL == 0) +/* Задаёт MG15_13PL = ~(1 << 2); данные MG15_13PL. */ +#define MG15_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_13PL = 0xFFFF; данные MG15_13PL. */ +#define MG15_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G15PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G15PL) || (G14PL == 0) +/* Задаёт MG15_14PL = ~(1 << 3); данные MG15_14PL. */ +#define MG15_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_14PL = 0xFFFF; данные MG15_14PL. */ +#define MG15_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G15PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G15PL) || (G16PL == 0) +/* Задаёт MG15_16PL = ~(1 << 5); данные MG15_16PL. */ +#define MG15_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_16PL = 0xFFFF; данные MG15_16PL. */ +#define MG15_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G15PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G15PL) || (G17PL == 0) +/* Задаёт MG15_17PL = ~(1 << 6); данные MG15_17PL. */ +#define MG15_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_17PL = 0xFFFF; данные MG15_17PL. */ +#define MG15_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G15PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G15PL) || (G18PL == 0) +/* Задаёт MG15_18PL = ~(1 << 7); данные MG15_18PL. */ +#define MG15_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG15_18PL = 0xFFFF; данные MG15_18PL. */ +#define MG15_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG15_15PL = 0x00EF; данные MG15_15PL. */ +#define MG15_15PL 0x00EF +/* Задаёт MG15 = (MG15_11PL & MG15_12PL & MG15_13PL & MG15_14PL &; маска разрешённых прерываний внутри группы PIE 15. */ +#define MG15 (MG15_11PL & MG15_12PL & MG15_13PL & MG15_14PL & \ + MG15_15PL & MG15_16PL & MG15_17PL & MG15_18PL) /* Продолжает список аргументов, полей или выражение MG15_15PL & MG15_16PL & MG15_17PL & MG15_18PL); порядок элементов сохраняется. */ +// End of MG15: + +// Beginning of MG16: +/* Условие компиляции (G11PL >= G16PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G16PL) || (G11PL == 0) +/* Задаёт MG16_11PL = ~(1); данные MG16_11PL. */ +#define MG16_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_11PL = 0xFFFF; данные MG16_11PL. */ +#define MG16_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G16PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G16PL) || (G12PL == 0) +/* Задаёт MG16_12PL = ~(1 << 1); данные MG16_12PL. */ +#define MG16_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_12PL = 0xFFFF; данные MG16_12PL. */ +#define MG16_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G16PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G16PL) || (G13PL == 0) +/* Задаёт MG16_13PL = ~(1 << 2); данные MG16_13PL. */ +#define MG16_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_13PL = 0xFFFF; данные MG16_13PL. */ +#define MG16_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G16PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G16PL) || (G14PL == 0) +/* Задаёт MG16_14PL = ~(1 << 3); данные MG16_14PL. */ +#define MG16_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_14PL = 0xFFFF; данные MG16_14PL. */ +#define MG16_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G16PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G16PL) || (G15PL == 0) +/* Задаёт MG16_15PL = ~(1 << 4); данные MG16_15PL. */ +#define MG16_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_15PL = 0xFFFF; данные MG16_15PL. */ +#define MG16_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G16PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G16PL) || (G17PL == 0) +/* Задаёт MG16_17PL = ~(1 << 6); данные MG16_17PL. */ +#define MG16_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_17PL = 0xFFFF; данные MG16_17PL. */ +#define MG16_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G16PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G16PL) || (G18PL == 0) +/* Задаёт MG16_18PL = ~(1 << 7); данные MG16_18PL. */ +#define MG16_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG16_18PL = 0xFFFF; данные MG16_18PL. */ +#define MG16_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG16_16PL = 0x00DF; данные MG16_16PL. */ +#define MG16_16PL 0x00DF +/* Задаёт MG16 = (MG16_11PL & MG16_12PL & MG16_13PL & MG16_14PL &; маска разрешённых прерываний внутри группы PIE 16. */ +#define MG16 (MG16_11PL & MG16_12PL & MG16_13PL & MG16_14PL & \ + MG16_15PL & MG16_16PL & MG16_17PL & MG16_18PL) /* Продолжает список аргументов, полей или выражение MG16_15PL & MG16_16PL & MG16_17PL & MG16_18PL); порядок элементов сохраняется. */ +// End of MG16: + +// Beginning of MG17: +/* Условие компиляции (G11PL >= G17PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G17PL) || (G11PL == 0) +/* Задаёт MG17_11PL = ~(1); данные MG17_11PL. */ +#define MG17_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_11PL = 0xFFFF; данные MG17_11PL. */ +#define MG17_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G17PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G17PL) || (G12PL == 0) +/* Задаёт MG17_12PL = ~(1 << 1); данные MG17_12PL. */ +#define MG17_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_12PL = 0xFFFF; данные MG17_12PL. */ +#define MG17_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G17PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G17PL) || (G13PL == 0) +/* Задаёт MG17_13PL = ~(1 << 2); данные MG17_13PL. */ +#define MG17_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_13PL = 0xFFFF; данные MG17_13PL. */ +#define MG17_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G17PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G17PL) || (G14PL == 0) +/* Задаёт MG17_14PL = ~(1 << 3); данные MG17_14PL. */ +#define MG17_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_14PL = 0xFFFF; данные MG17_14PL. */ +#define MG17_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G17PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G17PL) || (G15PL == 0) +/* Задаёт MG17_15PL = ~(1 << 4); данные MG17_15PL. */ +#define MG17_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_15PL = 0xFFFF; данные MG17_15PL. */ +#define MG17_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G17PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G17PL) || (G16PL == 0) +/* Задаёт MG17_16PL = ~(1 << 5); данные MG17_16PL. */ +#define MG17_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_16PL = 0xFFFF; данные MG17_16PL. */ +#define MG17_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G18PL >= G17PL) или (G18PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G18PL >= G17PL) || (G18PL == 0) +/* Задаёт MG17_18PL = ~(1 << 7); данные MG17_18PL. */ +#define MG17_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG17_18PL = 0xFFFF; данные MG17_18PL. */ +#define MG17_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG17_17PL = 0x00BF; данные MG17_17PL. */ +#define MG17_17PL 0x00BF +/* Задаёт MG17 = (MG17_11PL & MG17_12PL & MG17_13PL & MG17_14PL &; маска разрешённых прерываний внутри группы PIE 17. */ +#define MG17 (MG17_11PL & MG17_12PL & MG17_13PL & MG17_14PL & \ + MG17_15PL & MG17_16PL & MG17_17PL & MG17_18PL) /* Продолжает список аргументов, полей или выражение MG17_15PL & MG17_16PL & MG17_17PL & MG17_18PL); порядок элементов сохраняется. */ +// End of MG17: + +// Beginning of MG18: +/* Условие компиляции (G11PL >= G18PL) или (G11PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G11PL >= G18PL) || (G11PL == 0) +/* Задаёт MG18_11PL = ~(1); данные MG18_11PL. */ +#define MG18_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_11PL = 0xFFFF; данные MG18_11PL. */ +#define MG18_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G12PL >= G18PL) или (G12PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G12PL >= G18PL) || (G12PL == 0) +/* Задаёт MG18_12PL = ~(1 << 1); данные MG18_12PL. */ +#define MG18_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_12PL = 0xFFFF; данные MG18_12PL. */ +#define MG18_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G13PL >= G18PL) или (G13PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G13PL >= G18PL) || (G13PL == 0) +/* Задаёт MG18_13PL = ~(1 << 2); данные MG18_13PL. */ +#define MG18_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_13PL = 0xFFFF; данные MG18_13PL. */ +#define MG18_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G14PL >= G18PL) или (G14PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G14PL >= G18PL) || (G14PL == 0) +/* Задаёт MG18_14PL = ~(1 << 3); данные MG18_14PL. */ +#define MG18_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_14PL = 0xFFFF; данные MG18_14PL. */ +#define MG18_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G15PL >= G18PL) или (G15PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G15PL >= G18PL) || (G15PL == 0) +/* Задаёт MG18_15PL = ~(1 << 4); данные MG18_15PL. */ +#define MG18_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_15PL = 0xFFFF; данные MG18_15PL. */ +#define MG18_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G16PL >= G18PL) или (G16PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G16PL >= G18PL) || (G16PL == 0) +/* Задаёт MG18_16PL = ~(1 << 5); данные MG18_16PL. */ +#define MG18_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_16PL = 0xFFFF; данные MG18_16PL. */ +#define MG18_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G17PL >= G18PL) или (G17PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G17PL >= G18PL) || (G17PL == 0) +/* Задаёт MG18_17PL = ~(1 << 6); данные MG18_17PL. */ +#define MG18_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG18_17PL = 0xFFFF; данные MG18_17PL. */ +#define MG18_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG18_18PL = 0x007F; данные MG18_18PL. */ +#define MG18_18PL 0x007F +/* Задаёт MG18 = (MG18_11PL & MG18_12PL & MG18_13PL & MG18_14PL &; маска разрешённых прерываний внутри группы PIE 18. */ +#define MG18 (MG18_11PL & MG18_12PL & MG18_13PL & MG18_14PL & \ + MG18_15PL & MG18_16PL & MG18_17PL & MG18_18PL) /* Продолжает список аргументов, полей или выражение MG18_15PL & MG18_16PL & MG18_17PL & MG18_18PL); порядок элементов сохраняется. */ +// End of MG18: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG21 to MG28: +// + +// Beginning of MG21: +/* Условие компиляции (G22PL >= G21PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G21PL) || (G22PL == 0) +/* Задаёт MG21_12PL = ~(1 << 1); данные MG21_12PL. */ +#define MG21_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_12PL = 0xFFFF; данные MG21_12PL. */ +#define MG21_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G21PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G21PL) || (G23PL == 0) +/* Задаёт MG21_13PL = ~(1 << 2); данные MG21_13PL. */ +#define MG21_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_13PL = 0xFFFF; данные MG21_13PL. */ +#define MG21_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G21PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G21PL) || (G24PL == 0) +/* Задаёт MG21_14PL = ~(1 << 3); данные MG21_14PL. */ +#define MG21_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_14PL = 0xFFFF; данные MG21_14PL. */ +#define MG21_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G21PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G21PL) || (G25PL == 0) +/* Задаёт MG21_15PL = ~(1 << 4); данные MG21_15PL. */ +#define MG21_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_15PL = 0xFFFF; данные MG21_15PL. */ +#define MG21_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G21PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G21PL) || (G26PL == 0) +/* Задаёт MG21_16PL = ~(1 << 5); данные MG21_16PL. */ +#define MG21_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_16PL = 0xFFFF; данные MG21_16PL. */ +#define MG21_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G21PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G21PL) || (G27PL == 0) +/* Задаёт MG21_17PL = ~(1 << 6); данные MG21_17PL. */ +#define MG21_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_17PL = 0xFFFF; данные MG21_17PL. */ +#define MG21_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G21PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G21PL) || (G28PL == 0) +/* Задаёт MG21_18PL = ~(1 << 7); данные MG21_18PL. */ +#define MG21_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG21_18PL = 0xFFFF; данные MG21_18PL. */ +#define MG21_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG21_11PL = 0x00FE; данные MG21_11PL. */ +#define MG21_11PL 0x00FE +/* Задаёт MG21 = (MG21_11PL & MG21_12PL & MG21_13PL & MG21_14PL &; маска разрешённых прерываний внутри группы PIE 21. */ +#define MG21 (MG21_11PL & MG21_12PL & MG21_13PL & MG21_14PL & \ + MG21_15PL & MG21_16PL & MG21_17PL & MG21_18PL) /* Продолжает список аргументов, полей или выражение MG21_15PL & MG21_16PL & MG21_17PL & MG21_18PL); порядок элементов сохраняется. */ +// End of MG21: + +// Beginning of MG22: +/* Условие компиляции (G21PL >= G22PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G22PL) || (G21PL == 0) +/* Задаёт MG22_11PL = ~(1); данные MG22_11PL. */ +#define MG22_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_11PL = 0xFFFF; данные MG22_11PL. */ +#define MG22_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G22PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G22PL) || (G23PL == 0) +/* Задаёт MG22_13PL = ~(1 << 2); данные MG22_13PL. */ +#define MG22_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_13PL = 0xFFFF; данные MG22_13PL. */ +#define MG22_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G22PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G22PL) || (G24PL == 0) +/* Задаёт MG22_14PL = ~(1 << 3); данные MG22_14PL. */ +#define MG22_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_14PL = 0xFFFF; данные MG22_14PL. */ +#define MG22_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G22PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G22PL) || (G25PL == 0) +/* Задаёт MG22_15PL = ~(1 << 4); данные MG22_15PL. */ +#define MG22_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_15PL = 0xFFFF; данные MG22_15PL. */ +#define MG22_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G22PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G22PL) || (G26PL == 0) +/* Задаёт MG22_16PL = ~(1 << 5); данные MG22_16PL. */ +#define MG22_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_16PL = 0xFFFF; данные MG22_16PL. */ +#define MG22_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G22PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G22PL) || (G27PL == 0) +/* Задаёт MG22_17PL = ~(1 << 6); данные MG22_17PL. */ +#define MG22_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_17PL = 0xFFFF; данные MG22_17PL. */ +#define MG22_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G22PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G22PL) || (G28PL == 0) +/* Задаёт MG22_18PL = ~(1 << 7); данные MG22_18PL. */ +#define MG22_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG22_18PL = 0xFFFF; данные MG22_18PL. */ +#define MG22_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG22_12PL = 0x00FD; данные MG22_12PL. */ +#define MG22_12PL 0x00FD +/* Задаёт MG22 = (MG22_11PL & MG22_12PL & MG22_13PL & MG22_14PL &; маска разрешённых прерываний внутри группы PIE 22. */ +#define MG22 (MG22_11PL & MG22_12PL & MG22_13PL & MG22_14PL & \ + MG22_15PL & MG22_16PL & MG22_17PL & MG22_18PL) /* Продолжает список аргументов, полей или выражение MG22_15PL & MG22_16PL & MG22_17PL & MG22_18PL); порядок элементов сохраняется. */ +// End of MG22: + +// Beginning of MG23: +/* Условие компиляции (G21PL >= G23PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G23PL) || (G21PL == 0) +/* Задаёт MG23_11PL = ~(1); данные MG23_11PL. */ +#define MG23_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_11PL = 0xFFFF; данные MG23_11PL. */ +#define MG23_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G23PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G23PL) || (G22PL == 0) +/* Задаёт MG23_12PL = ~(1 << 1); данные MG23_12PL. */ +#define MG23_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_12PL = 0xFFFF; данные MG23_12PL. */ +#define MG23_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G23PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G23PL) || (G24PL == 0) +/* Задаёт MG23_14PL = ~(1 << 3); данные MG23_14PL. */ +#define MG23_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_14PL = 0xFFFF; данные MG23_14PL. */ +#define MG23_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G23PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G23PL) || (G25PL == 0) +/* Задаёт MG23_15PL = ~(1 << 4); данные MG23_15PL. */ +#define MG23_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_15PL = 0xFFFF; данные MG23_15PL. */ +#define MG23_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G23PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G23PL) || (G26PL == 0) +/* Задаёт MG23_16PL = ~(1 << 5); данные MG23_16PL. */ +#define MG23_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_16PL = 0xFFFF; данные MG23_16PL. */ +#define MG23_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G23PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G23PL) || (G27PL == 0) +/* Задаёт MG23_17PL = ~(1 << 6); данные MG23_17PL. */ +#define MG23_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_17PL = 0xFFFF; данные MG23_17PL. */ +#define MG23_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G23PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G23PL) || (G28PL == 0) +/* Задаёт MG23_18PL = ~(1 << 7); данные MG23_18PL. */ +#define MG23_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG23_18PL = 0xFFFF; данные MG23_18PL. */ +#define MG23_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG23_13PL = 0x00FB; данные MG23_13PL. */ +#define MG23_13PL 0x00FB +/* Задаёт MG23 = (MG23_11PL & MG23_12PL & MG23_13PL & MG23_14PL &; маска разрешённых прерываний внутри группы PIE 23. */ +#define MG23 (MG23_11PL & MG23_12PL & MG23_13PL & MG23_14PL & \ + MG23_15PL & MG23_16PL & MG23_17PL & MG23_18PL) /* Продолжает список аргументов, полей или выражение MG23_15PL & MG23_16PL & MG23_17PL & MG23_18PL); порядок элементов сохраняется. */ +// End of MG23: + +// Beginning of MG24: +/* Условие компиляции (G21PL >= G24PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G24PL) || (G21PL == 0) +/* Задаёт MG24_11PL = ~(1); данные MG24_11PL. */ +#define MG24_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_11PL = 0xFFFF; данные MG24_11PL. */ +#define MG24_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G24PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G24PL) || (G22PL == 0) +/* Задаёт MG24_12PL = ~(1 << 1); данные MG24_12PL. */ +#define MG24_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_12PL = 0xFFFF; данные MG24_12PL. */ +#define MG24_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G24PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G24PL) || (G23PL == 0) +/* Задаёт MG24_13PL = ~(1 << 2); данные MG24_13PL. */ +#define MG24_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_13PL = 0xFFFF; данные MG24_13PL. */ +#define MG24_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G24PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G24PL) || (G25PL == 0) +/* Задаёт MG24_15PL = ~(1 << 4); данные MG24_15PL. */ +#define MG24_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_15PL = 0xFFFF; данные MG24_15PL. */ +#define MG24_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G24PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G24PL) || (G26PL == 0) +/* Задаёт MG24_16PL = ~(1 << 5); данные MG24_16PL. */ +#define MG24_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_16PL = 0xFFFF; данные MG24_16PL. */ +#define MG24_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G24PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G24PL) || (G27PL == 0) +/* Задаёт MG24_17PL = ~(1 << 6); данные MG24_17PL. */ +#define MG24_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_17PL = 0xFFFF; данные MG24_17PL. */ +#define MG24_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G24PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G24PL) || (G28PL == 0) +/* Задаёт MG24_18PL = ~(1 << 7); данные MG24_18PL. */ +#define MG24_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG24_18PL = 0xFFFF; данные MG24_18PL. */ +#define MG24_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG24_14PL = 0x00F7; данные MG24_14PL. */ +#define MG24_14PL 0x00F7 +/* Задаёт MG24 = (MG24_11PL & MG24_12PL & MG24_13PL & MG24_14PL &; маска разрешённых прерываний внутри группы PIE 24. */ +#define MG24 (MG24_11PL & MG24_12PL & MG24_13PL & MG24_14PL & \ + MG24_15PL & MG24_16PL & MG24_17PL & MG24_18PL) /* Продолжает список аргументов, полей или выражение MG24_15PL & MG24_16PL & MG24_17PL & MG24_18PL); порядок элементов сохраняется. */ +// End of MG24: + +// Beginning of MG25: +/* Условие компиляции (G21PL >= G25PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G25PL) || (G21PL == 0) +/* Задаёт MG25_11PL = ~(1); данные MG25_11PL. */ +#define MG25_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_11PL = 0xFFFF; данные MG25_11PL. */ +#define MG25_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G25PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G25PL) || (G22PL == 0) +/* Задаёт MG25_12PL = ~(1 << 1); данные MG25_12PL. */ +#define MG25_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_12PL = 0xFFFF; данные MG25_12PL. */ +#define MG25_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G25PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G25PL) || (G23PL == 0) +/* Задаёт MG25_13PL = ~(1 << 2); данные MG25_13PL. */ +#define MG25_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_13PL = 0xFFFF; данные MG25_13PL. */ +#define MG25_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G25PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G25PL) || (G24PL == 0) +/* Задаёт MG25_14PL = ~(1 << 3); данные MG25_14PL. */ +#define MG25_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_14PL = 0xFFFF; данные MG25_14PL. */ +#define MG25_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G25PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G25PL) || (G26PL == 0) +/* Задаёт MG25_16PL = ~(1 << 5); данные MG25_16PL. */ +#define MG25_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_16PL = 0xFFFF; данные MG25_16PL. */ +#define MG25_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G25PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G25PL) || (G27PL == 0) +/* Задаёт MG25_17PL = ~(1 << 6); данные MG25_17PL. */ +#define MG25_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_17PL = 0xFFFF; данные MG25_17PL. */ +#define MG25_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G25PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G25PL) || (G28PL == 0) +/* Задаёт MG25_18PL = ~(1 << 7); данные MG25_18PL. */ +#define MG25_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG25_18PL = 0xFFFF; данные MG25_18PL. */ +#define MG25_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG25_15PL = 0x00EF; данные MG25_15PL. */ +#define MG25_15PL 0x00EF +/* Задаёт MG25 = (MG25_11PL & MG25_12PL & MG25_13PL & MG25_14PL &; маска разрешённых прерываний внутри группы PIE 25. */ +#define MG25 (MG25_11PL & MG25_12PL & MG25_13PL & MG25_14PL & \ + MG25_15PL & MG25_16PL & MG25_17PL & MG25_18PL) /* Продолжает список аргументов, полей или выражение MG25_15PL & MG25_16PL & MG25_17PL & MG25_18PL); порядок элементов сохраняется. */ +// End of MG25: + +// Beginning of MG26: +/* Условие компиляции (G21PL >= G26PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G26PL) || (G21PL == 0) +/* Задаёт MG26_11PL = ~(1); данные MG26_11PL. */ +#define MG26_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_11PL = 0xFFFF; данные MG26_11PL. */ +#define MG26_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G26PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G26PL) || (G22PL == 0) +/* Задаёт MG26_12PL = ~(1 << 1); данные MG26_12PL. */ +#define MG26_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_12PL = 0xFFFF; данные MG26_12PL. */ +#define MG26_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G26PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G26PL) || (G23PL == 0) +/* Задаёт MG26_13PL = ~(1 << 2); данные MG26_13PL. */ +#define MG26_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_13PL = 0xFFFF; данные MG26_13PL. */ +#define MG26_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G26PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G26PL) || (G24PL == 0) +/* Задаёт MG26_14PL = ~(1 << 3); данные MG26_14PL. */ +#define MG26_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_14PL = 0xFFFF; данные MG26_14PL. */ +#define MG26_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G26PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G26PL) || (G25PL == 0) +/* Задаёт MG26_15PL = ~(1 << 4); данные MG26_15PL. */ +#define MG26_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_15PL = 0xFFFF; данные MG26_15PL. */ +#define MG26_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G26PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G26PL) || (G27PL == 0) +/* Задаёт MG26_17PL = ~(1 << 6); данные MG26_17PL. */ +#define MG26_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_17PL = 0xFFFF; данные MG26_17PL. */ +#define MG26_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G26PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G26PL) || (G28PL == 0) +/* Задаёт MG26_18PL = ~(1 << 7); данные MG26_18PL. */ +#define MG26_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG26_18PL = 0xFFFF; данные MG26_18PL. */ +#define MG26_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG26_16PL = 0x00DF; данные MG26_16PL. */ +#define MG26_16PL 0x00DF +/* Задаёт MG26 = (MG26_11PL & MG26_12PL & MG26_13PL & MG26_14PL &; маска разрешённых прерываний внутри группы PIE 26. */ +#define MG26 (MG26_11PL & MG26_12PL & MG26_13PL & MG26_14PL & \ + MG26_15PL & MG26_16PL & MG26_17PL & MG26_18PL) /* Продолжает список аргументов, полей или выражение MG26_15PL & MG26_16PL & MG26_17PL & MG26_18PL); порядок элементов сохраняется. */ +// End of MG26: + +// Beginning of MG27: +/* Условие компиляции (G21PL >= G27PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G27PL) || (G21PL == 0) +/* Задаёт MG27_11PL = ~(1); данные MG27_11PL. */ +#define MG27_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_11PL = 0xFFFF; данные MG27_11PL. */ +#define MG27_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G27PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G27PL) || (G22PL == 0) +/* Задаёт MG27_12PL = ~(1 << 1); данные MG27_12PL. */ +#define MG27_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_12PL = 0xFFFF; данные MG27_12PL. */ +#define MG27_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G27PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G27PL) || (G23PL == 0) +/* Задаёт MG27_13PL = ~(1 << 2); данные MG27_13PL. */ +#define MG27_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_13PL = 0xFFFF; данные MG27_13PL. */ +#define MG27_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G27PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G27PL) || (G24PL == 0) +/* Задаёт MG27_14PL = ~(1 << 3); данные MG27_14PL. */ +#define MG27_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_14PL = 0xFFFF; данные MG27_14PL. */ +#define MG27_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G27PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G27PL) || (G25PL == 0) +/* Задаёт MG27_15PL = ~(1 << 4); данные MG27_15PL. */ +#define MG27_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_15PL = 0xFFFF; данные MG27_15PL. */ +#define MG27_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G27PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G27PL) || (G26PL == 0) +/* Задаёт MG27_16PL = ~(1 << 5); данные MG27_16PL. */ +#define MG27_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_16PL = 0xFFFF; данные MG27_16PL. */ +#define MG27_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G28PL >= G27PL) или (G28PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G28PL >= G27PL) || (G28PL == 0) +/* Задаёт MG27_18PL = ~(1 << 7); данные MG27_18PL. */ +#define MG27_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG27_18PL = 0xFFFF; данные MG27_18PL. */ +#define MG27_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG27_17PL = 0x00BF; данные MG27_17PL. */ +#define MG27_17PL 0x00BF +/* Задаёт MG27 = (MG27_11PL & MG27_12PL & MG27_13PL & MG27_14PL &; маска разрешённых прерываний внутри группы PIE 27. */ +#define MG27 (MG27_11PL & MG27_12PL & MG27_13PL & MG27_14PL & \ + MG27_15PL & MG27_16PL & MG27_17PL & MG27_18PL) /* Продолжает список аргументов, полей или выражение MG27_15PL & MG27_16PL & MG27_17PL & MG27_18PL); порядок элементов сохраняется. */ +// End of MG27: + +// Beginning of MG28: +/* Условие компиляции (G21PL >= G28PL) или (G21PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G21PL >= G28PL) || (G21PL == 0) +/* Задаёт MG28_11PL = ~(1); данные MG28_11PL. */ +#define MG28_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_11PL = 0xFFFF; данные MG28_11PL. */ +#define MG28_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G22PL >= G28PL) или (G22PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G22PL >= G28PL) || (G22PL == 0) +/* Задаёт MG28_12PL = ~(1 << 1); данные MG28_12PL. */ +#define MG28_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_12PL = 0xFFFF; данные MG28_12PL. */ +#define MG28_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G23PL >= G28PL) или (G23PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G23PL >= G28PL) || (G23PL == 0) +/* Задаёт MG28_13PL = ~(1 << 2); данные MG28_13PL. */ +#define MG28_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_13PL = 0xFFFF; данные MG28_13PL. */ +#define MG28_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G24PL >= G28PL) или (G24PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G24PL >= G28PL) || (G24PL == 0) +/* Задаёт MG28_14PL = ~(1 << 3); данные MG28_14PL. */ +#define MG28_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_14PL = 0xFFFF; данные MG28_14PL. */ +#define MG28_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G25PL >= G28PL) или (G25PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G25PL >= G28PL) || (G25PL == 0) +/* Задаёт MG28_15PL = ~(1 << 4); данные MG28_15PL. */ +#define MG28_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_15PL = 0xFFFF; данные MG28_15PL. */ +#define MG28_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G26PL >= G28PL) или (G26PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G26PL >= G28PL) || (G26PL == 0) +/* Задаёт MG28_16PL = ~(1 << 5); данные MG28_16PL. */ +#define MG28_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_16PL = 0xFFFF; данные MG28_16PL. */ +#define MG28_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G27PL >= G28PL) или (G27PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G27PL >= G28PL) || (G27PL == 0) +/* Задаёт MG28_17PL = ~(1 << 6); данные MG28_17PL. */ +#define MG28_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG28_17PL = 0xFFFF; данные MG28_17PL. */ +#define MG28_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG28_18PL = 0x007F; данные MG28_18PL. */ +#define MG28_18PL 0x007F +/* Задаёт MG28 = (MG28_11PL & MG28_12PL & MG28_13PL & MG28_14PL &; маска разрешённых прерываний внутри группы PIE 28. */ +#define MG28 (MG28_11PL & MG28_12PL & MG28_13PL & MG28_14PL & \ + MG28_15PL & MG28_16PL & MG28_17PL & MG28_18PL) /* Продолжает список аргументов, полей или выражение MG28_15PL & MG28_16PL & MG28_17PL & MG28_18PL); порядок элементов сохраняется. */ +// End of MG28: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG31 to MG38: +// + +// Beginning of MG31: +/* Условие компиляции (G32PL >= G31PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G31PL) || (G32PL == 0) +/* Задаёт MG31_12PL = ~(1 << 1); данные MG31_12PL. */ +#define MG31_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_12PL = 0xFFFF; данные MG31_12PL. */ +#define MG31_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G31PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G31PL) || (G33PL == 0) +/* Задаёт MG31_13PL = ~(1 << 2); данные MG31_13PL. */ +#define MG31_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_13PL = 0xFFFF; данные MG31_13PL. */ +#define MG31_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G31PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G31PL) || (G34PL == 0) +/* Задаёт MG31_14PL = ~(1 << 3); данные MG31_14PL. */ +#define MG31_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_14PL = 0xFFFF; данные MG31_14PL. */ +#define MG31_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G31PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G31PL) || (G35PL == 0) +/* Задаёт MG31_15PL = ~(1 << 4); данные MG31_15PL. */ +#define MG31_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_15PL = 0xFFFF; данные MG31_15PL. */ +#define MG31_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G31PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G31PL) || (G36PL == 0) +/* Задаёт MG31_16PL = ~(1 << 5); данные MG31_16PL. */ +#define MG31_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_16PL = 0xFFFF; данные MG31_16PL. */ +#define MG31_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G31PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G31PL) || (G37PL == 0) +/* Задаёт MG31_17PL = ~(1 << 6); данные MG31_17PL. */ +#define MG31_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_17PL = 0xFFFF; данные MG31_17PL. */ +#define MG31_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G31PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G31PL) || (G38PL == 0) +/* Задаёт MG31_18PL = ~(1 << 7); данные MG31_18PL. */ +#define MG31_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG31_18PL = 0xFFFF; данные MG31_18PL. */ +#define MG31_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG31_11PL = 0x00FE; данные MG31_11PL. */ +#define MG31_11PL 0x00FE +/* Задаёт MG31 = (MG31_11PL & MG31_12PL & MG31_13PL & MG31_14PL &; маска разрешённых прерываний внутри группы PIE 31. */ +#define MG31 (MG31_11PL & MG31_12PL & MG31_13PL & MG31_14PL & \ + MG31_15PL & MG31_16PL & MG31_17PL & MG31_18PL) /* Продолжает список аргументов, полей или выражение MG31_15PL & MG31_16PL & MG31_17PL & MG31_18PL); порядок элементов сохраняется. */ +// End of MG31: + +// Beginning of MG32: +/* Условие компиляции (G31PL >= G32PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G32PL) || (G31PL == 0) +/* Задаёт MG32_11PL = ~(1); данные MG32_11PL. */ +#define MG32_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_11PL = 0xFFFF; данные MG32_11PL. */ +#define MG32_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G32PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G32PL) || (G33PL == 0) +/* Задаёт MG32_13PL = ~(1 << 2); данные MG32_13PL. */ +#define MG32_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_13PL = 0xFFFF; данные MG32_13PL. */ +#define MG32_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G32PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G32PL) || (G34PL == 0) +/* Задаёт MG32_14PL = ~(1 << 3); данные MG32_14PL. */ +#define MG32_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_14PL = 0xFFFF; данные MG32_14PL. */ +#define MG32_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G32PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G32PL) || (G35PL == 0) +/* Задаёт MG32_15PL = ~(1 << 4); данные MG32_15PL. */ +#define MG32_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_15PL = 0xFFFF; данные MG32_15PL. */ +#define MG32_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G32PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G32PL) || (G36PL == 0) +/* Задаёт MG32_16PL = ~(1 << 5); данные MG32_16PL. */ +#define MG32_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_16PL = 0xFFFF; данные MG32_16PL. */ +#define MG32_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G32PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G32PL) || (G37PL == 0) +/* Задаёт MG32_17PL = ~(1 << 6); данные MG32_17PL. */ +#define MG32_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_17PL = 0xFFFF; данные MG32_17PL. */ +#define MG32_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G32PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G32PL) || (G38PL == 0) +/* Задаёт MG32_18PL = ~(1 << 7); данные MG32_18PL. */ +#define MG32_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG32_18PL = 0xFFFF; данные MG32_18PL. */ +#define MG32_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG32_12PL = 0x00FD; данные MG32_12PL. */ +#define MG32_12PL 0x00FD +/* Задаёт MG32 = (MG32_11PL & MG32_12PL & MG32_13PL & MG32_14PL &; маска разрешённых прерываний внутри группы PIE 32. */ +#define MG32 (MG32_11PL & MG32_12PL & MG32_13PL & MG32_14PL & \ + MG32_15PL & MG32_16PL & MG32_17PL & MG32_18PL) /* Продолжает список аргументов, полей или выражение MG32_15PL & MG32_16PL & MG32_17PL & MG32_18PL); порядок элементов сохраняется. */ +// End of MG32: + +// Beginning of MG33: +/* Условие компиляции (G31PL >= G33PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G33PL) || (G31PL == 0) +/* Задаёт MG33_11PL = ~(1); данные MG33_11PL. */ +#define MG33_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_11PL = 0xFFFF; данные MG33_11PL. */ +#define MG33_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G33PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G33PL) || (G32PL == 0) +/* Задаёт MG33_12PL = ~(1 << 1); данные MG33_12PL. */ +#define MG33_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_12PL = 0xFFFF; данные MG33_12PL. */ +#define MG33_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G33PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G33PL) || (G34PL == 0) +/* Задаёт MG33_14PL = ~(1 << 3); данные MG33_14PL. */ +#define MG33_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_14PL = 0xFFFF; данные MG33_14PL. */ +#define MG33_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G33PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G33PL) || (G35PL == 0) +/* Задаёт MG33_15PL = ~(1 << 4); данные MG33_15PL. */ +#define MG33_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_15PL = 0xFFFF; данные MG33_15PL. */ +#define MG33_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G33PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G33PL) || (G36PL == 0) +/* Задаёт MG33_16PL = ~(1 << 5); данные MG33_16PL. */ +#define MG33_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_16PL = 0xFFFF; данные MG33_16PL. */ +#define MG33_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G33PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G33PL) || (G37PL == 0) +/* Задаёт MG33_17PL = ~(1 << 6); данные MG33_17PL. */ +#define MG33_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_17PL = 0xFFFF; данные MG33_17PL. */ +#define MG33_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G33PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G33PL) || (G38PL == 0) +/* Задаёт MG33_18PL = ~(1 << 7); данные MG33_18PL. */ +#define MG33_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG33_18PL = 0xFFFF; данные MG33_18PL. */ +#define MG33_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG33_13PL = 0x00FB; данные MG33_13PL. */ +#define MG33_13PL 0x00FB +/* Задаёт MG33 = (MG33_11PL & MG33_12PL & MG33_13PL & MG33_14PL &; маска разрешённых прерываний внутри группы PIE 33. */ +#define MG33 (MG33_11PL & MG33_12PL & MG33_13PL & MG33_14PL & \ + MG33_15PL & MG33_16PL & MG33_17PL & MG33_18PL) /* Продолжает список аргументов, полей или выражение MG33_15PL & MG33_16PL & MG33_17PL & MG33_18PL); порядок элементов сохраняется. */ +// End of MG33: + +// Beginning of MG34: +/* Условие компиляции (G31PL >= G34PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G34PL) || (G31PL == 0) +/* Задаёт MG34_11PL = ~(1); данные MG34_11PL. */ +#define MG34_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_11PL = 0xFFFF; данные MG34_11PL. */ +#define MG34_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G34PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G34PL) || (G32PL == 0) +/* Задаёт MG34_12PL = ~(1 << 1); данные MG34_12PL. */ +#define MG34_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_12PL = 0xFFFF; данные MG34_12PL. */ +#define MG34_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G34PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G34PL) || (G33PL == 0) +/* Задаёт MG34_13PL = ~(1 << 2); данные MG34_13PL. */ +#define MG34_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_13PL = 0xFFFF; данные MG34_13PL. */ +#define MG34_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G34PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G34PL) || (G35PL == 0) +/* Задаёт MG34_15PL = ~(1 << 4); данные MG34_15PL. */ +#define MG34_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_15PL = 0xFFFF; данные MG34_15PL. */ +#define MG34_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G34PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G34PL) || (G36PL == 0) +/* Задаёт MG34_16PL = ~(1 << 5); данные MG34_16PL. */ +#define MG34_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_16PL = 0xFFFF; данные MG34_16PL. */ +#define MG34_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G34PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G34PL) || (G37PL == 0) +/* Задаёт MG34_17PL = ~(1 << 6); данные MG34_17PL. */ +#define MG34_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_17PL = 0xFFFF; данные MG34_17PL. */ +#define MG34_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G34PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G34PL) || (G38PL == 0) +/* Задаёт MG34_18PL = ~(1 << 7); данные MG34_18PL. */ +#define MG34_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG34_18PL = 0xFFFF; данные MG34_18PL. */ +#define MG34_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG34_14PL = 0x00F7; данные MG34_14PL. */ +#define MG34_14PL 0x00F7 +/* Задаёт MG34 = (MG34_11PL & MG34_12PL & MG34_13PL & MG34_14PL &; маска разрешённых прерываний внутри группы PIE 34. */ +#define MG34 (MG34_11PL & MG34_12PL & MG34_13PL & MG34_14PL & \ + MG34_15PL & MG34_16PL & MG34_17PL & MG34_18PL) /* Продолжает список аргументов, полей или выражение MG34_15PL & MG34_16PL & MG34_17PL & MG34_18PL); порядок элементов сохраняется. */ +// End of MG34: + +// Beginning of MG35: +/* Условие компиляции (G31PL >= G35PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G35PL) || (G31PL == 0) +/* Задаёт MG35_11PL = ~(1); данные MG35_11PL. */ +#define MG35_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_11PL = 0xFFFF; данные MG35_11PL. */ +#define MG35_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G35PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G35PL) || (G32PL == 0) +/* Задаёт MG35_12PL = ~(1 << 1); данные MG35_12PL. */ +#define MG35_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_12PL = 0xFFFF; данные MG35_12PL. */ +#define MG35_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G35PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G35PL) || (G33PL == 0) +/* Задаёт MG35_13PL = ~(1 << 2); данные MG35_13PL. */ +#define MG35_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_13PL = 0xFFFF; данные MG35_13PL. */ +#define MG35_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G35PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G35PL) || (G34PL == 0) +/* Задаёт MG35_14PL = ~(1 << 3); данные MG35_14PL. */ +#define MG35_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_14PL = 0xFFFF; данные MG35_14PL. */ +#define MG35_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G35PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G35PL) || (G36PL == 0) +/* Задаёт MG35_16PL = ~(1 << 5); данные MG35_16PL. */ +#define MG35_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_16PL = 0xFFFF; данные MG35_16PL. */ +#define MG35_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G35PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G35PL) || (G37PL == 0) +/* Задаёт MG35_17PL = ~(1 << 6); данные MG35_17PL. */ +#define MG35_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_17PL = 0xFFFF; данные MG35_17PL. */ +#define MG35_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G35PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G35PL) || (G38PL == 0) +/* Задаёт MG35_18PL = ~(1 << 7); данные MG35_18PL. */ +#define MG35_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG35_18PL = 0xFFFF; данные MG35_18PL. */ +#define MG35_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG35_15PL = 0x00EF; данные MG35_15PL. */ +#define MG35_15PL 0x00EF +/* Задаёт MG35 = (MG35_11PL & MG35_12PL & MG35_13PL & MG35_14PL &; маска разрешённых прерываний внутри группы PIE 35. */ +#define MG35 (MG35_11PL & MG35_12PL & MG35_13PL & MG35_14PL & \ + MG35_15PL & MG35_16PL & MG35_17PL & MG35_18PL) /* Продолжает список аргументов, полей или выражение MG35_15PL & MG35_16PL & MG35_17PL & MG35_18PL); порядок элементов сохраняется. */ +// End of MG35: + +// Beginning of MG36: +/* Условие компиляции (G31PL >= G36PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G36PL) || (G31PL == 0) +/* Задаёт MG36_11PL = ~(1); данные MG36_11PL. */ +#define MG36_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_11PL = 0xFFFF; данные MG36_11PL. */ +#define MG36_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G36PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G36PL) || (G32PL == 0) +/* Задаёт MG36_12PL = ~(1 << 1); данные MG36_12PL. */ +#define MG36_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_12PL = 0xFFFF; данные MG36_12PL. */ +#define MG36_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G36PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G36PL) || (G33PL == 0) +/* Задаёт MG36_13PL = ~(1 << 2); данные MG36_13PL. */ +#define MG36_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_13PL = 0xFFFF; данные MG36_13PL. */ +#define MG36_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G36PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G36PL) || (G34PL == 0) +/* Задаёт MG36_14PL = ~(1 << 3); данные MG36_14PL. */ +#define MG36_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_14PL = 0xFFFF; данные MG36_14PL. */ +#define MG36_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G36PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G36PL) || (G35PL == 0) +/* Задаёт MG36_15PL = ~(1 << 4); данные MG36_15PL. */ +#define MG36_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_15PL = 0xFFFF; данные MG36_15PL. */ +#define MG36_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G36PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G36PL) || (G37PL == 0) +/* Задаёт MG36_17PL = ~(1 << 6); данные MG36_17PL. */ +#define MG36_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_17PL = 0xFFFF; данные MG36_17PL. */ +#define MG36_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G36PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G36PL) || (G38PL == 0) +/* Задаёт MG36_18PL = ~(1 << 7); данные MG36_18PL. */ +#define MG36_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG36_18PL = 0xFFFF; данные MG36_18PL. */ +#define MG36_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG36_16PL = 0x00DF; данные MG36_16PL. */ +#define MG36_16PL 0x00DF +/* Задаёт MG36 = (MG36_11PL & MG36_12PL & MG36_13PL & MG36_14PL &; маска разрешённых прерываний внутри группы PIE 36. */ +#define MG36 (MG36_11PL & MG36_12PL & MG36_13PL & MG36_14PL & \ + MG36_15PL & MG36_16PL & MG36_17PL & MG36_18PL) /* Продолжает список аргументов, полей или выражение MG36_15PL & MG36_16PL & MG36_17PL & MG36_18PL); порядок элементов сохраняется. */ +// End of MG36: + +// Beginning of MG37: +/* Условие компиляции (G31PL >= G37PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G37PL) || (G31PL == 0) +/* Задаёт MG37_11PL = ~(1); данные MG37_11PL. */ +#define MG37_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_11PL = 0xFFFF; данные MG37_11PL. */ +#define MG37_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G37PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G37PL) || (G32PL == 0) +/* Задаёт MG37_12PL = ~(1 << 1); данные MG37_12PL. */ +#define MG37_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_12PL = 0xFFFF; данные MG37_12PL. */ +#define MG37_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G37PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G37PL) || (G33PL == 0) +/* Задаёт MG37_13PL = ~(1 << 2); данные MG37_13PL. */ +#define MG37_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_13PL = 0xFFFF; данные MG37_13PL. */ +#define MG37_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G37PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G37PL) || (G34PL == 0) +/* Задаёт MG37_14PL = ~(1 << 3); данные MG37_14PL. */ +#define MG37_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_14PL = 0xFFFF; данные MG37_14PL. */ +#define MG37_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G37PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G37PL) || (G35PL == 0) +/* Задаёт MG37_15PL = ~(1 << 4); данные MG37_15PL. */ +#define MG37_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_15PL = 0xFFFF; данные MG37_15PL. */ +#define MG37_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G37PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G37PL) || (G36PL == 0) +/* Задаёт MG37_16PL = ~(1 << 5); данные MG37_16PL. */ +#define MG37_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_16PL = 0xFFFF; данные MG37_16PL. */ +#define MG37_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G38PL >= G37PL) или (G38PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G38PL >= G37PL) || (G38PL == 0) +/* Задаёт MG37_18PL = ~(1 << 7); данные MG37_18PL. */ +#define MG37_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG37_18PL = 0xFFFF; данные MG37_18PL. */ +#define MG37_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG37_17PL = 0x00BF; данные MG37_17PL. */ +#define MG37_17PL 0x00BF +/* Задаёт MG37 = (MG37_11PL & MG37_12PL & MG37_13PL & MG37_14PL &; маска разрешённых прерываний внутри группы PIE 37. */ +#define MG37 (MG37_11PL & MG37_12PL & MG37_13PL & MG37_14PL & \ + MG37_15PL & MG37_16PL & MG37_17PL & MG37_18PL) /* Продолжает список аргументов, полей или выражение MG37_15PL & MG37_16PL & MG37_17PL & MG37_18PL); порядок элементов сохраняется. */ +// End of MG37: + +// Beginning of MG38: +/* Условие компиляции (G31PL >= G38PL) или (G31PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G31PL >= G38PL) || (G31PL == 0) +/* Задаёт MG38_11PL = ~(1); данные MG38_11PL. */ +#define MG38_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_11PL = 0xFFFF; данные MG38_11PL. */ +#define MG38_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G32PL >= G38PL) или (G32PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G32PL >= G38PL) || (G32PL == 0) +/* Задаёт MG38_12PL = ~(1 << 1); данные MG38_12PL. */ +#define MG38_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_12PL = 0xFFFF; данные MG38_12PL. */ +#define MG38_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G33PL >= G38PL) или (G33PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G33PL >= G38PL) || (G33PL == 0) +/* Задаёт MG38_13PL = ~(1 << 2); данные MG38_13PL. */ +#define MG38_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_13PL = 0xFFFF; данные MG38_13PL. */ +#define MG38_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G34PL >= G38PL) или (G34PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G34PL >= G38PL) || (G34PL == 0) +/* Задаёт MG38_14PL = ~(1 << 3); данные MG38_14PL. */ +#define MG38_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_14PL = 0xFFFF; данные MG38_14PL. */ +#define MG38_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G35PL >= G38PL) или (G35PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G35PL >= G38PL) || (G35PL == 0) +/* Задаёт MG38_15PL = ~(1 << 4); данные MG38_15PL. */ +#define MG38_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_15PL = 0xFFFF; данные MG38_15PL. */ +#define MG38_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G36PL >= G38PL) или (G36PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G36PL >= G38PL) || (G36PL == 0) +/* Задаёт MG38_16PL = ~(1 << 5); данные MG38_16PL. */ +#define MG38_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_16PL = 0xFFFF; данные MG38_16PL. */ +#define MG38_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G37PL >= G38PL) или (G37PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G37PL >= G38PL) || (G37PL == 0) +/* Задаёт MG38_17PL = ~(1 << 6); данные MG38_17PL. */ +#define MG38_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG38_17PL = 0xFFFF; данные MG38_17PL. */ +#define MG38_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG38_18PL = 0x007F; данные MG38_18PL. */ +#define MG38_18PL 0x007F +/* Задаёт MG38 = (MG38_11PL & MG38_12PL & MG38_13PL & MG38_14PL &; маска разрешённых прерываний внутри группы PIE 38. */ +#define MG38 (MG38_11PL & MG38_12PL & MG38_13PL & MG38_14PL & \ + MG38_15PL & MG38_16PL & MG38_17PL & MG38_18PL) /* Продолжает список аргументов, полей или выражение MG38_15PL & MG38_16PL & MG38_17PL & MG38_18PL); порядок элементов сохраняется. */ +// End of MG38: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG41 to MG48: +// + +// Beginning of MG41: +/* Условие компиляции (G42PL >= G41PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G41PL) || (G42PL == 0) +/* Задаёт MG41_12PL = ~(1 << 1); данные MG41_12PL. */ +#define MG41_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_12PL = 0xFFFF; данные MG41_12PL. */ +#define MG41_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G41PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G41PL) || (G43PL == 0) +/* Задаёт MG41_13PL = ~(1 << 2); данные MG41_13PL. */ +#define MG41_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_13PL = 0xFFFF; данные MG41_13PL. */ +#define MG41_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G41PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G41PL) || (G44PL == 0) +/* Задаёт MG41_14PL = ~(1 << 3); данные MG41_14PL. */ +#define MG41_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_14PL = 0xFFFF; данные MG41_14PL. */ +#define MG41_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G41PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G41PL) || (G45PL == 0) +/* Задаёт MG41_15PL = ~(1 << 4); данные MG41_15PL. */ +#define MG41_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_15PL = 0xFFFF; данные MG41_15PL. */ +#define MG41_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G41PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G41PL) || (G46PL == 0) +/* Задаёт MG41_16PL = ~(1 << 5); данные MG41_16PL. */ +#define MG41_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_16PL = 0xFFFF; данные MG41_16PL. */ +#define MG41_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G41PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G41PL) || (G47PL == 0) +/* Задаёт MG41_17PL = ~(1 << 6); данные MG41_17PL. */ +#define MG41_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_17PL = 0xFFFF; данные MG41_17PL. */ +#define MG41_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G41PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G41PL) || (G48PL == 0) +/* Задаёт MG41_18PL = ~(1 << 7); данные MG41_18PL. */ +#define MG41_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG41_18PL = 0xFFFF; данные MG41_18PL. */ +#define MG41_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG41_11PL = 0x00FE; данные MG41_11PL. */ +#define MG41_11PL 0x00FE +/* Задаёт MG41 = (MG41_11PL & MG41_12PL & MG41_13PL & MG41_14PL &; маска разрешённых прерываний внутри группы PIE 41. */ +#define MG41 (MG41_11PL & MG41_12PL & MG41_13PL & MG41_14PL & \ + MG41_15PL & MG41_16PL & MG41_17PL & MG41_18PL) /* Продолжает список аргументов, полей или выражение MG41_15PL & MG41_16PL & MG41_17PL & MG41_18PL); порядок элементов сохраняется. */ +// End of MG41: + +// Beginning of MG42: +/* Условие компиляции (G41PL >= G42PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G42PL) || (G41PL == 0) +/* Задаёт MG42_11PL = ~(1); данные MG42_11PL. */ +#define MG42_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_11PL = 0xFFFF; данные MG42_11PL. */ +#define MG42_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G42PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G42PL) || (G43PL == 0) +/* Задаёт MG42_13PL = ~(1 << 2); данные MG42_13PL. */ +#define MG42_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_13PL = 0xFFFF; данные MG42_13PL. */ +#define MG42_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G42PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G42PL) || (G44PL == 0) +/* Задаёт MG42_14PL = ~(1 << 3); данные MG42_14PL. */ +#define MG42_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_14PL = 0xFFFF; данные MG42_14PL. */ +#define MG42_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G42PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G42PL) || (G45PL == 0) +/* Задаёт MG42_15PL = ~(1 << 4); данные MG42_15PL. */ +#define MG42_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_15PL = 0xFFFF; данные MG42_15PL. */ +#define MG42_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G42PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G42PL) || (G46PL == 0) +/* Задаёт MG42_16PL = ~(1 << 5); данные MG42_16PL. */ +#define MG42_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_16PL = 0xFFFF; данные MG42_16PL. */ +#define MG42_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G42PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G42PL) || (G47PL == 0) +/* Задаёт MG42_17PL = ~(1 << 6); данные MG42_17PL. */ +#define MG42_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_17PL = 0xFFFF; данные MG42_17PL. */ +#define MG42_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G42PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G42PL) || (G48PL == 0) +/* Задаёт MG42_18PL = ~(1 << 7); данные MG42_18PL. */ +#define MG42_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG42_18PL = 0xFFFF; данные MG42_18PL. */ +#define MG42_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG42_12PL = 0x00FD; данные MG42_12PL. */ +#define MG42_12PL 0x00FD +/* Задаёт MG42 = (MG42_11PL & MG42_12PL & MG42_13PL & MG42_14PL &; маска разрешённых прерываний внутри группы PIE 42. */ +#define MG42 (MG42_11PL & MG42_12PL & MG42_13PL & MG42_14PL & \ + MG42_15PL & MG42_16PL & MG42_17PL & MG42_18PL) /* Продолжает список аргументов, полей или выражение MG42_15PL & MG42_16PL & MG42_17PL & MG42_18PL); порядок элементов сохраняется. */ +// End of MG42: + +// Beginning of MG43: +/* Условие компиляции (G41PL >= G43PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G43PL) || (G41PL == 0) +/* Задаёт MG43_11PL = ~(1); данные MG43_11PL. */ +#define MG43_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_11PL = 0xFFFF; данные MG43_11PL. */ +#define MG43_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G43PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G43PL) || (G42PL == 0) +/* Задаёт MG43_12PL = ~(1 << 1); данные MG43_12PL. */ +#define MG43_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_12PL = 0xFFFF; данные MG43_12PL. */ +#define MG43_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G43PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G43PL) || (G44PL == 0) +/* Задаёт MG43_14PL = ~(1 << 3); данные MG43_14PL. */ +#define MG43_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_14PL = 0xFFFF; данные MG43_14PL. */ +#define MG43_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G43PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G43PL) || (G45PL == 0) +/* Задаёт MG43_15PL = ~(1 << 4); данные MG43_15PL. */ +#define MG43_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_15PL = 0xFFFF; данные MG43_15PL. */ +#define MG43_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G43PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G43PL) || (G46PL == 0) +/* Задаёт MG43_16PL = ~(1 << 5); данные MG43_16PL. */ +#define MG43_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_16PL = 0xFFFF; данные MG43_16PL. */ +#define MG43_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G43PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G43PL) || (G47PL == 0) +/* Задаёт MG43_17PL = ~(1 << 6); данные MG43_17PL. */ +#define MG43_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_17PL = 0xFFFF; данные MG43_17PL. */ +#define MG43_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G43PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G43PL) || (G48PL == 0) +/* Задаёт MG43_18PL = ~(1 << 7); данные MG43_18PL. */ +#define MG43_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG43_18PL = 0xFFFF; данные MG43_18PL. */ +#define MG43_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG43_13PL = 0x00FB; данные MG43_13PL. */ +#define MG43_13PL 0x00FB +/* Задаёт MG43 = (MG43_11PL & MG43_12PL & MG43_13PL & MG43_14PL &; маска разрешённых прерываний внутри группы PIE 43. */ +#define MG43 (MG43_11PL & MG43_12PL & MG43_13PL & MG43_14PL & \ + MG43_15PL & MG43_16PL & MG43_17PL & MG43_18PL) /* Продолжает список аргументов, полей или выражение MG43_15PL & MG43_16PL & MG43_17PL & MG43_18PL); порядок элементов сохраняется. */ +// End of MG43: + +// Beginning of MG44: +/* Условие компиляции (G41PL >= G44PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G44PL) || (G41PL == 0) +/* Задаёт MG44_11PL = ~(1); данные MG44_11PL. */ +#define MG44_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_11PL = 0xFFFF; данные MG44_11PL. */ +#define MG44_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G44PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G44PL) || (G42PL == 0) +/* Задаёт MG44_12PL = ~(1 << 1); данные MG44_12PL. */ +#define MG44_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_12PL = 0xFFFF; данные MG44_12PL. */ +#define MG44_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G44PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G44PL) || (G43PL == 0) +/* Задаёт MG44_13PL = ~(1 << 2); данные MG44_13PL. */ +#define MG44_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_13PL = 0xFFFF; данные MG44_13PL. */ +#define MG44_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G44PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G44PL) || (G45PL == 0) +/* Задаёт MG44_15PL = ~(1 << 4); данные MG44_15PL. */ +#define MG44_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_15PL = 0xFFFF; данные MG44_15PL. */ +#define MG44_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G44PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G44PL) || (G46PL == 0) +/* Задаёт MG44_16PL = ~(1 << 5); данные MG44_16PL. */ +#define MG44_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_16PL = 0xFFFF; данные MG44_16PL. */ +#define MG44_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G44PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G44PL) || (G47PL == 0) +/* Задаёт MG44_17PL = ~(1 << 6); данные MG44_17PL. */ +#define MG44_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_17PL = 0xFFFF; данные MG44_17PL. */ +#define MG44_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G44PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G44PL) || (G48PL == 0) +/* Задаёт MG44_18PL = ~(1 << 7); данные MG44_18PL. */ +#define MG44_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG44_18PL = 0xFFFF; данные MG44_18PL. */ +#define MG44_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG44_14PL = 0x00F7; данные MG44_14PL. */ +#define MG44_14PL 0x00F7 +/* Задаёт MG44 = (MG44_11PL & MG44_12PL & MG44_13PL & MG44_14PL &; маска разрешённых прерываний внутри группы PIE 44. */ +#define MG44 (MG44_11PL & MG44_12PL & MG44_13PL & MG44_14PL & \ + MG44_15PL & MG44_16PL & MG44_17PL & MG44_18PL) /* Продолжает список аргументов, полей или выражение MG44_15PL & MG44_16PL & MG44_17PL & MG44_18PL); порядок элементов сохраняется. */ +// End of MG44: + +// Beginning of MG45: +/* Условие компиляции (G41PL >= G45PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G45PL) || (G41PL == 0) +/* Задаёт MG45_11PL = ~(1); данные MG45_11PL. */ +#define MG45_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_11PL = 0xFFFF; данные MG45_11PL. */ +#define MG45_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G45PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G45PL) || (G42PL == 0) +/* Задаёт MG45_12PL = ~(1 << 1); данные MG45_12PL. */ +#define MG45_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_12PL = 0xFFFF; данные MG45_12PL. */ +#define MG45_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G45PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G45PL) || (G43PL == 0) +/* Задаёт MG45_13PL = ~(1 << 2); данные MG45_13PL. */ +#define MG45_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_13PL = 0xFFFF; данные MG45_13PL. */ +#define MG45_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G45PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G45PL) || (G44PL == 0) +/* Задаёт MG45_14PL = ~(1 << 3); данные MG45_14PL. */ +#define MG45_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_14PL = 0xFFFF; данные MG45_14PL. */ +#define MG45_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G45PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G45PL) || (G46PL == 0) +/* Задаёт MG45_16PL = ~(1 << 5); данные MG45_16PL. */ +#define MG45_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_16PL = 0xFFFF; данные MG45_16PL. */ +#define MG45_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G45PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G45PL) || (G47PL == 0) +/* Задаёт MG45_17PL = ~(1 << 6); данные MG45_17PL. */ +#define MG45_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_17PL = 0xFFFF; данные MG45_17PL. */ +#define MG45_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G45PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G45PL) || (G48PL == 0) +/* Задаёт MG45_18PL = ~(1 << 7); данные MG45_18PL. */ +#define MG45_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG45_18PL = 0xFFFF; данные MG45_18PL. */ +#define MG45_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG45_15PL = 0x00EF; данные MG45_15PL. */ +#define MG45_15PL 0x00EF +/* Задаёт MG45 = (MG45_11PL & MG45_12PL & MG45_13PL & MG45_14PL &; маска разрешённых прерываний внутри группы PIE 45. */ +#define MG45 (MG45_11PL & MG45_12PL & MG45_13PL & MG45_14PL & \ + MG45_15PL & MG45_16PL & MG45_17PL & MG45_18PL) /* Продолжает список аргументов, полей или выражение MG45_15PL & MG45_16PL & MG45_17PL & MG45_18PL); порядок элементов сохраняется. */ +// End of MG45: + +// Beginning of MG46: +/* Условие компиляции (G41PL >= G46PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G46PL) || (G41PL == 0) +/* Задаёт MG46_11PL = ~(1); данные MG46_11PL. */ +#define MG46_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_11PL = 0xFFFF; данные MG46_11PL. */ +#define MG46_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G46PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G46PL) || (G42PL == 0) +/* Задаёт MG46_12PL = ~(1 << 1); данные MG46_12PL. */ +#define MG46_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_12PL = 0xFFFF; данные MG46_12PL. */ +#define MG46_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G46PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G46PL) || (G43PL == 0) +/* Задаёт MG46_13PL = ~(1 << 2); данные MG46_13PL. */ +#define MG46_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_13PL = 0xFFFF; данные MG46_13PL. */ +#define MG46_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G46PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G46PL) || (G44PL == 0) +/* Задаёт MG46_14PL = ~(1 << 3); данные MG46_14PL. */ +#define MG46_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_14PL = 0xFFFF; данные MG46_14PL. */ +#define MG46_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G46PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G46PL) || (G45PL == 0) +/* Задаёт MG46_15PL = ~(1 << 4); данные MG46_15PL. */ +#define MG46_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_15PL = 0xFFFF; данные MG46_15PL. */ +#define MG46_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G46PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G46PL) || (G47PL == 0) +/* Задаёт MG46_17PL = ~(1 << 6); данные MG46_17PL. */ +#define MG46_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_17PL = 0xFFFF; данные MG46_17PL. */ +#define MG46_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G46PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G46PL) || (G48PL == 0) +/* Задаёт MG46_18PL = ~(1 << 7); данные MG46_18PL. */ +#define MG46_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG46_18PL = 0xFFFF; данные MG46_18PL. */ +#define MG46_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG46_16PL = 0x00DF; данные MG46_16PL. */ +#define MG46_16PL 0x00DF +/* Задаёт MG46 = (MG46_11PL & MG46_12PL & MG46_13PL & MG46_14PL &; маска разрешённых прерываний внутри группы PIE 46. */ +#define MG46 (MG46_11PL & MG46_12PL & MG46_13PL & MG46_14PL & \ + MG46_15PL & MG46_16PL & MG46_17PL & MG46_18PL) /* Продолжает список аргументов, полей или выражение MG46_15PL & MG46_16PL & MG46_17PL & MG46_18PL); порядок элементов сохраняется. */ +// End of MG46: + +// Beginning of MG47: +/* Условие компиляции (G41PL >= G47PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G47PL) || (G41PL == 0) +/* Задаёт MG47_11PL = ~(1); данные MG47_11PL. */ +#define MG47_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_11PL = 0xFFFF; данные MG47_11PL. */ +#define MG47_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G47PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G47PL) || (G42PL == 0) +/* Задаёт MG47_12PL = ~(1 << 1); данные MG47_12PL. */ +#define MG47_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_12PL = 0xFFFF; данные MG47_12PL. */ +#define MG47_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G47PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G47PL) || (G43PL == 0) +/* Задаёт MG47_13PL = ~(1 << 2); данные MG47_13PL. */ +#define MG47_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_13PL = 0xFFFF; данные MG47_13PL. */ +#define MG47_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G47PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G47PL) || (G44PL == 0) +/* Задаёт MG47_14PL = ~(1 << 3); данные MG47_14PL. */ +#define MG47_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_14PL = 0xFFFF; данные MG47_14PL. */ +#define MG47_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G47PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G47PL) || (G45PL == 0) +/* Задаёт MG47_15PL = ~(1 << 4); данные MG47_15PL. */ +#define MG47_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_15PL = 0xFFFF; данные MG47_15PL. */ +#define MG47_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G47PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G47PL) || (G46PL == 0) +/* Задаёт MG47_16PL = ~(1 << 5); данные MG47_16PL. */ +#define MG47_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_16PL = 0xFFFF; данные MG47_16PL. */ +#define MG47_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G48PL >= G47PL) или (G48PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G48PL >= G47PL) || (G48PL == 0) +/* Задаёт MG47_18PL = ~(1 << 7); данные MG47_18PL. */ +#define MG47_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG47_18PL = 0xFFFF; данные MG47_18PL. */ +#define MG47_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG47_17PL = 0x00BF; данные MG47_17PL. */ +#define MG47_17PL 0x00BF +/* Задаёт MG47 = (MG47_11PL & MG47_12PL & MG47_13PL & MG47_14PL &; маска разрешённых прерываний внутри группы PIE 47. */ +#define MG47 (MG47_11PL & MG47_12PL & MG47_13PL & MG47_14PL & \ + MG47_15PL & MG47_16PL & MG47_17PL & MG47_18PL) /* Продолжает список аргументов, полей или выражение MG47_15PL & MG47_16PL & MG47_17PL & MG47_18PL); порядок элементов сохраняется. */ +// End of MG47: + +// Beginning of MG48: +/* Условие компиляции (G41PL >= G48PL) или (G41PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G41PL >= G48PL) || (G41PL == 0) +/* Задаёт MG48_11PL = ~(1); данные MG48_11PL. */ +#define MG48_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_11PL = 0xFFFF; данные MG48_11PL. */ +#define MG48_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G42PL >= G48PL) или (G42PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G42PL >= G48PL) || (G42PL == 0) +/* Задаёт MG48_12PL = ~(1 << 1); данные MG48_12PL. */ +#define MG48_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_12PL = 0xFFFF; данные MG48_12PL. */ +#define MG48_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G43PL >= G48PL) или (G43PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G43PL >= G48PL) || (G43PL == 0) +/* Задаёт MG48_13PL = ~(1 << 2); данные MG48_13PL. */ +#define MG48_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_13PL = 0xFFFF; данные MG48_13PL. */ +#define MG48_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G44PL >= G48PL) или (G44PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G44PL >= G48PL) || (G44PL == 0) +/* Задаёт MG48_14PL = ~(1 << 3); данные MG48_14PL. */ +#define MG48_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_14PL = 0xFFFF; данные MG48_14PL. */ +#define MG48_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G45PL >= G48PL) или (G45PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G45PL >= G48PL) || (G45PL == 0) +/* Задаёт MG48_15PL = ~(1 << 4); данные MG48_15PL. */ +#define MG48_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_15PL = 0xFFFF; данные MG48_15PL. */ +#define MG48_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G46PL >= G48PL) или (G46PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G46PL >= G48PL) || (G46PL == 0) +/* Задаёт MG48_16PL = ~(1 << 5); данные MG48_16PL. */ +#define MG48_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_16PL = 0xFFFF; данные MG48_16PL. */ +#define MG48_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G47PL >= G48PL) или (G47PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G47PL >= G48PL) || (G47PL == 0) +/* Задаёт MG48_17PL = ~(1 << 6); данные MG48_17PL. */ +#define MG48_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG48_17PL = 0xFFFF; данные MG48_17PL. */ +#define MG48_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG48_18PL = 0x007F; данные MG48_18PL. */ +#define MG48_18PL 0x007F +/* Задаёт MG48 = (MG48_11PL & MG48_12PL & MG48_13PL & MG48_14PL &; маска разрешённых прерываний внутри группы PIE 48. */ +#define MG48 (MG48_11PL & MG48_12PL & MG48_13PL & MG48_14PL & \ + MG48_15PL & MG48_16PL & MG48_17PL & MG48_18PL) /* Продолжает список аргументов, полей или выражение MG48_15PL & MG48_16PL & MG48_17PL & MG48_18PL); порядок элементов сохраняется. */ +// End of MG48: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG51 to MG58: +// + +// Beginning of MG51: +/* Условие компиляции (G52PL >= G51PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G51PL) || (G52PL == 0) +/* Задаёт MG51_12PL = ~(1 << 1); данные MG51_12PL. */ +#define MG51_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_12PL = 0xFFFF; данные MG51_12PL. */ +#define MG51_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G51PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G51PL) || (G53PL == 0) +/* Задаёт MG51_13PL = ~(1 << 2); данные MG51_13PL. */ +#define MG51_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_13PL = 0xFFFF; данные MG51_13PL. */ +#define MG51_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G51PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G51PL) || (G54PL == 0) +/* Задаёт MG51_14PL = ~(1 << 3); данные MG51_14PL. */ +#define MG51_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_14PL = 0xFFFF; данные MG51_14PL. */ +#define MG51_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G51PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G51PL) || (G55PL == 0) +/* Задаёт MG51_15PL = ~(1 << 4); данные MG51_15PL. */ +#define MG51_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_15PL = 0xFFFF; данные MG51_15PL. */ +#define MG51_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G51PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G51PL) || (G56PL == 0) +/* Задаёт MG51_16PL = ~(1 << 5); данные MG51_16PL. */ +#define MG51_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_16PL = 0xFFFF; данные MG51_16PL. */ +#define MG51_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G51PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G51PL) || (G57PL == 0) +/* Задаёт MG51_17PL = ~(1 << 6); данные MG51_17PL. */ +#define MG51_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_17PL = 0xFFFF; данные MG51_17PL. */ +#define MG51_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G51PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G51PL) || (G58PL == 0) +/* Задаёт MG51_18PL = ~(1 << 7); данные MG51_18PL. */ +#define MG51_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG51_18PL = 0xFFFF; данные MG51_18PL. */ +#define MG51_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG51_11PL = 0x00FE; данные MG51_11PL. */ +#define MG51_11PL 0x00FE +/* Задаёт MG51 = (MG51_11PL & MG51_12PL & MG51_13PL & MG51_14PL &; маска разрешённых прерываний внутри группы PIE 51. */ +#define MG51 (MG51_11PL & MG51_12PL & MG51_13PL & MG51_14PL & \ + MG51_15PL & MG51_16PL & MG51_17PL & MG51_18PL) /* Продолжает список аргументов, полей или выражение MG51_15PL & MG51_16PL & MG51_17PL & MG51_18PL); порядок элементов сохраняется. */ +// End of MG51: + +// Beginning of MG52: +/* Условие компиляции (G51PL >= G52PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G52PL) || (G51PL == 0) +/* Задаёт MG52_11PL = ~(1); данные MG52_11PL. */ +#define MG52_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_11PL = 0xFFFF; данные MG52_11PL. */ +#define MG52_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G52PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G52PL) || (G53PL == 0) +/* Задаёт MG52_13PL = ~(1 << 2); данные MG52_13PL. */ +#define MG52_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_13PL = 0xFFFF; данные MG52_13PL. */ +#define MG52_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G52PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G52PL) || (G54PL == 0) +/* Задаёт MG52_14PL = ~(1 << 3); данные MG52_14PL. */ +#define MG52_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_14PL = 0xFFFF; данные MG52_14PL. */ +#define MG52_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G52PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G52PL) || (G55PL == 0) +/* Задаёт MG52_15PL = ~(1 << 4); данные MG52_15PL. */ +#define MG52_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_15PL = 0xFFFF; данные MG52_15PL. */ +#define MG52_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G52PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G52PL) || (G56PL == 0) +/* Задаёт MG52_16PL = ~(1 << 5); данные MG52_16PL. */ +#define MG52_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_16PL = 0xFFFF; данные MG52_16PL. */ +#define MG52_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G52PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G52PL) || (G57PL == 0) +/* Задаёт MG52_17PL = ~(1 << 6); данные MG52_17PL. */ +#define MG52_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_17PL = 0xFFFF; данные MG52_17PL. */ +#define MG52_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G52PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G52PL) || (G58PL == 0) +/* Задаёт MG52_18PL = ~(1 << 7); данные MG52_18PL. */ +#define MG52_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG52_18PL = 0xFFFF; данные MG52_18PL. */ +#define MG52_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG52_12PL = 0x00FD; данные MG52_12PL. */ +#define MG52_12PL 0x00FD +/* Задаёт MG52 = (MG52_11PL & MG52_12PL & MG52_13PL & MG52_14PL &; маска разрешённых прерываний внутри группы PIE 52. */ +#define MG52 (MG52_11PL & MG52_12PL & MG52_13PL & MG52_14PL & \ + MG52_15PL & MG52_16PL & MG52_17PL & MG52_18PL) /* Продолжает список аргументов, полей или выражение MG52_15PL & MG52_16PL & MG52_17PL & MG52_18PL); порядок элементов сохраняется. */ +// End of MG52: + +// Beginning of MG53: +/* Условие компиляции (G51PL >= G53PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G53PL) || (G51PL == 0) +/* Задаёт MG53_11PL = ~(1); данные MG53_11PL. */ +#define MG53_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_11PL = 0xFFFF; данные MG53_11PL. */ +#define MG53_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G53PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G53PL) || (G52PL == 0) +/* Задаёт MG53_12PL = ~(1 << 1); данные MG53_12PL. */ +#define MG53_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_12PL = 0xFFFF; данные MG53_12PL. */ +#define MG53_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G53PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G53PL) || (G54PL == 0) +/* Задаёт MG53_14PL = ~(1 << 3); данные MG53_14PL. */ +#define MG53_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_14PL = 0xFFFF; данные MG53_14PL. */ +#define MG53_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G53PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G53PL) || (G55PL == 0) +/* Задаёт MG53_15PL = ~(1 << 4); данные MG53_15PL. */ +#define MG53_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_15PL = 0xFFFF; данные MG53_15PL. */ +#define MG53_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G53PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G53PL) || (G56PL == 0) +/* Задаёт MG53_16PL = ~(1 << 5); данные MG53_16PL. */ +#define MG53_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_16PL = 0xFFFF; данные MG53_16PL. */ +#define MG53_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G53PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G53PL) || (G57PL == 0) +/* Задаёт MG53_17PL = ~(1 << 6); данные MG53_17PL. */ +#define MG53_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_17PL = 0xFFFF; данные MG53_17PL. */ +#define MG53_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G53PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G53PL) || (G58PL == 0) +/* Задаёт MG53_18PL = ~(1 << 7); данные MG53_18PL. */ +#define MG53_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG53_18PL = 0xFFFF; данные MG53_18PL. */ +#define MG53_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG53_13PL = 0x00FB; данные MG53_13PL. */ +#define MG53_13PL 0x00FB +/* Задаёт MG53 = (MG53_11PL & MG53_12PL & MG53_13PL & MG53_14PL &; маска разрешённых прерываний внутри группы PIE 53. */ +#define MG53 (MG53_11PL & MG53_12PL & MG53_13PL & MG53_14PL & \ + MG53_15PL & MG53_16PL & MG53_17PL & MG53_18PL) /* Продолжает список аргументов, полей или выражение MG53_15PL & MG53_16PL & MG53_17PL & MG53_18PL); порядок элементов сохраняется. */ +// End of MG53: + +// Beginning of MG54: +/* Условие компиляции (G51PL >= G54PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G54PL) || (G51PL == 0) +/* Задаёт MG54_11PL = ~(1); данные MG54_11PL. */ +#define MG54_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_11PL = 0xFFFF; данные MG54_11PL. */ +#define MG54_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G54PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G54PL) || (G52PL == 0) +/* Задаёт MG54_12PL = ~(1 << 1); данные MG54_12PL. */ +#define MG54_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_12PL = 0xFFFF; данные MG54_12PL. */ +#define MG54_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G54PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G54PL) || (G53PL == 0) +/* Задаёт MG54_13PL = ~(1 << 2); данные MG54_13PL. */ +#define MG54_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_13PL = 0xFFFF; данные MG54_13PL. */ +#define MG54_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G54PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G54PL) || (G55PL == 0) +/* Задаёт MG54_15PL = ~(1 << 4); данные MG54_15PL. */ +#define MG54_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_15PL = 0xFFFF; данные MG54_15PL. */ +#define MG54_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G54PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G54PL) || (G56PL == 0) +/* Задаёт MG54_16PL = ~(1 << 5); данные MG54_16PL. */ +#define MG54_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_16PL = 0xFFFF; данные MG54_16PL. */ +#define MG54_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G54PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G54PL) || (G57PL == 0) +/* Задаёт MG54_17PL = ~(1 << 6); данные MG54_17PL. */ +#define MG54_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_17PL = 0xFFFF; данные MG54_17PL. */ +#define MG54_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G54PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G54PL) || (G58PL == 0) +/* Задаёт MG54_18PL = ~(1 << 7); данные MG54_18PL. */ +#define MG54_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG54_18PL = 0xFFFF; данные MG54_18PL. */ +#define MG54_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG54_14PL = 0x00F7; данные MG54_14PL. */ +#define MG54_14PL 0x00F7 +/* Задаёт MG54 = (MG54_11PL & MG54_12PL & MG54_13PL & MG54_14PL &; маска разрешённых прерываний внутри группы PIE 54. */ +#define MG54 (MG54_11PL & MG54_12PL & MG54_13PL & MG54_14PL & \ + MG54_15PL & MG54_16PL & MG54_17PL & MG54_18PL) /* Продолжает список аргументов, полей или выражение MG54_15PL & MG54_16PL & MG54_17PL & MG54_18PL); порядок элементов сохраняется. */ +// End of MG54: + +// Beginning of MG55: +/* Условие компиляции (G51PL >= G55PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G55PL) || (G51PL == 0) +/* Задаёт MG55_11PL = ~(1); данные MG55_11PL. */ +#define MG55_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_11PL = 0xFFFF; данные MG55_11PL. */ +#define MG55_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G55PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G55PL) || (G52PL == 0) +/* Задаёт MG55_12PL = ~(1 << 1); данные MG55_12PL. */ +#define MG55_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_12PL = 0xFFFF; данные MG55_12PL. */ +#define MG55_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G55PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G55PL) || (G53PL == 0) +/* Задаёт MG55_13PL = ~(1 << 2); данные MG55_13PL. */ +#define MG55_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_13PL = 0xFFFF; данные MG55_13PL. */ +#define MG55_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G55PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G55PL) || (G54PL == 0) +/* Задаёт MG55_14PL = ~(1 << 3); данные MG55_14PL. */ +#define MG55_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_14PL = 0xFFFF; данные MG55_14PL. */ +#define MG55_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G55PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G55PL) || (G56PL == 0) +/* Задаёт MG55_16PL = ~(1 << 5); данные MG55_16PL. */ +#define MG55_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_16PL = 0xFFFF; данные MG55_16PL. */ +#define MG55_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G55PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G55PL) || (G57PL == 0) +/* Задаёт MG55_17PL = ~(1 << 6); данные MG55_17PL. */ +#define MG55_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_17PL = 0xFFFF; данные MG55_17PL. */ +#define MG55_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G55PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G55PL) || (G58PL == 0) +/* Задаёт MG55_18PL = ~(1 << 7); данные MG55_18PL. */ +#define MG55_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG55_18PL = 0xFFFF; данные MG55_18PL. */ +#define MG55_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG55_15PL = 0x00EF; данные MG55_15PL. */ +#define MG55_15PL 0x00EF +/* Задаёт MG55 = (MG55_11PL & MG55_12PL & MG55_13PL & MG55_14PL &; маска разрешённых прерываний внутри группы PIE 55. */ +#define MG55 (MG55_11PL & MG55_12PL & MG55_13PL & MG55_14PL & \ + MG55_15PL & MG55_16PL & MG55_17PL & MG55_18PL) /* Продолжает список аргументов, полей или выражение MG55_15PL & MG55_16PL & MG55_17PL & MG55_18PL); порядок элементов сохраняется. */ +// End of MG55: + +// Beginning of MG56: +/* Условие компиляции (G51PL >= G56PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G56PL) || (G51PL == 0) +/* Задаёт MG56_11PL = ~(1); данные MG56_11PL. */ +#define MG56_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_11PL = 0xFFFF; данные MG56_11PL. */ +#define MG56_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G56PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G56PL) || (G52PL == 0) +/* Задаёт MG56_12PL = ~(1 << 1); данные MG56_12PL. */ +#define MG56_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_12PL = 0xFFFF; данные MG56_12PL. */ +#define MG56_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G56PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G56PL) || (G53PL == 0) +/* Задаёт MG56_13PL = ~(1 << 2); данные MG56_13PL. */ +#define MG56_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_13PL = 0xFFFF; данные MG56_13PL. */ +#define MG56_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G56PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G56PL) || (G54PL == 0) +/* Задаёт MG56_14PL = ~(1 << 3); данные MG56_14PL. */ +#define MG56_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_14PL = 0xFFFF; данные MG56_14PL. */ +#define MG56_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G56PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G56PL) || (G55PL == 0) +/* Задаёт MG56_15PL = ~(1 << 4); данные MG56_15PL. */ +#define MG56_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_15PL = 0xFFFF; данные MG56_15PL. */ +#define MG56_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G56PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G56PL) || (G57PL == 0) +/* Задаёт MG56_17PL = ~(1 << 6); данные MG56_17PL. */ +#define MG56_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_17PL = 0xFFFF; данные MG56_17PL. */ +#define MG56_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G56PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G56PL) || (G58PL == 0) +/* Задаёт MG56_18PL = ~(1 << 7); данные MG56_18PL. */ +#define MG56_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG56_18PL = 0xFFFF; данные MG56_18PL. */ +#define MG56_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG56_16PL = 0x00DF; данные MG56_16PL. */ +#define MG56_16PL 0x00DF +/* Задаёт MG56 = (MG56_11PL & MG56_12PL & MG56_13PL & MG56_14PL &; маска разрешённых прерываний внутри группы PIE 56. */ +#define MG56 (MG56_11PL & MG56_12PL & MG56_13PL & MG56_14PL & \ + MG56_15PL & MG56_16PL & MG56_17PL & MG56_18PL) /* Продолжает список аргументов, полей или выражение MG56_15PL & MG56_16PL & MG56_17PL & MG56_18PL); порядок элементов сохраняется. */ +// End of MG56: + +// Beginning of MG57: +/* Условие компиляции (G51PL >= G57PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G57PL) || (G51PL == 0) +/* Задаёт MG57_11PL = ~(1); данные MG57_11PL. */ +#define MG57_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_11PL = 0xFFFF; данные MG57_11PL. */ +#define MG57_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G57PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G57PL) || (G52PL == 0) +/* Задаёт MG57_12PL = ~(1 << 1); данные MG57_12PL. */ +#define MG57_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_12PL = 0xFFFF; данные MG57_12PL. */ +#define MG57_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G57PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G57PL) || (G53PL == 0) +/* Задаёт MG57_13PL = ~(1 << 2); данные MG57_13PL. */ +#define MG57_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_13PL = 0xFFFF; данные MG57_13PL. */ +#define MG57_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G57PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G57PL) || (G54PL == 0) +/* Задаёт MG57_14PL = ~(1 << 3); данные MG57_14PL. */ +#define MG57_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_14PL = 0xFFFF; данные MG57_14PL. */ +#define MG57_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G57PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G57PL) || (G55PL == 0) +/* Задаёт MG57_15PL = ~(1 << 4); данные MG57_15PL. */ +#define MG57_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_15PL = 0xFFFF; данные MG57_15PL. */ +#define MG57_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G57PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G57PL) || (G56PL == 0) +/* Задаёт MG57_16PL = ~(1 << 5); данные MG57_16PL. */ +#define MG57_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_16PL = 0xFFFF; данные MG57_16PL. */ +#define MG57_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G58PL >= G57PL) или (G58PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G58PL >= G57PL) || (G58PL == 0) +/* Задаёт MG57_18PL = ~(1 << 7); данные MG57_18PL. */ +#define MG57_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG57_18PL = 0xFFFF; данные MG57_18PL. */ +#define MG57_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG57_17PL = 0x00BF; данные MG57_17PL. */ +#define MG57_17PL 0x00BF +/* Задаёт MG57 = (MG57_11PL & MG57_12PL & MG57_13PL & MG57_14PL &; маска разрешённых прерываний внутри группы PIE 57. */ +#define MG57 (MG57_11PL & MG57_12PL & MG57_13PL & MG57_14PL & \ + MG57_15PL & MG57_16PL & MG57_17PL & MG57_18PL) /* Продолжает список аргументов, полей или выражение MG57_15PL & MG57_16PL & MG57_17PL & MG57_18PL); порядок элементов сохраняется. */ +// End of MG57: + +// Beginning of MG58: +/* Условие компиляции (G51PL >= G58PL) или (G51PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G51PL >= G58PL) || (G51PL == 0) +/* Задаёт MG58_11PL = ~(1); данные MG58_11PL. */ +#define MG58_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_11PL = 0xFFFF; данные MG58_11PL. */ +#define MG58_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G52PL >= G58PL) или (G52PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G52PL >= G58PL) || (G52PL == 0) +/* Задаёт MG58_12PL = ~(1 << 1); данные MG58_12PL. */ +#define MG58_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_12PL = 0xFFFF; данные MG58_12PL. */ +#define MG58_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G53PL >= G58PL) или (G53PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G53PL >= G58PL) || (G53PL == 0) +/* Задаёт MG58_13PL = ~(1 << 2); данные MG58_13PL. */ +#define MG58_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_13PL = 0xFFFF; данные MG58_13PL. */ +#define MG58_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G54PL >= G58PL) или (G54PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G54PL >= G58PL) || (G54PL == 0) +/* Задаёт MG58_14PL = ~(1 << 3); данные MG58_14PL. */ +#define MG58_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_14PL = 0xFFFF; данные MG58_14PL. */ +#define MG58_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G55PL >= G58PL) или (G55PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G55PL >= G58PL) || (G55PL == 0) +/* Задаёт MG58_15PL = ~(1 << 4); данные MG58_15PL. */ +#define MG58_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_15PL = 0xFFFF; данные MG58_15PL. */ +#define MG58_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G56PL >= G58PL) или (G56PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G56PL >= G58PL) || (G56PL == 0) +/* Задаёт MG58_16PL = ~(1 << 5); данные MG58_16PL. */ +#define MG58_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_16PL = 0xFFFF; данные MG58_16PL. */ +#define MG58_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G57PL >= G58PL) или (G57PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G57PL >= G58PL) || (G57PL == 0) +/* Задаёт MG58_17PL = ~(1 << 6); данные MG58_17PL. */ +#define MG58_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG58_17PL = 0xFFFF; данные MG58_17PL. */ +#define MG58_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG58_18PL = 0x007F; данные MG58_18PL. */ +#define MG58_18PL 0x007F +/* Задаёт MG58 = (MG58_11PL & MG58_12PL & MG58_13PL & MG58_14PL &; маска разрешённых прерываний внутри группы PIE 58. */ +#define MG58 (MG58_11PL & MG58_12PL & MG58_13PL & MG58_14PL & \ + MG58_15PL & MG58_16PL & MG58_17PL & MG58_18PL) /* Продолжает список аргументов, полей или выражение MG58_15PL & MG58_16PL & MG58_17PL & MG58_18PL); порядок элементов сохраняется. */ +// End of MG58: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG61 to MG68: +// + +// Beginning of MG61: +/* Условие компиляции (G62PL >= G61PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G61PL) || (G62PL == 0) +/* Задаёт MG61_12PL = ~(1 << 1); данные MG61_12PL. */ +#define MG61_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_12PL = 0xFFFF; данные MG61_12PL. */ +#define MG61_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G61PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G61PL) || (G63PL == 0) +/* Задаёт MG61_13PL = ~(1 << 2); данные MG61_13PL. */ +#define MG61_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_13PL = 0xFFFF; данные MG61_13PL. */ +#define MG61_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G61PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G61PL) || (G64PL == 0) +/* Задаёт MG61_14PL = ~(1 << 3); данные MG61_14PL. */ +#define MG61_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_14PL = 0xFFFF; данные MG61_14PL. */ +#define MG61_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G61PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G61PL) || (G65PL == 0) +/* Задаёт MG61_15PL = ~(1 << 4); данные MG61_15PL. */ +#define MG61_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_15PL = 0xFFFF; данные MG61_15PL. */ +#define MG61_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G61PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G61PL) || (G66PL == 0) +/* Задаёт MG61_16PL = ~(1 << 5); данные MG61_16PL. */ +#define MG61_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_16PL = 0xFFFF; данные MG61_16PL. */ +#define MG61_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G61PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G61PL) || (G67PL == 0) +/* Задаёт MG61_17PL = ~(1 << 6); данные MG61_17PL. */ +#define MG61_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_17PL = 0xFFFF; данные MG61_17PL. */ +#define MG61_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G61PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G61PL) || (G68PL == 0) +/* Задаёт MG61_18PL = ~(1 << 7); данные MG61_18PL. */ +#define MG61_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG61_18PL = 0xFFFF; данные MG61_18PL. */ +#define MG61_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG61_11PL = 0x00FE; данные MG61_11PL. */ +#define MG61_11PL 0x00FE +/* Задаёт MG61 = (MG61_11PL & MG61_12PL & MG61_13PL & MG61_14PL &; маска разрешённых прерываний внутри группы PIE 61. */ +#define MG61 (MG61_11PL & MG61_12PL & MG61_13PL & MG61_14PL & \ + MG61_15PL & MG61_16PL & MG61_17PL & MG61_18PL) /* Продолжает список аргументов, полей или выражение MG61_15PL & MG61_16PL & MG61_17PL & MG61_18PL); порядок элементов сохраняется. */ +// End of MG61: + +// Beginning of MG62: +/* Условие компиляции (G61PL >= G62PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G62PL) || (G61PL == 0) +/* Задаёт MG62_11PL = ~(1); данные MG62_11PL. */ +#define MG62_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_11PL = 0xFFFF; данные MG62_11PL. */ +#define MG62_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G62PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G62PL) || (G63PL == 0) +/* Задаёт MG62_13PL = ~(1 << 2); данные MG62_13PL. */ +#define MG62_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_13PL = 0xFFFF; данные MG62_13PL. */ +#define MG62_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G62PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G62PL) || (G64PL == 0) +/* Задаёт MG62_14PL = ~(1 << 3); данные MG62_14PL. */ +#define MG62_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_14PL = 0xFFFF; данные MG62_14PL. */ +#define MG62_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G62PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G62PL) || (G65PL == 0) +/* Задаёт MG62_15PL = ~(1 << 4); данные MG62_15PL. */ +#define MG62_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_15PL = 0xFFFF; данные MG62_15PL. */ +#define MG62_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G62PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G62PL) || (G66PL == 0) +/* Задаёт MG62_16PL = ~(1 << 5); данные MG62_16PL. */ +#define MG62_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_16PL = 0xFFFF; данные MG62_16PL. */ +#define MG62_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G62PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G62PL) || (G67PL == 0) +/* Задаёт MG62_17PL = ~(1 << 6); данные MG62_17PL. */ +#define MG62_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_17PL = 0xFFFF; данные MG62_17PL. */ +#define MG62_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G62PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G62PL) || (G68PL == 0) +/* Задаёт MG62_18PL = ~(1 << 7); данные MG62_18PL. */ +#define MG62_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG62_18PL = 0xFFFF; данные MG62_18PL. */ +#define MG62_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG62_12PL = 0x00FD; данные MG62_12PL. */ +#define MG62_12PL 0x00FD +/* Задаёт MG62 = (MG62_11PL & MG62_12PL & MG62_13PL & MG62_14PL &; маска разрешённых прерываний внутри группы PIE 62. */ +#define MG62 (MG62_11PL & MG62_12PL & MG62_13PL & MG62_14PL & \ + MG62_15PL & MG62_16PL & MG62_17PL & MG62_18PL) /* Продолжает список аргументов, полей или выражение MG62_15PL & MG62_16PL & MG62_17PL & MG62_18PL); порядок элементов сохраняется. */ +// End of MG62: + +// Beginning of MG63: +/* Условие компиляции (G61PL >= G63PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G63PL) || (G61PL == 0) +/* Задаёт MG63_11PL = ~(1); данные MG63_11PL. */ +#define MG63_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_11PL = 0xFFFF; данные MG63_11PL. */ +#define MG63_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G63PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G63PL) || (G62PL == 0) +/* Задаёт MG63_12PL = ~(1 << 1); данные MG63_12PL. */ +#define MG63_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_12PL = 0xFFFF; данные MG63_12PL. */ +#define MG63_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G63PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G63PL) || (G64PL == 0) +/* Задаёт MG63_14PL = ~(1 << 3); данные MG63_14PL. */ +#define MG63_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_14PL = 0xFFFF; данные MG63_14PL. */ +#define MG63_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G63PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G63PL) || (G65PL == 0) +/* Задаёт MG63_15PL = ~(1 << 4); данные MG63_15PL. */ +#define MG63_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_15PL = 0xFFFF; данные MG63_15PL. */ +#define MG63_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G63PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G63PL) || (G66PL == 0) +/* Задаёт MG63_16PL = ~(1 << 5); данные MG63_16PL. */ +#define MG63_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_16PL = 0xFFFF; данные MG63_16PL. */ +#define MG63_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G63PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G63PL) || (G67PL == 0) +/* Задаёт MG63_17PL = ~(1 << 6); данные MG63_17PL. */ +#define MG63_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_17PL = 0xFFFF; данные MG63_17PL. */ +#define MG63_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G63PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G63PL) || (G68PL == 0) +/* Задаёт MG63_18PL = ~(1 << 7); данные MG63_18PL. */ +#define MG63_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG63_18PL = 0xFFFF; данные MG63_18PL. */ +#define MG63_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG63_13PL = 0x00FB; данные MG63_13PL. */ +#define MG63_13PL 0x00FB +/* Задаёт MG63 = (MG63_11PL & MG63_12PL & MG63_13PL & MG63_14PL &; маска разрешённых прерываний внутри группы PIE 63. */ +#define MG63 (MG63_11PL & MG63_12PL & MG63_13PL & MG63_14PL & \ + MG63_15PL & MG63_16PL & MG63_17PL & MG63_18PL) /* Продолжает список аргументов, полей или выражение MG63_15PL & MG63_16PL & MG63_17PL & MG63_18PL); порядок элементов сохраняется. */ +// End of MG63: + +// Beginning of MG64: +/* Условие компиляции (G61PL >= G64PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G64PL) || (G61PL == 0) +/* Задаёт MG64_11PL = ~(1); данные MG64_11PL. */ +#define MG64_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_11PL = 0xFFFF; данные MG64_11PL. */ +#define MG64_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G64PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G64PL) || (G62PL == 0) +/* Задаёт MG64_12PL = ~(1 << 1); данные MG64_12PL. */ +#define MG64_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_12PL = 0xFFFF; данные MG64_12PL. */ +#define MG64_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G64PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G64PL) || (G63PL == 0) +/* Задаёт MG64_13PL = ~(1 << 2); данные MG64_13PL. */ +#define MG64_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_13PL = 0xFFFF; данные MG64_13PL. */ +#define MG64_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G64PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G64PL) || (G65PL == 0) +/* Задаёт MG64_15PL = ~(1 << 4); данные MG64_15PL. */ +#define MG64_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_15PL = 0xFFFF; данные MG64_15PL. */ +#define MG64_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G64PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G64PL) || (G66PL == 0) +/* Задаёт MG64_16PL = ~(1 << 5); данные MG64_16PL. */ +#define MG64_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_16PL = 0xFFFF; данные MG64_16PL. */ +#define MG64_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G64PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G64PL) || (G67PL == 0) +/* Задаёт MG64_17PL = ~(1 << 6); данные MG64_17PL. */ +#define MG64_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_17PL = 0xFFFF; данные MG64_17PL. */ +#define MG64_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G64PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G64PL) || (G68PL == 0) +/* Задаёт MG64_18PL = ~(1 << 7); данные MG64_18PL. */ +#define MG64_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG64_18PL = 0xFFFF; данные MG64_18PL. */ +#define MG64_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG64_14PL = 0x00F7; данные MG64_14PL. */ +#define MG64_14PL 0x00F7 +/* Задаёт MG64 = (MG64_11PL & MG64_12PL & MG64_13PL & MG64_14PL &; маска разрешённых прерываний внутри группы PIE 64. */ +#define MG64 (MG64_11PL & MG64_12PL & MG64_13PL & MG64_14PL & \ + MG64_15PL & MG64_16PL & MG64_17PL & MG64_18PL) /* Продолжает список аргументов, полей или выражение MG64_15PL & MG64_16PL & MG64_17PL & MG64_18PL); порядок элементов сохраняется. */ +// End of MG64: + +// Beginning of MG65: +/* Условие компиляции (G61PL >= G65PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G65PL) || (G61PL == 0) +/* Задаёт MG65_11PL = ~(1); данные MG65_11PL. */ +#define MG65_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_11PL = 0xFFFF; данные MG65_11PL. */ +#define MG65_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G65PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G65PL) || (G62PL == 0) +/* Задаёт MG65_12PL = ~(1 << 1); данные MG65_12PL. */ +#define MG65_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_12PL = 0xFFFF; данные MG65_12PL. */ +#define MG65_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G65PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G65PL) || (G63PL == 0) +/* Задаёт MG65_13PL = ~(1 << 2); данные MG65_13PL. */ +#define MG65_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_13PL = 0xFFFF; данные MG65_13PL. */ +#define MG65_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G65PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G65PL) || (G64PL == 0) +/* Задаёт MG65_14PL = ~(1 << 3); данные MG65_14PL. */ +#define MG65_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_14PL = 0xFFFF; данные MG65_14PL. */ +#define MG65_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G65PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G65PL) || (G66PL == 0) +/* Задаёт MG65_16PL = ~(1 << 5); данные MG65_16PL. */ +#define MG65_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_16PL = 0xFFFF; данные MG65_16PL. */ +#define MG65_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G65PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G65PL) || (G67PL == 0) +/* Задаёт MG65_17PL = ~(1 << 6); данные MG65_17PL. */ +#define MG65_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_17PL = 0xFFFF; данные MG65_17PL. */ +#define MG65_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G65PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G65PL) || (G68PL == 0) +/* Задаёт MG65_18PL = ~(1 << 7); данные MG65_18PL. */ +#define MG65_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG65_18PL = 0xFFFF; данные MG65_18PL. */ +#define MG65_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG65_15PL = 0x00EF; данные MG65_15PL. */ +#define MG65_15PL 0x00EF +/* Задаёт MG65 = (MG65_11PL & MG65_12PL & MG65_13PL & MG65_14PL &; маска разрешённых прерываний внутри группы PIE 65. */ +#define MG65 (MG65_11PL & MG65_12PL & MG65_13PL & MG65_14PL & \ + MG65_15PL & MG65_16PL & MG65_17PL & MG65_18PL) /* Продолжает список аргументов, полей или выражение MG65_15PL & MG65_16PL & MG65_17PL & MG65_18PL); порядок элементов сохраняется. */ +// End of MG65: + +// Beginning of MG66: +/* Условие компиляции (G61PL >= G66PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G66PL) || (G61PL == 0) +/* Задаёт MG66_11PL = ~(1); данные MG66_11PL. */ +#define MG66_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_11PL = 0xFFFF; данные MG66_11PL. */ +#define MG66_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G66PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G66PL) || (G62PL == 0) +/* Задаёт MG66_12PL = ~(1 << 1); данные MG66_12PL. */ +#define MG66_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_12PL = 0xFFFF; данные MG66_12PL. */ +#define MG66_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G66PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G66PL) || (G63PL == 0) +/* Задаёт MG66_13PL = ~(1 << 2); данные MG66_13PL. */ +#define MG66_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_13PL = 0xFFFF; данные MG66_13PL. */ +#define MG66_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G66PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G66PL) || (G64PL == 0) +/* Задаёт MG66_14PL = ~(1 << 3); данные MG66_14PL. */ +#define MG66_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_14PL = 0xFFFF; данные MG66_14PL. */ +#define MG66_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G66PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G66PL) || (G65PL == 0) +/* Задаёт MG66_15PL = ~(1 << 4); данные MG66_15PL. */ +#define MG66_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_15PL = 0xFFFF; данные MG66_15PL. */ +#define MG66_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G66PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G66PL) || (G67PL == 0) +/* Задаёт MG66_17PL = ~(1 << 6); данные MG66_17PL. */ +#define MG66_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_17PL = 0xFFFF; данные MG66_17PL. */ +#define MG66_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G66PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G66PL) || (G68PL == 0) +/* Задаёт MG66_18PL = ~(1 << 7); данные MG66_18PL. */ +#define MG66_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG66_18PL = 0xFFFF; данные MG66_18PL. */ +#define MG66_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG66_16PL = 0x00DF; данные MG66_16PL. */ +#define MG66_16PL 0x00DF +/* Задаёт MG66 = (MG66_11PL & MG66_12PL & MG66_13PL & MG66_14PL &; маска разрешённых прерываний внутри группы PIE 66. */ +#define MG66 (MG66_11PL & MG66_12PL & MG66_13PL & MG66_14PL & \ + MG66_15PL & MG66_16PL & MG66_17PL & MG66_18PL) /* Продолжает список аргументов, полей или выражение MG66_15PL & MG66_16PL & MG66_17PL & MG66_18PL); порядок элементов сохраняется. */ +// End of MG66: + +// Beginning of MG67: +/* Условие компиляции (G61PL >= G67PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G67PL) || (G61PL == 0) +/* Задаёт MG67_11PL = ~(1); данные MG67_11PL. */ +#define MG67_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_11PL = 0xFFFF; данные MG67_11PL. */ +#define MG67_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G67PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G67PL) || (G62PL == 0) +/* Задаёт MG67_12PL = ~(1 << 1); данные MG67_12PL. */ +#define MG67_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_12PL = 0xFFFF; данные MG67_12PL. */ +#define MG67_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G67PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G67PL) || (G63PL == 0) +/* Задаёт MG67_13PL = ~(1 << 2); данные MG67_13PL. */ +#define MG67_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_13PL = 0xFFFF; данные MG67_13PL. */ +#define MG67_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G67PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G67PL) || (G64PL == 0) +/* Задаёт MG67_14PL = ~(1 << 3); данные MG67_14PL. */ +#define MG67_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_14PL = 0xFFFF; данные MG67_14PL. */ +#define MG67_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G67PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G67PL) || (G65PL == 0) +/* Задаёт MG67_15PL = ~(1 << 4); данные MG67_15PL. */ +#define MG67_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_15PL = 0xFFFF; данные MG67_15PL. */ +#define MG67_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G67PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G67PL) || (G66PL == 0) +/* Задаёт MG67_16PL = ~(1 << 5); данные MG67_16PL. */ +#define MG67_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_16PL = 0xFFFF; данные MG67_16PL. */ +#define MG67_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G68PL >= G67PL) или (G68PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G68PL >= G67PL) || (G68PL == 0) +/* Задаёт MG67_18PL = ~(1 << 7); данные MG67_18PL. */ +#define MG67_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG67_18PL = 0xFFFF; данные MG67_18PL. */ +#define MG67_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG67_17PL = 0x00BF; данные MG67_17PL. */ +#define MG67_17PL 0x00BF +/* Задаёт MG67 = (MG67_11PL & MG67_12PL & MG67_13PL & MG67_14PL &; маска разрешённых прерываний внутри группы PIE 67. */ +#define MG67 (MG67_11PL & MG67_12PL & MG67_13PL & MG67_14PL & \ + MG67_15PL & MG67_16PL & MG67_17PL & MG67_18PL) /* Продолжает список аргументов, полей или выражение MG67_15PL & MG67_16PL & MG67_17PL & MG67_18PL); порядок элементов сохраняется. */ +// End of MG67: + +// Beginning of MG68: +/* Условие компиляции (G61PL >= G68PL) или (G61PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G61PL >= G68PL) || (G61PL == 0) +/* Задаёт MG68_11PL = ~(1); данные MG68_11PL. */ +#define MG68_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_11PL = 0xFFFF; данные MG68_11PL. */ +#define MG68_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G62PL >= G68PL) или (G62PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G62PL >= G68PL) || (G62PL == 0) +/* Задаёт MG68_12PL = ~(1 << 1); данные MG68_12PL. */ +#define MG68_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_12PL = 0xFFFF; данные MG68_12PL. */ +#define MG68_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G63PL >= G68PL) или (G63PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G63PL >= G68PL) || (G63PL == 0) +/* Задаёт MG68_13PL = ~(1 << 2); данные MG68_13PL. */ +#define MG68_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_13PL = 0xFFFF; данные MG68_13PL. */ +#define MG68_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G64PL >= G68PL) или (G64PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G64PL >= G68PL) || (G64PL == 0) +/* Задаёт MG68_14PL = ~(1 << 3); данные MG68_14PL. */ +#define MG68_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_14PL = 0xFFFF; данные MG68_14PL. */ +#define MG68_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G65PL >= G68PL) или (G65PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G65PL >= G68PL) || (G65PL == 0) +/* Задаёт MG68_15PL = ~(1 << 4); данные MG68_15PL. */ +#define MG68_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_15PL = 0xFFFF; данные MG68_15PL. */ +#define MG68_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G66PL >= G68PL) или (G66PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G66PL >= G68PL) || (G66PL == 0) +/* Задаёт MG68_16PL = ~(1 << 5); данные MG68_16PL. */ +#define MG68_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_16PL = 0xFFFF; данные MG68_16PL. */ +#define MG68_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G67PL >= G68PL) или (G67PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G67PL >= G68PL) || (G67PL == 0) +/* Задаёт MG68_17PL = ~(1 << 6); данные MG68_17PL. */ +#define MG68_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG68_17PL = 0xFFFF; данные MG68_17PL. */ +#define MG68_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG68_18PL = 0x007F; данные MG68_18PL. */ +#define MG68_18PL 0x007F +/* Задаёт MG68 = (MG68_11PL & MG68_12PL & MG68_13PL & MG68_14PL &; маска разрешённых прерываний внутри группы PIE 68. */ +#define MG68 (MG68_11PL & MG68_12PL & MG68_13PL & MG68_14PL & \ + MG68_15PL & MG68_16PL & MG68_17PL & MG68_18PL) /* Продолжает список аргументов, полей или выражение MG68_15PL & MG68_16PL & MG68_17PL & MG68_18PL); порядок элементов сохраняется. */ +// End of MG68: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG71 to MG78: +// + +// Beginning of MG71: +/* Условие компиляции (G72PL >= G71PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G71PL) || (G72PL == 0) +/* Задаёт MG71_12PL = ~(1 << 1); данные MG71_12PL. */ +#define MG71_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_12PL = 0xFFFF; данные MG71_12PL. */ +#define MG71_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G71PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G71PL) || (G73PL == 0) +/* Задаёт MG71_13PL = ~(1 << 2); данные MG71_13PL. */ +#define MG71_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_13PL = 0xFFFF; данные MG71_13PL. */ +#define MG71_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G71PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G71PL) || (G74PL == 0) +/* Задаёт MG71_14PL = ~(1 << 3); данные MG71_14PL. */ +#define MG71_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_14PL = 0xFFFF; данные MG71_14PL. */ +#define MG71_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G71PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G71PL) || (G75PL == 0) +/* Задаёт MG71_15PL = ~(1 << 4); данные MG71_15PL. */ +#define MG71_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_15PL = 0xFFFF; данные MG71_15PL. */ +#define MG71_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G71PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G71PL) || (G76PL == 0) +/* Задаёт MG71_16PL = ~(1 << 5); данные MG71_16PL. */ +#define MG71_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_16PL = 0xFFFF; данные MG71_16PL. */ +#define MG71_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G71PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G71PL) || (G77PL == 0) +/* Задаёт MG71_17PL = ~(1 << 6); данные MG71_17PL. */ +#define MG71_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_17PL = 0xFFFF; данные MG71_17PL. */ +#define MG71_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G71PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G71PL) || (G78PL == 0) +/* Задаёт MG71_18PL = ~(1 << 7); данные MG71_18PL. */ +#define MG71_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG71_18PL = 0xFFFF; данные MG71_18PL. */ +#define MG71_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG71_11PL = 0x00FE; данные MG71_11PL. */ +#define MG71_11PL 0x00FE +/* Задаёт MG71 = (MG71_11PL & MG71_12PL & MG71_13PL & MG71_14PL &; маска разрешённых прерываний внутри группы PIE 71. */ +#define MG71 (MG71_11PL & MG71_12PL & MG71_13PL & MG71_14PL & \ + MG71_15PL & MG71_16PL & MG71_17PL & MG71_18PL) /* Продолжает список аргументов, полей или выражение MG71_15PL & MG71_16PL & MG71_17PL & MG71_18PL); порядок элементов сохраняется. */ +// End of MG71: + +// Beginning of MG72: +/* Условие компиляции (G71PL >= G72PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G72PL) || (G71PL == 0) +/* Задаёт MG72_11PL = ~(1); данные MG72_11PL. */ +#define MG72_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_11PL = 0xFFFF; данные MG72_11PL. */ +#define MG72_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G72PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G72PL) || (G73PL == 0) +/* Задаёт MG72_13PL = ~(1 << 2); данные MG72_13PL. */ +#define MG72_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_13PL = 0xFFFF; данные MG72_13PL. */ +#define MG72_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G72PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G72PL) || (G74PL == 0) +/* Задаёт MG72_14PL = ~(1 << 3); данные MG72_14PL. */ +#define MG72_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_14PL = 0xFFFF; данные MG72_14PL. */ +#define MG72_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G72PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G72PL) || (G75PL == 0) +/* Задаёт MG72_15PL = ~(1 << 4); данные MG72_15PL. */ +#define MG72_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_15PL = 0xFFFF; данные MG72_15PL. */ +#define MG72_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G72PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G72PL) || (G76PL == 0) +/* Задаёт MG72_16PL = ~(1 << 5); данные MG72_16PL. */ +#define MG72_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_16PL = 0xFFFF; данные MG72_16PL. */ +#define MG72_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G72PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G72PL) || (G77PL == 0) +/* Задаёт MG72_17PL = ~(1 << 6); данные MG72_17PL. */ +#define MG72_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_17PL = 0xFFFF; данные MG72_17PL. */ +#define MG72_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G72PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G72PL) || (G78PL == 0) +/* Задаёт MG72_18PL = ~(1 << 7); данные MG72_18PL. */ +#define MG72_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG72_18PL = 0xFFFF; данные MG72_18PL. */ +#define MG72_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG72_12PL = 0x00FD; данные MG72_12PL. */ +#define MG72_12PL 0x00FD +/* Задаёт MG72 = (MG72_11PL & MG72_12PL & MG72_13PL & MG72_14PL &; маска разрешённых прерываний внутри группы PIE 72. */ +#define MG72 (MG72_11PL & MG72_12PL & MG72_13PL & MG72_14PL & \ + MG72_15PL & MG72_16PL & MG72_17PL & MG72_18PL) /* Продолжает список аргументов, полей или выражение MG72_15PL & MG72_16PL & MG72_17PL & MG72_18PL); порядок элементов сохраняется. */ +// End of MG72: + +// Beginning of MG73: +/* Условие компиляции (G71PL >= G73PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G73PL) || (G71PL == 0) +/* Задаёт MG73_11PL = ~(1); данные MG73_11PL. */ +#define MG73_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_11PL = 0xFFFF; данные MG73_11PL. */ +#define MG73_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G73PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G73PL) || (G72PL == 0) +/* Задаёт MG73_12PL = ~(1 << 1); данные MG73_12PL. */ +#define MG73_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_12PL = 0xFFFF; данные MG73_12PL. */ +#define MG73_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G73PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G73PL) || (G74PL == 0) +/* Задаёт MG73_14PL = ~(1 << 3); данные MG73_14PL. */ +#define MG73_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_14PL = 0xFFFF; данные MG73_14PL. */ +#define MG73_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G73PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G73PL) || (G75PL == 0) +/* Задаёт MG73_15PL = ~(1 << 4); данные MG73_15PL. */ +#define MG73_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_15PL = 0xFFFF; данные MG73_15PL. */ +#define MG73_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G73PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G73PL) || (G76PL == 0) +/* Задаёт MG73_16PL = ~(1 << 5); данные MG73_16PL. */ +#define MG73_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_16PL = 0xFFFF; данные MG73_16PL. */ +#define MG73_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G73PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G73PL) || (G77PL == 0) +/* Задаёт MG73_17PL = ~(1 << 6); данные MG73_17PL. */ +#define MG73_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_17PL = 0xFFFF; данные MG73_17PL. */ +#define MG73_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G73PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G73PL) || (G78PL == 0) +/* Задаёт MG73_18PL = ~(1 << 7); данные MG73_18PL. */ +#define MG73_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG73_18PL = 0xFFFF; данные MG73_18PL. */ +#define MG73_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG73_13PL = 0x00FB; данные MG73_13PL. */ +#define MG73_13PL 0x00FB +/* Задаёт MG73 = (MG73_11PL & MG73_12PL & MG73_13PL & MG73_14PL &; маска разрешённых прерываний внутри группы PIE 73. */ +#define MG73 (MG73_11PL & MG73_12PL & MG73_13PL & MG73_14PL & \ + MG73_15PL & MG73_16PL & MG73_17PL & MG73_18PL) /* Продолжает список аргументов, полей или выражение MG73_15PL & MG73_16PL & MG73_17PL & MG73_18PL); порядок элементов сохраняется. */ +// End of MG73: + +// Beginning of MG74: +/* Условие компиляции (G71PL >= G74PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G74PL) || (G71PL == 0) +/* Задаёт MG74_11PL = ~(1); данные MG74_11PL. */ +#define MG74_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_11PL = 0xFFFF; данные MG74_11PL. */ +#define MG74_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G74PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G74PL) || (G72PL == 0) +/* Задаёт MG74_12PL = ~(1 << 1); данные MG74_12PL. */ +#define MG74_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_12PL = 0xFFFF; данные MG74_12PL. */ +#define MG74_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G74PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G74PL) || (G73PL == 0) +/* Задаёт MG74_13PL = ~(1 << 2); данные MG74_13PL. */ +#define MG74_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_13PL = 0xFFFF; данные MG74_13PL. */ +#define MG74_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G74PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G74PL) || (G75PL == 0) +/* Задаёт MG74_15PL = ~(1 << 4); данные MG74_15PL. */ +#define MG74_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_15PL = 0xFFFF; данные MG74_15PL. */ +#define MG74_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G74PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G74PL) || (G76PL == 0) +/* Задаёт MG74_16PL = ~(1 << 5); данные MG74_16PL. */ +#define MG74_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_16PL = 0xFFFF; данные MG74_16PL. */ +#define MG74_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G74PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G74PL) || (G77PL == 0) +/* Задаёт MG74_17PL = ~(1 << 6); данные MG74_17PL. */ +#define MG74_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_17PL = 0xFFFF; данные MG74_17PL. */ +#define MG74_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G74PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G74PL) || (G78PL == 0) +/* Задаёт MG74_18PL = ~(1 << 7); данные MG74_18PL. */ +#define MG74_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG74_18PL = 0xFFFF; данные MG74_18PL. */ +#define MG74_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG74_14PL = 0x00F7; данные MG74_14PL. */ +#define MG74_14PL 0x00F7 +/* Задаёт MG74 = (MG74_11PL & MG74_12PL & MG74_13PL & MG74_14PL &; маска разрешённых прерываний внутри группы PIE 74. */ +#define MG74 (MG74_11PL & MG74_12PL & MG74_13PL & MG74_14PL & \ + MG74_15PL & MG74_16PL & MG74_17PL & MG74_18PL) /* Продолжает список аргументов, полей или выражение MG74_15PL & MG74_16PL & MG74_17PL & MG74_18PL); порядок элементов сохраняется. */ +// End of MG74: + +// Beginning of MG75: +/* Условие компиляции (G71PL >= G75PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G75PL) || (G71PL == 0) +/* Задаёт MG75_11PL = ~(1); данные MG75_11PL. */ +#define MG75_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_11PL = 0xFFFF; данные MG75_11PL. */ +#define MG75_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G75PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G75PL) || (G72PL == 0) +/* Задаёт MG75_12PL = ~(1 << 1); данные MG75_12PL. */ +#define MG75_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_12PL = 0xFFFF; данные MG75_12PL. */ +#define MG75_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G75PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G75PL) || (G73PL == 0) +/* Задаёт MG75_13PL = ~(1 << 2); данные MG75_13PL. */ +#define MG75_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_13PL = 0xFFFF; данные MG75_13PL. */ +#define MG75_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G75PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G75PL) || (G74PL == 0) +/* Задаёт MG75_14PL = ~(1 << 3); данные MG75_14PL. */ +#define MG75_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_14PL = 0xFFFF; данные MG75_14PL. */ +#define MG75_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G75PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G75PL) || (G76PL == 0) +/* Задаёт MG75_16PL = ~(1 << 5); данные MG75_16PL. */ +#define MG75_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_16PL = 0xFFFF; данные MG75_16PL. */ +#define MG75_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G75PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G75PL) || (G77PL == 0) +/* Задаёт MG75_17PL = ~(1 << 6); данные MG75_17PL. */ +#define MG75_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_17PL = 0xFFFF; данные MG75_17PL. */ +#define MG75_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G75PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G75PL) || (G78PL == 0) +/* Задаёт MG75_18PL = ~(1 << 7); данные MG75_18PL. */ +#define MG75_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG75_18PL = 0xFFFF; данные MG75_18PL. */ +#define MG75_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG75_15PL = 0x00EF; данные MG75_15PL. */ +#define MG75_15PL 0x00EF +/* Задаёт MG75 = (MG75_11PL & MG75_12PL & MG75_13PL & MG75_14PL &; маска разрешённых прерываний внутри группы PIE 75. */ +#define MG75 (MG75_11PL & MG75_12PL & MG75_13PL & MG75_14PL & \ + MG75_15PL & MG75_16PL & MG75_17PL & MG75_18PL) /* Продолжает список аргументов, полей или выражение MG75_15PL & MG75_16PL & MG75_17PL & MG75_18PL); порядок элементов сохраняется. */ +// End of MG75: + +// Beginning of MG76: +/* Условие компиляции (G71PL >= G76PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G76PL) || (G71PL == 0) +/* Задаёт MG76_11PL = ~(1); данные MG76_11PL. */ +#define MG76_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_11PL = 0xFFFF; данные MG76_11PL. */ +#define MG76_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G76PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G76PL) || (G72PL == 0) +/* Задаёт MG76_12PL = ~(1 << 1); данные MG76_12PL. */ +#define MG76_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_12PL = 0xFFFF; данные MG76_12PL. */ +#define MG76_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G76PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G76PL) || (G73PL == 0) +/* Задаёт MG76_13PL = ~(1 << 2); данные MG76_13PL. */ +#define MG76_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_13PL = 0xFFFF; данные MG76_13PL. */ +#define MG76_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G76PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G76PL) || (G74PL == 0) +/* Задаёт MG76_14PL = ~(1 << 3); данные MG76_14PL. */ +#define MG76_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_14PL = 0xFFFF; данные MG76_14PL. */ +#define MG76_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G76PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G76PL) || (G75PL == 0) +/* Задаёт MG76_15PL = ~(1 << 4); данные MG76_15PL. */ +#define MG76_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_15PL = 0xFFFF; данные MG76_15PL. */ +#define MG76_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G76PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G76PL) || (G77PL == 0) +/* Задаёт MG76_17PL = ~(1 << 6); данные MG76_17PL. */ +#define MG76_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_17PL = 0xFFFF; данные MG76_17PL. */ +#define MG76_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G76PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G76PL) || (G78PL == 0) +/* Задаёт MG76_18PL = ~(1 << 7); данные MG76_18PL. */ +#define MG76_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG76_18PL = 0xFFFF; данные MG76_18PL. */ +#define MG76_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG76_16PL = 0x00DF; данные MG76_16PL. */ +#define MG76_16PL 0x00DF +/* Задаёт MG76 = (MG76_11PL & MG76_12PL & MG76_13PL & MG76_14PL &; маска разрешённых прерываний внутри группы PIE 76. */ +#define MG76 (MG76_11PL & MG76_12PL & MG76_13PL & MG76_14PL & \ + MG76_15PL & MG76_16PL & MG76_17PL & MG76_18PL) /* Продолжает список аргументов, полей или выражение MG76_15PL & MG76_16PL & MG76_17PL & MG76_18PL); порядок элементов сохраняется. */ +// End of MG76: + +// Beginning of MG77: +/* Условие компиляции (G71PL >= G77PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G77PL) || (G71PL == 0) +/* Задаёт MG77_11PL = ~(1); данные MG77_11PL. */ +#define MG77_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_11PL = 0xFFFF; данные MG77_11PL. */ +#define MG77_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G77PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G77PL) || (G72PL == 0) +/* Задаёт MG77_12PL = ~(1 << 1); данные MG77_12PL. */ +#define MG77_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_12PL = 0xFFFF; данные MG77_12PL. */ +#define MG77_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G77PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G77PL) || (G73PL == 0) +/* Задаёт MG77_13PL = ~(1 << 2); данные MG77_13PL. */ +#define MG77_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_13PL = 0xFFFF; данные MG77_13PL. */ +#define MG77_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G77PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G77PL) || (G74PL == 0) +/* Задаёт MG77_14PL = ~(1 << 3); данные MG77_14PL. */ +#define MG77_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_14PL = 0xFFFF; данные MG77_14PL. */ +#define MG77_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G77PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G77PL) || (G75PL == 0) +/* Задаёт MG77_15PL = ~(1 << 4); данные MG77_15PL. */ +#define MG77_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_15PL = 0xFFFF; данные MG77_15PL. */ +#define MG77_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G77PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G77PL) || (G76PL == 0) +/* Задаёт MG77_16PL = ~(1 << 5); данные MG77_16PL. */ +#define MG77_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_16PL = 0xFFFF; данные MG77_16PL. */ +#define MG77_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G78PL >= G77PL) или (G78PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G78PL >= G77PL) || (G78PL == 0) +/* Задаёт MG77_18PL = ~(1 << 7); данные MG77_18PL. */ +#define MG77_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG77_18PL = 0xFFFF; данные MG77_18PL. */ +#define MG77_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG77_17PL = 0x00BF; данные MG77_17PL. */ +#define MG77_17PL 0x00BF +/* Задаёт MG77 = (MG77_11PL & MG77_12PL & MG77_13PL & MG77_14PL &; маска разрешённых прерываний внутри группы PIE 77. */ +#define MG77 (MG77_11PL & MG77_12PL & MG77_13PL & MG77_14PL & \ + MG77_15PL & MG77_16PL & MG77_17PL & MG77_18PL) /* Продолжает список аргументов, полей или выражение MG77_15PL & MG77_16PL & MG77_17PL & MG77_18PL); порядок элементов сохраняется. */ +// End of MG77: + +// Beginning of MG78: +/* Условие компиляции (G71PL >= G78PL) или (G71PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G71PL >= G78PL) || (G71PL == 0) +/* Задаёт MG78_11PL = ~(1); данные MG78_11PL. */ +#define MG78_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_11PL = 0xFFFF; данные MG78_11PL. */ +#define MG78_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G72PL >= G78PL) или (G72PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G72PL >= G78PL) || (G72PL == 0) +/* Задаёт MG78_12PL = ~(1 << 1); данные MG78_12PL. */ +#define MG78_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_12PL = 0xFFFF; данные MG78_12PL. */ +#define MG78_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G73PL >= G78PL) или (G73PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G73PL >= G78PL) || (G73PL == 0) +/* Задаёт MG78_13PL = ~(1 << 2); данные MG78_13PL. */ +#define MG78_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_13PL = 0xFFFF; данные MG78_13PL. */ +#define MG78_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G74PL >= G78PL) или (G74PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G74PL >= G78PL) || (G74PL == 0) +/* Задаёт MG78_14PL = ~(1 << 3); данные MG78_14PL. */ +#define MG78_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_14PL = 0xFFFF; данные MG78_14PL. */ +#define MG78_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G75PL >= G78PL) или (G75PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G75PL >= G78PL) || (G75PL == 0) +/* Задаёт MG78_15PL = ~(1 << 4); данные MG78_15PL. */ +#define MG78_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_15PL = 0xFFFF; данные MG78_15PL. */ +#define MG78_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G76PL >= G78PL) или (G76PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G76PL >= G78PL) || (G76PL == 0) +/* Задаёт MG78_16PL = ~(1 << 5); данные MG78_16PL. */ +#define MG78_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_16PL = 0xFFFF; данные MG78_16PL. */ +#define MG78_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G77PL >= G78PL) или (G77PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G77PL >= G78PL) || (G77PL == 0) +/* Задаёт MG78_17PL = ~(1 << 6); данные MG78_17PL. */ +#define MG78_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG78_17PL = 0xFFFF; данные MG78_17PL. */ +#define MG78_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG78_18PL = 0x007F; данные MG78_18PL. */ +#define MG78_18PL 0x007F +/* Задаёт MG78 = (MG78_11PL & MG78_12PL & MG78_13PL & MG78_14PL &; маска разрешённых прерываний внутри группы PIE 78. */ +#define MG78 (MG78_11PL & MG78_12PL & MG78_13PL & MG78_14PL & \ + MG78_15PL & MG78_16PL & MG78_17PL & MG78_18PL) /* Продолжает список аргументов, полей или выражение MG78_15PL & MG78_16PL & MG78_17PL & MG78_18PL); порядок элементов сохраняется. */ +// End of MG78: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG81 to MG88: +// + +// Beginning of MG81: +/* Условие компиляции (G82PL >= G81PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G81PL) || (G82PL == 0) +/* Задаёт MG81_12PL = ~(1 << 1); данные MG81_12PL. */ +#define MG81_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_12PL = 0xFFFF; данные MG81_12PL. */ +#define MG81_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G81PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G81PL) || (G83PL == 0) +/* Задаёт MG81_13PL = ~(1 << 2); данные MG81_13PL. */ +#define MG81_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_13PL = 0xFFFF; данные MG81_13PL. */ +#define MG81_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G81PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G81PL) || (G84PL == 0) +/* Задаёт MG81_14PL = ~(1 << 3); данные MG81_14PL. */ +#define MG81_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_14PL = 0xFFFF; данные MG81_14PL. */ +#define MG81_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G81PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G81PL) || (G85PL == 0) +/* Задаёт MG81_15PL = ~(1 << 4); данные MG81_15PL. */ +#define MG81_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_15PL = 0xFFFF; данные MG81_15PL. */ +#define MG81_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G81PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G81PL) || (G86PL == 0) +/* Задаёт MG81_16PL = ~(1 << 5); данные MG81_16PL. */ +#define MG81_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_16PL = 0xFFFF; данные MG81_16PL. */ +#define MG81_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G81PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G81PL) || (G87PL == 0) +/* Задаёт MG81_17PL = ~(1 << 6); данные MG81_17PL. */ +#define MG81_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_17PL = 0xFFFF; данные MG81_17PL. */ +#define MG81_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G81PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G81PL) || (G88PL == 0) +/* Задаёт MG81_18PL = ~(1 << 7); данные MG81_18PL. */ +#define MG81_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG81_18PL = 0xFFFF; данные MG81_18PL. */ +#define MG81_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG81_11PL = 0x00FE; данные MG81_11PL. */ +#define MG81_11PL 0x00FE +/* Задаёт MG81 = (MG81_11PL & MG81_12PL & MG81_13PL & MG81_14PL &; маска разрешённых прерываний внутри группы PIE 81. */ +#define MG81 (MG81_11PL & MG81_12PL & MG81_13PL & MG81_14PL & \ + MG81_15PL & MG81_16PL & MG81_17PL & MG81_18PL) /* Продолжает список аргументов, полей или выражение MG81_15PL & MG81_16PL & MG81_17PL & MG81_18PL); порядок элементов сохраняется. */ +// End of MG81: + +// Beginning of MG82: +/* Условие компиляции (G81PL >= G82PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G82PL) || (G81PL == 0) +/* Задаёт MG82_11PL = ~(1); данные MG82_11PL. */ +#define MG82_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_11PL = 0xFFFF; данные MG82_11PL. */ +#define MG82_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G82PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G82PL) || (G83PL == 0) +/* Задаёт MG82_13PL = ~(1 << 2); данные MG82_13PL. */ +#define MG82_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_13PL = 0xFFFF; данные MG82_13PL. */ +#define MG82_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G82PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G82PL) || (G84PL == 0) +/* Задаёт MG82_14PL = ~(1 << 3); данные MG82_14PL. */ +#define MG82_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_14PL = 0xFFFF; данные MG82_14PL. */ +#define MG82_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G82PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G82PL) || (G85PL == 0) +/* Задаёт MG82_15PL = ~(1 << 4); данные MG82_15PL. */ +#define MG82_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_15PL = 0xFFFF; данные MG82_15PL. */ +#define MG82_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G82PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G82PL) || (G86PL == 0) +/* Задаёт MG82_16PL = ~(1 << 5); данные MG82_16PL. */ +#define MG82_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_16PL = 0xFFFF; данные MG82_16PL. */ +#define MG82_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G82PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G82PL) || (G87PL == 0) +/* Задаёт MG82_17PL = ~(1 << 6); данные MG82_17PL. */ +#define MG82_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_17PL = 0xFFFF; данные MG82_17PL. */ +#define MG82_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G82PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G82PL) || (G88PL == 0) +/* Задаёт MG82_18PL = ~(1 << 7); данные MG82_18PL. */ +#define MG82_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG82_18PL = 0xFFFF; данные MG82_18PL. */ +#define MG82_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG82_12PL = 0x00FD; данные MG82_12PL. */ +#define MG82_12PL 0x00FD +/* Задаёт MG82 = (MG82_11PL & MG82_12PL & MG82_13PL & MG82_14PL &; маска разрешённых прерываний внутри группы PIE 82. */ +#define MG82 (MG82_11PL & MG82_12PL & MG82_13PL & MG82_14PL & \ + MG82_15PL & MG82_16PL & MG82_17PL & MG82_18PL) /* Продолжает список аргументов, полей или выражение MG82_15PL & MG82_16PL & MG82_17PL & MG82_18PL); порядок элементов сохраняется. */ +// End of MG82: + +// Beginning of MG83: +/* Условие компиляции (G81PL >= G83PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G83PL) || (G81PL == 0) +/* Задаёт MG83_11PL = ~(1); данные MG83_11PL. */ +#define MG83_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_11PL = 0xFFFF; данные MG83_11PL. */ +#define MG83_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G83PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G83PL) || (G82PL == 0) +/* Задаёт MG83_12PL = ~(1 << 1); данные MG83_12PL. */ +#define MG83_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_12PL = 0xFFFF; данные MG83_12PL. */ +#define MG83_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G83PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G83PL) || (G84PL == 0) +/* Задаёт MG83_14PL = ~(1 << 3); данные MG83_14PL. */ +#define MG83_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_14PL = 0xFFFF; данные MG83_14PL. */ +#define MG83_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G83PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G83PL) || (G85PL == 0) +/* Задаёт MG83_15PL = ~(1 << 4); данные MG83_15PL. */ +#define MG83_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_15PL = 0xFFFF; данные MG83_15PL. */ +#define MG83_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G83PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G83PL) || (G86PL == 0) +/* Задаёт MG83_16PL = ~(1 << 5); данные MG83_16PL. */ +#define MG83_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_16PL = 0xFFFF; данные MG83_16PL. */ +#define MG83_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G83PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G83PL) || (G87PL == 0) +/* Задаёт MG83_17PL = ~(1 << 6); данные MG83_17PL. */ +#define MG83_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_17PL = 0xFFFF; данные MG83_17PL. */ +#define MG83_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G83PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G83PL) || (G88PL == 0) +/* Задаёт MG83_18PL = ~(1 << 7); данные MG83_18PL. */ +#define MG83_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG83_18PL = 0xFFFF; данные MG83_18PL. */ +#define MG83_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG83_13PL = 0x00FB; данные MG83_13PL. */ +#define MG83_13PL 0x00FB +/* Задаёт MG83 = (MG83_11PL & MG83_12PL & MG83_13PL & MG83_14PL &; маска разрешённых прерываний внутри группы PIE 83. */ +#define MG83 (MG83_11PL & MG83_12PL & MG83_13PL & MG83_14PL & \ + MG83_15PL & MG83_16PL & MG83_17PL & MG83_18PL) /* Продолжает список аргументов, полей или выражение MG83_15PL & MG83_16PL & MG83_17PL & MG83_18PL); порядок элементов сохраняется. */ +// End of MG83: + +// Beginning of MG84: +/* Условие компиляции (G81PL >= G84PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G84PL) || (G81PL == 0) +/* Задаёт MG84_11PL = ~(1); данные MG84_11PL. */ +#define MG84_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_11PL = 0xFFFF; данные MG84_11PL. */ +#define MG84_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G84PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G84PL) || (G82PL == 0) +/* Задаёт MG84_12PL = ~(1 << 1); данные MG84_12PL. */ +#define MG84_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_12PL = 0xFFFF; данные MG84_12PL. */ +#define MG84_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G84PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G84PL) || (G83PL == 0) +/* Задаёт MG84_13PL = ~(1 << 2); данные MG84_13PL. */ +#define MG84_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_13PL = 0xFFFF; данные MG84_13PL. */ +#define MG84_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G84PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G84PL) || (G85PL == 0) +/* Задаёт MG84_15PL = ~(1 << 4); данные MG84_15PL. */ +#define MG84_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_15PL = 0xFFFF; данные MG84_15PL. */ +#define MG84_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G84PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G84PL) || (G86PL == 0) +/* Задаёт MG84_16PL = ~(1 << 5); данные MG84_16PL. */ +#define MG84_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_16PL = 0xFFFF; данные MG84_16PL. */ +#define MG84_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G84PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G84PL) || (G87PL == 0) +/* Задаёт MG84_17PL = ~(1 << 6); данные MG84_17PL. */ +#define MG84_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_17PL = 0xFFFF; данные MG84_17PL. */ +#define MG84_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G84PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G84PL) || (G88PL == 0) +/* Задаёт MG84_18PL = ~(1 << 7); данные MG84_18PL. */ +#define MG84_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG84_18PL = 0xFFFF; данные MG84_18PL. */ +#define MG84_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG84_14PL = 0x00F7; данные MG84_14PL. */ +#define MG84_14PL 0x00F7 +/* Задаёт MG84 = (MG84_11PL & MG84_12PL & MG84_13PL & MG84_14PL &; маска разрешённых прерываний внутри группы PIE 84. */ +#define MG84 (MG84_11PL & MG84_12PL & MG84_13PL & MG84_14PL & \ + MG84_15PL & MG84_16PL & MG84_17PL & MG84_18PL) /* Продолжает список аргументов, полей или выражение MG84_15PL & MG84_16PL & MG84_17PL & MG84_18PL); порядок элементов сохраняется. */ +// End of MG84: + +// Beginning of MG85: +/* Условие компиляции (G81PL >= G85PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G85PL) || (G81PL == 0) +/* Задаёт MG85_11PL = ~(1); данные MG85_11PL. */ +#define MG85_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_11PL = 0xFFFF; данные MG85_11PL. */ +#define MG85_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G85PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G85PL) || (G82PL == 0) +/* Задаёт MG85_12PL = ~(1 << 1); данные MG85_12PL. */ +#define MG85_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_12PL = 0xFFFF; данные MG85_12PL. */ +#define MG85_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G85PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G85PL) || (G83PL == 0) +/* Задаёт MG85_13PL = ~(1 << 2); данные MG85_13PL. */ +#define MG85_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_13PL = 0xFFFF; данные MG85_13PL. */ +#define MG85_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G85PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G85PL) || (G84PL == 0) +/* Задаёт MG85_14PL = ~(1 << 3); данные MG85_14PL. */ +#define MG85_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_14PL = 0xFFFF; данные MG85_14PL. */ +#define MG85_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G85PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G85PL) || (G86PL == 0) +/* Задаёт MG85_16PL = ~(1 << 5); данные MG85_16PL. */ +#define MG85_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_16PL = 0xFFFF; данные MG85_16PL. */ +#define MG85_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G85PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G85PL) || (G87PL == 0) +/* Задаёт MG85_17PL = ~(1 << 6); данные MG85_17PL. */ +#define MG85_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_17PL = 0xFFFF; данные MG85_17PL. */ +#define MG85_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G85PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G85PL) || (G88PL == 0) +/* Задаёт MG85_18PL = ~(1 << 7); данные MG85_18PL. */ +#define MG85_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG85_18PL = 0xFFFF; данные MG85_18PL. */ +#define MG85_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG85_15PL = 0x00EF; данные MG85_15PL. */ +#define MG85_15PL 0x00EF +/* Задаёт MG85 = (MG85_11PL & MG85_12PL & MG85_13PL & MG85_14PL &; маска разрешённых прерываний внутри группы PIE 85. */ +#define MG85 (MG85_11PL & MG85_12PL & MG85_13PL & MG85_14PL & \ + MG85_15PL & MG85_16PL & MG85_17PL & MG85_18PL) /* Продолжает список аргументов, полей или выражение MG85_15PL & MG85_16PL & MG85_17PL & MG85_18PL); порядок элементов сохраняется. */ +// End of MG85: + +// Beginning of MG86: +/* Условие компиляции (G81PL >= G86PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G86PL) || (G81PL == 0) +/* Задаёт MG86_11PL = ~(1); данные MG86_11PL. */ +#define MG86_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_11PL = 0xFFFF; данные MG86_11PL. */ +#define MG86_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G86PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G86PL) || (G82PL == 0) +/* Задаёт MG86_12PL = ~(1 << 1); данные MG86_12PL. */ +#define MG86_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_12PL = 0xFFFF; данные MG86_12PL. */ +#define MG86_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G86PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G86PL) || (G83PL == 0) +/* Задаёт MG86_13PL = ~(1 << 2); данные MG86_13PL. */ +#define MG86_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_13PL = 0xFFFF; данные MG86_13PL. */ +#define MG86_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G86PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G86PL) || (G84PL == 0) +/* Задаёт MG86_14PL = ~(1 << 3); данные MG86_14PL. */ +#define MG86_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_14PL = 0xFFFF; данные MG86_14PL. */ +#define MG86_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G86PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G86PL) || (G85PL == 0) +/* Задаёт MG86_15PL = ~(1 << 4); данные MG86_15PL. */ +#define MG86_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_15PL = 0xFFFF; данные MG86_15PL. */ +#define MG86_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G86PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G86PL) || (G87PL == 0) +/* Задаёт MG86_17PL = ~(1 << 6); данные MG86_17PL. */ +#define MG86_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_17PL = 0xFFFF; данные MG86_17PL. */ +#define MG86_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G86PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G86PL) || (G88PL == 0) +/* Задаёт MG86_18PL = ~(1 << 7); данные MG86_18PL. */ +#define MG86_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG86_18PL = 0xFFFF; данные MG86_18PL. */ +#define MG86_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG86_16PL = 0x00DF; данные MG86_16PL. */ +#define MG86_16PL 0x00DF +/* Задаёт MG86 = (MG86_11PL & MG86_12PL & MG86_13PL & MG86_14PL &; маска разрешённых прерываний внутри группы PIE 86. */ +#define MG86 (MG86_11PL & MG86_12PL & MG86_13PL & MG86_14PL & \ + MG86_15PL & MG86_16PL & MG86_17PL & MG86_18PL) /* Продолжает список аргументов, полей или выражение MG86_15PL & MG86_16PL & MG86_17PL & MG86_18PL); порядок элементов сохраняется. */ +// End of MG86: + +// Beginning of MG87: +/* Условие компиляции (G81PL >= G87PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G87PL) || (G81PL == 0) +/* Задаёт MG87_11PL = ~(1); данные MG87_11PL. */ +#define MG87_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_11PL = 0xFFFF; данные MG87_11PL. */ +#define MG87_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G87PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G87PL) || (G82PL == 0) +/* Задаёт MG87_12PL = ~(1 << 1); данные MG87_12PL. */ +#define MG87_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_12PL = 0xFFFF; данные MG87_12PL. */ +#define MG87_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G87PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G87PL) || (G83PL == 0) +/* Задаёт MG87_13PL = ~(1 << 2); данные MG87_13PL. */ +#define MG87_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_13PL = 0xFFFF; данные MG87_13PL. */ +#define MG87_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G87PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G87PL) || (G84PL == 0) +/* Задаёт MG87_14PL = ~(1 << 3); данные MG87_14PL. */ +#define MG87_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_14PL = 0xFFFF; данные MG87_14PL. */ +#define MG87_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G87PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G87PL) || (G85PL == 0) +/* Задаёт MG87_15PL = ~(1 << 4); данные MG87_15PL. */ +#define MG87_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_15PL = 0xFFFF; данные MG87_15PL. */ +#define MG87_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G87PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G87PL) || (G86PL == 0) +/* Задаёт MG87_16PL = ~(1 << 5); данные MG87_16PL. */ +#define MG87_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_16PL = 0xFFFF; данные MG87_16PL. */ +#define MG87_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G88PL >= G87PL) или (G88PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G88PL >= G87PL) || (G88PL == 0) +/* Задаёт MG87_18PL = ~(1 << 7); данные MG87_18PL. */ +#define MG87_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG87_18PL = 0xFFFF; данные MG87_18PL. */ +#define MG87_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG87_17PL = 0x00BF; данные MG87_17PL. */ +#define MG87_17PL 0x00BF +/* Задаёт MG87 = (MG87_11PL & MG87_12PL & MG87_13PL & MG87_14PL &; маска разрешённых прерываний внутри группы PIE 87. */ +#define MG87 (MG87_11PL & MG87_12PL & MG87_13PL & MG87_14PL & \ + MG87_15PL & MG87_16PL & MG87_17PL & MG87_18PL) /* Продолжает список аргументов, полей или выражение MG87_15PL & MG87_16PL & MG87_17PL & MG87_18PL); порядок элементов сохраняется. */ +// End of MG87: + +// Beginning of MG88: +/* Условие компиляции (G81PL >= G88PL) или (G81PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G81PL >= G88PL) || (G81PL == 0) +/* Задаёт MG88_11PL = ~(1); данные MG88_11PL. */ +#define MG88_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_11PL = 0xFFFF; данные MG88_11PL. */ +#define MG88_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G82PL >= G88PL) или (G82PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G82PL >= G88PL) || (G82PL == 0) +/* Задаёт MG88_12PL = ~(1 << 1); данные MG88_12PL. */ +#define MG88_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_12PL = 0xFFFF; данные MG88_12PL. */ +#define MG88_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G83PL >= G88PL) или (G83PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G83PL >= G88PL) || (G83PL == 0) +/* Задаёт MG88_13PL = ~(1 << 2); данные MG88_13PL. */ +#define MG88_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_13PL = 0xFFFF; данные MG88_13PL. */ +#define MG88_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G84PL >= G88PL) или (G84PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G84PL >= G88PL) || (G84PL == 0) +/* Задаёт MG88_14PL = ~(1 << 3); данные MG88_14PL. */ +#define MG88_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_14PL = 0xFFFF; данные MG88_14PL. */ +#define MG88_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G85PL >= G88PL) или (G85PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G85PL >= G88PL) || (G85PL == 0) +/* Задаёт MG88_15PL = ~(1 << 4); данные MG88_15PL. */ +#define MG88_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_15PL = 0xFFFF; данные MG88_15PL. */ +#define MG88_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G86PL >= G88PL) или (G86PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G86PL >= G88PL) || (G86PL == 0) +/* Задаёт MG88_16PL = ~(1 << 5); данные MG88_16PL. */ +#define MG88_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_16PL = 0xFFFF; данные MG88_16PL. */ +#define MG88_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G87PL >= G88PL) или (G87PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G87PL >= G88PL) || (G87PL == 0) +/* Задаёт MG88_17PL = ~(1 << 6); данные MG88_17PL. */ +#define MG88_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG88_17PL = 0xFFFF; данные MG88_17PL. */ +#define MG88_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG88_18PL = 0x007F; данные MG88_18PL. */ +#define MG88_18PL 0x007F +/* Задаёт MG88 = (MG88_11PL & MG88_12PL & MG88_13PL & MG88_14PL &; маска разрешённых прерываний внутри группы PIE 88. */ +#define MG88 (MG88_11PL & MG88_12PL & MG88_13PL & MG88_14PL & \ + MG88_15PL & MG88_16PL & MG88_17PL & MG88_18PL) /* Продолжает список аргументов, полей или выражение MG88_15PL & MG88_16PL & MG88_17PL & MG88_18PL); порядок элементов сохраняется. */ +// End of MG88: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG91 to MG98: +// + +// Beginning of MG91: +/* Условие компиляции (G92PL >= G91PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G91PL) || (G92PL == 0) +/* Задаёт MG91_12PL = ~(1 << 1); данные MG91_12PL. */ +#define MG91_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_12PL = 0xFFFF; данные MG91_12PL. */ +#define MG91_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G91PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G91PL) || (G93PL == 0) +/* Задаёт MG91_13PL = ~(1 << 2); данные MG91_13PL. */ +#define MG91_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_13PL = 0xFFFF; данные MG91_13PL. */ +#define MG91_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G91PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G91PL) || (G94PL == 0) +/* Задаёт MG91_14PL = ~(1 << 3); данные MG91_14PL. */ +#define MG91_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_14PL = 0xFFFF; данные MG91_14PL. */ +#define MG91_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G91PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G91PL) || (G95PL == 0) +/* Задаёт MG91_15PL = ~(1 << 4); данные MG91_15PL. */ +#define MG91_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_15PL = 0xFFFF; данные MG91_15PL. */ +#define MG91_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G91PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G91PL) || (G96PL == 0) +/* Задаёт MG91_16PL = ~(1 << 5); данные MG91_16PL. */ +#define MG91_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_16PL = 0xFFFF; данные MG91_16PL. */ +#define MG91_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G91PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G91PL) || (G97PL == 0) +/* Задаёт MG91_17PL = ~(1 << 6); данные MG91_17PL. */ +#define MG91_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_17PL = 0xFFFF; данные MG91_17PL. */ +#define MG91_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G91PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G91PL) || (G98PL == 0) +/* Задаёт MG91_18PL = ~(1 << 7); данные MG91_18PL. */ +#define MG91_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG91_18PL = 0xFFFF; данные MG91_18PL. */ +#define MG91_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG91_11PL = 0x00FE; данные MG91_11PL. */ +#define MG91_11PL 0x00FE +/* Задаёт MG91 = (MG91_11PL & MG91_12PL & MG91_13PL & MG91_14PL &; маска разрешённых прерываний внутри группы PIE 91. */ +#define MG91 (MG91_11PL & MG91_12PL & MG91_13PL & MG91_14PL & \ + MG91_15PL & MG91_16PL & MG91_17PL & MG91_18PL) /* Продолжает список аргументов, полей или выражение MG91_15PL & MG91_16PL & MG91_17PL & MG91_18PL); порядок элементов сохраняется. */ +// End of MG91: + +// Beginning of MG92: +/* Условие компиляции (G91PL >= G92PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G92PL) || (G91PL == 0) +/* Задаёт MG92_11PL = ~(1); данные MG92_11PL. */ +#define MG92_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_11PL = 0xFFFF; данные MG92_11PL. */ +#define MG92_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G92PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G92PL) || (G93PL == 0) +/* Задаёт MG92_13PL = ~(1 << 2); данные MG92_13PL. */ +#define MG92_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_13PL = 0xFFFF; данные MG92_13PL. */ +#define MG92_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G92PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G92PL) || (G94PL == 0) +/* Задаёт MG92_14PL = ~(1 << 3); данные MG92_14PL. */ +#define MG92_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_14PL = 0xFFFF; данные MG92_14PL. */ +#define MG92_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G92PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G92PL) || (G95PL == 0) +/* Задаёт MG92_15PL = ~(1 << 4); данные MG92_15PL. */ +#define MG92_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_15PL = 0xFFFF; данные MG92_15PL. */ +#define MG92_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G92PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G92PL) || (G96PL == 0) +/* Задаёт MG92_16PL = ~(1 << 5); данные MG92_16PL. */ +#define MG92_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_16PL = 0xFFFF; данные MG92_16PL. */ +#define MG92_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G92PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G92PL) || (G97PL == 0) +/* Задаёт MG92_17PL = ~(1 << 6); данные MG92_17PL. */ +#define MG92_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_17PL = 0xFFFF; данные MG92_17PL. */ +#define MG92_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G92PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G92PL) || (G98PL == 0) +/* Задаёт MG92_18PL = ~(1 << 7); данные MG92_18PL. */ +#define MG92_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG92_18PL = 0xFFFF; данные MG92_18PL. */ +#define MG92_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG92_12PL = 0x00FD; данные MG92_12PL. */ +#define MG92_12PL 0x00FD +/* Задаёт MG92 = (MG92_11PL & MG92_12PL & MG92_13PL & MG92_14PL &; маска разрешённых прерываний внутри группы PIE 92. */ +#define MG92 (MG92_11PL & MG92_12PL & MG92_13PL & MG92_14PL & \ + MG92_15PL & MG92_16PL & MG92_17PL & MG92_18PL) /* Продолжает список аргументов, полей или выражение MG92_15PL & MG92_16PL & MG92_17PL & MG92_18PL); порядок элементов сохраняется. */ +// End of MG92: + +// Beginning of MG93: +/* Условие компиляции (G91PL >= G93PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G93PL) || (G91PL == 0) +/* Задаёт MG93_11PL = ~(1); данные MG93_11PL. */ +#define MG93_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_11PL = 0xFFFF; данные MG93_11PL. */ +#define MG93_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G93PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G93PL) || (G92PL == 0) +/* Задаёт MG93_12PL = ~(1 << 1); данные MG93_12PL. */ +#define MG93_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_12PL = 0xFFFF; данные MG93_12PL. */ +#define MG93_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G93PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G93PL) || (G94PL == 0) +/* Задаёт MG93_14PL = ~(1 << 3); данные MG93_14PL. */ +#define MG93_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_14PL = 0xFFFF; данные MG93_14PL. */ +#define MG93_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G93PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G93PL) || (G95PL == 0) +/* Задаёт MG93_15PL = ~(1 << 4); данные MG93_15PL. */ +#define MG93_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_15PL = 0xFFFF; данные MG93_15PL. */ +#define MG93_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G93PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G93PL) || (G96PL == 0) +/* Задаёт MG93_16PL = ~(1 << 5); данные MG93_16PL. */ +#define MG93_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_16PL = 0xFFFF; данные MG93_16PL. */ +#define MG93_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G93PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G93PL) || (G97PL == 0) +/* Задаёт MG93_17PL = ~(1 << 6); данные MG93_17PL. */ +#define MG93_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_17PL = 0xFFFF; данные MG93_17PL. */ +#define MG93_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G93PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G93PL) || (G98PL == 0) +/* Задаёт MG93_18PL = ~(1 << 7); данные MG93_18PL. */ +#define MG93_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG93_18PL = 0xFFFF; данные MG93_18PL. */ +#define MG93_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG93_13PL = 0x00FB; данные MG93_13PL. */ +#define MG93_13PL 0x00FB +/* Задаёт MG93 = (MG93_11PL & MG93_12PL & MG93_13PL & MG93_14PL &; маска разрешённых прерываний внутри группы PIE 93. */ +#define MG93 (MG93_11PL & MG93_12PL & MG93_13PL & MG93_14PL & \ + MG93_15PL & MG93_16PL & MG93_17PL & MG93_18PL) /* Продолжает список аргументов, полей или выражение MG93_15PL & MG93_16PL & MG93_17PL & MG93_18PL); порядок элементов сохраняется. */ +// End of MG93: + +// Beginning of MG94: +/* Условие компиляции (G91PL >= G94PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G94PL) || (G91PL == 0) +/* Задаёт MG94_11PL = ~(1); данные MG94_11PL. */ +#define MG94_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_11PL = 0xFFFF; данные MG94_11PL. */ +#define MG94_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G94PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G94PL) || (G92PL == 0) +/* Задаёт MG94_12PL = ~(1 << 1); данные MG94_12PL. */ +#define MG94_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_12PL = 0xFFFF; данные MG94_12PL. */ +#define MG94_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G94PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G94PL) || (G93PL == 0) +/* Задаёт MG94_13PL = ~(1 << 2); данные MG94_13PL. */ +#define MG94_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_13PL = 0xFFFF; данные MG94_13PL. */ +#define MG94_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G94PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G94PL) || (G95PL == 0) +/* Задаёт MG94_15PL = ~(1 << 4); данные MG94_15PL. */ +#define MG94_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_15PL = 0xFFFF; данные MG94_15PL. */ +#define MG94_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G94PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G94PL) || (G96PL == 0) +/* Задаёт MG94_16PL = ~(1 << 5); данные MG94_16PL. */ +#define MG94_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_16PL = 0xFFFF; данные MG94_16PL. */ +#define MG94_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G94PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G94PL) || (G97PL == 0) +/* Задаёт MG94_17PL = ~(1 << 6); данные MG94_17PL. */ +#define MG94_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_17PL = 0xFFFF; данные MG94_17PL. */ +#define MG94_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G94PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G94PL) || (G98PL == 0) +/* Задаёт MG94_18PL = ~(1 << 7); данные MG94_18PL. */ +#define MG94_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG94_18PL = 0xFFFF; данные MG94_18PL. */ +#define MG94_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG94_14PL = 0x00F7; данные MG94_14PL. */ +#define MG94_14PL 0x00F7 +/* Задаёт MG94 = (MG94_11PL & MG94_12PL & MG94_13PL & MG94_14PL &; маска разрешённых прерываний внутри группы PIE 94. */ +#define MG94 (MG94_11PL & MG94_12PL & MG94_13PL & MG94_14PL & \ + MG94_15PL & MG94_16PL & MG94_17PL & MG94_18PL) /* Продолжает список аргументов, полей или выражение MG94_15PL & MG94_16PL & MG94_17PL & MG94_18PL); порядок элементов сохраняется. */ +// End of MG94: + +// Beginning of MG95: +/* Условие компиляции (G91PL >= G95PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G95PL) || (G91PL == 0) +/* Задаёт MG95_11PL = ~(1); данные MG95_11PL. */ +#define MG95_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_11PL = 0xFFFF; данные MG95_11PL. */ +#define MG95_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G95PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G95PL) || (G92PL == 0) +/* Задаёт MG95_12PL = ~(1 << 1); данные MG95_12PL. */ +#define MG95_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_12PL = 0xFFFF; данные MG95_12PL. */ +#define MG95_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G95PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G95PL) || (G93PL == 0) +/* Задаёт MG95_13PL = ~(1 << 2); данные MG95_13PL. */ +#define MG95_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_13PL = 0xFFFF; данные MG95_13PL. */ +#define MG95_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G95PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G95PL) || (G94PL == 0) +/* Задаёт MG95_14PL = ~(1 << 3); данные MG95_14PL. */ +#define MG95_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_14PL = 0xFFFF; данные MG95_14PL. */ +#define MG95_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G95PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G95PL) || (G96PL == 0) +/* Задаёт MG95_16PL = ~(1 << 5); данные MG95_16PL. */ +#define MG95_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_16PL = 0xFFFF; данные MG95_16PL. */ +#define MG95_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G95PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G95PL) || (G97PL == 0) +/* Задаёт MG95_17PL = ~(1 << 6); данные MG95_17PL. */ +#define MG95_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_17PL = 0xFFFF; данные MG95_17PL. */ +#define MG95_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G95PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G95PL) || (G98PL == 0) +/* Задаёт MG95_18PL = ~(1 << 7); данные MG95_18PL. */ +#define MG95_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG95_18PL = 0xFFFF; данные MG95_18PL. */ +#define MG95_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG95_15PL = 0x00EF; данные MG95_15PL. */ +#define MG95_15PL 0x00EF +/* Задаёт MG95 = (MG95_11PL & MG95_12PL & MG95_13PL & MG95_14PL &; маска разрешённых прерываний внутри группы PIE 95. */ +#define MG95 (MG95_11PL & MG95_12PL & MG95_13PL & MG95_14PL & \ + MG95_15PL & MG95_16PL & MG95_17PL & MG95_18PL) /* Продолжает список аргументов, полей или выражение MG95_15PL & MG95_16PL & MG95_17PL & MG95_18PL); порядок элементов сохраняется. */ +// End of MG95: + +// Beginning of MG96: +/* Условие компиляции (G91PL >= G96PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G96PL) || (G91PL == 0) +/* Задаёт MG96_11PL = ~(1); данные MG96_11PL. */ +#define MG96_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_11PL = 0xFFFF; данные MG96_11PL. */ +#define MG96_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G96PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G96PL) || (G92PL == 0) +/* Задаёт MG96_12PL = ~(1 << 1); данные MG96_12PL. */ +#define MG96_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_12PL = 0xFFFF; данные MG96_12PL. */ +#define MG96_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G96PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G96PL) || (G93PL == 0) +/* Задаёт MG96_13PL = ~(1 << 2); данные MG96_13PL. */ +#define MG96_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_13PL = 0xFFFF; данные MG96_13PL. */ +#define MG96_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G96PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G96PL) || (G94PL == 0) +/* Задаёт MG96_14PL = ~(1 << 3); данные MG96_14PL. */ +#define MG96_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_14PL = 0xFFFF; данные MG96_14PL. */ +#define MG96_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G96PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G96PL) || (G95PL == 0) +/* Задаёт MG96_15PL = ~(1 << 4); данные MG96_15PL. */ +#define MG96_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_15PL = 0xFFFF; данные MG96_15PL. */ +#define MG96_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G96PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G96PL) || (G97PL == 0) +/* Задаёт MG96_17PL = ~(1 << 6); данные MG96_17PL. */ +#define MG96_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_17PL = 0xFFFF; данные MG96_17PL. */ +#define MG96_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G96PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G96PL) || (G98PL == 0) +/* Задаёт MG96_18PL = ~(1 << 7); данные MG96_18PL. */ +#define MG96_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG96_18PL = 0xFFFF; данные MG96_18PL. */ +#define MG96_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG96_16PL = 0x00DF; данные MG96_16PL. */ +#define MG96_16PL 0x00DF +/* Задаёт MG96 = (MG96_11PL & MG96_12PL & MG96_13PL & MG96_14PL &; маска разрешённых прерываний внутри группы PIE 96. */ +#define MG96 (MG96_11PL & MG96_12PL & MG96_13PL & MG96_14PL & \ + MG96_15PL & MG96_16PL & MG96_17PL & MG96_18PL) /* Продолжает список аргументов, полей или выражение MG96_15PL & MG96_16PL & MG96_17PL & MG96_18PL); порядок элементов сохраняется. */ +// End of MG96: + +// Beginning of MG97: +/* Условие компиляции (G91PL >= G97PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G97PL) || (G91PL == 0) +/* Задаёт MG97_11PL = ~(1); данные MG97_11PL. */ +#define MG97_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_11PL = 0xFFFF; данные MG97_11PL. */ +#define MG97_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G97PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G97PL) || (G92PL == 0) +/* Задаёт MG97_12PL = ~(1 << 1); данные MG97_12PL. */ +#define MG97_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_12PL = 0xFFFF; данные MG97_12PL. */ +#define MG97_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G97PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G97PL) || (G93PL == 0) +/* Задаёт MG97_13PL = ~(1 << 2); данные MG97_13PL. */ +#define MG97_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_13PL = 0xFFFF; данные MG97_13PL. */ +#define MG97_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G97PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G97PL) || (G94PL == 0) +/* Задаёт MG97_14PL = ~(1 << 3); данные MG97_14PL. */ +#define MG97_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_14PL = 0xFFFF; данные MG97_14PL. */ +#define MG97_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G97PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G97PL) || (G95PL == 0) +/* Задаёт MG97_15PL = ~(1 << 4); данные MG97_15PL. */ +#define MG97_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_15PL = 0xFFFF; данные MG97_15PL. */ +#define MG97_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G97PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G97PL) || (G96PL == 0) +/* Задаёт MG97_16PL = ~(1 << 5); данные MG97_16PL. */ +#define MG97_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_16PL = 0xFFFF; данные MG97_16PL. */ +#define MG97_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G98PL >= G97PL) или (G98PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G98PL >= G97PL) || (G98PL == 0) +/* Задаёт MG97_18PL = ~(1 << 7); данные MG97_18PL. */ +#define MG97_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG97_18PL = 0xFFFF; данные MG97_18PL. */ +#define MG97_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG97_17PL = 0x00BF; данные MG97_17PL. */ +#define MG97_17PL 0x00BF +/* Задаёт MG97 = (MG97_11PL & MG97_12PL & MG97_13PL & MG97_14PL &; маска разрешённых прерываний внутри группы PIE 97. */ +#define MG97 (MG97_11PL & MG97_12PL & MG97_13PL & MG97_14PL & \ + MG97_15PL & MG97_16PL & MG97_17PL & MG97_18PL) /* Продолжает список аргументов, полей или выражение MG97_15PL & MG97_16PL & MG97_17PL & MG97_18PL); порядок элементов сохраняется. */ +// End of MG97: + +// Beginning of MG98: +/* Условие компиляции (G91PL >= G98PL) или (G91PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G91PL >= G98PL) || (G91PL == 0) +/* Задаёт MG98_11PL = ~(1); данные MG98_11PL. */ +#define MG98_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_11PL = 0xFFFF; данные MG98_11PL. */ +#define MG98_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G92PL >= G98PL) или (G92PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G92PL >= G98PL) || (G92PL == 0) +/* Задаёт MG98_12PL = ~(1 << 1); данные MG98_12PL. */ +#define MG98_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_12PL = 0xFFFF; данные MG98_12PL. */ +#define MG98_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G93PL >= G98PL) или (G93PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G93PL >= G98PL) || (G93PL == 0) +/* Задаёт MG98_13PL = ~(1 << 2); данные MG98_13PL. */ +#define MG98_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_13PL = 0xFFFF; данные MG98_13PL. */ +#define MG98_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G94PL >= G98PL) или (G94PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G94PL >= G98PL) || (G94PL == 0) +/* Задаёт MG98_14PL = ~(1 << 3); данные MG98_14PL. */ +#define MG98_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_14PL = 0xFFFF; данные MG98_14PL. */ +#define MG98_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G95PL >= G98PL) или (G95PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G95PL >= G98PL) || (G95PL == 0) +/* Задаёт MG98_15PL = ~(1 << 4); данные MG98_15PL. */ +#define MG98_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_15PL = 0xFFFF; данные MG98_15PL. */ +#define MG98_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G96PL >= G98PL) или (G96PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G96PL >= G98PL) || (G96PL == 0) +/* Задаёт MG98_16PL = ~(1 << 5); данные MG98_16PL. */ +#define MG98_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_16PL = 0xFFFF; данные MG98_16PL. */ +#define MG98_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G97PL >= G98PL) или (G97PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G97PL >= G98PL) || (G97PL == 0) +/* Задаёт MG98_17PL = ~(1 << 6); данные MG98_17PL. */ +#define MG98_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG98_17PL = 0xFFFF; данные MG98_17PL. */ +#define MG98_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG98_18PL = 0x007F; данные MG98_18PL. */ +#define MG98_18PL 0x007F +/* Задаёт MG98 = (MG98_11PL & MG98_12PL & MG98_13PL & MG98_14PL &; маска разрешённых прерываний внутри группы PIE 98. */ +#define MG98 (MG98_11PL & MG98_12PL & MG98_13PL & MG98_14PL & \ + MG98_15PL & MG98_16PL & MG98_17PL & MG98_18PL) /* Продолжает список аргументов, полей или выражение MG98_15PL & MG98_16PL & MG98_17PL & MG98_18PL); порядок элементов сохраняется. */ +// End of MG98: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG101 to MG108: +// + +// Beginning of MG101: +/* Условие компиляции (G102PL >= G101PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G101PL) || (G102PL == 0) +/* Задаёт MG101_12PL = ~(1 << 1); данные MG101_12PL. */ +#define MG101_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_12PL = 0xFFFF; данные MG101_12PL. */ +#define MG101_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G101PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G101PL) || (G103PL == 0) +/* Задаёт MG101_13PL = ~(1 << 2); данные MG101_13PL. */ +#define MG101_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_13PL = 0xFFFF; данные MG101_13PL. */ +#define MG101_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G101PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G101PL) || (G104PL == 0) +/* Задаёт MG101_14PL = ~(1 << 3); данные MG101_14PL. */ +#define MG101_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_14PL = 0xFFFF; данные MG101_14PL. */ +#define MG101_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G101PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G101PL) || (G105PL == 0) +/* Задаёт MG101_15PL = ~(1 << 4); данные MG101_15PL. */ +#define MG101_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_15PL = 0xFFFF; данные MG101_15PL. */ +#define MG101_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G101PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G101PL) || (G106PL == 0) +/* Задаёт MG101_16PL = ~(1 << 5); данные MG101_16PL. */ +#define MG101_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_16PL = 0xFFFF; данные MG101_16PL. */ +#define MG101_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G101PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G101PL) || (G107PL == 0) +/* Задаёт MG101_17PL = ~(1 << 6); данные MG101_17PL. */ +#define MG101_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_17PL = 0xFFFF; данные MG101_17PL. */ +#define MG101_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G101PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G101PL) || (G108PL == 0) +/* Задаёт MG101_18PL = ~(1 << 7); данные MG101_18PL. */ +#define MG101_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG101_18PL = 0xFFFF; данные MG101_18PL. */ +#define MG101_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG101_11PL = 0x00FE; данные MG101_11PL. */ +#define MG101_11PL 0x00FE +/* Задаёт MG101 = (MG101_11PL & MG101_12PL & MG101_13PL & MG101_14PL &; маска разрешённых прерываний внутри группы PIE 101. */ +#define MG101 (MG101_11PL & MG101_12PL & MG101_13PL & MG101_14PL & \ + MG101_15PL & MG101_16PL & MG101_17PL & MG101_18PL) /* Продолжает список аргументов, полей или выражение MG101_15PL & MG101_16PL & MG101_17PL & MG101_18PL); порядок элементов сохраняется. */ +// End of MG101: + +// Beginning of MG102: +/* Условие компиляции (G101PL >= G102PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G102PL) || (G101PL == 0) +/* Задаёт MG102_11PL = ~(1); данные MG102_11PL. */ +#define MG102_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_11PL = 0xFFFF; данные MG102_11PL. */ +#define MG102_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G102PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G102PL) || (G103PL == 0) +/* Задаёт MG102_13PL = ~(1 << 2); данные MG102_13PL. */ +#define MG102_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_13PL = 0xFFFF; данные MG102_13PL. */ +#define MG102_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G102PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G102PL) || (G104PL == 0) +/* Задаёт MG102_14PL = ~(1 << 3); данные MG102_14PL. */ +#define MG102_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_14PL = 0xFFFF; данные MG102_14PL. */ +#define MG102_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G102PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G102PL) || (G105PL == 0) +/* Задаёт MG102_15PL = ~(1 << 4); данные MG102_15PL. */ +#define MG102_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_15PL = 0xFFFF; данные MG102_15PL. */ +#define MG102_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G102PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G102PL) || (G106PL == 0) +/* Задаёт MG102_16PL = ~(1 << 5); данные MG102_16PL. */ +#define MG102_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_16PL = 0xFFFF; данные MG102_16PL. */ +#define MG102_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G102PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G102PL) || (G107PL == 0) +/* Задаёт MG102_17PL = ~(1 << 6); данные MG102_17PL. */ +#define MG102_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_17PL = 0xFFFF; данные MG102_17PL. */ +#define MG102_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G102PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G102PL) || (G108PL == 0) +/* Задаёт MG102_18PL = ~(1 << 7); данные MG102_18PL. */ +#define MG102_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG102_18PL = 0xFFFF; данные MG102_18PL. */ +#define MG102_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG102_12PL = 0x00FD; данные MG102_12PL. */ +#define MG102_12PL 0x00FD +/* Задаёт MG102 = (MG102_11PL & MG102_12PL & MG102_13PL & MG102_14PL &; маска разрешённых прерываний внутри группы PIE 102. */ +#define MG102 (MG102_11PL & MG102_12PL & MG102_13PL & MG102_14PL & \ + MG102_15PL & MG102_16PL & MG102_17PL & MG102_18PL) /* Продолжает список аргументов, полей или выражение MG102_15PL & MG102_16PL & MG102_17PL & MG102_18PL); порядок элементов сохраняется. */ +// End of MG102: + +// Beginning of MG103: +/* Условие компиляции (G101PL >= G103PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G103PL) || (G101PL == 0) +/* Задаёт MG103_11PL = ~(1); данные MG103_11PL. */ +#define MG103_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_11PL = 0xFFFF; данные MG103_11PL. */ +#define MG103_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G103PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G103PL) || (G102PL == 0) +/* Задаёт MG103_12PL = ~(1 << 1); данные MG103_12PL. */ +#define MG103_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_12PL = 0xFFFF; данные MG103_12PL. */ +#define MG103_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G103PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G103PL) || (G104PL == 0) +/* Задаёт MG103_14PL = ~(1 << 3); данные MG103_14PL. */ +#define MG103_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_14PL = 0xFFFF; данные MG103_14PL. */ +#define MG103_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G103PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G103PL) || (G105PL == 0) +/* Задаёт MG103_15PL = ~(1 << 4); данные MG103_15PL. */ +#define MG103_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_15PL = 0xFFFF; данные MG103_15PL. */ +#define MG103_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G103PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G103PL) || (G106PL == 0) +/* Задаёт MG103_16PL = ~(1 << 5); данные MG103_16PL. */ +#define MG103_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_16PL = 0xFFFF; данные MG103_16PL. */ +#define MG103_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G103PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G103PL) || (G107PL == 0) +/* Задаёт MG103_17PL = ~(1 << 6); данные MG103_17PL. */ +#define MG103_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_17PL = 0xFFFF; данные MG103_17PL. */ +#define MG103_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G103PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G103PL) || (G108PL == 0) +/* Задаёт MG103_18PL = ~(1 << 7); данные MG103_18PL. */ +#define MG103_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG103_18PL = 0xFFFF; данные MG103_18PL. */ +#define MG103_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG103_13PL = 0x00FB; данные MG103_13PL. */ +#define MG103_13PL 0x00FB +/* Задаёт MG103 = (MG103_11PL & MG103_12PL & MG103_13PL & MG103_14PL &; маска разрешённых прерываний внутри группы PIE 103. */ +#define MG103 (MG103_11PL & MG103_12PL & MG103_13PL & MG103_14PL & \ + MG103_15PL & MG103_16PL & MG103_17PL & MG103_18PL) /* Продолжает список аргументов, полей или выражение MG103_15PL & MG103_16PL & MG103_17PL & MG103_18PL); порядок элементов сохраняется. */ +// End of MG103: + +// Beginning of MG104: +/* Условие компиляции (G101PL >= G104PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G104PL) || (G101PL == 0) +/* Задаёт MG104_11PL = ~(1); данные MG104_11PL. */ +#define MG104_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_11PL = 0xFFFF; данные MG104_11PL. */ +#define MG104_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G104PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G104PL) || (G102PL == 0) +/* Задаёт MG104_12PL = ~(1 << 1); данные MG104_12PL. */ +#define MG104_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_12PL = 0xFFFF; данные MG104_12PL. */ +#define MG104_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G104PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G104PL) || (G103PL == 0) +/* Задаёт MG104_13PL = ~(1 << 2); данные MG104_13PL. */ +#define MG104_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_13PL = 0xFFFF; данные MG104_13PL. */ +#define MG104_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G104PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G104PL) || (G105PL == 0) +/* Задаёт MG104_15PL = ~(1 << 4); данные MG104_15PL. */ +#define MG104_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_15PL = 0xFFFF; данные MG104_15PL. */ +#define MG104_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G104PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G104PL) || (G106PL == 0) +/* Задаёт MG104_16PL = ~(1 << 5); данные MG104_16PL. */ +#define MG104_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_16PL = 0xFFFF; данные MG104_16PL. */ +#define MG104_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G104PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G104PL) || (G107PL == 0) +/* Задаёт MG104_17PL = ~(1 << 6); данные MG104_17PL. */ +#define MG104_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_17PL = 0xFFFF; данные MG104_17PL. */ +#define MG104_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G104PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G104PL) || (G108PL == 0) +/* Задаёт MG104_18PL = ~(1 << 7); данные MG104_18PL. */ +#define MG104_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG104_18PL = 0xFFFF; данные MG104_18PL. */ +#define MG104_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG104_14PL = 0x00F7; данные MG104_14PL. */ +#define MG104_14PL 0x00F7 +/* Задаёт MG104 = (MG104_11PL & MG104_12PL & MG104_13PL & MG104_14PL &; маска разрешённых прерываний внутри группы PIE 104. */ +#define MG104 (MG104_11PL & MG104_12PL & MG104_13PL & MG104_14PL & \ + MG104_15PL & MG104_16PL & MG104_17PL & MG104_18PL) /* Продолжает список аргументов, полей или выражение MG104_15PL & MG104_16PL & MG104_17PL & MG104_18PL); порядок элементов сохраняется. */ +// End of MG104: + +// Beginning of MG105: +/* Условие компиляции (G101PL >= G105PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G105PL) || (G101PL == 0) +/* Задаёт MG105_11PL = ~(1); данные MG105_11PL. */ +#define MG105_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_11PL = 0xFFFF; данные MG105_11PL. */ +#define MG105_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G105PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G105PL) || (G102PL == 0) +/* Задаёт MG105_12PL = ~(1 << 1); данные MG105_12PL. */ +#define MG105_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_12PL = 0xFFFF; данные MG105_12PL. */ +#define MG105_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G105PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G105PL) || (G103PL == 0) +/* Задаёт MG105_13PL = ~(1 << 2); данные MG105_13PL. */ +#define MG105_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_13PL = 0xFFFF; данные MG105_13PL. */ +#define MG105_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G105PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G105PL) || (G104PL == 0) +/* Задаёт MG105_14PL = ~(1 << 3); данные MG105_14PL. */ +#define MG105_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_14PL = 0xFFFF; данные MG105_14PL. */ +#define MG105_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G105PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G105PL) || (G106PL == 0) +/* Задаёт MG105_16PL = ~(1 << 5); данные MG105_16PL. */ +#define MG105_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_16PL = 0xFFFF; данные MG105_16PL. */ +#define MG105_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G105PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G105PL) || (G107PL == 0) +/* Задаёт MG105_17PL = ~(1 << 6); данные MG105_17PL. */ +#define MG105_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_17PL = 0xFFFF; данные MG105_17PL. */ +#define MG105_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G105PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G105PL) || (G108PL == 0) +/* Задаёт MG105_18PL = ~(1 << 7); данные MG105_18PL. */ +#define MG105_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG105_18PL = 0xFFFF; данные MG105_18PL. */ +#define MG105_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG105_15PL = 0x00EF; данные MG105_15PL. */ +#define MG105_15PL 0x00EF +/* Задаёт MG105 = (MG105_11PL & MG105_12PL & MG105_13PL & MG105_14PL &; маска разрешённых прерываний внутри группы PIE 105. */ +#define MG105 (MG105_11PL & MG105_12PL & MG105_13PL & MG105_14PL & \ + MG105_15PL & MG105_16PL & MG105_17PL & MG105_18PL) /* Продолжает список аргументов, полей или выражение MG105_15PL & MG105_16PL & MG105_17PL & MG105_18PL); порядок элементов сохраняется. */ +// End of MG105: + +// Beginning of MG106: +/* Условие компиляции (G101PL >= G106PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G106PL) || (G101PL == 0) +/* Задаёт MG106_11PL = ~(1); данные MG106_11PL. */ +#define MG106_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_11PL = 0xFFFF; данные MG106_11PL. */ +#define MG106_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G106PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G106PL) || (G102PL == 0) +/* Задаёт MG106_12PL = ~(1 << 1); данные MG106_12PL. */ +#define MG106_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_12PL = 0xFFFF; данные MG106_12PL. */ +#define MG106_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G106PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G106PL) || (G103PL == 0) +/* Задаёт MG106_13PL = ~(1 << 2); данные MG106_13PL. */ +#define MG106_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_13PL = 0xFFFF; данные MG106_13PL. */ +#define MG106_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G106PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G106PL) || (G104PL == 0) +/* Задаёт MG106_14PL = ~(1 << 3); данные MG106_14PL. */ +#define MG106_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_14PL = 0xFFFF; данные MG106_14PL. */ +#define MG106_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G106PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G106PL) || (G105PL == 0) +/* Задаёт MG106_15PL = ~(1 << 4); данные MG106_15PL. */ +#define MG106_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_15PL = 0xFFFF; данные MG106_15PL. */ +#define MG106_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G106PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G106PL) || (G107PL == 0) +/* Задаёт MG106_17PL = ~(1 << 6); данные MG106_17PL. */ +#define MG106_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_17PL = 0xFFFF; данные MG106_17PL. */ +#define MG106_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G106PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G106PL) || (G108PL == 0) +/* Задаёт MG106_18PL = ~(1 << 7); данные MG106_18PL. */ +#define MG106_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG106_18PL = 0xFFFF; данные MG106_18PL. */ +#define MG106_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG106_16PL = 0x00DF; данные MG106_16PL. */ +#define MG106_16PL 0x00DF +/* Задаёт MG106 = (MG106_11PL & MG106_12PL & MG106_13PL & MG106_14PL &; маска разрешённых прерываний внутри группы PIE 106. */ +#define MG106 (MG106_11PL & MG106_12PL & MG106_13PL & MG106_14PL & \ + MG106_15PL & MG106_16PL & MG106_17PL & MG106_18PL) /* Продолжает список аргументов, полей или выражение MG106_15PL & MG106_16PL & MG106_17PL & MG106_18PL); порядок элементов сохраняется. */ +// End of MG106: + +// Beginning of MG107: +/* Условие компиляции (G101PL >= G107PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G107PL) || (G101PL == 0) +/* Задаёт MG107_11PL = ~(1); данные MG107_11PL. */ +#define MG107_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_11PL = 0xFFFF; данные MG107_11PL. */ +#define MG107_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G107PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G107PL) || (G102PL == 0) +/* Задаёт MG107_12PL = ~(1 << 1); данные MG107_12PL. */ +#define MG107_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_12PL = 0xFFFF; данные MG107_12PL. */ +#define MG107_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G107PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G107PL) || (G103PL == 0) +/* Задаёт MG107_13PL = ~(1 << 2); данные MG107_13PL. */ +#define MG107_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_13PL = 0xFFFF; данные MG107_13PL. */ +#define MG107_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G107PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G107PL) || (G104PL == 0) +/* Задаёт MG107_14PL = ~(1 << 3); данные MG107_14PL. */ +#define MG107_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_14PL = 0xFFFF; данные MG107_14PL. */ +#define MG107_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G107PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G107PL) || (G105PL == 0) +/* Задаёт MG107_15PL = ~(1 << 4); данные MG107_15PL. */ +#define MG107_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_15PL = 0xFFFF; данные MG107_15PL. */ +#define MG107_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G107PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G107PL) || (G106PL == 0) +/* Задаёт MG107_16PL = ~(1 << 5); данные MG107_16PL. */ +#define MG107_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_16PL = 0xFFFF; данные MG107_16PL. */ +#define MG107_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G108PL >= G107PL) или (G108PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G108PL >= G107PL) || (G108PL == 0) +/* Задаёт MG107_18PL = ~(1 << 7); данные MG107_18PL. */ +#define MG107_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG107_18PL = 0xFFFF; данные MG107_18PL. */ +#define MG107_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG107_17PL = 0x00BF; данные MG107_17PL. */ +#define MG107_17PL 0x00BF +/* Задаёт MG107 = (MG107_11PL & MG107_12PL & MG107_13PL & MG107_14PL &; маска разрешённых прерываний внутри группы PIE 107. */ +#define MG107 (MG107_11PL & MG107_12PL & MG107_13PL & MG107_14PL & \ + MG107_15PL & MG107_16PL & MG107_17PL & MG107_18PL) /* Продолжает список аргументов, полей или выражение MG107_15PL & MG107_16PL & MG107_17PL & MG107_18PL); порядок элементов сохраняется. */ +// End of MG107: + +// Beginning of MG108: +/* Условие компиляции (G101PL >= G108PL) или (G101PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G101PL >= G108PL) || (G101PL == 0) +/* Задаёт MG108_11PL = ~(1); данные MG108_11PL. */ +#define MG108_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_11PL = 0xFFFF; данные MG108_11PL. */ +#define MG108_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G102PL >= G108PL) или (G102PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G102PL >= G108PL) || (G102PL == 0) +/* Задаёт MG108_12PL = ~(1 << 1); данные MG108_12PL. */ +#define MG108_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_12PL = 0xFFFF; данные MG108_12PL. */ +#define MG108_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G103PL >= G108PL) или (G103PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G103PL >= G108PL) || (G103PL == 0) +/* Задаёт MG108_13PL = ~(1 << 2); данные MG108_13PL. */ +#define MG108_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_13PL = 0xFFFF; данные MG108_13PL. */ +#define MG108_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G104PL >= G108PL) или (G104PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G104PL >= G108PL) || (G104PL == 0) +/* Задаёт MG108_14PL = ~(1 << 3); данные MG108_14PL. */ +#define MG108_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_14PL = 0xFFFF; данные MG108_14PL. */ +#define MG108_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G105PL >= G108PL) или (G105PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G105PL >= G108PL) || (G105PL == 0) +/* Задаёт MG108_15PL = ~(1 << 4); данные MG108_15PL. */ +#define MG108_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_15PL = 0xFFFF; данные MG108_15PL. */ +#define MG108_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G106PL >= G108PL) или (G106PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G106PL >= G108PL) || (G106PL == 0) +/* Задаёт MG108_16PL = ~(1 << 5); данные MG108_16PL. */ +#define MG108_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_16PL = 0xFFFF; данные MG108_16PL. */ +#define MG108_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G107PL >= G108PL) или (G107PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G107PL >= G108PL) || (G107PL == 0) +/* Задаёт MG108_17PL = ~(1 << 6); данные MG108_17PL. */ +#define MG108_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG108_17PL = 0xFFFF; данные MG108_17PL. */ +#define MG108_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG108_18PL = 0x007F; данные MG108_18PL. */ +#define MG108_18PL 0x007F +/* Задаёт MG108 = (MG108_11PL & MG108_12PL & MG108_13PL & MG108_14PL &; маска разрешённых прерываний внутри группы PIE 108. */ +#define MG108 (MG108_11PL & MG108_12PL & MG108_13PL & MG108_14PL & \ + MG108_15PL & MG108_16PL & MG108_17PL & MG108_18PL) /* Продолжает список аргументов, полей или выражение MG108_15PL & MG108_16PL & MG108_17PL & MG108_18PL); порядок элементов сохраняется. */ +// End of MG108: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG111 to MG118: +// + +// Beginning of MG111: +/* Условие компиляции (G112PL >= G111PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G111PL) || (G112PL == 0) +/* Задаёт MG111_12PL = ~(1 << 1); данные MG111_12PL. */ +#define MG111_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_12PL = 0xFFFF; данные MG111_12PL. */ +#define MG111_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G111PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G111PL) || (G113PL == 0) +/* Задаёт MG111_13PL = ~(1 << 2); данные MG111_13PL. */ +#define MG111_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_13PL = 0xFFFF; данные MG111_13PL. */ +#define MG111_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G111PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G111PL) || (G114PL == 0) +/* Задаёт MG111_14PL = ~(1 << 3); данные MG111_14PL. */ +#define MG111_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_14PL = 0xFFFF; данные MG111_14PL. */ +#define MG111_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G111PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G111PL) || (G115PL == 0) +/* Задаёт MG111_15PL = ~(1 << 4); данные MG111_15PL. */ +#define MG111_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_15PL = 0xFFFF; данные MG111_15PL. */ +#define MG111_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G111PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G111PL) || (G116PL == 0) +/* Задаёт MG111_16PL = ~(1 << 5); данные MG111_16PL. */ +#define MG111_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_16PL = 0xFFFF; данные MG111_16PL. */ +#define MG111_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G111PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G111PL) || (G117PL == 0) +/* Задаёт MG111_17PL = ~(1 << 6); данные MG111_17PL. */ +#define MG111_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_17PL = 0xFFFF; данные MG111_17PL. */ +#define MG111_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G111PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G111PL) || (G118PL == 0) +/* Задаёт MG111_18PL = ~(1 << 7); данные MG111_18PL. */ +#define MG111_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG111_18PL = 0xFFFF; данные MG111_18PL. */ +#define MG111_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG111_11PL = 0x00FE; данные MG111_11PL. */ +#define MG111_11PL 0x00FE +/* Задаёт MG111 = (MG111_11PL & MG111_12PL & MG111_13PL & MG111_14PL &; маска разрешённых прерываний внутри группы PIE 111. */ +#define MG111 (MG111_11PL & MG111_12PL & MG111_13PL & MG111_14PL & \ + MG111_15PL & MG111_16PL & MG111_17PL & MG111_18PL) /* Продолжает список аргументов, полей или выражение MG111_15PL & MG111_16PL & MG111_17PL & MG111_18PL); порядок элементов сохраняется. */ +// End of MG111: + +// Beginning of MG112: +/* Условие компиляции (G111PL >= G112PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G112PL) || (G111PL == 0) +/* Задаёт MG112_11PL = ~(1); данные MG112_11PL. */ +#define MG112_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_11PL = 0xFFFF; данные MG112_11PL. */ +#define MG112_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G112PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G112PL) || (G113PL == 0) +/* Задаёт MG112_13PL = ~(1 << 2); данные MG112_13PL. */ +#define MG112_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_13PL = 0xFFFF; данные MG112_13PL. */ +#define MG112_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G112PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G112PL) || (G114PL == 0) +/* Задаёт MG112_14PL = ~(1 << 3); данные MG112_14PL. */ +#define MG112_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_14PL = 0xFFFF; данные MG112_14PL. */ +#define MG112_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G112PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G112PL) || (G115PL == 0) +/* Задаёт MG112_15PL = ~(1 << 4); данные MG112_15PL. */ +#define MG112_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_15PL = 0xFFFF; данные MG112_15PL. */ +#define MG112_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G112PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G112PL) || (G116PL == 0) +/* Задаёт MG112_16PL = ~(1 << 5); данные MG112_16PL. */ +#define MG112_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_16PL = 0xFFFF; данные MG112_16PL. */ +#define MG112_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G112PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G112PL) || (G117PL == 0) +/* Задаёт MG112_17PL = ~(1 << 6); данные MG112_17PL. */ +#define MG112_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_17PL = 0xFFFF; данные MG112_17PL. */ +#define MG112_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G112PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G112PL) || (G118PL == 0) +/* Задаёт MG112_18PL = ~(1 << 7); данные MG112_18PL. */ +#define MG112_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG112_18PL = 0xFFFF; данные MG112_18PL. */ +#define MG112_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG112_12PL = 0x00FD; данные MG112_12PL. */ +#define MG112_12PL 0x00FD +/* Задаёт MG112 = (MG112_11PL & MG112_12PL & MG112_13PL & MG112_14PL &; маска разрешённых прерываний внутри группы PIE 112. */ +#define MG112 (MG112_11PL & MG112_12PL & MG112_13PL & MG112_14PL & \ + MG112_15PL & MG112_16PL & MG112_17PL & MG112_18PL) /* Продолжает список аргументов, полей или выражение MG112_15PL & MG112_16PL & MG112_17PL & MG112_18PL); порядок элементов сохраняется. */ +// End of MG112: + +// Beginning of MG113: +/* Условие компиляции (G111PL >= G113PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G113PL) || (G111PL == 0) +/* Задаёт MG113_11PL = ~(1); данные MG113_11PL. */ +#define MG113_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_11PL = 0xFFFF; данные MG113_11PL. */ +#define MG113_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G113PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G113PL) || (G112PL == 0) +/* Задаёт MG113_12PL = ~(1 << 1); данные MG113_12PL. */ +#define MG113_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_12PL = 0xFFFF; данные MG113_12PL. */ +#define MG113_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G113PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G113PL) || (G114PL == 0) +/* Задаёт MG113_14PL = ~(1 << 3); данные MG113_14PL. */ +#define MG113_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_14PL = 0xFFFF; данные MG113_14PL. */ +#define MG113_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G113PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G113PL) || (G115PL == 0) +/* Задаёт MG113_15PL = ~(1 << 4); данные MG113_15PL. */ +#define MG113_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_15PL = 0xFFFF; данные MG113_15PL. */ +#define MG113_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G113PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G113PL) || (G116PL == 0) +/* Задаёт MG113_16PL = ~(1 << 5); данные MG113_16PL. */ +#define MG113_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_16PL = 0xFFFF; данные MG113_16PL. */ +#define MG113_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G113PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G113PL) || (G117PL == 0) +/* Задаёт MG113_17PL = ~(1 << 6); данные MG113_17PL. */ +#define MG113_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_17PL = 0xFFFF; данные MG113_17PL. */ +#define MG113_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G113PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G113PL) || (G118PL == 0) +/* Задаёт MG113_18PL = ~(1 << 7); данные MG113_18PL. */ +#define MG113_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG113_18PL = 0xFFFF; данные MG113_18PL. */ +#define MG113_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG113_13PL = 0x00FB; данные MG113_13PL. */ +#define MG113_13PL 0x00FB +/* Задаёт MG113 = (MG113_11PL & MG113_12PL & MG113_13PL & MG113_14PL &; маска разрешённых прерываний внутри группы PIE 113. */ +#define MG113 (MG113_11PL & MG113_12PL & MG113_13PL & MG113_14PL & \ + MG113_15PL & MG113_16PL & MG113_17PL & MG113_18PL) /* Продолжает список аргументов, полей или выражение MG113_15PL & MG113_16PL & MG113_17PL & MG113_18PL); порядок элементов сохраняется. */ +// End of MG113: + +// Beginning of MG114: +/* Условие компиляции (G111PL >= G114PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G114PL) || (G111PL == 0) +/* Задаёт MG114_11PL = ~(1); данные MG114_11PL. */ +#define MG114_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_11PL = 0xFFFF; данные MG114_11PL. */ +#define MG114_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G114PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G114PL) || (G112PL == 0) +/* Задаёт MG114_12PL = ~(1 << 1); данные MG114_12PL. */ +#define MG114_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_12PL = 0xFFFF; данные MG114_12PL. */ +#define MG114_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G114PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G114PL) || (G113PL == 0) +/* Задаёт MG114_13PL = ~(1 << 2); данные MG114_13PL. */ +#define MG114_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_13PL = 0xFFFF; данные MG114_13PL. */ +#define MG114_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G114PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G114PL) || (G115PL == 0) +/* Задаёт MG114_15PL = ~(1 << 4); данные MG114_15PL. */ +#define MG114_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_15PL = 0xFFFF; данные MG114_15PL. */ +#define MG114_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G114PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G114PL) || (G116PL == 0) +/* Задаёт MG114_16PL = ~(1 << 5); данные MG114_16PL. */ +#define MG114_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_16PL = 0xFFFF; данные MG114_16PL. */ +#define MG114_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G114PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G114PL) || (G117PL == 0) +/* Задаёт MG114_17PL = ~(1 << 6); данные MG114_17PL. */ +#define MG114_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_17PL = 0xFFFF; данные MG114_17PL. */ +#define MG114_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G114PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G114PL) || (G118PL == 0) +/* Задаёт MG114_18PL = ~(1 << 7); данные MG114_18PL. */ +#define MG114_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG114_18PL = 0xFFFF; данные MG114_18PL. */ +#define MG114_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG114_14PL = 0x00F7; данные MG114_14PL. */ +#define MG114_14PL 0x00F7 +/* Задаёт MG114 = (MG114_11PL & MG114_12PL & MG114_13PL & MG114_14PL &; маска разрешённых прерываний внутри группы PIE 114. */ +#define MG114 (MG114_11PL & MG114_12PL & MG114_13PL & MG114_14PL & \ + MG114_15PL & MG114_16PL & MG114_17PL & MG114_18PL) /* Продолжает список аргументов, полей или выражение MG114_15PL & MG114_16PL & MG114_17PL & MG114_18PL); порядок элементов сохраняется. */ +// End of MG114: + +// Beginning of MG115: +/* Условие компиляции (G111PL >= G115PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G115PL) || (G111PL == 0) +/* Задаёт MG115_11PL = ~(1); данные MG115_11PL. */ +#define MG115_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_11PL = 0xFFFF; данные MG115_11PL. */ +#define MG115_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G115PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G115PL) || (G112PL == 0) +/* Задаёт MG115_12PL = ~(1 << 1); данные MG115_12PL. */ +#define MG115_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_12PL = 0xFFFF; данные MG115_12PL. */ +#define MG115_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G115PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G115PL) || (G113PL == 0) +/* Задаёт MG115_13PL = ~(1 << 2); данные MG115_13PL. */ +#define MG115_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_13PL = 0xFFFF; данные MG115_13PL. */ +#define MG115_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G115PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G115PL) || (G114PL == 0) +/* Задаёт MG115_14PL = ~(1 << 3); данные MG115_14PL. */ +#define MG115_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_14PL = 0xFFFF; данные MG115_14PL. */ +#define MG115_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G115PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G115PL) || (G116PL == 0) +/* Задаёт MG115_16PL = ~(1 << 5); данные MG115_16PL. */ +#define MG115_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_16PL = 0xFFFF; данные MG115_16PL. */ +#define MG115_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G115PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G115PL) || (G117PL == 0) +/* Задаёт MG115_17PL = ~(1 << 6); данные MG115_17PL. */ +#define MG115_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_17PL = 0xFFFF; данные MG115_17PL. */ +#define MG115_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G115PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G115PL) || (G118PL == 0) +/* Задаёт MG115_18PL = ~(1 << 7); данные MG115_18PL. */ +#define MG115_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG115_18PL = 0xFFFF; данные MG115_18PL. */ +#define MG115_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG115_15PL = 0x00EF; данные MG115_15PL. */ +#define MG115_15PL 0x00EF +/* Задаёт MG115 = (MG115_11PL & MG115_12PL & MG115_13PL & MG115_14PL &; маска разрешённых прерываний внутри группы PIE 115. */ +#define MG115 (MG115_11PL & MG115_12PL & MG115_13PL & MG115_14PL & \ + MG115_15PL & MG115_16PL & MG115_17PL & MG115_18PL) /* Продолжает список аргументов, полей или выражение MG115_15PL & MG115_16PL & MG115_17PL & MG115_18PL); порядок элементов сохраняется. */ +// End of MG115: + +// Beginning of MG116: +/* Условие компиляции (G111PL >= G116PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G116PL) || (G111PL == 0) +/* Задаёт MG116_11PL = ~(1); данные MG116_11PL. */ +#define MG116_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_11PL = 0xFFFF; данные MG116_11PL. */ +#define MG116_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G116PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G116PL) || (G112PL == 0) +/* Задаёт MG116_12PL = ~(1 << 1); данные MG116_12PL. */ +#define MG116_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_12PL = 0xFFFF; данные MG116_12PL. */ +#define MG116_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G116PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G116PL) || (G113PL == 0) +/* Задаёт MG116_13PL = ~(1 << 2); данные MG116_13PL. */ +#define MG116_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_13PL = 0xFFFF; данные MG116_13PL. */ +#define MG116_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G116PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G116PL) || (G114PL == 0) +/* Задаёт MG116_14PL = ~(1 << 3); данные MG116_14PL. */ +#define MG116_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_14PL = 0xFFFF; данные MG116_14PL. */ +#define MG116_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G116PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G116PL) || (G115PL == 0) +/* Задаёт MG116_15PL = ~(1 << 4); данные MG116_15PL. */ +#define MG116_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_15PL = 0xFFFF; данные MG116_15PL. */ +#define MG116_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G116PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G116PL) || (G117PL == 0) +/* Задаёт MG116_17PL = ~(1 << 6); данные MG116_17PL. */ +#define MG116_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_17PL = 0xFFFF; данные MG116_17PL. */ +#define MG116_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G116PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G116PL) || (G118PL == 0) +/* Задаёт MG116_18PL = ~(1 << 7); данные MG116_18PL. */ +#define MG116_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG116_18PL = 0xFFFF; данные MG116_18PL. */ +#define MG116_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG116_16PL = 0x00DF; данные MG116_16PL. */ +#define MG116_16PL 0x00DF +/* Задаёт MG116 = (MG116_11PL & MG116_12PL & MG116_13PL & MG116_14PL &; маска разрешённых прерываний внутри группы PIE 116. */ +#define MG116 (MG116_11PL & MG116_12PL & MG116_13PL & MG116_14PL & \ + MG116_15PL & MG116_16PL & MG116_17PL & MG116_18PL) /* Продолжает список аргументов, полей или выражение MG116_15PL & MG116_16PL & MG116_17PL & MG116_18PL); порядок элементов сохраняется. */ +// End of MG116: + +// Beginning of MG117: +/* Условие компиляции (G111PL >= G117PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G117PL) || (G111PL == 0) +/* Задаёт MG117_11PL = ~(1); данные MG117_11PL. */ +#define MG117_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_11PL = 0xFFFF; данные MG117_11PL. */ +#define MG117_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G117PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G117PL) || (G112PL == 0) +/* Задаёт MG117_12PL = ~(1 << 1); данные MG117_12PL. */ +#define MG117_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_12PL = 0xFFFF; данные MG117_12PL. */ +#define MG117_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G117PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G117PL) || (G113PL == 0) +/* Задаёт MG117_13PL = ~(1 << 2); данные MG117_13PL. */ +#define MG117_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_13PL = 0xFFFF; данные MG117_13PL. */ +#define MG117_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G117PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G117PL) || (G114PL == 0) +/* Задаёт MG117_14PL = ~(1 << 3); данные MG117_14PL. */ +#define MG117_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_14PL = 0xFFFF; данные MG117_14PL. */ +#define MG117_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G117PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G117PL) || (G115PL == 0) +/* Задаёт MG117_15PL = ~(1 << 4); данные MG117_15PL. */ +#define MG117_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_15PL = 0xFFFF; данные MG117_15PL. */ +#define MG117_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G117PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G117PL) || (G116PL == 0) +/* Задаёт MG117_16PL = ~(1 << 5); данные MG117_16PL. */ +#define MG117_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_16PL = 0xFFFF; данные MG117_16PL. */ +#define MG117_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G118PL >= G117PL) или (G118PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G118PL >= G117PL) || (G118PL == 0) +/* Задаёт MG117_18PL = ~(1 << 7); данные MG117_18PL. */ +#define MG117_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG117_18PL = 0xFFFF; данные MG117_18PL. */ +#define MG117_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG117_17PL = 0x00BF; данные MG117_17PL. */ +#define MG117_17PL 0x00BF +/* Задаёт MG117 = (MG117_11PL & MG117_12PL & MG117_13PL & MG117_14PL &; маска разрешённых прерываний внутри группы PIE 117. */ +#define MG117 (MG117_11PL & MG117_12PL & MG117_13PL & MG117_14PL & \ + MG117_15PL & MG117_16PL & MG117_17PL & MG117_18PL) /* Продолжает список аргументов, полей или выражение MG117_15PL & MG117_16PL & MG117_17PL & MG117_18PL); порядок элементов сохраняется. */ +// End of MG117: + +// Beginning of MG118: +/* Условие компиляции (G111PL >= G118PL) или (G111PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G111PL >= G118PL) || (G111PL == 0) +/* Задаёт MG118_11PL = ~(1); данные MG118_11PL. */ +#define MG118_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_11PL = 0xFFFF; данные MG118_11PL. */ +#define MG118_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G112PL >= G118PL) или (G112PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G112PL >= G118PL) || (G112PL == 0) +/* Задаёт MG118_12PL = ~(1 << 1); данные MG118_12PL. */ +#define MG118_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_12PL = 0xFFFF; данные MG118_12PL. */ +#define MG118_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G113PL >= G118PL) или (G113PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G113PL >= G118PL) || (G113PL == 0) +/* Задаёт MG118_13PL = ~(1 << 2); данные MG118_13PL. */ +#define MG118_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_13PL = 0xFFFF; данные MG118_13PL. */ +#define MG118_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G114PL >= G118PL) или (G114PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G114PL >= G118PL) || (G114PL == 0) +/* Задаёт MG118_14PL = ~(1 << 3); данные MG118_14PL. */ +#define MG118_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_14PL = 0xFFFF; данные MG118_14PL. */ +#define MG118_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G115PL >= G118PL) или (G115PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G115PL >= G118PL) || (G115PL == 0) +/* Задаёт MG118_15PL = ~(1 << 4); данные MG118_15PL. */ +#define MG118_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_15PL = 0xFFFF; данные MG118_15PL. */ +#define MG118_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G116PL >= G118PL) или (G116PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G116PL >= G118PL) || (G116PL == 0) +/* Задаёт MG118_16PL = ~(1 << 5); данные MG118_16PL. */ +#define MG118_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_16PL = 0xFFFF; данные MG118_16PL. */ +#define MG118_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G117PL >= G118PL) или (G117PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G117PL >= G118PL) || (G117PL == 0) +/* Задаёт MG118_17PL = ~(1 << 6); данные MG118_17PL. */ +#define MG118_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG118_17PL = 0xFFFF; данные MG118_17PL. */ +#define MG118_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG118_18PL = 0x007F; данные MG118_18PL. */ +#define MG118_18PL 0x007F +/* Задаёт MG118 = (MG118_11PL & MG118_12PL & MG118_13PL & MG118_14PL &; маска разрешённых прерываний внутри группы PIE 118. */ +#define MG118 (MG118_11PL & MG118_12PL & MG118_13PL & MG118_14PL & \ + MG118_15PL & MG118_16PL & MG118_17PL & MG118_18PL) /* Продолжает список аргументов, полей или выражение MG118_15PL & MG118_16PL & MG118_17PL & MG118_18PL); порядок элементов сохраняется. */ +// End of MG118: + +//------------------------------------------------------------------------------- +// Automatically generate PIEIER1 interrupt masks MG121 to MG128: +// + +// Beginning of MG121: +/* Условие компиляции (G122PL >= G121PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G121PL) || (G122PL == 0) +/* Задаёт MG121_12PL = ~(1 << 1); данные MG121_12PL. */ +#define MG121_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_12PL = 0xFFFF; данные MG121_12PL. */ +#define MG121_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G121PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G121PL) || (G123PL == 0) +/* Задаёт MG121_13PL = ~(1 << 2); данные MG121_13PL. */ +#define MG121_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_13PL = 0xFFFF; данные MG121_13PL. */ +#define MG121_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G121PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G121PL) || (G124PL == 0) +/* Задаёт MG121_14PL = ~(1 << 3); данные MG121_14PL. */ +#define MG121_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_14PL = 0xFFFF; данные MG121_14PL. */ +#define MG121_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G121PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G121PL) || (G125PL == 0) +/* Задаёт MG121_15PL = ~(1 << 4); данные MG121_15PL. */ +#define MG121_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_15PL = 0xFFFF; данные MG121_15PL. */ +#define MG121_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G121PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G121PL) || (G126PL == 0) +/* Задаёт MG121_16PL = ~(1 << 5); данные MG121_16PL. */ +#define MG121_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_16PL = 0xFFFF; данные MG121_16PL. */ +#define MG121_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G121PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G121PL) || (G127PL == 0) +/* Задаёт MG121_17PL = ~(1 << 6); данные MG121_17PL. */ +#define MG121_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_17PL = 0xFFFF; данные MG121_17PL. */ +#define MG121_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G121PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G121PL) || (G128PL == 0) +/* Задаёт MG121_18PL = ~(1 << 7); данные MG121_18PL. */ +#define MG121_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG121_18PL = 0xFFFF; данные MG121_18PL. */ +#define MG121_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG121_11PL = 0x00FE; данные MG121_11PL. */ +#define MG121_11PL 0x00FE +/* Задаёт MG121 = (MG121_11PL & MG121_12PL & MG121_13PL & MG121_14PL &; маска разрешённых прерываний внутри группы PIE 121. */ +#define MG121 (MG121_11PL & MG121_12PL & MG121_13PL & MG121_14PL & \ + MG121_15PL & MG121_16PL & MG121_17PL & MG121_18PL) /* Продолжает список аргументов, полей или выражение MG121_15PL & MG121_16PL & MG121_17PL & MG121_18PL); порядок элементов сохраняется. */ +// End of MG121: + +// Beginning of MG121: +/* Условие компиляции (G121PL >= G122PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G122PL) || (G121PL == 0) +/* Задаёт MG122_11PL = ~(1); данные MG122_11PL. */ +#define MG122_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_11PL = 0xFFFF; данные MG122_11PL. */ +#define MG122_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G122PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G122PL) || (G123PL == 0) +/* Задаёт MG122_13PL = ~(1 << 2); данные MG122_13PL. */ +#define MG122_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_13PL = 0xFFFF; данные MG122_13PL. */ +#define MG122_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G122PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G122PL) || (G124PL == 0) +/* Задаёт MG122_14PL = ~(1 << 3); данные MG122_14PL. */ +#define MG122_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_14PL = 0xFFFF; данные MG122_14PL. */ +#define MG122_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G122PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G122PL) || (G125PL == 0) +/* Задаёт MG122_15PL = ~(1 << 4); данные MG122_15PL. */ +#define MG122_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_15PL = 0xFFFF; данные MG122_15PL. */ +#define MG122_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G122PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G122PL) || (G126PL == 0) +/* Задаёт MG122_16PL = ~(1 << 5); данные MG122_16PL. */ +#define MG122_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_16PL = 0xFFFF; данные MG122_16PL. */ +#define MG122_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G122PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G122PL) || (G127PL == 0) +/* Задаёт MG122_17PL = ~(1 << 6); данные MG122_17PL. */ +#define MG122_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_17PL = 0xFFFF; данные MG122_17PL. */ +#define MG122_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G122PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G122PL) || (G128PL == 0) +/* Задаёт MG122_18PL = ~(1 << 7); данные MG122_18PL. */ +#define MG122_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG122_18PL = 0xFFFF; данные MG122_18PL. */ +#define MG122_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG122_12PL = 0x00FD; данные MG122_12PL. */ +#define MG122_12PL 0x00FD +/* Задаёт MG122 = (MG122_11PL & MG122_12PL & MG122_13PL & MG122_14PL &; маска разрешённых прерываний внутри группы PIE 122. */ +#define MG122 (MG122_11PL & MG122_12PL & MG122_13PL & MG122_14PL & \ + MG122_15PL & MG122_16PL & MG122_17PL & MG122_18PL) /* Продолжает список аргументов, полей или выражение MG122_15PL & MG122_16PL & MG122_17PL & MG122_18PL); порядок элементов сохраняется. */ +// End of MG122: + +// Beginning of MG123: +/* Условие компиляции (G121PL >= G123PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G123PL) || (G121PL == 0) +/* Задаёт MG123_11PL = ~(1); данные MG123_11PL. */ +#define MG123_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_11PL = 0xFFFF; данные MG123_11PL. */ +#define MG123_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G123PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G123PL) || (G122PL == 0) +/* Задаёт MG123_12PL = ~(1 << 1); данные MG123_12PL. */ +#define MG123_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_12PL = 0xFFFF; данные MG123_12PL. */ +#define MG123_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G123PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G123PL) || (G124PL == 0) +/* Задаёт MG123_14PL = ~(1 << 3); данные MG123_14PL. */ +#define MG123_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_14PL = 0xFFFF; данные MG123_14PL. */ +#define MG123_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G123PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G123PL) || (G125PL == 0) +/* Задаёт MG123_15PL = ~(1 << 4); данные MG123_15PL. */ +#define MG123_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_15PL = 0xFFFF; данные MG123_15PL. */ +#define MG123_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G123PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G123PL) || (G126PL == 0) +/* Задаёт MG123_16PL = ~(1 << 5); данные MG123_16PL. */ +#define MG123_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_16PL = 0xFFFF; данные MG123_16PL. */ +#define MG123_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G123PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G123PL) || (G127PL == 0) +/* Задаёт MG123_17PL = ~(1 << 6); данные MG123_17PL. */ +#define MG123_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_17PL = 0xFFFF; данные MG123_17PL. */ +#define MG123_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G123PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G123PL) || (G128PL == 0) +/* Задаёт MG123_18PL = ~(1 << 7); данные MG123_18PL. */ +#define MG123_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG123_18PL = 0xFFFF; данные MG123_18PL. */ +#define MG123_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG123_13PL = 0x00FB; данные MG123_13PL. */ +#define MG123_13PL 0x00FB +/* Задаёт MG123 = (MG123_11PL & MG123_12PL & MG123_13PL & MG123_14PL &; маска разрешённых прерываний внутри группы PIE 123. */ +#define MG123 (MG123_11PL & MG123_12PL & MG123_13PL & MG123_14PL & \ + MG123_15PL & MG123_16PL & MG123_17PL & MG123_18PL) /* Продолжает список аргументов, полей или выражение MG123_15PL & MG123_16PL & MG123_17PL & MG123_18PL); порядок элементов сохраняется. */ +// End of MG123: + +// Beginning of MG124: +/* Условие компиляции (G121PL >= G124PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G124PL) || (G121PL == 0) +/* Задаёт MG124_11PL = ~(1); данные MG124_11PL. */ +#define MG124_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_11PL = 0xFFFF; данные MG124_11PL. */ +#define MG124_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G124PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G124PL) || (G122PL == 0) +/* Задаёт MG124_12PL = ~(1 << 1); данные MG124_12PL. */ +#define MG124_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_12PL = 0xFFFF; данные MG124_12PL. */ +#define MG124_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G124PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G124PL) || (G123PL == 0) +/* Задаёт MG124_13PL = ~(1 << 2); данные MG124_13PL. */ +#define MG124_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_13PL = 0xFFFF; данные MG124_13PL. */ +#define MG124_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G124PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G124PL) || (G125PL == 0) +/* Задаёт MG124_15PL = ~(1 << 4); данные MG124_15PL. */ +#define MG124_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_15PL = 0xFFFF; данные MG124_15PL. */ +#define MG124_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G124PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G124PL) || (G126PL == 0) +/* Задаёт MG124_16PL = ~(1 << 5); данные MG124_16PL. */ +#define MG124_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_16PL = 0xFFFF; данные MG124_16PL. */ +#define MG124_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G124PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G124PL) || (G127PL == 0) +/* Задаёт MG124_17PL = ~(1 << 6); данные MG124_17PL. */ +#define MG124_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_17PL = 0xFFFF; данные MG124_17PL. */ +#define MG124_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G124PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G124PL) || (G128PL == 0) +/* Задаёт MG124_18PL = ~(1 << 7); данные MG124_18PL. */ +#define MG124_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG124_18PL = 0xFFFF; данные MG124_18PL. */ +#define MG124_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG124_14PL = 0x00F7; данные MG124_14PL. */ +#define MG124_14PL 0x00F7 +/* Задаёт MG124 = (MG124_11PL & MG124_12PL & MG124_13PL & MG124_14PL &; маска разрешённых прерываний внутри группы PIE 124. */ +#define MG124 (MG124_11PL & MG124_12PL & MG124_13PL & MG124_14PL & \ + MG124_15PL & MG124_16PL & MG124_17PL & MG124_18PL) /* Продолжает список аргументов, полей или выражение MG124_15PL & MG124_16PL & MG124_17PL & MG124_18PL); порядок элементов сохраняется. */ +// End of MG124: + +// Beginning of MG125: +/* Условие компиляции (G121PL >= G125PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G125PL) || (G121PL == 0) +/* Задаёт MG125_11PL = ~(1); данные MG125_11PL. */ +#define MG125_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_11PL = 0xFFFF; данные MG125_11PL. */ +#define MG125_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G125PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G125PL) || (G122PL == 0) +/* Задаёт MG125_12PL = ~(1 << 1); данные MG125_12PL. */ +#define MG125_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_12PL = 0xFFFF; данные MG125_12PL. */ +#define MG125_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G125PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G125PL) || (G123PL == 0) +/* Задаёт MG125_13PL = ~(1 << 2); данные MG125_13PL. */ +#define MG125_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_13PL = 0xFFFF; данные MG125_13PL. */ +#define MG125_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G125PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G125PL) || (G124PL == 0) +/* Задаёт MG125_14PL = ~(1 << 3); данные MG125_14PL. */ +#define MG125_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_14PL = 0xFFFF; данные MG125_14PL. */ +#define MG125_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G125PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G125PL) || (G126PL == 0) +/* Задаёт MG125_16PL = ~(1 << 5); данные MG125_16PL. */ +#define MG125_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_16PL = 0xFFFF; данные MG125_16PL. */ +#define MG125_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G125PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G125PL) || (G127PL == 0) +/* Задаёт MG125_17PL = ~(1 << 6); данные MG125_17PL. */ +#define MG125_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_17PL = 0xFFFF; данные MG125_17PL. */ +#define MG125_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G125PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G125PL) || (G128PL == 0) +/* Задаёт MG125_18PL = ~(1 << 7); данные MG125_18PL. */ +#define MG125_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG125_18PL = 0xFFFF; данные MG125_18PL. */ +#define MG125_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG125_15PL = 0x00EF; данные MG125_15PL. */ +#define MG125_15PL 0x00EF +/* Задаёт MG125 = (MG125_11PL & MG125_12PL & MG125_13PL & MG125_14PL &; маска разрешённых прерываний внутри группы PIE 125. */ +#define MG125 (MG125_11PL & MG125_12PL & MG125_13PL & MG125_14PL & \ + MG125_15PL & MG125_16PL & MG125_17PL & MG125_18PL) /* Продолжает список аргументов, полей или выражение MG125_15PL & MG125_16PL & MG125_17PL & MG125_18PL); порядок элементов сохраняется. */ +// End of MG125: + +// Beginning of MG126: +/* Условие компиляции (G121PL >= G126PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G126PL) || (G121PL == 0) +/* Задаёт MG126_11PL = ~(1); данные MG126_11PL. */ +#define MG126_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_11PL = 0xFFFF; данные MG126_11PL. */ +#define MG126_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G126PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G126PL) || (G122PL == 0) +/* Задаёт MG126_12PL = ~(1 << 1); данные MG126_12PL. */ +#define MG126_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_12PL = 0xFFFF; данные MG126_12PL. */ +#define MG126_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G126PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G126PL) || (G123PL == 0) +/* Задаёт MG126_13PL = ~(1 << 2); данные MG126_13PL. */ +#define MG126_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_13PL = 0xFFFF; данные MG126_13PL. */ +#define MG126_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G126PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G126PL) || (G124PL == 0) +/* Задаёт MG126_14PL = ~(1 << 3); данные MG126_14PL. */ +#define MG126_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_14PL = 0xFFFF; данные MG126_14PL. */ +#define MG126_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G126PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G126PL) || (G125PL == 0) +/* Задаёт MG126_15PL = ~(1 << 4); данные MG126_15PL. */ +#define MG126_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_15PL = 0xFFFF; данные MG126_15PL. */ +#define MG126_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G126PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G126PL) || (G127PL == 0) +/* Задаёт MG126_17PL = ~(1 << 6); данные MG126_17PL. */ +#define MG126_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_17PL = 0xFFFF; данные MG126_17PL. */ +#define MG126_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G126PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G126PL) || (G128PL == 0) +/* Задаёт MG126_18PL = ~(1 << 7); данные MG126_18PL. */ +#define MG126_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG126_18PL = 0xFFFF; данные MG126_18PL. */ +#define MG126_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG126_16PL = 0x00DF; данные MG126_16PL. */ +#define MG126_16PL 0x00DF +/* Задаёт MG126 = (MG126_11PL & MG126_12PL & MG126_13PL & MG126_14PL &; маска разрешённых прерываний внутри группы PIE 126. */ +#define MG126 (MG126_11PL & MG126_12PL & MG126_13PL & MG126_14PL & \ + MG126_15PL & MG126_16PL & MG126_17PL & MG126_18PL) /* Продолжает список аргументов, полей или выражение MG126_15PL & MG126_16PL & MG126_17PL & MG126_18PL); порядок элементов сохраняется. */ +// End of MG126: + +// Beginning of MG127: +/* Условие компиляции (G121PL >= G127PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G127PL) || (G121PL == 0) +/* Задаёт MG127_11PL = ~(1); данные MG127_11PL. */ +#define MG127_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_11PL = 0xFFFF; данные MG127_11PL. */ +#define MG127_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G127PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G127PL) || (G122PL == 0) +/* Задаёт MG127_12PL = ~(1 << 1); данные MG127_12PL. */ +#define MG127_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_12PL = 0xFFFF; данные MG127_12PL. */ +#define MG127_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G127PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G127PL) || (G123PL == 0) +/* Задаёт MG127_13PL = ~(1 << 2); данные MG127_13PL. */ +#define MG127_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_13PL = 0xFFFF; данные MG127_13PL. */ +#define MG127_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G127PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G127PL) || (G124PL == 0) +/* Задаёт MG127_14PL = ~(1 << 3); данные MG127_14PL. */ +#define MG127_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_14PL = 0xFFFF; данные MG127_14PL. */ +#define MG127_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G127PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G127PL) || (G125PL == 0) +/* Задаёт MG127_15PL = ~(1 << 4); данные MG127_15PL. */ +#define MG127_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_15PL = 0xFFFF; данные MG127_15PL. */ +#define MG127_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G127PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G127PL) || (G126PL == 0) +/* Задаёт MG127_16PL = ~(1 << 5); данные MG127_16PL. */ +#define MG127_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_16PL = 0xFFFF; данные MG127_16PL. */ +#define MG127_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G128PL >= G127PL) или (G128PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G128PL >= G127PL) || (G128PL == 0) +/* Задаёт MG127_18PL = ~(1 << 7); данные MG127_18PL. */ +#define MG127_18PL ~(1 << 7) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG127_18PL = 0xFFFF; данные MG127_18PL. */ +#define MG127_18PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG127_17PL = 0x00BF; данные MG127_17PL. */ +#define MG127_17PL 0x00BF +/* Задаёт MG127 = (MG127_11PL & MG127_12PL & MG127_13PL & MG127_14PL &; маска разрешённых прерываний внутри группы PIE 127. */ +#define MG127 (MG127_11PL & MG127_12PL & MG127_13PL & MG127_14PL & \ + MG127_15PL & MG127_16PL & MG127_17PL & MG127_18PL) /* Продолжает список аргументов, полей или выражение MG127_15PL & MG127_16PL & MG127_17PL & MG127_18PL); порядок элементов сохраняется. */ +// End of MG127: + +// Beginning of MG128: +/* Условие компиляции (G121PL >= G128PL) или (G121PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G121PL >= G128PL) || (G121PL == 0) +/* Задаёт MG128_11PL = ~(1); данные MG128_11PL. */ +#define MG128_11PL ~(1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_11PL = 0xFFFF; данные MG128_11PL. */ +#define MG128_11PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G122PL >= G128PL) или (G122PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G122PL >= G128PL) || (G122PL == 0) +/* Задаёт MG128_12PL = ~(1 << 1); данные MG128_12PL. */ +#define MG128_12PL ~(1 << 1) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_12PL = 0xFFFF; данные MG128_12PL. */ +#define MG128_12PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G123PL >= G128PL) или (G123PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G123PL >= G128PL) || (G123PL == 0) +/* Задаёт MG128_13PL = ~(1 << 2); данные MG128_13PL. */ +#define MG128_13PL ~(1 << 2) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_13PL = 0xFFFF; данные MG128_13PL. */ +#define MG128_13PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G124PL >= G128PL) или (G124PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G124PL >= G128PL) || (G124PL == 0) +/* Задаёт MG128_14PL = ~(1 << 3); данные MG128_14PL. */ +#define MG128_14PL ~(1 << 3) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_14PL = 0xFFFF; данные MG128_14PL. */ +#define MG128_14PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G125PL >= G128PL) или (G125PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G125PL >= G128PL) || (G125PL == 0) +/* Задаёт MG128_15PL = ~(1 << 4); данные MG128_15PL. */ +#define MG128_15PL ~(1 << 4) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_15PL = 0xFFFF; данные MG128_15PL. */ +#define MG128_15PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G126PL >= G128PL) или (G126PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G126PL >= G128PL) || (G126PL == 0) +/* Задаёт MG128_16PL = ~(1 << 5); данные MG128_16PL. */ +#define MG128_16PL ~(1 << 5) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_16PL = 0xFFFF; данные MG128_16PL. */ +#define MG128_16PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции (G127PL >= G128PL) или (G127PL == 0): выбранный блок включается в текущий вариант прошивки. */ +#if (G127PL >= G128PL) || (G127PL == 0) +/* Задаёт MG128_17PL = ~(1 << 6); данные MG128_17PL. */ +#define MG128_17PL ~(1 << 6) +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Задаёт MG128_17PL = 0xFFFF; данные MG128_17PL. */ +#define MG128_17PL 0xFFFF +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Задаёт MG128_18PL = 0x007F; данные MG128_18PL. */ +#define MG128_18PL 0x007F +/* Задаёт MG128 = (MG128_11PL & MG128_12PL & MG128_13PL & MG128_14PL &; маска разрешённых прерываний внутри группы PIE 128. */ +#define MG128 (MG128_11PL & MG128_12PL & MG128_13PL & MG128_14PL & \ + MG128_15PL & MG128_16PL & MG128_17PL & MG128_18PL) /* Продолжает список аргументов, полей или выражение MG128_15PL & MG128_16PL & MG128_17PL & MG128_18PL); порядок элементов сохраняется. */ +// End of MG128: + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // eof + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h b/c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h new file mode 100644 index 0000000..d94194a --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/common/include/DSP28x_Project.h @@ -0,0 +1,28 @@ +/* Настройки и интерфейс DSP28x_Project. Русские пояснения сохранены в UTF-8. */ + +// TI File $Revision: /main/1 $ +// Checkin $Date: April 22, 2008 14:35:56 $ +//########################################################################### +// +// FILE: DSP28x_Project.h +// +// TITLE: DSP28x Project Headerfile and Examples Include File +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP28x_PROJECT_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP28x_PROJECT_H +/* Определяет защитный символ или переключатель DSP28x_PROJECT_H для последующей компиляции. */ +#define DSP28x_PROJECT_H + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // DSP2833x Examples Include File + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP28x_PROJECT_H definition + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h new file mode 100644 index 0000000..289dea6 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Adc.h @@ -0,0 +1,465 @@ +/* Поставляемое TI описание Adc для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:51:50 $ +//########################################################################### +// +// FILE: DSP2833x_Adc.h +// +// TITLE: DSP2833x Device ADC Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_ADC_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_ADC_H +/* Определяет защитный символ или переключатель DSP2833x_ADC_H для последующей компиляции. */ +#define DSP2833x_ADC_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// ADC Individual Register Bit Definitions: + +/* Описывает структуру ADCTRL1_BITS; порядок полей определяет расположение данных. */ +struct ADCTRL1_BITS { // bits description + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 3:0 reserved + /* Битовое поле SEQ_CASC, ширина 1 бит; данные SEQ_CASC. */ + Uint16 SEQ_CASC:1; // 4 Cascaded sequencer mode + /* Битовое поле SEQ_OVRD, ширина 1 бит; данные SEQ_OVRD. */ + Uint16 SEQ_OVRD:1; // 5 Sequencer override + /* Битовое поле CONT_RUN, ширина 1 бит; данные CONT_RUN. */ + Uint16 CONT_RUN:1; // 6 Continuous run + /* Битовое поле CPS, ширина 1 бит; данные CPS. */ + Uint16 CPS:1; // 7 ADC core clock pre-scalar + /* Битовое поле ACQ_PS, ширина 4 бит; данные ACQ_PS. */ + Uint16 ACQ_PS:4; // 11:8 Acquisition window size + /* Битовое поле SUSMOD, ширина 2 бит; данные SUSMOD. */ + Uint16 SUSMOD:2; // 13:12 Emulation suspend mode + /* Битовое поле RESET, ширина 1 бит; сброс. */ + Uint16 RESET:1; // 14 ADC reset + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ADCTRL1_REG в одной области памяти. */ +union ADCTRL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCTRL1_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCTRL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCTRL2_BITS; порядок полей определяет расположение данных. */ +struct ADCTRL2_BITS { // bits description + /* Битовое поле EPWM_SOCB_SEQ2, ширина 1 бит; данные EPWM_SOCB_SEQ2. */ + Uint16 EPWM_SOCB_SEQ2:1; // 0 EPWM compare B SOC mask for SEQ2 + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле INT_MOD_SEQ2, ширина 1 бит; данные INT_MOD_SEQ2. */ + Uint16 INT_MOD_SEQ2:1; // 2 SEQ2 Interrupt mode + /* Битовое поле INT_ENA_SEQ2, ширина 1 бит; данные INT_ENA_SEQ2. */ + Uint16 INT_ENA_SEQ2:1; // 3 SEQ2 Interrupt enable + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 4 reserved + /* Битовое поле SOC_SEQ2, ширина 1 бит; данные SOC_SEQ2. */ + Uint16 SOC_SEQ2:1; // 5 Start of conversion for SEQ2 + /* Битовое поле RST_SEQ2, ширина 1 бит; данные RST_SEQ2. */ + Uint16 RST_SEQ2:1; // 6 Reset SEQ2 + /* Битовое поле EXT_SOC_SEQ1, ширина 1 бит; данные EXT_SOC_SEQ1. */ + Uint16 EXT_SOC_SEQ1:1; // 7 External start of conversion for SEQ1 + /* Битовое поле EPWM_SOCA_SEQ1, ширина 1 бит; данные EPWM_SOCA_SEQ1. */ + Uint16 EPWM_SOCA_SEQ1:1; // 8 EPWM compare B SOC mask for SEQ1 + /* Битовое поле rsvd3, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:1; // 9 reserved + /* Битовое поле INT_MOD_SEQ1, ширина 1 бит; данные INT_MOD_SEQ1. */ + Uint16 INT_MOD_SEQ1:1; // 10 SEQ1 Interrupt mode + /* Битовое поле INT_ENA_SEQ1, ширина 1 бит; данные INT_ENA_SEQ1. */ + Uint16 INT_ENA_SEQ1:1; // 11 SEQ1 Interrupt enable + /* Битовое поле rsvd4, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4:1; // 12 reserved + /* Битовое поле SOC_SEQ1, ширина 1 бит; данные SOC_SEQ1. */ + Uint16 SOC_SEQ1:1; // 13 Start of conversion trigger for SEQ1 + /* Битовое поле RST_SEQ1, ширина 1 бит; данные RST_SEQ1. */ + Uint16 RST_SEQ1:1; // 14 Restart sequencer 1 + /* Битовое поле EPWM_SOCB_SEQ, ширина 1 бит; данные EPWM_SOCB_SEQ. */ + Uint16 EPWM_SOCB_SEQ:1; // 15 EPWM compare B SOC enable +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ADCTRL2_REG в одной области памяти. */ +union ADCTRL2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCTRL2_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCTRL2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCASEQSR_BITS; порядок полей определяет расположение данных. */ +struct ADCASEQSR_BITS { // bits description + /* Битовое поле SEQ1_STATE, ширина 4 бит; данные SEQ1_STATE. */ + Uint16 SEQ1_STATE:4; // 3:0 SEQ1 state + /* Битовое поле SEQ2_STATE, ширина 3 бит; данные SEQ2_STATE. */ + Uint16 SEQ2_STATE:3; // 6:4 SEQ2 state + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 7 reserved + /* Битовое поле SEQ_CNTR, ширина 4 бит; данные SEQ_CNTR. */ + Uint16 SEQ_CNTR:4; // 11:8 Sequencing counter status + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCASEQSR_REG в одной области памяти. */ +union ADCASEQSR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCASEQSR_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCASEQSR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCMAXCONV_BITS; порядок полей определяет расположение данных. */ +struct ADCMAXCONV_BITS { // bits description + /* Битовое поле MAX_CONV1, ширина 4 бит; данные MAX_CONV1. */ + Uint16 MAX_CONV1:4; // 3:0 Max number of conversions + /* Битовое поле MAX_CONV2, ширина 3 бит; данные MAX_CONV2. */ + Uint16 MAX_CONV2:3; // 6:4 Max number of conversions + /* Битовое поле rsvd1, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:9; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCMAXCONV_REG в одной области памяти. */ +union ADCMAXCONV_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCMAXCONV_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCMAXCONV_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCCHSELSEQ1_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ1_BITS { // bits description + /* Битовое поле CONV00, ширина 4 бит; данные CONV00. */ + Uint16 CONV00:4; // 3:0 Conversion selection 00 + /* Битовое поле CONV01, ширина 4 бит; данные CONV01. */ + Uint16 CONV01:4; // 7:4 Conversion selection 01 + /* Битовое поле CONV02, ширина 4 бит; данные CONV02. */ + Uint16 CONV02:4; // 11:8 Conversion selection 02 + /* Битовое поле CONV03, ширина 4 бит; данные CONV03. */ + Uint16 CONV03:4; // 15:12 Conversion selection 03 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ1_REG в одной области памяти. */ +union ADCCHSELSEQ1_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ1_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCCHSELSEQ2_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ2_BITS { // bits description + /* Битовое поле CONV04, ширина 4 бит; данные CONV04. */ + Uint16 CONV04:4; // 3:0 Conversion selection 04 + /* Битовое поле CONV05, ширина 4 бит; данные CONV05. */ + Uint16 CONV05:4; // 7:4 Conversion selection 05 + /* Битовое поле CONV06, ширина 4 бит; данные CONV06. */ + Uint16 CONV06:4; // 11:8 Conversion selection 06 + /* Битовое поле CONV07, ширина 4 бит; данные CONV07. */ + Uint16 CONV07:4; // 15:12 Conversion selection 07 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ2_REG в одной области памяти. */ +union ADCCHSELSEQ2_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ2_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCCHSELSEQ3_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ3_BITS { // bits description + /* Битовое поле CONV08, ширина 4 бит; данные CONV08. */ + Uint16 CONV08:4; // 3:0 Conversion selection 08 + /* Битовое поле CONV09, ширина 4 бит; данные CONV09. */ + Uint16 CONV09:4; // 7:4 Conversion selection 09 + /* Битовое поле CONV10, ширина 4 бит; данные CONV10. */ + Uint16 CONV10:4; // 11:8 Conversion selection 10 + /* Битовое поле CONV11, ширина 4 бит; данные CONV11. */ + Uint16 CONV11:4; // 15:12 Conversion selection 11 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ3_REG в одной области памяти. */ +union ADCCHSELSEQ3_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ3_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ3_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCCHSELSEQ4_BITS; порядок полей определяет расположение данных. */ +struct ADCCHSELSEQ4_BITS { // bits description + /* Битовое поле CONV12, ширина 4 бит; данные CONV12. */ + Uint16 CONV12:4; // 3:0 Conversion selection 12 + /* Битовое поле CONV13, ширина 4 бит; данные CONV13. */ + Uint16 CONV13:4; // 7:4 Conversion selection 13 + /* Битовое поле CONV14, ширина 4 бит; данные CONV14. */ + Uint16 CONV14:4; // 11:8 Conversion selection 14 + /* Битовое поле CONV15, ширина 4 бит; данные CONV15. */ + Uint16 CONV15:4; // 15:12 Conversion selection 15 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCCHSELSEQ4_REG в одной области памяти. */ +union ADCCHSELSEQ4_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCCHSELSEQ4_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCCHSELSEQ4_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCTRL3_BITS; порядок полей определяет расположение данных. */ +struct ADCTRL3_BITS { // bits description + /* Битовое поле SMODE_SEL, ширина 1 бит; данные SMODE_SEL. */ + Uint16 SMODE_SEL:1; // 0 Sampling mode select + /* Битовое поле ADCCLKPS, ширина 4 бит; данные ADCCLKPS. */ + Uint16 ADCCLKPS:4; // 4:1 ADC core clock divider + /* Битовое поле ADCPWDN, ширина 1 бит; данные ADCPWDN. */ + Uint16 ADCPWDN:1; // 5 ADC powerdown + /* Битовое поле ADCBGRFDN, ширина 2 бит; данные ADCBGRFDN. */ + Uint16 ADCBGRFDN:2; // 7:6 ADC bandgap/ref power down + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCTRL3_REG в одной области памяти. */ +union ADCTRL3_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCTRL3_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCTRL3_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADCST_BITS; порядок полей определяет расположение данных. */ +struct ADCST_BITS { // bits description + /* Битовое поле INT_SEQ1, ширина 1 бит; данные INT_SEQ1. */ + Uint16 INT_SEQ1:1; // 0 SEQ1 Interrupt flag + /* Битовое поле INT_SEQ2, ширина 1 бит; данные INT_SEQ2. */ + Uint16 INT_SEQ2:1; // 1 SEQ2 Interrupt flag + /* Битовое поле SEQ1_BSY, ширина 1 бит; данные SEQ1_BSY. */ + Uint16 SEQ1_BSY:1; // 2 SEQ1 busy status + /* Битовое поле SEQ2_BSY, ширина 1 бит; данные SEQ2_BSY. */ + Uint16 SEQ2_BSY:1; // 3 SEQ2 busy status + /* Битовое поле INT_SEQ1_CLR, ширина 1 бит; данные INT_SEQ1_CLR. */ + Uint16 INT_SEQ1_CLR:1; // 4 SEQ1 Interrupt clear + /* Битовое поле INT_SEQ2_CLR, ширина 1 бит; данные INT_SEQ2_CLR. */ + Uint16 INT_SEQ2_CLR:1; // 5 SEQ2 Interrupt clear + /* Битовое поле EOS_BUF1, ширина 1 бит; данные EOS_BUF1. */ + Uint16 EOS_BUF1:1; // 6 End of sequence buffer1 + /* Битовое поле EOS_BUF2, ширина 1 бит; данные EOS_BUF2. */ + Uint16 EOS_BUF2:1; // 7 End of sequence buffer2 + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ADCST_REG в одной области памяти. */ +union ADCST_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCST_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCST_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCREFSEL_BITS; порядок полей определяет расположение данных. */ +struct ADCREFSEL_BITS { // bits description + /* Битовое поле rsvd1, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:14; // 13:0 reserved + /* Битовое поле REF_SEL, ширина 2 бит; данные REF_SEL. */ + Uint16 REF_SEL:2; // 15:14 Reference select +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; +/* Объединяет несколько представлений ADCREFSEL_REG в одной области памяти. */ +union ADCREFSEL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCREFSEL_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCREFSEL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру ADCOFFTRIM_BITS; порядок полей определяет расположение данных. */ +struct ADCOFFTRIM_BITS{ // bits description + /* Продолжает список аргументов, полей или выражение int16 OFFSET_TRIM:9;; порядок элементов сохраняется. */ + int16 OFFSET_TRIM:9; // 8:0 Offset Trim + /* Битовое поле rsvd1, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:7; // 15:9 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ADCOFFTRIM_REG в одной области памяти. */ +union ADCOFFTRIM_REG{ + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ADCOFFTRIM_BITS bit;; порядок полей определяет расположение данных. */ + struct ADCOFFTRIM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; +/* Описывает структуру ADC_REGS; порядок полей определяет расположение данных. */ +struct ADC_REGS { + /* Объединяет несколько представлений ADCTRL1_REG ADCTRL1; в одной области памяти. */ + union ADCTRL1_REG ADCTRL1; // ADC Control 1 + /* Объединяет несколько представлений ADCTRL2_REG ADCTRL2; в одной области памяти. */ + union ADCTRL2_REG ADCTRL2; // ADC Control 2 + /* Объединяет несколько представлений ADCMAXCONV_REG ADCMAXCONV; в одной области памяти. */ + union ADCMAXCONV_REG ADCMAXCONV; // Max conversions + /* Объединяет несколько представлений ADCCHSELSEQ1_REG ADCCHSELSEQ1; в одной области памяти. */ + union ADCCHSELSEQ1_REG ADCCHSELSEQ1; // Channel select sequencing control 1 + /* Объединяет несколько представлений ADCCHSELSEQ2_REG ADCCHSELSEQ2; в одной области памяти. */ + union ADCCHSELSEQ2_REG ADCCHSELSEQ2; // Channel select sequencing control 2 + /* Объединяет несколько представлений ADCCHSELSEQ3_REG ADCCHSELSEQ3; в одной области памяти. */ + union ADCCHSELSEQ3_REG ADCCHSELSEQ3; // Channel select sequencing control 3 + /* Объединяет несколько представлений ADCCHSELSEQ4_REG ADCCHSELSEQ4; в одной области памяти. */ + union ADCCHSELSEQ4_REG ADCCHSELSEQ4; // Channel select sequencing control 4 + /* Объединяет несколько представлений ADCASEQSR_REG ADCASEQSR; в одной области памяти. */ + union ADCASEQSR_REG ADCASEQSR; // Autosequence status register + /* Объявляет ADCRESULT0 — данные ADCRESULT0. */ + Uint16 ADCRESULT0; // Conversion Result Buffer 0 + /* Объявляет ADCRESULT1 — данные ADCRESULT1. */ + Uint16 ADCRESULT1; // Conversion Result Buffer 1 + /* Объявляет ADCRESULT2 — данные ADCRESULT2. */ + Uint16 ADCRESULT2; // Conversion Result Buffer 2 + /* Объявляет ADCRESULT3 — данные ADCRESULT3. */ + Uint16 ADCRESULT3; // Conversion Result Buffer 3 + /* Объявляет ADCRESULT4 — данные ADCRESULT4. */ + Uint16 ADCRESULT4; // Conversion Result Buffer 4 + /* Объявляет ADCRESULT5 — данные ADCRESULT5. */ + Uint16 ADCRESULT5; // Conversion Result Buffer 5 + /* Объявляет ADCRESULT6 — данные ADCRESULT6. */ + Uint16 ADCRESULT6; // Conversion Result Buffer 6 + /* Объявляет ADCRESULT7 — данные ADCRESULT7. */ + Uint16 ADCRESULT7; // Conversion Result Buffer 7 + /* Объявляет ADCRESULT8 — данные ADCRESULT8. */ + Uint16 ADCRESULT8; // Conversion Result Buffer 8 + /* Объявляет ADCRESULT9 — данные ADCRESULT9. */ + Uint16 ADCRESULT9; // Conversion Result Buffer 9 + /* Объявляет ADCRESULT10 — данные ADCRESULT10. */ + Uint16 ADCRESULT10; // Conversion Result Buffer 10 + /* Объявляет ADCRESULT11 — данные ADCRESULT11. */ + Uint16 ADCRESULT11; // Conversion Result Buffer 11 + /* Объявляет ADCRESULT12 — данные ADCRESULT12. */ + Uint16 ADCRESULT12; // Conversion Result Buffer 12 + /* Объявляет ADCRESULT13 — данные ADCRESULT13. */ + Uint16 ADCRESULT13; // Conversion Result Buffer 13 + /* Объявляет ADCRESULT14 — данные ADCRESULT14. */ + Uint16 ADCRESULT14; // Conversion Result Buffer 14 + /* Объявляет ADCRESULT15 — данные ADCRESULT15. */ + Uint16 ADCRESULT15; // Conversion Result Buffer 15 + /* Объединяет несколько представлений ADCTRL3_REG ADCTRL3; в одной области памяти. */ + union ADCTRL3_REG ADCTRL3; // ADC Control 3 + /* Объединяет несколько представлений ADCST_REG ADCST; в одной области памяти. */ + union ADCST_REG ADCST; // ADC Status Register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; + /* Объединяет несколько представлений ADCREFSEL_REG ADCREFSEL; в одной области памяти. */ + union ADCREFSEL_REG ADCREFSEL; // Reference Select Register + /* Объединяет несколько представлений ADCOFFTRIM_REG ADCOFFTRIM; в одной области памяти. */ + union ADCOFFTRIM_REG ADCOFFTRIM; // Offset Trim Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру ADC_RESULT_MIRROR_REGS; порядок полей определяет расположение данных. */ +struct ADC_RESULT_MIRROR_REGS +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет ADCRESULT0 — данные ADCRESULT0. */ + Uint16 ADCRESULT0; // Conversion Result Buffer 0 + /* Объявляет ADCRESULT1 — данные ADCRESULT1. */ + Uint16 ADCRESULT1; // Conversion Result Buffer 1 + /* Объявляет ADCRESULT2 — данные ADCRESULT2. */ + Uint16 ADCRESULT2; // Conversion Result Buffer 2 + /* Объявляет ADCRESULT3 — данные ADCRESULT3. */ + Uint16 ADCRESULT3; // Conversion Result Buffer 3 + /* Объявляет ADCRESULT4 — данные ADCRESULT4. */ + Uint16 ADCRESULT4; // Conversion Result Buffer 4 + /* Объявляет ADCRESULT5 — данные ADCRESULT5. */ + Uint16 ADCRESULT5; // Conversion Result Buffer 5 + /* Объявляет ADCRESULT6 — данные ADCRESULT6. */ + Uint16 ADCRESULT6; // Conversion Result Buffer 6 + /* Объявляет ADCRESULT7 — данные ADCRESULT7. */ + Uint16 ADCRESULT7; // Conversion Result Buffer 7 + /* Объявляет ADCRESULT8 — данные ADCRESULT8. */ + Uint16 ADCRESULT8; // Conversion Result Buffer 8 + /* Объявляет ADCRESULT9 — данные ADCRESULT9. */ + Uint16 ADCRESULT9; // Conversion Result Buffer 9 + /* Объявляет ADCRESULT10 — данные ADCRESULT10. */ + Uint16 ADCRESULT10; // Conversion Result Buffer 10 + /* Объявляет ADCRESULT11 — данные ADCRESULT11. */ + Uint16 ADCRESULT11; // Conversion Result Buffer 11 + /* Объявляет ADCRESULT12 — данные ADCRESULT12. */ + Uint16 ADCRESULT12; // Conversion Result Buffer 12 + /* Объявляет ADCRESULT13 — данные ADCRESULT13. */ + Uint16 ADCRESULT13; // Conversion Result Buffer 13 + /* Объявляет ADCRESULT14 — данные ADCRESULT14. */ + Uint16 ADCRESULT14; // Conversion Result Buffer 14 + /* Объявляет ADCRESULT15 — данные ADCRESULT15. */ + Uint16 ADCRESULT15; // Conversion Result Buffer 15 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// ADC External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct ADC_REGS AdcRegs;; порядок элементов сохраняется. */ +extern volatile struct ADC_REGS AdcRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ADC_RESULT_MIRROR_REGS AdcMirror;; порядок элементов сохраняется. */ +extern volatile struct ADC_RESULT_MIRROR_REGS AdcMirror; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_ADC_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h new file mode 100644 index 0000000..a3383fc --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_CpuTimers.h @@ -0,0 +1,283 @@ +/* Поставляемое TI описание CpuTimers для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/4 $ +// Checkin $Date: March 20, 2007 15:33:42 $ +//########################################################################### +// +// FILE: DSP2833x_CpuTimers.h +// +// TITLE: DSP2833x CPU 32-bit Timers Register Definitions. +// +// NOTES: CpuTimer1 and CpuTimer2 are reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use these two timers in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +// For this reason, comment out the code to manipulate these two timers +// if using DSP-BIOS or another realtime OS. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_CPU_TIMERS_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_CPU_TIMERS_H +/* Определяет защитный символ или переключатель DSP2833x_CPU_TIMERS_H для последующей компиляции. */ +#define DSP2833x_CPU_TIMERS_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// CPU Timer Register Bit Definitions: +// +// +// TCR: Control register bit definitions: +/* Описывает структуру TCR_BITS; порядок полей определяет расположение данных. */ +struct TCR_BITS { // bits description + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 3:0 reserved + /* Битовое поле TSS, ширина 1 бит; данные TSS. */ + Uint16 TSS:1; // 4 Timer Start/Stop + /* Битовое поле TRB, ширина 1 бит; данные TRB. */ + Uint16 TRB:1; // 5 Timer reload + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 9:6 reserved + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 10 Emulation modes + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 11 + /* Битовое поле rsvd3, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:2; // 12:13 reserved + /* Битовое поле TIE, ширина 1 бит; данные TIE. */ + Uint16 TIE:1; // 14 Output enable + /* Битовое поле TIF, ширина 1 бит; данные TIF. */ + Uint16 TIF:1; // 15 Interrupt flag +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TCR_REG в одной области памяти. */ +union TCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TCR_BITS bit;; порядок полей определяет расположение данных. */ + struct TCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// TPR: Pre-scale low bit definitions: +/* Описывает структуру TPR_BITS; порядок полей определяет расположение данных. */ +struct TPR_BITS { // bits description + /* Битовое поле TDDR, ширина 8 бит; данные TDDR. */ + Uint16 TDDR:8; // 7:0 Divide-down low + /* Битовое поле PSC, ширина 8 бит; данные PSC. */ + Uint16 PSC:8; // 15:8 Prescale counter low +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TPR_REG в одной области памяти. */ +union TPR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TPR_BITS bit;; порядок полей определяет расположение данных. */ + struct TPR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// TPRH: Pre-scale high bit definitions: +/* Описывает структуру TPRH_BITS; порядок полей определяет расположение данных. */ +struct TPRH_BITS { // bits description + /* Битовое поле TDDRH, ширина 8 бит; данные TDDRH. */ + Uint16 TDDRH:8; // 7:0 Divide-down high + /* Битовое поле PSCH, ширина 8 бит; данные PSCH. */ + Uint16 PSCH:8; // 15:8 Prescale counter high +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TPRH_REG в одной области памяти. */ +union TPRH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TPRH_BITS bit;; порядок полей определяет расположение данных. */ + struct TPRH_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// TIM, TIMH: Timer register definitions: +/* Описывает структуру TIM_REG; порядок полей определяет расположение данных. */ +struct TIM_REG { + /* Объявляет LSW — данные LSW. */ + Uint16 LSW; + /* Объявляет MSW — данные MSW. */ + Uint16 MSW; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TIM_GROUP в одной области памяти. */ +union TIM_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру TIM_REG half;; порядок полей определяет расположение данных. */ + struct TIM_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PRD, PRDH: Period register definitions: +/* Описывает структуру PRD_REG; порядок полей определяет расположение данных. */ +struct PRD_REG { + /* Объявляет LSW — данные LSW. */ + Uint16 LSW; + /* Объявляет MSW — данные MSW. */ + Uint16 MSW; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PRD_GROUP в одной области памяти. */ +union PRD_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру PRD_REG half;; порядок полей определяет расположение данных. */ + struct PRD_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// CPU Timer Register File: +// +/* Описывает структуру CPUTIMER_REGS; порядок полей определяет расположение данных. */ +struct CPUTIMER_REGS { + /* Объединяет несколько представлений TIM_GROUP TIM; в одной области памяти. */ + union TIM_GROUP TIM; // Timer counter register + /* Объединяет несколько представлений PRD_GROUP PRD; в одной области памяти. */ + union PRD_GROUP PRD; // Period register + /* Объединяет несколько представлений TCR_REG TCR; в одной области памяти. */ + union TCR_REG TCR; // Timer control register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объединяет несколько представлений TPR_REG TPR; в одной области памяти. */ + union TPR_REG TPR; // Timer pre-scale low + /* Объединяет несколько представлений TPRH_REG TPRH; в одной области памяти. */ + union TPRH_REG TPRH; // Timer pre-scale high +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// CPU Timer Support Variables: +// +/* Описывает структуру CPUTIMER_VARS; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS { + /* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS *RegsAddr;; порядок элементов сохраняется. */ + volatile struct CPUTIMER_REGS *RegsAddr; + /* Объявляет InterruptCount — прерывание число. */ + Uint32 InterruptCount; + /* Объявляет CPUFreqInMHz — данные CPUFreqInMHz. */ + float CPUFreqInMHz; + /* Объявляет PeriodInUSec — период In U Sec. */ + float PeriodInUSec; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// Function prototypes and external definitions: +// +/* Объявляет интерфейс функции InitCpuTimers; реализация вызывается через этот прототип. */ +void InitCpuTimers(void); +/* Объявляет интерфейс функции ConfigCpuTimer; реализация вызывается через этот прототип. */ +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period); + +/* Продолжает список аргументов, полей или выражение extern volatile struct CPUTIMER_REGS CpuTimer0Regs;; порядок элементов сохраняется. */ +extern volatile struct CPUTIMER_REGS CpuTimer0Regs; +/* Продолжает список аргументов, полей или выражение extern struct CPUTIMER_VARS CpuTimer0;; порядок элементов сохраняется. */ +extern struct CPUTIMER_VARS CpuTimer0; + +// CpuTimer 1 and CpuTimer2 are reserved for DSP BIOS & other RTOS. Comment out CpuTimer1 and CpuTimer2 if using DSP BIOS or other RTOS +/* Продолжает список аргументов, полей или выражение extern volatile struct CPUTIMER_REGS CpuTimer1Regs;; порядок элементов сохраняется. */ +extern volatile struct CPUTIMER_REGS CpuTimer1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct CPUTIMER_REGS CpuTimer2Regs;; порядок элементов сохраняется. */ +extern volatile struct CPUTIMER_REGS CpuTimer2Regs; + +/* Продолжает список аргументов, полей или выражение extern struct CPUTIMER_VARS CpuTimer1;; порядок элементов сохраняется. */ +extern struct CPUTIMER_VARS CpuTimer1; +/* Продолжает список аргументов, полей или выражение extern struct CPUTIMER_VARS CpuTimer2;; порядок элементов сохраняется. */ +extern struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// Usefull Timer Operations: +// +// Start Timer: +/* Задаёт StartCpuTimer0 = CpuTimer0Regs.TCR.bit.TSS = 0; Start Cpu таймер 0. */ +#define StartCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 0 + +// Stop Timer: +/* Задаёт StopCpuTimer0 = CpuTimer0Regs.TCR.bit.TSS = 1; Stop Cpu таймер 0. */ +#define StopCpuTimer0() CpuTimer0Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +/* Задаёт ReloadCpuTimer0 = CpuTimer0Regs.TCR.bit.TRB = 1; Reload Cpu таймер 0. */ +#define ReloadCpuTimer0() CpuTimer0Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +/* Задаёт ReadCpuTimer0Counter = CpuTimer0Regs.TIM.all; чтение Cpu таймер 0 счётчик. */ +#define ReadCpuTimer0Counter() CpuTimer0Regs.TIM.all + +// Read 32-Bit Period Value: +/* Задаёт ReadCpuTimer0Period = CpuTimer0Regs.PRD.all; чтение Cpu таймер 0 период. */ +#define ReadCpuTimer0Period() CpuTimer0Regs.PRD.all + +// CpuTimer 1 and CpuTimer2 are reserved for DSP BIOS & other RTOS +// Do not use these two timers if you ever plan on integrating +// DSP-BIOS or another realtime OS. +// +// For this reason, comment out the code to manipulate these two timers +// if using DSP-BIOS or another realtime OS. + +// Start Timer: +/* Задаёт StartCpuTimer1 = CpuTimer1Regs.TCR.bit.TSS = 0; Start Cpu таймер 1. */ +#define StartCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 0 +/* Задаёт StartCpuTimer2 = CpuTimer2Regs.TCR.bit.TSS = 0; Start Cpu таймер 2. */ +#define StartCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 0 + + +// Stop Timer: +/* Задаёт StopCpuTimer1 = CpuTimer1Regs.TCR.bit.TSS = 1; Stop Cpu таймер 1. */ +#define StopCpuTimer1() CpuTimer1Regs.TCR.bit.TSS = 1 +/* Задаёт StopCpuTimer2 = CpuTimer2Regs.TCR.bit.TSS = 1; Stop Cpu таймер 2. */ +#define StopCpuTimer2() CpuTimer2Regs.TCR.bit.TSS = 1 + +// Reload Timer With period Value: +/* Задаёт ReloadCpuTimer1 = CpuTimer1Regs.TCR.bit.TRB = 1; Reload Cpu таймер 1. */ +#define ReloadCpuTimer1() CpuTimer1Regs.TCR.bit.TRB = 1 +/* Задаёт ReloadCpuTimer2 = CpuTimer2Regs.TCR.bit.TRB = 1; Reload Cpu таймер 2. */ +#define ReloadCpuTimer2() CpuTimer2Regs.TCR.bit.TRB = 1 + +// Read 32-Bit Timer Value: +/* Задаёт ReadCpuTimer1Counter = CpuTimer1Regs.TIM.all; чтение Cpu таймер 1 счётчик. */ +#define ReadCpuTimer1Counter() CpuTimer1Regs.TIM.all +/* Задаёт ReadCpuTimer2Counter = CpuTimer2Regs.TIM.all; чтение Cpu таймер 2 счётчик. */ +#define ReadCpuTimer2Counter() CpuTimer2Regs.TIM.all + +// Read 32-Bit Period Value: +/* Задаёт ReadCpuTimer1Period = CpuTimer1Regs.PRD.all; чтение Cpu таймер 1 период. */ +#define ReadCpuTimer1Period() CpuTimer1Regs.PRD.all +/* Задаёт ReadCpuTimer2Period = CpuTimer2Regs.PRD.all; чтение Cpu таймер 2 период. */ +#define ReadCpuTimer2Period() CpuTimer2Regs.PRD.all + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_CPU_TIMERS_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h new file mode 100644 index 0000000..5508e70 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DMA.h @@ -0,0 +1,437 @@ +/* Поставляемое TI описание DMA для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/11 $ +// Checkin $Date: June 23, 2008 11:34:15 $ +//########################################################################### +// +// FILE: DSP2833x_DMA.h +// +// TITLE: DSP2833x DMA Module Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DMA_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DMA_H +/* Определяет защитный символ или переключатель DSP2833x_DMA_H для последующей компиляции. */ +#define DSP2833x_DMA_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Channel MODE register bit definitions: +/* Описывает структуру MODE_BITS; порядок полей определяет расположение данных. */ +struct MODE_BITS { // bits description + /* Битовое поле PERINTSEL, ширина 5 бит; данные PERINTSEL. */ + Uint16 PERINTSEL:5; // 4:0 Peripheral Interrupt and Sync Select Bits (R/W): + // 0 no interrupt + // 1 SEQ1INT & ADCSYNC + // 2 SEQ2INT + // 3 XINT1 + // 4 XINT2 + // 5 XINT3 + // 6 XINT4 + // 7 XINT5 + // 8 XINT6 + // 9 XINT7 + // 10 XINT13 + // 11 TINT0 + // 12 TINT1 + // 13 TINT2 + // 14 MXEVTA & MXSYNCA + // 15 MREVTA & MRSYNCA + // 16 MXEVTB & MXSYNCB + // 17 MREVTB & MRSYNCB + // 18 ePWM1SOCA + // 19 ePWM1SOCB + // 20 ePWM2SOCA + // 21 ePWM2SOCB + // 22 ePWM3SOCA + // 23 ePWM3SOCB + // 24 ePWM4SOCA + // 25 ePWM4SOCB + // 26 ePWM5SOCA + // 27 ePWM5SOCB + // 28 ePWM6SOCA + // 29 ePWM6SOCB + // 30:31 no interrupt + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 6:5 (R=0:0) + /* Битовое поле OVRINTE, ширина 1 бит; данные OVRINTE. */ + Uint16 OVRINTE:1; // 7 Overflow Interrupt Enable (R/W): + // 0 overflow interrupt disabled + // 1 overflow interrupt enabled + /* Битовое поле PERINTE, ширина 1 бит; данные PERINTE. */ + Uint16 PERINTE:1; // 8 Peripheral Interrupt Enable Bit (R/W): + // 0 peripheral interrupt disabled + // 1 peripheral interrupt enabled + /* Битовое поле CHINTMODE, ширина 1 бит; данные CHINTMODE. */ + Uint16 CHINTMODE:1; // 9 Channel Interrupt Mode Bit (R/W): + // 0 generate interrupt at beginning of new transfer + // 1 generate interrupt at end of transfer + /* Битовое поле ONESHOT, ширина 1 бит; данные ONESHOT. */ + Uint16 ONESHOT:1; // 10 One Shot Mode Bit (R/W): + // 0 only interrupt event triggers single burst transfer + // 1 first interrupt triggers burst, continue until transfer count is zero + /* Битовое поле CONTINUOUS, ширина 1 бит; данные CONTINUOUS. */ + Uint16 CONTINUOUS:1; // 11 Continous Mode Bit (R/W): + // 0 stop when transfer count is zero + // 1 re-initialize when transfer count is zero + /* Битовое поле SYNCE, ширина 1 бит; данные SYNCE. */ + Uint16 SYNCE:1; // 12 Sync Enable Bit (R/W): + // 0 ignore selected interrupt sync signal + // 1 enable selected interrupt sync signal + /* Битовое поле SYNCSEL, ширина 1 бит; данные SYNCSEL. */ + Uint16 SYNCSEL:1; // 13 Sync Select Bit (R/W): + // 0 sync signal controls source wrap counter + // 1 sync signal controls destination wrap counter + /* Битовое поле DATASIZE, ширина 1 бит; данные DATASIZE. */ + Uint16 DATASIZE:1; // 14 Data Size Mode Bit (R/W): + // 0 16-bit data transfer size + // 1 32-bit data transfer size + /* Битовое поле CHINTE, ширина 1 бит; данные CHINTE. */ + Uint16 CHINTE:1; // 15 Channel Interrupt Enable Bit (R/W): + // 0 channel interrupt disabled + // 1 channel interrupt enabled +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MODE_REG в одной области памяти. */ +union MODE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MODE_BITS bit;; порядок полей определяет расположение данных. */ + struct MODE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Channel CONTROL register bit definitions: +/* Описывает структуру CONTROL_BITS; порядок полей определяет расположение данных. */ +struct CONTROL_BITS { // bits description + /* Битовое поле RUN, ширина 1 бит; данные RUN. */ + Uint16 RUN:1; // 0 Run Bit (R=0/W=1) + /* Битовое поле HALT, ширина 1 бит; данные HALT. */ + Uint16 HALT:1; // 1 Halt Bit (R=0/W=1) + /* Битовое поле SOFTRESET, ширина 1 бит; данные SOFTRESET. */ + Uint16 SOFTRESET:1; // 2 Soft Reset Bit (R=0/W=1) + /* Битовое поле PERINTFRC, ширина 1 бит; данные PERINTFRC. */ + Uint16 PERINTFRC:1; // 3 Interrupt Force Bit (R=0/W=1) + /* Битовое поле PERINTCLR, ширина 1 бит; данные PERINTCLR. */ + Uint16 PERINTCLR:1; // 4 Interrupt Clear Bit (R=0/W=1) + /* Битовое поле SYNCFRC, ширина 1 бит; данные SYNCFRC. */ + Uint16 SYNCFRC:1; // 5 Sync Force Bit (R=0/W=1) + /* Битовое поле SYNCCLR, ширина 1 бит; данные SYNCCLR. */ + Uint16 SYNCCLR:1; // 6 Sync Clear Bit (R=0/W=1) + /* Битовое поле ERRCLR, ширина 1 бит; данные ERRCLR. */ + Uint16 ERRCLR:1; // 7 Error Clear Bit (R=0/W=1) + /* Битовое поле PERINTFLG, ширина 1 бит; данные PERINTFLG. */ + Uint16 PERINTFLG:1; // 8 Interrupt Flag Bit (R): + // 0 no interrupt pending + // 1 interrupt pending + /* Битовое поле SYNCFLG, ширина 1 бит; данные SYNCFLG. */ + Uint16 SYNCFLG:1; // 9 Sync Flag Bit (R): + // 0 no sync pending + // 1 sync pending + /* Битовое поле SYNCERR, ширина 1 бит; данные SYNCERR. */ + Uint16 SYNCERR:1; // 10 Sync Error Flag Bit (R): + // 0 no sync error + // 1 sync error detected + /* Битовое поле TRANSFERSTS, ширина 1 бит; данные TRANSFERSTS. */ + Uint16 TRANSFERSTS:1; // 11 Transfer Status Bit (R): + // 0 no transfer in progress or pending + // 1 transfer in progress or pending + /* Битовое поле BURSTSTS, ширина 1 бит; данные BURSTSTS. */ + Uint16 BURSTSTS:1; // 12 Burst Status Bit (R): + // 0 no burst in progress or pending + // 1 burst in progress or pending + /* Битовое поле RUNSTS, ширина 1 бит; данные RUNSTS. */ + Uint16 RUNSTS:1; // 13 Run Status Bit (R): + // 0 channel not running or halted + // 1 channel running + /* Битовое поле OVRFLG, ширина 1 бит; данные OVRFLG. */ + Uint16 OVRFLG:1; // 14 Overflow Flag Bit(R) + // 0 no overflow event + // 1 overflow event + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 15 (R=0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений CONTROL_REG в одной области памяти. */ +union CONTROL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CONTROL_BITS bit;; порядок полей определяет расположение данных. */ + struct CONTROL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// DMACTRL register bit definitions: +/* Описывает структуру DMACTRL_BITS; порядок полей определяет расположение данных. */ +struct DMACTRL_BITS { // bits description + /* Битовое поле HARDRESET, ширина 1 бит; данные HARDRESET. */ + Uint16 HARDRESET:1; // 0 Hard Reset Bit (R=0/W=1) + /* Битовое поле PRIORITYRESET, ширина 1 бит; данные PRIORITYRESET. */ + Uint16 PRIORITYRESET:1; // 1 Priority Reset Bit (R=0/W=1) + /* Битовое поле rsvd1, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:14; // 15:2 (R=0:0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DMACTRL_REG в одной области памяти. */ +union DMACTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DMACTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct DMACTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// DEBUGCTRL register bit definitions: +/* Описывает структуру DEBUGCTRL_BITS; порядок полей определяет расположение данных. */ +struct DEBUGCTRL_BITS { // bits description + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; // 14:0 (R=0:0) + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 15 Debug Mode Bit (R/W): + // 0 halt after current read-write operation + // 1 continue running +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DEBUGCTRL_REG в одной области памяти. */ +union DEBUGCTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DEBUGCTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct DEBUGCTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// PRIORITYCTRL1 register bit definitions: +/* Описывает структуру PRIORITYCTRL1_BITS; порядок полей определяет расположение данных. */ +struct PRIORITYCTRL1_BITS { // bits description + /* Битовое поле CH1PRIORITY, ширина 1 бит; 1 приоритет. */ + Uint16 CH1PRIORITY:1; // 0 Ch1 Priority Bit (R/W): + // 0 same priority as all other channels + // 1 highest priority channel + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; // 15:1 (R=0:0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PRIORITYCTRL1_REG в одной области памяти. */ +union PRIORITYCTRL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PRIORITYCTRL1_BITS bit;; порядок полей определяет расположение данных. */ + struct PRIORITYCTRL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// PRIORITYSTAT register bit definitions: +/* Описывает структуру PRIORITYSTAT_BITS; порядок полей определяет расположение данных. */ +struct PRIORITYSTAT_BITS { // bits description + /* Битовое поле ACTIVESTS, ширина 3 бит; данные ACTIVESTS. */ + Uint16 ACTIVESTS:3; // 2:0 Active Channel Status Bits (R): + // 0,0,0 no channel active + // 0,0,1 Ch1 channel active + // 0,1,0 Ch2 channel active + // 0,1,1 Ch3 channel active + // 1,0,0 Ch4 channel active + // 1,0,1 Ch5 channel active + // 1,1,0 Ch6 channel active + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 3 (R=0) + /* Битовое поле ACTIVESTS_SHADOW, ширина 3 бит; данные ACTIVESTS_SHADOW. */ + Uint16 ACTIVESTS_SHADOW:3; // 6:4 Active Channel Status Shadow Bits (R): + // 0,0,0 no channel active and interrupted by Ch1 + // 0,0,1 cannot occur + // 0,1,0 Ch2 was active and interrupted by Ch1 + // 0,1,1 Ch3 was active and interrupted by Ch1 + // 1,0,0 Ch4 was active and interrupted by Ch1 + // 1,0,1 Ch5 was active and interrupted by Ch1 + // 1,1,0 Ch6 was active and interrupted by Ch1 + /* Битовое поле rsvd2, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:9; // 15:7 (R=0:0) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PRIORITYSTAT_REG в одной области памяти. */ +union PRIORITYSTAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PRIORITYSTAT_BITS bit;; порядок полей определяет расположение данных. */ + struct PRIORITYSTAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Burst Size +/* Описывает структуру BURST_SIZE_BITS; порядок полей определяет расположение данных. */ +struct BURST_SIZE_BITS { // bits description + /* Битовое поле BURSTSIZE, ширина 5 бит; данные BURSTSIZE. */ + Uint16 BURSTSIZE:5; // 4:0 Burst transfer size + /* Битовое поле rsvd1, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений BURST_SIZE_REG в одной области памяти. */ +union BURST_SIZE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру BURST_SIZE_BITS bit;; порядок полей определяет расположение данных. */ + struct BURST_SIZE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Burst Count +/* Описывает структуру BURST_COUNT_BITS; порядок полей определяет расположение данных. */ +struct BURST_COUNT_BITS { // bits description + /* Битовое поле BURSTCOUNT, ширина 5 бит; данные BURSTCOUNT. */ + Uint16 BURSTCOUNT:5; // 4:0 Burst transfer size + /* Битовое поле rsvd1, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений BURST_COUNT_REG в одной области памяти. */ +union BURST_COUNT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру BURST_COUNT_BITS bit;; порядок полей определяет расположение данных. */ + struct BURST_COUNT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//---------------------------------------------------- +// DMA Channel Registers: +/* Описывает структуру CH_REGS; порядок полей определяет расположение данных. */ +struct CH_REGS { + /* Объединяет несколько представлений MODE_REG MODE; в одной области памяти. */ + union MODE_REG MODE; // Mode Register + /* Объединяет несколько представлений CONTROL_REG CONTROL; в одной области памяти. */ + union CONTROL_REG CONTROL; // Control Register + + /* Объединяет несколько представлений BURST_SIZE_REG BURST_SIZE; в одной области памяти. */ + union BURST_SIZE_REG BURST_SIZE; // Burst Size Register + /* Объединяет несколько представлений BURST_COUNT_REG BURST_COUNT; в одной области памяти. */ + union BURST_COUNT_REG BURST_COUNT; // Burst Count Register + /* Продолжает список аргументов, полей или выражение int16 SRC_BURST_STEP;; порядок элементов сохраняется. */ + int16 SRC_BURST_STEP; // Source Burst Step Register + /* Продолжает список аргументов, полей или выражение int16 DST_BURST_STEP;; порядок элементов сохраняется. */ + int16 DST_BURST_STEP; // Destination Burst Step Register + + /* Объявляет TRANSFER_SIZE — TRANSFER размер. */ + Uint16 TRANSFER_SIZE; // Transfer Size Register + /* Объявляет TRANSFER_COUNT — TRANSFER число. */ + Uint16 TRANSFER_COUNT; // Transfer Count Register + /* Продолжает список аргументов, полей или выражение int16 SRC_TRANSFER_STEP;; порядок элементов сохраняется. */ + int16 SRC_TRANSFER_STEP; // Source Transfer Step Register + /* Продолжает список аргументов, полей или выражение int16 DST_TRANSFER_STEP;; порядок элементов сохраняется. */ + int16 DST_TRANSFER_STEP; // Destination Transfer Step Register + + /* Объявляет SRC_WRAP_SIZE — SRC WRAP размер. */ + Uint16 SRC_WRAP_SIZE; // Source Wrap Size Register + /* Объявляет SRC_WRAP_COUNT — SRC WRAP число. */ + Uint16 SRC_WRAP_COUNT; // Source Wrap Count Register + /* Продолжает список аргументов, полей или выражение int16 SRC_WRAP_STEP;; порядок элементов сохраняется. */ + int16 SRC_WRAP_STEP; // Source Wrap Step Register + + /* Объявляет DST_WRAP_SIZE — DST WRAP размер. */ + Uint16 DST_WRAP_SIZE; // Destination Wrap Size Register + /* Объявляет DST_WRAP_COUNT — DST WRAP число. */ + Uint16 DST_WRAP_COUNT; // Destination Wrap Count Register + /* Продолжает список аргументов, полей или выражение int16 DST_WRAP_STEP;; порядок элементов сохраняется. */ + int16 DST_WRAP_STEP; // Destination Wrap Step Register + + /* Объявляет SRC_BEG_ADDR_SHADOW — данные SRC_BEG_ADDR_SHADOW. */ + Uint32 SRC_BEG_ADDR_SHADOW; // Source Begin Address Shadow Register + /* Объявляет SRC_ADDR_SHADOW — данные SRC_ADDR_SHADOW. */ + Uint32 SRC_ADDR_SHADOW; // Source Address Shadow Register + /* Объявляет SRC_BEG_ADDR_ACTIVE — данные SRC_BEG_ADDR_ACTIVE. */ + Uint32 SRC_BEG_ADDR_ACTIVE; // Source Begin Address Active Register + /* Объявляет SRC_ADDR_ACTIVE — данные SRC_ADDR_ACTIVE. */ + Uint32 SRC_ADDR_ACTIVE; // Source Address Active Register + + /* Объявляет DST_BEG_ADDR_SHADOW — данные DST_BEG_ADDR_SHADOW. */ + Uint32 DST_BEG_ADDR_SHADOW; // Destination Begin Address Shadow Register + /* Объявляет DST_ADDR_SHADOW — данные DST_ADDR_SHADOW. */ + Uint32 DST_ADDR_SHADOW; // Destination Address Shadow Register + /* Объявляет DST_BEG_ADDR_ACTIVE — данные DST_BEG_ADDR_ACTIVE. */ + Uint32 DST_BEG_ADDR_ACTIVE; // Destination Begin Address Active Register + /* Объявляет DST_ADDR_ACTIVE — данные DST_ADDR_ACTIVE. */ + Uint32 DST_ADDR_ACTIVE; // Destination Address Active Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// DMA Registers: +/* Описывает структуру DMA_REGS; порядок полей определяет расположение данных. */ +struct DMA_REGS { + /* Объединяет несколько представлений DMACTRL_REG DMACTRL; в одной области памяти. */ + union DMACTRL_REG DMACTRL; // DMA Control Register + /* Объединяет несколько представлений DEBUGCTRL_REG DEBUGCTRL; в одной области памяти. */ + union DEBUGCTRL_REG DEBUGCTRL; // Debug Control Register + /* Объявляет rsvd0 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd0; // reserved + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // + /* Объединяет несколько представлений PRIORITYCTRL1_REG PRIORITYCTRL1; в одной области памяти. */ + union PRIORITYCTRL1_REG PRIORITYCTRL1; // Priority Control 1 Register + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // + /* Объединяет несколько представлений PRIORITYSTAT_REG PRIORITYSTAT; в одной области памяти. */ + union PRIORITYSTAT_REG PRIORITYSTAT; // Priority Status Register + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3[25]; // + /* Описывает структуру CH_REGS CH1;; порядок полей определяет расположение данных. */ + struct CH_REGS CH1; // DMA Channel 1 Registers + /* Описывает структуру CH_REGS CH2;; порядок полей определяет расположение данных. */ + struct CH_REGS CH2; // DMA Channel 2 Registers + /* Описывает структуру CH_REGS CH3;; порядок полей определяет расположение данных. */ + struct CH_REGS CH3; // DMA Channel 3 Registers + /* Описывает структуру CH_REGS CH4;; порядок полей определяет расположение данных. */ + struct CH_REGS CH4; // DMA Channel 4 Registers + /* Описывает структуру CH_REGS CH5;; порядок полей определяет расположение данных. */ + struct CH_REGS CH5; // DMA Channel 5 Registers + /* Описывает структуру CH_REGS CH6;; порядок полей определяет расположение данных. */ + struct CH_REGS CH6; // DMA Channel 6 Registers +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct DMA_REGS DmaRegs;; порядок элементов сохраняется. */ +extern volatile struct DMA_REGS DmaRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DMA_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h new file mode 100644 index 0000000..b821aa7 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_DevEmu.h @@ -0,0 +1,154 @@ +/* Поставляемое TI описание DevEmu для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: June 2, 2008 11:12:30 $ +//########################################################################### +// +// FILE: DSP2833x_DevEmu.h +// +// TITLE: DSP2833x Device Emulation Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DEV_EMU_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DEV_EMU_H +/* Определяет защитный символ или переключатель DSP2833x_DEV_EMU_H для последующей компиляции. */ +#define DSP2833x_DEV_EMU_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// Device Emulation Register Bit Definitions: +// +// Device Configuration Register Bit Definitions +/* Описывает структуру DEVICECNF_BITS; порядок полей определяет расположение данных. */ +struct DEVICECNF_BITS { // bits description + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 2:0 reserved + /* Битовое поле VMAPS, ширина 1 бит; данные VMAPS. */ + Uint16 VMAPS:1; // 3 VMAP Status + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 4 reserved + /* Битовое поле XRSn, ширина 1 бит; данные XRSn. */ + Uint16 XRSn:1; // 5 XRSn Signal Status + /* Битовое поле rsvd3, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:10; // 15:6 + /* Битовое поле rsvd4, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4:3; // 18:16 + /* Битовое поле ENPROT, ширина 1 бит; данные ENPROT. */ + Uint16 ENPROT:1; // 19 Enable/Disable pipeline protection + /* Битовое поле MONPRIV, ширина 1 бит; данные MONPRIV. */ + Uint16 MONPRIV:1; // 20 MONPRIV enable bit + /* Битовое поле rsvd5, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5:1; // 21 reserved + /* Битовое поле EMU0SEL, ширина 2 бит; данные EMU0SEL. */ + Uint16 EMU0SEL:2; // 23,22 EMU0 Mux select + /* Битовое поле EMU1SEL, ширина 2 бит; данные EMU1SEL. */ + Uint16 EMU1SEL:2; // 25,24 EMU1 Mux select + /* Битовое поле MCBSPCON, ширина 1 бит; данные MCBSPCON. */ + Uint16 MCBSPCON:1; // 26 McBSP-B to EMU0/EMU1 pins control + /* Битовое поле rsvd6, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd6:5; // 31:27 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DEVICECNF_REG в одной области памяти. */ +union DEVICECNF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру DEVICECNF_BITS bit;; порядок полей определяет расположение данных. */ + struct DEVICECNF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// CLASSID +/* Описывает структуру CLASSID_BITS; порядок полей определяет расположение данных. */ +struct CLASSID_BITS { // bits description + /* Битовое поле CLASSNO, ширина 8 бит; данные CLASSNO. */ + Uint16 CLASSNO:8; // 7:0 Class Number + /* Битовое поле PARTTYPE, ширина 8 бит; данные PARTTYPE. */ + Uint16 PARTTYPE:8; // 15:8 Part Type +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений CLASSID_REG в одной области памяти. */ +union CLASSID_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CLASSID_BITS bit;; порядок полей определяет расположение данных. */ + struct CLASSID_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру DEV_EMU_REGS; порядок полей определяет расположение данных. */ +struct DEV_EMU_REGS { + /* Объединяет несколько представлений DEVICECNF_REG DEVICECNF; в одной области памяти. */ + union DEVICECNF_REG DEVICECNF; // device configuration + /* Объединяет несколько представлений CLASSID_REG CLASSID; в одной области памяти. */ + union CLASSID_REG CLASSID; // Class ID + /* Объявляет REVID — данные REVID. */ + Uint16 REVID; // Device ID + /* Объявляет PROTSTART — данные PROTSTART. */ + Uint16 PROTSTART; // Write-Read protection start + /* Объявляет PROTRANGE — данные PROTRANGE. */ + Uint16 PROTRANGE; // Write-Read protection range + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[202]; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PARTID +/* Описывает структуру PARTID_BITS; порядок полей определяет расположение данных. */ +struct PARTID_BITS { // bits description + /* Битовое поле PARTNO, ширина 8 бит; данные PARTNO. */ + Uint16 PARTNO:8; // 7:0 Part Number + /* Битовое поле PARTTYPE, ширина 8 бит; данные PARTTYPE. */ + Uint16 PARTTYPE:8; // 15:8 Part Type +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PARTID_REG в одной области памяти. */ +union PARTID_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PARTID_BITS bit;; порядок полей определяет расположение данных. */ + struct PARTID_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру PARTID_REGS; порядок полей определяет расположение данных. */ +struct PARTID_REGS { + /* Объединяет несколько представлений PARTID_REG PARTID; в одной области памяти. */ + union PARTID_REG PARTID; // Part ID +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//--------------------------------------------------------------------------- +// Device Emulation Register References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct DEV_EMU_REGS DevEmuRegs;; порядок элементов сохраняется. */ +extern volatile struct DEV_EMU_REGS DevEmuRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct PARTID_REGS PartIdRegs;; порядок элементов сохраняется. */ +extern volatile struct PARTID_REGS PartIdRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DEV_EMU_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h new file mode 100644 index 0000000..138d251 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Device.h @@ -0,0 +1,655 @@ +/* Поставляемое TI описание Device для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/5 $ +// Checkin $Date: January 22, 2008 16:55:35 $ +//########################################################################### +// +// FILE: DSP2833x_Device.h +// +// TITLE: DSP2833x Device Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_DEVICE_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_DEVICE_H +/* Определяет защитный символ или переключатель DSP2833x_DEVICE_H для последующей компиляции. */ +#define DSP2833x_DEVICE_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +/* Задаёт TARGET = 1; данные TARGET. */ +#define TARGET 1 +//--------------------------------------------------------------------------- +// User To Select Target Device: + +/* Задаёт DSP28_28335 = TARGET; данные DSP28_28335. */ +#define DSP28_28335 TARGET // Selects '28335/'28235 +/* Задаёт DSP28_28334 = 0; данные DSP28_28334. */ +#define DSP28_28334 0 // Selects '28334/'28234 +/* Задаёт DSP28_28332 = 0; данные DSP28_28332. */ +#define DSP28_28332 0 // Selects '28332/'28232 + + +//--------------------------------------------------------------------------- +// Common CPU Definitions: +// + +/* Продолжает список аргументов, полей или выражение extern cregister volatile unsigned int IFR;; порядок элементов сохраняется. */ +extern cregister volatile unsigned int IFR; +/* Продолжает список аргументов, полей или выражение extern cregister volatile unsigned int IER;; порядок элементов сохраняется. */ +extern cregister volatile unsigned int IER; + +/* Задаёт EINT = asm(" clrc INTM"); разрешение маскируемых прерываний ядра. */ +#define EINT asm(" clrc INTM") +/* Задаёт DINT = asm(" setc INTM"); запрет маскируемых прерываний ядра. */ +#define DINT asm(" setc INTM") +/* Задаёт ERTM = asm(" clrc DBGM"); данные ERTM. */ +#define ERTM asm(" clrc DBGM") +/* Задаёт DRTM = asm(" setc DBGM"); данные DRTM. */ +#define DRTM asm(" setc DBGM") +/* Задаёт EALLOW = asm(" EALLOW"); разрешение записи в защищённые регистры периферии. */ +#define EALLOW asm(" EALLOW") +/* Задаёт EDIS = asm(" EDIS"); закрытие доступа к защищённым регистрам периферии. */ +#define EDIS asm(" EDIS") +/* Задаёт ESTOP0 = asm(" ESTOP0"); данные ESTOP0. */ +#define ESTOP0 asm(" ESTOP0") + +/* Задаёт M_INT1 = 0x0001; данные M_INT1. */ +#define M_INT1 0x0001 +/* Задаёт M_INT2 = 0x0002; данные M_INT2. */ +#define M_INT2 0x0002 +/* Задаёт M_INT3 = 0x0004; данные M_INT3. */ +#define M_INT3 0x0004 +/* Задаёт M_INT4 = 0x0008; данные M_INT4. */ +#define M_INT4 0x0008 +/* Задаёт M_INT5 = 0x0010; данные M_INT5. */ +#define M_INT5 0x0010 +/* Задаёт M_INT6 = 0x0020; данные M_INT6. */ +#define M_INT6 0x0020 +/* Задаёт M_INT7 = 0x0040; данные M_INT7. */ +#define M_INT7 0x0040 +/* Задаёт M_INT8 = 0x0080; данные M_INT8. */ +#define M_INT8 0x0080 +/* Задаёт M_INT9 = 0x0100; данные M_INT9. */ +#define M_INT9 0x0100 +/* Задаёт M_INT10 = 0x0200; данные M_INT10. */ +#define M_INT10 0x0200 +/* Задаёт M_INT11 = 0x0400; данные M_INT11. */ +#define M_INT11 0x0400 +/* Задаёт M_INT12 = 0x0800; данные M_INT12. */ +#define M_INT12 0x0800 +/* Задаёт M_INT13 = 0x1000; данные M_INT13. */ +#define M_INT13 0x1000 +/* Задаёт M_INT14 = 0x2000; данные M_INT14. */ +#define M_INT14 0x2000 +/* Задаёт M_DLOG = 0x4000; данные M_DLOG. */ +#define M_DLOG 0x4000 +/* Задаёт M_RTOS = 0x8000; данные M_RTOS. */ +#define M_RTOS 0x8000 + +/* Задаёт BIT0 = 0x0001; данные BIT0. */ +#define BIT0 0x0001 +/* Задаёт BIT1 = 0x0002; данные BIT1. */ +#define BIT1 0x0002 +/* Задаёт BIT2 = 0x0004; данные BIT2. */ +#define BIT2 0x0004 +/* Задаёт BIT3 = 0x0008; данные BIT3. */ +#define BIT3 0x0008 +/* Задаёт BIT4 = 0x0010; данные BIT4. */ +#define BIT4 0x0010 +/* Задаёт BIT5 = 0x0020; данные BIT5. */ +#define BIT5 0x0020 +/* Задаёт BIT6 = 0x0040; данные BIT6. */ +#define BIT6 0x0040 +/* Задаёт BIT7 = 0x0080; данные BIT7. */ +#define BIT7 0x0080 +/* Задаёт BIT8 = 0x0100; данные BIT8. */ +#define BIT8 0x0100 +/* Задаёт BIT9 = 0x0200; данные BIT9. */ +#define BIT9 0x0200 +/* Задаёт BIT10 = 0x0400; данные BIT10. */ +#define BIT10 0x0400 +/* Задаёт BIT11 = 0x0800; данные BIT11. */ +#define BIT11 0x0800 +/* Задаёт BIT12 = 0x1000; данные BIT12. */ +#define BIT12 0x1000 +/* Задаёт BIT13 = 0x2000; данные BIT13. */ +#define BIT13 0x2000 +/* Задаёт BIT14 = 0x4000; данные BIT14. */ +#define BIT14 0x4000 +/* Задаёт BIT15 = 0x8000; данные BIT15. */ +#define BIT15 0x8000 + + + +//--------------------------------------------------------------------------- +// For Portability, User Is Recommended To Use Following Data Type Size +// Definitions For 16-bit and 32-Bit Signed/Unsigned Integers: +// + +/* Начинает условие: DSP28_DATA_TYPES ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP28_DATA_TYPES +/* Определяет защитный символ или переключатель DSP28_DATA_TYPES для последующей компиляции. */ +#define DSP28_DATA_TYPES +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef int int16; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef long int32; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef long long int64; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef unsigned int Uint16; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef unsigned long Uint32; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef unsigned long long Uint64; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef float float32; +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef long double float64; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef union +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле bit0, ширина 1 бит; бит 0. */ + unsigned int bit0: 1; + /* Битовое поле bit1, ширина 1 бит; бит 1. */ + unsigned int bit1: 1; + /* Битовое поле bit2, ширина 1 бит; бит 2. */ + unsigned int bit2: 1; + /* Битовое поле bit3, ширина 1 бит; бит 3. */ + unsigned int bit3: 1; + /* Битовое поле bit4, ширина 1 бит; бит 4. */ + unsigned int bit4: 1; + /* Битовое поле bit5, ширина 1 бит; бит 5. */ + unsigned int bit5: 1; + /* Битовое поле bit6, ширина 1 бит; бит 6. */ + unsigned int bit6: 1; + /* Битовое поле bit7, ширина 1 бит; бит 7. */ + unsigned int bit7: 1; + + /* Продолжает список аргументов, полей или выражение } bit;; порядок элементов сохраняется. */ + } bit; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле quad_0, ширина 4 бит; данные quad_0. */ + unsigned int quad_0 :4; + /* Битовое поле quad_1, ширина 4 бит; данные quad_1. */ + unsigned int quad_1 :4; + + /* Продолжает список аргументов, полей или выражение } qua;; порядок элементов сохраняется. */ + } qua; + + /* Продолжает список аргументов, полей или выражение unsigned short all;; порядок элементов сохраняется. */ + unsigned short all; + +/* Продолжает список аргументов, полей или выражение } BAITE;; порядок элементов сохраняется. */ +} BAITE; + +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef union +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле bit0, ширина 1 бит; бит 0. */ + unsigned int bit0: 1; + /* Битовое поле bit1, ширина 1 бит; бит 1. */ + unsigned int bit1: 1; + /* Битовое поле bit2, ширина 1 бит; бит 2. */ + unsigned int bit2: 1; + /* Битовое поле bit3, ширина 1 бит; бит 3. */ + unsigned int bit3: 1; + /* Битовое поле bit4, ширина 1 бит; бит 4. */ + unsigned int bit4: 1; + /* Битовое поле bit5, ширина 1 бит; бит 5. */ + unsigned int bit5: 1; + /* Битовое поле bit6, ширина 1 бит; бит 6. */ + unsigned int bit6: 1; + /* Битовое поле bit7, ширина 1 бит; бит 7. */ + unsigned int bit7: 1; + /* Битовое поле bit8, ширина 1 бит; бит 8. */ + unsigned int bit8: 1; + /* Битовое поле bit9, ширина 1 бит; бит 9. */ + unsigned int bit9: 1; + /* Битовое поле bitA, ширина 1 бит; бит A. */ + unsigned int bitA: 1; + /* Битовое поле bitB, ширина 1 бит; бит B. */ + unsigned int bitB: 1; + /* Битовое поле bitC, ширина 1 бит; бит C. */ + unsigned int bitC: 1; + /* Битовое поле bitD, ширина 1 бит; бит D. */ + unsigned int bitD: 1; + /* Битовое поле bitE, ширина 1 бит; бит E. */ + unsigned int bitE: 1; + /* Битовое поле bitF, ширина 1 бит; бит F. */ + unsigned int bitF: 1; + + /* Продолжает список аргументов, полей или выражение } bit;; порядок элементов сохраняется. */ + } bit; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле quad_0, ширина 4 бит; данные quad_0. */ + unsigned int quad_0 :4; + /* Битовое поле quad_1, ширина 4 бит; данные quad_1. */ + unsigned int quad_1 :4; + /* Битовое поле quad_2, ширина 4 бит; данные quad_2. */ + unsigned int quad_2 :4; + /* Битовое поле quad_3, ширина 4 бит; данные quad_3. */ + unsigned int quad_3 :4; + + /* Продолжает список аргументов, полей или выражение } qua;; порядок элементов сохраняется. */ + } qua; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле byte_0, ширина 8 бит; данные byte_0. */ + unsigned int byte_0 :8; + /* Битовое поле byte_1, ширина 8 бит; данные byte_1. */ + unsigned int byte_1 :8; + + /* Продолжает список аргументов, полей или выражение } byt;; порядок элементов сохраняется. */ + } byt; + + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + int all; + +/* Продолжает список аргументов, полей или выражение } WORDE;; порядок элементов сохраняется. */ +} WORDE; + +/* Начинает объявление типа, используемого структурами и интерфейсами этого модуля. */ +typedef union +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле bit00, ширина 1 бит; бит 00. */ + unsigned int bit00: 1; + /* Битовое поле bit01, ширина 1 бит; бит 01. */ + unsigned int bit01: 1; + /* Битовое поле bit02, ширина 1 бит; бит 02. */ + unsigned int bit02: 1; + /* Битовое поле bit03, ширина 1 бит; бит 03. */ + unsigned int bit03: 1; + /* Битовое поле bit04, ширина 1 бит; бит 04. */ + unsigned int bit04: 1; + /* Битовое поле bit05, ширина 1 бит; бит 05. */ + unsigned int bit05: 1; + /* Битовое поле bit06, ширина 1 бит; бит 06. */ + unsigned int bit06: 1; + /* Битовое поле bit07, ширина 1 бит; бит 07. */ + unsigned int bit07: 1; + /* Битовое поле bit08, ширина 1 бит; бит 08. */ + unsigned int bit08: 1; + /* Битовое поле bit09, ширина 1 бит; бит 09. */ + unsigned int bit09: 1; + /* Битовое поле bit0A, ширина 1 бит; бит 0 A. */ + unsigned int bit0A: 1; + /* Битовое поле bit0B, ширина 1 бит; бит 0 B. */ + unsigned int bit0B: 1; + /* Битовое поле bit0C, ширина 1 бит; бит 0 C. */ + unsigned int bit0C: 1; + /* Битовое поле bit0D, ширина 1 бит; бит 0 D. */ + unsigned int bit0D: 1; + /* Битовое поле bit0E, ширина 1 бит; бит 0 E. */ + unsigned int bit0E: 1; + /* Битовое поле bit0F, ширина 1 бит; бит 0 F. */ + unsigned int bit0F: 1; + /* Битовое поле bit10, ширина 1 бит; бит 10. */ + unsigned int bit10: 1; + /* Битовое поле bit11, ширина 1 бит; бит 11. */ + unsigned int bit11: 1; + /* Битовое поле bit12, ширина 1 бит; бит 12. */ + unsigned int bit12: 1; + /* Битовое поле bit13, ширина 1 бит; бит 13. */ + unsigned int bit13: 1; + /* Битовое поле bit14, ширина 1 бит; бит 14. */ + unsigned int bit14: 1; + /* Битовое поле bit15, ширина 1 бит; бит 15. */ + unsigned int bit15: 1; + /* Битовое поле bit16, ширина 1 бит; бит 16. */ + unsigned int bit16: 1; + /* Битовое поле bit17, ширина 1 бит; бит 17. */ + unsigned int bit17: 1; + /* Битовое поле bit18, ширина 1 бит; бит 18. */ + unsigned int bit18: 1; + /* Битовое поле bit19, ширина 1 бит; бит 19. */ + unsigned int bit19: 1; + /* Битовое поле bit1A, ширина 1 бит; бит 1 A. */ + unsigned int bit1A: 1; + /* Битовое поле bit1B, ширина 1 бит; бит 1 B. */ + unsigned int bit1B: 1; + /* Битовое поле bit1C, ширина 1 бит; бит 1 C. */ + unsigned int bit1C: 1; + /* Битовое поле bit1D, ширина 1 бит; бит 1 D. */ + unsigned int bit1D: 1; + /* Битовое поле bit1E, ширина 1 бит; бит 1 E. */ + unsigned int bit1E: 1; + /* Битовое поле bit1F, ширина 1 бит; бит 1 F. */ + unsigned int bit1F: 1; + + /* Продолжает список аргументов, полей или выражение } bit;; порядок элементов сохраняется. */ + } bit; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле quad_0, ширина 4 бит; данные quad_0. */ + unsigned int quad_0 :4; + /* Битовое поле quad_1, ширина 4 бит; данные quad_1. */ + unsigned int quad_1 :4; + /* Битовое поле quad_2, ширина 4 бит; данные quad_2. */ + unsigned int quad_2 :4; + /* Битовое поле quad_3, ширина 4 бит; данные quad_3. */ + unsigned int quad_3 :4; + /* Битовое поле quad_4, ширина 4 бит; данные quad_4. */ + unsigned int quad_4 :4; + /* Битовое поле quad_5, ширина 4 бит; данные quad_5. */ + unsigned int quad_5 :4; + /* Битовое поле quad_6, ширина 4 бит; данные quad_6. */ + unsigned int quad_6 :4; + /* Битовое поле quad_7, ширина 4 бит; данные quad_7. */ + unsigned int quad_7 :4; + + /* Продолжает список аргументов, полей или выражение } qua;; порядок элементов сохраняется. */ + } qua; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле byte_0, ширина 8 бит; данные byte_0. */ + unsigned int byte_0 :8; + /* Битовое поле byte_1, ширина 8 бит; данные byte_1. */ + unsigned int byte_1 :8; + /* Битовое поле byte_2, ширина 8 бит; данные byte_2. */ + unsigned int byte_2 :8; + /* Битовое поле byte_3, ширина 8 бит; данные byte_3. */ + unsigned int byte_3 :8; + + /* Продолжает список аргументов, полей или выражение } byt;; порядок элементов сохраняется. */ + } byt; + + /* Продолжает список аргументов, полей или выражение struct; порядок элементов сохраняется. */ + struct + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Битовое поле word_0, ширина 16 бит; слово 0. */ + unsigned int word_0 :16; + /* Битовое поле word_1, ширина 16 бит; слово 1. */ + unsigned int word_1 :16; + + /* Продолжает список аргументов, полей или выражение } wrd;; порядок элементов сохраняется. */ + } wrd; + + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + unsigned long all; + +/* Продолжает список аргументов, полей или выражение } LONGE;; порядок элементов сохраняется. */ +} LONGE; + +/* Задаёт XCLKIN = 30000000; данные XCLKIN. */ +#define XCLKIN 30000000 // external oscillator frequency +/* Объявляет SYSCLKOUT — данные SYSCLKOUT; LSPCLK — данные LSPCLK; HSPCLK — данные HSPCLK. Память определена в другом модуле. */ +extern long SYSCLKOUT, LSPCLK, HSPCLK; + +/* Задаёт CLKMULT = 2L; данные CLKMULT. */ +#define CLKMULT 2L // 1 to 5 + +/* Задаёт LOWORD = int)( (long int)(l) &0xFFFF)); данные LOWORD. */ +#define LOWORD(l)((short int)( (long int)(l) &0xFFFF)) +/* Задаёт HIWORD = int)(((long int)(l)>>16)&0xFFFF)); данные HIWORD. */ +#define HIWORD(l)((short int)(((long int)(l)>>16)&0xFFFF)) + +/* Задаёт LOBYTE = (short int)(w) &0xFF)); данные LOBYTE. */ +#define LOBYTE(w)((char)( (short int)(w) &0xFF)) +/* Задаёт HIBYTE = int)(w)>>8)&0xFF)); данные HIBYTE. */ +#define HIBYTE(w)((char)(((short int)(w)>>8)&0xFF)) + +/* Задаёт BYTE3 = int)(l)>>24)&0xFF)); данные BYTE3. */ +#define BYTE3(l)((char)(((long int)(l)>>24)&0xFF)) +/* Задаёт BYTE2 = int)(l)>>16)&0xFF)); данные BYTE2. */ +#define BYTE2(l)((char)(((long int)(l)>>16)&0xFF)) +/* Задаёт BYTE1 = int)(l)>> 8)&0xFF)); данные BYTE1. */ +#define BYTE1(l)((char)(((long int)(l)>> 8)&0xFF)) +/* Задаёт BYTE0 = (long int)(l) &0xFF)); данные BYTE0. */ +#define BYTE0(l)((char)( (long int)(l) &0xFF)) + +//--------------------------------------------------------------------------- +// Include All Peripheral Header Files: +// +/* Подключает "DSP2833x_Adc.h": поставляемое TI описание Adc для семейства C2833x. */ +#include "DSP2833x_Adc.h" // ADC Registers +/* Подключает "DSP2833x_DevEmu.h": поставляемое TI описание DevEmu для семейства C2833x. */ +#include "DSP2833x_DevEmu.h" // Device Emulation Registers +/* Подключает "DSP2833x_CpuTimers.h": поставляемое TI описание CpuTimers для семейства C2833x. */ +#include "DSP2833x_CpuTimers.h" // 32-bit CPU Timers +/* Подключает "DSP2833x_ECan.h": поставляемое TI описание ECan для семейства C2833x. */ +#include "DSP2833x_ECan.h" // Enhanced eCAN Registers +/* Подключает "DSP2833x_ECap.h": поставляемое TI описание ECap для семейства C2833x. */ +#include "DSP2833x_ECap.h" // Enhanced Capture +/* Подключает "DSP2833x_DMA.h": поставляемое TI описание DMA для семейства C2833x. */ +#include "DSP2833x_DMA.h" // DMA Registers +/* Подключает "DSP2833x_EPwm.h": поставляемое TI описание EPwm для семейства C2833x. */ +#include "DSP2833x_EPwm.h" // Enhanced PWM +/* Подключает "DSP2833x_EQep.h": поставляемое TI описание EQep для семейства C2833x. */ +#include "DSP2833x_EQep.h" // Enhanced QEP +/* Подключает "DSP2833x_Gpio.h": поставляемое TI описание Gpio для семейства C2833x. */ +#include "DSP2833x_Gpio.h" // General Purpose I/O Registers +/* Подключает "DSP2833x_I2c.h": поставляемое TI описание I2c для семейства C2833x. */ +#include "DSP2833x_I2c.h" // I2C Registers +/* Подключает "DSP2833x_McBSP.h": поставляемое TI описание McBSP для семейства C2833x. */ +#include "DSP2833x_McBSP.h" // McBSP +/* Подключает "DSP2833x_PieCtrl.h": поставляемое TI описание PieCtrl для семейства C2833x. */ +#include "DSP2833x_PieCtrl.h" // PIE Control Registers +/* Подключает "DSP2833x_PieVect.h": поставляемое TI описание PieVect для семейства C2833x. */ +#include "DSP2833x_PieVect.h" // PIE Vector Table +/* Подключает "DSP2833x_Spi.h": поставляемое TI описание Spi для семейства C2833x. */ +#include "DSP2833x_Spi.h" // SPI Registers +/* Подключает "DSP2833x_Sci.h": поставляемое TI описание Sci для семейства C2833x. */ +#include "DSP2833x_Sci.h" // SCI Registers +/* Подключает "DSP2833x_SysCtrl.h": поставляемое TI описание SysCtrl для семейства C2833x. */ +#include "DSP2833x_SysCtrl.h" // System Control/Power Modes +/* Подключает "DSP2833x_XIntrupt.h": поставляемое TI описание XIntrupt для семейства C2833x. */ +#include "DSP2833x_XIntrupt.h" // External Interrupts +/* Подключает "DSP2833x_Xintf.h": поставляемое TI описание Xintf для семейства C2833x. */ +#include "DSP2833x_Xintf.h" // XINTF External Interface + +/* Подключает "DSP2833x_GlobalPrototypes.h": поставляемое TI описание GlobalPrototypes для семейства C2833x. */ +#include "DSP2833x_GlobalPrototypes.h" // Prototypes for global functions within the + +/* Условие компиляции DSP28_28335: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28335 +/* Задаёт DSP28_EPWM1 = 1; данные DSP28_EPWM1. */ +#define DSP28_EPWM1 1 +/* Задаёт DSP28_EPWM2 = 1; данные DSP28_EPWM2. */ +#define DSP28_EPWM2 1 +/* Задаёт DSP28_EPWM3 = 1; данные DSP28_EPWM3. */ +#define DSP28_EPWM3 1 +/* Задаёт DSP28_EPWM4 = 1; данные DSP28_EPWM4. */ +#define DSP28_EPWM4 1 +/* Задаёт DSP28_EPWM5 = 1; данные DSP28_EPWM5. */ +#define DSP28_EPWM5 1 +/* Задаёт DSP28_EPWM6 = 1; данные DSP28_EPWM6. */ +#define DSP28_EPWM6 1 +/* Задаёт DSP28_ECAP1 = 1; данные DSP28_ECAP1. */ +#define DSP28_ECAP1 1 +/* Задаёт DSP28_ECAP2 = 1; данные DSP28_ECAP2. */ +#define DSP28_ECAP2 1 +/* Задаёт DSP28_ECAP3 = 1; данные DSP28_ECAP3. */ +#define DSP28_ECAP3 1 +/* Задаёт DSP28_ECAP4 = 1; данные DSP28_ECAP4. */ +#define DSP28_ECAP4 1 +/* Задаёт DSP28_ECAP5 = 1; данные DSP28_ECAP5. */ +#define DSP28_ECAP5 1 +/* Задаёт DSP28_ECAP6 = 1; данные DSP28_ECAP6. */ +#define DSP28_ECAP6 1 +/* Задаёт DSP28_EQEP1 = 1; данные DSP28_EQEP1. */ +#define DSP28_EQEP1 1 +/* Задаёт DSP28_EQEP2 = 1; данные DSP28_EQEP2. */ +#define DSP28_EQEP2 1 +/* Задаёт DSP28_ECANA = 1; данные DSP28_ECANA. */ +#define DSP28_ECANA 1 +/* Задаёт DSP28_ECANB = 1; данные DSP28_ECANB. */ +#define DSP28_ECANB 1 +/* Задаёт DSP28_MCBSPA = 1; данные DSP28_MCBSPA. */ +#define DSP28_MCBSPA 1 +/* Задаёт DSP28_MCBSPB = 1; данные DSP28_MCBSPB. */ +#define DSP28_MCBSPB 1 +/* Задаёт DSP28_SPIA = 1; данные DSP28_SPIA. */ +#define DSP28_SPIA 1 +/* Задаёт DSP28_SCIA = 1; данные DSP28_SCIA. */ +#define DSP28_SCIA 1 +/* Задаёт DSP28_SCIB = 1; данные DSP28_SCIB. */ +#define DSP28_SCIB 1 +/* Задаёт DSP28_SCIC = 1; данные DSP28_SCIC. */ +#define DSP28_SCIC 1 +/* Задаёт DSP28_I2CA = 1; данные DSP28_I2CA. */ +#define DSP28_I2CA 1 +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end DSP28_28335 + +/* Условие компиляции DSP28_28334: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28334 +/* Задаёт DSP28_EPWM1 = 1; данные DSP28_EPWM1. */ +#define DSP28_EPWM1 1 +/* Задаёт DSP28_EPWM2 = 1; данные DSP28_EPWM2. */ +#define DSP28_EPWM2 1 +/* Задаёт DSP28_EPWM3 = 1; данные DSP28_EPWM3. */ +#define DSP28_EPWM3 1 +/* Задаёт DSP28_EPWM4 = 1; данные DSP28_EPWM4. */ +#define DSP28_EPWM4 1 +/* Задаёт DSP28_EPWM5 = 1; данные DSP28_EPWM5. */ +#define DSP28_EPWM5 1 +/* Задаёт DSP28_EPWM6 = 1; данные DSP28_EPWM6. */ +#define DSP28_EPWM6 1 +/* Задаёт DSP28_ECAP1 = 1; данные DSP28_ECAP1. */ +#define DSP28_ECAP1 1 +/* Задаёт DSP28_ECAP2 = 1; данные DSP28_ECAP2. */ +#define DSP28_ECAP2 1 +/* Задаёт DSP28_ECAP3 = 1; данные DSP28_ECAP3. */ +#define DSP28_ECAP3 1 +/* Задаёт DSP28_ECAP4 = 1; данные DSP28_ECAP4. */ +#define DSP28_ECAP4 1 +/* Задаёт DSP28_ECAP5 = 0; данные DSP28_ECAP5. */ +#define DSP28_ECAP5 0 +/* Задаёт DSP28_ECAP6 = 0; данные DSP28_ECAP6. */ +#define DSP28_ECAP6 0 +/* Задаёт DSP28_EQEP1 = 1; данные DSP28_EQEP1. */ +#define DSP28_EQEP1 1 +/* Задаёт DSP28_EQEP2 = 1; данные DSP28_EQEP2. */ +#define DSP28_EQEP2 1 +/* Задаёт DSP28_ECANA = 1; данные DSP28_ECANA. */ +#define DSP28_ECANA 1 +/* Задаёт DSP28_ECANB = 1; данные DSP28_ECANB. */ +#define DSP28_ECANB 1 +/* Задаёт DSP28_MCBSPA = 1; данные DSP28_MCBSPA. */ +#define DSP28_MCBSPA 1 +/* Задаёт DSP28_MCBSPB = 1; данные DSP28_MCBSPB. */ +#define DSP28_MCBSPB 1 +/* Задаёт DSP28_SPIA = 1; данные DSP28_SPIA. */ +#define DSP28_SPIA 1 +/* Задаёт DSP28_SCIA = 1; данные DSP28_SCIA. */ +#define DSP28_SCIA 1 +/* Задаёт DSP28_SCIB = 1; данные DSP28_SCIB. */ +#define DSP28_SCIB 1 +/* Задаёт DSP28_SCIC = 1; данные DSP28_SCIC. */ +#define DSP28_SCIC 1 +/* Задаёт DSP28_I2CA = 1; данные DSP28_I2CA. */ +#define DSP28_I2CA 1 +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end DSP28_28334 + +/* Условие компиляции DSP28_28332: выбранный блок включается в текущий вариант прошивки. */ +#if DSP28_28332 +/* Задаёт DSP28_EPWM1 = 1; данные DSP28_EPWM1. */ +#define DSP28_EPWM1 1 +/* Задаёт DSP28_EPWM2 = 1; данные DSP28_EPWM2. */ +#define DSP28_EPWM2 1 +/* Задаёт DSP28_EPWM3 = 1; данные DSP28_EPWM3. */ +#define DSP28_EPWM3 1 +/* Задаёт DSP28_EPWM4 = 1; данные DSP28_EPWM4. */ +#define DSP28_EPWM4 1 +/* Задаёт DSP28_EPWM5 = 1; данные DSP28_EPWM5. */ +#define DSP28_EPWM5 1 +/* Задаёт DSP28_EPWM6 = 1; данные DSP28_EPWM6. */ +#define DSP28_EPWM6 1 +/* Задаёт DSP28_ECAP1 = 1; данные DSP28_ECAP1. */ +#define DSP28_ECAP1 1 +/* Задаёт DSP28_ECAP2 = 1; данные DSP28_ECAP2. */ +#define DSP28_ECAP2 1 +/* Задаёт DSP28_ECAP3 = 1; данные DSP28_ECAP3. */ +#define DSP28_ECAP3 1 +/* Задаёт DSP28_ECAP4 = 1; данные DSP28_ECAP4. */ +#define DSP28_ECAP4 1 +/* Задаёт DSP28_ECAP5 = 0; данные DSP28_ECAP5. */ +#define DSP28_ECAP5 0 +/* Задаёт DSP28_ECAP6 = 0; данные DSP28_ECAP6. */ +#define DSP28_ECAP6 0 +/* Задаёт DSP28_EQEP1 = 1; данные DSP28_EQEP1. */ +#define DSP28_EQEP1 1 +/* Задаёт DSP28_EQEP2 = 1; данные DSP28_EQEP2. */ +#define DSP28_EQEP2 1 +/* Задаёт DSP28_ECANA = 1; данные DSP28_ECANA. */ +#define DSP28_ECANA 1 +/* Задаёт DSP28_ECANB = 1; данные DSP28_ECANB. */ +#define DSP28_ECANB 1 +/* Задаёт DSP28_MCBSPA = 1; данные DSP28_MCBSPA. */ +#define DSP28_MCBSPA 1 +/* Задаёт DSP28_MCBSPB = 0; данные DSP28_MCBSPB. */ +#define DSP28_MCBSPB 0 +/* Задаёт DSP28_SPIA = 1; данные DSP28_SPIA. */ +#define DSP28_SPIA 1 +/* Задаёт DSP28_SCIA = 1; данные DSP28_SCIA. */ +#define DSP28_SCIA 1 +/* Задаёт DSP28_SCIB = 1; данные DSP28_SCIB. */ +#define DSP28_SCIB 1 +/* Задаёт DSP28_SCIC = 0; данные DSP28_SCIC. */ +#define DSP28_SCIC 0 +/* Задаёт DSP28_I2CA = 1; данные DSP28_I2CA. */ +#define DSP28_I2CA 1 +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end DSP28_28332 + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_DEVICE_H definition + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h new file mode 100644 index 0000000..965ee77 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECan.h @@ -0,0 +1,2109 @@ +/* Поставляемое TI описание ECan для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: May 7, 2007 16:05:39 $ +//########################################################################### +// +// FILE: DSP2833x_ECan.h +// +// TITLE: DSP2833x Device eCAN Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_ECAN_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_ECAN_H +/* Определяет защитный символ или переключатель DSP2833x_ECAN_H для последующей компиляции. */ +#define DSP2833x_ECAN_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +/* --------------------------------------------------- */ +/* eCAN Control & Status Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Mailbox enable register (CANME) bit definitions */ +/* Описывает структуру CANME_BITS; порядок полей определяет расположение данных. */ +struct CANME_BITS { // bit description + /* Битовое поле ME0, ширина 1 бит; данные ME0. */ + Uint16 ME0:1; // 0 Enable Mailbox 0 + /* Битовое поле ME1, ширина 1 бит; данные ME1. */ + Uint16 ME1:1; // 1 Enable Mailbox 1 + /* Битовое поле ME2, ширина 1 бит; данные ME2. */ + Uint16 ME2:1; // 2 Enable Mailbox 2 + /* Битовое поле ME3, ширина 1 бит; данные ME3. */ + Uint16 ME3:1; // 3 Enable Mailbox 3 + /* Битовое поле ME4, ширина 1 бит; данные ME4. */ + Uint16 ME4:1; // 4 Enable Mailbox 4 + /* Битовое поле ME5, ширина 1 бит; данные ME5. */ + Uint16 ME5:1; // 5 Enable Mailbox 5 + /* Битовое поле ME6, ширина 1 бит; данные ME6. */ + Uint16 ME6:1; // 6 Enable Mailbox 6 + /* Битовое поле ME7, ширина 1 бит; данные ME7. */ + Uint16 ME7:1; // 7 Enable Mailbox 7 + /* Битовое поле ME8, ширина 1 бит; данные ME8. */ + Uint16 ME8:1; // 8 Enable Mailbox 8 + /* Битовое поле ME9, ширина 1 бит; данные ME9. */ + Uint16 ME9:1; // 9 Enable Mailbox 9 + /* Битовое поле ME10, ширина 1 бит; данные ME10. */ + Uint16 ME10:1; // 10 Enable Mailbox 10 + /* Битовое поле ME11, ширина 1 бит; данные ME11. */ + Uint16 ME11:1; // 11 Enable Mailbox 11 + /* Битовое поле ME12, ширина 1 бит; данные ME12. */ + Uint16 ME12:1; // 12 Enable Mailbox 12 + /* Битовое поле ME13, ширина 1 бит; данные ME13. */ + Uint16 ME13:1; // 13 Enable Mailbox 13 + /* Битовое поле ME14, ширина 1 бит; данные ME14. */ + Uint16 ME14:1; // 14 Enable Mailbox 14 + /* Битовое поле ME15, ширина 1 бит; данные ME15. */ + Uint16 ME15:1; // 15 Enable Mailbox 15 + /* Битовое поле ME16, ширина 1 бит; данные ME16. */ + Uint16 ME16:1; // 16 Enable Mailbox 16 + /* Битовое поле ME17, ширина 1 бит; данные ME17. */ + Uint16 ME17:1; // 17 Enable Mailbox 17 + /* Битовое поле ME18, ширина 1 бит; данные ME18. */ + Uint16 ME18:1; // 18 Enable Mailbox 18 + /* Битовое поле ME19, ширина 1 бит; данные ME19. */ + Uint16 ME19:1; // 19 Enable Mailbox 19 + /* Битовое поле ME20, ширина 1 бит; данные ME20. */ + Uint16 ME20:1; // 20 Enable Mailbox 20 + /* Битовое поле ME21, ширина 1 бит; данные ME21. */ + Uint16 ME21:1; // 21 Enable Mailbox 21 + /* Битовое поле ME22, ширина 1 бит; данные ME22. */ + Uint16 ME22:1; // 22 Enable Mailbox 22 + /* Битовое поле ME23, ширина 1 бит; данные ME23. */ + Uint16 ME23:1; // 23 Enable Mailbox 23 + /* Битовое поле ME24, ширина 1 бит; данные ME24. */ + Uint16 ME24:1; // 24 Enable Mailbox 24 + /* Битовое поле ME25, ширина 1 бит; данные ME25. */ + Uint16 ME25:1; // 25 Enable Mailbox 25 + /* Битовое поле ME26, ширина 1 бит; данные ME26. */ + Uint16 ME26:1; // 26 Enable Mailbox 26 + /* Битовое поле ME27, ширина 1 бит; данные ME27. */ + Uint16 ME27:1; // 27 Enable Mailbox 27 + /* Битовое поле ME28, ширина 1 бит; данные ME28. */ + Uint16 ME28:1; // 28 Enable Mailbox 28 + /* Битовое поле ME29, ширина 1 бит; данные ME29. */ + Uint16 ME29:1; // 29 Enable Mailbox 29 + /* Битовое поле ME30, ширина 1 бит; данные ME30. */ + Uint16 ME30:1; // 30 Enable Mailbox 30 + /* Битовое поле ME31, ширина 1 бит; данные ME31. */ + Uint16 ME31:1; // 31 Enable Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANME_REG в одной области памяти. */ +union CANME_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANME_BITS bit;; порядок полей определяет расположение данных. */ + struct CANME_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Mailbox direction register (CANMD) bit definitions */ +/* Описывает структуру CANMD_BITS; порядок полей определяет расположение данных. */ +struct CANMD_BITS { // bit description + /* Битовое поле MD0, ширина 1 бит; данные MD0. */ + Uint16 MD0:1; // 0 0 -> Tx 1 -> Rx + /* Битовое поле MD1, ширина 1 бит; данные MD1. */ + Uint16 MD1:1; // 1 0 -> Tx 1 -> Rx + /* Битовое поле MD2, ширина 1 бит; данные MD2. */ + Uint16 MD2:1; // 2 0 -> Tx 1 -> Rx + /* Битовое поле MD3, ширина 1 бит; данные MD3. */ + Uint16 MD3:1; // 3 0 -> Tx 1 -> Rx + /* Битовое поле MD4, ширина 1 бит; данные MD4. */ + Uint16 MD4:1; // 4 0 -> Tx 1 -> Rx + /* Битовое поле MD5, ширина 1 бит; данные MD5. */ + Uint16 MD5:1; // 5 0 -> Tx 1 -> Rx + /* Битовое поле MD6, ширина 1 бит; данные MD6. */ + Uint16 MD6:1; // 6 0 -> Tx 1 -> Rx + /* Битовое поле MD7, ширина 1 бит; данные MD7. */ + Uint16 MD7:1; // 7 0 -> Tx 1 -> Rx + /* Битовое поле MD8, ширина 1 бит; данные MD8. */ + Uint16 MD8:1; // 8 0 -> Tx 1 -> Rx + /* Битовое поле MD9, ширина 1 бит; данные MD9. */ + Uint16 MD9:1; // 9 0 -> Tx 1 -> Rx + /* Битовое поле MD10, ширина 1 бит; данные MD10. */ + Uint16 MD10:1; // 10 0 -> Tx 1 -> Rx + /* Битовое поле MD11, ширина 1 бит; данные MD11. */ + Uint16 MD11:1; // 11 0 -> Tx 1 -> Rx + /* Битовое поле MD12, ширина 1 бит; данные MD12. */ + Uint16 MD12:1; // 12 0 -> Tx 1 -> Rx + /* Битовое поле MD13, ширина 1 бит; данные MD13. */ + Uint16 MD13:1; // 13 0 -> Tx 1 -> Rx + /* Битовое поле MD14, ширина 1 бит; данные MD14. */ + Uint16 MD14:1; // 14 0 -> Tx 1 -> Rx + /* Битовое поле MD15, ширина 1 бит; данные MD15. */ + Uint16 MD15:1; // 15 0 -> Tx 1 -> Rx + /* Битовое поле MD16, ширина 1 бит; данные MD16. */ + Uint16 MD16:1; // 16 0 -> Tx 1 -> Rx + /* Битовое поле MD17, ширина 1 бит; данные MD17. */ + Uint16 MD17:1; // 17 0 -> Tx 1 -> Rx + /* Битовое поле MD18, ширина 1 бит; данные MD18. */ + Uint16 MD18:1; // 18 0 -> Tx 1 -> Rx + /* Битовое поле MD19, ширина 1 бит; данные MD19. */ + Uint16 MD19:1; // 19 0 -> Tx 1 -> Rx + /* Битовое поле MD20, ширина 1 бит; данные MD20. */ + Uint16 MD20:1; // 20 0 -> Tx 1 -> Rx + /* Битовое поле MD21, ширина 1 бит; данные MD21. */ + Uint16 MD21:1; // 21 0 -> Tx 1 -> Rx + /* Битовое поле MD22, ширина 1 бит; данные MD22. */ + Uint16 MD22:1; // 22 0 -> Tx 1 -> Rx + /* Битовое поле MD23, ширина 1 бит; данные MD23. */ + Uint16 MD23:1; // 23 0 -> Tx 1 -> Rx + /* Битовое поле MD24, ширина 1 бит; данные MD24. */ + Uint16 MD24:1; // 24 0 -> Tx 1 -> Rx + /* Битовое поле MD25, ширина 1 бит; данные MD25. */ + Uint16 MD25:1; // 25 0 -> Tx 1 -> Rx + /* Битовое поле MD26, ширина 1 бит; данные MD26. */ + Uint16 MD26:1; // 26 0 -> Tx 1 -> Rx + /* Битовое поле MD27, ширина 1 бит; данные MD27. */ + Uint16 MD27:1; // 27 0 -> Tx 1 -> Rx + /* Битовое поле MD28, ширина 1 бит; данные MD28. */ + Uint16 MD28:1; // 28 0 -> Tx 1 -> Rx + /* Битовое поле MD29, ширина 1 бит; данные MD29. */ + Uint16 MD29:1; // 29 0 -> Tx 1 -> Rx + /* Битовое поле MD30, ширина 1 бит; данные MD30. */ + Uint16 MD30:1; // 30 0 -> Tx 1 -> Rx + /* Битовое поле MD31, ширина 1 бит; данные MD31. */ + Uint16 MD31:1; // 31 0 -> Tx 1 -> Rx + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMD_REG в одной области памяти. */ +union CANMD_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMD_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMD_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Request Set register (CANTRS) bit definitions */ +/* Описывает структуру CANTRS_BITS; порядок полей определяет расположение данных. */ +struct CANTRS_BITS { // bit description + /* Битовое поле TRS0, ширина 1 бит; данные TRS0. */ + Uint16 TRS0:1; // 0 TRS for Mailbox 0 + /* Битовое поле TRS1, ширина 1 бит; данные TRS1. */ + Uint16 TRS1:1; // 1 TRS for Mailbox 1 + /* Битовое поле TRS2, ширина 1 бит; данные TRS2. */ + Uint16 TRS2:1; // 2 TRS for Mailbox 2 + /* Битовое поле TRS3, ширина 1 бит; данные TRS3. */ + Uint16 TRS3:1; // 3 TRS for Mailbox 3 + /* Битовое поле TRS4, ширина 1 бит; данные TRS4. */ + Uint16 TRS4:1; // 4 TRS for Mailbox 4 + /* Битовое поле TRS5, ширина 1 бит; данные TRS5. */ + Uint16 TRS5:1; // 5 TRS for Mailbox 5 + /* Битовое поле TRS6, ширина 1 бит; данные TRS6. */ + Uint16 TRS6:1; // 6 TRS for Mailbox 6 + /* Битовое поле TRS7, ширина 1 бит; данные TRS7. */ + Uint16 TRS7:1; // 7 TRS for Mailbox 7 + /* Битовое поле TRS8, ширина 1 бит; данные TRS8. */ + Uint16 TRS8:1; // 8 TRS for Mailbox 8 + /* Битовое поле TRS9, ширина 1 бит; данные TRS9. */ + Uint16 TRS9:1; // 9 TRS for Mailbox 9 + /* Битовое поле TRS10, ширина 1 бит; данные TRS10. */ + Uint16 TRS10:1; // 10 TRS for Mailbox 10 + /* Битовое поле TRS11, ширина 1 бит; данные TRS11. */ + Uint16 TRS11:1; // 11 TRS for Mailbox 11 + /* Битовое поле TRS12, ширина 1 бит; данные TRS12. */ + Uint16 TRS12:1; // 12 TRS for Mailbox 12 + /* Битовое поле TRS13, ширина 1 бит; данные TRS13. */ + Uint16 TRS13:1; // 13 TRS for Mailbox 13 + /* Битовое поле TRS14, ширина 1 бит; данные TRS14. */ + Uint16 TRS14:1; // 14 TRS for Mailbox 14 + /* Битовое поле TRS15, ширина 1 бит; данные TRS15. */ + Uint16 TRS15:1; // 15 TRS for Mailbox 15 + /* Битовое поле TRS16, ширина 1 бит; данные TRS16. */ + Uint16 TRS16:1; // 16 TRS for Mailbox 16 + /* Битовое поле TRS17, ширина 1 бит; данные TRS17. */ + Uint16 TRS17:1; // 17 TRS for Mailbox 17 + /* Битовое поле TRS18, ширина 1 бит; данные TRS18. */ + Uint16 TRS18:1; // 18 TRS for Mailbox 18 + /* Битовое поле TRS19, ширина 1 бит; данные TRS19. */ + Uint16 TRS19:1; // 19 TRS for Mailbox 19 + /* Битовое поле TRS20, ширина 1 бит; данные TRS20. */ + Uint16 TRS20:1; // 20 TRS for Mailbox 20 + /* Битовое поле TRS21, ширина 1 бит; данные TRS21. */ + Uint16 TRS21:1; // 21 TRS for Mailbox 21 + /* Битовое поле TRS22, ширина 1 бит; данные TRS22. */ + Uint16 TRS22:1; // 22 TRS for Mailbox 22 + /* Битовое поле TRS23, ширина 1 бит; данные TRS23. */ + Uint16 TRS23:1; // 23 TRS for Mailbox 23 + /* Битовое поле TRS24, ширина 1 бит; данные TRS24. */ + Uint16 TRS24:1; // 24 TRS for Mailbox 24 + /* Битовое поле TRS25, ширина 1 бит; данные TRS25. */ + Uint16 TRS25:1; // 25 TRS for Mailbox 25 + /* Битовое поле TRS26, ширина 1 бит; данные TRS26. */ + Uint16 TRS26:1; // 26 TRS for Mailbox 26 + /* Битовое поле TRS27, ширина 1 бит; данные TRS27. */ + Uint16 TRS27:1; // 27 TRS for Mailbox 27 + /* Битовое поле TRS28, ширина 1 бит; данные TRS28. */ + Uint16 TRS28:1; // 28 TRS for Mailbox 28 + /* Битовое поле TRS29, ширина 1 бит; данные TRS29. */ + Uint16 TRS29:1; // 29 TRS for Mailbox 29 + /* Битовое поле TRS30, ширина 1 бит; данные TRS30. */ + Uint16 TRS30:1; // 30 TRS for Mailbox 30 + /* Битовое поле TRS31, ширина 1 бит; данные TRS31. */ + Uint16 TRS31:1; // 31 TRS for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTRS_REG в одной области памяти. */ +union CANTRS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTRS_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTRS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Request Reset register (CANTRR) bit definitions */ +/* Описывает структуру CANTRR_BITS; порядок полей определяет расположение данных. */ +struct CANTRR_BITS { // bit description + /* Битовое поле TRR0, ширина 1 бит; данные TRR0. */ + Uint16 TRR0:1; // 0 TRR for Mailbox 0 + /* Битовое поле TRR1, ширина 1 бит; данные TRR1. */ + Uint16 TRR1:1; // 1 TRR for Mailbox 1 + /* Битовое поле TRR2, ширина 1 бит; данные TRR2. */ + Uint16 TRR2:1; // 2 TRR for Mailbox 2 + /* Битовое поле TRR3, ширина 1 бит; данные TRR3. */ + Uint16 TRR3:1; // 3 TRR for Mailbox 3 + /* Битовое поле TRR4, ширина 1 бит; данные TRR4. */ + Uint16 TRR4:1; // 4 TRR for Mailbox 4 + /* Битовое поле TRR5, ширина 1 бит; данные TRR5. */ + Uint16 TRR5:1; // 5 TRR for Mailbox 5 + /* Битовое поле TRR6, ширина 1 бит; данные TRR6. */ + Uint16 TRR6:1; // 6 TRR for Mailbox 6 + /* Битовое поле TRR7, ширина 1 бит; данные TRR7. */ + Uint16 TRR7:1; // 7 TRR for Mailbox 7 + /* Битовое поле TRR8, ширина 1 бит; данные TRR8. */ + Uint16 TRR8:1; // 8 TRR for Mailbox 8 + /* Битовое поле TRR9, ширина 1 бит; данные TRR9. */ + Uint16 TRR9:1; // 9 TRR for Mailbox 9 + /* Битовое поле TRR10, ширина 1 бит; данные TRR10. */ + Uint16 TRR10:1; // 10 TRR for Mailbox 10 + /* Битовое поле TRR11, ширина 1 бит; данные TRR11. */ + Uint16 TRR11:1; // 11 TRR for Mailbox 11 + /* Битовое поле TRR12, ширина 1 бит; данные TRR12. */ + Uint16 TRR12:1; // 12 TRR for Mailbox 12 + /* Битовое поле TRR13, ширина 1 бит; данные TRR13. */ + Uint16 TRR13:1; // 13 TRR for Mailbox 13 + /* Битовое поле TRR14, ширина 1 бит; данные TRR14. */ + Uint16 TRR14:1; // 14 TRR for Mailbox 14 + /* Битовое поле TRR15, ширина 1 бит; данные TRR15. */ + Uint16 TRR15:1; // 15 TRR for Mailbox 15 + /* Битовое поле TRR16, ширина 1 бит; данные TRR16. */ + Uint16 TRR16:1; // 16 TRR for Mailbox 16 + /* Битовое поле TRR17, ширина 1 бит; данные TRR17. */ + Uint16 TRR17:1; // 17 TRR for Mailbox 17 + /* Битовое поле TRR18, ширина 1 бит; данные TRR18. */ + Uint16 TRR18:1; // 18 TRR for Mailbox 18 + /* Битовое поле TRR19, ширина 1 бит; данные TRR19. */ + Uint16 TRR19:1; // 19 TRR for Mailbox 19 + /* Битовое поле TRR20, ширина 1 бит; данные TRR20. */ + Uint16 TRR20:1; // 20 TRR for Mailbox 20 + /* Битовое поле TRR21, ширина 1 бит; данные TRR21. */ + Uint16 TRR21:1; // 21 TRR for Mailbox 21 + /* Битовое поле TRR22, ширина 1 бит; данные TRR22. */ + Uint16 TRR22:1; // 22 TRR for Mailbox 22 + /* Битовое поле TRR23, ширина 1 бит; данные TRR23. */ + Uint16 TRR23:1; // 23 TRR for Mailbox 23 + /* Битовое поле TRR24, ширина 1 бит; данные TRR24. */ + Uint16 TRR24:1; // 24 TRR for Mailbox 24 + /* Битовое поле TRR25, ширина 1 бит; данные TRR25. */ + Uint16 TRR25:1; // 25 TRR for Mailbox 25 + /* Битовое поле TRR26, ширина 1 бит; данные TRR26. */ + Uint16 TRR26:1; // 26 TRR for Mailbox 26 + /* Битовое поле TRR27, ширина 1 бит; данные TRR27. */ + Uint16 TRR27:1; // 27 TRR for Mailbox 27 + /* Битовое поле TRR28, ширина 1 бит; данные TRR28. */ + Uint16 TRR28:1; // 28 TRR for Mailbox 28 + /* Битовое поле TRR29, ширина 1 бит; данные TRR29. */ + Uint16 TRR29:1; // 29 TRR for Mailbox 29 + /* Битовое поле TRR30, ширина 1 бит; данные TRR30. */ + Uint16 TRR30:1; // 30 TRR for Mailbox 30 + /* Битовое поле TRR31, ширина 1 бит; данные TRR31. */ + Uint16 TRR31:1; // 31 TRR for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTRR_REG в одной области памяти. */ +union CANTRR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTRR_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTRR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Acknowledge register (CANTA) bit definitions */ +/* Описывает структуру CANTA_BITS; порядок полей определяет расположение данных. */ +struct CANTA_BITS { // bit description + /* Битовое поле TA0, ширина 1 бит; данные TA0. */ + Uint16 TA0:1; // 0 TA for Mailbox 0 + /* Битовое поле TA1, ширина 1 бит; данные TA1. */ + Uint16 TA1:1; // 1 TA for Mailbox 1 + /* Битовое поле TA2, ширина 1 бит; данные TA2. */ + Uint16 TA2:1; // 2 TA for Mailbox 2 + /* Битовое поле TA3, ширина 1 бит; данные TA3. */ + Uint16 TA3:1; // 3 TA for Mailbox 3 + /* Битовое поле TA4, ширина 1 бит; данные TA4. */ + Uint16 TA4:1; // 4 TA for Mailbox 4 + /* Битовое поле TA5, ширина 1 бит; данные TA5. */ + Uint16 TA5:1; // 5 TA for Mailbox 5 + /* Битовое поле TA6, ширина 1 бит; данные TA6. */ + Uint16 TA6:1; // 6 TA for Mailbox 6 + /* Битовое поле TA7, ширина 1 бит; данные TA7. */ + Uint16 TA7:1; // 7 TA for Mailbox 7 + /* Битовое поле TA8, ширина 1 бит; данные TA8. */ + Uint16 TA8:1; // 8 TA for Mailbox 8 + /* Битовое поле TA9, ширина 1 бит; данные TA9. */ + Uint16 TA9:1; // 9 TA for Mailbox 9 + /* Битовое поле TA10, ширина 1 бит; данные TA10. */ + Uint16 TA10:1; // 10 TA for Mailbox 10 + /* Битовое поле TA11, ширина 1 бит; данные TA11. */ + Uint16 TA11:1; // 11 TA for Mailbox 11 + /* Битовое поле TA12, ширина 1 бит; данные TA12. */ + Uint16 TA12:1; // 12 TA for Mailbox 12 + /* Битовое поле TA13, ширина 1 бит; данные TA13. */ + Uint16 TA13:1; // 13 TA for Mailbox 13 + /* Битовое поле TA14, ширина 1 бит; данные TA14. */ + Uint16 TA14:1; // 14 TA for Mailbox 14 + /* Битовое поле TA15, ширина 1 бит; данные TA15. */ + Uint16 TA15:1; // 15 TA for Mailbox 15 + /* Битовое поле TA16, ширина 1 бит; данные TA16. */ + Uint16 TA16:1; // 16 TA for Mailbox 16 + /* Битовое поле TA17, ширина 1 бит; данные TA17. */ + Uint16 TA17:1; // 17 TA for Mailbox 17 + /* Битовое поле TA18, ширина 1 бит; данные TA18. */ + Uint16 TA18:1; // 18 TA for Mailbox 18 + /* Битовое поле TA19, ширина 1 бит; данные TA19. */ + Uint16 TA19:1; // 19 TA for Mailbox 19 + /* Битовое поле TA20, ширина 1 бит; данные TA20. */ + Uint16 TA20:1; // 20 TA for Mailbox 20 + /* Битовое поле TA21, ширина 1 бит; данные TA21. */ + Uint16 TA21:1; // 21 TA for Mailbox 21 + /* Битовое поле TA22, ширина 1 бит; данные TA22. */ + Uint16 TA22:1; // 22 TA for Mailbox 22 + /* Битовое поле TA23, ширина 1 бит; данные TA23. */ + Uint16 TA23:1; // 23 TA for Mailbox 23 + /* Битовое поле TA24, ширина 1 бит; данные TA24. */ + Uint16 TA24:1; // 24 TA for Mailbox 24 + /* Битовое поле TA25, ширина 1 бит; данные TA25. */ + Uint16 TA25:1; // 25 TA for Mailbox 25 + /* Битовое поле TA26, ширина 1 бит; данные TA26. */ + Uint16 TA26:1; // 26 TA for Mailbox 26 + /* Битовое поле TA27, ширина 1 бит; данные TA27. */ + Uint16 TA27:1; // 27 TA for Mailbox 27 + /* Битовое поле TA28, ширина 1 бит; данные TA28. */ + Uint16 TA28:1; // 28 TA for Mailbox 28 + /* Битовое поле TA29, ширина 1 бит; данные TA29. */ + Uint16 TA29:1; // 29 TA for Mailbox 29 + /* Битовое поле TA30, ширина 1 бит; данные TA30. */ + Uint16 TA30:1; // 30 TA for Mailbox 30 + /* Битовое поле TA31, ширина 1 бит; данные TA31. */ + Uint16 TA31:1; // 31 TA for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTA_REG в одной области памяти. */ +union CANTA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTA_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Transmit Abort Acknowledge register (CANAA) bit definitions */ +/* Описывает структуру CANAA_BITS; порядок полей определяет расположение данных. */ +struct CANAA_BITS { // bit description + /* Битовое поле AA0, ширина 1 бит; данные AA0. */ + Uint16 AA0:1; // 0 AA for Mailbox 0 + /* Битовое поле AA1, ширина 1 бит; данные AA1. */ + Uint16 AA1:1; // 1 AA for Mailbox 1 + /* Битовое поле AA2, ширина 1 бит; данные AA2. */ + Uint16 AA2:1; // 2 AA for Mailbox 2 + /* Битовое поле AA3, ширина 1 бит; данные AA3. */ + Uint16 AA3:1; // 3 AA for Mailbox 3 + /* Битовое поле AA4, ширина 1 бит; данные AA4. */ + Uint16 AA4:1; // 4 AA for Mailbox 4 + /* Битовое поле AA5, ширина 1 бит; данные AA5. */ + Uint16 AA5:1; // 5 AA for Mailbox 5 + /* Битовое поле AA6, ширина 1 бит; данные AA6. */ + Uint16 AA6:1; // 6 AA for Mailbox 6 + /* Битовое поле AA7, ширина 1 бит; данные AA7. */ + Uint16 AA7:1; // 7 AA for Mailbox 7 + /* Битовое поле AA8, ширина 1 бит; данные AA8. */ + Uint16 AA8:1; // 8 AA for Mailbox 8 + /* Битовое поле AA9, ширина 1 бит; данные AA9. */ + Uint16 AA9:1; // 9 AA for Mailbox 9 + /* Битовое поле AA10, ширина 1 бит; данные AA10. */ + Uint16 AA10:1; // 10 AA for Mailbox 10 + /* Битовое поле AA11, ширина 1 бит; данные AA11. */ + Uint16 AA11:1; // 11 AA for Mailbox 11 + /* Битовое поле AA12, ширина 1 бит; данные AA12. */ + Uint16 AA12:1; // 12 AA for Mailbox 12 + /* Битовое поле AA13, ширина 1 бит; данные AA13. */ + Uint16 AA13:1; // 13 AA for Mailbox 13 + /* Битовое поле AA14, ширина 1 бит; данные AA14. */ + Uint16 AA14:1; // 14 AA for Mailbox 14 + /* Битовое поле AA15, ширина 1 бит; данные AA15. */ + Uint16 AA15:1; // 15 AA for Mailbox 15 + /* Битовое поле AA16, ширина 1 бит; данные AA16. */ + Uint16 AA16:1; // 16 AA for Mailbox 16 + /* Битовое поле AA17, ширина 1 бит; данные AA17. */ + Uint16 AA17:1; // 17 AA for Mailbox 17 + /* Битовое поле AA18, ширина 1 бит; данные AA18. */ + Uint16 AA18:1; // 18 AA for Mailbox 18 + /* Битовое поле AA19, ширина 1 бит; данные AA19. */ + Uint16 AA19:1; // 19 AA for Mailbox 19 + /* Битовое поле AA20, ширина 1 бит; данные AA20. */ + Uint16 AA20:1; // 20 AA for Mailbox 20 + /* Битовое поле AA21, ширина 1 бит; данные AA21. */ + Uint16 AA21:1; // 21 AA for Mailbox 21 + /* Битовое поле AA22, ширина 1 бит; данные AA22. */ + Uint16 AA22:1; // 22 AA for Mailbox 22 + /* Битовое поле AA23, ширина 1 бит; данные AA23. */ + Uint16 AA23:1; // 23 AA for Mailbox 23 + /* Битовое поле AA24, ширина 1 бит; данные AA24. */ + Uint16 AA24:1; // 24 AA for Mailbox 24 + /* Битовое поле AA25, ширина 1 бит; данные AA25. */ + Uint16 AA25:1; // 25 AA for Mailbox 25 + /* Битовое поле AA26, ширина 1 бит; данные AA26. */ + Uint16 AA26:1; // 26 AA for Mailbox 26 + /* Битовое поле AA27, ширина 1 бит; данные AA27. */ + Uint16 AA27:1; // 27 AA for Mailbox 27 + /* Битовое поле AA28, ширина 1 бит; данные AA28. */ + Uint16 AA28:1; // 28 AA for Mailbox 28 + /* Битовое поле AA29, ширина 1 бит; данные AA29. */ + Uint16 AA29:1; // 29 AA for Mailbox 29 + /* Битовое поле AA30, ширина 1 бит; данные AA30. */ + Uint16 AA30:1; // 30 AA for Mailbox 30 + /* Битовое поле AA31, ширина 1 бит; данные AA31. */ + Uint16 AA31:1; // 31 AA for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANAA_REG в одной области памяти. */ +union CANAA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANAA_BITS bit;; порядок полей определяет расположение данных. */ + struct CANAA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Received Message Pending register (CANRMP) bit definitions */ +/* Описывает структуру CANRMP_BITS; порядок полей определяет расположение данных. */ +struct CANRMP_BITS { // bit description + /* Битовое поле RMP0, ширина 1 бит; данные RMP0. */ + Uint16 RMP0:1; // 0 RMP for Mailbox 0 + /* Битовое поле RMP1, ширина 1 бит; данные RMP1. */ + Uint16 RMP1:1; // 1 RMP for Mailbox 1 + /* Битовое поле RMP2, ширина 1 бит; данные RMP2. */ + Uint16 RMP2:1; // 2 RMP for Mailbox 2 + /* Битовое поле RMP3, ширина 1 бит; данные RMP3. */ + Uint16 RMP3:1; // 3 RMP for Mailbox 3 + /* Битовое поле RMP4, ширина 1 бит; данные RMP4. */ + Uint16 RMP4:1; // 4 RMP for Mailbox 4 + /* Битовое поле RMP5, ширина 1 бит; данные RMP5. */ + Uint16 RMP5:1; // 5 RMP for Mailbox 5 + /* Битовое поле RMP6, ширина 1 бит; данные RMP6. */ + Uint16 RMP6:1; // 6 RMP for Mailbox 6 + /* Битовое поле RMP7, ширина 1 бит; данные RMP7. */ + Uint16 RMP7:1; // 7 RMP for Mailbox 7 + /* Битовое поле RMP8, ширина 1 бит; данные RMP8. */ + Uint16 RMP8:1; // 8 RMP for Mailbox 8 + /* Битовое поле RMP9, ширина 1 бит; данные RMP9. */ + Uint16 RMP9:1; // 9 RMP for Mailbox 9 + /* Битовое поле RMP10, ширина 1 бит; данные RMP10. */ + Uint16 RMP10:1; // 10 RMP for Mailbox 10 + /* Битовое поле RMP11, ширина 1 бит; данные RMP11. */ + Uint16 RMP11:1; // 11 RMP for Mailbox 11 + /* Битовое поле RMP12, ширина 1 бит; данные RMP12. */ + Uint16 RMP12:1; // 12 RMP for Mailbox 12 + /* Битовое поле RMP13, ширина 1 бит; данные RMP13. */ + Uint16 RMP13:1; // 13 RMP for Mailbox 13 + /* Битовое поле RMP14, ширина 1 бит; данные RMP14. */ + Uint16 RMP14:1; // 14 RMP for Mailbox 14 + /* Битовое поле RMP15, ширина 1 бит; данные RMP15. */ + Uint16 RMP15:1; // 15 RMP for Mailbox 15 + /* Битовое поле RMP16, ширина 1 бит; данные RMP16. */ + Uint16 RMP16:1; // 16 RMP for Mailbox 16 + /* Битовое поле RMP17, ширина 1 бит; данные RMP17. */ + Uint16 RMP17:1; // 17 RMP for Mailbox 17 + /* Битовое поле RMP18, ширина 1 бит; данные RMP18. */ + Uint16 RMP18:1; // 18 RMP for Mailbox 18 + /* Битовое поле RMP19, ширина 1 бит; данные RMP19. */ + Uint16 RMP19:1; // 19 RMP for Mailbox 19 + /* Битовое поле RMP20, ширина 1 бит; данные RMP20. */ + Uint16 RMP20:1; // 20 RMP for Mailbox 20 + /* Битовое поле RMP21, ширина 1 бит; данные RMP21. */ + Uint16 RMP21:1; // 21 RMP for Mailbox 21 + /* Битовое поле RMP22, ширина 1 бит; данные RMP22. */ + Uint16 RMP22:1; // 22 RMP for Mailbox 22 + /* Битовое поле RMP23, ширина 1 бит; данные RMP23. */ + Uint16 RMP23:1; // 23 RMP for Mailbox 23 + /* Битовое поле RMP24, ширина 1 бит; данные RMP24. */ + Uint16 RMP24:1; // 24 RMP for Mailbox 24 + /* Битовое поле RMP25, ширина 1 бит; данные RMP25. */ + Uint16 RMP25:1; // 25 RMP for Mailbox 25 + /* Битовое поле RMP26, ширина 1 бит; данные RMP26. */ + Uint16 RMP26:1; // 26 RMP for Mailbox 26 + /* Битовое поле RMP27, ширина 1 бит; данные RMP27. */ + Uint16 RMP27:1; // 27 RMP for Mailbox 27 + /* Битовое поле RMP28, ширина 1 бит; данные RMP28. */ + Uint16 RMP28:1; // 28 RMP for Mailbox 28 + /* Битовое поле RMP29, ширина 1 бит; данные RMP29. */ + Uint16 RMP29:1; // 29 RMP for Mailbox 29 + /* Битовое поле RMP30, ширина 1 бит; данные RMP30. */ + Uint16 RMP30:1; // 30 RMP for Mailbox 30 + /* Битовое поле RMP31, ширина 1 бит; данные RMP31. */ + Uint16 RMP31:1; // 31 RMP for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRMP_REG в одной области памяти. */ +union CANRMP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRMP_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRMP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Received Message Lost register (CANRML) bit definitions */ +/* Описывает структуру CANRML_BITS; порядок полей определяет расположение данных. */ +struct CANRML_BITS { // bit description + /* Битовое поле RML0, ширина 1 бит; данные RML0. */ + Uint16 RML0:1; // 0 RML for Mailbox 0 + /* Битовое поле RML1, ширина 1 бит; данные RML1. */ + Uint16 RML1:1; // 1 RML for Mailbox 1 + /* Битовое поле RML2, ширина 1 бит; данные RML2. */ + Uint16 RML2:1; // 2 RML for Mailbox 2 + /* Битовое поле RML3, ширина 1 бит; данные RML3. */ + Uint16 RML3:1; // 3 RML for Mailbox 3 + /* Битовое поле RML4, ширина 1 бит; данные RML4. */ + Uint16 RML4:1; // 4 RML for Mailbox 4 + /* Битовое поле RML5, ширина 1 бит; данные RML5. */ + Uint16 RML5:1; // 5 RML for Mailbox 5 + /* Битовое поле RML6, ширина 1 бит; данные RML6. */ + Uint16 RML6:1; // 6 RML for Mailbox 6 + /* Битовое поле RML7, ширина 1 бит; данные RML7. */ + Uint16 RML7:1; // 7 RML for Mailbox 7 + /* Битовое поле RML8, ширина 1 бит; данные RML8. */ + Uint16 RML8:1; // 8 RML for Mailbox 8 + /* Битовое поле RML9, ширина 1 бит; данные RML9. */ + Uint16 RML9:1; // 9 RML for Mailbox 9 + /* Битовое поле RML10, ширина 1 бит; данные RML10. */ + Uint16 RML10:1; // 10 RML for Mailbox 10 + /* Битовое поле RML11, ширина 1 бит; данные RML11. */ + Uint16 RML11:1; // 11 RML for Mailbox 11 + /* Битовое поле RML12, ширина 1 бит; данные RML12. */ + Uint16 RML12:1; // 12 RML for Mailbox 12 + /* Битовое поле RML13, ширина 1 бит; данные RML13. */ + Uint16 RML13:1; // 13 RML for Mailbox 13 + /* Битовое поле RML14, ширина 1 бит; данные RML14. */ + Uint16 RML14:1; // 14 RML for Mailbox 14 + /* Битовое поле RML15, ширина 1 бит; данные RML15. */ + Uint16 RML15:1; // 15 RML for Mailbox 15 + /* Битовое поле RML16, ширина 1 бит; данные RML16. */ + Uint16 RML16:1; // 16 RML for Mailbox 16 + /* Битовое поле RML17, ширина 1 бит; данные RML17. */ + Uint16 RML17:1; // 17 RML for Mailbox 17 + /* Битовое поле RML18, ширина 1 бит; данные RML18. */ + Uint16 RML18:1; // 18 RML for Mailbox 18 + /* Битовое поле RML19, ширина 1 бит; данные RML19. */ + Uint16 RML19:1; // 19 RML for Mailbox 19 + /* Битовое поле RML20, ширина 1 бит; данные RML20. */ + Uint16 RML20:1; // 20 RML for Mailbox 20 + /* Битовое поле RML21, ширина 1 бит; данные RML21. */ + Uint16 RML21:1; // 21 RML for Mailbox 21 + /* Битовое поле RML22, ширина 1 бит; данные RML22. */ + Uint16 RML22:1; // 22 RML for Mailbox 22 + /* Битовое поле RML23, ширина 1 бит; данные RML23. */ + Uint16 RML23:1; // 23 RML for Mailbox 23 + /* Битовое поле RML24, ширина 1 бит; данные RML24. */ + Uint16 RML24:1; // 24 RML for Mailbox 24 + /* Битовое поле RML25, ширина 1 бит; данные RML25. */ + Uint16 RML25:1; // 25 RML for Mailbox 25 + /* Битовое поле RML26, ширина 1 бит; данные RML26. */ + Uint16 RML26:1; // 26 RML for Mailbox 26 + /* Битовое поле RML27, ширина 1 бит; данные RML27. */ + Uint16 RML27:1; // 27 RML for Mailbox 27 + /* Битовое поле RML28, ширина 1 бит; данные RML28. */ + Uint16 RML28:1; // 28 RML for Mailbox 28 + /* Битовое поле RML29, ширина 1 бит; данные RML29. */ + Uint16 RML29:1; // 29 RML for Mailbox 29 + /* Битовое поле RML30, ширина 1 бит; данные RML30. */ + Uint16 RML30:1; // 30 RML for Mailbox 30 + /* Битовое поле RML31, ширина 1 бит; данные RML31. */ + Uint16 RML31:1; // 31 RML for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRML_REG в одной области памяти. */ +union CANRML_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRML_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRML_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Remote Frame Pending register (CANRFP) bit definitions */ +/* Описывает структуру CANRFP_BITS; порядок полей определяет расположение данных. */ +struct CANRFP_BITS { // bit description + /* Битовое поле RFP0, ширина 1 бит; данные RFP0. */ + Uint16 RFP0:1; // 0 RFP for Mailbox 0 + /* Битовое поле RFP1, ширина 1 бит; данные RFP1. */ + Uint16 RFP1:1; // 1 RFP for Mailbox 1 + /* Битовое поле RFP2, ширина 1 бит; данные RFP2. */ + Uint16 RFP2:1; // 2 RFP for Mailbox 2 + /* Битовое поле RFP3, ширина 1 бит; данные RFP3. */ + Uint16 RFP3:1; // 3 RFP for Mailbox 3 + /* Битовое поле RFP4, ширина 1 бит; данные RFP4. */ + Uint16 RFP4:1; // 4 RFP for Mailbox 4 + /* Битовое поле RFP5, ширина 1 бит; данные RFP5. */ + Uint16 RFP5:1; // 5 RFP for Mailbox 5 + /* Битовое поле RFP6, ширина 1 бит; данные RFP6. */ + Uint16 RFP6:1; // 6 RFP for Mailbox 6 + /* Битовое поле RFP7, ширина 1 бит; данные RFP7. */ + Uint16 RFP7:1; // 7 RFP for Mailbox 7 + /* Битовое поле RFP8, ширина 1 бит; данные RFP8. */ + Uint16 RFP8:1; // 8 RFP for Mailbox 8 + /* Битовое поле RFP9, ширина 1 бит; данные RFP9. */ + Uint16 RFP9:1; // 9 RFP for Mailbox 9 + /* Битовое поле RFP10, ширина 1 бит; данные RFP10. */ + Uint16 RFP10:1; // 10 RFP for Mailbox 10 + /* Битовое поле RFP11, ширина 1 бит; данные RFP11. */ + Uint16 RFP11:1; // 11 RFP for Mailbox 11 + /* Битовое поле RFP12, ширина 1 бит; данные RFP12. */ + Uint16 RFP12:1; // 12 RFP for Mailbox 12 + /* Битовое поле RFP13, ширина 1 бит; данные RFP13. */ + Uint16 RFP13:1; // 13 RFP for Mailbox 13 + /* Битовое поле RFP14, ширина 1 бит; данные RFP14. */ + Uint16 RFP14:1; // 14 RFP for Mailbox 14 + /* Битовое поле RFP15, ширина 1 бит; данные RFP15. */ + Uint16 RFP15:1; // 15 RFP for Mailbox 15 + /* Битовое поле RFP16, ширина 1 бит; данные RFP16. */ + Uint16 RFP16:1; // 16 RFP for Mailbox 16 + /* Битовое поле RFP17, ширина 1 бит; данные RFP17. */ + Uint16 RFP17:1; // 17 RFP for Mailbox 17 + /* Битовое поле RFP18, ширина 1 бит; данные RFP18. */ + Uint16 RFP18:1; // 18 RFP for Mailbox 18 + /* Битовое поле RFP19, ширина 1 бит; данные RFP19. */ + Uint16 RFP19:1; // 19 RFP for Mailbox 19 + /* Битовое поле RFP20, ширина 1 бит; данные RFP20. */ + Uint16 RFP20:1; // 20 RFP for Mailbox 20 + /* Битовое поле RFP21, ширина 1 бит; данные RFP21. */ + Uint16 RFP21:1; // 21 RFP for Mailbox 21 + /* Битовое поле RFP22, ширина 1 бит; данные RFP22. */ + Uint16 RFP22:1; // 22 RFP for Mailbox 22 + /* Битовое поле RFP23, ширина 1 бит; данные RFP23. */ + Uint16 RFP23:1; // 23 RFP for Mailbox 23 + /* Битовое поле RFP24, ширина 1 бит; данные RFP24. */ + Uint16 RFP24:1; // 24 RFP for Mailbox 24 + /* Битовое поле RFP25, ширина 1 бит; данные RFP25. */ + Uint16 RFP25:1; // 25 RFP for Mailbox 25 + /* Битовое поле RFP26, ширина 1 бит; данные RFP26. */ + Uint16 RFP26:1; // 26 RFP for Mailbox 26 + /* Битовое поле RFP27, ширина 1 бит; данные RFP27. */ + Uint16 RFP27:1; // 27 RFP for Mailbox 27 + /* Битовое поле RFP28, ширина 1 бит; данные RFP28. */ + Uint16 RFP28:1; // 28 RFP for Mailbox 28 + /* Битовое поле RFP29, ширина 1 бит; данные RFP29. */ + Uint16 RFP29:1; // 29 RFP for Mailbox 29 + /* Битовое поле RFP30, ширина 1 бит; данные RFP30. */ + Uint16 RFP30:1; // 30 RFP for Mailbox 30 + /* Битовое поле RFP31, ширина 1 бит; данные RFP31. */ + Uint16 RFP31:1; // 31 RFP for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRFP_REG в одной области памяти. */ +union CANRFP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRFP_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRFP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Global Acceptance Mask register (CANGAM) bit definitions */ +/* Описывает структуру CANGAM_BITS; порядок полей определяет расположение данных. */ +struct CANGAM_BITS { // bits description + /* Битовое поле GAM150, ширина 16 бит; данные GAM150. */ + Uint16 GAM150:16; // 15:0 Global acceptance mask bits 0-15 + /* Битовое поле GAM2816, ширина 13 бит; данные GAM2816. */ + Uint16 GAM2816:13; // 28:16 Global acceptance mask bits 16-28 + /* Битовое поле rsvd, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:2; // 30:29 reserved + /* Битовое поле AMI, ширина 1 бит; данные AMI. */ + Uint16 AMI:1; // 31 AMI bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGAM_REG в одной области памяти. */ +union CANGAM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGAM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGAM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Master Control register (CANMC) bit definitions */ +/* Описывает структуру CANMC_BITS; порядок полей определяет расположение данных. */ +struct CANMC_BITS { // bits description + /* Битовое поле MBNR, ширина 5 бит; данные MBNR. */ + Uint16 MBNR:5; // 4:0 MBX # for CDR bit + /* Битовое поле SRES, ширина 1 бит; данные SRES. */ + Uint16 SRES:1; // 5 Soft reset + /* Битовое поле STM, ширина 1 бит; данные STM. */ + Uint16 STM:1; // 6 Self-test mode + /* Битовое поле ABO, ширина 1 бит; данные ABO. */ + Uint16 ABO:1; // 7 Auto bus-on + /* Битовое поле CDR, ширина 1 бит; данные CDR. */ + Uint16 CDR:1; // 8 Change data request + /* Битовое поле WUBA, ширина 1 бит; данные WUBA. */ + Uint16 WUBA:1; // 9 Wake-up on bus activity + /* Битовое поле DBO, ширина 1 бит; данные DBO. */ + Uint16 DBO:1; // 10 Data-byte order + /* Битовое поле PDR, ширина 1 бит; данные PDR. */ + Uint16 PDR:1; // 11 Power-down mode request + /* Битовое поле CCR, ширина 1 бит; данные CCR. */ + Uint16 CCR:1; // 12 Change configuration request + /* Битовое поле SCB, ширина 1 бит; данные SCB. */ + Uint16 SCB:1; // 13 SCC compatibility bit + /* Битовое поле TCC, ширина 1 бит; данные TCC. */ + Uint16 TCC:1; // 14 TSC MSB clear bit + /* Битовое поле MBCC, ширина 1 бит; данные MBCC. */ + Uint16 MBCC:1; // 15 TSC clear bit thru mailbox 16 + /* Битовое поле SUSP, ширина 1 бит; данные SUSP. */ + Uint16 SUSP:1; // 16 SUSPEND free/soft bit + /* Битовое поле rsvd, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:15; // 31:17 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMC_REG в одной области памяти. */ +union CANMC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Bit -timing configuration register (CANBTC) bit definitions */ +/* Описывает структуру CANBTC_BITS; порядок полей определяет расположение данных. */ +struct CANBTC_BITS { // bits description + /* Битовое поле TSEG2REG, ширина 3 бит; данные TSEG2REG. */ + Uint16 TSEG2REG:3; // 2:0 TSEG2 register value + /* Битовое поле TSEG1REG, ширина 4 бит; данные TSEG1REG. */ + Uint16 TSEG1REG:4; // 6:3 TSEG1 register value + /* Битовое поле SAM, ширина 1 бит; данные SAM. */ + Uint16 SAM:1; // 7 Sample-point setting + /* Битовое поле SJWREG, ширина 2 бит; данные SJWREG. */ + Uint16 SJWREG:2; // 9:8 Synchroniztion Jump Width register value + /* Битовое поле rsvd1, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:6; // 15:10 reserved + /* Битовое поле BRPREG, ширина 8 бит; данные BRPREG. */ + Uint16 BRPREG:8; // 23:16 Baudrate prescaler register value + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 31:24 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANBTC_REG в одной области памяти. */ +union CANBTC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANBTC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANBTC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Error & Status register (CANES) bit definitions */ +/* Описывает структуру CANES_BITS; порядок полей определяет расположение данных. */ +struct CANES_BITS { // bits description + /* Битовое поле TM, ширина 1 бит; данные TM. */ + Uint16 TM:1; // 0 Transmit Mode + /* Битовое поле RM, ширина 1 бит; данные RM. */ + Uint16 RM:1; // 1 Receive Mode + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 2 reserved + /* Битовое поле PDA, ширина 1 бит; данные PDA. */ + Uint16 PDA:1; // 3 Power-down acknowledge + /* Битовое поле CCE, ширина 1 бит; данные CCE. */ + Uint16 CCE:1; // 4 Change Configuration Enable + /* Битовое поле SMA, ширина 1 бит; данные SMA. */ + Uint16 SMA:1; // 5 Suspend Mode Acknowledge + /* Битовое поле rsvd2, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:10; // 15:6 reserved + /* Битовое поле EW, ширина 1 бит; данные EW. */ + Uint16 EW:1; // 16 Warning status + /* Битовое поле EP, ширина 1 бит; данные EP. */ + Uint16 EP:1; // 17 Error Passive status + /* Битовое поле BO, ширина 1 бит; данные BO. */ + Uint16 BO:1; // 18 Bus-off status + /* Битовое поле ACKE, ширина 1 бит; данные ACKE. */ + Uint16 ACKE:1; // 19 Acknowledge error + /* Битовое поле SE, ширина 1 бит; данные SE. */ + Uint16 SE:1; // 20 Stuff error + /* Битовое поле CRCE, ширина 1 бит; данные CRCE. */ + Uint16 CRCE:1; // 21 CRC error + /* Битовое поле SA1, ширина 1 бит; данные SA1. */ + Uint16 SA1:1; // 22 Stuck at Dominant error + /* Битовое поле BE, ширина 1 бит; данные BE. */ + Uint16 BE:1; // 23 Bit error + /* Битовое поле FE, ширина 1 бит; данные FE. */ + Uint16 FE:1; // 24 Framing error + /* Битовое поле rsvd3, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:7; // 31:25 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANES_REG в одной области памяти. */ +union CANES_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANES_BITS bit;; порядок полей определяет расположение данных. */ + struct CANES_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Transmit Error Counter register (CANTEC) bit definitions */ +/* Описывает структуру CANTEC_BITS; порядок полей определяет расположение данных. */ +struct CANTEC_BITS { // bits description + /* Битовое поле TEC, ширина 8 бит; данные TEC. */ + Uint16 TEC:8; // 7:0 TEC + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved + /* Битовое поле rsvd2, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTEC_REG в одной области памяти. */ +union CANTEC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTEC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTEC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Receive Error Counter register (CANREC) bit definitions */ +/* Описывает структуру CANREC_BITS; порядок полей определяет расположение данных. */ +struct CANREC_BITS { // bits description + /* Битовое поле REC, ширина 8 бит; данные REC. */ + Uint16 REC:8; // 7:0 REC + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved + /* Битовое поле rsvd2, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANREC_REG в одной области памяти. */ +union CANREC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANREC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANREC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Global Interrupt Flag 0 (CANGIF0) bit definitions */ +/* Описывает структуру CANGIF0_BITS; порядок полей определяет расположение данных. */ +struct CANGIF0_BITS { // bits description + /* Битовое поле MIV0, ширина 5 бит; данные MIV0. */ + Uint16 MIV0:5; // 4:0 Mailbox Interrupt Vector + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved + /* Битовое поле WLIF0, ширина 1 бит; данные WLIF0. */ + Uint16 WLIF0:1; // 8 Warning level interrupt flag + /* Битовое поле EPIF0, ширина 1 бит; данные EPIF0. */ + Uint16 EPIF0:1; // 9 Error-passive interrupt flag + /* Битовое поле BOIF0, ширина 1 бит; данные BOIF0. */ + Uint16 BOIF0:1; // 10 Bus-off interrupt flag + /* Битовое поле RMLIF0, ширина 1 бит; данные RMLIF0. */ + Uint16 RMLIF0:1; // 11 Received message lost interrupt flag + /* Битовое поле WUIF0, ширина 1 бит; данные WUIF0. */ + Uint16 WUIF0:1; // 12 Wakeup interrupt flag + /* Битовое поле WDIF0, ширина 1 бит; данные WDIF0. */ + Uint16 WDIF0:1; // 13 Write denied interrupt flag + /* Битовое поле AAIF0, ширина 1 бит; данные AAIF0. */ + Uint16 AAIF0:1; // 14 Abort Ack interrupt flag + /* Битовое поле GMIF0, ширина 1 бит; данные GMIF0. */ + Uint16 GMIF0:1; // 15 Global MBX interrupt flag + /* Битовое поле TCOF0, ширина 1 бит; данные TCOF0. */ + Uint16 TCOF0:1; // 16 TSC Overflow flag + /* Битовое поле MTOF0, ширина 1 бит; данные MTOF0. */ + Uint16 MTOF0:1; // 17 Mailbox Timeout flag + /* Битовое поле rsvd2, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:14; // 31:18 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGIF0_REG в одной области памяти. */ +union CANGIF0_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGIF0_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGIF0_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Global Interrupt Mask register (CANGIM) bit definitions */ +/* Описывает структуру CANGIM_BITS; порядок полей определяет расположение данных. */ +struct CANGIM_BITS { // bits description + /* Битовое поле I0EN, ширина 1 бит; данные I0EN. */ + Uint16 I0EN:1; // 0 Interrupt 0 enable + /* Битовое поле I1EN, ширина 1 бит; данные I1EN. */ + Uint16 I1EN:1; // 1 Interrupt 1 enable + /* Битовое поле GIL, ширина 1 бит; данные GIL. */ + Uint16 GIL:1; // 2 Global Interrupt Level + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 7:3 reserved + /* Битовое поле WLIM, ширина 1 бит; данные WLIM. */ + Uint16 WLIM:1; // 8 Warning level interrupt mask + /* Битовое поле EPIM, ширина 1 бит; данные EPIM. */ + Uint16 EPIM:1; // 9 Error-passive interrupt mask + /* Битовое поле BOIM, ширина 1 бит; данные BOIM. */ + Uint16 BOIM:1; // 10 Bus-off interrupt mask + /* Битовое поле RMLIM, ширина 1 бит; данные RMLIM. */ + Uint16 RMLIM:1; // 11 Received message lost interrupt mask + /* Битовое поле WUIM, ширина 1 бит; данные WUIM. */ + Uint16 WUIM:1; // 12 Wakeup interrupt mask + /* Битовое поле WDIM, ширина 1 бит; данные WDIM. */ + Uint16 WDIM:1; // 13 Write denied interrupt mask + /* Битовое поле AAIM, ширина 1 бит; данные AAIM. */ + Uint16 AAIM:1; // 14 Abort Ack interrupt mask + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved + /* Битовое поле TCOM, ширина 1 бит; данные TCOM. */ + Uint16 TCOM:1; // 16 TSC overflow interrupt mask + /* Битовое поле MTOM, ширина 1 бит; данные MTOM. */ + Uint16 MTOM:1; // 17 MBX Timeout interrupt mask + /* Битовое поле rsvd3, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:14; // 31:18 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGIM_REG в одной области памяти. */ +union CANGIM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGIM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGIM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Global Interrupt Flag 1 (eCANGIF1) bit definitions */ +/* Описывает структуру CANGIF1_BITS; порядок полей определяет расположение данных. */ +struct CANGIF1_BITS { // bits description + /* Битовое поле MIV1, ширина 5 бит; данные MIV1. */ + Uint16 MIV1:5; // 4:0 Mailbox Interrupt Vector + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved + /* Битовое поле WLIF1, ширина 1 бит; данные WLIF1. */ + Uint16 WLIF1:1; // 8 Warning level interrupt flag + /* Битовое поле EPIF1, ширина 1 бит; данные EPIF1. */ + Uint16 EPIF1:1; // 9 Error-passive interrupt flag + /* Битовое поле BOIF1, ширина 1 бит; данные BOIF1. */ + Uint16 BOIF1:1; // 10 Bus-off interrupt flag + /* Битовое поле RMLIF1, ширина 1 бит; данные RMLIF1. */ + Uint16 RMLIF1:1; // 11 Received message lost interrupt flag + /* Битовое поле WUIF1, ширина 1 бит; данные WUIF1. */ + Uint16 WUIF1:1; // 12 Wakeup interrupt flag + /* Битовое поле WDIF1, ширина 1 бит; данные WDIF1. */ + Uint16 WDIF1:1; // 13 Write denied interrupt flag + /* Битовое поле AAIF1, ширина 1 бит; данные AAIF1. */ + Uint16 AAIF1:1; // 14 Abort Ack interrupt flag + /* Битовое поле GMIF1, ширина 1 бит; данные GMIF1. */ + Uint16 GMIF1:1; // 15 Global MBX interrupt flag + /* Битовое поле TCOF1, ширина 1 бит; данные TCOF1. */ + Uint16 TCOF1:1; // 16 TSC Overflow flag + /* Битовое поле MTOF1, ширина 1 бит; данные MTOF1. */ + Uint16 MTOF1:1; // 17 Mailbox Timeout flag + /* Битовое поле rsvd2, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:14; // 31:18 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANGIF1_REG в одной области памяти. */ +union CANGIF1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANGIF1_BITS bit;; порядок полей определяет расположение данных. */ + struct CANGIF1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Mailbox Interrupt Mask register (CANMIM) bit definitions */ +/* Описывает структуру CANMIM_BITS; порядок полей определяет расположение данных. */ +struct CANMIM_BITS { // bit description + /* Битовое поле MIM0, ширина 1 бит; данные MIM0. */ + Uint16 MIM0:1; // 0 MIM for Mailbox 0 + /* Битовое поле MIM1, ширина 1 бит; данные MIM1. */ + Uint16 MIM1:1; // 1 MIM for Mailbox 1 + /* Битовое поле MIM2, ширина 1 бит; данные MIM2. */ + Uint16 MIM2:1; // 2 MIM for Mailbox 2 + /* Битовое поле MIM3, ширина 1 бит; данные MIM3. */ + Uint16 MIM3:1; // 3 MIM for Mailbox 3 + /* Битовое поле MIM4, ширина 1 бит; данные MIM4. */ + Uint16 MIM4:1; // 4 MIM for Mailbox 4 + /* Битовое поле MIM5, ширина 1 бит; данные MIM5. */ + Uint16 MIM5:1; // 5 MIM for Mailbox 5 + /* Битовое поле MIM6, ширина 1 бит; данные MIM6. */ + Uint16 MIM6:1; // 6 MIM for Mailbox 6 + /* Битовое поле MIM7, ширина 1 бит; данные MIM7. */ + Uint16 MIM7:1; // 7 MIM for Mailbox 7 + /* Битовое поле MIM8, ширина 1 бит; данные MIM8. */ + Uint16 MIM8:1; // 8 MIM for Mailbox 8 + /* Битовое поле MIM9, ширина 1 бит; данные MIM9. */ + Uint16 MIM9:1; // 9 MIM for Mailbox 9 + /* Битовое поле MIM10, ширина 1 бит; данные MIM10. */ + Uint16 MIM10:1; // 10 MIM for Mailbox 10 + /* Битовое поле MIM11, ширина 1 бит; данные MIM11. */ + Uint16 MIM11:1; // 11 MIM for Mailbox 11 + /* Битовое поле MIM12, ширина 1 бит; данные MIM12. */ + Uint16 MIM12:1; // 12 MIM for Mailbox 12 + /* Битовое поле MIM13, ширина 1 бит; данные MIM13. */ + Uint16 MIM13:1; // 13 MIM for Mailbox 13 + /* Битовое поле MIM14, ширина 1 бит; данные MIM14. */ + Uint16 MIM14:1; // 14 MIM for Mailbox 14 + /* Битовое поле MIM15, ширина 1 бит; данные MIM15. */ + Uint16 MIM15:1; // 15 MIM for Mailbox 15 + /* Битовое поле MIM16, ширина 1 бит; данные MIM16. */ + Uint16 MIM16:1; // 16 MIM for Mailbox 16 + /* Битовое поле MIM17, ширина 1 бит; данные MIM17. */ + Uint16 MIM17:1; // 17 MIM for Mailbox 17 + /* Битовое поле MIM18, ширина 1 бит; данные MIM18. */ + Uint16 MIM18:1; // 18 MIM for Mailbox 18 + /* Битовое поле MIM19, ширина 1 бит; данные MIM19. */ + Uint16 MIM19:1; // 19 MIM for Mailbox 19 + /* Битовое поле MIM20, ширина 1 бит; данные MIM20. */ + Uint16 MIM20:1; // 20 MIM for Mailbox 20 + /* Битовое поле MIM21, ширина 1 бит; данные MIM21. */ + Uint16 MIM21:1; // 21 MIM for Mailbox 21 + /* Битовое поле MIM22, ширина 1 бит; данные MIM22. */ + Uint16 MIM22:1; // 22 MIM for Mailbox 22 + /* Битовое поле MIM23, ширина 1 бит; данные MIM23. */ + Uint16 MIM23:1; // 23 MIM for Mailbox 23 + /* Битовое поле MIM24, ширина 1 бит; данные MIM24. */ + Uint16 MIM24:1; // 24 MIM for Mailbox 24 + /* Битовое поле MIM25, ширина 1 бит; данные MIM25. */ + Uint16 MIM25:1; // 25 MIM for Mailbox 25 + /* Битовое поле MIM26, ширина 1 бит; данные MIM26. */ + Uint16 MIM26:1; // 26 MIM for Mailbox 26 + /* Битовое поле MIM27, ширина 1 бит; данные MIM27. */ + Uint16 MIM27:1; // 27 MIM for Mailbox 27 + /* Битовое поле MIM28, ширина 1 бит; данные MIM28. */ + Uint16 MIM28:1; // 28 MIM for Mailbox 28 + /* Битовое поле MIM29, ширина 1 бит; данные MIM29. */ + Uint16 MIM29:1; // 29 MIM for Mailbox 29 + /* Битовое поле MIM30, ширина 1 бит; данные MIM30. */ + Uint16 MIM30:1; // 30 MIM for Mailbox 30 + /* Битовое поле MIM31, ширина 1 бит; данные MIM31. */ + Uint16 MIM31:1; // 31 MIM for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMIM_REG в одной области памяти. */ +union CANMIM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMIM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMIM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Mailbox Interrupt Level register (CANMIL) bit definitions */ +/* Описывает структуру CANMIL_BITS; порядок полей определяет расположение данных. */ +struct CANMIL_BITS { // bit description + /* Битовое поле MIL0, ширина 1 бит; данные MIL0. */ + Uint16 MIL0:1; // 0 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL1, ширина 1 бит; данные MIL1. */ + Uint16 MIL1:1; // 1 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL2, ширина 1 бит; данные MIL2. */ + Uint16 MIL2:1; // 2 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL3, ширина 1 бит; данные MIL3. */ + Uint16 MIL3:1; // 3 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL4, ширина 1 бит; данные MIL4. */ + Uint16 MIL4:1; // 4 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL5, ширина 1 бит; данные MIL5. */ + Uint16 MIL5:1; // 5 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL6, ширина 1 бит; данные MIL6. */ + Uint16 MIL6:1; // 6 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL7, ширина 1 бит; данные MIL7. */ + Uint16 MIL7:1; // 7 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL8, ширина 1 бит; данные MIL8. */ + Uint16 MIL8:1; // 8 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL9, ширина 1 бит; данные MIL9. */ + Uint16 MIL9:1; // 9 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL10, ширина 1 бит; данные MIL10. */ + Uint16 MIL10:1; // 10 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL11, ширина 1 бит; данные MIL11. */ + Uint16 MIL11:1; // 11 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL12, ширина 1 бит; данные MIL12. */ + Uint16 MIL12:1; // 12 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL13, ширина 1 бит; данные MIL13. */ + Uint16 MIL13:1; // 13 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL14, ширина 1 бит; данные MIL14. */ + Uint16 MIL14:1; // 14 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL15, ширина 1 бит; данные MIL15. */ + Uint16 MIL15:1; // 15 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL16, ширина 1 бит; данные MIL16. */ + Uint16 MIL16:1; // 16 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL17, ширина 1 бит; данные MIL17. */ + Uint16 MIL17:1; // 17 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL18, ширина 1 бит; данные MIL18. */ + Uint16 MIL18:1; // 18 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL19, ширина 1 бит; данные MIL19. */ + Uint16 MIL19:1; // 19 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL20, ширина 1 бит; данные MIL20. */ + Uint16 MIL20:1; // 20 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL21, ширина 1 бит; данные MIL21. */ + Uint16 MIL21:1; // 21 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL22, ширина 1 бит; данные MIL22. */ + Uint16 MIL22:1; // 22 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL23, ширина 1 бит; данные MIL23. */ + Uint16 MIL23:1; // 23 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL24, ширина 1 бит; данные MIL24. */ + Uint16 MIL24:1; // 24 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL25, ширина 1 бит; данные MIL25. */ + Uint16 MIL25:1; // 25 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL26, ширина 1 бит; данные MIL26. */ + Uint16 MIL26:1; // 26 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL27, ширина 1 бит; данные MIL27. */ + Uint16 MIL27:1; // 27 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL28, ширина 1 бит; данные MIL28. */ + Uint16 MIL28:1; // 28 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL29, ширина 1 бит; данные MIL29. */ + Uint16 MIL29:1; // 29 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL30, ширина 1 бит; данные MIL30. */ + Uint16 MIL30:1; // 30 0 -> Int 9.5 1 -> Int 9.6 + /* Битовое поле MIL31, ширина 1 бит; данные MIL31. */ + Uint16 MIL31:1; // 31 0 -> Int 9.5 1 -> Int 9.6 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMIL_REG в одной области памяти. */ +union CANMIL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMIL_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMIL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Overwrite Protection Control register (CANOPC) bit definitions */ +/* Описывает структуру CANOPC_BITS; порядок полей определяет расположение данных. */ +struct CANOPC_BITS { // bit description + /* Битовое поле OPC0, ширина 1 бит; данные OPC0. */ + Uint16 OPC0:1; // 0 OPC for Mailbox 0 + /* Битовое поле OPC1, ширина 1 бит; данные OPC1. */ + Uint16 OPC1:1; // 1 OPC for Mailbox 1 + /* Битовое поле OPC2, ширина 1 бит; данные OPC2. */ + Uint16 OPC2:1; // 2 OPC for Mailbox 2 + /* Битовое поле OPC3, ширина 1 бит; данные OPC3. */ + Uint16 OPC3:1; // 3 OPC for Mailbox 3 + /* Битовое поле OPC4, ширина 1 бит; данные OPC4. */ + Uint16 OPC4:1; // 4 OPC for Mailbox 4 + /* Битовое поле OPC5, ширина 1 бит; данные OPC5. */ + Uint16 OPC5:1; // 5 OPC for Mailbox 5 + /* Битовое поле OPC6, ширина 1 бит; данные OPC6. */ + Uint16 OPC6:1; // 6 OPC for Mailbox 6 + /* Битовое поле OPC7, ширина 1 бит; данные OPC7. */ + Uint16 OPC7:1; // 7 OPC for Mailbox 7 + /* Битовое поле OPC8, ширина 1 бит; данные OPC8. */ + Uint16 OPC8:1; // 8 OPC for Mailbox 8 + /* Битовое поле OPC9, ширина 1 бит; данные OPC9. */ + Uint16 OPC9:1; // 9 OPC for Mailbox 9 + /* Битовое поле OPC10, ширина 1 бит; данные OPC10. */ + Uint16 OPC10:1; // 10 OPC for Mailbox 10 + /* Битовое поле OPC11, ширина 1 бит; данные OPC11. */ + Uint16 OPC11:1; // 11 OPC for Mailbox 11 + /* Битовое поле OPC12, ширина 1 бит; данные OPC12. */ + Uint16 OPC12:1; // 12 OPC for Mailbox 12 + /* Битовое поле OPC13, ширина 1 бит; данные OPC13. */ + Uint16 OPC13:1; // 13 OPC for Mailbox 13 + /* Битовое поле OPC14, ширина 1 бит; данные OPC14. */ + Uint16 OPC14:1; // 14 OPC for Mailbox 14 + /* Битовое поле OPC15, ширина 1 бит; данные OPC15. */ + Uint16 OPC15:1; // 15 OPC for Mailbox 15 + /* Битовое поле OPC16, ширина 1 бит; данные OPC16. */ + Uint16 OPC16:1; // 16 OPC for Mailbox 16 + /* Битовое поле OPC17, ширина 1 бит; данные OPC17. */ + Uint16 OPC17:1; // 17 OPC for Mailbox 17 + /* Битовое поле OPC18, ширина 1 бит; данные OPC18. */ + Uint16 OPC18:1; // 18 OPC for Mailbox 18 + /* Битовое поле OPC19, ширина 1 бит; данные OPC19. */ + Uint16 OPC19:1; // 19 OPC for Mailbox 19 + /* Битовое поле OPC20, ширина 1 бит; данные OPC20. */ + Uint16 OPC20:1; // 20 OPC for Mailbox 20 + /* Битовое поле OPC21, ширина 1 бит; данные OPC21. */ + Uint16 OPC21:1; // 21 OPC for Mailbox 21 + /* Битовое поле OPC22, ширина 1 бит; данные OPC22. */ + Uint16 OPC22:1; // 22 OPC for Mailbox 22 + /* Битовое поле OPC23, ширина 1 бит; данные OPC23. */ + Uint16 OPC23:1; // 23 OPC for Mailbox 23 + /* Битовое поле OPC24, ширина 1 бит; данные OPC24. */ + Uint16 OPC24:1; // 24 OPC for Mailbox 24 + /* Битовое поле OPC25, ширина 1 бит; данные OPC25. */ + Uint16 OPC25:1; // 25 OPC for Mailbox 25 + /* Битовое поле OPC26, ширина 1 бит; данные OPC26. */ + Uint16 OPC26:1; // 26 OPC for Mailbox 26 + /* Битовое поле OPC27, ширина 1 бит; данные OPC27. */ + Uint16 OPC27:1; // 27 OPC for Mailbox 27 + /* Битовое поле OPC28, ширина 1 бит; данные OPC28. */ + Uint16 OPC28:1; // 28 OPC for Mailbox 28 + /* Битовое поле OPC29, ширина 1 бит; данные OPC29. */ + Uint16 OPC29:1; // 29 OPC for Mailbox 29 + /* Битовое поле OPC30, ширина 1 бит; данные OPC30. */ + Uint16 OPC30:1; // 30 OPC for Mailbox 30 + /* Битовое поле OPC31, ширина 1 бит; данные OPC31. */ + Uint16 OPC31:1; // 31 OPC for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANOPC_REG в одной области памяти. */ +union CANOPC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANOPC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANOPC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN TX I/O Control Register (CANTIOC) bit definitions */ +/* Описывает структуру CANTIOC_BITS; порядок полей определяет расположение данных. */ +struct CANTIOC_BITS { // bits description + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 2:0 reserved + /* Битовое поле TXFUNC, ширина 1 бит; данные TXFUNC. */ + Uint16 TXFUNC:1; // 3 TXFUNC + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved + /* Битовое поле rsvd3, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTIOC_REG в одной области памяти. */ +union CANTIOC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTIOC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTIOC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN RX I/O Control Register (CANRIOC) bit definitions */ +/* Описывает структуру CANRIOC_BITS; порядок полей определяет расположение данных. */ +struct CANRIOC_BITS { // bits description + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 2:0 reserved + /* Битовое поле RXFUNC, ширина 1 бит; данные RXFUNC. */ + Uint16 RXFUNC:1; // 3 RXFUNC + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved + /* Битовое поле rsvd3, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANRIOC_REG в одной области памяти. */ +union CANRIOC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANRIOC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANRIOC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Time-out Control register (CANTOC) bit definitions */ +/* Описывает структуру CANTOC_BITS; порядок полей определяет расположение данных. */ +struct CANTOC_BITS { // bit description + /* Битовое поле TOC0, ширина 1 бит; данные TOC0. */ + Uint16 TOC0:1; // 0 TOC for Mailbox 0 + /* Битовое поле TOC1, ширина 1 бит; данные TOC1. */ + Uint16 TOC1:1; // 1 TOC for Mailbox 1 + /* Битовое поле TOC2, ширина 1 бит; данные TOC2. */ + Uint16 TOC2:1; // 2 TOC for Mailbox 2 + /* Битовое поле TOC3, ширина 1 бит; данные TOC3. */ + Uint16 TOC3:1; // 3 TOC for Mailbox 3 + /* Битовое поле TOC4, ширина 1 бит; данные TOC4. */ + Uint16 TOC4:1; // 4 TOC for Mailbox 4 + /* Битовое поле TOC5, ширина 1 бит; данные TOC5. */ + Uint16 TOC5:1; // 5 TOC for Mailbox 5 + /* Битовое поле TOC6, ширина 1 бит; данные TOC6. */ + Uint16 TOC6:1; // 6 TOC for Mailbox 6 + /* Битовое поле TOC7, ширина 1 бит; данные TOC7. */ + Uint16 TOC7:1; // 7 TOC for Mailbox 7 + /* Битовое поле TOC8, ширина 1 бит; данные TOC8. */ + Uint16 TOC8:1; // 8 TOC for Mailbox 8 + /* Битовое поле TOC9, ширина 1 бит; данные TOC9. */ + Uint16 TOC9:1; // 9 TOC for Mailbox 9 + /* Битовое поле TOC10, ширина 1 бит; данные TOC10. */ + Uint16 TOC10:1; // 10 TOC for Mailbox 10 + /* Битовое поле TOC11, ширина 1 бит; данные TOC11. */ + Uint16 TOC11:1; // 11 TOC for Mailbox 11 + /* Битовое поле TOC12, ширина 1 бит; данные TOC12. */ + Uint16 TOC12:1; // 12 TOC for Mailbox 12 + /* Битовое поле TOC13, ширина 1 бит; данные TOC13. */ + Uint16 TOC13:1; // 13 TOC for Mailbox 13 + /* Битовое поле TOC14, ширина 1 бит; данные TOC14. */ + Uint16 TOC14:1; // 14 TOC for Mailbox 14 + /* Битовое поле TOC15, ширина 1 бит; данные TOC15. */ + Uint16 TOC15:1; // 15 TOC for Mailbox 15 + /* Битовое поле TOC16, ширина 1 бит; данные TOC16. */ + Uint16 TOC16:1; // 16 TOC for Mailbox 16 + /* Битовое поле TOC17, ширина 1 бит; данные TOC17. */ + Uint16 TOC17:1; // 17 TOC for Mailbox 17 + /* Битовое поле TOC18, ширина 1 бит; данные TOC18. */ + Uint16 TOC18:1; // 18 TOC for Mailbox 18 + /* Битовое поле TOC19, ширина 1 бит; данные TOC19. */ + Uint16 TOC19:1; // 19 TOC for Mailbox 19 + /* Битовое поле TOC20, ширина 1 бит; данные TOC20. */ + Uint16 TOC20:1; // 20 TOC for Mailbox 20 + /* Битовое поле TOC21, ширина 1 бит; данные TOC21. */ + Uint16 TOC21:1; // 21 TOC for Mailbox 21 + /* Битовое поле TOC22, ширина 1 бит; данные TOC22. */ + Uint16 TOC22:1; // 22 TOC for Mailbox 22 + /* Битовое поле TOC23, ширина 1 бит; данные TOC23. */ + Uint16 TOC23:1; // 23 TOC for Mailbox 23 + /* Битовое поле TOC24, ширина 1 бит; данные TOC24. */ + Uint16 TOC24:1; // 24 TOC for Mailbox 24 + /* Битовое поле TOC25, ширина 1 бит; данные TOC25. */ + Uint16 TOC25:1; // 25 TOC for Mailbox 25 + /* Битовое поле TOC26, ширина 1 бит; данные TOC26. */ + Uint16 TOC26:1; // 26 TOC for Mailbox 26 + /* Битовое поле TOC27, ширина 1 бит; данные TOC27. */ + Uint16 TOC27:1; // 27 TOC for Mailbox 27 + /* Битовое поле TOC28, ширина 1 бит; данные TOC28. */ + Uint16 TOC28:1; // 28 TOC for Mailbox 28 + /* Битовое поле TOC29, ширина 1 бит; данные TOC29. */ + Uint16 TOC29:1; // 29 TOC for Mailbox 29 + /* Битовое поле TOC30, ширина 1 бит; данные TOC30. */ + Uint16 TOC30:1; // 30 TOC for Mailbox 30 + /* Битовое поле TOC31, ширина 1 бит; данные TOC31. */ + Uint16 TOC31:1; // 31 TOC for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTOC_REG в одной области памяти. */ +union CANTOC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTOC_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTOC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* eCAN Time-out Status register (CANTOS) bit definitions */ +/* Описывает структуру CANTOS_BITS; порядок полей определяет расположение данных. */ +struct CANTOS_BITS { // bit description + /* Битовое поле TOS0, ширина 1 бит; данные TOS0. */ + Uint16 TOS0:1; // 0 TOS for Mailbox 0 + /* Битовое поле TOS1, ширина 1 бит; данные TOS1. */ + Uint16 TOS1:1; // 1 TOS for Mailbox 1 + /* Битовое поле TOS2, ширина 1 бит; данные TOS2. */ + Uint16 TOS2:1; // 2 TOS for Mailbox 2 + /* Битовое поле TOS3, ширина 1 бит; данные TOS3. */ + Uint16 TOS3:1; // 3 TOS for Mailbox 3 + /* Битовое поле TOS4, ширина 1 бит; данные TOS4. */ + Uint16 TOS4:1; // 4 TOS for Mailbox 4 + /* Битовое поле TOS5, ширина 1 бит; данные TOS5. */ + Uint16 TOS5:1; // 5 TOS for Mailbox 5 + /* Битовое поле TOS6, ширина 1 бит; данные TOS6. */ + Uint16 TOS6:1; // 6 TOS for Mailbox 6 + /* Битовое поле TOS7, ширина 1 бит; данные TOS7. */ + Uint16 TOS7:1; // 7 TOS for Mailbox 7 + /* Битовое поле TOS8, ширина 1 бит; данные TOS8. */ + Uint16 TOS8:1; // 8 TOS for Mailbox 8 + /* Битовое поле TOS9, ширина 1 бит; данные TOS9. */ + Uint16 TOS9:1; // 9 TOS for Mailbox 9 + /* Битовое поле TOS10, ширина 1 бит; данные TOS10. */ + Uint16 TOS10:1; // 10 TOS for Mailbox 10 + /* Битовое поле TOS11, ширина 1 бит; данные TOS11. */ + Uint16 TOS11:1; // 11 TOS for Mailbox 11 + /* Битовое поле TOS12, ширина 1 бит; данные TOS12. */ + Uint16 TOS12:1; // 12 TOS for Mailbox 12 + /* Битовое поле TOS13, ширина 1 бит; данные TOS13. */ + Uint16 TOS13:1; // 13 TOS for Mailbox 13 + /* Битовое поле TOS14, ширина 1 бит; данные TOS14. */ + Uint16 TOS14:1; // 14 TOS for Mailbox 14 + /* Битовое поле TOS15, ширина 1 бит; данные TOS15. */ + Uint16 TOS15:1; // 15 TOS for Mailbox 15 + /* Битовое поле TOS16, ширина 1 бит; данные TOS16. */ + Uint16 TOS16:1; // 16 TOS for Mailbox 16 + /* Битовое поле TOS17, ширина 1 бит; данные TOS17. */ + Uint16 TOS17:1; // 17 TOS for Mailbox 17 + /* Битовое поле TOS18, ширина 1 бит; данные TOS18. */ + Uint16 TOS18:1; // 18 TOS for Mailbox 18 + /* Битовое поле TOS19, ширина 1 бит; данные TOS19. */ + Uint16 TOS19:1; // 19 TOS for Mailbox 19 + /* Битовое поле TOS20, ширина 1 бит; данные TOS20. */ + Uint16 TOS20:1; // 20 TOS for Mailbox 20 + /* Битовое поле TOS21, ширина 1 бит; данные TOS21. */ + Uint16 TOS21:1; // 21 TOS for Mailbox 21 + /* Битовое поле TOS22, ширина 1 бит; данные TOS22. */ + Uint16 TOS22:1; // 22 TOS for Mailbox 22 + /* Битовое поле TOS23, ширина 1 бит; данные TOS23. */ + Uint16 TOS23:1; // 23 TOS for Mailbox 23 + /* Битовое поле TOS24, ширина 1 бит; данные TOS24. */ + Uint16 TOS24:1; // 24 TOS for Mailbox 24 + /* Битовое поле TOS25, ширина 1 бит; данные TOS25. */ + Uint16 TOS25:1; // 25 TOS for Mailbox 25 + /* Битовое поле TOS26, ширина 1 бит; данные TOS26. */ + Uint16 TOS26:1; // 26 TOS for Mailbox 26 + /* Битовое поле TOS27, ширина 1 бит; данные TOS27. */ + Uint16 TOS27:1; // 27 TOS for Mailbox 27 + /* Битовое поле TOS28, ширина 1 бит; данные TOS28. */ + Uint16 TOS28:1; // 28 TOS for Mailbox 28 + /* Битовое поле TOS29, ширина 1 бит; данные TOS29. */ + Uint16 TOS29:1; // 29 TOS for Mailbox 29 + /* Битовое поле TOS30, ширина 1 бит; данные TOS30. */ + Uint16 TOS30:1; // 30 TOS for Mailbox 30 + /* Битовое поле TOS31, ширина 1 бит; данные TOS31. */ + Uint16 TOS31:1; // 31 TOS for Mailbox 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANTOS_REG в одной области памяти. */ +union CANTOS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANTOS_BITS bit;; порядок полей определяет расположение данных. */ + struct CANTOS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/**************************************/ +/* eCAN Control & Status register file */ +/**************************************/ + +/* Описывает структуру ECAN_REGS; порядок полей определяет расположение данных. */ +struct ECAN_REGS { + /* Объединяет несколько представлений CANME_REG CANME; в одной области памяти. */ + union CANME_REG CANME; // Mailbox Enable + /* Объединяет несколько представлений CANMD_REG CANMD; в одной области памяти. */ + union CANMD_REG CANMD; // Mailbox Direction + /* Объединяет несколько представлений CANTRS_REG CANTRS; в одной области памяти. */ + union CANTRS_REG CANTRS; // Transmit Request Set + /* Объединяет несколько представлений CANTRR_REG CANTRR; в одной области памяти. */ + union CANTRR_REG CANTRR; // Transmit Request Reset + /* Объединяет несколько представлений CANTA_REG CANTA; в одной области памяти. */ + union CANTA_REG CANTA; // Transmit Acknowledge + /* Объединяет несколько представлений CANAA_REG CANAA; в одной области памяти. */ + union CANAA_REG CANAA; // Abort Acknowledge + /* Объединяет несколько представлений CANRMP_REG CANRMP; в одной области памяти. */ + union CANRMP_REG CANRMP; // Received Message Pending + /* Объединяет несколько представлений CANRML_REG CANRML; в одной области памяти. */ + union CANRML_REG CANRML; // Received Message Lost + /* Объединяет несколько представлений CANRFP_REG CANRFP; в одной области памяти. */ + union CANRFP_REG CANRFP; // Remote Frame Pending + /* Объединяет несколько представлений CANGAM_REG CANGAM; в одной области памяти. */ + union CANGAM_REG CANGAM; // Global Acceptance Mask + /* Объединяет несколько представлений CANMC_REG CANMC; в одной области памяти. */ + union CANMC_REG CANMC; // Master Control + /* Объединяет несколько представлений CANBTC_REG CANBTC; в одной области памяти. */ + union CANBTC_REG CANBTC; // Bit Timing + /* Объединяет несколько представлений CANES_REG CANES; в одной области памяти. */ + union CANES_REG CANES; // Error Status + /* Объединяет несколько представлений CANTEC_REG CANTEC; в одной области памяти. */ + union CANTEC_REG CANTEC; // Transmit Error Counter + /* Объединяет несколько представлений CANREC_REG CANREC; в одной области памяти. */ + union CANREC_REG CANREC; // Receive Error Counter + /* Объединяет несколько представлений CANGIF0_REG CANGIF0; в одной области памяти. */ + union CANGIF0_REG CANGIF0; // Global Interrupt Flag 0 + /* Объединяет несколько представлений CANGIM_REG CANGIM; в одной области памяти. */ + union CANGIM_REG CANGIM; // Global Interrupt Mask 0 + /* Объединяет несколько представлений CANGIF1_REG CANGIF1; в одной области памяти. */ + union CANGIF1_REG CANGIF1; // Global Interrupt Flag 1 + /* Объединяет несколько представлений CANMIM_REG CANMIM; в одной области памяти. */ + union CANMIM_REG CANMIM; // Mailbox Interrupt Mask + /* Объединяет несколько представлений CANMIL_REG CANMIL; в одной области памяти. */ + union CANMIL_REG CANMIL; // Mailbox Interrupt Level + /* Объединяет несколько представлений CANOPC_REG CANOPC; в одной области памяти. */ + union CANOPC_REG CANOPC; // Overwrite Protection Control + /* Объединяет несколько представлений CANTIOC_REG CANTIOC; в одной области памяти. */ + union CANTIOC_REG CANTIOC; // TX I/O Control + /* Объединяет несколько представлений CANRIOC_REG CANRIOC; в одной области памяти. */ + union CANRIOC_REG CANRIOC; // RX I/O Control + /* Объявляет CANTSC — данные CANTSC. */ + Uint32 CANTSC; // Time-stamp counter + /* Объединяет несколько представлений CANTOC_REG CANTOC; в одной области памяти. */ + union CANTOC_REG CANTOC; // Time-out Control + /* Объединяет несколько представлений CANTOS_REG CANTOS; в одной области памяти. */ + union CANTOS_REG CANTOS; // Time-out Status + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* --------------------------------------------------- */ +/* eCAN Mailbox Registers */ +/* ----------------------------------------------------*/ + +/* eCAN Message ID (MSGID) bit definitions */ +/* Описывает структуру CANMSGID_BITS; порядок полей определяет расположение данных. */ +struct CANMSGID_BITS { // bits description + /* Битовое поле EXTMSGID_L, ширина 16 бит; данные EXTMSGID_L. */ + Uint16 EXTMSGID_L:16; // 0:15 + /* Битовое поле EXTMSGID_H, ширина 2 бит; данные EXTMSGID_H. */ + Uint16 EXTMSGID_H:2; // 16:17 + /* Битовое поле STDMSGID, ширина 11 бит; данные STDMSGID. */ + Uint16 STDMSGID:11; // 18:28 + /* Битовое поле AAM, ширина 1 бит; данные AAM. */ + Uint16 AAM:1; // 29 + /* Битовое поле AME, ширина 1 бит; данные AME. */ + Uint16 AME:1; // 30 + /* Битовое поле IDE, ширина 1 бит; данные IDE. */ + Uint16 IDE:1; // 31 + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMSGID_REG в одной области памяти. */ +union CANMSGID_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMSGID_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMSGID_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Control Register (MSGCTRL) bit definitions */ +/* Описывает структуру CANMSGCTRL_BITS; порядок полей определяет расположение данных. */ +struct CANMSGCTRL_BITS { // bits description + /* Битовое поле DLC, ширина 4 бит; данные DLC. */ + Uint16 DLC:4; // 0:3 + /* Битовое поле RTR, ширина 1 бит; данные RTR. */ + Uint16 RTR:1; // 4 + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved + /* Битовое поле TPL, ширина 5 бит; данные TPL. */ + Uint16 TPL:5; // 12:8 + /* Битовое поле rsvd2, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:3; // 15:13 reserved + /* Битовое поле rsvd3, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMSGCTRL_REG в одной области памяти. */ +union CANMSGCTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMSGCTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct CANMSGCTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Data Register low (MDR_L) word definitions */ +/* Описывает структуру CANMDL_WORDS; порядок полей определяет расположение данных. */ +struct CANMDL_WORDS { // bits description + /* Битовое поле LOW_WORD, ширина 16 бит; LOW слово. */ + Uint16 LOW_WORD:16; // 0:15 + /* Битовое поле HI_WORD, ширина 16 бит; HI слово. */ + Uint16 HI_WORD:16; // 31:16 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Data Register low (MDR_L) byte definitions */ +/* Описывает структуру CANMDL_BYTES; порядок полей определяет расположение данных. */ +struct CANMDL_BYTES { // bits description + /* Битовое поле BYTE3, ширина 8 бит; данные BYTE3. */ + Uint16 BYTE3:8; // 31:24 + /* Битовое поле BYTE2, ширина 8 бит; данные BYTE2. */ + Uint16 BYTE2:8; // 23:16 + /* Битовое поле BYTE1, ширина 8 бит; данные BYTE1. */ + Uint16 BYTE1:8; // 15:8 + /* Битовое поле BYTE0, ширина 8 бит; данные BYTE0. */ + Uint16 BYTE0:8; // 7:0 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Allow access to the bit fields or entire register */ + +/* Объединяет несколько представлений CANMDL_REG в одной области памяти. */ +union CANMDL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMDL_WORDS word;; порядок полей определяет расположение данных. */ + struct CANMDL_WORDS word; + /* Описывает структуру CANMDL_BYTES byte;; порядок полей определяет расположение данных. */ + struct CANMDL_BYTES byte; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +/* eCAN Message Data Register high (MDR_H) word definitions */ +/* Описывает структуру CANMDH_WORDS; порядок полей определяет расположение данных. */ +struct CANMDH_WORDS { // bits description + /* Битовое поле LOW_WORD, ширина 16 бит; LOW слово. */ + Uint16 LOW_WORD:16; // 0:15 + /* Битовое поле HI_WORD, ширина 16 бит; HI слово. */ + Uint16 HI_WORD:16; // 31:16 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Message Data Register low (MDR_H) byte definitions */ +/* Описывает структуру CANMDH_BYTES; порядок полей определяет расположение данных. */ +struct CANMDH_BYTES { // bits description + /* Битовое поле BYTE7, ширина 8 бит; данные BYTE7. */ + Uint16 BYTE7:8; // 63:56 + /* Битовое поле BYTE6, ширина 8 бит; данные BYTE6. */ + Uint16 BYTE6:8; // 55:48 + /* Битовое поле BYTE5, ширина 8 бит; данные BYTE5. */ + Uint16 BYTE5:8; // 47:40 + /* Битовое поле BYTE4, ширина 8 бит; данные BYTE4. */ + Uint16 BYTE4:8; // 39:32 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANMDH_REG в одной области памяти. */ +union CANMDH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANMDH_WORDS word;; порядок полей определяет расположение данных. */ + struct CANMDH_WORDS word; + /* Описывает структуру CANMDH_BYTES byte;; порядок полей определяет расположение данных. */ + struct CANMDH_BYTES byte; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру MBOX; порядок полей определяет расположение данных. */ +struct MBOX { + /* Объединяет несколько представлений CANMSGID_REG MSGID; в одной области памяти. */ + union CANMSGID_REG MSGID; + /* Объединяет несколько представлений CANMSGCTRL_REG MSGCTRL; в одной области памяти. */ + union CANMSGCTRL_REG MSGCTRL; + /* Объединяет несколько представлений CANMDL_REG MDL; в одной области памяти. */ + union CANMDL_REG MDL; + /* Объединяет несколько представлений CANMDH_REG MDH; в одной области памяти. */ + union CANMDH_REG MDH; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/**************************************/ +/* eCAN Mailboxes */ +/**************************************/ + +/* Описывает структуру ECAN_MBOXES; порядок полей определяет расположение данных. */ +struct ECAN_MBOXES { + /* Описывает структуру MBOX MBOX0;; порядок полей определяет расположение данных. */ + struct MBOX MBOX0; + /* Описывает структуру MBOX MBOX1;; порядок полей определяет расположение данных. */ + struct MBOX MBOX1; + /* Описывает структуру MBOX MBOX2;; порядок полей определяет расположение данных. */ + struct MBOX MBOX2; + /* Описывает структуру MBOX MBOX3;; порядок полей определяет расположение данных. */ + struct MBOX MBOX3; + /* Описывает структуру MBOX MBOX4;; порядок полей определяет расположение данных. */ + struct MBOX MBOX4; + /* Описывает структуру MBOX MBOX5;; порядок полей определяет расположение данных. */ + struct MBOX MBOX5; + /* Описывает структуру MBOX MBOX6;; порядок полей определяет расположение данных. */ + struct MBOX MBOX6; + /* Описывает структуру MBOX MBOX7;; порядок полей определяет расположение данных. */ + struct MBOX MBOX7; + /* Описывает структуру MBOX MBOX8;; порядок полей определяет расположение данных. */ + struct MBOX MBOX8; + /* Описывает структуру MBOX MBOX9;; порядок полей определяет расположение данных. */ + struct MBOX MBOX9; + /* Описывает структуру MBOX MBOX10;; порядок полей определяет расположение данных. */ + struct MBOX MBOX10; + /* Описывает структуру MBOX MBOX11;; порядок полей определяет расположение данных. */ + struct MBOX MBOX11; + /* Описывает структуру MBOX MBOX12;; порядок полей определяет расположение данных. */ + struct MBOX MBOX12; + /* Описывает структуру MBOX MBOX13;; порядок полей определяет расположение данных. */ + struct MBOX MBOX13; + /* Описывает структуру MBOX MBOX14;; порядок полей определяет расположение данных. */ + struct MBOX MBOX14; + /* Описывает структуру MBOX MBOX15;; порядок полей определяет расположение данных. */ + struct MBOX MBOX15; + /* Описывает структуру MBOX MBOX16;; порядок полей определяет расположение данных. */ + struct MBOX MBOX16; + /* Описывает структуру MBOX MBOX17;; порядок полей определяет расположение данных. */ + struct MBOX MBOX17; + /* Описывает структуру MBOX MBOX18;; порядок полей определяет расположение данных. */ + struct MBOX MBOX18; + /* Описывает структуру MBOX MBOX19;; порядок полей определяет расположение данных. */ + struct MBOX MBOX19; + /* Описывает структуру MBOX MBOX20;; порядок полей определяет расположение данных. */ + struct MBOX MBOX20; + /* Описывает структуру MBOX MBOX21;; порядок полей определяет расположение данных. */ + struct MBOX MBOX21; + /* Описывает структуру MBOX MBOX22;; порядок полей определяет расположение данных. */ + struct MBOX MBOX22; + /* Описывает структуру MBOX MBOX23;; порядок полей определяет расположение данных. */ + struct MBOX MBOX23; + /* Описывает структуру MBOX MBOX24;; порядок полей определяет расположение данных. */ + struct MBOX MBOX24; + /* Описывает структуру MBOX MBOX25;; порядок полей определяет расположение данных. */ + struct MBOX MBOX25; + /* Описывает структуру MBOX MBOX26;; порядок полей определяет расположение данных. */ + struct MBOX MBOX26; + /* Описывает структуру MBOX MBOX27;; порядок полей определяет расположение данных. */ + struct MBOX MBOX27; + /* Описывает структуру MBOX MBOX28;; порядок полей определяет расположение данных. */ + struct MBOX MBOX28; + /* Описывает структуру MBOX MBOX29;; порядок полей определяет расположение данных. */ + struct MBOX MBOX29; + /* Описывает структуру MBOX MBOX30;; порядок полей определяет расположение данных. */ + struct MBOX MBOX30; + /* Описывает структуру MBOX MBOX31;; порядок полей определяет расположение данных. */ + struct MBOX MBOX31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* eCAN Local Acceptance Mask (LAM) bit definitions */ +/* Описывает структуру CANLAM_BITS; порядок полей определяет расположение данных. */ +struct CANLAM_BITS { // bits description + /* Битовое поле LAM_L, ширина 16 бит; данные LAM_L. */ + Uint16 LAM_L:16; // 0:15 + /* Битовое поле LAM_H, ширина 13 бит; данные LAM_H. */ + Uint16 LAM_H:13; // 16:28 + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 29:30 reserved + /* Битовое поле LAMI, ширина 1 бит; данные LAMI. */ + Uint16 LAMI:1; // 31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CANLAM_REG в одной области памяти. */ +union CANLAM_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CANLAM_BITS bit;; порядок полей определяет расположение данных. */ + struct CANLAM_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/**************************************/ +/* eCAN Local Acceptance Masks */ +/**************************************/ + +/* eCAN LAM File */ +/* Описывает структуру LAM_REGS; порядок полей определяет расположение данных. */ +struct LAM_REGS { + /* Объединяет несколько представлений CANLAM_REG LAM0; в одной области памяти. */ + union CANLAM_REG LAM0; + /* Объединяет несколько представлений CANLAM_REG LAM1; в одной области памяти. */ + union CANLAM_REG LAM1; + /* Объединяет несколько представлений CANLAM_REG LAM2; в одной области памяти. */ + union CANLAM_REG LAM2; + /* Объединяет несколько представлений CANLAM_REG LAM3; в одной области памяти. */ + union CANLAM_REG LAM3; + /* Объединяет несколько представлений CANLAM_REG LAM4; в одной области памяти. */ + union CANLAM_REG LAM4; + /* Объединяет несколько представлений CANLAM_REG LAM5; в одной области памяти. */ + union CANLAM_REG LAM5; + /* Объединяет несколько представлений CANLAM_REG LAM6; в одной области памяти. */ + union CANLAM_REG LAM6; + /* Объединяет несколько представлений CANLAM_REG LAM7; в одной области памяти. */ + union CANLAM_REG LAM7; + /* Объединяет несколько представлений CANLAM_REG LAM8; в одной области памяти. */ + union CANLAM_REG LAM8; + /* Объединяет несколько представлений CANLAM_REG LAM9; в одной области памяти. */ + union CANLAM_REG LAM9; + /* Объединяет несколько представлений CANLAM_REG LAM10; в одной области памяти. */ + union CANLAM_REG LAM10; + /* Объединяет несколько представлений CANLAM_REG LAM11; в одной области памяти. */ + union CANLAM_REG LAM11; + /* Объединяет несколько представлений CANLAM_REG LAM12; в одной области памяти. */ + union CANLAM_REG LAM12; + /* Объединяет несколько представлений CANLAM_REG LAM13; в одной области памяти. */ + union CANLAM_REG LAM13; + /* Объединяет несколько представлений CANLAM_REG LAM14; в одной области памяти. */ + union CANLAM_REG LAM14; + /* Объединяет несколько представлений CANLAM_REG LAM15; в одной области памяти. */ + union CANLAM_REG LAM15; + /* Объединяет несколько представлений CANLAM_REG LAM16; в одной области памяти. */ + union CANLAM_REG LAM16; + /* Объединяет несколько представлений CANLAM_REG LAM17; в одной области памяти. */ + union CANLAM_REG LAM17; + /* Объединяет несколько представлений CANLAM_REG LAM18; в одной области памяти. */ + union CANLAM_REG LAM18; + /* Объединяет несколько представлений CANLAM_REG LAM19; в одной области памяти. */ + union CANLAM_REG LAM19; + /* Объединяет несколько представлений CANLAM_REG LAM20; в одной области памяти. */ + union CANLAM_REG LAM20; + /* Объединяет несколько представлений CANLAM_REG LAM21; в одной области памяти. */ + union CANLAM_REG LAM21; + /* Объединяет несколько представлений CANLAM_REG LAM22; в одной области памяти. */ + union CANLAM_REG LAM22; + /* Объединяет несколько представлений CANLAM_REG LAM23; в одной области памяти. */ + union CANLAM_REG LAM23; + /* Объединяет несколько представлений CANLAM_REG LAM24; в одной области памяти. */ + union CANLAM_REG LAM24; + /* Объединяет несколько представлений CANLAM_REG LAM25; в одной области памяти. */ + union CANLAM_REG LAM25; + /* Объединяет несколько представлений CANLAM_REG LAM26; в одной области памяти. */ + union CANLAM_REG LAM26; + /* Объединяет несколько представлений CANLAM_REG LAM27; в одной области памяти. */ + union CANLAM_REG LAM27; + /* Объединяет несколько представлений CANLAM_REG LAM28; в одной области памяти. */ + union CANLAM_REG LAM28; + /* Объединяет несколько представлений CANLAM_REG LAM29; в одной области памяти. */ + union CANLAM_REG LAM29; + /* Объединяет несколько представлений CANLAM_REG LAM30; в одной области памяти. */ + union CANLAM_REG LAM30; + /* Объединяет несколько представлений CANLAM_REG LAM31; в одной области памяти. */ + union CANLAM_REG LAM31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Mailbox MOTS File */ + +/* Описывает структуру MOTS_REGS; порядок полей определяет расположение данных. */ +struct MOTS_REGS { + /* Объявляет MOTS0 — данные MOTS0. */ + Uint32 MOTS0; + /* Объявляет MOTS1 — данные MOTS1. */ + Uint32 MOTS1; + /* Объявляет MOTS2 — данные MOTS2. */ + Uint32 MOTS2; + /* Объявляет MOTS3 — данные MOTS3. */ + Uint32 MOTS3; + /* Объявляет MOTS4 — данные MOTS4. */ + Uint32 MOTS4; + /* Объявляет MOTS5 — данные MOTS5. */ + Uint32 MOTS5; + /* Объявляет MOTS6 — данные MOTS6. */ + Uint32 MOTS6; + /* Объявляет MOTS7 — данные MOTS7. */ + Uint32 MOTS7; + /* Объявляет MOTS8 — данные MOTS8. */ + Uint32 MOTS8; + /* Объявляет MOTS9 — данные MOTS9. */ + Uint32 MOTS9; + /* Объявляет MOTS10 — данные MOTS10. */ + Uint32 MOTS10; + /* Объявляет MOTS11 — данные MOTS11. */ + Uint32 MOTS11; + /* Объявляет MOTS12 — данные MOTS12. */ + Uint32 MOTS12; + /* Объявляет MOTS13 — данные MOTS13. */ + Uint32 MOTS13; + /* Объявляет MOTS14 — данные MOTS14. */ + Uint32 MOTS14; + /* Объявляет MOTS15 — данные MOTS15. */ + Uint32 MOTS15; + /* Объявляет MOTS16 — данные MOTS16. */ + Uint32 MOTS16; + /* Объявляет MOTS17 — данные MOTS17. */ + Uint32 MOTS17; + /* Объявляет MOTS18 — данные MOTS18. */ + Uint32 MOTS18; + /* Объявляет MOTS19 — данные MOTS19. */ + Uint32 MOTS19; + /* Объявляет MOTS20 — данные MOTS20. */ + Uint32 MOTS20; + /* Объявляет MOTS21 — данные MOTS21. */ + Uint32 MOTS21; + /* Объявляет MOTS22 — данные MOTS22. */ + Uint32 MOTS22; + /* Объявляет MOTS23 — данные MOTS23. */ + Uint32 MOTS23; + /* Объявляет MOTS24 — данные MOTS24. */ + Uint32 MOTS24; + /* Объявляет MOTS25 — данные MOTS25. */ + Uint32 MOTS25; + /* Объявляет MOTS26 — данные MOTS26. */ + Uint32 MOTS26; + /* Объявляет MOTS27 — данные MOTS27. */ + Uint32 MOTS27; + /* Объявляет MOTS28 — данные MOTS28. */ + Uint32 MOTS28; + /* Объявляет MOTS29 — данные MOTS29. */ + Uint32 MOTS29; + /* Объявляет MOTS30 — данные MOTS30. */ + Uint32 MOTS30; + /* Объявляет MOTS31 — данные MOTS31. */ + Uint32 MOTS31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Mailbox MOTO File */ + +/* Описывает структуру MOTO_REGS; порядок полей определяет расположение данных. */ +struct MOTO_REGS { + /* Объявляет MOTO0 — данные MOTO0. */ + Uint32 MOTO0; + /* Объявляет MOTO1 — данные MOTO1. */ + Uint32 MOTO1; + /* Объявляет MOTO2 — данные MOTO2. */ + Uint32 MOTO2; + /* Объявляет MOTO3 — данные MOTO3. */ + Uint32 MOTO3; + /* Объявляет MOTO4 — данные MOTO4. */ + Uint32 MOTO4; + /* Объявляет MOTO5 — данные MOTO5. */ + Uint32 MOTO5; + /* Объявляет MOTO6 — данные MOTO6. */ + Uint32 MOTO6; + /* Объявляет MOTO7 — данные MOTO7. */ + Uint32 MOTO7; + /* Объявляет MOTO8 — данные MOTO8. */ + Uint32 MOTO8; + /* Объявляет MOTO9 — данные MOTO9. */ + Uint32 MOTO9; + /* Объявляет MOTO10 — данные MOTO10. */ + Uint32 MOTO10; + /* Объявляет MOTO11 — данные MOTO11. */ + Uint32 MOTO11; + /* Объявляет MOTO12 — данные MOTO12. */ + Uint32 MOTO12; + /* Объявляет MOTO13 — данные MOTO13. */ + Uint32 MOTO13; + /* Объявляет MOTO14 — данные MOTO14. */ + Uint32 MOTO14; + /* Объявляет MOTO15 — данные MOTO15. */ + Uint32 MOTO15; + /* Объявляет MOTO16 — данные MOTO16. */ + Uint32 MOTO16; + /* Объявляет MOTO17 — данные MOTO17. */ + Uint32 MOTO17; + /* Объявляет MOTO18 — данные MOTO18. */ + Uint32 MOTO18; + /* Объявляет MOTO19 — данные MOTO19. */ + Uint32 MOTO19; + /* Объявляет MOTO20 — данные MOTO20. */ + Uint32 MOTO20; + /* Объявляет MOTO21 — данные MOTO21. */ + Uint32 MOTO21; + /* Объявляет MOTO22 — данные MOTO22. */ + Uint32 MOTO22; + /* Объявляет MOTO23 — данные MOTO23. */ + Uint32 MOTO23; + /* Объявляет MOTO24 — данные MOTO24. */ + Uint32 MOTO24; + /* Объявляет MOTO25 — данные MOTO25. */ + Uint32 MOTO25; + /* Объявляет MOTO26 — данные MOTO26. */ + Uint32 MOTO26; + /* Объявляет MOTO27 — данные MOTO27. */ + Uint32 MOTO27; + /* Объявляет MOTO28 — данные MOTO28. */ + Uint32 MOTO28; + /* Объявляет MOTO29 — данные MOTO29. */ + Uint32 MOTO29; + /* Объявляет MOTO30 — данные MOTO30. */ + Uint32 MOTO30; + /* Объявляет MOTO31 — данные MOTO31. */ + Uint32 MOTO31; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// eCAN External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_REGS ECanaRegs;; порядок элементов сохраняется. */ +extern volatile struct ECAN_REGS ECanaRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_MBOXES ECanaMboxes;; порядок элементов сохраняется. */ +extern volatile struct ECAN_MBOXES ECanaMboxes; +/* Продолжает список аргументов, полей или выражение extern volatile struct LAM_REGS ECanaLAMRegs;; порядок элементов сохраняется. */ +extern volatile struct LAM_REGS ECanaLAMRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTO_REGS ECanaMOTORegs;; порядок элементов сохраняется. */ +extern volatile struct MOTO_REGS ECanaMOTORegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTS_REGS ECanaMOTSRegs;; порядок элементов сохраняется. */ +extern volatile struct MOTS_REGS ECanaMOTSRegs; + +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_REGS ECanbRegs;; порядок элементов сохраняется. */ +extern volatile struct ECAN_REGS ECanbRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAN_MBOXES ECanbMboxes;; порядок элементов сохраняется. */ +extern volatile struct ECAN_MBOXES ECanbMboxes; +/* Продолжает список аргументов, полей или выражение extern volatile struct LAM_REGS ECanbLAMRegs;; порядок элементов сохраняется. */ +extern volatile struct LAM_REGS ECanbLAMRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTO_REGS ECanbMOTORegs;; порядок элементов сохраняется. */ +extern volatile struct MOTO_REGS ECanbMOTORegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MOTS_REGS ECanbMOTSRegs;; порядок элементов сохраняется. */ +extern volatile struct MOTS_REGS ECanbMOTSRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_ECAN.H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h new file mode 100644 index 0000000..6ff4cea --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_ECap.h @@ -0,0 +1,245 @@ +/* Поставляемое TI описание ECap для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:07 $ +//########################################################################### +// +// FILE: DSP2833x_ECap.h +// +// TITLE: DSP2833x Enhanced Capture Module Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_ECAP_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_ECAP_H +/* Определяет защитный символ или переключатель DSP2833x_ECAP_H для последующей компиляции. */ +#define DSP2833x_ECAP_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Capture control register 1 bit definitions */ +/* Описывает структуру ECCTL1_BITS; порядок полей определяет расположение данных. */ +struct ECCTL1_BITS { // bits description + /* Битовое поле CAP1POL, ширина 1 бит; данные CAP1POL. */ + Uint16 CAP1POL:1; // 0 Capture Event 1 Polarity select + /* Битовое поле CTRRST1, ширина 1 бит; данные CTRRST1. */ + Uint16 CTRRST1:1; // 1 Counter Reset on Capture Event 1 + /* Битовое поле CAP2POL, ширина 1 бит; данные CAP2POL. */ + Uint16 CAP2POL:1; // 2 Capture Event 2 Polarity select + /* Битовое поле CTRRST2, ширина 1 бит; данные CTRRST2. */ + Uint16 CTRRST2:1; // 3 Counter Reset on Capture Event 2 + /* Битовое поле CAP3POL, ширина 1 бит; данные CAP3POL. */ + Uint16 CAP3POL:1; // 4 Capture Event 3 Polarity select + /* Битовое поле CTRRST3, ширина 1 бит; данные CTRRST3. */ + Uint16 CTRRST3:1; // 5 Counter Reset on Capture Event 3 + /* Битовое поле CAP4POL, ширина 1 бит; данные CAP4POL. */ + Uint16 CAP4POL:1; // 6 Capture Event 4 Polarity select + /* Битовое поле CTRRST4, ширина 1 бит; данные CTRRST4. */ + Uint16 CTRRST4:1; // 7 Counter Reset on Capture Event 4 + /* Битовое поле CAPLDEN, ширина 1 бит; данные CAPLDEN. */ + Uint16 CAPLDEN:1; // 8 Enable Loading CAP1-4 regs on a Cap Event + /* Битовое поле PRESCALE, ширина 5 бит; предделитель. */ + Uint16 PRESCALE:5; // 13:9 Event Filter prescale select + /* Битовое поле FREE_SOFT, ширина 2 бит; данные FREE_SOFT. */ + Uint16 FREE_SOFT:2; // 15:14 Emulation mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ECCTL1_REG в одной области памяти. */ +union ECCTL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECCTL1_BITS bit;; порядок полей определяет расположение данных. */ + struct ECCTL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// In V1.1 the STOPVALUE bit field was changed to +// STOP_WRAP. This correlated to a silicon change from +// F2833x Rev 0 to Rev A. +//---------------------------------------------------- +// Capture control register 2 bit definitions */ +/* Описывает структуру ECCTL2_BITS; порядок полей определяет расположение данных. */ +struct ECCTL2_BITS { // bits description + /* Битовое поле CONT_ONESHT, ширина 1 бит; данные CONT_ONESHT. */ + Uint16 CONT_ONESHT:1; // 0 Continuous or one-shot + /* Битовое поле STOP_WRAP, ширина 2 бит; данные STOP_WRAP. */ + Uint16 STOP_WRAP:2; // 2:1 Stop value for one-shot, Wrap for continuous + /* Битовое поле REARM, ширина 1 бит; данные REARM. */ + Uint16 REARM:1; // 3 One-shot re-arm + /* Битовое поле TSCTRSTOP, ширина 1 бит; данные TSCTRSTOP. */ + Uint16 TSCTRSTOP:1; // 4 TSCNT counter stop + /* Битовое поле SYNCI_EN, ширина 1 бит; данные SYNCI_EN. */ + Uint16 SYNCI_EN:1; // 5 Counter sync-in select + /* Битовое поле SYNCO_SEL, ширина 2 бит; данные SYNCO_SEL. */ + Uint16 SYNCO_SEL:2; // 7:6 Sync-out mode + /* Битовое поле SWSYNC, ширина 1 бит; данные SWSYNC. */ + Uint16 SWSYNC:1; // 8 SW forced counter sync + /* Битовое поле CAP_APWM, ширина 1 бит; данные CAP_APWM. */ + Uint16 CAP_APWM:1; // 9 CAP/APWM operating mode select + /* Битовое поле APWMPOL, ширина 1 бит; данные APWMPOL. */ + Uint16 APWMPOL:1; // 10 APWM output polarity select + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 15:11 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ECCTL2_REG в одной области памяти. */ +union ECCTL2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECCTL2_BITS bit;; порядок полей определяет расположение данных. */ + struct ECCTL2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// ECAP interrupt enable register bit definitions */ +/* Описывает структуру ECEINT_BITS; порядок полей определяет расположение данных. */ +struct ECEINT_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле CEVT1, ширина 1 бит; данные CEVT1. */ + Uint16 CEVT1:1; // 1 Capture Event 1 Interrupt Enable + /* Битовое поле CEVT2, ширина 1 бит; данные CEVT2. */ + Uint16 CEVT2:1; // 2 Capture Event 2 Interrupt Enable + /* Битовое поле CEVT3, ширина 1 бит; данные CEVT3. */ + Uint16 CEVT3:1; // 3 Capture Event 3 Interrupt Enable + /* Битовое поле CEVT4, ширина 1 бит; данные CEVT4. */ + Uint16 CEVT4:1; // 4 Capture Event 4 Interrupt Enable + /* Битовое поле CTROVF, ширина 1 бит; данные CTROVF. */ + Uint16 CTROVF:1; // 5 Counter Overflow Interrupt Enable + /* Битовое поле CTR_EQ_PRD, ширина 1 бит; данные CTR_EQ_PRD. */ + Uint16 CTR_EQ_PRD:1; // 6 Period Equal Interrupt Enable + /* Битовое поле CTR_EQ_CMP, ширина 1 бит; данные CTR_EQ_CMP. */ + Uint16 CTR_EQ_CMP:1; // 7 Compare Equal Interrupt Enable + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ECEINT_REG в одной области памяти. */ +union ECEINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECEINT_BITS bit;; порядок полей определяет расположение данных. */ + struct ECEINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// ECAP interrupt flag register bit definitions */ +/* Описывает структуру ECFLG_BITS; порядок полей определяет расположение данных. */ +struct ECFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global Flag + /* Битовое поле CEVT1, ширина 1 бит; данные CEVT1. */ + Uint16 CEVT1:1; // 1 Capture Event 1 Interrupt Flag + /* Битовое поле CEVT2, ширина 1 бит; данные CEVT2. */ + Uint16 CEVT2:1; // 2 Capture Event 2 Interrupt Flag + /* Битовое поле CEVT3, ширина 1 бит; данные CEVT3. */ + Uint16 CEVT3:1; // 3 Capture Event 3 Interrupt Flag + /* Битовое поле CEVT4, ширина 1 бит; данные CEVT4. */ + Uint16 CEVT4:1; // 4 Capture Event 4 Interrupt Flag + /* Битовое поле CTROVF, ширина 1 бит; данные CTROVF. */ + Uint16 CTROVF:1; // 5 Counter Overflow Interrupt Flag + /* Битовое поле CTR_EQ_PRD, ширина 1 бит; данные CTR_EQ_PRD. */ + Uint16 CTR_EQ_PRD:1; // 6 Period Equal Interrupt Flag + /* Битовое поле CTR_EQ_CMP, ширина 1 бит; данные CTR_EQ_CMP. */ + Uint16 CTR_EQ_CMP:1; // 7 Compare Equal Interrupt Flag + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений ECFLG_REG в одной области памяти. */ +union ECFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ECFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct ECFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- + +/* Описывает структуру ECAP_REGS; порядок полей определяет расположение данных. */ +struct ECAP_REGS { + /* Объявляет TSCTR — данные TSCTR. */ + Uint32 TSCTR; // Time stamp counter + /* Объявляет CTRPHS — данные CTRPHS. */ + Uint32 CTRPHS; // Counter phase + /* Объявляет CAP1 — данные CAP1. */ + Uint32 CAP1; // Capture 1 + /* Объявляет CAP2 — данные CAP2. */ + Uint32 CAP2; // Capture 2 + /* Объявляет CAP3 — данные CAP3. */ + Uint32 CAP3; // Capture 3 + /* Объявляет CAP4 — данные CAP4. */ + Uint32 CAP4; // Capture 4 + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[8]; // reserved + /* Объединяет несколько представлений ECCTL1_REG ECCTL1; в одной области памяти. */ + union ECCTL1_REG ECCTL1; // Capture Control Reg 1 + /* Объединяет несколько представлений ECCTL2_REG ECCTL2; в одной области памяти. */ + union ECCTL2_REG ECCTL2; // Capture Control Reg 2 + /* Объединяет несколько представлений ECEINT_REG ECEINT; в одной области памяти. */ + union ECEINT_REG ECEINT; // ECAP interrupt enable + /* Объединяет несколько представлений ECFLG_REG ECFLG; в одной области памяти. */ + union ECFLG_REG ECFLG; // ECAP interrupt flags + /* Объединяет несколько представлений ECFLG_REG ECCLR; в одной области памяти. */ + union ECFLG_REG ECCLR; // ECAP interrupt clear + /* Объединяет несколько представлений ECEINT_REG ECFRC; в одной области памяти. */ + union ECEINT_REG ECFRC; // ECAP interrupt force + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[6]; // reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap1Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap2Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap2Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap3Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap3Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap4Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap4Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap5Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap5Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct ECAP_REGS ECap6Regs;; порядок элементов сохраняется. */ +extern volatile struct ECAP_REGS ECap6Regs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_ECAP_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h new file mode 100644 index 0000000..b6ed86c --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EPwm.h @@ -0,0 +1,720 @@ +/* Поставляемое TI описание EPwm для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:10 $ +//########################################################################### +// +// FILE: DSP2833x_EPwm.h +// +// TITLE: DSP2833x Enhanced PWM Module Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EPWM_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EPWM_H +/* Определяет защитный символ или переключатель DSP2833x_EPWM_H для последующей компиляции. */ +#define DSP2833x_EPWM_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Time base control register bit definitions */ +/* Описывает структуру TBCTL_BITS; порядок полей определяет расположение данных. */ +struct TBCTL_BITS { // bits description + /* Битовое поле CTRMODE, ширина 2 бит; данные CTRMODE. */ + Uint16 CTRMODE:2; // 1:0 Counter Mode + /* Битовое поле PHSEN, ширина 1 бит; данные PHSEN. */ + Uint16 PHSEN:1; // 2 Phase load enable + /* Битовое поле PRDLD, ширина 1 бит; данные PRDLD. */ + Uint16 PRDLD:1; // 3 Active period load + /* Битовое поле SYNCOSEL, ширина 2 бит; данные SYNCOSEL. */ + Uint16 SYNCOSEL:2; // 5:4 Sync output select + /* Битовое поле SWFSYNC, ширина 1 бит; данные SWFSYNC. */ + Uint16 SWFSYNC:1; // 6 Software force sync pulse + /* Битовое поле HSPCLKDIV, ширина 3 бит; данные HSPCLKDIV. */ + Uint16 HSPCLKDIV:3; // 9:7 High speed time pre-scale + /* Битовое поле CLKDIV, ширина 3 бит; данные CLKDIV. */ + Uint16 CLKDIV:3; // 12:10 Timebase clock pre-scale + /* Битовое поле PHSDIR, ширина 1 бит; данные PHSDIR. */ + Uint16 PHSDIR:1; // 13 Phase Direction + /* Битовое поле FREE_SOFT, ширина 2 бит; данные FREE_SOFT. */ + Uint16 FREE_SOFT:2; // 15:14 Emulation mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TBCTL_REG в одной области памяти. */ +union TBCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TBCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct TBCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Time base status register bit definitions */ +/* Описывает структуру TBSTS_BITS; порядок полей определяет расположение данных. */ +struct TBSTS_BITS { // bits description + /* Битовое поле CTRDIR, ширина 1 бит; данные CTRDIR. */ + Uint16 CTRDIR:1; // 0 Counter direction status + /* Битовое поле SYNCI, ширина 1 бит; данные SYNCI. */ + Uint16 SYNCI:1; // 1 External input sync status + /* Битовое поле CTRMAX, ширина 1 бит; данные CTRMAX. */ + Uint16 CTRMAX:1; // 2 Counter max latched status + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TBSTS_REG в одной области памяти. */ +union TBSTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TBSTS_BITS bit;; порядок полей определяет расположение данных. */ + struct TBSTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Compare control register bit definitions */ +/* Описывает структуру CMPCTL_BITS; порядок полей определяет расположение данных. */ +struct CMPCTL_BITS { // bits description + /* Битовое поле LOADAMODE, ширина 2 бит; данные LOADAMODE. */ + Uint16 LOADAMODE:2; // 0:1 Active compare A + /* Битовое поле LOADBMODE, ширина 2 бит; данные LOADBMODE. */ + Uint16 LOADBMODE:2; // 3:2 Active compare B + /* Битовое поле SHDWAMODE, ширина 1 бит; данные SHDWAMODE. */ + Uint16 SHDWAMODE:1; // 4 Compare A block operating mode + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 5 reserved + /* Битовое поле SHDWBMODE, ширина 1 бит; данные SHDWBMODE. */ + Uint16 SHDWBMODE:1; // 6 Compare B block operating mode + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 7 reserved + /* Битовое поле SHDWAFULL, ширина 1 бит; данные SHDWAFULL. */ + Uint16 SHDWAFULL:1; // 8 Compare A Shadow registers full Status + /* Битовое поле SHDWBFULL, ширина 1 бит; данные SHDWBFULL. */ + Uint16 SHDWBFULL:1; // 9 Compare B Shadow registers full Status + /* Битовое поле rsvd3, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений CMPCTL_REG в одной области памяти. */ +union CMPCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CMPCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct CMPCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Action qualifier register bit definitions */ +/* Описывает структуру AQCTL_BITS; порядок полей определяет расположение данных. */ +struct AQCTL_BITS { // bits description + /* Битовое поле ZRO, ширина 2 бит; данные ZRO. */ + Uint16 ZRO:2; // 1:0 Action Counter = Zero + /* Битовое поле PRD, ширина 2 бит; данные PRD. */ + Uint16 PRD:2; // 3:2 Action Counter = Period + /* Битовое поле CAU, ширина 2 бит; данные CAU. */ + Uint16 CAU:2; // 5:4 Action Counter = Compare A up + /* Битовое поле CAD, ширина 2 бит; данные CAD. */ + Uint16 CAD:2; // 7:6 Action Counter = Compare A down + /* Битовое поле CBU, ширина 2 бит; данные CBU. */ + Uint16 CBU:2; // 9:8 Action Counter = Compare B up + /* Битовое поле CBD, ширина 2 бит; данные CBD. */ + Uint16 CBD:2; // 11:10 Action Counter = Compare B down + /* Битовое поле rsvd, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений AQCTL_REG в одной области памяти. */ +union AQCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру AQCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct AQCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Action qualifier SW force register bit definitions */ +/* Описывает структуру AQSFRC_BITS; порядок полей определяет расположение данных. */ +struct AQSFRC_BITS { // bits description + /* Битовое поле ACTSFA, ширина 2 бит; данные ACTSFA. */ + Uint16 ACTSFA:2; // 1:0 Action when One-time SW Force A invoked + /* Битовое поле OTSFA, ширина 1 бит; данные OTSFA. */ + Uint16 OTSFA:1; // 2 One-time SW Force A output + /* Битовое поле ACTSFB, ширина 2 бит; данные ACTSFB. */ + Uint16 ACTSFB:2; // 4:3 Action when One-time SW Force B invoked + /* Битовое поле OTSFB, ширина 1 бит; данные OTSFB. */ + Uint16 OTSFB:1; // 5 One-time SW Force A output + /* Битовое поле RLDCSF, ширина 2 бит; данные RLDCSF. */ + Uint16 RLDCSF:2; // 7:6 Reload from Shadow options + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений AQSFRC_REG в одной области памяти. */ +union AQSFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру AQSFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct AQSFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Action qualifier continuous SW force register bit definitions */ +/* Описывает структуру AQCSFRC_BITS; порядок полей определяет расположение данных. */ +struct AQCSFRC_BITS { // bits description + /* Битовое поле CSFA, ширина 2 бит; данные CSFA. */ + Uint16 CSFA:2; // 1:0 Continuous Software Force on output A + /* Битовое поле CSFB, ширина 2 бит; данные CSFB. */ + Uint16 CSFB:2; // 3:2 Continuous Software Force on output B + /* Битовое поле rsvd1, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений AQCSFRC_REG в одной области памяти. */ +union AQCSFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру AQCSFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct AQCSFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// As of version 1.1 +// Changed the MODE bit-field to OUT_MODE +// Added the bit-field IN_MODE +// This corresponds to changes in silicon as of F2833x devices +// Rev A silicon. +//---------------------------------------------------- +// Dead-band generator control register bit definitions +/* Описывает структуру DBCTL_BITS; порядок полей определяет расположение данных. */ +struct DBCTL_BITS { // bits description + /* Битовое поле OUT_MODE, ширина 2 бит; OUT режим. */ + Uint16 OUT_MODE:2; // 1:0 Dead Band Output Mode Control + /* Битовое поле POLSEL, ширина 2 бит; данные POLSEL. */ + Uint16 POLSEL:2; // 3:2 Polarity Select Control + /* Битовое поле IN_MODE, ширина 2 бит; IN режим. */ + Uint16 IN_MODE:2; // 5:4 Dead Band Input Select Mode Control + /* Битовое поле rsvd1, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:10; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DBCTL_REG в одной области памяти. */ +union DBCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DBCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct DBCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone select register bit definitions +/* Описывает структуру TZSEL_BITS; порядок полей определяет расположение данных. */ +struct TZSEL_BITS { // bits description + /* Битовое поле CBC1, ширина 1 бит; данные CBC1. */ + Uint16 CBC1:1; // 0 TZ1 CBC select + /* Битовое поле CBC2, ширина 1 бит; данные CBC2. */ + Uint16 CBC2:1; // 1 TZ2 CBC select + /* Битовое поле CBC3, ширина 1 бит; данные CBC3. */ + Uint16 CBC3:1; // 2 TZ3 CBC select + /* Битовое поле CBC4, ширина 1 бит; данные CBC4. */ + Uint16 CBC4:1; // 3 TZ4 CBC select + /* Битовое поле CBC5, ширина 1 бит; данные CBC5. */ + Uint16 CBC5:1; // 4 TZ5 CBC select + /* Битовое поле CBC6, ширина 1 бит; данные CBC6. */ + Uint16 CBC6:1; // 5 TZ6 CBC select + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 7:6 reserved + /* Битовое поле OSHT1, ширина 1 бит; данные OSHT1. */ + Uint16 OSHT1:1; // 8 One-shot TZ1 select + /* Битовое поле OSHT2, ширина 1 бит; данные OSHT2. */ + Uint16 OSHT2:1; // 9 One-shot TZ2 select + /* Битовое поле OSHT3, ширина 1 бит; данные OSHT3. */ + Uint16 OSHT3:1; // 10 One-shot TZ3 select + /* Битовое поле OSHT4, ширина 1 бит; данные OSHT4. */ + Uint16 OSHT4:1; // 11 One-shot TZ4 select + /* Битовое поле OSHT5, ширина 1 бит; данные OSHT5. */ + Uint16 OSHT5:1; // 12 One-shot TZ5 select + /* Битовое поле OSHT6, ширина 1 бит; данные OSHT6. */ + Uint16 OSHT6:1; // 13 One-shot TZ6 select + /* Битовое поле rsvd2, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:2; // 15:14 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZSEL_REG в одной области памяти. */ +union TZSEL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZSEL_BITS bit;; порядок полей определяет расположение данных. */ + struct TZSEL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone control register bit definitions */ +/* Описывает структуру TZCTL_BITS; порядок полей определяет расположение данных. */ +struct TZCTL_BITS { // bits description + /* Битовое поле TZA, ширина 2 бит; данные TZA. */ + Uint16 TZA:2; // 1:0 TZ1 to TZ6 Trip Action On EPWMxA + /* Битовое поле TZB, ширина 2 бит; данные TZB. */ + Uint16 TZB:2; // 3:2 TZ1 to TZ6 Trip Action On EPWMxB + /* Битовое поле rsvd, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZCTL_REG в одной области памяти. */ +union TZCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct TZCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone control register bit definitions */ +/* Описывает структуру TZEINT_BITS; порядок полей определяет расположение данных. */ +struct TZEINT_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int Enable + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int Enable + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений TZEINT_REG в одной области памяти. */ +union TZEINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZEINT_BITS bit;; порядок полей определяет расположение данных. */ + struct TZEINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Trip zone flag register bit definitions */ +/* Описывает структуру TZFLG_BITS; порядок полей определяет расположение данных. */ +struct TZFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global status + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZFLG_REG в одной области памяти. */ +union TZFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct TZFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Trip zone flag clear register bit definitions */ +/* Описывает структуру TZCLR_BITS; порядок полей определяет расположение данных. */ +struct TZCLR_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global status + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZCLR_REG в одной области памяти. */ +union TZCLR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZCLR_BITS bit;; порядок полей определяет расположение данных. */ + struct TZCLR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Trip zone flag force register bit definitions */ +/* Описывает структуру TZFRC_BITS; порядок полей определяет расположение данных. */ +struct TZFRC_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле CBC, ширина 1 бит; данные CBC. */ + Uint16 CBC:1; // 1 Trip Zones Cycle By Cycle Int + /* Битовое поле OST, ширина 1 бит; данные OST. */ + Uint16 OST:1; // 2 Trip Zones One Shot Int + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TZFRC_REG в одной области памяти. */ +union TZFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру TZFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct TZFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Event trigger select register bit definitions */ +/* Описывает структуру ETSEL_BITS; порядок полей определяет расположение данных. */ +struct ETSEL_BITS { // bits description + /* Битовое поле INTSEL, ширина 3 бит; данные INTSEL. */ + Uint16 INTSEL:3; // 2:0 EPWMxINTn Select + /* Битовое поле INTEN, ширина 1 бит; данные INTEN. */ + Uint16 INTEN:1; // 3 EPWMxINTn Enable + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 7:4 reserved + /* Битовое поле SOCASEL, ширина 3 бит; данные SOCASEL. */ + Uint16 SOCASEL:3; // 10:8 Start of conversion A Select + /* Битовое поле SOCAEN, ширина 1 бит; данные SOCAEN. */ + Uint16 SOCAEN:1; // 11 Start of conversion A Enable + /* Битовое поле SOCBSEL, ширина 3 бит; данные SOCBSEL. */ + Uint16 SOCBSEL:3; // 14:12 Start of conversion B Select + /* Битовое поле SOCBEN, ширина 1 бит; данные SOCBEN. */ + Uint16 SOCBEN:1; // 15 Start of conversion B Enable +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETSEL_REG в одной области памяти. */ +union ETSEL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETSEL_BITS bit;; порядок полей определяет расположение данных. */ + struct ETSEL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Event trigger pre-scale register bit definitions */ +/* Описывает структуру ETPS_BITS; порядок полей определяет расположение данных. */ +struct ETPS_BITS { // bits description + /* Битовое поле INTPRD, ширина 2 бит; данные INTPRD. */ + Uint16 INTPRD:2; // 1:0 EPWMxINTn Period Select + /* Битовое поле INTCNT, ширина 2 бит; данные INTCNT. */ + Uint16 INTCNT:2; // 3:2 EPWMxINTn Counter Register + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 7:4 reserved + /* Битовое поле SOCAPRD, ширина 2 бит; данные SOCAPRD. */ + Uint16 SOCAPRD:2; // 9:8 EPWMxSOCA Period Select + /* Битовое поле SOCACNT, ширина 2 бит; данные SOCACNT. */ + Uint16 SOCACNT:2; // 11:10 EPWMxSOCA Counter Register + /* Битовое поле SOCBPRD, ширина 2 бит; данные SOCBPRD. */ + Uint16 SOCBPRD:2; // 13:12 EPWMxSOCB Period Select + /* Битовое поле SOCBCNT, ширина 2 бит; данные SOCBCNT. */ + Uint16 SOCBCNT:2; // 15:14 EPWMxSOCB Counter Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETPS_REG в одной области памяти. */ +union ETPS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETPS_BITS bit;; порядок полей определяет расположение данных. */ + struct ETPS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Event trigger Flag register bit definitions */ +/* Описывает структуру ETFLG_BITS; порядок полей определяет расположение данных. */ +struct ETFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 EPWMxINTn Flag + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле SOCA, ширина 1 бит; данные SOCA. */ + Uint16 SOCA:1; // 2 EPWMxSOCA Flag + /* Битовое поле SOCB, ширина 1 бит; данные SOCB. */ + Uint16 SOCB:1; // 3 EPWMxSOCB Flag + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETFLG_REG в одной области памяти. */ +union ETFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct ETFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Event trigger Clear register bit definitions */ +/* Описывает структуру ETCLR_BITS; порядок полей определяет расположение данных. */ +struct ETCLR_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 EPWMxINTn Clear + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле SOCA, ширина 1 бит; данные SOCA. */ + Uint16 SOCA:1; // 2 EPWMxSOCA Clear + /* Битовое поле SOCB, ширина 1 бит; данные SOCB. */ + Uint16 SOCB:1; // 3 EPWMxSOCB Clear + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETCLR_REG в одной области памяти. */ +union ETCLR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETCLR_BITS bit;; порядок полей определяет расположение данных. */ + struct ETCLR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// Event trigger Force register bit definitions */ +/* Описывает структуру ETFRC_BITS; порядок полей определяет расположение данных. */ +struct ETFRC_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 EPWMxINTn Force + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле SOCA, ширина 1 бит; данные SOCA. */ + Uint16 SOCA:1; // 2 EPWMxSOCA Force + /* Битовое поле SOCB, ширина 1 бит; данные SOCB. */ + Uint16 SOCB:1; // 3 EPWMxSOCB Force + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений ETFRC_REG в одной области памяти. */ +union ETFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру ETFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct ETFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; +//---------------------------------------------------- +// PWM chopper control register bit definitions */ +/* Описывает структуру PCCTL_BITS; порядок полей определяет расположение данных. */ +struct PCCTL_BITS { // bits description + /* Битовое поле CHPEN, ширина 1 бит; данные CHPEN. */ + Uint16 CHPEN:1; // 0 PWM chopping enable + /* Битовое поле OSHTWTH, ширина 4 бит; данные OSHTWTH. */ + Uint16 OSHTWTH:4; // 4:1 One-shot pulse width + /* Битовое поле CHPFREQ, ширина 3 бит; данные CHPFREQ. */ + Uint16 CHPFREQ:3; // 7:5 Chopping clock frequency + /* Битовое поле CHPDUTY, ширина 3 бит; данные CHPDUTY. */ + Uint16 CHPDUTY:3; // 10:8 Chopping clock Duty cycle + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 15:11 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений PCCTL_REG в одной области памяти. */ +union PCCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct PCCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру HRCNFG_BITS; порядок полей определяет расположение данных. */ +struct HRCNFG_BITS { // bits description + /* Битовое поле EDGMODE, ширина 2 бит; данные EDGMODE. */ + Uint16 EDGMODE:2; // 1:0 Edge Mode select Bits + /* Битовое поле CTLMODE, ширина 1 бит; данные CTLMODE. */ + Uint16 CTLMODE:1; // 2 Control mode Select Bit + /* Битовое поле HRLOAD, ширина 1 бит; данные HRLOAD. */ + Uint16 HRLOAD:1; // 3 Shadow mode Select Bit + /* Битовое поле rsvd1, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений HRCNFG_REG в одной области памяти. */ +union HRCNFG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру HRCNFG_BITS bit;; порядок полей определяет расположение данных. */ + struct HRCNFG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру TBPHS_HRPWM_REG; порядок полей определяет расположение данных. */ +struct TBPHS_HRPWM_REG { // bits description + /* Объявляет TBPHSHR — данные TBPHSHR. */ + Uint16 TBPHSHR; // 15:0 Extension register for HRPWM Phase (8 bits) + /* Объявляет TBPHS — данные TBPHS. */ + Uint16 TBPHS; // 31:16 Phase offset register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений TBPHS_HRPWM_GROUP в одной области памяти. */ +union TBPHS_HRPWM_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру TBPHS_HRPWM_REG half;; порядок полей определяет расположение данных. */ + struct TBPHS_HRPWM_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру CMPA_HRPWM_REG; порядок полей определяет расположение данных. */ +struct CMPA_HRPWM_REG { // bits description + /* Объявляет CMPAHR — данные CMPAHR. */ + Uint16 CMPAHR; // 15:0 Extension register for HRPWM compare (8 bits) + /* Объявляет CMPA — данные CMPA. */ + Uint16 CMPA; // 31:16 Compare A reg +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений CMPA_HRPWM_GROUP в одной области памяти. */ +union CMPA_HRPWM_GROUP { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру CMPA_HRPWM_REG half;; порядок полей определяет расположение данных. */ + struct CMPA_HRPWM_REG half; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру EPWM_REGS; порядок полей определяет расположение данных. */ +struct EPWM_REGS { + /* Объединяет несколько представлений TBCTL_REG TBCTL; в одной области памяти. */ + union TBCTL_REG TBCTL; // + /* Объединяет несколько представлений TBSTS_REG TBSTS; в одной области памяти. */ + union TBSTS_REG TBSTS; // + /* Объединяет несколько представлений TBPHS_HRPWM_GROUP TBPHS; в одной области памяти. */ + union TBPHS_HRPWM_GROUP TBPHS; // Union of TBPHS:TBPHSHR + /* Объявляет TBCTR — данные TBCTR. */ + Uint16 TBCTR; // Counter + /* Объявляет TBPRD — данные TBPRD. */ + Uint16 TBPRD; // Period register set + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // + /* Объединяет несколько представлений CMPCTL_REG CMPCTL; в одной области памяти. */ + union CMPCTL_REG CMPCTL; // Compare control + /* Объединяет несколько представлений CMPA_HRPWM_GROUP CMPA; в одной области памяти. */ + union CMPA_HRPWM_GROUP CMPA; // Union of CMPA:CMPAHR + /* Объявляет CMPB — данные CMPB. */ + Uint16 CMPB; // Compare B reg + /* Объединяет несколько представлений AQCTL_REG AQCTLA; в одной области памяти. */ + union AQCTL_REG AQCTLA; // Action qual output A + /* Объединяет несколько представлений AQCTL_REG AQCTLB; в одной области памяти. */ + union AQCTL_REG AQCTLB; // Action qual output B + /* Объединяет несколько представлений AQSFRC_REG AQSFRC; в одной области памяти. */ + union AQSFRC_REG AQSFRC; // Action qual SW force + /* Объединяет несколько представлений AQCSFRC_REG AQCSFRC; в одной области памяти. */ + union AQCSFRC_REG AQCSFRC; // Action qualifier continuous SW force + /* Объединяет несколько представлений DBCTL_REG DBCTL; в одной области памяти. */ + union DBCTL_REG DBCTL; // Dead-band control + /* Объявляет DBRED — данные DBRED. */ + Uint16 DBRED; // Dead-band rising edge delay + /* Объявляет DBFED — данные DBFED. */ + Uint16 DBFED; // Dead-band falling edge delay + /* Объединяет несколько представлений TZSEL_REG TZSEL; в одной области памяти. */ + union TZSEL_REG TZSEL; // Trip zone select + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; + /* Объединяет несколько представлений TZCTL_REG TZCTL; в одной области памяти. */ + union TZCTL_REG TZCTL; // Trip zone control + /* Объединяет несколько представлений TZEINT_REG TZEINT; в одной области памяти. */ + union TZEINT_REG TZEINT; // Trip zone interrupt enable + /* Объединяет несколько представлений TZFLG_REG TZFLG; в одной области памяти. */ + union TZFLG_REG TZFLG; // Trip zone interrupt flags + /* Объединяет несколько представлений TZCLR_REG TZCLR; в одной области памяти. */ + union TZCLR_REG TZCLR; // Trip zone clear + /* Объединяет несколько представлений TZFRC_REG TZFRC; в одной области памяти. */ + union TZFRC_REG TZFRC; // Trip zone force interrupt + /* Объединяет несколько представлений ETSEL_REG ETSEL; в одной области памяти. */ + union ETSEL_REG ETSEL; // Event trigger selection + /* Объединяет несколько представлений ETPS_REG ETPS; в одной области памяти. */ + union ETPS_REG ETPS; // Event trigger pre-scaler + /* Объединяет несколько представлений ETFLG_REG ETFLG; в одной области памяти. */ + union ETFLG_REG ETFLG; // Event trigger flags + /* Объединяет несколько представлений ETCLR_REG ETCLR; в одной области памяти. */ + union ETCLR_REG ETCLR; // Event trigger clear + /* Объединяет несколько представлений ETFRC_REG ETFRC; в одной области памяти. */ + union ETFRC_REG ETFRC; // Event trigger force + /* Объединяет несколько представлений PCCTL_REG PCCTL; в одной области памяти. */ + union PCCTL_REG PCCTL; // PWM chopper control + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // + /* Объединяет несколько представлений HRCNFG_REG HRCNFG; в одной области памяти. */ + union HRCNFG_REG HRCNFG; // HRPWM Config Reg +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//--------------------------------------------------------------------------- +// External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm1Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm2Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm2Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm3Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm3Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm4Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm4Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm5Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm5Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EPWM_REGS EPwm6Regs;; порядок элементов сохраняется. */ +extern volatile struct EPWM_REGS EPwm6Regs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_EPWM_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h new file mode 100644 index 0000000..455839e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_EQep.h @@ -0,0 +1,407 @@ +/* Поставляемое TI описание EQep для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:13 $ +//########################################################################### +// +// FILE: DSP2833x_EQep.h +// +// TITLE: DSP2833x Enhanced Quadrature Encoder Pulse Module +// Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_EQEP_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_EQEP_H +/* Определяет защитный символ или переключатель DSP2833x_EQEP_H для последующей компиляции. */ +#define DSP2833x_EQEP_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// Capture decoder control register bit definitions */ +/* Описывает структуру QDECCTL_BITS; порядок полей определяет расположение данных. */ +struct QDECCTL_BITS { // bits description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле QSP, ширина 1 бит; данные QSP. */ + Uint16 QSP:1; // 5 QEPS input polarity + /* Битовое поле QIP, ширина 1 бит; данные QIP. */ + Uint16 QIP:1; // 6 QEPI input polarity + /* Битовое поле QBP, ширина 1 бит; данные QBP. */ + Uint16 QBP:1; // 7 QEPB input polarity + /* Битовое поле QAP, ширина 1 бит; данные QAP. */ + Uint16 QAP:1; // 8 QEPA input polarity + /* Битовое поле IGATE, ширина 1 бит; данные IGATE. */ + Uint16 IGATE:1; // 9 Index pulse gating option + /* Битовое поле SWAP, ширина 1 бит; данные SWAP. */ + Uint16 SWAP:1; // 10 CLK/DIR signal source for Position Counter + /* Битовое поле XCR, ширина 1 бит; данные XCR. */ + Uint16 XCR:1; // 11 External clock rate + /* Битовое поле SPSEL, ширина 1 бит; данные SPSEL. */ + Uint16 SPSEL:1; // 12 Sync output pin select + /* Битовое поле SOEN, ширина 1 бит; данные SOEN. */ + Uint16 SOEN:1; // 13 Enable position compare sync + /* Битовое поле QSRC, ширина 2 бит; данные QSRC. */ + Uint16 QSRC:2; // 15:14 Position counter source +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QDECCTL_REG в одной области памяти. */ +union QDECCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QDECCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QDECCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// QEP control register bit definitions */ +/* Описывает структуру QEPCTL_BITS; порядок полей определяет расположение данных. */ +struct QEPCTL_BITS { // bits description + /* Битовое поле WDE, ширина 1 бит; данные WDE. */ + Uint16 WDE:1; // 0 QEP watchdog enable + /* Битовое поле UTE, ширина 1 бит; данные UTE. */ + Uint16 UTE:1; // 1 QEP unit timer enable + /* Битовое поле QCLM, ширина 1 бит; данные QCLM. */ + Uint16 QCLM:1; // 2 QEP capture latch mode + /* Битовое поле QPEN, ширина 1 бит; данные QPEN. */ + Uint16 QPEN:1; // 3 Quadrature position counter enable + /* Битовое поле IEL, ширина 2 бит; данные IEL. */ + Uint16 IEL:2; // 5:4 Index event latch + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 6 Strobe event latch + /* Битовое поле SWI, ширина 1 бит; данные SWI. */ + Uint16 SWI:1; // 7 Software init position counter + /* Битовое поле IEI, ширина 2 бит; данные IEI. */ + Uint16 IEI:2; // 9:8 Index event init of position count + /* Битовое поле SEI, ширина 2 бит; данные SEI. */ + Uint16 SEI:2; // 11:10 Strobe event init + /* Битовое поле PCRM, ширина 2 бит; данные PCRM. */ + Uint16 PCRM:2; // 13:12 Position counter reset + /* Битовое поле FREE_SOFT, ширина 2 бит; данные FREE_SOFT. */ + Uint16 FREE_SOFT:2; // 15:14 Emulation mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QEPCTL_REG в одной области памяти. */ +union QEPCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QEPCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QEPCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// Quadrature capture control register bit definitions */ +/* Описывает структуру QCAPCTL_BITS; порядок полей определяет расположение данных. */ +struct QCAPCTL_BITS { // bits description + /* Битовое поле UPPS, ширина 4 бит; данные UPPS. */ + Uint16 UPPS:4; // 3:0 Unit position pre-scale + /* Битовое поле CCPS, ширина 3 бит; данные CCPS. */ + Uint16 CCPS:3; // 6:4 QEP capture timer pre-scale + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 14:7 reserved + /* Битовое поле CEN, ширина 1 бит; данные CEN. */ + Uint16 CEN:1; // 15 Enable QEP capture +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QCAPCTL_REG в одной области памяти. */ +union QCAPCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QCAPCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QCAPCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +//---------------------------------------------------- +// Position compare control register bit definitions */ +/* Описывает структуру QPOSCTL_BITS; порядок полей определяет расположение данных. */ +struct QPOSCTL_BITS { // bits description + /* Битовое поле PCSPW, ширина 12 бит; данные PCSPW. */ + Uint16 PCSPW:12; // 11:0 Position compare sync pulse width + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 12 Position compare enable/disable + /* Битовое поле PCPOL, ширина 1 бит; данные PCPOL. */ + Uint16 PCPOL:1; // 13 Polarity of sync output + /* Битовое поле PCLOAD, ширина 1 бит; данные PCLOAD. */ + Uint16 PCLOAD:1; // 14 Position compare of shadow load + /* Битовое поле PCSHDW, ширина 1 бит; данные PCSHDW. */ + Uint16 PCSHDW:1; // 15 Position compare shadow enable +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QPOSCTL_REG в одной области памяти. */ +union QPOSCTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QPOSCTL_BITS bit;; порядок полей определяет расположение данных. */ + struct QPOSCTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// QEP interrupt control register bit definitions */ +/* Описывает структуру QEINT_BITS; порядок полей определяет расположение данных. */ +struct QEINT_BITS { // bits description + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 0 reserved + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 1 Position counter error + /* Битовое поле QPE, ширина 1 бит; данные QPE. */ + Uint16 QPE:1; // 2 Quadrature phase error + /* Битовое поле QDC, ширина 1 бит; данные QDC. */ + Uint16 QDC:1; // 3 Quadrature dir change + /* Битовое поле WTO, ширина 1 бит; данные WTO. */ + Uint16 WTO:1; // 4 Watchdog timeout + /* Битовое поле PCU, ширина 1 бит; данные PCU. */ + Uint16 PCU:1; // 5 Position counter underflow + /* Битовое поле PCO, ширина 1 бит; данные PCO. */ + Uint16 PCO:1; // 6 Position counter overflow + /* Битовое поле PCR, ширина 1 бит; данные PCR. */ + Uint16 PCR:1; // 7 Position compare ready + /* Битовое поле PCM, ширина 1 бит; данные PCM. */ + Uint16 PCM:1; // 8 Position compare match + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 9 Strobe event latch + /* Битовое поле IEL, ширина 1 бит; данные IEL. */ + Uint16 IEL:1; // 10 Event latch + /* Битовое поле UTO, ширина 1 бит; данные UTO. */ + Uint16 UTO:1; // 11 Unit timeout + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QEINT_REG в одной области памяти. */ +union QEINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QEINT_BITS bit;; порядок полей определяет расположение данных. */ + struct QEINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// QEP interrupt status register bit definitions */ +/* Описывает структуру QFLG_BITS; порядок полей определяет расположение данных. */ +struct QFLG_BITS { // bits description + /* Битовое поле INT, ширина 1 бит; данные INT. */ + Uint16 INT:1; // 0 Global interrupt + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 1 Position counter error + /* Битовое поле PHE, ширина 1 бит; данные PHE. */ + Uint16 PHE:1; // 2 Quadrature phase error + /* Битовое поле QDC, ширина 1 бит; данные QDC. */ + Uint16 QDC:1; // 3 Quadrature dir change + /* Битовое поле WTO, ширина 1 бит; данные WTO. */ + Uint16 WTO:1; // 4 Watchdog timeout + /* Битовое поле PCU, ширина 1 бит; данные PCU. */ + Uint16 PCU:1; // 5 Position counter underflow + /* Битовое поле PCO, ширина 1 бит; данные PCO. */ + Uint16 PCO:1; // 6 Position counter overflow + /* Битовое поле PCR, ширина 1 бит; данные PCR. */ + Uint16 PCR:1; // 7 Position compare ready + /* Битовое поле PCM, ширина 1 бит; данные PCM. */ + Uint16 PCM:1; // 8 Position compare match + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 9 Strobe event latch + /* Битовое поле IEL, ширина 1 бит; данные IEL. */ + Uint16 IEL:1; // 10 Event latch + /* Битовое поле UTO, ширина 1 бит; данные UTO. */ + Uint16 UTO:1; // 11 Unit timeout + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QFLG_REG в одной области памяти. */ +union QFLG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QFLG_BITS bit;; порядок полей определяет расположение данных. */ + struct QFLG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// QEP interrupt force register bit definitions */ +/* Описывает структуру QFRC_BITS; порядок полей определяет расположение данных. */ +struct QFRC_BITS { // bits description + /* Битовое поле reserved, ширина 1 бит; Зарезервировано; сохраняет положение следующих полей в аппаратном регистре. */ + Uint16 reserved:1; // 0 Reserved + /* Битовое поле PCE, ширина 1 бит; данные PCE. */ + Uint16 PCE:1; // 1 Position counter error + /* Битовое поле PHE, ширина 1 бит; данные PHE. */ + Uint16 PHE:1; // 2 Quadrature phase error + /* Битовое поле QDC, ширина 1 бит; данные QDC. */ + Uint16 QDC:1; // 3 Quadrature dir change + /* Битовое поле WTO, ширина 1 бит; данные WTO. */ + Uint16 WTO:1; // 4 Watchdog timeout + /* Битовое поле PCU, ширина 1 бит; данные PCU. */ + Uint16 PCU:1; // 5 Position counter underflow + /* Битовое поле PCO, ширина 1 бит; данные PCO. */ + Uint16 PCO:1; // 6 Position counter overflow + /* Битовое поле PCR, ширина 1 бит; данные PCR. */ + Uint16 PCR:1; // 7 Position compare ready + /* Битовое поле PCM, ширина 1 бит; данные PCM. */ + Uint16 PCM:1; // 8 Position compare match + /* Битовое поле SEL, ширина 1 бит; данные SEL. */ + Uint16 SEL:1; // 9 Strobe event latch + /* Битовое поле IEL, ширина 1 бит; данные IEL. */ + Uint16 IEL:1; // 10 Event latch + /* Битовое поле UTO, ширина 1 бит; данные UTO. */ + Uint16 UTO:1; // 11 Unit timeout + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений QFRC_REG в одной области памяти. */ +union QFRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QFRC_BITS bit;; порядок полей определяет расположение данных. */ + struct QFRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// V1.1 Added UPEVNT (bit 7) This reflects changes +// made as of F2833x Rev A devices +//---------------------------------------------------- +// QEP status register bit definitions */ +/* Описывает структуру QEPSTS_BITS; порядок полей определяет расположение данных. */ +struct QEPSTS_BITS { // bits description + /* Битовое поле PCEF, ширина 1 бит; данные PCEF. */ + Uint16 PCEF:1; // 0 Position counter error + /* Битовое поле FIMF, ширина 1 бит; данные FIMF. */ + Uint16 FIMF:1; // 1 First index marker + /* Битовое поле CDEF, ширина 1 бит; данные CDEF. */ + Uint16 CDEF:1; // 2 Capture direction error + /* Битовое поле COEF, ширина 1 бит; данные COEF. */ + Uint16 COEF:1; // 3 Capture overflow error + /* Битовое поле QDLF, ширина 1 бит; данные QDLF. */ + Uint16 QDLF:1; // 4 QEP direction latch + /* Битовое поле QDF, ширина 1 бит; данные QDF. */ + Uint16 QDF:1; // 5 Quadrature direction + /* Битовое поле FIDF, ширина 1 бит; данные FIDF. */ + Uint16 FIDF:1; // 6 Direction on first index marker + /* Битовое поле UPEVNT, ширина 1 бит; данные UPEVNT. */ + Uint16 UPEVNT:1; // 7 Unit position event flag + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений QEPSTS_REG в одной области памяти. */ +union QEPSTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру QEPSTS_BITS bit;; порядок полей определяет расположение данных. */ + struct QEPSTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- + +/* Описывает структуру EQEP_REGS; порядок полей определяет расположение данных. */ +struct EQEP_REGS { + /* Объявляет QPOSCNT — данные QPOSCNT. */ + Uint32 QPOSCNT; // Position counter + /* Объявляет QPOSINIT — данные QPOSINIT. */ + Uint32 QPOSINIT; // Position counter init + /* Объявляет QPOSMAX — данные QPOSMAX. */ + Uint32 QPOSMAX; // Maximum position count + /* Объявляет QPOSCMP — данные QPOSCMP. */ + Uint32 QPOSCMP; // Position compare + /* Объявляет QPOSILAT — данные QPOSILAT. */ + Uint32 QPOSILAT; // Index position latch + /* Объявляет QPOSSLAT — данные QPOSSLAT. */ + Uint32 QPOSSLAT; // Strobe position latch + /* Объявляет QPOSLAT — данные QPOSLAT. */ + Uint32 QPOSLAT; // Position latch + /* Объявляет QUTMR — данные QUTMR. */ + Uint32 QUTMR; // Unit timer + /* Объявляет QUPRD — данные QUPRD. */ + Uint32 QUPRD; // Unit period + /* Объявляет QWDTMR — данные QWDTMR. */ + Uint16 QWDTMR; // QEP watchdog timer + /* Объявляет QWDPRD — данные QWDPRD. */ + Uint16 QWDPRD; // QEP watchdog period + /* Объединяет несколько представлений QDECCTL_REG QDECCTL; в одной области памяти. */ + union QDECCTL_REG QDECCTL; // Quadrature decoder control + /* Объединяет несколько представлений QEPCTL_REG QEPCTL; в одной области памяти. */ + union QEPCTL_REG QEPCTL; // QEP control + /* Объединяет несколько представлений QCAPCTL_REG QCAPCTL; в одной области памяти. */ + union QCAPCTL_REG QCAPCTL; // Quadrature capture control + /* Объединяет несколько представлений QPOSCTL_REG QPOSCTL; в одной области памяти. */ + union QPOSCTL_REG QPOSCTL; // Position compare control + /* Объединяет несколько представлений QEINT_REG QEINT; в одной области памяти. */ + union QEINT_REG QEINT; // QEP interrupt control + /* Объединяет несколько представлений QFLG_REG QFLG; в одной области памяти. */ + union QFLG_REG QFLG; // QEP interrupt flag + /* Объединяет несколько представлений QFLG_REG QCLR; в одной области памяти. */ + union QFLG_REG QCLR; // QEP interrupt clear + /* Объединяет несколько представлений QFRC_REG QFRC; в одной области памяти. */ + union QFRC_REG QFRC; // QEP interrupt force + /* Объединяет несколько представлений QEPSTS_REG QEPSTS; в одной области памяти. */ + union QEPSTS_REG QEPSTS; // QEP status + /* Объявляет QCTMR — данные QCTMR. */ + Uint16 QCTMR; // QEP capture timer + /* Объявляет QCPRD — данные QCPRD. */ + Uint16 QCPRD; // QEP capture period + /* Объявляет QCTMRLAT — данные QCTMRLAT. */ + Uint16 QCTMRLAT; // QEP capture latch + /* Объявляет QCPRDLAT — данные QCPRDLAT. */ + Uint16 QCPRDLAT; // QEP capture period latch + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[30]; // reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct EQEP_REGS EQep1Regs;; порядок элементов сохраняется. */ +extern volatile struct EQEP_REGS EQep1Regs; +/* Продолжает список аргументов, полей или выражение extern volatile struct EQEP_REGS EQep2Regs;; порядок элементов сохраняется. */ +extern volatile struct EQEP_REGS EQep2Regs; + + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_EQEP_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h new file mode 100644 index 0000000..772b340 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Gpio.h @@ -0,0 +1,711 @@ +/* Поставляемое TI описание Gpio для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/4 $ +// Checkin $Date: November 15, 2007 09:58:53 $ +//########################################################################### +// +// FILE: DSP2833x_Gpio.h +// +// TITLE: DSP2833x General Purpose I/O Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_GPIO_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_GPIO_H +/* Определяет защитный символ или переключатель DSP2833x_GPIO_H для последующей компиляции. */ +#define DSP2833x_GPIO_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//---------------------------------------------------- +// GPIO A control register bit definitions */ +/* Описывает структуру GPACTRL_BITS; порядок полей определяет расположение данных. */ +struct GPACTRL_BITS { // bits description + /* Битовое поле QUALPRD0, ширина 8 бит; данные QUALPRD0. */ + Uint16 QUALPRD0:8; // 7:0 Qual period + /* Битовое поле QUALPRD1, ширина 8 бит; данные QUALPRD1. */ + Uint16 QUALPRD1:8; // 15:8 Qual period + /* Битовое поле QUALPRD2, ширина 8 бит; данные QUALPRD2. */ + Uint16 QUALPRD2:8; // 23:16 Qual period + /* Битовое поле QUALPRD3, ширина 8 бит; данные QUALPRD3. */ + Uint16 QUALPRD3:8; // 31:24 Qual period +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPACTRL_REG в одной области памяти. */ +union GPACTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPACTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct GPACTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// GPIO B control register bit definitions */ +/* Описывает структуру GPBCTRL_BITS; порядок полей определяет расположение данных. */ +struct GPBCTRL_BITS { // bits description + /* Битовое поле QUALPRD0, ширина 8 бит; данные QUALPRD0. */ + Uint16 QUALPRD0:8; // 7:0 Qual period + /* Битовое поле QUALPRD1, ширина 8 бит; данные QUALPRD1. */ + Uint16 QUALPRD1:8; // 15:8 Qual period + /* Битовое поле QUALPRD2, ширина 8 бит; данные QUALPRD2. */ + Uint16 QUALPRD2:8; // 23:16 Qual period + /* Битовое поле QUALPRD3, ширина 8 бит; данные QUALPRD3. */ + Uint16 QUALPRD3:8; // 31:24 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPBCTRL_REG в одной области памяти. */ +union GPBCTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPBCTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct GPBCTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// GPIO A Qual/MUX select register bit definitions */ +/* Описывает структуру GPA1_BITS; порядок полей определяет расположение данных. */ +struct GPA1_BITS { // bits description + /* Битовое поле GPIO0, ширина 2 бит; аппаратная линия ввода/вывода GPIO0. */ + Uint16 GPIO0:2; // 1:0 GPIO0 + /* Битовое поле GPIO1, ширина 2 бит; аппаратная линия ввода/вывода GPIO1. */ + Uint16 GPIO1:2; // 3:2 GPIO1 + /* Битовое поле GPIO2, ширина 2 бит; аппаратная линия ввода/вывода GPIO2. */ + Uint16 GPIO2:2; // 5:4 GPIO2 + /* Битовое поле GPIO3, ширина 2 бит; аппаратная линия ввода/вывода GPIO3. */ + Uint16 GPIO3:2; // 7:6 GPIO3 + /* Битовое поле GPIO4, ширина 2 бит; аппаратная линия ввода/вывода GPIO4. */ + Uint16 GPIO4:2; // 9:8 GPIO4 + /* Битовое поле GPIO5, ширина 2 бит; аппаратная линия ввода/вывода GPIO5. */ + Uint16 GPIO5:2; // 11:10 GPIO5 + /* Битовое поле GPIO6, ширина 2 бит; аппаратная линия ввода/вывода GPIO6. */ + Uint16 GPIO6:2; // 13:12 GPIO6 + /* Битовое поле GPIO7, ширина 2 бит; аппаратная линия ввода/вывода GPIO7. */ + Uint16 GPIO7:2; // 15:14 GPIO7 + /* Битовое поле GPIO8, ширина 2 бит; аппаратная линия ввода/вывода GPIO8. */ + Uint16 GPIO8:2; // 17:16 GPIO8 + /* Битовое поле GPIO9, ширина 2 бит; аппаратная линия ввода/вывода GPIO9. */ + Uint16 GPIO9:2; // 19:18 GPIO9 + /* Битовое поле GPIO10, ширина 2 бит; аппаратная линия ввода/вывода GPIO10. */ + Uint16 GPIO10:2; // 21:20 GPIO10 + /* Битовое поле GPIO11, ширина 2 бит; аппаратная линия ввода/вывода GPIO11. */ + Uint16 GPIO11:2; // 23:22 GPIO11 + /* Битовое поле GPIO12, ширина 2 бит; аппаратная линия ввода/вывода GPIO12. */ + Uint16 GPIO12:2; // 25:24 GPIO12 + /* Битовое поле GPIO13, ширина 2 бит; аппаратная линия ввода/вывода GPIO13. */ + Uint16 GPIO13:2; // 27:26 GPIO13 + /* Битовое поле GPIO14, ширина 2 бит; аппаратная линия ввода/вывода GPIO14. */ + Uint16 GPIO14:2; // 29:28 GPIO14 + /* Битовое поле GPIO15, ширина 2 бит; аппаратная линия ввода/вывода GPIO15. */ + Uint16 GPIO15:2; // 31:30 GPIO15 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру GPA2_BITS; порядок полей определяет расположение данных. */ +struct GPA2_BITS { // bits description + /* Битовое поле GPIO16, ширина 2 бит; аппаратная линия ввода/вывода GPIO16. */ + Uint16 GPIO16:2; // 1:0 GPIO16 + /* Битовое поле GPIO17, ширина 2 бит; аппаратная линия ввода/вывода GPIO17. */ + Uint16 GPIO17:2; // 3:2 GPIO17 + /* Битовое поле GPIO18, ширина 2 бит; аппаратная линия ввода/вывода GPIO18. */ + Uint16 GPIO18:2; // 5:4 GPIO18 + /* Битовое поле GPIO19, ширина 2 бит; аппаратная линия ввода/вывода GPIO19. */ + Uint16 GPIO19:2; // 7:6 GPIO19 + /* Битовое поле GPIO20, ширина 2 бит; аппаратная линия ввода/вывода GPIO20. */ + Uint16 GPIO20:2; // 9:8 GPIO20 + /* Битовое поле GPIO21, ширина 2 бит; аппаратная линия ввода/вывода GPIO21. */ + Uint16 GPIO21:2; // 11:10 GPIO21 + /* Битовое поле GPIO22, ширина 2 бит; аппаратная линия ввода/вывода GPIO22. */ + Uint16 GPIO22:2; // 13:12 GPIO22 + /* Битовое поле GPIO23, ширина 2 бит; аппаратная линия ввода/вывода GPIO23. */ + Uint16 GPIO23:2; // 15:14 GPIO23 + /* Битовое поле GPIO24, ширина 2 бит; аппаратная линия ввода/вывода GPIO24. */ + Uint16 GPIO24:2; // 17:16 GPIO24 + /* Битовое поле GPIO25, ширина 2 бит; аппаратная линия ввода/вывода GPIO25. */ + Uint16 GPIO25:2; // 19:18 GPIO25 + /* Битовое поле GPIO26, ширина 2 бит; аппаратная линия ввода/вывода GPIO26. */ + Uint16 GPIO26:2; // 21:20 GPIO26 + /* Битовое поле GPIO27, ширина 2 бит; аппаратная линия ввода/вывода GPIO27. */ + Uint16 GPIO27:2; // 23:22 GPIO27 + /* Битовое поле GPIO28, ширина 2 бит; аппаратная линия ввода/вывода GPIO28. */ + Uint16 GPIO28:2; // 25:24 GPIO28 + /* Битовое поле GPIO29, ширина 2 бит; аппаратная линия ввода/вывода GPIO29. */ + Uint16 GPIO29:2; // 27:26 GPIO29 + /* Битовое поле GPIO30, ширина 2 бит; аппаратная линия ввода/вывода GPIO30. */ + Uint16 GPIO30:2; // 29:28 GPIO30 + /* Битовое поле GPIO31, ширина 2 бит; аппаратная линия ввода/вывода GPIO31. */ + Uint16 GPIO31:2; // 31:30 GPIO31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPB1_BITS; порядок полей определяет расположение данных. */ +struct GPB1_BITS { // bits description + /* Битовое поле GPIO32, ширина 2 бит; аппаратная линия ввода/вывода GPIO32. */ + Uint16 GPIO32:2; // 1:0 GPIO32 + /* Битовое поле GPIO33, ширина 2 бит; аппаратная линия ввода/вывода GPIO33. */ + Uint16 GPIO33:2; // 3:2 GPIO33 + /* Битовое поле GPIO34, ширина 2 бит; аппаратная линия ввода/вывода GPIO34. */ + Uint16 GPIO34:2; // 5:4 GPIO34 + /* Битовое поле GPIO35, ширина 2 бит; аппаратная линия ввода/вывода GPIO35. */ + Uint16 GPIO35:2; // 7:6 GPIO35 + /* Битовое поле GPIO36, ширина 2 бит; аппаратная линия ввода/вывода GPIO36. */ + Uint16 GPIO36:2; // 9:8 GPIO36 + /* Битовое поле GPIO37, ширина 2 бит; аппаратная линия ввода/вывода GPIO37. */ + Uint16 GPIO37:2; // 11:10 GPIO37 + /* Битовое поле GPIO38, ширина 2 бит; аппаратная линия ввода/вывода GPIO38. */ + Uint16 GPIO38:2; // 13:12 GPIO38 + /* Битовое поле GPIO39, ширина 2 бит; аппаратная линия ввода/вывода GPIO39. */ + Uint16 GPIO39:2; // 15:14 GPIO39 + /* Битовое поле GPIO40, ширина 2 бит; аппаратная линия ввода/вывода GPIO40. */ + Uint16 GPIO40:2; // 17:16 GPIO40 + /* Битовое поле GPIO41, ширина 2 бит; аппаратная линия ввода/вывода GPIO41. */ + Uint16 GPIO41:2; // 19:16 GPIO41 + /* Битовое поле GPIO42, ширина 2 бит; аппаратная линия ввода/вывода GPIO42. */ + Uint16 GPIO42:2; // 21:20 GPIO42 + /* Битовое поле GPIO43, ширина 2 бит; аппаратная линия ввода/вывода GPIO43. */ + Uint16 GPIO43:2; // 23:22 GPIO43 + /* Битовое поле GPIO44, ширина 2 бит; аппаратная линия ввода/вывода GPIO44. */ + Uint16 GPIO44:2; // 25:24 GPIO44 + /* Битовое поле GPIO45, ширина 2 бит; аппаратная линия ввода/вывода GPIO45. */ + Uint16 GPIO45:2; // 27:26 GPIO45 + /* Битовое поле GPIO46, ширина 2 бит; аппаратная линия ввода/вывода GPIO46. */ + Uint16 GPIO46:2; // 29:28 GPIO46 + /* Битовое поле GPIO47, ширина 2 бит; аппаратная линия ввода/вывода GPIO47. */ + Uint16 GPIO47:2; // 31:30 GPIO47 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPB2_BITS; порядок полей определяет расположение данных. */ +struct GPB2_BITS { // bits description + /* Битовое поле GPIO48, ширина 2 бит; аппаратная линия ввода/вывода GPIO48. */ + Uint16 GPIO48:2; // 1:0 GPIO48 + /* Битовое поле GPIO49, ширина 2 бит; аппаратная линия ввода/вывода GPIO49. */ + Uint16 GPIO49:2; // 3:2 GPIO49 + /* Битовое поле GPIO50, ширина 2 бит; аппаратная линия ввода/вывода GPIO50. */ + Uint16 GPIO50:2; // 5:4 GPIO50 + /* Битовое поле GPIO51, ширина 2 бит; аппаратная линия ввода/вывода GPIO51. */ + Uint16 GPIO51:2; // 7:6 GPIO51 + /* Битовое поле GPIO52, ширина 2 бит; аппаратная линия ввода/вывода GPIO52. */ + Uint16 GPIO52:2; // 9:8 GPIO52 + /* Битовое поле GPIO53, ширина 2 бит; аппаратная линия ввода/вывода GPIO53. */ + Uint16 GPIO53:2; // 11:10 GPIO53 + /* Битовое поле GPIO54, ширина 2 бит; аппаратная линия ввода/вывода GPIO54. */ + Uint16 GPIO54:2; // 13:12 GPIO54 + /* Битовое поле GPIO55, ширина 2 бит; аппаратная линия ввода/вывода GPIO55. */ + Uint16 GPIO55:2; // 15:14 GPIO55 + /* Битовое поле GPIO56, ширина 2 бит; аппаратная линия ввода/вывода GPIO56. */ + Uint16 GPIO56:2; // 17:16 GPIO56 + /* Битовое поле GPIO57, ширина 2 бит; аппаратная линия ввода/вывода GPIO57. */ + Uint16 GPIO57:2; // 19:18 GPIO57 + /* Битовое поле GPIO58, ширина 2 бит; аппаратная линия ввода/вывода GPIO58. */ + Uint16 GPIO58:2; // 21:20 GPIO58 + /* Битовое поле GPIO59, ширина 2 бит; аппаратная линия ввода/вывода GPIO59. */ + Uint16 GPIO59:2; // 23:22 GPIO59 + /* Битовое поле GPIO60, ширина 2 бит; аппаратная линия ввода/вывода GPIO60. */ + Uint16 GPIO60:2; // 25:24 GPIO60 + /* Битовое поле GPIO61, ширина 2 бит; аппаратная линия ввода/вывода GPIO61. */ + Uint16 GPIO61:2; // 27:26 GPIO61 + /* Битовое поле GPIO62, ширина 2 бит; аппаратная линия ввода/вывода GPIO62. */ + Uint16 GPIO62:2; // 29:28 GPIO62 + /* Битовое поле GPIO63, ширина 2 бит; аппаратная линия ввода/вывода GPIO63. */ + Uint16 GPIO63:2; // 31:30 GPIO63 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPC1_BITS; порядок полей определяет расположение данных. */ +struct GPC1_BITS { // bits description + /* Битовое поле GPIO64, ширина 2 бит; аппаратная линия ввода/вывода GPIO64. */ + Uint16 GPIO64:2; // 1:0 GPIO64 + /* Битовое поле GPIO65, ширина 2 бит; аппаратная линия ввода/вывода GPIO65. */ + Uint16 GPIO65:2; // 3:2 GPIO65 + /* Битовое поле GPIO66, ширина 2 бит; аппаратная линия ввода/вывода GPIO66. */ + Uint16 GPIO66:2; // 5:4 GPIO66 + /* Битовое поле GPIO67, ширина 2 бит; аппаратная линия ввода/вывода GPIO67. */ + Uint16 GPIO67:2; // 7:6 GPIO67 + /* Битовое поле GPIO68, ширина 2 бит; аппаратная линия ввода/вывода GPIO68. */ + Uint16 GPIO68:2; // 9:8 GPIO68 + /* Битовое поле GPIO69, ширина 2 бит; аппаратная линия ввода/вывода GPIO69. */ + Uint16 GPIO69:2; // 11:10 GPIO69 + /* Битовое поле GPIO70, ширина 2 бит; аппаратная линия ввода/вывода GPIO70. */ + Uint16 GPIO70:2; // 13:12 GPIO70 + /* Битовое поле GPIO71, ширина 2 бит; аппаратная линия ввода/вывода GPIO71. */ + Uint16 GPIO71:2; // 15:14 GPIO71 + /* Битовое поле GPIO72, ширина 2 бит; аппаратная линия ввода/вывода GPIO72. */ + Uint16 GPIO72:2; // 17:16 GPIO72 + /* Битовое поле GPIO73, ширина 2 бит; аппаратная линия ввода/вывода GPIO73. */ + Uint16 GPIO73:2; // 19:18 GPIO73 + /* Битовое поле GPIO74, ширина 2 бит; аппаратная линия ввода/вывода GPIO74. */ + Uint16 GPIO74:2; // 21:20 GPIO74 + /* Битовое поле GPIO75, ширина 2 бит; аппаратная линия ввода/вывода GPIO75. */ + Uint16 GPIO75:2; // 23:22 GPIO75 + /* Битовое поле GPIO76, ширина 2 бит; аппаратная линия ввода/вывода GPIO76. */ + Uint16 GPIO76:2; // 25:24 GPIO76 + /* Битовое поле GPIO77, ширина 2 бит; аппаратная линия ввода/вывода GPIO77. */ + Uint16 GPIO77:2; // 27:26 GPIO77 + /* Битовое поле GPIO78, ширина 2 бит; аппаратная линия ввода/вывода GPIO78. */ + Uint16 GPIO78:2; // 29:28 GPIO78 + /* Битовое поле GPIO79, ширина 2 бит; аппаратная линия ввода/вывода GPIO79. */ + Uint16 GPIO79:2; // 31:30 GPIO79 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру GPC2_BITS; порядок полей определяет расположение данных. */ +struct GPC2_BITS { // bits description + /* Битовое поле GPIO80, ширина 2 бит; аппаратная линия ввода/вывода GPIO80. */ + Uint16 GPIO80:2; // 1:0 GPIO80 + /* Битовое поле GPIO81, ширина 2 бит; аппаратная линия ввода/вывода GPIO81. */ + Uint16 GPIO81:2; // 3:2 GPIO81 + /* Битовое поле GPIO82, ширина 2 бит; аппаратная линия ввода/вывода GPIO82. */ + Uint16 GPIO82:2; // 5:4 GPIO82 + /* Битовое поле GPIO83, ширина 2 бит; аппаратная линия ввода/вывода GPIO83. */ + Uint16 GPIO83:2; // 7:6 GPIO83 + /* Битовое поле GPIO84, ширина 2 бит; аппаратная линия ввода/вывода GPIO84. */ + Uint16 GPIO84:2; // 9:8 GPIO84 + /* Битовое поле GPIO85, ширина 2 бит; аппаратная линия ввода/вывода GPIO85. */ + Uint16 GPIO85:2; // 11:10 GPIO85 + /* Битовое поле GPIO86, ширина 2 бит; аппаратная линия ввода/вывода GPIO86. */ + Uint16 GPIO86:2; // 13:12 GPIO86 + /* Битовое поле GPIO87, ширина 2 бит; аппаратная линия ввода/вывода GPIO87. */ + Uint16 GPIO87:2; // 15:14 GPIO87 + /* Битовое поле rsvd, ширина 16 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:16; // 31:16 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений GPA1_REG в одной области памяти. */ +union GPA1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPA1_BITS bit;; порядок полей определяет расположение данных. */ + struct GPA1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPA2_REG в одной области памяти. */ +union GPA2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPA2_BITS bit;; порядок полей определяет расположение данных. */ + struct GPA2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPB1_REG в одной области памяти. */ +union GPB1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPB1_BITS bit;; порядок полей определяет расположение данных. */ + struct GPB1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPB2_REG в одной области памяти. */ +union GPB2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPB2_BITS bit;; порядок полей определяет расположение данных. */ + struct GPB2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPC1_REG в одной области памяти. */ +union GPC1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPC1_BITS bit;; порядок полей определяет расположение данных. */ + struct GPC1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPC2_REG в одной области памяти. */ +union GPC2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPC2_BITS bit;; порядок полей определяет расположение данных. */ + struct GPC2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// GPIO A DIR/TOGGLE/SET/CLEAR register bit definitions */ +/* Описывает структуру GPADAT_BITS; порядок полей определяет расположение данных. */ +struct GPADAT_BITS { // bits description + /* Битовое поле GPIO0, ширина 1 бит; аппаратная линия ввода/вывода GPIO0. */ + Uint16 GPIO0:1; // 0 GPIO0 + /* Битовое поле GPIO1, ширина 1 бит; аппаратная линия ввода/вывода GPIO1. */ + Uint16 GPIO1:1; // 1 GPIO1 + /* Битовое поле GPIO2, ширина 1 бит; аппаратная линия ввода/вывода GPIO2. */ + Uint16 GPIO2:1; // 2 GPIO2 + /* Битовое поле GPIO3, ширина 1 бит; аппаратная линия ввода/вывода GPIO3. */ + Uint16 GPIO3:1; // 3 GPIO3 + /* Битовое поле GPIO4, ширина 1 бит; аппаратная линия ввода/вывода GPIO4. */ + Uint16 GPIO4:1; // 4 GPIO4 + /* Битовое поле GPIO5, ширина 1 бит; аппаратная линия ввода/вывода GPIO5. */ + Uint16 GPIO5:1; // 5 GPIO5 + /* Битовое поле GPIO6, ширина 1 бит; аппаратная линия ввода/вывода GPIO6. */ + Uint16 GPIO6:1; // 6 GPIO6 + /* Битовое поле GPIO7, ширина 1 бит; аппаратная линия ввода/вывода GPIO7. */ + Uint16 GPIO7:1; // 7 GPIO7 + /* Битовое поле GPIO8, ширина 1 бит; аппаратная линия ввода/вывода GPIO8. */ + Uint16 GPIO8:1; // 8 GPIO8 + /* Битовое поле GPIO9, ширина 1 бит; аппаратная линия ввода/вывода GPIO9. */ + Uint16 GPIO9:1; // 9 GPIO9 + /* Битовое поле GPIO10, ширина 1 бит; аппаратная линия ввода/вывода GPIO10. */ + Uint16 GPIO10:1; // 10 GPIO10 + /* Битовое поле GPIO11, ширина 1 бит; аппаратная линия ввода/вывода GPIO11. */ + Uint16 GPIO11:1; // 11 GPIO11 + /* Битовое поле GPIO12, ширина 1 бит; аппаратная линия ввода/вывода GPIO12. */ + Uint16 GPIO12:1; // 12 GPIO12 + /* Битовое поле GPIO13, ширина 1 бит; аппаратная линия ввода/вывода GPIO13. */ + Uint16 GPIO13:1; // 13 GPIO13 + /* Битовое поле GPIO14, ширина 1 бит; аппаратная линия ввода/вывода GPIO14. */ + Uint16 GPIO14:1; // 14 GPIO14 + /* Битовое поле GPIO15, ширина 1 бит; аппаратная линия ввода/вывода GPIO15. */ + Uint16 GPIO15:1; // 15 GPIO15 + /* Битовое поле GPIO16, ширина 1 бит; аппаратная линия ввода/вывода GPIO16. */ + Uint16 GPIO16:1; // 16 GPIO16 + /* Битовое поле GPIO17, ширина 1 бит; аппаратная линия ввода/вывода GPIO17. */ + Uint16 GPIO17:1; // 17 GPIO17 + /* Битовое поле GPIO18, ширина 1 бит; аппаратная линия ввода/вывода GPIO18. */ + Uint16 GPIO18:1; // 18 GPIO18 + /* Битовое поле GPIO19, ширина 1 бит; аппаратная линия ввода/вывода GPIO19. */ + Uint16 GPIO19:1; // 19 GPIO19 + /* Битовое поле GPIO20, ширина 1 бит; аппаратная линия ввода/вывода GPIO20. */ + Uint16 GPIO20:1; // 20 GPIO20 + /* Битовое поле GPIO21, ширина 1 бит; аппаратная линия ввода/вывода GPIO21. */ + Uint16 GPIO21:1; // 21 GPIO21 + /* Битовое поле GPIO22, ширина 1 бит; аппаратная линия ввода/вывода GPIO22. */ + Uint16 GPIO22:1; // 22 GPIO22 + /* Битовое поле GPIO23, ширина 1 бит; аппаратная линия ввода/вывода GPIO23. */ + Uint16 GPIO23:1; // 23 GPIO23 + /* Битовое поле GPIO24, ширина 1 бит; аппаратная линия ввода/вывода GPIO24. */ + Uint16 GPIO24:1; // 24 GPIO24 + /* Битовое поле GPIO25, ширина 1 бит; аппаратная линия ввода/вывода GPIO25. */ + Uint16 GPIO25:1; // 25 GPIO25 + /* Битовое поле GPIO26, ширина 1 бит; аппаратная линия ввода/вывода GPIO26. */ + Uint16 GPIO26:1; // 26 GPIO26 + /* Битовое поле GPIO27, ширина 1 бит; аппаратная линия ввода/вывода GPIO27. */ + Uint16 GPIO27:1; // 27 GPIO27 + /* Битовое поле GPIO28, ширина 1 бит; аппаратная линия ввода/вывода GPIO28. */ + Uint16 GPIO28:1; // 28 GPIO28 + /* Битовое поле GPIO29, ширина 1 бит; аппаратная линия ввода/вывода GPIO29. */ + Uint16 GPIO29:1; // 29 GPIO29 + /* Битовое поле GPIO30, ширина 1 бит; аппаратная линия ввода/вывода GPIO30. */ + Uint16 GPIO30:1; // 30 GPIO30 + /* Битовое поле GPIO31, ширина 1 бит; аппаратная линия ввода/вывода GPIO31. */ + Uint16 GPIO31:1; // 31 GPIO31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPBDAT_BITS; порядок полей определяет расположение данных. */ +struct GPBDAT_BITS { // bits description + /* Битовое поле GPIO32, ширина 1 бит; аппаратная линия ввода/вывода GPIO32. */ + Uint16 GPIO32:1; // 0 GPIO32 + /* Битовое поле GPIO33, ширина 1 бит; аппаратная линия ввода/вывода GPIO33. */ + Uint16 GPIO33:1; // 1 GPIO33 + /* Битовое поле GPIO34, ширина 1 бит; аппаратная линия ввода/вывода GPIO34. */ + Uint16 GPIO34:1; // 2 GPIO34 + /* Битовое поле GPIO35, ширина 1 бит; аппаратная линия ввода/вывода GPIO35. */ + Uint16 GPIO35:1; // 3 GPIO35 + /* Битовое поле GPIO36, ширина 1 бит; аппаратная линия ввода/вывода GPIO36. */ + Uint16 GPIO36:1; // 4 GPIO36 + /* Битовое поле GPIO37, ширина 1 бит; аппаратная линия ввода/вывода GPIO37. */ + Uint16 GPIO37:1; // 5 GPIO37 + /* Битовое поле GPIO38, ширина 1 бит; аппаратная линия ввода/вывода GPIO38. */ + Uint16 GPIO38:1; // 6 GPIO38 + /* Битовое поле GPIO39, ширина 1 бит; аппаратная линия ввода/вывода GPIO39. */ + Uint16 GPIO39:1; // 7 GPIO39 + /* Битовое поле GPIO40, ширина 1 бит; аппаратная линия ввода/вывода GPIO40. */ + Uint16 GPIO40:1; // 8 GPIO40 + /* Битовое поле GPIO41, ширина 1 бит; аппаратная линия ввода/вывода GPIO41. */ + Uint16 GPIO41:1; // 9 GPIO41 + /* Битовое поле GPIO42, ширина 1 бит; аппаратная линия ввода/вывода GPIO42. */ + Uint16 GPIO42:1; // 10 GPIO42 + /* Битовое поле GPIO43, ширина 1 бит; аппаратная линия ввода/вывода GPIO43. */ + Uint16 GPIO43:1; // 11 GPIO43 + /* Битовое поле GPIO44, ширина 1 бит; аппаратная линия ввода/вывода GPIO44. */ + Uint16 GPIO44:1; // 12 GPIO44 + /* Битовое поле GPIO45, ширина 1 бит; аппаратная линия ввода/вывода GPIO45. */ + Uint16 GPIO45:1; // 13 GPIO45 + /* Битовое поле GPIO46, ширина 1 бит; аппаратная линия ввода/вывода GPIO46. */ + Uint16 GPIO46:1; // 14 GPIO46 + /* Битовое поле GPIO47, ширина 1 бит; аппаратная линия ввода/вывода GPIO47. */ + Uint16 GPIO47:1; // 15 GPIO47 + /* Битовое поле GPIO48, ширина 1 бит; аппаратная линия ввода/вывода GPIO48. */ + Uint16 GPIO48:1; // 16 GPIO48 + /* Битовое поле GPIO49, ширина 1 бит; аппаратная линия ввода/вывода GPIO49. */ + Uint16 GPIO49:1; // 17 GPIO49 + /* Битовое поле GPIO50, ширина 1 бит; аппаратная линия ввода/вывода GPIO50. */ + Uint16 GPIO50:1; // 18 GPIO50 + /* Битовое поле GPIO51, ширина 1 бит; аппаратная линия ввода/вывода GPIO51. */ + Uint16 GPIO51:1; // 19 GPIO51 + /* Битовое поле GPIO52, ширина 1 бит; аппаратная линия ввода/вывода GPIO52. */ + Uint16 GPIO52:1; // 20 GPIO52 + /* Битовое поле GPIO53, ширина 1 бит; аппаратная линия ввода/вывода GPIO53. */ + Uint16 GPIO53:1; // 21 GPIO53 + /* Битовое поле GPIO54, ширина 1 бит; аппаратная линия ввода/вывода GPIO54. */ + Uint16 GPIO54:1; // 22 GPIO54 + /* Битовое поле GPIO55, ширина 1 бит; аппаратная линия ввода/вывода GPIO55. */ + Uint16 GPIO55:1; // 23 GPIO55 + /* Битовое поле GPIO56, ширина 1 бит; аппаратная линия ввода/вывода GPIO56. */ + Uint16 GPIO56:1; // 24 GPIO56 + /* Битовое поле GPIO57, ширина 1 бит; аппаратная линия ввода/вывода GPIO57. */ + Uint16 GPIO57:1; // 25 GPIO57 + /* Битовое поле GPIO58, ширина 1 бит; аппаратная линия ввода/вывода GPIO58. */ + Uint16 GPIO58:1; // 26 GPIO58 + /* Битовое поле GPIO59, ширина 1 бит; аппаратная линия ввода/вывода GPIO59. */ + Uint16 GPIO59:1; // 27 GPIO59 + /* Битовое поле GPIO60, ширина 1 бит; аппаратная линия ввода/вывода GPIO60. */ + Uint16 GPIO60:1; // 28 GPIO60 + /* Битовое поле GPIO61, ширина 1 бит; аппаратная линия ввода/вывода GPIO61. */ + Uint16 GPIO61:1; // 29 GPIO61 + /* Битовое поле GPIO62, ширина 1 бит; аппаратная линия ввода/вывода GPIO62. */ + Uint16 GPIO62:1; // 30 GPIO62 + /* Битовое поле GPIO63, ширина 1 бит; аппаратная линия ввода/вывода GPIO63. */ + Uint16 GPIO63:1; // 31 GPIO63 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPCDAT_BITS; порядок полей определяет расположение данных. */ +struct GPCDAT_BITS { // bits description + /* Битовое поле GPIO64, ширина 1 бит; аппаратная линия ввода/вывода GPIO64. */ + Uint16 GPIO64:1; // 0 GPIO64 + /* Битовое поле GPIO65, ширина 1 бит; аппаратная линия ввода/вывода GPIO65. */ + Uint16 GPIO65:1; // 1 GPIO65 + /* Битовое поле GPIO66, ширина 1 бит; аппаратная линия ввода/вывода GPIO66. */ + Uint16 GPIO66:1; // 2 GPIO66 + /* Битовое поле GPIO67, ширина 1 бит; аппаратная линия ввода/вывода GPIO67. */ + Uint16 GPIO67:1; // 3 GPIO67 + /* Битовое поле GPIO68, ширина 1 бит; аппаратная линия ввода/вывода GPIO68. */ + Uint16 GPIO68:1; // 4 GPIO68 + /* Битовое поле GPIO69, ширина 1 бит; аппаратная линия ввода/вывода GPIO69. */ + Uint16 GPIO69:1; // 5 GPIO69 + /* Битовое поле GPIO70, ширина 1 бит; аппаратная линия ввода/вывода GPIO70. */ + Uint16 GPIO70:1; // 6 GPIO70 + /* Битовое поле GPIO71, ширина 1 бит; аппаратная линия ввода/вывода GPIO71. */ + Uint16 GPIO71:1; // 7 GPIO71 + /* Битовое поле GPIO72, ширина 1 бит; аппаратная линия ввода/вывода GPIO72. */ + Uint16 GPIO72:1; // 8 GPIO72 + /* Битовое поле GPIO73, ширина 1 бит; аппаратная линия ввода/вывода GPIO73. */ + Uint16 GPIO73:1; // 9 GPIO73 + /* Битовое поле GPIO74, ширина 1 бит; аппаратная линия ввода/вывода GPIO74. */ + Uint16 GPIO74:1; // 10 GPIO74 + /* Битовое поле GPIO75, ширина 1 бит; аппаратная линия ввода/вывода GPIO75. */ + Uint16 GPIO75:1; // 11 GPIO75 + /* Битовое поле GPIO76, ширина 1 бит; аппаратная линия ввода/вывода GPIO76. */ + Uint16 GPIO76:1; // 12 GPIO76 + /* Битовое поле GPIO77, ширина 1 бит; аппаратная линия ввода/вывода GPIO77. */ + Uint16 GPIO77:1; // 13 GPIO77 + /* Битовое поле GPIO78, ширина 1 бит; аппаратная линия ввода/вывода GPIO78. */ + Uint16 GPIO78:1; // 14 GPIO78 + /* Битовое поле GPIO79, ширина 1 бит; аппаратная линия ввода/вывода GPIO79. */ + Uint16 GPIO79:1; // 15 GPIO79 + /* Битовое поле GPIO80, ширина 1 бит; аппаратная линия ввода/вывода GPIO80. */ + Uint16 GPIO80:1; // 16 GPIO80 + /* Битовое поле GPIO81, ширина 1 бит; аппаратная линия ввода/вывода GPIO81. */ + Uint16 GPIO81:1; // 17 GPIO81 + /* Битовое поле GPIO82, ширина 1 бит; аппаратная линия ввода/вывода GPIO82. */ + Uint16 GPIO82:1; // 18 GPIO82 + /* Битовое поле GPIO83, ширина 1 бит; аппаратная линия ввода/вывода GPIO83. */ + Uint16 GPIO83:1; // 19 GPIO83 + /* Битовое поле GPIO84, ширина 1 бит; аппаратная линия ввода/вывода GPIO84. */ + Uint16 GPIO84:1; // 20 GPIO84 + /* Битовое поле GPIO85, ширина 1 бит; аппаратная линия ввода/вывода GPIO85. */ + Uint16 GPIO85:1; // 21 GPIO85 + /* Битовое поле GPIO86, ширина 1 бит; аппаратная линия ввода/вывода GPIO86. */ + Uint16 GPIO86:1; // 22 GPIO86 + /* Битовое поле GPIO87, ширина 1 бит; аппаратная линия ввода/вывода GPIO87. */ + Uint16 GPIO87:1; // 23 GPIO87 + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 31:24 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений GPADAT_REG в одной области памяти. */ +union GPADAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPADAT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPADAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPBDAT_REG в одной области памяти. */ +union GPBDAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPBDAT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPBDAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPCDAT_REG в одной области памяти. */ +union GPCDAT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру GPCDAT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPCDAT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//---------------------------------------------------- +// GPIO Xint1/XINT2/XNMI select register bit definitions */ +/* Описывает структуру GPIOXINT_BITS; порядок полей определяет расположение данных. */ +struct GPIOXINT_BITS { // bits description + /* Битовое поле GPIOSEL, ширина 5 бит; аппаратная линия ввода/вывода GPIOSEL. */ + Uint16 GPIOSEL:5; // 4:0 Select GPIO interrupt input source + /* Битовое поле rsvd1, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений GPIOXINT_REG в одной области памяти. */ +union GPIOXINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру GPIOXINT_BITS bit;; порядок полей определяет расположение данных. */ + struct GPIOXINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру GPIO_CTRL_REGS; порядок полей определяет расположение данных. */ +struct GPIO_CTRL_REGS { + /* Объединяет несколько представлений GPACTRL_REG GPACTRL; в одной области памяти. */ + union GPACTRL_REG GPACTRL; // GPIO A Control Register (GPIO0 to 31) + /* Объединяет несколько представлений GPA1_REG GPAQSEL1; в одной области памяти. */ + union GPA1_REG GPAQSEL1; // GPIO A Qualifier Select 1 Register (GPIO0 to 15) + /* Объединяет несколько представлений GPA2_REG GPAQSEL2; в одной области памяти. */ + union GPA2_REG GPAQSEL2; // GPIO A Qualifier Select 2 Register (GPIO16 to 31) + /* Объединяет несколько представлений GPA1_REG GPAMUX1; в одной области памяти. */ + union GPA1_REG GPAMUX1; // GPIO A Mux 1 Register (GPIO0 to 15) + /* Объединяет несколько представлений GPA2_REG GPAMUX2; в одной области памяти. */ + union GPA2_REG GPAMUX2; // GPIO A Mux 2 Register (GPIO16 to 31) + /* Объединяет несколько представлений GPADAT_REG GPADIR; в одной области памяти. */ + union GPADAT_REG GPADIR; // GPIO A Direction Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPAPUD; в одной области памяти. */ + union GPADAT_REG GPAPUD; // GPIO A Pull Up Disable Register (GPIO0 to 31) + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd1; + /* Объединяет несколько представлений GPBCTRL_REG GPBCTRL; в одной области памяти. */ + union GPBCTRL_REG GPBCTRL; // GPIO B Control Register (GPIO32 to 63) + /* Объединяет несколько представлений GPB1_REG GPBQSEL1; в одной области памяти. */ + union GPB1_REG GPBQSEL1; // GPIO B Qualifier Select 1 Register (GPIO32 to 47) + /* Объединяет несколько представлений GPB2_REG GPBQSEL2; в одной области памяти. */ + union GPB2_REG GPBQSEL2; // GPIO B Qualifier Select 2 Register (GPIO48 to 63) + /* Объединяет несколько представлений GPB1_REG GPBMUX1; в одной области памяти. */ + union GPB1_REG GPBMUX1; // GPIO B Mux 1 Register (GPIO32 to 47) + /* Объединяет несколько представлений GPB2_REG GPBMUX2; в одной области памяти. */ + union GPB2_REG GPBMUX2; // GPIO B Mux 2 Register (GPIO48 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBDIR; в одной области памяти. */ + union GPBDAT_REG GPBDIR; // GPIO B Direction Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBPUD; в одной области памяти. */ + union GPBDAT_REG GPBPUD; // GPIO B Pull Up Disable Register (GPIO32 to 63) + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[8]; + /* Объединяет несколько представлений GPC1_REG GPCMUX1; в одной области памяти. */ + union GPC1_REG GPCMUX1; // GPIO C Mux 1 Register (GPIO64 to 79) + /* Объединяет несколько представлений GPC2_REG GPCMUX2; в одной области памяти. */ + union GPC2_REG GPCMUX2; // GPIO C Mux 2 Register (GPIO80 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCDIR; в одной области памяти. */ + union GPCDAT_REG GPCDIR; // GPIO C Direction Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCPUD; в одной области памяти. */ + union GPCDAT_REG GPCPUD; // GPIO C Pull Up Disable Register (GPIO64 to 95) +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPIO_DATA_REGS; порядок полей определяет расположение данных. */ +struct GPIO_DATA_REGS { + /* Объединяет несколько представлений GPADAT_REG GPADAT; в одной области памяти. */ + union GPADAT_REG GPADAT; // GPIO Data Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPASET; в одной области памяти. */ + union GPADAT_REG GPASET; // GPIO Data Set Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPACLEAR; в одной области памяти. */ + union GPADAT_REG GPACLEAR; // GPIO Data Clear Register (GPIO0 to 31) + /* Объединяет несколько представлений GPADAT_REG GPATOGGLE; в одной области памяти. */ + union GPADAT_REG GPATOGGLE; // GPIO Data Toggle Register (GPIO0 to 31) + /* Объединяет несколько представлений GPBDAT_REG GPBDAT; в одной области памяти. */ + union GPBDAT_REG GPBDAT; // GPIO Data Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBSET; в одной области памяти. */ + union GPBDAT_REG GPBSET; // GPIO Data Set Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBCLEAR; в одной области памяти. */ + union GPBDAT_REG GPBCLEAR; // GPIO Data Clear Register (GPIO32 to 63) + /* Объединяет несколько представлений GPBDAT_REG GPBTOGGLE; в одной области памяти. */ + union GPBDAT_REG GPBTOGGLE; // GPIO Data Toggle Register (GPIO32 to 63) + /* Объединяет несколько представлений GPCDAT_REG GPCDAT; в одной области памяти. */ + union GPCDAT_REG GPCDAT; // GPIO Data Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCSET; в одной области памяти. */ + union GPCDAT_REG GPCSET; // GPIO Data Set Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCCLEAR; в одной области памяти. */ + union GPCDAT_REG GPCCLEAR; // GPIO Data Clear Register (GPIO64 to 95) + /* Объединяет несколько представлений GPCDAT_REG GPCTOGGLE; в одной области памяти. */ + union GPCDAT_REG GPCTOGGLE; // GPIO Data Toggle Register (GPIO64 to 95) + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[8]; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру GPIO_INT_REGS; порядок полей определяет расположение данных. */ +struct GPIO_INT_REGS { + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT1SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT1SEL; // XINT1 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT2SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT2SEL; // XINT2 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXNMISEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXNMISEL; // XNMI_Xint13 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT3SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT3SEL; // XINT3 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT4SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT4SEL; // XINT4 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT5SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT5SEL; // XINT5 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT6SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT6SEL; // XINT6 GPIO Input Selection + /* Объединяет несколько представлений GPIOXINT_REG GPIOXINT7SEL; в одной области памяти. */ + union GPIOXINT_REG GPIOXINT7SEL; // XINT7 GPIO Input Selection + /* Объединяет несколько представлений GPADAT_REG GPIOLPMSEL; в одной области памяти. */ + union GPADAT_REG GPIOLPMSEL; // Low power modes GP I/O input select +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// GPI/O External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct GPIO_CTRL_REGS GpioCtrlRegs;; порядок элементов сохраняется. */ +extern volatile struct GPIO_CTRL_REGS GpioCtrlRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct GPIO_DATA_REGS GpioDataRegs;; порядок элементов сохраняется. */ +extern volatile struct GPIO_DATA_REGS GpioDataRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct GPIO_INT_REGS GpioIntRegs;; порядок элементов сохраняется. */ +extern volatile struct GPIO_INT_REGS GpioIntRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_GPIO_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h new file mode 100644 index 0000000..da548ce --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_I2c.h @@ -0,0 +1,319 @@ +/* Поставляемое TI описание I2c для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: March 22, 2007 10:40:22 $ +//########################################################################### +// +// FILE: DSP2833x_I2c.h +// +// TITLE: DSP2833x Enhanced Quadrature Encoder Pulse Module +// Register Bit Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_I2C_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_I2C_H +/* Определяет защитный символ или переключатель DSP2833x_I2C_H для последующей компиляции. */ +#define DSP2833x_I2C_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//---------------------------------------------------- +// I2C interrupt vector register bit definitions */ +/* Описывает структуру I2CISRC_BITS; порядок полей определяет расположение данных. */ +struct I2CISRC_BITS { // bits description + /* Битовое поле INTCODE, ширина 3 бит; данные INTCODE. */ + Uint16 INTCODE:3; // 2:0 Interrupt code + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CISRC_REG в одной области памяти. */ +union I2CISRC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CISRC_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CISRC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// I2C interrupt mask register bit definitions */ +/* Описывает структуру I2CIER_BITS; порядок полей определяет расположение данных. */ +struct I2CIER_BITS { // bits description + /* Битовое поле ARBL, ширина 1 бит; данные ARBL. */ + Uint16 ARBL:1; // 0 Arbitration lost interrupt + /* Битовое поле NACK, ширина 1 бит; данные NACK. */ + Uint16 NACK:1; // 1 No ack interrupt + /* Битовое поле ARDY, ширина 1 бит; данные ARDY. */ + Uint16 ARDY:1; // 2 Register access ready interrupt + /* Битовое поле RRDY, ширина 1 бит; данные RRDY. */ + Uint16 RRDY:1; // 3 Recieve data ready interrupt + /* Битовое поле XRDY, ширина 1 бит; данные XRDY. */ + Uint16 XRDY:1; // 4 Transmit data ready interrupt + /* Битовое поле SCD, ширина 1 бит; данные SCD. */ + Uint16 SCD:1; // 5 Stop condition detection + /* Битовое поле AAS, ширина 1 бит; данные AAS. */ + Uint16 AAS:1; // 6 Address as slave + /* Битовое поле rsvd, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:9; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CIER_REG в одной области памяти. */ +union I2CIER_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CIER_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CIER_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// I2C status register bit definitions */ +/* Описывает структуру I2CSTR_BITS; порядок полей определяет расположение данных. */ +struct I2CSTR_BITS { // bits description + /* Битовое поле ARBL, ширина 1 бит; данные ARBL. */ + Uint16 ARBL:1; // 0 Arbitration lost interrupt + /* Битовое поле NACK, ширина 1 бит; данные NACK. */ + Uint16 NACK:1; // 1 No ack interrupt + /* Битовое поле ARDY, ширина 1 бит; данные ARDY. */ + Uint16 ARDY:1; // 2 Register access ready interrupt + /* Битовое поле RRDY, ширина 1 бит; данные RRDY. */ + Uint16 RRDY:1; // 3 Recieve data ready interrupt + /* Битовое поле XRDY, ширина 1 бит; данные XRDY. */ + Uint16 XRDY:1; // 4 Transmit data ready interrupt + /* Битовое поле SCD, ширина 1 бит; данные SCD. */ + Uint16 SCD:1; // 5 Stop condition detection + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 7:6 reserved + /* Битовое поле AD0, ширина 1 бит; данные AD0. */ + Uint16 AD0:1; // 8 Address Zero + /* Битовое поле AAS, ширина 1 бит; данные AAS. */ + Uint16 AAS:1; // 9 Address as slave + /* Битовое поле XSMT, ширина 1 бит; данные XSMT. */ + Uint16 XSMT:1; // 10 XMIT shift empty + /* Битовое поле RSFULL, ширина 1 бит; данные RSFULL. */ + Uint16 RSFULL:1; // 11 Recieve shift full + /* Битовое поле BB, ширина 1 бит; данные BB. */ + Uint16 BB:1; // 12 Bus busy + /* Битовое поле NACKSNT, ширина 1 бит; данные NACKSNT. */ + Uint16 NACKSNT:1; // 13 A no ack sent + /* Битовое поле SDIR, ширина 1 бит; данные SDIR. */ + Uint16 SDIR:1; // 14 Slave direction + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CSTR_REG в одной области памяти. */ +union I2CSTR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CSTR_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CSTR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// I2C mode control register bit definitions */ +/* Описывает структуру I2CMDR_BITS; порядок полей определяет расположение данных. */ +struct I2CMDR_BITS { // bits description + /* Битовое поле BC, ширина 3 бит; данные BC. */ + Uint16 BC:3; // 2:0 Bit count + /* Битовое поле FDF, ширина 1 бит; данные FDF. */ + Uint16 FDF:1; // 3 Free data format + /* Битовое поле STB, ширина 1 бит; данные STB. */ + Uint16 STB:1; // 4 Start byte + /* Битовое поле IRS, ширина 1 бит; данные IRS. */ + Uint16 IRS:1; // 5 I2C Reset not + /* Битовое поле DLB, ширина 1 бит; данные DLB. */ + Uint16 DLB:1; // 6 Digital loopback + /* Битовое поле RM, ширина 1 бит; данные RM. */ + Uint16 RM:1; // 7 Repeat mode + /* Битовое поле XA, ширина 1 бит; данные XA. */ + Uint16 XA:1; // 8 Expand address + /* Битовое поле TRX, ширина 1 бит; данные TRX. */ + Uint16 TRX:1; // 9 Transmitter/reciever + /* Битовое поле MST, ширина 1 бит; данные MST. */ + Uint16 MST:1; // 10 Master/slave + /* Битовое поле STP, ширина 1 бит; данные STP. */ + Uint16 STP:1; // 11 Stop condition + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 12 reserved + /* Битовое поле STT, ширина 1 бит; данные STT. */ + Uint16 STT:1; // 13 Start condition + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 14 Emulation mode + /* Битовое поле NACKMOD, ширина 1 бит; данные NACKMOD. */ + Uint16 NACKMOD:1; // 15 No Ack mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CMDR_REG в одной области памяти. */ +union I2CMDR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CMDR_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CMDR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// I2C pre-scaler register bit definitions */ +/* Описывает структуру I2CPSC_BITS; порядок полей определяет расположение данных. */ +struct I2CPSC_BITS { // bits description + /* Битовое поле IPSC, ширина 8 бит; данные IPSC. */ + Uint16 IPSC:8; // 7:0 pre-scaler + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений I2CPSC_REG в одной области памяти. */ +union I2CPSC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CPSC_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CPSC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- +// TX FIFO control register bit definitions */ +/* Описывает структуру I2CFFTX_BITS; порядок полей определяет расположение данных. */ +struct I2CFFTX_BITS { // bits description + /* Битовое поле TXFFIL, ширина 5 бит; данные TXFFIL. */ + Uint16 TXFFIL:5; // 4:0 FIFO interrupt level + /* Битовое поле TXFFIENA, ширина 1 бит; данные TXFFIENA. */ + Uint16 TXFFIENA:1; // 5 FIFO interrupt enable/disable + /* Битовое поле TXFFINTCLR, ширина 1 бит; данные TXFFINTCLR. */ + Uint16 TXFFINTCLR:1; // 6 FIFO clear + /* Битовое поле TXFFINT, ширина 1 бит; данные TXFFINT. */ + Uint16 TXFFINT:1; // 7 FIFO interrupt flag + /* Битовое поле TXFFST, ширина 5 бит; данные TXFFST. */ + Uint16 TXFFST:5; // 12:8 FIFO level status + /* Битовое поле TXFFRST, ширина 1 бит; данные TXFFRST. */ + Uint16 TXFFRST:1; // 13 FIFO reset + /* Битовое поле I2CFFEN, ширина 1 бит; данные I2CFFEN. */ + Uint16 I2CFFEN:1; // 14 enable/disable TX & RX FIFOs + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 15 reserved + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CFFTX_REG в одной области памяти. */ +union I2CFFTX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CFFTX_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CFFTX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// RX FIFO control register bit definitions */ +/* Описывает структуру I2CFFRX_BITS; порядок полей определяет расположение данных. */ +struct I2CFFRX_BITS { // bits description + /* Битовое поле RXFFIL, ширина 5 бит; данные RXFFIL. */ + Uint16 RXFFIL:5; // 4:0 FIFO interrupt level + /* Битовое поле RXFFIENA, ширина 1 бит; данные RXFFIENA. */ + Uint16 RXFFIENA:1; // 5 FIFO interrupt enable/disable + /* Битовое поле RXFFINTCLR, ширина 1 бит; данные RXFFINTCLR. */ + Uint16 RXFFINTCLR:1; // 6 FIFO clear + /* Битовое поле RXFFINT, ширина 1 бит; данные RXFFINT. */ + Uint16 RXFFINT:1; // 7 FIFO interrupt flag + /* Битовое поле RXFFST, ширина 5 бит; данные RXFFST. */ + Uint16 RXFFST:5; // 12:8 FIFO level + /* Битовое поле RXFFRST, ширина 1 бит; данные RXFFRST. */ + Uint16 RXFFRST:1; // 13 FIFO reset + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 15:14 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений I2CFFRX_REG в одной области памяти. */ +union I2CFFRX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру I2CFFRX_BITS bit;; порядок полей определяет расположение данных. */ + struct I2CFFRX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//---------------------------------------------------- + +/* Описывает структуру I2C_REGS; порядок полей определяет расположение данных. */ +struct I2C_REGS { + /* Объявляет I2COAR — данные I2COAR. */ + Uint16 I2COAR; // Own address register + /* Объединяет несколько представлений I2CIER_REG I2CIER; в одной области памяти. */ + union I2CIER_REG I2CIER; // Interrupt enable + /* Объединяет несколько представлений I2CSTR_REG I2CSTR; в одной области памяти. */ + union I2CSTR_REG I2CSTR; // Interrupt status + /* Объявляет I2CCLKL — данные I2CCLKL. */ + Uint16 I2CCLKL; // Clock divider low + /* Объявляет I2CCLKH — данные I2CCLKH. */ + Uint16 I2CCLKH; // Clock divider high + /* Объявляет I2CCNT — данные I2CCNT. */ + Uint16 I2CCNT; // Data count + /* Объявляет I2CDRR — данные I2CDRR. */ + Uint16 I2CDRR; // Data recieve + /* Объявляет I2CSAR — данные I2CSAR. */ + Uint16 I2CSAR; // Slave address + /* Объявляет I2CDXR — данные I2CDXR. */ + Uint16 I2CDXR; // Data transmit + /* Объединяет несколько представлений I2CMDR_REG I2CMDR; в одной области памяти. */ + union I2CMDR_REG I2CMDR; // Mode + /* Объединяет несколько представлений I2CISRC_REG I2CISRC; в одной области памяти. */ + union I2CISRC_REG I2CISRC; // Interrupt source + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объединяет несколько представлений I2CPSC_REG I2CPSC; в одной области памяти. */ + union I2CPSC_REG I2CPSC; // Pre-scaler + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[19]; // reserved + /* Объединяет несколько представлений I2CFFTX_REG I2CFFTX; в одной области памяти. */ + union I2CFFTX_REG I2CFFTX; // Transmit FIFO + /* Объединяет несколько представлений I2CFFRX_REG I2CFFRX; в одной области памяти. */ + union I2CFFRX_REG I2CFFRX; // Recieve FIFO +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct I2C_REGS I2caRegs;; порядок элементов сохраняется. */ +extern volatile struct I2C_REGS I2caRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_I2C_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h new file mode 100644 index 0000000..b70e765 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Mcbsp.h @@ -0,0 +1,1299 @@ +/* Поставляемое TI описание Mcbsp для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/5 $ +// Checkin $Date: May 14, 2008 16:30:31 $ +//########################################################################### +// +// FILE: DSP2833x_Mcbsp.h +// +// TITLE: DSP2833x Device McBSP Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_MCBSP_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_MCBSP_H +/* Определяет защитный символ или переключатель DSP2833x_MCBSP_H для последующей компиляции. */ +#define DSP2833x_MCBSP_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// McBSP Individual Register Bit Definitions: +// +// McBSP DRR2 register bit definitions: +/* Описывает структуру DRR2_BITS; порядок полей определяет расположение данных. */ +struct DRR2_BITS { // bit description + /* Битовое поле HWLB, ширина 8 бит; данные HWLB. */ + Uint16 HWLB:8; // 16:23 High word low byte + /* Битовое поле HWHB, ширина 8 бит; данные HWHB. */ + Uint16 HWHB:8; // 24:31 High word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DRR2_REG в одной области памяти. */ +union DRR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DRR2_BITS bit;; порядок полей определяет расположение данных. */ + struct DRR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// McBSP DRR1 register bit definitions: +/* Описывает структуру DRR1_BITS; порядок полей определяет расположение данных. */ +struct DRR1_BITS { // bit description + /* Битовое поле LWLB, ширина 8 бит; данные LWLB. */ + Uint16 LWLB:8; // 16:23 Low word low byte + /* Битовое поле LWHB, ширина 8 бит; данные LWHB. */ + Uint16 LWHB:8; // 24:31 low word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DRR1_REG в одной области памяти. */ +union DRR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DRR1_BITS bit;; порядок полей определяет расположение данных. */ + struct DRR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// McBSP DXR2 register bit definitions: +/* Описывает структуру DXR2_BITS; порядок полей определяет расположение данных. */ +struct DXR2_BITS { // bit description + /* Битовое поле HWLB, ширина 8 бит; данные HWLB. */ + Uint16 HWLB:8; // 16:23 High word low byte + /* Битовое поле HWHB, ширина 8 бит; данные HWHB. */ + Uint16 HWHB:8; // 24:31 High word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DXR2_REG в одной области памяти. */ +union DXR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DXR2_BITS bit;; порядок полей определяет расположение данных. */ + struct DXR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// McBSP DXR1 register bit definitions: +/* Описывает структуру DXR1_BITS; порядок полей определяет расположение данных. */ +struct DXR1_BITS { // bit description + /* Битовое поле LWLB, ширина 8 бит; данные LWLB. */ + Uint16 LWLB:8; // 16:23 Low word low byte + /* Битовое поле LWHB, ширина 8 бит; данные LWHB. */ + Uint16 LWHB:8; // 24:31 low word high byte +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений DXR1_REG в одной области памяти. */ +union DXR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру DXR1_BITS bit;; порядок полей определяет расположение данных. */ + struct DXR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SPCR2 control register bit definitions: +/* Описывает структуру SPCR2_BITS; порядок полей определяет расположение данных. */ +struct SPCR2_BITS { // bit description + /* Битовое поле XRST, ширина 1 бит; данные XRST. */ + Uint16 XRST:1; // 0 transmit reset + /* Битовое поле XRDY, ширина 1 бит; данные XRDY. */ + Uint16 XRDY:1; // 1 transmit ready + /* Битовое поле XEMPTY, ширина 1 бит; данные XEMPTY. */ + Uint16 XEMPTY:1; // 2 Transmit empty + /* Битовое поле XSYNCERR, ширина 1 бит; данные XSYNCERR. */ + Uint16 XSYNCERR:1; // 3 Transmit syn errorINT flag + /* Битовое поле XINTM, ширина 2 бит; данные XINTM. */ + Uint16 XINTM:2; // 5:4 Transmit interrupt types + /* Битовое поле GRST, ширина 1 бит; данные GRST. */ + Uint16 GRST:1; // 6 CLKG reset + /* Битовое поле FRST, ширина 1 бит; данные FRST. */ + Uint16 FRST:1; // 7 Frame sync reset + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 8 SOFT bit + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 9 FREE bit + /* Битовое поле rsvd, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPCR2_REG в одной области памяти. */ +union SPCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct SPCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SPCR1 control register bit definitions: +/* Описывает структуру SPCR1_BITS; порядок полей определяет расположение данных. */ +struct SPCR1_BITS { // bit description + /* Битовое поле RRST, ширина 1 бит; данные RRST. */ + Uint16 RRST:1; // 0 Receive reset + /* Битовое поле RRDY, ширина 1 бит; данные RRDY. */ + Uint16 RRDY:1; // 1 Receive ready + /* Битовое поле RFULL, ширина 1 бит; данные RFULL. */ + Uint16 RFULL:1; // 2 Receive full + /* Битовое поле RSYNCERR, ширина 1 бит; данные RSYNCERR. */ + Uint16 RSYNCERR:1; // 7 Receive syn error + /* Битовое поле RINTM, ширина 2 бит; данные RINTM. */ + Uint16 RINTM:2; // 5:4 Receive interrupt types + /* Битовое поле ABIS, ширина 1 бит; данные ABIS. */ + Uint16 ABIS:1; // 6 ABIS mode select + /* Битовое поле DXENA, ширина 1 бит; данные DXENA. */ + Uint16 DXENA:1; // 7 DX hi-z enable + /* Битовое поле rsvd, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:3; // 10:8 reserved + /* Битовое поле CLKSTP, ширина 2 бит; данные CLKSTP. */ + Uint16 CLKSTP:2; // 12:11 CLKSTOP mode bit + /* Битовое поле RJUST, ширина 2 бит; данные RJUST. */ + Uint16 RJUST:2; // 13:14 Right justified + /* Битовое поле DLB, ширина 1 бит; данные DLB. */ + Uint16 DLB:1; // 15 Digital loop back +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPCR1_REG в одной области памяти. */ +union SPCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct SPCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCR2 control register bit definitions: +/* Описывает структуру RCR2_BITS; порядок полей определяет расположение данных. */ +struct RCR2_BITS { // bit description + /* Битовое поле RDATDLY, ширина 2 бит; данные RDATDLY. */ + Uint16 RDATDLY:2; // 1:0 Receive data delay + /* Битовое поле RFIG, ширина 1 бит; данные RFIG. */ + Uint16 RFIG:1; // 2 Receive frame sync ignore + /* Битовое поле RCOMPAND, ширина 2 бит; данные RCOMPAND. */ + Uint16 RCOMPAND:2; // 4:3 Receive Companding Mode selects + /* Битовое поле RWDLEN2, ширина 3 бит; данные RWDLEN2. */ + Uint16 RWDLEN2:3; // 7:5 Receive word length + /* Битовое поле RFRLEN2, ширина 7 бит; данные RFRLEN2. */ + Uint16 RFRLEN2:7; // 14:8 Receive Frame sync + /* Битовое поле RPHASE, ширина 1 бит; данные RPHASE. */ + Uint16 RPHASE:1; // 15 Receive Phase +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCR2_REG в одной области памяти. */ +union RCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct RCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCR1 control register bit definitions: +/* Описывает структуру RCR1_BITS; порядок полей определяет расположение данных. */ +struct RCR1_BITS { // bit description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле RWDLEN1, ширина 3 бит; данные RWDLEN1. */ + Uint16 RWDLEN1:3; // 7:5 Receive word length + /* Битовое поле RFRLEN1, ширина 7 бит; данные RFRLEN1. */ + Uint16 RFRLEN1:7; // 14:8 Receive frame length + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCR1_REG в одной области памяти. */ +union RCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct RCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCR2 control register bit definitions: + +/* Описывает структуру XCR2_BITS; порядок полей определяет расположение данных. */ +struct XCR2_BITS { // bit description + /* Битовое поле XDATDLY, ширина 2 бит; данные XDATDLY. */ + Uint16 XDATDLY:2; // 1:0 Transmit data delay + /* Битовое поле XFIG, ширина 1 бит; данные XFIG. */ + Uint16 XFIG:1; // 2 Transmit frame sync ignore + /* Битовое поле XCOMPAND, ширина 2 бит; данные XCOMPAND. */ + Uint16 XCOMPAND:2; // 4:3 Transmit Companding Mode selects + /* Битовое поле XWDLEN2, ширина 3 бит; данные XWDLEN2. */ + Uint16 XWDLEN2:3; // 7:5 Transmit word length + /* Битовое поле XFRLEN2, ширина 7 бит; данные XFRLEN2. */ + Uint16 XFRLEN2:7; // 14:8 Transmit Frame sync + /* Битовое поле XPHASE, ширина 1 бит; данные XPHASE. */ + Uint16 XPHASE:1; // 15 Transmit Phase +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCR2_REG в одной области памяти. */ +union XCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct XCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCR1 control register bit definitions: +/* Описывает структуру XCR1_BITS; порядок полей определяет расположение данных. */ +struct XCR1_BITS { // bit description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле XWDLEN1, ширина 3 бит; данные XWDLEN1. */ + Uint16 XWDLEN1:3; // 7:5 Transmit word length + /* Битовое поле XFRLEN1, ширина 7 бит; данные XFRLEN1. */ + Uint16 XFRLEN1:7; // 14:8 Transmit frame length + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCR1_REG в одной области памяти. */ +union XCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct XCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SRGR2 Sample rate generator control register bit definitions: +/* Описывает структуру SRGR2_BITS; порядок полей определяет расположение данных. */ +struct SRGR2_BITS { // bit description + /* Битовое поле FPER, ширина 12 бит; данные FPER. */ + Uint16 FPER:12; // 11:0 Frame period + /* Битовое поле FSGM, ширина 1 бит; данные FSGM. */ + Uint16 FSGM:1; // 12 Frame sync generator mode + /* Битовое поле CLKSM, ширина 1 бит; данные CLKSM. */ + Uint16 CLKSM:1; // 13 Sample rate generator mode + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 14 reserved + /* Битовое поле GSYNC, ширина 1 бит; данные GSYNC. */ + Uint16 GSYNC:1; // 15 CLKG sync +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SRGR2_REG в одной области памяти. */ +union SRGR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SRGR2_BITS bit;; порядок полей определяет расположение данных. */ + struct SRGR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SRGR1 control register bit definitions: +/* Описывает структуру SRGR1_BITS; порядок полей определяет расположение данных. */ +struct SRGR1_BITS { // bit description + /* Битовое поле CLKGDV, ширина 8 бит; данные CLKGDV. */ + Uint16 CLKGDV:8; // 7:0 CLKG divider + /* Битовое поле FWID, ширина 8 бит; данные FWID. */ + Uint16 FWID:8; // 15:8 Frame width +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SRGR1_REG в одной области памяти. */ +union SRGR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SRGR1_BITS bit;; порядок полей определяет расположение данных. */ + struct SRGR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// MCR2 Multichannel control register bit definitions: +/* Описывает структуру MCR2_BITS; порядок полей определяет расположение данных. */ +struct MCR2_BITS { // bit description + /* Битовое поле XMCM, ширина 2 бит; данные XMCM. */ + Uint16 XMCM:2; // 1:0 Transmit multichannel mode + /* Битовое поле XCBLK, ширина 3 бит; данные XCBLK. */ + Uint16 XCBLK:3; // 2:4 Transmit current block + /* Битовое поле XPABLK, ширина 2 бит; данные XPABLK. */ + Uint16 XPABLK:2; // 5:6 Transmit partition A Block + /* Битовое поле XPBBLK, ширина 2 бит; данные XPBBLK. */ + Uint16 XPBBLK:2; // 7:8 Transmit partition B Block + /* Битовое поле XMCME, ширина 1 бит; данные XMCME. */ + Uint16 XMCME:1; // 9 Transmit multi-channel enhance mode + /* Битовое поле rsvd, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MCR2_REG в одной области памяти. */ +union MCR2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MCR2_BITS bit;; порядок полей определяет расположение данных. */ + struct MCR2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// MCR1 Multichannel control register bit definitions: +/* Описывает структуру MCR1_BITS; порядок полей определяет расположение данных. */ +struct MCR1_BITS { // bit description + /* Битовое поле RMCM, ширина 1 бит; данные RMCM. */ + Uint16 RMCM:1; // 0 Receive multichannel mode + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 1 reserved + /* Битовое поле RCBLK, ширина 3 бит; данные RCBLK. */ + Uint16 RCBLK:3; // 4:2 Receive current block + /* Битовое поле RPABLK, ширина 2 бит; данные RPABLK. */ + Uint16 RPABLK:2; // 6:5 Receive partition A Block + /* Битовое поле RPBBLK, ширина 2 бит; данные RPBBLK. */ + Uint16 RPBBLK:2; // 7:8 Receive partition B Block + /* Битовое поле RMCME, ширина 1 бит; данные RMCME. */ + Uint16 RMCME:1; // 9 Receive multi-channel enhance mode + /* Битовое поле rsvd1, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:6; // 15:10 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MCR1_REG в одной области памяти. */ +union MCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct MCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERA control register bit definitions: +/* Описывает структуру RCERA_BITS; порядок полей определяет расположение данных. */ +struct RCERA_BITS { // bit description + /* Битовое поле RCEA0, ширина 1 бит; данные RCEA0. */ + Uint16 RCEA0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEA1, ширина 1 бит; данные RCEA1. */ + Uint16 RCEA1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEA2, ширина 1 бит; данные RCEA2. */ + Uint16 RCEA2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEA3, ширина 1 бит; данные RCEA3. */ + Uint16 RCEA3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEA4, ширина 1 бит; данные RCEA4. */ + Uint16 RCEA4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEA5, ширина 1 бит; данные RCEA5. */ + Uint16 RCEA5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEA6, ширина 1 бит; данные RCEA6. */ + Uint16 RCEA6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEA7, ширина 1 бит; данные RCEA7. */ + Uint16 RCEA7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEA8, ширина 1 бит; данные RCEA8. */ + Uint16 RCEA8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEA9, ширина 1 бит; данные RCEA9. */ + Uint16 RCEA9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEA10, ширина 1 бит; данные RCEA10. */ + Uint16 RCEA10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEA11, ширина 1 бит; данные RCEA11. */ + Uint16 RCEA11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEA12, ширина 1 бит; данные RCEA12. */ + Uint16 RCEA12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEA13, ширина 1 бит; данные RCEA13. */ + Uint16 RCEA13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEA14, ширина 1 бит; данные RCEA14. */ + Uint16 RCEA14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEA15, ширина 1 бит; данные RCEA15. */ + Uint16 RCEA15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERA_REG в одной области памяти. */ +union RCERA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERA_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERB control register bit definitions: +/* Описывает структуру RCERB_BITS; порядок полей определяет расположение данных. */ +struct RCERB_BITS { // bit description + /* Битовое поле RCEB0, ширина 1 бит; данные RCEB0. */ + Uint16 RCEB0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEB1, ширина 1 бит; данные RCEB1. */ + Uint16 RCEB1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEB2, ширина 1 бит; данные RCEB2. */ + Uint16 RCEB2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEB3, ширина 1 бит; данные RCEB3. */ + Uint16 RCEB3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEB4, ширина 1 бит; данные RCEB4. */ + Uint16 RCEB4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEB5, ширина 1 бит; данные RCEB5. */ + Uint16 RCEB5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEB6, ширина 1 бит; данные RCEB6. */ + Uint16 RCEB6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEB7, ширина 1 бит; данные RCEB7. */ + Uint16 RCEB7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEB8, ширина 1 бит; данные RCEB8. */ + Uint16 RCEB8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEB9, ширина 1 бит; данные RCEB9. */ + Uint16 RCEB9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEB10, ширина 1 бит; данные RCEB10. */ + Uint16 RCEB10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEB11, ширина 1 бит; данные RCEB11. */ + Uint16 RCEB11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEB12, ширина 1 бит; данные RCEB12. */ + Uint16 RCEB12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEB13, ширина 1 бит; данные RCEB13. */ + Uint16 RCEB13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEB14, ширина 1 бит; данные RCEB14. */ + Uint16 RCEB14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEB15, ширина 1 бит; данные RCEB15. */ + Uint16 RCEB15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERB_REG в одной области памяти. */ +union RCERB_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERB_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERB_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERA control register bit definitions: +/* Описывает структуру XCERA_BITS; порядок полей определяет расположение данных. */ +struct XCERA_BITS { // bit description + /* Битовое поле XCERA0, ширина 1 бит; данные XCERA0. */ + Uint16 XCERA0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERA1, ширина 1 бит; данные XCERA1. */ + Uint16 XCERA1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERA2, ширина 1 бит; данные XCERA2. */ + Uint16 XCERA2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERA3, ширина 1 бит; данные XCERA3. */ + Uint16 XCERA3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERA4, ширина 1 бит; данные XCERA4. */ + Uint16 XCERA4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERA5, ширина 1 бит; данные XCERA5. */ + Uint16 XCERA5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERA6, ширина 1 бит; данные XCERA6. */ + Uint16 XCERA6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERA7, ширина 1 бит; данные XCERA7. */ + Uint16 XCERA7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERA8, ширина 1 бит; данные XCERA8. */ + Uint16 XCERA8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERA9, ширина 1 бит; данные XCERA9. */ + Uint16 XCERA9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERA10, ширина 1 бит; данные XCERA10. */ + Uint16 XCERA10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERA11, ширина 1 бит; данные XCERA11. */ + Uint16 XCERA11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERA12, ширина 1 бит; данные XCERA12. */ + Uint16 XCERA12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERA13, ширина 1 бит; данные XCERA13. */ + Uint16 XCERA13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERA14, ширина 1 бит; данные XCERA14. */ + Uint16 XCERA14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERA15, ширина 1 бит; данные XCERA15. */ + Uint16 XCERA15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERA_REG в одной области памяти. */ +union XCERA_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERA_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERA_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERB control register bit definitions: +/* Описывает структуру XCERB_BITS; порядок полей определяет расположение данных. */ +struct XCERB_BITS { // bit description + /* Битовое поле XCERB0, ширина 1 бит; данные XCERB0. */ + Uint16 XCERB0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERB1, ширина 1 бит; данные XCERB1. */ + Uint16 XCERB1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERB2, ширина 1 бит; данные XCERB2. */ + Uint16 XCERB2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERB3, ширина 1 бит; данные XCERB3. */ + Uint16 XCERB3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERB4, ширина 1 бит; данные XCERB4. */ + Uint16 XCERB4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERB5, ширина 1 бит; данные XCERB5. */ + Uint16 XCERB5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERB6, ширина 1 бит; данные XCERB6. */ + Uint16 XCERB6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERB7, ширина 1 бит; данные XCERB7. */ + Uint16 XCERB7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERB8, ширина 1 бит; данные XCERB8. */ + Uint16 XCERB8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERB9, ширина 1 бит; данные XCERB9. */ + Uint16 XCERB9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERB10, ширина 1 бит; данные XCERB10. */ + Uint16 XCERB10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERB11, ширина 1 бит; данные XCERB11. */ + Uint16 XCERB11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERB12, ширина 1 бит; данные XCERB12. */ + Uint16 XCERB12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERB13, ширина 1 бит; данные XCERB13. */ + Uint16 XCERB13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERB14, ширина 1 бит; данные XCERB14. */ + Uint16 XCERB14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERB15, ширина 1 бит; данные XCERB15. */ + Uint16 XCERB15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERB_REG в одной области памяти. */ +union XCERB_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERB_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERB_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PCR control register bit definitions: +/* Описывает структуру PCR_BITS; порядок полей определяет расположение данных. */ +struct PCR_BITS { // bit description + /* Битовое поле CLKRP, ширина 1 бит; данные CLKRP. */ + Uint16 CLKRP:1; // 0 Receive Clock polarity + /* Битовое поле CLKXP, ширина 1 бит; данные CLKXP. */ + Uint16 CLKXP:1; // 1 Transmit clock polarity + /* Битовое поле FSRP, ширина 1 бит; данные FSRP. */ + Uint16 FSRP:1; // 2 Receive Frame synchronization polarity + /* Битовое поле FSXP, ширина 1 бит; данные FSXP. */ + Uint16 FSXP:1; // 3 Transmit Frame synchronization polarity + /* Битовое поле DR_STAT, ширина 1 бит; данные DR_STAT. */ + Uint16 DR_STAT:1; // 4 DR pin status - reserved for this McBSP + /* Битовое поле DX_STAT, ширина 1 бит; данные DX_STAT. */ + Uint16 DX_STAT:1; // 5 DX pin status - reserved for this McBSP + /* Битовое поле CLKS_STAT, ширина 1 бит; данные CLKS_STAT. */ + Uint16 CLKS_STAT:1; // 6 CLKS pin status - reserved for 28x -McBSP + /* Битовое поле SCLKME, ширина 1 бит; данные SCLKME. */ + Uint16 SCLKME:1; // 7 Enhanced sample clock mode selection bit. + /* Битовое поле CLKRM, ширина 1 бит; данные CLKRM. */ + Uint16 CLKRM:1; // 8 Receiver Clock Mode + /* Битовое поле CLKXM, ширина 1 бит; данные CLKXM. */ + Uint16 CLKXM:1; // 9 Transmitter Clock Mode. + /* Битовое поле FSRM, ширина 1 бит; данные FSRM. */ + Uint16 FSRM:1; // 10 Receive Frame Synchronization Mode + /* Битовое поле FSXM, ширина 1 бит; данные FSXM. */ + Uint16 FSXM:1; // 11 Transmit Frame Synchronization Mode + /* Битовое поле RIOEN, ширина 1 бит; данные RIOEN. */ + Uint16 RIOEN:1; // 12 General Purpose I/O Mode - reserved in this 28x-McBSP + /* Битовое поле XIOEN, ширина 1 бит; данные XIOEN. */ + Uint16 XIOEN:1; // 13 General Purpose I/O Mode - reserved in this 28x-McBSP + /* Битовое поле IDEL_EN, ширина 1 бит; данные IDEL_EN. */ + Uint16 IDEL_EN:1; // 14 reserved in this 28x-McBSP + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1 ; // 15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCR_REG в одной области памяти. */ +union PCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCR_BITS bit;; порядок полей определяет расположение данных. */ + struct PCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERC control register bit definitions: +/* Описывает структуру RCERC_BITS; порядок полей определяет расположение данных. */ +struct RCERC_BITS { // bit description + /* Битовое поле RCEC0, ширина 1 бит; данные RCEC0. */ + Uint16 RCEC0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEC1, ширина 1 бит; данные RCEC1. */ + Uint16 RCEC1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEC2, ширина 1 бит; данные RCEC2. */ + Uint16 RCEC2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEC3, ширина 1 бит; данные RCEC3. */ + Uint16 RCEC3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEC4, ширина 1 бит; данные RCEC4. */ + Uint16 RCEC4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEC5, ширина 1 бит; данные RCEC5. */ + Uint16 RCEC5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEC6, ширина 1 бит; данные RCEC6. */ + Uint16 RCEC6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEC7, ширина 1 бит; данные RCEC7. */ + Uint16 RCEC7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEC8, ширина 1 бит; данные RCEC8. */ + Uint16 RCEC8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEC9, ширина 1 бит; данные RCEC9. */ + Uint16 RCEC9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEC10, ширина 1 бит; данные RCEC10. */ + Uint16 RCEC10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEC11, ширина 1 бит; данные RCEC11. */ + Uint16 RCEC11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEC12, ширина 1 бит; данные RCEC12. */ + Uint16 RCEC12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEC13, ширина 1 бит; данные RCEC13. */ + Uint16 RCEC13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEC14, ширина 1 бит; данные RCEC14. */ + Uint16 RCEC14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEC15, ширина 1 бит; данные RCEC15. */ + Uint16 RCEC15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERC_REG в одной области памяти. */ +union RCERC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERC_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERD control register bit definitions: +/* Описывает структуру RCERD_BITS; порядок полей определяет расположение данных. */ +struct RCERD_BITS { // bit description + /* Битовое поле RCED0, ширина 1 бит; данные RCED0. */ + Uint16 RCED0:1; // 0 Receive Channel enable bit + /* Битовое поле RCED1, ширина 1 бит; данные RCED1. */ + Uint16 RCED1:1; // 1 Receive Channel enable bit + /* Битовое поле RCED2, ширина 1 бит; данные RCED2. */ + Uint16 RCED2:1; // 2 Receive Channel enable bit + /* Битовое поле RCED3, ширина 1 бит; данные RCED3. */ + Uint16 RCED3:1; // 3 Receive Channel enable bit + /* Битовое поле RCED4, ширина 1 бит; данные RCED4. */ + Uint16 RCED4:1; // 4 Receive Channel enable bit + /* Битовое поле RCED5, ширина 1 бит; данные RCED5. */ + Uint16 RCED5:1; // 5 Receive Channel enable bit + /* Битовое поле RCED6, ширина 1 бит; данные RCED6. */ + Uint16 RCED6:1; // 6 Receive Channel enable bit + /* Битовое поле RCED7, ширина 1 бит; данные RCED7. */ + Uint16 RCED7:1; // 7 Receive Channel enable bit + /* Битовое поле RCED8, ширина 1 бит; данные RCED8. */ + Uint16 RCED8:1; // 8 Receive Channel enable bit + /* Битовое поле RCED9, ширина 1 бит; данные RCED9. */ + Uint16 RCED9:1; // 9 Receive Channel enable bit + /* Битовое поле RCED10, ширина 1 бит; данные RCED10. */ + Uint16 RCED10:1; // 10 Receive Channel enable bit + /* Битовое поле RCED11, ширина 1 бит; данные RCED11. */ + Uint16 RCED11:1; // 11 Receive Channel enable bit + /* Битовое поле RCED12, ширина 1 бит; данные RCED12. */ + Uint16 RCED12:1; // 12 Receive Channel enable bit + /* Битовое поле RCED13, ширина 1 бит; данные RCED13. */ + Uint16 RCED13:1; // 13 Receive Channel enable bit + /* Битовое поле RCED14, ширина 1 бит; данные RCED14. */ + Uint16 RCED14:1; // 14 Receive Channel enable bit + /* Битовое поле RCED15, ширина 1 бит; данные RCED15. */ + Uint16 RCED15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERD_REG в одной области памяти. */ +union RCERD_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERD_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERD_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERC control register bit definitions: +/* Описывает структуру XCERC_BITS; порядок полей определяет расположение данных. */ +struct XCERC_BITS { // bit description + /* Битовое поле XCERC0, ширина 1 бит; данные XCERC0. */ + Uint16 XCERC0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERC1, ширина 1 бит; данные XCERC1. */ + Uint16 XCERC1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERC2, ширина 1 бит; данные XCERC2. */ + Uint16 XCERC2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERC3, ширина 1 бит; данные XCERC3. */ + Uint16 XCERC3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERC4, ширина 1 бит; данные XCERC4. */ + Uint16 XCERC4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERC5, ширина 1 бит; данные XCERC5. */ + Uint16 XCERC5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERC6, ширина 1 бит; данные XCERC6. */ + Uint16 XCERC6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERC7, ширина 1 бит; данные XCERC7. */ + Uint16 XCERC7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERC8, ширина 1 бит; данные XCERC8. */ + Uint16 XCERC8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERC9, ширина 1 бит; данные XCERC9. */ + Uint16 XCERC9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERC10, ширина 1 бит; данные XCERC10. */ + Uint16 XCERC10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERC11, ширина 1 бит; данные XCERC11. */ + Uint16 XCERC11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERC12, ширина 1 бит; данные XCERC12. */ + Uint16 XCERC12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERC13, ширина 1 бит; данные XCERC13. */ + Uint16 XCERC13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERC14, ширина 1 бит; данные XCERC14. */ + Uint16 XCERC14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERC15, ширина 1 бит; данные XCERC15. */ + Uint16 XCERC15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERC_REG в одной области памяти. */ +union XCERC_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERC_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERC_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERD control register bit definitions: +/* Описывает структуру XCERD_BITS; порядок полей определяет расположение данных. */ +struct XCERD_BITS { // bit description + /* Битовое поле XCERD0, ширина 1 бит; данные XCERD0. */ + Uint16 XCERD0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERD1, ширина 1 бит; данные XCERD1. */ + Uint16 XCERD1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERD2, ширина 1 бит; данные XCERD2. */ + Uint16 XCERD2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERD3, ширина 1 бит; данные XCERD3. */ + Uint16 XCERD3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERD4, ширина 1 бит; данные XCERD4. */ + Uint16 XCERD4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERD5, ширина 1 бит; данные XCERD5. */ + Uint16 XCERD5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERD6, ширина 1 бит; данные XCERD6. */ + Uint16 XCERD6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERD7, ширина 1 бит; данные XCERD7. */ + Uint16 XCERD7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERD8, ширина 1 бит; данные XCERD8. */ + Uint16 XCERD8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERD9, ширина 1 бит; данные XCERD9. */ + Uint16 XCERD9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERD10, ширина 1 бит; данные XCERD10. */ + Uint16 XCERD10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERD11, ширина 1 бит; данные XCERD11. */ + Uint16 XCERD11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERD12, ширина 1 бит; данные XCERD12. */ + Uint16 XCERD12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERD13, ширина 1 бит; данные XCERD13. */ + Uint16 XCERD13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERD14, ширина 1 бит; данные XCERD14. */ + Uint16 XCERD14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERD15, ширина 1 бит; данные XCERD15. */ + Uint16 XCERD15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERD_REG в одной области памяти. */ +union XCERD_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERD_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERD_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERE control register bit definitions: +/* Описывает структуру RCERE_BITS; порядок полей определяет расположение данных. */ +struct RCERE_BITS { // bit description + /* Битовое поле RCEE0, ширина 1 бит; данные RCEE0. */ + Uint16 RCEE0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEE1, ширина 1 бит; данные RCEE1. */ + Uint16 RCEE1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEE2, ширина 1 бит; данные RCEE2. */ + Uint16 RCEE2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEE3, ширина 1 бит; данные RCEE3. */ + Uint16 RCEE3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEE4, ширина 1 бит; данные RCEE4. */ + Uint16 RCEE4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEE5, ширина 1 бит; данные RCEE5. */ + Uint16 RCEE5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEE6, ширина 1 бит; данные RCEE6. */ + Uint16 RCEE6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEE7, ширина 1 бит; данные RCEE7. */ + Uint16 RCEE7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEE8, ширина 1 бит; данные RCEE8. */ + Uint16 RCEE8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEE9, ширина 1 бит; данные RCEE9. */ + Uint16 RCEE9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEE10, ширина 1 бит; данные RCEE10. */ + Uint16 RCEE10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEE11, ширина 1 бит; данные RCEE11. */ + Uint16 RCEE11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEE12, ширина 1 бит; данные RCEE12. */ + Uint16 RCEE12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEE13, ширина 1 бит; данные RCEE13. */ + Uint16 RCEE13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEE14, ширина 1 бит; данные RCEE14. */ + Uint16 RCEE14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEE15, ширина 1 бит; данные RCEE15. */ + Uint16 RCEE15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERE_REG в одной области памяти. */ +union RCERE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERE_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERF control register bit definitions: +/* Описывает структуру RCERF_BITS; порядок полей определяет расположение данных. */ +struct RCERF_BITS { // bit description + /* Битовое поле RCEF0, ширина 1 бит; данные RCEF0. */ + Uint16 RCEF0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEF1, ширина 1 бит; данные RCEF1. */ + Uint16 RCEF1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEF2, ширина 1 бит; данные RCEF2. */ + Uint16 RCEF2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEF3, ширина 1 бит; данные RCEF3. */ + Uint16 RCEF3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEF4, ширина 1 бит; данные RCEF4. */ + Uint16 RCEF4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEF5, ширина 1 бит; данные RCEF5. */ + Uint16 RCEF5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEF6, ширина 1 бит; данные RCEF6. */ + Uint16 RCEF6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEF7, ширина 1 бит; данные RCEF7. */ + Uint16 RCEF7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEF8, ширина 1 бит; данные RCEF8. */ + Uint16 RCEF8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEF9, ширина 1 бит; данные RCEF9. */ + Uint16 RCEF9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEF10, ширина 1 бит; данные RCEF10. */ + Uint16 RCEF10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEF11, ширина 1 бит; данные RCEF11. */ + Uint16 RCEF11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEF12, ширина 1 бит; данные RCEF12. */ + Uint16 RCEF12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEF13, ширина 1 бит; данные RCEF13. */ + Uint16 RCEF13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEF14, ширина 1 бит; данные RCEF14. */ + Uint16 RCEF14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEF15, ширина 1 бит; данные RCEF15. */ + Uint16 RCEF15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERF_REG в одной области памяти. */ +union RCERF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERF_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERE control register bit definitions: +/* Описывает структуру XCERE_BITS; порядок полей определяет расположение данных. */ +struct XCERE_BITS { // bit description + /* Битовое поле XCERE0, ширина 1 бит; данные XCERE0. */ + Uint16 XCERE0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERE1, ширина 1 бит; данные XCERE1. */ + Uint16 XCERE1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERE2, ширина 1 бит; данные XCERE2. */ + Uint16 XCERE2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERE3, ширина 1 бит; данные XCERE3. */ + Uint16 XCERE3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERE4, ширина 1 бит; данные XCERE4. */ + Uint16 XCERE4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERE5, ширина 1 бит; данные XCERE5. */ + Uint16 XCERE5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERE6, ширина 1 бит; данные XCERE6. */ + Uint16 XCERE6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERE7, ширина 1 бит; данные XCERE7. */ + Uint16 XCERE7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERE8, ширина 1 бит; данные XCERE8. */ + Uint16 XCERE8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERE9, ширина 1 бит; данные XCERE9. */ + Uint16 XCERE9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERE10, ширина 1 бит; данные XCERE10. */ + Uint16 XCERE10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERE11, ширина 1 бит; данные XCERE11. */ + Uint16 XCERE11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERE12, ширина 1 бит; данные XCERE12. */ + Uint16 XCERE12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERE13, ширина 1 бит; данные XCERE13. */ + Uint16 XCERE13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERE14, ширина 1 бит; данные XCERE14. */ + Uint16 XCERE14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERE15, ширина 1 бит; данные XCERE15. */ + Uint16 XCERE15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERE_REG в одной области памяти. */ +union XCERE_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERE_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERE_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERF control register bit definitions: +/* Описывает структуру XCERF_BITS; порядок полей определяет расположение данных. */ +struct XCERF_BITS { // bit description + /* Битовое поле XCERF0, ширина 1 бит; данные XCERF0. */ + Uint16 XCERF0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERF1, ширина 1 бит; данные XCERF1. */ + Uint16 XCERF1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERF2, ширина 1 бит; данные XCERF2. */ + Uint16 XCERF2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERF3, ширина 1 бит; данные XCERF3. */ + Uint16 XCERF3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERF4, ширина 1 бит; данные XCERF4. */ + Uint16 XCERF4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERF5, ширина 1 бит; данные XCERF5. */ + Uint16 XCERF5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERF6, ширина 1 бит; данные XCERF6. */ + Uint16 XCERF6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERF7, ширина 1 бит; данные XCERF7. */ + Uint16 XCERF7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERF8, ширина 1 бит; данные XCERF8. */ + Uint16 XCERF8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERF9, ширина 1 бит; данные XCERF9. */ + Uint16 XCERF9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERF10, ширина 1 бит; данные XCERF10. */ + Uint16 XCERF10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERF11, ширина 1 бит; данные XCERF11. */ + Uint16 XCERF11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERF12, ширина 1 бит; данные XCERF12. */ + Uint16 XCERF12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERF13, ширина 1 бит; данные XCERF13. */ + Uint16 XCERF13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERF14, ширина 1 бит; данные XCERF14. */ + Uint16 XCERF14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERF15, ширина 1 бит; данные XCERF15. */ + Uint16 XCERF15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERF_REG в одной области памяти. */ +union XCERF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERF_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERG control register bit definitions: +/* Описывает структуру RCERG_BITS; порядок полей определяет расположение данных. */ +struct RCERG_BITS { // bit description + /* Битовое поле RCEG0, ширина 1 бит; данные RCEG0. */ + Uint16 RCEG0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEG1, ширина 1 бит; данные RCEG1. */ + Uint16 RCEG1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEG2, ширина 1 бит; данные RCEG2. */ + Uint16 RCEG2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEG3, ширина 1 бит; данные RCEG3. */ + Uint16 RCEG3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEG4, ширина 1 бит; данные RCEG4. */ + Uint16 RCEG4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEG5, ширина 1 бит; данные RCEG5. */ + Uint16 RCEG5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEG6, ширина 1 бит; данные RCEG6. */ + Uint16 RCEG6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEG7, ширина 1 бит; данные RCEG7. */ + Uint16 RCEG7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEG8, ширина 1 бит; данные RCEG8. */ + Uint16 RCEG8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEG9, ширина 1 бит; данные RCEG9. */ + Uint16 RCEG9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEG10, ширина 1 бит; данные RCEG10. */ + Uint16 RCEG10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEG11, ширина 1 бит; данные RCEG11. */ + Uint16 RCEG11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEG12, ширина 1 бит; данные RCEG12. */ + Uint16 RCEG12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEG13, ширина 1 бит; данные RCEG13. */ + Uint16 RCEG13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEG14, ширина 1 бит; данные RCEG14. */ + Uint16 RCEG14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEG15, ширина 1 бит; данные RCEG15. */ + Uint16 RCEG15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERG_REG в одной области памяти. */ +union RCERG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERG_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// RCERH control register bit definitions: +/* Описывает структуру RCERH_BITS; порядок полей определяет расположение данных. */ +struct RCERH_BITS { // bit description + /* Битовое поле RCEH0, ширина 1 бит; данные RCEH0. */ + Uint16 RCEH0:1; // 0 Receive Channel enable bit + /* Битовое поле RCEH1, ширина 1 бит; данные RCEH1. */ + Uint16 RCEH1:1; // 1 Receive Channel enable bit + /* Битовое поле RCEH2, ширина 1 бит; данные RCEH2. */ + Uint16 RCEH2:1; // 2 Receive Channel enable bit + /* Битовое поле RCEH3, ширина 1 бит; данные RCEH3. */ + Uint16 RCEH3:1; // 3 Receive Channel enable bit + /* Битовое поле RCEH4, ширина 1 бит; данные RCEH4. */ + Uint16 RCEH4:1; // 4 Receive Channel enable bit + /* Битовое поле RCEH5, ширина 1 бит; данные RCEH5. */ + Uint16 RCEH5:1; // 5 Receive Channel enable bit + /* Битовое поле RCEH6, ширина 1 бит; данные RCEH6. */ + Uint16 RCEH6:1; // 6 Receive Channel enable bit + /* Битовое поле RCEH7, ширина 1 бит; данные RCEH7. */ + Uint16 RCEH7:1; // 7 Receive Channel enable bit + /* Битовое поле RCEH8, ширина 1 бит; данные RCEH8. */ + Uint16 RCEH8:1; // 8 Receive Channel enable bit + /* Битовое поле RCEH9, ширина 1 бит; данные RCEH9. */ + Uint16 RCEH9:1; // 9 Receive Channel enable bit + /* Битовое поле RCEH10, ширина 1 бит; данные RCEH10. */ + Uint16 RCEH10:1; // 10 Receive Channel enable bit + /* Битовое поле RCEH11, ширина 1 бит; данные RCEH11. */ + Uint16 RCEH11:1; // 11 Receive Channel enable bit + /* Битовое поле RCEH12, ширина 1 бит; данные RCEH12. */ + Uint16 RCEH12:1; // 12 Receive Channel enable bit + /* Битовое поле RCEH13, ширина 1 бит; данные RCEH13. */ + Uint16 RCEH13:1; // 13 Receive Channel enable bit + /* Битовое поле RCEH14, ширина 1 бит; данные RCEH14. */ + Uint16 RCEH14:1; // 14 Receive Channel enable bit + /* Битовое поле RCEH15, ширина 1 бит; данные RCEH15. */ + Uint16 RCEH15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений RCERH_REG в одной области памяти. */ +union RCERH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру RCERH_BITS bit;; порядок полей определяет расположение данных. */ + struct RCERH_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERG control register bit definitions: +/* Описывает структуру XCERG_BITS; порядок полей определяет расположение данных. */ +struct XCERG_BITS { // bit description + /* Битовое поле XCERG0, ширина 1 бит; данные XCERG0. */ + Uint16 XCERG0:1; // 0 Receive Channel enable bit + /* Битовое поле XCERG1, ширина 1 бит; данные XCERG1. */ + Uint16 XCERG1:1; // 1 Receive Channel enable bit + /* Битовое поле XCERG2, ширина 1 бит; данные XCERG2. */ + Uint16 XCERG2:1; // 2 Receive Channel enable bit + /* Битовое поле XCERG3, ширина 1 бит; данные XCERG3. */ + Uint16 XCERG3:1; // 3 Receive Channel enable bit + /* Битовое поле XCERG4, ширина 1 бит; данные XCERG4. */ + Uint16 XCERG4:1; // 4 Receive Channel enable bit + /* Битовое поле XCERG5, ширина 1 бит; данные XCERG5. */ + Uint16 XCERG5:1; // 5 Receive Channel enable bit + /* Битовое поле XCERG6, ширина 1 бит; данные XCERG6. */ + Uint16 XCERG6:1; // 6 Receive Channel enable bit + /* Битовое поле XCERG7, ширина 1 бит; данные XCERG7. */ + Uint16 XCERG7:1; // 7 Receive Channel enable bit + /* Битовое поле XCERG8, ширина 1 бит; данные XCERG8. */ + Uint16 XCERG8:1; // 8 Receive Channel enable bit + /* Битовое поле XCERG9, ширина 1 бит; данные XCERG9. */ + Uint16 XCERG9:1; // 9 Receive Channel enable bit + /* Битовое поле XCERG10, ширина 1 бит; данные XCERG10. */ + Uint16 XCERG10:1; // 10 Receive Channel enable bit + /* Битовое поле XCERG11, ширина 1 бит; данные XCERG11. */ + Uint16 XCERG11:1; // 11 Receive Channel enable bit + /* Битовое поле XCERG12, ширина 1 бит; данные XCERG12. */ + Uint16 XCERG12:1; // 12 Receive Channel enable bit + /* Битовое поле XCERG13, ширина 1 бит; данные XCERG13. */ + Uint16 XCERG13:1; // 13 Receive Channel enable bit + /* Битовое поле XCERG14, ширина 1 бит; данные XCERG14. */ + Uint16 XCERG14:1; // 14 Receive Channel enable bit + /* Битовое поле XCERG15, ширина 1 бит; данные XCERG15. */ + Uint16 XCERG15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERG_REG в одной области памяти. */ +union XCERG_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERG_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERG_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XCERH control register bit definitions: +/* Описывает структуру XCERH_BITS; порядок полей определяет расположение данных. */ +struct XCERH_BITS { // bit description + /* Битовое поле XCEH0, ширина 1 бит; данные XCEH0. */ + Uint16 XCEH0:1; // 0 Receive Channel enable bit + /* Битовое поле XCEH1, ширина 1 бит; данные XCEH1. */ + Uint16 XCEH1:1; // 1 Receive Channel enable bit + /* Битовое поле XCEH2, ширина 1 бит; данные XCEH2. */ + Uint16 XCEH2:1; // 2 Receive Channel enable bit + /* Битовое поле XCEH3, ширина 1 бит; данные XCEH3. */ + Uint16 XCEH3:1; // 3 Receive Channel enable bit + /* Битовое поле XCEH4, ширина 1 бит; данные XCEH4. */ + Uint16 XCEH4:1; // 4 Receive Channel enable bit + /* Битовое поле XCEH5, ширина 1 бит; данные XCEH5. */ + Uint16 XCEH5:1; // 5 Receive Channel enable bit + /* Битовое поле XCEH6, ширина 1 бит; данные XCEH6. */ + Uint16 XCEH6:1; // 6 Receive Channel enable bit + /* Битовое поле XCEH7, ширина 1 бит; данные XCEH7. */ + Uint16 XCEH7:1; // 7 Receive Channel enable bit + /* Битовое поле XCEH8, ширина 1 бит; данные XCEH8. */ + Uint16 XCEH8:1; // 8 Receive Channel enable bit + /* Битовое поле XCEH9, ширина 1 бит; данные XCEH9. */ + Uint16 XCEH9:1; // 9 Receive Channel enable bit + /* Битовое поле XCEH10, ширина 1 бит; данные XCEH10. */ + Uint16 XCEH10:1; // 10 Receive Channel enable bit + /* Битовое поле XCEH11, ширина 1 бит; данные XCEH11. */ + Uint16 XCEH11:1; // 11 Receive Channel enable bit + /* Битовое поле XCEH12, ширина 1 бит; данные XCEH12. */ + Uint16 XCEH12:1; // 12 Receive Channel enable bit + /* Битовое поле XCEH13, ширина 1 бит; данные XCEH13. */ + Uint16 XCEH13:1; // 13 Receive Channel enable bit + /* Битовое поле XCEH14, ширина 1 бит; данные XCEH14. */ + Uint16 XCEH14:1; // 14 Receive Channel enable bit + /* Битовое поле XCEH15, ширина 1 бит; данные XCEH15. */ + Uint16 XCEH15:1; // 15 Receive Channel enable bit +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XCERH_REG в одной области памяти. */ +union XCERH_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XCERH_BITS bit;; порядок полей определяет расположение данных. */ + struct XCERH_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// McBSP Interrupt enable register for RINT/XINT +/* Описывает структуру MFFINT_BITS; порядок полей определяет расположение данных. */ +struct MFFINT_BITS { // bits description + /* Битовое поле XINT, ширина 1 бит; данные XINT. */ + Uint16 XINT:1; // 0 XINT interrupt enable + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле RINT, ширина 1 бит; данные RINT. */ + Uint16 RINT:1; // 2 RINT interrupt enable + /* Битовое поле rsvd2, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MFFINT_REG в одной области памяти. */ +union MFFINT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MFFINT_BITS bit;; порядок полей определяет расположение данных. */ + struct MFFINT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// McBSP Register File: +// +/* Описывает структуру MCBSP_REGS; порядок полей определяет расположение данных. */ +struct MCBSP_REGS { + /* Объединяет несколько представлений DRR2_REG DRR2; в одной области памяти. */ + union DRR2_REG DRR2; // MCBSP Data receive register bits 31-16 + /* Объединяет несколько представлений DRR1_REG DRR1; в одной области памяти. */ + union DRR1_REG DRR1; // MCBSP Data receive register bits 15-0 + /* Объединяет несколько представлений DXR2_REG DXR2; в одной области памяти. */ + union DXR2_REG DXR2; // MCBSP Data transmit register bits 31-16 + /* Объединяет несколько представлений DXR1_REG DXR1; в одной области памяти. */ + union DXR1_REG DXR1; // MCBSP Data transmit register bits 15-0 + /* Объединяет несколько представлений SPCR2_REG SPCR2; в одной области памяти. */ + union SPCR2_REG SPCR2; // MCBSP control register bits 31-16 + /* Объединяет несколько представлений SPCR1_REG SPCR1; в одной области памяти. */ + union SPCR1_REG SPCR1; // MCBSP control register bits 15-0 + /* Объединяет несколько представлений RCR2_REG RCR2; в одной области памяти. */ + union RCR2_REG RCR2; // MCBSP receive control register bits 31-16 + /* Объединяет несколько представлений RCR1_REG RCR1; в одной области памяти. */ + union RCR1_REG RCR1; // MCBSP receive control register bits 15-0 + /* Объединяет несколько представлений XCR2_REG XCR2; в одной области памяти. */ + union XCR2_REG XCR2; // MCBSP transmit control register bits 31-16 + /* Объединяет несколько представлений XCR1_REG XCR1; в одной области памяти. */ + union XCR1_REG XCR1; // MCBSP transmit control register bits 15-0 + /* Объединяет несколько представлений SRGR2_REG SRGR2; в одной области памяти. */ + union SRGR2_REG SRGR2; // MCBSP sample rate gen register bits 31-16 + /* Объединяет несколько представлений SRGR1_REG SRGR1; в одной области памяти. */ + union SRGR1_REG SRGR1; // MCBSP sample rate gen register bits 15-0 + /* Объединяет несколько представлений MCR2_REG MCR2; в одной области памяти. */ + union MCR2_REG MCR2; // MCBSP multichannel register bits 31-16 + /* Объединяет несколько представлений MCR1_REG MCR1; в одной области памяти. */ + union MCR1_REG MCR1; // MCBSP multichannel register bits 15-0 + /* Объединяет несколько представлений RCERA_REG RCERA; в одной области памяти. */ + union RCERA_REG RCERA; // MCBSP Receive channel enable partition A + /* Объединяет несколько представлений RCERB_REG RCERB; в одной области памяти. */ + union RCERB_REG RCERB; // MCBSP Receive channel enable partition B + /* Объединяет несколько представлений XCERA_REG XCERA; в одной области памяти. */ + union XCERA_REG XCERA; // MCBSP Transmit channel enable partition A + /* Объединяет несколько представлений XCERB_REG XCERB; в одной области памяти. */ + union XCERB_REG XCERB; // MCBSP Transmit channel enable partition B + /* Объединяет несколько представлений PCR_REG PCR; в одной области памяти. */ + union PCR_REG PCR; // MCBSP Pin control register bits 15-0 + /* Объединяет несколько представлений RCERC_REG RCERC; в одной области памяти. */ + union RCERC_REG RCERC; // MCBSP Receive channel enable partition C + /* Объединяет несколько представлений RCERD_REG RCERD; в одной области памяти. */ + union RCERD_REG RCERD; // MCBSP Receive channel enable partition D + /* Объединяет несколько представлений XCERC_REG XCERC; в одной области памяти. */ + union XCERC_REG XCERC; // MCBSP Transmit channel enable partition C + /* Объединяет несколько представлений XCERD_REG XCERD; в одной области памяти. */ + union XCERD_REG XCERD; // MCBSP Transmit channel enable partition D + /* Объединяет несколько представлений RCERE_REG RCERE; в одной области памяти. */ + union RCERE_REG RCERE; // MCBSP Receive channel enable partition E + /* Объединяет несколько представлений RCERF_REG RCERF; в одной области памяти. */ + union RCERF_REG RCERF; // MCBSP Receive channel enable partition F + /* Объединяет несколько представлений XCERE_REG XCERE; в одной области памяти. */ + union XCERE_REG XCERE; // MCBSP Transmit channel enable partition E + /* Объединяет несколько представлений XCERF_REG XCERF; в одной области памяти. */ + union XCERF_REG XCERF; // MCBSP Transmit channel enable partition F + /* Объединяет несколько представлений RCERG_REG RCERG; в одной области памяти. */ + union RCERG_REG RCERG; // MCBSP Receive channel enable partition G + /* Объединяет несколько представлений RCERH_REG RCERH; в одной области памяти. */ + union RCERH_REG RCERH; // MCBSP Receive channel enable partition H + /* Объединяет несколько представлений XCERG_REG XCERG; в одной области памяти. */ + union XCERG_REG XCERG; // MCBSP Transmit channel enable partition G + /* Объединяет несколько представлений XCERH_REG XCERH; в одной области памяти. */ + union XCERH_REG XCERH; // MCBSP Transmit channel enable partition H + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1[4]; // reserved + /* Объединяет несколько представлений MFFINT_REG MFFINT; в одной области памяти. */ + union MFFINT_REG MFFINT; // MCBSP Interrupt enable register for RINT/XINT + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// McBSP External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct MCBSP_REGS McbspaRegs;; порядок элементов сохраняется. */ +extern volatile struct MCBSP_REGS McbspaRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct MCBSP_REGS McbspbRegs;; порядок элементов сохраняется. */ +extern volatile struct MCBSP_REGS McbspbRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_MCBSP_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h new file mode 100644 index 0000000..b7eece6 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieCtrl.h @@ -0,0 +1,260 @@ +/* Поставляемое TI описание PieCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:24 $ +//########################################################################### +// +// FILE: DSP2833x_PieCtrl.h +// +// TITLE: DSP2833x Device PIE Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + + +/* Начинает условие: DSP2833x_PIE_CTRL_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_PIE_CTRL_H +/* Определяет защитный символ или переключатель DSP2833x_PIE_CTRL_H для последующей компиляции. */ +#define DSP2833x_PIE_CTRL_H + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// PIE Control Register Bit Definitions: +// +// PIECTRL: Register bit definitions: +/* Описывает структуру PIECTRL_BITS; порядок полей определяет расположение данных. */ +struct PIECTRL_BITS { // bits description + /* Битовое поле ENPIE, ширина 1 бит; данные ENPIE. */ + Uint16 ENPIE:1; // 0 Enable PIE block + /* Битовое поле PIEVECT, ширина 15 бит; данные PIEVECT. */ + Uint16 PIEVECT:15; // 15:1 Fetched vector address +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIECTRL_REG в одной области памяти. */ +union PIECTRL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIECTRL_BITS bit;; порядок полей определяет расположение данных. */ + struct PIECTRL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PIEIER: Register bit definitions: +/* Описывает структуру PIEIER_BITS; порядок полей определяет расположение данных. */ +struct PIEIER_BITS { // bits description + /* Битовое поле INTx1, ширина 1 бит; данные INTx1. */ + Uint16 INTx1:1; // 0 INTx.1 + /* Битовое поле INTx2, ширина 1 бит; данные INTx2. */ + Uint16 INTx2:1; // 1 INTx.2 + /* Битовое поле INTx3, ширина 1 бит; данные INTx3. */ + Uint16 INTx3:1; // 2 INTx.3 + /* Битовое поле INTx4, ширина 1 бит; данные INTx4. */ + Uint16 INTx4:1; // 3 INTx.4 + /* Битовое поле INTx5, ширина 1 бит; данные INTx5. */ + Uint16 INTx5:1; // 4 INTx.5 + /* Битовое поле INTx6, ширина 1 бит; данные INTx6. */ + Uint16 INTx6:1; // 5 INTx.6 + /* Битовое поле INTx7, ширина 1 бит; данные INTx7. */ + Uint16 INTx7:1; // 6 INTx.7 + /* Битовое поле INTx8, ширина 1 бит; данные INTx8. */ + Uint16 INTx8:1; // 7 INTx.8 + /* Битовое поле rsvd, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIEIER_REG в одной области памяти. */ +union PIEIER_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIEIER_BITS bit;; порядок полей определяет расположение данных. */ + struct PIEIER_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PIEIFR: Register bit definitions: +/* Описывает структуру PIEIFR_BITS; порядок полей определяет расположение данных. */ +struct PIEIFR_BITS { // bits description + /* Битовое поле INTx1, ширина 1 бит; данные INTx1. */ + Uint16 INTx1:1; // 0 INTx.1 + /* Битовое поле INTx2, ширина 1 бит; данные INTx2. */ + Uint16 INTx2:1; // 1 INTx.2 + /* Битовое поле INTx3, ширина 1 бит; данные INTx3. */ + Uint16 INTx3:1; // 2 INTx.3 + /* Битовое поле INTx4, ширина 1 бит; данные INTx4. */ + Uint16 INTx4:1; // 3 INTx.4 + /* Битовое поле INTx5, ширина 1 бит; данные INTx5. */ + Uint16 INTx5:1; // 4 INTx.5 + /* Битовое поле INTx6, ширина 1 бит; данные INTx6. */ + Uint16 INTx6:1; // 5 INTx.6 + /* Битовое поле INTx7, ширина 1 бит; данные INTx7. */ + Uint16 INTx7:1; // 6 INTx.7 + /* Битовое поле INTx8, ширина 1 бит; данные INTx8. */ + Uint16 INTx8:1; // 7 INTx.8 + /* Битовое поле rsvd, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIEIFR_REG в одной области памяти. */ +union PIEIFR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIEIFR_BITS bit;; порядок полей определяет расположение данных. */ + struct PIEIFR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// PIEACK: Register bit definitions: +/* Описывает структуру PIEACK_BITS; порядок полей определяет расположение данных. */ +struct PIEACK_BITS { // bits description + /* Битовое поле ACK1, ширина 1 бит; данные ACK1. */ + Uint16 ACK1:1; // 0 Acknowledge PIE interrupt group 1 + /* Битовое поле ACK2, ширина 1 бит; данные ACK2. */ + Uint16 ACK2:1; // 1 Acknowledge PIE interrupt group 2 + /* Битовое поле ACK3, ширина 1 бит; данные ACK3. */ + Uint16 ACK3:1; // 2 Acknowledge PIE interrupt group 3 + /* Битовое поле ACK4, ширина 1 бит; данные ACK4. */ + Uint16 ACK4:1; // 3 Acknowledge PIE interrupt group 4 + /* Битовое поле ACK5, ширина 1 бит; данные ACK5. */ + Uint16 ACK5:1; // 4 Acknowledge PIE interrupt group 5 + /* Битовое поле ACK6, ширина 1 бит; данные ACK6. */ + Uint16 ACK6:1; // 5 Acknowledge PIE interrupt group 6 + /* Битовое поле ACK7, ширина 1 бит; данные ACK7. */ + Uint16 ACK7:1; // 6 Acknowledge PIE interrupt group 7 + /* Битовое поле ACK8, ширина 1 бит; данные ACK8. */ + Uint16 ACK8:1; // 7 Acknowledge PIE interrupt group 8 + /* Битовое поле ACK9, ширина 1 бит; данные ACK9. */ + Uint16 ACK9:1; // 8 Acknowledge PIE interrupt group 9 + /* Битовое поле ACK10, ширина 1 бит; данные ACK10. */ + Uint16 ACK10:1; // 9 Acknowledge PIE interrupt group 10 + /* Битовое поле ACK11, ширина 1 бит; данные ACK11. */ + Uint16 ACK11:1; // 10 Acknowledge PIE interrupt group 11 + /* Битовое поле ACK12, ширина 1 бит; данные ACK12. */ + Uint16 ACK12:1; // 11 Acknowledge PIE interrupt group 12 + /* Битовое поле rsvd, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:4; // 15:12 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PIEACK_REG в одной области памяти. */ +union PIEACK_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PIEACK_BITS bit;; порядок полей определяет расположение данных. */ + struct PIEACK_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// PIE Control Register File: +// +/* Описывает структуру PIE_CTRL_REGS; порядок полей определяет расположение данных. */ +struct PIE_CTRL_REGS { + /* Объединяет несколько представлений PIECTRL_REG PIECTRL; в одной области памяти. */ + union PIECTRL_REG PIECTRL; // PIE control register + /* Объединяет несколько представлений PIEACK_REG PIEACK; в одной области памяти. */ + union PIEACK_REG PIEACK; // PIE acknowledge + /* Объединяет несколько представлений PIEIER_REG PIEIER1; в одной области памяти. */ + union PIEIER_REG PIEIER1; // PIE int1 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR1; в одной области памяти. */ + union PIEIFR_REG PIEIFR1; // PIE int1 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER2; в одной области памяти. */ + union PIEIER_REG PIEIER2; // PIE INT2 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR2; в одной области памяти. */ + union PIEIFR_REG PIEIFR2; // PIE INT2 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER3; в одной области памяти. */ + union PIEIER_REG PIEIER3; // PIE INT3 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR3; в одной области памяти. */ + union PIEIFR_REG PIEIFR3; // PIE INT3 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER4; в одной области памяти. */ + union PIEIER_REG PIEIER4; // PIE INT4 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR4; в одной области памяти. */ + union PIEIFR_REG PIEIFR4; // PIE INT4 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER5; в одной области памяти. */ + union PIEIER_REG PIEIER5; // PIE INT5 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR5; в одной области памяти. */ + union PIEIFR_REG PIEIFR5; // PIE INT5 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER6; в одной области памяти. */ + union PIEIER_REG PIEIER6; // PIE INT6 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR6; в одной области памяти. */ + union PIEIFR_REG PIEIFR6; // PIE INT6 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER7; в одной области памяти. */ + union PIEIER_REG PIEIER7; // PIE INT7 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR7; в одной области памяти. */ + union PIEIFR_REG PIEIFR7; // PIE INT7 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER8; в одной области памяти. */ + union PIEIER_REG PIEIER8; // PIE INT8 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR8; в одной области памяти. */ + union PIEIFR_REG PIEIFR8; // PIE INT8 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER9; в одной области памяти. */ + union PIEIER_REG PIEIER9; // PIE INT9 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR9; в одной области памяти. */ + union PIEIFR_REG PIEIFR9; // PIE INT9 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER10; в одной области памяти. */ + union PIEIER_REG PIEIER10; // PIE int10 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR10; в одной области памяти. */ + union PIEIFR_REG PIEIFR10; // PIE int10 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER11; в одной области памяти. */ + union PIEIER_REG PIEIER11; // PIE int11 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR11; в одной области памяти. */ + union PIEIFR_REG PIEIFR11; // PIE int11 IFR register + /* Объединяет несколько представлений PIEIER_REG PIEIER12; в одной области памяти. */ + union PIEIER_REG PIEIER12; // PIE int12 IER register + /* Объединяет несколько представлений PIEIFR_REG PIEIFR12; в одной области памяти. */ + union PIEIFR_REG PIEIFR12; // PIE int12 IFR register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Задаёт PIEACK_GROUP1 = 0x0001; данные PIEACK_GROUP1. */ +#define PIEACK_GROUP1 0x0001 +/* Задаёт PIEACK_GROUP2 = 0x0002; данные PIEACK_GROUP2. */ +#define PIEACK_GROUP2 0x0002 +/* Задаёт PIEACK_GROUP3 = 0x0004; данные PIEACK_GROUP3. */ +#define PIEACK_GROUP3 0x0004 +/* Задаёт PIEACK_GROUP4 = 0x0008; данные PIEACK_GROUP4. */ +#define PIEACK_GROUP4 0x0008 +/* Задаёт PIEACK_GROUP5 = 0x0010; данные PIEACK_GROUP5. */ +#define PIEACK_GROUP5 0x0010 +/* Задаёт PIEACK_GROUP6 = 0x0020; данные PIEACK_GROUP6. */ +#define PIEACK_GROUP6 0x0020 +/* Задаёт PIEACK_GROUP7 = 0x0040; данные PIEACK_GROUP7. */ +#define PIEACK_GROUP7 0x0040 +/* Задаёт PIEACK_GROUP8 = 0x0080; данные PIEACK_GROUP8. */ +#define PIEACK_GROUP8 0x0080 +/* Задаёт PIEACK_GROUP9 = 0x0100; данные PIEACK_GROUP9. */ +#define PIEACK_GROUP9 0x0100 +/* Задаёт PIEACK_GROUP10 = 0x0200; данные PIEACK_GROUP10. */ +#define PIEACK_GROUP10 0x0200 +/* Задаёт PIEACK_GROUP11 = 0x0400; данные PIEACK_GROUP11. */ +#define PIEACK_GROUP11 0x0400 +/* Задаёт PIEACK_GROUP12 = 0x0800; данные PIEACK_GROUP12. */ +#define PIEACK_GROUP12 0x0800 + +//--------------------------------------------------------------------------- +// PIE Control Registers External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct PIE_CTRL_REGS PieCtrlRegs;; порядок элементов сохраняется. */ +extern volatile struct PIE_CTRL_REGS PieCtrlRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_PIE_CTRL_H definition + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h new file mode 100644 index 0000000..b768be2 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_PieVect.h @@ -0,0 +1,349 @@ +/* Поставляемое TI описание PieVect для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: March 16, 2007 09:00:21 $ +//########################################################################### +// +// FILE: DSP2833x_PieVect.h +// +// TITLE: DSP2833x Devices PIE Vector Table Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_PIE_VECT_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_PIE_VECT_H +/* Определяет защитный символ или переключатель DSP2833x_PIE_VECT_H для последующей компиляции. */ +#define DSP2833x_PIE_VECT_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table Definition: +// +// Create a user type called PINT (pointer to interrupt): + +/* Объявляет интерфейс функции void; реализация вызывается через этот прототип. */ +typedef interrupt void(*PINT)(void); + +// Define Vector Table: +/* Описывает структуру PIE_VECT_TABLE; порядок полей определяет расположение данных. */ +struct PIE_VECT_TABLE { + +// Reset is never fetched from this table. +// It will always be fetched from 0x3FFFC0 in +// boot ROM + + /* Продолжает список аргументов, полей или выражение PINT PIE1_RESERVED;; порядок элементов сохраняется. */ + PINT PIE1_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE2_RESERVED;; порядок элементов сохраняется. */ + PINT PIE2_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE3_RESERVED;; порядок элементов сохраняется. */ + PINT PIE3_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE4_RESERVED;; порядок элементов сохраняется. */ + PINT PIE4_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE5_RESERVED;; порядок элементов сохраняется. */ + PINT PIE5_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE6_RESERVED;; порядок элементов сохраняется. */ + PINT PIE6_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE7_RESERVED;; порядок элементов сохраняется. */ + PINT PIE7_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE8_RESERVED;; порядок элементов сохраняется. */ + PINT PIE8_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE9_RESERVED;; порядок элементов сохраняется. */ + PINT PIE9_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE10_RESERVED;; порядок элементов сохраняется. */ + PINT PIE10_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE11_RESERVED;; порядок элементов сохраняется. */ + PINT PIE11_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE12_RESERVED;; порядок элементов сохраняется. */ + PINT PIE12_RESERVED; + /* Продолжает список аргументов, полей или выражение PINT PIE13_RESERVED;; порядок элементов сохраняется. */ + PINT PIE13_RESERVED; + +// Non-Peripheral Interrupts: + /* Продолжает список аргументов, полей или выражение PINT XINT13;; порядок элементов сохраняется. */ + PINT XINT13; // XINT13 / CPU-Timer1 + /* Продолжает список аргументов, полей или выражение PINT TINT2;; порядок элементов сохраняется. */ + PINT TINT2; // CPU-Timer2 + /* Продолжает список аргументов, полей или выражение PINT DATALOG;; порядок элементов сохраняется. */ + PINT DATALOG; // Datalogging interrupt + /* Продолжает список аргументов, полей или выражение PINT RTOSINT;; порядок элементов сохраняется. */ + PINT RTOSINT; // RTOS interrupt + /* Продолжает список аргументов, полей или выражение PINT EMUINT;; порядок элементов сохраняется. */ + PINT EMUINT; // Emulation interrupt + /* Продолжает список аргументов, полей или выражение PINT XNMI;; порядок элементов сохраняется. */ + PINT XNMI; // Non-maskable interrupt + /* Продолжает список аргументов, полей или выражение PINT ILLEGAL;; порядок элементов сохраняется. */ + PINT ILLEGAL; // Illegal operation TRAP + /* Продолжает список аргументов, полей или выражение PINT USER1;; порядок элементов сохраняется. */ + PINT USER1; // User Defined trap 1 + /* Продолжает список аргументов, полей или выражение PINT USER2;; порядок элементов сохраняется. */ + PINT USER2; // User Defined trap 2 + /* Продолжает список аргументов, полей или выражение PINT USER3;; порядок элементов сохраняется. */ + PINT USER3; // User Defined trap 3 + /* Продолжает список аргументов, полей или выражение PINT USER4;; порядок элементов сохраняется. */ + PINT USER4; // User Defined trap 4 + /* Продолжает список аргументов, полей или выражение PINT USER5;; порядок элементов сохраняется. */ + PINT USER5; // User Defined trap 5 + /* Продолжает список аргументов, полей или выражение PINT USER6;; порядок элементов сохраняется. */ + PINT USER6; // User Defined trap 6 + /* Продолжает список аргументов, полей или выражение PINT USER7;; порядок элементов сохраняется. */ + PINT USER7; // User Defined trap 7 + /* Продолжает список аргументов, полей или выражение PINT USER8;; порядок элементов сохраняется. */ + PINT USER8; // User Defined trap 8 + /* Продолжает список аргументов, полей или выражение PINT USER9;; порядок элементов сохраняется. */ + PINT USER9; // User Defined trap 9 + /* Продолжает список аргументов, полей или выражение PINT USER10;; порядок элементов сохраняется. */ + PINT USER10; // User Defined trap 10 + /* Продолжает список аргументов, полей или выражение PINT USER11;; порядок элементов сохраняется. */ + PINT USER11; // User Defined trap 11 + /* Продолжает список аргументов, полей или выражение PINT USER12;; порядок элементов сохраняется. */ + PINT USER12; // User Defined trap 12 + +// Group 1 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT SEQ1INT;; порядок элементов сохраняется. */ + PINT SEQ1INT; + /* Продолжает список аргументов, полей или выражение PINT SEQ2INT;; порядок элементов сохраняется. */ + PINT SEQ2INT; + /* Продолжает список аргументов, полей или выражение PINT rsvd1_3;; порядок элементов сохраняется. */ + PINT rsvd1_3; + /* Продолжает список аргументов, полей или выражение PINT XINT1;; порядок элементов сохраняется. */ + PINT XINT1; + /* Продолжает список аргументов, полей или выражение PINT XINT2;; порядок элементов сохраняется. */ + PINT XINT2; + /* Продолжает список аргументов, полей или выражение PINT ADCINT;; порядок элементов сохраняется. */ + PINT ADCINT; // ADC + /* Продолжает список аргументов, полей или выражение PINT TINT0;; порядок элементов сохраняется. */ + PINT TINT0; // Timer 0 + /* Продолжает список аргументов, полей или выражение PINT WAKEINT;; порядок элементов сохраняется. */ + PINT WAKEINT; // WD + +// Group 2 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT EPWM1_TZINT;; порядок элементов сохраняется. */ + PINT EPWM1_TZINT; // EPWM-1 + /* Продолжает список аргументов, полей или выражение PINT EPWM2_TZINT;; порядок элементов сохраняется. */ + PINT EPWM2_TZINT; // EPWM-2 + /* Продолжает список аргументов, полей или выражение PINT EPWM3_TZINT;; порядок элементов сохраняется. */ + PINT EPWM3_TZINT; // EPWM-3 + /* Продолжает список аргументов, полей или выражение PINT EPWM4_TZINT;; порядок элементов сохраняется. */ + PINT EPWM4_TZINT; // EPWM-4 + /* Продолжает список аргументов, полей или выражение PINT EPWM5_TZINT;; порядок элементов сохраняется. */ + PINT EPWM5_TZINT; // EPWM-5 + /* Продолжает список аргументов, полей или выражение PINT EPWM6_TZINT;; порядок элементов сохраняется. */ + PINT EPWM6_TZINT; // EPWM-6 + /* Продолжает список аргументов, полей или выражение PINT rsvd2_7;; порядок элементов сохраняется. */ + PINT rsvd2_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd2_8;; порядок элементов сохраняется. */ + PINT rsvd2_8; + +// Group 3 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT EPWM1_INT;; порядок элементов сохраняется. */ + PINT EPWM1_INT; // EPWM-1 + /* Продолжает список аргументов, полей или выражение PINT EPWM2_INT;; порядок элементов сохраняется. */ + PINT EPWM2_INT; // EPWM-2 + /* Продолжает список аргументов, полей или выражение PINT EPWM3_INT;; порядок элементов сохраняется. */ + PINT EPWM3_INT; // EPWM-3 + /* Продолжает список аргументов, полей или выражение PINT EPWM4_INT;; порядок элементов сохраняется. */ + PINT EPWM4_INT; // EPWM-4 + /* Продолжает список аргументов, полей или выражение PINT EPWM5_INT;; порядок элементов сохраняется. */ + PINT EPWM5_INT; // EPWM-5 + /* Продолжает список аргументов, полей или выражение PINT EPWM6_INT;; порядок элементов сохраняется. */ + PINT EPWM6_INT; // EPWM-6 + /* Продолжает список аргументов, полей или выражение PINT rsvd3_7;; порядок элементов сохраняется. */ + PINT rsvd3_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd3_8;; порядок элементов сохраняется. */ + PINT rsvd3_8; + +// Group 4 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT ECAP1_INT;; порядок элементов сохраняется. */ + PINT ECAP1_INT; // ECAP-1 + /* Продолжает список аргументов, полей или выражение PINT ECAP2_INT;; порядок элементов сохраняется. */ + PINT ECAP2_INT; // ECAP-2 + /* Продолжает список аргументов, полей или выражение PINT ECAP3_INT;; порядок элементов сохраняется. */ + PINT ECAP3_INT; // ECAP-3 + /* Продолжает список аргументов, полей или выражение PINT ECAP4_INT;; порядок элементов сохраняется. */ + PINT ECAP4_INT; // ECAP-4 + /* Продолжает список аргументов, полей или выражение PINT ECAP5_INT;; порядок элементов сохраняется. */ + PINT ECAP5_INT; // ECAP-5 + /* Продолжает список аргументов, полей или выражение PINT ECAP6_INT;; порядок элементов сохраняется. */ + PINT ECAP6_INT; // ECAP-6 + /* Продолжает список аргументов, полей или выражение PINT rsvd4_7;; порядок элементов сохраняется. */ + PINT rsvd4_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd4_8;; порядок элементов сохраняется. */ + PINT rsvd4_8; + +// Group 5 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT EQEP1_INT;; порядок элементов сохраняется. */ + PINT EQEP1_INT; // EQEP-1 + /* Продолжает список аргументов, полей или выражение PINT EQEP2_INT;; порядок элементов сохраняется. */ + PINT EQEP2_INT; // EQEP-2 + /* Продолжает список аргументов, полей или выражение PINT rsvd5_3;; порядок элементов сохраняется. */ + PINT rsvd5_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_4;; порядок элементов сохраняется. */ + PINT rsvd5_4; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_5;; порядок элементов сохраняется. */ + PINT rsvd5_5; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_6;; порядок элементов сохраняется. */ + PINT rsvd5_6; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_7;; порядок элементов сохраняется. */ + PINT rsvd5_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd5_8;; порядок элементов сохраняется. */ + PINT rsvd5_8; + +// Group 6 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT SPIRXINTA;; порядок элементов сохраняется. */ + PINT SPIRXINTA; // SPI-A + /* Продолжает список аргументов, полей или выражение PINT SPITXINTA;; порядок элементов сохраняется. */ + PINT SPITXINTA; // SPI-A + /* Продолжает список аргументов, полей или выражение PINT MRINTB;; порядок элементов сохраняется. */ + PINT MRINTB; // McBSP-B + /* Продолжает список аргументов, полей или выражение PINT MXINTB;; порядок элементов сохраняется. */ + PINT MXINTB; // McBSP-B + /* Продолжает список аргументов, полей или выражение PINT MRINTA;; порядок элементов сохраняется. */ + PINT MRINTA; // McBSP-A + /* Продолжает список аргументов, полей или выражение PINT MXINTA;; порядок элементов сохраняется. */ + PINT MXINTA; // McBSP-A + /* Продолжает список аргументов, полей или выражение PINT rsvd6_7;; порядок элементов сохраняется. */ + PINT rsvd6_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd6_8;; порядок элементов сохраняется. */ + PINT rsvd6_8; + +// Group 7 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT DINTCH1;; порядок элементов сохраняется. */ + PINT DINTCH1; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH2;; порядок элементов сохраняется. */ + PINT DINTCH2; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH3;; порядок элементов сохраняется. */ + PINT DINTCH3; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH4;; порядок элементов сохраняется. */ + PINT DINTCH4; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH5;; порядок элементов сохраняется. */ + PINT DINTCH5; // DMA + /* Продолжает список аргументов, полей или выражение PINT DINTCH6;; порядок элементов сохраняется. */ + PINT DINTCH6; // DMA + /* Продолжает список аргументов, полей или выражение PINT rsvd7_7;; порядок элементов сохраняется. */ + PINT rsvd7_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd7_8;; порядок элементов сохраняется. */ + PINT rsvd7_8; + +// Group 8 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT I2CINT1A;; порядок элементов сохраняется. */ + PINT I2CINT1A; // I2C-A + /* Продолжает список аргументов, полей или выражение PINT I2CINT2A;; порядок элементов сохраняется. */ + PINT I2CINT2A; // I2C-A + /* Продолжает список аргументов, полей или выражение PINT rsvd8_3;; порядок элементов сохраняется. */ + PINT rsvd8_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd8_4;; порядок элементов сохраняется. */ + PINT rsvd8_4; + /* Продолжает список аргументов, полей или выражение PINT SCIRXINTC;; порядок элементов сохраняется. */ + PINT SCIRXINTC; // SCI-C + /* Продолжает список аргументов, полей или выражение PINT SCITXINTC;; порядок элементов сохраняется. */ + PINT SCITXINTC; // SCI-C + /* Продолжает список аргументов, полей или выражение PINT rsvd8_7;; порядок элементов сохраняется. */ + PINT rsvd8_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd8_8;; порядок элементов сохраняется. */ + PINT rsvd8_8; + +// Group 9 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT SCIRXINTA;; порядок элементов сохраняется. */ + PINT SCIRXINTA; // SCI-A + /* Продолжает список аргументов, полей или выражение PINT SCITXINTA;; порядок элементов сохраняется. */ + PINT SCITXINTA; // SCI-A + /* Продолжает список аргументов, полей или выражение PINT SCIRXINTB;; порядок элементов сохраняется. */ + PINT SCIRXINTB; // SCI-B + /* Продолжает список аргументов, полей или выражение PINT SCITXINTB;; порядок элементов сохраняется. */ + PINT SCITXINTB; // SCI-B + /* Продолжает список аргументов, полей или выражение PINT ECAN0INTA;; порядок элементов сохраняется. */ + PINT ECAN0INTA; // eCAN-A + /* Продолжает список аргументов, полей или выражение PINT ECAN1INTA;; порядок элементов сохраняется. */ + PINT ECAN1INTA; // eCAN-A + /* Продолжает список аргументов, полей или выражение PINT ECAN0INTB;; порядок элементов сохраняется. */ + PINT ECAN0INTB; // eCAN-B + /* Продолжает список аргументов, полей или выражение PINT ECAN1INTB;; порядок элементов сохраняется. */ + PINT ECAN1INTB; // eCAN-B + +// Group 10 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT rsvd10_1;; порядок элементов сохраняется. */ + PINT rsvd10_1; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_2;; порядок элементов сохраняется. */ + PINT rsvd10_2; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_3;; порядок элементов сохраняется. */ + PINT rsvd10_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_4;; порядок элементов сохраняется. */ + PINT rsvd10_4; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_5;; порядок элементов сохраняется. */ + PINT rsvd10_5; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_6;; порядок элементов сохраняется. */ + PINT rsvd10_6; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_7;; порядок элементов сохраняется. */ + PINT rsvd10_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd10_8;; порядок элементов сохраняется. */ + PINT rsvd10_8; + +// Group 11 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT rsvd11_1;; порядок элементов сохраняется. */ + PINT rsvd11_1; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_2;; порядок элементов сохраняется. */ + PINT rsvd11_2; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_3;; порядок элементов сохраняется. */ + PINT rsvd11_3; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_4;; порядок элементов сохраняется. */ + PINT rsvd11_4; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_5;; порядок элементов сохраняется. */ + PINT rsvd11_5; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_6;; порядок элементов сохраняется. */ + PINT rsvd11_6; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_7;; порядок элементов сохраняется. */ + PINT rsvd11_7; + /* Продолжает список аргументов, полей или выражение PINT rsvd11_8;; порядок элементов сохраняется. */ + PINT rsvd11_8; + +// Group 12 PIE Peripheral Vectors: + /* Продолжает список аргументов, полей или выражение PINT XINT3;; порядок элементов сохраняется. */ + PINT XINT3; // External interrupt + /* Продолжает список аргументов, полей или выражение PINT XINT4;; порядок элементов сохраняется. */ + PINT XINT4; + /* Продолжает список аргументов, полей или выражение PINT XINT5;; порядок элементов сохраняется. */ + PINT XINT5; + /* Продолжает список аргументов, полей или выражение PINT XINT6;; порядок элементов сохраняется. */ + PINT XINT6; + /* Продолжает список аргументов, полей или выражение PINT XINT7;; порядок элементов сохраняется. */ + PINT XINT7; + /* Продолжает список аргументов, полей или выражение PINT rsvd12_6;; порядок элементов сохраняется. */ + PINT rsvd12_6; + /* Продолжает список аргументов, полей или выражение PINT LVF;; порядок элементов сохраняется. */ + PINT LVF; // Latched overflow + /* Продолжает список аргументов, полей или выражение PINT LUF;; порядок элементов сохраняется. */ + PINT LUF; // Latched underflow +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// PIE Interrupt Vector Table External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern struct PIE_VECT_TABLE PieVectTable;; порядок элементов сохраняется. */ +extern struct PIE_VECT_TABLE PieVectTable; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_PIE_VECT_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h new file mode 100644 index 0000000..83b5a65 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Sci.h @@ -0,0 +1,377 @@ +/* Поставляемое TI описание Sci для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/2 $ +// Checkin $Date: March 1, 2007 15:57:02 $ +//########################################################################### +// +// FILE: DSP2833x_Sci.h +// +// TITLE: DSP2833x Device SCI Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SCI_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SCI_H +/* Определяет защитный символ или переключатель DSP2833x_SCI_H для последующей компиляции. */ +#define DSP2833x_SCI_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- +// SCI Individual Register Bit Definitions + +//---------------------------------------------------------- +// SCICCR communication control register bit definitions: +// + +/* Описывает структуру SCICCR_BITS; порядок полей определяет расположение данных. */ +struct SCICCR_BITS { // bit description + /* Битовое поле SCICHAR, ширина 3 бит; данные SCICHAR. */ + Uint16 SCICHAR:3; // 2:0 Character length control + /* Битовое поле ADDRIDLE_MODE, ширина 1 бит; ADDRIDLE режим. */ + Uint16 ADDRIDLE_MODE:1; // 3 ADDR/IDLE Mode control + /* Битовое поле LOOPBKENA, ширина 1 бит; данные LOOPBKENA. */ + Uint16 LOOPBKENA:1; // 4 Loop Back enable + /* Битовое поле PARITYENA, ширина 1 бит; данные PARITYENA. */ + Uint16 PARITYENA:1; // 5 Parity enable + /* Битовое поле PARITY, ширина 1 бит; чётность. */ + Uint16 PARITY:1; // 6 Even or Odd Parity + /* Битовое поле STOPBITS, ширина 1 бит; данные STOPBITS. */ + Uint16 STOPBITS:1; // 7 Number of Stop Bits + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Объединяет несколько представлений SCICCR_REG в одной области памяти. */ +union SCICCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCICCR_BITS bit;; порядок полей определяет расположение данных. */ + struct SCICCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------- +// SCICTL1 control register 1 bit definitions: +// + +/* Описывает структуру SCICTL1_BITS; порядок полей определяет расположение данных. */ +struct SCICTL1_BITS { // bit description + /* Битовое поле RXENA, ширина 1 бит; данные RXENA. */ + Uint16 RXENA:1; // 0 SCI receiver enable + /* Битовое поле TXENA, ширина 1 бит; данные TXENA. */ + Uint16 TXENA:1; // 1 SCI transmitter enable + /* Битовое поле SLEEP, ширина 1 бит; данные SLEEP. */ + Uint16 SLEEP:1; // 2 SCI sleep + /* Битовое поле TXWAKE, ширина 1 бит; данные TXWAKE. */ + Uint16 TXWAKE:1; // 3 Transmitter wakeup method + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 4 reserved + /* Битовое поле SWRESET, ширина 1 бит; данные SWRESET. */ + Uint16 SWRESET:1; // 5 Software reset + /* Битовое поле RXERRINTENA, ширина 1 бит; данные RXERRINTENA. */ + Uint16 RXERRINTENA:1; // 6 Recieve interrupt enable + /* Битовое поле rsvd1, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:9; // 15:7 reserved + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCICTL1_REG в одной области памяти. */ +union SCICTL1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCICTL1_BITS bit;; порядок полей определяет расположение данных. */ + struct SCICTL1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------- +// SCICTL2 control register 2 bit definitions: +// + +/* Описывает структуру SCICTL2_BITS; порядок полей определяет расположение данных. */ +struct SCICTL2_BITS { // bit description + /* Битовое поле TXINTENA, ширина 1 бит; данные TXINTENA. */ + Uint16 TXINTENA:1; // 0 Transmit interrupt enable + /* Битовое поле RXBKINTENA, ширина 1 бит; данные RXBKINTENA. */ + Uint16 RXBKINTENA:1; // 1 Receiver-buffer break enable + /* Битовое поле rsvd, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:4; // 5:2 reserved + /* Битовое поле TXEMPTY, ширина 1 бит; данные TXEMPTY. */ + Uint16 TXEMPTY:1; // 6 Transmitter empty flag + /* Битовое поле TXRDY, ширина 1 бит; данные TXRDY. */ + Uint16 TXRDY:1; // 7 Transmitter ready flag + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 15:8 reserved + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCICTL2_REG в одной области памяти. */ +union SCICTL2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCICTL2_BITS bit;; порядок полей определяет расположение данных. */ + struct SCICTL2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------- +// SCIRXST Receiver status register bit definitions: +// + +/* Описывает структуру SCIRXST_BITS; порядок полей определяет расположение данных. */ +struct SCIRXST_BITS { // bit description + /* Битовое поле rsvd, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:1; // 0 reserved + /* Битовое поле RXWAKE, ширина 1 бит; данные RXWAKE. */ + Uint16 RXWAKE:1; // 1 Receiver wakeup detect flag + /* Битовое поле PE, ширина 1 бит; данные PE. */ + Uint16 PE:1; // 2 Parity error flag + /* Битовое поле OE, ширина 1 бит; данные OE. */ + Uint16 OE:1; // 3 Overrun error flag + /* Битовое поле FE, ширина 1 бит; данные FE. */ + Uint16 FE:1; // 4 Framing error flag + /* Битовое поле BRKDT, ширина 1 бит; данные BRKDT. */ + Uint16 BRKDT:1; // 5 Break-detect flag + /* Битовое поле RXRDY, ширина 1 бит; данные RXRDY. */ + Uint16 RXRDY:1; // 6 Receiver ready flag + /* Битовое поле RXERROR, ширина 1 бит; данные RXERROR. */ + Uint16 RXERROR:1; // 7 Receiver error flag + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIRXST_REG в одной области памяти. */ +union SCIRXST_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIRXST_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIRXST_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//---------------------------------------------------- +// SCIRXBUF Receiver Data Buffer with FIFO bit definitions: +// + +/* Описывает структуру SCIRXBUF_BITS; порядок полей определяет расположение данных. */ +struct SCIRXBUF_BITS { // bits description + /* Битовое поле RXDT, ширина 8 бит; данные RXDT. */ + Uint16 RXDT:8; // 7:0 Receive word + /* Битовое поле rsvd, ширина 6 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:6; // 13:8 reserved + /* Битовое поле SCIFFPE, ширина 1 бит; данные SCIFFPE. */ + Uint16 SCIFFPE:1; // 14 SCI PE error in FIFO mode + /* Битовое поле SCIFFFE, ширина 1 бит; данные SCIFFFE. */ + Uint16 SCIFFFE:1; // 15 SCI FE error in FIFO mode +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIRXBUF_REG в одной области памяти. */ +union SCIRXBUF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIRXBUF_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIRXBUF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------------------- +// SCIPRI Priority control register bit definitions: +// +// + +/* Описывает структуру SCIPRI_BITS; порядок полей определяет расположение данных. */ +struct SCIPRI_BITS { // bit description + /* Битовое поле rsvd, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:3; // 2:0 reserved + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 3 Free emulation suspend mode + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 4 Soft emulation suspend mode + /* Битовое поле rsvd1, ширина 3 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:3; // 7:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIPRI_REG в одной области памяти. */ +union SCIPRI_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIPRI_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIPRI_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------- +// SCI FIFO Transmit register bit definitions: +// +// + +/* Описывает структуру SCIFFTX_BITS; порядок полей определяет расположение данных. */ +struct SCIFFTX_BITS { // bit description + /* Битовое поле TXFFIL, ширина 5 бит; данные TXFFIL. */ + Uint16 TXFFIL:5; // 4:0 Interrupt level + /* Битовое поле TXFFIENA, ширина 1 бит; данные TXFFIENA. */ + Uint16 TXFFIENA:1; // 5 Interrupt enable + /* Битовое поле TXFFINTCLR, ширина 1 бит; данные TXFFINTCLR. */ + Uint16 TXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле TXFFINT, ширина 1 бит; данные TXFFINT. */ + Uint16 TXFFINT:1; // 7 INT flag + /* Битовое поле TXFFST, ширина 5 бит; данные TXFFST. */ + Uint16 TXFFST:5; // 12:8 FIFO status + /* Битовое поле TXFIFOXRESET, ширина 1 бит; данные TXFIFOXRESET. */ + Uint16 TXFIFOXRESET:1; // 13 FIFO reset + /* Битовое поле SCIFFENA, ширина 1 бит; данные SCIFFENA. */ + Uint16 SCIFFENA:1; // 14 Enhancement enable + /* Битовое поле SCIRST, ширина 1 бит; данные SCIRST. */ + Uint16 SCIRST:1; // 15 SCI reset rx/tx channels + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIFFTX_REG в одной области памяти. */ +union SCIFFTX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIFFTX_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIFFTX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------ +// SCI FIFO recieve register bit definitions: +// +// + +/* Описывает структуру SCIFFRX_BITS; порядок полей определяет расположение данных. */ +struct SCIFFRX_BITS { // bits description + /* Битовое поле RXFFIL, ширина 5 бит; данные RXFFIL. */ + Uint16 RXFFIL:5; // 4:0 Interrupt level + /* Битовое поле RXFFIENA, ширина 1 бит; данные RXFFIENA. */ + Uint16 RXFFIENA:1; // 5 Interrupt enable + /* Битовое поле RXFFINTCLR, ширина 1 бит; данные RXFFINTCLR. */ + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле RXFFINT, ширина 1 бит; данные RXFFINT. */ + Uint16 RXFFINT:1; // 7 INT flag + /* Битовое поле RXFFST, ширина 5 бит; данные RXFFST. */ + Uint16 RXFFST:5; // 12:8 FIFO status + /* Битовое поле RXFIFORESET, ширина 1 бит; данные RXFIFORESET. */ + Uint16 RXFIFORESET:1; // 13 FIFO reset + /* Битовое поле RXFFOVRCLR, ширина 1 бит; данные RXFFOVRCLR. */ + Uint16 RXFFOVRCLR:1; // 14 Clear overflow + /* Битовое поле RXFFOVF, ширина 1 бит; данные RXFFOVF. */ + Uint16 RXFFOVF:1; // 15 FIFO overflow + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIFFRX_REG в одной области памяти. */ +union SCIFFRX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIFFRX_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIFFRX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// SCI FIFO control register bit definitions: +/* Описывает структуру SCIFFCT_BITS; порядок полей определяет расположение данных. */ +struct SCIFFCT_BITS { // bits description + /* Битовое поле FFTXDLY, ширина 8 бит; данные FFTXDLY. */ + Uint16 FFTXDLY:8; // 7:0 FIFO transmit delay + /* Битовое поле rsvd, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:5; // 12:8 reserved + /* Битовое поле CDC, ширина 1 бит; данные CDC. */ + Uint16 CDC:1; // 13 Auto baud mode enable + /* Битовое поле ABDCLR, ширина 1 бит; данные ABDCLR. */ + Uint16 ABDCLR:1; // 14 Auto baud clear + /* Битовое поле ABD, ширина 1 бит; данные ABD. */ + Uint16 ABD:1; // 15 Auto baud detect +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SCIFFCT_REG в одной области памяти. */ +union SCIFFCT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SCIFFCT_BITS bit;; порядок полей определяет расположение данных. */ + struct SCIFFCT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SCI Register File: +// +/* Описывает структуру SCI_REGS; порядок полей определяет расположение данных. */ +struct SCI_REGS { + /* Объединяет несколько представлений SCICCR_REG SCICCR; в одной области памяти. */ + union SCICCR_REG SCICCR; // Communications control register + /* Объединяет несколько представлений SCICTL1_REG SCICTL1; в одной области памяти. */ + union SCICTL1_REG SCICTL1; // Control register 1 + /* Объявляет SCIHBAUD — данные SCIHBAUD. */ + Uint16 SCIHBAUD; // Baud rate (high) register + /* Объявляет SCILBAUD — данные SCILBAUD. */ + Uint16 SCILBAUD; // Baud rate (low) register + /* Объединяет несколько представлений SCICTL2_REG SCICTL2; в одной области памяти. */ + union SCICTL2_REG SCICTL2; // Control register 2 + /* Объединяет несколько представлений SCIRXST_REG SCIRXST; в одной области памяти. */ + union SCIRXST_REG SCIRXST; // Recieve status register + /* Объявляет SCIRXEMU — данные SCIRXEMU. */ + Uint16 SCIRXEMU; // Recieve emulation buffer register + /* Объединяет несколько представлений SCIRXBUF_REG SCIRXBUF; в одной области памяти. */ + union SCIRXBUF_REG SCIRXBUF; // Recieve data buffer + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объявляет SCITXBUF — данные SCITXBUF. */ + Uint16 SCITXBUF; // Transmit data buffer + /* Объединяет несколько представлений SCIFFTX_REG SCIFFTX; в одной области памяти. */ + union SCIFFTX_REG SCIFFTX; // FIFO transmit register + /* Объединяет несколько представлений SCIFFRX_REG SCIFFRX; в одной области памяти. */ + union SCIFFRX_REG SCIFFRX; // FIFO recieve register + /* Объединяет несколько представлений SCIFFCT_REG SCIFFCT; в одной области памяти. */ + union SCIFFCT_REG SCIFFCT; // FIFO control register + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // reserved + /* Объединяет несколько представлений SCIPRI_REG SCIPRI; в одной области памяти. */ + union SCIPRI_REG SCIPRI; // FIFO Priority control +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SCI External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct SCI_REGS SciaRegs;; порядок элементов сохраняется. */ +extern volatile struct SCI_REGS SciaRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct SCI_REGS ScibRegs;; порядок элементов сохраняется. */ +extern volatile struct SCI_REGS ScibRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct SCI_REGS ScicRegs;; порядок элементов сохраняется. */ +extern volatile struct SCI_REGS ScicRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_SCI_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h new file mode 100644 index 0000000..cdce516 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Spi.h @@ -0,0 +1,292 @@ +/* Поставляемое TI описание Spi для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: April 17, 2008 11:08:27 $ +//########################################################################### +// +// FILE: DSP2833x_Spi.h +// +// TITLE: DSP2833x Device SPI Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SPI_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SPI_H +/* Определяет защитный символ или переключатель DSP2833x_SPI_H для последующей компиляции. */ +#define DSP2833x_SPI_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// SPI Individual Register Bit Definitions: +// +// SPI FIFO Transmit register bit definitions: +/* Описывает структуру SPIFFTX_BITS; порядок полей определяет расположение данных. */ +struct SPIFFTX_BITS { // bit description + /* Битовое поле TXFFIL, ширина 5 бит; данные TXFFIL. */ + Uint16 TXFFIL:5; // 4:0 Interrupt level + /* Битовое поле TXFFIENA, ширина 1 бит; данные TXFFIENA. */ + Uint16 TXFFIENA:1; // 5 Interrupt enable + /* Битовое поле TXFFINTCLR, ширина 1 бит; данные TXFFINTCLR. */ + Uint16 TXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле TXFFINT, ширина 1 бит; данные TXFFINT. */ + Uint16 TXFFINT:1; // 7 INT flag + /* Битовое поле TXFFST, ширина 5 бит; данные TXFFST. */ + Uint16 TXFFST:5; // 12:8 FIFO status + /* Битовое поле TXFIFO, ширина 1 бит; данные TXFIFO. */ + Uint16 TXFIFO:1; // 13 FIFO reset + /* Битовое поле SPIFFENA, ширина 1 бит; данные SPIFFENA. */ + Uint16 SPIFFENA:1; // 14 Enhancement enable + /* Битовое поле SPIRST, ширина 1 бит; данные SPIRST. */ + Uint16 SPIRST:1; // 15 Reset SPI +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIFFTX_REG в одной области памяти. */ +union SPIFFTX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIFFTX_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIFFTX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------------- +// SPI FIFO recieve register bit definitions: +// +// +/* Описывает структуру SPIFFRX_BITS; порядок полей определяет расположение данных. */ +struct SPIFFRX_BITS { // bits description + /* Битовое поле RXFFIL, ширина 5 бит; данные RXFFIL. */ + Uint16 RXFFIL:5; // 4:0 Interrupt level + /* Битовое поле RXFFIENA, ширина 1 бит; данные RXFFIENA. */ + Uint16 RXFFIENA:1; // 5 Interrupt enable + /* Битовое поле RXFFINTCLR, ширина 1 бит; данные RXFFINTCLR. */ + Uint16 RXFFINTCLR:1; // 6 Clear INT flag + /* Битовое поле RXFFINT, ширина 1 бит; данные RXFFINT. */ + Uint16 RXFFINT:1; // 7 INT flag + /* Битовое поле RXFFST, ширина 5 бит; данные RXFFST. */ + Uint16 RXFFST:5; // 12:8 FIFO status + /* Битовое поле RXFIFORESET, ширина 1 бит; данные RXFIFORESET. */ + Uint16 RXFIFORESET:1; // 13 FIFO reset + /* Битовое поле RXFFOVFCLR, ширина 1 бит; данные RXFFOVFCLR. */ + Uint16 RXFFOVFCLR:1; // 14 Clear overflow + /* Битовое поле RXFFOVF, ширина 1 бит; данные RXFFOVF. */ + Uint16 RXFFOVF:1; // 15 FIFO overflow + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIFFRX_REG в одной области памяти. */ +union SPIFFRX_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIFFRX_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIFFRX_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------------- +// SPI FIFO control register bit definitions: +// +// +/* Описывает структуру SPIFFCT_BITS; порядок полей определяет расположение данных. */ +struct SPIFFCT_BITS { // bits description + /* Битовое поле TXDLY, ширина 8 бит; данные TXDLY. */ + Uint16 TXDLY:8; // 7:0 FIFO transmit delay + /* Битовое поле rsvd, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIFFCT_REG в одной области памяти. */ +union SPIFFCT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIFFCT_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIFFCT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------- +// SPI configuration register bit definitions: +// +// +/* Описывает структуру SPICCR_BITS; порядок полей определяет расположение данных. */ +struct SPICCR_BITS { // bits description + /* Битовое поле SPICHAR, ширина 4 бит; данные SPICHAR. */ + Uint16 SPICHAR:4; // 3:0 Character length control + /* Битовое поле SPILBK, ширина 1 бит; данные SPILBK. */ + Uint16 SPILBK:1; // 4 Loop-back enable/disable + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 5 reserved + /* Битовое поле CLKPOLARITY, ширина 1 бит; данные CLKPOLARITY. */ + Uint16 CLKPOLARITY:1; // 6 Clock polarity + /* Битовое поле SPISWRESET, ширина 1 бит; данные SPISWRESET. */ + Uint16 SPISWRESET:1; // 7 SPI SW Reset + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPICCR_REG в одной области памяти. */ +union SPICCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPICCR_BITS bit;; порядок полей определяет расположение данных. */ + struct SPICCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------- +// SPI operation control register bit definitions: +// +// +/* Описывает структуру SPICTL_BITS; порядок полей определяет расположение данных. */ +struct SPICTL_BITS { // bits description + /* Битовое поле SPIINTENA, ширина 1 бит; данные SPIINTENA. */ + Uint16 SPIINTENA:1; // 0 Interrupt enable + /* Битовое поле TALK, ширина 1 бит; данные TALK. */ + Uint16 TALK:1; // 1 Master/Slave transmit enable + /* Битовое поле MASTER_SLAVE, ширина 1 бит; данные MASTER_SLAVE. */ + Uint16 MASTER_SLAVE:1; // 2 Network control mode + /* Битовое поле CLK_PHASE, ширина 1 бит; CLK фаза. */ + Uint16 CLK_PHASE:1; // 3 Clock phase select + /* Битовое поле OVERRUNINTENA, ширина 1 бит; данные OVERRUNINTENA. */ + Uint16 OVERRUNINTENA:1; // 4 Overrun interrupt enable + /* Битовое поле rsvd, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:11; // 15:5 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPICTL_REG в одной области памяти. */ +union SPICTL_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPICTL_BITS bit;; порядок полей определяет расположение данных. */ + struct SPICTL_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//-------------------------------------- +// SPI status register bit definitions: +// +// +/* Описывает структуру SPISTS_BITS; порядок полей определяет расположение данных. */ +struct SPISTS_BITS { // bits description + /* Битовое поле rsvd1, ширина 5 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:5; // 4:0 reserved + /* Битовое поле BUFFULL_FLAG, ширина 1 бит; BUFFULL флаг. */ + Uint16 BUFFULL_FLAG:1; // 5 SPI transmit buffer full flag + /* Битовое поле INT_FLAG, ширина 1 бит; INT флаг. */ + Uint16 INT_FLAG:1; // 6 SPI interrupt flag + /* Битовое поле OVERRUN_FLAG, ширина 1 бит; OVERRUN флаг. */ + Uint16 OVERRUN_FLAG:1; // 7 SPI reciever overrun flag + /* Битовое поле rsvd2, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:8; // 15:8 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPISTS_REG в одной области памяти. */ +union SPISTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPISTS_BITS bit;; порядок полей определяет расположение данных. */ + struct SPISTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//------------------------------------------------ +// SPI priority control register bit definitions: +// +// +/* Описывает структуру SPIPRI_BITS; порядок полей определяет расположение данных. */ +struct SPIPRI_BITS { // bits description + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 3:0 reserved + /* Битовое поле FREE, ширина 1 бит; данные FREE. */ + Uint16 FREE:1; // 4 Free emulation mode control + /* Битовое поле SOFT, ширина 1 бит; данные SOFT. */ + Uint16 SOFT:1; // 5 Soft emulation mode control + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 6 reserved + /* Битовое поле rsvd3, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:9; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений SPIPRI_REG в одной области памяти. */ +union SPIPRI_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру SPIPRI_BITS bit;; порядок полей определяет расположение данных. */ + struct SPIPRI_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SPI Register File: +// +/* Описывает структуру SPI_REGS; порядок полей определяет расположение данных. */ +struct SPI_REGS { + /* Объединяет несколько представлений SPICCR_REG SPICCR; в одной области памяти. */ + union SPICCR_REG SPICCR; // Configuration register + /* Объединяет несколько представлений SPICTL_REG SPICTL; в одной области памяти. */ + union SPICTL_REG SPICTL; // Operation control register + /* Объединяет несколько представлений SPISTS_REG SPISTS; в одной области памяти. */ + union SPISTS_REG SPISTS; // Status register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объявляет SPIBRR — данные SPIBRR. */ + Uint16 SPIBRR; // Baud Rate + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved + /* Объявляет SPIRXEMU — данные SPIRXEMU. */ + Uint16 SPIRXEMU; // Emulation buffer + /* Объявляет SPIRXBUF — данные SPIRXBUF. */ + Uint16 SPIRXBUF; // Serial input buffer + /* Объявляет SPITXBUF — данные SPITXBUF. */ + Uint16 SPITXBUF; // Serial output buffer + /* Объявляет SPIDAT — данные SPIDAT. */ + Uint16 SPIDAT; // Serial data + /* Объединяет несколько представлений SPIFFTX_REG SPIFFTX; в одной области памяти. */ + union SPIFFTX_REG SPIFFTX; // FIFO transmit register + /* Объединяет несколько представлений SPIFFRX_REG SPIFFRX; в одной области памяти. */ + union SPIFFRX_REG SPIFFRX; // FIFO recieve register + /* Объединяет несколько представлений SPIFFCT_REG SPIFFCT; в одной области памяти. */ + union SPIFFCT_REG SPIFFCT; // FIFO control register + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3[2]; // reserved + /* Объединяет несколько представлений SPIPRI_REG SPIPRI; в одной области памяти. */ + union SPIPRI_REG SPIPRI; // FIFO Priority control +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// SPI External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct SPI_REGS SpiaRegs;; порядок элементов сохраняется. */ +extern volatile struct SPI_REGS SpiaRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_SPI_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h new file mode 100644 index 0000000..0ab964e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_SysCtrl.h @@ -0,0 +1,642 @@ +/* Поставляемое TI описание SysCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/5 $ +// Checkin $Date: May 12, 2008 09:34:58 $ +//########################################################################### +// +// FILE: DSP2833x_SysCtrl.h +// +// TITLE: DSP2833x Device System Control Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_SYS_CTRL_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_SYS_CTRL_H +/* Определяет защитный символ или переключатель DSP2833x_SYS_CTRL_H для последующей компиляции. */ +#define DSP2833x_SYS_CTRL_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +//--------------------------------------------------------------------------- +// System Control Individual Register Bit Definitions: +// + + +// PLL Status Register +/* Описывает структуру PLLSTS_BITS; порядок полей определяет расположение данных. */ +struct PLLSTS_BITS { // bits description + /* Битовое поле PLLLOCKS, ширина 1 бит; данные PLLLOCKS. */ + Uint16 PLLLOCKS:1; // 0 PLL lock status + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле PLLOFF, ширина 1 бит; данные PLLOFF. */ + Uint16 PLLOFF:1; // 2 PLL off bit + /* Битовое поле MCLKSTS, ширина 1 бит; данные MCLKSTS. */ + Uint16 MCLKSTS:1; // 3 Missing clock status bit + /* Битовое поле MCLKCLR, ширина 1 бит; данные MCLKCLR. */ + Uint16 MCLKCLR:1; // 4 Missing clock clear bit + /* Битовое поле OSCOFF, ширина 1 бит; данные OSCOFF. */ + Uint16 OSCOFF:1; // 5 Oscillator clock off + /* Битовое поле MCLKOFF, ширина 1 бит; данные MCLKOFF. */ + Uint16 MCLKOFF:1; // 6 Missing clock detect + /* Битовое поле DIVSEL, ширина 2 бит; данные DIVSEL. */ + Uint16 DIVSEL:2; // 7 Divide Select + /* Битовое поле rsvd2, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:7; // 15:7 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PLLSTS_REG в одной области памяти. */ +union PLLSTS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PLLSTS_BITS bit;; порядок полей определяет расположение данных. */ + struct PLLSTS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// High speed peripheral clock register bit definitions: +/* Описывает структуру HISPCP_BITS; порядок полей определяет расположение данных. */ +struct HISPCP_BITS { // bits description + /* Битовое поле HSPCLK, ширина 3 бит; данные HSPCLK. */ + Uint16 HSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений HISPCP_REG в одной области памяти. */ +union HISPCP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру HISPCP_BITS bit;; порядок полей определяет расположение данных. */ + struct HISPCP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Low speed peripheral clock register bit definitions: +/* Описывает структуру LOSPCP_BITS; порядок полей определяет расположение данных. */ +struct LOSPCP_BITS { // bits description + /* Битовое поле LSPCLK, ширина 3 бит; данные LSPCLK. */ + Uint16 LSPCLK:3; // 2:0 Rate relative to SYSCLKOUT + /* Битовое поле rsvd1, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:13; // 15:3 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений LOSPCP_REG в одной области памяти. */ +union LOSPCP_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру LOSPCP_BITS bit;; порядок полей определяет расположение данных. */ + struct LOSPCP_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Peripheral clock control register 0 bit definitions: +/* Описывает структуру PCLKCR0_BITS; порядок полей определяет расположение данных. */ +struct PCLKCR0_BITS { // bits description + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 1:0 reserved + /* Битовое поле TBCLKSYNC, ширина 1 бит; данные TBCLKSYNC. */ + Uint16 TBCLKSYNC:1; // 2 EWPM Module TBCLK enable/sync + /* Битовое поле ADCENCLK, ширина 1 бит; данные ADCENCLK. */ + Uint16 ADCENCLK:1; // 3 Enable high speed clk to ADC + /* Битовое поле I2CAENCLK, ширина 1 бит; данные I2CAENCLK. */ + Uint16 I2CAENCLK:1; // 4 Enable SYSCLKOUT to I2C-A + /* Битовое поле SCICENCLK, ширина 1 бит; данные SCICENCLK. */ + Uint16 SCICENCLK:1; // 5 Enalbe low speed clk to SCI-C + /* Битовое поле rsvd2, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:2; // 7:6 reserved + /* Битовое поле SPIAENCLK, ширина 1 бит; данные SPIAENCLK. */ + Uint16 SPIAENCLK:1; // 8 Enable low speed clk to SPI-A + /* Битовое поле rsvd3, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:1; // 9 reserved + /* Битовое поле SCIAENCLK, ширина 1 бит; данные SCIAENCLK. */ + Uint16 SCIAENCLK:1; // 10 Enable low speed clk to SCI-A + /* Битовое поле SCIBENCLK, ширина 1 бит; данные SCIBENCLK. */ + Uint16 SCIBENCLK:1; // 11 Enable low speed clk to SCI-B + /* Битовое поле MCBSPAENCLK, ширина 1 бит; данные MCBSPAENCLK. */ + Uint16 MCBSPAENCLK:1; // 12 Enable low speed clk to McBSP-A + /* Битовое поле MCBSPBENCLK, ширина 1 бит; данные MCBSPBENCLK. */ + Uint16 MCBSPBENCLK:1; // 13 Enable low speed clk to McBSP-B + /* Битовое поле ECANAENCLK, ширина 1 бит; данные ECANAENCLK. */ + Uint16 ECANAENCLK:1; // 14 Enable system clk to eCAN-A + /* Битовое поле ECANBENCLK, ширина 1 бит; данные ECANBENCLK. */ + Uint16 ECANBENCLK:1; // 15 Enable system clk to eCAN-B +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCLKCR0_REG в одной области памяти. */ +union PCLKCR0_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCLKCR0_BITS bit;; порядок полей определяет расположение данных. */ + struct PCLKCR0_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Peripheral clock control register 1 bit definitions: +/* Описывает структуру PCLKCR1_BITS; порядок полей определяет расположение данных. */ +struct PCLKCR1_BITS { // bits description + /* Битовое поле EPWM1ENCLK, ширина 1 бит; данные EPWM1ENCLK. */ + Uint16 EPWM1ENCLK:1; // 0 Enable SYSCLKOUT to EPWM1 + /* Битовое поле EPWM2ENCLK, ширина 1 бит; данные EPWM2ENCLK. */ + Uint16 EPWM2ENCLK:1; // 1 Enable SYSCLKOUT to EPWM2 + /* Битовое поле EPWM3ENCLK, ширина 1 бит; данные EPWM3ENCLK. */ + Uint16 EPWM3ENCLK:1; // 2 Enable SYSCLKOUT to EPWM3 + /* Битовое поле EPWM4ENCLK, ширина 1 бит; данные EPWM4ENCLK. */ + Uint16 EPWM4ENCLK:1; // 3 Enable SYSCLKOUT to EPWM4 + /* Битовое поле EPWM5ENCLK, ширина 1 бит; данные EPWM5ENCLK. */ + Uint16 EPWM5ENCLK:1; // 4 Enable SYSCLKOUT to EPWM5 + /* Битовое поле EPWM6ENCLK, ширина 1 бит; данные EPWM6ENCLK. */ + Uint16 EPWM6ENCLK:1; // 5 Enable SYSCLKOUT to EPWM6 + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 7:6 reserved + /* Битовое поле ECAP1ENCLK, ширина 1 бит; данные ECAP1ENCLK. */ + Uint16 ECAP1ENCLK:1; // 8 Enable SYSCLKOUT to ECAP1 + /* Битовое поле ECAP2ENCLK, ширина 1 бит; данные ECAP2ENCLK. */ + Uint16 ECAP2ENCLK:1; // 9 Enable SYSCLKOUT to ECAP2 + /* Битовое поле ECAP3ENCLK, ширина 1 бит; данные ECAP3ENCLK. */ + Uint16 ECAP3ENCLK:1; // 10 Enable SYSCLKOUT to ECAP3 + /* Битовое поле ECAP4ENCLK, ширина 1 бит; данные ECAP4ENCLK. */ + Uint16 ECAP4ENCLK:1; // 11 Enable SYSCLKOUT to ECAP4 + /* Битовое поле ECAP5ENCLK, ширина 1 бит; данные ECAP5ENCLK. */ + Uint16 ECAP5ENCLK:1; // 12 Enable SYSCLKOUT to ECAP5 + /* Битовое поле ECAP6ENCLK, ширина 1 бит; данные ECAP6ENCLK. */ + Uint16 ECAP6ENCLK:1; // 13 Enable SYSCLKOUT to ECAP6 + /* Битовое поле EQEP1ENCLK, ширина 1 бит; данные EQEP1ENCLK. */ + Uint16 EQEP1ENCLK:1; // 14 Enable SYSCLKOUT to EQEP1 + /* Битовое поле EQEP2ENCLK, ширина 1 бит; данные EQEP2ENCLK. */ + Uint16 EQEP2ENCLK:1; // 15 Enable SYSCLKOUT to EQEP2 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCLKCR1_REG в одной области памяти. */ +union PCLKCR1_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCLKCR1_BITS bit;; порядок полей определяет расположение данных. */ + struct PCLKCR1_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +// Peripheral clock control register 2 bit definitions: +/* Описывает структуру PCLKCR3_BITS; порядок полей определяет расположение данных. */ +struct PCLKCR3_BITS { // bits description + /* Битовое поле rsvd1, ширина 8 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:8; // 7:0 reserved + /* Битовое поле CPUTIMER0ENCLK, ширина 1 бит; данные CPUTIMER0ENCLK. */ + Uint16 CPUTIMER0ENCLK:1; // 8 Enable SYSCLKOUT to CPU-Timer 0 + /* Битовое поле CPUTIMER1ENCLK, ширина 1 бит; данные CPUTIMER1ENCLK. */ + Uint16 CPUTIMER1ENCLK:1; // 9 Enable SYSCLKOUT to CPU-Timer 1 + /* Битовое поле CPUTIMER2ENCLK, ширина 1 бит; данные CPUTIMER2ENCLK. */ + Uint16 CPUTIMER2ENCLK:1; // 10 Enable SYSCLKOUT to CPU-Timer 2 + /* Битовое поле DMAENCLK, ширина 1 бит; данные DMAENCLK. */ + Uint16 DMAENCLK:1; // 11 Enable the DMA clock + /* Битовое поле XINTFENCLK, ширина 1 бит; данные XINTFENCLK. */ + Uint16 XINTFENCLK:1; // 12 Enable SYSCLKOUT to XINTF + /* Битовое поле GPIOINENCLK, ширина 1 бит; аппаратная линия ввода/вывода GPIOINENCLK. */ + Uint16 GPIOINENCLK:1; // Enable GPIO input clock + /* Битовое поле rsvd2, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:2; // 15:14 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PCLKCR3_REG в одной области памяти. */ +union PCLKCR3_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PCLKCR3_BITS bit;; порядок полей определяет расположение данных. */ + struct PCLKCR3_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +// PLL control register bit definitions: +/* Описывает структуру PLLCR_BITS; порядок полей определяет расположение данных. */ +struct PLLCR_BITS { // bits description + /* Битовое поле DIV, ширина 4 бит; данные DIV. */ + Uint16 DIV:4; // 3:0 Set clock ratio for the PLL + /* Битовое поле rsvd1, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений PLLCR_REG в одной области памяти. */ +union PLLCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру PLLCR_BITS bit;; порядок полей определяет расположение данных. */ + struct PLLCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Low Power Mode 0 control register bit definitions: +/* Описывает структуру LPMCR0_BITS; порядок полей определяет расположение данных. */ +struct LPMCR0_BITS { // bits description + /* Битовое поле LPM, ширина 2 бит; данные LPM. */ + Uint16 LPM:2; // 1:0 Set the low power mode + /* Битовое поле QUALSTDBY, ширина 6 бит; данные QUALSTDBY. */ + Uint16 QUALSTDBY:6; // 7:2 Qualification + /* Битовое поле rsvd1, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:7; // 14:8 reserved + /* Битовое поле WDINTE, ширина 1 бит; данные WDINTE. */ + Uint16 WDINTE:1; // 15 Enables WD to wake the device from STANDBY +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений LPMCR0_REG в одной области памяти. */ +union LPMCR0_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру LPMCR0_BITS bit;; порядок полей определяет расположение данных. */ + struct LPMCR0_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// Dual-mapping configuration register bit definitions: +/* Описывает структуру MAPCNF_BITS; порядок полей определяет расположение данных. */ +struct MAPCNF_BITS { // bits description + /* Битовое поле MAPEPWM, ширина 1 бит; данные MAPEPWM. */ + Uint16 MAPEPWM:1; // 0 EPWM dual-map enable + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; // 15:1 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений MAPCNF_REG в одной области памяти. */ +union MAPCNF_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру MAPCNF_BITS bit;; порядок полей определяет расположение данных. */ + struct MAPCNF_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// System Control Register File: +// +/* Описывает структуру SYS_CTRL_REGS; порядок полей определяет расположение данных. */ +struct SYS_CTRL_REGS { + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // 0 + /* Объединяет несколько представлений PLLSTS_REG PLLSTS; в одной области памяти. */ + union PLLSTS_REG PLLSTS; // 1 + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2[8]; // 2-9 + /* Объединяет несколько представлений HISPCP_REG HISPCP; в одной области памяти. */ + union HISPCP_REG HISPCP; // 10: High-speed peripheral clock pre-scaler + /* Объединяет несколько представлений LOSPCP_REG LOSPCP; в одной области памяти. */ + union LOSPCP_REG LOSPCP; // 11: Low-speed peripheral clock pre-scaler + /* Объединяет несколько представлений PCLKCR0_REG PCLKCR0; в одной области памяти. */ + union PCLKCR0_REG PCLKCR0; // 12: Peripheral clock control register + /* Объединяет несколько представлений PCLKCR1_REG PCLKCR1; в одной области памяти. */ + union PCLKCR1_REG PCLKCR1; // 13: Peripheral clock control register + /* Объединяет несколько представлений LPMCR0_REG LPMCR0; в одной области памяти. */ + union LPMCR0_REG LPMCR0; // 14: Low-power mode control register 0 + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // 15: reserved + /* Объединяет несколько представлений PCLKCR3_REG PCLKCR3; в одной области памяти. */ + union PCLKCR3_REG PCLKCR3; // 16: Peripheral clock control register + /* Объединяет несколько представлений PLLCR_REG PLLCR; в одной области памяти. */ + union PLLCR_REG PLLCR; // 17: PLL control register + // No bit definitions are defined for SCSR because + // a read-modify-write instruction can clear the WDOVERRIDE bit + /* Объявляет SCSR — данные SCSR. */ + Uint16 SCSR; // 18: System control and status register + /* Объявляет WDCNTR — данные WDCNTR. */ + Uint16 WDCNTR; // 19: WD counter register + /* Объявляет rsvd4 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4; // 20 + /* Объявляет WDKEY — данные WDKEY. */ + Uint16 WDKEY; // 21: WD reset key register + /* Объявляет rsvd5 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5[3]; // 22-24 + // No bit definitions are defined for WDCR because + // the proper value must be written to the WDCHK field + // whenever writing to this register. + /* Объявляет WDCR — данные WDCR. */ + Uint16 WDCR; // 25: WD timer control register + /* Объявляет rsvd6 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd6[4]; // 26-29 + /* Объединяет несколько представлений MAPCNF_REG MAPCNF; в одной области памяти. */ + union MAPCNF_REG MAPCNF; // 30: Dual-mapping configuration register + /* Объявляет rsvd7 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd7[1]; // 31 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* --------------------------------------------------- */ +/* CSM Registers */ +/* */ +/* ----------------------------------------------------*/ + +/* CSM Status & Control register bit definitions */ +/* Описывает структуру CSMSCR_BITS; порядок полей определяет расположение данных. */ +struct CSMSCR_BITS { // bit description + /* Битовое поле SECURE, ширина 1 бит; данные SECURE. */ + Uint16 SECURE:1; // 0 Secure flag + /* Битовое поле rsvd1, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:14; // 14-1 reserved + /* Битовое поле FORCESEC, ширина 1 бит; данные FORCESEC. */ + Uint16 FORCESEC:1; // 15 Force Secure control bit + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений CSMSCR_REG в одной области памяти. */ +union CSMSCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру CSMSCR_BITS bit;; порядок полей определяет расположение данных. */ + struct CSMSCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* CSM Register File */ +/* Описывает структуру CSM_REGS; порядок полей определяет расположение данных. */ +struct CSM_REGS { + /* Объявляет KEY0 — данные KEY0. */ + Uint16 KEY0; // KEY reg bits 15-0 + /* Объявляет KEY1 — данные KEY1. */ + Uint16 KEY1; // KEY reg bits 31-16 + /* Объявляет KEY2 — данные KEY2. */ + Uint16 KEY2; // KEY reg bits 47-32 + /* Объявляет KEY3 — данные KEY3. */ + Uint16 KEY3; // KEY reg bits 63-48 + /* Объявляет KEY4 — данные KEY4. */ + Uint16 KEY4; // KEY reg bits 79-64 + /* Объявляет KEY5 — данные KEY5. */ + Uint16 KEY5; // KEY reg bits 95-80 + /* Объявляет KEY6 — данные KEY6. */ + Uint16 KEY6; // KEY reg bits 111-96 + /* Объявляет KEY7 — данные KEY7. */ + Uint16 KEY7; // KEY reg bits 127-112 + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2; // reserved + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3; // reserved + /* Объявляет rsvd4 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4; // reserved + /* Объявляет rsvd5 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5; // reserved + /* Объявляет rsvd6 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd6; // reserved + /* Объявляет rsvd7 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd7; // reserved + /* Объединяет несколько представлений CSMSCR_REG CSMSCR; в одной области памяти. */ + union CSMSCR_REG CSMSCR; // CSM Status & Control register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Password locations */ +/* Описывает структуру CSM_PWL; порядок полей определяет расположение данных. */ +struct CSM_PWL { + /* Объявляет PSWD0 — данные PSWD0. */ + Uint16 PSWD0; // PSWD bits 15-0 + /* Объявляет PSWD1 — данные PSWD1. */ + Uint16 PSWD1; // PSWD bits 31-16 + /* Объявляет PSWD2 — данные PSWD2. */ + Uint16 PSWD2; // PSWD bits 47-32 + /* Объявляет PSWD3 — данные PSWD3. */ + Uint16 PSWD3; // PSWD bits 63-48 + /* Объявляет PSWD4 — данные PSWD4. */ + Uint16 PSWD4; // PSWD bits 79-64 + /* Объявляет PSWD5 — данные PSWD5. */ + Uint16 PSWD5; // PSWD bits 95-80 + /* Объявляет PSWD6 — данные PSWD6. */ + Uint16 PSWD6; // PSWD bits 111-96 + /* Объявляет PSWD7 — данные PSWD7. */ + Uint16 PSWD7; // PSWD bits 127-112 +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + +/* Flash Registers */ + +/* Задаёт FLASH_SLEEP = 0x0000;; данные FLASH_SLEEP. */ +#define FLASH_SLEEP 0x0000; +/* Задаёт FLASH_STANDBY = 0x0001;; данные FLASH_STANDBY. */ +#define FLASH_STANDBY 0x0001; +/* Задаёт FLASH_ACTIVE = 0x0003;; данные FLASH_ACTIVE. */ +#define FLASH_ACTIVE 0x0003; + + +/* Flash Option Register bit definitions */ +/* Описывает структуру FOPT_BITS; порядок полей определяет расположение данных. */ +struct FOPT_BITS { // bit description + /* Битовое поле ENPIPE, ширина 1 бит; данные ENPIPE. */ + Uint16 ENPIPE:1; // 0 Enable Pipeline Mode + /* Битовое поле rsvd, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:15; // 1-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FOPT_REG в одной области памяти. */ +union FOPT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FOPT_BITS bit;; порядок полей определяет расположение данных. */ + struct FOPT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Flash Power Modes Register bit definitions */ +/* Описывает структуру FPWR_BITS; порядок полей определяет расположение данных. */ +struct FPWR_BITS { // bit description + /* Битовое поле PWR, ширина 2 бит; данные PWR. */ + Uint16 PWR:2; // 0-1 Power Mode bits + /* Битовое поле rsvd, ширина 14 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:14; // 2-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FPWR_REG в одной области памяти. */ +union FPWR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FPWR_BITS bit;; порядок полей определяет расположение данных. */ + struct FPWR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Flash Status Register bit definitions */ +/* Описывает структуру FSTATUS_BITS; порядок полей определяет расположение данных. */ +struct FSTATUS_BITS { // bit description + /* Битовое поле PWRS, ширина 2 бит; данные PWRS. */ + Uint16 PWRS:2; // 0-1 Power Mode Status bits + /* Битовое поле STDBYWAITS, ширина 1 бит; данные STDBYWAITS. */ + Uint16 STDBYWAITS:1; // 2 Bank/Pump Sleep to Standby Wait Counter Status bits + /* Битовое поле ACTIVEWAITS, ширина 1 бит; данные ACTIVEWAITS. */ + Uint16 ACTIVEWAITS:1; // 3 Bank/Pump Standby to Active Wait Counter Status bits + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 4-7 reserved + /* Битовое поле V3STAT, ширина 1 бит; данные V3STAT. */ + Uint16 V3STAT:1; // 8 VDD3V Status Latch bit + /* Битовое поле rsvd2, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:7; // 9-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FSTATUS_REG в одной области памяти. */ +union FSTATUS_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FSTATUS_BITS bit;; порядок полей определяет расположение данных. */ + struct FSTATUS_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Flash Sleep to Standby Wait Counter Register bit definitions */ +/* Описывает структуру FSTDBYWAIT_BITS; порядок полей определяет расположение данных. */ +struct FSTDBYWAIT_BITS { // bit description + /* Битовое поле STDBYWAIT, ширина 9 бит; данные STDBYWAIT. */ + Uint16 STDBYWAIT:9; // 0-8 Bank/Pump Sleep to Standby Wait Count bits + /* Битовое поле rsvd, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:7; // 9-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FSTDBYWAIT_REG в одной области памяти. */ +union FSTDBYWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FSTDBYWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FSTDBYWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Flash Standby to Active Wait Counter Register bit definitions */ +/* Описывает структуру FACTIVEWAIT_BITS; порядок полей определяет расположение данных. */ +struct FACTIVEWAIT_BITS { // bit description + /* Битовое поле ACTIVEWAIT, ширина 9 бит; данные ACTIVEWAIT. */ + Uint16 ACTIVEWAIT:9; // 0-8 Bank/Pump Standby to Active Wait Count bits + /* Битовое поле rsvd, ширина 7 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:7; // 9-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FACTIVEWAIT_REG в одной области памяти. */ +union FACTIVEWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FACTIVEWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FACTIVEWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Bank Read Access Wait State Register bit definitions */ +/* Описывает структуру FBANKWAIT_BITS; порядок полей определяет расположение данных. */ +struct FBANKWAIT_BITS { // bit description + /* Битовое поле RANDWAIT, ширина 4 бит; данные RANDWAIT. */ + Uint16 RANDWAIT:4; // 0-3 Flash Random Read Wait State bits + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 4-7 reserved + /* Битовое поле PAGEWAIT, ширина 4 бит; данные PAGEWAIT. */ + Uint16 PAGEWAIT:4; // 8-11 Flash Paged Read Wait State bits + /* Битовое поле rsvd2, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:4; // 12-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FBANKWAIT_REG в одной области памяти. */ +union FBANKWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FBANKWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FBANKWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* OTP Read Access Wait State Register bit definitions */ +/* Описывает структуру FOTPWAIT_BITS; порядок полей определяет расположение данных. */ +struct FOTPWAIT_BITS { // bit description + /* Битовое поле OTPWAIT, ширина 5 бит; данные OTPWAIT. */ + Uint16 OTPWAIT:5; // 0-4 OTP Read Wait State bits + /* Битовое поле rsvd, ширина 11 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:11; // 5-15 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Allow access to the bit fields or entire register */ +/* Объединяет несколько представлений FOTPWAIT_REG в одной области памяти. */ +union FOTPWAIT_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру FOTPWAIT_BITS bit;; порядок полей определяет расположение данных. */ + struct FOTPWAIT_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +/* Описывает структуру FLASH_REGS; порядок полей определяет расположение данных. */ +struct FLASH_REGS { + /* Объединяет несколько представлений FOPT_REG FOPT; в одной области памяти. */ + union FOPT_REG FOPT; // Option Register + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1; // reserved + /* Объединяет несколько представлений FPWR_REG FPWR; в одной области памяти. */ + union FPWR_REG FPWR; // Power Modes Register + /* Объединяет несколько представлений FSTATUS_REG FSTATUS; в одной области памяти. */ + union FSTATUS_REG FSTATUS; // Status Register + /* Объединяет несколько представлений FSTDBYWAIT_REG FSTDBYWAIT; в одной области памяти. */ + union FSTDBYWAIT_REG FSTDBYWAIT; // Pump/Bank Sleep to Standby Wait State Register + /* Объединяет несколько представлений FACTIVEWAIT_REG FACTIVEWAIT; в одной области памяти. */ + union FACTIVEWAIT_REG FACTIVEWAIT; // Pump/Bank Standby to Active Wait State Register + /* Объединяет несколько представлений FBANKWAIT_REG FBANKWAIT; в одной области памяти. */ + union FBANKWAIT_REG FBANKWAIT; // Bank Read Access Wait State Register + /* Объединяет несколько представлений FOTPWAIT_REG FOTPWAIT; в одной области памяти. */ + union FOTPWAIT_REG FOTPWAIT; // OTP Read Access Wait State Register +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// System Control External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct SYS_CTRL_REGS SysCtrlRegs;; порядок элементов сохраняется. */ +extern volatile struct SYS_CTRL_REGS SysCtrlRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct CSM_REGS CsmRegs;; порядок элементов сохраняется. */ +extern volatile struct CSM_REGS CsmRegs; +/* Продолжает список аргументов, полей или выражение extern volatile struct CSM_PWL CsmPwl;; порядок элементов сохраняется. */ +extern volatile struct CSM_PWL CsmPwl; +/* Продолжает список аргументов, полей или выражение extern volatile struct FLASH_REGS FlashRegs;; порядок элементов сохраняется. */ +extern volatile struct FLASH_REGS FlashRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_SYS_CTRL_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h new file mode 100644 index 0000000..91eca18 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_XIntrupt.h @@ -0,0 +1,127 @@ +/* Поставляемое TI описание XIntrupt для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:52:39 $ +//########################################################################### +// +// FILE: DSP2833x_XIntrupt.h +// +// TITLE: DSP2833x Device External Interrupt Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_XINTRUPT_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_XINTRUPT_H +/* Определяет защитный символ или переключатель DSP2833x_XINTRUPT_H для последующей компиляции. */ +#define DSP2833x_XINTRUPT_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +//--------------------------------------------------------------------------- + +/* Описывает структуру XINTCR_BITS; порядок полей определяет расположение данных. */ +struct XINTCR_BITS { + /* Битовое поле ENABLE, ширина 1 бит; разрешение. */ + Uint16 ENABLE:1; // 0 enable/disable + /* Битовое поле rsvd1, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:1; // 1 reserved + /* Битовое поле POLARITY, ширина 2 бит; данные POLARITY. */ + Uint16 POLARITY:2; // 3:2 pos/neg, both triggered + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; //15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XINTCR_REG в одной области памяти. */ +union XINTCR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XINTCR_BITS bit;; порядок полей определяет расположение данных. */ + struct XINTCR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру XNMICR_BITS; порядок полей определяет расположение данных. */ +struct XNMICR_BITS { + /* Битовое поле ENABLE, ширина 1 бит; разрешение. */ + Uint16 ENABLE:1; // 0 enable/disable + /* Битовое поле SELECT, ширина 1 бит; выбор. */ + Uint16 SELECT:1; // 1 Timer 1 or XNMI connected to int13 + /* Битовое поле POLARITY, ширина 2 бит; данные POLARITY. */ + Uint16 POLARITY:2; // 3:2 pos/neg, or both triggered + /* Битовое поле rsvd2, ширина 12 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:12; // 15:4 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XNMICR_REG в одной области памяти. */ +union XNMICR_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XNMICR_BITS bit;; порядок полей определяет расположение данных. */ + struct XNMICR_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + + + +//--------------------------------------------------------------------------- +// External Interrupt Register File: +// +/* Описывает структуру XINTRUPT_REGS; порядок полей определяет расположение данных. */ +struct XINTRUPT_REGS { + /* Объединяет несколько представлений XINTCR_REG XINT1CR; в одной области памяти. */ + union XINTCR_REG XINT1CR; + /* Объединяет несколько представлений XINTCR_REG XINT2CR; в одной области памяти. */ + union XINTCR_REG XINT2CR; + /* Объединяет несколько представлений XINTCR_REG XINT3CR; в одной области памяти. */ + union XINTCR_REG XINT3CR; + /* Объединяет несколько представлений XINTCR_REG XINT4CR; в одной области памяти. */ + union XINTCR_REG XINT4CR; + /* Объединяет несколько представлений XINTCR_REG XINT5CR; в одной области памяти. */ + union XINTCR_REG XINT5CR; + /* Объединяет несколько представлений XINTCR_REG XINT6CR; в одной области памяти. */ + union XINTCR_REG XINT6CR; + /* Объединяет несколько представлений XINTCR_REG XINT7CR; в одной области памяти. */ + union XINTCR_REG XINT7CR; + /* Объединяет несколько представлений XNMICR_REG XNMICR; в одной области памяти. */ + union XNMICR_REG XNMICR; + /* Объявляет XINT1CTR — данные XINT1CTR. */ + Uint16 XINT1CTR; + /* Объявляет XINT2CTR — данные XINT2CTR. */ + Uint16 XINT2CTR; + /* Объявляет rsvd — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd[5]; + /* Объявляет XNMICTR — данные XNMICTR. */ + Uint16 XNMICTR; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// External Interrupt References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct XINTRUPT_REGS XIntruptRegs;; порядок элементов сохраняется. */ +extern volatile struct XINTRUPT_REGS XIntruptRegs; + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_XINTF_H definition + +//=========================================================================== +// End of file. +//=========================================================================== + diff --git a/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h new file mode 100644 index 0000000..63686b1 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/include/DSP2833x_Xintf.h @@ -0,0 +1,197 @@ +/* Поставляемое TI описание Xintf для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 20, 2007 16:34:08 $ +//########################################################################### +// +// FILE: DSP2833x_Xintf.h +// +// TITLE: DSP2833x Device External Interface Register Definitions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Начинает условие: DSP2833x_XINTF_H ещё не определён; защищает повторное включение или задаёт значение сборки. */ +#ifndef DSP2833x_XINTF_H +/* Определяет защитный символ или переключатель DSP2833x_XINTF_H для последующей компиляции. */ +#define DSP2833x_XINTF_H + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Задаёт C-соглашение о связывании имён при включении заголовка из C++. */ +extern "C" { +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + +// XINTF timing register bit definitions: +/* Описывает структуру XTIMING_BITS; порядок полей определяет расположение данных. */ +struct XTIMING_BITS { // bits description + /* Битовое поле XWRTRAIL, ширина 2 бит; данные XWRTRAIL. */ + Uint16 XWRTRAIL:2; // 1:0 Write access trail timing + /* Битовое поле XWRACTIVE, ширина 3 бит; данные XWRACTIVE. */ + Uint16 XWRACTIVE:3; // 4:2 Write access active timing + /* Битовое поле XWRLEAD, ширина 2 бит; данные XWRLEAD. */ + Uint16 XWRLEAD:2; // 6:5 Write access lead timing + /* Битовое поле XRDTRAIL, ширина 2 бит; данные XRDTRAIL. */ + Uint16 XRDTRAIL:2; // 8:7 Read access trail timing + /* Битовое поле XRDACTIVE, ширина 3 бит; данные XRDACTIVE. */ + Uint16 XRDACTIVE:3; // 11:9 Read access active timing + /* Битовое поле XRDLEAD, ширина 2 бит; данные XRDLEAD. */ + Uint16 XRDLEAD:2; // 13:12 Read access lead timing + /* Битовое поле USEREADY, ширина 1 бит; данные USEREADY. */ + Uint16 USEREADY:1; // 14 Extend access using HW waitstates + /* Битовое поле READYMODE, ширина 1 бит; данные READYMODE. */ + Uint16 READYMODE:1; // 15 Ready mode + /* Битовое поле XSIZE, ширина 2 бит; данные XSIZE. */ + Uint16 XSIZE:2; // 17:16 XINTF bus width - must be written as 11b + /* Битовое поле rsvd1, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:4; // 21:18 reserved + /* Битовое поле X2TIMING, ширина 1 бит; данные X2TIMING. */ + Uint16 X2TIMING:1; // 22 Double lead/active/trail timing + /* Битовое поле rsvd3, ширина 9 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:9; // 31:23 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XTIMING_REG в одной области памяти. */ +union XTIMING_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру XTIMING_BITS bit;; порядок полей определяет расположение данных. */ + struct XTIMING_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XINTF control register bit definitions: +/* Описывает структуру XINTCNF2_BITS; порядок полей определяет расположение данных. */ +struct XINTCNF2_BITS { // bits description + /* Битовое поле WRBUFF, ширина 2 бит; данные WRBUFF. */ + Uint16 WRBUFF:2; // 1:0 Write buffer depth + /* Битовое поле CLKMODE, ширина 1 бит; данные CLKMODE. */ + Uint16 CLKMODE:1; // 2 Ratio for XCLKOUT with respect to XTIMCLK + /* Битовое поле CLKOFF, ширина 1 бит; данные CLKOFF. */ + Uint16 CLKOFF:1; // 3 Disable XCLKOUT + /* Битовое поле rsvd1, ширина 2 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:2; // 5:4 reserved + /* Битовое поле WLEVEL, ширина 2 бит; данные WLEVEL. */ + Uint16 WLEVEL:2; // 7:6 Current level of the write buffer + /* Битовое поле rsvd2, ширина 1 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd2:1; // 8 reserved + /* Битовое поле HOLD, ширина 1 бит; данные HOLD. */ + Uint16 HOLD:1; // 9 Hold enable/disable + /* Битовое поле HOLDS, ширина 1 бит; данные HOLDS. */ + Uint16 HOLDS:1; // 10 Current state of HOLDn input + /* Битовое поле HOLDAS, ширина 1 бит; данные HOLDAS. */ + Uint16 HOLDAS:1; // 11 Current state of HOLDAn output + /* Битовое поле rsvd3, ширина 4 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd3:4; // 15:12 reserved + /* Битовое поле XTIMCLK, ширина 3 бит; данные XTIMCLK. */ + Uint16 XTIMCLK:3; // 18:16 Ratio for XTIMCLK + /* Битовое поле rsvd4, ширина 13 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4:13; // 31:19 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XINTCNF2_REG в одной области памяти. */ +union XINTCNF2_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint32 all; + /* Описывает структуру XINTCNF2_BITS bit;; порядок полей определяет расположение данных. */ + struct XINTCNF2_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +// XINTF bank switching register bit definitions: +/* Описывает структуру XBANK_BITS; порядок полей определяет расположение данных. */ +struct XBANK_BITS { // bits description + /* Битовое поле BANK, ширина 3 бит; данные BANK. */ + Uint16 BANK:3; // 2:0 Zone for which banking is enabled + /* Битовое поле BCYC, ширина 3 бит; данные BCYC. */ + Uint16 BCYC:3; // 5:3 XTIMCLK cycles to add + /* Битовое поле rsvd, ширина 10 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd:10; // 15:6 reserved +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XBANK_REG в одной области памяти. */ +union XBANK_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XBANK_BITS bit;; порядок полей определяет расположение данных. */ + struct XBANK_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Описывает структуру XRESET_BITS; порядок полей определяет расположение данных. */ +struct XRESET_BITS { + /* Битовое поле XHARDRESET, ширина 1 бит; данные XHARDRESET. */ + Uint16 XHARDRESET:1; + /* Битовое поле rsvd1, ширина 15 бит; зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd1:15; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +/* Объединяет несколько представлений XRESET_REG в одной области памяти. */ +union XRESET_REG { + /* Объявляет all — представление регистра целым словом без разбиения на битовые поля. */ + Uint16 all; + /* Описывает структуру XBANK_BITS bit;; порядок полей определяет расположение данных. */ + struct XBANK_BITS bit; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + + +//--------------------------------------------------------------------------- +// XINTF Register File: +// +/* Описывает структуру XINTF_REGS; порядок полей определяет расположение данных. */ +struct XINTF_REGS { + /* Объединяет несколько представлений XTIMING_REG XTIMING0; в одной области памяти. */ + union XTIMING_REG XTIMING0; + /* Объявляет rsvd1 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd1[5]; + /* Объединяет несколько представлений XTIMING_REG XTIMING6; в одной области памяти. */ + union XTIMING_REG XTIMING6; + /* Объединяет несколько представлений XTIMING_REG XTIMING7; в одной области памяти. */ + union XTIMING_REG XTIMING7; + /* Объявляет rsvd2 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd2[2]; + /* Объединяет несколько представлений XINTCNF2_REG XINTCNF2; в одной области памяти. */ + union XINTCNF2_REG XINTCNF2; + /* Объявляет rsvd3 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint32 rsvd3; + /* Объединяет несколько представлений XBANK_REG XBANK; в одной области памяти. */ + union XBANK_REG XBANK; + /* Объявляет rsvd4 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd4; + /* Объявляет XREVISION — данные XREVISION. */ + Uint16 XREVISION; + /* Объявляет rsvd5 — зарезервированные биты для сохранения аппаратного расположения. */ + Uint16 rsvd5[2]; + /* Объединяет несколько представлений XRESET_REG XRESET; в одной области памяти. */ + union XRESET_REG XRESET; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +}; + +//--------------------------------------------------------------------------- +// XINTF External References & Function Declarations: +// +/* Продолжает список аргументов, полей или выражение extern volatile struct XINTF_REGS XintfRegs;; порядок элементов сохраняется. */ +extern volatile struct XINTF_REGS XintfRegs; + + +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} +#endif /* extern "C" */ /* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ + +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif // end of DSP2833x_XINTF_H definition + +//=========================================================================== +// No more. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm new file mode 100644 index 0000000..1de162b --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm @@ -0,0 +1,51 @@ +; Поставляемое ti описание adc_cal для семейства c2833x. Пояснения в UTF-8. +;; TI File $Revision: /main/1 $ +;; Checkin $Date: July 30, 2007 10:29:23 $ +;;########################################################################### +;; +;; FILE: ADC_cal.asm +;; +;; TITLE: 2833x Boot Rom ADC Cal routine. +;; +;; Functions: +;; +;; _ADC_cal - Copies device specific calibration data into ADCREFSEL and ADCOFFTRIM registers +;; Notes: +;; +;;########################################################################### +;; $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +;; $Release Date: August 1, 2008 $ +;;########################################################################### + + ; Экспортирует символ для связывания с C-кодом. Операция: .def _ADC_cal. + .def _ADC_cal + ; Задаёт текстовый псевдоним константы для ассемблера. Операция: .asg "0x711C", ADCREFSEL_LOC. + .asg "0x711C", ADCREFSEL_LOC + +;----------------------------------------------- +; _ADC_cal +;----------------------------------------------- +;----------------------------------------------- +; This is the ADC cal routine.This routine is programmed into +; reserved memory by the factory. 0xAAAA and 0xBBBB are place- +; holders for calibration data. +;The actual values programmed by TI are device specific. +; +; This function assumes that the clocks have been +; enabled to the ADC module. +;----------------------------------------------- + + ; Выбирает секцию объектного файла для следующих инструкций. Операция: .sect ".adc_cal". + .sect ".adc_cal" + +; Объявляет метку _ADC_cal для перехода или вызова. Операция: _ADC_cal. +_ADC_cal + ; Загружает регистр страниц данных DP для доступа к указанной области. Операция: MOVW DP, #ADCREFSEL_LOC >> 6. + MOVW DP, #ADCREFSEL_LOC >> 6 + ; Переносит операнд в регистр или ячейку назначения. Операция: MOV @28, #0xAAAA. + MOV @28, #0xAAAA ; actual value may not be 0xAAAA + ; Переносит операнд в регистр или ячейку назначения. Операция: MOV @29, #0xBBBB. + MOV @29, #0xBBBB ; actual value may not be 0xBBBB + ; Возвращает управление вызывающему коду через длинный адрес возврата. Операция: LRETR. + LRETR +;eof ---------- diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c new file mode 100644 index 0000000..def985e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_CpuTimers.c @@ -0,0 +1,161 @@ +/* Поставляемое TI описание CpuTimers для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/3 $ +// Checkin $Date: March 16, 2007 08:37:30 $ +//########################################################################### +// +// FILE: DSP2833x_CpuTimers.c +// +// TITLE: CPU 32-bit Timers Initialization & Support Functions. +// +// NOTES: CpuTimer1 and CpuTimer2 are reserved for use with DSP BIOS and +// other realtime operating systems. +// +// Do not use these two timers in your application if you ever plan +// on integrating DSP-BIOS or another realtime OS. +// +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // Examples Include File + +/* Описывает структуру CPUTIMER_VARS CpuTimer0;; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS CpuTimer0; + +// CpuTimer 1 and CpuTimer2 are used by DSP BIOS & other RTOS. Comment out if using DSP BIOS or other RTOS. +/* Описывает структуру CPUTIMER_VARS CpuTimer1;; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS CpuTimer1; +/* Описывает структуру CPUTIMER_VARS CpuTimer2;; порядок полей определяет расположение данных. */ +struct CPUTIMER_VARS CpuTimer2; + +//--------------------------------------------------------------------------- +// InitCpuTimers: +//--------------------------------------------------------------------------- +// This function initializes all three CPU timers to a known state. +// +/* Начинает функцию InitCpuTimers; назначение модуля — поставляемое TI описание CpuTimers для семейства C2833x. */ +void InitCpuTimers(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + // CPU Timer 0 + // Initialize address pointers to respective timer registers: + /* Записывает CpuTimer0.RegsAddr значением &CpuTimer0Regs; данные RegsAddr. */ + CpuTimer0.RegsAddr = &CpuTimer0Regs; + // Initialize timer period to maximum: + /* Записывает CpuTimer0Regs.PRD.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer0Regs.PRD.all = 0xFFFFFFFF; + // Initialize pre-scale counter to divide by 1 (SYSCLKOUT): + /* Записывает CpuTimer0Regs.TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer0Regs.TPR.all = 0; + /* Записывает CpuTimer0Regs.TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer0Regs.TPRH.all = 0; + // Make sure timer is stopped: + /* Записывает CpuTimer0Regs.TCR.bit.TSS значением 1; данные TSS. */ + CpuTimer0Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + /* Записывает CpuTimer0Regs.TCR.bit.TRB значением 1; данные TRB. */ + CpuTimer0Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + /* Записывает CpuTimer0.InterruptCount значением 0; прерывание число. */ + CpuTimer0.InterruptCount = 0; + + +// CpuTimer 1 and CpuTimer2 are reserved for DSP BIOS & other RTOS +// Do not use these two timers if you ever plan on integrating +// DSP-BIOS or another realtime OS. +// +// Initialize address pointers to respective timer registers: + /* Записывает CpuTimer1.RegsAddr значением &CpuTimer1Regs; данные RegsAddr. */ + CpuTimer1.RegsAddr = &CpuTimer1Regs; + /* Записывает CpuTimer2.RegsAddr значением &CpuTimer2Regs; данные RegsAddr. */ + CpuTimer2.RegsAddr = &CpuTimer2Regs; + // Initialize timer period to maximum: + /* Записывает CpuTimer1Regs.PRD.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer1Regs.PRD.all = 0xFFFFFFFF; + /* Записывает CpuTimer2Regs.PRD.all значением 0xFFFFFFFF; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer2Regs.PRD.all = 0xFFFFFFFF; + // Initialize pre-scale counter to divide by 1 (SYSCLKOUT): + /* Записывает CpuTimer1Regs.TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer1Regs.TPR.all = 0; + /* Записывает CpuTimer1Regs.TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer1Regs.TPRH.all = 0; + /* Записывает CpuTimer2Regs.TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer2Regs.TPR.all = 0; + /* Записывает CpuTimer2Regs.TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + CpuTimer2Regs.TPRH.all = 0; + // Make sure timers are stopped: + /* Записывает CpuTimer1Regs.TCR.bit.TSS значением 1; данные TSS. */ + CpuTimer1Regs.TCR.bit.TSS = 1; + /* Записывает CpuTimer2Regs.TCR.bit.TSS значением 1; данные TSS. */ + CpuTimer2Regs.TCR.bit.TSS = 1; + // Reload all counter register with period value: + /* Записывает CpuTimer1Regs.TCR.bit.TRB значением 1; данные TRB. */ + CpuTimer1Regs.TCR.bit.TRB = 1; + /* Записывает CpuTimer2Regs.TCR.bit.TRB значением 1; данные TRB. */ + CpuTimer2Regs.TCR.bit.TRB = 1; + // Reset interrupt counters: + /* Записывает CpuTimer1.InterruptCount значением 0; прерывание число. */ + CpuTimer1.InterruptCount = 0; + /* Записывает CpuTimer2.InterruptCount значением 0; прерывание число. */ + CpuTimer2.InterruptCount = 0; + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// ConfigCpuTimer: +//--------------------------------------------------------------------------- +// This function initializes the selected timer to the period specified +// by the "Freq" and "Period" parameters. The "Freq" is entered as "MHz" +// and the period in "uSeconds". The timer is held in the stopped state +// after configuration. +// +/* Начинает функцию ConfigCpuTimer; назначение модуля — поставляемое TI описание CpuTimers для семейства C2833x. */ +void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет temp — данные temp. */ + Uint32 temp; + + // Initialize timer period: + /* Записывает Timer->CPUFreqInMHz значением Freq; таймер CPU Freq In M Hz. */ + Timer->CPUFreqInMHz = Freq; + /* Записывает Timer->PeriodInUSec значением Period; таймер период In U Sec. */ + Timer->PeriodInUSec = Period; + /* Записывает temp значением (long) (Freq * Period); данные temp. */ + temp = (long) (Freq * Period); + /* Записывает Timer->RegsAddr->PRD.all значением temp; представление регистра целым словом без разбиения на битовые поля. */ + Timer->RegsAddr->PRD.all = temp; + + // Set pre-scale counter to divide by 1 (SYSCLKOUT): + /* Записывает Timer->RegsAddr->TPR.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + Timer->RegsAddr->TPR.all = 0; + /* Записывает Timer->RegsAddr->TPRH.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + Timer->RegsAddr->TPRH.all = 0; + + // Initialize timer control register: + /* Записывает Timer->RegsAddr->TCR.bit.TSS значением 1; данные TSS. */ + Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 = Start/Restart Timer + /* Записывает Timer->RegsAddr->TCR.bit.TRB значением 1; данные TRB. */ + Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer + /* Записывает Timer->RegsAddr->TCR.bit.SOFT значением 0; данные SOFT. */ + Timer->RegsAddr->TCR.bit.SOFT = 0; + /* Записывает Timer->RegsAddr->TCR.bit.FREE значением 0; данные FREE. */ + Timer->RegsAddr->TCR.bit.FREE = 0; // Timer Free Run Disabled + /* Записывает Timer->RegsAddr->TCR.bit.TIE значением 1; данные TIE. */ + Timer->RegsAddr->TCR.bit.TIE = 1; // 0 = Disable/ 1 = Enable Timer Interrupt + + // Reset interrupt counter: + /* Записывает Timer->InterruptCount значением 0; таймер прерывание число. */ + Timer->InterruptCount = 0; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c new file mode 100644 index 0000000..74a8a7e --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c @@ -0,0 +1,746 @@ +/* Поставляемое TI описание GlobalVariableDefs для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/4 $ +// Checkin $Date: June 2, 2008 11:12:33 $ +//########################################################################### +// +// FILE: DSP2833x_GlobalVariableDefs.c +// +// TITLE: DSP2833x Global Variables and Data Section Pragmas. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File + +//--------------------------------------------------------------------------- +// Define Global Peripheral Variables: +// +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("AdcRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("AdcRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(AdcRegs,"AdcRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(AdcRegs,"AdcRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ADC_REGS AdcRegs;; порядок элементов сохраняется. */ +volatile struct ADC_REGS AdcRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("AdcMirrorFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("AdcMirrorFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(AdcMirror,"AdcMirrorFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(AdcMirror,"AdcMirrorFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ADC_RESULT_MIRROR_REGS AdcMirror;; порядок элементов сохраняется. */ +volatile struct ADC_RESULT_MIRROR_REGS AdcMirror; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CpuTimer0RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CpuTimer0RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CpuTimer0Regs,"CpuTimer0RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CpuTimer0Regs,"CpuTimer0RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS CpuTimer0Regs;; порядок элементов сохраняется. */ +volatile struct CPUTIMER_REGS CpuTimer0Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CpuTimer1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CpuTimer1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CpuTimer1Regs,"CpuTimer1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CpuTimer1Regs,"CpuTimer1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS CpuTimer1Regs;; порядок элементов сохраняется. */ +volatile struct CPUTIMER_REGS CpuTimer1Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CpuTimer2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CpuTimer2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CpuTimer2Regs,"CpuTimer2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CpuTimer2Regs,"CpuTimer2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CPUTIMER_REGS CpuTimer2Regs;; порядок элементов сохраняется. */ +volatile struct CPUTIMER_REGS CpuTimer2Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CsmPwlFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CsmPwlFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CsmPwl,"CsmPwlFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CsmPwl,"CsmPwlFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CSM_PWL CsmPwl;; порядок элементов сохраняется. */ +volatile struct CSM_PWL CsmPwl; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("CsmRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("CsmRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(CsmRegs,"CsmRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(CsmRegs,"CsmRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct CSM_REGS CsmRegs;; порядок элементов сохраняется. */ +volatile struct CSM_REGS CsmRegs; + + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("DevEmuRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("DevEmuRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(DevEmuRegs,"DevEmuRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(DevEmuRegs,"DevEmuRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct DEV_EMU_REGS DevEmuRegs;; порядок элементов сохраняется. */ +volatile struct DEV_EMU_REGS DevEmuRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("DmaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("DmaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(DmaRegs,"DmaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(DmaRegs,"DmaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct DMA_REGS DmaRegs;; порядок элементов сохраняется. */ +volatile struct DMA_REGS DmaRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaRegs,"ECanaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaRegs,"ECanaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_REGS ECanaRegs;; порядок элементов сохраняется. */ +volatile struct ECAN_REGS ECanaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaMboxesFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaMboxesFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaMboxes,"ECanaMboxesFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaMboxes,"ECanaMboxesFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_MBOXES ECanaMboxes;; порядок элементов сохраняется. */ +volatile struct ECAN_MBOXES ECanaMboxes; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaLAMRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaLAMRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaLAMRegs,"ECanaLAMRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaLAMRegs,"ECanaLAMRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct LAM_REGS ECanaLAMRegs;; порядок элементов сохраняется. */ +volatile struct LAM_REGS ECanaLAMRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaMOTSRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaMOTSRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaMOTSRegs,"ECanaMOTSRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaMOTSRegs,"ECanaMOTSRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTS_REGS ECanaMOTSRegs;; порядок элементов сохраняется. */ +volatile struct MOTS_REGS ECanaMOTSRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanaMOTORegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanaMOTORegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanaMOTORegs,"ECanaMOTORegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanaMOTORegs,"ECanaMOTORegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTO_REGS ECanaMOTORegs;; порядок элементов сохраняется. */ +volatile struct MOTO_REGS ECanaMOTORegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbRegs,"ECanbRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbRegs,"ECanbRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_REGS ECanbRegs;; порядок элементов сохраняется. */ +volatile struct ECAN_REGS ECanbRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbMboxesFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbMboxesFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbMboxes,"ECanbMboxesFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbMboxes,"ECanbMboxesFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAN_MBOXES ECanbMboxes;; порядок элементов сохраняется. */ +volatile struct ECAN_MBOXES ECanbMboxes; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbLAMRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbLAMRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbLAMRegs,"ECanbLAMRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbLAMRegs,"ECanbLAMRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct LAM_REGS ECanbLAMRegs;; порядок элементов сохраняется. */ +volatile struct LAM_REGS ECanbLAMRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbMOTSRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbMOTSRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbMOTSRegs,"ECanbMOTSRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbMOTSRegs,"ECanbMOTSRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTS_REGS ECanbMOTSRegs;; порядок элементов сохраняется. */ +volatile struct MOTS_REGS ECanbMOTSRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECanbMOTORegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECanbMOTORegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECanbMOTORegs,"ECanbMOTORegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECanbMOTORegs,"ECanbMOTORegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MOTO_REGS ECanbMOTORegs;; порядок элементов сохраняется. */ +volatile struct MOTO_REGS ECanbMOTORegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm1Regs,"EPwm1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm1Regs,"EPwm1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm1Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm1Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm2Regs,"EPwm2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm2Regs,"EPwm2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm2Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm2Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm3RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm3RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm3Regs,"EPwm3RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm3Regs,"EPwm3RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm3Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm3Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm4RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm4RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm4Regs,"EPwm4RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm4Regs,"EPwm4RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm4Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm4Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm5RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm5RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm5Regs,"EPwm5RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm5Regs,"EPwm5RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm5Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm5Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EPwm6RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EPwm6RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EPwm6Regs,"EPwm6RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EPwm6Regs,"EPwm6RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EPWM_REGS EPwm6Regs;; порядок элементов сохраняется. */ +volatile struct EPWM_REGS EPwm6Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap1Regs,"ECap1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap1Regs,"ECap1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap1Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap1Regs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap2Regs,"ECap2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap2Regs,"ECap2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap2Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap2Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap3RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap3RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap3Regs,"ECap3RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap3Regs,"ECap3RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap3Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap3Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap4RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap4RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap4Regs,"ECap4RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap4Regs,"ECap4RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap4Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap4Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap5RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap5RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap5Regs,"ECap5RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap5Regs,"ECap5RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap5Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap5Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ECap6RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ECap6RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ECap6Regs,"ECap6RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ECap6Regs,"ECap6RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct ECAP_REGS ECap6Regs;; порядок элементов сохраняется. */ +volatile struct ECAP_REGS ECap6Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EQep1RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EQep1RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EQep1Regs,"EQep1RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EQep1Regs,"EQep1RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EQEP_REGS EQep1Regs;; порядок элементов сохраняется. */ +volatile struct EQEP_REGS EQep1Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("EQep2RegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("EQep2RegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(EQep2Regs,"EQep2RegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(EQep2Regs,"EQep2RegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct EQEP_REGS EQep2Regs;; порядок элементов сохраняется. */ +volatile struct EQEP_REGS EQep2Regs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("GpioCtrlRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("GpioCtrlRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(GpioCtrlRegs,"GpioCtrlRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(GpioCtrlRegs,"GpioCtrlRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct GPIO_CTRL_REGS GpioCtrlRegs;; порядок элементов сохраняется. */ +volatile struct GPIO_CTRL_REGS GpioCtrlRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("GpioDataRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("GpioDataRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(GpioDataRegs,"GpioDataRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(GpioDataRegs,"GpioDataRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct GPIO_DATA_REGS GpioDataRegs;; порядок элементов сохраняется. */ +volatile struct GPIO_DATA_REGS GpioDataRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("GpioIntRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("GpioIntRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(GpioIntRegs,"GpioIntRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(GpioIntRegs,"GpioIntRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct GPIO_INT_REGS GpioIntRegs;; порядок элементов сохраняется. */ +volatile struct GPIO_INT_REGS GpioIntRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("I2caRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("I2caRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(I2caRegs,"I2caRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(I2caRegs,"I2caRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct I2C_REGS I2caRegs;; порядок элементов сохраняется. */ +volatile struct I2C_REGS I2caRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("McbspaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("McbspaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(McbspaRegs,"McbspaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(McbspaRegs,"McbspaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MCBSP_REGS McbspaRegs;; порядок элементов сохраняется. */ +volatile struct MCBSP_REGS McbspaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("McbspbRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("McbspbRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(McbspbRegs,"McbspbRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(McbspbRegs,"McbspbRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct MCBSP_REGS McbspbRegs;; порядок элементов сохраняется. */ +volatile struct MCBSP_REGS McbspbRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("PartIdRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("PartIdRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(PartIdRegs,"PartIdRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(PartIdRegs,"PartIdRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct PARTID_REGS PartIdRegs;; порядок элементов сохраняется. */ +volatile struct PARTID_REGS PartIdRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("PieCtrlRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("PieCtrlRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(PieCtrlRegs,"PieCtrlRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(PieCtrlRegs,"PieCtrlRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct PIE_CTRL_REGS PieCtrlRegs;; порядок элементов сохраняется. */ +volatile struct PIE_CTRL_REGS PieCtrlRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("PieVectTableFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("PieVectTableFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(PieVectTable,"PieVectTableFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(PieVectTable,"PieVectTableFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Описывает структуру PIE_VECT_TABLE PieVectTable;; порядок полей определяет расположение данных. */ +struct PIE_VECT_TABLE PieVectTable; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("SciaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("SciaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(SciaRegs,"SciaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(SciaRegs,"SciaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SCI_REGS SciaRegs;; порядок элементов сохраняется. */ +volatile struct SCI_REGS SciaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ScibRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ScibRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ScibRegs,"ScibRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ScibRegs,"ScibRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SCI_REGS ScibRegs;; порядок элементов сохраняется. */ +volatile struct SCI_REGS ScibRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("ScicRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("ScicRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(ScicRegs,"ScicRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(ScicRegs,"ScicRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SCI_REGS ScicRegs;; порядок элементов сохраняется. */ +volatile struct SCI_REGS ScicRegs; + + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("SpiaRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("SpiaRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(SpiaRegs,"SpiaRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(SpiaRegs,"SpiaRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SPI_REGS SpiaRegs;; порядок элементов сохраняется. */ +volatile struct SPI_REGS SpiaRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("SysCtrlRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("SysCtrlRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(SysCtrlRegs,"SysCtrlRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(SysCtrlRegs,"SysCtrlRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct SYS_CTRL_REGS SysCtrlRegs;; порядок элементов сохраняется. */ +volatile struct SYS_CTRL_REGS SysCtrlRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("FlashRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("FlashRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(FlashRegs,"FlashRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(FlashRegs,"FlashRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct FLASH_REGS FlashRegs;; порядок элементов сохраняется. */ +volatile struct FLASH_REGS FlashRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("XIntruptRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("XIntruptRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(XIntruptRegs,"XIntruptRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(XIntruptRegs,"XIntruptRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct XINTRUPT_REGS XIntruptRegs;; порядок элементов сохраняется. */ +volatile struct XINTRUPT_REGS XIntruptRegs; + +//---------------------------------------- +/* Включает следующий блок только при определённом символе __cplusplus. */ +#ifdef __cplusplus +/* Указание компилятору DATA_SECTION("XintfRegsFile"): размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION("XintfRegsFile") +/* Выбирает альтернативный блок текущего условия компиляции. */ +#else +/* Указание компилятору DATA_SECTION(XintfRegs,"XintfRegsFile");: размещение данных или настройка обработки объявлений. */ +#pragma DATA_SECTION(XintfRegs,"XintfRegsFile"); +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Продолжает список аргументов, полей или выражение volatile struct XINTF_REGS XintfRegs;; порядок элементов сохраняется. */ +volatile struct XINTF_REGS XintfRegs; + + + +//=========================================================================== +// End of file. +//=========================================================================== + + + + + + + + + diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c new file mode 100644 index 0000000..0ca4201 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_PieCtrl.c @@ -0,0 +1,121 @@ +/* Поставляемое TI описание PieCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/1 $ +// Checkin $Date: August 18, 2006 13:46:35 $ +//########################################################################### +// +// FILE: DSP2833x_PieCtrl.c +// +// TITLE: DSP2833x Device PIE Control Register Initialization Functions. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // DSP2833x Examples Include File + +//--------------------------------------------------------------------------- +// InitPieCtrl: +//--------------------------------------------------------------------------- +// This function initializes the PIE control registers to a known state. +// +/* Начинает функцию InitPieCtrl; назначение модуля — поставляемое TI описание PieCtrl для семейства C2833x. */ +void InitPieCtrl(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + // Disable Interrupts at the CPU level: + /* Запрет маскируемых прерываний ядра. */ + DINT; + + // Disable the PIE + /* Записывает PieCtrlRegs.PIECTRL.bit.ENPIE значением 0; данные ENPIE. */ + PieCtrlRegs.PIECTRL.bit.ENPIE = 0; + + // Clear all PIEIER registers: + /* Записывает PieCtrlRegs.PIEIER1.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER1.all = 0; + /* Записывает PieCtrlRegs.PIEIER2.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER2.all = 0; + /* Записывает PieCtrlRegs.PIEIER3.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER3.all = 0; + /* Записывает PieCtrlRegs.PIEIER4.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER4.all = 0; + /* Записывает PieCtrlRegs.PIEIER5.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER5.all = 0; + /* Записывает PieCtrlRegs.PIEIER6.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER6.all = 0; + /* Записывает PieCtrlRegs.PIEIER7.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER7.all = 0; + /* Записывает PieCtrlRegs.PIEIER8.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER8.all = 0; + /* Записывает PieCtrlRegs.PIEIER9.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER9.all = 0; + /* Записывает PieCtrlRegs.PIEIER10.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER10.all = 0; + /* Записывает PieCtrlRegs.PIEIER11.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER11.all = 0; + /* Записывает PieCtrlRegs.PIEIER12.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIER12.all = 0; + + // Clear all PIEIFR registers: + /* Записывает PieCtrlRegs.PIEIFR1.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR1.all = 0; + /* Записывает PieCtrlRegs.PIEIFR2.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR2.all = 0; + /* Записывает PieCtrlRegs.PIEIFR3.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR3.all = 0; + /* Записывает PieCtrlRegs.PIEIFR4.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR4.all = 0; + /* Записывает PieCtrlRegs.PIEIFR5.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR5.all = 0; + /* Записывает PieCtrlRegs.PIEIFR6.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR6.all = 0; + /* Записывает PieCtrlRegs.PIEIFR7.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR7.all = 0; + /* Записывает PieCtrlRegs.PIEIFR8.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR8.all = 0; + /* Записывает PieCtrlRegs.PIEIFR9.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR9.all = 0; + /* Записывает PieCtrlRegs.PIEIFR10.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR10.all = 0; + /* Записывает PieCtrlRegs.PIEIFR11.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR11.all = 0; + /* Записывает PieCtrlRegs.PIEIFR12.all значением 0; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEIFR12.all = 0; + + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// EnableInterrupts: +//--------------------------------------------------------------------------- +// This function enables the PIE module and CPU interrupts +// +/* Начинает функцию EnableInterrupts; назначение модуля — поставляемое TI описание PieCtrl для семейства C2833x. */ +void EnableInterrupts() +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + + // Enable the PIE + /* Записывает PieCtrlRegs.PIECTRL.bit.ENPIE значением 1; данные ENPIE. */ + PieCtrlRegs.PIECTRL.bit.ENPIE = 1; + + // Enables PIE to drive a pulse into the CPU + /* Записывает PieCtrlRegs.PIEACK.all значением 0xFFFF; представление регистра целым словом без разбиения на битовые поля. */ + PieCtrlRegs.PIEACK.all = 0xFFFF; + + // Enable Interrupts at the CPU level + /* Разрешение маскируемых прерываний ядра. */ + EINT; + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c new file mode 100644 index 0000000..eaa98f3 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_SysCtrl.c @@ -0,0 +1,604 @@ +/* Поставляемое TI описание SysCtrl для семейства C2833x. Русские пояснения сохранены в UTF-8. */ +// TI File $Revision: /main/7 $ +// Checkin $Date: September 20, 2007 13:30:31 $ +//########################################################################### +// +// FILE: DSP2833x_SysCtrl.c +// +// TITLE: DSP2833x Device System Control Initialization & Support Functions. +// +// DESCRIPTION: +// +// Example initialization of system resources. +// +//########################################################################### +// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +// $Release Date: August 1, 2008 $ +//########################################################################### + + +/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */ +#include "DSP2833x_Device.h" // Headerfile Include File +/* Подключает "DSP2833x_Examples.h": поставляемое TI описание Examples для семейства C2833x. */ +#include "DSP2833x_Examples.h" // Examples Include File + +//#include "RS485.h" +//#include "message.h" + +// Functions that will be run from RAM need to be assigned to +// a different section. This section will then be mapped to a load and +// run address using the linker cmd file. + +/* Указание компилятору CODE_SECTION(InitFlash, "ramfuncs");: размещение данных или настройка обработки объявлений. */ +#pragma CODE_SECTION(InitFlash, "ramfuncs"); + +//--------------------------------------------------------------------------- +// InitSysCtrl: +//--------------------------------------------------------------------------- +// This function initializes the System Control registers to a known state. +// - Disables the watchdog +// - Set the PLLCR for proper SYSCLKOUT frequency +// - Set the pre-scaler for the high and low frequency peripheral clocks +// - Enable the clocks to the peripherals + +/* Объявляет SYSCLKOUT — данные SYSCLKOUT; LSPCLK — данные LSPCLK; HSPCLK — данные HSPCLK. */ +long SYSCLKOUT, LSPCLK, HSPCLK; + +/* Начинает функцию InitSysCtrl; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitSysCtrl(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + + // Disable the watchdog + /* Вызывает DisableDog с аргументами () в текущей последовательности операций. */ + DisableDog(); + + // Initialize the PLL control: PLLCR and DIVSEL + // DSP28_PLLCR and DSP28_DIVSEL are defined in DSP2833x_Examples.h + /* Инициализирует модуль вызовом InitPll(DSP28_PLLCR,DSP28_DIVSEL); перед его дальнейшим использованием. */ + InitPll(DSP28_PLLCR,DSP28_DIVSEL); + + // Initialize the peripheral clocks + /* Инициализирует модуль вызовом InitPeripheralClocks(); перед его дальнейшим использованием. */ + InitPeripheralClocks(); +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//--------------------------------------------------------------------------- +// Example: InitFlash: +//--------------------------------------------------------------------------- +// This function initializes the Flash Control registers + +// CAUTION +// This function MUST be executed out of RAM. Executing it +// out of OTP/Flash will yield unpredictable results + +/* Начинает функцию InitFlash; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitFlash(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + //Enable Flash Pipeline mode to improve performance + //of code executed from Flash. + /* Записывает FlashRegs.FOPT.bit.ENPIPE значением 1; данные ENPIPE. */ + FlashRegs.FOPT.bit.ENPIPE = 1; + + // CAUTION + //Minimum waitstates required for the flash operating + //at a given CPU rate must be characterized by TI. + //Refer to the datasheet for the latest information. +/* Условие компиляции CPU_FRQ_150MHZ: выбранный блок включается в текущий вариант прошивки. */ +#if CPU_FRQ_150MHZ + //Set the Paged Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.PAGEWAIT значением 5; данные PAGEWAIT. */ + FlashRegs.FBANKWAIT.bit.PAGEWAIT = 5; + + //Set the Random Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.RANDWAIT значением 5; данные RANDWAIT. */ + FlashRegs.FBANKWAIT.bit.RANDWAIT = 5; + + //Set the Waitstate for the OTP + /* Записывает FlashRegs.FOTPWAIT.bit.OTPWAIT значением 8; данные OTPWAIT. */ + FlashRegs.FOTPWAIT.bit.OTPWAIT = 8; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + +/* Условие компиляции CPU_FRQ_100MHZ: выбранный блок включается в текущий вариант прошивки. */ +#if CPU_FRQ_100MHZ + //Set the Paged Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.PAGEWAIT значением 3; данные PAGEWAIT. */ + FlashRegs.FBANKWAIT.bit.PAGEWAIT = 3; + + //Set the Random Waitstate for the Flash + /* Записывает FlashRegs.FBANKWAIT.bit.RANDWAIT значением 3; данные RANDWAIT. */ + FlashRegs.FBANKWAIT.bit.RANDWAIT = 3; + + //Set the Waitstate for the OTP + /* Записывает FlashRegs.FOTPWAIT.bit.OTPWAIT значением 5; данные OTPWAIT. */ + FlashRegs.FOTPWAIT.bit.OTPWAIT = 5; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + // CAUTION + //ONLY THE DEFAULT VALUE FOR THESE 2 REGISTERS SHOULD BE USED + /* Записывает FlashRegs.FSTDBYWAIT.bit.STDBYWAIT значением 0x01FF; данные STDBYWAIT. */ + FlashRegs.FSTDBYWAIT.bit.STDBYWAIT = 0x01FF; + /* Записывает FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT значением 0x01FF; данные ACTIVEWAIT. */ + FlashRegs.FACTIVEWAIT.bit.ACTIVEWAIT = 0x01FF; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + + //Force a pipeline flush to ensure that the write to + //the last register configured occurs before returning. + + /* Вызывает asm с аргументами (" RPT #7 || NOP") в текущей последовательности операций. */ + asm(" RPT #7 || NOP"); +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//--------------------------------------------------------------------------- +// Example: ServiceDog: +//--------------------------------------------------------------------------- +// This function resets the watchdog timer. +// Enable this function for using ServiceDog in the application + +/* Начинает функцию ServiceDog; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void ServiceDog(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Проверяет if(SysCtrlRegs.PLLCR.bit.DIV == DSP28_PLLCR); последующий оператор выполняется только при истинном условии. */ + if(SysCtrlRegs.PLLCR.bit.DIV == DSP28_PLLCR) + /* Проверяет if(SysCtrlRegs.PLLSTS.bit.DIVSEL == DSP28_DIVSEL); последующий оператор выполняется только при истинном условии. */ + if(SysCtrlRegs.PLLSTS.bit.DIVSEL == DSP28_DIVSEL) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.WDKEY значением 0x0055; данные WDKEY. */ + SysCtrlRegs.WDKEY = 0x0055; + /* Записывает SysCtrlRegs.WDKEY значением 0x00AA; данные WDKEY. */ + SysCtrlRegs.WDKEY = 0x00AA; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Завершает ServiceDog без возвращаемого значения. */ + return; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} } + + +//--------------------------------------------------------------------------- +// Example: DisableDog: +//--------------------------------------------------------------------------- +// This function disables the watchdog timer. + +/* Начинает функцию DisableDog; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void DisableDog(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.WDCR значением 0x0068; данные WDCR. */ + SysCtrlRegs.WDCR= 0x0068; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// Example: InitPll: +//--------------------------------------------------------------------------- +// This function initializes the PLLCR register. + +/* Начинает функцию InitPll; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitPll(Uint16 divval, Uint16 divsel) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет clkVal — данные clkVal. */ + long clkVal; + + // Make sure the PLL is not running in limp mode + /* Проверяет if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0); последующий оператор выполняется только при истинном условии. */ + if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + // Missing external clock has been detected + // Replace this line with a call to an appropriate + // SystemShutdown(); function. + /* Вызывает asm с аргументами (" ESTOP0") в текущей последовательности операций. */ + asm(" ESTOP0"); + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + // DIVSEL MUST be 0 before PLLCR can be changed from + // 0x0000. It is set to 0 by an external reset XRSn + // This puts us in 1/4 + /* Проверяет if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0); последующий оператор выполняется только при истинном условии. */ + if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением 0; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = 0; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + // Change the PLLCR +// if (SysCtrlRegs.PLLCR.bit.DIV != val) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + // Before setting PLLCR turn off missing clock detect logic + /* Записывает SysCtrlRegs.PLLSTS.bit.MCLKOFF значением 1; данные MCLKOFF. */ + SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1; + /* Записывает SysCtrlRegs.PLLCR.bit.DIV значением divval; данные DIV. */ + SysCtrlRegs.PLLCR.bit.DIV = divval; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + + /* Записывает clkVal значением (divval)?divval:1; данные clkVal. */ + clkVal = (divval)?divval:1; + /* Записывает clkVal значением XCLKIN * clkVal; данные clkVal. */ + clkVal = XCLKIN * clkVal; + + // Optional: Wait for PLL to lock. + // During this time the CPU will switch to OSCCLK/2 until + // the PLL is stable. Once the PLL is stable the CPU will + // switch to the new PLL value. + // + // This time-to-lock is monitored by a PLL lock counter. + // + // Code is not required to sit and wait for the PLL to lock. + // However, if the code does anything that is timing critical, + // and requires the correct clock be locked, then it is best to + // wait until this switching has completed. + + // Wait for the PLL lock bit to be set. + + // The watchdog should be disabled before this loop, or fed within + // the loop via ServiceDog(). + + // Uncomment to disable the watchdog + /* Вызывает DisableDog с аргументами () в текущей последовательности операций. */ + DisableDog(); + + /* Повторяет или ожидает, пока выполняется while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1). */ + while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + // Uncomment to service the watchdog + // ServiceDog(); + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.MCLKOFF значением 0; данные MCLKOFF. */ + SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + // If switching to 1/2 + /* Проверяет if((divsel == 1) или (divsel == 2)); последующий оператор выполняется только при истинном условии. */ + if((divsel == 1)||(divsel == 2)) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением divsel; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + /* Проверяет if(divsel == 0) clkVal /= 4; последующий оператор выполняется только при истинном условии. */ + if(divsel == 0) clkVal /= 4; + /* Проверяет if(divsel == 1) clkVal /= 4; последующий оператор выполняется только при истинном условии. */ + if(divsel == 1) clkVal /= 4; + /* Проверяет if(divsel == 2) clkVal /= 2; последующий оператор выполняется только при истинном условии. */ + if(divsel == 2) clkVal /= 2; + + // If switching to 1/1 + // * First go to 1/2 and let the power settle + // The time required will depend on the system, this is only an example + // * Then switch to 1/1 + + /* Проверяет if((divval == 0) и (divsel == 3)); последующий оператор выполняется только при истинном условии. */ + if((divval == 0) && (divsel == 3)) + /* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ + { + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением 2; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = 2; + /* Вызывает DELAY_US с аргументами (50L) в текущей последовательности операций. */ + DELAY_US(50L); +// pause_us(50L); + /* Записывает SysCtrlRegs.PLLSTS.bit.DIVSEL значением 3; данные DIVSEL. */ + SysCtrlRegs.PLLSTS.bit.DIVSEL = 3; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + /* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ + } + + /* Записывает SYSCLKOUT значением clkVal; данные SYSCLKOUT. */ + SYSCLKOUT = clkVal; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//-------------------------------------------------------------------------- +// Example: InitPeripheralClocks: +//--------------------------------------------------------------------------- +// This function initializes the clocks to the peripheral modules. +// First the high and low clock prescalers are set +// Second the clocks are enabled to each peripheral. +// To reduce power, leave clocks to unused peripherals disabled +// +// Note: If a peripherals clock is not enabled then you cannot +// read or write to the registers for that peripheral + +/* Начинает функцию InitPeripheralClocks; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +void InitPeripheralClocks(void) +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет Val — данные Val. */ + long Val; + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + +// HISPCP/LOSPCP prescale register settings, normally it will be set to default values + +/* Условие компиляции CLKMULT == 0: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 0 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0000; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0000; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 1: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 1 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0000; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0000; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 2: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 2 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0001; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0001; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 3: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 3 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0002; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0002; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 4: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 4 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0002; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0002; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif +/* Условие компиляции CLKMULT == 5: выбранный блок включается в текущий вариант прошивки. */ +#if CLKMULT == 5 + /* Записывает SysCtrlRegs.HISPCP.all значением 0x0003; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.HISPCP.all = 0x0003; +/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */ +#endif + + /* Записывает SysCtrlRegs.LOSPCP.all значением 0x0000; представление регистра целым словом без разбиения на битовые поля. */ + SysCtrlRegs.LOSPCP.all = 0x0000; + + /* Записывает Val значением (SysCtrlRegs.HISPCP.all)?; данные Val. */ + Val = (SysCtrlRegs.HISPCP.all)? + /* Продолжает список аргументов, полей или выражение SysCtrlRegs.HISPCP.all*2 : 1;; порядок элементов сохраняется. */ + SysCtrlRegs.HISPCP.all*2 : 1; + /* Записывает Val значением SYSCLKOUT / Val; данные Val. */ + Val = SYSCLKOUT / Val; + + /* Записывает HSPCLK значением Val; данные HSPCLK. */ + HSPCLK = Val; + + /* Записывает Val значением (SysCtrlRegs.LOSPCP.all)?; данные Val. */ + Val = (SysCtrlRegs.LOSPCP.all)? + /* Продолжает список аргументов, полей или выражение SysCtrlRegs.LOSPCP.all*2 : 1;; порядок элементов сохраняется. */ + SysCtrlRegs.LOSPCP.all*2 : 1; + /* Записывает Val значением SYSCLKOUT / Val; данные Val. */ + Val = SYSCLKOUT / Val; + /* Записывает LSPCLK значением Val; данные LSPCLK. */ + LSPCLK = Val; + +// XCLKOUT to SYSCLKOUT ratio. By default XCLKOUT = 1/4 SYSCLKOUT + // XTIMCLK = SYSCLKOUT/2 + /* Записывает XintfRegs.XINTCNF2.bit.XTIMCLK значением 1; данные XTIMCLK. */ + XintfRegs.XINTCNF2.bit.XTIMCLK = 1; + // XCLKOUT = XTIMCLK/2 + /* Записывает XintfRegs.XINTCNF2.bit.CLKMODE значением 1; данные CLKMODE. */ + XintfRegs.XINTCNF2.bit.CLKMODE = 1; + // Enable XCLKOUT + /* Записывает XintfRegs.XINTCNF2.bit.CLKOFF значением 0; данные CLKOFF. */ + XintfRegs.XINTCNF2.bit.CLKOFF = 0; + +// Peripheral clock enables set for the selected peripherals. +// If you are not using a peripheral leave the clock off +// to save on power. +// +// Note: not all peripherals are available on all 2833x derivates. +// Refer to the datasheet for your particular device. +// +// This function is not written to be an example of efficient code. + + /* Записывает SysCtrlRegs.PCLKCR0.bit.ADCENCLK значением 1; данные ADCENCLK. */ + SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1; // ADC + + // *IMPORTANT* + // The ADC_cal function, which copies the ADC calibration values from TI reserved + // OTP into the ADCREFSEL and ADCOFFTRIM registers, occurs automatically in the + // Boot ROM. If the boot ROM code is bypassed during the debug process, the + // following function MUST be called for the ADC to function according + // to specification. The clocks to the ADC MUST be enabled before calling this + // function. + // See the device data manual and/or the ADC Reference + // Manual for more information. + + /* Вызывает ADC_cal с аргументами () в текущей последовательности операций. */ + ADC_cal(); + + + /* Записывает SysCtrlRegs.PCLKCR0.bit.I2CAENCLK значением 1; данные I2CAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 1; // I2C + /* Записывает SysCtrlRegs.PCLKCR0.bit.SCIAENCLK значением 1; данные SCIAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 1; // SCI-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.SCIBENCLK значением 1; данные SCIBENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SCIBENCLK = 1; // SCI-B + /* Записывает SysCtrlRegs.PCLKCR0.bit.SCICENCLK значением 1; данные SCICENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SCICENCLK = 1; // SCI-C + /* Записывает SysCtrlRegs.PCLKCR0.bit.SPIAENCLK значением 1; данные SPIAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1; // SPI-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.MCBSPAENCLK значением 1; данные MCBSPAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.MCBSPAENCLK = 1; // McBSP-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.MCBSPBENCLK значением 1; данные MCBSPBENCLK. */ + SysCtrlRegs.PCLKCR0.bit.MCBSPBENCLK = 1; // McBSP-B + /* Записывает SysCtrlRegs.PCLKCR0.bit.ECANAENCLK значением 1; данные ECANAENCLK. */ + SysCtrlRegs.PCLKCR0.bit.ECANAENCLK=1; // eCAN-A + /* Записывает SysCtrlRegs.PCLKCR0.bit.ECANBENCLK значением 1; данные ECANBENCLK. */ + SysCtrlRegs.PCLKCR0.bit.ECANBENCLK=1; // eCAN-B + + /* Записывает SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC значением 0; данные TBCLKSYNC. */ + SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Disable TBCLK within the ePWM + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK значением 1; данные EPWM1ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 1; // ePWM1 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK значением 1; данные EPWM2ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 1; // ePWM2 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK значением 1; данные EPWM3ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 1; // ePWM3 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK значением 1; данные EPWM4ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 1; // ePWM4 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK значением 1; данные EPWM5ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 1; // ePWM5 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK значением 1; данные EPWM6ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 1; // ePWM6 + /* Записывает SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC значением 1; данные TBCLKSYNC. */ + SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Enable TBCLK within the ePWM + + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP3ENCLK значением 1; данные ECAP3ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP3ENCLK = 1; // eCAP3 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP4ENCLK значением 1; данные ECAP4ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP4ENCLK = 1; // eCAP4 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP5ENCLK значением 1; данные ECAP5ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP5ENCLK = 1; // eCAP5 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP6ENCLK значением 1; данные ECAP6ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP6ENCLK = 1; // eCAP6 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK значением 1; данные ECAP1ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 1; // eCAP1 + /* Записывает SysCtrlRegs.PCLKCR1.bit.ECAP2ENCLK значением 1; данные ECAP2ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.ECAP2ENCLK = 1; // eCAP2 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK значением 1; данные EQEP1ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1; // eQEP1 + /* Записывает SysCtrlRegs.PCLKCR1.bit.EQEP2ENCLK значением 1; данные EQEP2ENCLK. */ + SysCtrlRegs.PCLKCR1.bit.EQEP2ENCLK = 1; // eQEP2 + + /* Записывает SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK значением 1; данные CPUTIMER0ENCLK. */ + SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer 0 + /* Записывает SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK значением 1; данные CPUTIMER1ENCLK. */ + SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK = 1; // CPU Timer 1 + /* Записывает SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK значением 1; данные CPUTIMER2ENCLK. */ + SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK = 1; // CPU Timer 2 + + /* Записывает SysCtrlRegs.PCLKCR3.bit.DMAENCLK значением 1; данные DMAENCLK. */ + SysCtrlRegs.PCLKCR3.bit.DMAENCLK = 1; // DMA Clock + /* Записывает SysCtrlRegs.PCLKCR3.bit.XINTFENCLK значением 1; данные XINTFENCLK. */ + SysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 1; // XTIMCLK + /* Записывает SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK значением 1; аппаратная линия ввода/вывода GPIOINENCLK. */ + SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1; // GPIO input clock + + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + +//--------------------------------------------------------------------------- +// Example: CsmUnlock: +//--------------------------------------------------------------------------- +// This function unlocks the CSM. User must replace 0xFFFF's with current +// password for the DSP. Returns 1 if unlock is successful. + +/* Задаёт STATUS_FAIL = 0; состояние FAIL. */ +#define STATUS_FAIL 0 +/* Задаёт STATUS_SUCCESS = 1; состояние SUCCESS. */ +#define STATUS_SUCCESS 1 + +/* Начинает функцию CsmUnlock; назначение модуля — поставляемое TI описание SysCtrl для семейства C2833x. */ +Uint16 CsmUnlock() +/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */ +{ + /* Объявляет temp — данные temp. volatile требует фактического чтения или записи при каждом доступе. */ + volatile Uint16 temp; + + // Load the key registers with the current password. The 0xFFFF's are dummy + // passwords. User should replace them with the correct password for the DSP. + + /* Разрешение записи в защищённые регистры периферии. */ + EALLOW; + /* Записывает CsmRegs.KEY0 значением 0xFFFF; данные KEY0. */ + CsmRegs.KEY0 = 0xFFFF; + /* Записывает CsmRegs.KEY1 значением 0xFFFF; данные KEY1. */ + CsmRegs.KEY1 = 0xFFFF; + /* Записывает CsmRegs.KEY2 значением 0xFFFF; данные KEY2. */ + CsmRegs.KEY2 = 0xFFFF; + /* Записывает CsmRegs.KEY3 значением 0xFFFF; данные KEY3. */ + CsmRegs.KEY3 = 0xFFFF; + /* Записывает CsmRegs.KEY4 значением 0xFFFF; данные KEY4. */ + CsmRegs.KEY4 = 0xFFFF; + /* Записывает CsmRegs.KEY5 значением 0xFFFF; данные KEY5. */ + CsmRegs.KEY5 = 0xFFFF; + /* Записывает CsmRegs.KEY6 значением 0xFFFF; данные KEY6. */ + CsmRegs.KEY6 = 0xFFFF; + /* Записывает CsmRegs.KEY7 значением 0xFFFF; данные KEY7. */ + CsmRegs.KEY7 = 0xFFFF; + /* Закрытие доступа к защищённым регистрам периферии. */ + EDIS; + + // Perform a dummy read of the password locations + // if they match the key values, the CSM will unlock + + /* Записывает temp значением CsmPwl.PSWD0; данные temp. */ + temp = CsmPwl.PSWD0; + /* Записывает temp значением CsmPwl.PSWD1; данные temp. */ + temp = CsmPwl.PSWD1; + /* Записывает temp значением CsmPwl.PSWD2; данные temp. */ + temp = CsmPwl.PSWD2; + /* Записывает temp значением CsmPwl.PSWD3; данные temp. */ + temp = CsmPwl.PSWD3; + /* Записывает temp значением CsmPwl.PSWD4; данные temp. */ + temp = CsmPwl.PSWD4; + /* Записывает temp значением CsmPwl.PSWD5; данные temp. */ + temp = CsmPwl.PSWD5; + /* Записывает temp значением CsmPwl.PSWD6; данные temp. */ + temp = CsmPwl.PSWD6; + /* Записывает temp значением CsmPwl.PSWD7; данные temp. */ + temp = CsmPwl.PSWD7; + + // If the CSM unlocked, return succes, otherwise return + // failure. + /* Проверяет if (CsmRegs.CSMSCR.bit.SECURE == 0) return STATUS_SUCCESS; последующий оператор выполняется только при истинном условии. */ + if (CsmRegs.CSMSCR.bit.SECURE == 0) return STATUS_SUCCESS; + /* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */ + else return STATUS_FAIL; + +/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */ +} + + +//=========================================================================== +// End of file. +//=========================================================================== diff --git a/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm new file mode 100644 index 0000000..9425409 --- /dev/null +++ b/c/protocan-boot/vendor/ti/f28335/source/DSP2833x_usDelay.asm @@ -0,0 +1,84 @@ +; Поставляемое ti описание usdelay для семейства c2833x. Пояснения в UTF-8. +;// TI File $Revision: /main/4 $ +;// Checkin $Date: July 30, 2007 10:28:57 $ +;//########################################################################### +;// +;// FILE: DSP2833x_usDelay.asm +;// +;// TITLE: Simple delay function +;// +;// DESCRIPTION: +;// +;// This is a simple delay function that can be used to insert a specified +;// delay into code. +;// +;// This function is only accurate if executed from internal zero-waitstate +;// SARAM. If it is executed from waitstate memory then the delay will be +;// longer then specified. +;// +;// To use this function: +;// +;// 1 - update the CPU clock speed in the DSP2833x_Examples.h +;// file. For example: +;// #define CPU_RATE 6.667L // for a 150MHz CPU clock speed +;// or #define CPU_RATE 10.000L // for a 100MHz CPU clock speed +;// +;// 2 - Call this function by using the DELAY_US(A) macro +;// that is defined in the DSP2833x_Examples.h file. This macro +;// will convert the number of microseconds specified +;// into a loop count for use with this function. +;// This count will be based on the CPU frequency you specify. +;// +;// 3 - For the most accurate delay +;// - Execute this function in 0 waitstate RAM. +;// - Disable interrupts before calling the function +;// If you do not disable interrupts, then think of +;// this as an "at least" delay function as the actual +;// delay may be longer. +;// +;// The C assembly call from the DELAY_US(time) macro will +;// look as follows: +;// +;// extern void Delay(long LoopCount); +;// +;// MOV AL,#LowLoopCount +;// MOV AH,#HighLoopCount +;// LCR _Delay +;// +;// Or as follows (if count is less then 16-bits): +;// +;// MOV ACC,#LoopCount +;// LCR _Delay +;// +;// +;//########################################################################### +;// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $ +;// $Release Date: August 1, 2008 $ +;//########################################################################### + + ; Экспортирует символ для связывания с C-кодом. Операция: .def _DSP28x_usDelay. + .def _DSP28x_usDelay + ; Выбирает секцию объектного файла для следующих инструкций. Операция: .sect ".text". + .sect ".text" + + ; Объявляет глобальный символ для линкера. Операция: .global __DSP28x_usDelay. + .global __DSP28x_usDelay +; Объявляет метку _DSP28x_usDelay: для перехода или вызова. Операция: _DSP28x_usDelay:. +_DSP28x_usDelay: + ; Вычитает операнд и обновляет арифметическое состояние. Операция: SUB ACC,#1. + SUB ACC,#1 + ; Выполняет условный переход по флагам результата. Операция: BF _DSP28x_usDelay,GEQ. + BF _DSP28x_usDelay,GEQ ;; Loop if ACC >= 0 + ; Возвращает управление вызывающему коду через длинный адрес возврата. Операция: LRETR. + LRETR + +;There is a 9/10 cycle overhead and each loop +;takes five cycles. The LoopCount is given by +;the following formula: +; DELAY_CPU_CYCLES = 9 + 5*LoopCount +; LoopCount = (DELAY_CPU_CYCLES - 9) / 5 +; The macro DELAY_US(A) performs this calculation for you +; +;//=========================================================================== +;// End of file. +;//=========================================================================== diff --git a/python/protocan/can_boot.py b/python/protocan/can_boot.py index 8b80446..ca2960b 100644 --- a/python/protocan/can_boot.py +++ b/python/protocan/can_boot.py @@ -37,6 +37,8 @@ class CanBootTransfer: def __init__(self, image, target: CanBootTarget): if not 0 < len(image.data) <= 512 * 1024: raise ValueError("ProtoCAN Boot: размер образа 1…512 КиБ") + if target.product_type == 0x2833 and len(image.data) > 0x1FE00: + raise ValueError("F28335 M95M02 A/B: образ не должен превышать 130560 байт") if not 0 <= image.version <= 0xFFFFFFFF: raise ValueError("Версия образа вне диапазона u32") self.image, self.target = image, target @@ -46,6 +48,10 @@ class CanBootTransfer: self.finished = False self._window_end = 0 + @property + def response_timeout_ms(self): + return 15000 if self.stage in ("enter", "verify", "commit") else 1500 + @property def percent(self): return min(100, self.next_block * 8 * 100 // len(self.image.data)) @@ -74,7 +80,7 @@ class CanBootTransfer: # но метаданные образа сохраняют исходную длину без этого дополнения. def _window(self): total = (len(self.image.data) + 7) // 8 - self._window_end = min(total, self.next_block + 16) + self._window_end = min(total, (self.next_block // 16 + 1) * 16) # Ядро подтверждает абсолютные границы по 16 блоков; после потери повторяется только хвост текущего окна, чтобы его ACK не застал в очереди кадры следующего окна. return [self._frame(10 + self.slot, i, self.image.data[i * 8:(i + 1) * 8].ljust(8, b"\xff")) for i in range(self.next_block, self._window_end)] @@ -113,8 +119,11 @@ class CanBootTransfer: limit = total if self.stage == "erase" else self._window_end if expected > limit: raise RuntimeError("ProtoCAN Boot: подтверждён непереданный блок") - if self.stage == "data" and status == 0 and expected < self.next_block: - return [], "" + # Один и тот же ACK или SEQUENCE_ERROR может прийти от нескольких оставшихся кадров старого окна. + # Повторная отправка на каждый такой ответ переполняет очередь MCU; при отсутствии продвижения + # последнее окно повторяет транспорт по тайм-ауту, а подтверждённые ранее блоки не отправляются заново. + if self.stage == "data" and expected <= self.next_block: # Сравнивает next_block для обоих статусов: OK и SEQUENCE_ERROR не должны повторно открывать одно окно. + return [], "" # Оставляет текущие кадры и срок ожидания транспорта без изменений до нового прогресса или тайм-аута. self.next_block = expected if expected == total: self.stage = "verify" @@ -128,4 +137,93 @@ class CanBootTransfer: self.stage = "reboot" return self._control(9), "Перезапуск прибора" self.stage, self.finished = "finished", True + if self.target.product_type == 0x2833: + return [], "Образ принят; после перезапуска приложение подтвердит пробный запуск" return [], "Прошивка ProtoCAN Boot завершена" + + +class CanBootServices: + """Read-only passport queries and explicit session service commands. + + Replies use message D, body=(page<<8)|command. IDENTIFY/discovery reply body=1. + All multibyte values are little endian; version is major:8/minor:8/patch:16. + """ + def __init__(self, target: CanBootTarget): + self.target = target + + def request(self, command: int, page: int = 0): + if command not in (1, 8, 11, 12, 13, 14, 15): + raise ValueError("Unsupported service command") + if not 0 <= page <= 255 or (page and command not in (14, 15)): + raise ValueError("Invalid service page") + t = self.target + payload = bytes([page]) if command in (14, 15) else b"" + return build_frame(ProtoCanId.build(1, 0, t.device_type, t.device, 9, + t.session_id << 8 | command), payload, to_can=True) + + @staticmethod + def discover(): + return build_frame(ProtoCanId.build(1, 0, 7, 15, 13, 0), b"", to_can=True) + + def decode(self, frame, *, discovery=False): + p = ProtoCanId.parse(frame.can_id) + if (frame.to_can or not frame.ide or frame.rtr or frame.is_error or p.pm != 1 + or p.msg_type not in (12, 13) or len(frame.data) != 8): + return None + if discovery: + if p.msg_type != 13 or p.body != 1: + return None + elif (p.device_type, p.device) != (self.target.device_type, self.target.device): + return None + if p.msg_type == 12: + if p.body >> 8 != self.target.session_id: + return None + status, slot, next_block, crc32 = struct.unpack("> 8 + d = frame.data + result = {"kind": "passport", "device_type": p.device_type, "device": p.device, "command": command, "page": page} + if command == 1 and page == 0: + product, hardware, protocol, version = struct.unpack("> 24, (version >> 16) & 255, version & 65535)) + elif command == 12 and page == 0: + result.update(protocol_version=d[0], state=d[1], active_slot=d[2], target_slot=d[3], + session_id=d[4], slot_count=d[5], last_status=d[6]) + elif command == 13 and page == 0: + flags, capacity = struct.unpack("> 16, APP_DATA & 65535, APP_DATA >> 16, end & 65535, end >> 16, crc & 65535, crc >> 16, (~entry) & 65535, ((~entry) >> 16) & 65535, 0x5AA5, 0xA55A) # Первые четыре физических октета образуют ASCII FAB1; далее следуют версия, размер, адреса, CRC, инверсия entry и маркеры завершения. + return struct.pack('<16H', *values) # Передаёт ровно 32 октета без платформенного выравнивания структуры. + + +def validate_words(entry, loaded): # Одинаково проверяет содержимое JTAG COFF и транспортной таблицы RS Flash. + if any(APP_START + index not in loaded for index in range(HEADER_WORDS)): # Все слова заголовка должны присутствовать явно, а не получаться заполнением 0xFFFF. + raise ValueError('Нет полного заголовка Flash-приложения FAB1; требуется новая сборка под постоянный загрузчик') # Старый образ с codestart по 0x33FFF6 не допускается. + actual = struct.pack('<16H', *(loaded[APP_START + index] for index in range(HEADER_WORDS))) # Получает описание именно из передаваемых данных. + if actual != descriptor(entry, loaded): # Проверяет CRC, границы, обе половины entry и маркеры одной независимой реконструкцией. + raise ValueError('Заголовок или CRC32 Flash-приложения FAB1 не соответствует данным') # Повреждение нельзя скрыть корректным именем файла или внешним паспортом. + + +def parse_sci8(data): # Разбирает только приложение ниже сектора A, не разрешая аппаратный переход ROM. + if len(data) < 24 or len(data) % 2 or data[:2] != b'\xaa\x08': # SCI8 имеет ключ 0x08AA, 22-октетный заголовок и чётный терминатор. + raise ValueError('Неверный заголовок или размер Flash SCI8') # Обычный бинарный дамп и COFF не являются таблицей адресных блоков TI. + def address(offset): # Адрес TI состоит из старшего 16-битного слова, затем младшего; каждое слово little endian. + high, low = struct.unpack_from(' len(data): # Адрес и все слова должны помещаться в текущем файле. + raise ValueError('Обрезанный блок Flash SCI8') # Не читает случайные байты за границей изображения. + start = address(offset) # Получает абсолютный адрес назначения очередного блока. + offset += 4 # Пропускает две половины абсолютного адреса. + if not APP_START <= start < start + count <= APP_STOP: # Сектор A и весь аппаратный boot исключены независимо от имени секции. + raise ValueError(f'Запрещённый Flash-диапазон 0x{start:06X}, {count} слов: загрузчик защищён') # Показывает точное пересечение до начала обновления. + values = struct.unpack_from('<' + 'H' * count, data, offset) # Читает только полностью проверенный блок. + if any(start + index in loaded for index in range(count)): # Дублирование адреса могло бы скрыть подмену заголовка поздним блоком. + raise ValueError('Перекрывающиеся блоки Flash SCI8') # Запрещает неоднозначный порядок программирования. + loaded.update((start + index, value) for index, value in enumerate(values)) # Сохраняет каждое слово по его физическому LOAD-адресу. + blocks.append((start, data[offset:offset + count * 2])) # Сохраняет исходные октеты без изменения порядка секций. + offset += count * 2 # Переходит к размеру следующего блока. + raise ValueError('Нет терминатора Flash SCI8') # Обрезанный файл не считается полным приложением. + + +def coff_sections(document): # Извлекает адреса и точные октеты из результата TI ofd2000 -x. + coff = document.find('.//ti_coff') # Рабочая прошивка F28335 использует COFF ABI. + if coff is None or coff.findtext('file_header/target_id') != '0x9d' or coff.findtext('file_header/exec') != 'true': # Проверяет процессор и признак связанного исполняемого файла. + raise ValueError('Требуется исполняемый COFF C2000') # Объектные модули и файлы другой архитектуры не программируются. + entry = int(coff.findtext('optional_file_header/entry_point', '0'), 0) # Entry задаёт запуск приложения через общий Flash boot. + sections, loaded = {}, {} # Отдельно хранит XML полей секций и адресное пространство программируемых слов. + for section in coff.findall('section'): # Рассматривает все секции, включая LOAD для функций, исполняемых из RAM. + sections[section.findtext('name')] = section # Служебный заголовок находится по стабильному имени .flash_app. + raw, start = section.findtext('raw_data'), int(section.findtext('virtual_addr', '0'), 0) # OFD называет virtual адресом LOAD, physical — RUN. + if raw is None or section.findtext('copy') == 'true': # Только явно незагружаемые COPY/отладочные секции и секции без данных исключаются из программирования. + continue # Их наличие не расширяет область разрешённого программирования. + payload = base64.b64decode(raw) # Получает точные октеты вместо доверия к соседней MAP. + if len(payload) != int(section.findtext('raw_data_size', '0'), 0) or len(payload) % 2 or not APP_START <= start < start + len(payload) // 2 <= APP_STOP: # Любая загружаемая секция обязана целиком находиться ниже A; RAM, OTP, CSM и несогласованный размер запрещены. + raise ValueError('COFF содержит запрещённую Flash-секцию: ' + str(section.findtext('name'))) # Старый самостоятельный codestart будет отклонён. + for index, value in enumerate(struct.unpack('<' + 'H' * (len(payload) // 2), payload)): # Восстанавливает 16-битное представление каждого слова C28x. + if start + index in loaded: # Две секции не должны программировать одно физическое слово. + raise ValueError('Перекрывающиеся LOAD-секции COFF') # Сохраняет единственность заголовка и однозначную контрольную сумму. + loaded[start + index] = value # Собирает ожидаемый Flash-образ для проверки CRC и конверсии SCI8. + return entry, loaded, sections # Метаданные нужны как подписанию, так и независимой проверке готового OUT. + + +def seal_coff(image, inspector): # Заполняет только заранее выделенный linker заголовок после успешной линковки. + image = Path(image) # Принимает путь текущей сборки без зависимости от рабочего каталога. + document = ET.fromstring(subprocess.check_output([str(inspector), '-x', str(image)])) # Доверяет размещению секций, подтверждённому официальным TI-инспектором. + entry, loaded, sections = coff_sections(document) # Отсекает любой LOAD в сектор A до изменения двоичного файла. + section = sections.get('.flash_app') # Секция размером 16 слов резервируется linker и не меняет адресов остальной программы. + if section is None or int(section.findtext('virtual_addr', '0'), 0) != APP_START or int(section.findtext('raw_data_size', '0'), 0) != HEADER_WORDS * 2: # Нельзя добавлять заголовок поверх машинного кода. + raise ValueError('Linker должен выделить .flash_app из 16 слов по адресу 0x300000') # Ошибка требует пересборки вместо небезопасного смещения программы. + offset = int(section.findtext('file_offsets/raw_data_ptr', '0'), 0) # OFD указывает точное файловое смещение содержимого секции COFF. + raw, signed = bytearray(image.read_bytes()), descriptor(entry, loaded) # Считает CRC уже окончательно связанных Flash LOAD-секций. + if offset <= 0 or offset + len(signed) > len(raw): # Проверяет размер файла до адресной записи заголовка. + raise ValueError('Неверное смещение заголовка COFF') # Повреждённые метаданные не могут изменить постороннюю часть OUT. + raw[offset:offset + len(signed)] = signed # Меняет только зарезервированные 32 октета, не трогая символы, адреса и отладочную информацию. + image.write_bytes(raw) # Сохраняет подписанный результат до конверсии в SCI8 и создания внешнего SHA-256. + loaded.update((APP_START + index, value) for index, value in enumerate(struct.unpack('<16H', signed))) # Приводит адресную модель к записанному заголовку. + validate_words(entry, loaded) # Независимо проверяет только что сформированный результат. diff --git a/python/tests/test_can_boot_services.py b/python/tests/test_can_boot_services.py new file mode 100644 index 0000000..ede386f --- /dev/null +++ b/python/tests/test_can_boot_services.py @@ -0,0 +1,86 @@ +from types import SimpleNamespace +import struct +import pytest + +from protocan.can_boot import CanBootServices, CanBootTarget, CanBootTransfer, CanBootPingExchange +from protocan.protocan import ProtoCanId +from protocan.transport import build_frame + + +def response(command, data, device=7): + return build_frame(ProtoCanId.build(1, 1, 3, device, 13, command), data, to_can=False) + + +def test_passport_and_discovery_address_filters(): + service = CanBootServices(CanBootTarget(device_type=3, device=7, product_type=0x2833)) + identify = response(1, struct.pack(' Date: Fri, 23 Oct 2026 14:16:20 +0300 Subject: [PATCH 10/18] =?UTF-8?q?build(firmware-info):=20=D0=9E=D0=B1?= =?UTF-8?q?=D1=8A=D0=B5=D0=B4=D0=B8=D0=BD=D0=B8=20=D0=BF=D0=BE=D0=B4=D0=B3?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=B2=D0=BA=D1=83=20=D0=B8=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=20C2000?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Направь CCS precompile/postcompile в общий c2000_build, чтобы резервирование версии, проверка EEPROM, MAP, SCI8 и Flash выполнялись одним процессом перед экспортом. Сохраняй варианты eeprom, flash, can и rs в одном проверенном комплекте с manifest и SHA-256. Ошибка проверки блокирует постоянный выпуск и копирование устаревших образов. --- c/firmware-info/tests/test_c2000_build.py | 30 ++ c/firmware-info/tools/c2000_build.py | 436 ++++++++++++++++++++++ tools/firmware-build/ccs/postcompile.bat | 6 +- tools/firmware-build/ccs/precompile.bat | 3 +- 4 files changed, 472 insertions(+), 3 deletions(-) create mode 100644 c/firmware-info/tests/test_c2000_build.py create mode 100644 c/firmware-info/tools/c2000_build.py diff --git a/c/firmware-info/tests/test_c2000_build.py b/c/firmware-info/tests/test_c2000_build.py new file mode 100644 index 0000000..58bb5a7 --- /dev/null +++ b/c/firmware-info/tests/test_c2000_build.py @@ -0,0 +1,30 @@ +import importlib.util # Загружает общий модуль подготовки непосредственно из проверяемой копии templates. +import json # Проверяет сохранение пользовательских полей при резервировании версии 166. +from pathlib import Path # Все файлы теста находятся в изолированном временном каталоге. +import tempfile # Исключает запись версий и паспортов в рабочие прошивки пользователя. +import unittest # Запускает проверки без зависимостей SETGUI и Qt. + +TOOLS = Path(__file__).resolve().parents[1] / "tools" # Тест переносится вместе с c/firmware-info в полный checkout templates. +SPEC = importlib.util.spec_from_file_location("checked_c2000_build", TOOLS / "c2000_build.py") # Выбирает одну реализацию общего процесса. +BUILD = importlib.util.module_from_spec(SPEC) # Импорт не выполняет prebuild и не меняет счётчики версии. +SPEC.loader.exec_module(BUILD) # Проверяет реальный модуль, а не копию функций внутри теста. + + +class LegacyVersionTests(unittest.TestCase): # Подтверждает совместимость общей подготовки с JSON-конфигурацией 166. + def test_json_counter_increments_once_and_keeps_settings(self): # Перенос в templates не должен удваивать резервирование версии. + with tempfile.TemporaryDirectory() as temporary: # Версия настоящего проекта 166 остаётся неизменной. + project = Path(temporary) # Минимальный проект использует прежние настройки без нового аппаратного профиля. + settings = {"product": "Balsam-166-PM35", "target": "TMS320F28335", "version": [1, 0, 999], "increment_version": True, "max_image_bytes": 32508, "copy_to": "../Bin"} # Patch 999 проверяет перенос в minor по общему контракту версии. + config = project / "firmware_identity.json" # Сохраняемый счётчик расположен в том же JSON, что в ветке 166. + config.write_text(json.dumps(settings), encoding="utf-8") # Русские данные и настройки сохраняются как UTF-8. + templates = TOOLS.parents[2] # Полный путь templates восстанавливается из c/firmware-info/tools. + metadata = BUILD.prepare(project, templates, project / "Debug/generated") # Выполняет настоящий общий prebuild без компиляции и сети. + saved = json.loads(config.read_text(encoding="utf-8")) # Проверяет именно сохранённую версию, а не только возвращённые метаданные. + self.assertEqual(saved["version"], [1, 1, 0]) # Номер увеличен один раз с переносом patch в minor. + self.assertEqual(metadata["version"], saved["version"]) # Паспорт и сохраняемый счётчик описывают одну попытку компиляции. + self.assertEqual(metadata["max_image_bytes"], 32508) # Историческая граница EEPROM 166 остаётся обязательной для postbuild. + self.assertEqual(saved["copy_to"], settings["copy_to"]) # Общий генератор сохраняет пользовательские поля, даже если сеть выполняет Публикатор. + + +if __name__ == "__main__": # Импорт набора проверок не запускает их повторно. + unittest.main() # Позволяет проверить совместимость прямой командой Python. diff --git a/c/firmware-info/tools/c2000_build.py b/c/firmware-info/tools/c2000_build.py new file mode 100644 index 0000000..f175618 --- /dev/null +++ b/c/firmware-info/tools/c2000_build.py @@ -0,0 +1,436 @@ +"""Единая подготовка паспорта и проверенного RAM/Flash-комплекта C2000 для CCS и Публикатора.""" # Сетевой выпуск выполняет отдельный Публикатор SETGUI после импорта подготовленной папки. +import argparse # Разбирает одинаковые аргументы защищённого postbuild для CCS Debug и Release. +import base64 # Декодирует точные байты секций COFF из официального XML-вывода TI ofd2000. +from datetime import datetime # Восстанавливает слова UTC из паспорта, созданного перед компиляцией. +import hashlib # Проверяет точные байты конечного BIN и сопроводительного SHA-256. +import importlib.util # Подключает штатный механизм экспорта только после проверки временного выпуска. +import json # Сверяет изделие, аппаратный профиль и идентификацию текущей сборки. +from pathlib import Path # Разрешает пути относительно выбранной конфигурации CCS, а не текущего терминала. +import re # Читает абсолютные EEPROM-символы из карты линкера TI. +import shutil # Копирует только полностью проверенные файлы из временного каталога. +import struct # Разбирает 16-битные слова SCI8 и адреса загрузочных блоков C28x. +import subprocess # Вызывает общую BAT-точку конверсии без публикации во внешнее приложение. +import tempfile # Изолирует непроверенные результаты общего postcompile от постоянных выпусков. +import xml.etree.ElementTree as ET # Проверяет фактические LOAD/RUN адреса Flash COFF без собственного двоичного парсера TI. +import sys # Запускает общий CLI и подключает конвертор без зависимости от GUI. +sys.path.insert(0, str(Path(__file__).resolve().parents[3] / 'python')) # Контракт защищённой Flash берётся из того же checkout templates, что общий сборщик. +from protocan.f28335_flash import APP_START, APP_DATA, APP_STOP, coff_sections, validate_words # Проверяет отсутствие сектора A и описание FAB1 одинаково для COFF и SCI8. + +def numeric_define(header, name): # Читает единственное числовое C-определение без исполнения выражений из заголовка платы. + text = header.read_text(encoding="utf-8-sig") # Поддерживает UTF-8 с BOM для пользовательских заголовков конфигурации. + text = re.sub(r"/\*.*?\*/|//[^\n]*", "", text, flags=re.S) # Удаляет комментарии перед поиском настоящих директив препроцессора. + values = re.findall(r"^\s*#\s*define\s+" + re.escape(name) + r"\s+([^\n]+)", text, re.M) # Требует определение нужного макроса, а не упоминание в тексте. + if len(values) != 1 or not re.fullmatch(r"(?:0[xX][0-9a-fA-F]+|[0-9]+)[uUlL]*", values[0].strip()): # Исключает неоднозначность и выражения, которые могут отличаться от C-препроцессора. + raise ValueError(f"{header}: define {name} once as an integer") # Останавливает выпуск при неподдерживаемой структуре общей разметки. + return int(values[0].strip().rstrip("uUlL"), 0) # Преобразует десятичную либо шестнадцатеричную величину в число Python. + + +def git_state(repository): # Снимает происхождение выбранного рабочего дерева с локальным safe.directory без изменения глобальных настроек Git. + directory = repository.resolve() # Рабочий каталог CCS может быть вложен в репозиторий приложения. + trusted = next((path for path in (directory, *directory.parents) if (path / ".git").exists()), directory) # Git проверяет корень checkout; .git-файл также учитывает подключённый templates submodule. + command = ["git", "-c", "safe.directory=" + trusted.as_posix(), "-C", str(directory)] # Локальное доверие ограничено корнем явно выбранной зависимости или исходников проекта. + try: # Отсутствие Git сохраняет прежний явный NOGIT-контракт общей библиотеки. + commit = subprocess.check_output(command + ["rev-parse", "HEAD"], stderr=subprocess.DEVNULL, text=True, encoding="utf-8").strip() # Получает полный SHA именно компилируемого дерева. + dirty = bool(subprocess.check_output(command + ["status", "--porcelain", "--untracked-files=normal"], stderr=subprocess.DEVNULL, text=True, encoding="utf-8").strip()) # Учитывает новые и изменённые исходники при формировании знака плюс. + return {"commit": commit, "dirty": dirty} # Возвращает совместимую с общим генератором структуру происхождения. + except (OSError, subprocess.CalledProcessError): # Не выдаёт неизвестную ревизию за чистое дерево. + return {"commit": None, "dirty": None} # Генератор пометит такую сборку идентификатором NOGIT000. + + +# Объявляет функцию read_version и её входные параметры. +def read_version(header): + # Читает исходный файл или образ для последующей проверки и разбора. + text = header.read_text(encoding="utf-8-sig") + # Задаёт text по выражению справа; значение используется последующими операциями. + text = re.sub(r"/\*.*?\*/|//[^\n]*", "", text, flags=re.S) + # Задаёт version по выражению справа; значение используется последующими операциями. + version = [] + # Перебирает part, limit in (("MAJOR", 255), ("MINOR", 255), ("PATCH", 999)) в указанном порядке. + for part, limit in (("MAJOR", 255), ("MINOR", 255), ("PATCH", 999)): + # Задаёт name по выражению справа; значение используется последующими операциями. + name = "FIRMWARE_VERSION_" + part + # Задаёт definitions по выражению справа; значение используется последующими операциями. + definitions = re.findall(r"^\s*#\s*define\s+" + name + r"\b([^\n]*)", text, re.M) + # Проверяет условие if len(definitions) != 1 перед выполнением следующего блока. + if len(definitions) != 1: + # Останавливает текущую операцию с исключением ValueError(f"{header}: define {name} exactly once"). + raise ValueError(f"{header}: define {name} exactly once") + # Задаёт value по выражению справа; значение используется последующими операциями. + value = definitions[0].strip() + # Проверяет условие if not re.fullmatch(r"(?:0|[1-9][0-9]*)[uU]?", value) перед выполнением следующего блока. + if not re.fullmatch(r"(?:0|[1-9][0-9]*)[uU]?", value): + # Останавливает текущую операцию с исключением ValueError(f"{header}: {name} must be a decimal integer"). + raise ValueError(f"{header}: {name} must be a decimal integer") + # Задаёт number по выражению справа; значение используется последующими операциями. + number = int(value.rstrip("uU")) + # Проверяет условие if not 0 <= number <= limit перед выполнением следующего блока. + if not 0 <= number <= limit: + # Останавливает текущую операцию с исключением ValueError(f"{header}: {name} must be in 0..{limit}"). + raise ValueError(f"{header}: {name} must be in 0..{limit}") + # Продолжает текущий вызов, список или выражение: version.append(number); порядок аргументов сохраняется. + version.append(number) + # Возвращает version вызывающему коду и завершает функцию. + return version + + +def read_policy(project): # Загружает декларативные настройки памяти платы, оставляя общий алгоритм в templates. + path = project / "firmware_build_profile.json" # Профиль расположен рядом с CCS-проектом и версионируется вместе с linker-файлами. + return json.loads(path.read_text(encoding="utf-8-sig")) if path.is_file() else {} # Старые проекты 166 используют прежний JSON без обязательного нового файла. + + +def configured_version(project, settings): # Поддерживает ручной C-заголовок 167 и сохраняемый JSON-счётчик 166 одной реализацией. + header = read_policy(project).get("version_header") # Источник версии задаётся платой явно, без определения модели по имени каталога. + return read_version(project / header) if header else settings["version"] # Проверку диапазонов JSON выполняет существующий генератор identity. + + +def read_profile(project, templates, eeprom=None): # Получает физическую EEPROM из тех же C-заголовков, которыми пользуется компилятор. + policy = read_policy(project) # Все аппаратные пути и имена макросов остаются данными конкретной платы. + can_profile = policy.get("can_boot_profile") # Явное включение CAN-выпуска не меняет поведение старых проектов без этого поля. + if can_profile not in (None, "f28335-m95m02-ab"): # Поддерживаемый профиль соответствует реальному порту M95M02 с двумя слотами по 130560 октетов. + raise ValueError("Unsupported CAN boot profile: " + str(can_profile)) # Опечатка в профиле не должна незаметно отключать обязательный CAN-образ. + config = policy.get("eeprom") # Отсутствие профиля сохраняет контракт 166 с max_image_bytes в основном JSON. + if not config: # У старого проекта нет дополнительной аппаратной разметки для проверки MAP. + path = project / "firmware_identity.json" # Прямой общий postcompile также поддерживает отдельно переданный готовый паспорт. + settings = json.loads(path.read_text(encoding="utf-8-sig")) if path.is_file() else {} # Отсутствие проектной конфигурации не создаёт вымышленные ограничения памяти. + limit = settings.get("max_image_bytes") # Прежняя конфигурация 166 задаёт предел в физических октетах полного SCI8. + if limit is not None and (type(limit) is not int or limit < 24): # Не допускает отрицательную ёмкость, bool или размер меньше заголовка и терминатора SCI8. + raise ValueError("max_image_bytes must be an integer >= 24") # Не создаёт паспорт с непригодным проектным ограничением. + return {"max_image_bytes": limit} if limit is not None else {} # Старый предел EEPROM также применяется общим postbuild. + selected = numeric_define(project / config["selection_header"], config["selection_macro"]) # Читает только числовое определение, исключая исполнение текста заголовка. + variants = config["variants"] # Таблица связывает значение compiler define, название микросхемы и макрос физической ёмкости. + if str(selected) not in variants: # Неизвестное значение конфигурации не подменяется произвольным профилем. + raise ValueError("Unsupported EEPROM selection: " + str(selected)) # Ошибка возникает до компиляции и создания постоянного выпуска. + chosen = next((value for value in variants.values() if value["name"] == eeprom), None) if eeprom else variants[str(selected)] # CLI override сохраняет согласованный выбор отдельной тестовой сборки. + if chosen is None: # Неподдерживаемый профиль запрещён и при программном вызове общего модуля. + raise ValueError("Unsupported EEPROM profile: " + str(eeprom)) # Не создаёт паспорт с вымышленной ёмкостью. + layout = templates / config["layout_header"] # Разметка читается из фактически компилируемой зависимости, а не из другой копии templates. + total = numeric_define(layout, chosen["bytes_macro"]) # Ёмкость выражена физическими октетами EEPROM согласно общему C-контракту. + words = numeric_define(layout, config["param_words_macro"]) # Число параметров выражено 16-битными словами C28x и включает контрольную сумму. + limit = total - (words + 1) * 2 # Сохраняет параметры и последнее резервное слово; одно слово EEPROM занимает два октета. + if total <= 0 or total % 2 or words <= 0 or limit < 24: # Полная SCI8-таблица требует минимум 22 октета заголовка и два октета терминатора. + raise ValueError("Invalid EEPROM layout") # Не выпускает образ с отрицательной или неполной областью прошивки. + result = {"eeprom": chosen["name"], "eeprom_bytes": total, "eeprom_param_words": words, "max_image_bytes": limit, "ram_ranges": policy["ram_ranges"]} # Паспорт фиксирует аппаратный выбор и допустимые адреса приложения. + if can_profile and chosen["name"] == "M95M02": result["can_boot_profile"] = can_profile # Малая AT25256B не получает неподдерживаемый A/B-образ, даже если проект поддерживает второй аппаратный вариант. + return result # Prebuild сохраняет CAN-профиль, а postbuild проверяет его неизменность вместе с EEPROM и версией. + + +def load_identity(templates): # Загружает действующий генератор паспорта из явно выбранной библиотеки. + spec = importlib.util.spec_from_file_location("unified_identity_tools", templates / "c/firmware-info/tools/identity.py") # Обе схемы CCS используют одинаковый публичный контракт identity. + module = importlib.util.module_from_spec(spec) # Изолированный модуль не меняет импорты SETGUI и других проектов. + spec.loader.exec_module(module) # Ошибка отсутствующей зависимости возвращается вызывающему процессу до записи выпуска. + module.git_state = git_state # Локальное доверие Git ограничено выбранными рабочими деревьями без изменения глобального safe.directory. + return module # Подготовка и упаковка используют одну реализацию формата manifest. + + +def prepare(project, templates, output, eeprom=None, config=None): # Единый prebuild поддерживает исходный счётчик 166 и ручную версию 167. + project, templates, output = project.resolve(), templates.resolve(), output.resolve() # Все относительные пути фиксируются до запуска общих инструментов. + config = config.resolve() if config else project / "firmware_identity.json" # Старые BAT-вызовы могут явно передать прежний файл настроек. + settings = json.loads(config.read_text(encoding="utf-8-sig")) # Читает пользовательские поля без потери дополнительных настроек проекта. + policy, profile = read_policy(project), read_profile(project, templates, eeprom) # Физическая разметка проверяется до изменения счётчика версии. + identity = load_identity(templates) # Подключает генератор той библиотеки, которая включена в компиляцию. + if policy.get("version_header"): # Ручной заголовок остаётся единственным источником версии 167. + settings.update(version=configured_version(project, settings), increment_version=False) # Не увеличивает номер при повторном prebuild или ошибке компиляции. + with tempfile.TemporaryDirectory(prefix="c2000-identity-") as directory: # Временные настройки не переписывают пользовательский JSON. + temporary = Path(directory) / "config.json" # Временный файл нужен только публичному интерфейсу существующего генератора. + temporary.write_text(json.dumps(settings, ensure_ascii=False), encoding="utf-8") # Сохраняет ручной номер и все поля изделия в UTF-8. + metadata = identity.prepare(project, templates, temporary, output) # Генерирует прежние 12 слов паспорта без изменения протокола прошивки. + else: # Проект 166 продолжает резервировать следующий номер непосредственно в своём JSON. + metadata = identity.prepare(project, templates, config, output) # Итератор вызывается ровно один раз, сохраняя старый контракт precompile. + metadata.update(profile) # Предел EEPROM применяется и к старым проектам, и к новым аппаратным профилям. + if "eeprom_bytes" in profile: # Только явный аппаратный профиль требует сверки compiler define и происхождения разметки. + metadata["templates_root"] = str(templates) # Защищает postbuild от проверки по другой копии C-заголовков. + selection = policy["eeprom"] # Имена заголовка и макроса определены декларативным профилем платы. + value = next(key for key, item in selection["variants"].items() if item["name"] == profile["eeprom"]) # Вычисляет точное значение define для выбранной микросхемы. + guard = '\n#include "' + Path(selection["selection_header"]).name + '" /* Проверяет аппаратный профиль текущей компиляции. */\n' # Проверка включается в генерируемый C-заголовок паспорта. + guard += '#if ' + selection["selection_macro"] + ' != ' + value + ' /* Сверяет define компилятора с подготовленным паспортом. */\n#error EEPROM_profile_differs_from_prebuild /* Требует согласованную пересборку платы. */\n#endif /* Завершает проверку профиля EEPROM. */\n' # Compiler-only override не может незаметно изменить физическую разметку. + header = output / "firmware_identity.h" # Добавляет защиту после прежних констант версии и времени. + identity.write_atomic(header, header.read_text(encoding="utf-8") + guard) # Заголовок заменяется атомарно и всегда остаётся в UTF-8. + identity.write_atomic(output / "firmware_identity.json", json.dumps(metadata, ensure_ascii=False, indent=2) + "\n") # Сохраняет фактическую разметку для проверки после линковки. + return metadata # Публичный результат совместим с прежними host-тестами и проектными вызовами. + + +def convert(compiler, build_dir, artifact, metadata_path, stage, tools_templates): # Выполняет только конвертацию во временный каталог до общей проверки выпуска. + spec = importlib.util.spec_from_file_location("unified_c2000_converter", tools_templates / "c/firmware-info/tools/c2000_postbuild.py") # Использует единственную низкоуровневую реализацию hex2000 и сборки дополнительного Flash. + converter = importlib.util.module_from_spec(spec) # Изолирует импорт от старых командных точек входа и исключает рекурсивный postbuild. + sys.path.insert(0, str(tools_templates / "c/firmware-info/tools")) # Соседний identity нужен существующему конвертору при импорте. + try: # Любая ошибка конвертации остаётся внутри staged-выпуска. + spec.loader.exec_module(converter) # Загружает библиотечную функцию без запуска CLI. + source = Path(artifact) # CCS передаёт абсолютный базис OUT либо имя относительно активного BuildDirectory. + source = Path(str(source if source.is_absolute() else build_dir / source) + ".out") # Выбирает конкретный исходный файл текущей сборки. + with tempfile.TemporaryDirectory(prefix=".input-", dir=stage) as directory: # Дополнительные копии конвертора не попадают рядом с постоянным RAM OUT до проверки. + staged = Path(directory) / source.name # Имя артефакта сохраняется для штатного именования Flash и BIN. + shutil.copy2(source, staged) # Передаёт точные байты текущего COFF, сохраняя исходный файл. + converter.postbuild(compiler, build_dir, str(staged.with_suffix("")), metadata_path, stage) # Публикация и сеть отсутствуют: результаты ещё должны пройти проверки общего модуля. + finally: # Импорт другого проекта не должен наследовать временно добавленный каталог инструментов. + sys.path.pop(0) # Возвращает прежний порядок поиска Python-модулей даже при отказе TI. + + +def write_receipt(output, archive_name, image_name): # Передаёт Публикатору точную папку текущего проверенного выпуска. + value = {"schema": 1, "folder": archive_name, "manifest": image_name + ".manifest.json"} # Относительные имена сохраняют переносимость комплекта между компьютерами. + receipt = output / "latest_build.json" # Служебный указатель находится вне папки неизменяемого комплекта. + temporary = receipt.with_suffix(".tmp") # Атомарная замена не оставляет частичный JSON при прерывании записи. + temporary.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") # Записывает только локальный указатель без сетевой публикации. + temporary.replace(receipt) # Указатель меняется лишь после успешной проверки и копирования всех файлов. + + +def atomic_copy(source, destination): # Сохраняет проверенный файл без открытия старого результата на перезапись и без частичного содержимого. + destination = Path(destination) # Нормализует также строковые пути, переданные стандартным shutil.copytree. + with tempfile.NamedTemporaryFile(dir=destination.parent, prefix=".prepared-", delete=False) as stream: # Собственный временный файл наследует права каталога и находится на том же диске для атомарной замены. + temporary = Path(stream.name) # Запоминает только созданный текущим вызовом файл для безопасной очистки. + try: # Ошибка записи или замены должна оставить прежний результат пригодным для чтения. + shutil.copy2(source, temporary) # Сначала полностью записывает новые байты и сохраняет время исходного артефакта. + temporary.replace(destination) # Одной файловой операцией заменяет старый результат после успешной записи временного файла. + finally: # Незавершённый временный файл не должен попадать в будущий комплект Публикатора. + temporary.unlink(missing_ok=True) # Удаляет только собственный незавершённый файл; после успешной замены его уже нет. + return str(destination) # Сохраняет контракт copy_function стандартного shutil.copytree. + + +def verify_embedded(image, metadata, flash=False): # RAM и Flash SCI8 проверяются отдельно по разным допустимым адресам и ограничениям загрузчика. + data = image.read_bytes() # Проверяет содержимое файла, которое будет передано в EEPROM-программатор. + limit = 0xFC00 * 2 - 2 if flash else metadata.get("max_image_bytes", 0xFFFFFFFF) # RS Flash использует внешний буфер 0x200000..0x20FC00 и ещё два октета CRC; RAM BIN ограничен резервом физической EEPROM. + if not 24 <= len(data) <= limit: # Учитывает заголовки SCI8 вместе с кодом, не позволяя переписать резерв параметров либо выйти за буфер RS. + raise ValueError("SCI8 exceeds EEPROM firmware boundary or is too short") # Отвергает слишком большой BIN до создания постоянного каталога выпуска. + if data[:2] != b"\xaa\x08": # 0x08AA — обязательный ключ восьмибитной boot-таблицы TI. + raise ValueError("Invalid SCI8 header") # Не принимает HEX, COFF либо плоский дамп под видом загрузочного BIN. + stamp = datetime.fromisoformat(metadata["built_at_utc"].replace("Z", "+00:00")) # Берёт момент именно того prebuild, который подготовил C-заголовок. + build_id = metadata["build_id"] # Контракт firmware-info v1 хранит ровно восемь ASCII-символов идентификатора. + if not re.fullmatch(r"[0-9a-fA-F]{8}|[0-9a-fA-F]{7}\+|NOGIT000", build_id) or stamp.utcoffset() is None or stamp.utcoffset().total_seconds(): # Исключает неоднозначную дату и неподдерживаемый идентификатор. + raise ValueError("Invalid prebuild identity") # Требует заново выполнить prebuild вместо выпуска чужих метаданных. + words = [1, *metadata["version"], stamp.year, stamp.month * 256 + stamp.day, stamp.hour * 256 + stamp.minute, stamp.second] # Независимо восстанавливает первые восемь 16-битных регистров общего контракта. + words += [ord(build_id[index]) * 256 + ord(build_id[index + 1]) for index in range(0, 8, 2)] # Упаковывает две ASCII-октеты в каждое из четырёх слов идентификатора. + expected = struct.pack("<12H", *words) # TI SCI8 хранит каждое слово полезных данных младшей октетой вперёд. + high, low = struct.unpack_from(" len(data): # Требует полный 32-битный адрес и все октеты полезной нагрузки. + raise ValueError("Truncated SCI8 section") # Не допускает выпуск усечённой секции даже при паспорте в её начале. + high, low = struct.unpack_from("= metadata.get("max_sections", 0xFFFFFFFF): # CAN-порт F28335 принимает не более 64 секций; обычные RAM/Flash-профили сохраняют прежний контракт. + raise ValueError("SCI8 exceeds bootloader section count") # Совместимый размер файла не разрешает таблицу, которую аппаратный загрузчик не сможет разобрать. + blocks.append((address, end)) # Сохраняет проверенный диапазон для контроля следующих блоков и точки входа. + payload = data[offset + 4:offset + 4 + count * 2] # Ищет паспорт только внутри данных, исключая поля заголовка и адреса. + boot += int(flash and address == APP_START and count >= 16) # Ровно один блок содержит полный FAB1; аппаратный boot 0x33FFF6 запрещён. + loaded.update((address + index, value) for index, value in enumerate(struct.unpack("<" + "H" * count, payload))) # Фиксирует реальные 16-битные слова, которые RS-загрузчик запрограммирует во Flash. + found += sum(payload[index:index + 24] == expected for index in range(0, len(payload) - 23, 2)) # Учитывает лишь выровненные на слово экземпляры 12 регистров firmware-info. + offset += 4 + count * 2 # Переходит за полный адрес и полезные слова к следующему размеру. + raise ValueError("Missing SCI8 terminator") # Исчерпание файла без нулевого слова никогда не считается успешной конверсией. + + +def verify_package(image, metadata): # Связывает BIN, manifest и SHA-256 с тем же prebuild и аппаратной EEPROM. + manifest = json.loads(image.with_suffix(image.suffix + ".manifest.json").read_text(encoding="utf-8")) # Один контракт SHA/паспорта обслуживает отдельные RAM BIN, Flash COFF и Flash SCI8. + data = image.read_bytes() # Повторно считывает точные октеты перед постоянной публикацией. + digest = hashlib.sha256(data).hexdigest() # Вычисляет контрольную сумму независимо от общего seal. + if manifest.get("file") != image.name or manifest.get("size_bytes") != len(data) or manifest.get("sha256") != digest: # Требует согласованности имени, размера и содержимого файла. + raise ValueError("BIN does not match its manifest") # Не публикует повреждённый либо перепутанный комплект. + if any(manifest.get(key) != value for key, value in metadata.items()): # Проверяет также eeprom, физическую границу, версию и происхождение компилируемых templates. + raise ValueError("Manifest does not match prebuild identity/EEPROM") # Один лишь корректный SHA не разрешает паспорт другого аппаратного варианта. + if image.with_suffix(image.suffix + ".sha256").read_text(encoding="utf-8").strip() != f"{digest} {image.name}": # Общий sidecar содержит SHA и точное имя через два пробела. + raise ValueError("Invalid BIN SHA-256 sidecar") # Требует целостности всех трёх публикуемых файлов. + + +def verify_linker_profile(map_path, profile): # Сверяет аппаратную настройку Python с фактическими абсолютными символами линкера. + text = map_path.read_text(encoding="utf-8-sig") # MAP текущей конфигурации является обязательным результатом успешной линковки. + expected = {"_EEPROM_TOTAL_BYTES": profile["eeprom_bytes"], "_EEPROM_FIRMWARE_LIMIT_BYTES": profile["max_image_bytes"], "_EEPROM_PARAMS_START_WORD": profile["max_image_bytes"] // 2} # Символы разделяют физические октеты и адресуемые слова C28x. + for name, value in expected.items(): # Проверяет ёмкость, конец прошивки и начало сохраняемых параметров до запуска hex2000. + values = re.findall(r"^\s*(?:\w+\s+)?([0-9a-fA-F]{8})\s+" + re.escape(name) + r"\b", text, re.M) # Принимает формат глобальных TI-символов с номером страницы либо признаком ABS. + if not values or any(int(item, 16) != value for item in values): # Повторные списки MAP обязаны описывать один и тот же профиль. + raise ValueError(f"Linker EEPROM profile mismatch: {name}") # Выявляет define, переданный только компилятору или только линкеру, и устаревшую карту. + + +def verify_flash_coff(image, compiler): # Проверяет реальные секции COFF официальным TI-декодером и возвращает точные Flash-слова загрузки. + tool = compiler / "bin/ofd2000.exe" # Разбирает формат тем же установленным C2000 toolchain, который создал OUT. + document = ET.fromstring(subprocess.check_output([str(tool), "-x", str(image)], stderr=subprocess.STDOUT)) # XML содержит фактические адреса и двоичные данные секций, а не неподтверждённую соседнюю MAP. + coff = document.find(".//ti_coff") # Вариант предназначен строго для COFF ABI F28335. + if coff is None or coff.findtext("file_header/target_id") != "0x9d" or coff.findtext("file_header/exec") != "true": # Не принимает объект другого процессора, ELF либо незалинкованный модуль. + raise ValueError("Expected executable C2000 COFF Flash image") # Явно отделяет JTAG Flash OUT от обычного RAM OUT и чужих архитектур. + sections = {section.findtext("name"): section for section in coff.findall("section")} # Именованные выходные секции соответствуют отдельной Flash-карте линкера 167. + required = {".text": (APP_DATA, APP_STOP, APP_DATA, APP_STOP), ".flash_app": (APP_START, APP_DATA, APP_START, APP_DATA), "flash_rs": (0x8000, 0xC000, APP_DATA, APP_STOP), "ramfuncs": (0xC000, 0xD000, APP_DATA, APP_STOP)} # FAB1 находится в секторе H; все Flash LOAD-секции исключают постоянный сектор A, сохраняя прежние RUN-области RAM. + for name, (run_begin, run_end, load_begin, load_end) in required.items(): # Наличие автономного RAM-загрузчика и InitFlash обязательно для выпуска Flash-варианта. + section = sections.get(name) # Отсутствующая обязательная секция не маскируется другими именами или символами MAP. + if section is None: # Проверяет отдельную карту и startup, а не одно лишь расположение основного кода. + raise ValueError("Missing Flash COFF section: " + name) # Не выдаёт RAM COFF за пригодный для автономной Flash. + run, load, size = (int(section.findtext(field, "0"), 0) for field in ("physical_addr", "virtual_addr", "raw_data_size")) # Длина OFD задана физическими октетами, оба адреса — 16-битными словами CPU. + if not size or size % 2 or not run_begin <= run < run + size // 2 <= run_end or not load_begin <= load < load + size // 2 <= load_end or (name == ".flash_app" and size != 32): # FAB1 занимает ровно 16 слов; прочие секции целиком помещаются в разрешённых LOAD/RUN-областях ниже сектора A. + raise ValueError("Invalid Flash COFF LOAD/RUN section: " + name) # Отвергает stale linker, размещение API во Flash во время стирания и аппаратный вход вне 0x33FFF6. + loaded = {} # Сопоставляет слова всех загружаемых Flash-секций с будущей SCI8-таблицей RS. + for section in sections.values(): # Служебные debug/copy-секции адреса ноль в программирование не входят. + address = int(section.findtext("virtual_addr", "0"), 0) # Для COFF TI это загрузочный адрес содержимого секции. + raw = section.findtext("raw_data") # Пустая .ebss, NOLOAD или DSECT не задаёт байтов прошивки. + if raw is None or not 0x300000 <= address < 0x340000: # Не включает отладочные записи, ROM-таблицы и рабочую RAM в образ Flash. + continue # Права оставшихся загружаемых Flash-слов дополнительно проверит общий SCI8-валидатор. + data = base64.b64decode(raw) # Получает именно те октеты, которые записаны в COFF и должны оказаться в Flash SCI8. + if len(data) % 2: # Любая программируемая секция C28x должна содержать целые 16-битные слова. + raise ValueError("Odd Flash COFF section size") # Не допускает неоднозначную упаковку образа RS. + for index, value in enumerate(struct.unpack("<" + "H" * (len(data) // 2), data)): # Восстанавливает little-endian представление каждого физического слова COFF. + if address + index in loaded: # Два выходных диапазона не должны программировать одно слово повторно. + raise ValueError("Overlapping Flash COFF load sections") # Проверяет реальный OUT независимо от доверия к линкерной карте. + loaded[address + index] = value # Сохраняет ожидаемые данные для независимого сравнения с hex2000. + entry = int(coff.findtext("optional_file_header/entry_point", "0"), 0) # Получает реальную точку входа C runtime из заголовка COFF. + if entry not in loaded or not 0x300000 <= entry < 0x33FF80: # C startup должен находиться в полностью загружаемой исполняемой Flash. + raise ValueError("Flash COFF entry is not loaded") # Исключает OUT со старой RAM-точкой входа или отрезанным startup. + checked_entry, checked_loaded, _ = coff_sections(document) # Общий декодер дополнительно отвергает любой загружаемый RAW вне области приложения, включая OTP и RAM. + if checked_entry != entry or checked_loaded != loaded: raise ValueError('Flash COFF load data mismatch') # Ни одна секция не должна быть потеряна при независимом обходе OFD XML. + validate_words(entry, loaded) # Проверяет FAB1 и CRC по полному согласованному COFF-образу. + return entry, loaded # Полное сравнение с SCI8 обнаружит конверсию другого OUT, потерю секции или подмену одного слова. + + +def verify_flash_release(stage, artifact, metadata, compiler, identity, required=False): # Проверяет и отдельно маркирует Flash COFF/SCI8 в staged-выпуске до любого постоянного копирования. + base = Path(artifact.replace("\\", "/")).name # Использует исходное имя артефакта CCS без директории и расширения OUT. + coff, serial = stage / (base + "_flash.out"), stage / (base + "_flash_rs.bin") # JTAG COFF и RS SCI8 являются разными формами одного отдельного Flash-варианта. + if not coff.exists() and not serial.exists() and not required: # Проекты без build_flash.py и host-фикстуры сохраняют прежний защищённый выпуск RAM. + return # Наличие обычного RAM BIN само по себе не объявляет поддержку Flash. + if not coff.is_file() or not serial.is_file(): # Сборка Flash должна выпустить оба согласованных артефакта. + raise ValueError("Incomplete Flash COFF/SCI8 release") # Не экспортирует один старый OUT вместе с новым RAM-выпуском. + verify_linker_profile(coff.with_suffix(".map"), metadata) # Flash использует физическую EEPROM для параметров и не меняет её профиль при размещении кода внутри CPU. + if verify_flash_coff(coff, compiler) != verify_embedded(serial, metadata, flash=True): # Сравнивает entry и каждое загрузочное слово официального COFF с результатом hex2000. + raise ValueError("Flash SCI8 does not match its COFF") # Отклоняет stale конверсию даже при правильных независимых SHA-файлах. + pairs = [(path, "COFF") for path in stage.rglob(coff.name)] + [(path, "SCI8-FLASH") for path in stage.rglob(serial.name)] # Включает плоские результаты и все их копии внутри текущего архива. + for path, kind in pairs: # Сначала проверяет весь исходный комплект, не меняя даже временных паспортов при первом отказе. + verify_package(path, metadata) # Общий postcompile обязан сохранить текущие version/EEPROM/SHA для каждого результата. + if path.read_bytes() != (coff if kind == "COFF" else serial).read_bytes(): # Архивированная копия должна быть побайтно тем же проверенным вариантом. + raise ValueError("Flash archive differs from staged release") # Не позволяет экспортировать чужой Flash внутри корректного RAM-архива. + with tempfile.TemporaryDirectory(prefix=".variant-", dir=stage) as directory: # Вариантные JSON нужны только для подписи разных форматов и не попадают в постоянный выпуск. + metadata_path = Path(directory) / "metadata.json" # Общий seal принимает обычный путь и не требует изменения соседнего templates. + for path, kind in pairs: # Только проверенные Flash-файлы получают явный признак исполнения и транспортный формат. + specific = dict(metadata, execution="FLASH", image_format=kind, boot_contract="f28335-universal-v1", boot_protected=True, flash_app_start=APP_START, flash_app_stop=APP_STOP) # Паспорт явно отличает защищённое приложение от старого самостоятельного Flash; аппаратная EEPROM сохраняется отдельно. + metadata_path.write_text(json.dumps(specific, ensure_ascii=False), encoding="utf-8") # Сохраняет все поля происхождения и ручную версию из общего prebuild. + identity.seal(path, metadata_path) # Переподписывает конкретный COFF либо SCI8 с явным execution=FLASH только после проверки байтов. + verify_package(path, specific) # Подтверждает согласованность готового вариантного manifest и SHA перед публикацией. + + +def create_can_release(stage, image, metadata, map_path, identity): # Добавляет отдельный CAN BIN только после проверки текущего RAM-образа и его интеграции с загрузчиком. + if not metadata.get("can_boot_profile"): return None # Старые проекты и AT25256B продолжают выпускаться без дополнительного неподдерживаемого файла. + if metadata["can_boot_profile"] != "f28335-m95m02-ab" or metadata.get("target") != "TMS320F28335" or metadata.get("eeprom") != "M95M02": # Профиль связан с конкретными процессором, памятью и A/B-портом. + raise ValueError("CAN profile requires TMS320F28335 with M95M02") # Запрещает переименование произвольного RAM либо Flash BIN в пригодный CAN-образ. + limits = dict(metadata, max_image_bytes=130560, ram_ranges=[[0x8000, 0xE000]], max_sections=64) # Ограничения взяты из f28335_boot_store: длина в октетах, адреса в 16-битных словах CPU. + _entry, loaded = verify_embedded(image, limits) # Проверяет SCI8, паспорт, entry, все секции, перекрытия и защиту RAM загрузчика. + symbols = map_path.read_text(encoding="utf-8", errors="replace") # Использует MAP именно активной линковки, уже проверенный по профилю EEPROM. + for name in ("_F28335CanBoot_Init", "_F28335CanBoot_Ready", "_F28335CanBoot_Service", "_F28335CanBoot_RxISR"): # CAN-приложение должно содержать инициализацию, готовность, основной сервис и обработчик приёма. + matches = re.findall(r"^\s*\d+\s+([0-9a-fA-F]{8})\s+" + re.escape(name) + r"\s*$", symbols, re.M) # Читает адреса экспортированных TI-символов, исключая простые упоминания имени в описании секции. + if not matches or any(int(address, 16) not in loaded for address in matches): # Требует присутствие hook в загружаемом payload текущего BIN, а не только в произвольном MAP. + raise ValueError("CAN application hook missing from SCI8/MAP: " + name) # Старое приложение без READY/CONFIRM нельзя выпускать как автоматически пригодное для CAN A/B. + specific = dict(metadata, execution="RAM", image_format="SCI8-RAM", transport="can", protocol="ProtoCAN Boot", product_type=0x2833, hardware_min=1, hardware_max=1) # Паспорт отделяет CAN от RS Flash и сохраняет прежние ручную версию, SHA и аппаратную идентичность. + can_image = image.with_name(image.stem + "_can.bin") # Отдельный суффикс однозначно показывает назначение файла, сохраняя имя артефакта и Build ID. + can_image.write_bytes(image.read_bytes()) # По CAN передаётся та же полная SCI8-таблица RAM без нового заголовка или изменения адресов секций. + with tempfile.TemporaryDirectory(prefix=".can-metadata-", dir=stage) as directory: # Вариантный паспорт не подменяет исходные метаданные компиляции. + metadata_path = Path(directory) / "metadata.json" # Общий seal читает отдельный временный JSON для конкретного транспортного файла. + metadata_path.write_text(json.dumps(specific, ensure_ascii=False), encoding="utf-8") # Русские поля пользовательского паспорта сохраняются в UTF-8. + identity.seal(can_image, metadata_path) # Создаёт собственные manifest и SHA-256 с точным именем CAN BIN. + verify_package(can_image, specific) # До публикации сверяет все поля нового паспорта и точные байты файла. + archive = stage / identity.build_folder_name(metadata) # Дополняет тот же архив текущей сборки, который уже содержит обычный RAM и варианты Flash. + if not archive.is_dir(): raise ValueError("CAN release requires the current build archive") # Не создаёт отдельный неполный выпуск, который не попадёт в штатный экспорт GUI. + for file in (can_image, can_image.with_suffix(".bin.manifest.json"), can_image.with_suffix(".bin.sha256")): # Все три файла должны одновременно попасть в плоский выпуск и архив. + shutil.copy2(file, archive / file.name) # Копирование ещё выполняется внутри временного staged-комплекта без изменения предыдущих выпусков. + verify_package(archive / can_image.name, specific) # Проверяет архивную копию до копирования в output и каталог GUI. + return can_image # Вызывающий выводит точное имя только после успешного завершения всего защищённого postbuild. + + +def arrange_release(stage, archive_name, artifact, image_name, can_image): # Разделяет уже проверенный комплект по способу программирования в текущем выпуске и его архиве. + base = Path(artifact.replace("\\", "/")).name # Использует базовое имя CCS, включая случай абсолютного BuildArtifactFileBaseName. + routes = {base + "_flash.out": "flash", base + "_flash.map": "flash", base + "_flash_rs.bin": "rs"} # OUT и карта относятся к JTAG, а отдельный SCI8 Flash BIN передаётся последовательным загрузчиком. + if can_image is not None: routes[can_image.name] = "can" # CAN получает только вариант, прошедший ограничения A/B-слота и проверку прикладных hooks. + shutil.copy2(stage / archive_name / "firmware_identity.json", stage / "firmware_identity.json") # Общий паспорт связывает четыре папки как в текущем локальном выпуске CCS, так и в его неизменяемом архиве. + for folder in (stage / archive_name, stage): # Сначала перестраивает архив, затем плоские результаты того же временного выпуска. + for file in tuple(folder.iterdir()): # Снимок списка исключает повторную обработку создаваемых папок назначения. + if not file.is_file() or file.name == "firmware_identity.json": continue # Архив и исходный общий паспорт остаются на своём уровне без дублирования между назначениями. + purpose = next((route for name, route in routes.items() if file.name == name or file.name.startswith(name + ".")), "eeprom") # Sidecar-паспорта, SHA и карты следуют за точным именем своего образа; прочие RAM/HEX-файлы сопровождают EEPROM. + destination = folder / purpose # Одинаковые четыре назначения применяются к локальному CCS-выпуску и экспортируемому архиву. + destination.mkdir(exist_ok=True) # Пустая папка неподдержанного CAN/Flash не создаётся и не обещает отсутствующего образа. + file.replace(destination / file.name) # Перемещает только внутри временного stage, не затрагивая ранее опубликованные файлы. + return (Path("eeprom") / image_name).as_posix() # Переносимый относительный путь сохраняется в receipt и используется штатным экспортом identity. + + +def publish(project, templates, tools_templates, compiler, build_dir, artifact, map_path, output, export=None, eeprom=None): # Выпускает только проверенные результаты конкретной конфигурации CCS. + project, templates, tools_templates = project.resolve(), templates.resolve(), tools_templates.resolve() # Фиксирует выбранные исходники и инструменты независимо от рабочего каталога терминала. + build_dir, compiler = build_dir.resolve(), compiler.resolve() # Общая BAT-точка получает полные пути текущих компилятора и Debug/Release. + metadata_path = build_dir / "generated/firmware_identity.json" # Использует паспорт, подготовленный до компиляции этой конфигурации. + metadata = json.loads(metadata_path.read_text(encoding="utf-8")) # Отсутствующий prebuild останавливает работу до создания выпуска. + profile = read_profile(project, templates, eeprom) # Повторно читает текущий выбор EEPROM и общий резерв параметров. + settings = json.loads((project / "firmware_identity.json").read_text(encoding="utf-8-sig")) if (project / "firmware_identity.json").is_file() else metadata # Сверяет product и target с действующим проектом. + expected = {"product": settings["product"], "target": settings["target"], "version": configured_version(project, settings), **({"templates_root": str(templates)} if "eeprom_bytes" in profile else {}), **profile} # Ручной номер и аппаратный вариант обязаны совпадать с prebuild. + if any(metadata.get(key) != value for key, value in expected.items()) or metadata.get("can_boot_profile") != profile.get("can_boot_profile"): # Включение и отключение CAN после prebuild также требуют пересборки, как изменение версии, EEPROM или зависимости. + raise ValueError("Configuration changed: run prebuild and rebuild before publishing") # Требует пересборку вместо подмены старых метаданных. + verify_linker_profile(map_path.resolve(), profile) if "eeprom_bytes" in profile else None # Проверяет аппаратный выбор линкера, который нельзя вывести только из Python-конфигурации. + with tempfile.TemporaryDirectory(prefix=".verified-release-", dir=build_dir) as directory: # Единственное место, куда общий postcompile пишет до подтверждения пригодности BIN. + stage = Path(directory) # Изолирует все архивы и промежуточные HEX от постоянных каталогов выпуска. + convert(compiler, build_dir, artifact, metadata_path, stage, tools_templates) # Любая ошибка TI или общей библиотеки прерывает публикацию. + image_name = Path(artifact.replace("\\", "/")).name + "_" + metadata["build_id"] + ".bin" # Повторяет штатное имя конкретного образа, не сканируя старые BIN. + image = stage / image_name # Проверяет только результат текущего вызова конвертора. + verify_embedded(image, metadata) # Обязательные проверки EEPROM, полной SCI8-таблицы и реально встроенных 12 слов. + verify_package(image, metadata) # Сверяет SHA и весь паспорт, включая физический профиль EEPROM. + for archived in stage.rglob(image_name): # Проверяет также копии внутри текущего архива перед их публикацией или export. + verify_package(archived, metadata) # Архив обязан содержать те же байты и профиль, что плоский выпуск. + spec = importlib.util.spec_from_file_location("release_identity_tools", tools_templates / "c/firmware-info/tools/identity.py") # Подключает существующий формат именования и экспорта архива без копирования реализации. + identity = importlib.util.module_from_spec(spec) # Создаёт отдельный модуль инструментов, не подменяя компилируемую зависимость паспорта. + spec.loader.exec_module(identity) # Ошибка подключения остаётся внутри временного этапа до постоянных файлов. + verify_flash_release(stage, artifact, metadata, compiler, identity, required=(project / "build_flash.py").is_file()) # Отдельная Flash-сборка требует собственного безопасного COFF/SCI8 и не ослабляет прежние RAM-проверки. + can_image = create_can_release(stage, image, metadata, map_path, identity) # Автоматически создаёт и проверяет CAN-вариант до переноса любого результата в постоянный выпуск. + archive_name = identity.build_folder_name(metadata) # Сохраняет принятые имена архивов с ревизией, признаком изменений и временем UTC+3. + if not (stage / archive_name / image_name).is_file(): # Полный архив является обязательным результатом общей конверсии, а не необязательной старой папкой. + raise ValueError("Common postcompile did not produce the current build archive") # Не публикует неполный комплект без OUT, MAP и паспорта текущего выпуска. + image_name = arrange_release(stage, archive_name, artifact, image_name, can_image) # Общая раскладка выполняется после всех проверок RAM/Flash/CAN и до постоянного копирования. + output = output.resolve() # Постоянный каталог появляется только после всех проверок staged-комплекта. + output.mkdir(parents=True, exist_ok=True) # Прежние проверенные выпуски сохраняются при добавлении нового. + for item in sorted(stage.iterdir(), key=lambda item: item.is_dir()): # Переносит только файлы и архив, созданные данным postcompile. + if item.is_dir(): # Архив содержит сопроводительные результаты той же сборки. + shutil.copytree(item, output / item.name, dirs_exist_ok=True, copy_function=atomic_copy) # Сохраняет только проверенный архив с атомарной заменой файлов при повторном выпуске той же компиляции. + else: # Общие служебные файлы, если они появятся, сохраняются в корне текущего выпуска. + atomic_copy(item, output / item.name) # Не открывает старые файлы другой ветки на перезапись и не оставляет частичный BIN/HEX при отказе записи. + verify_package(output / image_name, metadata) # Подтверждает отсутствие повреждения при копировании на постоянный диск. + if export is not None: # Копирование в каталог GUI выполняется последним и лишь для прошедшего проверки архива. + identity.export_build(output / archive_name, export.resolve(), image_name) # Использует общий экспорт уже проверенного локального выпуска. + print(f"[firmware-build] Verified {profile.get('eeprom', settings['target'])} BIN: {output / image_name}") # Показывает пригодный аппаратный профиль и точный путь конечного файла. + if can_image is not None: print(f"[firmware-build] CAN BIN: {output / 'can' / can_image.name}") # После успешного выпуска показывает файл из отдельной папки ProtoCAN. + write_receipt(output, archive_name, image_name) # Фиксирует точную папку выпуска для импорта Публикатором без поиска по времени. + return output / image_name # Даёт тестам и внешним средствам однозначный результат без поиска по времени. + + +def main(argv=None): # Общая точка входа CCS и старых BAT: подготовка и проверка не выполняют сетевую публикацию. + parser = argparse.ArgumentParser(description="Единая подготовка C2000 для CCS и Публикатора SETGUI") # Показывает назначение обеих команд пользователю терминала. + parser.add_argument("command", choices=("prepare", "build")) # Разделяет резервирование версии до компиляции и проверку готового OUT после неё. + for name in ("project", "templates", "tools-templates", "config", "compiler", "build-dir", "metadata", "map", "output", "export"): # Все пути передаются явно или выводятся из публичных соглашений CCS. + parser.add_argument("--" + name, type=Path) # Path исключает интерпретацию аргументов через командную оболочку. + parser.add_argument("--artifact") # Базовое имя OUT передаётся без расширения как штатный макрос CCS. + parser.add_argument("--eeprom", choices=("AT25256B", "M95M02")) # Сохраняет существующий явный выбор тестового аппаратного профиля. + args = parser.parse_args(argv) # Ошибки аргументов завершают процесс до любых изменений версии или файлов выпуска. + tools = Path(__file__).resolve().parents[3] # В полной библиотеке модуль расположен в c/firmware-info/tools. + project = (args.project or (args.build_dir.parent if args.build_dir else Path.cwd())).resolve() # Старый postcompile определяет проект по родителю Debug/Release. + config = args.config or project / "firmware_identity.json" # Старый JSON 166 остаётся совместимым без обязательной миграции. + if args.command == "build" and not config.is_file() and args.build_dir: # Прямой postcompile допускает подготовленный паспорт без отдельного пользовательского JSON. + config = args.metadata or args.build_dir / "generated/firmware_identity.json" # В таком случае доступные проверки определяются реальными метаданными компиляции. + settings = json.loads(config.read_text(encoding="utf-8-sig")) # Изделие и зависимости определяются настройками проекта, а не текущим каталогом. + templates = args.templates or (config.parent / settings["templates"] if settings.get("templates") else tools) # Поддерживает относительный путь общей библиотеки старых проектов. + if args.command == "build" and not args.templates and args.build_dir: # Старый BAT postcompile не передаёт отдельный путь компилируемых исходников templates. + previous = json.loads((args.metadata or args.build_dir / "generated/firmware_identity.json").read_text(encoding="utf-8")) # Использует точный путь, зафиксированный prebuild активной конфигурации. + templates = Path(previous.get("templates_root", templates)) # Проверки EEPROM читают те же заголовки даже при отдельном полном checkout инструментов. + try: # Возвращает CCS ненулевой код при отказе любой проверки. + if args.command == "prepare": # Prebuild вызывается ровно один раз перед компиляцией паспорта. + prepare(project, templates, args.output or args.build_dir / "generated", args.eeprom, config) # При ручной версии исходный JSON не меняется. + else: # Postbuild получает уже подготовленный паспорт текущей конфигурации. + if not args.compiler or not args.build_dir or not args.artifact: # Нельзя подменить отсутствующий артефакт произвольным старым файлом из каталога. + parser.error("build requires --compiler, --build-dir and --artifact") # Показывает обязательные параметры до запуска TI. + metadata = args.build_dir / "generated/firmware_identity.json" # Основное расположение совпадает с прежними конфигурациями CCS. + if args.metadata and args.metadata.resolve() != metadata.resolve(): # Защищённый выпуск использует только паспорт активной конфигурации. + raise ValueError("metadata must belong to the selected build directory") # Не принимает паспорт другой сборки с совпадающим номером версии. + image = Path(args.artifact) # Путь карты по умолчанию находится рядом с выбранным OUT. + image = image if image.is_absolute() else args.build_dir / image # Относительные артефакты разрешаются от BuildDirectory. + publish(project, templates, args.tools_templates or tools, args.compiler, args.build_dir, args.artifact, args.map or image.with_suffix(".map"), args.output or args.build_dir / "firmware", args.export, args.eeprom) # Подготовленный комплект передаётся Публикатору отдельно от сетевых действий. + except (OSError, ValueError, KeyError, TypeError, struct.error, subprocess.CalledProcessError) as error: # Ошибки формата, зависимостей и компилятора не скрываются успешным завершением сборки. + parser.exit(1, f"[firmware-build] ERROR: {error}\n") # Краткая причина остаётся видна в Console CCS. + return 0 # Успех подтверждает подготовку проверенного локального комплекта. + + +if __name__ == "__main__": # Импорт из проектного адаптера или тестов не запускает сборку. + raise SystemExit(main()) # Возвращает командной оболочке фактический результат подготовки. diff --git a/tools/firmware-build/ccs/postcompile.bat b/tools/firmware-build/ccs/postcompile.bat index 04265f1..14c730c 100644 --- a/tools/firmware-build/ccs/postcompile.bat +++ b/tools/firmware-build/ccs/postcompile.bat @@ -18,10 +18,12 @@ if "%~5"=="" goto usage if "%~6"=="" goto usage if not "%~8"=="" goto usage if "%~7"=="" goto identity_local -python "%~dp0..\..\..\c\firmware-info\tools\c2000_postbuild.py" --compiler "%~f2" --build-dir "%~f3" --artifact "%~4" --metadata "%~f5" --output "%~f6" --export "%~f7" +rem Общая подготовка и проверка выполняются в templates; сетевую публикацию выполняет Публикатор SETGUI. +python "%~dp0..\..\..\c\firmware-info\tools\c2000_build.py" build --compiler "%~f2" --build-dir "%~f3" --artifact "%~4" --metadata "%~f5" --output "%~f6" --export "%~f7" exit /b %errorlevel% :identity_local -python "%~dp0..\..\..\c\firmware-info\tools\c2000_postbuild.py" --compiler "%~f2" --build-dir "%~f3" --artifact "%~4" --metadata "%~f5" --output "%~f6" +rem Общая подготовка и проверка выполняются в templates; сетевую публикацию выполняет Публикатор SETGUI. +python "%~dp0..\..\..\c\firmware-info\tools\c2000_build.py" build --compiler "%~f2" --build-dir "%~f3" --artifact "%~4" --metadata "%~f5" --output "%~f6" exit /b %errorlevel% :usage echo Usage: postcompile.bat --identity "compiler-root" "build-dir" "artifact-name" "generated-metadata.json" "output-dir" ["export-dir"] 1>&2 diff --git a/tools/firmware-build/ccs/precompile.bat b/tools/firmware-build/ccs/precompile.bat index 163f2b2..b45ea9a 100644 --- a/tools/firmware-build/ccs/precompile.bat +++ b/tools/firmware-build/ccs/precompile.bat @@ -23,7 +23,8 @@ if not exist "%~f3" ( echo [firmware-build] Created configuration: "%~f3" echo [firmware-build] Edit product, target and version in this file, then rebuild. ) -python "%~dp0..\..\..\c\firmware-info\tools\identity.py" prepare --repository "%~f2" --templates "%~dp0..\..\.." --config "%~f3" --output "%~f4" +rem Общая подготовка и проверка выполняются в templates; сетевую публикацию выполняет Публикатор SETGUI. +python "%~dp0..\..\..\c\firmware-info\tools\c2000_build.py" prepare --project "%~f2" --templates "%~dp0..\..\.." --config "%~f3" --output "%~f4" exit /b %errorlevel% :usage echo Usage: precompile.bat --identity "project-root" "firmware_identity.json" "generated-dir" 1>&2 From 62c0492bfd0ef3f447374bf100e567f0c884bc2f Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Oct 2026 14:16:21 +0300 Subject: [PATCH 11/18] =?UTF-8?q?feat(firmware-build):=20=D0=94=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D1=8C=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D1=83?= =?UTF-8?q?=20=D0=B8=20=D0=BF=D0=B0=D1=81=D0=BF=D0=BE=D1=80=D1=82=D0=B0=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=BE=D0=B2=20=D0=9F=D0=9B?= =?UTF-8?q?=D0=98=D0=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Подключи ISE, Vivado и Quartus к общему итератору версии и HDL-паспорту. Проверяй новый bit/sof до создания manifest, SHA-256 и архива выпуска. Добавь установку локальных команд ISE, инструкции переноса и регрессионные проверки успешных и прерванных сборок. --- firmware-version-porting.md | 1 + tools/firmware-build/fpga/.gitattributes | 2 + tools/firmware-build/fpga/INSTALL_ISE.bat | 29 +++ tools/firmware-build/fpga/ISE_PORTING.md | 42 +++ tools/firmware-build/fpga/README.md | 241 ++++++++++++++++++ tools/firmware-build/fpga/common.tcl | 76 ++++++ .../fpga/firmware_identity.example.json | 6 + tools/firmware-build/fpga/identity.py | 92 +++++++ tools/firmware-build/fpga/ise-build.bat | 19 ++ tools/firmware-build/fpga/ise-env.bat | 8 + tools/firmware-build/fpga/ise-project.md | 27 ++ tools/firmware-build/fpga/ise.tcl | 32 +++ tools/firmware-build/fpga/ise_bootstrap.py | 23 ++ tools/firmware-build/fpga/ise_project.py | 185 ++++++++++++++ tools/firmware-build/fpga/quartus.tcl | 60 +++++ tools/firmware-build/fpga/tests/test_flows.py | 96 +++++++ .../fpga/tests/test_identity.py | 94 +++++++ .../fpga/tests/test_ise_project.py | 138 ++++++++++ tools/firmware-build/fpga/vivado.tcl | 56 ++++ 19 files changed, 1227 insertions(+) create mode 100644 tools/firmware-build/fpga/.gitattributes create mode 100644 tools/firmware-build/fpga/INSTALL_ISE.bat create mode 100644 tools/firmware-build/fpga/ISE_PORTING.md create mode 100644 tools/firmware-build/fpga/README.md create mode 100644 tools/firmware-build/fpga/common.tcl create mode 100644 tools/firmware-build/fpga/firmware_identity.example.json create mode 100644 tools/firmware-build/fpga/identity.py create mode 100644 tools/firmware-build/fpga/ise-build.bat create mode 100644 tools/firmware-build/fpga/ise-env.bat create mode 100644 tools/firmware-build/fpga/ise-project.md create mode 100644 tools/firmware-build/fpga/ise.tcl create mode 100644 tools/firmware-build/fpga/ise_bootstrap.py create mode 100644 tools/firmware-build/fpga/ise_project.py create mode 100644 tools/firmware-build/fpga/quartus.tcl create mode 100644 tools/firmware-build/fpga/tests/test_flows.py create mode 100644 tools/firmware-build/fpga/tests/test_identity.py create mode 100644 tools/firmware-build/fpga/tests/test_ise_project.py create mode 100644 tools/firmware-build/fpga/vivado.tcl diff --git a/firmware-version-porting.md b/firmware-version-porting.md index ece253c..9844ffb 100644 --- a/firmware-version-porting.md +++ b/firmware-version-porting.md @@ -4,6 +4,7 @@ - [Пошаговое подключение модуля версии](c/firmware-info/PORTING.md). - [BAT-файлы precompile и postcompile для CCS и Keil](tools/firmware-build/README.md). +- [Шаблон контроля версий ПЛИС: Xilinx ISE, Vivado и Altera/Intel Quartus](tools/firmware-build/fpga/README.md). - [Настройка подготовки и публикации образов](tools/firmware-publish/PORTING.md). В режиме CCS `--identity` precompile создаёт заголовок версии и Git-метаданные, а postcompile преобразует OUT в SCI8 HEX/BIN и создаёт manifest и SHA-256. В прежнем режиме postcompile запускает SETGUI preflight готового образа. Для каждого проекта задаются явные пути; алгоритмы остаются в templates. diff --git a/tools/firmware-build/fpga/.gitattributes b/tools/firmware-build/fpga/.gitattributes new file mode 100644 index 0000000..22f70a5 --- /dev/null +++ b/tools/firmware-build/fpga/.gitattributes @@ -0,0 +1,2 @@ +# CMD требует CRLF для надёжного чтения BAT с русскими комментариями в UTF-8. +*.bat text eol=crlf diff --git a/tools/firmware-build/fpga/INSTALL_ISE.bat b/tools/firmware-build/fpga/INSTALL_ISE.bat new file mode 100644 index 0000000..0186b94 --- /dev/null +++ b/tools/firmware-build/fpga/INSTALL_ISE.bat @@ -0,0 +1,29 @@ +@chcp 65001 >nul +@rem Переключение на UTF-8 нужно для русских комментариев и путей; установщик создаёт локальные файлы ISE. +@echo off +rem Сохраняет окружение и не раскрывает восклицательные знаки в путях проекта. +setlocal EnableExtensions DisableDelayedExpansion +rem Предпочитает штатный Windows launcher Python 3, если он установлен. +where py >nul 2>nul +rem При отсутствии launcher использует Python из PATH. +if errorlevel 1 goto use_python +rem Передаёт путь проекта или дополнительные параметры без изменения их порядка. +py -3 "%~dp0ise_project.py" install %* +rem Запоминает код установки до вывода подсказок и ожидания клавиши. +set "FW_EXIT=%errorlevel%" +rem Не запускает установку повторно через другой интерпретатор. +goto done +rem Начинает вариант для компьютеров без Windows launcher. +:use_python +rem При двойном щелчке Python запросит путь к проекту интерактивно. +python "%~dp0ise_project.py" install %* +rem Сохраняет исходный результат установщика. +set "FW_EXIT=%errorlevel%" +rem Завершает оба варианта запуска одинаково. +:done +rem Автоматические вызовы могут отключить ожидание переменной окружения. +if defined FW_NO_PAUSE exit /b %FW_EXIT% +rem Оставляет результат видимым при запуске двойным щелчком или перетаскиванием .xise. +pause +rem Передаёт вызывающей программе результат установки, а не команды pause. +exit /b %FW_EXIT% diff --git a/tools/firmware-build/fpga/ISE_PORTING.md b/tools/firmware-build/fpga/ISE_PORTING.md new file mode 100644 index 0000000..b40604d --- /dev/null +++ b/tools/firmware-build/fpga/ISE_PORTING.md @@ -0,0 +1,42 @@ +# Простое подключение контроля прошивки к ISE + +1. Запустите **`INSTALL_ISE.bat` из этого каталога** и вставьте путь к вашему + `.xise`. Можно просто перетащить `.xise` на этот BAT. +2. Установщик сам прочитает кристалл, язык, имя `.bit` и рабочий каталог + из проекта, скопирует локальные команды и создаст настройки. +3. Один раз подключите паспорт к шине проекта по созданному файлу + `firmware_identity_instance.txt`: адрес слова — `word_addr[3:0]`, + данные — `word_data[15:0]`. Без использования выхода паспорт удалит синтезатор. +4. Для сборки запускайте **`build_firmware.bat` рядом с `.xise`**. + Для проверки настройки без сборки — `build_firmware.bat --check`. + +Автоматически создаются: + +| Файл | Назначение | +|---|---| +| `build_firmware.bat`, `firmware_build.py` | Локальная команда сборки | +| `firmware_build.json` | Найденные пути проекта, библиотеки templates, `.bit` и окружения ISE | +| `firmware_identity.json` | Изделие, кристалл и сохраняемый счётчик версии | +| `firmware_identity_instance.txt` | Заготовка подключения для Verilog или VHDL | +| `FIRMWARE_SETUP.md` | Памятка внутри проекта | +| `build/ise/generated/` | Предварительно созданный HDL-паспорт; обновляется перед каждой сборкой | + +Нужен Python 3.9+ через `py -3` или `python`. Окружение ISE ищется в PATH +и стандартных каталогах Xilinx. Для нестандартной установки один раз задайте +`ise_settings` в `firmware_build.json` — полный путь к `settings64.bat` +или `settings32.bat`. + +Общие инструменты используются из вашей библиотеки templates; вручную +копировать её внутрь проекта не требуется. Если библиотека переехала, +исправьте поле `templates` в `firmware_build.json`. + +Первая сборка получает **0.1.1**. Установка и `--check` номер не расходуют; +неудачная попытка синтеза расходует. Повторная установка сохраняет существующие +JSON и версию; чужие BAT с тем же именем не перезаписывает. + +Готовый `.bit`, manifest, SHA-256, HDL и метаданные сохраняются в +`build/ise/firmware/HASH_ДАТА_ВРЕМЯ_UTC+3/`. После загрузки на плату сравните +12 слов паспорта с `fpga.register_words` в manifest. + +Установщик предназначен для FPGA-проектов с результатом `.bit`; CPLD с `.jed` +требует отдельного шаблона. [Подробности паспорта и прямая Tcl-сборка](README.md). diff --git a/tools/firmware-build/fpga/README.md b/tools/firmware-build/fpga/README.md new file mode 100644 index 0000000..2a1a542 --- /dev/null +++ b/tools/firmware-build/fpga/README.md @@ -0,0 +1,241 @@ +# Контроль прошивок ПЛИС: Xilinx ISE, Vivado и Altera Quartus + +Для ISE: запустите `INSTALL_ISE.bat`, укажите `.xise`, затем используйте +созданный в проекте `build_firmware.bat`. [Краткая инструкция](ISE_PORTING.md). + +Шаблон подключает к существующему проекту ПЛИС общий механизм +[`firmware-info`](../../../c/firmware-info/README.md): сохраняемый итератор +SemVer, время сборки в UTC, Git build ID, manifest, SHA-256 и архив выпуска. +Параметры кристалла, выводы, частоты, ограничения и транспорт чтения регистров +задаёт проект платы. + +Цепочка: проект → Tcl своей САПР → `identity.py` из этого каталога → общий +`c/firmware-info/tools/identity.py`. Итератор, правила Git и архивирования +используются те же, что для CCS и Keil. + +## Файлы и зависимости + +| Файл | Назначение | Зависимости | +|---|---|---| +| `firmware_identity.example.json` | Начальная конфигурация изделия и счётчика | Копируется в проект | +| `INSTALL_ISE.bat`, `ise_project.py` | Автоматическая установка локальных BAT, JSON, HDL и памятки из `.xise` | Windows, Python 3.9+ | +| `ise-build.bat`, `ise_bootstrap.py`, `ise-project.md` | Шаблоны локальной команды сборки и памятки | Копируются установщиком в проект | +| `identity.py` | Генерация Verilog-2001/VHDL-93 и контроль готового файла | Python 3.9+, stdlib, общий `identity.py` из templates | +| `common.tcl` | Пути, язык, вызовы Python, обработка отказов | Tcl 8.5+ в САПР | +| `ise.tcl` | Полная сборка `.xise` до `.bit` | Xilinx ISE / `xtclsh` | +| `vivado.tcl` | Полная сборка `.xpr` до `.bit` | Vivado Project Mode | +| `quartus.tcl` | Полная сборка `.qpf` до `.sof` | Altera/Intel Quartus II или Prime / `quartus_sh` | + +Python 3 должен быть доступен как `python` из окружения САПР. Если ISE или +Quartus подставляет старый Python, передайте путь к `python.exe` шестым +аргументом. Git в PATH нужен для хешей; при недоступном Git получается +явный `NOGIT000`, локальная сборка продолжается. + +## 1. Конфигурация проекта + +Скопируйте `firmware_identity.example.json` рядом с `.xise`, `.xpr` или `.qpf` +под именем `firmware_identity.json`. Пример намеренно требует заменить имя +кристалла; задайте своё изделие и точный part number. + +| Поле | Смысл | +|---|---| +| `product` | Имя изделия, например `MY_FPGA_BOARD` | +| `target` | Точное обозначение кристалла; информационное поле, настройки part в проекте не меняет | +| `version` | Последний занятый номер `[major, minor, patch]`; в примере `[0, 1, 0]` | +| `increment_version` | `true` включает общий сохраняемый итератор; `false` оставляет ручную версию | + +Первая подготовка примера выдаёт **0.1.1**. Следующий pre-build выдаёт 0.1.2, +включая попытки после ошибки синтеза. Переносы: 0.1.999 → 0.2.0, +0.255.999 → 1.0.0. После 255.255.999 сборка останавливается. Post-build номер +не увеличивает. Clean не сбрасывает конфигурацию. + +Храните этот JSON в Git. Каталог `build/` добавьте в `.gitignore` проекта; +файлы результатов САПР также должны игнорироваться, иначе они пометят сборку +как dirty. Одна конфигурация JSON обслуживает только одну сборку одновременно. +Для независимых ревизий платы используйте отдельные JSON и выходные каталоги. + +## 2. Подключение паспорта к логике + +Генератор создаёт `generated/firmware_identity.v` и +`generated/firmware_identity.vhd`. Tcl добавляет в проект только выбранный +язык. Паспорт — комбинационный ROM из 12 слов по 16 бит: + +| Относительный адрес слова | Значение | +|---|---| +| 0 | Версия контракта: 1 | +| 1, 2, 3 | Major, minor, patch | +| 4 | Год, 2000..2199 | +| 5 | Месяц в битах 15..8, день в 7..0 | +| 6 | Час UTC в битах 15..8, минута в 7..0 | +| 7 | Секунда UTC | +| 8..11 | Восемь ASCII-символов build ID, первый символ пары в старшем октете | +| 12..15 | Ноль | + +Адреса относительные, без привязки к CPU, AXI, Avalon, SPI, Modbus или SETCAN. +Базовый адрес в системе назначает проект. Это тот же порядок слов, что в +`firmware_info_to_registers()`. Порядок байтов на конкретной шине задаёт +адаптер проекта. + +В верхний модуль Verilog добавьте экземпляр: + +```verilog +wire [15:0] identity_data; // 16-битное слово паспорта для мультиплексора чтения шины проекта. +firmware_identity u_identity ( // Экземпляр генерируемого до синтеза паспорта текущей сборки. + .word_addr(identity_word_offset), // Четыре младших бита относительного адреса слова в выделенном окне регистров. + .word_data(identity_data) // Выход должен участвовать в ответе шины, чтобы синтезатор сохранил паспорт. +); // Выбор окна и тактовое согласование выполняет логика проекта. +``` + +Для VHDL объявите component в declarative part архитектуры и подключите его +в теле архитектуры; component не требует заранее анализировать generated entity: + +```vhdl +component firmware_identity is -- Объявление размещается до begin архитектуры верхнего уровня. + port ( -- Интерфейс совпадает с генерируемой entity firmware_identity. + word_addr : in std_logic_vector(3 downto 0); -- Относительный адрес одного из 12 слов паспорта. + word_data : out std_logic_vector(15 downto 0) -- Данные для ответа шины проекта. + ); -- Закрывает список портов компонента. +end component; -- Привязка к entity из work выполняется при elaboration. +signal identity_data : std_logic_vector(15 downto 0); -- Объявляется до begin и подключается к чтению регистров. +-- Следующий экземпляр размещается после begin архитектуры верхнего уровня. +u_identity : firmware_identity -- Создаёт экземпляр паспорта без примитивов производителя. + port map ( -- Согласует имена сигналов проекта с интерфейсом компонента. + word_addr => identity_word_offset, -- Четырёхбитный сигнал относительного адреса слова задаёт проект. + word_data => identity_data -- Выход включается в мультиплексор ответа хосту. + ); -- Завершает подключение экземпляра. +``` + +`identity_word_offset`, декодер окна и ответ шины реализуйте в проекте. +Паспорт не имеет clock/reset, чтение комбинационное; при необходимости +зарегистрируйте ответ в тактовом домене шины. Без подключения выхода синтезатор +удалит паспорт. Смена языка существующего проекта требует удалить прежний +generated-файл из списка исходников, чтобы не получить два одноимённых модуля. + +## 3. Полная сборка + +Команды запускаются **из корня проекта** в командной строке с настроенным +окружением соответствующей САПР. В примерах templates подключён как +`lib/templates`. Проект должен уже содержать свой top, part и UCF/XDC/QSF. +Сценарии регистрируют generated-исходник в существующем проекте и выполняют +полную цепочку до файла программирования. + +Аргументы общие: `project config output image verilog|vhdl [python]`. +Пути разрешаются относительно начального рабочего каталога. `image` — точный +путь результата вашей САПР, а `output` — отдельный каталог паспорта и архивов; +передача `output` не меняет настройки выходного каталога САПР. + +**ISE:** + +```bat +rem Собирает существующий ISE-проект, в котором BitGen создаёт top.bit рядом с .xise. +xtclsh "lib/templates/tools/firmware-build/fpga/ise.tcl" "board.xise" "firmware_identity.json" "build/ise" "top.bit" verilog +``` + +Используется `Generate Programming File -force rerun_all`: XST, реализация +и BitGen выполняются заново. Логический `false` от процесса считается ошибкой. + +**Vivado:** + +```bat +rem Замените board.runs/impl_1/top.bit реальным путём .bit выбранного implementation run. +vivado -mode batch -source "lib/templates/tools/firmware-build/fpga/vivado.tcl" -tclargs "board.xpr" "firmware_identity.json" "build/vivado" "board.runs/impl_1/top.bit" verilog +``` + +Берётся активный implementation run и его родительский synthesis run; +нестандартные имена runs поддерживаются. Оба запуска сбрасываются, затем +выполняются синтез и реализация до `write_bitstream`. После `wait_on_run` +отдельно проверяется `PROGRESS`, поэтому завершение с ошибкой не вызывает упаковку. + +**Altera / Intel Quartus:** + +```bat +rem Собирает текущую revision из .qpf; image должен совпадать с результатом Assembler. +quartus_sh -t "lib/templates/tools/firmware-build/fpga/quartus.tcl" "board.qpf" "firmware_identity.json" "build/quartus" "output_files/board.sof" vhdl +``` + +`execute_flow -compile` запускает полную компиляцию с Assembler. +Для другой revision передайте седьмой аргумент после пути к Python: + +```bat +rem Укажите реальный Python 3 и отдельный JSON счётчика ревизии B. +quartus_sh -t "lib/templates/tools/firmware-build/fpga/quartus.tcl" "board.qpf" "identity_B.json" "build/quartus_B" "output_files/board_B.sof" vhdl "C:/Python313/python.exe" "board_B" +``` + +Не добавляйте второе увеличение версии в существующие pre-flow/pre-synthesis hooks. +Эти Tcl-файлы предназначены для запуска полной сборки из командной строки; +их нельзя подключать как вложенные hooks этапов синтеза. Для выпуска через +данную схему запускайте указанный сценарий, в том числе после работы в GUI. + +## 4. Результаты и проверка + +```text +build/vivado/ + generated/ + firmware_identity.h + firmware_identity.v + firmware_identity.vhd + firmware_identity.json + firmware/ + HASH_YYYY-MM-DD_HH-MM-SS_UTC+3/ + top.bit + top.bit.manifest.json + top.bit.sha256 + firmware_identity.v + firmware_identity.json +``` + +Для VHDL архив содержит выбранный `.vhd`, для Quartus — `.sof` вместо `.bit`. +Manifest и `.sha256` также создаются рядом с исходным файлом программирования. +Хеш и дата архивной папки берутся из pre-build, дата имени переводится в UTC+3; +в самом паспорте остаётся UTC. Знак `+` у build ID означает изменённые исходники +или templates. `firmware_identity.h` — сопутствующий результат общего генератора; +FPGA-сценарии используют HDL. + +Упаковка отклоняет отсутствующий, пустой или не обновившийся после prepare +файл. Проверяется содержимое и время записи: повторная запись тех же байтов +допускается. Это защита от старого результата; она не проверяет наличие паспорта +внутри vendor bitstream. Правильность подключения подтверждается чтением всех +12 регистров с работающей ПЛИС и сравнением с `fpga.register_words` в manifest. +SHA-256 относится к файлу программатора целиком и хранится снаружи образа. + +Проверить сохранённый файл можно общим инструментом: + +```bat +rem Проверяет размер и SHA-256 указанного файла по созданному рядом manifest. +python "lib/templates/c/firmware-info/tools/identity.py" verify --image "board.runs/impl_1/top.bit" --manifest "board.runs/impl_1/top.bit.manifest.json" +``` + +Для локального экспорта папки выпуска повторите только finish с `--export`; +номер версии при этом не меняется: + +```bat +rem Копирует текущую архивную папку и проверяет SHA-256 экспортной копии. +python "lib/templates/tools/firmware-build/fpga/identity.py" finish --metadata "build/vivado/generated/firmware_identity.json" --output "build/vivado/firmware" --export "D:/Firmware/FPGA" +``` + +Шаблон выпускает `.bit` и `.sof`. Преобразование в `.mcs`, `.bin`, `.pof` или +`.rbf`, загрузка на плату и публикация в сетевую базу требуют отдельного +проектного этапа. Контрольная сумма нативного образа не переносится на +преобразованный файл: для него создайте отдельные seal/verify общим инструментом. + +## Проверки и состояние + +Хостовые тесты проверяют эталон всех 12 слов, совпадение Verilog/VHDL, +итератор, свежесть результата, повреждение SHA-256, архив и экспорт. Реальные +Tcl-сценарии исполняются в Tcl из Python tkinter с заменой API производителей; +Python-генератор и упаковка выполняются полностью. Нужен Python с tkinter/Tcl, +графическое окно не открывается. + +```bat +rem Запускает проверки адаптера и управляющих сценариев без лицензии САПР. +python -m unittest discover -s tools/firmware-build/fpga/tests -v +``` + +Шаблон пока не подключён к конкретной плате. Полный синтез и чтение паспорта +на железе требуют установленной САПР, проекта и платы; хостовые тесты эти +проверки не заменяют. + +Команды сверены с руководствами производителей: +[ISE Command Line Tools UG628](https://docs.amd.com/v/u/en-US/devref), +[Vivado: запуск синтеза и реализации UG939](https://docs.amd.com/r/2023.1-English/ug939-vivado-designing-with-ip-tutorial/Step-8-Launch-Synthesis-and-Implementation), +[Quartus: полный Tcl flow](https://www.intel.com/content/www/us/en/docs/programmable/683432/22-1/the-tcl-shell-in-interactive-mode-example.html). diff --git a/tools/firmware-build/fpga/common.tcl b/tools/firmware-build/fpga/common.tcl new file mode 100644 index 0000000..d72e948 --- /dev/null +++ b/tools/firmware-build/fpga/common.tcl @@ -0,0 +1,76 @@ +# Общие процедуры совместимы с Tcl 8.5 старых ISE; пути передаются списками без eval. +namespace eval fw { + # Определяет Python-инструмент относительно поставки, а не текущего каталога САПР. + variable helper [file normalize [file join [file dirname [info script]] identity.py]] +# Закрывает пространство имён, не меняя глобальные команды САПР. +} +# Проверяет общие аргументы до открытия проекта и резервирования версии. +proc fw::init {arguments toolchain} { + # Объявляет настройки сценария в общем пространстве имён. + variable settings + # Пять обязательных аргументов и необязательный путь к python.exe. + if {[llength $arguments] < 5 || [llength $arguments] > 6} { + # Неверная команда не должна расходовать номер версии. + error "Usage: project config output image verilog|vhdl ?python?" + # Завершает проверку количества аргументов. + } + # Имена полей определяют одинаковый порядок аргументов всех трёх сценариев. + foreach name {project config output image} value [lrange $arguments 0 3] { + # Нормализует пути до перехода в каталог проекта. + set settings($name) [file normalize $value] + # Заканчивает обработку четырёх путей. + } + # Сохраняет выбранный HDL, чтобы в проект не попали две реализации одного модуля. + set settings(language) [lindex $arguments 4] + # Принимает только языки, поддержанные генератором паспорта. + if {[lsearch -exact {verilog vhdl} $settings(language)] < 0} { + # Останавливает сборку при опечатке в языке. + error "Expected verilog or vhdl" + # Заканчивает проверку выбранного языка. + } + # По умолчанию использует Python 3 из PATH, без аргументов командной оболочки. + set settings(python) python + # Полный путь позволяет обойти Python старой версии, встроенный в САПР. + if {[llength $arguments] == 6} { + # Делает путь python.exe абсолютным без раскрытия Windows junction до последующего cd. + set settings(python) [file join [pwd] [lindex $arguments 5]] + # Завершает выбор интерпретатора. + } + # Передаёт генератору имя формата нативного результата. + set settings(toolchain) $toolchain + # Разделяет генерируемые исходники и архивы внутри каталога конфигурации. + set settings(generated) [file join $settings(output) generated] + # Выбирает расширение только одного подключаемого HDL-файла. + set extension [expr {$settings(language) eq "verilog" ? "v" : "vhd"}] + # Имя модуля совпадает в Verilog и VHDL и известно верхнему уровню проекта. + set settings(hdl) [file join $settings(generated) firmware_identity.$extension] + # Проверяет наличие проектного файла до запуска САПР. + if {![file isfile $settings(project)] || ![file isfile $settings(config)]} { + # JSON создаётся пользователем из примера, чтобы не выпустить изделие с чужим именем. + error "Project or firmware identity config does not exist" + # Завершает проверку обязательных файлов. + } + # Зависимые исходники и ограничения проекта разрешаются относительно его каталога. + cd [file dirname $settings(project)] +# Заканчивает инициализацию путей и языка. +} +# Резервирует версию один раз до любых шагов синтеза. +proc fw::prepare {} { + # Получает проверенные аргументы текущего запуска. + variable settings + # Получает абсолютный путь общего генератора. + variable helper + # exec передаёт каждый путь отдельно; stderr остаётся в журнале САПР, ненулевой код вызывает Tcl error. + puts [exec $settings(python) $helper prepare --repository [file dirname $settings(project)] --config $settings(config) --output $settings(generated) --image $settings(image) --toolchain $settings(toolchain) --language $settings(language) 2>@stderr] +# Завершает подготовку паспорта. +} +# Упаковывает результат только после успешного возврата полного flow. +proc fw::finish {} { + # Использует те же пути, что и pre-build данного запуска. + variable settings + # Выбирает тот же Python-инструмент, который создавал паспорт. + variable helper + # Генератор проверяет обновление файла, SHA-256 и архивную копию; ошибка блокирует успешное завершение Tcl. + puts [exec $settings(python) $helper finish --metadata [file join $settings(generated) firmware_identity.json] --output [file join $settings(output) firmware] 2>@stderr] +# Завершает контроль готового образа. +} diff --git a/tools/firmware-build/fpga/firmware_identity.example.json b/tools/firmware-build/fpga/firmware_identity.example.json new file mode 100644 index 0000000..d483e0e --- /dev/null +++ b/tools/firmware-build/fpga/firmware_identity.example.json @@ -0,0 +1,6 @@ +{ + "product": "MY_FPGA_BOARD", + "target": "REPLACE_WITH_EXACT_FPGA_PART", + "version": [0, 1, 0], + "increment_version": true +} diff --git a/tools/firmware-build/fpga/identity.py b/tools/firmware-build/fpga/identity.py new file mode 100644 index 0000000..d1f7e8b --- /dev/null +++ b/tools/firmware-build/fpga/identity.py @@ -0,0 +1,92 @@ +"""Паспорт ПЛИС и контроль готового образа через общий итератор firmware-info.""" # CLI используется из Tcl трёх систем сборки. +from __future__ import annotations # Откладывает вычисление аннотаций для Python 3.9+. +import argparse # Разбирает явные пути, чтобы рабочий каталог IDE не менял назначение файлов. +from datetime import datetime # Разбирает UTC-время, зафиксированное общим pre-build. +import hashlib # Сравнивает исходный и новый образы при защите от устаревшего результата. +import importlib.util # Подключает существующий генератор без второй реализации итератора. +import json # Читает и сохраняет переносимые метаданные сборки в UTF-8. +from pathlib import Path # Нормализует пути проектов, результатов и общей библиотеки. +TEMPLATES = Path(__file__).resolve().parents[3] # От fpga/ поднимается к корню templates. +SPEC = importlib.util.spec_from_file_location("firmware_identity_shared", TEMPLATES / "c/firmware-info/tools/identity.py") # Выбирает общий модуль из этой же поставки. +shared = importlib.util.module_from_spec(SPEC) # Создаёт пространство имён общего генератора без изменения sys.path. +SPEC.loader.exec_module(shared) # Загружает prepare, seal, verify и archive_build без запуска общего CLI. +FORMATS = {"ise": {".bit"}, "vivado": {".bit"}, "quartus": {".sof"}} # Полные сценарии выпускают нативный файл конфигурации своей САПР. + + +def registers(metadata): # Переносит публичный 12-словный контракт firmware-info v1 в константную HDL-память. + stamp = datetime.fromisoformat(metadata["built_at_utc"]) # Общий prepare всегда сохраняет дату с часовым поясом UTC. + words = [1, *metadata["version"], stamp.year, (stamp.month << 8) | stamp.day, (stamp.hour << 8) | stamp.minute, stamp.second] # Слова 0..7: контракт, SemVer и календарные поля; сдвиг на 8 размещает старший октет. + build_id = metadata["build_id"].encode("ascii") # Контракт использует ровно восемь печатных ASCII-символов. + words.extend((build_id[index] << 8) | build_id[index + 1] for index in range(0, 8, 2)) # Слова 8..11 содержат пары символов, первый в старших восьми битах. + return words # Порядок совпадает с firmware_info_to_registers(), включая дату в UTC. + + +def verilog(words): # Генерирует Verilog-2001 без примитивов конкретного производителя. + lines = ["module firmware_identity ( // Комбинационный паспорт сборки с адресацией 16-битными словами.", " input wire [3:0] word_addr, // Четыре бита адресуют слова 0..11; остальные адреса возвращают ноль.", " output reg [15:0] word_data // Данные выбранного слова; синхронизацию с шиной выполняет проект.", "); // Интерфейс не требует тактового сигнала и сброса.", "always @* begin // Полная комбинационная чувствительность исключает устаревшее значение при смене адреса.", " case (word_addr) // Каждому адресу соответствует константа, вычисленная до синтеза."] # Использует синтаксис, доступный старым XST и Quartus II. + lines.extend(f" 4'd{index}: word_data = 16'h{word:04X}; // Слово {index} общего контракта firmware-info v1, значение без знака." for index, word in enumerate(words)) # Явные размеры исключают расширение констант и зависимость от порядка байтов. + lines.extend([" default: word_data = 16'h0000; // Неиспользуемые адреса не создают защёлок и возвращают ноль.", " endcase // Все входные комбинации определяют выход.", "end // Завершает комбинационное чтение паспорта.", "endmodule // Проект должен подключить выход к доступной хосту карте регистров."]) # Выход обязательно используется верхним уровнем, иначе синтезатор удалит паспорт. + return "\n".join(lines) + "\n" # Сохраняет единый формат строк UTF-8 с завершающим переводом строки. + + +def vhdl(words): # Генерирует VHDL-93 с тем же интерфейсом для проектов без Verilog. + lines = ["library ieee; -- Подключает стандартную библиотеку логических типов.", "use ieee.std_logic_1164.all; -- Определяет std_logic_vector для адреса и 16-битного слова.", "entity firmware_identity is -- Объявляет паспорт, подключаемый к карте регистров проекта.", " port ( -- Описывает комбинационный интерфейс без тактового домена.", " word_addr : in std_logic_vector(3 downto 0); -- Адрес слова 0..11; четыре бита покрывают весь контракт.", " word_data : out std_logic_vector(15 downto 0) -- 16-битное значение общего регистра версии.", " ); -- Завершает описание портов.", "end firmware_identity; -- Закрывает внешний интерфейс паспорта.", "architecture rtl of firmware_identity is -- Реализует паспорт только константами без памяти производителя.", "begin -- Начинает комбинационную архитектуру.", " with word_addr select word_data <= -- При изменении адреса немедленно выбирает соответствующее слово."] # Выбор с others определяет выход для всех состояний входа. + lines.extend(f' x"{word:04X}" when "{index:04b}", -- Слово {index} контракта firmware-info v1, шестнадцатеричная константа 16 бит.' for index, word in enumerate(words)) # Двоичные селекторы не требуют numeric_std и преобразования адреса. + lines.extend([' x"0000" when others; -- Неиспользуемые и неопределённые адреса возвращают нулевое слово.', "end rtl; -- Завершает синтезируемый паспорт сборки."]) # Полный выбор исключает защёлки. + return "\n".join(lines) + "\n" # Возвращает текст для атомарной записи в UTF-8. + + +def fingerprint(image): # Фиксирует состояние результата перед сборкой для отказа при повторной упаковке старого файла. + if not image.exists(): # При первой сборке ожидаемого образа ещё нет. + return None # Любой непустой файл после успешной сборки будет новым результатом. + return {"mtime_ns": image.stat().st_mtime_ns, "sha256": hashlib.sha256(image.read_bytes()).hexdigest()} # Изменение времени допускает побайтно воспроизводимую пересборку. + + +def prepare(repository, config, output, image, toolchain, language): # Резервирует единственный номер до синтеза и создаёт оба варианта HDL. + repository, config, output, image = (path.resolve() for path in (repository, config, output, image)) # Все пути в метаданных независимы от последующих cd в САПР. + if image.suffix.lower() not in FORMATS[toolchain]: # Не выдаёт произвольный или служебный файл за нативный результат данного flow. + raise ValueError(f"{toolchain}: expected {sorted(FORMATS[toolchain])}") # Неверный путь останавливает подготовку до увеличения версии. + before = fingerprint(image) # Читает старый результат до резервирования номера, чтобы отказ чтения не занимал версию. + metadata = shared.prepare(repository, TEMPLATES, config, output) # Использует общий атомарный итератор, Git, SOURCE_DATE_EPOCH и UTC. + words = registers(metadata) # Упаковывает уже зарезервированную версию в общий контракт регистров. + metadata["fpga"] = {"toolchain": toolchain, "language": language, "image_path": str(image), "image_before": before, "register_words": words} # Связывает post-build с конкретным файлом и снимком pre-build. + shared.write_atomic(output / "firmware_identity.v", verilog(words)) # Даёт старым XST/Quartus синтезируемый Verilog-2001. + shared.write_atomic(output / "firmware_identity.vhd", vhdl(words)) # Даёт VHDL-проекту тот же паспорт без смешения языков. + shared.write_atomic(output / "firmware_identity.json", json.dumps(metadata, ensure_ascii=False, indent=2) + "\n") # Сохраняет FPGA-привязку в тех же метаданных, которые попадут в manifest. + return metadata # Вызывающий сценарий добавляет в проект только один выбранный язык. + + +def finish(metadata_path, output, export=None): # Вызывается только после успешной полной сборки нативного образа. + metadata_path = metadata_path.resolve() # Исключает зависимость пути от рабочего каталога post-build. + metadata = json.loads(metadata_path.read_text(encoding="utf-8")) # Использует сохранённый pre-build, не запрашивая Git и время повторно. + image = Path(metadata["fpga"]["image_path"]) # Упаковывает исключительно тот файл, который был указан перед синтезом. + if not image.is_file() or not image.stat().st_size: # Отсутствующий или пустой результат не может стать выпуском. + raise ValueError(f"Missing or empty FPGA image: {image}") # Ошибка блокирует создание manifest и архива. + if fingerprint(image) == metadata["fpga"]["image_before"]: # Старый файл с прежним временем и содержимым означает отсутствие нового результата. + raise ValueError("FPGA image was not updated after prepare") # Не связывает новый номер версии с прежней прошивкой после неудачного запуска. + shared.seal(image, metadata_path) # Считает SHA-256 точных байтов .bit/.sof, передаваемых программатору. + shared.verify(image, image.with_suffix(image.suffix + ".manifest.json")) # Проверяет размер и контрольную сумму до архивирования. + extension = "v" if metadata["fpga"]["language"] == "verilog" else "vhd" # Выбирает точный HDL-паспорт, зарегистрированный в проекте перед синтезом. + hdl = metadata_path.parent / ("firmware_identity." + extension) # Хранит исходник констант рядом с pre-build JSON. + return shared.archive_build(image, metadata_path, output, extra_files=(hdl,), export=export) # Сохраняет HDL с образом; общий архиватор проверяет локальную и экспортную копии. + + +def main(): # Разделяет подготовку и упаковку, чтобы Tcl мог остановиться между ними при ошибке САПР. + parser = argparse.ArgumentParser(description=__doc__) # Печатает назначение общего FPGA-инструмента в --help. + commands = parser.add_subparsers(dest="command", required=True) # Требует явный этап сборки. + before = commands.add_parser("prepare") # Создаёт интерфейс pre-build без запуска САПР из Python. + for name in ("repository", "config", "output", "image"): # Все входные и выходные пути передаются отдельными аргументами. + before.add_argument("--" + name, type=Path, required=True) # Path сохраняет пробелы и кириллицу без shell-подстановки. + before.add_argument("--toolchain", choices=FORMATS, required=True) # Ограничивает форматы результата выбранной САПР. + before.add_argument("--language", choices=("verilog", "vhdl"), default="verilog") # Позволяет выбрать один HDL для регистрации в проекте. + after = commands.add_parser("finish") # Создаёт интерфейс post-build только для готового результата. + after.add_argument("--metadata", dest="metadata_path", type=Path, required=True) # Требует тот же паспорт, что был создан перед синтезом. + after.add_argument("--output", type=Path, required=True) # Размещает архивы отдельно от файлов синтеза. + after.add_argument("--export", type=Path) # По явному запросу копирует проверенную архивную папку в локальный каталог. + arguments = vars(parser.parse_args()) # Преобразует именованные аргументы в параметры выбранной функции. + command = arguments.pop("command") # Удаляет служебное имя команды из аргументов функции. + result = {"prepare": prepare, "finish": finish}[command](**arguments) # Ошибки прерывают процесс с ненулевым кодом для Tcl catch. + print(json.dumps(result, ensure_ascii=False)) # Даёт журналу САПР путь архива и использованные метаданные. + + +if __name__ == "__main__": # Импорт в тестах не должен изменять проектную версию. + main() # Запускает CLI только при прямом вызове Python. diff --git a/tools/firmware-build/fpga/ise-build.bat b/tools/firmware-build/fpga/ise-build.bat new file mode 100644 index 0000000..3c15bc3 --- /dev/null +++ b/tools/firmware-build/fpga/ise-build.bat @@ -0,0 +1,19 @@ +@chcp 65001 >nul +@rem Переключение на UTF-8 сохраняет русские пути и комментарии локальной команды сборки ISE. +@echo off +rem Не допускает изменения окружения родительской консоли и раскрытия символа ! в путях. +setlocal EnableExtensions DisableDelayedExpansion +rem Находит штатный launcher Python 3 без привязки к каталогу его установки. +where py >nul 2>nul +rem При отсутствии launcher переключается на Python из PATH. +if errorlevel 1 goto use_python +rem Запускает локальную обвязку независимо от текущего рабочего каталога. +py -3 "%~dp0firmware_build.py" %* +rem Возвращает точный код сборки или проверки параметров. +exit /b %errorlevel% +rem Обслуживает компьютеры, где установлен только python.exe. +:use_python +rem Передаёт необязательный --check для проверки настройки без увеличения версии. +python "%~dp0firmware_build.py" %* +rem Не скрывает ошибку отсутствующего Python, окружения ISE или самой сборки. +exit /b %errorlevel% diff --git a/tools/firmware-build/fpga/ise-env.bat b/tools/firmware-build/fpga/ise-env.bat new file mode 100644 index 0000000..b1fa478 --- /dev/null +++ b/tools/firmware-build/fpga/ise-env.bat @@ -0,0 +1,8 @@ +@rem Получает окружение ISE в дочернем CMD; вывод SET захватывается Python и не попадает в журнал. +@echo off +rem Активирует штатную установку, путь передан через окружение без вставки в shell-код. +call "%FW_ISE_SETTINGS%" >nul +rem Не возвращает частично настроенное окружение после отказа settings.bat. +if errorlevel 1 exit /b %errorlevel% +rem CMD /u выдаёт переменные в UTF-16LE независимо от текущей кодовой страницы. +set diff --git a/tools/firmware-build/fpga/ise-project.md b/tools/firmware-build/fpga/ise-project.md new file mode 100644 index 0000000..a07c3fa --- /dev/null +++ b/tools/firmware-build/fpga/ise-project.md @@ -0,0 +1,27 @@ +# Сборка прошивки ISE + +Для сборки запускайте `build_firmware.bat`. Версия увеличивается перед +синтезом; результат и архив сохраняются в `build/ise/firmware/`. +`build_firmware.bat --check` проверяет настройки и наличие ISE без сборки +и увеличения версии. + +Один раз подключите экземпляр `firmware_identity` к верхнему модулю: +адрес слова — `word_addr[3:0]`, выход — `word_data[15:0]`. +Заготовка подключения находится в `firmware_identity_instance.txt`. +Выход включите в чтение вашей шины, иначе синтезатор удалит паспорт. +Сценарий сам добавит generated HDL к проекту при сборке. + +В `firmware_identity.json` меняются изделие и номер версии. +В `firmware_build.json` находятся пути проекта, `.bit`, templates, +каталог результатов, язык и необязательный путь `ise_settings` к +`settings64.bat` или `settings32.bat` вашей установки ISE. +Если окружение ISE не найдено автоматически, задайте этот путь один раз. + +Общие инструменты используются из каталога templates, указанного в настройках. +Храните локальные BAT, Python, JSON и заготовку подключения в Git. +Каталог сборки добавлен установщиком в `.gitignore`; остальные результаты +ISE также добавьте в игнорируемые файлы проекта. + +После загрузки `.bit` сравните 12 слов паспорта с `fpga.register_words` +в manifest из архива. Повторная установка сохраняет существующие JSON +и занятый номер версии. Одновременные сборки с одним JSON не поддерживаются. diff --git a/tools/firmware-build/fpga/ise.tcl b/tools/firmware-build/fpga/ise.tcl new file mode 100644 index 0000000..2336371 --- /dev/null +++ b/tools/firmware-build/fpga/ise.tcl @@ -0,0 +1,32 @@ +# Подключает общие процедуры из того же каталога поставки templates. +source [file join [file dirname [info script]] common.tcl] +# Любая ошибка подготовки, XST, реализации или упаковки возвращает ненулевой код xtclsh. +if {[catch { + # Принимает project.xise, config.json, output, top.bit, язык и необязательный python.exe. + fw::init $argv ise + # Открывает существующий проект с выбранной платой, top и ограничениями UCF. + project open $fw::settings(project) + # Создаёт HDL-паспорт до синтеза XST и увеличивает только общий счётчик. + fw::prepare + # Добавляет выбранный HDL-паспорт; повторное добавление существующего источника поддерживает ISE. + xfile add $fw::settings(hdl) + # Принудительно повторяет всю цепочку до BitGen, чтобы паспорт вошёл в новый bitstream. + set result [process run "Generate Programming File" -force rerun_all] + # ISE может вернуть false без Tcl-исключения при отказе дочернего процесса. + if {![string is true -strict $result]} { + # Не позволяет упаковать оставшийся от предыдущей сборки файл .bit. + error "ISE Generate Programming File failed: $result" + # Заканчивает проверку результата процесса. + } + # Записывает manifest, SHA-256 и архив только после успешного BitGen. + fw::finish + # Сохраняет регистрацию HDL-паспорта и закрывает проект. + project close +# catch сохраняет текст ошибки, не продолжая цепочку сборки. +} message]} { + # Выводит причину отказа в поток ошибок командной строки. + puts stderr $message + # Ненулевой код позволяет внешнему BAT или CI остановить выпуск. + exit 1 +# Закрывает обработчик ошибок. +} diff --git a/tools/firmware-build/fpga/ise_bootstrap.py b/tools/firmware-build/fpga/ise_bootstrap.py new file mode 100644 index 0000000..148cea7 --- /dev/null +++ b/tools/firmware-build/fpga/ise_bootstrap.py @@ -0,0 +1,23 @@ +"""Локальная обвязка ISE: настройки проекта и запуск общего инструмента templates.""" # Установщик копирует файл как firmware_build.py. +import json # Читает только настройки путей, оставляя номер версии отдельному JSON. +from pathlib import Path # Разрешает пути относительно установленной обвязки. +import subprocess # Передаёт аргументы отдельным списком без сборки shell-команды. +import sys # Сохраняет выбранный Python 3 и код возврата общей сборки. + + +def main(): # Одна локальная команда обращается к алгоритмам общей библиотеки. + config = Path(__file__).resolve().with_name("firmware_build.json") # Не зависит от того, из какой папки запущен BAT. + settings = json.loads(config.read_text(encoding="utf-8-sig")) # Принимает UTF-8, включая JSON, сохранённый редактором с BOM. + templates = (config.parent / settings["templates"]).resolve() # Поддерживает относительное подключение или абсолютный путь библиотеки. + helper = templates / "tools/firmware-build/fpga/ise_project.py" # Хранит реализацию сборки в одном месте для всех проектов. + if not helper.is_file(): # Перемещение библиотеки должно дать понятную причину отказа. + raise ValueError(f"templates not found; edit templates in {config}") # Не запускает сборку с неподходящим инструментом из PATH. + return subprocess.call([sys.executable, str(helper), "build", "--settings", str(config), *sys.argv[1:]]) # Сохраняет пробелы и кириллицу в каждом аргументе. + + +if __name__ == "__main__": # Импорт для проверки не должен запускать сборку проекта. + try: # Превращает ошибку настройки в короткое сообщение для консоли. + sys.exit(main()) # Сохраняет точный код завершения общего Tcl-flow. + except (OSError, ValueError, KeyError) as error: # Обрабатывает отсутствующие файлы и неверный JSON до запуска САПР. + print(f"[firmware-build] {error}", file=sys.stderr) # Не скрывает путь настройки, которую требуется исправить. + sys.exit(2) # Отличает ошибку настройки от успешной сборки. diff --git a/tools/firmware-build/fpga/ise_project.py b/tools/firmware-build/fpga/ise_project.py new file mode 100644 index 0000000..bf250e6 --- /dev/null +++ b/tools/firmware-build/fpga/ise_project.py @@ -0,0 +1,185 @@ +"""Установка локальных BAT и автоматический запуск контроля прошивки проекта ISE.""" # Общие алгоритмы версии остаются в identity.py. +import argparse # Поддерживает интерактивную установку и явные параметры для автоматизации. +import importlib.util # Подключает существующий FPGA-генератор без повторения его алгоритмов. +import json # Сохраняет отдельно параметры сборки и сохраняемый номер версии. +import os # Разрешает относительные пути библиотеки и окружение Windows. +from pathlib import Path # Работает с путями проекта независимо от текущего каталога. +import shutil # Находит xtclsh в PATH настроенного окружения ISE. +import subprocess # Запускает окружение ISE и готовый Tcl-flow с контролем кодов возврата. +import sys # Передаёт Tcl тот же Python 3, которым запущена обвязка. +import tempfile # Подготавливает предварительный HDL без увеличения рабочего счётчика. +import xml.etree.ElementTree as ET # Читает стандартный XML .xise, не меняя исходный проект. +HERE = Path(__file__).resolve().parent # Находит шаблоны рядом с установщиком. +TEMPLATES = HERE.parents[2] # Поднимается от tools/firmware-build/fpga к корню библиотеки. + + +def relative(path, root): # Сохраняет переносимые пути при расположении проекта и templates на одном диске. + try: # Windows не позволяет вычислить относительный путь между разными дисками. + return Path(os.path.relpath(path, root)).as_posix() # JSON использует прямые слеши без двойного экранирования. + except ValueError: # Разные диски требуют абсолютной привязки. + return path.as_posix() # Абсолютный путь можно заменить в firmware_build.json после переноса. + + +def project_info(project, language=None, image=None): # Извлекает параметры из существующего .xise без пользовательского копирования команд. + project = project.resolve() # Нормализует путь до чтения XML и выбора корня проекта. + if project.is_dir(): # Разрешает перетащить папку проекта вместо отдельного .xise. + choices = list(project.glob("*.xise")) # Не выбирает вложенные архивы и другие платы рекурсивным поиском. + if len(choices) != 1: # Несколько проектов требуют явного выбора .xise пользователем. + raise ValueError("Select one .xise file; the directory must contain exactly one project") # Не угадывает плату по времени изменения. + project = choices[0] # Единственный проект определён однозначно. + if project.suffix.lower() != ".xise" or not project.is_file(): # Не принимает произвольный каталог как проект ISE. + raise ValueError(f"ISE project not found: {project}") # Останавливает установку до записи локальных файлов. + tree = ET.parse(project) # Использует XML-парсер stdlib с поддержкой пространства имён Xilinx. + properties = {} # Собирает только свойства проекта, необходимые для запуска сборки. + for element in tree.iter(): # Поддерживает как namespaced .xise, так и минимальные тестовые проекты. + if element.tag.rsplit("}", 1)[-1] == "property": # Игнорирует список исходников и настройки других XML-элементов. + attributes = {key.rsplit("}", 1)[-1]: value for key, value in element.attrib.items()} # Снимает namespace с атрибутов name и value. + properties[attributes.get("name", "")] = attributes.get("value", "") # Читает сохранённое значение свойства без изменения .xise. + device = properties.get("Device", "") # Точное устройство берётся из настроек исходного проекта. + if not device or "cpld" in properties.get("Device Family", "").lower() or device.lower().startswith(("xc95", "xc2c")): # Данный flow выпускает FPGA .bit, а CPLD требует отдельной цепочки .jed. + raise ValueError("A configured FPGA project producing .bit is required") # Не устанавливает неподходящий шаблон на CPLD. + top = properties.get("Implementation Top", "").split("|") # ISE хранит тип и имя top через вертикальный разделитель. + name = properties.get("Output File Name") or (top[1] if len(top) > 1 else "") # Явное имя BitGen имеет приоритет над именем верхнего модуля. + if not name and image is None: # Отсутствующие настройки не должны приводить к выбору случайного .bit. + raise ValueError("Set Implementation Top in ISE or pass --image path/to/top.bit") # Позволяет явно указать нестандартный результат BitGen. + working = project.parent / properties.get("Working Directory", ".") # Учитывает отдельный рабочий каталог реализации ISE. + image = (project.parent / image if image is not None else working / (name if name.lower().endswith(".bit") else name + ".bit")).resolve() # Путь CLI разрешается от проекта, штатный результат — от Working Directory. + if image.suffix.lower() != ".bit": # Только .bit поддерживается исходным ise.tcl. + raise ValueError("ISE image must have .bit extension") # Ошибка пути обнаруживается до создания настройки. + top_file = properties.get("Implementation Top File", "").lower() # Расширение реального верхнего исходника точнее общего предпочтения языка. + detected = "vhdl" if top_file.endswith((".vhd", ".vhdl")) else "verilog" if top_file.endswith((".v", ".sv")) else properties.get("Preferred Language", "Verilog").lower() # Поддерживает оба языка генерируемого паспорта. + target = device + properties.get("Speed Grade", "") + properties.get("Package", "") # Сохраняет устройство, скоростную группу и корпус из .xise в информационном поле target. + return project, image, language or detected, target # Возвращает только параметры, требуемые общему Tcl-flow. + + +def find_settings(): # Ищет стандартную установку ISE без рекурсивного сканирования дисков. + candidates = [] # Порядок поиска предпочитает уже активное окружение. + xilinx = os.environ.get("XILINX") # Штатная переменная ISE обычно указывает на ISE_DS/ISE. + if xilinx: # Активное окружение даёт наиболее точную подсказку расположения. + candidates.extend(Path(xilinx).parent / name for name in ("settings64.bat", "settings32.bat")) # Проверяет оба варианта разрядности установки. + for drive in "CDEFGHIJKLMNOPQRSTUVWXYZ": # Проверяет стандартный корень Xilinx только на обычных дисках Windows. + base = Path(drive + ":/Xilinx") # Не просматривает содержимое пользовательских проектов. + if base.is_dir(): # Отсутствующий диск или каталог пропускается без ошибки установки. + candidates.extend(sorted(base.glob("*/ISE_DS/settings64.bat"), reverse=True)) # Сначала предлагает 64-битную установку из стандартной структуры. + candidates.extend(sorted(base.glob("*/ISE_DS/settings32.bat"), reverse=True)) # Поддерживает старые 32-битные установки при отсутствии 64-битной. + return next((str(path.resolve()) for path in candidates if path.is_file()), "") # Пустое значение разрешает настроить путь позже. + + +def install(project, language=None, image=None, ise_settings=None): # Создаёт локальные команды и настройки без увеличения версии. + project, image, language, target = project_info(project, language, image) # Проверяет все входные параметры до записи файлов. + if language not in ("verilog", "vhdl"): # Не переносит неизвестные предпочтения языка в общий flow. + raise ValueError("Expected verilog or vhdl") # Ошибка языка требует явного --language при установке. + root = project.parent # Все локальные файлы лежат рядом с .xise для простого запуска. + build_path = root / "firmware_build.json" # Настройки путей отделены от сохраняемого итератора версии. + identity_path = root / "firmware_identity.json" # Существующая рабочая версия никогда не заменяется примером. + settings = {"schema": 1, "project": project.name, "templates": relative(TEMPLATES, root), "image": relative(image, root), "language": language, "output": "build/ise", "ise_settings": str(ise_settings.resolve()) if ise_settings else find_settings()} # По умолчанию пользователь не редактирует пути вручную. + if build_path.exists(): # Повторная установка должна сохранить индивидуальные настройки сборки. + settings = json.loads(build_path.read_text(encoding="utf-8-sig")) # Использует прежний output и язык при создании предварительного HDL. + if (root / settings["project"]).resolve() != project: # Один набор локальных BAT не должен незаметно переключиться на другую плату. + raise ValueError("firmware_build.json belongs to another .xise project") # Требует отдельную папку настройки для другого проекта. + identity = json.loads(identity_path.read_text(encoding="utf-8-sig")) if identity_path.exists() else {"product": project.stem, "target": target, "version": [0, 1, 0], "increment_version": True} # Сохраняет прежний счётчик побайтно, а новый заполняет из .xise. + if type(identity.get("increment_version", False)) is not bool: # Предварительная генерация не должна скрыть неверный тип рабочего флага итератора. + raise ValueError("increment_version must be true or false") # Останавливает установку до создания предварительного HDL. + files = {root / "build_firmware.bat": (HERE / "ise-build.bat").read_bytes(), root / "firmware_build.py": (HERE / "ise_bootstrap.py").read_bytes(), root / "FIRMWARE_SETUP.md": (HERE / "ise-project.md").read_bytes()} # Копирует только локальные обвязки; алгоритмы остаются в указанной библиотеке templates. + for path, data in files.items(): # Проверяет коллизии всех управляемых файлов до первой записи. + if path.exists() and path.read_bytes() != data: # Не перезаписывает чужой BAT или правки пользователя при повторном запуске. + raise ValueError(f"Existing file differs; preserve or rename it before installation: {path}") # Существующие пользовательские файлы требуют явного разрешения конфликта. + spec = importlib.util.spec_from_file_location("ise_install_identity", HERE / "identity.py") # Использует тот же генератор, что последующая сборка. + fpga = importlib.util.module_from_spec(spec) # Создаёт изолированный модуль подготовки предварительного HDL. + spec.loader.exec_module(fpga) # Загружает общий итератор и FPGA-адаптер без запуска CLI. + output = (root / settings["output"]).resolve() # Учитывает выходной каталог, сохранённый предыдущей установкой. + output.mkdir(parents=True, exist_ok=True) # Создаёт место предварительного паспорта и временной конфигурации. + with tempfile.TemporaryDirectory(prefix=".ise-setup-", dir=output) as temporary: # Не редактирует рабочую версию ради предварительной генерации исходников. + preview = Path(temporary) / "identity.json" # Временный JSON существует только во время установки. + preview.write_text(json.dumps({**identity, "increment_version": False}, ensure_ascii=False), encoding="utf-8") # Явно отключает итератор только в копии для предварительного HDL. + fpga.prepare(root, preview, output / "generated", (root / settings["image"]).resolve(), "ise", settings["language"]) # Создаёт HDL до первого запуска ISE, не занимая номер. + for path, data in files.items(): # Записывает заранее проверенные локальные обвязки. + if not path.exists(): # Повторная установка не меняет время и содержимое прежних файлов. + path.write_bytes(data) # Сохраняет исходные UTF-8 файлы из templates без изменения комментариев. + for path, data in ((build_path, settings), (identity_path, identity)): # Устанавливает две настройки с разными назначениями. + if not path.exists(): # Существующие настройки и рабочая версия остаются побайтно прежними. + path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") # Новые JSON доступны для обычного ручного редактирования. + snippet = root / "firmware_identity_instance.txt" # Отдельная заготовка показывает единственную проектную часть подключения. + if not snippet.exists(): # Не меняет уже адаптированный пользователем экземпляр паспорта. + snippet.write_text(instance(settings["language"]), encoding="utf-8") # Генерирует пример именно для языка проекта. + ignore = root / ".gitignore" # Исключение результатов предотвращает ложный dirty от generated-файлов. + existing = ignore.read_text(encoding="utf-8-sig") if ignore.exists() else "" # Сохраняет все существующие правила игнорирования проекта. + ignored = relative(output, root) + "/" # Привязывает исключение к установленному выходному каталогу. + if output.is_relative_to(root) and ignored not in existing.splitlines(): # Внешние каталоги не добавляет в .gitignore данного репозитория. + with ignore.open("a", encoding="utf-8", newline="\n") as stream: # Дописывает одно правило, не заменяя пользовательский файл. + stream.write(("\n" if existing and not existing.endswith("\n") else "") + "# Результаты контроля прошивки ISE.\n" + ignored + "\n") # Отделяет новое правило и объясняет его назначение. + print(f"[firmware-build] Installed: {root / 'build_firmware.bat'}") # Показывает готовую команду для обычной сборки. + print(f"[firmware-build] Connect identity ports using: {snippet}") # Оставляет пользователю только подключение к шине конкретного проекта. + return settings # Позволяет тестам проверить автоматически извлечённые параметры. + + +def instance(language): # Возвращает короткую заготовку подключения без изменения верхней схемы пользователя. + if language == "verilog": # Verilog допускает прямое создание экземпляра с именованными портами. + return "wire [15:0] identity_data; // Слово паспорта подключается к мультиплексору чтения вашей шины.\nfirmware_identity u_identity ( // Генерируемый модуль добавляется сценарием сборки.\n .word_addr(identity_word_offset), // Четырёхбитный относительный адрес слова задаёт декодер проекта.\n .word_data(identity_data) // Выход должен использоваться схемой, иначе синтезатор удалит паспорт.\n); // Тактовое согласование чтения выполняет проект.\n" # Каждый элемент интерфейса снабжён пояснением для адаптации. + return "component firmware_identity is -- Объявляется до begin архитектуры верхнего уровня.\n port ( -- Описывает интерфейс генерируемого паспорта.\n word_addr : in std_logic_vector(3 downto 0); -- Относительный адрес слова 0..11 задаёт декодер проекта.\n word_data : out std_logic_vector(15 downto 0) -- 16-битное слово для ответа шины.\n ); -- Закрывает список портов.\nend component; -- Завершает декларацию компонента.\nsignal identity_data : std_logic_vector(15 downto 0); -- Объявляется до begin и используется при чтении шины.\n-- Следующий экземпляр размещается после begin архитектуры.\nu_identity : firmware_identity -- Создаёт паспорт текущей сборки.\n port map ( -- Сопоставляет интерфейс паспорта с сигналами проекта.\n word_addr => identity_word_offset, -- Четырёхбитный относительный адрес слова формирует проект.\n word_data => identity_data -- Выход включается в ответ шины, чтобы сохранить паспорт при синтезе.\n ); -- Завершает подключение компонента.\n" # Декларация component позволяет создать entity только перед фактической сборкой. + + +def ise_environment(settings): # Подготавливает окружение автоматически, если xtclsh ещё отсутствует в PATH. + environment = {name.upper(): value for name, value in os.environ.items()} # В Windows имена переменных нечувствительны к регистру; единый регистр исключает два разных PATH. + if shutil.which("xtclsh", path=environment.get("PATH")): # Запуск из уже настроенной консоли не требует повторной настройки. + return environment # Сохраняет окружение выбранной пользователем установки. + startup = settings.get("ise_settings") or find_settings() # Использует явный путь либо стандартную найденную установку. + if not startup or not Path(startup).is_file(): # Не запускает pre-build, пока САПР не найдена. + raise ValueError("ISE not found; set ise_settings in firmware_build.json to settings64.bat") # Даёт одно место для исправления нестандартной установки. + if any(character in startup for character in '%!"\r\n'): # CALL повторно раскрывает переменные, поэтому специальные подстановки в пути запрещены. + raise ValueError("ISE settings path contains unsupported command expansion characters") # Не допускает интерпретацию пути как дополнительной команды. + environment["FW_ISE_SETTINGS"] = startup # Путь передаётся через окружение, без вставки в shell-код. + capture = HERE / "ise-env.bat" # Статический BAT исключает вложенное экранирование команды CALL с пробелами. + result = subprocess.run([environment.get("COMSPEC", "cmd.exe"), "/d", "/u", "/v:off", "/c", "call", str(capture)], env=environment, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) # Ключ /u выдаёт SET в UTF-16LE независимо от кодовой страницы; окружение не выводится в журнал. + for line in result.stdout.decode("utf-16-le").splitlines(): # Декодирование Unicode сохраняет русские пути после запуска UTF-8 BAT. + name, separator, value = line.partition("=") # Значения переменных могут сами содержать знак равенства. + if separator and name: # Служебные записи текущих дисков вида =C: не передаются в subprocess. + environment[name.upper()] = value # Получает PATH, XILINX и библиотечные пути без дублирования переменных Windows. + return environment # Настройка применяется к последующему запуску Tcl. + + +def build(settings_path, check=False): # Читает локальную настройку и запускает существующий полный Tcl-flow. + settings_path = settings_path.resolve() # Разрешает пути относительно каталога локальной обвязки. + root = settings_path.parent # Рабочий каталог .xise задаётся настройкой данного проекта. + settings = json.loads(settings_path.read_text(encoding="utf-8-sig")) # Не читает номер версии: он изменяется только внутри общего pre-build. + paths = {name: (root / settings[name]).resolve() for name in ("project", "templates", "image", "output")} # Преобразует все сохранённые пути до запуска САПР. + script = paths["templates"] / "tools/firmware-build/fpga/ise.tcl" # Общий Tcl выполняет генерацию паспорта, синтез и контроль результата. + if not script.is_file() or not paths["project"].is_file() or not (root / "firmware_identity.json").is_file(): # Проверяет обязательные файлы до запуска итератора. + raise ValueError("Project, templates or firmware_identity.json not found; check firmware_build.json") # Не создаёт пустую конфигурацию вместо потерянной пользовательской. + environment = ise_environment(settings) # Находит и активирует штатную установку ISE перед pre-build. + executable = shutil.which("xtclsh", path=environment.get("PATH", environment.get("Path"))) # Использует исполняемый файл именно подготовленного окружения. + if not executable: # Неподходящий settings.bat не должен запускать случайную программу. + raise ValueError("xtclsh was not found after loading ISE settings") # Останавливает сборку до увеличения версии. + print(f"[firmware-build] Project: {paths['project']}", flush=True) # Показывает выбранный проект при запуске BAT двойным щелчком. + if check: # Проверка установки не должна создавать новый паспорт или занимать номер. + print(f"[firmware-build] Ready: {executable}") # Подтверждает наличие зависимостей для обычного запуска. + return 0 # Завершает проверку без Tcl-flow. + return subprocess.call([executable, str(script), str(paths["project"]), str(root / "firmware_identity.json"), str(paths["output"]), str(paths["image"]), settings["language"], sys.executable], cwd=root, env=environment) # Передаёт параметры отдельными аргументами и сохраняет исходный код ошибки САПР. + + +def main(): # Разделяет установку проекта и последующие сборки одной локальной командой. + parser = argparse.ArgumentParser(description=__doc__) # Предоставляет справку для нестандартных путей проекта. + commands = parser.add_subparsers(dest="command", required=True) # Явно выбирает действие без скрытого запуска сборки. + setup = commands.add_parser("install") # Установка создаёт обвязки и предварительный паспорт. + setup.add_argument("project", type=Path, nargs="?") # Двойной щелчок без аргументов включает запрос пути. + setup.add_argument("--language", choices=("verilog", "vhdl")) # Позволяет переопределить язык для смешанного проекта. + setup.add_argument("--image", type=Path) # Поддерживает нестандартное имя результата BitGen. + setup.add_argument("--ise-settings", type=Path) # Указывает settings.bat при нестандартной установке ISE. + run = commands.add_parser("build") # Этот режим вызывает установленная локальная Python-обвязка. + run.add_argument("--settings", dest="settings_path", type=Path, required=True) # Требует явный путь параметров проекта. + run.add_argument("--check", action="store_true") # Проверяет настройку без увеличения версии. + arguments = vars(parser.parse_args()) # Передаёт выбранной функции только её именованные параметры. + command = arguments.pop("command") # Удаляет служебное имя режима из параметров функции. + if command == "install": # Интерактивный запрос нужен только при запуске установщика без пути. + arguments["project"] = arguments["project"] or Path(input("ISE project (.xise or directory): ").strip().strip('"')) # Принимает вставленный путь из Проводника с внешними кавычками. + install(**arguments) # Заполняет локальную настройку и показывает готовую команду сборки. + return 0 # Успешная установка не запускает синтез автоматически. + return build(**arguments) # Обычная команда возвращает результат полного Tcl-flow. + + +if __name__ == "__main__": # Импорт для тестов не должен устанавливать файлы в рабочий проект. + try: # Сохраняет понятную причину отказа без длинной трассировки в BAT-окне. + sys.exit(main()) # Передаёт точный код сборки внешнему BAT или CI. + except (OSError, ValueError, KeyError, ET.ParseError, subprocess.CalledProcessError) as error: # Обрабатывает неверную настройку и отказ штатного settings.bat. + print(f"[firmware-build] {error}", file=sys.stderr) # Печатает исправимую причину остановки. + sys.exit(2) # Возвращает ошибку конфигурации, не скрывая её успешным завершением. diff --git a/tools/firmware-build/fpga/quartus.tcl b/tools/firmware-build/fpga/quartus.tcl new file mode 100644 index 0000000..daadf87 --- /dev/null +++ b/tools/firmware-build/fpga/quartus.tcl @@ -0,0 +1,60 @@ +# Подключает общие пути и Python-этапы, совместимые с Quartus II и Prime. +source [file join [file dirname [info script]] common.tcl] +# Ошибка execute_flow или упаковки не должна выглядеть успешным выпуском. +if {[catch { + # Берёт аргументы quartus_sh из штатного массива Quartus, включая необязательную revision. + set arguments $quartus(args) + # По умолчанию project_open выбирает текущую revision из .qpf. + set revision "" + # Седьмой аргумент разрешён только после явного пути python.exe. + if {[llength $arguments] == 7} { + # Позволяет явно собрать ревизию платы вместо текущей из .qpf. + set revision [lindex $arguments 6] + # Передаёт общему разбору только его шесть аргументов. + set arguments [lrange $arguments 0 5] + # Завершает извлечение необязательной revision. + } + # Принимает project.qpf, config.json, output, revision.sof, язык и необязательный python.exe. + fw::init $arguments quartus + # Подключает штатные команды открытия проекта. + package require ::quartus::project + # Загружает полную цепочку Analysis/Synthesis, Fitter, Assembler и Timing Analyzer. + load_package flow + # Quartus принимает имя проекта без расширения .qpf. + set project_name [file rootname $fw::settings(project)] + # Явная revision нужна для нескольких аппаратных конфигураций одного проекта. + if {$revision eq ""} { + # Использует текущую ревизию проекта, сохранённую в .qpf. + project_open $project_name + # При наличии имени выбирает заданную ревизию. + } else { + # Раздельный аргумент сохраняет пробелы в имени ревизии. + project_open -revision $revision $project_name + # Завершает открытие проекта. + } + # Генерирует новый паспорт перед Analysis/Synthesis, используя общий итератор. + fw::prepare + # По умолчанию регистрирует Verilog-2001 для старых Quartus II. + set assignment VERILOG_FILE + # VHDL-проект получает только альтернативный .vhd файл. + if {$fw::settings(language) eq "vhdl"} { + # Штатное назначение Quartus определяет язык нового исходника. + set assignment VHDL_FILE + # Завершает выбор языка. + } + # Добавляет паспорт к исходникам выбранной ревизии проекта. + set_global_assignment -name $assignment $fw::settings(hdl) + # Полная компиляция экспортирует назначения перед запуском модулей и создаёт новый .sof. + execute_flow -compile + # Контролирует свежесть .sof, формирует SHA-256, manifest и архив. + fw::finish + # Закрывает проект после успешной упаковки результата. + project_close +# Перехватывает отказ САПР и сохраняет причину для внешней сборки. +} message]} { + # Пишет сообщение в стандартный поток ошибок. + puts stderr $message + # Не допускает успешный exit при ошибке компиляции или проверки образа. + exit 1 +# Завершает общий обработчик ошибок. +} diff --git a/tools/firmware-build/fpga/tests/test_flows.py b/tools/firmware-build/fpga/tests/test_flows.py new file mode 100644 index 0000000..58367e1 --- /dev/null +++ b/tools/firmware-build/fpga/tests/test_flows.py @@ -0,0 +1,96 @@ +"""Исполняет реальные Tcl-сценарии с заменой только команд производителей САПР.""" # Проверяет порядок, пути с пробелами и блокирование post-build. +import json # Проверяет, сколько номеров занял каждый запуск сценария. +import os # Временно задаёт путь минимальной инициализации Tcl без GUI. +from pathlib import Path # Находит сценарии относительно тестов. +import sys # Передаёт Tcl путь к тому же Python 3, которым выполняется тест. +import tempfile # Изолирует проекты и готовые образы каждого запуска. +import unittest # Организует успешные и ошибочные сценарии трёх САПР. +import tkinter # Предоставляет настоящий Tcl-интерпретатор без открытия окна Tk. +SCRIPTS = Path(__file__).resolve().parents[1] # Находит поставку FPGA-сценариев. + + +class FlowTests(unittest.TestCase): # Проверяет Tcl-управление без подмены генерации паспорта и архивирования. + def run_flow(self, toolchain, language="verilog", failure="", revision=""): # Исполняет один полный flow во временном проекте. + scratch = SCRIPTS.parents[2] / ".codex-build" # Каталог внутри репозитория исключает внешние junction AppData при проверке Tcl на Windows. + scratch.mkdir(exist_ok=True) # Хранит временные проекты в уже игнорируемой области сборки. + with tempfile.TemporaryDirectory(prefix="FPGA flow пробел ", dir=scratch) as temporary: # Кириллица и пробелы должны пережить Tcl exec и Python CLI. + root = Path(temporary) # Не использует настоящие проекты или настройки САПР. + project = root / {"ise": "board.xise", "vivado": "board.xpr", "quartus": "board.qpf"}[toolchain] # Создаёт только входной маркер нужного типа проекта. + project.touch() # Открытие моделируется командами производителя, наличие проверяет реальный common.tcl. + config = root / "identity.json" # Хранит реальный сохраняемый счётчик. + config.write_text(json.dumps({"product": "Плата", "target": "test", "version": [0, 1, 0], "increment_version": "true" if failure == "prepare" else True}), encoding="utf-8") # Ошибка типа флага должна остановить prepare до резервирования; штатный flow занимает 0.1.1. + image = root / ("board.sof" if toolchain == "quartus" else "board.bit") # Совпадает с нативным форматом сценария. + image.write_bytes(b"old image") # Позволяет проверить отказ упаковки старого файла после сбоя сборки. + previous = Path.cwd() # Настоящий Tcl cd меняет текущий каталог процесса Python. + script = os.path.relpath(SCRIPTS / (toolchain + ".tcl"), previous) # Относительный путь проверяет нахождение Python-helper после перехода в другой каталог проекта. + interpreter = tkinter.Tcl() # Выполняет установленный Tcl без окна и без запуска xtclsh/Vivado/Quartus. + calls = [] # Собирает последовательность только вендорных команд. + def vendor(name, *arguments): # Моделирует интерфейс САПР, сохраняя настоящий exec Python-инструмента. + calls.append((name, *arguments)) # Позволяет проверить порядок подготовки и запуска дочерних шагов. + if name == "current_run": # В Vivado выбирается активная реализация с нестандартным именем. + return "impl_board" # Проверяет отсутствие жёсткой привязки к impl_1. + if name == "get_runs": # Возвращает имя объекта run без лишних преобразований. + return arguments[-1] # Достаточно для чтения PARENT, SRCSET и PROGRESS. + if name == "get_property": # Моделирует свойства выбранного синтеза и реализации. + field, target = arguments # Сохраняет различие родительского синтеза и активного в GUI. + if field == "PARENT": # Реализация может зависеть от другого синтеза. + return "synth_board" # Сценарий должен выбрать этого родителя. + if field == "SRCSET": # Новый модуль должен попасть именно в исходники родителя реализации. + return "sources_board" # Проверяет выбор набора вместо предположения sources_1. + return "0%" if failure == target else "100%" # Ожидание завершения при ошибке не считается успехом. + finished = name == "execute_flow" or name == "process" or (name == "wait_on_run" and arguments[0] == "impl_board") # Определяет место записи результата компиляции. + if finished and not failure: # Только успешный flow создаёт новый файл. + image.write_bytes(b"new image from " + toolchain.encode("ascii")) # Имитирует точные байты нового .bit/.sof. + if name == "process": # ISE сообщает отказ логическим результатом без Tcl error. + return "false" if failure else "true" # Проверяет особую обработку boolean в ise.tcl. + if name == "execute_flow" and failure: # Quartus сообщает ошибку компиляции Tcl-исключением. + raise RuntimeError("test compiler failure") # Вызывает catch в настоящем quartus.tcl. + return "" # Остальные команды производителя успешно завершаются без значения. + for name in ("project", "xfile", "process", "open_project", "current_run", "get_property", "get_runs", "add_files", "update_compile_order", "reset_run", "launch_runs", "wait_on_run", "close_project", "load_package", "project_open", "set_global_assignment", "execute_flow", "project_close"): # Подменяет только API производителя, не команды ядра Tcl. + interpreter.createcommand(name, lambda *arguments, name=name: vendor(name, *arguments)) # Привязывает имя при создании каждой callback-функции. + interpreter.eval('proc exit {code} {error "flow-exit:$code"}') # Не позволяет Tcl exit завершить процесс тестов. + interpreter.call("package", "provide", "::quartus::project", "1.0") # Удовлетворяет require пакета, чьи команды заменены заглушками. + arguments = [str(project), str(config), str(root / "build"), str(image), language, sys.executable] # Передаёт пути списком, без shell-экранирования. + if revision: # Quartus допускает дополнительное имя аппаратной ревизии. + arguments.append(revision) # Проверяет передачу значения с пробелами одним аргументом. + interpreter.call("set", "quartus(args)" if toolchain == "quartus" else "argv", tuple(arguments)) # Создаёт штатный источник аргументов соответствующей САПР. + try: # Гарантирует восстановление cwd даже при ожидаемом exit 1. + if failure: # Неудачная компиляция должна прервать сценарий до упаковки. + with self.assertRaisesRegex(tkinter.TclError, "flow-exit:1"): # Проверяет внешнее состояние отказа. + interpreter.call("source", script) # Исполняет настоящий сценарий со всеми проверками. + else: # Успешный сценарий обязан дойти до архива. + interpreter.call("source", script) # Реальный exec создаёт HDL, manifest и архив. + self.assertEqual(json.loads(config.read_text(encoding="utf-8"))["version"], [0, 1, 0] if failure == "prepare" else [0, 1, 1]) # Ошибка конфигурации не занимает номер; после начала сборки номер резервируется ровно один раз. + manifests = list((root / "build/firmware").glob("*/*.manifest.json")) # Ищет только выпущенные архивы текущего запуска. + self.assertEqual(len(manifests), 0 if failure else 1) # Ошибка синтеза/реализации не должна выпустить старый образ. + if failure == "prepare": # Ошибка общего Python pre-build должна блокировать запуск САПР. + self.assertFalse(any(call[0] in ("process", "launch_runs", "execute_flow") for call in calls)) # Не допускает синтез с прежним паспортом после ошибки настроек. + if not failure: # Дополнительно проверяет выбранный HDL после реального prepare. + suffix = "v" if language == "verilog" else "vhd" # В проект регистрируется только выбранный вариант. + self.assertTrue(any(str(root / "build/generated" / ("firmware_identity." + suffix)).replace("\\", "/") in str(call).replace("\\\\", "/") for call in calls)) # Учитывает Windows-разделители в строковом представлении кортежей. + finally: # Tcl cd не должен влиять на следующий тест или временную очистку. + os.chdir(previous) # Возвращает исходный каталог процесса до удаления проекта. + return calls # Отдаёт последовательность команд для специфических проверок САПР. + + def test_all_toolchains_and_languages(self): # Каждый сценарий должен выпустить файл для обеих HDL-реализаций. + for toolchain in ("ise", "vivado", "quartus"): # Покрывает три независимых набора Tcl-команд. + for language in ("verilog", "vhdl"): # Проверяет правильное расширение и тип назначения исходника. + with self.subTest(toolchain=toolchain, language=language): # Показывает точную конфигурацию возможного отказа. + self.run_flow(toolchain, language) # Создаёт реальный паспорт и архив без лицензии производителя. + + def test_failures_do_not_archive_old_images(self): # Проверяет false ISE, ошибку Quartus и неуспешные runs Vivado. + for toolchain, failure in (("ise", "compile"), ("quartus", "compile"), ("vivado", "synth_board"), ("vivado", "impl_board"), ("ise", "prepare"), ("vivado", "prepare"), ("quartus", "prepare")): # Отдельно покрывает обе стадии Vivado и отказ Python pre-build во всех САПР. + with self.subTest(toolchain=toolchain, failure=failure): # Сохраняет контекст ожидаемой ошибки. + self.run_flow(toolchain, failure=failure) # Старый файл существует, но архив не должен появиться. + + def test_revision_and_parent_synthesis(self): # Проверяет нестандартные имена конфигураций проектов. + quartus = self.run_flow("quartus", revision="board revision B") # Явная ревизия содержит пробелы и передаётся единым аргументом. + self.assertTrue(any(call[:3] == ("project_open", "-revision", "board revision B") for call in quartus)) # Не допускает случайной сборки default revision. + vivado = self.run_flow("vivado") # Активная реализация зависит от синтеза с нестандартным именем. + self.assertIn(("launch_runs", "synth_board"), vivado) # Собирается именно родитель выбранной реализации. + self.assertIn(("update_compile_order", "-fileset", "sources_board"), vivado) # Паспорт относится к набору исходников этого синтеза. + self.assertLess(vivado.index(("wait_on_run", "synth_board")), vivado.index(("launch_runs", "impl_board", "-to_step", "write_bitstream"))) # Реализация начинается только после ожидания синтеза. + + +if __name__ == "__main__": # Поддерживает прямой запуск файла проверки. + unittest.main() # Возвращает ненулевой код при нарушении порядка сборки. diff --git a/tools/firmware-build/fpga/tests/test_identity.py b/tools/firmware-build/fpga/tests/test_identity.py new file mode 100644 index 0000000..9faaad7 --- /dev/null +++ b/tools/firmware-build/fpga/tests/test_identity.py @@ -0,0 +1,94 @@ +"""Проверяет FPGA-паспорт, общий итератор и точные байты архивов без лицензии САПР.""" # Запуск через unittest discover из корня репозитория. +import importlib.util # Импортирует реальный FPGA-адаптер без установки пакета. +import json # Сравнивает конфигурацию, метаданные и manifest готового образа. +import os # Управляет меткой времени файла в тесте воспроизводимой пересборки. +from pathlib import Path # Ограничивает изменения собственными временными каталогами. +import re # Извлекает значения из HDL для проверки общего регистрационного контракта. +import tempfile # Изолирует результаты от рабочих проектов пользователя. +import unittest # Проверяет успешные сборки и отказы при устаревших файлах. +from unittest.mock import patch # Делает Git и время независимыми от машины запуска. +TOOL = Path(__file__).resolve().parents[1] / "identity.py" # Находит инструмент рядом с тестами. +SPEC = importlib.util.spec_from_file_location("fpga_identity", TOOL) # Создаёт отдельное имя для адаптера. +fpga = importlib.util.module_from_spec(SPEC) # Подготавливает импорт без вызова CLI. +SPEC.loader.exec_module(fpga) # Загружает код, используемый всеми тремя сценариями САПР. + + +class IdentityTests(unittest.TestCase): # Проверяет границу между общим генератором и HDL. + def setUp(self): # Создаёт проект с кириллицей и пробелами в пути. + temporary = tempfile.TemporaryDirectory(prefix="ПЛИС project ") # Проверяет UTF-8 и корректную передачу путей. + self.addCleanup(temporary.cleanup) # Очищает только файлы данного теста. + self.root = Path(temporary.name) # Хранит все входы и выходы внутри временного проекта. + self.config = self.root / "firmware_identity.json" # Служит единственным источником ручного номера версии. + self.generated = self.root / "build/generated" # Имитирует каталог текущей конфигурации сборки. + self.image = self.root / "board.bit" # Нативный результат ISE или Vivado. + self.config.write_text(json.dumps({"product": "Плата", "target": "test-part", "version": [1, 2, 3], "increment_version": True}), encoding="utf-8") # Не изменяет пример или настройки реальных проектов. + self.git = patch.object(fpga.shared, "git_state", return_value={"commit": None, "dirty": None}) # Без Git должен получаться явный NOGIT000. + self.git.start() # Фиксирует отсутствие Git для всех вызовов данного теста. + self.addCleanup(self.git.stop) # Восстанавливает функцию после проверки. + self.epoch = patch.dict(os.environ, {"SOURCE_DATE_EPOCH": "1792413296"}) # UTC 2026-10-19 12:34:56 позволяет проверить точные календарные слова. + self.epoch.start() # Делает дату HDL детерминированной. + self.addCleanup(self.epoch.stop) # Не меняет окружение остальных тестов. + + def prepare(self, toolchain="vivado", language="verilog"): # Вызывает публичную функцию адаптера теми же аргументами, что Tcl. + return fpga.prepare(self.root, self.config, self.generated, self.image, toolchain, language) # Делегирует резервирование версии общему prepare. + + def test_hdl_matches_contract_and_iterator(self): # Одним вектором сравнивает обе HDL-реализации с контрактом C. + metadata = self.prepare() # Первый запуск должен увеличить patch ровно один раз. + expected = [1, 1, 2, 4, 2026, 0x0A13, 0x0C22, 56, 0x4E4F, 0x4749, 0x5430, 0x3030] # 12 слов: контракт, 1.2.4, UTC и ASCII NOGIT000. + self.assertEqual(metadata["fpga"]["register_words"], expected) # Фиксирует независимый эталон адресов и старшинства октетов. + verilog = (self.generated / "firmware_identity.v").read_text(encoding="utf-8") # Читает фактически записанный файл для синтеза XST. + vhdl = (self.generated / "firmware_identity.vhd").read_text(encoding="utf-8") # Читает альтернативный VHDL-93 паспорт. + self.assertEqual([int(value, 16) for value in re.findall(r"word_data = 16'h([0-9A-F]{4})", verilog)][:12], expected) # Проверяет константы без зависимости от пробелов и комментариев. + self.assertEqual([int(value, 16) for value in re.findall(r'x"([0-9A-F]{4})" when "[01]{4}"', vhdl)], expected) # Проверяет то же расположение слов в VHDL. + self.assertEqual(json.loads(self.config.read_text(encoding="utf-8"))["version"], [1, 2, 4]) # HDL и сохраняемый счётчик обязаны совпадать. + self.assertEqual(self.prepare()["version"], [1, 2, 5]) # Следующая попытка использует следующий номер общего итератора. + + def test_seal_archive_export_and_tampering(self): # Проверяет реальную упаковку точных байтов и отказ при повреждении. + self.prepare() # Фиксирует паспорт до появления готового .bit. + data = b"test-only FPGA bitstream\x00\xff" # Произвольные байты моделируют файл программатора без разбора вендорного контейнера. + self.image.write_bytes(data) # Имитирует успешный выход полной сборки САПР. + result = fpga.finish(self.generated / "firmware_identity.json", self.root / "firmware", self.root / "export") # Запускает общий seal, verify, archive и проверку экспорта. + for folder in (Path(result["directory"]), Path(result["exported_directory"])): # Проверяет обе сохраняемые копии текущего выпуска. + self.assertEqual((folder / self.image.name).read_bytes(), data) # Архивы должны содержать точные исходные байты. + self.assertEqual((folder / "firmware_identity.v").read_bytes(), (self.generated / "firmware_identity.v").read_bytes()) # Вместе с образом сохраняется точный исходник паспорта, переданный синтезатору. + manifest = fpga.shared.verify(folder / self.image.name, folder / (self.image.name + ".manifest.json")) # Повторно считает размер и SHA-256 независимо от результата finish. + self.assertEqual(manifest["version"], [1, 2, 4]) # Post-build не увеличивает версию второй раз. + self.image.write_bytes(b"damaged") # Имитирует изменение файла после выпуска manifest. + with self.assertRaises(ValueError): # Проверка обязана обнаружить повреждение до программирования. + fpga.shared.verify(self.image, self.image.with_suffix(".bit.manifest.json")) # Использует публичную общую проверку образа. + + def test_stale_missing_and_empty_images_are_rejected(self): # Отказы сборки не должны связывать новый паспорт со старым результатом. + self.image.write_bytes(b"old image") # Оставляет нативный файл от предыдущего выпуска. + self.prepare() # Запоминает его содержимое и время до синтеза. + with self.assertRaisesRegex(ValueError, "not updated"): # Неизменившийся старый файл не считается новым выпуском. + fpga.finish(self.generated / "firmware_identity.json", self.root / "firmware") # Отказывается до создания manifest. + self.image.unlink() # Моделирует отсутствие результата после сбоя САПР. + with self.assertRaisesRegex(ValueError, "Missing or empty"): # Нет образа — нет архива. + fpga.finish(self.generated / "firmware_identity.json", self.root / "firmware") # Проверяет отсутствие файла. + self.image.write_bytes(b"") # Моделирует оборванную запись выходного файла. + with self.assertRaisesRegex(ValueError, "Missing or empty"): # Пустой файл также блокирует выпуск. + fpga.finish(self.generated / "firmware_identity.json", self.root / "firmware") # Не допускает SHA-256 пустого файла как прошивки. + self.assertFalse((self.root / "firmware").exists()) # Ни один из отказов не должен создать архив. + + def test_reproducible_image_with_new_mtime_is_accepted(self): # Ручная версия и воспроизводимый BitGen могут дать прежние байты. + self.image.write_bytes(b"same image") # Готовит существующий результат предыдущей сборки. + metadata = self.prepare() # Запоминает прежнее время записи. + stamp = metadata["fpga"]["image_before"]["mtime_ns"] + 2_000_000_000 # Две секунды покрывают даже грубую точность времени старых файловых систем. + os.utime(self.image, ns=(stamp, stamp)) # Имитирует реальную повторную запись тех же байтов. + fpga.finish(self.generated / "firmware_identity.json", self.root / "firmware") # Обновлённый файл допускается без требования отличающегося хеша. + + def test_quartus_and_wrong_extension(self): # Проверяет нативный .sof и отказы до резервирования номера. + original = self.config.read_bytes() # Неверная команда не должна увеличивать счётчик. + with self.assertRaises(ValueError): # .bit не является нативным результатом Quartus. + self.prepare(toolchain="quartus") # Проверяет соответствие расширения выбранной САПР. + self.assertEqual(self.config.read_bytes(), original) # Конфигурация остаётся прежней после отказа. + self.image = self.root / "revision.sof" # Выбирает штатный выход Assembler. + metadata = self.prepare(toolchain="quartus", language="vhdl") # Использует тот же итератор для Altera и VHDL. + self.image.write_bytes(b"test SOF") # Моделирует успешную компиляцию Quartus. + result = fpga.finish(self.generated / "firmware_identity.json", self.root / "firmware") # Архивирует .sof через общий механизм. + self.assertEqual(result["file"], "revision.sof") # Сохраняет имя ревизии программатора. + self.assertEqual(metadata["fpga"]["language"], "vhdl") # Фиксирует язык для последующего аудита. + + +if __name__ == "__main__": # Позволяет запускать проверку отдельным файлом. + unittest.main() # Возвращает ненулевой код при нарушении контракта. diff --git a/tools/firmware-build/fpga/tests/test_ise_project.py b/tools/firmware-build/fpga/tests/test_ise_project.py new file mode 100644 index 0000000..ebd7f75 --- /dev/null +++ b/tools/firmware-build/fpga/tests/test_ise_project.py @@ -0,0 +1,138 @@ +"""Проверяет автоматическую установку ISE, сохранение версии и локальные BAT.""" # Тесты не изменяют реальные .xise пользователя. +import importlib.util # Загружает установщик без вызова его интерактивного CLI. +import json # Проверяет автоматически извлечённые и сохраняемые настройки проекта. +import os # Подготавливает окружение Windows для реального запуска BAT. +from pathlib import Path # Изолирует проекты в игнорируемом каталоге репозитория. +import subprocess # Проверяет установочный BAT и установленную команду --check. +import tempfile # Создаёт независимый проект для каждой проверки. +import unittest # Проверяет успешную установку, повторные вызовы и отказы до сборки. +from unittest.mock import patch # Заменяет только внешние команды ISE в тестах запуска. +HERE = Path(__file__).resolve().parents[1] # Находит общий установщик рядом с остальными FPGA-инструментами. +SPEC = importlib.util.spec_from_file_location("ise_project_setup", HERE / "ise_project.py") # Выделяет установщику отдельное пространство имён. +ise = importlib.util.module_from_spec(SPEC) # Создаёт модуль для проверки публичных функций. +SPEC.loader.exec_module(ise) # Загружает код без запросов к пользователю и без установки в чужие каталоги. +PROJECT = ''' + + + + + + + + + + + + + +''' # Фикстура воспроизводит namespace и свойства настоящего ISE 14.7 без исходников платы. + + +class SetupTests(unittest.TestCase): # Проверяет автоматическое подключение одного проекта без ручного копирования. + def setUp(self): # Каждый сценарий получает свой рабочий каталог с пробелами и кириллицей. + scratch = HERE.parents[2] / ".codex-build" # Держит тестовые проекты внутри разрешённой области и вне индекса Git. + scratch.mkdir(exist_ok=True) # Поддерживает запуск тестов из свежей копии библиотеки. + temporary = tempfile.TemporaryDirectory(prefix="ISE setup плата & ", dir=scratch) # Амперсанд проверяет передачу путей без вставки shell-команд. + self.addCleanup(temporary.cleanup) # Удаляет только собственный тестовый проект. + self.root = Path(temporary.name) # Хранит весь созданный комплект рядом с тестовым .xise. + self.project = self.root / "board.xise" # Отличается от имени top и результата BitGen для проверки автоподбора. + self.project.write_text(PROJECT, encoding="utf-8") # Не изменяет существующие проекты на диске. + + def install(self, **arguments): # Вызывает установщик без поиска реальной САПР на каждом тесте. + with patch.object(ise, "find_settings", return_value=""): # Автоматическая установка допускается и до установки ISE. + return ise.install(self.project, **arguments) # Проверяет настоящую запись обвязок и предварительного HDL. + + def test_install_detects_project_and_does_not_consume_version(self): # Установка должна завершиться готовым локальным BAT и исходниками паспорта. + before = self.project.read_bytes() # Автоматическое подключение не должно менять XML проекта без ISE. + settings = self.install() # Извлекает параметры и создаёт локальные файлы. + self.assertEqual(settings["image"], "impl/programmer_top.bit") # Output File Name и Working Directory важнее имени .xise. + self.assertEqual(settings["language"], "verilog") # Определяет язык по реальному верхнему исходнику. + identity = json.loads((self.root / "firmware_identity.json").read_text(encoding="utf-8")) # Читает рабочий, а не временный счётчик. + self.assertEqual(identity["target"], "xc6slx16-3ftg256") # Паспорт получает реальный кристалл с корпусом и скоростной группой. + self.assertEqual(identity["version"], [0, 1, 0]) # Установка не является попыткой синтеза и не расходует номер. + self.assertEqual(self.project.read_bytes(), before) # Исходный .xise сохранён побайтно. + for name in ("build_firmware.bat", "firmware_build.py", "firmware_build.json", "FIRMWARE_SETUP.md", "firmware_identity_instance.txt", "build/ise/generated/firmware_identity.v"): # Все ранее ручные файлы создаются автоматически. + self.assertTrue((self.root / name).is_file(), name) # Проверяет полноту установленного комплекта. + self.assertIn("build/ise/", (self.root / ".gitignore").read_text(encoding="utf-8")) # Сгенерированные исходники исключаются из статуса Git проекта. + + def test_reinstall_preserves_configs_version_and_ignore(self): # Повторное подключение не должно сбросить уже выпущенный номер. + self.install() # Сначала создаёт штатный набор локальных файлов. + identity = self.root / "firmware_identity.json" # Рабочий счётчик изменяется только как часть тестового сценария. + identity.write_text('{"product":"Моя плата","target":"xc6slx16","version":[3,4,5],"increment_version":true}', encoding="utf-8") # Имитирует существующую версию и пользовательское форматирование. + config = self.root / "firmware_build.json" # Параметры установки также сохраняются при повторном запуске. + settings = json.loads(config.read_text(encoding="utf-8")) # Сохраняет автоматически определённые значения остальных полей. + settings["output"] = "build/custom" # Проект может поменять каталог архивов после установки. + config.write_text(json.dumps(settings), encoding="utf-8") # Создаёт пользовательский формат настройки. + originals = {path: path.read_bytes() for path in (identity, config)} # Проверяет побайтную сохранность обоих JSON. + self.install() # Повторный вызов должен использовать выбранный пользователем output. + for path, data in originals.items(): # Ни версия, ни пути не должны замениться значениями из .xise. + self.assertEqual(path.read_bytes(), data) # Не допускает переформатирования сохранённых настроек. + ignore = (self.root / ".gitignore").read_bytes() # Запоминает результат после добавления custom output. + self.install() # Третий вызов проверяет отсутствие повторяющихся правил. + self.assertEqual((self.root / ".gitignore").read_bytes(), ignore) # .gitignore не растёт при каждом запуске. + self.assertTrue((self.root / "build/custom/generated/firmware_identity.v").is_file()) # Предварительный HDL соответствует сохранённой настройке. + + def test_existing_user_bat_is_preserved_without_partial_installation(self): # Установщик не должен заменять существующие проектные команды. + custom = self.root / "build_firmware.bat" # Создаёт пользовательскую команду с занятым именем. + custom.write_bytes(b"@echo custom build\n") # Содержимое отличается от управляемого шаблона. + with self.assertRaisesRegex(ValueError, "Existing file differs"): # Коллизия должна быть обнаружена до записи JSON и generated. + self.install() # Выполняет настоящую предварительную проверку устанавливаемых файлов. + self.assertEqual(custom.read_bytes(), b"@echo custom build\n") # Пользовательский файл остаётся прежним. + self.assertFalse((self.root / "firmware_identity.json").exists()) # Частичная установка не создаёт рабочий счётчик. + self.assertFalse((self.root / "build").exists()) # Отказ коллизии не оставляет предварительный паспорт. + + def test_vhdl_override_and_ambiguous_or_cpld_project(self): # Поддерживает VHDL и останавливает неподходящие проекты до записи файлов. + self.project.write_text(PROJECT.replace("logic_top.v", "logic_top.vhd"), encoding="utf-8") # Расширение top имеет приоритет над Preferred Language. + project, image, language, target = ise.project_info(self.root) # Единственный .xise выбирается из переданной папки. + self.assertEqual(language, "vhdl") # Выбирает VHDL автоматически без ручного параметра. + settings = self.install(image=Path("custom/result.bit")) # Разрешает явно переопределить нестандартный путь BitGen. + self.assertEqual(settings["image"], "custom/result.bit") # Не теряет ручное уточнение при автоматическом заполнении. + self.assertIn("component firmware_identity", (self.root / "firmware_identity_instance.txt").read_text(encoding="utf-8")) # Выдаёт VHDL-заготовку для подключения до первого синтеза. + (self.root / "other.xise").write_text(PROJECT, encoding="utf-8") # Моделирует две платы в одной папке. + with self.assertRaisesRegex(ValueError, "exactly one"): # Установщик не должен угадывать нужную плату. + ise.project_info(self.root) # Требует явный файл .xise. + self.project.write_text(PROJECT.replace("xc6slx16", "xc9572xl"), encoding="utf-8") # CPLD требует .jed вместо .bit. + with self.assertRaisesRegex(ValueError, "FPGA project"): # Неподходящий FPGA-шаблон не устанавливается на CPLD. + ise.project_info(self.project) # Проверяет устройство до любых изменений проекта. + + def test_build_preserves_arguments_exit_code_and_check_version(self): # Локальная настройка должна доходить до общего Tcl отдельными аргументами. + self.install() # Готовит настоящий набор настроек и исходную версию. + config = self.root / "firmware_build.json" # Выбирает установленную локальную настройку. + version = (self.root / "firmware_identity.json").read_bytes() # --check не имеет права занимать следующий номер. + with patch.object(ise, "ise_environment", return_value={"PATH": "test"}), patch.object(ise.shutil, "which", return_value="C:/ISE path/xtclsh.exe"), patch.object(ise.subprocess, "call", return_value=7) as invoke: # Не запускает лицензируемую САПР в тесте аргументов. + self.assertEqual(ise.build(config, check=True), 0) # Проверка должна завершиться до запуска Tcl-flow. + invoke.assert_not_called() # Подтверждает отсутствие скрытой сборки в --check. + self.assertEqual(ise.build(config), 7) # Код ошибки САПР передаётся пользователю без подмены. + arguments = invoke.call_args.args[0] # Каждый элемент списка соответствует одному аргументу процесса. + self.assertEqual(arguments[2], str(self.project)) # Пробелы, кириллица и амперсанд сохраняются в пути .xise. + self.assertEqual(arguments[-2], "verilog") # Общий Tcl получает выбранный при установке язык. + self.assertEqual(invoke.call_args.kwargs["cwd"], self.root) # Относительные исходники .xise разрешаются из папки проекта. + self.assertEqual((self.root / "firmware_identity.json").read_bytes(), version) # До настоящего pre-build номер не изменяется. + + @unittest.skipUnless(os.name == "nt", "Windows BAT execution") # Реальные BAT проверяются только на Windows, остальные тесты переносимы. + def test_native_settings_environment_preserves_unicode(self): # Автоматическое окружение должно сохранить пути при любой кодовой странице консоли. + settings = self.root / "settings64.bat" # Путь содержит пробелы, кириллицу и амперсанд. + settings.write_bytes('@echo off\r\n@rem Передаёт переменную с русским путём из исходного окружения.\r\n@set "ISE_TEST_RESULT=%FW_TEST_UNICODE%"\r\n'.encode("utf-8")) # Моделирует штатный settings.bat без настоящей установки ISE. + expected = str(self.root / "русская папка") # Результат не должен зависеть от OEM-кодировки Windows. + with patch.dict(os.environ, {"FW_TEST_UNICODE": expected}), patch.object(ise.shutil, "which", return_value=None): # Принуждает настройку окружения через settings.bat. + environment = ise.ise_environment({"ise_settings": str(settings)}) # Исполняет настоящий CMD /u с захватом SET. + self.assertEqual(environment["ISE_TEST_RESULT"], expected) # Декодирование UTF-16LE должно сохранить каждый символ пути. + + @unittest.skipUnless(os.name == "nt", "Windows BAT execution") # Реальный запуск обвязок требует командного процессора Windows. + def test_real_installer_and_local_bat_check(self): # Проверяет запуск пользователем без ручного копирования файлов или длинной Tcl-команды. + environment = os.environ.copy() # Наследует Python launcher и стандартные системные программы. + environment["FW_NO_PAUSE"] = "1" # Автотест не должен ожидать клавиши установщика. + setup = subprocess.run([environment.get("COMSPEC", "cmd.exe"), "/d", "/c", "call", str(HERE / "INSTALL_ISE.bat"), str(self.project)], env=environment, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # CALL сохраняет кавычки имени BAT; аргумент проекта содержит пробелы и амперсанд. + self.assertEqual(setup.returncode, 0, setup.stderr.decode(errors="replace")) # Файлы должен создать сам установщик. + stub = self.root / "stub bin" # Создаёт отдельный PATH для проверки наличия xtclsh. + stub.mkdir() # Не подменяет системную установку ISE. + (stub / "xtclsh.bat").write_text("@rem Только маркер наличия ISE для --check.\n@exit /b 99\n", encoding="utf-8") # Проверка не должна выполнять эту заглушку. + environment["PATH"] = str(stub) + os.pathsep + environment.get("PATH", "") # Добавляет тестовую САПР перед остальными программами. + before = (self.root / "firmware_identity.json").read_bytes() # Сохраняет номер перед запуском установленного BAT. + run = subprocess.run([environment.get("COMSPEC", "cmd.exe"), "/d", "/c", "call", str(self.root / "build_firmware.bat"), "--check"], cwd=HERE, env=environment, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Рабочий каталог специально отличается от каталога проекта; CALL сохраняет кавычки пути BAT. + self.assertEqual(run.returncode, 0, run.stderr.decode(errors="replace")) # Локальная Python-обвязка должна найти настройку и библиотеку самостоятельно. + self.assertEqual((self.root / "firmware_identity.json").read_bytes(), before) # Проверка установленного комплекта не увеличивает версию. + + +if __name__ == "__main__": # Поддерживает прямой запуск тестов установщика. + unittest.main() # Возвращает ненулевой код при ошибке установки или потере настроек. diff --git a/tools/firmware-build/fpga/vivado.tcl b/tools/firmware-build/fpga/vivado.tcl new file mode 100644 index 0000000..91d403f --- /dev/null +++ b/tools/firmware-build/fpga/vivado.tcl @@ -0,0 +1,56 @@ +# Находит общий код независимо от рабочего каталога Vivado. +source [file join [file dirname [info script]] common.tcl] +# Объединяет запуск и контроль результата в одну прерываемую при ошибке операцию. +if {[catch { + # Принимает project.xpr, config.json, output, top.bit, язык и необязательный python.exe. + fw::init $argv vivado + # Открывает проект с его part, top, XDC и настройками реализации. + open_project $fw::settings(project) + # Берёт активную реализацию, а не предполагает стандартное имя impl_1. + set implementation [current_run -implementation] + # Синтез выбирается по родителю реализации, даже если в GUI активен другой synth run. + set synthesis [get_property PARENT $implementation] + # Файловый набор принадлежит именно синтезу выбранной реализации. + set sources [get_property SRCSET [get_runs $synthesis]] + # Генерирует паспорт до запуска синтеза; повторное увеличение в hooks проекта не требуется. + fw::prepare + # Регистрирует только один вариант HDL в правильном наборе исходников. + add_files -fileset $sources -norecurse $fw::settings(hdl) + # Обновляет порядок компиляции для нового модуля или VHDL entity. + update_compile_order -fileset $sources + # Сбрасывает реализацию перед синтезом, чтобы не использовать прежнюю размещённую схему. + reset_run $implementation + # Полный синтез обязателен при новом паспорте даже в ручном режиме номера версии. + reset_run $synthesis + # Запускает синтез с настройками проекта. + launch_runs $synthesis + # Ожидает завершения дочернего процесса до проверки результата. + wait_on_run $synthesis + # Ожидание само по себе не означает успех; 100% проверяется отдельно. + if {[get_property PROGRESS [get_runs $synthesis]] ne "100%"} { + # Не запускает реализацию при отказе синтеза. + error "Vivado synthesis failed" + # Заканчивает проверку синтеза. + } + # Включает write_bitstream, который обычная реализация по умолчанию не выполняет. + launch_runs $implementation -to_step write_bitstream + # Ждёт записи .bit перед вызовом общего post-build. + wait_on_run $implementation + # Проверяет завершение полной цепочки генерации файла программирования. + if {[get_property PROGRESS $implementation] ne "100%"} { + # Отказ маршрутизации, DRC или BitGen блокирует архивирование. + error "Vivado implementation/bitstream failed" + # Завершает проверку реализации. + } + # Упаковывает именно ожидаемый .bit после успешной сборки. + fw::finish + # Завершает работу с сохранёнными настройками проекта. + close_project +# Ошибка любого шага передаётся внешнему вызывающему процессу. +} message]} { + # Сохраняет исходное сообщение САПР или общего генератора в журнале. + puts stderr $message + # Возвращает отказ внешней сборке или CI. + exit 1 +# Заканчивает обработку ошибок. +} From 2da7e7b525913ca528931b0d28fd54a4a902fb40 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Oct 2026 14:16:21 +0300 Subject: [PATCH 12/18] =?UTF-8?q?feat(global-time):=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D1=8C=20=D0=BE=D0=B1=D1=89=D0=B8=D0=B5=20=D1=87?= =?UTF-8?q?=D0=B0=D1=81=D1=8B=20=D0=B8=20=D0=BF=D0=BE=D1=80=D1=82=20TMS320?= =?UTF-8?q?F28335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Вынеси программные часы, коррекцию по ProtoCAN RTCSETUP и атомарную метку логгера в переносимое ядро без глобального состояния. Подключи eCAN-A и CPU Timer2 отдельным портом F28335; зафиксируй календарные границы, переполнение, задержку RX и защиту IRQ в хостовых тестах. --- c/gas-logger/README.md | 2 + c/global-time/CMakeLists.txt | 21 +++ c/global-time/README.md | 167 +++++++++++++++++ c/global-time/include/global_time.h | 65 +++++++ .../ports/tms320f28335/global_time_f28335.c | 168 ++++++++++++++++++ .../ports/tms320f28335/global_time_f28335.h | 19 ++ c/global-time/src/global_time.c | 156 ++++++++++++++++ .../tests/f28335_stubs/DSP2833x_Device.h | 26 +++ c/global-time/tests/run_tests.py | 36 ++++ c/global-time/tests/test_f28335.c | 88 +++++++++ c/global-time/tests/test_global_time.c | 145 +++++++++++++++ c/parallel-nand/docs/MEMORY_GAS.md | 2 + doc/setcan/protocan/GLOBAL_TIME.md | 97 ++++++++++ 13 files changed, 992 insertions(+) create mode 100644 c/global-time/CMakeLists.txt create mode 100644 c/global-time/README.md create mode 100644 c/global-time/include/global_time.h create mode 100644 c/global-time/ports/tms320f28335/global_time_f28335.c create mode 100644 c/global-time/ports/tms320f28335/global_time_f28335.h create mode 100644 c/global-time/src/global_time.c create mode 100644 c/global-time/tests/f28335_stubs/DSP2833x_Device.h create mode 100644 c/global-time/tests/run_tests.py create mode 100644 c/global-time/tests/test_f28335.c create mode 100644 c/global-time/tests/test_global_time.c create mode 100644 doc/setcan/protocan/GLOBAL_TIME.md diff --git a/c/gas-logger/README.md b/c/gas-logger/README.md index f17c4db..0e10a25 100644 --- a/c/gas-logger/README.md +++ b/c/gas-logger/README.md @@ -1,5 +1,7 @@ # GAS Logger — экспериментальная версия 1 +> GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Спецификация: `doc/setcan/protocan/OAP.md`; адреса этого документа остаются регистровыми. + Непрерывный регистратор с двумя кольцевыми банками, неизменяемым снимком и общей картой GAS / ProtoCAN GAS / Modbus FC03/FC06. Весь код и проектные/MCU адаптеры находятся в `templates`; приложения подключают ревизию сабмодулем. diff --git a/c/global-time/CMakeLists.txt b/c/global-time/CMakeLists.txt new file mode 100644 index 0000000..88db168 --- /dev/null +++ b/c/global-time/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.13) # Задаёт минимальную версию, совместимую с соседними C-библиотеками templates. +project(global_time C) # Создаёт независимую цель для программных глобальных часов. +add_library(global_time STATIC src/global_time.c) # Собирает переносимое ядро без обязательных MCU заголовков. +target_include_directories(global_time PUBLIC include) # Экспортирует потребителю только публичный контракт часов. +target_compile_features(global_time PUBLIC c_std_99) # Требует C99 для точных целочисленных типов и uint64_t меток. +option(GLOBAL_TIME_BUILD_F28335 "Собирать аппаратный порт TI F28335" OFF) # Позволяет MCU проекту явно включить адаптер со своими TI include-путями. +if(GLOBAL_TIME_BUILD_F28335) # Не навязывает host-приложению аппаратные регистры TI. + target_sources(global_time PRIVATE ports/tms320f28335/global_time_f28335.c) # Добавляет eCAN и необязательный CPU Timer2 порт к той же библиотеке. + target_include_directories(global_time PUBLIC ports/tms320f28335) # Делает аппаратные hooks доступными прошивке потребителя. +endif() # Завершает условное подключение аппаратного адаптера. +option(GLOBAL_TIME_BUILD_TESTS "Собирать host-проверки глобального времени" ON) # Разрешает выключить host-исполняемые файлы в MCU сборке. +if(GLOBAL_TIME_BUILD_TESTS AND NOT GLOBAL_TIME_BUILD_F28335) # Не подмешивает host-модель регистров к настоящему TI порту. + enable_testing() # Регистрирует проверяемые сценарии в CTest. + add_executable(test_global_time tests/test_global_time.c) # Собирает календарные, CAN и монотонные сценарии. + target_link_libraries(test_global_time PRIVATE global_time) # Использует то же ядро, которое подключает прошивка. + add_test(NAME global_time COMMAND test_global_time) # Делает host-проверку доступной через ctest. + add_executable(test_global_time_f28335 tests/test_f28335.c ports/tms320f28335/global_time_f28335.c) # Собирает настоящий аппаратный адаптер с минимальной моделью регистров. + target_include_directories(test_global_time_f28335 PRIVATE tests/f28335_stubs ports/tms320f28335) # Ограничивает подмену заголовков только этой host-целью. + target_link_libraries(test_global_time_f28335 PRIVATE global_time) # Связывает аппаратные hooks с реальным ядром часов. + add_test(NAME global_time_f28335 COMMAND test_global_time_f28335) # Регистрирует eCAN/Timer2 проверку отдельно от календарной. +endif() # Завершает host-проверки без влияния на MCU исходники. diff --git a/c/global-time/README.md b/c/global-time/README.md new file mode 100644 index 0000000..b4e0bf4 --- /dev/null +++ b/c/global-time/README.md @@ -0,0 +1,167 @@ +# Глобальное время + +Программные часы с тактом 1 мс, синхронизацией даты и времени через ProtoCAN +и атомарным получением метки для логгера. Ядро C99 не требует аппаратного RTC, +операционной системы или динамической памяти. Порт TMS320F28335 включает +eCAN-A и необязательный CPU Timer2. Все текстовые файлы — UTF-8. + +## Обмен при запуске + +1. Приложение инициализирует часы до разрешения IRQ и запускает источник 1 мс. +2. После завершения инициализации **всей платы** вызывает `gt_ready()` / + `gt_f28335_ready()`. +3. Из main библиотека отправляет `DISCRETE/FLAGS`, `MsgBody=0x3000`, + `Route=1`, адрес самой платы, `DLC=1`, `DATA=01`. +4. Верхний уровень распознаёт пакет через `gt_parse_ready()`, берёт свою + текущую дату и посылает **один broadcast всем платам**, используя `gt_make_rtc()`. +5. Каждый узел принимает штатный `RTCSETUP`, сравнивает время со своим, + сохраняет величину коррекции и немедленно обновляет календарные часы. + При отсутствии ответа узел повторяет готовность не чаще раза в секунду. + +`RTCSETUP` полностью сохраняет действующий формат ProtoCAN. +Универсальное сообщение готовности здесь определено как новый профиль +`DISCRETE/FLAGS`; ранее такого общего пакета в базовом протоколе не было. +Подробный [контракт обмена](../../doc/setcan/protocan/GLOBAL_TIME.md). +Код верхнего уровня для автоматической отправки времени подключается в его +приложении; библиотека предоставляет кодировщик и распознавание события старта. + +## Метка логгера + +`gt_get()` одним атомарным чтением возвращает: + +| Поле | Значение | +|---|---| +| `seconds`, `millisecond` | секунды от 2000-01-01 и доля 0..999 мс | +| `synchronized` | 0 до первого корректного RTCSETUP, 1 после | +| `uptime_ms` | время работы modulo 2^32, независимое от переводов часов | +| `sync_uptime_ms` | момент приёма последнего опорного пакета | +| `generation` | номер принятой коррекции | +| `correction_ms` | последнее смещение, знаковое 64-битное значение в мс | +| `weekday` | фаза недели 0..6, продвигаемая при смене суток | + +`gt_timestamp_ms()` формирует 64-битную метку от 2000 года. +`gt_calendar()` преобразует снимок в календарь и возвращает 0, пока дата неизвестна. +Для записей, которые должны различать переводы часов, сохраняйте также +`generation`, `synchronized` и/или `uptime_ms`. Календарное время может идти назад +после коррекции. Тайм-ауты следует считать по разности `uptime_ms`. +Без новых broadcast часы продолжают ход по локальному генератору; +возраст синхронизации равен `(uint32_t)(uptime_ms - sync_uptime_ms)`. + +```c +#include "global_time_f28335.h" /* Подключает общую временную базу F28335. */ +gt_stamp stamp; /* Содержит согласованную дату, миллисекунды и качество времени. */ +gt_get(gt_f28335_clock(), &stamp); /* Допускается из main и ISR, включая ISR логгера. */ +uint64_t time_ms = gt_timestamp_ms(&stamp); /* Перед сохранением календарной метки проверяется stamp.synchronized. */ +``` + +Это фрагмент для функции потребителя. Формат хранения существующего логгера +библиотека не меняет. В частности, старое 32-битное поле `time_ms` в GAS logger +и v4 УМП не вмещает календарные миллисекунды: потребителю нужен собственный +формат абсолютной метки либо отдельная временная база и номер поколения. + +## Подключение TMS320F28335 + +Добавьте в сборку `src/global_time.c` и +`ports/tms320f28335/global_time_f28335.c`. Include-пути: `include`, +`ports/tms320f28335`, штатные TI `DSP2833x_headers/include`, +`DSP2833x_common/include` и include компилятора. + +Ресурсы порта: + +| Ресурс | Назначение | +|---|---| +| eCAN-A MBOX7 | RX точного RTCSETUP, любой приоритет, IRQ line0 | +| eCAN-A MBOX8 | TX готовности, ACK проверяется в main | +| CPU Timer2 / INT14 | необязательный собственный такт 1 мс | + +Mailbox 0..6, скорость CAN, GPIO и глобальные маршруты PIE/CANGIM настраивает +приложение. `DBO=0` обязателен; порт отвергает другую раскладку октетов. +MBOX7 использует CANOPC: кадр защищён от аппаратной перезаписи до копирования ISR. +В программной очереди хранится последний broadcast, поскольку более новый +опорный пакет заменяет предыдущий. + +При запрещённых IRQ, **после** `InitECan` и `InitPieVectTable`: + +```c +int ok = gt_f28335_init_periph(5U); /* PERIPH5=Type1/ID5, то есть УМП1; номер берётся из конфигурации платы. */ +if (ok) ok = gt_f28335_timer2_start(150000000UL); /* Частота CPU задаётся проектом в Гц; пример соответствует 150 МГц. */ +``` + +`gt_f28335_init()` позволяет передать Type и ID непосредственно. +`init_periph()` поддерживает физические PERIPH 0..31: Type1/2 и ID0..15; +5 — УМП1, 6 — УМП2, 8 — задатчик. Порт инициализируется до подключения hooks. +Повторный init разрешён только при остановленном собственном Timer2, +отсутствующем TX и запрещённых глобальных IRQ. + +Если Timer2 занят RTOS или приложением, **не вызывайте** `timer2_start()`; +в существующем ISR с периодом ровно 1 мс вызывайте `gt_f28335_tick_1ms()`. +Используйте один источник такта. Отдельный Timer2 продолжает отсчёт и при +медленном main, но длительная блокировка IRQ на несколько миллисекунд приводит +к потере тиков: аппаратный флаг прерывания не считает пропущенные периоды. + +В существующем `ECAN0INTA` ISR перед очисткой общих CAN-флагов и PIEACK: + +```c +gt_f28335_rx_isr(); /* Копирует только MBOX7 и запоминает uptime при приёме, календарь проверяется позднее. */ +``` + +Приложение должно разрешить соответствующий CAN IRQ: `CANGIM.I0EN`, +PIE group9 `INTx5`, CPU `M_INT9`; оставить свой обработчик остальных mailbox +и штатные подтверждения CANGIF/PIEACK. Порт не заменяет общий CAN ISR. +Глобальный `EINT` выполняет приложение после полной настройки. + +После прикладной инициализации и в каждом проходе главного цикла соответственно: + +```c +gt_f28335_ready(); /* Выполняется один раз после загрузки параметров и запуска прикладных подсистем. */ +gt_f28335_service(); /* Выполняется регулярно в main; обработка календаря и CAN не ждёт аппаратного ACK. */ +``` + +Все атомарные чтения и обновления используют TI +`__disable_interrupts()` / `__restore_interrupts()`, сохраняя прежний INTM. +Транспорт ждёт подтверждение CANTA асинхронно и не перезаписывает занятый MBOX8. +При отсутствии других CAN-узлов передача остаётся аппаратному контроллеру +до восстановления шины. CAN ACK не подтверждает обработку пакета мастером; +приход корректного RTCSETUP прекращает повторные объявления готовности. + +## Точность и календарь + +Разрешение локальных часов — 1 мс. Действующий RTCSETUP передаёт только целые +секунды, поэтому сам формат **не гарантирует синхронизацию плат с точностью 1 мс**. +Мастер должен посылать актуальное значение около секундной границы. +Арбитраж CAN и задержка до RX ISR остаются погрешностью; задержка после RX ISR +до обработки в main компенсируется по монотонному счётчику. Для точности между +платами до 1 мс понадобится согласованное расширение проводного протокола. + +Одна шкала времени выбирается верхним уровнем (рекомендуется UTC); кадр не +содержит часовой пояс. Входные годы 2000..2099, дата проверяется по григорианскому +календарю. Формат дня недели 0..6 соответствует проверке существующего +STM32-порта; профиль обозначает 0 как воскресенье. Для совместимости переданная +фаза недели сохраняется без дополнительной проверки соответствия дате. +Некоторые старые клиенты отображают неделю как 1..7; перед отправкой им нужен +перевод воскресенья 7 → 0. +Секундная шкала uint32_t от 2000 года переполнится в феврале 2136 года. +Период между захватом RX uptime и `gt_receive()` должен быть меньше 2^32 мс. + +## Проверки + +Из корня templates: + +```text +python c/global-time/tests/run_tests.py +``` + +`--cc` задаёт GCC/Clang. Для отдельной TI C28x проверки передайте +`--ti-cgt` (каталог компилятора), `--ti-headers` (DSP2833x_headers/include) +и при необходимости `--ti-common` (DSP2833x_common/include). +Объекты и EXE создаются во временном каталоге. CMake также предоставляет +`global_time`, два CTest и опции `GLOBAL_TIME_BUILD_F28335` / +`GLOBAL_TIME_BUILD_TESTS`; MCU проект задаёт свои TI include-пути. + +Проверяются ошибки даты и кадра, високосный февраль, смена года, коррекции +в обе стороны, компенсация очереди через переполнение uptime, ранний broadcast, +повторы готовности, сохранение IRQ, изоляция eCAN mailbox, аппаратный ACK, +значения периода Timer2 и его реальный ISR через назначенный вектор. +TI-проверка компилирует исходники с large/COFF ABI и настоящими заголовками +проекта 28335_periph. Полная линковка конкретной прошивки и проверка на плате +в этот набор не входят. diff --git a/c/global-time/include/global_time.h b/c/global-time/include/global_time.h new file mode 100644 index 0000000..46f406c --- /dev/null +++ b/c/global-time/include/global_time.h @@ -0,0 +1,65 @@ +#ifndef GLOBAL_TIME_H /* Защищает единый контракт часов от повторного включения. */ +#define GLOBAL_TIME_H /* Отмечает подключённый интерфейс программных глобальных часов. */ +#include /* Фиксирует разрядность счётчиков и поддерживает 16-битный char TI C28x. */ +#ifdef __cplusplus /* Сохраняет совместимость C-библиотеки с приложениями C++. */ +extern "C" { /* Экспортирует функции без изменения имён компилятором C++. */ +#endif /* Завершает условное объявление C ABI. */ +#define GT_RTC_ID 0x00000030UL /* ProtoCAN: Route=0, Type/ID=0, BROADCAST=0, RTCSETUP=3 в Body[15:4]. */ +#define GT_READY_BODY 0x3000U /* Контракт GLOBAL_TIME.md: DISCRETE/FLAGS=3, страница общих флагов=0. */ +#define GT_READY_RETRY_MS 1000UL /* Повторяет сообщение готовности раз в секунду до первой синхронизации. */ +typedef struct gt_frame { /* Описывает classic CAN независимо от регистров и размера char процессора. */ + uint32_t id; /* Хранит только 29 бит идентификатора, без служебных битов драйвера. */ + uint16_t extended; /* Единица означает IDE=1; стандартные кадры часы игнорируют. */ + uint16_t remote; /* Единица означает RTR; удалённый запрос не содержит время. */ + uint16_t dlc; /* Считает октеты на линии, а не sizeof элементов массива C28x. */ + uint16_t data[8]; /* Каждый элемент содержит один октет 0..255 даже при CHAR_BIT=16. */ +} gt_frame; /* Завершает переносимый контейнер кадра. */ +typedef struct gt_datetime { /* Представляет календарь без зависимости от time_t и часового пояса ОС. */ + uint16_t year; /* Полный год; входной ProtoCAN поддерживает 2000..2099. */ + uint16_t month; /* Номер месяца 1..12, без BCD-кодирования. */ + uint16_t day; /* Число месяца с проверкой високосного февраля. */ + uint16_t weekday; /* День недели 0..6; профиль использует 0=воскресенье, 1=понедельник. */ + uint16_t hour; /* Часы 0..23 в 24-часовом формате. */ + uint16_t minute; /* Минуты 0..59; leap seconds протокол не передаёт. */ + uint16_t second; /* Секунды 0..59 согласно существующему RTCSETUP. */ + uint16_t millisecond; /* Доля секунды 0..999; RTCSETUP задаёт нулевую долю. */ +} gt_datetime; /* Завершает публичный календарный тип. */ +typedef struct gt_stamp { /* Даёт логгеру согласованную метку и её качество одним чтением. */ + uint32_t seconds; /* Секунды от 2000-01-01 00:00:00 в шкале времени мастера. */ + uint16_t millisecond; /* Миллисекундная доля текущей секунды. */ + uint16_t synchronized; /* Ноль до первого корректного RTCSETUP, единица после него. */ + uint32_t uptime_ms; /* Независимый счётчик работы modulo 2^32; коррекции его не меняют. */ + uint32_t sync_uptime_ms; /* Момент приёма последнего RTCSETUP для оценки давности синхронизации. */ + uint32_t generation; /* Число коррекций; логгер отличает участки до и после перевода часов. */ + int64_t correction_ms; /* Последнее смещение новых часов относительно старых, в миллисекундах. */ + uint16_t weekday; /* Принятый день недели, продвигаемый при каждом переходе через полночь. */ +} gt_stamp; /* Завершает атомарно читаемый снимок. */ +typedef struct gt_port { /* Передаёт ядру короткие критические секции и неблокирующую отправку CAN. */ + void *user; /* Контекст платформы, передаваемый каждому callback без преобразования. */ + uint16_t (*enter)(void *user); /* Запрещает IRQ и возвращает прежнее состояние для вложенных вызовов. */ + void (*leave)(void *user, uint16_t state); /* Восстанавливает прежнее состояние IRQ, включая вызовы из ISR. */ + int (*send)(void *user, const gt_frame *frame); /* Копирует кадр до возврата; 1=принят, 0=занято/ошибка. */ +} gt_port; /* Завершает платформенный контракт; heap и аппаратный RTC не нужны. */ +typedef struct gt_clock { /* Хранит состояние одного узла; инициализация обязательна до разрешения ISR. */ + gt_port port; /* Содержит проверенные callbacks и контекст платформы. */ + volatile gt_stamp stamp; /* Меняется только при удержании блокировки IRQ. */ + uint16_t device_type; /* Три адресных бита ProtoCAN, диапазон 0..7. */ + uint16_t device_id; /* Четыре адресных бита экземпляра, диапазон 0..15. */ + uint16_t ready; /* Устанавливается приложением после завершения всей инициализации платы. */ + uint16_t announced; /* Помнит принятую транспортом отправку готовности, даже если часы уже синхронизированы. */ + uint32_t sent_uptime_ms; /* Ограничивает частоту повторов готовности монотонной шкалой. */ +} gt_clock; /* Состояние допускает статическое выделение памяти на микроконтроллере. */ +int gt_init(gt_clock *clock, const gt_port *port, uint16_t device_type, uint16_t device_id); /* Проверяет адрес/callbacks и явно очищает RAM, включая TI COFF. */ +void gt_tick_1ms(gt_clock *clock); /* Вызывается ровно один раз за аппаратную миллисекунду и выполняет только короткую арифметику. */ +void gt_get(gt_clock *clock, gt_stamp *out); /* Атомарно копирует всю метку; допустим вызов из main, логгера и ISR. */ +void gt_ready(gt_clock *clock); /* Идемпотентно разрешает сообщение «плата инициализирована»; CAN отправляется из poll. */ +void gt_poll(gt_clock *clock); /* Вызывается единственным потребителем в main; не ждёт освобождения CAN. */ +int gt_receive(gt_clock *clock, const gt_frame *frame, uint32_t received_uptime_ms); /* Проверяет RTCSETUP и компенсирует задержку от приёма до обработки, менее 2^32 мс. */ +int gt_make_rtc(const gt_datetime *date, gt_frame *out); /* Даёт верхнему уровню кодировщик штатного 7-октетного broadcast. */ +int gt_parse_ready(const gt_frame *frame, uint16_t *device_type, uint16_t *device_id); /* Позволяет мастеру распознать готовность и выбрать ответ RTCSETUP. */ +int gt_calendar(const gt_stamp *stamp, gt_datetime *out); /* Преобразует согласованный снимок в календарь; до синхронизации возвращает 0. */ +uint64_t gt_timestamp_ms(const gt_stamp *stamp); /* Возвращает широкую метку от 2000 года без переполнения через 49,7 суток. */ +#ifdef __cplusplus /* Закрывает C ABI только для компилятора C++. */ +} /* Завершает блок функций с C-связыванием. */ +#endif /* Завершает проверку языка потребителя. */ +#endif /* Завершает защиту публичного заголовка. */ diff --git a/c/global-time/ports/tms320f28335/global_time_f28335.c b/c/global-time/ports/tms320f28335/global_time_f28335.c new file mode 100644 index 0000000..9a07f78 --- /dev/null +++ b/c/global-time/ports/tms320f28335/global_time_f28335.c @@ -0,0 +1,168 @@ +#include "DSP2833x_Device.h" /* Использует штатные описания 32-битных регистров eCAN, Timer2 и векторов TI. */ +#include "global_time_f28335.h" /* Подключает переносимые часы и контракт интеграции порта. */ +#include /* Явно очищает отложенный RX до первого прохода main, включая TI COFF. */ +#define GT_RX 0x00000080UL /* Бит 7 регистров eCAN соответствует выделенному приёмному MBOX7. */ +#define GT_TX 0x00000100UL /* Бит 8 регистров eCAN соответствует отдельному передающему MBOX8. */ +static gt_clock board_clock; /* Один узел F28335 использует одну глобальную временную шкалу. */ +static gt_frame pending_frame; /* Последний RX хранится до обработки в main; новый broadcast заменяет устаревший. */ +static volatile uint16_t pending_rx; /* Публикует полностью скопированный RX и его монотонную привязку. */ +static uint32_t received_at; /* Запоминает миллисекундный uptime в момент обработки CAN ISR. */ +static uint16_t tx_busy, timer_owned; /* Явно сбрасывается init: TI COFF не гарантирует нули в .ebss. */ +static uint16_t initialized = 0U; /* Запись в .cinit гарантирует безопасный отказ ранних ISR hooks до init даже при TI COFF. */ +static uint16_t enter(void *user) /* Реализует вложенную критическую секцию TI C28x. */ +{ /* Не разрешает прерывания при выходе из уже выполняющегося ISR. */ + (void)user; /* Порт использует один статический экземпляр, поэтому контекст не требуется. */ + return __disable_interrupts(); /* Возвращает предыдущее состояние ST1, необходимое для восстановления INTM. */ +} /* Завершает платформенный вход в критическую секцию. */ +static void leave(void *user, uint16_t state) /* Восстанавливает состояние IRQ до входа в библиотеку. */ +{ /* Сохраняет корректность вызовов и из main, и из ISR. */ + (void)user; /* Отдельный аппаратный экземпляр выбирается статическими регистрами eCAN-A. */ + __restore_interrupts(state); /* Восстанавливает исходный INTM вместо безусловного разрешения IRQ. */ +} /* Завершает платформенный выход из критической секции. */ +static int send(void *user, const gt_frame *frame) /* Копирует пакет готовности в выделенный аппаратный mailbox без ожидания. */ +{ /* Транспорт не перезаписывает кадр, пока контроллер не подтвердит передачу. */ + uint16_t state = enter(0); /* Защищает RMW общих регистров CANME от чужих CAN ISR, сохраняя прежний INTM. */ + (void)user; /* Контекст платформы не нужен для фиксированного eCAN-A MBOX8. */ + if (tx_busy || (ECanaRegs.CANTRS.all & GT_TX)) { /* При занятости сохраняет исходный пакет и предлагает повтор из main. */ + leave(0, state); /* Восстанавливает исходные IRQ и на раннем выходе занятого транспорта. */ + return 0; /* Не теряет готовность и не ждёт окончания аппаратной передачи. */ + } /* Продолжает только при владении свободным MBOX8. */ + EALLOW; /* Открывает запись защищённой конфигурации mailbox контроллера. */ + ECanaRegs.CANME.all &= ~GT_TX; /* Отключает только MBOX8 перед изменением ID и payload. */ + ECanaMboxes.MBOX8.MSGID.all = 0x80000000UL | frame->id; /* IDE в бите 31 eCAN разрешает расширенный ProtoCAN ID. */ + ECanaMboxes.MBOX8.MSGCTRL.all = 1UL; /* DLC=1 и RTR=0 соответствуют единственному октету готовности. */ + ECanaMboxes.MBOX8.MDL.all = frame->data[0]; /* Первый проводной октет располагается в младших восьми битах MDL при DBO=0. */ + ECanaMboxes.MBOX8.MDH.all = 0UL; /* Убирает остатки прежнего payload, хотя DLC передаёт только один октет. */ + ECanaRegs.CANTA.all = GT_TX; /* Сбрасывает только старый ACK MBOX8 записью единицы. */ + ECanaRegs.CANAA.all = GT_TX; /* Сбрасывает только старое подтверждение отмены MBOX8. */ + ECanaRegs.CANME.all |= GT_TX; /* Возвращает MBOX8 в работу, сохраняя чужие mailbox. */ + ECanaRegs.CANTRS.all = GT_TX; /* Запрашивает передачу без блокирующего ожидания ACK шины. */ + EDIS; /* Закрывает запись защищённых регистров после полной публикации кадра. */ + tx_busy = 1U; /* Отмечает владение кадром до CANTA или CANAA, даже при отсутствии других узлов на шине. */ + leave(0, state); /* Освобождает короткую аппаратную секцию сразу после публикации запроса передачи. */ + return 1; /* Подтверждает приём транспортом, но не отдельное прикладное подтверждение мастера. */ +} /* Завершает неблокирующий callback передачи. */ +int gt_f28335_init(uint16_t device_type, uint16_t device_id) /* Настраивает часы и только два выделенных mailbox при запрещённых IRQ. */ +{ /* Приложение заранее задаёт скорость eCAN, GPIO, DBO=0 и общие векторы прерываний. */ + gt_port port; /* Локальная таблица callbacks копируется ядром в постоянное состояние. */ + if (device_type > 7U || device_id > 15U || (ECanaRegs.CANTRS.all & GT_TX) || ECanaRegs.CANMC.bit.DBO) return 0; /* Проверяет адрес и порядок октетов; активную TX-передачу не прерывает повторным init. */ + if (initialized && timer_owned) return 0; /* Требует остановить захваченный Timer2 перед повторным init, сохраняя его владение при отказе. */ + port.user = 0; /* Единственный экземпляр порта не требует внешнего контекста. */ + port.enter = enter; /* Подключает защиту снимка штатным intrinsic TI. */ + port.leave = leave; /* Подключает восстановление предыдущей маски прерываний. */ + port.send = send; /* Подключает отправку в MBOX8 без ожидания свободной шины. */ + if (!gt_init(&board_clock, &port, device_type, device_id)) return 0; /* Сбрасывает RAM до открытия источников IRQ. */ + pending_rx = tx_busy = timer_owned = 0U; /* Явно очищает программные флаги после холодного и тёплого старта. */ + memset(&pending_frame, 0, sizeof(pending_frame)); /* Не читает неопределённую RAM при первом service без полученного пакета. */ + received_at = 0UL; /* Начальная привязка не читается до получения первого кадра. */ + EALLOW; /* Открывает изменение аппаратной конфигурации eCAN-A. */ + ECanaRegs.CANME.all &= ~(GT_RX | GT_TX); /* Временно отключает только выделенные mailbox 7/8. */ + ECanaMboxes.MBOX7.MSGID.all = 0xC0000000UL | GT_RTC_ID; /* IDE=1 и AME=1 включают расширенный ID и локальную маску точного RTCSETUP. */ + ECanaLAMRegs.LAM7.all = 0x10000000UL; /* LAM игнорирует только бит Priority[28]; LAMI=0 сохраняет проверку IDE. */ + ECanaMboxes.MBOX7.MSGCTRL.all = 7UL; /* Задаёт ожидаемые семь октетов; фактический DLC дополнительно проверяется ядром. */ + ECanaMboxes.MBOX8.MSGID.all = 0x80000000UL; /* Подготавливает расширенный TX без AME; адрес будет установлен callback отправки. */ + ECanaMboxes.MBOX8.MSGCTRL.all = 1UL; /* Пакет готовности занимает один октет CAN payload. */ + ECanaRegs.CANMD.all = (ECanaRegs.CANMD.all | GT_RX) & ~GT_TX; /* MBOX7 становится RX, MBOX8 — TX, направления остальных mailbox сохраняются. */ + ECanaRegs.CANOPC.all |= GT_RX; /* Запрещает перезапись RX до чтения ISR; при потере используется следующий периодический broadcast. */ + ECanaRegs.CANMIL.all &= ~GT_RX; /* Направляет MBOX7 в общую линию ECAN0INTA приложения. */ + ECanaRegs.CANMIM.all = (ECanaRegs.CANMIM.all | GT_RX) & ~GT_TX; /* Разрешает IRQ только на RX, а завершение TX проверяет main. */ + ECanaRegs.CANRMP.all = GT_RX; /* Удаляет старый pending только MBOX7 записью единицы. */ + ECanaRegs.CANRML.all = GT_RX; /* Очищает старую потерю приёма только выделенного mailbox. */ + ECanaRegs.CANTA.all = GT_TX; /* Удаляет старый ACK выделенного передатчика, не затрагивая CAN Boot. */ + ECanaRegs.CANAA.all = GT_TX; /* Удаляет старый флаг отмены перед настройкой нового обмена. */ + ECanaRegs.CANME.all |= GT_RX | GT_TX; /* Включает приём синхронизации и передачу готовности. */ + EDIS; /* Закрывает защищённую конфигурацию контроллера. */ + initialized = 1U; /* Публикует готовность самого порта после сброса всех RAM- и аппаратных флагов. */ + return 1; /* Приложение может запускать такт и разрешать общие CAN-прерывания. */ +} /* Завершает настройку без сброса скорости, GPIO и других CAN-сервисов. */ +int gt_f28335_init_periph(uint16_t periph) /* Привязывает часы к физическому адресу периферийной платы. */ +{ /* Использует тот же реестр, что существующий порт CAN Boot F28335. */ + if (periph >= 32U) return 0; /* Адреса PERIPH определены только для 32 устройств, без циклического обрезания. */ + return gt_f28335_init((uint16_t)(1U + periph / 16U), periph % 16U); /* Номера 0..15 используют Type=1, 16..31 — Type=2, младшие четыре бита задают ID. */ +} /* Завершает преобразование физического адреса. */ +gt_clock *gt_f28335_clock(void) /* Предоставляет логгеру общую временную базу платы. */ +{ /* Действует после успешной инициализации порта. */ + return &board_clock; /* Один и тот же объект обслуживают CAN, таймер и все потребители времени. */ +} /* Завершает доступ к экземпляру переносимого ядра. */ +void gt_f28335_ready(void) /* Публикует готовность прикладного оборудования после загрузки параметров. */ +{ /* Не объявляет успех при отказе конфигурации порта. */ + if (initialized) gt_ready(&board_clock); /* Первый пакет будет послан из main даже при уже полученном времени. */ +} /* Завершает hook завершения инициализации платы. */ +void gt_f28335_tick_1ms(void) /* Позволяет использовать существующий периодический ISR вместо Timer2. */ +{ /* Приложение выбирает один источник миллисекунд, исключая двойной отсчёт. */ + if (initialized) gt_tick_1ms(&board_clock); /* Продвигает локальные и календарные часы только после явного init. */ +} /* Завершает универсальный миллисекундный hook. */ +void gt_f28335_rx_isr(void) /* Захватывает CAN-время и момент получения без календарной обработки в ISR. */ +{ /* Вызывается существующим обработчиком ECAN0INTA до очистки CANGIF и PIEACK. */ + uint32_t low, high, uptime; /* Однократные 32-битные чтения не рвут слова аппаратного mailbox. */ + uint16_t i, state; /* Индекс восьми октетов и прежняя маска прерываний. */ + if (!initialized || !(ECanaRegs.CANRMP.all & GT_RX)) return; /* Не читает MBOX7 по прерыванию другого CAN-сервиса. */ + state = enter(0); /* Исключает вложенный таймер между чтением uptime и публикацией полученного кадра. */ + uptime = board_clock.stamp.uptime_ms; /* Фиксирует момент RX в монотонных миллисекундах, независимых от синхронизации. */ + pending_frame.id = ECanaMboxes.MBOX7.MSGID.all & 0x1FFFFFFFUL; /* Удаляет служебные IDE/AME биты регистра из 29-битного ID. */ + pending_frame.extended = (uint16_t)(ECanaMboxes.MBOX7.MSGID.all >> 31U); /* Ядро дополнительно проверит IDE даже при аппаратной фильтрации. */ + pending_frame.remote = ECanaMboxes.MBOX7.MSGCTRL.bit.RTR; /* Сохраняет RTR, чтобы удалённый запрос никогда не устанавливал часы. */ + pending_frame.dlc = ECanaMboxes.MBOX7.MSGCTRL.bit.DLC; /* Сохраняет фактическую длину, включая ошибочный или пустой payload. */ + low = ECanaMboxes.MBOX7.MDL.all; /* Читает первые четыре октета одним 32-битным доступом eCAN. */ + high = ECanaMboxes.MBOX7.MDH.all; /* Читает оставшиеся четыре октета без указателей на байты C28x. */ + for (i = 0U; i < 8U; ++i) pending_frame.data[i] = (uint16_t)(((i < 4U ? low : high) >> (8U * (i % 4U))) & 255UL); /* Извлекает каждый проводной октет при DBO=0 в отдельное 16-битное слово. */ + received_at = uptime; /* Публикует временную привязку того же аппаратного кадра. */ + pending_rx = 1U; /* Отмечает полностью готовый снимок; main читает его под той же блокировкой. */ + ECanaRegs.CANRMP.all = GT_RX; /* Освобождает MBOX7 только после полного копирования защищённого CANOPC кадра. */ + ECanaRegs.CANRML.all = GT_RX; /* Сбрасывает индикатор пропущенного кадра, сохраняя уже скопированное опорное время. */ + leave(0, state); /* Возвращает исходный INTM обработчика CAN. */ +} /* Завершает короткий ISR без отправки, ожидания CAN и расчёта календаря. */ +void gt_f28335_service(void) /* Обрабатывает часы и готовность из единственного основного цикла. */ +{ /* Отложенная календарная работа не увеличивает длительность CAN ISR. */ + gt_frame frame; /* Локальная копия допускает замену следующего pending кадра новым CAN ISR. */ + uint32_t uptime; /* Сохраняет привязку прочитанного кадра до выхода из критической секции. */ + uint16_t state, have_rx; /* Разделяет короткий захват очереди и длительную проверку календаря. */ + if (!initialized) return; /* Не обращается к неинициализированным callbacks после отказа init. */ + state = enter(0); /* Блокирует ISR только на время копирования одного небольшого кадра. */ + have_rx = pending_rx; /* Запоминает наличие кадра перед освобождением слота. */ + frame = pending_frame; /* Копирует payload и заголовок согласованно с моментом RX. */ + uptime = received_at; /* Забирает момент получения того же кадра. */ + pending_rx = 0U; /* Разрешает приём следующего broadcast, пока main рассчитывает дату текущего. */ + leave(0, state); /* Возобновляет IRQ до календарных циклов. */ + if (have_rx) (void)gt_receive(&board_clock, &frame, uptime); /* Проверяет время и добавляет тики, прошедшие с RX ISR. */ + if (tx_busy && ((ECanaRegs.CANTA.all | ECanaRegs.CANAA.all) & GT_TX)) { /* Освобождает TX только после подтверждения передачи либо аппаратной отмены. */ + ECanaRegs.CANTA.all = GT_TX; /* Сбрасывает только ACK собственного mailbox. */ + ECanaRegs.CANAA.all = GT_TX; /* Сбрасывает только флаг отмены собственного mailbox. */ + tx_busy = 0U; /* Следующий gt_poll сможет повторить готовность, если время ещё не получено. */ + } /* При отсутствии ACK запрос остаётся аппаратному CAN для автоматической передачи после восстановления шины. */ + gt_poll(&board_clock); /* Объявляет готовность и ограничивает повторы одной секундой локального времени. */ +} /* Завершает неблокирующий проход обслуживания. */ +__interrupt void gt_f28335_timer2_isr(void) /* Обслуживает прямой CPU INT14 без использования группы PIE. */ +{ /* Этот вектор принадлежит библиотеке только после явного timer2_start. */ + CpuTimer2Regs.TCR.all = 0xC000U; /* TIF[15]=1 очищает флаг, TIE[14]=1 сохраняет IRQ, TSS=0 продолжает счёт. */ + gt_f28335_tick_1ms(); /* Один период Timer2 соответствует одной миллисекунде программных часов. */ +} /* Для прямого INT14 подтверждение PIEACK не требуется. */ +int gt_f28335_timer2_start(uint32_t cpu_hz) /* Опционально запускает выделенный таймер с периодом ровно 1 мс. */ +{ /* Частота поступает от проекта; порт не предполагает жёстко заданные 150 МГц. */ + uint16_t state; /* Сохраняет прежнюю глобальную маску IRQ на время смены вектора. */ + if (!initialized || cpu_hz < 1000UL || cpu_hz % 1000UL != 0UL) return 0; /* Отвергает период с дробным числом тактов вместо накопления скрытого дрейфа. */ + state = enter(0); /* Исключает запуск INT14 со старым вектором и новым периодом. */ + CpuTimer2Regs.TCR.all = 0x0010U; /* TSS[4]=1 останавливает счёт, TIE=0 временно запрещает IRQ Timer2. */ + CpuTimer2Regs.PRD.all = cpu_hz / 1000UL - 1UL; /* Период включает значения PRD..0; при 150 МГц это 149999, то есть 150000 тактов за 1 мс. */ + CpuTimer2Regs.TPR.all = 0U; /* Нулевой младший предделитель означает один такт CPU на шаг счётчика. */ + CpuTimer2Regs.TPRH.all = 0U; /* Нулевой старший предделитель не добавляет деления частоты. */ + EALLOW; /* Разрешает запись защищённой таблицы векторов прерываний TI. */ + PieVectTable.TINT2 = >_f28335_timer2_isr; /* Подключает собственный обработчик прямого CPU Timer2/INT14. */ + EDIS; /* Закрывает доступ к векторной таблице после установки обработчика. */ + IFR &= (uint16_t)~M_INT14; /* Снимает старый pending CPU INT14 до запуска нового периодического такта. */ + IER |= M_INT14; /* Разрешает только INT14, сохраняя маски остальных CPU-прерываний. */ + timer_owned = 1U; /* Позволяет stop изменять Timer2 только после явного захвата этим портом. */ + CpuTimer2Regs.TCR.all = 0xC020U; /* TIF=1 очищает флаг, TIE=1 разрешает IRQ, TRB=1 загружает PRD, TSS=0 запускает таймер. */ + leave(0, state); /* Сохраняет выбор приложения, когда разрешить глобальные прерывания. */ + return 1; /* Приложение должно исключить параллельный вызов tick из своего Timer1. */ +} /* Завершает настройку автономного миллисекундного такта. */ +void gt_f28335_timer2_stop(void) /* Освобождает аппаратный такт, ранее явно запущенный библиотекой. */ +{ /* Не трогает чужой Timer2, если выбран hook существующего таймера. */ + uint16_t state = enter(0); /* Не допускает INT14 между остановкой счётчика и снятием разрешения CPU. */ + if (timer_owned) { /* Ограничивает изменения ресурсом, захваченным этим портом. */ + CpuTimer2Regs.TCR.all = 0x8010U; /* TIF=1 очищает флаг, TSS=1 останавливает таймер, TIE=0 запрещает источник IRQ. */ + IER &= (uint16_t)~M_INT14; /* Убирает только разрешение прямого Timer2 IRQ, сохраняя остальные CPU-сервисы. */ + timer_owned = 0U; /* Фиксирует освобождение источника аппаратного такта. */ + } /* При отсутствии владения никакие регистры таймера не меняются. */ + leave(0, state); /* Возвращает прежнее состояние глобальной маски IRQ. */ +} /* Завершает необязательную остановку аппаратных часов. */ diff --git a/c/global-time/ports/tms320f28335/global_time_f28335.h b/c/global-time/ports/tms320f28335/global_time_f28335.h new file mode 100644 index 0000000..92ccbce --- /dev/null +++ b/c/global-time/ports/tms320f28335/global_time_f28335.h @@ -0,0 +1,19 @@ +#ifndef GLOBAL_TIME_F28335_H /* Защищает порт F28335 от повторного включения. */ +#define GLOBAL_TIME_F28335_H /* Отмечает единственный экземпляр аппаратного порта. */ +#include "global_time.h" /* Экспортирует тот же снимок метки и календарный API, что переносимое ядро. */ +#ifdef __cplusplus /* Сохраняет возможность подключения из приложения C++. */ +extern "C" { /* Фиксирует C ABI аппаратных точек входа. */ +#endif /* Завершает условное открытие C ABI. */ +int gt_f28335_init(uint16_t device_type, uint16_t device_id); /* После InitECan и InitPieVectTable, до IRQ: занимает только eCAN-A MBOX7 RX и MBOX8 TX. */ +int gt_f28335_init_periph(uint16_t periph); /* Преобразует PERIPH 0..31 в Type=1/2, ID=0..15 по реестру ProtoCAN. */ +gt_clock *gt_f28335_clock(void); /* Даёт логгеру ядро для gt_get; указатель действителен после успешного init. */ +void gt_f28335_ready(void); /* Вызывается после успешной инициализации всей платы, затем отправка происходит из service. */ +void gt_f28335_tick_1ms(void); /* Подключается к существующему ISR 1 мс, если отдельный Timer2 не используется. */ +void gt_f28335_rx_isr(void); /* Вызывается общим ECAN0INTA ISR до очистки общих флагов; не выполняет календарных циклов. */ +void gt_f28335_service(void); /* Вызывается в main: применяет последний RX, обслуживает ACK и повторы готовности без ожиданий. */ +int gt_f28335_timer2_start(uint32_t cpu_hz); /* Необязательный такт: занимает CPU Timer2/INT14, принимает частоту CPU в Гц, кратную 1000. */ +void gt_f28335_timer2_stop(void); /* Останавливает только ранее запущенный портом Timer2, сохраняя остальные разрешения CPU IRQ. */ +#ifdef __cplusplus /* Закрывает C ABI при использовании C++. */ +} /* Завершает блок аппаратных функций с C-связыванием. */ +#endif /* Завершает языковую проверку. */ +#endif /* Завершает защиту заголовка порта. */ diff --git a/c/global-time/src/global_time.c b/c/global-time/src/global_time.c new file mode 100644 index 0000000..5ef014c --- /dev/null +++ b/c/global-time/src/global_time.c @@ -0,0 +1,156 @@ +#include "global_time.h" /* Подключает переносимые типы, API часов и фиксированные поля ProtoCAN. */ +#include /* Использует явный сброс состояния вместо предположений о старте TI COFF. */ +static uint16_t month_days(uint16_t year, uint16_t month) /* Вычисляет длину уже проверенного месяца по григорианскому календарю. */ +{ /* Ограничивает область таблицы календаря и условия високосного года. */ + static const uint16_t days[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; /* Число суток каждого месяца обычного года. */ + return (uint16_t)(days[month - 1U] + (month == 2U && year % 4U == 0U && (year % 100U != 0U || year % 400U == 0U))); /* Добавляет 29 февраля, включая исключение для 2100 года. */ +} /* Завершает календарный расчёт без обращения к платформе. */ +static int date_seconds(const gt_datetime *date, uint32_t *seconds) /* Проверяет все входные поля до индексации календарных таблиц. */ +{ /* Собирает секунды эпохи отдельно от критической секции часов. */ + uint16_t year, month; /* Счётчики лет и месяцев нужны только при редкой синхронизации. */ + uint32_t days = 0; /* Накопленные сутки от начала 2000 года; диапазон CAN не превышает 36525 суток. */ + if (!date || date->year < 2000U || date->year > 2099U || date->month < 1U || date->month > 12U) return 0; /* Отвергает неподдерживаемую эпоху и неверный индекс месяца. */ + if (date->day < 1U || date->day > month_days(date->year, date->month) || date->weekday > 6U) return 0; /* Принимает только существующую дату и формат дня недели действующего STM32 RTCSETUP. */ + if (date->hour > 23U || date->minute > 59U || date->second > 59U || date->millisecond > 999U) return 0; /* Исключает перенос некорректных полей в соседние сутки. */ + for (year = 2000U; year < date->year; ++year) days += 365UL + (month_days(year, 2U) == 29U); /* Учитывает каждый полный год относительно фиксированной эпохи. */ + for (month = 1U; month < date->month; ++month) days += month_days(date->year, month); /* Прибавляет полные месяцы текущего года. */ + days += date->day - 1U; /* Переводит календарное число 1..31 в число завершённых суток. */ + *seconds = days * 86400UL + (uint32_t)date->hour * 3600UL + (uint32_t)date->minute * 60UL + date->second; /* Константы задают секунд в сутках, часе и минуте; UL исключает 16-битное умножение C28x. */ + return 1; /* Подтверждает полностью проверенную календарную величину. */ +} /* Завершает преобразование календаря в секундную шкалу. */ +uint64_t gt_timestamp_ms(const gt_stamp *stamp) /* Позволяет логгеру сохранить абсолютное время без потери миллисекунд. */ +{ /* Выполняет расчёт по уже снятому атомарному снимку. */ + return (uint64_t)stamp->seconds * 1000ULL + stamp->millisecond; /* Расширяет до умножения, чтобы календарная метка не переполняла uint32_t. */ +} /* Завершает получение широкой метки времени. */ +int gt_init(gt_clock *clock, const gt_port *port, uint16_t device_type, uint16_t device_id) /* Создаёт часы до запуска прерываний устройства. */ +{ /* Отказывается от конфигурации без реальной защиты общего состояния. */ + if (!clock || !port || !port->enter || !port->leave || !port->send || device_type > 7U || device_id > 15U) return 0; /* Не обрезает ошибочный CAN-адрес до адреса другой платы. */ + memset(clock, 0, sizeof(*clock)); /* Сбрасывает в том числе неинициализированную .ebss TI COFF и старый признак синхронизации. */ + clock->port = *port; /* Сохраняет callbacks без выделения динамической памяти. */ + clock->device_type = device_type; /* Запоминает тип источника пакета готовности. */ + clock->device_id = device_id; /* Запоминает экземпляр источника пакета готовности. */ + clock->stamp.weekday = 6U; /* Начальная локальная эпоха 2000-01-01 приходится на субботу при 0=воскресенье. */ + return 1; /* Разрешает приложению подключать такт и CAN только после успеха. */ +} /* Завершает обязательную явную инициализацию. */ +void gt_tick_1ms(gt_clock *clock) /* Выполняет короткий шаг часов из миллисекундного ISR. */ +{ /* Защищает разрядные переносы и от вложенных читателей. */ + uint16_t state = clock->port.enter(clock->port.user); /* Сохраняет прежний INTM, чтобы выход из ISR не разрешил вложенные IRQ. */ + ++clock->stamp.uptime_ms; /* Продвигает независимое время работы modulo 2^32 миллисекунд. */ + if (++clock->stamp.millisecond == 1000U) { /* Переносит ровно 1000 аппаратных миллисекунд в одну секунду. */ + clock->stamp.millisecond = 0U; /* Начинает следующую секунду с нулевой дробной части. */ + if (++clock->stamp.seconds % 86400UL == 0UL) clock->stamp.weekday = (clock->stamp.weekday + 1U) % 7U; /* При переходе суток продвигает принятый день недели по циклу из семи дней. */ + } /* Завершает редкую секундную ветвь без календарных циклов в ISR. */ + clock->port.leave(clock->port.user, state); /* Восстанавливает исходную маску IRQ вызывающего кода. */ +} /* Завершает единственный источник продвижения часов. */ +void gt_get(gt_clock *clock, gt_stamp *out) /* Снимает согласованные дату, долю секунды и качество синхронизации. */ +{ /* Не допускает разрыва 32/64-битных полей на 16-битной шине C28x. */ + uint16_t state = clock->port.enter(clock->port.user); /* Блокирует изменение снимка таймером и CAN до завершения копирования. */ + *out = clock->stamp; /* Копирует все поля в пределах одной критической секции. */ + clock->port.leave(clock->port.user, state); /* Восстанавливает IRQ без безусловного EINT. */ +} /* Завершает чтение метки для логгера и тайм-аутов. */ +void gt_ready(gt_clock *clock) /* Отмечает фактическое завершение инициализации прикладных подсистем. */ +{ /* Разделяет настройку часов и объявление готовности всей платы. */ + clock->ready = 1U; /* Повторные вызовы не сбрасывают историю отправок или синхронизаций. */ +} /* Передачу сообщения выполнит основной цикл. */ +void gt_poll(gt_clock *clock) /* Обслуживает объявление готовности без задержек и ожидания CAN. */ +{ /* Разрешён один вызывающий основной цикл; callback send копирует временный кадр. */ + gt_stamp now; /* Согласованное время определяет частоту повторов независимо от перевода часов. */ + gt_frame frame; /* Локальный пакет не занимает место в постоянной очереди ядра. */ + if (!clock->ready) return; /* Плата не сообщает об успехе раньше завершения своей инициализации. */ + gt_get(clock, &now); /* Снимает монотонную базу и признак получения RTCSETUP. */ + if (clock->announced && (now.synchronized || (uint32_t)(now.uptime_ms - clock->sent_uptime_ms) < GT_READY_RETRY_MS)) return; /* После синхронизации прекращает повторы, сохраняя обязательную первую отправку. */ + memset(&frame, 0, sizeof(frame)); /* Явно обнуляет RTR и неиспользуемые октеты сообщения. */ + frame.id = 0x18010000UL | ((uint32_t)clock->device_type << 24U) | ((uint32_t)clock->device_id << 20U) | GT_READY_BODY; /* Задаёт стандартный приоритет, Route=1, DISCRETE=1 и FLAGS=3. */ + frame.extended = 1U; /* Использует только штатный расширенный идентификатор ProtoCAN. */ + frame.dlc = 1U; /* Одного октета хватает для общего флага готовности. */ + frame.data[0] = 1U; /* Бит 0 означает завершение инициализации; прочие биты зарезервированы нулями. */ + if (clock->port.send(clock->port.user, &frame)) { /* Не считает занятый mailbox успешной отправкой. */ + clock->announced = 1U; /* Фиксирует приём транспортом, а не отдельный прикладной ACK мастера. */ + clock->sent_uptime_ms = now.uptime_ms; /* Начинает секундный интервал до повтора при отсутствии RTCSETUP. */ + } /* При отказе транспорта следующая итерация main повторит попытку без ожидания. */ +} /* Завершает неблокирующее обслуживание готовности. */ +static int data_frame(const gt_frame *frame) /* Выполняет общую проверку контейнера classic CAN. */ +{ /* Не позволяет служебным битам драйвера участвовать в разборе ID. */ + return frame && frame->extended == 1U && !frame->remote && frame->id <= 0x1FFFFFFFUL; /* Требует IDE=1, RTR=0 и ровно 29 адресных битов. */ +} /* Завершает общую проверку адресного формата. */ +int gt_parse_ready(const gt_frame *frame, uint16_t *device_type, uint16_t *device_id) /* Распознаёт на верхнем уровне только определённый пакет готовности. */ +{ /* Не путает событие старта с пульсом или произвольными дискретными флагами. */ + if (!data_frame(frame) || (frame->id & 0x080FFFFFUL) != (0x08010000UL | GT_READY_BODY) || frame->dlc != 1U || frame->data[0] != 1U) return 0; /* Проверяет Route=1, MsgType=1, Body=0x3000 и единственный разрешённый флаг. */ + if (device_type) *device_type = (uint16_t)((frame->id >> 24U) & 7UL); /* Возвращает трёхбитный тип источника при наличии выходного указателя. */ + if (device_id) *device_id = (uint16_t)((frame->id >> 20U) & 15UL); /* Возвращает четырёхбитный номер экземпляра источника. */ + return 1; /* Верхний уровень может ответить одним общим RTCSETUP всем устройствам. */ +} /* Завершает распознавание стартового события мастером. */ +int gt_make_rtc(const gt_datetime *date, gt_frame *out) /* Кодирует существующую команду синхронизации для верхнего уровня. */ +{ /* Передаёт ровно те семь полей, которые принимает STM32-порт ProtoCAN. */ + uint32_t seconds; /* При проверке календаря получает допустимую секундную величину. */ + if (!out || !date_seconds(date, &seconds) || date->millisecond != 0U) return 0; /* Не отбрасывает ненулевые миллисекунды молча: проводной формат их не содержит. */ + memset(out, 0, sizeof(*out)); /* Нули задают RTR=0, критический приоритет и резерв payload. */ + out->id = GT_RTC_ID; /* Передаёт BROADCAST RTCSETUP от верхнего уровня с нулевым параметром команды. */ + out->extended = 1U; /* Выбирает расширенный 29-битный CAN-кадр. */ + out->dlc = 7U; /* Сохраняет существующий контракт DLC=7 без добавления миллисекундного расширения. */ + out->data[0] = date->hour; /* Первый октет содержит часы в двоичном представлении. */ + out->data[1] = date->minute; /* Второй октет содержит минуты. */ + out->data[2] = date->second; /* Третий октет содержит целые секунды. */ + out->data[3] = date->year - 2000U; /* Четвёртый октет хранит смещение года 0..99 от эпохи 2000. */ + out->data[4] = date->month; /* Пятый октет содержит месяц 1..12. */ + out->data[5] = date->day; /* Шестой октет содержит проверенное число месяца. */ + out->data[6] = date->weekday; /* Седьмой октет сохраняет принятый формат дня недели 0..6. */ + return 1; /* Кадр готов к неблокирующей отправке транспортом мастера. */ +} /* Завершает кодирование общего broadcast. */ +int gt_receive(gt_clock *clock, const gt_frame *frame, uint32_t received_uptime_ms) /* Проверяет и применяет RTCSETUP, привязанный к моменту приёма. */ +{ /* Отвергает некорректные кадры до изменения состояния устройства. */ + gt_datetime date; /* Временный календарь строится из отдельных октетов без struct overlay. */ + uint32_t seconds, elapsed, corrected_seconds, whole_days; /* Содержит секунды мастера, задержку в мс, актуальные секунды и перенос дня недели. */ + uint16_t i, state; /* Индекс проверки payload и сохранённое состояние IRQ. */ + uint16_t corrected_ms; /* Хранит дробную часть отдельно, исключая дорогие 64-битные деления под маской IRQ C28x. */ + if (!data_frame(frame) || (frame->id & 0x0FFFFFFFUL) != GT_RTC_ID || frame->dlc != 7U) return 0; /* Принимает оба приоритета, но только Route=0, Type/ID=0, BROADCAST RTCSETUP с параметром 0. */ + for (i = 0U; i < 7U; ++i) if (frame->data[i] > 255U) return 0; /* C28x хранит октет в 16-битном элементе; старшие биты означают ошибку адаптера. */ + date.hour = frame->data[0]; /* Восстанавливает часы по штатному порядку RTCSETUP. */ + date.minute = frame->data[1]; /* Восстанавливает минуты без BCD-преобразований. */ + date.second = frame->data[2]; /* Восстанавливает целые секунды мастера. */ + date.year = 2000U + frame->data[3]; /* Восстанавливает полный год из двухзначного поля протокола. */ + date.month = frame->data[4]; /* Читает номер месяца до проверки таблицы длительности. */ + date.day = frame->data[5]; /* Читает число месяца для строгой календарной проверки. */ + date.weekday = frame->data[6]; /* Сохраняет присланную мастером фазу недели. */ + date.millisecond = 0U; /* Семь октетов RTCSETUP задают точность источника только до секунды. */ + if (!date_seconds(&date, &seconds)) return 0; /* Неверные даты не сбрасывают часы и признак предыдущей синхронизации. */ + state = clock->port.enter(clock->port.user); /* Защищает сравнение, перенос и публикацию новой временной базы. */ + elapsed = clock->stamp.uptime_ms - received_uptime_ms; /* Учитывает время очереди main, в том числе через переполнение uint32_t uptime. */ + corrected_seconds = seconds + elapsed / 1000UL; /* Прибавляет полные секунды задержки RX; диапазон входных годов и задержка до 2^32 мс помещаются в uint32_t. */ + corrected_ms = (uint16_t)(elapsed % 1000UL); /* Восстанавливает фазу миллисекунд без 64-битного деления в критической секции. */ + clock->stamp.correction_ms = ((int64_t)corrected_seconds - clock->stamp.seconds) * 1000LL + corrected_ms - clock->stamp.millisecond; /* Сохраняет знак и полную величину смещения, расширяя разность секунд до умножения. */ + whole_days = corrected_seconds / 86400UL - seconds / 86400UL; /* Определяет переходы через полночь за время отложенной обработки. */ + clock->stamp.seconds = corrected_seconds; /* Публикует новые секунды независимо от монотонного uptime. */ + clock->stamp.millisecond = corrected_ms; /* Публикует долю секунды, соответствующую текущему локальному тику. */ + clock->stamp.weekday = (uint16_t)((date.weekday + whole_days) % 7UL); /* Сохраняет правильный день недели даже при обработке после полуночи. */ + clock->stamp.sync_uptime_ms = received_uptime_ms; /* Позволяет потребителю вычислить возраст последнего опорного пакета. */ + ++clock->stamp.generation; /* Отмечает любую принятую коррекцию, включая перевод часов назад. */ + clock->stamp.synchronized = 1U; /* Последней записью подтверждает валидность полностью опубликованной даты. */ + clock->port.leave(clock->port.user, state); /* Возвращает прежнюю маску прерываний после атомарного обновления. */ + return 1; /* Сообщает транспорту об успешной обработке синхронизации. */ +} /* Завершает сравнение и немедленную коррекцию часов. */ +int gt_calendar(const gt_stamp *stamp, gt_datetime *out) /* Преобразует снимок для человека без блокировки аппаратного таймера. */ +{ /* Вызывает календарные циклы только по требованию логгера или интерфейса. */ + uint32_t days, remainder; /* Разделяет полные сутки и секунды внутри суток. */ + uint16_t year = 2000U, month = 1U, length; /* Начинает разбор от эпохи библиотеки. */ + if (!stamp || !out || !stamp->synchronized) return 0; /* Не выдаёт локальный отсчёт до синхронизации за известную календарную дату. */ + days = stamp->seconds / 86400UL; /* Выделяет количество завершённых календарных суток. */ + remainder = stamp->seconds % 86400UL; /* Сохраняет секунды текущих суток отдельно от календарных вычислений. */ + while (days >= (uint32_t)(length = (uint16_t)(365U + (month_days(year, 2U) == 29U)))) { /* Вычитает полные годы с учётом григорианских исключений. */ + days -= length; /* Оставляет только сутки после текущего полного года. */ + ++year; /* Переходит к следующему году, включая работу после 2099 без нового CAN-пакета. */ + } /* Завершает поиск календарного года. */ + while (days >= (length = month_days(year, month))) { /* Вычитает полные месяцы найденного года. */ + days -= length; /* Сохраняет остаток суток внутри следующего месяца. */ + ++month; /* Продвигает месяц до того, которому принадлежит остаток. */ + } /* Завершает поиск календарного месяца. */ + out->year = year; /* Возвращает полный календарный год. */ + out->month = month; /* Возвращает месяц в привычном диапазоне 1..12. */ + out->day = (uint16_t)(days + 1UL); /* Переводит нулевой индекс остатка суток в календарное число. */ + out->weekday = stamp->weekday; /* Возвращает фазу недели из согласованного снимка, а не из текущих часов. */ + out->hour = (uint16_t)(remainder / 3600UL); /* Выделяет целые часы внутри суток. */ + out->minute = (uint16_t)((remainder % 3600UL) / 60UL); /* Выделяет минуты после последнего полного часа. */ + out->second = (uint16_t)(remainder % 60UL); /* Возвращает остаток секунд текущей минуты. */ + out->millisecond = stamp->millisecond; /* Сохраняет миллисекундную долю исходного снимка. */ + return 1; /* Подтверждает наличие календарной синхронизации в исходной метке. */ +} /* Завершает календарное представление метки логгера. */ diff --git a/c/global-time/tests/f28335_stubs/DSP2833x_Device.h b/c/global-time/tests/f28335_stubs/DSP2833x_Device.h new file mode 100644 index 0000000..a4659db --- /dev/null +++ b/c/global-time/tests/f28335_stubs/DSP2833x_Device.h @@ -0,0 +1,26 @@ +#ifndef GT_TEST_DSP2833X_DEVICE_H /* Изолирует модель регистров от настоящих заголовков TI. */ +#define GT_TEST_DSP2833X_DEVICE_H /* Предотвращает повторное определение тестовых типов. */ +#include /* Использует одинаковые разрядности полей на host-платформе. */ +#define EALLOW ((void)0) /* Модель не требует аппаратного разрешения защищённой записи. */ +#define EDIS ((void)0) /* Закрытие защищённой записи не меняет модельные регистры. */ +#define __interrupt /* Host-компилятор проверяет обычное тело ISR без ABI TI. */ +#define M_INT14 0x2000U /* CPU INT14 соответствует биту 13 в IER/IFR TMS320F28335. */ +union gt_test_reg { /* Даёт модели 32-битный доступ all и поля, которые использует настоящий порт. */ + uint32_t all; /* Имитирует единственный аппаратный доступ к регистру eCAN. */ + struct { unsigned DLC:4; unsigned RTR:1; unsigned DBO:1; } bit; /* Для модели важны доступные имена; фактическую раскладку проверяет отдельная TI-компиляция. */ +}; /* Завершает минимальную модель регистра. */ +struct gt_test_mbox { union gt_test_reg MSGID, MSGCTRL, MDL, MDH; }; /* Выделяет поля mailbox, реально используемые драйвером. */ +struct gt_test_mboxes { struct gt_test_mbox MBOX7, MBOX8; }; /* Не предоставляет портам доступ к невыделенным mailbox. */ +struct gt_test_ecan { union gt_test_reg CANME, CANMD, CANOPC, CANMIL, CANMIM, CANRMP, CANRML, CANTA, CANAA, CANTRS, CANMC; }; /* Моделирует только задействованные управляющие регистры CAN. */ +struct gt_test_lam { union gt_test_reg LAM7; }; /* Предоставляет локальную маску только своего RX. */ +struct gt_test_timer { union gt_test_reg TCR, PRD, TPR, TPRH; }; /* Хранит настройку периода и предделителей CPU Timer2. */ +struct gt_test_vectors { void (*TINT2)(void); }; /* Позволяет вызвать реальный обработчик порта через установленный им вектор. */ +extern struct gt_test_mboxes ECanaMboxes; /* Делит модельные mailbox между портом и тестом. */ +extern struct gt_test_ecan ECanaRegs; /* Делит управляющие регистры между кодом порта и проверками. */ +extern struct gt_test_lam ECanaLAMRegs; /* Делит состояние аппаратного фильтра. */ +extern struct gt_test_timer CpuTimer2Regs; /* Делит конфигурацию автономного миллисекундного таймера. */ +extern struct gt_test_vectors PieVectTable; /* Делит назначенный Timer2 вектор. */ +extern uint16_t IER, IFR; /* Имитирует CPU-регистры разрешения и ожидания прерываний. */ +uint16_t __disable_interrupts(void); /* Предоставляет модель intrinsic с реальным сохранением прежнего состояния. */ +void __restore_interrupts(uint16_t state); /* Предоставляет модель точного восстановления IRQ. */ +#endif /* Завершает защиту тестовой модели аппаратуры. */ diff --git a/c/global-time/tests/run_tests.py b/c/global-time/tests/run_tests.py new file mode 100644 index 0000000..3410ad2 --- /dev/null +++ b/c/global-time/tests/run_tests.py @@ -0,0 +1,36 @@ +"""Проверяет ядро и настоящий порт на host; опционально компилирует их TI C28x.""" # Описывает границу проверки без обещания аппаратного испытания. +import argparse # Принимает явные пути TI SDK вместо привязки библиотеки к рабочему компьютеру. +import os # Настраивает PATH компилятора, чтобы Windows находила его DLL. +from pathlib import Path # Строит пути относительно самого тестового набора. +import shutil # Находит GCC или Clang в окружении разработчика. +import subprocess # Запускает компиляторы аргументами без shell-интерполяции. +import tempfile # Изолирует все исполняемые и объектные файлы во временном каталоге. +root = Path(__file__).resolve().parents[1] # Определяет корень c/global-time независимо от текущего каталога. +parser = argparse.ArgumentParser(description=__doc__) # Показывает назначение host- и TI-проверок при --help. +parser.add_argument("--cc", default=os.environ.get("CC")) # Разрешает явно выбрать совместимый host-компилятор. +parser.add_argument("--ti-cgt", type=Path) # Принимает каталог TI C2000 compiler с bin/cl2000 и include. +parser.add_argument("--ti-headers", type=Path) # Принимает каталог с настоящим DSP2833x_Device.h проекта или TI SDK. +parser.add_argument("--ti-common", type=Path) # Принимает дополнительный каталог DSP2833x_GlobalPrototypes.h из DSP2833x_common/include. +args = parser.parse_args() # Проверяет параметры до создания любых файлов сборки. +candidates = [args.cc, shutil.which("gcc"), shutil.which("clang"), "C:/msys64/ucrt64/bin/gcc.exe"] # Последний путь обеспечивает привычное Windows-окружение без изменения глобального PATH. +compiler = next((str(Path(p).resolve()) for p in candidates if p and Path(p).is_file()), None) # Выбирает первый существующий компилятор, сохраняя явный --cc в приоритете. +if not compiler: # Не заменяет отсутствие компилятора успешным пустым запуском. + parser.error("Укажите --cc с путём к GCC/Clang") # Даёт воспроизводимое требование для запуска регрессий. +if bool(args.ti_cgt) != bool(args.ti_headers): # TI проверка требует одновременно компилятор и аппаратные заголовки. + parser.error("--ti-cgt и --ti-headers нужно указать вместе") # Предотвращает случайную проверку порта с host-моделью вместо SDK. +env = dict(os.environ) # Сохраняет исходное окружение остальных инструментов. +env["PATH"] = str(Path(compiler).parent) + os.pathsep + env.get("PATH", "") # Добавляет соседние DLL GCC только в дочерние процессы тестов. +with tempfile.TemporaryDirectory(prefix="global-time-") as output: # Удаляет только собственный временный каталог после завершения проверок. + for name, sources, includes in [("core", ["src/global_time.c", "tests/test_global_time.c"], ["include"]), ("f28335", ["src/global_time.c", "ports/tms320f28335/global_time_f28335.c", "tests/test_f28335.c"], ["include", "ports/tms320f28335", "tests/f28335_stubs"])]: # Проверяет ядро отдельно и реальный порт с модельными регистрами. + exe = Path(output) / (name + (".exe" if os.name == "nt" else "")) # Сохраняет host-программы за пределами исходного дерева. + command = [compiler, "-std=c99", "-Wall", "-Wextra", "-Werror", "-pedantic", *["-I" + str(root / p) for p in includes], *[str(root / p) for p in sources], "-o", str(exe)] # Считает все предупреждения ошибками и использует реальные исходники библиотеки. + subprocess.run(command, check=True, env=env, timeout=60) # Не маскирует ошибку компиляции успешным запуском старого EXE. + subprocess.run([str(exe)], check=True, env=env, timeout=30) # Выполняет календарные и аппаратные сценарии с ограниченным временем. + if args.ti_cgt: # Дополнительная проверка нужна для ABI с 16-битным char и настоящих регистров TI. + ti = args.ti_cgt.resolve() # Фиксирует абсолютный корень выбранного SDK компилятора. + for source in ["src/global_time.c", "ports/tms320f28335/global_time_f28335.c"]: # Компилирует оба поставляемых MCU исходника без изменения прошивки потребителя. + obj = Path(output) / (Path(source).stem + ".obj") # Разделяет объектные файлы ядра и аппаратного адаптера. + include_paths = [root / "include", root / "ports/tms320f28335", args.ti_headers.resolve(), ti / "include", *([args.ti_common.resolve()] if args.ti_common else [])] # Отдельно подключает common-заголовки старого TI SDK, не смешивая их с host-моделью. + command = [str(ti / "bin/cl2000.exe"), "--compile_only", "-v28", "-ml", "-mt", "--float_support=fpu32", "--abi=coffabi", "--c99", "-O2", "--opt_for_speed=0", "--display_error_number", *["--include_path=" + str(p) for p in include_paths], "--output_file=" + str(obj), str(root / source)] # Использует large/COFF ABI действующего проекта F28335 и штатные заголовки. + subprocess.run(command, check=True, timeout=60) # Ошибка TI C28x останавливает проверку вместо объявления host-модели достаточной. + print("global-time: TI C28x large/COFF compilation OK") # Подтверждает именно компиляцию объектов, не аппаратные испытания или полную линковку прошивки. diff --git a/c/global-time/tests/test_f28335.c b/c/global-time/tests/test_f28335.c new file mode 100644 index 0000000..76c3cb2 --- /dev/null +++ b/c/global-time/tests/test_f28335.c @@ -0,0 +1,88 @@ +#include "DSP2833x_Device.h" /* Использует host-модель регистров, а не альтернативную реализацию драйвера. */ +#include "global_time_f28335.h" /* Тестирует публичные hooks настоящего аппаратного порта. */ +#ifdef NDEBUG /* Не позволяет Release-сборке превратить аппаратные проверки в пустую программу. */ +#undef NDEBUG /* Включает assert независимо от флагов конфигурации CMake. */ +#endif /* Завершает настройку обязательных проверяющих утверждений. */ +#include /* Проверяет сохранность соседних ресурсов, обработку CAN и период Timer2. */ +#include /* Выводит краткое подтверждение проверенных сценариев. */ +struct gt_test_mboxes ECanaMboxes; /* Выделяет модельные MBOX7 и MBOX8. */ +struct gt_test_ecan ECanaRegs; /* Выделяет модель управляющих регистров eCAN-A. */ +struct gt_test_lam ECanaLAMRegs; /* Выделяет локальную маску RX. */ +struct gt_test_timer CpuTimer2Regs; /* Выделяет модель CPU Timer2. */ +struct gt_test_vectors PieVectTable; /* Хранит реальный адрес ISR, назначенный портом. */ +uint16_t IER, IFR; /* Выделяет модель CPU-масок INT14 и соседних прерываний. */ +static uint16_t masked; /* Сохраняет модельное состояние глобальной маски INTM. */ +uint16_t __disable_interrupts(void) /* Моделирует атомарный запрет IRQ и возвращаемый предыдущий INTM. */ +{ /* Повторный запрет из ISR обязан вернуть уже установленную маску. */ + uint16_t old = masked; /* Сохраняет прежнюю маску до её изменения. */ + masked = 1U; /* Имитирует запрет маскируемых IRQ. */ + return old; /* Позволяет реальному порту точно восстановить предыдущий режим. */ +} /* Завершает модель intrinsic запрета. */ +void __restore_interrupts(uint16_t state) /* Восстанавливает маску, полученную соответствующим входом. */ +{ /* Проверяет, что порт действительно вызвал вход в критическую секцию. */ + assert(masked == 1U); /* Восстановление без предшествующего запрета нарушило бы вложенность. */ + masked = state; /* Сохраняет исходный ISR-контекст без безусловного разрешения IRQ. */ +} /* Завершает модель intrinsic восстановления. */ +static void inject(const gt_frame *frame) /* Доставляет wire-данные в аппаратный RX и вызывает настоящий ISR hook. */ +{ /* Не вызывает gt_receive напрямую, проверяя весь путь распаковки MDL/MDH. */ + uint16_t i; /* Перебирает восемь проводных октетов фиксированного classic CAN. */ + ECanaMboxes.MBOX7.MSGID.all = 0xC0000000UL | frame->id; /* Имитирует расширенный ID и включённую локальную фильтрацию eCAN. */ + ECanaMboxes.MBOX7.MSGCTRL.all = frame->dlc | ((uint32_t)frame->remote << 4U); /* Укладывает DLC и RTR в модельный регистр сообщения. */ + ECanaMboxes.MBOX7.MDL.all = ECanaMboxes.MBOX7.MDH.all = 0UL; /* Сбрасывает старый payload перед имитацией нового приёма. */ + for (i = 0U; i < 8U; ++i) { /* Укладывает данные младшим октетом вперёд, как eCAN при DBO=0. */ + if (i < 4U) ECanaMboxes.MBOX7.MDL.all |= (uint32_t)frame->data[i] << (8U * i); /* Первые четыре октета занимают MDL. */ + else ECanaMboxes.MBOX7.MDH.all |= (uint32_t)frame->data[i] << (8U * (i - 4U)); /* Следующие четыре октета занимают MDH. */ + } /* Завершает аппаратное размещение кадра. */ + ECanaRegs.CANRMP.all = 0x82UL; /* Выставляет RX7 и независимый pending legacy mailbox1. */ + gt_f28335_rx_isr(); /* Захватывает временную привязку и кадр в очередь настоящего порта. */ + assert(ECanaRegs.CANRMP.all == 0x80UL); /* Запись W1C должна содержать только бит собственного mailbox, сохраняя pending соседа на аппаратуре. */ + ECanaRegs.CANRMP.all = 2UL; /* Вручную применяет W1C к обычной RAM модели: RX7 снят, RX1 сохранён. */ +} /* Завершает модель получения кадра без подмены алгоритма порта. */ +int main(void) /* Проверяет аппаратную настройку и общий путь ISR → main → метка логгера. */ +{ /* Модель не утверждает электрические тайминги или CAN ACK настоящего трансивера. */ + gt_stamp stamp; /* Читает время через тот же атомарный API, которым будет пользоваться логгер. */ + gt_datetime date = {2026U, 10U, 19U, 1U, 12U, 34U, 56U, 0U}; /* Независимый календарный эталон: понедельник 19 октября 2026 года. */ + gt_frame frame; /* Содержит broadcast мастера для доставки через модель eCAN. */ + uint16_t i; /* Управляет известным числом тиков до обработки кадра в main. */ + gt_f28335_tick_1ms(); gt_f28335_rx_isr(); gt_f28335_service(); /* Ранние hooks до init обязаны безопасно завершаться. */ + ECanaRegs.CANME.all = 0x7FUL; /* Резервирует существующие mailbox0..6 для legacy CAN, Boot и pulse. */ + ECanaRegs.CANMD.all = 0xFFFFFFFAUL; /* Воспроизводит исходные направления legacy mailbox проекта 28335_periph. */ + ECanaRegs.CANMIM.all = 0x4AUL; /* Имитирует разрешённые RX1/RX3/RX6 других CAN-сервисов. */ + ECanaRegs.CANMIL.all = 0x40UL; /* Фиксирует чужую маршрутизацию IRQ, которую порт обязан сохранить. */ + assert(!gt_f28335_init_periph(32U)); /* Некорректный физический адрес не должен открыть новый CAN-сервис. */ + assert(gt_f28335_init_periph(5U)); /* Настраивает УМП1 как PERIPH5, Type1/ID5. */ + assert(ECanaRegs.CANME.all == 0x1FFUL && (ECanaRegs.CANMD.all & 0x7FUL) == 0x7AUL); /* Проверяет добавление только mailbox7/8 и сохранность чужих направлений. */ + assert(ECanaRegs.CANMIM.all == 0xCAUL && ECanaRegs.CANMIL.all == 0x40UL); /* Проверяет RX7 IRQ line0 без изменения RX1/RX3/RX6. */ + assert(ECanaMboxes.MBOX7.MSGID.all == 0xC0000030UL && ECanaLAMRegs.LAM7.all == 0x10000000UL); /* Фильтр принимает только время мастера с любым приоритетом. */ + ECanaRegs.CANTA.all = ECanaRegs.CANAA.all = ECanaRegs.CANRMP.all = 0UL; /* Применяет к RAM модели W1C, выполненные init на реальной аппаратуре. */ + gt_f28335_service(); /* Проверяет первый проход main при отсутствии входящего кадра. */ + assert(ECanaRegs.CANTRS.all == 0UL); /* Сам init не должен объявить готовность прикладной платы. */ + gt_f28335_ready(); gt_f28335_service(); /* Публикует прикладной успех и запускает передачу из main. */ + assert(ECanaRegs.CANTRS.all == 0x100UL && ECanaMboxes.MBOX8.MSGID.all == 0x99513000UL && ECanaMboxes.MBOX8.MDL.all == 1UL); /* Проверяет точный аппаратный запрос READY с правильным адресом. */ + assert(gt_make_rtc(&date, &frame)); /* Строит штатный RTCSETUP без аппаратного RTC мастера в тесте. */ + inject(&frame); /* Проверяет разбор всех календарных полей через настоящий RX ISR. */ + for (i = 0U; i < 37U; ++i) gt_f28335_tick_1ms(); /* Имитирует 37 мс задержки main при продолжающемся такте. */ + gt_f28335_service(); /* Применяет отложенный RX и сохраняет привязку к исходному моменту приёма. */ + gt_get(gt_f28335_clock(), &stamp); /* Снимает тот же экземпляр часов, что обслуживает порт. */ + assert(gt_calendar(&stamp, &date) && date.year == 2026U && date.month == 10U && date.day == 19U && date.hour == 12U && date.minute == 34U && date.second == 56U && date.millisecond == 37U); /* Проверяет календарь и компенсацию задержки всего пути приёма. */ + assert(stamp.sync_uptime_ms == 0UL && stamp.uptime_ms == 37UL); /* Очередь не должна подменить время RX временем обработки main. */ + ECanaRegs.CANTA.all = 0x100UL; ECanaRegs.CANTRS.all = 0UL; /* Имитирует аппаратный ACK ранее отправленной готовности. */ + gt_f28335_service(); /* Освобождает собственный TX без повторной отправки после синхронизации. */ + ECanaRegs.CANTA.all = ECanaRegs.CANAA.all = 0UL; /* Применяет аппаратное W1C к RAM модели ACK. */ + assert(ECanaRegs.CANTRS.all == 0UL); /* Синхронизация прекращает повторную стартовую рассылку. */ + IER = 0x1001U; IFR = 0x3001U; /* Подготавливает чужие CPU IRQ и старый pending INT14. */ + assert(!gt_f28335_timer2_start(150000001UL)); /* Некратная 1000 частота не должна давать скрытый дробный период. */ + assert(gt_f28335_timer2_start(150000000UL)); /* Настраивает аппаратные 1 мс для типичной частоты F28335 150 МГц. */ + assert(CpuTimer2Regs.PRD.all == 149999UL && CpuTimer2Regs.TPR.all == 0UL && CpuTimer2Regs.TPRH.all == 0UL); /* Проверяет включительный период PRD..0 и отсутствие предделителей. */ + assert(IER == 0x3001U && IFR == 0x1001U && CpuTimer2Regs.TCR.all == 0xC020UL); /* Сохраняет чужие CPU маски и запускает только Timer2. */ + PieVectTable.TINT2(); /* Вызывает реальное тело ISR через вектор, назначенный портом. */ + gt_get(gt_f28335_clock(), &stamp); /* Проверяет единственный миллисекундный шаг собственного ISR. */ + assert(stamp.uptime_ms == 38UL && stamp.millisecond == 38U); /* Timer2 должен добавлять ровно один тик на прерывание. */ + assert(!gt_f28335_init_periph(6U)); /* Повторный init не должен потерять владение работающим Timer2. */ + gt_f28335_timer2_stop(); /* Освобождает ранее захваченный аппаратный такт. */ + assert(IER == 0x1001U && CpuTimer2Regs.TCR.all == 0x8010UL && masked == 0U); /* Остановка сохраняет чужие IRQ и исходный глобальный INTM. */ + ECanaRegs.CANMC.bit.DBO = 1U; /* Имитирует несовместимый порядок октетов контроллера. */ + assert(!gt_f28335_init_periph(6U)); /* Не позволяет молча декодировать другую аппаратную раскладку payload. */ + puts("global-time F28335: eCAN isolation, RX delay, ACK and Timer2 OK"); /* Выводит компактный результат аппаратных сценариев. */ + return 0; /* Завершает проверку после всех обязательных утверждений. */ +} /* Завершает host-регрессию порта TI F28335. */ diff --git a/c/global-time/tests/test_global_time.c b/c/global-time/tests/test_global_time.c new file mode 100644 index 0000000..ecfa67a --- /dev/null +++ b/c/global-time/tests/test_global_time.c @@ -0,0 +1,145 @@ +#include "global_time.h" /* Проверяет настоящий переносимый код часов без подмены его реализации. */ +#ifdef NDEBUG /* Проверки должны выполняться и при Release-сборке CMake. */ +#undef NDEBUG /* Сохраняет assert активным независимо от выбранного уровня оптимизации. */ +#endif /* Завершает принудительное включение проверяющих утверждений. */ +#include /* Останавливает тест при нарушении временного или проводного контракта. */ +#include /* Выводит компактное подтверждение выполнения набора проверок. */ +#include /* Позволяет воспроизвести ненулевую RAM после тёплого старта. */ +static uint16_t irq_mask, depth; /* Моделирует исходную маску IRQ и вложенность критических секций. */ +static int accepted, sends; /* Управляет занятостью транспорта и считает попытки объявления готовности. */ +static gt_frame sent; /* Сохраняет последний кадр для независимой проверки ID и payload. */ +static uint16_t enter(void *user) /* Моделирует TI intrinsic с сохранением предыдущего INTM. */ +{ /* Проверяет, что ядро пользуется единым механизмом защиты состояния. */ + uint16_t previous = irq_mask; /* Сохраняет маску до входа в текущий уровень блокировки. */ + assert(user == &sends); /* Подтверждает неизменную передачу пользовательского контекста. */ + irq_mask = 1U; /* Запрещает модельным прерываниям менять данные до leave. */ + ++depth; /* Отмечает вложенный уровень для контроля парности входа и выхода. */ + return previous; /* Возвращает исходное состояние, включая вызов из уже закрытого ISR. */ +} /* Завершает модель входа в критическую секцию. */ +static void leave(void *user, uint16_t previous) /* Проверяет восстановление предыдущей маски без безусловного разрешения. */ +{ /* Делает нарушения вложенности видимыми в host-тесте. */ + assert(user == &sends && depth > 0U && irq_mask == 1U); /* Выход допустим только из реально захваченной секции. */ + --depth; /* Освобождает один уровень модельной блокировки. */ + irq_mask = previous; /* Возвращает именно исходную маску вызывающего кода. */ +} /* Завершает проверяемую модель выхода. */ +static int send(void *user, const gt_frame *frame) /* Моделирует неблокирующую передачу и копирование временного payload. */ +{ /* Callback не должен выполняться с длинной критической секцией ядра. */ + assert(user == &sends && depth == 0U); /* Проверяет передачу контекста и отсутствие блокировки IRQ на время отправки. */ + ++sends; /* Считает и принятые, и отклонённые транспортом попытки. */ + sent = *frame; /* Сохраняет независимую копию до возврата callback. */ + return accepted; /* Имитирует занятость mailbox без ожидания. */ +} /* Завершает модель транспорта. */ +static void advance(gt_clock *clock, uint32_t milliseconds) /* Продвигает реальный алгоритм через границы календарных полей. */ +{ /* Пошаговый вызов также проверяет миллисекундные переносы в ISR. */ + while (milliseconds--) gt_tick_1ms(clock); /* Не подменяет поведение таймера прямой правкой абсолютного времени. */ +} /* Завершает управляемое продвижение времени. */ +static gt_frame rtc(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second) /* Строит календарный эталон кодировщиком верхнего уровня. */ +{ /* Ожидаемые значения времени в тестах проверяются отдельно от кодировщика. */ + gt_datetime date = {year, month, day, 6U, hour, minute, second, 0U}; /* День недели сохраняется как допустимая фаза цикла, исходная суббота=6. */ + gt_frame frame; /* Получает полноценный расширенный CAN кадр. */ + assert(gt_make_rtc(&date, &frame)); /* Корректный календарь обязан кодироваться в существующие семь октетов. */ + return frame; /* Возвращает независимый контейнер для изменения ошибочных полей. */ +} /* Завершает построение тестовых опорных кадров. */ +int main(void) /* Проверяет календарь, коррекции, задержки, переполнения и стартовый CAN-обмен. */ +{ /* Использует только публичный API, кроме целевой установки границы uptime. */ + gt_clock clock; /* Состояние заполняется мусором, имитируя startup без очистки .ebss. */ + gt_port port = {&sends, enter, leave, send}; /* Подключает проверяющие блокировки и управляемый транспорт. */ + gt_stamp stamp, before; /* Два атомарных снимка позволяют проверять отсутствие побочных изменений при ошибке. */ + gt_datetime date; /* Календарный результат проверяется по известным границам дат. */ + gt_frame frame, bad; /* Исходный корректный кадр и копия для отрицательных проверок. */ + uint16_t type, id, index; /* Полученные адресные поля и индекс проверки каждого октета. */ + const uint16_t invalid[7] = {24U, 60U, 60U, 100U, 0U, 0U, 7U}; /* Независимые граничные ошибки каждого календарного поля на линии. */ + memset(&clock, 0xA5, sizeof(clock)); /* Воспроизводит остатки RAM вместо неявной инициализации нулями хоста. */ + assert(!gt_init(&clock, &port, 8U, 0U)); /* Запрещает трёхбитному типу переполниться в направление Route. */ + assert(!gt_init(&clock, &port, 1U, 16U)); /* Запрещает молчаливое обрезание экземпляра до адреса другой платы. */ + assert(gt_init(&clock, &port, 1U, 5U)); /* Создаёт УМП1 по действующему реестру PERIPH. */ + gt_get(&clock, &stamp); /* Проверяет результат явной инициализации всей временной базы. */ + assert(stamp.seconds == 0UL && stamp.uptime_ms == 0UL && !stamp.synchronized && stamp.generation == 0UL); /* До синхронизации календарь не должен выглядеть достоверным. */ + assert(!gt_calendar(&stamp, &date)); /* Не позволяет приложению выдавать локальную эпоху за полученную дату. */ + advance(&clock, 1001UL); /* Пересекает первую секундную границу программного таймера. */ + gt_get(&clock, &stamp); /* Снимает дробную часть после переноса секунды. */ + assert(stamp.seconds == 1UL && stamp.millisecond == 1U && stamp.uptime_ms == 1001UL); /* Проверяет ровно 1000 тиков на секунду без ошибки на единицу. */ + gt_poll(&clock); /* Пытается обслужить отправку до завершения инициализации платы. */ + assert(sends == 0); /* Пакет готовности запрещён до явного ready. */ + gt_ready(&clock); /* Разрешает стартовый пакет только после прикладной готовности. */ + gt_poll(&clock); /* Имитирует занятую CAN передачу при accepted=0. */ + assert(sends == 1 && !clock.announced); /* Занятость транспорта не теряет обязательный пакет инициализации. */ + accepted = 1; /* Освобождает транспорт на следующем проходе main. */ + gt_poll(&clock); /* Повторяет отклонённую попытку без задержки и блокировки IRQ. */ + assert(sends == 2 && sent.id == 0x19513000UL && sent.dlc == 1U && sent.data[0] == 1U); /* Фиксирует проводной эталон READY узла Type=1, ID=5. */ + assert(gt_parse_ready(&sent, &type, &id) && type == 1U && id == 5U); /* Мастер должен узнать физический адрес стартовавшей платы. */ + bad = sent; /* Готовит отрицательный вариант стартового сообщения. */ + bad.id ^= 0x08000000UL; /* Меняет направление на запрос мастера, сохранив payload. */ + assert(!gt_parse_ready(&bad, 0, 0)); /* Исключает распознавание собственного запроса как готовности платы. */ + advance(&clock, 999UL); /* Проверяет ограничение частоты повторов перед секундной границей. */ + gt_poll(&clock); /* Обслуживает CAN на последней миллисекунде запрета повтора. */ + assert(sends == 2); /* Готовность не должна засорять шину на каждом проходе main. */ + advance(&clock, 1UL); /* Достигает точно секундного интервала повторной отправки. */ + gt_poll(&clock); /* Повторяет событие старта при отсутствии ответа временем. */ + assert(sends == 3); /* Потерянный ответ мастера должен приводить к повтору объявления готовности. */ + frame = rtc(2024U, 2U, 28U, 23U, 59U, 59U); /* Задаёт известную границу високосного февраля. */ + assert(frame.id == 0x30UL && frame.dlc == 7U && frame.data[3] == 24U && frame.data[4] == 2U); /* Проверяет совместимый ID и календарный wire format. */ + assert(gt_receive(&clock, &frame, clock.stamp.uptime_ms)); /* Устанавливает первую реальную календарную дату. */ + advance(&clock, 1001UL); /* Пересекает полночь на один миллисекундный тик. */ + gt_get(&clock, &stamp); /* Снимает календарную метку после перехода даты. */ + assert(gt_calendar(&stamp, &date) && date.year == 2024U && date.month == 2U && date.day == 29U && date.hour == 0U && date.millisecond == 1U); /* Проверяет 29 февраля и сброс часов/минут/секунд на полночь. */ + assert(stamp.weekday == 0U && stamp.generation == 1UL); /* День недели циклически продвигается, а тики не создают новые поколения коррекции. */ + assert(gt_timestamp_ms(&stamp) > UINT32_MAX); /* Календарные миллисекунды остаются широкими и не обрезаются до uptime. */ + advance(&clock, 2000UL); /* Даёт мастеру время ответить; уже синхронизированный узел не повторяет READY. */ + gt_poll(&clock); /* Проверяет прекращение стартовых повторов после RTCSETUP. */ + assert(sends == 3); /* Получение календаря завершает повторный запрос времени. */ + before = stamp; /* Сохраняет известную метку для проверки отрицательной коррекции. */ + frame = rtc(2000U, 1U, 1U, 0U, 0U, 0U); /* Задаёт независимый эталон нулевой секунды эпохи библиотеки. */ + assert(gt_receive(&clock, &frame, clock.stamp.uptime_ms)); /* Применяет разрешённый перевод глобальных часов назад. */ + gt_get(&clock, &stamp); /* Снимает результат атомарной коррекции. */ + assert(stamp.seconds == 0UL && stamp.millisecond == 0U && stamp.correction_ms < 0 && stamp.uptime_ms > before.uptime_ms && stamp.generation == 2UL); /* Проверяет независимость тайм-аутов от отрицательной календарной коррекции. */ + assert(gt_timestamp_ms(&stamp) == 0ULL); /* Фиксирует точное начало принятой эпохи. */ + before = stamp; /* Сохраняет состояние до серии ошибочных CAN кадров. */ + for (index = 0U; index < 7U; ++index) { /* Проверяет наличие лишних старших битов в каждом слове, содержащем октет C28x. */ + bad = frame; /* Восстанавливает исходный корректный RTCSETUP перед каждой ошибкой. */ + bad.data[index] = 256U; /* Значение вне одного проводного октета не должно обрезаться до нуля. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* Отвергает ошибку порта до изменения даты. */ + bad = frame; /* Возвращает корректный исходный кадр для проверки допустимого диапазона поля. */ + bad.data[index] = invalid[index]; /* Подставляет двоичное, но календарно недопустимое значение. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* Исключает нормализацию ошибочного времени и выход за границы таблицы месяцев. */ + } /* Завершает проверку всей широкой wire-границы. */ + bad = frame; bad.extended = 0U; /* Подготавливает стандартный 11-битный кадр с похожим ID. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* ProtoCAN требует IDE=1 независимо от численного ID. */ + bad = frame; bad.remote = 1U; /* Подготавливает RTR без реальных календарных данных. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* Удалённый запрос не устанавливает глобальное время. */ + bad = frame; bad.dlc = 8U; /* Добавляет неописанный восьмой октет без согласованного расширения протокола. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* Длина существующего RTCSETUP должна быть ровно семь октетов. */ + bad = frame; bad.id |= 0x01000000UL; /* Имитирует broadcast от чужого типа устройства вместо верхнего уровня. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* Исключает коррекцию по произвольным сообщениям другой платы. */ + bad = frame; bad.data[4] = 2U; bad.data[5] = 30U; /* Подготавливает несуществующее 30 февраля високосного года. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* Календарные ошибки не нормализуются в другую дату. */ + bad = frame; bad.data[3] = 23U; bad.data[4] = 2U; bad.data[5] = 29U; /* Подготавливает 29 февраля невисокосного года. */ + assert(!gt_receive(&clock, &bad, before.uptime_ms)); /* Отвергает некорректную дату даже при допустимых диапазонах отдельных полей. */ + gt_get(&clock, &stamp); /* Проверяет итоговое состояние после всех отклонённых кадров. */ + assert(stamp.seconds == before.seconds && stamp.generation == before.generation && stamp.synchronized); /* Неверные пакеты не теряют последнюю достоверную синхронизацию. */ + before.seconds = 3160857600UL; /* Независимый календарный эталон: ровно 36584 суток от 2000-01-01 до 2100-03-01. */ + assert(gt_calendar(&before, &date) && date.year == 2100U && date.month == 3U && date.day == 1U); /* Проверяет исключение невисокосного 2100 года при продолжении локального хода часов. */ + clock.stamp.uptime_ms = UINT32_MAX - 4UL; /* Целевым образом размещает монотонный счётчик около переполнения 49,7 суток. */ + advance(&clock, 10UL); /* Пересекает modulo-границу до обработки уже полученного кадра. */ + frame.id |= 0x10000000UL; /* Проверяет допустимость стандартного приоритета RTCSETUP наряду с критическим. */ + assert(gt_receive(&clock, &frame, UINT32_MAX - 4UL)); /* Передаёт момент RX до переполнения, обработку — после. */ + gt_get(&clock, &stamp); /* Снимает скорректированную фазу доли секунды. */ + assert(stamp.seconds == 0UL && stamp.millisecond == 10U && stamp.uptime_ms == 5UL); /* Компенсация очереди должна быть 10 мс, независимо от переполнения uptime. */ + frame = rtc(2023U, 12U, 31U, 23U, 59U, 59U); /* Проверяет смену календарного года при отложенной обработке. */ + before = stamp; /* Запоминает момент RX непосредственно перед задержкой основного цикла. */ + advance(&clock, 1250UL); /* Имитирует долгую прикладную операцию при продолжающемся аппаратном таймере. */ + assert(gt_receive(&clock, &frame, before.uptime_ms)); /* Применяет время по моменту RX, а не по моменту выхода из очереди. */ + gt_get(&clock, &stamp); /* Снимает дату после учёта задержки обработки. */ + assert(gt_calendar(&stamp, &date) && date.year == 2024U && date.month == 1U && date.day == 1U && date.second == 0U && date.millisecond == 250U); /* Проверяет перенос секунды, суток и года с сохранением 250 мс. */ + irq_mask = 1U; /* Имитирует вызов логгера из ISR с уже запрещёнными прерываниями. */ + gt_get(&clock, &stamp); /* Проверяет чтение метки при вложенной критической секции. */ + gt_tick_1ms(&clock); /* Проверяет продвижение часов при исходном INTM=1. */ + assert(irq_mask == 1U && depth == 0U); /* Выходы не должны случайно разрешить IRQ вызывающего обработчика. */ + irq_mask = 0U; /* Восстанавливает модельное окружение main перед новой инициализацией. */ + assert(gt_init(&clock, &port, 2U, 15U)); /* Проверяет холодный reset качества и верхний адрес PERIPH31. */ + assert(gt_receive(&clock, &frame, 0UL)); /* Имитирует broadcast ещё до прикладного ready. */ + gt_ready(&clock); gt_ready(&clock); gt_poll(&clock); /* Повторный ready должен быть идемпотентным, но первая отправка всё равно обязательна. */ + assert(sends == 4 && gt_parse_ready(&sent, &type, &id) && type == 2U && id == 15U); /* Ранняя синхронизация не подавляет сообщение об успешной инициализации платы. */ + puts("global-time: calendar, CAN, correction, IRQ and rollover OK"); /* Возвращает краткое свидетельство пройденных смысловых сценариев. */ + return 0; /* Завершает host-тест только после всех обязательных проверок. */ +} /* Завершает независимую проверку переносимого ядра. */ diff --git a/c/parallel-nand/docs/MEMORY_GAS.md b/c/parallel-nand/docs/MEMORY_GAS.md index a91be51..4792dd2 100644 --- a/c/parallel-nand/docs/MEMORY_GAS.md +++ b/c/parallel-nand/docs/MEMORY_GAS.md @@ -1,5 +1,7 @@ # Работа с parallel NAND через GAS +> GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Спецификация: `doc/setcan/protocan/OAP.md`; адреса этого документа остаются регистровыми. + ## Архитектура Внешняя NAND значительно больше общего адресного пространства GAS. Например, diff --git a/doc/setcan/protocan/GLOBAL_TIME.md b/doc/setcan/protocan/GLOBAL_TIME.md new file mode 100644 index 0000000..ae25d39 --- /dev/null +++ b/doc/setcan/protocan/GLOBAL_TIME.md @@ -0,0 +1,97 @@ +# ProtoCAN: глобальное время и завершение инициализации платы + +Профиль библиотеки [`c/global-time`](../../../c/global-time/README.md). +Время использует штатную команду BROADCAST RTCSETUP. +Общий флаг готовности — новое соглашение этого профиля поверх DISCRETE/FLAGS; +его нельзя считать уже реализованным всеми историческими приборами ProtoCAN. + +## Плата → верхний уровень: готовность + +После успешной инициализации оборудования и параметров плата отправляет: + +| Поле | Значение | +|---|---| +| IDE / RTR | 1 / 0 | +| Priority | 1, standard | +| Route | 1, от устройства | +| DeviceType / DeviceID | собственный адрес платы | +| MsgType | 0x1, DISCRETE | +| MsgBody | 0x3000: подтип FLAGS=3, страница 0 | +| DLC | 1 | +| DATA[0] | 0x01: бит 0 означает «инициализация завершена» | + +Биты DATA[0] 1..7 зарезервированы нулями. Пакет не меняет локальные +технологические флаги «Статус инициализации» в ОАП конкретных приборов. +В этом профиле Body `0x3000`, DLC1, DATA01 закреплены за общим событием готовности; +приборы с другим историческим назначением этой комбинации требуют адаптера. + +Для PERIPH5 / УМП1, Type1/ID5: + +```text +CAN ID 0x19513000, DLC 1, DATA 01 +``` + +Плата посылает готовность хотя бы один раз, даже если успела получить broadcast +ещё до завершения собственной инициализации. Пока синхронизация не получена, +событие повторяется не чаще одного раза в 1000 мс. Повтор не означает новый reset; +мастер может объединять несколько близких запросов в один broadcast. + +## Верхний уровень → все платы: дата и время + +При получении готовности мастер читает свою текущую дату, формирует штатный +RTCSETUP и отправляет один кадр всем узлам. Может также периодически передавать +RTCSETUP для коррекции дрейфа; библиотека принимает каждый корректный пакет. + +| Поле | Значение | +|---|---| +| IDE / RTR | 1 / 0 | +| Priority | 0 или 1 | +| Route | 0, от ПМ | +| DeviceType / DeviceID | 0 / 0, верхний уровень | +| MsgType | 0, BROADCAST | +| MsgBody | 0x0030: команда RTCSETUP=3, параметр=0 | +| DLC | ровно 7 | +| DATA | hour, minute, second, year−2000, month, day, weekday | + +Все поля двоичные, без BCD. Диапазоны: часы 0..23, минуты/секунды 0..59, +год 0..99, месяц 1..12, число согласно календарю, день недели 0..6. +Профиль использует 0=воскресенье, 1=понедельник; библиотека сохраняет переданную +фазу недели и затем продвигает её вместе с календарём. Дата имеет приоритет +для абсолютной метки; несоответствие фазы недели календарю не меняет дату. + +Пример: 2026-10-19 12:34:56, понедельник: + +```text +CAN ID 0x00000030, DLC 7, DATA 0C 22 38 1A 0A 13 01 +``` + +Каждая плата независимо проверяет кадр и календарь, рассчитывает смещение +от своей временной базы и атомарно корректирует её. Повреждённый или чужой +кадр не меняет время и качество предыдущей синхронизации. При отсутствии +новых пакетов часы продолжают локальный отсчёт. Тайм-ауты основаны на независимом +uptime; перевод календаря назад не удлиняет и не сокращает их. + +## Миллисекунды и потребители + +Нулевой миллисекундной долей опорной даты считается момент RX ISR. +Тики, прошедшие до обработки в main, прибавляются к присланному времени. +Исходный кадр содержит только целые секунды: локальное разрешение 1 мс +не означает погрешность синхронизации между платами 1 мс. +Мастер выбирает общую шкалу, например UTC, и момент отправки около секундной +границы. Часовой пояс, leap seconds и компенсация арбитража CAN не передаются. + +Логгер снимает `gt_stamp` с секундами от 2000 года, миллисекундной долей, +признаком синхронизации, номером коррекции и независимым uptime. +64-битная календарная метка не помещается в старое 32-битное поле времени +логгеров; изменение формата архива выполняет конкретное приложение. + +## Верхний уровень: точки подключения + +`gt_parse_ready()` извлекает Type/ID из сообщения платы. +`gt_make_rtc()` проверяет дату и формирует кадр с DLC7; ненулевые миллисекунды +на входе отклоняются, чтобы не терять точность молча. Источник календаря, +CAN-транспорт и обработчик входящего события предоставляет приложение мастера. + +Для TMS320F28335 готовый порт занимает eCAN-A mailbox7/8 и по выбору +CPU Timer2/INT14 либо hook существующего ISR 1 мс. Подробные порядок вызовов, +требования к общему CAN ISR и проверки — в README библиотеки. From f17c124f0e3cd398ef9ca8861a533608eda039b7 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Oct 2026 14:16:22 +0300 Subject: [PATCH 13/18] =?UTF-8?q?docs:=20=D0=A1=D0=BE=D0=B3=D0=BB=D0=B0?= =?UTF-8?q?=D1=81=D1=83=D0=B9=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=86=D0=B8=D1=8E=20ProtoCAN=20=D0=B8=20=D0=B8?= =?UTF-8?q?=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Обнови спецификацию GAS 0x3/0x4, реестр устройств и описание загрузочных сервисов одновременно в Markdown, HTML и XLSX. Свяжи новые аппаратные порты, глобальное время и сборку C2000/ПЛИС с корневыми инструкциями, чтобы проекты подключались по одному актуальному контракту. --- NEW_PROJECT.md | 2 +- README.md | 6 +- doc/setcan/ALTERA_LOGIC_STREAM.md | 2 + doc/setcan/DEVICE_REGISTRY.md | 22 +- doc/setcan/README.md | 4 + doc/setcan/index.html | 570 ++++++++++++++++++++++++----- doc/setcan/protocan/CHANGELOG.md | 7 + doc/setcan/protocan/OAP.md | 192 +++++++--- doc/setcan/protocan/PROTOCOL.md | 15 +- doc/setcan/protocan/README.md | 8 +- doc/setcan/Протокол CAN и ОАП.html | 306 +++++++++++++--- doc/setcan/Протокол CAN и ОАП.md | 82 ++++- doc/setcan/Протокол CAN и ОАП.xlsx | Bin 103216 -> 266313 bytes tools/firmware-build/README.md | 93 +++++ 14 files changed, 1113 insertions(+), 196 deletions(-) diff --git a/NEW_PROJECT.md b/NEW_PROJECT.md index c3aeb12..7701a24 100644 --- a/NEW_PROJECT.md +++ b/NEW_PROJECT.md @@ -84,7 +84,7 @@ STM32F103RC, STM32F103ZE и STM32G474CE объявляют поддержку з возвращают `PNAND_ERROR_WRITE_PROTECTED`, пока плата и порт не доработаны. Рабочий пример полноценного G474-порта находится в соседнем проекте -`candleLight_fw`: `src/device/device_g4.c` отвечает за clock/GPIO, +`CANdle_stm32` (candleLight): `src/device/device_g4.c` отвечает за clock/GPIO, `src/can/m_can.c` — за FDCAN, а `include/config.h` — за привязку платы STM32G474VET6. Эти файлы остаются в прошивке, поскольку зависят от STM32 HAL, USB gs_usb и конкретной разводки адаптера; переносимая логика протоколов diff --git a/README.md b/README.md index 0c1001c..3ac3239 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,10 @@ templates/ | [`c/set-protocol/ports/stm32f407-devboard-v1`](c/set-protocol/ports/stm32f407-devboard-v1) | доступ SETGUI к Modbus-регистрам F407 через CAN485 DevBoard_V1 | `pcan_modbus_server`, STM32 HAL CAN | bxCAN FIFO0 и callbacks карты регистров | | [`c/set-protocol/ports/stm32-bxcan`](c/set-protocol/ports/stm32-bxcan) | порт прикладного ProtoCAN для STM32, бывший SETCAN; сохранён API `PROTOCAN_*` | STM32 HAL CAN/RTC/TIM + общее ядро `pcan_id` | classic bxCAN; настройки платы предоставляет прошивка | | [`c/set-protocol/ports/tms320f2812`](c/set-protocol/ports/tms320f2812) | SETProtocol v2 firmware service по segmented classic CAN | `set_protocol`, `set_can`, `set_firmware` | CAN TX, Flash erase/write/read, optional signature policy и reboot | -| [`c/protocan-boot`](c/protocan-boot) | адресная прошивка по ProtoCAN: A/B-слоты, сессия, CRC32, verify и rollback-контракт | C99 | CAN TX, erase/write Flash, boot metadata, проверка образа и reboot | +| [`c/protocan-boot`](c/protocan-boot) | адресная прошивка по ProtoCAN: A/B-слоты, сессия, CRC32, verify и rollback-контракт | C99 | **STM32F103C8/F407VE/G474VE и TMS320F2812/F28335-порты в комплекте**; проекты STM32 подключены через templates, есть boot main и вход из приложения | | [`c/rs485-boot`](c/rs485-boot) | прошивка по RS-485 в формате SETGUI v1: потоковый parser, CRC32 и resume | C99 | UART TX/RX, DE, Flash — **порты STM32F103 и STM32G474VET в комплекте** | | [`c/rtc-service`](c/rtc-service) | RTC с резервированным backup-томом | `stdint.h` | доступ к RTC и backup-памяти — **порт K1921VK028 в комплекте** | +| [`c/global-time`](c/global-time) | программные часы 1 мс, ProtoCAN RTCSETUP, готовность платы и атомарная метка логгера | C99 | IRQ lock, CAN TX, такт 1 мс — **порт TMS320F28335 eCAN-A / CPU Timer2 в комплекте** | | [`c/firmware-info`](c/firmware-info) | SemVer, build stamp и git build ID работающего образа | C99 | config-порты STM32F1/F4/G4 и К1921ВК028; упаковка для Modbus/SETGUI | | [`c/parallel-nand`](c/parallel-nand) | parallel NAND x8: raw read/program/erase, профили Micron MT29F1G08 и Hynix HY27UF084G2M, bad-block marker и банковое окно GAS для SETGUI | C99, опционально `set-protocol/pcan_gas` | **порты TMS320F2812, STM32F103RC/ZE, STM32F407VE и STM32G474CEU6; запись требует управляемого WP#** | @@ -64,6 +65,7 @@ templates/ | Инструмент | Что делает | |---|---| +| [`tools/firmware-build/fpga`](tools/firmware-build/fpga/README.md) | общий итератор версии и HDL-паспорт для Xilinx ISE, Vivado и Altera/Intel Quartus; контроль `.bit`/`.sof`, manifest, SHA-256 и архив | | [`tools/firmware-publish`](tools/firmware-publish) | единый BAT и конфигурации для проверки и публикации `.hex` Keil / `.bin` CCS 12 в каталоге SETGUI | Общие тренды для Android GUI и SETGUI: [формат JSON, C99-ядро и адаптеры](c/set-protocol/docs/GUI_TRENDS.md). @@ -118,7 +120,7 @@ git subtree pull --prefix lib/templates https://git.rd12.ru/Andrey/templates.git | `KONOR_ds18b20` | st7789, keypad, menu, eeprom-ft24c256, can-sensor, ds18b20, firmware-info | | `OpticalTester` | st7789, keypad, menu, eeprom-ft24c256 | | `CAN_to_RS485` | set-protocol legacy transport, python/protocan | -| `candleLight_fw` | эталон разделения общей логики и G431/G474 FDCAN-порта; общий ProtoCAN Boot переносится по контракту `protocan-boot` | +| `CANdle_stm32` (candleLight) | G431/G474 FDCAN board-support; CAN/UART-загрузчик G474 и вход из приложения подключены к `protocan-boot/ports/stm32g474` через templates | | `SETGUI` | python/protocan | | `SETGUI`, Android GUI и новые устройства SET | set-protocol | | `k1921vk028` | rtc-service | diff --git a/doc/setcan/ALTERA_LOGIC_STREAM.md b/doc/setcan/ALTERA_LOGIC_STREAM.md index 13b6078..acf8e55 100644 --- a/doc/setcan/ALTERA_LOGIC_STREAM.md +++ b/doc/setcan/ALTERA_LOGIC_STREAM.md @@ -1,5 +1,7 @@ # Altera Logic — ONLINE через SETCAN / GAS / UART +> GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Спецификация: `doc/setcan/protocan/OAP.md`; адреса этого документа остаются регистровыми. + Версия профиля: **1**. Реализация, порты и тесты принадлежат `templates`. Это профиль существующего classic SETCAN/ProtoCAN с 29-битным ID; он не подменяется кадром SETP v2 и не использует старые команды `A5 CMD` FPGA. diff --git a/doc/setcan/DEVICE_REGISTRY.md b/doc/setcan/DEVICE_REGISTRY.md index f25a2cd..c9dc88e 100644 --- a/doc/setcan/DEVICE_REGISTRY.md +++ b/doc/setcan/DEVICE_REGISTRY.md @@ -7,10 +7,24 @@ Device Name — отображаемое имя адреса, а не допол | DeviceType | DeviceID | Device Name | Назначение | |---|---|---|---| | `0x0` | существующие | Верхний уровень | Существующие адреса исходной таблицы | -| `0x6` | `0xE` | **Altera Logic** | Онлайн-анализатор 16 цифровых каналов | +| `0x1` | `0x0…0xF` | PERIPH 0–15 | Первая группа периферии по обновлённому листу «Интерфейс протокола» | +| `0x2` | `0x0…0xF` | PERIPH 16–31 | Вторая группа; номер PERIPH = 16 + DeviceID | +| `0x1` | `0x5` | **УМП1** | PERIPH 5, собственный адрес обычного обмена ProtoCAN и загрузчика | +| `0x1` | `0x6` | УМП2 | PERIPH 6, GAS 0x3 — регистры; GAS SLOT 0x4 — слоты 0x0600…0x0642 | +| `0x6` | `0xE` | Altera Logic | Отдельный существующий потоковый профиль FE00/FF00 | | `0x7` | `0xD` | configurator | Существующий конфигуратор | +| `0x7` | `0xE` | **STM Invertor** | Самостоятельный ПЧ STM32G474VET6; отдельный GAS-профиль на 250 слотов 0x4, 750 значений; Word0 — маска | | `0x7` | `0xF` | KONOR / SETTINGS | Существующий профиль SETCAN и привязка датчиков | +Источник PERIPH: [Протокол CAN и ОАП.xlsx](Протокол%20CAN%20и%20ОАП.xlsx), +лист «Интерфейс протокола», A44:F79. Формула: Type = 1 + ID PERIPH / 16 +(целая часть), DeviceID = ID PERIPH mod 16. Зарезервированные номера не получают +назначений по аналогии со старым Бальзам CAN. Общий Boot-адрес `3/7` отменён. +В ПМ35 приложение использует аппаратный Mode, постоянный загрузчик читает те же +GPIO21/20/22/51; на существующей плате четыре перемычки задают номера 1–16. +Для номеров 0 и 17–31 требуется соответствующий источник аппаратного номера. +Старые CAN ID `0x00BA0007`/`0x00BA0017` задатчика остаются отдельным legacy-форматом. + Для Altera Logic выбран предпоследний тип `0x6` и предпоследний экземпляр `0xE`: эта пара не была назначена в проверенных локальных таблицах и исходниках. Тип `0x7` уже используется. Наличие другого физического узла с тем же адресом @@ -19,3 +33,9 @@ Device Name — отображаемое имя адреса, а не допол Числовые константы устройства: `c/set-protocol/include/altera_stream.h`. Отображаемые имена: `python/protocan/protocan.py`. Контракт потока: [ALTERA_LOGIC_STREAM.md](ALTERA_LOGIC_STREAM.md). + +## Mode и два типа GAS + +Таблица назначений и правила: [OAP.md](protocan/OAP.md). Mode 1/2 — трансформаторы; 3/4 — силовые узлы; 5/6 — УМП; 7 — ENG1; 8 — задатчик/пульт (`adr_PULT`); 9 — шкаф. 10 и 11 — служебные роли общего адреса и терминала. Остальные назначения не выводятся по аналогии со старым Бальзам CAN. + +GAS 0x3 адресует отдельные регистры 0…65535. GAS SLOT 0x4: `Slot=(mode<<8)|LocalSlot`, LocalSlot `0x00…0x42`; Word0 — маска, Word1…Word3 — значения. На mode сохранены 200 значений; последний слот содержит два. Прибор 5 не обслуживает страницу 0x06xx. diff --git a/doc/setcan/README.md b/doc/setcan/README.md index 734ab80..e6987ea 100644 --- a/doc/setcan/README.md +++ b/doc/setcan/README.md @@ -36,3 +36,7 @@ - [Реестр устройств SETCAN](DEVICE_REGISTRY.md). - [ONLINE-поток Altera Logic через GAS и UART](ALTERA_LOGIC_STREAM.md). + +## GAS: регистры 0x3 и слоты 0x4 + +[Адресация GAS](protocan/OAP.md): `0x3` — отдельные 16-битные регистры `0…65535`, запись 1…4 слов. `0x4` — слот с Word0-маской и тремя значениями; PERIPH сохраняет 200 слов в 67 слотах `0xMM00…0xMM42`. Формат определяется MsgType, без настройки профиля. diff --git a/doc/setcan/index.html b/doc/setcan/index.html index bc83213..c455bb1 100644 --- a/doc/setcan/index.html +++ b/doc/setcan/index.html @@ -168,7 +168,7 @@ Priority Route DeviceType DeviceID MsgType MsgBody 1 бит 1 бит 3 бита 4 бита 4 бита 16 бит
Многобайтовые значения payload передаются little-endian. Разметка ID через C bit-fields требует проверки при смене компилятора или ABI.

Реестр MsgType

- +
КодТипНазначениеСтатус
0x0BROADCASTОбщие команды всем устройствамstable
0x1DISCRETEСостояния, команды, флагиstable
0x2ANALOGДатчики U / I / T и универсальные данныеstable
0x3GASОбщее 16-битное адресное пространствоstable
0x4…0x7MODBUSCoil, Discrete, Holding, Inputstable
0x8ERRORКод ошибки и дополнительная информацияstable
0x9…0xDBOOTУправление, блоки A/B, статус, discoverydraft
0xESETTINGSПривязка 1-Wire ROM к локации Z/Ystable
0xFPULSEПрисутствие устройстваstable
0x0BROADCASTОбщие команды всем устройствамstable
0x1DISCRETEСостояния, команды, флагиstable
0x2ANALOGДатчики U / I / T и универсальные данныеstable
0x3GASОбщее 16-битное адресное пространствоstable
0x4GAS SLOTWord0 — маска битов 1…3, Word1…Word3 — три значенияstable
0x5…0x7MODBUSDiscrete, Holding, Inputstable
0x8ERRORКод ошибки и дополнительная информацияstable
0x9…0xDBOOTУправление, блоки A/B, статус, discoverydraft
0xESETTINGSПривязка 1-Wire ROM к локации Z/Ystable
0xFPULSEПрисутствие устройстваstable
@@ -300,8 +300,8 @@ if (PROTOCAN_SEND(id, tx) != PROTOCAN_OK) {

Документация ProtoCAN

Статус комплекта: Draft
-Версия комплекта: 1.0
-Дата редакции: 2026-08-29
+Версия комплекта: 2.1
+Дата редакции: 2026-10-23
Транспорт: Classic CAN 2.0B, Extended ID, DLC 0…8

Этот каталог разделяет нормативное описание протокола, загрузчик и реестр общего адресного пространства. Большой исходный документ @@ -364,10 +364,12 @@ if (PROTOCAN_SEND(id, tx) != PROTOCAN_OK) {

Все документы и тестовые векторы включаются в единый файл doc/setcan/index.html. Скрипт не изменяет исходные Markdown/XLSX и пригоден для запуска в CI.

+

GAS: регистры 0x3 и слоты 0x4

+

Адресация GAS: 0x3 — отдельные 16-битные регистры 0…65535, запись 1…4 слов. 0x4 — слот с Word0-маской и тремя значениями; PERIPH сохраняет 200 слов в 67 слотах 0xMM00…0xMM42. Формат определяется MsgType, без настройки профиля.

ProtoCAN — базовый протокол

Статус: Stable с зарезервированным загрузочным расширением
-Версия: 1.0
+Версия: 2.1: GAS 0x3 и масочный GAS SLOT 0x4
Порядок байтов payload: little-endian, если явно не указано иное

Назначение

ProtoCAN — прикладной протокол поверх classic CAN 2.0B. Используются только @@ -502,14 +504,14 @@ Priority Route DeviceType DeviceID MsgType MsgBody GAS оба 0/2/4/6/8 -stable +регистры 0…65535 0x4 -MODBUS_COIL +GAS_SLOT оба -0…8 -stable +0/8 +Word0 — маска, Word1…Word3 — значения 0x5 @@ -613,10 +615,14 @@ Priority Route DeviceType DeviceID MsgType MsgBody начальный адрес [15:4], количество [3:0] -GAS +GAS 0x3 адрес первого 16-битного регистра [15:0] +GAS SLOT 0x4 +адрес слота [15:0]; маска — в Word0 payload, значения — Word1…Word3 + + error дополнительная информация [15:8], код [7:0] @@ -634,7 +640,11 @@ Priority Route DeviceType DeviceID MsgType MsgBody +

Контракт обоих GAS: OAP.md. Тип 0x3 адресует отдельные слова; тип 0x4 имеет маску битов 1…3 в Word0 и три значения. Для PERIPH 0x4 используются 67 слотов 0xMM00…0xMM42, последний содержит два значения. Старый Coil 0x4 заменён; формат определяется MsgType.

Общие правила обмена

+

Профиль синхронизации часов и сообщения платы о завершении инициализации: +GLOBAL_TIME.md. Он сохраняет штатный BROADCAST RTCSETUP +и определяет общий пакет готовности поверх DISCRETE/FLAGS.

  • Многобайтовые значения в DATA передаются little-endian.
  • Узел игнорирует адресованные кадры с чужим DeviceType/DeviceID.
  • @@ -998,99 +1008,493 @@ anti-rollback. Bootloader не обновляется командами B
  • Новое приложение после самопроверки выполняет CONFIRM.
-

Общее адресное пространство

-

Статус: Stable, данные ведутся в XLSX
-Порядок значений: 16-битные регистры, little-endian в CAN payload

-

Редактируемый источник реестра: -Протокол CAN и ОАП.xlsx.

-

Просматриваемая большая таблица находится в -Протокол CAN и ОАП.html и -Протокол CAN и ОАП.md.

-

Назначение

-

ОАП связывает 16-битный адрес регистра с его типом, назначением, доступом и -масштабом. В ProtoCAN используется MsgType=0x3, а MsgBody содержит адрес -первого регистра.

-

Обязательные поля реестра

+

Общее адресное пространство: GAS и GAS SLOT

+

Дата редакции: 2026-10-23. Номер типа однозначно определяет единицу адресации:

- - + + + + - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + +
ПолеТребованиеMsgTypeИмяMsgBodyPayload
AddressHex0x0000…0xFFFF, уникальное значение0x3GASадрес первого 16-битного регистра1…4 последовательных регистра, DLC 2/4/6/8
AddressDecдесятичный эквивалент AddressHex
Groupфункциональная группа
Nameоднозначное имя параметра
Typeu16, i16, u32, i32, float32, bitmap или массив
Registersчисло занятых 16-битных регистров
AccessR, W или RW
Unitфизическая единица либо —
Scaleмножитель/делитель представления
Defaultзначение после сброса, если применимо
Descriptionсемантика, диапазон и особые значения0x4GAS SLOTадрес слотаWord0 — маска; Word1…Word3 — три значения; DLC 8
-

Правила ведения

+

В обоих случаях запрос чтения — extended data frame с DLC=0, Route=0. +Ответ имеет Route=1, тот же узел и адрес. Прикладного ACK записи нет; +успех применения уставки проверяется прикладным ответом или последующим чтением. +RTR, error frame, стандартный 11-битный ID и нечётные длины не исполняются.

+

GAS 0x3: отдельные регистры

+

MsgBody=RegisterAddress[15:0]. Адреса 0…65535 (0x0000…0xFFFF) +обозначают 65 536 отдельных 16-битных регистров, логически 128 КиБ на узел. +Это адреса протокола, а не указатели RAM MCU; provider подключает только существующие регионы.

+

Payload содержит значения с адресов addr, addr+1, addr+2, addr+3 +в порядке little-endian. Количество равно DLC/2, допускаются DLC 2, 4, 6, 8. +Для изменения одной уставки по адресу 0x0001 на 0x1234 передаются +MsgBody=0x0001, DLC=2, Data=34 12; соседние слова не изменяются. +Чтение возвращает до четырёх существующих последовательных регистров, +останавливаясь на первом недоступном адресе или границе 0xFFFF. +Запись, пересекающая 0xFFFF, отвергается до изменения данных.

+

Регионы карты, права и значения проверяет pcan_gas; callback остаётся +ответственностью приложения. Блочная запись может остановиться на первом отказе provider: +атомарность нескольких регистров не обещается. Связанные u32/float32 и команды +требуют согласованной прикладной операции. Основной контракт: c/set-protocol/docs/legacy/GAS.md. +GAS 167/v1, GAS Logger, GAS_WATCH2, NAND и Altera Logic сохраняют регистровые адреса. +Номер mode задаёт адрес узла; его нельзя автоматически прибавлять к адресу регистра.

+

GAS SLOT 0x4: маска в Word0

+

MsgBody=SlotAddress[15:0]. Восемь октетов имеют фиксированное расположение:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ОктетыWire-словоНазначение
0…1Word016-битная маска, little-endian
2…3Word1первое значение
4…5Word2второе значение
6…7Word3третье значение
+

Биты маски 1, 2, 3 соответствуют Word1, Word2, Word3. Бит 0 и биты 4…15 +зарезервированы и должны быть нулевыми. Маска непустая; все допустимые маски: +0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, 0x000E. +При записи отмеченные значения применяются, неотмеченные позиции игнорируются +и сохраняют текущие значения устройства. Нули не являются специальными маркерами. +При чтении маска ответа отмечает достоверные/доступные значения.

+

Например, изменить только Word2 на 0x1234: Data=04 00 00 00 34 12 00 00. +Word1 и Word3 сохраняются. Полная запись трёх значений использует маску 0x000E. +Передаются всегда восемь октетов, кроме пустого запроса чтения. Сжатия или сегментации нет. +Provider проверяет все выбранные права и значения до первого изменения, затем применяет +выбранные слова под общей блокировкой. Невыбранные readonly-поля не записываются. +Ядро не выполняет опасное чтение-изменение-запись слота на стороне клиента.

+

Полное пространство 0x4 содержит 65 536 слотов × 3 значения = 196 608 слов = 384 КиБ. +Word0 — метаданные кадра, не четвёртый хранимый регистр. Координата значения — +(SlotAddress, WordIndex), где WordIndex=1…3. Любой узел поддерживается общими +pcan_gas_slot_id() и pcan_gas_slot_handle_address(); адрес слота не ограничен страницами PERIPH. +Тип 0x4 MODBUS_COIL заменён этим сервисом. Modbus 0x5/0x6/0x7 сохраняет номера. +Старое оборудование с Coil 0x4 требует согласованного обновления; автоопределения формата нет.

+

PERIPH: проекция 200 слов на слоты 0x4

+

mode=0…31; DeviceType=1+mode/16, DeviceID=mode mod 16. +SlotAddress=(mode<<8)|LocalSlot. Маски не занимают места в карте значений. +На mode сохранены 200 слов, поэтому используются 67 слотов LocalSlot=0x00…0x42: +66 полных слотов и два значения последнего. В последнем разрешена только маска +из битов 1/2 (0x0002, 0x0004, 0x0006); Word3 не существует. +LocalSlot=0x43…0xFF — резерв. Узел и старший октет слота должны совпадать.

+

Смещение технологического слова: n=3*LocalSlot+(WordIndex-1). +Обратное преобразование: LocalSlot=n/3, WordIndex=1+n mod 3. +Соседние native-сервисы могут оказаться в одном слоте, поэтому provider проверяет +доступ и наличие каждой отмеченной позиции отдельно.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
modeНазначениеDeviceType / DeviceIDСлоты 0x4Запрос первого слота
0Резерв0x01 / 0x000x0000…0x00420x11040000
1Трансформатор 10x01 / 0x010x0100…0x01420x11140100
2Трансформатор 20x01 / 0x020x0200…0x02420x11240200
3Силовой узел 10x01 / 0x030x0300…0x03420x11340300
4Силовой узел 20x01 / 0x040x0400…0x04420x11440400
5УМП10x01 / 0x050x0500…0x05420x11540500
6УМП20x01 / 0x060x0600…0x06420x11640600
7ENG10x01 / 0x070x0700…0x07420x11740700
8Задатчик / пульт0x01 / 0x080x0800…0x08420x11840800
9Шкаф0x01 / 0x090x0900…0x09420x11940900
10Общий адрес: служебная роль0x01 / 0x0A0x0A00…0x0A420x11A40A00
11Терминал: служебная роль0x01 / 0x0B0x0B00…0x0B420x11B40B00
12Резерв назначения0x01 / 0x0C0x0C00…0x0C420x11C40C00
13Резерв назначения0x01 / 0x0D0x0D00…0x0D420x11D40D00
14Резерв назначения0x01 / 0x0E0x0E00…0x0E420x11E40E00
15Резерв назначения0x01 / 0x0F0x0F00…0x0F420x11F40F00
16Резерв назначения0x02 / 0x000x1000…0x10420x12041000
17Резерв назначения0x02 / 0x010x1100…0x11420x12141100
18Резерв назначения0x02 / 0x020x1200…0x12420x12241200
19Резерв назначения0x02 / 0x030x1300…0x13420x12341300
20Резерв назначения0x02 / 0x040x1400…0x14420x12441400
21Резерв назначения0x02 / 0x050x1500…0x15420x12541500
22Резерв назначения0x02 / 0x060x1600…0x16420x12641600
23Резерв назначения0x02 / 0x070x1700…0x17420x12741700
24Резерв назначения0x02 / 0x080x1800…0x18420x12841800
25Резерв назначения0x02 / 0x090x1900…0x19420x12941900
26Резерв назначения0x02 / 0x0A0x1A00…0x1A420x12A41A00
27Резерв назначения0x02 / 0x0B0x1B00…0x1B420x12B41B00
28Резерв назначения0x02 / 0x0C0x1C00…0x1C420x12C41C00
29Резерв назначения0x02 / 0x0D0x1D00…0x1D420x12D41D00
30Резерв назначения0x02 / 0x0E0x1E00…0x1E420x12E41E00
31Резерв назначения0x02 / 0x0F0x1F00…0x1F420x12F41F00
+

Назначения mode из periph_28335

+

Источники: 28335_periph/Source/Internal/Include/package.h, peripher.c:get_Mode(), cntrl_adr.c. Код платы Desk не участвует в вычислении адреса.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
modeНазначениеИсходный символ
0РезервПеремычками текущей платы не задаётся
1 / 2Трансформаторные узлы 1 / 2adr_TRN1 / adr_TRN2
3 / 4Силовые узлы 1 / 2adr_POW1 / adr_POW2
5 / 6УМП1 / УМП2adr_LOA1 / adr_LOA2, Desk=dsk_LOAD=6
7ENG1adr_ENG1
8Задатчик / пультadr_PULT; имя «Задатчик» принято в реестре PERIPH
9Шкафadr_SHKF
10Общий адрес, служебная рольCNTRL_ADDR_UNIVERSAL, ADDR_FOR_ALL; не отдельная плата
11Терминал, служебная рольADDR_TERMINAL; не доказательство отдельной платы
12…31Резерв назначенияПеремычки текущей платы дают только 1…16
+

Соответствия native-сервисам PERIPH

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Смещение nNative-адресНазначениеДоступ
0…1270x0000…0x007Fтехнологические данные, уставки, командыпо provider
128…1430x1000…0x100Fстатус регистратора УМПR
144…1550x1200…0x120Bпаспорт прошивкиR
156…1630x1300…0x1307защита УМПW только 0x1302/0x1303
164…1670x1000…0x1003команды регистраторапо операции
168…199нетрезервотказ
+

pcan_gas_slot_native() принимает WordIndex=1…3; WordIndex=0 является маской +и не переводится в регистр. Наличие сервиса, права и блокировку проверяет приложение. +GAS 0x3 сохраняет собственные адреса подключённых регионов; эта проекция относится только к 0x4. +Архив УМП, окна 120/124 слова и физическая EEPROM сохраняют native-контракты.

+

Реализация и реестр

    -
  • Адрес не переиспользуется с другим смыслом после выпуска стабильной версии.
  • -
  • Многорегистровое значение занимает непрерывный диапазон.
  • -
  • Порядок 16-битных слов для 32-битного значения фиксируется в строке типа.
  • -
  • Резервные диапазоны явно отмечаются и не используются без изменения версии.
  • -
  • Удалённый параметр помечается deprecated, а не исчезает молча.
  • -
  • Изменение адреса, типа или масштаба отражается в CHANGELOG.md.
  • +
  • GAS 0x3: pcan_gas.h/.c, существующие ABI и клиенты.
  • +
  • GAS SLOT 0x4: pcan_gas_slot.h/.c; тонкие Python GasSlots и Android/JNI GasSlots.
  • +
  • Формат определяется MsgType, параметр gas_profile не используется.
  • +
  • C28x хранит wire-октеты в uint_least8_t; DLC измеряется октетами линии.
  • +
  • Перенос в другую единицу адресации или fallback после отказа запрещены.
-

Экспорт

-

Для программной генерации каталог следует экспортировать из XLSX в CSV с -UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на:

-
    -
  • уникальность адресов;
  • -
  • пересечение многорегистровых значений;
  • -
  • допустимые типы и права доступа;
  • -
  • равенство шестнадцатеричного и десятичного адреса;
  • -
  • попадание адреса в диапазон 0x0000…0xFFFF.
  • -
-

До появления автоматического экспортёра нормативным источником адресов -остаётся XLSX, а HTML/Markdown считаются представлением.

+

XLSX «Интерфейс протокола» содержит оба типа; «Общее адресное пространство» — +проекцию 0x4 и native-адреса её значений; «ОАП legacy» сохраняет исходный словный реестр 0x3. +Уникальный ключ реестра включает узел, MsgType, адрес и для 0x4 WordIndex. +Права, тип, единица, масштаб и порядок слов u32/float32 задаются явно. +Эталоны: examples/gas-slot-vectors.json; регистровые проверки — test_gas_register.c.

История изменений ProtoCAN

Формат основан на Keep a Changelog. Версия относится к спецификации, а не к версии прошивки отдельного прибора.

[Unreleased]

+

Changed — 2026-10-23

+
    +
  • GAS 0x3 возвращён к адресации отдельных 16-битных регистров 0…65535, DLC 0/2/4/6/8.
  • +
  • Слотный GAS перенесён на 0x4 вместо MODBUS_COIL; Word0 содержит маску битов 1…3, Word1…Word3 — значения.
  • +
  • PERIPH сохраняет 200 значений на mode в 67 слотах; последний содержит два значения.
  • +
  • Формат выбирается номером MsgType; Python/JNI, STM32, Modbus routing, тесты, XLSX и HTML согласованы.
  • +

Added

  • Структурированный комплект документации doc/setcan/protocan.
  • diff --git a/doc/setcan/protocan/CHANGELOG.md b/doc/setcan/protocan/CHANGELOG.md index 73c921e..827ff7a 100644 --- a/doc/setcan/protocan/CHANGELOG.md +++ b/doc/setcan/protocan/CHANGELOG.md @@ -5,6 +5,13 @@ ## [Unreleased] +### Changed — 2026-10-23 + +- GAS 0x3 возвращён к адресации отдельных 16-битных регистров 0…65535, DLC 0/2/4/6/8. +- Слотный GAS перенесён на 0x4 вместо MODBUS_COIL; Word0 содержит маску битов 1…3, Word1…Word3 — значения. +- PERIPH сохраняет 200 значений на mode в 67 слотах; последний содержит два значения. +- Формат выбирается номером MsgType; Python/JNI, STM32, Modbus routing, тесты, XLSX и HTML согласованы. + ### Added - Структурированный комплект документации `doc/setcan/protocan`. diff --git a/doc/setcan/protocan/OAP.md b/doc/setcan/protocan/OAP.md index 28918bf..9bab425 100644 --- a/doc/setcan/protocan/OAP.md +++ b/doc/setcan/protocan/OAP.md @@ -1,56 +1,162 @@ -# Общее адресное пространство +# Общее адресное пространство: GAS и GAS SLOT -Статус: **Stable, данные ведутся в XLSX**
    -Порядок значений: **16-битные регистры, little-endian в CAN payload** +Дата редакции: **2026-10-23**. Номер типа однозначно определяет единицу адресации: -Редактируемый источник реестра: -[`Протокол CAN и ОАП.xlsx`](../Протокол%20CAN%20и%20ОАП.xlsx). +| MsgType | Имя | MsgBody | Payload | +|---|---|---|---| +| `0x3` | GAS | адрес первого 16-битного регистра | 1…4 последовательных регистра, DLC 2/4/6/8 | +| `0x4` | GAS SLOT | адрес слота | Word0 — маска; Word1…Word3 — три значения; DLC 8 | -Просматриваемая большая таблица находится в -[`Протокол CAN и ОАП.html`](../Протокол%20CAN%20и%20ОАП.html) и -[`Протокол CAN и ОАП.md`](../Протокол%20CAN%20и%20ОАП.md). +В обоих случаях запрос чтения — extended data frame с `DLC=0`, `Route=0`. +Ответ имеет `Route=1`, тот же узел и адрес. Прикладного ACK записи нет; +успех применения уставки проверяется прикладным ответом или последующим чтением. +RTR, error frame, стандартный 11-битный ID и нечётные длины не исполняются. -## Назначение +## GAS 0x3: отдельные регистры -ОАП связывает 16-битный адрес регистра с его типом, назначением, доступом и -масштабом. В ProtoCAN используется `MsgType=0x3`, а `MsgBody` содержит адрес -первого регистра. +`MsgBody=RegisterAddress[15:0]`. Адреса `0…65535` (`0x0000…0xFFFF`) +обозначают **65 536 отдельных 16-битных регистров**, логически 128 КиБ на узел. +Это адреса протокола, а не указатели RAM MCU; provider подключает только существующие регионы. -## Обязательные поля реестра +Payload содержит значения с адресов `addr`, `addr+1`, `addr+2`, `addr+3` +в порядке little-endian. Количество равно `DLC/2`, допускаются DLC 2, 4, 6, 8. +Для изменения одной уставки по адресу `0x0001` на `0x1234` передаются +`MsgBody=0x0001`, `DLC=2`, Data=`34 12`; соседние слова не изменяются. +Чтение возвращает до четырёх существующих последовательных регистров, +останавливаясь на первом недоступном адресе или границе `0xFFFF`. +Запись, пересекающая `0xFFFF`, отвергается до изменения данных. -| Поле | Требование | -|---|---| -| AddressHex | `0x0000…0xFFFF`, уникальное значение | -| AddressDec | десятичный эквивалент AddressHex | -| Group | функциональная группа | -| Name | однозначное имя параметра | -| Type | `u16`, `i16`, `u32`, `i32`, `float32`, bitmap или массив | -| Registers | число занятых 16-битных регистров | -| Access | `R`, `W` или `RW` | -| Unit | физическая единица либо `—` | -| Scale | множитель/делитель представления | -| Default | значение после сброса, если применимо | -| Description | семантика, диапазон и особые значения | +Регионы карты, права и значения проверяет `pcan_gas`; callback остаётся +ответственностью приложения. Блочная запись может остановиться на первом отказе provider: +атомарность нескольких регистров не обещается. Связанные `u32/float32` и команды +требуют согласованной прикладной операции. Основной контракт: `c/set-protocol/docs/legacy/GAS.md`. +GAS 167/v1, GAS Logger, GAS_WATCH2, NAND и Altera Logic сохраняют регистровые адреса. +Номер mode задаёт адрес узла; его нельзя автоматически прибавлять к адресу регистра. -## Правила ведения +## GAS SLOT 0x4: маска в Word0 -- Адрес не переиспользуется с другим смыслом после выпуска стабильной версии. -- Многорегистровое значение занимает непрерывный диапазон. -- Порядок 16-битных слов для 32-битного значения фиксируется в строке типа. -- Резервные диапазоны явно отмечаются и не используются без изменения версии. -- Удалённый параметр помечается deprecated, а не исчезает молча. -- Изменение адреса, типа или масштаба отражается в `CHANGELOG.md`. +`MsgBody=SlotAddress[15:0]`. Восемь октетов имеют фиксированное расположение: -## Экспорт +| Октеты | Wire-слово | Назначение | +|---|---|---| +| 0…1 | Word0 | 16-битная маска, little-endian | +| 2…3 | Word1 | первое значение | +| 4…5 | Word2 | второе значение | +| 6…7 | Word3 | третье значение | -Для программной генерации каталог следует экспортировать из XLSX в CSV с -UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на: +Биты маски 1, 2, 3 соответствуют Word1, Word2, Word3. Бит 0 и биты 4…15 +зарезервированы и должны быть нулевыми. Маска непустая; все допустимые маски: +`0x0002`, `0x0004`, `0x0006`, `0x0008`, `0x000A`, `0x000C`, `0x000E`. +При записи отмеченные значения применяются, неотмеченные позиции игнорируются +и сохраняют текущие значения устройства. Нули не являются специальными маркерами. +При чтении маска ответа отмечает достоверные/доступные значения. -- уникальность адресов; -- пересечение многорегистровых значений; -- допустимые типы и права доступа; -- равенство шестнадцатеричного и десятичного адреса; -- попадание адреса в диапазон `0x0000…0xFFFF`. +Например, изменить только Word2 на `0x1234`: Data=`04 00 00 00 34 12 00 00`. +Word1 и Word3 сохраняются. Полная запись трёх значений использует маску `0x000E`. +Передаются всегда восемь октетов, кроме пустого запроса чтения. Сжатия или сегментации нет. +Provider проверяет все выбранные права и значения до первого изменения, затем применяет +выбранные слова под общей блокировкой. Невыбранные readonly-поля не записываются. +Ядро не выполняет опасное чтение-изменение-запись слота на стороне клиента. -До появления автоматического экспортёра нормативным источником адресов -остаётся XLSX, а HTML/Markdown считаются представлением. +Полное пространство 0x4 содержит **65 536 слотов × 3 значения = 196 608 слов = 384 КиБ**. +Word0 — метаданные кадра, не четвёртый хранимый регистр. Координата значения — +`(SlotAddress, WordIndex)`, где `WordIndex=1…3`. Любой узел поддерживается общими +`pcan_gas_slot_id()` и `pcan_gas_slot_handle_address()`; адрес слота не ограничен страницами PERIPH. +Тип `0x4 MODBUS_COIL` заменён этим сервисом. Modbus `0x5/0x6/0x7` сохраняет номера. +Старое оборудование с Coil 0x4 требует согласованного обновления; автоопределения формата нет. + +## PERIPH: проекция 200 слов на слоты 0x4 + +`mode=0…31`; `DeviceType=1+mode/16`, `DeviceID=mode mod 16`. +`SlotAddress=(mode<<8)|LocalSlot`. Маски не занимают места в карте значений. +На mode сохранены 200 слов, поэтому используются 67 слотов `LocalSlot=0x00…0x42`: +66 полных слотов и два значения последнего. В последнем разрешена только маска +из битов 1/2 (`0x0002`, `0x0004`, `0x0006`); Word3 не существует. +`LocalSlot=0x43…0xFF` — резерв. Узел и старший октет слота должны совпадать. + +Смещение технологического слова: `n=3*LocalSlot+(WordIndex-1)`. +Обратное преобразование: `LocalSlot=n/3`, `WordIndex=1+n mod 3`. +Соседние native-сервисы могут оказаться в одном слоте, поэтому provider проверяет +доступ и наличие каждой отмеченной позиции отдельно. + +| mode | Назначение | DeviceType / DeviceID | Слоты 0x4 | Запрос первого слота | +|---:|---|---|---|---| +| 0 | Резерв | `0x01 / 0x00` | `0x0000…0x0042` | `0x11040000` | +| 1 | Трансформатор 1 | `0x01 / 0x01` | `0x0100…0x0142` | `0x11140100` | +| 2 | Трансформатор 2 | `0x01 / 0x02` | `0x0200…0x0242` | `0x11240200` | +| 3 | Силовой узел 1 | `0x01 / 0x03` | `0x0300…0x0342` | `0x11340300` | +| 4 | Силовой узел 2 | `0x01 / 0x04` | `0x0400…0x0442` | `0x11440400` | +| 5 | УМП1 | `0x01 / 0x05` | `0x0500…0x0542` | `0x11540500` | +| 6 | УМП2 | `0x01 / 0x06` | `0x0600…0x0642` | `0x11640600` | +| 7 | ENG1 | `0x01 / 0x07` | `0x0700…0x0742` | `0x11740700` | +| 8 | Задатчик / пульт | `0x01 / 0x08` | `0x0800…0x0842` | `0x11840800` | +| 9 | Шкаф | `0x01 / 0x09` | `0x0900…0x0942` | `0x11940900` | +| 10 | Общий адрес: служебная роль | `0x01 / 0x0A` | `0x0A00…0x0A42` | `0x11A40A00` | +| 11 | Терминал: служебная роль | `0x01 / 0x0B` | `0x0B00…0x0B42` | `0x11B40B00` | +| 12 | Резерв назначения | `0x01 / 0x0C` | `0x0C00…0x0C42` | `0x11C40C00` | +| 13 | Резерв назначения | `0x01 / 0x0D` | `0x0D00…0x0D42` | `0x11D40D00` | +| 14 | Резерв назначения | `0x01 / 0x0E` | `0x0E00…0x0E42` | `0x11E40E00` | +| 15 | Резерв назначения | `0x01 / 0x0F` | `0x0F00…0x0F42` | `0x11F40F00` | +| 16 | Резерв назначения | `0x02 / 0x00` | `0x1000…0x1042` | `0x12041000` | +| 17 | Резерв назначения | `0x02 / 0x01` | `0x1100…0x1142` | `0x12141100` | +| 18 | Резерв назначения | `0x02 / 0x02` | `0x1200…0x1242` | `0x12241200` | +| 19 | Резерв назначения | `0x02 / 0x03` | `0x1300…0x1342` | `0x12341300` | +| 20 | Резерв назначения | `0x02 / 0x04` | `0x1400…0x1442` | `0x12441400` | +| 21 | Резерв назначения | `0x02 / 0x05` | `0x1500…0x1542` | `0x12541500` | +| 22 | Резерв назначения | `0x02 / 0x06` | `0x1600…0x1642` | `0x12641600` | +| 23 | Резерв назначения | `0x02 / 0x07` | `0x1700…0x1742` | `0x12741700` | +| 24 | Резерв назначения | `0x02 / 0x08` | `0x1800…0x1842` | `0x12841800` | +| 25 | Резерв назначения | `0x02 / 0x09` | `0x1900…0x1942` | `0x12941900` | +| 26 | Резерв назначения | `0x02 / 0x0A` | `0x1A00…0x1A42` | `0x12A41A00` | +| 27 | Резерв назначения | `0x02 / 0x0B` | `0x1B00…0x1B42` | `0x12B41B00` | +| 28 | Резерв назначения | `0x02 / 0x0C` | `0x1C00…0x1C42` | `0x12C41C00` | +| 29 | Резерв назначения | `0x02 / 0x0D` | `0x1D00…0x1D42` | `0x12D41D00` | +| 30 | Резерв назначения | `0x02 / 0x0E` | `0x1E00…0x1E42` | `0x12E41E00` | +| 31 | Резерв назначения | `0x02 / 0x0F` | `0x1F00…0x1F42` | `0x12F41F00` | + +## Назначения mode из periph_28335 + +Источники: `28335_periph/Source/Internal/Include/package.h`, `peripher.c:get_Mode()`, `cntrl_adr.c`. Код платы `Desk` не участвует в вычислении адреса. + +| mode | Назначение | Исходный символ | +|---:|---|---| +| 0 | Резерв | Перемычками текущей платы не задаётся | +| 1 / 2 | Трансформаторные узлы 1 / 2 | `adr_TRN1 / adr_TRN2` | +| 3 / 4 | Силовые узлы 1 / 2 | `adr_POW1 / adr_POW2` | +| 5 / 6 | УМП1 / УМП2 | `adr_LOA1 / adr_LOA2`, `Desk=dsk_LOAD=6` | +| 7 | ENG1 | `adr_ENG1` | +| 8 | Задатчик / пульт | `adr_PULT`; имя «Задатчик» принято в реестре PERIPH | +| 9 | Шкаф | `adr_SHKF` | +| 10 | Общий адрес, служебная роль | `CNTRL_ADDR_UNIVERSAL`, `ADDR_FOR_ALL`; не отдельная плата | +| 11 | Терминал, служебная роль | `ADDR_TERMINAL`; не доказательство отдельной платы | +| 12…31 | Резерв назначения | Перемычки текущей платы дают только 1…16 | + +## Соответствия native-сервисам PERIPH + +| Смещение n | Native-адрес | Назначение | Доступ | +|---|---|---|---| +| 0…127 | `0x0000…0x007F` | технологические данные, уставки, команды | по provider | +| 128…143 | `0x1000…0x100F` | статус регистратора УМП | R | +| 144…155 | `0x1200…0x120B` | паспорт прошивки | R | +| 156…163 | `0x1300…0x1307` | защита УМП | W только `0x1302/0x1303` | +| 164…167 | `0x1000…0x1003` | команды регистратора | по операции | +| 168…199 | нет | резерв | отказ | + +`pcan_gas_slot_native()` принимает WordIndex=1…3; WordIndex=0 является маской +и не переводится в регистр. Наличие сервиса, права и блокировку проверяет приложение. +GAS 0x3 сохраняет собственные адреса подключённых регионов; эта проекция относится только к 0x4. +Архив УМП, окна 120/124 слова и физическая EEPROM сохраняют native-контракты. + +## Реализация и реестр + +- GAS 0x3: `pcan_gas.h/.c`, существующие ABI и клиенты. +- GAS SLOT 0x4: `pcan_gas_slot.h/.c`; тонкие Python `GasSlots` и Android/JNI `GasSlots`. +- Формат определяется MsgType, параметр `gas_profile` не используется. +- C28x хранит wire-октеты в `uint_least8_t`; DLC измеряется октетами линии. +- Перенос в другую единицу адресации или fallback после отказа запрещены. + +XLSX «Интерфейс протокола» содержит оба типа; «Общее адресное пространство» — +проекцию 0x4 и native-адреса её значений; «ОАП legacy» сохраняет исходный словный реестр 0x3. +Уникальный ключ реестра включает узел, MsgType, адрес и для 0x4 WordIndex. +Права, тип, единица, масштаб и порядок слов u32/float32 задаются явно. +Эталоны: `examples/gas-slot-vectors.json`; регистровые проверки — `test_gas_register.c`. diff --git a/doc/setcan/protocan/PROTOCOL.md b/doc/setcan/protocan/PROTOCOL.md index aea4627..644c707 100644 --- a/doc/setcan/protocan/PROTOCOL.md +++ b/doc/setcan/protocan/PROTOCOL.md @@ -1,7 +1,7 @@ # ProtoCAN — базовый протокол Статус: **Stable с зарезервированным загрузочным расширением**
    -Версия: **1.0**
    +Версия: **2.1: GAS 0x3 и масочный GAS SLOT 0x4**
    Порядок байтов payload: **little-endian**, если явно не указано иное ## Назначение @@ -59,8 +59,8 @@ can_id = | `0x0` | `BROADCAST` | ПМ → все | зависит от команды | stable | | `0x1` | `DISCRETE` | оба | 0…8 | stable | | `0x2` | `ANALOG` | оба | 0…8 | stable | -| `0x3` | `GAS` | оба | 0/2/4/6/8 | stable | -| `0x4` | `MODBUS_COIL` | оба | 0…8 | stable | +| `0x3` | `GAS` | оба | 0/2/4/6/8 | регистры 0…65535 | +| `0x4` | `GAS_SLOT` | оба | 0/8 | Word0 — маска, Word1…Word3 — значения | | `0x5` | `MODBUS_DISCRETE` | оба | 0…8 | stable | | `0x6` | `MODBUS_HOLDING` | оба | 0…8 | stable | | `0x7` | `MODBUS_INPUT` | оба | 0…8 | stable | @@ -82,14 +82,21 @@ can_id = | broadcast | команда `[15:4]`, параметр `[3:0]` | | discrete/analog | подтип `[15:12]`, значение/адрес `[11:0]` | | Modbus | начальный адрес `[15:4]`, количество `[3:0]` | -| GAS | адрес первого 16-битного регистра `[15:0]` | +| GAS 0x3 | адрес первого 16-битного регистра `[15:0]` | +| GAS SLOT 0x4 | адрес слота `[15:0]`; маска — в Word0 payload, значения — Word1…Word3 | | error | дополнительная информация `[15:8]`, код `[7:0]` | | settings | номер сборки `[15:8]`, позиция `[7:0]` | | boot control/status | `SessionID[15:8]`, команда `[7:0]` | | boot data | `BlockIndex[15:0]` | +Контракт обоих GAS: [OAP.md](OAP.md). Тип 0x3 адресует отдельные слова; тип 0x4 имеет маску битов 1…3 в Word0 и три значения. Для PERIPH 0x4 используются 67 слотов `0xMM00…0xMM42`, последний содержит два значения. Старый Coil 0x4 заменён; формат определяется MsgType. + ## Общие правила обмена +Профиль синхронизации часов и сообщения платы о завершении инициализации: +[GLOBAL_TIME.md](GLOBAL_TIME.md). Он сохраняет штатный BROADCAST RTCSETUP +и определяет общий пакет готовности поверх DISCRETE/FLAGS. + - Многобайтовые значения в `DATA` передаются little-endian. - Узел игнорирует адресованные кадры с чужим `DeviceType/DeviceID`. - Прибор принимает команды ПМ с `Route=0`; ПМ принимает ответы с `Route=1`. diff --git a/doc/setcan/protocan/README.md b/doc/setcan/protocan/README.md index 841978e..b696bdb 100644 --- a/doc/setcan/protocan/README.md +++ b/doc/setcan/protocan/README.md @@ -1,8 +1,8 @@ # Документация ProtoCAN Статус комплекта: **Draft**
    -Версия комплекта: **1.0**
    -Дата редакции: **2026-08-29**
    +Версия комплекта: **2.1**
    +Дата редакции: **2026-10-23**
    Транспорт: **Classic CAN 2.0B, Extended ID, DLC 0…8** Этот каталог разделяет нормативное описание протокола, загрузчик и реестр @@ -41,3 +41,7 @@ Все документы и тестовые векторы включаются в единый файл `doc/setcan/index.html`. Скрипт не изменяет исходные Markdown/XLSX и пригоден для запуска в CI. + +## GAS: регистры 0x3 и слоты 0x4 + +[Адресация GAS](OAP.md): `0x3` — отдельные 16-битные регистры `0…65535`, запись 1…4 слов. `0x4` — слот с Word0-маской и тремя значениями; PERIPH сохраняет 200 слов в 67 слотах `0xMM00…0xMM42`. Формат определяется MsgType, без настройки профиля. diff --git a/doc/setcan/Протокол CAN и ОАП.html b/doc/setcan/Протокол CAN и ОАП.html index e4c7fbc..2c53c82 100644 --- a/doc/setcan/Протокол CAN и ОАП.html +++ b/doc/setcan/Протокол CAN и ОАП.html @@ -1,32 +1,259 @@ - - - - - -Протокол CAN и ОАП - - -

    Протокол CAN и ОАП

    +ProtoCAN — GAS 0x3 и GAS SLOT 0x4

    Протокол CAN и ОАП

    Таблицы перенесены из Протокол CAN и ОАП.xlsx. Цвета, объединённые ячейки и структура листов сохранены средствами HTML внутри Markdown.

    +

    Адреса PERIPH обновлены по листу «Интерфейс протокола», A44:F79: +Type 0x01 содержит PERIPH 0–15, Type 0x02 — PERIPH 16–31; +Device ID равен младшим четырём битам номера PERIPH. +УМП1 — 0x01/0x05, УМП2 — 0x01/0x06, задатчик — 0x01/0x08. +Назначения остальных mode уточнены по periph_28335: 1/2 — трансформаторы, 3/4 — силовые узлы, 7 — ENG1, 9 — шкаф; 10/11 — служебные роли. Общий Boot-адрес 0x03/0x07 отменён. +Полный реестр назначений применяется и к загрузчику, и к GUI.

    -

    +

    +

    +

    GAS: регистры 0x3 и масочные слоты 0x4

    +

    Нормативная спецификация: OAP.md. GAS 0x3: адрес первого регистра 0…65535, DLC 0/2/4/6/8. GAS SLOT 0x4: Word0 — маска битов 1…3, Word1…Word3 — три значения, DLC 0/8. PERIPH сохраняет 200 значений в 67 слотах; последний содержит два. Словный реестр ниже сохраняет адреса GAS 0x3.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    modeНазначениеType / IDСлоты 0x4CAN запрос
    0Резерв0x01 / 0x000x0000…0x00420x11040000
    1Трансформатор 10x01 / 0x010x0100…0x01420x11140100
    2Трансформатор 20x01 / 0x020x0200…0x02420x11240200
    3Силовой узел 10x01 / 0x030x0300…0x03420x11340300
    4Силовой узел 20x01 / 0x040x0400…0x04420x11440400
    5УМП10x01 / 0x050x0500…0x05420x11540500
    6УМП20x01 / 0x060x0600…0x06420x11640600
    7ENG10x01 / 0x070x0700…0x07420x11740700
    8Задатчик / пульт0x01 / 0x080x0800…0x08420x11840800
    9Шкаф0x01 / 0x090x0900…0x09420x11940900
    10Общий адрес: служебная роль0x01 / 0x0A0x0A00…0x0A420x11A40A00
    11Терминал: служебная роль0x01 / 0x0B0x0B00…0x0B420x11B40B00
    12Резерв назначения0x01 / 0x0C0x0C00…0x0C420x11C40C00
    13Резерв назначения0x01 / 0x0D0x0D00…0x0D420x11D40D00
    14Резерв назначения0x01 / 0x0E0x0E00…0x0E420x11E40E00
    15Резерв назначения0x01 / 0x0F0x0F00…0x0F420x11F40F00
    16Резерв назначения0x02 / 0x000x1000…0x10420x12041000
    17Резерв назначения0x02 / 0x010x1100…0x11420x12141100
    18Резерв назначения0x02 / 0x020x1200…0x12420x12241200
    19Резерв назначения0x02 / 0x030x1300…0x13420x12341300
    20Резерв назначения0x02 / 0x040x1400…0x14420x12441400
    21Резерв назначения0x02 / 0x050x1500…0x15420x12541500
    22Резерв назначения0x02 / 0x060x1600…0x16420x12641600
    23Резерв назначения0x02 / 0x070x1700…0x17420x12741700
    24Резерв назначения0x02 / 0x080x1800…0x18420x12841800
    25Резерв назначения0x02 / 0x090x1900…0x19420x12941900
    26Резерв назначения0x02 / 0x0A0x1A00…0x1A420x12A41A00
    27Резерв назначения0x02 / 0x0B0x1B00…0x1B420x12B41B00
    28Резерв назначения0x02 / 0x0C0x1C00…0x1C420x12C41C00
    29Резерв назначения0x02 / 0x0D0x1D00…0x1D420x12D41D00
    30Резерв назначения0x02 / 0x0E0x1E00…0x1E420x12E41E00
    31Резерв назначения0x02 / 0x0F0x1F00…0x1F420x12F41F00

    Прошивка приборов по CAN

    -

    Ниже зафиксирован формат планируемого загрузочного сервиса. Значения -MsgType=0x9..0xD зарезервированы в протоколе, но обработчики загрузчика в -текущих protocan.c/.h ещё не реализованы.

    +

    Загрузчик MsgType=0x9…0xD реализован в c/protocan-boot. Актуальные команды, A/B и single-slot: BOOTLOADER.md. Ниже сохранена историческая таблица; при расхождении применяется актуальная спецификация.

    Загрузчик работает поверх classic CAN 2.0B с Extended ID. Управляющий модуль использует Route=0, прибор отвечает с Route=1. Команды стирания и записи всегда должны быть адресованы конкретной паре DeviceType/DeviceID; @@ -704,8 +931,8 @@ DATA[4..7] RunningCRC32, uint32 little-endian 0x1. Стандартный 0х1. Устройство -0x1 -0x0 - 0xF устройств +0x01 PERIPH +0x0–0xF; PERIPH 0–15
    0x5: УМП1; 0x6: УМП2; 0x8: Задатчик 0x1. Запрос на вкл/выкл Выбор "страницы" из 64 устройств (Битовые флаги в Data)   @@ -716,8 +943,8 @@ DATA[4..7] RunningCRC32, uint32 little-endian     -0x2 -0x0 - 0xF устройств +0x02 PERIPH +0x0–0xF; PERIPH 16–31 0x2. Рестарт устройств Выбор "страницы" из 64 устройств (Битовые флаги в Data)   @@ -955,14 +1182,14 @@ DATA[4..7] RunningCRC32, uint32 little-endian     0x3. Общее адресное пространство -Адрес регистра (Стартовый адрес, если DLC COUNT > 2) (0, 0x0000 - 65535, 0xFFFF) +GAS: адрес первого 16-битного регистра 0x0000…0xFFFF; до четырёх последовательных значений.   0/2/4/6/8   -Четвёртый регистр -Третий регистр -Второй регистр -Первый регистр +Регистр addr+3 +Регистр addr+2 +Регистр addr+1 +Регистр addr+0   @@ -971,13 +1198,12 @@ DATA[4..7] RunningCRC32, uint32 little-endian       -0x4. Modbus Coil -Стартовый адрес регистра (0x0 - 0xFFF) -Кол-во регистров (0-15) +0x4. GAS SLOT +Адрес слота 0x0000…0xFFFF   -  +0/8   -NULL +Word3 | Word2 | Word1 | Word0: маска битов 1…3   @@ -1421,8 +1647,8 @@ DATA[4..7] RunningCRC32, uint32 little-endian

-

-

Лист «Общее адресное пространство»

+

+

Исторический лист «ОАП legacy»: адреса регистров

Таблица прокручивается по горизонтали; длинный лист ограничен по высоте окна.

@@ -13399,6 +13625,4 @@ DATA[4..7] RunningCRC32, uint32 little-endian
- - - + \ No newline at end of file diff --git a/doc/setcan/Протокол CAN и ОАП.md b/doc/setcan/Протокол CAN и ОАП.md index da42337..11c9aee 100644 --- a/doc/setcan/Протокол CAN и ОАП.md +++ b/doc/setcan/Протокол CAN и ОАП.md @@ -2,16 +2,61 @@ Таблицы перенесены из `Протокол CAN и ОАП.xlsx`. Цвета, объединённые ячейки и структура листов сохранены средствами HTML внутри Markdown. +Адреса PERIPH обновлены по листу «Интерфейс протокола», A44:F79: +Type `0x01` содержит PERIPH 0–15, Type `0x02` — PERIPH 16–31; +Device ID равен младшим четырём битам номера PERIPH. +УМП1 — `0x01/0x05`, УМП2 — `0x01/0x06`, задатчик — `0x01/0x08`. +Назначения остальных mode уточнены по periph_28335: 1/2 — трансформаторы, 3/4 — силовые узлы, 7 — ENG1, 9 — шкаф; 10/11 — служебные роли. Общий Boot-адрес `0x03/0x07` отменён. +Полный [реестр назначений](DEVICE_REGISTRY.md) применяется и к загрузчику, и к GUI. + - [Интерфейс протокола](#sheet-protocol) - [Общее адресное пространство](#sheet-oap) - [Прошивка приборов по CAN](#can-firmware) + +## GAS: регистры 0x3 и масочные слоты 0x4 + +Нормативная спецификация: [OAP.md](protocan/OAP.md). GAS 0x3: адрес первого регистра 0…65535, DLC 0/2/4/6/8. GAS SLOT 0x4: Word0 — маска битов 1…3, Word1…Word3 — три значения, DLC 0/8. PERIPH сохраняет 200 значений в 67 слотах; последний содержит два. Словный реестр ниже сохраняет адреса GAS 0x3. + +| mode | Назначение | Type / ID | Слоты 0x4 | CAN запрос | +|---:|---|---|---|---| +| 0 | Резерв | `0x01 / 0x00` | `0x0000…0x0042` | `0x11040000` | +| 1 | Трансформатор 1 | `0x01 / 0x01` | `0x0100…0x0142` | `0x11140100` | +| 2 | Трансформатор 2 | `0x01 / 0x02` | `0x0200…0x0242` | `0x11240200` | +| 3 | Силовой узел 1 | `0x01 / 0x03` | `0x0300…0x0342` | `0x11340300` | +| 4 | Силовой узел 2 | `0x01 / 0x04` | `0x0400…0x0442` | `0x11440400` | +| 5 | УМП1 | `0x01 / 0x05` | `0x0500…0x0542` | `0x11540500` | +| 6 | УМП2 | `0x01 / 0x06` | `0x0600…0x0642` | `0x11640600` | +| 7 | ENG1 | `0x01 / 0x07` | `0x0700…0x0742` | `0x11740700` | +| 8 | Задатчик / пульт | `0x01 / 0x08` | `0x0800…0x0842` | `0x11840800` | +| 9 | Шкаф | `0x01 / 0x09` | `0x0900…0x0942` | `0x11940900` | +| 10 | Общий адрес: служебная роль | `0x01 / 0x0A` | `0x0A00…0x0A42` | `0x11A40A00` | +| 11 | Терминал: служебная роль | `0x01 / 0x0B` | `0x0B00…0x0B42` | `0x11B40B00` | +| 12 | Резерв назначения | `0x01 / 0x0C` | `0x0C00…0x0C42` | `0x11C40C00` | +| 13 | Резерв назначения | `0x01 / 0x0D` | `0x0D00…0x0D42` | `0x11D40D00` | +| 14 | Резерв назначения | `0x01 / 0x0E` | `0x0E00…0x0E42` | `0x11E40E00` | +| 15 | Резерв назначения | `0x01 / 0x0F` | `0x0F00…0x0F42` | `0x11F40F00` | +| 16 | Резерв назначения | `0x02 / 0x00` | `0x1000…0x1042` | `0x12041000` | +| 17 | Резерв назначения | `0x02 / 0x01` | `0x1100…0x1142` | `0x12141100` | +| 18 | Резерв назначения | `0x02 / 0x02` | `0x1200…0x1242` | `0x12241200` | +| 19 | Резерв назначения | `0x02 / 0x03` | `0x1300…0x1342` | `0x12341300` | +| 20 | Резерв назначения | `0x02 / 0x04` | `0x1400…0x1442` | `0x12441400` | +| 21 | Резерв назначения | `0x02 / 0x05` | `0x1500…0x1542` | `0x12541500` | +| 22 | Резерв назначения | `0x02 / 0x06` | `0x1600…0x1642` | `0x12641600` | +| 23 | Резерв назначения | `0x02 / 0x07` | `0x1700…0x1742` | `0x12741700` | +| 24 | Резерв назначения | `0x02 / 0x08` | `0x1800…0x1842` | `0x12841800` | +| 25 | Резерв назначения | `0x02 / 0x09` | `0x1900…0x1942` | `0x12941900` | +| 26 | Резерв назначения | `0x02 / 0x0A` | `0x1A00…0x1A42` | `0x12A41A00` | +| 27 | Резерв назначения | `0x02 / 0x0B` | `0x1B00…0x1B42` | `0x12B41B00` | +| 28 | Резерв назначения | `0x02 / 0x0C` | `0x1C00…0x1C42` | `0x12C41C00` | +| 29 | Резерв назначения | `0x02 / 0x0D` | `0x1D00…0x1D42` | `0x12D41D00` | +| 30 | Резерв назначения | `0x02 / 0x0E` | `0x1E00…0x1E42` | `0x12E41E00` | +| 31 | Резерв назначения | `0x02 / 0x0F` | `0x1F00…0x1F42` | `0x12F41F00` | + ## Прошивка приборов по CAN -Ниже зафиксирован формат планируемого загрузочного сервиса. Значения -`MsgType=0x9..0xD` зарезервированы в протоколе, но обработчики загрузчика в -текущих `protocan.c/.h` ещё не реализованы. +Загрузчик `MsgType=0x9…0xD` реализован в `c/protocan-boot`. Актуальные команды, A/B и single-slot: [BOOTLOADER.md](protocan/BOOTLOADER.md). Ниже сохранена историческая таблица; при расхождении применяется актуальная спецификация. Загрузчик работает поверх classic CAN 2.0B с Extended ID. Управляющий модуль использует `Route=0`, прибор отвечает с `Route=1`. Команды стирания и записи @@ -576,8 +621,8 @@ CRC32 обнаруживает случайное повреждение, но 0x1. Стандартный 0х1. Устройство -0x1 -0x0 - 0xF устройств +0x01 PERIPH +0x0–0xF; PERIPH 0–15
0x5: УМП1; 0x6: УМП2; 0x8: Задатчик 0x1. Запрос на вкл/выкл Выбор "страницы" из 64 устройств (Битовые флаги в Data)   @@ -588,8 +633,8 @@ CRC32 обнаруживает случайное повреждение, но     -0x2 -0x0 - 0xF устройств +0x02 PERIPH +0x0–0xF; PERIPH 16–31 0x2. Рестарт устройств Выбор "страницы" из 64 устройств (Битовые флаги в Data)   @@ -827,14 +872,14 @@ CRC32 обнаруживает случайное повреждение, но     0x3. Общее адресное пространство -Адрес регистра (Стартовый адрес, если DLC COUNT > 2) (0, 0x0000 - 65535, 0xFFFF) +GAS: адрес первого 16-битного регистра 0x0000…0xFFFF; до четырёх последовательных значений.   0/2/4/6/8   -Четвёртый регистр -Третий регистр -Второй регистр -Первый регистр +Регистр addr+3 +Регистр addr+2 +Регистр addr+1 +Регистр addr+0   @@ -843,13 +888,12 @@ CRC32 обнаруживает случайное повреждение, но       -0x4. Modbus Coil -Стартовый адрес регистра (0x0 - 0xFFF) -Кол-во регистров (0-15) +0x4. GAS SLOT +Адрес слота 0x0000…0xFFFF   -  +0/8   -NULL +Word3 | Word2 | Word1 | Word0: маска битов 1…3   @@ -1294,8 +1338,8 @@ CRC32 обнаруживает случайное повреждение, но - -## Лист «Общее адресное пространство» + +## Исторический лист «ОАП legacy»: адреса регистров

Таблица прокручивается по горизонтали; длинный лист ограничен по высоте окна.

diff --git a/doc/setcan/Протокол CAN и ОАП.xlsx b/doc/setcan/Протокол CAN и ОАП.xlsx index 7ddba5f08aabed041d3dd2b145e341a7c40310b6..f8c0b582ea95639e54e0e0306455ac8fda392b6a 100644 GIT binary patch literal 266313 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�s^T9ueWLlcJ0Me@ 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 literal 103216 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 diff --git a/tools/firmware-build/README.md b/tools/firmware-build/README.md index b86b63e..7e9a7b2 100644 --- a/tools/firmware-build/README.md +++ b/tools/firmware-build/README.md @@ -1,7 +1,57 @@ # Подключение precompile и postcompile из templates +Для проектов ПЛИС используйте [шаблон Xilinx ISE, Vivado и Altera/Intel Quartus](fpga/README.md): +общий сохраняемый итератор, паспорт на Verilog/VHDL, полная сборка `.bit`/`.sof`, +manifest, SHA-256 и архив выпуска. + +## Единая подготовка C2000 для 166/167 и Публикатора SETGUI + +Общая точка входа — `c/firmware-info/tools/c2000_build.py` с командами +`prepare` и `build`. CCS и совместимые `ccs/precompile.bat --identity` / +`ccs/postcompile.bat --identity` вызывают один процесс подготовки. + +`prepare` сохраняет JSON-счётчик старых проектов 166 либо читает ручную версию +из заголовка, заданного в `firmware_build_profile.json` проекта 167. Аппаратный +профиль содержит пути C-заголовков, имена макросов EEPROM и допустимые RAM-адреса +в 16-битных словах C28x. Ёмкость и размер SCI8 выражены в октетах. + +`build` проверяет встроенный паспорт, границу EEPROM, MAP, SHA-256, полноту +SCI8, Flash LOAD/RUN и точное соответствие Flash OUT ↔ Flash RS BIN до сохранения +постоянного выпуска. Проектный `build_flash.py` остаётся аппаратным сборщиком; +общих проверок или сетевых операций в нём нет. + +В текущей 167 каталог результата задан как `Debug/firmware/prepared` либо +`Release/firmware/prepared`; в остальных проектах он задаётся аргументом `--output`. +В этом каталоге создаётся папка +`HASH_дата_UTC+3` с RAM BIN, исходным RAM OUT, `*_flash.out` для JTAG, +`*_flash_rs.bin` для RS, картами, manifest и SHA-256. Flash-файлы создаются +только при наличии проектного `build_flash.py`. `latest_build.json` рядом +с папками указывает точную папку и основной manifest последнего успешного выпуска. + +Дальнейшая публикация выполняется в SETGUI: **Сервис → Прошивка → Публикатор → +Из папки postbuild / manifest → Импорт папки postbuild**. Выбирайте папку одной +сборки, указанную в `latest_build.json`. Для Flash по RS выбирайте manifest +`*_flash_rs.bin.manifest.json`; для JTAG можно выбрать основной RAM BIN manifest, +поскольку полный комплект содержит подписанный Flash OUT. Публикатор выбирает +Flash OUT по `execution=FLASH` и `image_format=COFF`, сохраняя соседний RAM OUT. +Проверьте назначение загрузчика и предпросмотр, затем публикуйте через штатное +хранилище Публикатора. Команды подготовки сами не создают сетевой выпуск. + +Ниже сохранены команды подключения старых проектов. Дополнительный аргумент +`export` остаётся совместимым локальным копированием; новые проекты могут +передавать готовый комплект прямо Публикатору без этого аргумента. + ## Пути на этом компьютере +Самостоятельные постоянные CAN-загрузчики **F28335_CAN_AB** и **F2812_CAN_NOR** +имеют собственные prebuild/postbuild в Debug и Release. Они вызывают общий +`c/protocan-boot/projects/build.py`, проверяют Flash COFF через TI `ofd2000` и +автоматически копируют OUT/MAP, manifest, SHA-256 и метаданные в +`SETGUI/..periph_28335/firmware/periph28335/balzam167/canboot/28335/HASH_дата_UTC+3` +и `.../canboot/2812/HASH_дата_UTC+3` соответственно. +Команды, переопределение пути и структура результата описаны в +[инструкции CCS-проектов ProtoCAN Boot](../../c/protocan-boot/projects/README.md#prebuildpostbuild-и-копирование-в-setgui). + | Назначение | Полный путь | |---|---| | Корень общей библиотеки templates | `K:\git_project\newProject\templates` | @@ -307,3 +357,46 @@ firmware/ ## Совместимость со старыми проектами Вызовы BAT без `--identity` сохранены для уже настроенных проектов: прежний precompile генерирует только build ID, прежний postcompile запускает SETGUI preflight по release-конфигурации. Эта отдельная схема описана в [инструкции публикатора](../firmware-publish/README.md). Для новых CCS и Keil используйте приведённые выше команды с `--identity`. + +## Автоматический CAN BIN вместе с Flash + +Защищённый `c/firmware-info/tools/c2000_build.py build`, вызываемый из CCS +postbuild и `postcompile.bat --identity`, дополнительно создаёт CAN-вариант, +если проект явно задаёт `can_boot_profile` равным `f28335-m95m02-ab` +в `firmware_build_profile.json` и выбрана EEPROM M95M02. +Для AT25256B этот A/B-профиль отключён. Старые проекты без поля сохраняют +прежний состав выпуска. Изменение CAN-профиля требует нового prebuild и сборки. + +В одном выпуске сохраняются: + +| Файл | Назначение | +|---|---| +| `eeprom/_.bin` | Основной SCI8 RAM/EEPROM-образ | +| `can/__can.bin` | ProtoCAN Boot, M95M02 A/B, RAM-приложение | +| `flash/_flash.out` | Внутренняя Flash через JTAG, если проект имеет build_flash.py | +| `rs/_flash_rs.bin` | Обновление внутренней Flash по RS из того же Flash OUT | + +CAN BIN содержит точные байты проверенного RAM SCI8. Отдельно проверяются +предел 130560 октетов, максимум 64 секции, адреса RAM `[0x8000,0xE000)`, +entry, встроенный паспорт и экспортированные CAN hooks Init/Ready/Service/RxISR +в загружаемом payload. Flash-таблица не допускается как CAN BIN. +Каждый вариант получает собственные manifest и SHA-256. CAN-файл и оба +sidecar добавляются в тот же архив сборки и проходят штатный экспорт в GUI. +При отказе проверки CAN или обязательного Flash-варианта новая попытка +не копируется в постоянный output/export. Сетевая публикация и запись платы +этой командой не выполняются. + +Защищённый C2000 postbuild располагает образы, их manifest, SHA-256 и карты +в папках `eeprom`, `flash`, `can`, `rs` как непосредственно в `--output`, так +и внутри архива `HASH_дата_UTC+3`. При `--export` весь архив переносится +в SETGUI с той же структурой. Общий `firmware_identity.json` остаётся +в корне архива; `latest_build.json` указывает manifest с относительным +путём `eeprom/_.bin.manifest.json`. Папка +неподдержанного варианта не создаётся. Низкоуровневые конверторы и другие +семейства MCU сохраняют прежний контракт своих результатов. + +В SETGUI можно импортировать корень одной сборки или выбрать её папку +`eeprom`, `can`, `rs`. Основной BIN определяется выбранным паспортом, +а ZIP сохраняет все назначения этой компиляции. Для JTAG выберите +совместимый загрузчик полного комплекта: он возьмёт подписанный OUT +из `flash`. Старые плоские комплекты также поддерживаются. From 41f5b879fc948487235b8bee15838d13b3307839 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Oct 2026 16:15:11 +0300 Subject: [PATCH 14/18] =?UTF-8?q?=D0=9E=D0=B1=D1=8A=D0=B5=D0=B4=D0=B8?= =?UTF-8?q?=D0=BD=D0=B8=20Modbus=20=D0=B2=20=D0=BE=D0=B4=D0=B8=D0=BD=20?= =?UTF-8?q?=D1=82=D0=B8=D0=BF=20=D1=81=20=D1=84=D1=83=D0=BD=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=D0=BC=D0=B8=20=D0=B8=20=D0=BA=D0=BE=D0=BB=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=BE=D0=BC=201=E2=80=934?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/set-protocol/include/pcan_id.h | 24 +- c/set-protocol/include/pcan_modbus_server.h | 9 +- .../setcorp/setflash/core/ProtoCanCatalog.kt | 10 +- .../setflash/core/ProtoCanCatalogTest.kt | 6 +- c/set-protocol/ports/stm32-bxcan/protocan.c | 267 +++--------------- c/set-protocol/ports/stm32-bxcan/protocan.h | 18 +- c/set-protocol/src/pcan_modbus_server.c | 31 +- c/set-protocol/tests/test_modbus_server.c | 58 +++- c/set-protocol/tests/test_transport.c | 2 +- python/logic_analyzer/decoders/set_can.py | 14 +- python/protocan/protocan.py | 105 ++++--- python/set_devices/bus_demo.py | 4 +- .../set_devices/qt_ports/can_frame_builder.py | 15 +- python/tests/test_modbus_unified.py | 38 +++ 14 files changed, 247 insertions(+), 354 deletions(-) create mode 100644 python/tests/test_modbus_unified.py diff --git a/c/set-protocol/include/pcan_id.h b/c/set-protocol/include/pcan_id.h index b4e9e4d..753639f 100644 --- a/c/set-protocol/include/pcan_id.h +++ b/c/set-protocol/include/pcan_id.h @@ -47,9 +47,7 @@ typedef enum { PCAN_MSG_ANALOG = 0x2U, PCAN_MSG_GAS = 0x3U, /**< общее адресное пространство */ PCAN_MSG_GAS_SLOT = 0x4U, /**< Слотный GAS с маской слов; код 0x4 освобождён от Modbus Coil. */ - PCAN_MSG_MODBUS_DISCR = 0x5U, - PCAN_MSG_MODBUS_HOLDING = 0x6U, - PCAN_MSG_MODBUS_INPUT = 0x7U, + PCAN_MSG_MODBUS = 0x5U, /**< Единый Modbus; банк выбирается функцией 1…4 в MsgBody, коды 0x6/0x7 свободны. */ PCAN_MSG_ERROR = 0x8U, PCAN_MSG_PULSE = 0xFU } pcan_msgtype_t; @@ -81,11 +79,21 @@ static inline uint16_t pcan_body_typed(uint_least8_t type, uint16_t body) /* Н return (uint16_t)(((uint16_t)(type & 0x0FU) << 12) | (body & 0x0FFFU)); } -/** MODBUS: StrAdr[15:4], RegCount[3:0]. */ -static inline uint16_t pcan_body_modbus(uint16_t addr, uint_least8_t count) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ -{ - return (uint16_t)(((addr & 0x0FFFU) << 4) | (count & 0x0FU)); -} +/** MODBUS: StrAdr[15:4], Function-1[3:2], RegCount-1[1:0]; вызывающий проверяет адрес 0…4095 и значения 1…4. */ +static inline uint16_t pcan_body_modbus(uint16_t addr, uint_least8_t count, uint_least8_t function) /* Два двухбитных поля кодируют четыре функции и четыре количества без потери 12-битного адреса. */ +{ /* Упаковка применяется после проверки диапазонов параметров на стороне клиента. */ + return (uint16_t)(((addr & 0x0FFFU) << 4) | (((function - 1U) & 3U) << 2) | ((count - 1U) & 3U)); /* 0xFFF ограничивает адрес 12 битами; смещение на единицу переводит значения 1…4 в wire-коды 0…3. */ +} /* Конец упаковки единого Modbus типа 0x5. */ + +static inline uint_least8_t pcan_modbus_count(uint16_t body) /* Возвращает физическое количество регистров или битов из двух младших битов Body. */ +{ /* Каждый двухбитный wire-код имеет допустимое значение. */ + return (uint_least8_t)((body & 3U) + 1U); /* Маска 3 выделяет биты 1:0; прибавление единицы восстанавливает диапазон 1…4. */ +} /* Конец извлечения количества. */ + +static inline uint_least8_t pcan_modbus_function(uint16_t body) /* Возвращает номер функции: Coil=1, Discrete=2, Holding=3, Input=4. */ +{ /* Функция занимает два бита между адресом и количеством. */ + return (uint_least8_t)(((body >> 2) & 3U) + 1U); /* Сдвиг выделяет биты 3:2; wire-коды 0…3 соответствуют функциям 1…4. */ +} /* Конец извлечения функции. */ /** ERROR: Info[15:8], Code[7:0]. */ static inline uint16_t pcan_body_error(uint_least8_t info, uint_least8_t code) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */ diff --git a/c/set-protocol/include/pcan_modbus_server.h b/c/set-protocol/include/pcan_modbus_server.h index f6874b9..088e43d 100644 --- a/c/set-protocol/include/pcan_modbus_server.h +++ b/c/set-protocol/include/pcan_modbus_server.h @@ -21,9 +21,10 @@ extern "C" { #endif typedef enum { - PCAN_MODBUS_DISCRETE = 0x5U, - PCAN_MODBUS_HOLDING = 0x6U, - PCAN_MODBUS_INPUT = 0x7U + PCAN_MODBUS_COIL = 1U, /* Функция 1 выбирает банк дискретных выходов. */ + PCAN_MODBUS_DISCRETE = 2U, /* Функция 2 выбирает банк дискретных входов. */ + PCAN_MODBUS_HOLDING = 3U, /* Функция 3 выбирает банк изменяемых 16-битных регистров. */ + PCAN_MODBUS_INPUT = 4U /* Функция 4 выбирает банк входных 16-битных регистров. */ } pcan_modbus_bank_t; typedef bool (*pcan_modbus_read_fn)(void *user, pcan_modbus_bank_t bank, @@ -53,7 +54,7 @@ bool pcan_modbus_server_init(pcan_modbus_server_t *server, pcan_modbus_read_fn read, pcan_modbus_write_fn write, void *user); -/** DLC=0 читает DISCRETE/HOLDING/INPUT; данные записывают только HOLDING. Тип 0x4 принадлежит GAS SLOT. */ +/** MsgType=0x5, функция/количество 1…4: DLC=0 читает банк; данные записывают COIL/HOLDING по правилам ProtoCAN. */ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, const pcan_frame_t *request, pcan_frame_t *response); diff --git a/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt b/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt index 7e367a8..74fb702 100644 --- a/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt +++ b/c/set-protocol/ports/android/kotlin/ru/setcorp/setflash/core/ProtoCanCatalog.kt @@ -12,9 +12,7 @@ enum class ProtoCanMessageType(val code: Int, val title: String) { ANALOG(0x2, "Analog"), GENERAL_ADDRESS_SPACE(0x3, "General Address Space"), GAS_SLOT(0x4, "GAS Slot"), // Код 0x4 выбирает слотный GAS с маской, регистровый GAS сохраняет собственный код 0x3. - MODBUS_DISCRETE(0x5, "Modbus Discrete"), - MODBUS_HOLDING(0x6, "Modbus Holding"), - MODBUS_INPUT(0x7, "Modbus Input"), + MODBUS(0x5, "Modbus"), // Функции 1…4 в Body выбирают банк; номера типов 0x6 и 0x7 освобождены. ERROR(0x8, "Error"), BOOT_CONTROL(0x9, "Boot Control"), BOOT_DATA_A(0xA, "Boot Data A"), @@ -63,8 +61,10 @@ object ProtoCanBody { fun typed(type: Int, body: Int): Int = ((type and 0xF) shl 12) or (body and 0xFFF) - fun modbus(address: Int, registerCount: Int): Int = - ((address and 0xFFF) shl 4) or (registerCount and 0xF) + fun modbus(address: Int, registerCount: Int, function: Int): Int { // Явная функция 1…4 выбирает Coil, Discrete, Holding или Input. + require(address in 0..0xFFF && registerCount in 1..4 && function in 1..4 && address + registerCount <= 0x1000) // Проверяем 12-битное окно и два поля без молчаливого усечения. + return (address shl 4) or ((function - 1) shl 2) or (registerCount - 1) // Биты 3:2 содержат функцию минус один, биты 1:0 — количество минус один. + } // Конец упаковки единого Modbus типа 0x5. fun error(info: Int, code: Int): Int = ((info and 0xFF) shl 8) or (code and 0xFF) diff --git a/c/set-protocol/ports/android/tests/ru/setcorp/setflash/core/ProtoCanCatalogTest.kt b/c/set-protocol/ports/android/tests/ru/setcorp/setflash/core/ProtoCanCatalogTest.kt index 4cbc58e..5f032b6 100644 --- a/c/set-protocol/ports/android/tests/ru/setcorp/setflash/core/ProtoCanCatalogTest.kt +++ b/c/set-protocol/ports/android/tests/ru/setcorp/setflash/core/ProtoCanCatalogTest.kt @@ -14,14 +14,14 @@ class ProtoCanCatalogTest { fun bodyLayoutsMatchSetGuiBuilder() { assertEquals(0x1234, ProtoCanBody.broadcast(0x123, 0x4)) assertEquals(0x2001, ProtoCanBody.typed(ProtoCanAnalogType.U.code, 1)) - assertEquals(0x1234, ProtoCanBody.modbus(0x123, 4)) + assertEquals(0x123B, ProtoCanBody.modbus(0x123, 4, 3)) // Holding=3 и четыре регистра кодируются младшим полубайтом 1011. assertEquals(0xABCD, ProtoCanBody.error(0xAB, 0xCD)) assertEquals(0xFF01, ProtoCanBody.settings(0xFF, 0x01)) } @Test - fun messageRegistryCoversAllFourBitValues() { - assertEquals((0..0xF).toList(), ProtoCanMessageType.entries.map { it.code }) + fun messageRegistryReservesFormerModbusTypes() { // После объединения Modbus два кода остаются свободными, остальные сохраняют назначение. + assertEquals((0..0xF).filter { it != 6 && it != 7 }, ProtoCanMessageType.entries.map { it.code }) // Освобождённые MsgType 0x6/0x7 отсутствуют в каталоге после объединения Modbus. assertEquals("Settings", ProtoCanId.parse(0x17FE1234).messageTypeName) } } diff --git a/c/set-protocol/ports/stm32-bxcan/protocan.c b/c/set-protocol/ports/stm32-bxcan/protocan.c index 1bdeca0..3f67d63 100644 --- a/c/set-protocol/ports/stm32-bxcan/protocan.c +++ b/c/set-protocol/ports/stm32-bxcan/protocan.c @@ -178,9 +178,7 @@ void PROTOCAN_LoopProcessRxMsgs(void) { PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); } - else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || /* Тип 0x4 передаётся отдельному слотному обработчику, Modbus начинается с 0x5. */ - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS) /* Единый MsgType 0x5 передаёт функцию 1…4 в Body; 0x6/0x7 больше не относятся к Modbus. */ { PROTOCAN_ModbusProcessing(rxMsg[CurrentStep]); } @@ -237,9 +235,7 @@ PROTOCAN_StatusTypeDef PROTOCAN_ProcessAllRxMsgs(void) { result = PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); } - else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || /* Тип 0x4 передаётся отдельному слотному обработчику, Modbus начинается с 0x5. */ - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS) /* Единый MsgType 0x5 передаёт функцию 1…4 в Body; 0x6/0x7 больше не относятся к Modbus. */ { result = PROTOCAN_ModbusProcessing(rxMsg[CurrentStep]); } @@ -297,9 +293,7 @@ PROTOCAN_StatusTypeDef PROTOCAN_ProcessSingleRxMsg(void) { result = PROTOCAN_SettingsProcessing(rxMsg[CurrentStep]); } - else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE || /* Тип 0x4 передаётся отдельному слотному обработчику, Modbus начинается с 0x5. */ - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || - rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) + else if(rxMsg[CurrentStep].eID.Fields.MsgType == PROTOCAN_MSGTYPE_MODBUS) /* Единый MsgType 0x5 передаёт функцию 1…4 в Body; 0x6/0x7 больше не относятся к Modbus. */ { result = PROTOCAN_ModbusProcessing(rxMsg[CurrentStep]); } @@ -1121,39 +1115,16 @@ PROTOCAN_StatusTypeDef PROTOCAN_SEND_GENERAL_ADDRESS_SPACE(ProtoCanId_t id, uint return (PROTOCAN_StatusTypeDef)HAL_OK; } -/** -* @brief Обработка запроса на основе типа Modbus. -* В зависимости от типа сообщения, вызывает соответствующую функцию -* для отправки Modbus-запроса по CAN-шине. -* @param _rxMsg Структура входящего сообщения RXMsg. -* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). -*/ -PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg _rxMsg) -{ - switch(_rxMsg.eID.Fields.MsgType) - { - case PROTOCAN_MSGTYPE_MODBUS_DISCRETE: - { - return ProtoCanMsgToModbusDiscrete(_rxMsg); - break; - } - case PROTOCAN_MSGTYPE_MODBUS_HOLDING: - { - return ProtoCanMsgToModbusHolding(_rxMsg); - break; - } - case PROTOCAN_MSGTYPE_MODBUS_INPUT: - { - return ProtoCanMsgToModbusInput(_rxMsg); - break; - } - default: - //ERROR - return PROTOCAN_ERROR; - break; - } - return PROTOCAN_ERROR; -} +PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg message) /* Проверяем общий контракт перед передачей единому обработчику приложения. */ +{ /* Битовая функция и количество извлекаются переносимыми помощниками, без зависимости от C bitfields. */ + unsigned count = pcan_modbus_count((uint16_t)message.eID.Fields.MsgBody); /* Wire-код 0…3 преобразуется в физическое количество 1…4. */ + unsigned function = pcan_modbus_function((uint16_t)message.eID.Fields.MsgBody); /* Функции 1/2 выбирают биты, 3/4 — 16-битные регистры. */ + unsigned expected = function <= 2U ? 1U : count * 2U; /* Битовому банку нужен один октет, регистровому — два октета на слово. */ + if (message.eID.Fields.MsgType != PROTOCAN_MSGTYPE_MODBUS || !message.info.EXT || message.info.RTR || (message.eID.Fields.MsgBody >> 4U) + count > 0x1000U) return PROTOCAN_ERROR; /* Отвергаем чужой формат и выход окна за 12-битное адресное пространство. */ + if (message.DLC != 0U && message.DLC != expected) return PROTOCAN_ERROR; /* Непустой payload должен точно соответствовать функции и количеству. */ + if (message.DLC != 0U && function <= 2U && (message.Data[0] >> count) != 0U) return PROTOCAN_ERROR; /* За пределами запрошенных 1…4 битов нет значащих данных. */ + return ProtoCanMsgToModbus(message); /* Приложение получает единый тип сообщения и само выбирает карту по функции. */ +} /* Конец проверки и диспетчеризации единого Modbus. */ static const pcan_gas_slot_port_t *gas_slot_port; /* Provider принадлежит приложению; NULL означает, что слотный сервис ещё не подключён. */ void PROTOCAN_GAS_SLOT_BIND(const pcan_gas_slot_port_t *port) /* Вызывать при инициализации до обработки очереди CAN. */ @@ -1187,187 +1158,35 @@ __weak PROTOCAN_StatusTypeDef ProtoCanMsgToGasSlot(struct RXMsg message) /* Пр } /* Завершаем отправку сформированного ответа. */ } /* Конец стандартного адаптера слотного GAS. */ -/** -* @brief __weak Функция отправки ответа на запрос Discrete Modbus по CAN. -* Формирует CAN ответ на запрос Discrete Modbus и отправляет его. -* @param _rxMsg Структура входящего сообщения RXMsg. -* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). -*/ -__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusDiscrete(struct RXMsg _rxMsg) -{ - CAN_TxHeaderTypeDef TxHeader; - uint32_t TxMailBox = 0; - uint8_t data[8]; - TxHeader.IDE = CAN_ID_EXT; - TxHeader.TransmitGlobalTime = DISABLE; - TxHeader.RTR = CAN_RTR_DATA; - ProtoCanId_t tmp_eID; - tmp_eID.BitAll = _rxMsg.eID.BitAll; - tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; - TxHeader.ExtId = PROTOCAN_IdPack(&tmp_eID); - TxHeader.DLC = 8; - msgBodyModbusType msg; - msg.Body = _rxMsg.eID.Fields.MsgBody; - data[0] = 'M'; - data[1] = 'D'; - data[2] = ' '; - data[3] = 'S'; - data[4] = msg.Fields.StrAdr; - data[5] = ' '; - data[6] = 'C'; - data[7] = msg.Fields.RegCount; - return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); -} +__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbus(struct RXMsg message) /* Приложение переопределяет одну точку для функций 1…4. */ +{ /* Без прикладной карты регистров возвращаем штатную ошибку необработанного запроса. */ + return PROTOCAN_RequestError(message); /* Не публикуем демонстрационные ASCII-байты как реальные значения Modbus. */ +} /* Конец стандартного обработчика неподключённой карты. */ -/** -* @brief __weak Функция отправки ответа на запрос Holding Modbus по CAN. -* Формирует CAN ответ на запрос Holding Modbus и отправляет его. -* @param _rxMsg Структура входящего сообщения RXMsg. -* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). -*/ -__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusHolding(struct RXMsg _rxMsg) -{ - CAN_TxHeaderTypeDef TxHeader; - uint32_t TxMailBox = 0; - uint8_t data[8]; - TxHeader.IDE = CAN_ID_EXT; - TxHeader.TransmitGlobalTime = DISABLE; - TxHeader.RTR = CAN_RTR_DATA; - ProtoCanId_t tmp_eID; - tmp_eID.BitAll = _rxMsg.eID.BitAll; - tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; - TxHeader.ExtId = PROTOCAN_IdPack(&tmp_eID); - TxHeader.DLC = 8; - msgBodyModbusType msg; - msg.Body = _rxMsg.eID.Fields.MsgBody; - data[0] = 'M'; - data[1] = 'H'; - data[2] = ' '; - data[3] = 'S'; - data[4] = msg.Fields.StrAdr; - data[5] = ' '; - data[6] = 'C'; - data[7] = msg.Fields.RegCount; - return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); -} - -/** -* @brief __weak Функция отправки ответа на запрос Input Modbus по CAN. -* Формирует CAN ответ на запрос Input Modbus и отправляет его. -* @param _rxMsg Структура входящего сообщения RXMsg. -* @return HAL_StatusTypeDef Статус выполнения команды CAN (успех или ошибка). -*/ -__weak PROTOCAN_StatusTypeDef ProtoCanMsgToModbusInput(struct RXMsg _rxMsg) -{ - CAN_TxHeaderTypeDef TxHeader; - uint32_t TxMailBox = 0; - uint8_t data[8]; - TxHeader.IDE = CAN_ID_EXT; - TxHeader.TransmitGlobalTime = DISABLE; - TxHeader.RTR = CAN_RTR_DATA; - ProtoCanId_t tmp_eID; - tmp_eID.BitAll = _rxMsg.eID.BitAll; - tmp_eID.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE; - TxHeader.ExtId = PROTOCAN_IdPack(&tmp_eID); - TxHeader.DLC = 8; - msgBodyModbusType msg; - msg.Body = _rxMsg.eID.Fields.MsgBody; - data[0] = 'M'; - data[1] = 'I'; - data[2] = ' '; - data[3] = 'S'; - data[4] = msg.Fields.StrAdr; - data[5] = ' '; - data[6] = 'C'; - data[7] = msg.Fields.RegCount; - return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &TxHeader, data, &TxMailBox); -} - -/** - * @brief Отправляет данные Modbus через CAN-шину в соответствии с типом сообщения. - * Эта функция формирует и отправляет Modbus-данные по CAN-шине, поддерживая - * различные типы сообщений: Coil, Discrete, Holding Register и Input Register. - * Для сообщений, превышающих 4 регистров, данные отправляются пакетами. - * @param id Идентификатор сообщения, содержащий тип сообщения и другую информацию. - * @param modbusData Структура с данными Modbus: адрес, количество регистров и сами данные. - * @return PROTOCAN_StatusTypeDef Статус операции. - * @details - * В зависимости от типа Modbus (discrete или holding/input), формируется - * соответствующий CAN-пакет. Для discrete отправляется один пакет, для holding/input — - * несколько, по 4 регистра в пакете. В случае ошибок при добавлении сообщения API HAL возвращается ошибка. - */ -PROTOCAN_StatusTypeDef PROTOCAN_SEND_MODBUS(const ProtoCanId_t id, const struct ProtoCanModbusData modbusData) -{ - ProtoCanId_t localId = id; - uint8_t msgType = localId.Fields.MsgType; - // Структура для отправки - CAN_TxHeaderTypeDef TxHeader; - uint32_t TxMailBox = 0; - uint8_t canData[8]; - if(msgType == PROTOCAN_MSGTYPE_MODBUS_DISCRETE) /* Битовая ветвь Modbus поддерживает только входы 0x5; 0x4 зарезервирован слотному GAS. */ - { - // Формируем body - msgBodyModbusType body; - body.Fields.StrAdr = modbusData.StrAdr; - body.Fields.RegCount = modbusData.RegCount; - // Устанавливаем коллизию ExtId с body.Body - localId.Fields.MsgBody = (body.Body & 0xFFFF); - // Обновляем ExtId - TxHeader.ExtId = PROTOCAN_IdPack(&localId); - // Остальные настройки - TxHeader.IDE = CAN_ID_EXT; - TxHeader.RTR = CAN_RTR_DATA; - TxHeader.TransmitGlobalTime = DISABLE; - TxHeader.DLC = modbusData.RegCount % 8 + 1; - // Формируем CAN данные - canData[0] = LowByteOfWord(modbusData.Data[0]); - canData[1] = HighByteOfWord(modbusData.Data[0]); - if (HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK) - { - return PROTOCAN_ERROR; - } - } - else if(msgType == PROTOCAN_MSGTYPE_MODBUS_HOLDING || msgType == PROTOCAN_MSGTYPE_MODBUS_INPUT) - { - uint16_t* dataPtr = modbusData.Data; - unsigned totalRegs = modbusData.RegCount; - unsigned regsProcessed = 0; - unsigned startAddress = modbusData.StrAdr; - while (regsProcessed < totalRegs) - { - uint8_t regsInPacket = (totalRegs - regsProcessed) > 4 ? 4 : (totalRegs - regsProcessed); - // Формируем body - msgBodyModbusType body; - body.Fields.StrAdr = startAddress; - body.Fields.RegCount = regsInPacket; - // Обновляем ExtId - localId.Fields.MsgBody = (body.Body & 0xFFFF); - TxHeader.ExtId = PROTOCAN_IdPack(&localId); - TxHeader.IDE = CAN_ID_EXT; - TxHeader.RTR = CAN_RTR_DATA; - TxHeader.TransmitGlobalTime = DISABLE; - TxHeader.DLC = regsInPacket * 2; - // Добавляем регистры - for (int i = 0; i < regsInPacket; i++) - { - canData[i * 2] = LowByteOfWord(dataPtr[regsProcessed + i]); - canData[i * 2 + 1] = HighByteOfWord(dataPtr[regsProcessed + i]); - } - // Отправляем сообщение - if(HAL_CAN_AddTxMessage(_HCAN, &TxHeader, canData, &TxMailBox) != HAL_OK) - { - return PROTOCAN_ERROR; - } - regsProcessed += regsInPacket; - startAddress += regsInPacket; - } - } - else - { - return PROTOCAN_ERROR; // Неверный тип сообщения - } - return PROTOCAN_OK; -} +PROTOCAN_StatusTypeDef PROTOCAN_SEND_MODBUS(const ProtoCanId_t id, const struct ProtoCanModbusData data) /* Отправляет одно окно из 1…4 битов или регистров. */ +{ /* Вся полезная нагрузка помещается в один classic CAN-кадр с DLC не более восьми. */ + ProtoCanId_t local = id; /* Сохраняем исходный адрес узла, приоритет и направление. */ + CAN_TxHeaderTypeDef header = {0}; /* Нулевая инициализация исключает неопределённые поля HAL-заголовка. */ + uint32_t mailbox = 0U; /* HAL запишет номер использованного аппаратного mailbox. */ + uint8_t bytes[8] = {0}; /* Максимум четыре 16-битных регистра занимают восемь октетов. */ + unsigned index; /* Индекс ограничен проверенным количеством регистров 1…4. */ + if (_HCAN == NULL || local.Fields.MsgType != PROTOCAN_MSGTYPE_MODBUS || data.Function < 1U || data.Function > 4U || data.RegCount < 1U || data.RegCount > 4U || data.StrAdr > 0xFFFU || data.StrAdr + data.RegCount > 0x1000U) return PROTOCAN_ERROR; /* Не отправляем неинициализированный CAN или значения за пределами wire-полей. */ + if (data.Data == NULL && local.Fields.Route == PROTOCAN_ROUTE_FROM_DEVICE) return PROTOCAN_ERROR; /* Устройство не отправляет пустые ответы вместо запрошенных значений. */ + local.Fields.MsgBody = pcan_body_modbus(data.StrAdr, (uint_least8_t)data.RegCount, (uint_least8_t)data.Function); /* Общий упаковщик помещает функцию минус один в 3:2, количество минус один в 1:0. */ + header.ExtId = PROTOCAN_IdPack(&local); /* Используем явную переносимую упаковку всех полей CAN ID. */ + header.IDE = CAN_ID_EXT; header.RTR = CAN_RTR_DATA; header.TransmitGlobalTime = DISABLE; /* ProtoCAN передаётся расширенным data frame без RTR. */ + header.DLC = data.Data == NULL ? 0U : (data.Function <= 2U ? 1U : data.RegCount * 2U); /* NULL запрашивает чтение; непустой буфер содержит один октет битов либо 2…8 октетов регистров. */ + if (data.Data != NULL && data.Function <= 2U) { /* Битовые банки используют младшие биты первого слова, как и переносимый сервер. */ + if ((data.Data[0] >> data.RegCount) != 0U) return PROTOCAN_ERROR; /* Не усекаем установленные биты за пределами запрошенного окна. */ + bytes[0] = (uint8_t)data.Data[0]; /* Для 1…4 битов достаточно одного wire-октета. */ + } else if (data.Data != NULL) { /* Слова Holding/Input кодируются little-endian. */ + for (index = 0U; index < data.RegCount; ++index) { /* Каждому адресу соответствует ровно одно 16-битное слово. */ + bytes[index * 2U] = (uint8_t)data.Data[index]; /* Младший октет располагается первым в payload. */ + bytes[index * 2U + 1U] = (uint8_t)(data.Data[index] >> 8U); /* Сдвиг на восемь бит извлекает старший октет регистра. */ + } /* Заканчиваем упаковку проверенного числа регистров. */ + } /* Для запроса чтения массив остаётся пустым, поскольку DLC равен нулю. */ + return (PROTOCAN_StatusTypeDef)HAL_CAN_AddTxMessage(_HCAN, &header, bytes, &mailbox); /* Возвращаем фактический результат постановки одного кадра в очередь HAL. */ +} /* Конец отправки единого Modbus типа 0x5. */ /** * @brief __weak Функция отправки сообщения об ошибке. @@ -1655,9 +1474,7 @@ PROTOCAN_StatusTypeDef PROTOCAN_SEND(ProtoCanId_t id, ProtoCanData_t data) } case PROTOCAN_MSGTYPE_GAS_SLOT: /* Отправка 0x4 использует служебную маску, а не структуру Modbus. */ return PROTOCAN_SEND_GAS_SLOT(id, data.GasSlotData.Address, data.GasSlotData.Words, data.GasSlotData.Count); /* Count=0 запрашивает чтение; Count=4 передаёт маску и три значения. */ - case PROTOCAN_MSGTYPE_MODBUS_DISCRETE: - case PROTOCAN_MSGTYPE_MODBUS_HOLDING: - case PROTOCAN_MSGTYPE_MODBUS_INPUT: + case PROTOCAN_MSGTYPE_MODBUS: /* Все четыре банка отправляются одним типом, функция задаётся в ModbusData. */ { return PROTOCAN_SEND_MODBUS(id, data.ModbusData); break; diff --git a/c/set-protocol/ports/stm32-bxcan/protocan.h b/c/set-protocol/ports/stm32-bxcan/protocan.h index 08636bc..5e30422 100644 --- a/c/set-protocol/ports/stm32-bxcan/protocan.h +++ b/c/set-protocol/ports/stm32-bxcan/protocan.h @@ -84,9 +84,7 @@ typedef enum { PROTOCAN_MSGTYPE_ANALOG = 0b0010, /**< Аналоговое сообщение. */ PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE = 0b0011, /**< Сообщение общего адресного пространства. */ PROTOCAN_MSGTYPE_GAS_SLOT = 0b0100, /**< Слотный GAS: Word0 — маска, Word1…Word3 — значения; прежний код Coil заменён. */ - PROTOCAN_MSGTYPE_MODBUS_DISCRETE = 0b0101, /**< Сообщение Modbus - Discrete. */ - PROTOCAN_MSGTYPE_MODBUS_HOLDING = 0b0110, /**< Сообщение Modbus - Holding. */ - PROTOCAN_MSGTYPE_MODBUS_INPUT = 0b0111, /**< Сообщение Modbus - Input. */ + PROTOCAN_MSGTYPE_MODBUS = 0b0101, /**< Единый Modbus с функцией 1…4 в Body; номера 0x6/0x7 свободны. */ PROTOCAN_MSGTYPE_ERROR = 0b1000, /**< Сообщение об ошибке. */ PROTOCAN_MSGTYPE_BOOT_CONTROL = 0b1001, /**< Команды ProtoCAN Boot. */ PROTOCAN_MSGTYPE_BOOT_DATA_A = 0b1010, /**< Блок образа для слота A. */ @@ -225,7 +223,8 @@ typedef union{ */ typedef union{ struct msgBody_Modbus{ - unsigned RegCount:4; /**< Количество регистров (4 бита). */ + unsigned RegCountMinus1:2; /**< Биты 1:0 хранят количество регистров или битов минус один, wire-коды 0…3. */ + unsigned FunctionMinus1:2; /**< Биты 3:2 хранят функцию Coil=1, Discrete=2, Holding=3, Input=4 минус один. */ unsigned StrAdr:12; /**< Адрес строки или регистра (12 бит). */ } Fields; /**< Поля структуры сообщения Modbus. */ unsigned Body; /**< Общее 16-битное представление сообщения. */ @@ -321,9 +320,10 @@ typedef struct{ unsigned Count; /* Ноль означает чтение, четыре — маску и три значения; другие размеры отвергает C-кодек. */ } GasSlotData; /* Член структуры используется только для MsgType=0x4. */ struct ProtoCanModbusData{ - uint16_t StrAdr; - uint16_t *Data; - unsigned RegCount:4; + uint16_t StrAdr; /* Адрес первого регистра или бита 0…4095; всё окно должно помещаться в этот диапазон. */ + uint16_t *Data; /* NULL запрашивает чтение; битовые банки используют упакованную маску в Data[0], регистровые — массив слов. */ + unsigned RegCount; /* Физическое количество 1…4; обычное поле позволяет отклонить неверный ввод до упаковки. */ + unsigned Function; /* Физический номер функции 1…4, независимый от единого MsgType=0x5. */ } ModbusData; struct ProtoCanErrorData{ uint16_t Info; @@ -431,9 +431,7 @@ PROTOCAN_StatusTypeDef PROTOCAN_ModbusProcessing(struct RXMsg _rxMsg); void PROTOCAN_GAS_SLOT_BIND(const pcan_gas_slot_port_t *port); /* Подключает долгоживущий provider слотов до обработки очереди; NULL отключает сервис. */ PROTOCAN_StatusTypeDef ProtoCanMsgToGasSlot(struct RXMsg message); /* Передаёт тип 0x4 общему обработчику с проверкой адреса узла и маски Word0. */ PROTOCAN_StatusTypeDef PROTOCAN_SEND_GAS_SLOT(ProtoCanId_t id, uint16_t address, const uint16_t *words, unsigned count); /* Отправляет один слот через общий C-кодек, без Modbus-упаковки адреса. */ -PROTOCAN_StatusTypeDef ProtoCanMsgToModbusDiscrete(struct RXMsg _rxMsg); -PROTOCAN_StatusTypeDef ProtoCanMsgToModbusHolding(struct RXMsg _rxMsg); -PROTOCAN_StatusTypeDef ProtoCanMsgToModbusInput(struct RXMsg _rxMsg); +PROTOCAN_StatusTypeDef ProtoCanMsgToModbus(struct RXMsg _rxMsg); /* Единая weak-точка приложения обрабатывает все четыре банка по полю функции Body. */ void PROTOCAN_RTC_SYNC(uint8_t *data); diff --git a/c/set-protocol/src/pcan_modbus_server.c b/c/set-protocol/src/pcan_modbus_server.c index f0107df..38758fb 100644 --- a/c/set-protocol/src/pcan_modbus_server.c +++ b/c/set-protocol/src/pcan_modbus_server.c @@ -10,12 +10,6 @@ #include "pcan_id.h" -static bool is_bank(uint8_t value) -{ - return (value >= (uint8_t)PCAN_MODBUS_DISCRETE) && /* Диапазон Modbus начинается с 0x5: тип 0x4 занят слотным GAS и не должен вызывать Modbus callbacks. */ - (value <= (uint8_t)PCAN_MODBUS_INPUT); /* Сохраняем существующие номера HOLDING=0x6 и INPUT=0x7 без сдвига адресации. */ -} - bool pcan_modbus_server_init(pcan_modbus_server_t *server, uint8_t device_type, uint8_t device_id, pcan_modbus_read_fn read, @@ -58,15 +52,15 @@ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, pcan_id_unpack(request->id, &id); if ((id.route != PCAN_ROUTE_FROM_PM) || (id.device_type != server->device_type) || - (id.device_id != server->device_id) || !is_bank(id.msg_type)) { + (id.device_id != server->device_id) || (id.msg_type != PCAN_MSG_MODBUS)) { /* Только единый тип 0x5 адресует Modbus; 0x4, 0x6 и 0x7 не вызывают provider. */ return PCAN_MODBUS_NOT_FOR_US; } server->requests++; address = (uint16_t)(id.msg_body >> 4U); - count = (uint8_t)(id.msg_body & 0x0FU); - bank = (pcan_modbus_bank_t)id.msg_type; - if (count == 0U) { + count = (uint8_t)pcan_modbus_count(id.msg_body); /* Два младших бита хранят количество минус один, поэтому нулевого запроса больше нет. */ + bank = (pcan_modbus_bank_t)pcan_modbus_function(id.msg_body); /* Биты 3:2 выбирают банк Coil/Discrete/Holding/Input через функцию 1…4. */ + if ((address + count > 0x1000U) || (request->dlc > 8U) || ((request->flags & PCAN_FLAG_RTR) != 0U)) { /* Диапазон не пересекает границу 4096 адресов; поддерживаются только classic data frames. */ return reject(server); } @@ -78,10 +72,7 @@ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, if (request->dlc == 0U) { uint16_t packed = 0U; - if (bank == PCAN_MODBUS_DISCRETE) { /* Только тип 0x5 передаёт битовые входы; 0x4 обрабатывается отдельным GAS-кодеком. */ - if (count > 16U) { - return reject(server); - } + if ((bank == PCAN_MODBUS_COIL) || (bank == PCAN_MODBUS_DISCRETE)) { /* Функции 1 и 2 возвращают до четырёх последовательных битов в одном октете. */ for (uint8_t index = 0U; index < count; ++index) { uint16_t value = 0U; if (!server->read(server->user, bank, @@ -92,9 +83,8 @@ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, packed |= (uint16_t)(1U << index); } } - response->dlc = 2U; + response->dlc = 1U; /* Для 1…4 битов достаточно одного октета; старшие биты остаются нулевыми. */ response->data[0] = (uint8_t)packed; - response->data[1] = (uint8_t)(packed >> 8U); } else { if (count > 4U) { return reject(server); @@ -111,11 +101,16 @@ pcan_modbus_result_t pcan_modbus_server_handle(pcan_modbus_server_t *server, } } } else { - if ((bank == PCAN_MODBUS_INPUT) || (bank == PCAN_MODBUS_DISCRETE) || + if ((bank == PCAN_MODBUS_INPUT) || (bank == PCAN_MODBUS_DISCRETE) || /* Входные банки функций 2 и 4 сохраняют запрет записи. */ (server->write == NULL)) { return reject(server); } - { /* После проверки readonly-банков запись возможна только в HOLDING; битовая запись бывшего 0x4 удалена. */ + if (bank == PCAN_MODBUS_COIL) { /* ProtoCAN выбирает запись по непустому payload, сохраняя номер функции как селектор банка. */ + if ((request->dlc != 1U) || (request->data[0] >> count) != 0U) return reject(server); /* Ровно один октет хранит маску выбранного числа выходов без лишних установленных битов. */ + for (uint8_t index = 0U; index < count; ++index) { /* Выходы записываются по возрастанию адреса начиная с младшего бита маски. */ + if (!server->write(server->user, bank, (uint16_t)(address + index), (uint16_t)((request->data[0] >> index) & 1U))) return reject(server); /* Передаём provider значение 0 или 1 каждого выхода. */ + } /* Все запрошенные выходы обработаны. */ + } else { /* Для Holding сохраняется запись 16-битных значений little-endian. */ if ((count > 4U) || (request->dlc != (uint8_t)(count * 2U))) { return reject(server); } diff --git a/c/set-protocol/tests/test_modbus_server.c b/c/set-protocol/tests/test_modbus_server.c index 75a86d9..55b9189 100644 --- a/c/set-protocol/tests/test_modbus_server.c +++ b/c/set-protocol/tests/test_modbus_server.c @@ -10,18 +10,20 @@ #include "pcan_id.h" #include "pcan_modbus_server.h" -static uint16_t holding[32]; -static uint16_t input[32]; +static uint16_t holding[4096]; /* Полная 12-битная карта позволяет проверить последний допустимый адрес 0xFFF. */ +static uint16_t input[4096]; /* Входной банк имеет тот же размер 4096 адресов, что поле StrAdr. */ +static uint16_t coils = 0x000AU; /* Чередующиеся выходы 1 и 3 отличают функцию Coil=1 от Discrete=2. */ static uint16_t discretes = 0x0014U; /* Входы 2 и 4 установлены для проверки сохранённого битового чтения типа 0x5. */ static bool read_word(void *user, pcan_modbus_bank_t bank, uint16_t address, uint16_t *value) { (void)user; - if (address >= 32U) return false; + if (address >= 4096U) return false; /* Provider не принимает адреса вне 12-битной карты. */ if (bank == PCAN_MODBUS_HOLDING) *value = holding[address]; else if (bank == PCAN_MODBUS_INPUT) *value = input[address]; else if (bank == PCAN_MODBUS_DISCRETE && address < 16U) *value = (uint16_t)((discretes >> address) & 1U); /* Не сдвигаем 16-битное поле на недопустимое число позиций. */ + else if (bank == PCAN_MODBUS_COIL && address < 16U) *value = (uint16_t)((coils >> address) & 1U); /* Функция 1 читает независимую маску выходов. */ else return false; return true; } @@ -30,13 +32,14 @@ static bool write_word(void *user, pcan_modbus_bank_t bank, uint16_t address, uint16_t value) { (void)user; - if (address >= 32U) return false; + if (address >= 4096U) return false; /* Запись ограничена тем же адресным пространством, что чтение. */ if (bank == PCAN_MODBUS_HOLDING) holding[address] = value; - else return false; /* Битовые входы и новый слотный GAS не записываются через Modbus provider. */ + else if (bank == PCAN_MODBUS_COIL && address < 16U) coils = (uint16_t)((coils & ~(1U << address)) | ((value & 1U) << address)); /* Один callback изменяет ровно выбранный выход. */ + else return false; /* Входные банки Discrete/Input недоступны для записи. */ return true; } -static pcan_frame_t request(uint8_t type, uint16_t address, uint8_t count) +static pcan_frame_t request(uint8_t function, uint16_t address, uint8_t count) /* Функция задаёт банк независимо от единого MsgType=0x5. */ { pcan_id_t id = {0}; pcan_frame_t frame = {0}; @@ -44,8 +47,8 @@ static pcan_frame_t request(uint8_t type, uint16_t address, uint8_t count) id.route = PCAN_ROUTE_FROM_PM; id.device_type = 7U; id.device_id = 3U; - id.msg_type = type; - id.msg_body = pcan_body_modbus(address, count); + id.msg_type = PCAN_MSG_MODBUS; /* Все четыре функции используют один код сообщения 0x5. */ + id.msg_body = pcan_body_modbus(address, count, function); /* Передаём физические значения функции и количества 1…4 общему упаковщику. */ frame.id = pcan_id_pack(&id); frame.flags = PCAN_FLAG_IDE; return frame; @@ -83,12 +86,45 @@ int main(void) req = request(PCAN_MODBUS_DISCRETE, 2U, 3U); /* Читаем три входа 2…4 через сохранённый тип 0x5. */ CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_RESPONSE); - CHECK(rsp.dlc == 2U && rsp.data[0] == 0x05U && rsp.data[1] == 0U); /* Маска прочитанных входов должна сохранять порядок младших битов. */ - req = request(PCAN_MSG_GAS_SLOT, 2U, 3U); /* Передаём бывший номер Coil, теперь занятый независимым GAS SLOT. */ + CHECK(rsp.dlc == 1U && rsp.data[0] == 0x05U); /* Три входа передаются младшими битами одного октета. */ + req.id = (req.id & ~0xF0000UL) | ((uint32_t)PCAN_MSG_GAS_SLOT << 16U); /* Подменяем MsgType на независимый GAS SLOT 0x4, сохраняя остальные поля. */ CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_NOT_FOR_US); /* Слотный кадр не должен вызывать Modbus provider и менять его счётчики. */ - req = request(PCAN_MODBUS_INPUT, 0U, 5U); + req = request(PCAN_MODBUS_INPUT, 0xFFFU, 2U); /* Двухрегистровое окно с последнего адреса должно быть отвергнуто до обращения к карте. */ CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_HANDLED_NO_RESPONSE); CHECK(server.requests == 4U && server.responses == 3U && server.rejected == 1U); + for (uint8_t function = 1U; function <= 4U; ++function) { /* Покрываем все четыре банка единого сообщения. */ + for (uint8_t count = 1U; count <= 4U; ++count) { /* Каждая функция проверяется с каждым допустимым количеством. */ + uint16_t expected = (uint16_t)(0x20U | ((function - 1U) << 2U) | (count - 1U)); /* Адрес 2 остаётся в старших 12 битах, функция и количество независимо занимают по два бита. */ + CHECK(pcan_body_modbus(2U, count, function) == expected); /* Проверяем эталонную битовую раскладку всех 16 сочетаний. */ + CHECK(pcan_modbus_count(expected) == count && pcan_modbus_function(expected) == function); /* Декодирование возвращает исходные физические значения 1…4. */ + req = request(function, 2U, count); /* Запрашиваем окно в пределах тестовых битовых и регистровых банков. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_RESPONSE); /* Все допустимые сочетания обслуживаются сервером. */ + CHECK(rsp.dlc == (function <= 2U ? 1U : count * 2U)); /* Функции 1/2 возвращают октет, 3/4 — два октета на слово. */ + pcan_id_unpack(rsp.id, &id); /* Ответ должен сохранять банк и количество исходного запроса. */ + CHECK(id.msg_type == PCAN_MSG_MODBUS && id.msg_body == expected && id.route == PCAN_ROUTE_FROM_DEVICE); /* Меняется только направление сообщения. */ + if (function <= 2U) CHECK(rsp.data[0] == (((function == 1U ? coils : discretes) >> 2U) & ((1U << count) - 1U))); /* Сверяем каждый бит с независимым источником банка. */ + } /* Завершаем перебор количеств для текущей функции. */ + } /* Проверены все шестнадцать вариантов. */ + input[4095] = 0xFEDCU; /* Последний адрес карты содержит отличимое 16-битное значение. */ + req = request(PCAN_MODBUS_INPUT, 4095U, 1U); /* Окно из одного регистра на границе допустимо. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_RESPONSE && rsp.data[0] == 0xDCU && rsp.data[1] == 0xFEU); /* Верхняя граница и little-endian проверяются одновременно. */ + req = request(PCAN_MODBUS_COIL, 2U, 4U); /* Записываем четыре последовательных выхода отдельными битами. */ + req.dlc = 1U; req.data[0] = 0x09U; /* Выходы addr+0 и addr+3 включены, промежуточные выключены. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_RESPONSE && ((coils >> 2U) & 15U) == 9U); /* Provider получает правильные адреса и значения каждого выхода. */ + req.data[0] = 0x10U; /* Пятый бит не входит в заявленное четырёхбитное окно. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_HANDLED_NO_RESPONSE && ((coils >> 2U) & 15U) == 9U); /* Неверная маска отклоняется до изменения выходов. */ + req = request(PCAN_MODBUS_HOLDING, 3U, 2U); req.dlc = 3U; /* Двум регистрам нужны четыре октета; три являются неполным payload. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_HANDLED_NO_RESPONSE && holding[3] == 0x1122U); /* Неверная длина не меняет уже записанные значения. */ + for (uint8_t function = 2U; function <= 4U; function += 2U) { /* Функции входных банков 2 и 4 доступны только для чтения. */ + req = request(function, 2U, 1U); req.dlc = function == 2U ? 1U : 2U; /* Подготавливаем формально правильный payload записи readonly-банка. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_HANDLED_NO_RESPONSE); /* Сервер отвергает запись независимо от длины данных. */ + } /* Оба входных банка защищены. */ + req = request(PCAN_MODBUS_HOLDING, 0U, 1U); req.flags |= PCAN_FLAG_RTR; /* Remote frame не несёт разрешённого data payload ProtoCAN. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_HANDLED_NO_RESPONSE); /* RTR отвергается до чтения банка. */ + for (uint8_t type = 6U; type <= 7U; ++type) { /* Старые отдельные типы Holding/Input освобождены. */ + req = request(PCAN_MODBUS_HOLDING, 0U, 1U); req.id = (req.id & ~0xF0000UL) | ((uint32_t)type << 16U); /* Сохраняем адрес и Body, изменяя только номер сервиса. */ + CHECK(pcan_modbus_server_handle(&server, &req, &rsp) == PCAN_MODBUS_NOT_FOR_US); /* Освобождённые типы не маршрутизируются в Modbus. */ + } /* Проверены оба освобождённых номера. */ return 0; } diff --git a/c/set-protocol/tests/test_transport.c b/c/set-protocol/tests/test_transport.c index b25bcc3..5ce3b64 100644 --- a/c/set-protocol/tests/test_transport.c +++ b/c/set-protocol/tests/test_transport.c @@ -207,7 +207,7 @@ static void test_id(void) /* Раскладки MsgBody из protocan.h */ CHECK(pcan_body_broadcast(3U, 0U) == 0x0030U); CHECK(pcan_body_typed(4U, 17U) == 0x4011U); - CHECK(pcan_body_modbus(0x100U, 3U) == 0x1003U); + CHECK(pcan_body_modbus(0x100U, 3U, 4U) == 0x100EU); /* Адрес 0x100, функция Input=4 и три регистра дают wire-коды функции 3 и количества 2. */ CHECK(pcan_body_error(0U, 0xFFU) == 0x00FFU); } diff --git a/python/logic_analyzer/decoders/set_can.py b/python/logic_analyzer/decoders/set_can.py index 075623c..9e8e51e 100644 --- a/python/logic_analyzer/decoders/set_can.py +++ b/python/logic_analyzer/decoders/set_can.py @@ -6,8 +6,8 @@ from .set_uart import number, parse_frame TYPES = {0: 'BROADCAST', 1: 'DISCRETE', 2: 'ANALOG', 3: 'GAS', - 4: 'GAS_SLOT', 5: 'MODBUS_DISCRETE', 6: 'MODBUS_HOLDING', # Тип 0x4 теперь означает масочный слотный GAS, номера остальных Modbus-типов сохранены. - 7: 'MODBUS_INPUT', 8: 'ERROR', 9: 'BOOT_CONTROL', 10: 'BOOT_DATA_A', + 4: 'GAS_SLOT', 5: 'MODBUS', # Единый Modbus занимает 0x5, прежние коды 0x6 и 0x7 освобождены. + 8: 'ERROR', 9: 'BOOT_CONTROL', 10: 'BOOT_DATA_A', # Остальные сервисы сохраняют числовые коды. 11: 'BOOT_DATA_B', 12: 'BOOT_STATUS', 13: 'BOOT_DISCOVERY', 15: 'PULSE'} BOOT = dict(enumerate(('IDENTIFY ENTER_BOOT BEGIN_IMAGE BEGIN_COMPAT ERASE VERIFY ' 'COMMIT CONFIRM REBOOT ABORT QUERY_PROGRESS').split(), 1)) @@ -49,8 +49,14 @@ def legacy(ident, data, profile='protocan'): result['mask'] = values[0] if values else None # Пустой запрос чтения не содержит фиктивной маски. result['slot_words'] = [(index, values[index]) for index in range(1, 4) if values and values[0] & (1 << index)] # Публикуем только выбранные или достоверные значения, без служебного Word0. text += ' slot=%04X' % body + (' READ' if not values else ' mask=%04X' % values[0]) # В логе ясно различаются адрес и маска частичной записи. - elif 5 <= msg <= 7: # Диапазон Modbus больше не включает бывший Coil 0x4. - text += ' address=%03X count=%d' % (body >> 4, body & 15) + elif msg == 5: # Modbus использует один тип сообщения и поле функции внутри Body. + from protocan.protocan import decode # Один подробный декодер проверяет длину, диапазон адресов и битовые маски. + decoded = decode(ident, bytes(data)) # Передаём исходный payload без повторной реализации протокольных проверок. + if decoded.warnings: # Некорректные значения должны быть видны вызывающему анализатору. + raise ValueError('; '.join(decoded.warnings)) # Сохраняем подробные сообщения общей реализации. + result['address'], result['count'], result['function'] = body >> 4, (body & 3) + 1, ((body >> 2) & 3) + 1 # Внешний результат содержит физические значения полей 1…4. + result['registers'] = decoded.registers # Для Coil/Discrete публикуются отдельные биты, для Holding/Input — 16-битные слова. + text += ' FC%d address=%03X count=%d' % (result['function'], result['address'], result['count']) # Журнал явно различает четыре банка единого Modbus. elif msg == 8: text += ' info=%02X code=%02X' % (body >> 8, body & 255) elif msg in (9, 12): diff --git a/python/protocan/protocan.py b/python/protocan/protocan.py index da3383e..3a76e3e 100644 --- a/python/protocan/protocan.py +++ b/python/protocan/protocan.py @@ -47,9 +47,7 @@ class MsgType(IntEnum): ANALOG = 0b0010 GENERAL_ADDRESS_SPACE = 0b0011 GAS_SLOT = 0b0100 # Тип 0x4 однозначно выбирает слотный GAS с маской вместо прежнего Modbus Coil. - MODBUS_DISCRETE = 0b0101 - MODBUS_HOLDING = 0b0110 - MODBUS_INPUT = 0b0111 + MODBUS = 0b0101 # Единый тип 0x5 выбирает банк функцией 1…4 в Body; номера 0x6 и 0x7 освобождены. ERROR = 0b1000 BOOT_CONTROL = 0b1001 BOOT_DATA_A = 0b1010 @@ -60,6 +58,13 @@ class MsgType(IntEnum): PULSE = 0b1111 +class ModbusFunction(IntEnum): # Функция единого типа Modbus выбирает один из четырёх банков. + COIL = 1 # Дискретные выходы соответствуют функции 1. + DISCRETE = 2 # Дискретные входы соответствуют функции 2. + HOLDING = 3 # Изменяемые 16-битные регистры соответствуют функции 3. + INPUT = 4 # Входные 16-битные регистры соответствуют функции 4. + + class SettingsResult(IntEnum): OK = 0x00 INVALID_DLC = 0x01 @@ -116,9 +121,7 @@ MSGTYPE_RU = { MsgType.ANALOG: "Analog", MsgType.GENERAL_ADDRESS_SPACE: "General Address Space", MsgType.GAS_SLOT: "GAS Slot", # Отдельное имя показывает, что адрес в Body относится к слоту, а не к Modbus-регистру. - MsgType.MODBUS_DISCRETE: "Modbus Discrete", - MsgType.MODBUS_HOLDING: "Modbus Holding", - MsgType.MODBUS_INPUT: "Modbus Input", + MsgType.MODBUS: "Modbus", # Один тип охватывает Coil, Discrete, Holding и Input через поле функции. MsgType.ERROR: "Error", MsgType.BOOT_CONTROL: "Boot Control", MsgType.BOOT_DATA_A: "Boot Data A", @@ -348,9 +351,8 @@ def split_analog(body: int): return body & 0xFFF, (body >> 12) & 0xF -def split_modbus(body: int): - """MODBUS: RegCount[3:0], StrAdr[15:4].""" - return (body >> 4) & 0xFFF, body & 0xF +def split_modbus(body: int): # Возвращает адрес, количество и функцию в тех же единицах, что принимает упаковщик. + return (body >> 4) & 0xFFF, (body & 3) + 1, ((body >> 2) & 3) + 1 # Адрес занимает 12 бит, два остальных поля кодируются значением минус один. def split_error(body: int): @@ -370,8 +372,10 @@ def merge_analog(an_type: int, sensor_id: int) -> int: return ((an_type & 0xF) << 12) | (sensor_id & 0xFFF) -def merge_modbus(str_adr: int, reg_count: int) -> int: - return ((str_adr & 0xFFF) << 4) | (reg_count & 0xF) +def merge_modbus(str_adr: int, reg_count: int, function: int) -> int: # Функция 1…4 явно задаёт банк единого сообщения Modbus. + if not 0 <= str_adr <= 0xFFF or not 1 <= reg_count <= 4 or not 1 <= function <= 4 or str_adr + reg_count > 0x1000: # Проверяем окно целиком, чтобы не усекать адреса и значения двухбитных полей. + raise ValueError("Modbus: адрес 0…4095, количество и функция 1…4; окно не должно выходить за 4095") # Ошибочный ввод не превращается в допустимый кадр другого банка. + return (str_adr << 4) | ((function - 1) << 2) | (reg_count - 1) # Функция занимает биты 3:2, количество — 1:0; оба wire-кода лежат в диапазоне 0…3. def merge_error(info: int, code: int) -> int: @@ -460,14 +464,16 @@ def decode(raw_id: int, data: bytes, ide: bool = True, rtr: bool = False) -> Dec res.fields.append(("Слот 0x%04X, Word%d" % (pid.body, index), "0x%04X (%d)" % (values[index], values[index]))) # Полная координата сохраняет адрес слота и выбранную позицию. res.summary = "GAS SLOT slot=0x%04X%s" % (pid.body, " mask=0x%04X" % values[0] if values else " (запрос)") # CAN-журнал явно показывает маску частичного изменения. return res # Не передаём четыре слова старому обработчику адреса первого регистра. + if pid.msg_type == MsgType.MODBUS and len(source_data) > 8: # Проверяем реальную длину до усечения отображаемого classic CAN payload. + res.summary = "MODBUS: неверная длина кадра" # Нельзя выдавать девять и более октетов за допустимые восемь. + res.warnings.append("Modbus: classic CAN допускает не более 8 байт") # Сохраняем причину отказа для журнала и анализатора захвата. + return res # Не публикуем регистры из частично обрезанного кадра. handler = { MsgType.BROADCAST: _decode_broadcast, MsgType.DISCRETE: _decode_discrete, MsgType.ANALOG: _decode_analog, MsgType.GENERAL_ADDRESS_SPACE: _decode_gas, - MsgType.MODBUS_DISCRETE: _decode_modbus_bit, - MsgType.MODBUS_HOLDING: _decode_modbus_reg, - MsgType.MODBUS_INPUT: _decode_modbus_reg, + MsgType.MODBUS: _decode_modbus, # Банк выбирается функцией из Body внутри общего обработчика. MsgType.ERROR: _decode_error, MsgType.BOOT_CONTROL: _decode_boot, MsgType.BOOT_DATA_A: _decode_boot, @@ -663,47 +669,36 @@ def _decode_gas(res: Decoded) -> None: res.summary = "GAS: запрос по адресу 0x%04X" % start -def _decode_modbus_bit(res: Decoded) -> None: - str_adr, reg_count = split_modbus(res.id.body) - kind = "DISCRETE" # После назначения 0x4 слотному GAS битовым Modbus-сообщением остаётся только тип 0x5. - res.fields.append((" Modbus.StrAdr", "0x%03X (%d)" % (str_adr, str_adr))) - res.fields.append((" Modbus.RegCount", "%d" % reg_count)) - expected = reg_count % 8 + 1 - if res.dlc and res.dlc != expected: - res.warnings.append( - "Для %s ожидается DLC = RegCount %% 8 + 1 = %d, получено %d" - % (kind, expected, res.dlc)) - if len(res.data) >= 2: - val = res.data[0] | (res.data[1] << 8) - bits = ["%d" % ((val >> i) & 1) for i in range(16)] - res.registers = [(str_adr, val)] - res.fields.append((" Значение", "0x%04X" % val)) - res.fields.append((" Биты 0..15", " ".join(bits))) - res.summary = "MODBUS %s @0x%03X x%d = 0x%04X" % (kind, str_adr, reg_count, val) - else: - res.summary = "MODBUS %s @0x%03X x%d (запрос)" % (kind, str_adr, reg_count) - - -def _decode_modbus_reg(res: Decoded) -> None: - str_adr, reg_count = split_modbus(res.id.body) - kind = "HOLDING" if res.id.msg_type == MsgType.MODBUS_HOLDING else "INPUT" - res.fields.append((" Modbus.StrAdr", "0x%03X (%d)" % (str_adr, str_adr))) - res.fields.append((" Modbus.RegCount", "%d" % reg_count)) - if res.dlc and res.dlc != reg_count * 2: - res.warnings.append( - "Для %s ожидается DLC = 2 * RegCount = %d, получено %d" - % (kind, reg_count * 2, res.dlc)) - if reg_count > 4: - res.warnings.append("В одном кадре не более 4 регистров, в ID указано %d" % reg_count) - vals = regs_le(res.data) - res.registers = [(str_adr + i, v) for i, v in enumerate(vals)] - for adr, v in res.registers: - res.fields.append((" Reg 0x%04X" % adr, "0x%04X (%d)" % (v, v))) - if vals: - res.summary = "MODBUS %s @0x%03X: %s" % ( - kind, str_adr, " ".join("%04X" % v for v in vals)) - else: - res.summary = "MODBUS %s @0x%03X x%d (запрос)" % (kind, str_adr, reg_count) +def _decode_modbus(res: Decoded) -> None: # Единый тип 0x5 разбирается по номеру функции, а не по прежним трём MsgType. + if not res.ide or res.rtr: # Modbus поверх ProtoCAN принимает только расширенные data frames. + return # Общий декодер уже добавил предупреждение о неверном формате; данные такого кадра не публикуются. + str_adr, reg_count, function = split_modbus(res.id.body) # Извлекаем физические значения функции и количества 1…4. + kind = ("COIL", "DISCRETE", "HOLDING", "INPUT")[function - 1] # Порядок банков соответствует функциям Modbus 1, 2, 3 и 4. + res.fields.extend([(" Modbus.Function", "%d (%s)" % (function, kind)), (" Modbus.StrAdr", "0x%03X (%d)" % (str_adr, str_adr)), (" Modbus.RegCount", str(reg_count))]) # Журнал показывает функцию отдельно от единого типа сообщения. + res.summary = "MODBUS FC%d %s @0x%03X x%d" % (function, kind, str_adr, reg_count) # Общая подпись сохраняется также для ошибочного payload. + if str_adr + reg_count > 0x1000: # Проверяем конец окна относительно 12-битного адресного пространства. + res.warnings.append("Modbus: окно выходит за адрес 0xFFF") # Не отображаем выход за границу как корректные регистры. + return # Неверное окно не интерпретируется дальше. + expected = 1 if function <= 2 else reg_count * 2 # До четырёх битов помещаются в октет; каждому 16-битному регистру нужны два октета. + if not res.dlc: # Пустой payload обозначает запрос чтения от ПМ. + if res.id.route == Route.FROM_DEVICE: # Ответ устройства обязан содержать запрошенные значения. + res.warnings.append("Modbus: пустой ответ устройства") # Пустой ответ не маскируется под запрос. + res.summary += " (запрос)" # Запрос отображается без вымышленных нулевых значений. + return # Чтение не содержит регистров для декодирования. + if res.dlc != expected: # Длина должна точно соответствовать функции и количеству в Body. + res.warnings.append("Modbus FC%d: ожидается DLC=%d, получено %d" % (function, expected, res.dlc)) # Сообщаем ожидаемую длину без частичного разбора. + return # Некорректный payload не выдаётся за действительные данные. + if function <= 2: # Coil и Discrete передают значения младшими битами одного октета. + if res.data[0] >> reg_count: # Биты вне запрошенного количества должны оставаться нулевыми. + res.warnings.append("Modbus: установлены биты вне запрошенного количества") # Выявляем неверную битовую маску. + return # Не публикуем неверные значения. + values = [(res.data[0] >> index) & 1 for index in range(reg_count)] # Каждый следующий адрес соответствует следующему младшему биту. + else: # Holding и Input сохраняют порядок little-endian внутри каждого регистра. + values = regs_le(res.data) # Общий помощник извлекает проверенное число 16-битных значений. + res.registers = [(str_adr + index, value) for index, value in enumerate(values)] # Возвращаем отдельную координату для каждого бита или регистра. + for address, value in res.registers: # Детальная панель показывает все значения выбранного банка. + res.fields.append((" Reg 0x%04X" % address, "0x%04X (%d)" % (value, value))) # Одновременно доступны HEX и десятичное представление. + res.summary += ": " + " ".join("%04X" % value for value in values) # Краткая строка журнала включает полученные значения. def _decode_error(res: Decoded) -> None: diff --git a/python/set_devices/bus_demo.py b/python/set_devices/bus_demo.py index ee81014..56a46e4 100644 --- a/python/set_devices/bus_demo.py +++ b/python/set_devices/bus_demo.py @@ -53,8 +53,8 @@ class BusDemoSource: data = tag + ("%04d" % sid).encode() elif kind == "modbus": adr, cnt = self._rng.randint(0, 0x200), self._rng.randint(1, 4) - cid = pc.ProtoCanId.build(0, 1, dev_type, dev_id, pc.MsgType.MODBUS_HOLDING, - pc.merge_modbus(adr, cnt)) + cid = pc.ProtoCanId.build(0, 1, dev_type, dev_id, pc.MsgType.MODBUS, # Демонстрация использует единый тип 0x5 вместо прежнего Holding 0x6. + pc.merge_modbus(adr, cnt, pc.ModbusFunction.HOLDING)) # Функция 3 обозначает банк Holding, количество по-прежнему находится в диапазоне 1…4. data = b"".join(self._rng.randint(0, 0xFFFF).to_bytes(2, "little") for _ in range(cnt)) elif kind == "gas": diff --git a/python/set_devices/qt_ports/can_frame_builder.py b/python/set_devices/qt_ports/can_frame_builder.py index 008428b..7a1abe4 100644 --- a/python/set_devices/qt_ports/can_frame_builder.py +++ b/python/set_devices/qt_ports/can_frame_builder.py @@ -64,7 +64,7 @@ class CanFrameFields(QWidget): # Компонент содержит тольк arg_layout.addWidget(self.settings_body) # Два байта SETTINGS заменяют единое поле аргумента. arg_layout.addStretch(1) # Свободная ширина остаётся справа от редакторов. self.count = QSpinBox() # RegCount используется протокольными типами Modbus. - self.count.setRange(0, 15) # Поле количества занимает четыре бита Body Modbus. + self.count.setRange(1, 4) # Два младших бита Body кодируют количество минус один, допустимы 1…4 регистра или бита. self.count.setValue(1) # Исходный запрос относится к одному регистру. self.sub_label = QLabel("Подтип") # Подпись уточняется при выборе типа сообщения. self.arg_label = QLabel("SensorID / адрес") # Назначение аргумента зависит от MsgType. @@ -116,10 +116,11 @@ class CanFrameFields(QWidget): # Компонент содержит тольк settings = msg_type == pc.MsgType.SETTINGS # Только SETTINGS редактируется отдельными байтами Z и Y. self.arg.setVisible(not settings) # Единый числовой аргумент скрывается для SETTINGS. self.settings_body.setVisible(settings) # Двухбайтовый редактор появляется вместо числового аргумента. - table = {pc.MsgType.BROADCAST: (pc.BroadcastType, "Broadcast.Type", "Body (0..15)"), pc.MsgType.DISCRETE: (pc.DiscreteType, "Discrete.Type", "Body (0..4095)"), pc.MsgType.ANALOG: (pc.AnalogType, "Analog.Type", "SensorID (0..4095)")} # Таблица определяет визуальные подписи существующих протокольных перечислений. + table = {pc.MsgType.BROADCAST: (pc.BroadcastType, "Broadcast.Type", "Body (0..15)"), pc.MsgType.DISCRETE: (pc.DiscreteType, "Discrete.Type", "Body (0..4095)"), pc.MsgType.ANALOG: (pc.AnalogType, "Analog.Type", "SensorID (0..4095)"), pc.MsgType.MODBUS: (pc.ModbusFunction, "Функция Modbus (1..4)", "StrAdr (0..4095)")} # Для единого Modbus селектор подтипа выбирает функцию Coil/Discrete/Holding/Input. + self.count.setEnabled(msg_type == pc.MsgType.MODBUS) # Количество доступно только для типа, использующего это поле Body. current = self.sub.currentText() # Сохраняем выбранный подтип, если он допустим для нового сообщения. self.sub.clear() # Старые варианты не должны остаться в новом типе сообщения. - self.sub.setEnabled(msg_type in table) # Отдельный подтип доступен только у трёх перечисленных типов. + self.sub.setEnabled(msg_type in table) # Подтип доступен для Broadcast/Discrete/Analog, а у Modbus выбирается функция 1…4. if msg_type in table: # Подписи и значения перечислений берутся из одного места. enum, sub_label, arg_label = table[msg_type] # Получаем визуальное описание выбранного MsgType. self.sub.addItems([item.name for item in enum]) # Значения берутся из общего протокольного каталога. @@ -128,9 +129,7 @@ class CanFrameFields(QWidget): # Компонент содержит тольк else: # Типы без отдельного подтипа используют Body по собственному назначению. sub_label = "—" # Подпись явно показывает отсутствие подтипа. arg_label = "Body (обычно 0)" # Для PULSE сохраняем исходное описание аргумента. - if msg_type in (pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # Только сохранённые типы 0x5…0x7 используют Modbus-адрес и количество. - arg_label = "StrAdr (0..4095)" # Двенадцатибитный адрес показан в прежних единицах регистров. - elif msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE: # GAS использует всё поле Body под адрес. + if msg_type == pc.MsgType.GENERAL_ADDRESS_SPACE: # GAS использует всё поле Body под адрес. arg_label = "Адрес регистра (0..65535)" # Полный 16-битный диапазон указан в подписи. elif msg_type == pc.MsgType.GAS_SLOT: # Новый тип 0x4 использует весь Body под номер слота, а не StrAdr/RegCount. arg_label = "Адрес слота (0..65535), Data: маска + 3 слова" # Напоминаем оператору о Word0 с маской и фиксированных позициях трёх значений. @@ -148,8 +147,8 @@ class CanFrameFields(QWidget): # Компонент содержит тольк return pc.merge_discrete(pc.DiscreteType[self.sub.currentText()], arg) # Поле собирается общим протокольным модулем. if msg_type == pc.MsgType.ANALOG: # Аналоговое сообщение передаёт SensorID в Body. return pc.merge_analog(pc.AnalogType[self.sub.currentText()], arg) # Существующий кодек задаёт расположение подтипа и SensorID. - if msg_type in (pc.MsgType.MODBUS_DISCRETE, pc.MsgType.MODBUS_HOLDING, pc.MsgType.MODBUS_INPUT): # Формат Modbus применяется только к трём оставшимся типам 0x5…0x7. - return pc.merge_modbus(arg, count) # Адрес и количество объединяются общей функцией протокола. + if msg_type == pc.MsgType.MODBUS: # Один MsgType содержит адрес, количество 1…4 и выбранную функцию. + return pc.merge_modbus(arg, count, pc.ModbusFunction[self.sub.currentText()]) # Общий упаковщик проверяет диапазоны и кодирует функцию и количество со смещением на единицу. if msg_type == pc.MsgType.ERROR: # Сохраняем существующую категорию ошибки с нулевым кодом источника. return pc.merge_error(0, arg) # Размещение кода ошибки остаётся ответственностью общего ядра. return arg & 0xFFFF # Остальные типы сохраняют прежнее ограничение Body шестнадцатью битами. diff --git a/python/tests/test_modbus_unified.py b/python/tests/test_modbus_unified.py new file mode 100644 index 0000000..a13c445 --- /dev/null +++ b/python/tests/test_modbus_unified.py @@ -0,0 +1,38 @@ +import unittest # Стандартный тестовый раннер проверяет wire-контракт без зависимости от GUI. +from protocan import protocan as pc # Используем публичный построитель и декодер CAN-сообщений. +from logic_analyzer.decoders.set_can import legacy # Тот же формат должен распознаваться при анализе аппаратного захвата. + + +class ModbusTests(unittest.TestCase): # Проверяем объединение банков, битовую упаковку и отбраковку неверных окон. + def test_functions_and_counts(self): # Все шестнадцать сочетаний должны сохранять функцию, количество и значения. + for function in range(1, 5): # Номера 1…4 соответствуют Coil, Discrete, Holding и Input. + for count in range(1, 5): # Количество ограничено 1…4 независимо от размера элемента банка. + body = pc.merge_modbus(0x123, count, function) # Адрес выбран так, чтобы старшие биты отличались от младших служебных полей. + self.assertEqual(body, 0x1230 | ((function - 1) << 2) | (count - 1)) # Эталон явно задаёт адрес [15:4], функцию [3:2] и количество [1:0]. + self.assertEqual(pc.split_modbus(body), (0x123, count, function)) # Обратное преобразование возвращает физические значения 1…4. + values = [index % 2 for index in range(count)] if function <= 2 else [0x1234 + index for index in range(count)] # Битовые и регистровые банки содержат различимые последовательности. + data = bytes([sum(value << index for index, value in enumerate(values))]) if function <= 2 else b''.join(value.to_bytes(2, 'little') for value in values) # Биты начинаются с младшего, слова передаются little-endian. + identifier = pc.ProtoCanId.build(1, 1, 7, 3, pc.MsgType.MODBUS, body) # Каждый ответ имеет единый MsgType=0x5 и направление от устройства. + decoded = pc.decode(identifier, data) # Проверяем штатный путь CAN-журнала приложения. + self.assertFalse(decoded.warnings, decoded.warnings) # Допустимое окно не должно сопровождаться предупреждениями. + self.assertEqual(decoded.registers, list(zip(range(0x123, 0x123 + count), values))) # Для каждого бита и слова публикуется точный адрес. + captured = legacy(identifier, data) # Проверяем согласованность анализатора захватов с протокольной библиотекой. + self.assertEqual((captured['function'], captured['count'], captured['registers']), (function, count, decoded.registers)) # Оба публичных пути возвращают одинаковые физические значения. + + def test_invalid_inputs_and_payloads(self): # Ошибки должны отклоняться до превращения в другой допустимый wire-код. + for args in ((0, 0, 1), (0, 5, 1), (0, 1, 0), (0, 1, 5), (-1, 1, 1), (4096, 1, 1), (4095, 2, 4)): # Охватываем обе границы полей и переполнение окна. + with self.assertRaises(ValueError): pc.merge_modbus(*args) # Неверные значения не маскируются и не оборачиваются. + self.assertEqual(pc.merge_modbus(4095, 1, 4), 0xFFFC) # Последний адрес остаётся доступным для одного регистра Input. + for body, data in ((0x1233, b'\x10'), (0x123B, b'\x01\x02'), (0xFFFF, b'\0' * 8), (0x123B, b'\0' * 9)): # Проверяем лишний бит, короткие данные, выход окна за 0xFFF и запрет молчаливой обрезки девятого октета. + decoded = pc.decode(0x1F350000 | body, data) # Формируем ответ устройства с единым типом 0x5. + self.assertTrue(decoded.warnings) # Каждая ошибка должна быть видима в журнале. + self.assertFalse(decoded.registers) # Некорректный payload не становится источником значений для тренда. + with self.assertRaises(ValueError): legacy(0x1F350000 | body, data) # Анализатор захвата использует те же проверки. + self.assertFalse(pc.decode(0x1735123F, b'').warnings) # Запрос ПМ с функцией 4 и количеством 4 не содержит данных. + self.assertTrue(pc.decode(0x1F35123F, b'').warnings) # Пустой ответ прибора является ошибкой протокола. + for msg_type in (6, 7): # Бывшие отдельные типы Modbus освобождены. + self.assertTrue(pc.decode(0x1F300000 | (msg_type << 16), b'').warnings) # Декодер не трактует старые MsgType как единый Modbus. + + +if __name__ == '__main__': # Допускаем прямой запуск теста на хосте. + unittest.main() # Стандартный код завершения отражает результат проверок. From 83fb9b6fe897377d688d5bdf412fc50b50f393f4 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Oct 2026 16:15:37 +0300 Subject: [PATCH 15/18] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B5=D1=86=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8E=20=D0=B8=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86?= =?UTF-8?q?=D1=8B=20=D0=B5=D0=B4=D0=B8=D0=BD=D0=BE=D0=B3=D0=BE=20Modbus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/set-protocol/docs/legacy/PROTOCOL.md | 38 +++++++- c/set-protocol/ports/stm32-bxcan/README.md | 13 ++- doc/setcan/index.html | 106 ++++++++++++++++----- doc/setcan/protocan/CHANGELOG.md | 3 + doc/setcan/protocan/OAP.md | 2 +- doc/setcan/protocan/PROTOCOL.md | 38 +++++++- doc/setcan/Протокол CAN и ОАП.html | 25 +++-- doc/setcan/Протокол CAN и ОАП.md | 25 +++-- doc/setcan/Протокол CAN и ОАП.xlsx | Bin 266313 -> 231631 bytes 9 files changed, 180 insertions(+), 70 deletions(-) diff --git a/c/set-protocol/docs/legacy/PROTOCOL.md b/c/set-protocol/docs/legacy/PROTOCOL.md index 3daef73..4c044d2 100644 --- a/c/set-protocol/docs/legacy/PROTOCOL.md +++ b/c/set-protocol/docs/legacy/PROTOCOL.md @@ -3,7 +3,7 @@ > GAS `0x3` использует адреса отдельных 16-битных регистров. GAS SLOT `0x4` — отдельный сервис с маской в Word0 и тремя значениями Word1…Word3. Полный контракт: [ОАП](../../../../doc/setcan/protocan/OAP.md). Существующие регистровые сервисы сохраняют свои адреса. Статус: **Stable с зарезервированным загрузочным расширением** -Версия: **2.1: GAS 0x3 и масочный GAS SLOT 0x4**
+Версия: **2.2: единый Modbus 0x5, функции и количество 1…4**
Порядок байтов payload: **little-endian**, если явно не указано иное ## Назначение @@ -63,9 +63,8 @@ can_id = | `0x2` | `ANALOG` | оба | 0…8 | stable | | `0x3` | `GAS` | оба | 0/2/4/6/8 | регистры 0…65535 | | `0x4` | `GAS_SLOT` | оба | 0/8 | Word0 — маска, Word1…Word3 — значения | -| `0x5` | `MODBUS_DISCRETE` | оба | 0…8 | stable | -| `0x6` | `MODBUS_HOLDING` | оба | 0…8 | stable | -| `0x7` | `MODBUS_INPUT` | оба | 0…8 | stable | +| `0x5` | `MODBUS` | оба | 0/1/2/4/6/8 | функции 1…4, количество 1…4 | +| `0x6…0x7` | резерв | — | — | свободны | | `0x8` | `ERROR` | прибор → ПМ | 0 | stable | | `0x9` | `BOOT_CONTROL` | ПМ → прибор | 0/8 | draft | | `0xA` | `BOOT_DATA_A` | ПМ → прибор | 8 | draft | @@ -83,7 +82,7 @@ can_id = |---|---| | broadcast | команда `[15:4]`, параметр `[3:0]` | | discrete/analog | подтип `[15:12]`, значение/адрес `[11:0]` | -| Modbus | начальный адрес `[15:4]`, количество `[3:0]` | +| Modbus 0x5 | адрес `[15:4]`, функция − 1 `[3:2]`, количество − 1 `[1:0]` | | GAS 0x3 | адрес первого 16-битного регистра `[15:0]` | | GAS SLOT 0x4 | адрес слота `[15:0]`; маска — в Word0 payload, значения — Word1…Word3 | | error | дополнительная информация `[15:8]`, код `[7:0]` | @@ -91,6 +90,35 @@ can_id = | boot control/status | `SessionID[15:8]`, команда `[7:0]` | | boot data | `BlockIndex[15:0]` | +## Единый Modbus `0x5` + +Все четыре банка используют один `MsgType=0x5`. Коды `0x6` и `0x7` свободны. +Начальный адрес занимает `[15:4]` и лежит в диапазоне `0x000…0xFFF`. +Биты `[3:2]` содержат `Function − 1`, биты `[1:0]` — `RegCount − 1`. +Физические значения функции и количества: **1…4**. Всё окно должно помещаться +в 4096 адресов: `StrAdr + RegCount ≤ 4096`. + +| Функция | Банк | Элемент | DLC данных | +|---:|---|---|---| +| 1 | Coil | дискретный выход | 1 байт для 1…4 битов | +| 2 | Discrete | дискретный вход | 1 байт для 1…4 битов | +| 3 | Holding | 16-битный регистр | `2 × RegCount`, 2/4/6/8 байт | +| 4 | Input | 16-битный регистр | `2 × RegCount`, 2/4/6/8 байт | + +Это селектор банка в ProtoCAN по нумерации функций Modbus, без RTU-заголовка +и CRC. Сохраняется правило ProtoCAN: `Route=0, DLC=0` читает окно; +непустой payload записывает Coil/Holding, Discrete/Input доступны только +для чтения. Ответ имеет `Route=1`, сохраняет `MsgBody` и содержит значения +либо эхо успешной записи. RTR запрещён. Биты упакованы начиная с младшего, +старшие неиспользуемые биты нулевые. Регистры передаются little-endian. + +Пример: адрес `0x123`, функция 3, четыре регистра дают +`MsgBody = (0x123 << 4) | ((3 − 1) << 2) | (4 − 1) = 0x123B`. + +Изменение wire-формата несовместимо с прежними отдельными типами +`0x5/0x6/0x7`: узлы и клиенты обновляются согласованно. Тип GAS SLOT `0x4` +сохраняет своё назначение. + ## Общие правила обмена - Многобайтовые значения в `DATA` передаются little-endian. diff --git a/c/set-protocol/ports/stm32-bxcan/README.md b/c/set-protocol/ports/stm32-bxcan/README.md index 04c89a3..537bfdf 100644 --- a/c/set-protocol/ports/stm32-bxcan/README.md +++ b/c/set-protocol/ports/stm32-bxcan/README.md @@ -81,9 +81,8 @@ c/set-protocol/ | `0x2` | аналоговое (`ANALOG`) | | `0x3` | общее адресное пространство | | `0x4` | GAS SLOT: Word0-маска и три значения | -| `0x5` | Modbus Discrete | -| `0x6` | Modbus Holding | -| `0x7` | Modbus Input | +| `0x5` | Modbus: функции 1…4, количество 1…4 | +| `0x6…0x7` | Резерв | | `0x8` | ошибка | | `0x9` | управление загрузчиком (`BOOT_CONTROL`, зарезервировано) | | `0xA` | данные прошивки, слот A (`BOOT_DATA_A`, зарезервировано) | @@ -98,7 +97,7 @@ c/set-protocol/ - broadcast: младшие 4 бита — дополнительное поле, старшие 12 бит — команда; - discrete: младшие 12 бит — данные/адрес, старшие 4 бита — подтип; - analog: младшие 12 бит — ID датчика, старшие 4 бита — тип величины; -- Modbus: младшие 4 бита — количество регистров, старшие 12 бит — начальный адрес; +- Modbus: адрес `[15:4]`, функция минус один `[3:2]`, количество минус один `[1:0]`; функция и количество 1…4; - SETTINGS: старший байт — номер сборки `Z`, младший байт — позиция `Y`; - error: младший байт — код ошибки, старший байт — дополнительная информация. @@ -264,7 +263,7 @@ PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg msg) - `ProtoCanMsgToAnalog...()` — универсальные данные, настройки, U/I/T; - `ProtoCanMsgToSettings()` — GET/WRITE/CLEAR привязки ROM к локации; - `ProtoCanMsgToGeneralAddressSpace()`; -- `ProtoCanMsgToModbus...()`; +- `ProtoCanMsgToModbus()`; - `PROTOCAN_RequestError()`. Стандартные слабые обработчики в основном являются демонстрационными: часть возвращает `PROTOCAN_OK` без действий, часть отправляет текстовые ответы вроде `TS0001` или `GAS-0001`. Для рабочего изделия их обычно нужно переопределить. @@ -373,7 +372,7 @@ tx.ErrorData.Info = 0x34; (void)PROTOCAN_SEND(id, tx); ``` -Для `BROADCAST`, `DISCRETE` и `ANALOG` используется `tx.CoreData`; для Modbus-типов — `tx.ModbusData`, для `SETTINGS` — `tx.SettingsData`. Для успешных ответов и ошибок SETTINGS удобнее использовать готовые функции `PROTOCAN_SEND_SETTINGS_RESPONSE()` и `PROTOCAN_SEND_SETTINGS_ERROR()`. Если количество передаваемых элементов больше нуля, соответствующий указатель `Data` должен быть валиден до завершения вызова. +Для `BROADCAST`, `DISCRETE` и `ANALOG` используется `tx.CoreData`; для единого Modbus — `tx.ModbusData` с полями `Function` и `RegCount` 1…4, для `SETTINGS` — `tx.SettingsData`. Для успешных ответов и ошибок SETTINGS удобнее использовать готовые функции `PROTOCAN_SEND_SETTINGS_RESPONSE()` и `PROTOCAN_SEND_SETTINGS_ERROR()`. Если количество передаваемых элементов больше нуля, соответствующий указатель `Data` должен быть валиден до завершения вызова. ## Пульс устройства @@ -605,4 +604,4 @@ CRC32 обнаруживает случайное повреждение, но [Адресация GAS](../../docs/GAS_SLOT.md): `0x3` — отдельные 16-битные регистры `0…65535`, запись 1…4 слов. `0x4` — слот с Word0-маской и тремя значениями; PERIPH сохраняет 200 слов в 67 слотах `0xMM00…0xMM42`. Формат определяется MsgType, без настройки профиля. -`PROTOCAN_GAS_SLOT_BIND(&port)` подключает provider типа 0x4 до обработки очереди. `ProtoCanMsgToGasSlot()` вызывает общий адресный обработчик, `PROTOCAN_SEND_GAS_SLOT()` кодирует Word0-маску и три значения. Неподключённый provider возвращает ошибку. Типы Modbus 0x5…0x7 сохраняют прежние номера. +`PROTOCAN_GAS_SLOT_BIND(&port)` подключает provider типа 0x4 до обработки очереди. `ProtoCanMsgToGasSlot()` вызывает общий адресный обработчик, `PROTOCAN_SEND_GAS_SLOT()` кодирует Word0-маску и три значения. Неподключённый provider возвращает ошибку. Единый Modbus использует MsgType 0x5; коды 0x6/0x7 свободны. `ProtoCanMsgToModbus()` заменяет три прежних weak-обработчика; функция и количество извлекаются через `pcan_modbus_function()` и `pcan_modbus_count()`. `PROTOCAN_SEND_MODBUS()` отправляет одно окно 1…4; `Data=NULL` означает запрос чтения, битовые банки используют маску в `Data[0]`. Неподключённая карта отвечает штатной ошибкой, без демонстрационных ASCII-значений. diff --git a/doc/setcan/index.html b/doc/setcan/index.html index c455bb1..0cffed8 100644 --- a/doc/setcan/index.html +++ b/doc/setcan/index.html @@ -134,7 +134,7 @@ └── doc/index.html эта страница

Входящие

Путь кадра

IRQ вычитывает FIFO0. Pulse обрабатывается сразу, остальные Extended-кадры попадают в кольцевой буфер и разбираются в основном цикле.

-
Исходящие

Единая точка отправки

PROTOCAN_SEND() выбирает упаковщик по MsgType. GAS и Modbus автоматически разбиваются на кадры до 8 байт.

+
Исходящие

Единая точка отправки

PROTOCAN_SEND() выбирает упаковщик по MsgType. GAS разбивается на кадры до 8 байт; единый Modbus передаёт одно окно из 1–4 битов или регистров.

Граница

Что приложение реализует само

Прикладные действия, хранение SETTINGS, EEPROM, DS18B20, таймаут online/offline и полноценный bootloader не входят в ядро.

@@ -157,7 +157,7 @@ ProtoCanPulseCallbackОтправляет периодический pulse со счётчиком.Из callback нужного базового таймера. PROTOCAN_SEND_SETTINGS_RESPONSE / ERRORФормирует успешный либо ошибочный ответ привязки ROM.Из пользовательского обработчика SETTINGS.
-

Точки расширения

Переопределите нужную __weak-функцию в собственном C-файле: семейства ProtoCanMsgToBroadcast…, …Discrete…, …Analog…, ProtoCanMsgToSettings, ProtoCanMsgToGeneralAddressSpace и …Modbus…. Не редактируйте демонстрационную реализацию в ядре — так обновлять библиотеку проще.

+

Точки расширения

Переопределите нужную __weak-функцию в собственном C-файле: семейства ProtoCanMsgToBroadcast…, …Discrete…, …Analog…, ProtoCanMsgToSettings, ProtoCanMsgToGeneralAddressSpace и ProtoCanMsgToModbus. Не редактируйте демонстрационную реализацию в ядре — так обновлять библиотеку проще.

@@ -168,7 +168,7 @@ Priority Route DeviceType DeviceID MsgType MsgBody 1 бит 1 бит 3 бита 4 бита 4 бита 16 бит

Реестр MsgType

- +
КодТипНазначениеСтатус
0x0BROADCASTОбщие команды всем устройствамstable
0x1DISCRETEСостояния, команды, флагиstable
0x2ANALOGДатчики U / I / T и универсальные данныеstable
0x3GASОбщее 16-битное адресное пространствоstable
0x4GAS SLOTWord0 — маска битов 1…3, Word1…Word3 — три значенияstable
0x5…0x7MODBUSDiscrete, Holding, Inputstable
0x8ERRORКод ошибки и дополнительная информацияstable
0x9…0xDBOOTУправление, блоки A/B, статус, discoverydraft
0xESETTINGSПривязка 1-Wire ROM к локации Z/Ystable
0xFPULSEПрисутствие устройстваstable
0x0BROADCASTОбщие команды всем устройствамstable
0x1DISCRETEСостояния, команды, флагиstable
0x2ANALOGДатчики U / I / T и универсальные данныеstable
0x3GASОбщее 16-битное адресное пространствоstable
0x4GAS SLOTWord0 — маска битов 1…3, Word1…Word3 — три значенияstable
0x5MODBUSФункция 1–4: Coil, Discrete, Holding, Input; количество 1–4stable
0x6…0x7РезервСвободныreserved
0x8ERRORКод ошибки и дополнительная информацияstable
0x9…0xDBOOTУправление, блоки A/B, статус, discoverydraft
0xESETTINGSПривязка 1-Wire ROM к локации Z/Ystable
0xFPULSEПрисутствие устройстваstable
@@ -369,7 +369,7 @@ if (PROTOCAN_SEND(id, tx) != PROTOCAN_OK) {

ProtoCAN — базовый протокол

Статус: Stable с зарезервированным загрузочным расширением
-Версия: 2.1: GAS 0x3 и масочный GAS SLOT 0x4
+Версия: 2.2: единый Modbus 0x5, функции и количество 1…4
Порядок байтов payload: little-endian, если явно не указано иное

Назначение

ProtoCAN — прикладной протокол поверх classic CAN 2.0B. Используются только @@ -515,24 +515,17 @@ Priority Route DeviceType DeviceID MsgType MsgBody 0x5 -MODBUS_DISCRETE +MODBUS оба -0…8 -stable +0/1/2/4/6/8 +функции 1…4, количество 1…4 -0x6 -MODBUS_HOLDING -оба -0…8 -stable - - -0x7 -MODBUS_INPUT -оба -0…8 -stable +0x6…0x7 +резерв +— +— +свободны 0x8 @@ -611,8 +604,8 @@ Priority Route DeviceType DeviceID MsgType MsgBody подтип [15:12], значение/адрес [11:0] -Modbus -начальный адрес [15:4], количество [3:0] +Modbus 0x5 +адрес [15:4], функция − 1 [3:2], количество − 1 [1:0] GAS 0x3 @@ -641,6 +634,59 @@ Priority Route DeviceType DeviceID MsgType MsgBody

Контракт обоих GAS: OAP.md. Тип 0x3 адресует отдельные слова; тип 0x4 имеет маску битов 1…3 в Word0 и три значения. Для PERIPH 0x4 используются 67 слотов 0xMM00…0xMM42, последний содержит два значения. Старый Coil 0x4 заменён; формат определяется MsgType.

+

Единый Modbus 0x5

+

Все четыре банка используют один MsgType=0x5. Коды 0x6 и 0x7 свободны. +Начальный адрес занимает [15:4] и лежит в диапазоне 0x000…0xFFF. +Биты [3:2] содержат Function − 1, биты [1:0] — RegCount − 1. +Физические значения функции и количества: 1…4. Всё окно должно помещаться +в 4096 адресов: StrAdr + RegCount ≤ 4096.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ФункцияБанкЭлементDLC данных
1Coilдискретный выход1 байт для 1…4 битов
2Discreteдискретный вход1 байт для 1…4 битов
3Holding16-битный регистр2 × RegCount, 2/4/6/8 байт
4Input16-битный регистр2 × RegCount, 2/4/6/8 байт
+

Это селектор банка в ProtoCAN по нумерации функций Modbus, без RTU-заголовка +и CRC. Сохраняется правило ProtoCAN: Route=0, DLC=0 читает окно; +непустой payload записывает Coil/Holding, Discrete/Input доступны только +для чтения. Ответ имеет Route=1, сохраняет MsgBody и содержит значения +либо эхо успешной записи. RTR запрещён. Биты упакованы начиная с младшего, +старшие неиспользуемые биты нулевые. Регистры передаются little-endian.

+

Пример: адрес 0x123, функция 3, четыре регистра дают +MsgBody = (0x123 << 4) | ((3 − 1) << 2) | (4 − 1) = 0x123B.

+

Изменение wire-формата несовместимо с прежними отдельными типами +0x5/0x6/0x7: узлы и клиенты обновляются согласованно. Тип GAS SLOT 0x4 +сохраняет своё назначение.

Общие правила обмена

Профиль синхронизации часов и сообщения платы о завершении инициализации: GLOBAL_TIME.md. Он сохраняет штатный BROADCAST RTCSETUP @@ -1104,7 +1150,7 @@ Provider проверяет все выбранные права и значен Word0 — метаданные кадра, не четвёртый хранимый регистр. Координата значения — (SlotAddress, WordIndex), где WordIndex=1…3. Любой узел поддерживается общими pcan_gas_slot_id() и pcan_gas_slot_handle_address(); адрес слота не ограничен страницами PERIPH. -Тип 0x4 MODBUS_COIL заменён этим сервисом. Modbus 0x5/0x6/0x7 сохраняет номера. +Тип 0x4 MODBUS_COIL заменён этим сервисом. Единый Modbus использует 0x5, функцию и количество 1…4 в Body; 0x6/0x7 свободны. Старое оборудование с Coil 0x4 требует согласованного обновления; автоопределения формата нет.

PERIPH: проекция 200 слов на слоты 0x4

mode=0…31; DeviceType=1+mode/16, DeviceID=mode mod 16. @@ -1490,10 +1536,18 @@ GAS 0x3 сохраняет собственные адреса подключё

[Unreleased]

Changed — 2026-10-23

    -
  • GAS 0x3 возвращён к адресации отдельных 16-битных регистров 0…65535, DLC 0/2/4/6/8.
  • -
  • Слотный GAS перенесён на 0x4 вместо MODBUS_COIL; Word0 содержит маску битов 1…3, Word1…Word3 — значения.
  • -
  • PERIPH сохраняет 200 значений на mode в 67 слотах; последний содержит два значения.
  • -
  • Формат выбирается номером MsgType; Python/JNI, STM32, Modbus routing, тесты, XLSX и HTML согласованы.
  • +
  • Modbus Discrete/Holding/Input объединены в MsgType 0x5; Coil/Discrete/Holding/Input выбираются функцией 1…4, количество ограничено 1…4.

    +
  • +
  • Body Modbus: адрес [15:4], функция минус один [3:2], количество минус один [1:0]; номера 0x6/0x7 освобождены.

    +
  • +
  • GAS 0x3 возвращён к адресации отдельных 16-битных регистров 0…65535, DLC 0/2/4/6/8.

    +
  • +
  • Слотный GAS перенесён на 0x4 вместо MODBUS_COIL; Word0 содержит маску битов 1…3, Word1…Word3 — значения.

    +
  • +
  • PERIPH сохраняет 200 значений на mode в 67 слотах; последний содержит два значения.

    +
  • +
  • Формат выбирается номером MsgType; Python/JNI, STM32, Modbus routing, тесты, XLSX и HTML согласованы.

    +

Added