From aa27973f6119e56e2f1123d1a89e523f842d95df Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Sun, 19 Jan 2025 12:19:24 +0300 Subject: [PATCH] wrapper init --- .gitignore | 63 ++++++++ Inu/MCU.c | 205 ++++++++++++++++++++++++ Inu/app_wrapper | 1 + Inu/mcu_wrapper.c | 176 +++++++++++++++++++++ Inu/mcu_wrapper_conf.h | 180 ++++++++++++++++++++++ Inu/xilinx_wrapper/adc_sim.c | 3 + Inu/xilinx_wrapper/adc_sim.h | 12 ++ Inu/xilinx_wrapper/pwm_sim.c | 291 +++++++++++++++++++++++++++++++++++ Inu/xilinx_wrapper/pwm_sim.h | 116 ++++++++++++++ README.md | 126 ++++++++++++++- allmex.m | 16 ++ asynchronous_machine.p | Bin 0 -> 1232 bytes electr_mach.slx | Bin 0 -> 41878 bytes 13 files changed, 1188 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Inu/MCU.c create mode 160000 Inu/app_wrapper create mode 100644 Inu/mcu_wrapper.c create mode 100644 Inu/mcu_wrapper_conf.h create mode 100644 Inu/xilinx_wrapper/adc_sim.c create mode 100644 Inu/xilinx_wrapper/adc_sim.h create mode 100644 Inu/xilinx_wrapper/pwm_sim.c create mode 100644 Inu/xilinx_wrapper/pwm_sim.h create mode 100644 allmex.m create mode 100644 asynchronous_machine.p create mode 100644 electr_mach.slx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f9184b --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +# ---> MATLAB +# Windows default autosave extension +*.asv + +# OSX / *nix default autosave extension +*.m~ + +# Compiled MEX binaries (all platforms) +*.mex* + +# Packaged app and toolbox files +*.mlappinstall +*.mltbx + +# Generated helpsearch folders +helpsearch*/ + +# Simulink code generation folders +slprj/ +sccprj/ + +# Matlab code generation folders +codegen/ + +# Simulink autosave extension +*.autosave + +# Simulink cache files +*.slxc + +# Octave session info +octave-workspace + + +/.vs/Inu_im_2wnd_3lvl_23550/v16/.suo +/.vs/Inu_im_2wnd_3lvl_23550/v16/Browse.VC.db +/.vs/Inu_im_2wnd_3lvl_23550/v16/Browse.VC.db-shm +/.vs/Inu_im_2wnd_3lvl_23550/v16/Browse.VC.db-wal +/.vs/Inu_im_2wnd_3lvl_23550/v16/Browse.VC.opendb +/.vs/ProjectSettings.json +/.vs/slnx.sqlite +/slprj/_cgxe/inu_im_2wnd_3lvl/inu_im_2wnd_3lvl_Cache.mat +/slprj/_jitprj/4jSHq6tpkAOru8OWjpPNFB.l +/slprj/_jitprj/4jSHq6tpkAOru8OWjpPNFB.mat +/slprj/accel/inu_im_2wnd_3lvl/amsi_serial.mat +/slprj/accel/inu_im_2wnd_3lvl/inu_im_2wnd_3lvl_instrumentation_settings.mat +/slprj/accel/inu_im_2wnd_3lvl/inu_im_2wnd_3lvl_SolverChangeInfo.mat +/slprj/accel/inu_im_2wnd_3lvl/inu_im_2wnd_3lvl_top_vm.bc +/slprj/accel/inu_im_2wnd_3lvl/inu_im_2wnd_3lvl_top_vm.ll +/slprj/accel/inu_im_2wnd_3lvl/tmwinternal/simulink_cache.xml +/slprj/sim/varcache/inu_im_2wnd_3lvl/checksumOfCache.mat +/slprj/sim/varcache/inu_im_2wnd_3lvl/tmwinternal/simulink_cache.xml +/slprj/sim/varcache/inu_im_2wnd_3lvl/varInfo.mat +/slprj/sl_proj.tmw + + + +/slprj/ +/.vs/ + + +init.m +inu_23550.slx \ No newline at end of file diff --git a/Inu/MCU.c b/Inu/MCU.c new file mode 100644 index 0000000..6cca00c --- /dev/null +++ b/Inu/MCU.c @@ -0,0 +1,205 @@ +/** +************************************************************************** +* @file MCU.c +* @brief Исходный код S-Function. +************************************************************************** +@details +Данный файл содержит функции S-Function, который вызывает MATLAB. +************************************************************************** +@note +Описание функций по большей части сгенерировано MATLAB'ом, поэтому на английском +**************************************************************************/ + +/** + * @addtogroup WRAPPER_SFUNC S-Function funtions + * @ingroup MCU_WRAPPER + * @brief Дефайны и функции блока S-Function + * @details Здесь собраны функции, с которыми непосредственно работает S-Function + * @note Описание функций по большей части сгенерировано MATLAB'ом, поэтому на английском + * @{ + */ + +#define S_FUNCTION_NAME wrapper_inu +#define S_FUNCTION_LEVEL 2 + +#include "mcu_wrapper_conf.h" + +#define MDL_UPDATE ///< для подключения mdlUpdate() +/** + * @brief Update S-Function at every step of simulation + * @param S - pointer to S-Function (library struct from "simstruc.h") + * @details Abstract: + * This function is called once for every major integration time step. + * Discrete states are typically updated here, but this function is useful + * for performing any tasks that should only take place once per + * integration step. + */ +static void mdlUpdate(SimStruct *S) +{ + // get time of simulation + time_T TIME = ssGetT(S); + + //---------------SIMULATE MCU--------------- + MCU_Step_Simulation(S, TIME); // SIMULATE MCU + //------------------------------------------ +}//end mdlUpdate + +/** + * @brief Writting outputs of S-Function + * @param S - pointer to S-Function (library struct from "simstruc.h") + * @details Abstract: + * In this function, you compute the outputs of your S-function + * block. Generally outputs are placed in the output vector(s), + * ssGetOutputPortSignal. + */ +static void mdlOutputs(SimStruct *S) +{ + SIM_writeOutputs(S); +}//end mdlOutputs + +#define MDL_CHECK_PARAMETERS /* Change to #undef to remove function */ +#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE) +static void mdlCheckParameters(SimStruct *S) +{ + int i; + + // Проверяем и принимаем параметры и разрешаем или запрещаем их менять + // в процессе моделирования + for (i=0; i<1; i++) + { + // Input parameter must be scalar or vector of type double + if (!mxIsDouble(ssGetSFcnParam(S,i)) || mxIsComplex(ssGetSFcnParam(S,i)) || + mxIsEmpty(ssGetSFcnParam(S,i))) + { + ssSetErrorStatus(S,"Input parameter must be of type double"); + return; + } + // Параметр м.б. только скаляром, вектором или матрицей + if (mxGetNumberOfDimensions(ssGetSFcnParam(S,i)) > 2) + { + ssSetErrorStatus(S,"Параметр м.б. только скаляром, вектором или матрицей"); + return; + } +// sim_dt = mxGetPr(ssGetSFcnParam(S,0))[0]; + // Parameter not tunable +// ssSetSFcnParamTunable(S, i, SS_PRM_NOT_TUNABLE); + // Parameter tunable (we must create a corresponding run-time parameter) + ssSetSFcnParamTunable(S, i, SS_PRM_TUNABLE); + // Parameter tunable only during simulation +// ssSetSFcnParamTunable(S, i, SS_PRM_SIM_ONLY_TUNABLE); + + }//for (i=0; i 0; i--) + { + } + SuspendThread(hmcu.hMCUThread); +#endif //RUN_APP_MAIN_FUNC_THREAD + + MCU_writeOutputs(S); // запись портов (по факту запись в буфер. запись в порты в mdlOutputs) +} + +/* SIMULATE MCU PERIPHERAL */ +/** + * @brief Симуляция периферии МК + * @details Пользовательский код, который симулирует работу периферии МК. + */ +void MCU_Periph_Simulation(void) +{ + Simulate_PWM(); +} + +/* READ INPUTS S-FUNCTION TO MCU REGS */ +/** + * @brief Считывание входов S-Function в порты ввода-вывода. + * @param S - указатель на структуру S-Function из "simstruc.h" + * @details Пользовательский код, который записывает входы МК из входов S-Function. + */ +void MCU_readInputs(SimStruct* S) +{ + /* Get S-Function inputs */ + real_T* IN = ssGetInputPortRealSignal(S, 0); + + readInputParameters(IN); +} + +/* 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 */ + real_T* Out_Buff = ssGetDiscStates(S); + + writeOutputParameters(Out_Buff); +} +//-----------------CONTROLLER SIMULATE FUNCTIONS---------------// +//-------------------------------------------------------------// + + + +//-------------------------------------------------------------// +//----------------------SIMULINK FUNCTIONS---------------------// +/* MCU WRAPPER DEINITIALIZATION */ +/** + * @brief Инициализация симуляции МК. + * @details Пользовательский код, который создает поток для приложения МК + и настраивает симулятор МК для симуляции. + */ +void SIM_Initialize_Simulation(void) +{ +#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 */ + Init_PWM_Simulation(); + app_init(); + + /* clock step initialization */ + hmcu.sSystemClock_step = MCU_CORE_CLOCK * hmcu.sSimSampleTime; // set system clock step +} +/* MCU WRAPPER DEINITIALIZATION */ +/** + * @brief Деинициализация симуляции МК. + * @details Пользовательский код, который будет очищать все структуры после окончания симуляции. + */ +void SIM_deInitialize_Simulation(void) +{ + //// simulate structures of peripheral deinitialization + //deInitialize_Periph_Sim(); + //// mcu peripheral memory deinitialization + //deInitialize_MCU(); +} +/* WRITE OUTPUTS OF S-BLOCK */ +/** + * @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); + + //-------------WRITTING OUTPUT-------------- + for (int i = 0; i < OUT_PORT_WIDTH; i++) + Output[i] = Out_Buff[i]; + //for (int j = 0; j < OUT_PORT_NUMB; j++) + //{ + // GPIO = ssGetOutputPortRealSignal(S, j); + // for (int i = 0; i < OUT_PORT_WIDTH; i++) + // { + // GPIO[i] = Out_Buff[j * OUT_PORT_WIDTH + i]; + // Out_Buff[j * OUT_PORT_WIDTH + i] = 0; + // } + //} + //------------------------------------------ +} +//-------------------------------------------------------------// diff --git a/Inu/mcu_wrapper_conf.h b/Inu/mcu_wrapper_conf.h new file mode 100644 index 0000000..7ef62bd --- /dev/null +++ b/Inu/mcu_wrapper_conf.h @@ -0,0 +1,180 @@ +/** +************************************************************************** +* @dir ../MCU_Wrapper +* @brief Папка с исходным кодом оболочки МК. +* @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" +- для потоков +**************************************************************************/ +#ifndef _WRAPPER_CONF_H_ +#define _WRAPPER_CONF_H_ + +// Includes +#include "simstruc.h" // For S-Function variables +#include // 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 +#define IN_PORT_WIDTH 20 ///< width of input ports +#define IN_PORT_NUMB 1 ///< number of input ports +#define OUT_PORT_WIDTH 51 ///< width of output ports +#define OUT_PORT_NUMB 1 ///< number of output ports + + +#define RWORK_0_WIDTH 5 //width of the real-work vector +#define IWORK_0_WIDTH 5 //width of the integer-work vector + + +/** WRAPPER_CONF + * @} + */ + + +/** + * @addtogroup MCU_WRAPPER + * @{ + */ + +// Fixed parameters(?) of S_Function +#define NPARAMS 1 ///< number of input parametrs (only Ts) +#define DISC_STATES_WIDTH OUT_PORT_WIDTH*OUT_PORT_NUMB ///< 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; ///< флаг для выхода из потока программы МК + + 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(void); + +/* Initialize MCU simulation */ +void SIM_Initialize_Simulation(void); + +/* Deinitialize MCU simulation */ +void SIM_deInitialize_Simulation(void); + +/* 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_writeOutput(SimStruct* S); +//---------------- SIMULATE FUNCTIONS PROTOTYPES -------------// +//-------------------------------------------------------------// + +/** MCU_WRAPPER + * @} + */ +#endif // _WRAPPER_CONF_H_ + + +//-------------------------------------------------------------// +//---------------------BAT FILE DESCRIBTION--------------------// +/** + * @file run_mex.bat + * @brief Батник для компиляции оболочки МК. + * @details + * Вызывается в матлабе из allmex.m. + * + * Исходный код батника: + * @include run_mex.bat + */ \ No newline at end of file diff --git a/Inu/xilinx_wrapper/adc_sim.c b/Inu/xilinx_wrapper/adc_sim.c new file mode 100644 index 0000000..ef81c81 --- /dev/null +++ b/Inu/xilinx_wrapper/adc_sim.c @@ -0,0 +1,3 @@ +#include "adc_sim.h" + +AdcSimHandle adcsim; diff --git a/Inu/xilinx_wrapper/adc_sim.h b/Inu/xilinx_wrapper/adc_sim.h new file mode 100644 index 0000000..03b98a2 --- /dev/null +++ b/Inu/xilinx_wrapper/adc_sim.h @@ -0,0 +1,12 @@ +#ifndef PWM_SIM +#define PWM_SIM + +// ADC +typedef struct +{ + int tAdc; + int Tadc; + int nAdc; +}AdcSimHandle; + +#endif //PWM_SIM diff --git a/Inu/xilinx_wrapper/pwm_sim.c b/Inu/xilinx_wrapper/pwm_sim.c new file mode 100644 index 0000000..5cf73c4 --- /dev/null +++ b/Inu/xilinx_wrapper/pwm_sim.c @@ -0,0 +1,291 @@ +#include "pwm_sim.h" + +TimerSimHandle t1sim; +TimerSimHandle t2sim; +TimerSimHandle t3sim; +TimerSimHandle t4sim; +TimerSimHandle t5sim; +TimerSimHandle t6sim; +TimerSimHandle t7sim; +TimerSimHandle t8sim; +TimerSimHandle t9sim; +TimerSimHandle t10sim; +TimerSimHandle t11sim; +TimerSimHandle t12sim; + +PWMPhaseSimHandle PWMPhaseA1; +PWMPhaseSimHandle PWMPhaseB1; +PWMPhaseSimHandle PWMPhaseC1; +PWMPhaseSimHandle PWMPhaseA2; +PWMPhaseSimHandle PWMPhaseB2; +PWMPhaseSimHandle PWMPhaseC2; + +void Simulate_PWM(void) +{ + Simulate_PWMPhase(&PWMPhaseA1, xpwm_time.Ta0_1, xpwm_time.Ta0_0); + Simulate_PWMPhase(&PWMPhaseB1, xpwm_time.Tb0_1, xpwm_time.Tb0_0); + Simulate_PWMPhase(&PWMPhaseC1, xpwm_time.Tc0_1, xpwm_time.Tc0_0); + Simulate_PWMPhase(&PWMPhaseA2, xpwm_time.Ta1_1, xpwm_time.Ta1_0); + Simulate_PWMPhase(&PWMPhaseB2, xpwm_time.Tb1_1, xpwm_time.Tb1_0); + Simulate_PWMPhase(&PWMPhaseC2, xpwm_time.Tc1_1, xpwm_time.Tc1_0); +} + +void Init_PWM_Simulation(void) +{ + Init_PWMPhase_Simulation(&PWMPhaseA1, &t1sim, &t2sim, + PWM_PERIOD, PWM_TICK_STEP); + + Init_PWMPhase_Simulation(&PWMPhaseB1, &t3sim, &t4sim, + PWM_PERIOD, PWM_TICK_STEP); + + Init_PWMPhase_Simulation(&PWMPhaseC1, &t5sim, &t6sim, + PWM_PERIOD, PWM_TICK_STEP); + + Init_PWMPhase_Simulation(&PWMPhaseA2, &t7sim, &t8sim, + PWM_PERIOD, PWM_TICK_STEP); + + Init_PWMPhase_Simulation(&PWMPhaseB2, &t9sim, &t10sim, + PWM_PERIOD, PWM_TICK_STEP); + + Init_PWMPhase_Simulation(&PWMPhaseC2, &t11sim, &t12sim, + PWM_PERIOD, PWM_TICK_STEP); + + + t1sim.simulatePwm = (void (*)())Simulate_MainTIM; +} + + + +void Simulate_PWMPhase(PWMPhaseSimHandle* tksim, int T1, int T0) +{ + tksim->tsim1->simulatePwm(tksim->tsim1, T1); + tksim->tsim2->simulatePwm(tksim->tsim2, T0); + +#ifdef PWM_SIMULATION_MODE_TK_LINES + convertSVGenTimesToTkLines(tksim); + xilinxPwm3LevelSimulation(tksim); +#endif + +#ifdef PWM_SIMULATION_MODE_REGULAR_PWM + simulateActionActionQualifierSubmodule(tksim->tsim1); + simulateDeadBendSubmodule(tksim->tsim1, &tksim->pwmOut.ci1A, &tksim->pwmOut.ci1B); + simulateTripZoneSubmodule(tksim->tsim1); + + simulateActionActionQualifierSubmodule(tksim->tsim2); + simulateDeadBendSubmodule(tksim->tsim2, &tksim->pwmOut.ci2A, &tksim->pwmOut.ci2B); + simulateTripZoneSubmodule(tksim->tsim2); +#endif +} + +void Simulate_MainTIM(TimerSimHandle* tsim, int compare) +{ +#ifdef ENABLE_UNITED_COUNTER_FOR_ALL_PWM + tsim->tcntAuxPrev = tsim->tcntAux; + tsim->tcntAux += tsim->TxCntPlus; +#endif + if (simulateTimAndGetCompare(tsim, compare)) + mcu_simulate_step(); +} + +void Simulate_SimpleTIM(TimerSimHandle* tsim, int compare) +{ + simulateTimAndGetCompare(tsim, compare); +} + + +int simulateTimAndGetCompare(TimerSimHandle* tsim, int compare) +{ + int interruptflag = 0; + +#ifdef ENABLE_UNITED_COUNTER_FOR_ALL_PWM + tsim->tcntAuxPrev = t1sim.tcntAuxPrev; + tsim->tcntAux = t1sim.tcntAux; +#else + tsim->tcntAuxPrev = tsim->tcntAux; + tsim->tcntAux += tsim->TxCntPlus; +#endif + + if (tsim->tcntAux > tsim->TxPeriod) { + tsim->tcntAux -= tsim->TxPeriod * 2.; + tsim->cmpA = compare; + interruptflag = 1; + } + if ((tsim->tcntAuxPrev < 0) && (tsim->tcntAux >= 0)) { + tsim->cmpA = compare; + interruptflag = 1; + } + tsim->tcnt = fabs(tsim->tcntAux); + return interruptflag; +} + + +void convertSVGenTimesToTkLines(PWMPhaseSimHandle *tksim) { + TimerSimHandle* tsim1 = tksim->tsim1; + TimerSimHandle* tsim2 = tksim->tsim2; + //Phase Uni + if ((tsim1->cmpA < tsim1->tcnt) && (tsim2->cmpA < tsim2->tcnt)) { + tksim->tkLineA = 0; + tksim->tkLineB = 1; + } + else if ((tsim1->cmpA > tsim1->tcnt) && (tsim2->cmpA > tsim2->tcnt)) { + tksim->tkLineA = 1; + tksim->tkLineB = 0; + } + else if ((tsim1->cmpA < tsim1->tcnt) && (tsim2->cmpA > tsim2->tcnt)) { + //. . . + tksim->tkLineA = 1; + tksim->tkLineB = 1; + } + else { + tksim->tkLineA = 0; + tksim->tkLineB = 0; + } + +} + + +void xilinxPwm3LevelSimulation(PWMPhaseSimHandle *tksim) { + TimerSimHandle* tsim1 = tksim->tsim1; + TimerSimHandle* tsim2 = tksim->tsim2; + DeadTimeSimHandle* deadtime = &tksim->deadtime; + PWMPhaseOutput* pwmOut = &tksim->pwmOut; + + // + //PhaseA Uni1 + if (tksim->tkLineB == 0 && tksim->tkLineA == 1) { + if ((pwmOut->ci1A == 0 || pwmOut->ci2A == 0) && deadtime->stateDt == stateDtReady) { + pwmOut->ci1B = 0; + pwmOut->ci2B = 0; + deadtime->dtcnt = deadtime->DtPeriod; + deadtime->stateDt = stateDtWait; + } + if (deadtime->stateDt == stateDtWait) { + if (deadtime->dtcnt > 0) + deadtime->dtcnt--; + else + deadtime->stateDt = stateDtReady; + } + if (deadtime->stateDt == stateDtReady) { + pwmOut->ci1A = 1; + pwmOut->ci2A = 1; + pwmOut->ci1B = 0; + pwmOut->ci2B = 0; + } + } + else if (tksim->tkLineB == 1 && tksim->tkLineA == 0) { + if ((pwmOut->ci1B == 0 || pwmOut->ci2B == 0) && deadtime->stateDt == stateDtReady) { + pwmOut->ci1A = 0; + pwmOut->ci2B = 0; + deadtime->dtcnt = deadtime->DtPeriod; + deadtime->stateDt = stateDtWait; + } + if (deadtime->stateDt == stateDtWait) { + if (deadtime->dtcnt > 0) + deadtime->dtcnt--; + else + deadtime->stateDt = stateDtReady; + } + if (deadtime->stateDt == stateDtReady) { + pwmOut->ci1A = 0; + pwmOut->ci2A = 0; + pwmOut->ci1B = 1; + pwmOut->ci2B = 1; + } + } + else if (tksim->tkLineA == 0 && tksim->tkLineB == 0) { + if ((pwmOut->ci1B == 0 || pwmOut->ci2A == 0) && deadtime->stateDt == stateDtReady) { + pwmOut->ci1A = 0; + pwmOut->ci2B = 0; + deadtime->dtcnt = deadtime->DtPeriod; + deadtime->stateDt = stateDtWait; + } + if (deadtime->stateDt == stateDtWait) { + if (deadtime->dtcnt > 0) + deadtime->dtcnt--; + else + deadtime->stateDt = stateDtReady; + } + if (deadtime->stateDt == stateDtReady) { + pwmOut->ci1A = 0; + pwmOut->ci2A = 1; + pwmOut->ci1B = 1; + pwmOut->ci2B = 0; + } + } + else { + pwmOut->ci1A = 0; + pwmOut->ci2A = 0; + pwmOut->ci1B = 0; + pwmOut->ci2B = 0; + } +} + +void simulateActionActionQualifierSubmodule(TimerSimHandle* tsim) +{ + // Action-Qualifier Submodule + if (tsim->cmpA > tsim->tcnt) { + tsim->deadtime.pre_ciA = 0; + tsim->deadtime.pre_ciB = 1; + } + else if (tsim->cmpA < tsim->tcnt) { + tsim->deadtime.pre_ciA = 1; + tsim->deadtime.pre_ciB = 0; + } +} + +void simulateDeadBendSubmodule(TimerSimHandle* tsim, int* ciA, int* ciB) +{ + // Dead-Band Submodule + if (tsim->deadtime.stateDt == 0) { + *ciA = tsim->deadtime.pre_ciA; + *ciB = 0; + if (tsim->deadtime.pre_ciA == 1) + tsim->deadtime.dtcnt = tsim->deadtime.DtPeriod; + if (tsim->deadtime.dtcnt > 0) + tsim->deadtime.dtcnt--; + else + tsim->deadtime.stateDt = 1; + } + else if (tsim->deadtime.stateDt == 1) { + *ciA = 0; + *ciB = tsim->deadtime.pre_ciB; + if (tsim->deadtime.pre_ciB == 1) + tsim->deadtime.dtcnt = tsim->deadtime.DtPeriod; + if (tsim->deadtime.dtcnt > 0) + tsim->deadtime.dtcnt--; + else + tsim->deadtime.stateDt = 0; + } +} + +void simulateTripZoneSubmodule(TimerSimHandle* tsim) +{ + // Trip-Zone Submodule + // ... clear flag for one-shot trip latch + // // ... clear flag for one-shot trip latch + //if (EPwm1Regs.TZCLR.all == 0x0004) { + // EPwm1Regs.TZCLR.all = 0x0000; + // EPwm1Regs.TZFRC.all = 0x0000; + //} // ... forces a one-shot trip event + //if (EPwm1Regs.TZFRC.all == 0x0004) + // ci1A_DT = ci1B_DT = 0; +} + + +void Init_PWMPhase_Simulation(PWMPhaseSimHandle* tksim, TimerSimHandle* tsim1, TimerSimHandle* tsim2, int period, double step) +{ + tksim->tsim1 = tsim1; + tksim->tsim2 = tsim2; + + Init_TIM_Simulation(tksim->tsim1, period, step); + Init_TIM_Simulation(tksim->tsim2, period, step); +} + +void Init_TIM_Simulation(TimerSimHandle* tsim, int period, double step) +{ + tsim->deadtime.stateDt = stateDtWait; + tsim->TxPeriod = period; + tsim->TxCntPlus = step * 2; + tsim->deadtime.DtPeriod = (int)(DT / hmcu.sSimSampleTime); + tsim->simulatePwm = (void (*)())Simulate_SimpleTIM; +} \ No newline at end of file diff --git a/Inu/xilinx_wrapper/pwm_sim.h b/Inu/xilinx_wrapper/pwm_sim.h new file mode 100644 index 0000000..9c814c5 --- /dev/null +++ b/Inu/xilinx_wrapper/pwm_sim.h @@ -0,0 +1,116 @@ +#include "mcu_wrapper_conf.h" + +#ifndef PWM_SIM +#define PWM_SIM + + + +#define ENABLE_UNITED_COUNTER_FOR_ALL_PWM + + +#define PWM_SIMULATION_MODE_TK_LINES +//#define PWM_SIMULATION_MODE_REGULAR_PWM + +#define PWM_PERIOD (FREQ_INTERNAL_GENERATOR_XILINX_TMS / FREQ_PWM) +#define PWM_TICK_STEP (FREQ_INTERNAL_GENERATOR_XILINX_TMS * hmcu.sSimSampleTime) + +// Для моделирования ШИМ +/** +* @brief 3lvl PWM One Phase Simulation handle +*/ +typedef struct +{ + int ci1A; + int ci1B; + int ci2A; + int ci2B; + +}PWMPhaseOutput; +/** +* @brief DeadTime Simulation Handle +*/ +typedef struct +{ + int DtPeriod; + int stateDt; + int dtcnt; + int pre_ciA; + int pre_ciB; +}DeadTimeSimHandle; +enum StateDeadTime { + stateDtWait = 0, + stateDtReady +}; +/** +* @brief Tim Simulation Handle +*/ +typedef struct +{ + double TxCntPlus; + double TxPeriod; + double tcntAux; + double tcntAuxPrev; + double tcnt; + double cmpA; + double cmpB; + DeadTimeSimHandle deadtime; + + void (*simulatePwm)(); +}TimerSimHandle; + +/** +* @brief PWM Phase Simulation Handle +*/ +typedef struct +{ + PWMPhaseOutput pwmOut; + TimerSimHandle* tsim1; + TimerSimHandle* tsim2; + int tkLineA; + int tkLineB; + DeadTimeSimHandle deadtime; +}PWMPhaseSimHandle; + +extern TimerSimHandle t1sim; +extern TimerSimHandle t2sim; +extern TimerSimHandle t3sim; +extern TimerSimHandle t4sim; +extern TimerSimHandle t5sim; +extern TimerSimHandle t6sim; +extern TimerSimHandle t7sim; +extern TimerSimHandle t8sim; +extern TimerSimHandle t9sim; +extern TimerSimHandle t10sim; +extern TimerSimHandle t11sim; +extern TimerSimHandle t12sim; + +extern PWMPhaseSimHandle PWMPhaseA1; +extern PWMPhaseSimHandle PWMPhaseB1; +extern PWMPhaseSimHandle PWMPhaseC1; +extern PWMPhaseSimHandle PWMPhaseA2; +extern PWMPhaseSimHandle PWMPhaseB2; +extern PWMPhaseSimHandle PWMPhaseC2; + +void Simulate_PWM(void); +void Init_PWM_Simulation(void); + +void Simulate_PWMPhase(PWMPhaseSimHandle* tksim, int T1, int T0); + +void Simulate_MainTIM(TimerSimHandle* tsim, int compare); +void Simulate_SimpleTIM(TimerSimHandle* tsim, int compare); + +int simulateTimAndGetCompare(TimerSimHandle* tsim, int compare); +void simulateActionActionQualifierSubmodule(TimerSimHandle* tsim); +void simulateDeadBendSubmodule(TimerSimHandle* tsim, int* ciA, int* ciB); +void simulateTripZoneSubmodule(TimerSimHandle* tsim); + + +void Init_TIM_Simulation(TimerSimHandle* tsim, int period, double step); +void Init_PWMPhase_Simulation(PWMPhaseSimHandle* tksim, TimerSimHandle* tsim1, TimerSimHandle* tsim2, int period, double step); +void convertSVGenTimesToTkLines(PWMPhaseSimHandle* tksim); +void xilinxPwm3LevelSimulation(PWMPhaseSimHandle* tksim); + +#if defined(PWM_SIMULATION_MODE_REGULAR_PWM) && defined(PWM_SIMULATION_MODE_TK_LINES) +#error Choose only one PWM simulation mode! +#endif +#endif //PWM_SIM diff --git a/README.md b/README.md index cc922f9..b1134bb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,126 @@ -# test_branches +# MATLAB 23550 + **СОДЕРЖАНИЕ** +- [Общая структура симулятора](#общая-структура-симулятора) +- [Описание стуктуры симулятора](#описание-стуктуры-симулятора) + - [Оболочка МК](#оболочка-мк) + - [Оболочка программы](#оболочка-программы) + - [Код пользователя](#код-пользователя) + - [Симуляция плат](#симуляция-плат) +- [Инструкция](#инструкция) + - [Портирование кода](#портирование-кода) + - [Как скомпилировать код](#как-скомпилировать-код) + - [Как запустить отладку](#как-запустить-отладку) + - [Ошибки при портировании](#ошибки) +## Общая структура симулятора +Код для компиляции S-Function лежит в папке ***Inu***. В ней содержатся: +- **Оболочка МК ([файлы в корне](#оболочка-мк))**: код S-Function, который запускает код программы +- **Оболочка программы ([_app_wrapper_](#оболочка-программы))**: связывает программу и S-Function +- **Программа МК ([_Src_](#код-пользователя))**: программа для симуляции +- **Симуляция плат (beta) ([_xilinx_wrapper_](#симуляция-плат))**: моделирует внешние платы (пока только ШИМ) + +Далее приведена структура симулятора. Инструкция для портирования другого кода в MATLAB приведена [ниже](#инструкция) + +## Описание стуктуры симулятора +Здесь содержиться описание трех блоков симулятора: +- [Оболочка МК](#оболочка-мк) +- [Оболочка программы](#оболочка-программы) +- [Код пользователя](#код-пользователя) +- [Симуляция плат (beta)](#симуляция-плат) + +### Оболочка МК +В этой папке содержиться оболочка (англ. wrapper) для запуска и контроля симуляции микроконтроллеров в MATLAB (любого МК, не только TMS). Оболочка представляет собой 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. +- ***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*** и прописываются дефайны для компиляции. + +Конфигурации оболочки: +- `RUN_APP_MAIN_FUNC_THREAD` - создание и запуск отдельного потока для main() +- `DEKSTOP_CYCLES_FOR_MCU_APP` - количество циклов пустого for(;;), в течении которого будет работать поток main() +- `MCU_CORE_CLOCK` - частота симулируемого процессора (пока нигде не используется) +- `IN_PORT_WIDTH` - размерность входного вектора S-Function +- `IN_PORT_NUMB` - количество входных векторов S-Function +- `OUT_PORT_WIDTH` - размерность выходного вектора S-Function +- `OUT_PORT_NUMB` - количество выходных векторов S-Function + +_Note: дефайн `RUN_APP_MAIN_FUNC_THREAD` пока выключен и поток для main() не используется)_ + +_Note for future: разные вектора можно использовать для разных плат_ + +### Оболочка программы +Оболочка для программы позволяет имитировать реальный алгоритм программы. Она инициализирует её, запускает необходимые для её работы функции и связывает её с входами/выходами S-Function + +Ниже приведен перечень всех файлов и краткое описание зачем они нужны: +- ***app_includes.h***     - Содержит ARM дефайны для компиляции в MSVC. +- ***app_init.c/.h***      - инициализация программы +- ***app_io.c/.h***        - запись/считывание входов/выходов S-Function в программу +- ***app_wrapper.c/.h***      - вызов функций из программы и создание заглушек для ненужных функций +- ***def.h***          - дефайны для симуляции программы в симулинке (осталось от улитковского) + +Также в папке ***\app_wrapper\device_support*** находяться стандартные библиотеки для TMS, но переделанные под компилятор MSVC (удален `volatile`, добавлены заглушки для `interrupt`, `asm`, `cregister`, добавлен код для симуляции IQlib). + +### Код пользователя +Данная папка содержит исходный код приложения МК. При этом стандартные библиотеки, которые общие для всех проектов следует помещать в [папку с оболочкой программы](#оболочка-программы). Чтобы не редактировать исходники общих библиотек в каждом проекте. + +### Симуляция плат +Модули в этой папке моделируют внешние платы. Пока более-менее сделан только ШИМ, но в будущем планируется расширение и вывод их в отельные S-Function. Чтобы сделать подобие корзины. + +###### adc_sim +***adc_sim.c/.h*** - симуляция АЦП (пока просто заготовка) + +###### pwm_sim +***pwm_sim.c/.h*** - симуляция ШИМ +Поддерживает два режимы формирования ШИМ: +- для каждого таймера отдельно (PWM_SIMULATION_MODE_REGULAR_PWM) +- через линии ТК для всей фазы разом (PWM_SIMULATION_MODE_TK_LINES). + + +## Инструкция +Общий алгоритм портирования кода для симуляции в MATLAB приведен ниже. В инструкции есть ссылки на более подробное описание действий. +1. [Портировать код для MATLAB](#портирование-кода) (можно начать с портирования без изменений и далее действовать от шага 2) +2. Проверить [компилируеться ли код](#как-скомпилировать-код). А далее: + - если есть ошибки при компиляции, [исправить их](#ошибки-при-компиляции) и вернуться на шаг 2. + - если ошибок нет, перейти на шаг 3. +3. Проверить нормально ли запускается и работает симуляция с МК. А далее: + - если симуляции вылетает, то необходимо [исправить ошибки](#ошибки-при-симуляции) в [режиме отладки](#как-запустить-отладку) и вернуться на шаг 3. + - если симуляция нормально запускается только один раз, и не завершается или не запускается второй раз, то необходимо [исправить ошибки](#ошибки-при-симуляции) в [режиме отладки](#как-запустить-отладку) и вернуться на шаг 3. + - если симуляция работает, не вылетает и перезапускается, то перейти на шаг 4. +4. Оценить результаты симуляции. А далее: + - если симуляция сходится с реальностью - то всё работает корректно. + - если нет - необходимо разбираться в алгоритме и после исправить его и перейти на шаг 2. + +#### Портирование кода +Для начала необходимо весь пользовательский код портировать в отдельную папку для удобства. Например в "***\Src***". + +Далее в "[run_bat.mex](#оболочка-мк)" надо прописать пути для заголовочных файлов (***\Includes***) и все необходимые для симуляции программы исходники. Все файлы исходников "***.c***" прописывать не обязательно. Если нужно отладить какой-то отдельный модуль программы, можно попробовать ограничиться им, и при возникновении ошибок подключать новые исходники. + +#### Как скомпилировать код +Для компиляции кода необходимо открыть файл ***mexing.m***. Это MATLAB-скрипт, который запускает скрипт "[***run_bat.mex***](#оболочка-мк)" для компиляции. Есть возможность компиляции кода для [отладки](#как-запустить-отладку) + +#### Как запустить отладку +Для отладки симуляции необходимо приписать в ***mexing.m*** в вызове ***run_mex.bat*** слово `debug`, тогда код скомпилируется для дебага. После этого необходимо открыть Visual Studio, открыть папку проекта (там должны быть все исходники программы и симулятора). И подключиться к ***MATLAB.exe***. + +Теперь можно поставить точку в исходном коде симулятора или программы МК и запустить симуляцию. Когда MATLAB дойдет до этого места, симуляция остановиться и в Visual Studio можно будет посмотреть все переменные, пройти код по строкам и в общем делать всё то, что можно делать в режиме отладки. + +Для отладки необходимо сначала подключится к процессу, а потом уже запускать симуляцию. Также отладка рабоатет только один раз. При повторном запуске симуляции остановки не произойдет. Поэтому перед каждой отладкой надо перекомпилировать код. + + +#### Ошибки +##### Ошибки при компиляции +Самые распространеные ошибки компилятора при портировании нового кода - это ошибки из-за неподключенных исходных файлов. Для исправления ошибок необходимо подключить требуемые модули или создавать заглушки. + +Также еще могут быть ошибки связанные с разными компиляторами и отсутствия ключевых слов в MSVC, например, ошибки с `volatile`, `interrupt`, `asm`... в библиотеках DPS. Для исправления ошибок надо или удалять эти ключевые слова или создавать для них заглушки-define + +##### Ошибки при симуляции +Обычно это исключения при чтении по недоступному адресу. Надо выяснить на какой строке произошло исключение и смотреть по какому адресу произошла попытка чтения и по какому адресу надо на самом деле считывать. И после этого скорректировать код так, чтобы адрес брался корректный. + +Это обычно неинициализированные указатели или некоторые функции (напр. `ReadMemory`/`WriteMemory` когда пытаются считать что-то по адрессам "несуществующей" шины) \ No newline at end of file diff --git a/allmex.m b/allmex.m new file mode 100644 index 0000000..d7071ff --- /dev/null +++ b/allmex.m @@ -0,0 +1,16 @@ +clc +% S-function +currFolder = cd; +%cd([currFolder, '\Inu']); + +delete("wrapper_inu.mexw64") +delete("*.mexw64.pdb") + +status=system('Inu\run_mex.bat debug') + + +if status==0 + beep +else + error('Error!'); +end \ No newline at end of file diff --git a/asynchronous_machine.p b/asynchronous_machine.p new file mode 100644 index 0000000000000000000000000000000000000000..9a34a055c104d3ebae3ff35aabe5cd0b5b92a68f GIT binary patch literal 1232 zcmV;>1TXt`FflGLFm^C7E-)|v3&0#uTK};C00sa600giA01I%3WS>#l#CH?VLlszn z9m>FgGApMiho?*j1|z-xl~O0qmv05Gx_<^jm!C<9lu9vixUj4r#f?dEwheRSgqJW1 z5~VH;4hos5#erWk5FRt=8L;S^!b%v$>}X!g-69b512qdf(?1f}(mDBTDX9W32!AKi zWJ)3c^Q0z67uc&KwI}HtjZ2pcq$I|3VtRHZq&E)P@hhI&^-x z(;%tYId&ex1(}3XiakquXZ-j_;{jrQ-i$UZ3VLDBD&@uUGt3c@e^wg6`pweX)F5MG zjs1K$+m;(0hoU#F9v>%Tr`CntDcQ-&-su2j11h}J2gq1^rU1pcA7PA~Xge6r8)VaP zec2Zedg0?MNc+=Kehs*?&cCuIT^&J0!Zz-S#p)A-2 z*!jP$SV9&xMYS7}aPzugzgM0Ojk+2jff#}kAHRMYx+p1Br*s8_N=%Vm$i~*HSK1LG zmb9fZ5~mdr-Y=vx^}G=!_552)7=*GuJpCqnx+fwpsOH$(&>n_*X6F)(1m?1W{-n}7 zro6uBn2L7&zidH7_}wQXHmt&aJWK8V>FEpE@MkC@FV_JJ2?-=}Z|Y%sQ38JK%oK=j zY8%VndYs@UMzsSv|7$C7(ZatmtX zP%Xl1S)5Gi6Zc7y1#oB=Z>~zEC!faL+{4*rfm}eYFR5Mm;7|NwFf2$kq{*DxJZf4q zLA&E3#x!*Z^~y$v7sA)?rsdYuC7ZK{BjkXPXB{9n>Os`f`(1nPj2wJrW$3uQm4gh( z|0Zp58ZK5D2yh$8>?x7Hgd?RC{qWJjN6X;lDaN|bK$Kj(-Tob<~ z8D^U-Jrcp)Xw;o!!oANV?u{#J6CMyKTD-Fgw0M9fPeL^%(M31`dc_lMKCHo@M;z0x zIbNM@$~E)j&vhU!7k{>j==Go8_54i*{P!g(L@`^^nBS)mS={LT@~=Bk2tqvca0lK1 z$VaQ~A4an^o>k-BRebM3QR+}2VQ{_VLFTrGjwiSR1d=y=HuT0A@GQ#he@UjS4DW%S zHMYre($0(NAd`4OG6CgJm}^8zrB>0)KteWsni_muh;vuBO1YFSJebUMX@x*ItR@)8#T!# zXdOt7cMZ59Am(&ijgO<3R)}NvdS|%ezi3X&b*_-Ny8(|Em|)01_wE;t5HG0?PTbT* z2~DB(tA-Jpev~;qjOs-jUIH>ezH|B$%1(FKF!`h*a~A%w4C~-v+&`Hr1y?HJVr3+EfD)nK>8sg3D_dJw5k}~F&MXS uMGvO>D+@C)rFLP>l}n=Smgz5(k&=UT$4_sM_@DVD-N~lj=mt4?@q-r&^-b;o literal 0 HcmV?d00001 diff --git a/electr_mach.slx b/electr_mach.slx new file mode 100644 index 0000000000000000000000000000000000000000..8b9774982362fa932436f7af3fb9bd224dcba6ce GIT binary patch literal 41878 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