diff --git a/README.md b/README.md index 4e9a837..bb55dc6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,149 @@ -# matlab_stm_emulate +# MATLAB STM32 EMULATOR + **СОДЕРЖАНИЕ** +- [Общая структура эмулятора](#общая-структура-эмулятора) +- [Описание стуктуры эмулятора (пример для STM32)](#описание-стуктуры-эмулятора-пример-для-stm32) + - [Оболочка МК](#оболочка-мк) + - [Эмулятор STM для MATLAB](#эмулятор-stm-для-matlab) + - [Код пользователя](#код-пользователя) +- [Инструкция](#инструкция) + - [Портирование кода](#портирование-кода) + - [Как скомпилировать код](#как-скомпилировать-код) + - [Как запустить отладку](#как-запустить-отладку) + - [Ошибки при портировании](#ошибки) +## Общая структура эмулятора +Эмулятор состоит из блух блоков: +- приложение МК +- оболочка МК для MATLAB, которая запускает приложение МК и эмулирует его периферию + +Приложение МК в свою очередь разделено еще на два блока: +- исходный код пользователя (код приложения) +- исходный код библиотек и драйверов + +Для каждого блока своя папка. Всего три папки: +- Code ([_код пользователя_](#код-пользователя)) +- MCU_STM32xxx_Matlab ([_эмулятор STM для MATLAB_](#эмулятор-stm-для-matlab)) +- MCU_Wrapper ([_оболочка МК_](#оболочка-мк)) +_*в скобочках ссылки на подробное описание папки_ + +Далее приведена структура эмулятора. Инструкция для портирования кода в MATLAB приведена [ниже](#инструкция) + +## Описание стуктуры эмулятора (пример для STM32) +Здесь содержиться описание трех блоков эмулятора: +- [Оболочка МК](#оболочка-мк) +- [Эмулятор STM для MATLAB](#эмулятор-stm-для-matlab) +- [Код пользователя](#код-пользователя) + +#### Оболочка МК +В этой папке содержаться оболочка(англ. wrapper) для запуска и контроля эмуляции микроконтроллеров в MATLAB (любого МК, не только STM). Оболочка представляет собой S-Function - блок в Simulink, который работает по скомпилированому коду. Компиляция происходит с помощью MSVC-компилятора. + +S-Function работает особым образом: на шаге _n_ она запускает скомпилированный код и ждет пока этот код выполниться. Только когда завершается выполнение кода, S-Function переходит на следующий шаг _n_+1. + +Но программа МК это бесконечный цикл, который никогда не завершается. Поэтому есть несколько особенностей в выполнении такого кода в виде S-Function: +- Для эмуляции создается отдельный поток для программы МК. Этот поток запускается в начале текущего шага симуляции, выполняется какое-то время, а потом приостанавливается. Это позволяет коду S-Function завершиться и перейти на следующий шаг. +- Необходимо закрыть поток программы МК в конце симуляции. Для этого используется особый дефайн для while. Этот дефайн помимо условия while, проверяет условие окончания симуляции. И если симуляцию надо завершить, все бесконечные циклы _while()_ пропускаются и поток доходит до конца функции _main()_ и завершает себя. + +Всего оболочка содержит 4 файла: +- mcu_wrapper.c     - файл, который запускает код МК и управляет его ходом. В нем содержаться функции для запуска/остановки потока программы МК, считывании входов и запись входов S-Function в соответствии с I/O портами МК. +- MCU.c          - базовый файл, который представляет собой исходный код для компиляции S-Function в MATLAB. Вызывает функции из "mcu_wrapper.c" +- mcu_wrapper_conf.h   - общий для mcu_wrapper.c и MCU.c заголовочный файл. Содержит настройки для блока S-Function, а также дефайны для управления ходом программы МК. +- run_mex.bat       - скрипт для компиляции кода компилятором MSVC. В нем прописываются пути для заголовочных файлов ".h", указываются файлы исходного кода ".c" и прописываются дефайны для компиляции. + +#### Эмулятор STM для MATLAB +В папке "_\MCU_STM32xxx_Matlab_" есть два файла "stm32fxxx_matlab_conf.c/.h". + +В них задаётся используемая периферия и подключаются библиотеки для периферии. Также объявляются функкции для инициализации/деинициализации периферии МК и структуры для эмуляции периферии. + +В папке "_\MCU_STM32xxx_Matlab\Drivers_" находяться стандартные библиотеки для STM/ARM, но переделанные под компилятор MSVC. Всего там три папки: [STM32F4xx_SIMULINK](#папка-stm32f4xx_simulink), [CMSIS](#папка-cmsis), [STM32F4xx_HAL_Driver](#папка-stm32f4xx_hal_driver). + +###### Папка STM32F4xx_SIMULINK +В этой папке содержаться файлы для эмуляции периферии STM32 в MATLAB. Структура файлов такая же, как в библиотеки HAL: +- название серии МК, который эмулируется (matlab), +- идентификатор, что это для MATLAB (matlab), +- периферия, функции для эмуляции которой содержит конкретный файл (gpio, tim). +Пример: "stm32f4xx_matlab_tim.c/.h" + +###### Папка CMSIS +"Порт" библиотеки CMSIS для MSVC. Ниже приведен перечень всех файлов и краткое описание зачем они нужны: +- **arm_defines.h** + Содержит ARM дефайны для компиляции в MSVC. +- **core_cm4_matlab.h** + Данный файл является копией "core_cm4.h" с некоторыми изменениями + - удалены первые ~160 строк, которые определяют компилятор ARM. + - добавлена структура **имитирующая память ядра***. Для того, чтобы при обращении по адресам регистров МК не было исключений при чтении по недоступному адресу. +- **stdint.h** + Данный файл является копией "stdint.h", из библиотеки для STM32. (_только все дефайны uint32_t передалны как uint64_t. Т.к. в MATLAB всё компилируется в 64-битном формате, то сохранении адресов в 32-битных переменных, адреса будут усекаться и будут ошибки._) +- **stm32f407xx_matlab.h** + Данный файл является копией "stm32f407xx.h" с некоторыми изменениями: + - добавлен кастомный "stdint.h" (через "", вместо <>) + - добавлен "arm_defines.h" с ARM дефайнами для MSVC + - добавлен матлабовский "cmsis_armcc_matlab.h" с вместо "cmsis_armcc.h" + - добавлена структура **имитирующая память ядра***. Для того, чтобы при обращении по адресам регистров МК не было исключений при чтении по недоступному адресу. +- **stm32f4xx.h** - оригинальный файл "stm32f4xx.h". +- **system_stm32f4xx.h** - оригинальный файл "system_stm32f4xx.h". + +_*память ядра не имитируется в полной мере, потому что STM32 - это 32-битный процессор, он имеет 4 Гб памяти. А MATLAB/MSVC делает ограничение на использование не больше 4Гб оперативной памяти. При этом еще есть матлабовские переменные которые тоже занимают место. Поэтому память эмулируется лишь частично. Как имено - задается в дефайнах и структуруре stm32f407xx_matlab.h._ + +###### Папка STM32F4xx_HAL_Driver +Данная библиотека является копией HAL, за некоторыми исключениями. В основном касаются макросов для ожидания флага. Т.к. весь МК реализован програмно, то надо самому писать код, который будет выставлять флаги по определенным условиям. Только тогда библиотека HAL будет это считывать и выполнять свои функции. Но далеко не всегда есть необходимость так делать. + +Поэтому, вместо того, чтобы пользоваться оригиальным HAL и писать эмулятор для всего 32-битного контроллера, можно переписать макросы или даже функции целиком под свои нужды. + +#### Код пользователя +Данная папка содержит исходный код приложения МК. При этом драйверы и стандартные/HAL библиотеки, которые общие для всех проектов следует помещать в [папку с эмулятором МК](#эмулятор-stm-для-matlab). Чтобы не редактировать исходники общих библиотек (CMSIS/HAL) в каждом проекте. + +## Инструкция +Общий алгоритм портирования кода для симуляции в MATLAB приведен ниже. В инструкции есть ссылки на более подробное описание действий. +1. [Портировать код для MATLAB](#портирование-кода) (можно начать с портирования без изменений и далее действовать от шага 2) +2. Проверить [компилируеться ли код](#как-скомпилировать-код). А далее: + - если есть ошибки при компиляции, [исправить их](#ошибки-при-компиляции) и вернуться на шаг 2. + - если ошибок нет, перейти на шаг 3. +3. Проверить нормально ли запускается и работает симуляция с МК. А далее: + - если симуляции вылетает, то необходимо [исправить ошибки](#ошибки-при-симуляции) в [режиме отладки](#как-запустить-отладку) и вернуться на шаг 3. + - если симуляция нормально запускается только один раз, и не завершается или не запускается второй раз, то необходимо [исправить ошибки](#ошибки-при-симуляции) в [режиме отладки](#как-запустить-отладку) и вернуться на шаг 3. + - если симуляция работает полностью корректно, перейти на шаг. 4. +4. Оценить результаты симуляции. А далее: + - если симуляция сходится с реальностью - то всё работает корректно. + - если нет - необходимо исправить ошибки в [драйверах](#эмулятор-и-периферия) и перейти на шаг 2. + +#### Портирование кода +###### Код программы +Для начала необходимо весь пользовательский код портировать в отдельную папку для удобства. Например в "_\Code_". + +Далее в "[run_bat.mex](#оболочка-мк)" надо прописать пути для заголовочных файлов (_\Includes_). Все файлы исходников "_*.c_" прописывать не обязательно. Можно прописать только папки с исходниками, как с заголовочными файлами. Далее скрипт сам сканирует и ищет все исходники. + +###### Эмулятор и библиотеки +Эмулятор и библиотеки связаны в том плане, что необходимо выбрать через что будет реализована периферия +- полноценный эмулятор, тогда функции библиотек остаются без изменений и просто работает не с реальной периферией, а с её эмулятором +- упрощенный эмулятор, тогда функции библиотек тоже надо или упростить или сделать их-dummy. +- игнорирование периферии. Если периферия не важна для симуляции, можно просто в программе МК убрать все выховы функций, связанные с ней или сделать их dummy. + +Скрипты для эмуляции периферии необходимо прописывать вручную. В случае 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), для которых [не определено адресное пространство в симуляции](#папка-cmsis). \ No newline at end of file