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