template + constexpr (C++14) |
. - constexpr-, , . , static_assert . static_assert , constexpr, - .constexpr , , throw constexpr . , - , , ( ).
? - , , :
/*
* .
*/
struct __attribute__( ( packed ) ) pin_config_t {
EC_PORT_NAME port; //
// ( : EC_PORT_NAME::A ).
EC_PORT_PIN_NAME pin_name; //
// ( : EC_PORT_PIN_NAME::PIN_0 ).
EC_PIN_MODE mode; //
// ( : EC_PIN_MODE::OUTPUT ).
EC_PIN_OUTPUT_CFG output_config; //
// ( : EC_PIN_OUTPUT_CFG::NOT_USE ).
EC_PIN_SPEED speed; //
// ( : EC_PIN_SPEED::MEDIUM ).
EC_PIN_PULL pull; //
// ( : EC_PIN_PULL::NO ).
EC_PIN_AF af; //
// ( : EC_PIN_AF::NOT_USE ).
EC_LOCKED locked; //
//
// global_port
// ( EC_LOCKED::NOT_LOCKED ).
EC_PIN_STATE_AFTER_INIT state_after_init; //
// ( , ).
// ( EC_PIN_STATE_AFTER_INIT::NO_USE).
};
/**********************************************************************
* enum class-.
**********************************************************************/
/*
* .
*/
enum class EC_PORT_PIN_NAME {
PIN_0 = 0,
PIN_1 = 1,
PIN_2 = 2,
PIN_3 = 3,
PIN_4 = 4,
PIN_5 = 5,
PIN_6 = 6,
PIN_7 = 7,
PIN_8 = 8,
PIN_9 = 9,
PIN_10 = 10,
PIN_11 = 11,
PIN_12 = 12,
PIN_13 = 13,
PIN_14 = 14,
PIN_15 = 15
};
/*
* .
*/
enum class EC_PIN_MODE {
INPUT = 0, // .
OUTPUT = 1, // .
AF = 2, // .
ANALOG = 3 // .
};
/*
* .
*/
enum class EC_PIN_OUTPUT_CFG {
NO_USE = 0, // .
PUSH_PULL = 0, // "-".
OPEN_DRAIN = 1 // " ".
};
/*
* .
*/
enum class EC_PIN_SPEED {
LOW = 0, // .
MEDIUM = 1, // .
FAST = 2, // .
HIGH = 3 //
};
/*
*
*/
enum class EC_PIN_PULL {
NO_USE = 0, // .
UP = 1, // .
DOWN = 2 // .
};
/*
* , .
*/
enum class EC_PIN_AF {
AF_0 = 0,
NO_USE = AF_0,
SYS = AF_0,
AF_1 = 1,
TIM1 = AF_1,
TIM2 = AF_1,
AF_2 = 2,
TIM3 = AF_2,
TIM4 = AF_2,
TIM5 = AF_2,
AF_3 = 3,
TIM8 = AF_3,
TIM9 = AF_3,
TIM10 = AF_3,
TIM11 = AF_3,
AF_4 = 4,
I2C1 = AF_4,
I2C2 = AF_4,
I2C3 = AF_4,
AF_5 = 5,
SPI1 = AF_5,
SPI2 = AF_5,
I2S2 = AF_5,
AF_6 = 6,
SPI3 = AF_6,
I2S3 = AF_6,
AF_7 = 7,
USART1 = AF_7,
USART2 = AF_7,
USART3 = AF_7,
AF_8 = 8,
UART4 = AF_8,
UART5 = AF_8,
USART6 = AF_8,
AF_9 = 9,
CAN1 = AF_9,
CAN2 = AF_9,
TIM12 = AF_9,
TIM13 = AF_9,
TIM14 = AF_9,
AF_10 = 10,
OTG_FS = AF_10,
AF_11 = 11,
ETH = AF_11,
AF_12 = 12,
FSMC = AF_12,
SDIO = AF_12,
AF_13 = 13,
DCMI = AF_13,
AF_14 = 14,
AF_15 = 15,
EVENTOUT = AF_15
};
/*
* set_locked_key_port
* set_locked_keys_all_port global_port.
* ! global_port.
* - .
* - .
*/
enum class EC_LOCKED {
NOT_LOCKED = 0, // .
LOCKED = 1 // .
};
/*
*
* ( , ).
*/
enum class EC_PIN_STATE_AFTER_INIT {
NO_USE = 0,
RESET = 0,
SET = 1
};
class pin {
public:
constexpr pin ( const pin_config_t* const pin_cfg_array );
void set ( void ) const;
void reset ( void ) const;
void set ( uint8_t state ) const;
void set ( bool state ) const;
void set ( int state ) const;
private:
constexpr uint32_t p_bsr_get ( const pin_config_t* const pin_cfg_array );
constexpr uint32_t set_msk_get ( const pin_config_t* const pin_cfg_array );
constexpr uint32_t reset_msk_get ( const pin_config_t* const pin_cfg_array );
const uint32_t p_bsr;
const uint32_t bsr_set_msk, bsr_reset_msk;
};
/*
* <<1>>,
* .
*/
void pin::set ( void ) const {
*M_U32_TO_P(this->p_bsr) = this->bsr_set_msk;
}
/*
* <<0>>,
* .
*/
void pin::reset ( void ) const {
*M_U32_TO_P(this->p_bsr) = this->bsr_reset_msk;
}
/*
* ,
* .
*/
void pin::set ( uint8_t state ) const {
if ( state ) {
this->set();
} else {
this->reset();
}
}
void pin::set ( bool state ) const {
this->set( static_cast< uint8_t >( state ) );
}
void pin::set ( int state ) const {
this->set( static_cast< uint8_t >( state ) );
}
// uint32_t uint32_t.
// .
#define M_U32_TO_P(point) ((uint32_t *)(point))
/**********************************************************************
* constexpr .
**********************************************************************/
/*
* "1" BSR.
*/
constexpr uint32_t pin::set_msk_get ( const pin_config_t* const pin_cfg_array ) {
return 1 << M_EC_TO_U8(pin_cfg_array->pin_name);
}
/*
* "0" BSR.
*/
constexpr uint32_t pin::reset_msk_get ( const pin_config_t* const pin_cfg_array ) {
return 1 << M_EC_TO_U8( pin_cfg_array->pin_name ) + 16;
}
/*
* BSR, .
*/
constexpr uint32_t pin::p_bsr_get( const pin_config_t* const pin_cfg_array ) {
uint32_t p_port = p_base_port_address_get( pin_cfg_array->port );
return p_port + 0x18;
}
// enum class uint8_t.
#define M_EC_TO_U8(ENUM_VALUE) ((uint8_t)ENUM_VALUE)
/*
* -
* .
*/
constexpr uint32_t p_base_port_address_get( EC_PORT_NAME port_name ) {
switch( port_name ) {
#ifdef PORTA
case EC_PORT_NAME::A: return 0x40020000;
#endif
#ifdef PORTB
case EC_PORT_NAME::B: return 0x40020400;
#endif
#ifdef PORTC
case EC_PORT_NAME::C: return 0x40020800;
#endif
#ifdef PORTD
case EC_PORT_NAME::D: return 0x40020C00;
#endif
#ifdef PORTE
case EC_PORT_NAME::E: return 0x40021000;
#endif
#ifdef PORTF
case EC_PORT_NAME::F: return 0x40021400;
#endif
#ifdef PORTG
case EC_PORT_NAME::G: return 0x40021800;
#endif
#ifdef PORTH
case EC_PORT_NAME::H: return 0x40021C00;
#endif
#ifdef PORTI
case EC_PORT_NAME::I: return 0x40022000;
#endif
}
}
/**********************************************************************
* constexpr .
**********************************************************************/
constexpr pin::pin ( const pin_config_t* const pin_cfg_array ):
p_bsr ( this->p_bsr_get( pin_cfg_array ) ),
bsr_set_msk ( this->set_msk_get( pin_cfg_array ) ),
bsr_reset_msk ( this->reset_msk_get( pin_cfg_array ) ) {};
/**********************************************************************
* template .
**********************************************************************/
template < EC_PORT_NAME PORT,
EC_PORT_PIN_NAME PIN_NAME,
EC_PIN_MODE MODE,
EC_PIN_OUTPUT_CFG OUTPUT_CONFIG,
EC_PIN_SPEED SPEED,
EC_PIN_PULL PULL,
EC_PIN_AF AF,
EC_LOCKED LOCKED,
EC_PIN_STATE_AFTER_INIT STATE_AFTER_INIT >
class pin_config_check_param : public pin_config_t {
public:
constexpr pin_config_check_param(): pin_config_t( {
.port = PORT,
.pin_name = PIN_NAME,
.mode = MODE,
.output_config = OUTPUT_CONFIG,
.speed = SPEED,
.pull = PULL,
.af = AF,
.locked = LOCKED,
.state_after_init = STATE_AFTER_INIT
} ) {
/*
* .
*/
#if defined(STM32F205RB)|defined(STM32F205RC)|defined(STM32F205RE) \
|defined(STM32F205RF)|defined(STM32F205RG)
static_assert( PORT >= EC_PORT_NAME::A &&
PORT <= EC_PORT_NAME::H,
"Invalid port name. The port name must be A..H." );
#endif
static_assert( PIN_NAME >= EC_PORT_PIN_NAME::PIN_0 &&
PIN_NAME <= EC_PORT_PIN_NAME::PIN_15,
"Invalid output name. An output with this name does not"
"exist in any port. The output can have a name PIN_0..PIN_15." );
static_assert( MODE >= EC_PIN_MODE::INPUT &&
MODE <= EC_PIN_MODE::ANALOG,
"The selected mode does not exist. "
"The output can be set to mode: INPUT, OUTPUT, AF or ANALOG." );
static_assert( OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::PUSH_PULL ||
OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::OPEN_DRAIN,
"A non-existent output mode is selected. "
"The output can be in the mode: PUSH_PULL, OPEN_DRAIN." );
static_assert( SPEED >= EC_PIN_SPEED::LOW &&
SPEED <= EC_PIN_SPEED::HIGH,
"A non-existent mode of port speed is selected. "
"Possible modes: LOW, MEDIUM, FAST or HIGH." );
static_assert( PULL >= EC_PIN_PULL::NO_USE &&
PULL <= EC_PIN_PULL::DOWN,
"A non-existent brace mode is selected."
"The options are: NO_USE, UP or DOWN." );
static_assert( AF >= EC_PIN_AF::AF_0 &&
AF <= EC_PIN_AF::AF_15,
"A non-existent mode of the alternative port function is selected." );
static_assert( LOCKED == EC_LOCKED::NOT_LOCKED ||
LOCKED == EC_LOCKED::LOCKED,
"Invalid port lock mode selected." );
static_assert( STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::NO_USE ||
STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::SET,
"The wrong state of the output is selected."
"The status can be: NO_USE, UP or DOWN." );
};
};
const pin_config_check_param< EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_4,
EC_PIN_MODE::OUTPUT, EC_PIN_OUTPUT_CFG::PUSH_PULL,
EC_PIN_SPEED::MEDIUM, EC_PIN_PULL::NO_USE,
EC_PIN_AF::NO_USE, EC_LOCKED::LOCKED,
EC_PIN_STATE_AFTER_INIT::SET > lcd_res;
const constexpr pin pin_lcd_res( &lcd_res );
void port_test ( void ) {
pin_lcd_res.reset();
pin_lcd_res.set();
}
/*
* bit_banding
* , .
*/
constexpr uint32_t pin::bb_p_idr_read_get ( const pin_config_t* const pin_cfg_array ) {
uint32_t p_port = p_base_port_address_get( pin_cfg_array->port );
uint32_t p_idr = p_port + 0x10;
return M_GET_BB_P_PER(p_idr, M_EC_TO_U8(pin_cfg_array->pin_name));
}
/*
* bit banding ,
* .
*/
constexpr uint32_t pin::odr_bit_read_bb_p_get ( const pin_config_t* const pin_cfg_array ) {
uint32_t p_port = p_base_port_address_get( pin_cfg_array->port );
uint32_t p_reg_odr = p_port + 0x14;
return M_GET_BB_P_PER(p_reg_odr, M_EC_TO_U8(pin_cfg_array->pin_name));
}
//*********************************************************************
// , .
//*********************************************************************
#define BIT_BAND_SRAM_REF 0x20000000
#define BIT_BAND_SRAM_BASE 0x22000000
// RAM Bit Banding .
#define MACRO_GET_BB_P_SRAM(reg, bit) \
((BIT_BAND_SRAM_BASE + (reg - BIT_BAND_SRAM_REF)*32 + (bit * 4)))
#define BIT_BAND_PER_REF ((uint32_t)0x40000000)
#define BIT_BAND_PER_BASE ((uint32_t)0x42000000)
// Bit Banding .
#define M_GET_BB_P_PER(ADDRESS,BIT) \
((BIT_BAND_PER_BASE + (ADDRESS - BIT_BAND_PER_REF)*32 + (BIT * 4)))
/**********************************************************************
* constexpr .
**********************************************************************/
constexpr pin::pin ( const pin_config_t* const pin_cfg_array ):
p_bsr ( this->p_bsr_get( pin_cfg_array ) ),
p_bb_odr_read ( this->odr_bit_read_bb_p_get( pin_cfg_array ) ),
bsr_set_msk ( this->set_msk_get( pin_cfg_array ) ),
bsr_reset_msk ( this->reset_msk_get( pin_cfg_array ) ),
p_bb_idr_read ( this->bb_p_idr_read_get( pin_cfg_array ) ) {};
/*
* ,
* .
*/
void pin::invert( void ) const {
if (*M_U32_TO_P_CONST(p_bb_odr_read)) { // 1, 0.
this->reset();
} else {
this->set();
}
}
/*
* .
*/
int pin::read() const {
return *M_U32_TO_P_CONST(p_bb_idr_read);
}
// uint32_t uint32_t.
// , ( ).
#define M_U32_TO_P_CONST(point) ((const uint32_t *const)(point))
class pin {
public:
constexpr pin ( const pin_config_t* const pin_cfg_array );
void set ( void ) const;
void reset ( void ) const;
void set ( uint8_t state ) const;
void set ( bool state ) const;
void set ( int state ) const;
void invert ( void ) const;
int read ( void ) const;
private:
constexpr uint32_t p_bsr_get ( const pin_config_t* const pin_cfg_array );
constexpr uint32_t set_msk_get ( const pin_config_t* const pin_cfg_array );
constexpr uint32_t reset_msk_get ( const pin_config_t* const pin_cfg_array );
constexpr uint32_t odr_bit_read_bb_p_get ( const pin_config_t* const pin_cfg_array );
constexpr uint32_t bb_p_idr_read_get ( const pin_config_t* const pin_cfg_array );
const uint32_t p_bsr;
const uint32_t bsr_set_msk, bsr_reset_msk;
const uint32_t p_bb_odr_read, p_bb_idr_read;
};
template < EC_PORT_NAME PORT,
EC_PORT_PIN_NAME PIN_NAME >
class pin_config_adc_check_param : public pin_config_check_param< PORT, PIN_NAME,
EC_PIN_MODE::INPUT,
EC_PIN_OUTPUT_CFG::NO_USE,
EC_PIN_SPEED::LOW,
EC_PIN_PULL::UP,
EC_PIN_AF::NO_USE,
EC_LOCKED::LOCKED,
EC_PIN_STATE_AFTER_INIT::NO_USE > {
public:
constexpr pin_config_adc_check_param() {};
};
const pin_config_adc_check_param< EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_1 > adc_left;