/* **************************************************************************** * Mcucpp © Konstantin Chizhov https://github.com/KonstantinChizhov/Mcucpp * **************************************************************************** * **************************************************************************** * ATtiny/261-461-861/TimerRegs.h TimerC Timer<0> * TimerI Timer<1> * **************************************************************************** * **************************************************************************** * Timer/CounterC Clear Timer on Compare Match (Auto Reload) * ************** One Input Capture unit * Four Independent Interrupt Sources (TOV_, OCF_A, OCF_B, ICF_) * 8-bit Mode with Two Independent Output Compare Units * 16-bit Mode with One Independent Output Compare Unit * * Timer/CounterI 8/10-Bit Accuracy * ************** Three Independent Output Compare Units * Clear Timer on Compare Match (Auto Reload) * Glitch Free, Phase and Frequency Correct Pulse Width Modulator (PWM) * Variable PWM Period * High Speed Asynchronous and Synchronous Clocking with Dedicated Prescaler * Independent Dead Time Generators for Each PWM Channel * Fault Protection Unit Can Disable PWM Output Pins * Five Independent Interrupt Sources (TOV_, OCF_A, OCD_B, OCF_D, FPF_) * ****************************************************************************** * defines Timer0, Timer1 all Timers are TYPES not !VARS! * ******* * modified: AUTO_IO_REG_WRAPPER with type cast DataT(enum flags) in reg-wrapper * ******** * remark: BaseTimerA .. BaseTimerI do represent different AVR-Timer register * ****** configurations and are in no way corresponding with the new AVR/ * Microchip's Timer/Counter Type A..D naming * * ****************************************************************************/ #pragma once #ifndef CTC0 #define CTC0 0 // missing in iotn861a.h #endif #ifndef PWM1X #define PWM1X 7 // missing in iotn861a.h #endif // includes //***********************************************// #include // IO_REG_WRAPPERT #include // enable bitmask operations #include // #include // adj.osc|sys clock div|delay //#include // Timer0 // include file after TimerRegs //#include // Timer1 // include file after TimerRegs namespace Mcucpp { // namespace Timers { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// template //****************************** requires ((cATtiny_xx1 ()) && ((N==0||N==1))) //****************************** struct TimerRegs { /**************** * interface between avr/io and c++ ***********************************************/ using mcu_t = MCU; using DataT = uint8_t ; static constexpr int number{N}; }; template<> //********************* struct TimerRegs<0> { // TimerC //**************** TimerRegs() = delete; // c++ register implementation // *******************|********|**********|********* // AUTO_IO_REG_WRAPPER(TIMSK, TIntMask, uint8_t); // Interrupt Mask // same as TimerRegs<0> // different flags AUTO_IO_REG_WRAPPER(TIFR, TIntflag, uint8_t); // Interrupt flag // same as TimerRegs<0> // different flags AUTO_IO_REG_WRAPPER(TCCR0A, TControlA, uint8_t); // Counter Control|A| AUTO_IO_REG_WRAPPER(TCCR0B, TControlB, uint8_t); // |B| AUTO_IO_REG_WRAPPER(TCNT0L, TCounterL, uint8_t); // Counter |L| 8 Bit AUTO_IO_REG_WRAPPER(TCNT0H, TCounterH, uint8_t); // Counter |H| 8 Bit AUTO_IO_REG_WRAPPER(OCR0A, TOCompareA, uint8_t); // Output Compare |A| AUTO_IO_REG_WRAPPER(OCR0B, TOCompareB, uint8_t); // Output Compare |B| // ************************************************* // static constexpr int number{0}; using DataT = uint8_t; // c++ bitflag implementation // ******************************************** // enum class imask : DataT { // **************** toie = 1 << TOIE0, // TIMSK // interrupt mask ociea = 1 << OCIE0A, ocieb = 1 << OCIE0B, ticie = 1 << TICIE0, // ------------------------------------------ // derived flags NoInterrupt = 0, Overflow_IntEn = toie, OCompA_IntEn = ociea, OCompB_IntEn = ocieb, ICapture_IntEn = ticie }; enum class iflag : DataT { // **************** tov = 1 << TOV0, // TIFR // interrupt flag ocfa = 1 << OCF0A, ocfb = 1 << OCF0B, icf = 1 << ICF0, // ------------------------------------------ // derived flags OverFlow_flag = tov, OCompA_flag = ocfa, OCompB_flag = ocfb, ICapture_flag = icf, }; enum class cca : DataT { // ************** ctc = 1 << CTC0, // TCCR0A // counter control|A| acic = 1 << ACIC0, ices = 1 << ICES0, icnc = 1 << ICNC0, icen = 1 << ICEN0, tcw = 1 << TCW0, }; enum class ccb : DataT { // TCCR0B // Counter Control|B| // ************** cs0 = 1 << CS00, // cs1 = 1 << CS01, // cs2 = 1 << CS02, // psr = 1 << PSR0, // tsm = 1 << TSM, // }; enum class mode : DataT { // *************** ctc = 1 << CTC0, // TCCR0A // counter control|A| icen = 1 << ICEN0, tcw = 1 << TCW0, // -------------------------------------------- // derived flags Normal_8Bit = 0, Normal_16Bit = tcw , ClearOnCompA = ctc , InputCapture_8Bit = icen , InputCaptrue_16Bit = tcw| icen , // -------------------------------------------- // clearmask = tcw|ctc|icen , }; enum class divider : DataT { // ****************** cs0 = 1 << CS00, // TCCR0B // Counter Control|B| cs1 = 1 << CS01, cs2 = 1 << CS02, // ------------------------------------------ // derived flags DivStop = 0, Div1 = cs0, // 1 << 0 ( 1) Div8 = cs1, // 1 << 3 (*8) Div64 = cs1|cs0, // 1 << 6 (*8) Div256 = cs2, // 1 << 8 (*4) Div1024 = cs2| cs0, // 1 << 10 (*4) // ------------------------------------------ // ExtFalling = cs2|cs1, // ExtRising = cs2|cs1|cs0, // // ------------------------------------------ // clearmask = cs2|cs1|cs0, // }; // divider factors // ********************************** static inline constexpr int div_x[] = {0,1,8,64,256,1024}; }; //.TimerRegs<0> }} //.Timers //.Mcucpp // enum class - bitmask operators // ********************************************** template<> struct std::enable_bitmask_operators ::imask> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::iflag> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::cca> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::ccb> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::mode> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::divider> { static constexpr bool enable = true; }; namespace Mcucpp { // namespace Timers { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// template<> //********************* struct TimerRegs<1> { // TimerI //**************** TimerRegs() = delete; // c++ register implementation // *******************|******|***********|********|** // AUTO_IO_REG_WRAPPER(TCCR1A, TControlA, uint8_t ); // Counter Control|A| AUTO_IO_REG_WRAPPER(TCCR1B, TControlB, uint8_t ); // |B| AUTO_IO_REG_WRAPPER(TCCR1C, TControlC, uint8_t ); // |C| AUTO_IO_REG_WRAPPER(TCCR1D, TControlD, uint8_t ); // |D| AUTO_IO_REG_WRAPPER(TCCR1E, TControlE, uint8_t ); // |E| AUTO_IO_REG_WRAPPER(TCNT1, TCounterL, uint8_t ); // Counter | | 8 Bit AUTO_IO_REG_WRAPPER(TIMSK, TIntMask, uint8_t ); // Interrupt Mask // same as TimerRegs<0> // different flags AUTO_IO_REG_WRAPPER(TIFR, TIntflag, uint8_t ); // Interrupt flag // same as TimerRegs<0> // different flags AUTO_IO_REG_WRAPPER(OCR1C, TTimerTop, uint8_t ); // TimerTop AUTO_IO_REG_WRAPPER(TC1H, TTimerH, uint8_t ); // TimerHigh | | 2 Bit AUTO_IO_REG_WRAPPER(OCR1A, TOCompareA, uint8_t ); // Output Compare |A| AUTO_IO_REG_WRAPPER(OCR1B, TOCompareB, uint8_t ); // Output Compare |B| AUTO_IO_REG_WRAPPER(OCR1D, TOCompareD, uint8_t ); // Output Compare |D| AUTO_IO_REG_WRAPPER(PLLCSR, TControlPLL,uint8_t ); // PLL AUTO_IO_REG_WRAPPER(DT1, TDeadTime ,uint8_t ); // DeadTimeValue // ********************************************* // static constexpr int number{1}; using DataT = uint8_t ; // c++ bitflag implementation // ********************************************* // enum class cca : DataT { // ************** pwm_b = 1 << PWM1B, // TCCR1A // Counter Control|A| pwm_a = 1 << PWM1A, foc_b = 1 << FOC1B, foc_a = 1 << FOC1A, com_b0 = 1 << COM1B0, com_b1 = 1 << COM1B1, com_a0 = 1 << COM1A0, com_a1 = 1 << COM1A1, }; enum class ccb : DataT { // ************** cs_0 = 1 << CS10, // TCCR1B // Counter Control|B| cs_1 = 1 << CS11, cs_2 = 1 << CS12, cs_3 = 1 << CS13, dtps_0 = 1 << DTPS10, dtps_1 = 1 << DTPS11, psr_ = 1 << PSR1, pwm_x = 1 << PWM1X, }; enum class ccc : DataT { // ************** pwm_d = 1 << PWM1D, // TCCR1C // Counter Control|C| foc_d = 1 << FOC1D, com_d0 = 1 << COM1D0, com_d1 = 1 << COM1D1, com_b0s = 1 << COM1B0S, com_b1s = 1 << COM1B1S, com_a0s = 1 << COM1A0S, com_a1s = 1 << COM1A1S, }; enum class ccd : DataT { // ************** wgm_0 = 1 << WGM10, // TCCR1D // Counter Control|D| wgm_1 = 1 << WGM11, fpf_ = 1 << FPF1, fpac_ = 1 << FPAC1, fpes_ = 1 << FPES1, fpnc_ = 1 << FPNC1, fpen_ = 1 << FPEN1, fpie_ = 1 << FPIE1, }; enum class cce : DataT { // *************************** oc_oe0 = 1<< OC1OE0, // TCCR1E // Counter Control|D| oc_oe1 = 1<< OC1OE1, oc_oe2 = 1<< OC1OE2, oc_oe3 = 1<< OC1OE3, oc_oe4 = 1<< OC1OE4, oc_oe5 = 1<< OC1OE5 }; enum class imask : DataT { // *************************** toie_ = 1 << TOIE1, // TIMSK // Interrupt Mask ocie_a = 1 << OCIE1A, ocie_b = 1 << OCIE1B, ocie_d = 1 << OCIE1D, fpie_ = 1 << FPIE1, // TCCR_D.7 // ------------------------------------------- // derived flags NoInterrupt = 0, Overflow_IntEn = toie_, OCompA_IntEn = ocie_a, OCompB_IntEn = ocie_b, OCompD_IntEn = ocie_d, FaultProt_IntEn = fpie_, // TCCR_D.7 }; enum class iflag : DataT { // *************************** tov_ = 1 << TOV1, // TIFR // Interrupt flag ocf_a = 1 << OCF1A, ocf_b = 1 << OCF1B, ocf_d = 1 << OCF1D, // ------------------------------------------- // derived flags OverFlow_flag = tov_, OCompA_flag = ocf_a, OCompB_flag = ocf_b, OCompD_flag = ocf_b, }; enum class pll : DataT { // ************** plock_ = 1 << PLOCK, // PLLCSR // PLL Control plle_ = 1 << PLLE, pcke_ = 1 << PCKE, lsm_ = 1 << LSM, // ------------------------------------------- // PLL_Enable = plle_, PLL_Locked = plock_, PCLK_Enable = pcke_, PCLK_LowSpeed = lsm_ }; enum class dtc : DataT { // *************************** dt_l0 = 1 << DT1L0, // DT1 // DeadTime Control dt_l1 = 1 << DT1L1, dt_l2 = 1 << DT1L2, dt_l3 = 1 << DT1L3, dt_h0 = 1 << DT1H0, dt_h1 = 1 << DT1H1, dt_h2 = 1 << DT1H2, dt_h3 = 1 << DT1H3, }; enum class pwm : DataT { // ************** pwm_b = 1 << PWM1B, // TCCR1A // Counter Control|A| pwm_a = 1 << PWM1A, // ------------------------------------------- // ----------------------------- pwm_d = 1 << PWM1D, // TCCR1C // Counter Control|C| // ------------------------------------------- // derived flags EnableA = pwm_a, EnableB = pwm_b, EnableD = pwm_d, }; enum class dead_time_ps : DataT { // *********************** dtps_0 = 1 << DTPS10, // TCCR1B // dtps_1 = 1 << DTPS11, // ------------------------------------------- // derived flags DT_Div1 = 0, DT_Div2 = dtps_0, DT_Div4 = dtps_1, DT_Div8 = dtps_1|dtps_0, // ------------------------------------------- // clearmask = dtps_1|dtps_0, }; enum class mode : DataT { // *************** wgm_0 = 1 << WGM10, // TCCR1D // Counter Control|D| wgm_1 = 1 << WGM11, // ------------------------------------------- // derived Normal = 0, FastPWM = 0, PhaseAndFreqCorrectPWM = wgm_0, PWM6_SingleSlope = wgm_1, PWM6_DoubleSlope = wgm_1|wgm_0, // ------------------------------------------- // clearmask = wgm_1|wgm_0, }; enum class divider : DataT { // ****************** cs_0 = 1 << CS10, // TCCR1B // Counter Control|B| cs_1 = 1 << CS11, cs_2 = 1 << CS12, cs_3 = 1 << CS13, // ------------------------------------------- // derived flags DivStop = 0, Div1 = cs_0, Div2 = cs_1, Div4 = cs_1|cs_0, Div8 = cs_2, Div16 = cs_2| cs_0, Div32 = cs_2|cs_1, Div64 = cs_2|cs_1|cs_0, Div128 = cs_3, Div256 = cs_3| cs_0, Div512 = cs_3| cs_1, Div1024 = cs_3| cs_1|cs_0, Div2048 = cs_3|cs_2, Div4096 = cs_3|cs_2| cs_0, Div8192 = cs_3|cs_2|cs_1, Div16384 = cs_3|cs_2|cs_1|cs_0, //(1 << cs[0..3]) // ----------------------------------------- ----- clearmask = cs_3|cs_2|cs_1|cs_0, }; enum class oc_pin_modeA : DataT { // *********************** com_a0 = 1 << COM1A0, // TCCR1A // Counter Control|A| com_a1 = 1 << COM1A1, // ------------------------------------------------------------- // !pwm_a normal mode // ------------------------------------------------------------- oc_normal_d_d = 0, oc_toggle_oc_c_d = com_a0, oc_cleared_oc_c_d = com_a1, oc_set_oc_c_d = com_a1|com_a0, // ------------------------------------------------------------- // pwm_a|!wgm_1|!wgm_0 - fast pwm // ------------------------------------------------------------- fpwm_normal_d_d = 0, fpwm_cleared_oc_set_on_zero_c_c = com_a0, fpwm_cleared_oc_set_on_zero_c_d = com_a1, fpwm_set_oc_cleared_on_zero_c_d = com_a1|com_a0, // ------------------------------------------------------------- // pwm_a|!wgm_1| wgm_0 phase correct pwm // ------------------------------------------------------------- phfc_pwm_normal_d_d = 0, phfc_pwm_cleared_oc_upc_set_oc_downc_c_c = com_a0, phfc_pwm_cleared_oc_upc_set_oc_downc_c_d = com_a1, phfc_pwm_set_oc_upc_cleared_oc_downc_c_d = com_a1|com_a0, // ------------------------------------------------------------- // pwm_a| wgm_1|!wgm_0 single slope pwm6 // ------------------------------------------------------------- ss_pwm6_normal_d_d = 0, ss_pwm6_cleared_oc_set_on_zero = com_a0, ss_pwm6_cleared_oc_set_on_zero_ = com_a1, ss_pwm6_set_oc_cleared_on_zero = com_a1|com_a0, // ------------------------------------------------------------- // pwm_a| wgm_1| wgm_0 dual slope pwm6 // ------------------------------------------------------------- ds_pwm6_pwm_normal_d_d = 0, ds_pwm6_cleared_oc_upc_set_oc_down = com_a0, ds_pwm6_cleared_oc_upc_set_oc_downc_ = com_a1, ds_pwm6_set_oc_upc_cleared_oc_downc = com_a1|com_a0, // ----------------------------------------------------------* clearmask = com_a1|com_a0 }; enum class oc_pin_modeB : DataT { // *********************** com_b0 = 1 << COM1B0, // TCCR1A // Counter Control|A| com_b1 = 1 << COM1B1, // ------------------------------------------------------------- // pwm_b // ------------------------------------------------------------- oc_normal_d_d = 0, oc_toggle_oc_c_d = com_b0, oc_cleared_oc_c_d = com_b1, oc_set_oc_c_d = com_b1|com_b0, // ------------------------------------------------------------- // pwm_b|!wgm_1|!wgm_0 // ------------------------------------------------------------- fpwm_normal_d_d = 0, fpwm_cleared_oc_set_on_zero_c_d = com_b0, fpwm_cleared_oc_set_on_zero_c_d_ = com_b1, fpwm_set_oc_cleared_on_zero_c_d = com_b1|com_b0, // ------------------------------------------------------------- // pwm_b|!wgm_1| wgm_0 // ------------------------------------------------------------- phfc_pwm_normal_d_d = 0, phfc_pwm_cleared_oc_upc_set_oc_downc_c_c = com_b0, phfc_pwm_cleared_oc_upc_set_oc_downc_c_d = com_b1, phfc_pwm_set_oc_upc_cleared_oc_downc_c_d = com_b1|com_b0, // ------------------------------------------------------------- // pwm_b| wgm_1|!wgm_0 // ------------------------------------------------------------- ss_pwm6_normal_d_d = 0, ss_pwm6_cleared_oc_set_on_zero = com_b0, ss_pwm6_cleared_oc_set_on_zero_ = com_b1, ss_pwm6_set_oc_cleared_on_zero = com_b1|com_b0, // ------------------------------------------------------------- // pwm_b| wgm_1| wgm_0 // ------------------------------------------------------------- ds_pwm6_pwm_normal_d_d = 0, ds_pwm6_cleared_oc_upc_set_oc_downc = com_b0, ds_pwm6_cleared_oc_upc_set_oc_downc_ = com_b1, ds_pwm6_set_oc_upc_cleared_oc_downc = com_b1|com_b0, // ------------------------------------------------------------- clearmask = com_b1|com_b0 }; enum class oc_pin_modeD : DataT { // ********************* com_d0 = 1 << COM1D0, // TCCR1C // Counter Control|C| com_d1 = 1 << COM1D1, // ------------------------------------------------------------ // !pwm_d // ------------------------------------------------------------ oc_normal_d_d = 0, oc_toggle_oc_c_d = com_d0, oc_cleared_oc_c_d = com_d1, oc_set_oc_c_d = com_d1|com_d0, // ------------------------------------------------------------ // pwm_d|!wgm_1|!wgm_0 // ------------------------------------------------------------ fpwm_normal_d_d = 0, fpwm_cleared_oc_set_on_zero_c_d = com_d0, fpwm_cleared_oc_set_on_zero_c_d_ = com_d1, fpwm_set_oc_cleared_on_zero_c_d = com_d1|com_d0, // ------------------------------------------------------------ // pwm_d|!wgm_1| wgm_0 // ------------------------------------------------------------ phfc_pwm_normal_d_d = 0, phfc_pwm_cleared_oc_upc_set_oc_downc_c_c = com_d0, phfc_pwm_cleared_oc_upc_set_oc_downc_c_d = com_d1, phfc_pwm_set_oc_upc_cleared_oc_downc_c_d = com_d1|com_d0, // ------------------------------------------------------------ // pwm_d| wgm_1|!wgm_0 // ------------------------------------------------------------ ss_pwm6_normal_d_d = 0, ss_pwm6_cleared_oc_set_on_zero = com_d0, ss_pwm6_cleared_oc_set_on_zero_ = com_d1, ss_pwm6_set_oc_cleared_on_zero = com_d1|com_d0, // ------------------------------------------------------------ // pwm_d| wgm_1| wgm_0 // ------------------------------------------------------------ ds_pwm6_pwm_normal_d_d = 0, ds_pwm6_cleared_oc_upc_set_oc_downc = com_d0, ds_pwm6_cleared_oc_upc_set_oc_downc_ = com_d1, ds_pwm6_set_oc_upc_cleared_oc_downc = com_d1|com_d0, // ---------------------------------------------------------- clearmask = com_d1|com_d0 }; using div_t = divider; using mode_t = mode; // divider factors // ************************************ // can be calculated : (1 << cs[0..3]) }; //.TimerRegs } //.Timers } //.Mcucpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // a.b.11.2018 template<> struct std::enable_bitmask_operators ::cca> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::ccb> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::ccc> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::ccd> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::cce> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::pll> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::dtc> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::imask> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::iflag> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::pwm> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::dead_time_ps> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::mode> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::divider> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::oc_pin_modeA> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::oc_pin_modeB> { static constexpr bool enable = true; }; template<> struct std::enable_bitmask_operators ::oc_pin_modeD> { static constexpr bool enable = true; }; /* timer implementation ******************************************/ #include #include /* timer declaration ******************************************/ using Timer0 = Mcucpp::Timers::TimerC<0> ; using Timer1 = Mcucpp::Timers::TimerI<1> ; /************************************************************************** * Code Snippet ioreg.h ************************************************************************** #define AUTO_IO_REG_WRAPPER(REG_NAME, CLASS_NAME, DATA_TYPE) \ \ struct CLASS_NAME { \ typedef DATA_TYPE DataT; \ \ static volatile DataT* Addr() {return ®_NAME ;} \ \ static DataT Get () {return REG_NAME ;} \ static void Set (auto value){ REG_NAME = DataT(value);} \ static void Or (auto value){ REG_NAME |= DataT(value);} \ \ static void And (auto value){ REG_NAME &= DataT(value);} \ static void Xor (auto value){ REG_NAME ^= DataT(value);} \ \ static void AndOr (auto andMask, \ auto orMask ) { REG_NAME = \ ( REG_NAME & DataT(andMask)) \ | DataT(orMask );}\ static void ClrSet (auto andMask, \ auto orMask ) { REG_NAME = \ ( REG_NAME & DataT(~andMask))\ | DataT( orMask);}\ \ static bool BitIsSet (auto mask) {return (REG_NAME & DataT(mask));} \ static bool BitIsClear(auto mask) {return!(REG_NAME & DataT(mask));} \ }; ***************************************************************************/