NXP i.MX7D программируемый сопроцессор
ввода - вывода
Итак, вы написали программу для одного или нескольких каналов SDMA. Ассемблировали в бинарник.
Теперь необходимо загрузить его в память и стартовать на выполнение. Поехали.
@ Работа практически любого модуля
@ Начинается с тактирования
MOV32 R0, CCM_BASE + CCGR72 @ SDMA clock gate
SER R1
STR R1, [R0]
@ Базовый адрес SDMA
MOV32 R0, SDMAARM_BASE
@ Назначить приоритеты тем каналам
@ Которые планируется использовать
@ В диапазоне от 1 (младший) до 7 (старший)
@ Чем выше номер, тем больше шансов получит канал
MOV R1, 1 @ Номер приоритета
STR R1, [R0, SDMA_CHNPRI0] @ Канал 0
MOV R1, 2 @ Номер приоритета
STR R1, [R0, SDMA_CHNPRI1] @ Канал 1
MOV R1, 3 @ Номер приоритета
STR R1, [R0, SDMA_CHNPRI2] @ Канал 2
@ На этих каналах
@ Активация будет только ручная
MOV R1, 1<<0 + 1<<1 @ Нулевой и первый
STR R1, [R0, EVTOVR]
@ На этих каналах
@ Активация будет только по прерываниям
MOV R1, 1<<2 @ Второй канал SDMA
STR R1, [R0, HOSTOVR]
@ Настроить приём внешних прерываний
MOV R1, 1<<2 @ На втором канале SDMA
STR R1, [R0, CHNENBL31] @ Линия 31 (UART5 Tx FIFO)
@ Можно подключить к любому каналу
@ До 48 источников внешних событий (прерываний)
@ =======================
@ Загрузка программ в SDMA
@ =======================
@ Перейти в режим static
LDR R1, [R0, SDMAARM_CONFIG]
BIC R1, 0b11 << CSM
STR R1, [R0, SDMAARM_CONFIG]
@ Адрес листинга CCB
MOV32 R1, CCB0
STR R1, [R0, MC0PTR]
@ Загрузить программы в память SDMA
MOV R1, 1 << 0 @ Через нулевой канал
STR R1, [R0, HSTART] @ Стартовать
@ Дождаться завершения
1:
LDR R1, [R0, STOP_STAT]
TST R1, 1
BNE 1b @ если =1, значит ch0 ещё работает
Программы загружены. А вот с контекстами придётся повозиться.
Мне так и не удалось реализовать загрузку контекстов через ch0.
Поэтому был использован отладочный порт OnCE. Этот метод рекомендуется
и в референсном мануале.
Кстати, метод OnCE позволит в будущем перестроить ch0
на выполнение любых ваших программ.
Для этого просто загрузите в ch0 новый регистровый контекст.
И вы получите в своё распоряжение все 32 канала!
Проверено, работает!
@ =======================
@ Загрузка контекстов в SDMA
@ =======================
@ Войти в отладку OnCE
MOV R1, 1
STR R1, [R0, ONCE_ENB]
@ Запросить режим отладки
MOV R1, 5 @ 5=debug_rqst
STR R1, [R0, ONCE_CMD]
@ Цикл загрузки контекстов
@ Один проход цикла загружает 1 слово в память контекстов
@ И состоит из четырёх команд
MOV32 R2, Контекст_sdma_01 @ Базовый адрес
CLR R3 @ Обнулить счётчик загруженных слов
1:
@ Команда R1 <-> DATA
MOV32 R1, 0x0800 + 24 * 1 @ Адрес во внутренней памяти sdma
ADD R1, R3 @ Добавить смещение
STR R1, [R0, ONCE_DATA] @ Поместить в порт DATA
MOV R1, 1 @ Команда 1=dmov
STR R1, [R0, ONCE_CMD] @ И переместить в R1
@ Выполнить инструкцию MOV R0, R1
MOV32 R1, 0x00000089 @ Код инструкции
STR R1, [R0, ONCE_INSTR] @ Поместить в порт INSTR
MOV R1, 2 @ 2=exec_once
STR R1, [R0, ONCE_CMD] @ И выполнить её
@ Команда R1 <-> DATA
LDR R1, [R2], 4 @ Взять одно слово данных
STR R1, [R0, ONCE_DATA] @ Поместить в порт DATA
MOV R1, 1 @ Команда 1=dmov
STR R1, [R0, ONCE_CMD] @ И переместить в R1
@ Выполнить инструкцию ST R1, (R0, 0)
MOV32 R1, 0x00005900 @ Код инструкции
STR R1, [R0, ONCE_INSTR] @ Поместить в порт INSTR
MOV R1, 2 @ 2=exec_once
STR R1, [R0, ONCE_CMD] @ И выполнить её
@ Счётчик загруженных слов
INC R3 @ Увеличить на 1 слово
CMP R3, 24*2 @ Загружаем 48 слов, для двух каналов
BNE 1b @ Переход, если счётчик != 48
@ Последний шаг
@ Активировать SDMA
MOV R1, 3 @ 3=run_core
STR R1, [R0, ONCE_CMD]
@ Завершить сеанс OnCE
CLR R1
STR R1, [R0, ONCE_ENB]
Основной набор содержит всё необходимое для написания программ
и запуска их в камушке.
Заветный файл "
sdma_init.asm" настраивает модуль.
А файл "
Карта скриптов.asm" размещает всю скриптовую канитель в прошивке.
Файл "
sdma.bat" ассемблирует код SDMA.
Там же вы найдёте пару тестовых программ для ch1 и ch2.
Ассемблера для SDMA не существует! Ха-ха три раза! Всем салютики!
NXP даёт только коды и описание инструкций. Ассемблер делайте сами! Как хотите, так и делайте!
Поэтому энтузиастами был написан самопальный ассемблер на perl.
Благодарим
Элика за это.
Исходник был поправлен, добавлена улучшенная поддержка русского.
Забирайте его
тутъ.
В дальнейшем, исходник на perl был собран утилитой
Perl2Exe.
И получился полноценный однофайловый транслятор SDMA ассемблера для Windows. Не благодарите.
Найти его можно в папке
exe в
стартовом комплекте.
Размер конечно конский, потому что он включает в себя исполняемый perl с модулями и листинг программы.
Что сказать хорошего. SDMA - это прикосновение к вечному... Так делают настоящие и серьёзные вещи.
Весьма рекомендую его изучить и начать писать на ассемблере!
Ищем энтузиастов для написания статей по SDMA!
Документации к сожалению, очень мало.
Хоть SDMA существуют уже с десяток лет и больше,
на русском языке вы не найдёте о нём ни слова...
А что бы не сбиться с толку, то поначалу вам пригодится следующая инфа.
Если вы всю жизнь писали на ассемблере для нормальных камушков,
то здесь вам придётся немного пошевелить мозгами. И понять, как адресуются программа и данные
во внутренней памяти SDMA.
Внутреннее ОЗУ является общим для сохранения регистровых контекстов, программ и данных.
Оно начинается с адреса 0x800 и имеет размер 0x800 (2048) 32-битных слов.
И теперь внимание - данные адресуются 32-битными словами,
а исполняемый код - 16-битными полусловами. (!)
Адресация внутренней памяти в sdma немного специфичная. Это связано с тем, что ядро считывает и записывает данные
в память только целыми 32-битными словами.
И приращение счётчика адреса на 1 означает переход к следующему слову данных.
В отличии от многих привычных ядер, которые адресуют память байтами, и для перехода к следующему слову, счётчик увеличивают на 4.
Но и это ещё не всё. Так как ядро по своей природе 16-битное, то инструкции адресуются полусловами.
И PC с каждой инструкцией инкрементируется на единицу (!).
Ещё раз, внимательно: приращение счётчика данных на 1 означает переход к следующему 32-битному слову (а не байту!).
Приращение счётчика команд (PC) на 1 означает переход к следующей исполняемой инструкции ассемблера.
Отсюда следует: если вы разместили программу в ОЗУ по адресу 0xC00, то счётчик команд будет видеть её как 0x1800.
Именно этот адрес заносится в первую строку регистрового контекста.
Содержимое почти всего контекста, во время переключения каналов,
считываются и сохраняются ядром автоматически. Таким образом реализуется многозадачность.
Для контекстов зарезервировано 24 слова * 32 канала = 768 слов в самом начале ОЗУ.
Память контекстов начинается с самого первого слова по адресу 0x800. И заканчивается 0xAFF.
Для программ и данных отводится вся оставшаяся часть ОЗУ, которая начинается на 0xB00 и заканчивается 0xFFF.
Таким образом, размещать программы и данные можно с адреса 0xB00.
Счётчик команд видит этот адрес как 0xB00*2=0x1600, так как команды адресуются полусловами.
Нужно бы проверить.. Я не проверял. Но скорей всего, когда не все каналы задействованы, то свободную память,
оставшуюся от регистровых контекстов, можно использовать для размещения программ (?)
Ну всё. Хватит. Ждём более полных статей по SDMA!