From 0f3ac734bf501355a2651909595b25b812304c8f Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Sun, 15 Jun 2025 02:07:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE=D1=88?= =?UTF-8?q?=D1=83=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BD=D0=B5=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Inc/stm32f1xx_hal_def.h | 2 +- MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.c | 1 + MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h | 2 +- ...config.json => stm32f1xx_matlab_conf.json} | 53 ++ MCU_Wrapper/MCU.c | 22 +- MCU_Wrapper/app_wrapper.c | 138 ---- MCU_Wrapper/findjobj.mltbx | Bin 188716 -> 0 bytes MCU_Wrapper/mcu_wrapper.c | 208 +++-- MCU_Wrapper/mcu_wrapper_conf.h | 215 +++-- MCU_Wrapper/mexing.m | 718 ----------------- MCU_Wrapper/run_mex.bat | 108 ++- app_wrapper/app_configs.h | 10 + app_wrapper/app_includes.h | 17 + app_wrapper/app_init.c | 38 + app_wrapper/app_io.c | 118 +++ app_wrapper/app_wrapper.c | 27 + app_wrapper/app_wrapper.h | 12 + mcu_test_r2023.slx | Bin 69550 -> 67781 bytes mexing.asv | 734 ----------------- mexing.m | 738 ------------------ periph_config.json | 252 ------ 21 files changed, 634 insertions(+), 2779 deletions(-) rename MCU_STM32F1xx_Matlab/{periph_config.json => stm32f1xx_matlab_conf.json} (78%) delete mode 100644 MCU_Wrapper/app_wrapper.c delete mode 100644 MCU_Wrapper/findjobj.mltbx delete mode 100644 MCU_Wrapper/mexing.m create mode 100644 app_wrapper/app_configs.h create mode 100644 app_wrapper/app_includes.h create mode 100644 app_wrapper/app_init.c create mode 100644 app_wrapper/app_io.c create mode 100644 app_wrapper/app_wrapper.c create mode 100644 app_wrapper/app_wrapper.h delete mode 100644 mexing.asv delete mode 100644 mexing.m delete mode 100644 periph_config.json diff --git a/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h b/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h index 1950978..263b866 100644 --- a/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h +++ b/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h @@ -30,7 +30,7 @@ extern "C" { #include "stm32f1xx.h" #include "Legacy/stm32_hal_legacy.h" #include -#include "mcu_wrapper_conf.h" +//#include "mcu_wrapper_conf.h" /* Exported types ------------------------------------------------------------*/ diff --git a/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.c b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.c index c330d14..ea1927b 100644 --- a/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.c +++ b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.c @@ -3,6 +3,7 @@ δετΰινΰμθ β stm32f4xx_matlab_conf.h. **************************************************************************/ +#include "stm32f1xx_matlab_conf.h" #include "mcu_wrapper_conf.h" MCU_MemoryTypeDef MCU_MEM; diff --git a/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h index 6ad9d73..43717cb 100644 --- a/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h +++ b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h @@ -7,7 +7,7 @@ #define _MATLAB_SETUP_H_ #include "stm32_defs.h" #include "stm32f1xx_hal.h" -//#include "mcu_wrapper_conf.h" +#include "mcu_wrapper_conf.h" // DEFINES (UNCOMMENT WHAT YOU WILL SIMULATE) // TIMS diff --git a/MCU_STM32F1xx_Matlab/periph_config.json b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.json similarity index 78% rename from MCU_STM32F1xx_Matlab/periph_config.json rename to MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.json index 8d354ed..263f7ba 100644 --- a/MCU_STM32F1xx_Matlab/periph_config.json +++ b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.json @@ -1,4 +1,57 @@ { + "Code": { + "Sources": { + "Type": "files", + "Options": [ + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_adc.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_adc_ex.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c", + "Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c", + "stm32f1xx_matlab_conf.c", + "Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_gpio.c", + "Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_tim.c", + "Drivers/STM32F1xx_SIMULINK/stm32f1xx_periph_registers.c" + ] + }, + "Includes": { + "Type": "paths", + "Options": [ + "", + "Drivers/STM32F1xx_SIMULINK", + "Drivers/CMSIS", + "Drivers/CMSIS/Device/STM32F1xx", + "Drivers/STM32F1xx_HAL_Driver/Inc", + "Drivers/STM32F1xx_HAL_Driver/Inc/Legacy" + ] + } + }, + "UserCode": { + "Functions": { + "PeriphInit": { + "Options": [ + "Initialize_Periph_Sim()" + ] + }, + "PeriphSimulation": { + "Options": [ + "Simulate_TIMs()", + "Simulate_GPIO_BSRR()" + ] + }, + "PeriphDeinit": { + "Options": [ + "deInitialize_Periph_Sim()" + ] + } + } + }, "RCC": { "Defines": { "HCLK_Clock": { diff --git a/MCU_Wrapper/MCU.c b/MCU_Wrapper/MCU.c index 05ad921..f0bbed8 100644 --- a/MCU_Wrapper/MCU.c +++ b/MCU_Wrapper/MCU.c @@ -19,7 +19,7 @@ * @{ */ -#define S_FUNCTION_NAME MCU +#define S_FUNCTION_NAME MCU #define S_FUNCTION_LEVEL 2 #include "mcu_wrapper_conf.h" @@ -111,16 +111,18 @@ static void mdlInitializeSizes(SimStruct* S) ssSetNumDiscStates(S, DISC_STATES_WIDTH); // number of discrete states // set up input port - if (!ssSetNumInputPorts(S, 1)) return; + if (!ssSetNumInputPorts(S, IN_PORT_NUMB)) return; for (int i = 0; i < IN_PORT_NUMB; i++) - ssSetInputPortWidth(S, i, IN_PORT_WIDTH); - ssSetInputPortDirectFeedThrough(S, 0, 0); - ssSetInputPortRequiredContiguous(S, 0, 1); // direct input signal access + { + ssSetInputPortWidth(S, i, inLengths[i]); + ssSetInputPortDirectFeedThrough(S, i, 0); + ssSetInputPortRequiredContiguous(S, i, 1); + } // set up output port if (!ssSetNumOutputPorts(S, OUT_PORT_NUMB)) return; for (int i = 0; i < OUT_PORT_NUMB; i++) - ssSetOutputPortWidth(S, i, OUT_PORT_WIDTH); + ssSetOutputPortWidth(S, i, outLengths[i]); ssSetNumSampleTimes(S, 1); @@ -152,7 +154,7 @@ static void mdlInitializeSizes(SimStruct* S) */ static void mdlStart(SimStruct* S) { - SIM_Initialize_Simulation(); + SIM_Initialize_Simulation(S); } #endif // MDL_START @@ -167,10 +169,10 @@ static void mdlStart(SimStruct* S) static void mdlInitializeSampleTimes(SimStruct* S) { // Π¨Π°Π³ дискрСтизации - hmcu.SIM_Sample_Time = mxGetPr(ssGetSFcnParam(S, NPARAMS - 1))[0]; + hmcu.sSimSampleTime = mxGetPr(ssGetSFcnParam(S, NPARAMS - 1))[0]; // Register one pair for each sample time - ssSetSampleTime(S, 0, hmcu.SIM_Sample_Time); + ssSetSampleTime(S, 0, hmcu.sSimSampleTime); ssSetOffsetTime(S, 0, 0.0); } @@ -189,7 +191,7 @@ static void mdlTerminate(SimStruct* S) ResumeThread(hmcu.hMCUThread); WaitForSingleObject(hmcu.hMCUThread, 10000); #endif - SIM_deInitialize_Simulation(); + SIM_deInitialize_Simulation(S); mexUnlock(); } diff --git a/MCU_Wrapper/app_wrapper.c b/MCU_Wrapper/app_wrapper.c deleted file mode 100644 index 17be3d1..0000000 --- a/MCU_Wrapper/app_wrapper.c +++ /dev/null @@ -1,138 +0,0 @@ -/** -************************************************************************** -* @file app_wrapper.c -* @brief Код для ΠΈΠ· прилоТСния МК для симуляции. -************************************************************************** -**************************************************************************/ - -#include "mcu_wrapper_conf.h" -// Includes START -#include "upp.h" -#include "main.h" -// Inlcudes END - -// Dummy functions START -uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk) {} -void SystemClock_Config(void) {} -void Error_Handler(void) {} -// Dummy functions END - -void app_init(void) -{ -/* USER CODE BEGIN 1 */ - - /* USER CODE END 1 */ - - /* MCU Configuration--------------------------------------------------------*/ - - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); - - /* USER CODE BEGIN Init */ - - /* USER CODE END Init */ - - /* Configure the system clock */ - SystemClock_Config(); - - /* USER CODE BEGIN SysInit */ - - /* USER CODE END SysInit */ - - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_TIM2_Init(); - /* USER CODE BEGIN 2 */ - upp_init(); - - /* USER CODE END 2 */ - - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - //while (1) - //{ - // upp_main(); - // /* USER CODE END WHILE */ - - // /* USER CODE BEGIN 3 */ - //} - /* USER CODE END 3 */ -} - - -void app_step(void) -{ - upp_main(); -} - -void app_writeOutputBuffer(real_T* disc) -{ - - for (int i = 0; i < PORT_WIDTH; i++) - { - if (GPIOA->ODR & (1 << i)) - { - disc[i] = 1; - } - - if (GPIOB->ODR & (1 << i)) - { - disc[PORT_WIDTH + i] = 1; - } - } - disc[2 * PORT_WIDTH + 0] = phase_A.ctrl.angle.delay_us; - disc[2 * PORT_WIDTH + 1] = (uint16_t)((uint16_t)TIMER->CNT - phase_A.ctrl.angle.start_delay_tick); - disc[2 * PORT_WIDTH + 2] = phase_A.ctrl.angle.start_delay_tick; - disc[2 * PORT_WIDTH + 3] = TIMER->CNT; -} - - - -void app_readInputs(real_T* in) -{ - -#define detect_front(_in_numb_, _var_, _val_) { \ -if ((in[_in_numb_] > 0.5) && (prev_in[_in_numb_] <= 0.5)) \ -{ \ - _var_ = _val_; \ -} } - -#define detect_rise(_in_numb_, _var_, _val_) { \ -if ((in[_in_numb_] < 0.5) && (prev_in[_in_numb_] >= 0.5)) \ -{ \ - _var_ = _val_; \ -} } - - static real_T prev_in[IN_PORT_WIDTH]; - - detect_front(0, phase_A.zc_detector.f.EXTIZeroCrossDetected, 1); - detect_rise(0, phase_A.zc_detector.f.EXTIZeroCrossDetected, 1); - - detect_front(1, phase_B.zc_detector.f.EXTIZeroCrossDetected, 1); - detect_rise(1, phase_B.zc_detector.f.EXTIZeroCrossDetected, 1); - - detect_front(2, phase_C.zc_detector.f.EXTIZeroCrossDetected, 1); - detect_rise(2, phase_C.zc_detector.f.EXTIZeroCrossDetected, 1); - - detect_front(3, Upp.GoSafe, 1); - detect_rise(3, Upp.GoSafe, 0); - - detect_front(4, Upp.Prepare, 1); - detect_rise(4, Upp.Prepare, 0); - - detect_front(5, Upp.ForceStop, 1); - detect_rise(5, Upp.ForceStop, 0); - - detect_front(6, Upp.ForceDisconnect, 1); - detect_rise(6, Upp.ForceDisconnect, 0); - - - Upp.sine_freq = in[7]; - Upp.Duration = in[8]; - - - for (int i = 0; i < IN_PORT_WIDTH; i++) - { - prev_in[i] = in[i]; - } -} diff --git a/MCU_Wrapper/findjobj.mltbx b/MCU_Wrapper/findjobj.mltbx deleted file mode 100644 index fda256a3915ecc1389af0c0ac0bb618d56211a58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188716 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