release 1.0

This commit is contained in:
2025-06-14 19:51:05 +03:00
commit 1bd5009b9d
25 changed files with 3386 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
/**
**************************************************************************
* @file mcu_wrapper.c
* @brief Исходный код оболочки МК.
**************************************************************************
@details
Данный файл содержит функции для симуляции МК в Simulink (S-Function).
**************************************************************************/
#include "mcu_wrapper_conf.h"
#include "app_wrapper.h"
/**
* @addtogroup WRAPPER_CONF
* @{
*/
SIM__MCUHandleTypeDef hmcu; ///< Хендл для управления потоком программы МК
// INPUT/OUTPUTS AUTO-PARAMS START
// INPUT/OUTPUTS AUTO-PARAMS END
/** MCU_WRAPPER
* @}
*/
//-------------------------------------------------------------//
//-----------------CONTROLLER SIMULATE FUNCTIONS---------------//
/* THREAD FOR MCU APP */
#ifdef RUN_APP_MAIN_FUNC_THREAD
/**
* @brief Главная функция приложения МК.
* @details Функция с которой начинается выполнение кода МК. Выход из данной функции происходит только в конце симуляции @ref mdlTerminate
*/
extern int main(void); // extern while from main.c
/**
* @brief Поток приложения МК.
* @details Поток, который запускает и выполняет код МК (@ref main).
*/
unsigned __stdcall MCU_App_Thread(void) {
main(); // run MCU code
return 0; // end thread
// note: this return will reached only at the end of simulation, when all whiles will be skipped due to @ref sim_while
}
#endif //RUN_APP_MAIN_FUNC_THREAD
/* SIMULATE MCU FOR ONE SIMULATION STEP */
/**
* @brief Симуляция МК на один такт симуляции.
* @param S - указатель на структуру S-Function из "simstruc.h"
* @param time - текущее время симуляции.
* @details Запускает поток, который выполняет код МК и управляет ходом потока:
* Если прошел таймаут, поток прерывается, симулируется периферия
* и на следующем шаге поток возобнавляется.
*
* Вызывается из mdlUpdate()
*/
void MCU_Step_Simulation(SimStruct* S, time_T time)
{
hmcu.SystemClockDouble += hmcu.sSystemClock_step; // emulate core clock
hmcu.SystemClock = hmcu.SystemClockDouble;
hmcu.SimTime = time;
MCU_readInputs(S); // считывание портов
MCU_Periph_Simulation(S); // simulate peripheral
#ifdef RUN_APP_MAIN_FUNC_THREAD
ResumeThread(hmcu.hMCUThread);
for (int i = DEKSTOP_CYCLES_FOR_MCU_APP; i > 0; i--)
{
}
SuspendThread(hmcu.hMCUThread);
#else
app_step();
#endif //RUN_APP_MAIN_FUNC_THREAD
MCU_writeOutputs(S); // запись портов (по факту запись в буфер. запись в порты в mdlOutputs)
}
/* SIMULATE MCU PERIPHERAL */
/**
* @brief Симуляция периферии МК
* @details Пользовательский код, который симулирует работу периферии МК.
*/
void MCU_Periph_Simulation(SimStruct* S)
{
// PERIPH SIM START
// PERIPH SIM END
}
/* READ INPUTS S-FUNCTION TO MCU REGS */
/**
* @brief Считывание входов S-Function в порты ввода-вывода.
* @param S - указатель на структуру S-Function из "simstruc.h"
* @details Пользовательский код, который записывает входы МК из входов S-Function.
*/
void MCU_readInputs(SimStruct* S)
{
SIM_readInputs(S);
/* Get S-Function descrete array (IO buffer) */
real_T* In_Buff = ssGetDiscStates(S);
app_readInputs(In_Buff);
}
/* WRITE OUTPUTS BUFFER S-FUNCTION FROM MCU REGS*/
/**
* @brief Запись портов ввода-вывода в буфер выхода S-Function
* @param S - указатель на структуру S-Function из "simstruc.h"
* @details Пользовательский код, который записывает буфер выходов S-Function из портов ввода-вывода.
*/
void MCU_writeOutputs(SimStruct* S)
{
/* Get S-Function descrete array (IO buffer) */
real_T* Out_Buff = ssGetDiscStates(S);
app_writeOutputBuffer(Out_Buff);
}
//-----------------CONTROLLER SIMULATE FUNCTIONS---------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//----------------------SIMULINK FUNCTIONS---------------------//
/* MCU WRAPPER DEINITIALIZATION */
/**
* @brief Инициализация симуляции МК.
* @details Пользовательский код, который создает поток для приложения МК
и настраивает симулятор МК для симуляции.
*/
void SIM_Initialize_Simulation(SimStruct* S)
{
#ifdef RUN_APP_MAIN_FUNC_THREAD
// инициализация потока, который будет выполнять код МК
hmcu.hMCUThread = (HANDLE)CreateThread(NULL, 0, MCU_App_Thread, 0, CREATE_SUSPENDED, &hmcu.idMCUThread);
#endif //RUN_APP_MAIN_FUNC_THREAD
/* user initialization */
app_init();
// PERIPH INIT START
// PERIPH INIT END
/* clock step initialization */
hmcu.sSystemClock_step = MCU_CORE_CLOCK * hmcu.sSimSampleTime; // set system clock step
hmcu.fInitDone = 1;
}
/* MCU WRAPPER DEINITIALIZATION */
/**
* @brief Деинициализация симуляции МК.
* @details Пользовательский код, который будет очищать все структуры после окончания симуляции.
*/
void SIM_deInitialize_Simulation(SimStruct* S)
{
#ifdef DEINITIALIZE_AFTER_SIM
// deinitialize app
app_deinit();
// PERIPH DEINIT START
// PERIPH DEINIT END
#endif// DEINITIALIZE_AFTER_SIM
}
/* WORK WITH IN/OUT BUFFER OF S-BLOCK */
/**
* @brief Функция для записи переменной в буфер выходов в определенный массив
* @param xD - указатель на буфер состояний
* @param value - значение для записи
* @param array_index - индекс выходного массива
* @param value_index - индекс внутри массива
*/
void __WriteOutputArray(real_T* xD, float value, int array_index, int value_index)
{
if (array_index >= OUT_PORT_NUMB)
return;
if (value_index >= outLengths[array_index])
return;
int global_index = XD_OUTPUT_START + outOffsets[array_index] + value_index;
xD[global_index] = value;
}
/**
* @brief Функция для чтения значения из буфера входов из определенного массива
* @param xD - указатель на буфер состояний
* @param array_index - индекс входного массива
* @param value_index - индекс внутри массива
* @return - считанное значение или 0.0 при выходе за границы
*/
float __ReadInputArray(const real_T* xD, int array_index, int value_index)
{
if (array_index >= IN_PORT_NUMB)
return 0.0f;
if (value_index >= inLengths[array_index])
return 0.0f;
int global_index = XD_INPUT_START + inOffsets[array_index] + value_index;
return xD[global_index];
}
/**
* @brief Формирование выходов S-Function.
* @param S - указатель на структуру S-Function из "simstruc.h"
* @details Пользовательский код, который записывает выходы S-Function из буфера дискретных состояний.
*/
void SIM_writeOutputs(SimStruct* S)
{
real_T* Output = ssGetOutputPortRealSignal(S,0);
real_T* Out_Buff = ssGetDiscStates(S);
int global_index;
//-------------WRITTING OUTPUT--------------
for (int j = 0; j < OUT_PORT_NUMB; j++)
{
Output = ssGetOutputPortRealSignal(S, j);
for (int i = 0; i < outLengths[i]; i++)
{
global_index = XD_OUTPUT_START + outOffsets[j] + i;
Output[i] = Out_Buff[global_index];
Out_Buff[global_index] = 0;
}
}
//------------------------------------------
}
/**
* @brief Формирование входов S-Function.
* @param S - указатель на структуру S-Function из "simstruc.h"
* @details Пользовательский код, который считывает входы S-Function в буфер дискретных состояний.
*/
void SIM_readInputs(SimStruct* S)
{
real_T* Input = ssGetInputPortRealSignal(S, 0);
real_T* In_Buff = ssGetDiscStates(S);
int global_index;
//-------------READING INPUTS---------------
for (int j = 0; j < IN_PORT_NUMB; j++)
{
Input = ssGetInputPortRealSignal(S, j);
for (int i = 0; i < inLengths[j]; i++)
{
global_index = XD_INPUT_START + inOffsets[j] + i;
In_Buff[global_index] = Input[i];
}
}
//------------------------------------------
}
//-------------------------------------------------------------//

View File

@@ -0,0 +1,219 @@
/**
**************************************************************************
* @dir ../MCU_Wrapper
* @brief <b> Папка с исходным кодом оболочки МК. </b>
* @details
В этой папке содержаться оболочка(англ. wrapper) для запуска и контроля
эмуляции микроконтроллеров в MATLAB (любого МК, не только STM).
Оболочка представляет собой S-Function - блок в Simulink, который работает
по скомпилированому коду. Компиляция происходит с помощью MSVC-компилятора.
**************************************************************************/
/**
**************************************************************************
* @file mcu_wrapper_conf.h
* @brief Заголовочный файл для оболочки МК.
**************************************************************************
@details
Главный заголовочный файл для матлаба. Включает дейфайны для S-Function,
объявляет базовые функции для симуляции МК и подключает базовые библиотеки:
- для симуляции "stm32fxxx_matlab_conf.h"
- для S-Function "simstruc.h"
- для потоков <process.h>
**************************************************************************/
#ifndef _WRAPPER_CONF_H_
#define _WRAPPER_CONF_H_
// Includes
#include "simstruc.h" // For S-Function variables
#include <process.h> // For threads
#include "app_includes.h"
/**
* @defgroup MCU_WRAPPER MCU Wrapper
* @brief Всякое для оболочки МК
*/
/**
* @addtogroup WRAPPER_CONF Wrapper Configuration
* @ingroup MCU_WRAPPER
* @brief Параметры конфигурации для оболочки МК
* @details Здесь дефайнами задается параметры оболочки, которые определяют как она будет работать
* @{
*/
// Parametrs of MCU simulator
//#define RUN_APP_MAIN_FUNC_THREAD ///< Enable using thread for MCU main() func
//#define DEKSTOP_CYCLES_FOR_MCU_APP 0xFFFF ///< number of for() cycles after which MCU thread would be suspended
//#define MCU_CORE_CLOCK 150000000 ///< MCU clock rate for simulation
// Parameters of S_Function
// INPUT/OUTPUTS PARAMS START
// INPUT/OUTPUTS PARAMS END
/** WRAPPER_CONF
* @}
*/
/**
* @addtogroup MCU_WRAPPER
* @{
*/
/** @brief Записывает значение в выходной массив блока S-Function
* @param _var_ Значение, которое необходимо записать (будет преобразовано в float)
* @param _arr_ind_ Индекс выходного порта
* @param _val_ind_ Индекс элемента в выходном массиве
*/
#define WriteOutputArray(_var_, _arr_ind_, _val_ind_) __WriteOutputArray(Buffer, (float)_var_, _arr_ind_, _val_ind_)
/** @brief Считывает значение из входного массива блока S-Function
* @param _var_ Значение, которое необходимо записать (будет преобразовано в float)
* @param _arr_ind_ Индекс входного порта
* @param _val_ind_ Индекс элемента во входном массиве
*/
#define ReadInputArray(_arr_ind_, _val_ind_) __ReadInputArray(Buffer, _arr_ind_, _val_ind_)
// INPUT/OUTPUTS AUTO-PARAMS START
// INPUT/OUTPUTS AUTO-PARAMS END
extern const int outLengths[OUT_PORT_NUMB];
extern const int outOffsets[OUT_PORT_NUMB];
extern const int inLengths[IN_PORT_NUMB];
extern const int inOffsets[IN_PORT_NUMB];
#define TOTAL_XD_SIZE (TOTAL_IN_SIZE + TOTAL_OUT_SIZE)
#define XD_INPUT_START 0
#define XD_OUTPUT_START (XD_INPUT_START + TOTAL_IN_SIZE)
// Fixed parameters(?) of S_Function
#define NPARAMS 1 ///< number of input parametrs (only Ts)
#define DISC_STATES_WIDTH TOTAL_XD_SIZE ///< width of discrete states array (outbup buffer)
/**
* @brief Define for creating thread in suspended state.
* @details Define from WinBase.h. We dont wanna include "Windows.h" or smth like this, because of HAL there are a lot of redefine errors.
*/
#define CREATE_SUSPENDED 0x00000004
typedef void* HANDLE; ///< MCU handle typedef
/**
* @brief MCU handle Structure definition.
* @note Prefixes: h - handle, s - settings, f - flag
*/
typedef struct {
// MCU Thread
HANDLE hMCUThread; ///< Хендл для потока МК
int idMCUThread; ///< id потока МК (unused)
// Flags
unsigned fMCU_Stop : 1; ///< флаг для выхода из потока программы МК
unsigned fInitDone : 1; ///< флаг для выхода из потока программы МК
double SimTime; ///< Текущее время симуляции
long SystemClock; ///< Счетчик тактов для симуляции системных тиков (в целочисленном формате)
double SystemClockDouble; ///< Счетчик в формате double для точной симуляции системных тиков С промежуточными значений
double sSystemClock_step; ///< Шаг тиков для их симуляции, в формате double
double sSimSampleTime; ///< Период дискретизации симуляции
}SIM__MCUHandleTypeDef;
extern SIM__MCUHandleTypeDef hmcu; // extern для видимости переменной во всех файлах
//-------------------------------------------------------------//
//------------------ SIMULINK WHILE DEFINES -----------------//
#ifdef RUN_APP_MAIN_FUNC_THREAD
/* DEFINE TO WHILE WITH SIMULINK WHILE */
/**
* @brief Redefine C while statement with sim_while() macro.
* @param _expression_ - expression for while.
* @details Это while который будет использоваться в симулинке @ref sim_while для подробностей.
*/
#define while(_expression_) sim_while(_expression_)
#endif
/* SIMULINK WHILE */
/**
* @brief While statement for emulate MCU code in Simulink.
* @param _expression_ - expression for while.
* @details Данный while необходим, чтобы в конце симуляции, завершить поток МК:
* При выставлении флага окончания симуляции, все while будут пропускаться
* и поток сможет дойти до конца функции main и завершить себя.
*/
#define sim_while(_expression_) while((_expression_)&&(hmcu.fMCU_Stop == 0))
/* DEFAULT WHILE */
/**
* @brief Default/Native C while statement.
* @param _expression_ - expression for while.
* @details Данный while - аналог обычного while, без дополнительного функционала.
*/
#define native_while(_expression_) for(; (_expression_); )
/***************************************************************/
//------------------ SIMULINK WHILE DEFINES -----------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//---------------- SIMULATE FUNCTIONS PROTOTYPES -------------//
/* Step simulation */
void MCU_Step_Simulation(SimStruct *S, time_T time);
/* MCU peripheral simulation */
void MCU_Periph_Simulation(SimStruct* S);
/* Initialize MCU simulation */
void SIM_Initialize_Simulation(SimStruct* S);
/* Deinitialize MCU simulation */
void SIM_deInitialize_Simulation(SimStruct* S);
/* Read inputs S-function */
void MCU_readInputs(SimStruct* S);
/* Write pre-outputs S-function (out_buff states) */
void MCU_writeOutputs(SimStruct* S);
/* Write outputs of block of S-Function*/
void SIM_writeOutputs(SimStruct* S);
/* Write inputs of block of S-Function*/
void SIM_readInputs(SimStruct* S);
/* Set output of block of S-Function*/
void __WriteOutputArray(real_T* xD, float value, int array_index, int value_index);
/* Get input of block of S-Function*/
float __ReadInputArray(const real_T* xD, int array_index, int value_index);
//---------------- SIMULATE FUNCTIONS PROTOTYPES -------------//
//-------------------------------------------------------------//
/** MCU_WRAPPER
* @}
*/
#endif // _WRAPPER_CONF_H_
//-------------------------------------------------------------//
//---------------------BAT FILE DESCRIBTION--------------------//
/**
* @file run_mex.bat
* @brief Батник для компиляции оболочки МК.
* @details
* Вызывается в матлабе из allmex.m.
*
* Исходный код батника:
* @include run_mex.bat
*/

View File

@@ -0,0 +1,115 @@
@echo off
:: Получаем аргументы из командной строки
:: %1 - includes_USER
:: %2 - code_USER
:: %3 - режим (например, debug)
:: Аргументы:
:: %1 — includes строка (в кавычках)
:: %2 — sources строка
:: %3 — defines строка
:: %4 — режим компиляции (debug/release)
:: Сохраняем как переменные
set includes_USER=%~1
set code_USER=%~2
set defines_USER=%~3
set defines_CONFIG=%~4
set compil_mode=%~5
:: Заменяем __EQ__ на =
set defines_USER=%defines_USER:__EQ__==%
set defines_CONFIG=%defines_CONFIG:__EQ__==%
set defines_WRAPPER=-D"MATLAB"^ -D"__sizeof_ptr=8"
:: -------------------------USERS PATHS AND CODE---------------------------
::-------------------------------------------------------------------------
:: -------------------------WRAPPER PATHS AND CODE---------------------------
:: оболочка, которая будет моделировать работу МК в симулинке
set includes_WRAPPER=-I"."^
-I".\MCU_Wrapper"^
-I".\app_wrapper"
set code_WRAPPER= .\MCU_Wrapper\MCU.c^
.\MCU_Wrapper\mcu_wrapper.c^
.\app_wrapper\app_init.c^
.\app_wrapper\app_io.c^
.\app_wrapper\app_wrapper.c
:: PERIPH BAT START
:: PERIPH BAT END
::-------------------------------------------------------------------------
:: ---------------------SET PARAMS FOR MEX COMPILING-----------------------
:: -------------ALL------------
set includes= %includes_WRAPPER% %includes_PERIPH% %includes_USER%
set codes= %code_WRAPPER% %code_PERIPH% %code_USER%
set defines= %defines_WRAPPER% %defines_CONFIG% %defines_USER%
:: -------OUTPUT FOLDER--------
set output= -outdir "."
:: если нужен дебаг, до запускаем run_mex с припиской debug
IF [%1]==[debug] (set debug= -g)
::-------------------------------------------------------------------------
::------START COMPILING-------
if "%6"=="echo_enable" (
echo Compiling...
echo ===========================
echo =========INCLUDES==========
echo USER:
for %%f in (%includes_USER%) do (
echo %%f
)
echo INTERNAL:
for %%f in (%includes_WRAPPER%) do (
echo %%f
)
echo PERIPH:
for %%f in (%includes_PERIPH%) do (
echo %%f
)
echo ===========================
echo ==========SOURCES==========
echo USER:
for %%f in (%code_USER%) do (
echo %%f
)
echo INTERNAL:
for %%f in (%code_WRAPPER%) do (
echo %%f
)
echo PERIPH:
for %%f in (%code_PERIPH%) do (
echo %%f
)
echo ===========================
echo ==========DEFINES==========
echo USER:
for %%d in (%defines_USER%) do (
echo %%d
)
echo CONFIG:
for %%f in (%defines_CONFIG%) do (
echo %%f
)
echo INTERNAL:
for %%f in (%defines_WRAPPER%) do (
echo %%f
)
)
echo ===========================
echo MODE: %compil_mode%
echo ===========================
mex %output% %defines% %includes% %codes% %debug%
echo %DATE% %TIME%
exit /b %ERRORLEVEL%