diff --git a/MATLAB/MCU_Wrapper/MCU.c b/MATLAB/MCU_Wrapper/MCU.c index 72b00c7..eca9a09 100644 --- a/MATLAB/MCU_Wrapper/MCU.c +++ b/MATLAB/MCU_Wrapper/MCU.c @@ -26,8 +26,61 @@ #include #include +#include #include "mex.h" + +static unsigned long long get_timer_frequency(void) +{ +#ifdef USE_CPU_TIMER + HKEY hKey; + DWORD frequency = 0; + DWORD size = sizeof(DWORD); + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + if (RegQueryValueExA(hKey, "~MHz", NULL, NULL, (LPBYTE)&frequency, &size) == ERROR_SUCCESS) { + RegCloseKey(hKey); + return (unsigned long long)frequency * 1000000ULL; // MHz -> Hz + } + RegCloseKey(hKey); + } +#elif defined(USE_QPF_TIMER) + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return frequency.QuadPart; +#endif +} + +static double ticksToNanoseconds(unsigned long long start, unsigned long long end) +{ +#if defined(USE_CPU_TIMER) || defined(USE_QPF_TIMER) + unsigned long long elapsed = end - start; + unsigned long long frequency = get_timer_frequency(); + return (double)elapsed * 1e9 / (double)frequency; +#endif +} + +static void InitializeHighPrecisionTimer(void) +{ +#ifdef USE_QPF_TIMER + QueryPerformanceFrequency(&hmcu.dTimer.Frequency); + hmcu.dTimer.TimerResolutionNs = 1e9 / (double)(hmcu.dTimer.Frequency); +#endif +} + +static unsigned long long read_timer(void) +{ +#ifdef USE_CPU_TIMER + return __rdtsc(); +#elif defined(USE_QPF_TIMER) + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return counter.QuadPart; +#endif +} + + #define MDL_UPDATE ///< для подключения mdlUpdate() /** * @brief Update S-Function at every step of simulation @@ -40,12 +93,32 @@ */ static void mdlUpdate(SimStruct* S, int_T tid) { + // Расчет периода (время между вызовами) + if (hmcu.dTimer.call_count > 0 && hmcu.dTimer.SFuncPrevTime != 0) { + hmcu.dSFuncPeriod = ticksToNanoseconds( + hmcu.dTimer.SFuncPrevTime, + hmcu.dTimer.SFuncStartTime) / 1000.0; // в микросекундах + } + + // Сохраняем текущее время для следующего расчета периода + hmcu.dTimer.SFuncPrevTime = hmcu.dTimer.SFuncStartTime; + // Текущий вызов становится началом S-Function + hmcu.dTimer.SFuncStartTime = read_timer(); + // get time of simulation time_T TIME = ssGetT(S); //---------------SIMULATE MCU--------------- + // Измерение времени выполнения MCU_Step_Simulation + hmcu.dTimer.MCUStepStartTime = read_timer(); MCU_Step_Simulation(S, TIME); // SIMULATE MCU + hmcu.dTimer.MCUStepEndTime = read_timer(); //------------------------------------------ + + // Расчет времени выполнения в микросекундах + hmcu.dMCUStepTime = ticksToNanoseconds( + hmcu.dTimer.MCUStepStartTime, + hmcu.dTimer.MCUStepEndTime) / 1000.0; }//end mdlUpdate /** @@ -59,6 +132,20 @@ static void mdlUpdate(SimStruct* S, int_T tid) static void mdlOutputs(SimStruct* S, int_T tid) { SIM_writeOutputs(S); + + // Измерение времени окончания выполнения mdlOutputs + hmcu.dTimer.SFuncEndTime = read_timer(); + + // Общее время выполнения S-Function в микросекундах + if (hmcu.dTimer.SFuncStartTime) + { + hmcu.dSFuncTime = ticksToNanoseconds( + hmcu.dTimer.SFuncStartTime, + hmcu.dTimer.SFuncEndTime) / 1000.0; + } + + // Накопление статистики + hmcu.dTimer.call_count++; }//end mdlOutputs #define MDL_CHECK_PARAMETERS /* Change to #undef to remove function */ @@ -158,6 +245,9 @@ static void mdlInitializeSizes(SimStruct* S) */ static void mdlStart(SimStruct* S) { + // Инициализация высокоточного таймера + InitializeHighPrecisionTimer(); + SIM_Initialize_Simulation(S); } #endif // MDL_START diff --git a/MATLAB/MCU_Wrapper/mcu_wrapper.c b/MATLAB/MCU_Wrapper/mcu_wrapper.c index d654635..d1e01dc 100644 --- a/MATLAB/MCU_Wrapper/mcu_wrapper.c +++ b/MATLAB/MCU_Wrapper/mcu_wrapper.c @@ -37,7 +37,7 @@ const int inOffsets[IN_PORT_NUMB] = { */ const int outLengths[OUT_PORT_NUMB] = { THYR_PORT_1_WIDTH, - OUT_PORT_2_WIDTH, + PM_PORT_2_WIDTH, OUT_PORT_3_WIDTH }; /** diff --git a/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h b/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h index 534cd4a..bd26971 100644 --- a/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h +++ b/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h @@ -47,6 +47,10 @@ //#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 +// Выбор Timer +//#define USE_QPF_TIMER +#define USE_CPU_TIMER + // Parameters of S_Function // INPUT/OUTPUTS PARAMS START #define IN_PORT_NUMB 2 @@ -55,7 +59,7 @@ #define OUT_PORT_NUMB 3 #define THYR_PORT_1_WIDTH 6 -#define OUT_PORT_2_WIDTH 6 +#define PM_PORT_2_WIDTH 16 #define OUT_PORT_3_WIDTH 16 // INPUT/OUTPUTS PARAMS END @@ -95,12 +99,12 @@ #define OFFSET_IN_ARRAY_2 (OFFSET_IN_ARRAY_1 + ADC_PORT_1_WIDTH) /// === Полный размер буфера === -#define TOTAL_OUT_SIZE (THYR_PORT_1_WIDTH + OUT_PORT_2_WIDTH + OUT_PORT_3_WIDTH) +#define TOTAL_OUT_SIZE (THYR_PORT_1_WIDTH + PM_PORT_2_WIDTH + OUT_PORT_3_WIDTH) /// === Смещения массивов (внутри общего буфера) === #define OFFSET_OUT_ARRAY_1 0 #define OFFSET_OUT_ARRAY_2 (OFFSET_OUT_ARRAY_1 + THYR_PORT_1_WIDTH) -#define OFFSET_OUT_ARRAY_3 (OFFSET_OUT_ARRAY_2 + OUT_PORT_2_WIDTH) +#define OFFSET_OUT_ARRAY_3 (OFFSET_OUT_ARRAY_2 + PM_PORT_2_WIDTH) // INPUT/OUTPUTS AUTO-PARAMS END @@ -129,9 +133,24 @@ extern const int inOffsets[IN_PORT_NUMB]; #define CREATE_SUSPENDED 0x00000004 typedef void* HANDLE; ///< MCU handle typedef +typedef struct +{ + unsigned long long Frequency; ///< Частота таймера + double TimerResolutionNs; ///< Разрешение таймера в наносекундах + + unsigned long long SFuncPrevTime; ///< Время предыдущего вызова S-Function + unsigned long long SFuncStartTime; ///< Начало выполнения S-Function + unsigned long long SFuncEndTime; ///< Окончание выполнения S-Function + unsigned long long MCUStepStartTime; ///< Начало MCU_Step_Simulation + unsigned long long MCUStepEndTime; ///< Окончание MCU_Step_Simulation + + // Statistics + long call_count; ///< Количество вызовов +}SIM_HighPrecisionTimer; + /** * @brief MCU handle Structure definition. - * @note Prefixes: h - handle, s - settings, f - flag + * @note Prefixes: h - handle, s - settings, f - flag, d - debug info */ typedef struct { // MCU Thread @@ -147,6 +166,12 @@ typedef struct { double SystemClockDouble; ///< Счетчик в формате double для точной симуляции системных тиков С промежуточными значений double sSystemClock_step; ///< Шаг тиков для их симуляции, в формате double double sSimSampleTime; ///< Период дискретизации симуляции + + + SIM_HighPrecisionTimer dTimer; ///< Высокоточный таймер + double dSFuncPeriod; ///< Период вызова S-Function в микросекундах + double dSFuncTime; ///< Время "выполнения" S-Function (от начала Update до конца Outputs) в микросекундах + double dMCUStepTime; ///< Время выполнения приложения в микросекундах }SIM__MCUHandleTypeDef; extern SIM__MCUHandleTypeDef hmcu; // extern для видимости переменной во всех файлах diff --git a/MATLAB/app_wrapper/app_io.c b/MATLAB/app_wrapper/app_io.c index 2f0e131..f8400cd 100644 --- a/MATLAB/app_wrapper/app_io.c +++ b/MATLAB/app_wrapper/app_io.c @@ -8,7 +8,7 @@ #define PIN_READ(_verbname_) (_verbname_##_GPIO_Port->ODR & (_verbname_##_Pin)) ? 1 : 0 -void ThyristorWrite(real_T* Buffer) +void Write_Thyristors(real_T* Buffer, int ind_port) { int pwm1_pin = PIN_READ(PWM1); int pwm2_pin = PIN_READ(PWM2); @@ -18,14 +18,38 @@ void ThyristorWrite(real_T* Buffer) int pwm6_pin = PIN_READ(PWM6); - WriteOutputArray(pwm1_pin, 0, 0); - WriteOutputArray(pwm2_pin, 0, 1); - WriteOutputArray(pwm3_pin, 0, 2); - WriteOutputArray(pwm4_pin, 0, 3); - WriteOutputArray(pwm5_pin, 0, 4); - WriteOutputArray(pwm6_pin, 0, 5); + WriteOutputArray(pwm1_pin, ind_port, 0); + WriteOutputArray(pwm2_pin, ind_port, 1); + WriteOutputArray(pwm3_pin, ind_port, 2); + WriteOutputArray(pwm4_pin, ind_port, 3); + WriteOutputArray(pwm5_pin, ind_port, 4); + WriteOutputArray(pwm6_pin, ind_port, 5); } +void Write_PowerMonitor(real_T* Buffer, int ind_port) +{ + int nn = 0; + for (int i = 0; i < 3; i++) + { + WriteOutputArray(pm.U[i], ind_port, nn++); + } + for (int i = 0; i < 3; i++) + { + WriteOutputArray(pm.ZC_Detected[i], ind_port, nn++); + } + for (int i = 0; i < 3; i++) + { + WriteOutputArray(pm.F[i], ind_port, nn++); + } + for (int i = 0; i < 3; i++) + { + WriteOutputArray(pm.I[i], ind_port, nn++); + } + for (int i = 0; i < 2; i++) + { + WriteOutputArray(pm.T[i], ind_port, nn++); + } +} /** * @brief Функция для записи входов в приложение МК * @param u - массив входных значений @@ -49,41 +73,13 @@ void app_readInputs(const real_T* Buffer) { */ void app_writeOutputBuffer(real_T* Buffer) { // USER APP OUTPUT START - //ThyristorWrite(Buffer); - for (int i = 0; i < 2; i++) - { - WriteOutputArray(pm.ZC_Detected[i], 0, i); - } - for (int i = 0; i < 2; i++) - { - WriteOutputArray(pm.zc.Channel[i].DebounceCounter, 0, i+2); - } + //ThyristorWrite(Buffer, 0); + Write_PowerMonitor(Buffer, 1); - extern ADC_Periodic_t adc; - for(int i = 0; i < 6; i++) - { - WriteOutputArray(pm.adc.Data[i], 1, i); - } - - - - - for (int i = 0; i < 3; i++) - { - WriteOutputArray(pm.U[i], 2, i); - } - for (int i = 0; i < 3; i++) - { - WriteOutputArray(pm.ZC_Detected[i], 2, i + 3); - } - for (int i = 0; i < 3; i++) - { - WriteOutputArray(pm.I[i], 2, i + 6); - } - for (int i = 0; i < 3; i++) - { - WriteOutputArray(pm.F[i], 2, i + 9); - } + WriteOutputArray(hmcu.dSFuncPeriod, 2, 12); + WriteOutputArray(hmcu.dSFuncTime, 2, 13); + WriteOutputArray(hmcu.dMCUStepTime, 2, 14); + // USER APP OUTPUT END } \ No newline at end of file diff --git a/MATLAB/upp_r2023.slx b/MATLAB/upp_r2023.slx index 2f5d6e8..a6fac22 100644 Binary files a/MATLAB/upp_r2023.slx and b/MATLAB/upp_r2023.slx differ diff --git a/UPP/AllLibs/MyLibs b/UPP/AllLibs/MyLibs index 48dacce..606058e 160000 --- a/UPP/AllLibs/MyLibs +++ b/UPP/AllLibs/MyLibs @@ -1 +1 @@ -Subproject commit 48daccef2d1fefe965f020e5b342ed683fe40a62 +Subproject commit 606058ef552c6341c965bc76d3eda6929ca58e13 diff --git a/UPP/Core/PowerMonitor/adc_tools.c b/UPP/Core/PowerMonitor/adc_tools.c index cd95ac9..dbd81d7 100644 --- a/UPP/Core/PowerMonitor/adc_tools.c +++ b/UPP/Core/PowerMonitor/adc_tools.c @@ -55,14 +55,14 @@ static void ADC_InitAllFilters(ADC_Periodic_t *adc) { Filter_Init(&adc->filter[i], Filter_Initializator); } - FilterLUTInt_Init(&adc->temp_map[0], - (int32_t *)adc_temp_quants, - (int32_t *)adc_temp_vals, - sizeof(adc_temp_quants), 0); - FilterLUTInt_Init(&adc->temp_map[1], - (int32_t *)adc_temp_quants, - (int32_t *)adc_temp_vals, - sizeof(adc_temp_quants), 0); + FilterLUT_Init(&adc->temp_map[0], + (float *)adc_temp_quants, + (float *)adc_temp_vals, + numbof(adc_temp_quants), 1); + FilterLUT_Init(&adc->temp_map[1], + (float *)adc_temp_quants, + (float *)adc_temp_vals, + numbof(adc_temp_quants), 1); } /** * @brief Инициализация периодического АЦП. @@ -199,7 +199,7 @@ HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc) // Преобразования температуры по таблице for (int i = ADC_TEMP_CHANNELS_START; i < ADC_NUMB_OF_CHANNELS; i++) { - data[i] = FilterLUTInt_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]); + data[i] = Filter_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]); ADC_UpdateStatistics(adc, i, ADC_LEVEL_BASE); } diff --git a/UPP/Core/PowerMonitor/adc_tools.h b/UPP/Core/PowerMonitor/adc_tools.h index ad5c6e9..12da5ae 100644 --- a/UPP/Core/PowerMonitor/adc_tools.h +++ b/UPP/Core/PowerMonitor/adc_tools.h @@ -48,8 +48,8 @@ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, \ 82, 83, 84, 85, 86, 87, 88, 89, 90} -static const int32_t adc_temp_vals[] = ADC_TEMPERATURES; -static const int32_t adc_temp_quants[] = ADC_TEMPERATURES_QUANTS; +static const float adc_temp_vals[] = ADC_TEMPERATURES; +static const float adc_temp_quants[] = ADC_TEMPERATURES_QUANTS; #define Filter_t FilterMedian_t #define Filter_Init FilterMedian_Init @@ -102,7 +102,7 @@ typedef struct Filter_t filter[ADC_NUMB_OF_CHANNELS]; ///< Фильтр от шумов АЦП - FilterLUTInt_t temp_map[2]; ///< Коррекция нелинейности датчиков температуры + FilterLUT_t temp_map[2]; ///< Коррекция нелинейности датчиков температуры float Data[ADC_NUMB_OF_CHANNELS]; ///< Пересчитанные значения АЦП (в Вольтах/Амперах) ADC_Statistics Stat[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Статистика для регулярных каналов (не температуры) diff --git a/UPP/Core/PowerMonitor/power_monitor.c b/UPP/Core/PowerMonitor/power_monitor.c index c16178a..53f5f3e 100644 --- a/UPP/Core/PowerMonitor/power_monitor.c +++ b/UPP/Core/PowerMonitor/power_monitor.c @@ -51,6 +51,7 @@ HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm) void PowerMonitor_Handle(PowerMonitor_t *hpm) { + static uint32_t last_zc_state[ADC_NUMB_OF_U_CHANNELS] = {0}; ADC_Handle(&hpm->adc); diff --git a/UPP/Core/PowerMonitor/power_monitor.h b/UPP/Core/PowerMonitor/power_monitor.h index 858a8a0..54ac6e6 100644 --- a/UPP/Core/PowerMonitor/power_monitor.h +++ b/UPP/Core/PowerMonitor/power_monitor.h @@ -19,7 +19,7 @@ typedef struct float U[3]; float F[3]; float I[3]; - float T[3]; + float T[2]; }PowerMonitor_t; extern PowerMonitor_t pm;