diplom/научка/README.html
2025-05-09 21:26:59 +03:00

155 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html><head><style>body {
color: black;
}
</style></head><body><h1 id="matlab-stm32-emulator">MATLAB STM32 EMULATOR</h1>
<p> <strong>СОДЕРЖАНИЕ</strong></p>
<ul>
<li><a href="#общая-структура-эмулятора">Общая структура эмулятора</a></li>
<li><a href="#описание-стуктуры-эмулятора-пример-для-stm32">Описание стуктуры эмулятора (пример для STM32)</a><ul>
<li><a href="#оболочка-мк">Оболочка МК</a></li>
<li><a href="#эмулятор-stm-для-matlab">Эмулятор STM для MATLAB</a></li>
<li><a href="#код-пользователя">Код пользователя</a></li>
</ul>
</li>
<li><a href="#инструкция">Инструкция</a><ul>
<li><a href="#портирование-кода">Портирование кода</a></li>
<li><a href="#как-скомпилировать-код">Как скомпилировать код</a></li>
<li><a href="#как-запустить-отладку">Как запустить отладку</a></li>
<li><a href="#ошибки">Ошибки при портировании</a></li>
</ul>
</li>
</ul>
<h2 id="-">Общая структура эмулятора</h2>
<p>Эмулятор состоит из блух блоков:</p>
<ul>
<li>приложение МК</li>
<li>оболочка МК для MATLAB, которая запускает приложение МК и эмулирует его периферию</li>
</ul>
<p>Приложение МК в свою очередь разделено еще на два блока:</p>
<ul>
<li>исходный код пользователя (код приложения)</li>
<li>исходный код библиотек и драйверов</li>
</ul>
<p>Для каждого блока своя папка. Всего три папки:</p>
<ul>
<li>Code (<a href="#код-пользователя"><em>код пользователя</em></a>)</li>
<li>MCU_STM32xxx<em>Matlab ([</em>эмулятор STM для MATLAB_](#эмулятор-stm-для-matlab))</li>
<li>MCU<em>Wrapper ([</em>оболочка МК<em>](#оболочка-мк))
</em>*в скобочках ссылки на подробное описание папки_</li>
</ul>
<p>Далее приведена структура эмулятора. Инструкция для портирования кода в MATLAB приведена <a href="#инструкция">ниже</a></p>
<h2 id="-stm32-">Описание стуктуры эмулятора (пример для STM32)</h2>
<p>Здесь содержиться описание трех блоков эмулятора:</p>
<ul>
<li><a href="#оболочка-мк">Оболочка МК</a></li>
<li><a href="#эмулятор-stm-для-matlab">Эмулятор STM для MATLAB</a></li>
<li><a href="#код-пользователя">Код пользователя</a></li>
</ul>
<h4 id="-">Оболочка МК</h4>
<p>В этой папке содержаться оболочка(англ. wrapper) для запуска и контроля эмуляции микроконтроллеров в MATLAB (любого МК, не только STM). Оболочка представляет собой S-Function - блок в Simulink, который работает по скомпилированому коду. Компиляция происходит с помощью MSVC-компилятора. </p>
<p>S-Function работает особым образом: на шаге <em>n</em> она запускает скомпилированный код и ждет пока этот код выполниться. Только когда завершается выполнение кода, S-Function переходит на следующий шаг <em>n</em>+1.</p>
<p>Но программа МК это бесконечный цикл, который никогда не завершается. Поэтому есть несколько особенностей в выполнении такого кода в виде S-Function:</p>
<ul>
<li>Для эмуляции создается отдельный поток для программы МК. Этот поток запускается в начале текущего шага симуляции, выполняется какое-то время, а потом приостанавливается. Это позволяет коду S-Function завершиться и перейти на следующий шаг.</li>
<li>Необходимо закрыть поток программы МК в конце симуляции. Для этого используется особый дефайн для while. Этот дефайн помимо условия while, проверяет условие окончания симуляции. И если симуляцию надо завершить, все бесконечные циклы <em>while()</em> пропускаются и поток доходит до конца функции <em>main()</em> и завершает себя.</li>
</ul>
<p>Всего оболочка содержит 4 файла:</p>
<ul>
<li>mcu_wrapper.c &emsp;&emsp;&emsp; - файл, который запускает код МК и управляет его ходом. В нем содержаться функции для запуска/остановки потока программы МК, считывании входов и запись входов S-Function в соответствии с I/O портами МК.</li>
<li>MCU.c &nbsp;&ensp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; - базовый файл, который представляет собой исходный код для компиляции S-Function в MATLAB. Вызывает функции из &quot;mcu_wrapper.c&quot;</li>
<li>mcu_wrapper_conf.h &ensp; - общий для mcu_wrapper.c и MCU.c заголовочный файл. Содержит настройки для блока S-Function, а также дефайны для управления ходом программы МК. </li>
<li>run_mex.bat &nbsp;&emsp;&emsp;&emsp;&emsp; - скрипт для компиляции кода компилятором MSVC. В нем прописываются пути для заголовочных файлов &quot;.h&quot;, указываются файлы исходного кода &quot;.c&quot; и прописываются дефайны для компиляции.</li>
</ul>
<h4 id="-stm-matlab">Эмулятор STM для MATLAB</h4>
<p>В папке &quot;_\MCU_STM32xxx<em>Matlab</em>&quot; есть два файла &quot;stm32fxxx_matlab_conf.c/.h&quot;. </p>
<p>В них задаётся используемая периферия и подключаются библиотеки для периферии. Также объявляются функкции для инициализации/деинициализации периферии МК и структуры для эмуляции периферии.</p>
<p>В папке &quot;_\MCU_STM32xxx<em>Matlab\Drivers</em>&quot; находяться стандартные библиотеки для STM/ARM, но переделанные под компилятор MSVC. Всего там три папки: <a href="#папка-stm32f4xx_simulink">STM32F4xx_SIMULINK</a>, <a href="#папка-cmsis">CMSIS</a>, <a href="#папка-stm32f4xx_hal_driver">STM32F4xx_HAL_Driver</a>.</p>
<h6 id="-stm32f4xx_simulink">Папка STM32F4xx_SIMULINK</h6>
<p>В этой папке содержаться файлы для эмуляции периферии STM32 в MATLAB. Структура файлов такая же, как в библиотеки HAL: </p>
<ul>
<li>название серии МК, который эмулируется (matlab), </li>
<li>идентификатор, что это для MATLAB (matlab), </li>
<li>периферия, функции для эмуляции которой содержит конкретный файл (gpio, tim).
Пример: &quot;stm32f4xx_matlab_tim.c/.h&quot;</li>
</ul>
<h6 id="-cmsis">Папка CMSIS</h6>
<p>&quot;Порт&quot; библиотеки CMSIS для MSVC. Ниже приведен перечень всех файлов и краткое описание зачем они нужны:</p>
<ul>
<li><strong>arm_defines.h</strong>
Содержит ARM дефайны для компиляции в MSVC.</li>
<li><strong>core_cm4_matlab.h</strong>
Данный файл является копией &quot;core_cm4.h&quot; с некоторыми изменениями<ul>
<li>удалены первые ~160 строк, которые определяют компилятор ARM. </li>
<li>добавлена структура <strong>имитирующая память ядра*</strong>. Для того, чтобы при обращении по адресам регистров МК не было исключений при чтении по недоступному адресу.</li>
</ul>
</li>
<li><strong>stdint.h</strong>
Данный файл является копией &quot;stdint.h&quot;, из библиотеки для STM32. (_только все дефайны uint32_t передалны как uint64<em>t. Т.к. в MATLAB всё компилируется в 64-битном формате, то сохранении адресов в 32-битных переменных, адреса будут усекаться и будут ошибки.</em>) </li>
<li><strong>stm32f407xx_matlab.h</strong>
Данный файл является копией &quot;stm32f407xx.h&quot; с некоторыми изменениями:<ul>
<li>добавлен кастомный &quot;stdint.h&quot; (через &quot;&quot;, вместо &lt;&gt;)</li>
<li>добавлен &quot;arm_defines.h&quot; с ARM дефайнами для MSVC</li>
<li>добавлен матлабовский &quot;cmsis_armcc_matlab.h&quot; с вместо &quot;cmsis_armcc.h&quot;</li>
<li>добавлена структура <strong>имитирующая память ядра*</strong>. Для того, чтобы при обращении по адресам регистров МК не было исключений при чтении по недоступному адресу.</li>
</ul>
</li>
<li><strong>stm32f4xx.h</strong> - оригинальный файл &quot;stm32f4xx.h&quot;.</li>
<li><strong>system_stm32f4xx.h</strong> - оригинальный файл &quot;system_stm32f4xx.h&quot;.</li>
</ul>
<p>_*память ядра не имитируется в полной мере, потому что STM32 - это 32-битный процессор, он имеет 4 Гб памяти. А MATLAB/MSVC делает ограничение на использование не больше 4Гб оперативной памяти. При этом еще есть матлабовские переменные которые тоже занимают место. Поэтому память эмулируется лишь частично. Как имено - задается в дефайнах и структуруре stm32f407xx<em>matlab.h.</em></p>
<h6 id="-stm32f4xx_hal_driver">Папка STM32F4xx_HAL_Driver</h6>
<p>Данная библиотека является копией HAL, за некоторыми исключениями. В основном касаются макросов для ожидания флага. Т.к. весь МК реализован програмно, то надо самому писать код, который будет выставлять флаги по определенным условиям. Только тогда библиотека HAL будет это считывать и выполнять свои функции. Но далеко не всегда есть необходимость так делать. </p>
<p>Поэтому, вместо того, чтобы пользоваться оригиальным HAL и писать эмулятор для всего 32-битного контроллера, можно переписать макросы или даже функции целиком под свои нужды.</p>
<h4 id="-">Код пользователя</h4>
<p>Данная папка содержит исходный код приложения МК. При этом драйверы и стандартные/HAL библиотеки, которые общие для всех проектов следует помещать в <a href="#эмулятор-stm-для-matlab">папку с эмулятором МК</a>. Чтобы не редактировать исходники общих библиотек (CMSIS/HAL) в каждом проекте.</p>
<h2 id="-">Инструкция</h2>
<p>Общий алгоритм портирования кода для симуляции в MATLAB приведен ниже. В инструкции есть ссылки на более подробное описание действий.</p>
<ol>
<li><a href="#портирование-кода">Портировать код для MATLAB</a> (можно начать с портирования без изменений и далее действовать от шага 2)</li>
<li>Проверить <a href="#как-скомпилировать-код">компилируеться ли код</a>. А далее:<ul>
<li>если есть ошибки при компиляции, <a href="#ошибки-при-компиляции">исправить их</a> и вернуться на шаг 2.</li>
<li>если ошибок нет, перейти на шаг 3.</li>
</ul>
</li>
<li>Проверить нормально ли запускается и работает симуляция с МК. А далее:<ul>
<li>если симуляции вылетает, то необходимо <a href="#ошибки-при-симуляции">исправить ошибки</a> в <a href="#как-запустить-отладку">режиме отладки</a> и вернуться на шаг 3.</li>
<li>если симуляция нормально запускается только один раз, и не завершается или не запускается второй раз, то необходимо <a href="#ошибки-при-симуляции">исправить ошибки</a> в <a href="#как-запустить-отладку">режиме отладки</a> и вернуться на шаг 3.</li>
<li>если симуляция работает полностью корректно, перейти на шаг. 4.</li>
</ul>
</li>
<li>Оценить результаты симуляции. А далее:<ul>
<li>если симуляция сходится с реальностью - то всё работает корректно. </li>
<li>если нет - необходимо исправить ошибки в <a href="#эмулятор-и-периферия">драйверах</a> и перейти на шаг 2.</li>
</ul>
</li>
</ol>
<h4 id="-">Портирование кода</h4>
<h6 id="-">Код программы</h6>
<p>Для начала необходимо весь пользовательский код портировать в отдельную папку для удобства. Например в &quot;<em>\Code</em>&quot;.</p>
<p>Далее в &quot;<a href="#оболочка-мк">run_bat.mex</a>&quot; надо прописать пути для заголовочных файлов (<em>\Includes</em>). Все файлы исходников &quot;<em>*.c</em>&quot; прописывать не обязательно. Можно прописать только папки с исходниками, как с заголовочными файлами. Далее скрипт сам сканирует и ищет все исходники. </p>
<h6 id="-">Эмулятор и библиотеки</h6>
<p>Эмулятор и библиотеки связаны в том плане, что необходимо выбрать через что будет реализована периферия</p>
<ul>
<li>полноценный эмулятор, тогда функции библиотек остаются без изменений и просто работает не с реальной периферией, а с её эмулятором</li>
<li>упрощенный эмулятор, тогда функции библиотек тоже надо или упростить или сделать их-dummy.</li>
<li>игнорирование периферии. Если периферия не важна для симуляции, можно просто в программе МК убрать все выховы функций, связанные с ней или сделать их dummy.</li>
</ul>
<p>Скрипты для эмуляции периферии необходимо прописывать вручную. В случае STM32 руководствоваться следует только регистрами CMSIS, чтобы не привязываться к HAL, и была возможность симуляции кода без него. Или же пробовать делать универсальный через дефайны, которые будут определять доступ к конкретным регистрам конкретного МК.</p>
<h6 id="-">Примеры эмуляции периферии</h6>
<p><strong>Пример 1 (полноценный эмулятор):</strong> можно написать полный эмулятор для таймеров, т.к. это очень важна часть МК. Плюс она часто корректируется: разные режимы таймеров, разная частота, разные каналы. И удобно, если всё это можно менять &quot;на ходу&quot;, а не только во время компиляциию.</p>
<p><strong>Пример 2 (упрощенный эмулятор):</strong> В случае, если не нужна эмуляция периферии. Например для протоколов общения, типа UART/MODBUS, можно просто сделать отдельные входы в S-Function, и напрямую брать значения оттуда и записывать в переменные программы, без приёма отдельных битов, парсинга и прочего. Но тогда надо будет редактировать библиотеки и делать dummy-функции, чтобы они не ждали ответа от периферии, которая не эмулируется. Или же редактировать пользовательский код.</p>
<p><strong>Пример 3 (игнорирование периферии):</strong> CubeMX использует функции RCC_Config, которые настраивают тактирование МК. В HAL&#39;e в функции инициализации постоянно используются bit-banding, который реализован аппаратно. Это некоторые адресса, которые могут переключать отдельные биты через присваивание (сродни BSRR у GPIO, только для всей периферии). Плюс еще HAL дополнительно проверяет реально ли выставились эти биты в регистрах, поэтому с этим надо что-то сделать. Т.к. регистры RCC не важны для симуляции большинства программ, можно просто убрать единственный вызов этой функции в main, или сделать её dummy - в HAL-библиотеке.</p>
<p>После портирования кода надо скомпилировать код МК и далее уже смотреть по <a href="#ошибки-при-компиляции">ошибкам</a>, что надо исправлять.</p>
<h4 id="-">Как скомпилировать код</h4>
<p>Для компиляции кода необходимо открыть файл mexing.m. Это MATLAB-скрипт, который запускает скрипт &quot;<a href="#оболочка-мк">run_bat.mex</a>&quot; для компиляции. Также этот файл задает время дискретизации для симуляции и дает возможность компиляции кода для <a href="#как-запустить-отладку">отладки</a></p>
<h4 id="-">Как запустить отладку</h4>
<p>Для отладки симуляции необходимо приписать в mexing.m в вызове &quot;run_mex.bat&quot; слово debug, тогда код скомпилируется для дебага. После этого необходимо открыть любой(?) редактор кода, например Visual Studio. Открыть папку проекта (там должны быть все исходники программы и эмулятора). И подключиться к MATLAB.exe.</p>
<p>Теперь можно поставить точку в исходном коде эмулятора или программы МК и запустить симуляцию. Когда MATLAB дойдет до этого места, симуляция остановиться и в Visual Studio можно будет посмотреть все переменные, пройти код по строкам и в общем делать всё то, что можно делать в режиме отладки.
Но отладка рабоатет только один раз. При повторном запуске симуляции остановки не произойдет. Поэтому перед каждой отладкой надо перекомпилировать код.</p>
<h4 id="-">Ошибки</h4>
<h5 id="-">Ошибки при компиляции</h5>
<p>Самые распространеные ошибки компилятора при портировании нового кода - это ошибки переопределения. Связаны с weak-фукнциями. В MSVC их нет как таковых. Поэтому необходимо закомментировать все weak-функции в HAL или пользовательском коде, чтобы на весь код было только одно определение функции.</p>
<h5 id="-">Ошибки при симуляции</h5>
<p>Обычно это исключения при чтении по недоступному адресу. Связано с разным адресным пространством МК и ПК. Поэтому надо выяснить на какой строке произошло исключение. И смотреть по какому адресу произошла попытка чтения и по какому адресу надо на самом деле считывать. И после этого скорректировать код так, чтобы адрес брался корректный.</p>
<p>Из общих решений - это может быть при попытки чтения по &quot;экзотическим&quot; адресам (bit-banding), для которых <a href="#папка-cmsis">не определено адресное пространство в симуляции</a>.</p>
</body></html>