Добавлена модель МК матлаб с компилятором MinGW

Но по какой-то приниче запуск модели лочит MCU.mexw64 и его нельзя удалить. Но при этом можно переименовать... непонятно крч
This commit is contained in:
2025-11-08 18:18:17 +03:00
parent 67c8d0e039
commit afc4a114f6
412 changed files with 863427 additions and 120 deletions

View File

@@ -0,0 +1,36 @@
#include "stm32_matlab_gpio.h"
void __GPIO_BSRR_Sim(GPIO_TypeDef* port);
void Simulate_GPIO_BSRR(void)
{
#ifdef GPIOA
__GPIO_BSRR_Sim(GPIOA);
#endif
#ifdef GPIOB
__GPIO_BSRR_Sim(GPIOB);
#endif
#ifdef GPIOC
__GPIO_BSRR_Sim(GPIOC);
#endif
#ifdef GPIOD
__GPIO_BSRR_Sim(GPIOD);
#endif
}
void __GPIO_BSRR_Sim(GPIO_TypeDef* port)
{
// Сохраняем значение регистра BSRR
uint32_t bsrr = port->BSRR;
// Нижние 16 бит — установка соответствующих битов ODR
port->ODR |= (uint16_t)(bsrr & 0xFFFF);
// Верхние 16 бит — сброс соответствующих битов ODR
port->ODR &= ~(uint16_t)((bsrr >> 16) & 0xFFFF);
// Обнуляем BSRR после обработки (в реальных STM32 он не сохраняет значение)
port->BSRR = 0;
}

View File

@@ -0,0 +1,39 @@
#ifndef _MATLAB_GPIO_H_
#define _MATLAB_GPIO_H_
#include "simstruc.h"
#include "stm32_matlab_conf.h"
//#include "mcu_wrapper_conf.h"
#ifdef STM32F1
/* дефайны для проверки конфигурации GPIO) */
#define GET_GPIO_CONF(_reg_, _pos_) \
((_pos_ < 8)?\
GET_BITS_FROM_REG(_reg_->CRL, GPIO_CRL_CNF0 << (_pos_<<2u), (_pos_<<2u)+GPIO_CRL_CNF0_Pos):\
GET_BITS_FROM_REG(_reg_->CRH, GPIO_CRL_CNF0 << ((_pos_-8)<<2u), ((_pos_-8)<<2u)+GPIO_CRL_CNF0_Pos) )
/* дефайны для проверки режима GPIO) */
#define GET_GPIO_MODE(_reg_, _pos_) \
((_pos_ < 8)?\
GET_BITS_FROM_REG(_reg_->CRL, GPIO_CRL_MODE0 << (_pos_<<2u), (_pos_<<2u)+GPIO_CRL_MODE0_Pos):\
GET_BITS_FROM_REG(_reg_->CRH, GPIO_CRL_MODE0 << ((_pos_-8)<<2u), ((_pos_-8)<<2u)+GPIO_CRL_MODE0_Pos) )
#endif
#ifdef STM32F4
/* дефайны для проверки конфигурации GPIO для STM32F4 */
#define GET_GPIO_CONF(_reg_, _pos_) \
((_reg_->MODER >> (_pos_ * 2u)) & 0x3u) // возвращает только MODER
/* дефайны для проверки режима GPIO для STM32F4 */
#define GET_GPIO_MODE(_reg_, _pos_) \
((_reg_->MODER >> (_pos_ * 2u)) & GPIO_MODER_MODER0)
/* константы для совместимости с F1 - должны соответствовать значениям MODER */
#define GPIO_MODE_AF 0x2u /* Alternate Function mode */
#endif
void Simulate_GPIO_BSRR(void);
#endif // _MATLAB_GPIO_H_

View File

@@ -0,0 +1,36 @@
#ifndef _MATLAB_RCC_H_
#define _MATLAB_RCC_H_
#include "stm32_matlab_conf.h"
//#define SYSLCK_Value ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)
//#define AHB_Prescaler ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos)
//#define AHB_Prescaler ((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)
//#define HCLK_Value (double)72000000;
//#define ABP1_Value (double)36000000;
//#define ABP1_TIMS_Value (double)72000000;
//#define ABP2_Value (double)72000000;
//#define ABP2_TIMS_Value (double)72000000;
/* Ёти дефайны добавлены в код stm32f4xx_hal_rcc.c, чтобы не попасть в бесконечный цикл */
/* ћб перенести в MCU_Periph_Simulation(), но чет не хочетс¤ нагружать симул¤цию этой херней*/
#define _RCC_SET_FLAG(__FLAG__) \
if(((__FLAG__) >> 5U) == 1U) RCC->CR |= (1U << ((__FLAG__) & RCC_FLAG_MASK)); \
else if(((__FLAG__) >> 5U) == 2U) RCC->BDCR |= (1U << ((__FLAG__) & RCC_FLAG_MASK)); \
else if(((__FLAG__) >> 5U) == 3U) RCC->CSR |= (1U << ((__FLAG__) & RCC_FLAG_MASK)); \
#define _RCC_CLEAR_FLAG(__FLAG__) \
if(((__FLAG__) >> 5U) == 1U) RCC->CR &= ~(1U << ((__FLAG__) & RCC_FLAG_MASK)); \
else if(((__FLAG__) >> 5U) == 2U) RCC->BDCR &= ~(1U << ((__FLAG__) & RCC_FLAG_MASK)); \
else if(((__FLAG__) >> 5U) == 3U) RCC->CSR &= ~(1U << ((__FLAG__) & RCC_FLAG_MASK)); \
#define Set_Flag_If_Its_Expected(_flag_, _condition_) \
if(_condition_) _RCC_CLEAR_FLAG(_flag_)
#define Clear_Flag_If_Its_Expected(_flag_, _condition_) \
if(_condition_) _RCC_SET_FLAG(_flag_)
#endif // _MATLAB_RCC_H_

View File

@@ -0,0 +1,617 @@
/**************************************************************************
Данный файл содержит функции для симуляции таймеров STM32F407xx.
**************************************************************************/
#include "stm32_matlab_tim.h"
struct SlaveChannels Slave_Channels; // структура для связи и синхронизации таймеров
//----------------------TIMER BASE FUNCTIONS-----------------------//
/* Базовая функция для симуляции таймера: она вызывается каждый шаг симуляции */
void TIM_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{
Overflow_Check(TIMx, TIMS);
// Выбор режима работы таймера
switch (TIMx->SMCR & TIM_SMCR_SMS) // TIMER MODE
{
// обычный счет
case(TIM_SLAVEMODE_DISABLE):// NORMAL MODE counting
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
break;
// включение слейв таймера по ивенту
case(TIM_SLAVEMODE_TRIGGER): // SLAVE MODE: TRIGGER MODE
Slave_Mode_Check_Source(TIMx, TIMS);
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
break;
}
}
/* Счет таймера за один такт */
void TIMx_Count(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
if ((TIMx->CR1 & TIM_CR1_DIR) && TIMx->CR1) // up COUNTER and COUNTER ENABLE
TIMS->tx_cnt -= TIMS->tx_step / (TIMx->PSC + 1);
else if (((TIMx->CR1 & TIM_CR1_DIR) == 0) && TIMx->CR1) // down COUNTER and COUNTER ENABLE
TIMS->tx_cnt += TIMS->tx_step / (TIMx->PSC + 1);
TIMx->CNT = (uint32_t)TIMS->tx_cnt;
}
/* Проверка на переполнение и дальнейшая его обработка */
void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
// Переполнение таймера: сброс таймера и вызов прерывания
if ((TIMx->CR1 & TIM_CR1_UDIS) == 0) // UPDATE enable
{
if ((TIMx->CR1 & TIM_CR1_ARPE) == 0) TIMS->RELOAD = TIMx->ARR; // PRELOAD disable - update ARR every itteration
if (TIMS->tx_cnt > TIMS->RELOAD || TIMS->tx_cnt < 0) // OVERFLOW
{
TIMS->RELOAD = TIMx->ARR; // RELOAD ARR
if (TIMS->tx_cnt > TIMx->ARR) // reset COUNTER
TIMS->tx_cnt -= TIMS->RELOAD+1;
else if (TIMS->tx_cnt < 0)
TIMS->tx_cnt += TIMS->RELOAD+1;
call_IRQHandller(TIMx); // call HANDLER
}
}
}
//-----------------------------------------------------------------//
//----------------------------CHANNELS-----------------------------//
/* Симуляция каналов таймера */
void Channels_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
CC_PWM_Ch1_Simulation(TIMx, TIMS);
CC_PWM_Ch2_Simulation(TIMx, TIMS);
CC_PWM_Ch3_Simulation(TIMx, TIMS);
CC_PWM_Ch4_Simulation(TIMx, TIMS);
Write_OC_to_GPIO(TIMx, TIMS);
Write_OC_to_TRGO(TIMx, TIMS);
}
//-----------------CAPTURE COPMARE & PWM FUNCTIONS------------------//
/* Выбор режима CaptureCompare или PWM и симуляция для каждого канала */
void CC_PWM_Ch1_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
switch (TIMx->CCMR1 & TIM_CCMR1_OC1M)
{
case (TIM_OCMODE_ACTIVE): // ACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step)
TIMS->Channels.OC1REF = 1;
break;
case (TIM_OCMODE_INACTIVE): // INACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step)
TIMS->Channels.OC1REF = 0;
break;
case (TIM_OCMODE_TOGGLE): // TOOGLE mode
if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step)
TIMS->Channels.OC1REF = ~TIMS->Channels.OC1REF;
break;
case (TIM_OCMODE_PWM1): // PWM MODE 1 mode
if (TIMx->CNT < TIMx->CCR1)
TIMS->Channels.OC1REF = 1;
else
TIMS->Channels.OC1REF = 0;
break;
case (TIM_OCMODE_PWM2): // PWM MODE 2 mode
if (TIMx->CNT < TIMx->CCR1)
TIMS->Channels.OC1REF = 0;
else
TIMS->Channels.OC1REF = 1;
break;
case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode
TIMS->Channels.OC1REF = 1; break;
case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode
TIMS->Channels.OC1REF = 0; break;
}
}
void CC_PWM_Ch2_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
switch (TIMx->CCMR1 & TIM_CCMR1_OC2M)
{
case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step)
TIMS->Channels.OC2REF = 1;
break;
case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step)
TIMS->Channels.OC2REF = 0;
break;
case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode
if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step)
TIMS->Channels.OC2REF = ~TIMS->Channels.OC2REF;
break;
case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode
if (TIMx->CNT < TIMx->CCR2)
TIMS->Channels.OC2REF = 1;
else
TIMS->Channels.OC2REF = 0;
break;
case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode
if (TIMx->CNT < TIMx->CCR2)
TIMS->Channels.OC2REF = 0;
else
TIMS->Channels.OC2REF = 1;
break;
case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode
TIMS->Channels.OC2REF = 1; break;
case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode
TIMS->Channels.OC2REF = 0; break;
}
}
void CC_PWM_Ch3_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
switch (TIMx->CCMR2 & TIM_CCMR1_OC1M)
{
case (TIM_OCMODE_ACTIVE): // ACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step)
TIMS->Channels.OC3REF = 1;
break;
case (TIM_OCMODE_INACTIVE): // INACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step)
TIMS->Channels.OC3REF = 0;
break;
case (TIM_OCMODE_TOGGLE): // Toogle mode
if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step)
TIMS->Channels.OC3REF = ~TIMS->Channels.OC3REF;
break;
case (TIM_OCMODE_PWM1): // PWM mode 1 mode
if (TIMx->CNT < TIMx->CCR3)
TIMS->Channels.OC3REF = 1;
else
TIMS->Channels.OC3REF = 0;
break;
case (TIM_OCMODE_PWM2): // PWM mode 2 mode
if (TIMx->CNT < TIMx->CCR3)
TIMS->Channels.OC3REF = 0;
else
TIMS->Channels.OC3REF = 1;
break;
case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode
TIMS->Channels.OC3REF = 1; break;
case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode
TIMS->Channels.OC3REF = 0; break;
}
}
void CC_PWM_Ch4_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
switch (TIMx->CCMR1 & TIM_CCMR1_OC2M)
{
case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step)
TIMS->Channels.OC4REF = 1;
break;
case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step)
TIMS->Channels.OC4REF = 0;
break;
case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode
if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step)
TIMS->Channels.OC4REF = ~TIMS->Channels.OC4REF;
break;
case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode
if (TIMx->CNT < TIMx->CCR4)
TIMS->Channels.OC4REF = 1;
else
TIMS->Channels.OC4REF = 0;
break;
case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode
if (TIMx->CNT < TIMx->CCR4)
TIMS->Channels.OC4REF = 0;
else
TIMS->Channels.OC4REF = 1;
break;
case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode
TIMS->Channels.OC4REF = 1; break;
case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode
TIMS->Channels.OC4REF = 0; break;
}
}
/* Запись каналов таймера в порты GPIO */
void Write_OC_to_GPIO(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{
// write gpio pin if need
if (Check_OC1_GPIO_Output(TIMS)) // check OC OUTPUT 4 enable (GPIO AF MODE)
{
uint32_t temp2 = ~(uint32_t)(1 << (TIMS->Channels.OC1_PIN_SHIFT));
if (TIMx->CCER & TIM_CCER_CC1P) // POLARITY check
{ // low POLARITY
if (TIMS->Channels.OC1REF)
TIMS->Channels.OC1_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC1_PIN_SHIFT));
else
TIMS->Channels.OC1_GPIOx->ODR |= 1 << (TIMS->Channels.OC1_PIN_SHIFT);
}
else
{ // high POLARITY
if (TIMS->Channels.OC1REF)
TIMS->Channels.OC1_GPIOx->ODR |= 1 << (TIMS->Channels.OC1_PIN_SHIFT);
else
TIMS->Channels.OC1_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC1_PIN_SHIFT));
}
}
if (Check_OC2_GPIO_Output(TIMS)) // check OC OUTPUT 4 enable (GPIO AF MODE)
{
if (TIMx->CCER & TIM_CCER_CC2P) // POLARITY check
{ // low POLARITY
if (TIMS->Channels.OC2REF)
TIMS->Channels.OC2_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC2_PIN_SHIFT));
else
TIMS->Channels.OC2_GPIOx->ODR |= 1 << (TIMS->Channels.OC2_PIN_SHIFT);
}
else
{ // high POLARITY
if (TIMS->Channels.OC2REF)
TIMS->Channels.OC2_GPIOx->ODR |= 1 << (TIMS->Channels.OC2_PIN_SHIFT);
else
TIMS->Channels.OC2_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC2_PIN_SHIFT));
}
}
if (Check_OC3_GPIO_Output(TIMS)) // check OC OUTPUT 4 enable (GPIO AF MODE)
{
if (TIMx->CCER & TIM_CCER_CC3P) // POLARITY check
{ // low POLARITY
if (TIMS->Channels.OC3REF)
TIMS->Channels.OC3_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC3_PIN_SHIFT));
else
TIMS->Channels.OC3_GPIOx->ODR |= 1 << (TIMS->Channels.OC3_PIN_SHIFT);
}
else
{ // high POLARITY
if (TIMS->Channels.OC3REF)
TIMS->Channels.OC3_GPIOx->ODR |= 1 << (TIMS->Channels.OC3_PIN_SHIFT);
else
TIMS->Channels.OC3_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC3_PIN_SHIFT));
}
}
if (Check_OC4_GPIO_Output(TIMS)) // check OC CHANNEL 4 enable (GPIO AF MODE)
{
if (TIMx->CCER & TIM_CCER_CC4P) // POLARITY check
{ // low POLARITY
if (TIMS->Channels.OC4REF)
TIMS->Channels.OC4_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC4_PIN_SHIFT));
else
TIMS->Channels.OC4_GPIOx->ODR |= (1) << (TIMS->Channels.OC4_PIN_SHIFT);
}
else
{ // high POLARITY
if (TIMS->Channels.OC4REF)
TIMS->Channels.OC4_GPIOx->ODR |= (1) << (TIMS->Channels.OC4_PIN_SHIFT);
else
TIMS->Channels.OC4_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC4_PIN_SHIFT));
}
}
}
/* Запись результата compare в глабальную структуру с TRIGGER OUTPUT */
void Write_OC_to_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
// write trigger output from OCxREF pin if need
unsigned temp_trgo;
if ((TIMx->CR2 & TIM_CR2_MMS) == (0b100 << TIM_CR2_MMS_Pos))
{
temp_trgo = TIMS->Channels.OC1REF;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (0b101 << TIM_CR2_MMS_Pos))
{
temp_trgo = TIMS->Channels.OC2REF;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (0b110 << TIM_CR2_MMS_Pos))
{
temp_trgo = TIMS->Channels.OC3REF;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (0b111 << TIM_CR2_MMS_Pos))
{
temp_trgo = TIMS->Channels.OC4REF;
}
// select TIMx TRGO
if(0) {}
#ifdef USE_TIM1
else if (TIMx == TIM1)
Slave_Channels.TIM1_TRGO = temp_trgo;
#endif
#ifdef USE_TIM2
else if (TIMx == TIM2)
Slave_Channels.TIM2_TRGO = temp_trgo;
#endif
#ifdef USE_TIM3
else if (TIMx == TIM3)
Slave_Channels.TIM3_TRGO = temp_trgo;
#endif
#ifdef USE_TIM4
else if (TIMx == TIM4)
Slave_Channels.TIM4_TRGO = temp_trgo;
#endif
#ifdef USE_TIM5
else if (TIMx == TIM5)
Slave_Channels.TIM5_TRGO = temp_trgo;
#endif
#ifdef USE_TIM6
else if (TIMx == TIM6)
Slave_Channels.TIM6_TRGO = temp_trgo;
#endif
#ifdef USE_TIM7
else if (TIMx == TIM7)
Slave_Channels.TIM7_TRGO = temp_trgo;
#endif
#ifdef USE_TIM8
else if (TIMx == TIM8)
Slave_Channels.TIM8_TRGO = temp_trgo;
#endif
temp_trgo = 0;
}
//------------------------------------------------------------------//
//--------------------MISC (temporary) FUNCTIONS--------------------//
/* Определение источника для запуска таймера в SLAVE MODE */
void Slave_Mode_Check_Source(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
if(0) {}
#ifdef USE_TIM2
else if (TIMx == TIM2)
{
if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
TIMx->CR1 |= (Slave_Channels.TIM1_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
TIMx->CR1 |= (Slave_Channels.TIM1_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
TIMx->CR1 |= (Slave_Channels.TIM1_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
TIMx->CR1 |= (Slave_Channels.TIM8_TRGO << TIM_CR1_CEN_Pos);
}
#endif
#ifdef USE_TIM3
else if (TIMx == TIM3)
{
if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
TIMx->CR1 |= (Slave_Channels.TIM8_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
TIMx->CR1 |= (Slave_Channels.TIM2_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
TIMx->CR1 |= (Slave_Channels.TIM2_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
TIMx->CR1 |= (Slave_Channels.TIM3_TRGO << TIM_CR1_CEN_Pos);
}
#endif
#ifdef USE_TIM4
else if (TIMx == TIM4)
{
if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
TIMx->CR1 |= (Slave_Channels.TIM3_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
TIMx->CR1 |= (Slave_Channels.TIM5_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
TIMx->CR1 |= (Slave_Channels.TIM3_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
TIMx->CR1 |= (Slave_Channels.TIM4_TRGO << TIM_CR1_CEN_Pos);
}
#endif
#ifdef USE_TIM5
else if (TIMx == TIM5)
{
if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
TIMx->CR1 |= (Slave_Channels.TIM4_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
TIMx->CR1 |= (Slave_Channels.TIM4_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
TIMx->CR1 |= (Slave_Channels.TIM7_TRGO << TIM_CR1_CEN_Pos);
else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
TIMx->CR1 |= (Slave_Channels.TIM7_TRGO << TIM_CR1_CEN_Pos);
}
#endif
}
//------------------------------------------------------------------//
//------------------------SIMULINK FUNCTIONS------------------------//
// Симулирование выбранных таймеров
void Simulate_TIMs(void)
{
//uwTick = hmcu.SystemClock / (MCU_CORE_CLOCK / 1000);
#ifdef USE_TIM1
TIM_Simulation(TIM1, &tim1s);
#endif
#ifdef USE_TIM2
TIM_Simulation(TIM2, &tim2s);
#endif
#ifdef USE_TIM3
TIM_Simulation(TIM3, &tim3s);
#endif
#ifdef USE_TIM4
TIM_Simulation(TIM4, &tim4s);
#endif
#ifdef USE_TIM5
TIM_Simulation(TIM5, &tim5s);
#endif
#ifdef USE_TIM6
TIM_Simulation(TIM6, &tim6s);
#endif
#ifdef USE_TIM7
TIM_Simulation(TIM7, &tim7s);
#endif
#ifdef USE_TIM8
TIM_Simulation(TIM8, &tim8s);
#endif
#ifdef USE_TIM9
TIM_Simulation(TIM9, &tim9s);
#endif
#ifdef USE_TIM10
TIM_Simulation(TIM10, &tim10s);
#endif
#ifdef USE_TIM11
TIM_Simulation(TIM11, &tim11s);
#endif
#ifdef USE_TIM12
TIM_Simulation(TIM12, &tim12s);
#endif
#ifdef USE_TIM13
TIM_Simulation(TIM13, &tim13s);
#endif
#ifdef USE_TIM14
TIM_Simulation(TIM14, &tim14s);
#endif
}
// Деинициализирование выбранных таймеров (вызывается в конце симуляции)
void TIM_SIM_DEINIT(void)
{
#ifdef USE_TIM1
memset(&tim1s, 0, sizeof(tim1s));
#endif
#ifdef USE_TIM2
memset(&tim2s, 0, sizeof(tim2s));
#endif
#ifdef USE_TIM3
memset(&tim3s, 0, sizeof(tim3s));
#endif
#ifdef USE_TIM4
memset(&tim4s, 0, sizeof(tim4s));
#endif
#ifdef USE_TIM5
memset(&tim5s, 0, sizeof(tim5s));
#endif
#ifdef USE_TIM6
memset(&tim6s, 0, sizeof(tim6s));
#endif
#ifdef USE_TIM7
memset(&tim7s, 0, sizeof(tim7s));
#endif
#ifdef USE_TIM8
memset(&tim8s, 0, sizeof(tim8s));
#endif
#ifdef USE_TIM9
memset(&tim9s, 0, sizeof(tim9s));
#endif
#ifdef USE_TIM10
memset(&tim10s, 0, sizeof(tim10s));
#endif
#ifdef USE_TIM11
memset(&tim11s, 0, sizeof(tim11s));
#endif
#ifdef USE_TIM12
memset(&tim12s, 0, sizeof(tim12s));
#endif
#ifdef USE_TIM13
memset(&tim13s, 0, sizeof(tim13s));
#endif
#ifdef USE_TIM14
memset(&tim14s, 0, sizeof(tim14s));
#endif
}
//------------------------------------------------------------------//
//------------------TIM'S HANDLERS (BETA) FUNCTIONS-----------------//
// Определение обработчиков, которые не используются
// Т.к. в MSVC нет понятия weak function, необходимо объявить все колбеки
// И если какой-то колбек не используется, его надо определить
//#ifndef USE_TIM1_UP_TIM10_HANDLER
//void TIM1_UP_TIM10_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM2_HANDLER
//void TIM2_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM3_HANDLER
//void TIM3_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM4_HANDLER
//void TIM4_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM5_HANDLER
//void TIM5_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM6_HANDLER
//void TIM6_DAC_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM7_HANDLER
//void TIM7_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM8_UP_TIM13_HANDLER
//void TIM8_UP_TIM13_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM1_BRK_TIM9_HANDLER
//void TIM1_BRK_TIM9_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM1_TRG_COM_TIM11_HANDLER
//void TIM1_TRG_COM_TIM11_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM8_BRK_TIM12_HANDLER
//void TIM8_BRK_TIM12_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM8_TRG_COM_TIM14_HANDLER
//void TIM8_TRG_COM_TIM14_IRQHandler(void) {}
//#endif
/* Вызов прерывания */
void call_IRQHandller(TIM_TypeDef* TIMx)
{ // calling HANDLER
//if (TIMx == TIM1)
// TIM1_UP_IRQHandler();
//if ((TIMx == TIM1) || (TIMx == TIM10))
// TIM1_UP_TIM10_IRQHandler();
//else if (TIMx == TIM2)
// TIM2_IRQHandler();
//else if (TIMx == TIM3)
// TIM3_IRQHandler();
//else if (TIMx == TIM4)
// TIM4_IRQHandler();
//else if (TIMx == TIM5)
// TIM5_IRQHandler();
//else if (TIMx == TIM6)
// TIM6_DAC_IRQHandler();
//else if (TIMx == TIM7)
// TIM7_IRQHandler();
//else if ((TIMx == TIM8) || (TIMx == TIM13))
// TIM8_UP_TIM13_IRQHandler();
//else if ((TIMx == TIM1) || (TIMx == TIM9))
// TIM1_BRK_TIM9_IRQHandler();
//else if ((TIMx == TIM1) || (TIMx == TIM11))
// TIM1_TRG_COM_TIM11_IRQHandler();
//else if ((TIMx == TIM8) || (TIMx == TIM12))
// TIM8_BRK_TIM12_IRQHandler();
//else if ((TIMx == TIM8) || (TIMx == TIM14))
// TIM8_TRG_COM_TIM14_IRQHandler();
}
//------------------------------------------------------------------//

View File

@@ -0,0 +1,123 @@
/**************************************************************************
Данный файл содержит объявления всякого для симуляции таймеров STM32F407xx.
**************************************************************************/
#ifndef _MATLAB_TIM_H_
#define _MATLAB_TIM_H_
#include "stm32_matlab_conf.h"
//#include "mcu_wrapper_conf.h"
/////////////////////////////---DEFINES---/////////////////////////////
/* дефайн для сдвига между первой и второй половиной CCMRx регистров */
#define TIM_OCMODE_SECOND_SHIFT TIM_CCMR1_OC2M_Pos - TIM_CCMR1_OC1M_Pos
///* дефайны для проверки выводить ли канал на GPIO (настроен ли GPIO на альтернативную функцию) */
//#define READ_GPIO_CRL_CNF(_reg_, _pos_) ((_pos_ < 8)? \
// ((((_reg_->CRL) & (GPIO_CRL_CNF0 << (_pos_ << 2u))) >> ( _pos_ << 2u)) >> 2): \
// ((((_reg_->CRH) & (GPIO_CRL_CNF0 << ((_pos_ - 8) << 2u))) >> ((_pos_ - 8) << 2u)) >> 2) )
#define Check_OC1_GPIO_Output(_tims_) (GPIO_MODE_AF_PP == GET_GPIO_CONF(_tims_->Channels.OC1_GPIOx, _tims_->Channels.OC1_PIN_SHIFT))
#define Check_OC2_GPIO_Output(_tims_) (GPIO_MODE_AF_PP == GET_GPIO_CONF(_tims_->Channels.OC2_GPIOx, _tims_->Channels.OC2_PIN_SHIFT))
#define Check_OC3_GPIO_Output(_tims_) (GPIO_MODE_AF_PP == GET_GPIO_CONF(_tims_->Channels.OC3_GPIOx, _tims_->Channels.OC3_PIN_SHIFT))
#define Check_OC4_GPIO_Output(_tims_) (GPIO_MODE_AF_PP == GET_GPIO_CONF(_tims_->Channels.OC4_GPIOx, _tims_->Channels.OC4_PIN_SHIFT))
/////////////////////////////////////////////////////////////////////
///////////////////////////---STRUCTURES---//////////////////////////
/* Структура для управления Слейв Таймерами */
struct SlaveChannels
{
unsigned TIM1_TRGO : 1;
unsigned TIM2_TRGO : 1;
unsigned TIM3_TRGO : 1;
unsigned TIM4_TRGO : 1;
unsigned TIM5_TRGO : 1;
unsigned TIM6_TRGO : 1;
unsigned TIM7_TRGO : 1;
unsigned TIM8_TRGO : 1;
};
/* Структура для моделирования каналов таймера */
struct Channels_Sim
{
// связанные с каналами GPIO порты и пины
GPIO_TypeDef *OC1_GPIOx;
uint32_t OC1_PIN_SHIFT;
GPIO_TypeDef *OC2_GPIOx;
uint32_t OC2_PIN_SHIFT;
GPIO_TypeDef *OC3_GPIOx;
uint32_t OC3_PIN_SHIFT;
GPIO_TypeDef *OC4_GPIOx;
uint32_t OC4_PIN_SHIFT;
// Каналы таймера
unsigned OC1REF:1;
unsigned OC2REF:1;
unsigned OC3REF:1;
unsigned OC4REF:1;
};
/* Структура для моделирования таймера */
struct TIM_Sim
{
double tx_cnt; // счетчик таймера
double tx_step; // шаг счета за один шаг симуляции
int RELOAD; // буфер, если PRELOAD = 1
struct Channels_Sim Channels; // структура для симуляции каналов
};
/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
//----------------------TIMER BASE FUNCTIONS-----------------------//
/* Базовая функция для симуляции таймера: она вызывается каждый шаг симуляции */
void TIM_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS);
/* Счет таймера за один такт */
void TIMx_Count(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Проверка на переполнение и дальнейшая его обработка */
void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Вызов прерывания */
void call_IRQHandller(TIM_TypeDef *TIMx);
//-----------------------------------------------------------------//
//------------------------CHANNELS FUNCTIONS-----------------------//
/* Симуляция каналов таймера */
void Channels_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS);
/*---------------- - CAPTURE COPMARE & PWM FUNCTIONS------------------*/
/* Выбор режима CaptureCompare или PWM и симуляция для каждого канала */
void CC_PWM_Ch1_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
void CC_PWM_Ch2_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
void CC_PWM_Ch3_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
void CC_PWM_Ch4_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Запись каналов таймера в порты GPIO */
void Write_OC_to_GPIO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Запись результата compare в глабальную структуру с TRIGGER OUTPUT */
void Write_OC_to_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
//------------------------------------------------------------------//
//--------------------MISC (temporary) FUNCTIONS--------------------//
/* Определение источника для запуска таймера в SLAVE MODE */
void Slave_Mode_Check_Source(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
//------------------------------------------------------------------//
//------------------------SIMULINK FUNCTIONS------------------------//
// Симулирование выбранных таймеров
void Simulate_TIMs(void);
// Деинициализирование выбранных таймеров (вызывается в конце симуляции)
void TIM_SIM_DEINIT(void);
//------------------------------------------------------------------//
#endif // _MATLAB_TIM_H_

View File

@@ -0,0 +1,395 @@
/**************************************************************************
Данный файл необходим для объявления структур для отображения их в watch
В оригинальном stm32f407xx они объявлены дефайнами, которые не видны в watch.
Поэтому дополнительно объявлены данные структуры.
Называются также, как CMSISные, только в нижнем регистре
**************************************************************************/
#include "stm32_matlab_conf.h"
#ifdef TIM1
TIM_TypeDef *tim1 = TIM1;
#endif
#ifdef TIM2
TIM_TypeDef *tim2 = TIM2;
#endif
#ifdef TIM3
TIM_TypeDef *tim3 = TIM3;
#endif
#ifdef TIM4
TIM_TypeDef *tim4 = TIM4;
#endif
#ifdef TIM5
TIM_TypeDef *tim5 = TIM5;
#endif
#ifdef TIM6
TIM_TypeDef *tim6 = TIM6;
#endif
#ifdef TIM7
TIM_TypeDef *tim7 = TIM7;
#endif
#ifdef TIM8
TIM_TypeDef *tim8 = TIM8;
#endif
#ifdef TIM9
TIM_TypeDef *tim9 = TIM9;
#endif
#ifdef TIM10
TIM_TypeDef *tim10 = TIM10;
#endif
#ifdef TIM11
TIM_TypeDef *tim11 = TIM11;
#endif
#ifdef TIM12
TIM_TypeDef *tim12 = TIM12;
#endif
#ifdef TIM13
TIM_TypeDef *tim13 = TIM13;
#endif
#ifdef TIM14
TIM_TypeDef *tim14 = TIM14;
#endif
#ifdef RTC
RTC_TypeDef *rtc = RTC;
#endif
#ifdef WWDG
WWDG_TypeDef *wwdg = WWDG;
#endif
#ifdef IWDG
IWDG_TypeDef *iwdg = IWDG;
#endif
#ifdef SPI1
SPI_TypeDef *spi1 = SPI1;
#endif
#ifdef SPI2
SPI_TypeDef *spi2 = SPI2;
#endif
#ifdef SPI3
SPI_TypeDef *spi3 = SPI3;
#endif
#ifdef SPI4
SPI_TypeDef *spi4 = SPI4;
#endif
#ifdef SPI5
SPI_TypeDef *spi5 = SPI5;
#endif
#ifdef SPI6
SPI_TypeDef *spi6 = SPI6;
#endif
#ifdef USART1
USART_TypeDef *usart1 = USART1;
#endif
#ifdef USART2
USART_TypeDef *usart2 = USART2;
#endif
#ifdef USART3
USART_TypeDef *usart3 = USART3;
#endif
#ifdef UART4
USART_TypeDef *uart4 = UART4;
#endif
#ifdef UART5
USART_TypeDef *uart5 = UART5;
#endif
#ifdef USART6
USART_TypeDef *usart6 = USART6;
#endif
#ifdef I2C1
I2C_TypeDef *i2c1 = I2C1;
#endif
#ifdef I2C2
I2C_TypeDef *i2c2 = I2C2;
#endif
#ifdef I2C3
I2C_TypeDef *i2c3 = I2C3;
#endif
#ifdef CAN1
CAN_TypeDef *can1 = CAN1;
#endif
#ifdef CAN2
CAN_TypeDef *can2 = CAN2;
#endif
#ifdef PWR
PWR_TypeDef *pwr = PWR;
#endif
#ifdef ADC1
ADC_TypeDef *adc1 = ADC1;
#endif
#ifdef ADC2
ADC_TypeDef *adc2 = ADC2;
#endif
#ifdef ADC3
ADC_TypeDef *adc3 = ADC3;
#endif
#ifdef EXTI
EXTI_TypeDef *exti = EXTI;
#endif
#ifdef GPIOA
GPIO_TypeDef *gpioa = GPIOA;
#endif
#ifdef GPIOB
GPIO_TypeDef *gpiob = GPIOB;
#endif
#ifdef GPIOC
GPIO_TypeDef *gpioc = GPIOC;
#endif
#ifdef GPIOD
GPIO_TypeDef *gpiod = GPIOD;
#endif
#ifdef GPIOE
GPIO_TypeDef *gpioe = GPIOE;
#endif
#ifdef GPIOF
GPIO_TypeDef *gpiof = GPIOF;
#endif
#ifdef GPIOG
GPIO_TypeDef *gpiog = GPIOG;
#endif
#ifdef GPIOH
GPIO_TypeDef *gpioh = GPIOH;
#endif
#ifdef GPIOI
GPIO_TypeDef *gpioi = GPIOI;
#endif
#ifdef GPIOJ
GPIO_TypeDef *gpioj = GPIOJ;
#endif
#ifdef GPIOK
GPIO_TypeDef *gpiok = GPIOK;
#endif
#ifdef CRC
CRC_TypeDef *crc = CRC;
#endif
#ifdef RCC
RCC_TypeDef *rcc = RCC;
#endif
#ifdef FLASH
FLASH_TypeDef *flash_r = FLASH;
#endif
#ifdef DMA1
DMA_TypeDef *dma1 = DMA1;
#endif
#ifdef DMA2
DMA_TypeDef *dma2 = DMA2;
#endif
#ifdef DMA1_Channel1
DMA_Channel_TypeDef *dma1_channel1 = DMA1_Channel1;
#endif
#ifdef DMA1_Channel2
DMA_Channel_TypeDef *dma1_channel2 = DMA1_Channel2;
#endif
#ifdef DMA1_Channel3
DMA_Channel_TypeDef *dma1_channel3 = DMA1_Channel3;
#endif
#ifdef DMA1_Channel4
DMA_Channel_TypeDef *dma1_channel4 = DMA1_Channel4;
#endif
#ifdef DMA1_Channel5
DMA_Channel_TypeDef *dma1_channel5 = DMA1_Channel5;
#endif
#ifdef DMA1_Channel6
DMA_Channel_TypeDef *dma1_channel6 = DMA1_Channel6;
#endif
#ifdef DMA1_Channel7
DMA_Channel_TypeDef *dma1_channel7 = DMA1_Channel7;
#endif
#ifdef DMA2_Channel1
DMA_Channel_TypeDef *dma2_channel1 = DMA2_Channel1;
#endif
#ifdef DMA2_Channel2
DMA_Channel_TypeDef *dma2_channel2 = DMA2_Channel2;
#endif
#ifdef DMA2_Channel3
DMA_Channel_TypeDef *dma2_channel3 = DMA2_Channel3;
#endif
#ifdef DMA2_Channel4
DMA_Channel_TypeDef *dma2_channel4 = DMA2_Channel4;
#endif
#ifdef DMA2_Channel5
DMA_Channel_TypeDef *dma2_channel5 = DMA2_Channel5;
#endif
#ifdef DMA1_Stream0
DMA_Stream_TypeDef *dma1_stream0 = DMA1_Stream0;
#endif
#ifdef DMA1_Stream1
DMA_Stream_TypeDef *dma1_stream1 = DMA1_Stream1;
#endif
#ifdef DMA1_Stream2
DMA_Stream_TypeDef *dma1_stream2 = DMA1_Stream2;
#endif
#ifdef DMA1_Stream3
DMA_Stream_TypeDef *dma1_stream3 = DMA1_Stream3;
#endif
#ifdef DMA1_Stream4
DMA_Stream_TypeDef *dma1_stream4 = DMA1_Stream4;
#endif
#ifdef DMA1_Stream5
DMA_Stream_TypeDef *dma1_stream5 = DMA1_Stream5;
#endif
#ifdef DMA1_Stream6
DMA_Stream_TypeDef *dma1_stream6 = DMA1_Stream6;
#endif
#ifdef DMA1_Stream7
DMA_Stream_TypeDef *dma1_stream7 = DMA1_Stream7;
#endif
#ifdef DMA2_Stream0
DMA_Stream_TypeDef *dma2_stream0 = DMA2_Stream0;
#endif
#ifdef DMA2_Stream1
DMA_Stream_TypeDef *dma2_stream1 = DMA2_Stream1;
#endif
#ifdef DMA2_Stream2
DMA_Stream_TypeDef *dma2_stream2 = DMA2_Stream2;
#endif
#ifdef DMA2_Stream3
DMA_Stream_TypeDef *dma2_stream3 = DMA2_Stream3;
#endif
#ifdef DMA2_Stream4
DMA_Stream_TypeDef *dma2_stream4 = DMA2_Stream4;
#endif
#ifdef DMA2_Stream5
DMA_Stream_TypeDef *dma2_stream5 = DMA2_Stream5;
#endif
#ifdef DMA2_Stream6
DMA_Stream_TypeDef *dma2_stream6 = DMA2_Stream6;
#endif
#ifdef DMA2_Stream7
DMA_Stream_TypeDef *dma2_stream7 = DMA2_Stream7;
#endif
#ifdef DBGMCU
DBGMCU_TypeDef *dbgmcu = DBGMCU;
#endif
#ifdef SYSCFG
SYSCFG_TypeDef *syscfg = SYSCFG;
#endif
#ifdef NVIC
NVIC_Type *nvic = NVIC;
#endif
#ifdef SDIO
SDIO_TypeDef *sdio = SDIO;
#endif
#ifdef ETH
ETH_TypeDef *eth = ETH;
#endif
#ifdef USB_OTG_FS
USB_OTG_GlobalTypeDef *usb_otg_fs = USB_OTG_FS;
#endif
#ifdef USB_OTG_HS
USB_OTG_GlobalTypeDef *usb_otg_hs = USB_OTG_HS;
#endif
#ifdef DAC
DAC_TypeDef *dac = DAC;
#endif
#ifdef CRYP
CRYP_TypeDef *cryp = CRYP;
#endif
#ifdef HASH
HASH_TypeDef *hash = HASH;
#endif
#ifdef RNG
RNG_TypeDef *rng = RNG;
#endif
#ifdef FSMC
FSMC_TypeDef *fsmc = FSMC;
#endif
#ifdef DCMI
DCMI_TypeDef *dcmi = DCMI;
#endif