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 0000000..9a34a05 Binary files /dev/null and b/asynchronous_machine.p differ diff --git a/electr_mach.slx b/electr_mach.slx new file mode 100644 index 0000000..8b97749 Binary files /dev/null and b/electr_mach.slx differ