СОДЕРЖАНИЕ
Эмулятор состоит из блух блоков:
Приложение МК в свою очередь разделено еще на два блока:
Для каждого блока своя папка. Всего три папки:
Далее приведена структура эмулятора. Инструкция для портирования кода в MATLAB приведена ниже
Здесь содержиться описание трех блоков эмулятора:
В этой папке содержаться оболочка(англ. wrapper) для запуска и контроля эмуляции микроконтроллеров в MATLAB (любого МК, не только STM). Оболочка представляет собой S-Function - блок в Simulink, который работает по скомпилированому коду. Компиляция происходит с помощью MSVC-компилятора.
S-Function работает особым образом: на шаге n она запускает скомпилированный код и ждет пока этот код выполниться. Только когда завершается выполнение кода, S-Function переходит на следующий шаг n+1.
Но программа МК это бесконечный цикл, который никогда не завершается. Поэтому есть несколько особенностей в выполнении такого кода в виде S-Function:
Всего оболочка содержит 4 файла:
В папке "_\MCU_STM32xxxMatlab" есть два файла "stm32fxxx_matlab_conf.c/.h".
В них задаётся используемая периферия и подключаются библиотеки для периферии. Также объявляются функкции для инициализации/деинициализации периферии МК и структуры для эмуляции периферии.
В папке "_\MCU_STM32xxxMatlab\Drivers" находяться стандартные библиотеки для STM/ARM, но переделанные под компилятор MSVC. Всего там три папки: STM32F4xx_SIMULINK, CMSIS, STM32F4xx_HAL_Driver.
В этой папке содержаться файлы для эмуляции периферии STM32 в MATLAB. Структура файлов такая же, как в библиотеки HAL:
"Порт" библиотеки CMSIS для MSVC. Ниже приведен перечень всех файлов и краткое описание зачем они нужны:
_*память ядра не имитируется в полной мере, потому что STM32 - это 32-битный процессор, он имеет 4 Гб памяти. А MATLAB/MSVC делает ограничение на использование не больше 4Гб оперативной памяти. При этом еще есть матлабовские переменные которые тоже занимают место. Поэтому память эмулируется лишь частично. Как имено - задается в дефайнах и структуруре stm32f407xxmatlab.h.
Данная библиотека является копией HAL, за некоторыми исключениями. В основном касаются макросов для ожидания флага. Т.к. весь МК реализован програмно, то надо самому писать код, который будет выставлять флаги по определенным условиям. Только тогда библиотека HAL будет это считывать и выполнять свои функции. Но далеко не всегда есть необходимость так делать.
Поэтому, вместо того, чтобы пользоваться оригиальным HAL и писать эмулятор для всего 32-битного контроллера, можно переписать макросы или даже функции целиком под свои нужды.
Данная папка содержит исходный код приложения МК. При этом драйверы и стандартные/HAL библиотеки, которые общие для всех проектов следует помещать в папку с эмулятором МК. Чтобы не редактировать исходники общих библиотек (CMSIS/HAL) в каждом проекте.
Общий алгоритм портирования кода для симуляции в MATLAB приведен ниже. В инструкции есть ссылки на более подробное описание действий.
Для начала необходимо весь пользовательский код портировать в отдельную папку для удобства. Например в "\Code".
Далее в "run_bat.mex" надо прописать пути для заголовочных файлов (\Includes). Все файлы исходников "*.c" прописывать не обязательно. Можно прописать только папки с исходниками, как с заголовочными файлами. Далее скрипт сам сканирует и ищет все исходники.
Эмулятор и библиотеки связаны в том плане, что необходимо выбрать через что будет реализована периферия
Скрипты для эмуляции периферии необходимо прописывать вручную. В случае STM32 руководствоваться следует только регистрами CMSIS, чтобы не привязываться к HAL, и была возможность симуляции кода без него. Или же пробовать делать универсальный через дефайны, которые будут определять доступ к конкретным регистрам конкретного МК.
Пример 1 (полноценный эмулятор): можно написать полный эмулятор для таймеров, т.к. это очень важна часть МК. Плюс она часто корректируется: разные режимы таймеров, разная частота, разные каналы. И удобно, если всё это можно менять "на ходу", а не только во время компиляциию.
Пример 2 (упрощенный эмулятор): В случае, если не нужна эмуляция периферии. Например для протоколов общения, типа UART/MODBUS, можно просто сделать отдельные входы в S-Function, и напрямую брать значения оттуда и записывать в переменные программы, без приёма отдельных битов, парсинга и прочего. Но тогда надо будет редактировать библиотеки и делать dummy-функции, чтобы они не ждали ответа от периферии, которая не эмулируется. Или же редактировать пользовательский код.
Пример 3 (игнорирование периферии): CubeMX использует функции RCC_Config, которые настраивают тактирование МК. В HAL'e в функции инициализации постоянно используются bit-banding, который реализован аппаратно. Это некоторые адресса, которые могут переключать отдельные биты через присваивание (сродни BSRR у GPIO, только для всей периферии). Плюс еще HAL дополнительно проверяет реально ли выставились эти биты в регистрах, поэтому с этим надо что-то сделать. Т.к. регистры RCC не важны для симуляции большинства программ, можно просто убрать единственный вызов этой функции в main, или сделать её dummy - в HAL-библиотеке.
После портирования кода надо скомпилировать код МК и далее уже смотреть по ошибкам, что надо исправлять.
Для компиляции кода необходимо открыть файл mexing.m. Это MATLAB-скрипт, который запускает скрипт "run_bat.mex" для компиляции. Также этот файл задает время дискретизации для симуляции и дает возможность компиляции кода для отладки
Для отладки симуляции необходимо приписать в mexing.m в вызове "run_mex.bat" слово debug, тогда код скомпилируется для дебага. После этого необходимо открыть любой(?) редактор кода, например Visual Studio. Открыть папку проекта (там должны быть все исходники программы и эмулятора). И подключиться к MATLAB.exe.
Теперь можно поставить точку в исходном коде эмулятора или программы МК и запустить симуляцию. Когда MATLAB дойдет до этого места, симуляция остановиться и в Visual Studio можно будет посмотреть все переменные, пройти код по строкам и в общем делать всё то, что можно делать в режиме отладки. Но отладка рабоатет только один раз. При повторном запуске симуляции остановки не произойдет. Поэтому перед каждой отладкой надо перекомпилировать код.
Самые распространеные ошибки компилятора при портировании нового кода - это ошибки переопределения. Связаны с weak-фукнциями. В MSVC их нет как таковых. Поэтому необходимо закомментировать все weak-функции в HAL или пользовательском коде, чтобы на весь код было только одно определение функции.
Обычно это исключения при чтении по недоступному адресу. Связано с разным адресным пространством МК и ПК. Поэтому надо выяснить на какой строке произошло исключение. И смотреть по какому адресу произошла попытка чтения и по какому адресу надо на самом деле считывать. И после этого скорректировать код так, чтобы адрес брался корректный.
Из общих решений - это может быть при попытки чтения по "экзотическим" адресам (bit-banding), для которых не определено адресное пространство в симуляции.