├── CMakeLists.txt ├── README.rst └── cm3cpp ├── adc.cpp ├── adc.hpp ├── adc_dma.cpp ├── adc_dma.hpp ├── dma.cpp ├── dma.hpp ├── extra ├── one_wire.cpp └── one_wire.hpp ├── flash_cycle.hpp ├── flash_otp.hpp ├── gpio.cpp ├── gpio.hpp ├── i2c.cpp ├── i2c.hpp ├── irq ├── gen_irq.py ├── irq.cpp └── irq.hpp ├── private ├── assert.h └── pinout.h ├── rs485.cpp ├── rs485.hpp ├── spi.cpp ├── spi.hpp ├── systick.cpp ├── systick.hpp ├── timer.cpp ├── timer.hpp ├── usart.cpp ├── usart.hpp ├── usart_rb.cpp ├── usart_rb.hpp └── utils ├── round_buffer.cpp └── round_buffer.hpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(cm3cpp LANGUAGES C CXX ASM) 4 | 5 | add_library(${PROJECT_NAME} INTERFACE) 6 | 7 | target_sources(${PROJECT_NAME} INTERFACE 8 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/extra/one_wire.cpp 9 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/irq/irq.cpp 10 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/utils/round_buffer.cpp 11 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/adc_dma.cpp 12 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/adc.cpp 13 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/gpio.cpp 14 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/i2c.cpp 15 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/spi.cpp 16 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/systick.cpp 17 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/timer.cpp 18 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/usart_rb.cpp 19 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/usart.cpp 20 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/rs485.cpp 21 | ${CMAKE_CURRENT_LIST_DIR}/cm3cpp/dma.cpp 22 | ) 23 | 24 | target_include_directories(${PROJECT_NAME} 25 | INTERFACE 26 | ${CMAKE_CURRENT_LIST_DIR} 27 | ) -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. role:: cpp(code) 2 | :language: cpp 3 | 4 | ============== 5 | cm3cpp library 6 | ============== 7 | 8 | ----------------------------------- 9 | C++ extensions over OpenCM3 library 10 | ----------------------------------- 11 | 12 | CMake target 13 | ============ 14 | 15 | CMake target name for this library is cm3cpp. Target 16 | is a interface library. Just use ``add_subdirectory`` to 17 | add library to your build. 18 | 19 | Required dependency of this library is opencm3 library. 20 | Be sure you link it to your target that uses cm3cpp. 21 | 22 | Library supports only F2 and F4 microcontrollers. 23 | 24 | Library defines: 25 | ================ 26 | 27 | - ``CM3CPP_CUSTOM_SYSTICK`` — disable library systick realization 28 | (enabled by default). If define enabled you could not use 29 | :cpp:`systick::Counter` class; 30 | 31 | - ``CM3CPP_ENABLE_IMPLISIT_DESTRUCTOR_CALLS`` — do not call 32 | ``assert(false)`` if dangerous destructor of library class is 33 | called. 34 | 35 | - ``CM3CPP_CUSTOM_INTERRUPT_SERVICE`` — disable IInterruptable 36 | and leave all opencm3 interrupt functions undeclared. 37 | -------------------------------------------------------------------------------- /cm3cpp/adc.cpp: -------------------------------------------------------------------------------- 1 | #include "adc.hpp" 2 | 3 | namespace cm3cpp { 4 | 5 | namespace adc { 6 | 7 | Adc::Adc(Number adc) 8 | { 9 | switch (adc) { 10 | case ADC_1: 11 | _adc = ADC1; 12 | break; 13 | case ADC_2: 14 | _adc = ADC2; 15 | break; 16 | case ADC_3: 17 | _adc = ADC3; 18 | break; 19 | } 20 | } 21 | 22 | void Adc::set_resolution(Resolution res) 23 | { 24 | ADC_CR1(_adc) &= ~ADC_CR1_RES_MASK; 25 | ADC_CR1(_adc) |= (uint32_t)res; 26 | } 27 | 28 | void Adc::enable_scan_mode() 29 | { 30 | ADC_CR1(_adc) |= ADC_CR1_SCAN_MASK; 31 | } 32 | 33 | void Adc::disable_scan_mode() 34 | { 35 | ADC_CR1(_adc) &= ~ADC_CR1_SCAN_MASK; 36 | } 37 | 38 | void Adc::set_data_alignment(Alignment align) 39 | { 40 | switch (align) { 41 | case RIGHT_ALIGN: 42 | ADC_CR2(_adc) &= ~ADC_CR2_ALIGN_MASK; 43 | break; 44 | case LEFT_ALIGN: 45 | ADC_CR2(_adc) |= ADC_CR2_ALIGN_MASK; 46 | break; 47 | } 48 | } 49 | 50 | void Adc::set_external_trigger_for_regular_group(RegularGroupTrigger trigger) 51 | { 52 | ADC_CR2(_adc) &= ~ADC_CR2_EXTSEL_MASK; 53 | ADC_CR2(_adc) |= (uint32_t)trigger; 54 | } 55 | 56 | void Adc::set_external_trigger_polarity_for_regular_group( 57 | RegularGroupTriggerPolarity polarity) 58 | { 59 | ADC_CR2(_adc) &= ~ADC_CR2_EXTEN_MASK; 60 | ADC_CR2(_adc) |= (uint32_t)polarity; 61 | } 62 | 63 | void Adc::set_conversion_mode(ConversionMode mode) 64 | { 65 | switch (mode) { 66 | case CONTINUOUS_CONV: 67 | ADC_CR2(_adc) |= ADC_CR2_CONT_MASK; 68 | break; 69 | case SINGLE_CONV: 70 | ADC_CR2(_adc) &= ~ADC_CR2_CONT_MASK; 71 | break; 72 | } 73 | } 74 | 75 | void Adc::enable_dma_request() 76 | { 77 | ADC_CR2(_adc) |= ADC_CR2_DDS_MASK; 78 | } 79 | 80 | void Adc::disable_dma_request() 81 | { 82 | ADC_CR2(_adc) &= ~ADC_CR2_DDS_MASK; 83 | } 84 | 85 | void Adc::enable_dma() 86 | { 87 | ADC_CR2(_adc) |= ADC_CR2_DMA_MASK; 88 | } 89 | 90 | void Adc::disable_dma() 91 | { 92 | ADC_CR2(_adc) &= ~ADC_CR2_DMA_MASK; 93 | } 94 | 95 | void Adc::enable() 96 | { 97 | ADC_CR2(_adc) |= ADC_CR2_ADON_MASK; 98 | } 99 | 100 | void Adc::disable() 101 | { 102 | ADC_CR2(_adc) &= ~ADC_CR2_ADON_MASK; 103 | } 104 | 105 | void Adc::start_conversion() 106 | { 107 | ADC_CR2(_adc) |= ADC_CR2_SWSTART_MASK; 108 | } 109 | 110 | void Adc::set_number_of_conversions(uint8_t number) 111 | { 112 | ADC_SQR1(_adc) &= ~ADC_SQR1_L_MASK; 113 | ADC_SQR1(_adc) |= (uint32_t)((number - 1) & 0x0F); 114 | } 115 | 116 | void Adc::set_channel_sampling_time_selection(SamplingTime time, 117 | Channel channel) 118 | { 119 | if (channel < ADC_CHANNEL10) { 120 | uint32_t offset = (channel * ADC_SMP_MASK); 121 | ADC_SMPR2(_adc) &= ~(ADC_SMP_MASK << offset); 122 | ADC_SMPR2(_adc) |= static_cast(time << offset); 123 | } 124 | 125 | else { 126 | uint32_t offset = ((channel - ADC_CHANNEL10) * ADC_SMP_MASK); 127 | ADC_SMPR1(_adc) &= ~(ADC_SMP_MASK << offset); 128 | ADC_SMPR1(_adc) |= static_cast(time << offset); 129 | } 130 | } 131 | 132 | void Adc::set_conversion_number_in_sequence(uint8_t length, Channel* channel) 133 | { 134 | uint32_t fifth6 = 0; 135 | uint32_t fourth6 = 0; 136 | uint32_t third6 = 0; 137 | uint32_t second6 = 0; 138 | uint32_t first6 = 0; 139 | uint8_t i = 0; 140 | 141 | if (length > 16) { 142 | return; 143 | } 144 | 145 | for (i = 1; i <= length; i++) { 146 | if (i <= 6) { 147 | first6 |= static_cast(channel[i - 1] << ((i - 1) * 5)); 148 | } 149 | if ((i > 6) & (i <= 12)) { 150 | second6 |= 151 | static_cast(channel[i - 1] << ((i - 6 - 1) * 5)); 152 | } 153 | if ((i > 12) & (i <= 18)) { 154 | third6 |= 155 | static_cast(channel[i - 1] << ((i - 12 - 1) * 5)); 156 | } 157 | if ((i > 18) & (i <= 24)) { 158 | fourth6 |= 159 | static_cast(channel[i - 1] << ((i - 18 - 1) * 5)); 160 | } 161 | if ((i > 24) & (i <= 28)) { 162 | fifth6 |= 163 | static_cast(channel[i - 1] << ((i - 24 - 1) * 5)); 164 | } 165 | } 166 | 167 | ADC_SQR1(_adc) = third6 | static_cast((length - 1) << 20); 168 | ADC_SQR2(_adc) = second6; 169 | ADC_SQR3(_adc) = first6; 170 | } 171 | 172 | void Adc::set_prescaler(Prescaler prescaler) 173 | { 174 | ADC_CCR &= ~ADC_CCR_ADCPRE_MASK; 175 | ADC_CCR |= prescaler; 176 | } 177 | 178 | void Adc::set_dma_mode(DmaMode mode) 179 | { 180 | ADC_CCR &= ~ADC_CCR_DMA_MASK; 181 | ADC_CCR |= mode; 182 | } 183 | 184 | void Adc::set_delay_between_two_samples(Delay delay) 185 | { 186 | ADC_CCR &= ~ADC_CCR_DELAY_MASK; 187 | ADC_CCR |= delay; 188 | } 189 | 190 | void Adc::set_multi_mode(MultiMode mode) 191 | { 192 | ADC_CCR &= ~ADC_CCR_MULTI_MASK; 193 | ADC_CCR |= mode; 194 | } 195 | 196 | void Adc::enable_temp_sensor() 197 | { 198 | ADC_CCR |= ADC_CCR_TSVREFE_MASK; 199 | } 200 | 201 | void Adc::disable_temp_sensor() 202 | { 203 | ADC_CCR &= ~ADC_CCR_TSVREFE_MASK; 204 | } 205 | 206 | } // namespace adc 207 | 208 | } // namespace cm3cpp 209 | -------------------------------------------------------------------------------- /cm3cpp/adc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CM3CPP_ADC_H_ 2 | #define CM3CPP_ADC_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define ADC1 (PERIPH_BASE_APB2 + 0x2000) 9 | #define ADC2 (PERIPH_BASE_APB2 + 0x2100) 10 | #define ADC3 (PERIPH_BASE_APB2 + 0x2200) 11 | #define ADC0 (PERIPH_BASE_APB2 + 0x2300) 12 | 13 | /* --- ADC registers ------------------------------------------------------- */ 14 | #define ADC_SR(block) MMIO32((block) + 0x00) 15 | #define ADC_CR1(block) MMIO32((block) + 0x04) 16 | #define ADC_CR2(block) MMIO32((block) + 0x08) 17 | #define ADC_SMPR1(block) MMIO32((block) + 0x0c) 18 | #define ADC_SMPR2(block) MMIO32((block) + 0x10) 19 | #define ADC_JOFR1(block) MMIO32((block) + 0x14) 20 | #define ADC_JOFR2(block) MMIO32((block) + 0x18) 21 | #define ADC_JOFR3(block) MMIO32((block) + 0x1c) 22 | #define ADC_JOFR4(block) MMIO32((block) + 0x20) 23 | #define ADC_HTR(block) MMIO32((block) + 0x24) 24 | #define ADC_LTR(block) MMIO32((block) + 0x28) 25 | #define ADC_SQR1(block) MMIO32((block) + 0x2c) 26 | #define ADC_SQR2(block) MMIO32((block) + 0x30) 27 | #define ADC_SQR3(block) MMIO32((block) + 0x34) 28 | #define ADC_JSQR(block) MMIO32((block) + 0x38) 29 | #define ADC_JDR1(block) MMIO32((block) + 0x3c) 30 | #define ADC_JDR2(block) MMIO32((block) + 0x40) 31 | #define ADC_JDR3(block) MMIO32((block) + 0x44) 32 | #define ADC_JDR4(block) MMIO32((block) + 0x48) 33 | #define ADC_DR(block) MMIO32((block) + 0x4c) 34 | #define ADC_CSR MMIO32(ADC0 + 0x0) 35 | #define ADC_CCR MMIO32(ADC0 + 0x4) 36 | #define ADC_CDR MMIO32(ADC0 + 0x8) 37 | 38 | #define ADC1_SR ADC_SR(ADC1) 39 | #define ADC1_CR1 ADC_CR1(ADC1) 40 | #define ADC1_CR2 ADC_CR2(ADC1) 41 | #define ADC1_SMPR1 ADC_SMPR1(ADC1) 42 | #define ADC1_SMPR2 ADC_SMPR2(ADC1) 43 | #define ADC1_JOFR1 ADC_JOFR1(ADC1) 44 | #define ADC1_JOFR2 ADC_JOFR2(ADC1) 45 | #define ADC1_JOFR3 ADC_JOFR3(ADC1) 46 | #define ADC1_JOFR4 ADC_JOFR4(ADC1) 47 | #define ADC1_HTR ADC_HTR(ADC1) 48 | #define ADC1_LTR ADC_LTR(ADC1) 49 | #define ADC1_SQR1 ADC_SQR1(ADC1) 50 | #define ADC1_SQR2 ADC_SQR2(ADC1) 51 | #define ADC1_SQR3 ADC_SQR3(ADC1) 52 | #define ADC1_JSQR ADC_JSQR(ADC1) 53 | #define ADC1_JDR1 ADC_JDR1(ADC1) 54 | #define ADC1_JDR2 ADC_JDR2(ADC1) 55 | #define ADC1_JDR3 ADC_JDR3(ADC1) 56 | #define ADC1_JDR4 ADC_JDR4(ADC1) 57 | #define ADC1_DR ADC_DR(ADC1) 58 | 59 | #define ADC2_SR ADC_SR(ADC2) 60 | #define ADC2_CR1 ADC_CR1(ADC2) 61 | #define ADC2_CR2 ADC_CR2(ADC2) 62 | #define ADC2_SMPR1 ADC_SMPR1(ADC2) 63 | #define ADC2_SMPR2 ADC_SMPR2(ADC2) 64 | #define ADC2_JOFR1 ADC_JOFR1(ADC2) 65 | #define ADC2_JOFR2 ADC_JOFR2(ADC2) 66 | #define ADC2_JOFR3 ADC_JOFR3(ADC2) 67 | #define ADC2_JOFR4 ADC_JOFR4(ADC2) 68 | #define ADC2_HTR ADC_HTR(ADC2) 69 | #define ADC2_LTR ADC_LTR(ADC2) 70 | #define ADC2_SQR1 ADC_SQR1(ADC2) 71 | #define ADC2_SQR2 ADC_SQR2(ADC2) 72 | #define ADC2_SQR3 ADC_SQR3(ADC2) 73 | #define ADC2_JSQR ADC_JSQR(ADC2) 74 | #define ADC2_JDR1 ADC_JDR1(ADC2) 75 | #define ADC2_JDR2 ADC_JDR2(ADC2) 76 | #define ADC2_JDR3 ADC_JDR3(ADC2) 77 | #define ADC2_JDR4 ADC_JDR4(ADC2) 78 | #define ADC2_DR ADC_DR(ADC2) 79 | 80 | #define ADC3_SR ADC_SR(ADC3) 81 | #define ADC3_CR1 ADC_CR1(ADC3) 82 | #define ADC3_CR2 ADC_CR2(ADC3) 83 | #define ADC3_SMPR1 ADC_SMPR1(ADC3) 84 | #define ADC3_SMPR2 ADC_SMPR2(ADC3) 85 | #define ADC3_JOFR1 ADC_JOFR1(ADC3) 86 | #define ADC3_JOFR2 ADC_JOFR2(ADC3) 87 | #define ADC3_JOFR3 ADC_JOFR3(ADC3) 88 | #define ADC3_JOFR4 ADC_JOFR4(ADC3) 89 | #define ADC3_HTR ADC_HTR(ADC3) 90 | #define ADC3_LTR ADC_LTR(ADC3) 91 | #define ADC3_SQR1 ADC_SQR1(ADC3) 92 | #define ADC3_SQR2 ADC_SQR2(ADC3) 93 | #define ADC3_SQR3 ADC_SQR3(ADC3) 94 | #define ADC3_JSQR ADC_JSQR(ADC3) 95 | #define ADC3_JDR1 ADC_JDR1(ADC3) 96 | #define ADC3_JDR2 ADC_JDR2(ADC3) 97 | #define ADC3_JDR3 ADC_JDR3(ADC3) 98 | #define ADC3_JDR4 ADC_JDR4(ADC3) 99 | #define ADC3_DR ADC_DR(ADC3) 100 | 101 | #define ADC_CR1_RES_MASK (uint32_t)(0x3 << 24) 102 | #define ADC_CR1_SCAN_MASK (uint32_t)(0x1 << 8) 103 | #define ADC_CR2_ALIGN_MASK (uint32_t)(0x1 << 11) 104 | #define ADC_CR2_EXTSEL_MASK (uint32_t)(0xF << 24) 105 | #define ADC_CR2_EXTEN_MASK (uint32_t)(0x3 << 28) 106 | #define ADC_CR2_CONT_MASK (uint32_t)(0x1 << 1) 107 | #define ADC_CR2_DDS_MASK (uint32_t)(0x1 << 9) 108 | #define ADC_CR2_DMA_MASK (uint32_t)(0x1 << 8) 109 | #define ADC_CR2_ADON_MASK (uint32_t)(0x1) 110 | #define ADC_CR2_SWSTART_MASK (uint32_t)(0x1 << 30) 111 | #define ADC_SQR1_L_MASK (uint32_t)(0xF << 20) 112 | #define ADC_SMP_MASK (uint32_t)(0x3) 113 | #define ADC_SQR_MASK (uint32_t)(0x1F) 114 | #define ADC_CCR_ADCPRE_MASK (uint32_t)(0x3 << 16) 115 | #define ADC_CCR_DMA_MASK (uint32_t)(0x3 << 14) 116 | #define ADC_CCR_DELAY_MASK (uint32_t)(0xF << 8) 117 | #define ADC_CCR_MULTI_MASK (uint32_t)(0x1F) 118 | #define ADC_CCR_TSVREFE_MASK (uint32_t)(0x1 << 23) 119 | 120 | namespace cm3cpp { 121 | 122 | namespace adc { 123 | 124 | class Adc 125 | { 126 | public: 127 | enum Number 128 | { 129 | ADC_1, 130 | ADC_2, 131 | ADC_3, 132 | }; 133 | 134 | enum Resolution 135 | { 136 | RES_12_BIT = (uint32_t)(0 << 24), 137 | RES_10_BIT = (uint32_t)(1 << 24), 138 | RES_08_BIT = (uint32_t)(2 << 24), 139 | RES_06_BIT = (uint32_t)(3 << 24), 140 | }; 141 | 142 | enum Alignment 143 | { 144 | RIGHT_ALIGN, 145 | LEFT_ALIGN, 146 | }; 147 | 148 | enum RegularGroupTrigger 149 | { 150 | T1_CC1 = (uint32_t)(0 << 24), 151 | T1_CC2 = (uint32_t)(1 << 24), 152 | T1_CC3 = (uint32_t)(2 << 24), 153 | T2_CC2 = (uint32_t)(3 << 24), 154 | T2_CC3 = (uint32_t)(4 << 24), 155 | T2_CC4 = (uint32_t)(5 << 24), 156 | T2_TRGO = (uint32_t)(6 << 24), 157 | T3_CC1 = (uint32_t)(7 << 24), 158 | T3_TRGO = (uint32_t)(8 << 24), 159 | T4_CC4 = (uint32_t)(9 << 24), 160 | T5_CC1 = (uint32_t)(10 << 24), 161 | T5_CC2 = (uint32_t)(11 << 24), 162 | T5_CC3 = (uint32_t)(12 << 24), 163 | T8_CC1 = (uint32_t)(13 << 24), 164 | T8_TRGO = (uint32_t)(14 << 24), 165 | EXTI_LINE_11 = (uint32_t)(15 << 24), 166 | }; 167 | 168 | enum RegularGroupTriggerPolarity 169 | { 170 | TRIGGER_NONE = (uint32_t)(0 << 28), 171 | TRIGGER_ON_RISING = (uint32_t)(1 << 28), 172 | TRIGGER_ON_FALLING = (uint32_t)(2 << 28), 173 | TRIGGER_ON_BOTH = (uint32_t)(3 << 28), 174 | }; 175 | 176 | enum ConversionMode 177 | { 178 | CONTINUOUS_CONV, 179 | SINGLE_CONV, 180 | }; 181 | 182 | enum MultiMode : uint32_t 183 | { 184 | MODE_INDEPENDENT = 0, 185 | }; 186 | 187 | enum SamplingTime: uint8_t 188 | { 189 | CYCLES_3 = 0, 190 | CYCLES_15 = 1, 191 | CYCLES_28 = 2, 192 | CYCLES_56 = 3, 193 | CYCLES_84 = 4, 194 | CYCLES_112 = 5, 195 | CYCLES_144 = 6, 196 | CYCLES_480 = 7, 197 | }; 198 | 199 | enum Channel: uint8_t 200 | { 201 | ADC_CHANNEL0 = 0x00, 202 | ADC_CHANNEL1 = 0x01, 203 | ADC_CHANNEL2 = 0x02, 204 | ADC_CHANNEL3 = 0x03, 205 | ADC_CHANNEL4 = 0x04, 206 | ADC_CHANNEL5 = 0x05, 207 | ADC_CHANNEL6 = 0x06, 208 | ADC_CHANNEL7 = 0x07, 209 | ADC_CHANNEL8 = 0x08, 210 | ADC_CHANNEL9 = 0x09, 211 | ADC_CHANNEL10 = 0x0A, 212 | ADC_CHANNEL11 = 0x0B, 213 | ADC_CHANNEL12 = 0x0C, 214 | ADC_CHANNEL13 = 0x0D, 215 | ADC_CHANNEL14 = 0x0E, 216 | ADC_CHANNEL15 = 0x0F, 217 | ADC_CHANNEL16 = 0x10, 218 | ADC_CHANNEL17 = 0x11, 219 | ADC_CHANNEL18 = 0x12, 220 | }; 221 | 222 | enum Rank 223 | { 224 | RANK_1 = 1, 225 | RANK_2 = 2, 226 | RANK_3 = 3, 227 | RANK_4 = 4, 228 | RANK_5 = 5, 229 | RANK_6 = 6, 230 | RANK_7 = 7, 231 | RANK_8 = 8, 232 | RANK_9 = 9, 233 | RANK_10 = 10, 234 | RANK_11 = 11, 235 | RANK_12 = 12, 236 | RANK_13 = 13, 237 | RANK_14 = 14, 238 | RANK_15 = 15, 239 | RANK_16 = 16, 240 | }; 241 | 242 | enum Prescaler : uint32_t 243 | { 244 | PRESCALER_2 = (uint32_t)(0 << 16), 245 | PRESCALER_4 = (uint32_t)(1 << 16), 246 | PRESCALER_6 = (uint32_t)(2 << 16), 247 | PRESCALER_8 = (uint32_t)(3 << 16), 248 | }; 249 | 250 | enum DmaMode : uint32_t 251 | { 252 | MODE_NONE = (uint32_t)(0 << 14), 253 | MODE_1 = (uint32_t)(1 << 14), 254 | MODE_2 = (uint32_t)(2 << 14), 255 | MODE_3 = (uint32_t)(3 << 14), 256 | }; 257 | 258 | enum Delay : uint32_t 259 | { 260 | DELAY_CYCLES_5 = (uint32_t)(0 << 8), 261 | DELAY_CYCLES_6 = (uint32_t)(1 << 8), 262 | DELAY_CYCLES_7 = (uint32_t)(2 << 8), 263 | DELAY_CYCLES_8 = (uint32_t)(3 << 8), 264 | DELAY_CYCLES_9 = (uint32_t)(4 << 8), 265 | DELAY_CYCLES_10 = (uint32_t)(5 << 8), 266 | DELAY_CYCLES_11 = (uint32_t)(6 << 8), 267 | DELAY_CYCLES_12 = (uint32_t)(7 << 8), 268 | DELAY_CYCLES_13 = (uint32_t)(8 << 8), 269 | DELAY_CYCLES_14 = (uint32_t)(9 << 8), 270 | DELAY_CYCLES_15 = (uint32_t)(10 << 8), 271 | DELAY_CYCLES_16 = (uint32_t)(11 << 8), 272 | DELAY_CYCLES_17 = (uint32_t)(12 << 8), 273 | DELAY_CYCLES_18 = (uint32_t)(13 << 8), 274 | DELAY_CYCLES_19 = (uint32_t)(14 << 8), 275 | DELAY_CYCLES_20 = (uint32_t)(15 << 8), 276 | }; 277 | 278 | Adc(Number adc); 279 | 280 | void set_resolution(Resolution res); 281 | 282 | void enable_scan_mode(); 283 | void disable_scan_mode(); 284 | 285 | void set_data_alignment(Alignment align); 286 | void set_external_trigger_for_regular_group(RegularGroupTrigger trigger); 287 | void set_external_trigger_polarity_for_regular_group( 288 | RegularGroupTriggerPolarity polarity); 289 | void set_conversion_mode(ConversionMode mode); 290 | 291 | void enable_dma_request(); 292 | void disable_dma_request(); 293 | 294 | void enable_dma(); 295 | void disable_dma(); 296 | 297 | void enable(); 298 | void disable(); 299 | 300 | void start_conversion(); 301 | 302 | void set_number_of_conversions(uint8_t number); 303 | void set_channel_sampling_time_selection(SamplingTime time, 304 | Channel channel); 305 | void set_conversion_number_in_sequence(uint8_t length, Channel* channel); 306 | void set_prescaler(Prescaler prescaler); 307 | void set_dma_mode(DmaMode mode); 308 | void set_delay_between_two_samples(Delay delay); 309 | void set_multi_mode(MultiMode mode); 310 | 311 | void enable_temp_sensor(); 312 | void disable_temp_sensor(); 313 | 314 | uint32_t get_base_address() { return (_adc); } 315 | 316 | private: 317 | uint32_t _adc; 318 | }; 319 | 320 | } // namespace adc 321 | 322 | } // namespace cm3cpp 323 | 324 | #endif /* CM3CPP_ADC_H_ */ 325 | -------------------------------------------------------------------------------- /cm3cpp/adc_dma.cpp: -------------------------------------------------------------------------------- 1 | #include "adc_dma.hpp" 2 | 3 | namespace cm3cpp { 4 | 5 | namespace adc { 6 | 7 | AdcDma::AdcDma(DmaConf dma, AdcConf adc, bool is_temp_sensor) 8 | { 9 | _adc = new Adc(adc.number); 10 | _data = new uint16_t[adc.channels_count]; 11 | memset(_data, 0, (adc.channels_count * sizeof(uint16_t))); 12 | 13 | dma_stream_reset(dma.number, dma.stream); 14 | dma_channel_select(dma.number, dma.stream, dma.channel); 15 | dma_set_memory_address(dma.number, dma.stream, (uint32_t)_data); 16 | dma_set_peripheral_address(dma.number, dma.stream, 17 | (uint32_t)&ADC_DR(_adc->get_base_address())); 18 | dma_set_transfer_mode(dma.number, dma.stream, 19 | DMA_SxCR_DIR_PERIPHERAL_TO_MEM); 20 | dma_set_number_of_data(dma.number, dma.stream, adc.channels_count); 21 | dma_disable_peripheral_increment_mode(dma.number, dma.stream); 22 | dma_enable_memory_increment_mode(dma.number, dma.stream); 23 | dma_set_peripheral_size(dma.number, dma.stream, DMA_SxCR_PSIZE_16BIT); 24 | dma_set_memory_size(dma.number, dma.stream, DMA_SxCR_MSIZE_16BIT); 25 | dma_enable_circular_mode(dma.number, dma.stream); 26 | dma_set_priority(dma.number, dma.stream, DMA_SxCR_PL_MEDIUM); 27 | dma_enable_fifo_mode(dma.number, dma.stream); 28 | dma_set_fifo_threshold(dma.number, dma.stream, DMA_SxFCR_FTH_2_4_FULL); 29 | dma_set_memory_burst(dma.number, dma.stream, DMA_SxCR_MBURST_SINGLE); 30 | dma_set_peripheral_burst(dma.number, dma.stream, DMA_SxCR_PBURST_SINGLE); 31 | dma_enable_stream(dma.number, dma.stream); 32 | 33 | if (is_temp_sensor) { 34 | _adc->enable_temp_sensor(); 35 | } 36 | _adc->set_multi_mode(Adc::MultiMode::MODE_INDEPENDENT); 37 | _adc->set_prescaler(Adc::Prescaler::PRESCALER_8); 38 | _adc->set_dma_mode(Adc::DmaMode::MODE_NONE); 39 | _adc->set_delay_between_two_samples(Adc::Delay::DELAY_CYCLES_20); 40 | _adc->set_resolution(Adc::Resolution::RES_12_BIT); 41 | _adc->enable_scan_mode(); 42 | _adc->set_conversion_mode(Adc::ConversionMode::CONTINUOUS_CONV); 43 | _adc->set_external_trigger_polarity_for_regular_group( 44 | Adc::RegularGroupTriggerPolarity::TRIGGER_NONE); 45 | _adc->set_external_trigger_for_regular_group( 46 | Adc::RegularGroupTrigger::T1_CC1); 47 | _adc->set_data_alignment(Adc::Alignment::RIGHT_ALIGN); 48 | _adc->set_conversion_number_in_sequence(adc.channels_count, adc.channels); 49 | 50 | for (int i = 0; i < adc.channels_count; ++i) { 51 | _adc->set_channel_sampling_time_selection(Adc::SamplingTime::CYCLES_480, 52 | adc.channels[i]); 53 | } 54 | 55 | _adc->enable_dma_request(); 56 | _adc->enable_dma(); 57 | _adc->enable(); 58 | _adc->start_conversion(); 59 | } 60 | 61 | uint16_t AdcDma::get_value(uint8_t index) 62 | { 63 | return (_data[index]); 64 | } 65 | 66 | } // namespace adc 67 | 68 | } // namespace cm3cpp 69 | -------------------------------------------------------------------------------- /cm3cpp/adc_dma.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CM3CPP_ADC_DMA_H_ 2 | #define CM3CPP_ADC_DMA_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "adc.hpp" 8 | #include "private/assert.h" 9 | 10 | namespace cm3cpp { 11 | 12 | namespace adc { 13 | 14 | class AdcDma 15 | { 16 | public: 17 | struct DmaConf 18 | { 19 | uint32_t number; 20 | uint8_t stream; 21 | uint32_t channel; 22 | }; 23 | 24 | struct AdcConf 25 | { 26 | Adc::Number number; 27 | Adc::Channel* channels; 28 | uint8_t channels_count; 29 | }; 30 | 31 | AdcDma(DmaConf dma, AdcConf adc, bool is_temp_sensor); 32 | 33 | CM3CPP_EXPLISIT_DESTRUCTOR(AdcDma) 34 | 35 | uint16_t get_value(uint8_t index); 36 | 37 | private: 38 | Adc* _adc; 39 | uint16_t* _data; 40 | }; 41 | 42 | } // namespace adc 43 | 44 | } // namespace cm3cpp 45 | 46 | #endif /* CM3CPP_ADC_DMA_H_ */ 47 | -------------------------------------------------------------------------------- /cm3cpp/dma.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file dma 4 | * @author 5 | * @version V1.0 6 | * @date 05-2019 7 | * @brief This is file realise uart. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | ****************************************************************************** 12 | */ 13 | 14 | /* Includes ------------------------------------------------------------------*/ 15 | #include "dma.hpp" 16 | 17 | // LIBOPENCM3 INCLUDES 18 | #include 19 | #include 20 | #include 21 | 22 | namespace cm3cpp { 23 | 24 | namespace dma { 25 | 26 | Dma::Dma(const LowLevelConfig& config) : 27 | _dma_num(config.dma_num), 28 | _stream(config.stream), 29 | _irq(config.irq) 30 | { 31 | // Enable clock DMA 32 | if (_dma_num == DmaNumber::_1) { 33 | rcc_periph_clock_enable(RCC_DMA1); 34 | } 35 | else { 36 | rcc_periph_clock_enable(RCC_DMA2); 37 | } 38 | 39 | // Reset channel 40 | dma_stream_reset(_dma_num, _stream); 41 | 42 | // Config DMA 43 | dma_set_priority(_dma_num, _stream, config.priority); 44 | dma_set_memory_size(_dma_num, _stream, config.mem_size); 45 | dma_set_peripheral_size(_dma_num, _stream, config.periph_size); 46 | 47 | if (config.periph_inc_mode == IncrementedMode::ENABLE) { 48 | dma_enable_peripheral_increment_mode(_dma_num, _stream); 49 | } 50 | else { 51 | dma_disable_peripheral_increment_mode(_dma_num, _stream); 52 | } 53 | 54 | if (config.mem_inc_mode == IncrementedMode::ENABLE) { 55 | dma_enable_memory_increment_mode(_dma_num, _stream); 56 | } 57 | else { 58 | dma_disable_memory_increment_mode(_dma_num, _stream); 59 | } 60 | 61 | if (config.mode == Mode::CIRCULAR) { 62 | dma_enable_circular_mode(_dma_num, _stream); 63 | } 64 | 65 | dma_set_transfer_mode(_dma_num, _stream, config.direction); 66 | 67 | dma_set_peripheral_address(_dma_num, _stream, config.peripheral_base_addr); 68 | 69 | dma_channel_select(_dma_num, _stream, config.channel); 70 | 71 | /// Configure interrupt 72 | dma_enable_transfer_complete_interrupt(_dma_num, _stream); 73 | enable_irq(); 74 | } 75 | 76 | void Dma::set_memory_address(uint32_t address) const 77 | { 78 | DMA_SM0AR(_dma_num, _stream) = (uint32_t*)address; 79 | } 80 | 81 | void Dma::set_data_counter(uint16_t len) const 82 | { 83 | dma_set_number_of_data(_dma_num, _stream, len); 84 | } 85 | 86 | void Dma::enable_stream() const 87 | { 88 | dma_enable_stream(_dma_num, _stream); 89 | } 90 | 91 | void Dma::disable_stream() const 92 | { 93 | dma_disable_stream(_dma_num, _stream); 94 | } 95 | 96 | void Dma::enable_irq() const 97 | { 98 | nvic_enable_irq(_irq); 99 | } 100 | 101 | void Dma::disable_irq() const 102 | { 103 | nvic_disable_irq(_irq); 104 | } 105 | 106 | bool Dma::get_interrupt_flag() const 107 | { 108 | return dma_get_interrupt_flag(_dma_num, _stream, DMA_TCIF); 109 | } 110 | 111 | void Dma::clear_interrupt_flag() const 112 | { 113 | dma_clear_interrupt_flags(_dma_num, _stream, DMA_TCIF); 114 | } 115 | 116 | } // namespace dma 117 | } // namespace cm3cpp 118 | -------------------------------------------------------------------------------- /cm3cpp/dma.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file dma.hpp 4 | * @author 5 | * @version V1.0 6 | * @date 05-2019 7 | * @brief This is file realise DMA. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | ****************************************************************************** 12 | */ 13 | 14 | /* Define to prevent recursive inclusion -------------------------------------*/ 15 | #pragma once 16 | 17 | // LIBOPENCM3 INCLUDES 18 | #include 19 | 20 | namespace cm3cpp { 21 | 22 | namespace dma { 23 | 24 | enum DmaNumber 25 | { 26 | _1 = DMA1, 27 | _2 = DMA2, 28 | }; 29 | 30 | /// Streams for USARTs 31 | enum Stream 32 | { 33 | STREAM1 = DMA_STREAM1, 34 | STREAM2 = DMA_STREAM2, 35 | STREAM3 = DMA_STREAM3, 36 | STREAM4 = DMA_STREAM4, 37 | STREAM5 = DMA_STREAM5, 38 | STREAM6 = DMA_STREAM6, 39 | STREAM7 = DMA_STREAM7 40 | }; 41 | 42 | /// Channels for USARTs 43 | enum Channel 44 | { 45 | CHANNEL1 = DMA_SxCR_CHSEL_1, 46 | CHANNEL2 = DMA_SxCR_CHSEL_2, 47 | CHANNEL3 = DMA_SxCR_CHSEL_3, 48 | CHANNEL4 = DMA_SxCR_CHSEL_4, 49 | CHANNEL5 = DMA_SxCR_CHSEL_5, 50 | CHANNEL6 = DMA_SxCR_CHSEL_6, 51 | CHANNEL7 = DMA_SxCR_CHSEL_7 52 | }; 53 | 54 | enum DataTransferDirection 55 | { 56 | MEM_TO_PERIPHERAL = DMA_SxCR_DIR_MEM_TO_PERIPHERAL, 57 | PERIPHERAL_TO_MEM = DMA_SxCR_DIR_PERIPHERAL_TO_MEM, 58 | MEM_TO_MEM = DMA_SxCR_DIR_MEM_TO_MEM 59 | }; 60 | 61 | /// Shows where or where data will be sent, to the periphery or memory 62 | enum class IncrementedMode 63 | { 64 | DISABLE, 65 | ENABLE 66 | }; 67 | 68 | /// Shows how much the size will be increased for the periphery 69 | enum DataSize 70 | { 71 | PERIPHERAL_BYTE = DMA_SxCR_PSIZE_8BIT, 72 | PERIPHERAL_HALF_WORD = DMA_SxCR_PSIZE_16BIT, 73 | PERIPHERAL_WORD = DMA_SxCR_PSIZE_32BIT, 74 | 75 | MEMORY_BYTE = DMA_SxCR_MSIZE_8BIT, 76 | MEMORY_HALF_WORD = DMA_SxCR_MSIZE_16BIT, 77 | MEMORY_WORD = DMA_SxCR_MSIZE_32BIT, 78 | }; 79 | 80 | /// DMA data recording mode, cyclic or normal 81 | enum class Mode 82 | { 83 | NORMAL, 84 | CIRCULAR 85 | }; 86 | 87 | /// The priorities of DMA 88 | enum Priority 89 | { 90 | LOW = DMA_SxCR_PL_LOW, 91 | MEDIUM = DMA_SxCR_PL_MEDIUM, 92 | HIGH = DMA_SxCR_PL_HIGH, 93 | VERY_HIGH = DMA_SxCR_PL_VERY_HIGH 94 | }; 95 | 96 | /// Low level config for DMA 97 | struct LowLevelConfig 98 | { 99 | DmaNumber dma_num; 100 | Stream stream; 101 | Channel channel; 102 | uint32_t peripheral_base_addr; 103 | DataTransferDirection direction; 104 | IncrementedMode periph_inc_mode; 105 | IncrementedMode mem_inc_mode; 106 | DataSize periph_size; 107 | DataSize mem_size; 108 | Mode mode; 109 | Priority priority; 110 | uint8_t irq; 111 | }; 112 | 113 | /** 114 | * Class hard DMA 115 | */ 116 | class Dma 117 | { 118 | public: 119 | Dma(const LowLevelConfig& config); 120 | 121 | ~Dma() = default; 122 | 123 | bool get_interrupt_flag() const; 124 | 125 | void clear_interrupt_flag() const; 126 | 127 | void set_memory_address(uint32_t address) const; 128 | 129 | void enable_stream() const; 130 | 131 | void disable_stream() const; 132 | 133 | void set_data_counter(uint16_t len) const; 134 | 135 | void enable_irq() const; 136 | 137 | void disable_irq() const; 138 | 139 | protected: 140 | Dma() = delete; /// Constructor default is delete 141 | Dma(const Dma& a) = delete; /// Constructor copy is delete 142 | Dma(Dma&& a) = delete; /// Constructor move is delete 143 | 144 | Dma& operator=(const Dma&) = delete; /// Operator copy is delete 145 | Dma& operator=(Dma&&) = delete; /// Operator move is delete 146 | 147 | private: 148 | DmaNumber _dma_num; ///< Number configured DMA 149 | Stream _stream; ///< Shows the stream on which DMA is configured 150 | 151 | uint8_t _irq; ///< Interrupt number 152 | }; 153 | 154 | } // namespace dma 155 | 156 | } // namespace cm3cpp 157 | -------------------------------------------------------------------------------- /cm3cpp/extra/one_wire.cpp: -------------------------------------------------------------------------------- 1 | #include "one_wire.hpp" 2 | 3 | namespace cm3cpp { 4 | 5 | namespace extra { 6 | 7 | OneWire::OneWire(Gpio::Pinout p, uint8_t tim_number, uint32_t tim_presc) : 8 | _pinout(p), 9 | _timer(tim_number) 10 | { 11 | _timer.set_counter_direction(Timer::CounterDirection::UP); 12 | _timer.set_alignment(Timer::Alignment::EDGE); 13 | _timer.set_clock_division(Timer::ClockDivision::TIMER_CLOCK_MUL_1); 14 | _timer.set_prescaler_value(tim_presc); 15 | _timer.set_counter_mode(Timer::CounterMode::CONTINUOUS); 16 | _timer.disable_autoreload_preload(); 17 | _timer.set_counter_value(0); 18 | 19 | _last_discrepancy = 0; 20 | _last_device = false; 21 | _last_family_discrepancy = 0; 22 | } 23 | 24 | uint8_t OneWire::read_byte(void) 25 | { 26 | uint8_t data = 0; 27 | 28 | for (uint8_t bit_count = 0; bit_count < 8; bit_count++) { 29 | /*pull low to initiate read*/ 30 | _pinout.mode_setup(Gpio::Mode::OUTPUT, Gpio::PullMode::PULL_UP); 31 | _pinout.set_output_options(Gpio::OutputType::OPEN_DRAIN, 32 | Gpio::Speed::FAST_50MHz); 33 | _pinout.clear(); 34 | _wait(_LOW_PULSE_TIME_US); 35 | 36 | /*float high*/ 37 | _pinout.mode_setup(Gpio::Mode::INPUT, Gpio::PullMode::PULL_UP); 38 | _wait(_READ_SAMPLE_WAIT_US); 39 | 40 | /*sample bus and shift into msb*/ 41 | data = static_cast(data >> 1); 42 | if (_pinout.get() != 0) 43 | data |= 0x80; 44 | 45 | /*wait until end of time slot*/ 46 | _wait(_END_READ_SLOT_WAIT_US); 47 | } 48 | 49 | return data; 50 | } 51 | 52 | void OneWire::write_byte(uint8_t data) 53 | { 54 | for (uint8_t bit_count = 0; bit_count < 8; bit_count++) { 55 | /*pull low to initiate write*/ 56 | _pinout.mode_setup(Gpio::Mode::OUTPUT, Gpio::PullMode::PULL_UP); 57 | _pinout.set_output_options(Gpio::OutputType::OPEN_DRAIN, 58 | Gpio::Speed::FAST_50MHz); 59 | _pinout.clear(); 60 | _wait(_LOW_PULSE_TIME_US); 61 | 62 | /*write next bit*/ 63 | ((bool)(data & 0x01)) ? _pinout.set() : _pinout.clear(); 64 | data = static_cast(data >> 1); 65 | 66 | /*wait until end of slot*/ 67 | _wait(_WRITE_SLOT_WAIT_US); 68 | 69 | /*float high and let device recover*/ 70 | _pinout.mode_setup(Gpio::Mode::INPUT, Gpio::PullMode::PULL_UP); 71 | _wait(_RECOVERY_TIME_US); 72 | } 73 | } 74 | 75 | bool OneWire::read_bit(void) 76 | { 77 | bool bit; 78 | 79 | /*pull low to initiate read*/ 80 | _pinout.mode_setup(Gpio::Mode::OUTPUT, Gpio::PullMode::PULL_UP); 81 | _pinout.set_output_options(Gpio::OutputType::OPEN_DRAIN, 82 | Gpio::Speed::FAST_50MHz); 83 | _pinout.clear(); 84 | 85 | _wait(_LOW_PULSE_TIME_US); 86 | 87 | /*float high*/ 88 | _pinout.mode_setup(Gpio::Mode::INPUT, Gpio::PullMode::PULL_UP); 89 | _wait(_READ_SAMPLE_WAIT_US); 90 | 91 | /*sample bus*/ 92 | if (_pinout.get() > 0) 93 | bit = true; 94 | else 95 | bit = false; 96 | 97 | /*wait until end of time slot*/ 98 | _wait(_END_READ_SLOT_WAIT_US); 99 | 100 | return bit; 101 | } 102 | 103 | void OneWire::write_bit(bool bit) 104 | { 105 | /*pull low to initiate write*/ 106 | _pinout.mode_setup(Gpio::Mode::OUTPUT, Gpio::PullMode::PULL_UP); 107 | _pinout.set_output_options(Gpio::OutputType::OPEN_DRAIN, 108 | Gpio::Speed::FAST_50MHz); 109 | _pinout.clear(); 110 | 111 | _wait(_LOW_PULSE_TIME_US); 112 | 113 | /*write next bit*/ 114 | bit ? _pinout.set() : _pinout.clear(); 115 | 116 | /*wait until end of slot*/ 117 | _wait(_WRITE_SLOT_WAIT_US); 118 | 119 | /*float high and let device recover*/ 120 | _pinout.mode_setup(Gpio::Mode::INPUT, Gpio::PullMode::PULL_UP); 121 | _wait(_RECOVERY_TIME_US); 122 | } 123 | 124 | bool OneWire::touch_reset(void) 125 | { 126 | bool presence = false; 127 | char sample_count = (_RESET_PULSE_TIME_US / 8); 128 | 129 | /*low reset pulse*/ 130 | _pinout.mode_setup(Gpio::Mode::OUTPUT, Gpio::PullMode::PULL_UP); 131 | _pinout.set_output_options(Gpio::OutputType::OPEN_DRAIN, 132 | Gpio::Speed::FAST_50MHz); 133 | _pinout.clear(); 134 | _wait(_RESET_PULSE_TIME_US); 135 | 136 | /*float high*/ 137 | _pinout.mode_setup(Gpio::Mode::INPUT, Gpio::PullMode::PULL_UP); 138 | 139 | while (sample_count-- != 0) { 140 | _wait(8); 141 | 142 | /*sample bus to check for connected devices*/ 143 | if (_pinout.get() == 0) 144 | presence = true; 145 | } 146 | 147 | return presence; 148 | } 149 | 150 | bool OneWire::search_first(bool do_reset, bool alarm_only) 151 | { 152 | _last_discrepancy = 0; 153 | _last_device = false; 154 | _last_family_discrepancy = 0; 155 | return search_next(do_reset, alarm_only); 156 | } 157 | 158 | bool OneWire::search_next(bool do_reset, bool alarm_only) 159 | { 160 | uint8_t bit_test, search_direction, bit_number; 161 | uint8_t last_zero, serial_byte_number; 162 | uint8_t serial_byte_mask; 163 | uint8_t lastcrc8 = 0; 164 | 165 | // initialize for search 166 | bit_number = 1; 167 | last_zero = 0; 168 | serial_byte_number = 0; 169 | serial_byte_mask = 1; 170 | bool next_result = 0; 171 | 172 | // if the last call was not the last one 173 | if (!_last_device) { 174 | // check if reset first is requested 175 | if (do_reset) { 176 | // reset the 1-wire 177 | // if there are no parts on 1-wire, return FALSE 178 | if (!touch_reset()) { 179 | _last_discrepancy = 0; 180 | _last_family_discrepancy = 0; 181 | return false; 182 | } 183 | } 184 | 185 | // If finding alarming devices issue a different command 186 | if (alarm_only) 187 | write_byte(_SEARCH_ALARM); // issue the alarming search command 188 | else 189 | write_byte(_SEARCH); // issue the search command 190 | 191 | // loop to do the search 192 | do { 193 | // read a bit and its compliment 194 | bit_test = static_cast(uint8_t(read_bit()) << 1); 195 | bit_test = 196 | static_cast(bit_test | static_cast(read_bit())); 197 | 198 | // check for no devices on 1-wire 199 | if (bit_test == 3) 200 | break; 201 | else { 202 | // all devices coupled have 0 or 1 203 | if (bit_test > 0) 204 | search_direction = 205 | !(bit_test & 0x01); // bit write value for search 206 | else { 207 | // if this discrepancy if before the Last Discrepancy 208 | // on a previous next then pick the same as last time 209 | if (bit_number < _last_discrepancy) 210 | search_direction = ((_serial[serial_byte_number] & 211 | serial_byte_mask) > 0); 212 | else 213 | // if equal to last pick 1, if not then pick 0 214 | search_direction = (bit_number == _last_discrepancy); 215 | 216 | // if 0 was picked then record its position in LastZero 217 | if (search_direction == 0) { 218 | last_zero = bit_number; 219 | 220 | // check for Last discrepancy in family 221 | if (last_zero < 9) 222 | _last_family_discrepancy = last_zero; 223 | } 224 | } 225 | 226 | // set or clear the bit in the SerialNum[portnum] byte 227 | // serial_byte_number with mask serial_byte_mask 228 | if (search_direction == 1) 229 | _serial[serial_byte_number] |= serial_byte_mask; 230 | else 231 | _serial[serial_byte_number] = static_cast( 232 | _serial[serial_byte_number] & ~serial_byte_mask); 233 | 234 | // serial number search direction write bit 235 | write_bit((bool)search_direction); 236 | 237 | // increment the byte counter bit_number 238 | // and shift the mask serial_byte_mask 239 | bit_number++; 240 | serial_byte_mask = static_cast(serial_byte_mask << 1); 241 | 242 | // if the mask is 0 then go to new SerialNum[portnum] byte 243 | // serial_byte_number and reset mask 244 | if (serial_byte_mask == 0) { 245 | // The below has been added to accomidate the valid CRC with 246 | // the possible changing serial number values of the 247 | // DS28E04. 248 | if (((_serial[0] & 0x7F) == 0x1C) && 249 | (serial_byte_number == 1)) 250 | _crc_check(0x7F, &lastcrc8); 251 | else 252 | _crc_check(_serial[serial_byte_number], 253 | &lastcrc8); // accumulate the CRC 254 | 255 | serial_byte_number++; 256 | serial_byte_mask = 1; 257 | } 258 | } 259 | } while (serial_byte_number < 260 | 8); // loop until through all SerialNum[portnum] bytes 0-7 261 | 262 | // if the search was successful then 263 | if (!((bit_number < 65) || lastcrc8)) { 264 | // search successful so set 265 | // LastDiscrepancy[portnum],LastDevice[portnum],next_result 266 | _last_discrepancy = last_zero; 267 | _last_device = (_last_discrepancy == 0); 268 | next_result = true; 269 | } 270 | } 271 | 272 | // if no device found then reset counters so next 'next' will be 273 | // like a first 274 | if (!next_result || !_serial[0]) { 275 | _last_discrepancy = 0; 276 | _last_device = false; 277 | _last_family_discrepancy = 0; 278 | next_result = false; 279 | } 280 | 281 | return next_result; 282 | } 283 | 284 | void OneWire::get_serial_number(uint8_t* sn_buffer, bool do_read) 285 | { 286 | if (do_read) 287 | memcpy(sn_buffer, _serial, _SERIAL_LENGTH); 288 | else 289 | memcpy(_serial, sn_buffer, _SERIAL_LENGTH); 290 | } 291 | 292 | void OneWire::_wait(uint16_t time) 293 | { 294 | _timer.set_autoreload_value(time); 295 | _timer.enable_counter(); 296 | 297 | while (_timer.get_counter_value() < time) {} 298 | 299 | _timer.disable_counter(); 300 | _timer.set_counter_value(0); 301 | } 302 | 303 | void OneWire::_crc_check(uint8_t data, uint8_t* crc_byte) 304 | { 305 | uint8_t tmp = *crc_byte; 306 | 307 | for (uint8_t bit_count = 0; bit_count < 8; bit_count++) { 308 | if ((data & 0x01) ^ (tmp & 0x01)) { 309 | tmp = static_cast(tmp >> 1); 310 | tmp = tmp ^ 0x8c; // 0b10001100; 311 | } 312 | else { 313 | tmp = static_cast(tmp >> 1); 314 | } 315 | 316 | data = static_cast(data >> 1); 317 | } 318 | 319 | *crc_byte = tmp; 320 | } 321 | 322 | } /* namespace extra */ 323 | 324 | } /* namespace cm3cpp */ 325 | -------------------------------------------------------------------------------- /cm3cpp/extra/one_wire.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXTRA_ONE_WIRE_H_ 2 | #define EXTRA_ONE_WIRE_H_ 3 | 4 | #include "../gpio.hpp" 5 | #include "../timer.hpp" 6 | #include 7 | 8 | namespace cm3cpp { 9 | 10 | namespace extra { 11 | 12 | namespace timer = cm3cpp::tim; 13 | 14 | class OneWire 15 | { 16 | public: 17 | using Timer = cm3cpp::tim::Timer; 18 | using Gpio = cm3cpp::gpio::Gpio; 19 | 20 | OneWire(Gpio::Pinout p, uint8_t tim_number, uint32_t tim_presc); 21 | ~OneWire() = default; 22 | 23 | uint8_t read_byte(void); 24 | void write_byte(uint8_t data); 25 | bool read_bit(void); 26 | void write_bit(bool bit); 27 | bool touch_reset(void); 28 | bool search_first(bool do_reset, bool alarm_only); 29 | bool search_next(bool do_reset, bool alarm_only); 30 | void get_serial_number(uint8_t* sn_buffer, bool do_read); 31 | 32 | private: 33 | static constexpr uint16_t _SLOT_LENGTH = 78; 34 | static constexpr uint16_t _RESET_PULSE_TIME_US = 520; 35 | static constexpr uint16_t _LOW_PULSE_TIME_US = 3; 36 | static constexpr uint16_t _READ_SAMPLE_TIME_US = 12; 37 | static constexpr uint16_t _READ_SAMPLE_WAIT_US = 38 | (_READ_SAMPLE_TIME_US - _LOW_PULSE_TIME_US); 39 | static constexpr uint16_t _END_READ_SLOT_WAIT_US = 40 | (_SLOT_LENGTH - _READ_SAMPLE_TIME_US); 41 | static constexpr uint16_t _RECOVERY_TIME_US = 6; 42 | static constexpr uint16_t _WRITE_SLOT_WAIT_US = 43 | (_SLOT_LENGTH - _LOW_PULSE_TIME_US); 44 | static constexpr uint8_t _SERIAL_LENGTH = 8; 45 | 46 | static constexpr uint8_t _SEARCH = 0xF0; 47 | static constexpr uint8_t _SEARCH_ALARM = 0xEC; 48 | 49 | Gpio _pinout; 50 | Timer _timer; 51 | uint8_t _serial[_SERIAL_LENGTH]; 52 | 53 | uint8_t _last_discrepancy; 54 | uint8_t _last_family_discrepancy; 55 | bool _last_device; 56 | 57 | void _wait(uint16_t time); 58 | void _crc_check(uint8_t data, uint8_t* crc_byte); 59 | }; 60 | 61 | } /* namespace extra */ 62 | 63 | } /* namespace cm3cpp */ 64 | 65 | #endif /* EXTRA_ONE_WIRE_H_ */ 66 | -------------------------------------------------------------------------------- /cm3cpp/flash_cycle.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CM3CPP_FLASH_CYCLE_H_ 2 | #define CM3CPP_FLASH_CYCLE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace cm3cpp { 9 | 10 | namespace flash { 11 | 12 | enum FlashSector : uint32_t 13 | { 14 | SECTOR_0 = 0x08000000, 15 | SECTOR_1 = 0x08004000, 16 | SECTOR_2 = 0x08008000, 17 | SECTOR_3 = 0x0800C000, 18 | SECTOR_4 = 0x08010000, 19 | SECTOR_5 = 0x08020000, 20 | }; 21 | 22 | constexpr uint32_t USER_FLASH_END_ADDRESS = 0x080FFFFF; 23 | 24 | template 25 | class FlashCycle 26 | { 27 | public: 28 | FlashCycle(FlashSector sector) 29 | { 30 | _error = false; 31 | _ifexist = false; 32 | _flashSector = sector; 33 | _startAddr = 0; 34 | _endAddr = 0; 35 | _getSectorAddrs(); 36 | _pLastContainer = _searchLastContainer(); 37 | } 38 | 39 | bool write(T* newContainer) 40 | { 41 | if (_error) { 42 | return (false); 43 | } 44 | 45 | uint32_t writeTo; 46 | 47 | flash_unlock(); 48 | 49 | if (!_ifexist) { 50 | writeTo = _startAddr; 51 | _ifexist = true; 52 | } 53 | else if ((uint32_t)_pLastContainer >= (_endAddr - sizeof(T))) { 54 | __disable_irq(); 55 | flash_erase_sector(5, 2); 56 | __enable_irq(); 57 | writeTo = _startAddr; 58 | } 59 | else { 60 | writeTo = (uint32_t)(_pLastContainer + 1); 61 | } 62 | 63 | uint8_t* pContainer = (uint8_t*)newContainer; 64 | 65 | for (int i = 0; i < sizeof(T); i++) { 66 | __disable_irq(); 67 | flash_program_byte(writeTo++, pContainer[i]); 68 | __enable_irq(); 69 | } 70 | 71 | flash_lock(); 72 | _pLastContainer = (T*)(writeTo - sizeof(T)); 73 | return (true); 74 | } 75 | 76 | T* get(void) { return (_pLastContainer); } 77 | 78 | bool is_exist(void) { return (_ifexist); } 79 | 80 | private: 81 | bool _error; 82 | bool _ifexist; 83 | FlashSector _flashSector; 84 | uint32_t _startAddr; 85 | uint32_t _endAddr; 86 | T* _pLastContainer; 87 | 88 | static constexpr uint8_t NUM_SECTORS = 6; 89 | 90 | void _getSectorAddrs(void) 91 | { 92 | _startAddr = (uint32_t)_flashSector; 93 | 94 | if (_flashSector == FlashSector::SECTOR_1) 95 | _endAddr = (uint32_t)FlashSector::SECTOR_2; 96 | else if (_flashSector == FlashSector::SECTOR_2) 97 | _endAddr = (uint32_t)FlashSector::SECTOR_3; 98 | else if (_flashSector == FlashSector::SECTOR_3) 99 | _endAddr = (uint32_t)FlashSector::SECTOR_4; 100 | else if (_flashSector == FlashSector::SECTOR_4) 101 | _endAddr = (uint32_t)FlashSector::SECTOR_5; 102 | else if (_flashSector == FlashSector::SECTOR_5) 103 | _endAddr = USER_FLASH_END_ADDRESS + 1; 104 | 105 | if (!_startAddr) 106 | _error = true; 107 | } 108 | 109 | T* _searchLastContainer(void) 110 | { 111 | if (_error) { 112 | return (0); 113 | } 114 | 115 | T* addr = (T*)_startAddr; 116 | _ifexist = true; 117 | while ((uint32_t)addr <= (_endAddr - sizeof(T))) { 118 | if (*(((uint8_t*)addr)) == 0xFF) { 119 | if (addr == (T*)_startAddr) { 120 | _ifexist = false; 121 | return (addr); 122 | // addr = 0; 123 | } 124 | 125 | break; 126 | } 127 | 128 | addr += 1; 129 | } 130 | 131 | return (addr - 1); 132 | } 133 | }; 134 | 135 | } /* namespace flash */ 136 | 137 | } /* namespace cm3cpp */ 138 | 139 | #endif /* CM3CPP_FLASH_CYCLE_H_ */ 140 | -------------------------------------------------------------------------------- /cm3cpp/flash_otp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CM3CPP_FLASH_OTP_HPP_ 2 | #define CM3CPP_FLASH_OTP_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | namespace cm3cpp { 8 | 9 | namespace flash { 10 | 11 | enum class OtpBlock : uint8_t 12 | { 13 | BLOCK_0, 14 | BLOCK_1, 15 | BLOCK_2, 16 | BLOCK_3, 17 | BLOCK_4, 18 | BLOCK_5, 19 | BLOCK_6, 20 | BLOCK_7, 21 | BLOCK_8, 22 | BLOCK_9, 23 | BLOCK_10, 24 | BLOCK_11, 25 | BLOCK_12, 26 | BLOCK_13, 27 | BLOCK_14, 28 | BLOCK_15, 29 | }; 30 | 31 | enum class OtpByte 32 | { 33 | BYTE_0, 34 | BYTE_1, 35 | BYTE_2, 36 | BYTE_3, 37 | BYTE_4, 38 | BYTE_5, 39 | BYTE_6, 40 | BYTE_7, 41 | BYTE_8, 42 | BYTE_9, 43 | BYTE_10, 44 | BYTE_11, 45 | BYTE_12, 46 | BYTE_13, 47 | BYTE_14, 48 | BYTE_15, 49 | BYTE_16, 50 | BYTE_17, 51 | BYTE_18, 52 | BYTE_19, 53 | BYTE_20, 54 | BYTE_21, 55 | BYTE_22, 56 | BYTE_23, 57 | BYTE_24, 58 | BYTE_25, 59 | BYTE_26, 60 | BYTE_27, 61 | BYTE_28, 62 | BYTE_29, 63 | BYTE_30, 64 | BYTE_31, 65 | }; 66 | 67 | enum class Flag 68 | { 69 | BSY = FLASH_SR_BSY, 70 | PGSERR = FLASH_SR_PGSERR, 71 | PGPERR = FLASH_SR_PGPERR, 72 | PGAERR = FLASH_SR_PGAERR, 73 | WRPERR = FLASH_SR_WRPERR, 74 | OPERR = FLASH_SR_OPERR, 75 | EOP = FLASH_SR_EOP, 76 | }; 77 | 78 | class FlashOtp 79 | { 80 | public: 81 | static void write(OtpBlock block, OtpByte byte, uint8_t data) 82 | { 83 | flash_unlock(); 84 | clear_flag(Flag::EOP); 85 | clear_flag(Flag::OPERR); 86 | clear_flag(Flag::WRPERR); 87 | clear_flag(Flag::PGAERR); 88 | clear_flag(Flag::PGPERR); 89 | clear_flag(Flag::PGSERR); 90 | flash_wait_for_last_operation(); 91 | uint32_t address = _OTP_START_ADDR + 92 | ((uint32_t)block * _OTP_BYTES_IN_BLOCK) + 93 | (uint32_t)byte; 94 | __disable_irq(); 95 | flash_program_byte(address, data); 96 | __enable_irq(); 97 | flash_lock(); 98 | } 99 | 100 | static uint8_t read(OtpBlock block, OtpByte byte) 101 | { 102 | uint32_t address = _OTP_START_ADDR + 103 | ((uint32_t)block * _OTP_BYTES_IN_BLOCK) + 104 | (uint32_t)byte; 105 | return *(uint8_t*)address; 106 | } 107 | 108 | static const uint8_t* const get_pointer(OtpBlock block, OtpByte byte) 109 | { 110 | uint32_t address = _OTP_START_ADDR + 111 | ((uint32_t)block * _OTP_BYTES_IN_BLOCK) + 112 | (uint32_t)byte; 113 | return (uint8_t*)address; 114 | } 115 | 116 | static bool get_flag(Flag flag) 117 | { 118 | uint32_t status = FLASH_SR | (uint32_t)flag; 119 | if (status > 0) 120 | return true; 121 | return false; 122 | } 123 | 124 | static void clear_flag(Flag flag) 125 | { 126 | if (flag == Flag::BSY) 127 | return; 128 | 129 | FLASH_SR |= (uint32_t)flag; 130 | } 131 | 132 | static void lock_block(OtpBlock block) 133 | { 134 | flash_unlock(); 135 | clear_flag(Flag::EOP); 136 | clear_flag(Flag::OPERR); 137 | clear_flag(Flag::WRPERR); 138 | clear_flag(Flag::PGAERR); 139 | clear_flag(Flag::PGPERR); 140 | clear_flag(Flag::PGSERR); 141 | flash_wait_for_last_operation(); 142 | uint32_t address = _OTP_LOCK_ADDR + static_cast(block); 143 | __disable_irq(); 144 | flash_program_byte(address, _OTP_LOCK_BLOCK); 145 | __enable_irq(); 146 | flash_lock(); 147 | } 148 | 149 | private: 150 | static constexpr uint32_t _OTP_START_ADDR = (0x1FFF7800); 151 | static constexpr uint32_t _OTP_LOCK_ADDR = (0x1FFF7A00); 152 | static constexpr uint32_t _OTP_BLOCKS = 16; 153 | static constexpr uint32_t _OTP_BYTES_IN_BLOCK = 32; 154 | static constexpr uint32_t _OTP_SIZE = (_OTP_BLOCKS * _OTP_BYTES_IN_BLOCK); 155 | static constexpr uint8_t _OTP_LOCK_BLOCK = 0x00; 156 | }; 157 | 158 | } /* namespace flash */ 159 | 160 | } /* namespace cm3cpp */ 161 | 162 | #endif /* CM3CPP_FLASH_OTP_HPP_ */ 163 | -------------------------------------------------------------------------------- /cm3cpp/gpio.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | GPIO C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #include "gpio.hpp" 27 | 28 | namespace cm3cpp { 29 | 30 | namespace gpio { 31 | 32 | Gpio::Gpio(Pinout pinout) 33 | { 34 | _pinout = pinout; 35 | } 36 | 37 | void Gpio::init(Pinout pinout) 38 | { 39 | _pinout = pinout; 40 | } 41 | 42 | void Gpio::set() 43 | { 44 | gpio_set(_pinout.port, _pinout.pin); 45 | } 46 | 47 | void Gpio::clear() 48 | { 49 | gpio_clear(_pinout.port, _pinout.pin); 50 | } 51 | 52 | bool Gpio::get() const 53 | { 54 | return gpio_get(_pinout.port, _pinout.pin); 55 | } 56 | 57 | void Gpio::toggle() 58 | { 59 | gpio_toggle(_pinout.port, _pinout.pin); 60 | } 61 | 62 | uint16_t Gpio::port_read() const 63 | { 64 | return gpio_port_read(_pinout.port); 65 | } 66 | 67 | void Gpio::port_write(uint16_t data) 68 | { 69 | gpio_port_write(_pinout.port, data); 70 | } 71 | 72 | void Gpio::port_config_lock() 73 | { 74 | gpio_port_config_lock(_pinout.port, _pinout.pin); 75 | } 76 | 77 | void Gpio::mode_setup(Mode mode, PullMode pull_mode) 78 | { 79 | uint8_t _mode; 80 | uint8_t _pull_mode; 81 | 82 | switch (mode) { 83 | case INPUT: 84 | _mode = GPIO_MODE_INPUT; 85 | break; 86 | case OUTPUT: 87 | _mode = GPIO_MODE_OUTPUT; 88 | break; 89 | case ALTERNATE_FUNCTION: 90 | _mode = GPIO_MODE_AF; 91 | break; 92 | case ANALOG: 93 | _mode = GPIO_MODE_ANALOG; 94 | break; 95 | } 96 | 97 | switch (pull_mode) { 98 | case NO_PULL: 99 | _pull_mode = GPIO_PUPD_NONE; 100 | break; 101 | case PULL_UP: 102 | _pull_mode = GPIO_PUPD_PULLUP; 103 | break; 104 | case PULL_DOWN: 105 | _pull_mode = GPIO_PUPD_PULLDOWN; 106 | break; 107 | } 108 | 109 | gpio_mode_setup(_pinout.port, _mode, _pull_mode, _pinout.pin); 110 | } 111 | 112 | void Gpio::set_output_options(OutputType type, Speed speed) 113 | { 114 | uint8_t _type; 115 | uint8_t _speed; 116 | 117 | switch (type) { 118 | case PUSH_PULL: 119 | _type = GPIO_OTYPE_PP; 120 | break; 121 | case OPEN_DRAIN: 122 | _type = GPIO_OTYPE_OD; 123 | break; 124 | } 125 | 126 | switch (speed) { 127 | case LOW_2MHz: 128 | _speed = GPIO_OSPEED_2MHZ; 129 | break; 130 | case MEDIUM_25MHz: 131 | _speed = GPIO_OSPEED_25MHZ; 132 | break; 133 | case FAST_50MHz: 134 | _speed = GPIO_OSPEED_50MHZ; 135 | break; 136 | case HIGH_SPEED_100MHz: 137 | _speed = GPIO_OSPEED_100MHZ; 138 | break; 139 | } 140 | 141 | gpio_set_output_options(_pinout.port, _type, _speed, _pinout.pin); 142 | } 143 | 144 | void Gpio::set_af(AltFuncNumber af_num) 145 | { 146 | uint8_t _af; 147 | switch (af_num) { 148 | case AF0: 149 | _af = GPIO_AF0; 150 | break; 151 | case AF1: 152 | _af = GPIO_AF1; 153 | break; 154 | case AF2: 155 | _af = GPIO_AF2; 156 | break; 157 | case AF3: 158 | _af = GPIO_AF3; 159 | break; 160 | case AF4: 161 | _af = GPIO_AF4; 162 | break; 163 | case AF5: 164 | _af = GPIO_AF5; 165 | break; 166 | case AF6: 167 | _af = GPIO_AF6; 168 | break; 169 | case AF7: 170 | _af = GPIO_AF7; 171 | break; 172 | case AF8: 173 | _af = GPIO_AF8; 174 | break; 175 | case AF9: 176 | _af = GPIO_AF9; 177 | break; 178 | case AF10: 179 | _af = GPIO_AF10; 180 | break; 181 | case AF11: 182 | _af = GPIO_AF11; 183 | break; 184 | case AF12: 185 | _af = GPIO_AF12; 186 | break; 187 | case AF13: 188 | _af = GPIO_AF13; 189 | break; 190 | case AF14: 191 | _af = GPIO_AF14; 192 | break; 193 | case AF15: 194 | _af = GPIO_AF15; 195 | break; 196 | } 197 | 198 | gpio_set_af(_pinout.port, _af, _pinout.pin); 199 | } 200 | 201 | void Gpio::setup_exti(exti_trigger_type trigger) 202 | { 203 | exti_select_source(_pinout.pin, _pinout.port); 204 | exti_set_trigger(_pinout.pin, trigger); 205 | exti_enable_request(_pinout.pin); 206 | } 207 | 208 | void Gpio::clear_exti_pending_bit() 209 | { 210 | exti_reset_request(_pinout.pin); 211 | } 212 | 213 | bool Gpio::get_exti_flag_status() const 214 | { 215 | uint32_t flag = exti_get_flag_status(_pinout.pin); 216 | if (flag != 0) 217 | return true; 218 | return false; 219 | } 220 | 221 | } // namespace gpio 222 | 223 | } // namespace cm3cpp 224 | -------------------------------------------------------------------------------- /cm3cpp/gpio.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | GPIO C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #ifndef CM3CPP_GPIO_H_ 27 | #define CM3CPP_GPIO_H_ 28 | 29 | // GENERAL INCLUDES 30 | #include "stdint.h" 31 | 32 | // LIBOPENCM3 INCLUDES 33 | #include 34 | #include 35 | #include 36 | #ifdef STM32F2 37 | #include 38 | #endif 39 | #ifdef STM32F4 40 | #include 41 | #endif 42 | 43 | // CM3CPP INCLUDES 44 | #include "private/pinout.h" 45 | 46 | namespace cm3cpp { 47 | 48 | namespace gpio { 49 | 50 | class Gpio 51 | { 52 | public: 53 | struct Pinout 54 | { 55 | enum Port 56 | { 57 | // Check preprocessor value is not empty 58 | // Works for integer values 59 | // https://stackoverflow.com/questions/4102351/test-for-empty-macro-definition 60 | #if (GPIOA + 0) 61 | PORT_A = GPIOA 62 | #endif 63 | #if (GPIOB + 0) 64 | , 65 | PORT_B = GPIOB 66 | #endif 67 | #if (GPIOC + 0) 68 | , 69 | PORT_C = GPIOC 70 | #endif 71 | #if (GPIOD + 0) 72 | , 73 | PORT_D = GPIOD 74 | #endif 75 | #if (GPIOE + 0) 76 | , 77 | PORT_E = GPIOE 78 | #endif 79 | #if (GPIOF + 0) 80 | , 81 | PORT_F = GPIOF 82 | #endif 83 | #if (GPIOG + 0) 84 | , 85 | PORT_G = GPIOG 86 | #endif 87 | #if (GPIOH + 0) 88 | , 89 | PORT_H = GPIOH 90 | #endif 91 | #if (GPIOI + 0) 92 | , 93 | PORT_I = GPIOI 94 | #endif 95 | #if (GPIOJ + 0) 96 | , 97 | PORT_J = GPIOJ 98 | #endif 99 | #if (GPIOK + 0) 100 | , 101 | PORT_K = GPIOK 102 | #endif 103 | }; 104 | 105 | Port port; 106 | uint16_t pin; 107 | uint8_t pin_number; 108 | }; 109 | 110 | enum Mode 111 | { 112 | INPUT, 113 | OUTPUT, 114 | ALTERNATE_FUNCTION, 115 | ANALOG 116 | }; 117 | 118 | enum PullMode 119 | { 120 | NO_PULL, 121 | PULL_UP, 122 | PULL_DOWN 123 | }; 124 | 125 | enum OutputType 126 | { 127 | PUSH_PULL, 128 | OPEN_DRAIN 129 | }; 130 | 131 | enum Speed 132 | { 133 | LOW_2MHz, 134 | MEDIUM_25MHz, 135 | FAST_50MHz, 136 | HIGH_SPEED_100MHz 137 | }; 138 | 139 | enum AltFuncNumber 140 | { 141 | AF0, 142 | AF1, 143 | AF2, 144 | AF3, 145 | AF4, 146 | AF5, 147 | AF6, 148 | AF7, 149 | AF8, 150 | AF9, 151 | AF10, 152 | AF11, 153 | AF12, 154 | AF13, 155 | AF14, 156 | AF15 157 | }; 158 | 159 | Gpio() {} 160 | Gpio(Pinout pinout); 161 | 162 | void init(Pinout pinout); 163 | void set(); 164 | void clear(); 165 | bool get() const; 166 | void toggle(); 167 | uint16_t port_read() const; 168 | void port_write(uint16_t data); 169 | void port_config_lock(); 170 | void mode_setup(Mode mode, PullMode pull_mode); 171 | void set_output_options(OutputType type, Speed speed); 172 | void set_af(AltFuncNumber af_num); 173 | void setup_exti(enum exti_trigger_type trigger); 174 | void clear_exti_pending_bit(); 175 | bool get_exti_flag_status() const; 176 | 177 | private: 178 | Pinout _pinout; 179 | }; // namespace gpio 180 | 181 | } // namespace gpio 182 | 183 | } // namespace cm3cpp 184 | 185 | #endif /* CM3CPP_GPIO_H_ */ 186 | -------------------------------------------------------------------------------- /cm3cpp/i2c.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | I2C C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #include "i2c.hpp" 27 | 28 | namespace cm3cpp { 29 | 30 | namespace i2c { 31 | 32 | #ifndef CM3CPP_CUSTOM_SYSTICK 33 | 34 | I2c::I2c(Config i2c_conf) : 35 | _counter_ms(new systick::Counter(systick::Counter::Mode::ONE_SHOT, 36 | MAX_TRANSMIT_TIME_MS)) 37 | { 38 | _config = i2c_conf; 39 | 40 | switch (_config.number) { 41 | case 1: 42 | _i2c = I2C1; 43 | break; 44 | case 2: 45 | _i2c = I2C2; 46 | break; 47 | case 3: 48 | _i2c = I2C3; 49 | break; 50 | default: 51 | break; 52 | } 53 | 54 | Gpio scl(_config.scl_pin); 55 | scl.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 56 | scl.set_output_options(Gpio::OutputType::OPEN_DRAIN, Gpio::Speed::LOW_2MHz); 57 | scl.set_af(Gpio::AltFuncNumber::AF4); 58 | 59 | Gpio sda(_config.sda_pin); 60 | sda.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 61 | sda.set_output_options(Gpio::OutputType::OPEN_DRAIN, Gpio::Speed::LOW_2MHz); 62 | sda.set_af(Gpio::AltFuncNumber::AF4); 63 | } 64 | 65 | void I2c::reset() 66 | { 67 | i2c_reset(_i2c); 68 | } 69 | 70 | void I2c::enable() 71 | { 72 | i2c_peripheral_enable(_i2c); 73 | } 74 | 75 | void I2c::disable() 76 | { 77 | i2c_peripheral_disable(_i2c); 78 | } 79 | 80 | void I2c::set_clock_frequency(ClockFrequency freq) 81 | { 82 | i2c_set_clock_frequency(_i2c, freq); 83 | } 84 | 85 | void I2c::set_ccr(uint16_t freq) 86 | { 87 | i2c_set_ccr(_i2c, freq); 88 | } 89 | 90 | void I2c::set_trise(uint16_t trise) 91 | { 92 | i2c_set_trise(_i2c, trise); 93 | } 94 | 95 | void I2c::set_mode(Mode mode) 96 | { 97 | switch (mode) { 98 | case STANDARD: 99 | i2c_set_standard_mode(_i2c); 100 | break; 101 | case FAST: 102 | i2c_set_fast_mode(_i2c); 103 | break; 104 | } 105 | } 106 | 107 | void I2c::set_address_mode(AddressMode mode) 108 | { 109 | switch (mode) { 110 | case ADDRESS_MODE_7BIT: 111 | I2C_OAR1(_i2c) &= ~static_cast(I2C_OAR1_ADDMODE); 112 | break; 113 | case ADDRESS_MODE_10BIT: 114 | I2C_OAR1(_i2c) |= I2C_OAR1_ADDMODE; 115 | break; 116 | } 117 | } 118 | 119 | void I2c::set_dutycycle(FastModeDuty dutycycle) 120 | { 121 | i2c_set_dutycycle(_i2c, dutycycle); 122 | } 123 | 124 | void I2c::set_own_7bit_slave_address(uint8_t slave) 125 | { 126 | i2c_set_own_7bit_slave_address(_i2c, slave); 127 | } 128 | 129 | void I2c::set_own_10bit_slave_address(uint16_t slave) 130 | { 131 | i2c_set_own_10bit_slave_address(_i2c, slave); 132 | } 133 | 134 | void I2c::set_own_7bit_slave_address_two(uint8_t slave) 135 | { 136 | i2c_set_own_7bit_slave_address_two(_i2c, slave); 137 | } 138 | 139 | void I2c::enable_dual_addressing_mode() 140 | { 141 | i2c_enable_dual_addressing_mode(_i2c); 142 | } 143 | 144 | void I2c::disable_dual_addressing_mode() 145 | { 146 | i2c_disable_dual_addressing_mode(_i2c); 147 | } 148 | 149 | void I2c::enable_interrupt(Interrupt interrupt) 150 | { 151 | switch (interrupt) { 152 | case IT_BUFFER: 153 | i2c_enable_interrupt(_i2c, I2C_CR2_ITBUFEN); 154 | break; 155 | case IT_EVENT: 156 | i2c_enable_interrupt(_i2c, I2C_CR2_ITEVTEN); 157 | break; 158 | case IT_ERROR: 159 | i2c_enable_interrupt(_i2c, I2C_CR2_ITERREN); 160 | break; 161 | } 162 | } 163 | 164 | void I2c::disable_interrupt(Interrupt interrupt) 165 | { 166 | switch (interrupt) { 167 | case IT_BUFFER: 168 | i2c_disable_interrupt(_i2c, I2C_CR2_ITBUFEN); 169 | break; 170 | case IT_EVENT: 171 | i2c_disable_interrupt(_i2c, I2C_CR2_ITEVTEN); 172 | break; 173 | case IT_ERROR: 174 | i2c_disable_interrupt(_i2c, I2C_CR2_ITERREN); 175 | break; 176 | } 177 | } 178 | 179 | auto I2c::master_transfer(MasterTransferCfg cfg) -> Result 180 | { 181 | uint32_t reg __attribute__((unused)); 182 | Result result = OK; 183 | 184 | _counter_ms->start(); 185 | 186 | _send_start(); 187 | while (_get_flag_status(MASTER_MODE_SELECTED) == Result::ERROR) { 188 | if (_counter_ms->timeout()) { 189 | result = TIMEOUT; 190 | break; 191 | } 192 | } 193 | 194 | _send_7bit_address(cfg.device_address, WRITE); 195 | while (_get_flag_status(MASTER_TRANSMITTER_MODE_SELECTED) == 196 | Result::ERROR) { 197 | if (_counter_ms->timeout()) { 198 | result = TIMEOUT; 199 | break; 200 | } 201 | } 202 | 203 | uint8_t index = 0; 204 | 205 | while (cfg.write_len > 0) { 206 | _send_data(cfg.write_buf[index]); 207 | 208 | while (_get_flag_status(MASTER_BYTE_TRANSMITTED) == Result::ERROR) { 209 | if (_counter_ms->timeout()) { 210 | result = TIMEOUT; 211 | break; 212 | } 213 | } 214 | 215 | cfg.write_len--; 216 | index++; 217 | } 218 | 219 | if (cfg.read_len != 0) { 220 | _send_start(); 221 | while (_get_flag_status(MASTER_MODE_SELECTED) == Result::ERROR) { 222 | if (_counter_ms->timeout()) { 223 | result = TIMEOUT; 224 | break; 225 | } 226 | } 227 | 228 | _enable_ack(); 229 | 230 | _send_7bit_address(cfg.device_address, READ); 231 | while (_get_flag_status(MASTER_RECEIVER_MODE_SELECTED) == 232 | Result::ERROR) { 233 | if (_counter_ms->timeout()) { 234 | result = TIMEOUT; 235 | break; 236 | } 237 | } 238 | 239 | uint8_t size_to_read = cfg.read_len; 240 | index = 0; 241 | 242 | while (size_to_read > 0) { 243 | size_to_read--; 244 | if (!size_to_read) 245 | _disable_ack(); 246 | while (_get_flag_status(MASTER_BYTE_RECEIVED) == Result::ERROR) { 247 | if (_counter_ms->timeout()) { 248 | result = TIMEOUT; 249 | break; 250 | } 251 | } 252 | 253 | uint8_t data = _get_data(); 254 | cfg.read_buf[index] = data; 255 | index++; 256 | } 257 | } 258 | 259 | _send_stop(); 260 | _counter_ms->stop(); 261 | 262 | return result; 263 | } 264 | 265 | void I2c::_send_start() 266 | { 267 | i2c_send_start(_i2c); 268 | } 269 | 270 | void I2c::_send_stop() 271 | { 272 | i2c_send_stop(_i2c); 273 | } 274 | 275 | void I2c::_clear_stop() 276 | { 277 | i2c_clear_stop(_i2c); 278 | } 279 | 280 | void I2c::_send_data(uint8_t data) 281 | { 282 | i2c_send_data(_i2c, data); 283 | } 284 | 285 | uint8_t I2c::_get_data() 286 | { 287 | return i2c_get_data(_i2c); 288 | } 289 | 290 | void I2c::_send_7bit_address(uint8_t slave, Command readwrite) 291 | { 292 | i2c_send_7bit_address(_i2c, slave, readwrite); 293 | } 294 | 295 | void I2c::_enable_ack() 296 | { 297 | i2c_enable_ack(_i2c); 298 | } 299 | 300 | void I2c::_disable_ack() 301 | { 302 | i2c_disable_ack(_i2c); 303 | } 304 | 305 | auto I2c::_get_flag_status(Event event) -> Result 306 | { 307 | Result result = ERROR; 308 | uint32_t reg_sr1 = I2C_SR1(_i2c); 309 | uint32_t reg_sr2 = (I2C_SR2(_i2c)) << 16; 310 | uint32_t lastevent = (reg_sr1 | reg_sr2) & I2C_FLAG_MASK; 311 | 312 | switch (event) { 313 | case MASTER_MODE_SELECTED: 314 | if ((lastevent & MASTER_MODE_SELECTED_MASK) == 315 | MASTER_MODE_SELECTED_MASK) { 316 | result = OK; 317 | } 318 | break; 319 | case MASTER_TRANSMITTER_MODE_SELECTED: 320 | if ((lastevent & MASTER_TRANSMITTER_MODE_SELECTED_MASK) == 321 | MASTER_TRANSMITTER_MODE_SELECTED_MASK) { 322 | result = OK; 323 | } 324 | break; 325 | case MASTER_RECEIVER_MODE_SELECTED: 326 | if ((lastevent & MASTER_RECEIVER_MODE_SELECTED_MASK) == 327 | MASTER_RECEIVER_MODE_SELECTED_MASK) { 328 | result = OK; 329 | } 330 | break; 331 | case MASTER_MODE_ADDRESS10: 332 | if ((lastevent & MASTER_MODE_ADDRESS10_MASK) == 333 | MASTER_MODE_ADDRESS10_MASK) { 334 | result = OK; 335 | } 336 | break; 337 | case MASTER_BYTE_RECEIVED: 338 | if ((lastevent & MASTER_BYTE_RECEIVED_MASK) == 339 | MASTER_BYTE_RECEIVED_MASK) { 340 | result = OK; 341 | } 342 | break; 343 | case MASTER_BYTE_TRANSMITTING: 344 | if ((lastevent & MASTER_BYTE_TRANSMITTING_MASK) == 345 | MASTER_BYTE_TRANSMITTING_MASK) { 346 | result = OK; 347 | } 348 | break; 349 | case MASTER_BYTE_TRANSMITTED: 350 | if ((lastevent & MASTER_BYTE_TRANSMITTED_MASK) == 351 | MASTER_BYTE_TRANSMITTED_MASK) { 352 | result = OK; 353 | } 354 | break; 355 | } 356 | 357 | return result; 358 | } 359 | 360 | #endif // CM3CPP_CUSTOM_SYSTICK 361 | 362 | } // namespace i2c 363 | 364 | } // namespace cm3cpp 365 | -------------------------------------------------------------------------------- /cm3cpp/i2c.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | I2C C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #ifndef I2C_EXT_H 27 | #define I2C_EXT_H 28 | 29 | #include 30 | 31 | #include "gpio.hpp" 32 | #include "private/assert.h" 33 | 34 | #include "systick.hpp" 35 | 36 | namespace cm3cpp { 37 | 38 | namespace i2c { 39 | 40 | #ifndef CM3CPP_CUSTOM_SYSTICK 41 | 42 | class I2c 43 | { 44 | public: 45 | using Gpio = gpio::Gpio; 46 | 47 | enum Mode 48 | { 49 | STANDARD = 0, 50 | FAST 51 | }; 52 | 53 | enum FastModeDuty 54 | { 55 | DUTY_DIV2 = 0, 56 | DUTY_16_DIV_9 57 | }; 58 | 59 | enum AddressMode 60 | { 61 | ADDRESS_MODE_7BIT = 0, 62 | ADDRESS_MODE_10BIT = 1 63 | }; 64 | 65 | enum Command 66 | { 67 | WRITE = 0, 68 | READ = 1 69 | }; 70 | 71 | enum Event 72 | { 73 | MASTER_MODE_SELECTED, 74 | MASTER_TRANSMITTER_MODE_SELECTED, 75 | MASTER_RECEIVER_MODE_SELECTED, 76 | MASTER_MODE_ADDRESS10, 77 | MASTER_BYTE_RECEIVED, 78 | MASTER_BYTE_TRANSMITTING, 79 | MASTER_BYTE_TRANSMITTED 80 | }; 81 | 82 | enum TransferStatus 83 | { 84 | MASTER_MODE_SELECTED_ERROR, 85 | MASTER_TRANSMITTER_MODE_SELECTED_ERROR, 86 | MASTER_RECEIVER_MODE_SELECTED_ERROR, 87 | MASTER_MODE_ADDRESS10_ERROR, 88 | MASTER_BYTE_RECEIVED_ERROR, 89 | MASTER_BYTE_TRANSMITTING_ERROR, 90 | MASTER_BYTE_TRANSMITTED_ERROR, 91 | SUCCESS 92 | }; 93 | 94 | enum Interrupt 95 | { 96 | IT_BUFFER, 97 | IT_EVENT, 98 | IT_ERROR 99 | }; 100 | 101 | enum ClockFrequency 102 | { 103 | FREQ_2MHZ = 0x02, 104 | FREQ_3MHZ = 0x03, 105 | FREQ_4MHZ = 0x04, 106 | FREQ_5MHZ = 0x05, 107 | FREQ_6MHZ = 0x06, 108 | FREQ_7MHZ = 0x07, 109 | FREQ_8MHZ = 0x08, 110 | FREQ_9MHZ = 0x09, 111 | FREQ_10MHZ = 0x0a, 112 | FREQ_11MHZ = 0x0b, 113 | FREQ_12MHZ = 0x0c, 114 | FREQ_13MHZ = 0x0d, 115 | FREQ_14MHZ = 0x0e, 116 | FREQ_15MHZ = 0x0f, 117 | FREQ_16MHZ = 0x10, 118 | FREQ_17MHZ = 0x11, 119 | FREQ_18MHZ = 0x12, 120 | FREQ_19MHZ = 0x13, 121 | FREQ_20MHZ = 0x14, 122 | FREQ_21MHZ = 0x15, 123 | FREQ_22MHZ = 0x16, 124 | FREQ_23MHZ = 0x17, 125 | FREQ_24MHZ = 0x18, 126 | FREQ_25MHZ = 0x19, 127 | FREQ_26MHZ = 0x1a, 128 | FREQ_27MHZ = 0x1b, 129 | FREQ_28MHZ = 0x1c, 130 | FREQ_29MHZ = 0x1d, 131 | FREQ_30MHZ = 0x1e, 132 | FREQ_31MHZ = 0x1f, 133 | FREQ_32MHZ = 0x20, 134 | FREQ_33MHZ = 0x21, 135 | FREQ_34MHZ = 0x22, 136 | FREQ_35MHZ = 0x23, 137 | FREQ_36MHZ = 0x24, 138 | FREQ_37MHZ = 0x25, 139 | FREQ_38MHZ = 0x26, 140 | FREQ_39MHZ = 0x27, 141 | FREQ_40MHZ = 0x28, 142 | FREQ_41MHZ = 0x29, 143 | FREQ_42MHZ = 0x2a 144 | }; 145 | 146 | struct Config 147 | { 148 | uint8_t number; 149 | Gpio::Pinout scl_pin; 150 | Gpio::Pinout sda_pin; 151 | }; 152 | 153 | struct MasterTransferCfg 154 | { 155 | uint8_t device_address; 156 | uint8_t* write_buf; 157 | uint8_t write_len; 158 | uint8_t read_len; 159 | uint8_t* read_buf; 160 | }; 161 | 162 | enum Result 163 | { 164 | OK, 165 | ERROR, 166 | TIMEOUT, 167 | }; 168 | 169 | I2c(Config i2c_conf); 170 | CM3CPP_EXPLISIT_DESTRUCTOR(I2c) 171 | 172 | void reset(); 173 | void enable(); 174 | void disable(); 175 | void set_clock_frequency(ClockFrequency freq); 176 | void set_ccr(uint16_t freq); 177 | void set_trise(uint16_t trise); 178 | void set_mode(Mode mode); 179 | void set_address_mode(AddressMode mode); 180 | void set_dutycycle(FastModeDuty dutycycle); 181 | void set_own_7bit_slave_address(uint8_t slave); 182 | void set_own_10bit_slave_address(uint16_t slave); 183 | void set_own_7bit_slave_address_two(uint8_t slave); 184 | void enable_dual_addressing_mode(); 185 | void disable_dual_addressing_mode(); 186 | void enable_interrupt(Interrupt interrupt); 187 | void disable_interrupt(Interrupt interrupt); 188 | Result master_transfer(MasterTransferCfg cfg); 189 | 190 | private: 191 | static constexpr uint8_t MAX_TRANSMIT_TIME_MS = 3; 192 | static constexpr uint32_t I2C_FLAG_MASK = 0x00FFFFFF; 193 | static constexpr uint32_t MASTER_MODE_SELECTED_MASK = 0x00030001; 194 | static constexpr uint32_t MASTER_TRANSMITTER_MODE_SELECTED_MASK = 195 | 0x00070082; 196 | static constexpr uint32_t MASTER_RECEIVER_MODE_SELECTED_MASK = 0x00030002; 197 | static constexpr uint32_t MASTER_MODE_ADDRESS10_MASK = 0x00030008; 198 | static constexpr uint32_t MASTER_BYTE_RECEIVED_MASK = 0x00030040; 199 | static constexpr uint32_t MASTER_BYTE_TRANSMITTING_MASK = 0x00070080; 200 | static constexpr uint32_t MASTER_BYTE_TRANSMITTED_MASK = 0x00070084; 201 | 202 | uint32_t _i2c; 203 | Config _config; 204 | 205 | systick::Counter* _counter_ms; 206 | 207 | void _send_start(); 208 | void _send_stop(); 209 | void _clear_stop(); 210 | void _send_data(uint8_t data); 211 | uint8_t _get_data(); 212 | void _send_7bit_address(uint8_t slave, Command readwrite); 213 | void _enable_ack(); 214 | void _disable_ack(); 215 | Result _get_flag_status(Event event); 216 | }; 217 | 218 | #endif // CM3CPP_CUSTOM_SYSTICK 219 | 220 | } // namespace i2c 221 | 222 | } // namespace cm3cpp 223 | 224 | #endif 225 | -------------------------------------------------------------------------------- /cm3cpp/irq/gen_irq.py: -------------------------------------------------------------------------------- 1 | irq_defines = """ 2 | #define NVIC_NVIC_WWDG_IRQ 0 3 | #define NVIC_PVD_IRQ 1 4 | #define NVIC_TAMP_STAMP_IRQ 2 5 | #define NVIC_RTC_WKUP_IRQ 3 6 | #define NVIC_FLASH_IRQ 4 7 | #define NVIC_RCC_IRQ 5 8 | #define NVIC_EXTI0_IRQ 6 9 | #define NVIC_EXTI1_IRQ 7 10 | #define NVIC_EXTI2_IRQ 8 11 | #define NVIC_EXTI3_IRQ 9 12 | #define NVIC_EXTI4_IRQ 10 13 | #define NVIC_DMA1_STREAM0_IRQ 11 14 | #define NVIC_DMA1_STREAM1_IRQ 12 15 | #define NVIC_DMA1_STREAM2_IRQ 13 16 | #define NVIC_DMA1_STREAM3_IRQ 14 17 | #define NVIC_DMA1_STREAM4_IRQ 15 18 | #define NVIC_DMA1_STREAM5_IRQ 16 19 | #define NVIC_DMA1_STREAM6_IRQ 17 20 | #define NVIC_ADC_IRQ 18 21 | #define NVIC_CAN1_TX_IRQ 19 22 | #define NVIC_CAN1_RX0_IRQ 20 23 | #define NVIC_CAN1_RX1_IRQ 21 24 | #define NVIC_CAN1_SCE_IRQ 22 25 | #define NVIC_EXTI9_5_IRQ 23 26 | #define NVIC_TIM1_BRK_TIM9_IRQ 24 27 | #define NVIC_TIM1_UP_TIM10_IRQ 25 28 | #define NVIC_TIM1_TRG_COM_TIM11_IRQ 26 29 | #define NVIC_TIM1_CC_IRQ 27 30 | #define NVIC_TIM2_IRQ 28 31 | #define NVIC_TIM3_IRQ 29 32 | #define NVIC_TIM4_IRQ 30 33 | #define NVIC_I2C1_EV_IRQ 31 34 | #define NVIC_I2C1_ER_IRQ 32 35 | #define NVIC_I2C2_EV_IRQ 33 36 | #define NVIC_I2C2_ER_IRQ 34 37 | #define NVIC_SPI1_IRQ 35 38 | #define NVIC_SPI2_IRQ 36 39 | #define NVIC_USART1_IRQ 37 40 | #define NVIC_USART2_IRQ 38 41 | #define NVIC_USART3_IRQ 39 42 | #define NVIC_EXTI15_10_IRQ 40 43 | #define NVIC_RTC_ALARM_IRQ 41 44 | #define NVIC_USB_FS_WKUP_IRQ 42 45 | #define NVIC_TIM8_BRK_TIM12_IRQ 43 46 | #define NVIC_TIM8_UP_TIM13_IRQ 44 47 | #define NVIC_TIM8_TRG_COM_TIM14_IRQ 45 48 | #define NVIC_TIM8_CC_IRQ 46 49 | #define NVIC_DMA1_STREAM7_IRQ 47 50 | #define NVIC_FSMC_IRQ 48 51 | #define NVIC_SDIO_IRQ 49 52 | #define NVIC_TIM5_IRQ 50 53 | #define NVIC_SPI3_IRQ 51 54 | #define NVIC_UART4_IRQ 52 55 | #define NVIC_UART5_IRQ 53 56 | #define NVIC_TIM6_DAC_IRQ 54 57 | #define NVIC_TIM7_IRQ 55 58 | #define NVIC_DMA2_STREAM0_IRQ 56 59 | #define NVIC_DMA2_STREAM1_IRQ 57 60 | #define NVIC_DMA2_STREAM2_IRQ 58 61 | #define NVIC_DMA2_STREAM3_IRQ 59 62 | #define NVIC_DMA2_STREAM4_IRQ 60 63 | #define NVIC_ETH_IRQ 61 64 | #define NVIC_ETH_WKUP_IRQ 62 65 | #define NVIC_CAN2_TX_IRQ 63 66 | #define NVIC_CAN2_RX0_IRQ 64 67 | #define NVIC_CAN2_RX1_IRQ 65 68 | #define NVIC_CAN2_SCE_IRQ 66 69 | #define NVIC_OTG_FS_IRQ 67 70 | #define NVIC_DMA2_STREAM5_IRQ 68 71 | #define NVIC_DMA2_STREAM6_IRQ 69 72 | #define NVIC_DMA2_STREAM7_IRQ 70 73 | #define NVIC_USART6_IRQ 71 74 | #define NVIC_I2C3_EV_IRQ 72 75 | #define NVIC_I2C3_ER_IRQ 73 76 | #define NVIC_OTG_HS_EP1_OUT_IRQ 74 77 | #define NVIC_OTG_HS_EP1_IN_IRQ 75 78 | #define NVIC_OTG_HS_WKUP_IRQ 76 79 | #define NVIC_OTG_HS_IRQ 77 80 | #define NVIC_DCMI_IRQ 78 81 | #define NVIC_CRYP_IRQ 79 82 | #define NVIC_HASH_RNG_IRQ 80 83 | #define NVIC_FPU_IRQ 81 84 | #define NVIC_UART7_IRQ 82 85 | #define NVIC_UART8_IRQ 83 86 | #define NVIC_SPI4_IRQ 84 87 | #define NVIC_SPI5_IRQ 85 88 | #define NVIC_SPI6_IRQ 86 89 | #define NVIC_SAI1_IRQ 87 90 | #define NVIC_LCD_TFT_IRQ 88 91 | #define NVIC_LCD_TFT_ERR_IRQ 89 92 | #define NVIC_DMA2D_IRQ 90 93 | """ 94 | 95 | splitted_irqs = irq_defines.split("\n")[1:-1] 96 | splitted_irqs = [s[13:] for s in splitted_irqs] 97 | 98 | for i, irq in enumerate(splitted_irqs): 99 | space_i = irq.find(' ') 100 | splitted_irqs[i] = "ISR_" + irq[:space_i - 4] 101 | 102 | splitted_irqs_for_enum = [] 103 | for i, irq in enumerate(splitted_irqs): 104 | space_i = irq.find(' ') 105 | if i == 0: 106 | irq = "ISR_" + irq + " = 0," 107 | else: 108 | irq = "ISR_" + irq + "," 109 | 110 | splitted_irqs_for_enum.append(irq) 111 | 112 | f = open("irq_enum.txt", "w+") 113 | f.write("enum Interrupt : uint32_t {" + "\n") 114 | for irq in splitted_irqs_for_enum: 115 | f.write("\t" + irq + "\n") 116 | f.write("};") 117 | f.close() 118 | 119 | defines = ["DEFINE_CALLBACK({}_isr, {:>25s})".format(s[4:].lower(), s) for s in splitted_irqs] 120 | 121 | f = open("irq_defines.txt", "w+") 122 | for define in defines: 123 | f.write(define + "\n") 124 | f.close() -------------------------------------------------------------------------------- /cm3cpp/irq/irq.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "irq.hpp" 4 | 5 | #define DEFINE_CALLBACK(cfunc, int_enum) \ 6 | [[gnu::weak]] void cfunc(void) \ 7 | { \ 8 | const uint32_t indx = static_cast(Interrupt::int_enum); \ 9 | isr_vector_table[indx]->call(); \ 10 | } 11 | 12 | namespace cm3cpp { 13 | 14 | #ifndef CM3CPP_CUSTOM_INTERRUPT_SERVICE 15 | 16 | struct EmptyInterrupt : public IInterruptable 17 | { 18 | void call() {} 19 | EmptyInterrupt() = default; 20 | ~EmptyInterrupt() = default; 21 | } _empty_interrupt; 22 | 23 | constexpr uint32_t INTERRUPTS_COUNT = NVIC_IRQ_COUNT; 24 | static IInterruptable* isr_vector_table[INTERRUPTS_COUNT]; 25 | 26 | struct InterruptInitializer 27 | { 28 | InterruptInitializer() 29 | { 30 | for (uint32_t i = 0; i < INTERRUPTS_COUNT; ++i) { 31 | if (isr_vector_table[i] == nullptr) { 32 | /* init an irq table with empty functions for safe */ 33 | isr_vector_table[i] = &_empty_interrupt; 34 | } 35 | } 36 | } 37 | } _init; 38 | 39 | void IInterruptable::register_isr(Interrupt interrupt, 40 | IInterruptable* interrupt_owner) 41 | { 42 | const uint32_t indx = static_cast(interrupt); 43 | isr_vector_table[indx] = interrupt_owner; 44 | } 45 | 46 | BEGIN_DECLS 47 | 48 | #ifdef STM32F2 49 | DEFINE_CALLBACK(nvic_wwdg_isr, ISR_NVIC_WWDG) 50 | DEFINE_CALLBACK(pvd_isr, ISR_PVD) 51 | DEFINE_CALLBACK(tamp_stamp_isr, ISR_TAMP_STAMP) 52 | DEFINE_CALLBACK(rtc_wkup_isr, ISR_RTC_WKUP) 53 | DEFINE_CALLBACK(flash_isr, ISR_FLASH) 54 | DEFINE_CALLBACK(rcc_isr, ISR_RCC) 55 | DEFINE_CALLBACK(exti0_isr, ISR_EXTI0) 56 | DEFINE_CALLBACK(exti1_isr, ISR_EXTI1) 57 | DEFINE_CALLBACK(exti2_isr, ISR_EXTI2) 58 | DEFINE_CALLBACK(exti3_isr, ISR_EXTI3) 59 | DEFINE_CALLBACK(exti4_isr, ISR_EXTI4) 60 | DEFINE_CALLBACK(dma1_stream0_isr, ISR_DMA1_STREAM0) 61 | DEFINE_CALLBACK(dma1_stream1_isr, ISR_DMA1_STREAM1) 62 | DEFINE_CALLBACK(dma1_stream2_isr, ISR_DMA1_STREAM2) 63 | DEFINE_CALLBACK(dma1_stream3_isr, ISR_DMA1_STREAM3) 64 | DEFINE_CALLBACK(dma1_stream4_isr, ISR_DMA1_STREAM4) 65 | DEFINE_CALLBACK(dma1_stream5_isr, ISR_DMA1_STREAM5) 66 | DEFINE_CALLBACK(dma1_stream6_isr, ISR_DMA1_STREAM6) 67 | DEFINE_CALLBACK(adc_isr, ISR_ADC) 68 | DEFINE_CALLBACK(can1_tx_isr, ISR_CAN1_TX) 69 | DEFINE_CALLBACK(can1_rx0_isr, ISR_CAN1_RX0) 70 | DEFINE_CALLBACK(can1_rx1_isr, ISR_CAN1_RX1) 71 | DEFINE_CALLBACK(can1_sce_isr, ISR_CAN1_SCE) 72 | DEFINE_CALLBACK(exti9_5_isr, ISR_EXTI9_5) 73 | DEFINE_CALLBACK(tim1_brk_tim9_isr, ISR_TIM1_BRK_TIM9) 74 | DEFINE_CALLBACK(tim1_up_tim10_isr, ISR_TIM1_UP_TIM10) 75 | DEFINE_CALLBACK(tim1_trg_com_tim11_isr, ISR_TIM1_TRG_COM_TIM11) 76 | DEFINE_CALLBACK(tim1_cc_isr, ISR_TIM1_CC) 77 | DEFINE_CALLBACK(tim2_isr, ISR_TIM2) 78 | DEFINE_CALLBACK(tim3_isr, ISR_TIM3) 79 | DEFINE_CALLBACK(tim4_isr, ISR_TIM4) 80 | DEFINE_CALLBACK(i2c1_ev_isr, ISR_I2C1_EV) 81 | DEFINE_CALLBACK(i2c1_er_isr, ISR_I2C1_ER) 82 | DEFINE_CALLBACK(i2c2_ev_isr, ISR_I2C2_EV) 83 | DEFINE_CALLBACK(i2c2_er_isr, ISR_I2C2_ER) 84 | DEFINE_CALLBACK(spi1_isr, ISR_SPI1) 85 | DEFINE_CALLBACK(spi2_isr, ISR_SPI2) 86 | DEFINE_CALLBACK(usart1_isr, ISR_USART1) 87 | DEFINE_CALLBACK(usart2_isr, ISR_USART2) 88 | DEFINE_CALLBACK(usart3_isr, ISR_USART3) 89 | DEFINE_CALLBACK(exti15_10_isr, ISR_EXTI15_10) 90 | DEFINE_CALLBACK(rtc_alarm_isr, ISR_RTC_ALARM) 91 | DEFINE_CALLBACK(usb_fs_wkup_isr, ISR_USB_FS_WKUP) 92 | DEFINE_CALLBACK(tim8_brk_tim12_isr, ISR_TIM8_BRK_TIM12) 93 | DEFINE_CALLBACK(tim8_up_tim13_isr, ISR_TIM8_UP_TIM13) 94 | DEFINE_CALLBACK(tim8_trg_com_tim14_isr, ISR_TIM8_TRG_COM_TIM14) 95 | DEFINE_CALLBACK(tim8_cc_isr, ISR_TIM8_CC) 96 | DEFINE_CALLBACK(dma1_stream7_isr, ISR_DMA1_STREAM7) 97 | DEFINE_CALLBACK(fsmc_isr, ISR_FSMC) 98 | DEFINE_CALLBACK(sdio_isr, ISR_SDIO) 99 | DEFINE_CALLBACK(tim5_isr, ISR_TIM5) 100 | DEFINE_CALLBACK(spi3_isr, ISR_SPI3) 101 | DEFINE_CALLBACK(uart4_isr, ISR_UART4) 102 | DEFINE_CALLBACK(uart5_isr, ISR_UART5) 103 | DEFINE_CALLBACK(tim6_dac_isr, ISR_TIM6_DAC) 104 | DEFINE_CALLBACK(tim7_isr, ISR_TIM7) 105 | DEFINE_CALLBACK(dma2_stream0_isr, ISR_DMA2_STREAM0) 106 | DEFINE_CALLBACK(dma2_stream1_isr, ISR_DMA2_STREAM1) 107 | DEFINE_CALLBACK(dma2_stream2_isr, ISR_DMA2_STREAM2) 108 | DEFINE_CALLBACK(dma2_stream3_isr, ISR_DMA2_STREAM3) 109 | DEFINE_CALLBACK(dma2_stream4_isr, ISR_DMA2_STREAM4) 110 | DEFINE_CALLBACK(eth_isr, ISR_ETH) 111 | DEFINE_CALLBACK(eth_wkup_isr, ISR_ETH_WKUP) 112 | DEFINE_CALLBACK(can2_tx_isr, ISR_CAN2_TX) 113 | DEFINE_CALLBACK(can2_rx0_isr, ISR_CAN2_RX0) 114 | DEFINE_CALLBACK(can2_rx1_isr, ISR_CAN2_RX1) 115 | DEFINE_CALLBACK(can2_sce_isr, ISR_CAN2_SCE) 116 | DEFINE_CALLBACK(otg_fs_isr, ISR_OTG_FS) 117 | DEFINE_CALLBACK(dma2_stream5_isr, ISR_DMA2_STREAM5) 118 | DEFINE_CALLBACK(dma2_stream6_isr, ISR_DMA2_STREAM6) 119 | DEFINE_CALLBACK(dma2_stream7_isr, ISR_DMA2_STREAM7) 120 | DEFINE_CALLBACK(usart6_isr, ISR_USART6) 121 | DEFINE_CALLBACK(i2c3_ev_isr, ISR_I2C3_EV) 122 | DEFINE_CALLBACK(i2c3_er_isr, ISR_I2C3_ER) 123 | DEFINE_CALLBACK(otg_hs_ep1_out_isr, ISR_OTG_HS_EP1_OUT) 124 | DEFINE_CALLBACK(otg_hs_ep1_in_isr, ISR_OTG_HS_EP1_IN) 125 | DEFINE_CALLBACK(otg_hs_wkup_isr, ISR_OTG_HS_WKUP) 126 | DEFINE_CALLBACK(otg_hs_isr, ISR_OTG_HS) 127 | DEFINE_CALLBACK(dcmi_isr, ISR_DCMI) 128 | DEFINE_CALLBACK(cryp_isr, ISR_CRYP) 129 | DEFINE_CALLBACK(hash_rng_isr, ISR_HASH_RNG) 130 | #endif 131 | 132 | #ifdef STM32F4 133 | DEFINE_CALLBACK(nvic_wwdg_isr, ISR_NVIC_WWDG) 134 | DEFINE_CALLBACK(pvd_isr, ISR_PVD) 135 | DEFINE_CALLBACK(tamp_stamp_isr, ISR_TAMP_STAMP) 136 | DEFINE_CALLBACK(rtc_wkup_isr, ISR_RTC_WKUP) 137 | DEFINE_CALLBACK(flash_isr, ISR_FLASH) 138 | DEFINE_CALLBACK(rcc_isr, ISR_RCC) 139 | DEFINE_CALLBACK(exti0_isr, ISR_EXTI0) 140 | DEFINE_CALLBACK(exti1_isr, ISR_EXTI1) 141 | DEFINE_CALLBACK(exti2_isr, ISR_EXTI2) 142 | DEFINE_CALLBACK(exti3_isr, ISR_EXTI3) 143 | DEFINE_CALLBACK(exti4_isr, ISR_EXTI4) 144 | DEFINE_CALLBACK(dma1_stream0_isr, ISR_DMA1_STREAM0) 145 | DEFINE_CALLBACK(dma1_stream1_isr, ISR_DMA1_STREAM1) 146 | DEFINE_CALLBACK(dma1_stream2_isr, ISR_DMA1_STREAM2) 147 | DEFINE_CALLBACK(dma1_stream3_isr, ISR_DMA1_STREAM3) 148 | DEFINE_CALLBACK(dma1_stream4_isr, ISR_DMA1_STREAM4) 149 | DEFINE_CALLBACK(dma1_stream5_isr, ISR_DMA1_STREAM5) 150 | DEFINE_CALLBACK(dma1_stream6_isr, ISR_DMA1_STREAM6) 151 | DEFINE_CALLBACK(adc_isr, ISR_ADC) 152 | DEFINE_CALLBACK(can1_tx_isr, ISR_CAN1_TX) 153 | DEFINE_CALLBACK(can1_rx0_isr, ISR_CAN1_RX0) 154 | DEFINE_CALLBACK(can1_rx1_isr, ISR_CAN1_RX1) 155 | DEFINE_CALLBACK(can1_sce_isr, ISR_CAN1_SCE) 156 | DEFINE_CALLBACK(exti9_5_isr, ISR_EXTI9_5) 157 | DEFINE_CALLBACK(tim1_brk_tim9_isr, ISR_TIM1_BRK_TIM9) 158 | DEFINE_CALLBACK(tim1_up_tim10_isr, ISR_TIM1_UP_TIM10) 159 | DEFINE_CALLBACK(tim1_trg_com_tim11_isr, ISR_TIM1_TRG_COM_TIM11) 160 | DEFINE_CALLBACK(tim1_cc_isr, ISR_TIM1_CC) 161 | DEFINE_CALLBACK(tim2_isr, ISR_TIM2) 162 | DEFINE_CALLBACK(tim3_isr, ISR_TIM3) 163 | DEFINE_CALLBACK(tim4_isr, ISR_TIM4) 164 | DEFINE_CALLBACK(i2c1_ev_isr, ISR_I2C1_EV) 165 | DEFINE_CALLBACK(i2c1_er_isr, ISR_I2C1_ER) 166 | DEFINE_CALLBACK(i2c2_ev_isr, ISR_I2C2_EV) 167 | DEFINE_CALLBACK(i2c2_er_isr, ISR_I2C2_ER) 168 | DEFINE_CALLBACK(spi1_isr, ISR_SPI1) 169 | DEFINE_CALLBACK(spi2_isr, ISR_SPI2) 170 | DEFINE_CALLBACK(usart1_isr, ISR_USART1) 171 | DEFINE_CALLBACK(usart2_isr, ISR_USART2) 172 | DEFINE_CALLBACK(usart3_isr, ISR_USART3) 173 | DEFINE_CALLBACK(exti15_10_isr, ISR_EXTI15_10) 174 | DEFINE_CALLBACK(rtc_alarm_isr, ISR_RTC_ALARM) 175 | DEFINE_CALLBACK(usb_fs_wkup_isr, ISR_USB_FS_WKUP) 176 | DEFINE_CALLBACK(tim8_brk_tim12_isr, ISR_TIM8_BRK_TIM12) 177 | DEFINE_CALLBACK(tim8_up_tim13_isr, ISR_TIM8_UP_TIM13) 178 | DEFINE_CALLBACK(tim8_trg_com_tim14_isr, ISR_TIM8_TRG_COM_TIM14) 179 | DEFINE_CALLBACK(tim8_cc_isr, ISR_TIM8_CC) 180 | DEFINE_CALLBACK(dma1_stream7_isr, ISR_DMA1_STREAM7) 181 | DEFINE_CALLBACK(fsmc_isr, ISR_FSMC) 182 | DEFINE_CALLBACK(sdio_isr, ISR_SDIO) 183 | DEFINE_CALLBACK(tim5_isr, ISR_TIM5) 184 | DEFINE_CALLBACK(spi3_isr, ISR_SPI3) 185 | DEFINE_CALLBACK(uart4_isr, ISR_UART4) 186 | DEFINE_CALLBACK(uart5_isr, ISR_UART5) 187 | DEFINE_CALLBACK(tim6_dac_isr, ISR_TIM6_DAC) 188 | DEFINE_CALLBACK(tim7_isr, ISR_TIM7) 189 | DEFINE_CALLBACK(dma2_stream0_isr, ISR_DMA2_STREAM0) 190 | DEFINE_CALLBACK(dma2_stream1_isr, ISR_DMA2_STREAM1) 191 | DEFINE_CALLBACK(dma2_stream2_isr, ISR_DMA2_STREAM2) 192 | DEFINE_CALLBACK(dma2_stream3_isr, ISR_DMA2_STREAM3) 193 | DEFINE_CALLBACK(dma2_stream4_isr, ISR_DMA2_STREAM4) 194 | DEFINE_CALLBACK(eth_isr, ISR_ETH) 195 | DEFINE_CALLBACK(eth_wkup_isr, ISR_ETH_WKUP) 196 | DEFINE_CALLBACK(can2_tx_isr, ISR_CAN2_TX) 197 | DEFINE_CALLBACK(can2_rx0_isr, ISR_CAN2_RX0) 198 | DEFINE_CALLBACK(can2_rx1_isr, ISR_CAN2_RX1) 199 | DEFINE_CALLBACK(can2_sce_isr, ISR_CAN2_SCE) 200 | DEFINE_CALLBACK(otg_fs_isr, ISR_OTG_FS) 201 | DEFINE_CALLBACK(dma2_stream5_isr, ISR_DMA2_STREAM5) 202 | DEFINE_CALLBACK(dma2_stream6_isr, ISR_DMA2_STREAM6) 203 | DEFINE_CALLBACK(dma2_stream7_isr, ISR_DMA2_STREAM7) 204 | DEFINE_CALLBACK(usart6_isr, ISR_USART6) 205 | DEFINE_CALLBACK(i2c3_ev_isr, ISR_I2C3_EV) 206 | DEFINE_CALLBACK(i2c3_er_isr, ISR_I2C3_ER) 207 | DEFINE_CALLBACK(otg_hs_ep1_out_isr, ISR_OTG_HS_EP1_OUT) 208 | DEFINE_CALLBACK(otg_hs_ep1_in_isr, ISR_OTG_HS_EP1_IN) 209 | DEFINE_CALLBACK(otg_hs_wkup_isr, ISR_OTG_HS_WKUP) 210 | DEFINE_CALLBACK(otg_hs_isr, ISR_OTG_HS) 211 | DEFINE_CALLBACK(dcmi_isr, ISR_DCMI) 212 | DEFINE_CALLBACK(cryp_isr, ISR_CRYP) 213 | DEFINE_CALLBACK(hash_rng_isr, ISR_HASH_RNG) 214 | DEFINE_CALLBACK(fpu_isr, ISR_FPU) 215 | DEFINE_CALLBACK(uart7_isr, ISR_UART7) 216 | DEFINE_CALLBACK(uart8_isr, ISR_UART8) 217 | DEFINE_CALLBACK(spi4_isr, ISR_SPI4) 218 | DEFINE_CALLBACK(spi5_isr, ISR_SPI5) 219 | DEFINE_CALLBACK(spi6_isr, ISR_SPI6) 220 | DEFINE_CALLBACK(sai1_isr, ISR_SAI1) 221 | DEFINE_CALLBACK(lcd_tft_isr, ISR_LCD_TFT) 222 | DEFINE_CALLBACK(lcd_tft_err_isr, ISR_LCD_TFT_ERR) 223 | DEFINE_CALLBACK(dma2d_isr, ISR_DMA2D) 224 | #endif 225 | 226 | END_DECLS 227 | 228 | #endif // CM3CPP_CUSTOM_INTERRUPT_SERVICE 229 | 230 | } // namespace cm3cpp 231 | -------------------------------------------------------------------------------- /cm3cpp/irq/irq.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef STM32F2 4 | #include 5 | #endif 6 | #ifdef STM32F4 7 | #include 8 | #endif 9 | 10 | namespace cm3cpp { 11 | 12 | #ifdef STM32F2 13 | enum class Interrupt : uint32_t 14 | { 15 | ISR_NVIC_WWDG = 0, 16 | ISR_PVD, 17 | ISR_TAMP_STAMP, 18 | ISR_RTC_WKUP, 19 | ISR_FLASH, 20 | ISR_RCC, 21 | ISR_EXTI0, 22 | ISR_EXTI1, 23 | ISR_EXTI2, 24 | ISR_EXTI3, 25 | ISR_EXTI4, 26 | ISR_DMA1_STREAM0, 27 | ISR_DMA1_STREAM1, 28 | ISR_DMA1_STREAM2, 29 | ISR_DMA1_STREAM3, 30 | ISR_DMA1_STREAM4, 31 | ISR_DMA1_STREAM5, 32 | ISR_DMA1_STREAM6, 33 | ISR_ADC, 34 | ISR_CAN1_TX, 35 | ISR_CAN1_RX0, 36 | ISR_CAN1_RX1, 37 | ISR_CAN1_SCE, 38 | ISR_EXTI9_5, 39 | ISR_TIM1_BRK_TIM9, 40 | ISR_TIM1_UP_TIM10, 41 | ISR_TIM1_TRG_COM_TIM11, 42 | ISR_TIM1_CC, 43 | ISR_TIM2, 44 | ISR_TIM3, 45 | ISR_TIM4, 46 | ISR_I2C1_EV, 47 | ISR_I2C1_ER, 48 | ISR_I2C2_EV, 49 | ISR_I2C2_ER, 50 | ISR_SPI1, 51 | ISR_SPI2, 52 | ISR_USART1, 53 | ISR_USART2, 54 | ISR_USART3, 55 | ISR_EXTI15_10, 56 | ISR_RTC_ALARM, 57 | ISR_USB_FS_WKUP, 58 | ISR_TIM8_BRK_TIM12, 59 | ISR_TIM8_UP_TIM13, 60 | ISR_TIM8_TRG_COM_TIM14, 61 | ISR_TIM8_CC, 62 | ISR_DMA1_STREAM7, 63 | ISR_FSMC, 64 | ISR_SDIO, 65 | ISR_TIM5, 66 | ISR_SPI3, 67 | ISR_UART4, 68 | ISR_UART5, 69 | ISR_TIM6_DAC, 70 | ISR_TIM7, 71 | ISR_DMA2_STREAM0, 72 | ISR_DMA2_STREAM1, 73 | ISR_DMA2_STREAM2, 74 | ISR_DMA2_STREAM3, 75 | ISR_DMA2_STREAM4, 76 | ISR_ETH, 77 | ISR_ETH_WKUP, 78 | ISR_CAN2_TX, 79 | ISR_CAN2_RX0, 80 | ISR_CAN2_RX1, 81 | ISR_CAN2_SCE, 82 | ISR_OTG_FS, 83 | ISR_DMA2_STREAM5, 84 | ISR_DMA2_STREAM6, 85 | ISR_DMA2_STREAM7, 86 | ISR_USART6, 87 | ISR_I2C3_EV, 88 | ISR_I2C3_ER, 89 | ISR_OTG_HS_EP1_OUT, 90 | ISR_OTG_HS_EP1_IN, 91 | ISR_OTG_HS_WKUP, 92 | ISR_OTG_HS, 93 | ISR_DCMI, 94 | ISR_CRYP, 95 | ISR_HASH_RNG, 96 | }; 97 | #endif 98 | 99 | #ifdef STM32F4 100 | enum Interrupt : uint32_t 101 | { 102 | ISR_NVIC_WWDG = 0, 103 | ISR_PVD, 104 | ISR_TAMP_STAMP, 105 | ISR_RTC_WKUP, 106 | ISR_FLASH, 107 | ISR_RCC, 108 | ISR_EXTI0, 109 | ISR_EXTI1, 110 | ISR_EXTI2, 111 | ISR_EXTI3, 112 | ISR_EXTI4, 113 | ISR_DMA1_STREAM0, 114 | ISR_DMA1_STREAM1, 115 | ISR_DMA1_STREAM2, 116 | ISR_DMA1_STREAM3, 117 | ISR_DMA1_STREAM4, 118 | ISR_DMA1_STREAM5, 119 | ISR_DMA1_STREAM6, 120 | ISR_ADC, 121 | ISR_CAN1_TX, 122 | ISR_CAN1_RX0, 123 | ISR_CAN1_RX1, 124 | ISR_CAN1_SCE, 125 | ISR_EXTI9_5, 126 | ISR_TIM1_BRK_TIM9, 127 | ISR_TIM1_UP_TIM10, 128 | ISR_TIM1_TRG_COM_TIM11, 129 | ISR_TIM1_CC, 130 | ISR_TIM2, 131 | ISR_TIM3, 132 | ISR_TIM4, 133 | ISR_I2C1_EV, 134 | ISR_I2C1_ER, 135 | ISR_I2C2_EV, 136 | ISR_I2C2_ER, 137 | ISR_SPI1, 138 | ISR_SPI2, 139 | ISR_USART1, 140 | ISR_USART2, 141 | ISR_USART3, 142 | ISR_EXTI15_10, 143 | ISR_RTC_ALARM, 144 | ISR_USB_FS_WKUP, 145 | ISR_TIM8_BRK_TIM12, 146 | ISR_TIM8_UP_TIM13, 147 | ISR_TIM8_TRG_COM_TIM14, 148 | ISR_TIM8_CC, 149 | ISR_DMA1_STREAM7, 150 | ISR_FSMC, 151 | ISR_SDIO, 152 | ISR_TIM5, 153 | ISR_SPI3, 154 | ISR_UART4, 155 | ISR_UART5, 156 | ISR_TIM6_DAC, 157 | ISR_TIM7, 158 | ISR_DMA2_STREAM0, 159 | ISR_DMA2_STREAM1, 160 | ISR_DMA2_STREAM2, 161 | ISR_DMA2_STREAM3, 162 | ISR_DMA2_STREAM4, 163 | ISR_ETH, 164 | ISR_ETH_WKUP, 165 | ISR_CAN2_TX, 166 | ISR_CAN2_RX0, 167 | ISR_CAN2_RX1, 168 | ISR_CAN2_SCE, 169 | ISR_OTG_FS, 170 | ISR_DMA2_STREAM5, 171 | ISR_DMA2_STREAM6, 172 | ISR_DMA2_STREAM7, 173 | ISR_USART6, 174 | ISR_I2C3_EV, 175 | ISR_I2C3_ER, 176 | ISR_OTG_HS_EP1_OUT, 177 | ISR_OTG_HS_EP1_IN, 178 | ISR_OTG_HS_WKUP, 179 | ISR_OTG_HS, 180 | ISR_DCMI, 181 | ISR_CRYP, 182 | ISR_HASH_RNG, 183 | ISR_FPU, 184 | ISR_UART7, 185 | ISR_UART8, 186 | ISR_SPI4, 187 | ISR_SPI5, 188 | ISR_SPI6, 189 | ISR_SAI1, 190 | ISR_LCD_TFT, 191 | ISR_LCD_TFT_ERR, 192 | ISR_DMA2D, 193 | }; 194 | #endif 195 | 196 | #ifndef CM3CPP_CUSTOM_INTERRUPT_SERVICE 197 | class IInterruptable 198 | { 199 | public: 200 | IInterruptable() = default; 201 | virtual ~IInterruptable() = default; 202 | 203 | static void register_isr(Interrupt interrupt, 204 | IInterruptable* interrupt_owner); 205 | virtual void call() = 0; 206 | }; 207 | #endif 208 | 209 | } /* namespace cm3cpp */ 210 | -------------------------------------------------------------------------------- /cm3cpp/private/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef CM3CPP_ASSERT_H_ 2 | #define CM3CPP_ASSERT_H_ 3 | 4 | #ifndef CM3CPP_ASSERT 5 | #define CM3CPP_ASSERT(x) \ 6 | if ((x)) { \ 7 | while (true) { \ 8 | asm("nop"); \ 9 | } \ 10 | } 11 | #endif 12 | 13 | #ifdef CM3CPP_ENABLE_IMPLISIT_DESTRUCTOR_CALLS 14 | #define CM3CPP_EXPLISIT_DESTRUCTOR(c) ~c() = default; 15 | #else 16 | #define CM3CPP_EXPLISIT_DESTRUCTOR(c) \ 17 | ~c() { CM3CPP_ASSERT(false); } 18 | #endif 19 | 20 | #endif /* CM3CPP_ASSERT_H_ */ 21 | -------------------------------------------------------------------------------- /cm3cpp/private/pinout.h: -------------------------------------------------------------------------------- 1 | #ifndef CM3CPP_PINOUT_H_ 2 | #define CM3CPP_PINOUT_H_ 3 | 4 | #define PINOUT_CTOR(port, pin) \ 5 | { \ 6 | static_cast<::cm3cpp::gpio::Gpio::Pinout::Port>(GPIO##port), \ 7 | GPIO##pin, pin, \ 8 | } 9 | 10 | #define PNULL \ 11 | { \ 12 | 0, 0, 0 \ 13 | } 14 | 15 | #define PA0 PINOUT_CTOR(A, 0) 16 | #define PA1 PINOUT_CTOR(A, 1) 17 | #define PA2 PINOUT_CTOR(A, 2) 18 | #define PA3 PINOUT_CTOR(A, 3) 19 | #define PA4 PINOUT_CTOR(A, 4) 20 | #define PA5 PINOUT_CTOR(A, 5) 21 | #define PA6 PINOUT_CTOR(A, 6) 22 | #define PA7 PINOUT_CTOR(A, 7) 23 | #define PA8 PINOUT_CTOR(A, 8) 24 | #define PA9 PINOUT_CTOR(A, 9) 25 | #define PA10 PINOUT_CTOR(A, 10) 26 | #define PA11 PINOUT_CTOR(A, 11) 27 | #define PA12 PINOUT_CTOR(A, 12) 28 | #define PA13 PINOUT_CTOR(A, 13) 29 | #define PA14 PINOUT_CTOR(A, 14) 30 | #define PA15 PINOUT_CTOR(A, 15) 31 | 32 | #define PB0 PINOUT_CTOR(B, 0) 33 | #define PB1 PINOUT_CTOR(B, 1) 34 | #define PB2 PINOUT_CTOR(B, 2) 35 | #define PB3 PINOUT_CTOR(B, 3) 36 | #define PB4 PINOUT_CTOR(B, 4) 37 | #define PB5 PINOUT_CTOR(B, 5) 38 | #define PB6 PINOUT_CTOR(B, 6) 39 | #define PB7 PINOUT_CTOR(B, 7) 40 | #define PB8 PINOUT_CTOR(B, 8) 41 | #define PB9 PINOUT_CTOR(B, 9) 42 | #define PB10 PINOUT_CTOR(B, 10) 43 | #define PB11 PINOUT_CTOR(B, 11) 44 | #define PB12 PINOUT_CTOR(B, 12) 45 | #define PB13 PINOUT_CTOR(B, 13) 46 | #define PB14 PINOUT_CTOR(B, 14) 47 | #define PB15 PINOUT_CTOR(B, 15) 48 | 49 | #define PC0 PINOUT_CTOR(C, 0) 50 | #define PC1 PINOUT_CTOR(C, 1) 51 | #define PC2 PINOUT_CTOR(C, 2) 52 | #define PC3 PINOUT_CTOR(C, 3) 53 | #define PC4 PINOUT_CTOR(C, 4) 54 | #define PC5 PINOUT_CTOR(C, 5) 55 | #define PC6 PINOUT_CTOR(C, 6) 56 | #define PC7 PINOUT_CTOR(C, 7) 57 | #define PC8 PINOUT_CTOR(C, 8) 58 | #define PC9 PINOUT_CTOR(C, 9) 59 | #define PC10 PINOUT_CTOR(C, 10) 60 | #define PC11 PINOUT_CTOR(C, 11) 61 | #define PC12 PINOUT_CTOR(C, 12) 62 | #define PC13 PINOUT_CTOR(C, 13) 63 | #define PC14 PINOUT_CTOR(C, 14) 64 | #define PC15 PINOUT_CTOR(C, 15) 65 | 66 | #define PD0 PINOUT_CTOR(D, 0) 67 | #define PD1 PINOUT_CTOR(D, 1) 68 | #define PD2 PINOUT_CTOR(D, 2) 69 | #define PD3 PINOUT_CTOR(D, 3) 70 | #define PD4 PINOUT_CTOR(D, 4) 71 | #define PD5 PINOUT_CTOR(D, 5) 72 | #define PD6 PINOUT_CTOR(D, 6) 73 | #define PD7 PINOUT_CTOR(D, 7) 74 | #define PD8 PINOUT_CTOR(D, 8) 75 | #define PD9 PINOUT_CTOR(D, 9) 76 | #define PD10 PINOUT_CTOR(D, 10) 77 | #define PD11 PINOUT_CTOR(D, 11) 78 | #define PD12 PINOUT_CTOR(D, 12) 79 | #define PD13 PINOUT_CTOR(D, 13) 80 | #define PD14 PINOUT_CTOR(D, 14) 81 | #define PD15 PINOUT_CTOR(D, 15) 82 | 83 | #define PE0 PINOUT_CTOR(E, 0) 84 | #define PE1 PINOUT_CTOR(E, 1) 85 | #define PE2 PINOUT_CTOR(E, 2) 86 | #define PE3 PINOUT_CTOR(E, 3) 87 | #define PE4 PINOUT_CTOR(E, 4) 88 | #define PE5 PINOUT_CTOR(E, 5) 89 | #define PE6 PINOUT_CTOR(E, 6) 90 | #define PE7 PINOUT_CTOR(E, 7) 91 | #define PE8 PINOUT_CTOR(E, 8) 92 | #define PE9 PINOUT_CTOR(E, 9) 93 | #define PE10 PINOUT_CTOR(E, 10) 94 | #define PE11 PINOUT_CTOR(E, 11) 95 | #define PE12 PINOUT_CTOR(E, 12) 96 | #define PE13 PINOUT_CTOR(E, 13) 97 | #define PE14 PINOUT_CTOR(E, 14) 98 | #define PE15 PINOUT_CTOR(E, 15) 99 | 100 | #define PF0 PINOUT_CTOR(F, 0) 101 | #define PF1 PINOUT_CTOR(F, 1) 102 | #define PF2 PINOUT_CTOR(F, 2) 103 | #define PF3 PINOUT_CTOR(F, 3) 104 | #define PF4 PINOUT_CTOR(F, 4) 105 | #define PF5 PINOUT_CTOR(F, 5) 106 | #define PF6 PINOUT_CTOR(F, 6) 107 | #define PF7 PINOUT_CTOR(F, 7) 108 | #define PF8 PINOUT_CTOR(F, 8) 109 | #define PF9 PINOUT_CTOR(F, 9) 110 | #define PF10 PINOUT_CTOR(F, 10) 111 | #define PF11 PINOUT_CTOR(F, 11) 112 | #define PF12 PINOUT_CTOR(F, 12) 113 | #define PF13 PINOUT_CTOR(F, 13) 114 | #define PF14 PINOUT_CTOR(F, 14) 115 | #define PF15 PINOUT_CTOR(F, 15) 116 | 117 | #define PG0 PINOUT_CTOR(G, 0) 118 | #define PG1 PINOUT_CTOR(G, 1) 119 | #define PG2 PINOUT_CTOR(G, 2) 120 | #define PG3 PINOUT_CTOR(G, 3) 121 | #define PG4 PINOUT_CTOR(G, 4) 122 | #define PG5 PINOUT_CTOR(G, 5) 123 | #define PG6 PINOUT_CTOR(G, 6) 124 | #define PG7 PINOUT_CTOR(G, 7) 125 | #define PG8 PINOUT_CTOR(G, 8) 126 | #define PG9 PINOUT_CTOR(G, 9) 127 | #define PG10 PINOUT_CTOR(G, 10) 128 | #define PG11 PINOUT_CTOR(G, 11) 129 | #define PG12 PINOUT_CTOR(G, 12) 130 | #define PG13 PINOUT_CTOR(G, 13) 131 | #define PG14 PINOUT_CTOR(G, 14) 132 | #define PG15 PINOUT_CTOR(G, 15) 133 | 134 | #define PH0 PINOUT_CTOR(H, 0) 135 | #define PH1 PINOUT_CTOR(H, 1) 136 | #define PH2 PINOUT_CTOR(H, 2) 137 | #define PH3 PINOUT_CTOR(H, 3) 138 | #define PH4 PINOUT_CTOR(H, 4) 139 | #define PH5 PINOUT_CTOR(H, 5) 140 | #define PH6 PINOUT_CTOR(H, 6) 141 | #define PH7 PINOUT_CTOR(H, 7) 142 | #define PH8 PINOUT_CTOR(H, 8) 143 | #define PH9 PINOUT_CTOR(H, 9) 144 | #define PH10 PINOUT_CTOR(H, 10) 145 | #define PH11 PINOUT_CTOR(H, 11) 146 | #define PH12 PINOUT_CTOR(H, 12) 147 | #define PH13 PINOUT_CTOR(H, 13) 148 | #define PH14 PINOUT_CTOR(H, 14) 149 | #define PH15 PINOUT_CTOR(H, 15) 150 | 151 | #define PI0 PINOUT_CTOR(I, 0) 152 | #define PI1 PINOUT_CTOR(I, 1) 153 | #define PI2 PINOUT_CTOR(I, 2) 154 | #define PI3 PINOUT_CTOR(I, 3) 155 | #define PI4 PINOUT_CTOR(I, 4) 156 | #define PI5 PINOUT_CTOR(I, 5) 157 | #define PI6 PINOUT_CTOR(I, 6) 158 | #define PI7 PINOUT_CTOR(I, 7) 159 | #define PI8 PINOUT_CTOR(I, 8) 160 | #define PI9 PINOUT_CTOR(I, 9) 161 | #define PI10 PINOUT_CTOR(I, 10) 162 | #define PI11 PINOUT_CTOR(I, 11) 163 | #define PI12 PINOUT_CTOR(I, 12) 164 | #define PI13 PINOUT_CTOR(I, 13) 165 | #define PI14 PINOUT_CTOR(I, 14) 166 | #define PI15 PINOUT_CTOR(I, 15) 167 | 168 | #endif /* CM3CPP_PINOUT_H_ */ 169 | -------------------------------------------------------------------------------- /cm3cpp/rs485.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | RS485 implementation, public interface 24 | */ 25 | 26 | #include "rs485.hpp" 27 | 28 | namespace cm3cpp { 29 | 30 | RS485::RS485(Struct rs485, 31 | Settings settings, 32 | utils::RoundBuffer rb_in_size, 33 | utils::RoundBuffer rb_out_size) : 34 | _de(rs485.de) 35 | { 36 | rb_in = new utils::RoundBuffer(rb_in_size); 37 | rb_out = new utils::RoundBuffer(rb_out_size); 38 | 39 | if (rs485.rx.pin) { 40 | Gpio rx(rs485.rx); 41 | rx.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 42 | rx.set_output_options(Gpio::OutputType::PUSH_PULL, 43 | Gpio::Speed::MEDIUM_25MHz); 44 | rx.set_af(Gpio::AltFuncNumber::AF7); 45 | } 46 | 47 | if (rs485.tx.pin) { 48 | Gpio tx(rs485.tx); 49 | tx.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 50 | tx.set_output_options(Gpio::OutputType::PUSH_PULL, 51 | Gpio::Speed::MEDIUM_25MHz); 52 | tx.set_af(Gpio::AltFuncNumber::AF7); 53 | } 54 | 55 | _de.mode_setup(Gpio::Mode::OUTPUT, Gpio::PullMode::NO_PULL); 56 | _de.set_output_options(Gpio::OutputType::PUSH_PULL, 57 | Gpio::Speed::MEDIUM_25MHz); 58 | _de.clear(); 59 | 60 | switch (rs485.number) { 61 | case 1: 62 | _rs485 = USART1; 63 | nvic_enable_irq(NVIC_USART1_IRQ); 64 | break; 65 | case 2: 66 | _rs485 = USART2; 67 | nvic_enable_irq(NVIC_USART2_IRQ); 68 | break; 69 | case 3: 70 | _rs485 = USART3; 71 | nvic_enable_irq(NVIC_USART3_IRQ); 72 | break; 73 | } 74 | 75 | usart_set_baudrate(_rs485, settings.baud_rate); 76 | usart_set_databits(_rs485, settings.word_length); 77 | usart_set_stopbits(_rs485, settings.stop_bits); 78 | usart_set_mode(_rs485, settings.mode); 79 | usart_set_parity(_rs485, settings.parity); 80 | usart_set_flow_control(_rs485, settings.flow_control); 81 | 82 | if (settings.mode & USART_MODE_RX) 83 | usart_enable_rx_interrupt(_rs485); 84 | 85 | usart_enable(_rs485); 86 | } 87 | 88 | } // namespace cm3cpp 89 | -------------------------------------------------------------------------------- /cm3cpp/rs485.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | RS485 implementation, public interface 24 | */ 25 | 26 | #ifndef RS_485_H 27 | #define RS_485_H 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #ifdef STM32F2 35 | #include 36 | #endif 37 | #ifdef STM32F4 38 | #include 39 | #endif 40 | 41 | #include "gpio.hpp" 42 | #include "private/assert.h" 43 | #include "utils/round_buffer.hpp" 44 | 45 | namespace cm3cpp { 46 | 47 | class RS485 48 | { 49 | public: 50 | using Gpio = gpio::Gpio; 51 | 52 | struct Settings 53 | { 54 | uint32_t baud_rate; 55 | uint16_t word_length; 56 | uint16_t stop_bits; 57 | uint16_t parity; 58 | uint16_t mode; 59 | uint16_t flow_control; 60 | }; 61 | 62 | struct Struct 63 | { 64 | uint32_t number; 65 | Gpio::Pinout tx; 66 | Gpio::Pinout rx; 67 | Gpio::Pinout de; 68 | }; 69 | 70 | utils::RoundBuffer* rb_in; 71 | utils::RoundBuffer* rb_out; 72 | 73 | RS485(Struct rs485, 74 | Settings settings, 75 | utils::RoundBuffer rb_in_size, 76 | utils::RoundBuffer rb_out_size); 77 | 78 | CM3CPP_EXPLISIT_DESTRUCTOR(RS485) 79 | 80 | void usart_enable_tc_interrupt() { USART_CR1(_rs485) |= USART_CR1_TCIE; } 81 | 82 | void usart_disable_tc_interrupt() 83 | { 84 | USART_CR1(_rs485) &= ~static_cast(USART_CR1_TCIE); 85 | } 86 | 87 | bool interrupt_source_RXNE() 88 | { 89 | return (((USART_CR1(_rs485) & USART_CR1_RXNEIE) != 0) && 90 | usart_get_flag(_rs485, USART_SR_RXNE)); 91 | } 92 | 93 | bool interrupt_source_TXE() 94 | { 95 | return (((USART_CR1(_rs485) & USART_CR1_TXEIE) != 0) && 96 | usart_get_flag(_rs485, USART_SR_TXE)); 97 | } 98 | 99 | bool interrupt_source_TC() 100 | { 101 | return (((USART_CR1(_rs485) & USART_CR1_TCIE) != 0) && 102 | usart_get_flag(_rs485, USART_SR_TC)); 103 | } 104 | 105 | void start_send() 106 | { 107 | _de.set(); 108 | usart_enable_tx_interrupt(_rs485); 109 | } 110 | 111 | void receive_handler() 112 | { 113 | if (interrupt_source_RXNE()) { 114 | using byte_t = uint8_t; 115 | 116 | const uint16_t byte16 = usart_recv(_rs485); 117 | assert(byte16 < std::numeric_limits::max()); 118 | 119 | rb_in->push(static_cast(byte16)); 120 | } 121 | } 122 | 123 | void transmit_handler() 124 | { 125 | if (interrupt_source_TXE()) { 126 | if (rb_out->get_count()) { 127 | usart_send(_rs485, rb_out->pop()); 128 | } 129 | else { 130 | usart_disable_tx_interrupt(_rs485); 131 | usart_enable_tc_interrupt(); 132 | } 133 | } 134 | if (interrupt_source_TC()) { 135 | _de.clear(); 136 | usart_disable_tc_interrupt(); 137 | } 138 | } 139 | 140 | void inirq() 141 | { 142 | receive_handler(); 143 | transmit_handler(); 144 | } 145 | 146 | private: 147 | uint32_t _rs485; 148 | gpio::Gpio _de; 149 | }; 150 | 151 | } // namespace cm3cpp 152 | #endif 153 | -------------------------------------------------------------------------------- /cm3cpp/spi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * Written by Maxim Ambrosevich 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | */ 22 | 23 | /* 24 | SPI C++ Wrapper of libopencm3 library for STM32F2, STM32F4 25 | */ 26 | 27 | #include "spi.hpp" 28 | 29 | namespace cm3cpp { 30 | 31 | namespace spi { 32 | 33 | Spi::Spi(Config spi_conf) 34 | { 35 | switch (spi_conf.spi_number) { 36 | case 1: 37 | _spi = SPI1; 38 | _irq = Interrupt::ISR_SPI1; 39 | break; 40 | case 2: 41 | _spi = SPI2; 42 | _irq = Interrupt::ISR_SPI2; 43 | break; 44 | case 3: 45 | _spi = SPI3; 46 | _irq = Interrupt::ISR_SPI3; 47 | break; 48 | default: 49 | break; 50 | } 51 | 52 | Gpio mosi(spi_conf.mosi_pin); 53 | mosi.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 54 | mosi.set_output_options(Gpio::OutputType::PUSH_PULL, 55 | Gpio::Speed::HIGH_SPEED_100MHz); 56 | 57 | Gpio miso(spi_conf.miso_pin); 58 | miso.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 59 | miso.set_output_options(Gpio::OutputType::PUSH_PULL, 60 | Gpio::Speed::HIGH_SPEED_100MHz); 61 | 62 | Gpio scl(spi_conf.scl_pin); 63 | scl.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 64 | scl.set_output_options(Gpio::OutputType::PUSH_PULL, 65 | Gpio::Speed::HIGH_SPEED_100MHz); 66 | 67 | switch (_spi) { 68 | case SPI1: 69 | case SPI2: 70 | mosi.set_af(Gpio::AltFuncNumber::AF5); 71 | miso.set_af(Gpio::AltFuncNumber::AF5); 72 | scl.set_af(Gpio::AltFuncNumber::AF5); 73 | break; 74 | 75 | case SPI3: 76 | mosi.set_af(Gpio::AltFuncNumber::AF6); 77 | miso.set_af(Gpio::AltFuncNumber::AF6); 78 | scl.set_af(Gpio::AltFuncNumber::AF6); 79 | break; 80 | 81 | default: 82 | break; 83 | } 84 | } 85 | 86 | void Spi::set_next_tx_from(NextTx next) 87 | { 88 | switch (next) { 89 | case NEXT_TX_FROM_BUFFER: 90 | spi_set_next_tx_from_buffer(_spi); 91 | break; 92 | case NEXT_TX_FROM_CRC: 93 | spi_set_next_tx_from_crc(_spi); 94 | break; 95 | } 96 | } 97 | 98 | void Spi::set_data_drame_format(DataFrameFormat dff) 99 | { 100 | switch (dff) { 101 | case DFF_8BIT: 102 | spi_set_dff_8bit(_spi); 103 | break; 104 | case DFF_16BIT: 105 | spi_set_dff_16bit(_spi); 106 | break; 107 | } 108 | } 109 | 110 | void Spi::set_software_slave_management(State state) 111 | { 112 | switch (state) { 113 | case DISABLE: 114 | spi_disable_software_slave_management(_spi); 115 | break; 116 | case ENABLE: 117 | spi_enable_software_slave_management(_spi); 118 | break; 119 | } 120 | } 121 | 122 | void Spi::set_nss(NssState nss) 123 | { 124 | switch (nss) { 125 | case LOW: 126 | spi_set_nss_low(_spi); 127 | break; 128 | case HIGH: 129 | spi_set_nss_high(_spi); 130 | break; 131 | } 132 | } 133 | 134 | void Spi::set_bit_position(BitPos pos) 135 | { 136 | switch (pos) { 137 | case MSB_FIRST: 138 | spi_send_msb_first(_spi); 139 | break; 140 | case LSB_FIRST: 141 | spi_send_lsb_first(_spi); 142 | break; 143 | } 144 | } 145 | 146 | void Spi::set_clock_polarity(Polarity polarity) 147 | { 148 | switch (polarity) { 149 | case POLARITY_LOW: 150 | spi_set_clock_polarity_0(_spi); 151 | break; 152 | case POLARITY_HIGH: 153 | spi_set_clock_polarity_1(_spi); 154 | break; 155 | } 156 | } 157 | 158 | void Spi::set_clock_phase(Phase phase) 159 | { 160 | switch (phase) { 161 | case PHASE_LOW: 162 | spi_set_clock_phase_0(_spi); 163 | break; 164 | case PHASE_HIGH: 165 | spi_set_clock_phase_1(_spi); 166 | break; 167 | } 168 | } 169 | 170 | bool Spi::get_flag_status(Flag flag) const 171 | { 172 | const uint32_t reg_sr = SPI_SR(_spi); 173 | const uint32_t flag_state = reg_sr & static_cast(flag); 174 | 175 | return flag == static_cast(flag_state); 176 | } 177 | 178 | inline void Spi::enable_nvic() 179 | { 180 | nvic_enable_irq(static_cast(_irq)); 181 | } 182 | 183 | } // namespace spi 184 | 185 | } // namespace cm3cpp 186 | -------------------------------------------------------------------------------- /cm3cpp/spi.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * Written by Maxim Ambrosevich 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | */ 22 | 23 | /* 24 | SPI C++ Wrapper of libopencm3 library for STM32F2, STM32F4 25 | */ 26 | 27 | #ifndef SPI_EXT_H 28 | #define SPI_EXT_H 29 | 30 | #include 31 | 32 | #include "gpio.hpp" 33 | #include "irq/irq.hpp" 34 | 35 | namespace cm3cpp { 36 | 37 | namespace spi { 38 | 39 | constexpr bool OK = true; 40 | constexpr bool ERROR = false; 41 | 42 | enum Flag : uint32_t 43 | { 44 | RECEIVE_BUFFER_NOT_EMPTY = 0x0001, 45 | TRANSMIT_BUFFER_EMPTY = 0x0002, 46 | CHANEL_SIDE = 0x0004, 47 | UNDERRUN_FLAG = 0x0008, 48 | CRC_ERROR = 0x0010, 49 | MODE_FAULT = 0x0020, 50 | OVERRUN_FLAG = 0x0040, 51 | BUSY_FLAG = 0x0080, 52 | TI_FRAME_FORMAT_ERROR = 0x0100, 53 | }; 54 | 55 | enum BaudRate : uint8_t 56 | { 57 | BAUDRATE_FPCLK_DIV_2 = 0x00, 58 | BAUDRATE_FPCLK_DIV_4 = 0x01, 59 | BAUDRATE_FPCLK_DIV_8 = 0x02, 60 | BAUDRATE_FPCLK_DIV_16 = 0x03, 61 | BAUDRATE_FPCLK_DIV_32 = 0x04, 62 | BAUDRATE_FPCLK_DIV_64 = 0x05, 63 | BAUDRATE_FPCLK_DIV_128 = 0x06, 64 | BAUDRATE_FPCLK_DIV_256 = 0x07, 65 | }; 66 | 67 | enum NextTx 68 | { 69 | NEXT_TX_FROM_BUFFER, 70 | NEXT_TX_FROM_CRC 71 | }; 72 | 73 | enum DataFrameFormat 74 | { 75 | DFF_8BIT, 76 | DFF_16BIT 77 | }; 78 | 79 | enum State 80 | { 81 | DISABLE, 82 | ENABLE 83 | }; 84 | 85 | enum NssState 86 | { 87 | LOW, 88 | HIGH 89 | }; 90 | 91 | enum Polarity 92 | { 93 | POLARITY_LOW, 94 | POLARITY_HIGH 95 | }; 96 | 97 | enum Phase 98 | { 99 | PHASE_LOW, 100 | PHASE_HIGH 101 | }; 102 | 103 | enum BitPos 104 | { 105 | MSB_FIRST, 106 | LSB_FIRST 107 | }; 108 | 109 | enum StdMode 110 | { 111 | MODE_0 = 0, 112 | MODE_1, 113 | MODE_2, 114 | MODE_3 115 | }; 116 | 117 | class Spi 118 | { 119 | public: 120 | using Gpio = gpio::Gpio; 121 | 122 | struct Config 123 | { 124 | uint8_t spi_number; 125 | Gpio::Pinout mosi_pin; 126 | Gpio::Pinout miso_pin; 127 | Gpio::Pinout scl_pin; 128 | Gpio::Pinout ss_pin; 129 | }; 130 | 131 | Spi(); 132 | Spi(Config spi_conf); 133 | 134 | bool get_flag_status(Flag flag) const; 135 | 136 | void reset() { spi_reset(_spi); } 137 | 138 | void enable() { spi_enable(_spi); } 139 | 140 | void disable() { spi_disable(_spi); } 141 | 142 | void clean_disable() { spi_clean_disable(_spi); } 143 | 144 | void write(uint16_t data) 145 | { 146 | while (!get_flag_status(Flag::TRANSMIT_BUFFER_EMPTY)) 147 | ; 148 | SPI_DR(_spi) = data; 149 | } 150 | 151 | void write_end() 152 | { 153 | while (!get_flag_status(Flag::RECEIVE_BUFFER_NOT_EMPTY)) 154 | ; 155 | (void)SPI_DR(_spi); 156 | } 157 | 158 | uint16_t read(uint16_t data) 159 | { 160 | while (!get_flag_status(Flag::TRANSMIT_BUFFER_EMPTY)) { 161 | __asm__("nop"); 162 | } 163 | 164 | SPI_DR(_spi) = data; 165 | 166 | while (!get_flag_status(Flag::RECEIVE_BUFFER_NOT_EMPTY)) { 167 | __asm__("nop"); 168 | } 169 | 170 | return static_cast(SPI_DR(_spi)); 171 | } 172 | 173 | void set_master_mode() { spi_set_master_mode(_spi); } 174 | 175 | void set_slave_mode() { spi_set_slave_mode(_spi); } 176 | 177 | void full_duplex_mode() { spi_set_full_duplex_mode(_spi); } 178 | 179 | void set_bidirectional_mode() { spi_set_bidirectional_mode(_spi); } 180 | 181 | void set_bidirectional_transmit_only_mode() 182 | { 183 | spi_set_bidirectional_transmit_only_mode(_spi); 184 | } 185 | 186 | void set_bidirectional_receive_only_mode() 187 | { 188 | spi_set_bidirectional_receive_only_mode(_spi); 189 | } 190 | 191 | void set_unidirectional_mode() { spi_set_unidirectional_mode(_spi); } 192 | 193 | void set_receive_only_mode() { spi_set_receive_only_mode(_spi); } 194 | 195 | void enable_crc() { spi_enable_crc(_spi); } 196 | 197 | void disable_crc() { spi_disable_crc(_spi); } 198 | 199 | void set_next_tx_from(NextTx next); 200 | void set_data_drame_format(DataFrameFormat dff); 201 | void set_software_slave_management(State state); 202 | void set_nss(NssState nss); 203 | void set_bit_position(BitPos pos); 204 | 205 | void set_baudrate_prescaler(BaudRate baudrate) 206 | { 207 | spi_set_baudrate_prescaler(_spi, (uint8_t)baudrate); 208 | } 209 | 210 | void set_clock_polarity(Polarity polarity); 211 | void set_clock_phase(Phase phase); 212 | 213 | void enable_nvic(); 214 | 215 | void enable_tx_buffer_empty_interrupt() 216 | { 217 | spi_enable_tx_buffer_empty_interrupt(_spi); 218 | } 219 | 220 | void disable_tx_buffer_empty_interrupt() 221 | { 222 | spi_disable_tx_buffer_empty_interrupt(_spi); 223 | } 224 | 225 | void enable_rx_buffer_not_empty_interrupt() 226 | { 227 | spi_enable_rx_buffer_not_empty_interrupt(_spi); 228 | } 229 | 230 | void disable_rx_buffer_not_empty_interrupt() 231 | { 232 | spi_disable_rx_buffer_not_empty_interrupt(_spi); 233 | } 234 | 235 | void enable_error_interrupt() { spi_enable_error_interrupt(_spi); } 236 | 237 | void disable_error_interrupt() { spi_disable_error_interrupt(_spi); } 238 | 239 | void enable_ss_output() { spi_enable_ss_output(_spi); } 240 | 241 | void disable_ss_output() { spi_disable_ss_output(_spi); } 242 | 243 | void enable_tx_dma() { spi_enable_tx_dma(_spi); } 244 | 245 | void disable_tx_dma() { spi_disable_tx_dma(_spi); } 246 | 247 | void enable_rx_dma() { spi_enable_rx_dma(_spi); } 248 | 249 | void disable_rx_dma() { spi_disable_rx_dma(_spi); } 250 | 251 | void set_standard_mode(StdMode mode) { spi_set_standard_mode(_spi, mode); } 252 | 253 | private: 254 | uint32_t _spi; 255 | Interrupt _irq; 256 | }; 257 | 258 | } // namespace spi 259 | 260 | } // namespace cm3cpp 261 | 262 | #endif 263 | -------------------------------------------------------------------------------- /cm3cpp/systick.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | SYSTICK implementation, public interface 24 | */ 25 | 26 | #include "systick.hpp" 27 | 28 | #ifndef CM3CPP_CUSTOM_SYSTICK 29 | static volatile uint32_t counter; 30 | 31 | void sys_tick_handler(void) 32 | { 33 | counter++; 34 | } 35 | #endif 36 | 37 | void delay_nop(uint32_t count) 38 | { 39 | while (count--) { 40 | __asm("nop"); 41 | } 42 | } 43 | 44 | namespace cm3cpp { 45 | 46 | namespace systick { 47 | 48 | #ifndef CM3CPP_CUSTOM_SYSTICK 49 | void delay_systick(uint32_t ms) 50 | { 51 | uint32_t time = get_counter(); 52 | while ((get_counter() - time) < ms) { 53 | __asm("nop"); 54 | } 55 | } 56 | #endif // CM3CPP_CUSTOM_SYSTICK 57 | 58 | void init(uint32_t system_core_freq, uint32_t clock_div) 59 | { 60 | #ifndef CM3CPP_CUSTOM_SYSTICK 61 | counter = 0; 62 | #endif 63 | systick_set_reload(system_core_freq / clock_div); 64 | systick_set_clocksource(STK_CSR_CLKSOURCE_AHB); 65 | systick_counter_enable(); 66 | systick_interrupt_enable(); 67 | } 68 | 69 | void deinit() 70 | { 71 | systick_interrupt_disable(); 72 | systick_counter_disable(); 73 | } 74 | 75 | #ifndef CM3CPP_CUSTOM_SYSTICK 76 | uint32_t get_counter() 77 | { 78 | return counter; 79 | } 80 | 81 | Counter::Counter(Mode mode, uint32_t period) 82 | { 83 | init(mode, period); 84 | } 85 | 86 | void Counter::init(Mode mode, uint32_t period) 87 | { 88 | _mode = mode; 89 | _saved = get_counter(); 90 | _period = period; 91 | 92 | switch (_mode) { 93 | case CYCLE: 94 | _is_active = true; 95 | break; 96 | case ONE_SHOT: 97 | _is_active = false; 98 | break; 99 | } 100 | } 101 | 102 | bool Counter::timeout() 103 | { 104 | if (_is_active && ((get_counter() - _saved) >= _period)) { 105 | switch (_mode) { 106 | case CYCLE: 107 | _saved = get_counter(); 108 | return true; 109 | case ONE_SHOT: 110 | return true; 111 | } 112 | } 113 | 114 | return false; 115 | } 116 | 117 | bool Counter::start() 118 | { 119 | if (_mode == CYCLE) 120 | return false; 121 | _saved = get_counter(); 122 | _is_active = true; 123 | return true; 124 | } 125 | 126 | bool Counter::stop() 127 | { 128 | if (_mode == CYCLE) 129 | return false; 130 | _is_active = false; 131 | return true; 132 | } 133 | 134 | bool Counter::is_active() const 135 | { 136 | return _is_active; 137 | } 138 | 139 | #endif // CM3CPP_CUSTOM_SYSTICK 140 | } // namespace systick 141 | 142 | 143 | } // namespace cm3cpp 144 | -------------------------------------------------------------------------------- /cm3cpp/systick.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | SYSTICK implementation, public interface 24 | */ 25 | 26 | #ifndef SYSTICK_API_H 27 | #define SYSTICK_API_H 28 | 29 | #include 30 | #include 31 | 32 | #ifndef CM3CPP_CUSTOM_SYSTICK 33 | extern "C" void sys_tick_handler(void); 34 | #endif 35 | 36 | extern "C" void delay_nop(uint32_t count); 37 | 38 | namespace cm3cpp { 39 | 40 | namespace systick { 41 | 42 | void init(uint32_t system_core_freq, uint32_t div = 1000); 43 | void deinit(); 44 | 45 | #ifndef CM3CPP_CUSTOM_SYSTICK 46 | 47 | uint32_t get_counter(); 48 | void delay_systick(uint32_t ms); 49 | 50 | class Counter 51 | { 52 | public: 53 | enum Mode 54 | { 55 | CYCLE, 56 | ONE_SHOT 57 | }; 58 | 59 | Counter(Mode mode, uint32_t period); 60 | void init(Mode mode, uint32_t period); 61 | bool timeout(); 62 | bool start(); 63 | bool stop(); 64 | bool is_active() const; 65 | 66 | void set_period(uint32_t const period) { _period = period; } 67 | uint32_t period() const { return _period; } 68 | 69 | private: 70 | uint32_t _saved; 71 | uint32_t _period; 72 | Mode _mode; 73 | bool _is_active; 74 | }; 75 | 76 | #endif // CM3CPP_CUSTOM_SYSTICK 77 | 78 | } // namespace systick 79 | 80 | } // namespace cm3cpp 81 | #endif 82 | -------------------------------------------------------------------------------- /cm3cpp/timer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | TIM C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #include "timer.hpp" 27 | 28 | namespace cm3cpp { 29 | 30 | namespace tim { 31 | 32 | /** Helper for make explicit opencm3 defined constants conversions */ 33 | template 34 | constexpr uint32_t to_u32(T t) 35 | { 36 | return static_cast(t); 37 | } 38 | 39 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 40 | auto Timer::enable_counter() -> Result 41 | { 42 | TIM_CR1(_timer) |= to_u32(TIM_CR1_CEN); 43 | return OK; 44 | } 45 | 46 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 47 | auto Timer::disable_counter() -> Result 48 | { 49 | TIM_CR1(_timer) &= ~to_u32(TIM_CR1_CEN); 50 | return OK; 51 | } 52 | 53 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 54 | auto Timer::enable_update_event_generation() -> Result 55 | { 56 | TIM_CR1(_timer) &= ~to_u32(TIM_CR1_UDIS); 57 | return OK; 58 | } 59 | 60 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 61 | auto Timer::disable_update_event_generation() -> Result 62 | { 63 | TIM_CR1(_timer) |= to_u32(TIM_CR1_UDIS); 64 | return OK; 65 | } 66 | 67 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 68 | auto Timer::set_update_event_source(UevSource source) -> Result 69 | { 70 | switch (source) { 71 | case COUNTER_OVERFLOW_AND_UG: 72 | TIM_CR1(_timer) &= ~to_u32(TIM_CR1_URS); 73 | break; 74 | case COUNTER_OVERFLOW: 75 | TIM_CR1(_timer) |= TIM_CR1_URS; 76 | break; 77 | } 78 | 79 | return OK; 80 | } 81 | 82 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 83 | auto Timer::set_counter_mode(CounterMode mode) -> Result 84 | { 85 | switch (mode) { 86 | case ONE_SHOT: 87 | TIM_CR1(_timer) |= TIM_CR1_OPM; 88 | break; 89 | case CONTINUOUS: 90 | TIM_CR1(_timer) &= ~to_u32(TIM_CR1_OPM); 91 | break; 92 | } 93 | 94 | return OK; 95 | } 96 | 97 | // 1,2,3,4,5,8 98 | auto Timer::set_counter_direction(CounterDirection dir) -> Result 99 | { 100 | if ((_timer != TIM1) && (_timer != TIM2) && (_timer != TIM3) && 101 | (_timer != TIM4) && (_timer != TIM5) && (_timer != TIM8)) { 102 | return NOT_SUPPORTED; 103 | } 104 | 105 | switch (dir) { 106 | case UP: 107 | TIM_CR1(_timer) &= ~to_u32(TIM_CR1_DIR_DOWN); 108 | break; 109 | case DOWN: 110 | TIM_CR1(_timer) |= TIM_CR1_DIR_DOWN; 111 | break; 112 | } 113 | 114 | return OK; 115 | } 116 | 117 | // 1,2,3,4,5,8 118 | auto Timer::set_alignment(Alignment alignment) -> Result 119 | { 120 | if ((_timer != TIM1) && (_timer != TIM2) && (_timer != TIM3) && 121 | (_timer != TIM4) && (_timer != TIM5) && (_timer != TIM8)) { 122 | return NOT_SUPPORTED; 123 | } 124 | 125 | bool counter_enable = TIM_CR1(_timer) & TIM_CR1_CEN; 126 | const auto cms_clear_mask = TIM_CR1(_timer) & ~to_u32(TIM_CR1_CMS_MASK); 127 | 128 | switch (alignment) { 129 | case EDGE: 130 | TIM_CR1(_timer) = cms_clear_mask | TIM_CR1_CMS_EDGE; 131 | return OK; 132 | case CENTER_DOWN: 133 | if (counter_enable) { 134 | return USAGE_ERROR; 135 | } 136 | TIM_CR1(_timer) = cms_clear_mask | TIM_CR1_CMS_CENTER_1; 137 | return OK; 138 | case CENTER_UP: 139 | if (counter_enable) { 140 | return USAGE_ERROR; 141 | } 142 | TIM_CR1(_timer) = cms_clear_mask | TIM_CR1_CMS_CENTER_2; 143 | return OK; 144 | case CENTER_UP_DOWN: 145 | if (counter_enable) { 146 | return USAGE_ERROR; 147 | } 148 | TIM_CR1(_timer) = cms_clear_mask | TIM_CR1_CMS_CENTER_3; 149 | return OK; 150 | } 151 | 152 | return NOT_SUPPORTED; 153 | } 154 | 155 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 156 | auto Timer::enable_autoreload_preload() -> Result 157 | { 158 | TIM_CR1(_timer) |= TIM_CR1_ARPE; 159 | return OK; 160 | } 161 | 162 | // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 163 | auto Timer::disable_autoreload_preload() -> Result 164 | { 165 | TIM_CR1(_timer) &= ~to_u32(TIM_CR1_ARPE); 166 | return OK; 167 | } 168 | 169 | // 1,2,3,4,5,8,9,10,11,12,13,14 170 | auto Timer::set_clock_division(ClockDivision div) -> Result 171 | { 172 | if ((_timer == TIM6) || (_timer == TIM7)) { 173 | return USAGE_ERROR; 174 | } 175 | 176 | const auto ckd_ck_int_clear_mask = 177 | TIM_CR1(_timer) & ~to_u32(TIM_CR1_CKD_CK_INT_MASK); 178 | 179 | switch (div) { 180 | case TIMER_CLOCK_MUL_1: 181 | TIM_CR1(_timer) = ckd_ck_int_clear_mask | TIM_CR1_CKD_CK_INT; 182 | break; 183 | case TIMER_CLOCK_MUL_2: 184 | TIM_CR1(_timer) = ckd_ck_int_clear_mask | TIM_CR1_CKD_CK_INT_MUL_2; 185 | break; 186 | case TIMER_CLOCK_MUL_4: 187 | TIM_CR1(_timer) = ckd_ck_int_clear_mask | TIM_CR1_CKD_CK_INT_MUL_4; 188 | break; 189 | } 190 | 191 | return OK; 192 | } 193 | 194 | // 9,12 195 | auto Timer::set_master_mode(MasterMode mode) -> Result 196 | { 197 | const auto mms_clear_mask = TIM_CR2(_timer) & ~to_u32(TIM_CR2_MMS_MASK); 198 | 199 | switch (mode) { 200 | case MASTER_RESET: 201 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_RESET; 202 | break; 203 | case ENABLE: 204 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_ENABLE; 205 | break; 206 | case UPDATE: 207 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_UPDATE; 208 | break; 209 | case COMPARE_PULSE: 210 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_COMPARE_PULSE; 211 | break; 212 | case COMPARE_OC1REF: 213 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_COMPARE_OC1REF; 214 | break; 215 | case COMPARE_OC2REF: 216 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_COMPARE_OC2REF; 217 | break; 218 | case COMPARE_OC3REF: 219 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_COMPARE_OC3REF; 220 | break; 221 | case COMPARE_OC4REF: 222 | TIM_CR2(_timer) = mms_clear_mask | TIM_CR2_MMS_COMPARE_OC4REF; 223 | break; 224 | } 225 | 226 | return OK; 227 | } 228 | 229 | // 9,12 230 | auto Timer::set_slave_mode(SlaveMode mode) -> Result 231 | { 232 | const auto clear_sms_mask = TIM_SMCR(_timer) & ~to_u32(TIM_SMCR_SMS_MASK); 233 | 234 | switch (mode) { 235 | case DISABLED: 236 | TIM_SMCR(_timer) = clear_sms_mask | TIM_SMCR_SMS_OFF; 237 | break; 238 | case SLAVE_RESET: 239 | TIM_SMCR(_timer) = clear_sms_mask | TIM_SMCR_SMS_RM; 240 | break; 241 | case GATED: 242 | if (TIM_SMCR(_timer) & TIM_SMCR_TS_TI1F_ED) { 243 | return USAGE_ERROR; 244 | } 245 | TIM_SMCR(_timer) = clear_sms_mask | TIM_SMCR_SMS_GM; 246 | break; 247 | case TRIGGER: 248 | TIM_SMCR(_timer) = clear_sms_mask | TIM_SMCR_SMS_TM; 249 | break; 250 | case EXTERNAL_CLOCK: 251 | TIM_SMCR(_timer) = clear_sms_mask | TIM_SMCR_SMS_ECM1; 252 | break; 253 | } 254 | 255 | return OK; 256 | } 257 | 258 | // 9,12 259 | auto Timer::set_trigger(Trigger trigger) -> Result 260 | { 261 | const auto clear_ts_mask = TIM_SMCR(_timer) & ~to_u32(TIM_SMCR_TS_MASK); 262 | 263 | switch (trigger) { 264 | case INTERNAL_TRIGGER_0: 265 | TIM_SMCR(_timer) = clear_ts_mask | TIM_SMCR_TS_ITR0; 266 | break; 267 | case INTERNAL_TRIGGER_1: 268 | TIM_SMCR(_timer) = clear_ts_mask | TIM_SMCR_TS_ITR1; 269 | break; 270 | case INTERNAL_TRIGGER_2: 271 | TIM_SMCR(_timer) = clear_ts_mask | TIM_SMCR_TS_ITR2; 272 | break; 273 | case INTERNAL_TRIGGER_3: 274 | TIM_SMCR(_timer) = clear_ts_mask | TIM_SMCR_TS_ITR3; 275 | break; 276 | case EDGE_DETECTOR: 277 | TIM_SMCR(_timer) = clear_ts_mask | TIM_SMCR_TS_TI1F_ED; 278 | break; 279 | case FILTERED_TIMER_INPUT_1: 280 | TIM_SMCR(_timer) = clear_ts_mask | TIM_SMCR_TS_TI1FP1; 281 | break; 282 | case FILTERED_TIMER_INPUT_2: 283 | TIM_SMCR(_timer) = clear_ts_mask | TIM_SMCR_TS_TI2FP2; 284 | break; 285 | } 286 | 287 | return OK; 288 | } 289 | 290 | // 9,12 291 | auto Timer::enable_master_slave_mode() -> Result 292 | { 293 | TIM_SMCR(_timer) |= TIM_SMCR_MSM; 294 | return OK; 295 | } 296 | 297 | // 9,12 298 | auto Timer::disable_master_slave_mode() -> Result 299 | { 300 | TIM_SMCR(_timer) &= ~to_u32(TIM_SMCR_MSM); 301 | return OK; 302 | } 303 | 304 | // 9,12 305 | auto Timer::enable_update_interrupt() -> Result 306 | { 307 | TIM_DIER(_timer) |= TIM_DIER_UIE; 308 | return OK; 309 | } 310 | 311 | // 9,12 312 | auto Timer::disable_update_interrupt() -> Result 313 | { 314 | TIM_DIER(_timer) &= ~to_u32(TIM_DIER_UIE); 315 | return OK; 316 | } 317 | 318 | // 9,12 319 | auto Timer::enable_capture_compare_1_interrupt() -> Result 320 | { 321 | TIM_DIER(_timer) |= TIM_DIER_CC1IE; 322 | return OK; 323 | } 324 | 325 | // 9,12 326 | auto Timer::disable_capture_compare_1_interrupt() -> Result 327 | { 328 | TIM_DIER(_timer) &= ~to_u32(TIM_DIER_CC1IE); 329 | return OK; 330 | } 331 | 332 | // 9,12 333 | auto Timer::enable_capture_compare_2_interrupt() -> Result 334 | { 335 | TIM_DIER(_timer) |= TIM_DIER_CC2IE; 336 | return OK; 337 | } 338 | 339 | // 9,12 340 | auto Timer::disable_capture_compare_2_interrupt() -> Result 341 | { 342 | TIM_DIER(_timer) &= ~to_u32(TIM_DIER_CC2IE); 343 | return OK; 344 | } 345 | 346 | auto Timer::enable_capture_compare_3_interrupt() -> Result 347 | { 348 | TIM_DIER(_timer) |= TIM_DIER_CC3IE; 349 | return OK; 350 | } 351 | 352 | // 9,12 353 | auto Timer::disable_capture_compare_3_interrupt() -> Result 354 | { 355 | TIM_DIER(_timer) &= ~to_u32(TIM_DIER_CC3IE); 356 | return OK; 357 | } 358 | 359 | // 9,12 360 | auto Timer::enable_capture_compare_4_interrupt() -> Result 361 | { 362 | TIM_DIER(_timer) |= TIM_DIER_CC4IE; 363 | return OK; 364 | } 365 | 366 | // 9,12 367 | auto Timer::disable_capture_compare_4_interrupt() -> Result 368 | { 369 | TIM_DIER(_timer) &= ~to_u32(TIM_DIER_CC4IE); 370 | return OK; 371 | } 372 | 373 | // 9,12 374 | auto Timer::enable_trigger_interrupt() -> Result 375 | { 376 | TIM_DIER(_timer) |= TIM_DIER_TIE; 377 | return OK; 378 | } 379 | 380 | // 9,12 381 | auto Timer::disable_trigger_interrupt() -> Result 382 | { 383 | TIM_DIER(_timer) &= ~to_u32(TIM_DIER_TIE); 384 | return OK; 385 | } 386 | 387 | // 9,12 388 | bool Timer::get_flag_status(Flag flag) const 389 | { 390 | bool status = false; 391 | 392 | switch (flag) { 393 | case UPDATE_INTERRUPT: 394 | status = TIM_SR(_timer) & TIM_SR_UIF; 395 | break; 396 | case CAPTURE_COMPARE_1_INTERRUPT: 397 | status = TIM_SR(_timer) & TIM_SR_CC1IF; 398 | break; 399 | case CAPTURE_COMPARE_2_INTERRUPT: 400 | status = TIM_SR(_timer) & TIM_SR_CC2IF; 401 | break; 402 | case CAPTURE_COMPARE_3_INTERRUPT: 403 | status = TIM_SR(_timer) & TIM_SR_CC3IF; 404 | break; 405 | case CAPTURE_COMPARE_4_INTERRUPT: 406 | status = TIM_SR(_timer) & TIM_SR_CC4IF; 407 | break; 408 | case TRIGGER_INTERRUPT: 409 | status = TIM_SR(_timer) & TIM_SR_TIF; 410 | break; 411 | case CAPTURE_COMPARE_1_OVERCAPTURE: 412 | status = TIM_SR(_timer) & TIM_SR_CC1OF; 413 | break; 414 | case CAPTURE_COMPARE_2_OVERCAPTURE: 415 | status = TIM_SR(_timer) & TIM_SR_CC2OF; 416 | break; 417 | case CAPTURE_COMPARE_3_OVERCAPTURE: 418 | status = TIM_SR(_timer) & TIM_SR_CC3OF; 419 | break; 420 | case CAPTURE_COMPARE_4_OVERCAPTURE: 421 | status = TIM_SR(_timer) & TIM_SR_CC4OF; 422 | break; 423 | } 424 | 425 | return status; 426 | } 427 | 428 | // 9,12 429 | auto Timer::clear_flag_status(Flag flag) -> Result 430 | { 431 | switch (flag) { 432 | case UPDATE_INTERRUPT: 433 | TIM_SR(_timer) &= ~to_u32(TIM_SR_UIF); 434 | break; 435 | case CAPTURE_COMPARE_1_INTERRUPT: 436 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC1IF); 437 | break; 438 | case CAPTURE_COMPARE_2_INTERRUPT: 439 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC2IF); 440 | break; 441 | case CAPTURE_COMPARE_3_INTERRUPT: 442 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC3IF); 443 | break; 444 | case CAPTURE_COMPARE_4_INTERRUPT: 445 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC4IF); 446 | break; 447 | case TRIGGER_INTERRUPT: 448 | TIM_SR(_timer) &= ~to_u32(TIM_SR_TIF); 449 | break; 450 | case CAPTURE_COMPARE_1_OVERCAPTURE: 451 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC1OF); 452 | break; 453 | case CAPTURE_COMPARE_2_OVERCAPTURE: 454 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC2OF); 455 | break; 456 | case CAPTURE_COMPARE_3_OVERCAPTURE: 457 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC3OF); 458 | break; 459 | case CAPTURE_COMPARE_4_OVERCAPTURE: 460 | TIM_SR(_timer) &= ~to_u32(TIM_SR_CC4OF); 461 | break; 462 | } 463 | 464 | return OK; 465 | } 466 | 467 | void Timer::update_generation() 468 | { 469 | TIM_EGR(_timer) |= TIM_EGR_UG; 470 | } 471 | 472 | // 9,12 473 | auto Timer::set_capture_compare_1_mode(CcMode mode) -> Result 474 | { 475 | bool channel_on = TIM_CCER(_timer) & TIM_CCER_CC1E; 476 | 477 | if (channel_on) { 478 | return USAGE_ERROR; 479 | } 480 | 481 | const uint32_t cc1s_clear_mask = 482 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_CC1S_MASK); 483 | 484 | switch (mode) { 485 | case OUTPUT: 486 | TIM_CCMR1(_timer) = cc1s_clear_mask | TIM_CCMR1_CC1S_OUT; 487 | break; 488 | case INPUT_MAPPED_TI1: 489 | TIM_CCMR1(_timer) = cc1s_clear_mask | TIM_CCMR1_CC1S_IN_TI1; 490 | break; 491 | case INPUT_MAPPED_TI2: 492 | TIM_CCMR1(_timer) = cc1s_clear_mask | TIM_CCMR1_CC1S_IN_TI2; 493 | break; 494 | case INPUT_MAPPED_TRC: 495 | TIM_CCMR1(_timer) = cc1s_clear_mask | TIM_CCMR1_CC1S_IN_TRC; 496 | break; 497 | 498 | default: 499 | break; 500 | } 501 | 502 | return OK; 503 | } 504 | 505 | // 9,12 506 | auto Timer::set_capture_compare_2_mode(CcMode mode) -> Result 507 | { 508 | bool channel_on = TIM_CCER(_timer) & TIM_CCER_CC2E; 509 | 510 | if (channel_on) { 511 | return USAGE_ERROR; 512 | } 513 | 514 | const uint32_t cc2s_clear_mask = 515 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_CC2S_MASK); 516 | 517 | switch (mode) { 518 | case OUTPUT: 519 | TIM_CCMR1(_timer) = cc2s_clear_mask | TIM_CCMR1_CC2S_OUT; 520 | break; 521 | case INPUT_MAPPED_TI1: 522 | TIM_CCMR1(_timer) = cc2s_clear_mask | TIM_CCMR1_CC2S_IN_TI1; 523 | break; 524 | case INPUT_MAPPED_TI2: 525 | TIM_CCMR1(_timer) = cc2s_clear_mask | TIM_CCMR1_CC2S_IN_TI2; 526 | break; 527 | case INPUT_MAPPED_TRC: 528 | TIM_CCMR1(_timer) = cc2s_clear_mask | TIM_CCMR1_CC2S_IN_TRC; 529 | break; 530 | 531 | default: 532 | break; 533 | } 534 | 535 | return OK; 536 | } 537 | 538 | // 9,12 539 | auto Timer::set_input_capture_1_prescaler(Prescaler prescaler) -> Result 540 | { 541 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC1S_MASK; 542 | 543 | if (!channel_is_input) { 544 | return USAGE_ERROR; 545 | } 546 | 547 | const uint32_t ic1psc_clear_mask = 548 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_IC1PSC_MASK); 549 | 550 | switch (prescaler) { 551 | case NO_PRESCALER: 552 | TIM_CCMR1(_timer) = ic1psc_clear_mask | TIM_CCMR1_IC1PSC_OFF; 553 | break; 554 | case CAPTURE_EVERY_2_EVENTS: 555 | TIM_CCMR1(_timer) = ic1psc_clear_mask | TIM_CCMR1_IC1PSC_2; 556 | break; 557 | case CAPTURE_EVERY_4_EVENTS: 558 | TIM_CCMR1(_timer) = ic1psc_clear_mask | TIM_CCMR1_IC1PSC_4; 559 | break; 560 | case CAPTURE_EVERY_8_EVENTS: 561 | TIM_CCMR1(_timer) = ic1psc_clear_mask | TIM_CCMR1_IC1PSC_8; 562 | break; 563 | } 564 | 565 | return OK; 566 | } 567 | 568 | // 9,12 569 | auto Timer::set_input_capture_2_prescaler(Prescaler prescaler) -> Result 570 | { 571 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC2S_MASK; 572 | 573 | if (!channel_is_input) { 574 | return USAGE_ERROR; 575 | } 576 | 577 | const uint32_t ic2psc_clear_mask = 578 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_IC2PSC_MASK); 579 | 580 | switch (prescaler) { 581 | case NO_PRESCALER: 582 | TIM_CCMR1(_timer) = ic2psc_clear_mask | TIM_CCMR1_IC2PSC_OFF; 583 | break; 584 | case CAPTURE_EVERY_2_EVENTS: 585 | TIM_CCMR1(_timer) = ic2psc_clear_mask | TIM_CCMR1_IC2PSC_2; 586 | break; 587 | case CAPTURE_EVERY_4_EVENTS: 588 | TIM_CCMR1(_timer) = ic2psc_clear_mask | TIM_CCMR1_IC2PSC_4; 589 | break; 590 | case CAPTURE_EVERY_8_EVENTS: 591 | TIM_CCMR1(_timer) = ic2psc_clear_mask | TIM_CCMR1_IC2PSC_8; 592 | break; 593 | } 594 | 595 | return OK; 596 | } 597 | 598 | // 9,12 599 | auto Timer::set_input_capture_1_filter(Filter filter) -> Result 600 | { 601 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC1S_MASK; 602 | 603 | if (!channel_is_input) { 604 | return USAGE_ERROR; 605 | } 606 | 607 | const uint32_t ic1f_clear_mask = 608 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_IC1F_MASK); 609 | 610 | switch (filter) { 611 | case NO_FILTER: 612 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_OFF; 613 | break; 614 | case CK_INT_N_2: 615 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_CK_INT_N_2; 616 | break; 617 | case CK_INT_N_4: 618 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_CK_INT_N_4; 619 | break; 620 | case CK_INT_N_8: 621 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_CK_INT_N_8; 622 | break; 623 | case DTF_DIV_2_N_6: 624 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_2_N_6; 625 | break; 626 | case DTF_DIV_2_N_8: 627 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_2_N_8; 628 | break; 629 | case TF_DIV_4_N_6: 630 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_4_N_6; 631 | break; 632 | case DTF_DIV_4_N_8: 633 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_4_N_8; 634 | break; 635 | case DTF_DIV_8_N_6: 636 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_8_N_6; 637 | break; 638 | case DTF_DIV_8_N_8: 639 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_8_N_8; 640 | break; 641 | case DTF_DIV_16_N_5: 642 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_16_N_5; 643 | break; 644 | case DTF_DIV_16_N_6: 645 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_16_N_6; 646 | break; 647 | case DTF_DIV_16_N_8: 648 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_16_N_8; 649 | break; 650 | case DTF_DIV_32_N_5: 651 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_32_N_5; 652 | break; 653 | case DTF_DIV_32_N_6: 654 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_32_N_6; 655 | break; 656 | case DTF_DIV_32_N_8: 657 | TIM_CCMR1(_timer) = ic1f_clear_mask | TIM_CCMR1_IC1F_DTF_DIV_32_N_8; 658 | break; 659 | } 660 | 661 | return OK; 662 | } 663 | 664 | // 9,12 665 | auto Timer::set_input_capture_2_filter(Filter filter) -> Result 666 | { 667 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC2S_MASK; 668 | 669 | if (!channel_is_input) { 670 | return USAGE_ERROR; 671 | } 672 | 673 | const uint32_t ic2f_clear_mask = 674 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_IC2F_MASK); 675 | 676 | switch (filter) { 677 | case NO_FILTER: 678 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_OFF; 679 | break; 680 | case CK_INT_N_2: 681 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_CK_INT_N_2; 682 | break; 683 | case CK_INT_N_4: 684 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_CK_INT_N_4; 685 | break; 686 | case CK_INT_N_8: 687 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_CK_INT_N_8; 688 | break; 689 | case DTF_DIV_2_N_6: 690 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_2_N_6; 691 | break; 692 | case DTF_DIV_2_N_8: 693 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_2_N_8; 694 | break; 695 | case TF_DIV_4_N_6: 696 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_4_N_6; 697 | break; 698 | case DTF_DIV_4_N_8: 699 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_4_N_8; 700 | break; 701 | case DTF_DIV_8_N_6: 702 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_8_N_6; 703 | break; 704 | case DTF_DIV_8_N_8: 705 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_8_N_8; 706 | break; 707 | case DTF_DIV_16_N_5: 708 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_16_N_5; 709 | break; 710 | case DTF_DIV_16_N_6: 711 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_16_N_6; 712 | break; 713 | case DTF_DIV_16_N_8: 714 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_16_N_8; 715 | break; 716 | case DTF_DIV_32_N_5: 717 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_32_N_5; 718 | break; 719 | case DTF_DIV_32_N_6: 720 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_32_N_6; 721 | break; 722 | case DTF_DIV_32_N_8: 723 | TIM_CCMR1(_timer) = ic2f_clear_mask | TIM_CCMR1_IC2F_DTF_DIV_32_N_8; 724 | break; 725 | } 726 | 727 | return OK; 728 | } 729 | 730 | // 9,12 731 | auto Timer::enable_fast_output_compare_1() -> Result 732 | { 733 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC1S_MASK; 734 | 735 | if (channel_is_input) { 736 | return USAGE_ERROR; 737 | } 738 | 739 | TIM_CCMR1(_timer) |= TIM_CCMR1_OC1FE; 740 | return OK; 741 | } 742 | 743 | // 9,12 744 | auto Timer::disable_fast_output_compare_1() -> Result 745 | { 746 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC1S_MASK; 747 | 748 | if (channel_is_input) { 749 | return USAGE_ERROR; 750 | } 751 | 752 | TIM_CCMR1(_timer) &= ~to_u32(TIM_CCMR1_OC1FE); 753 | return OK; 754 | } 755 | 756 | // 9,12 757 | auto Timer::enable_fast_output_compare_2() -> Result 758 | { 759 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC2S_MASK; 760 | 761 | if (channel_is_input) { 762 | return USAGE_ERROR; 763 | } 764 | 765 | TIM_CCMR1(_timer) |= TIM_CCMR1_OC2FE; 766 | return OK; 767 | } 768 | 769 | // 9,12 770 | auto Timer::disable_fast_output_compare_2() -> Result 771 | { 772 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC2S_MASK; 773 | 774 | if (channel_is_input) { 775 | return USAGE_ERROR; 776 | } 777 | 778 | TIM_CCMR1(_timer) &= ~to_u32(TIM_CCMR1_OC2FE); 779 | return OK; 780 | } 781 | 782 | // 9,12 783 | auto Timer::enable_output_compare_1_preload() -> Result 784 | { 785 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC1S_MASK; 786 | 787 | if (channel_is_input) { 788 | return USAGE_ERROR; 789 | } 790 | 791 | TIM_CCMR1(_timer) |= TIM_CCMR1_OC1PE; 792 | return OK; 793 | } 794 | 795 | // 9,12 796 | auto Timer::disable_output_compare_1_preload() -> Result 797 | { 798 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC1S_MASK; 799 | 800 | if (channel_is_input) { 801 | return USAGE_ERROR; 802 | } 803 | 804 | TIM_CCMR1(_timer) &= ~to_u32(TIM_CCMR1_OC1PE); 805 | return OK; 806 | } 807 | 808 | // 9,12 809 | auto Timer::enable_output_compare_2_preload() -> Result 810 | { 811 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC2S_MASK; 812 | 813 | if (channel_is_input) { 814 | return USAGE_ERROR; 815 | } 816 | 817 | TIM_CCMR1(_timer) |= TIM_CCMR1_OC2PE; 818 | 819 | return OK; 820 | } 821 | 822 | // 9,12 823 | auto Timer::disable_output_compare_2_preload() -> Result 824 | { 825 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC2S_MASK; 826 | 827 | if (channel_is_input) { 828 | return USAGE_ERROR; 829 | } 830 | 831 | TIM_CCMR1(_timer) &= ~to_u32(TIM_CCMR1_OC2PE); 832 | return OK; 833 | } 834 | 835 | // 9,12 836 | auto Timer::set_output_compare_1_mode(OcMode mode) -> Result 837 | { 838 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC1S_MASK; 839 | 840 | if (channel_is_input) { 841 | return USAGE_ERROR; 842 | } 843 | 844 | const uint32_t oc1m_clear_mask = 845 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_OC1M_MASK); 846 | 847 | switch (mode) { 848 | case FROZEN: 849 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_FROZEN; 850 | break; 851 | case ACTIVE_LEVEL_ON_MATCH: 852 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_ACTIVE; 853 | break; 854 | case INACTIVE_LEVEL_ON_MATCH: 855 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_INACTIVE; 856 | break; 857 | case TOGGLE: 858 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_TOGGLE; 859 | break; 860 | case FORCE_INACTIVE_LEVEL: 861 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_FORCE_LOW; 862 | break; 863 | case FORCE_ACTIVE_LEVEL: 864 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_FORCE_HIGH; 865 | break; 866 | case PWM_MODE_1: 867 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_PWM1; 868 | break; 869 | case PWM_MODE_2: 870 | TIM_CCMR1(_timer) = oc1m_clear_mask | TIM_CCMR1_OC1M_PWM2; 871 | break; 872 | } 873 | 874 | return OK; 875 | } 876 | 877 | // 9,12 878 | auto Timer::set_output_compare_2_mode(OcMode mode) -> Result 879 | { 880 | bool channel_is_input = TIM_CCMR1(_timer) & TIM_CCMR1_CC2S_MASK; 881 | 882 | if (channel_is_input) { 883 | return USAGE_ERROR; 884 | } 885 | 886 | const uint32_t oc2m_clear_mask = 887 | TIM_CCMR1(_timer) & ~to_u32(TIM_CCMR1_OC2M_MASK); 888 | 889 | switch (mode) { 890 | case FROZEN: 891 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_FROZEN; 892 | break; 893 | case ACTIVE_LEVEL_ON_MATCH: 894 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_ACTIVE; 895 | break; 896 | case INACTIVE_LEVEL_ON_MATCH: 897 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_INACTIVE; 898 | break; 899 | case TOGGLE: 900 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_TOGGLE; 901 | break; 902 | case FORCE_INACTIVE_LEVEL: 903 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_FORCE_LOW; 904 | break; 905 | case FORCE_ACTIVE_LEVEL: 906 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_FORCE_HIGH; 907 | break; 908 | case PWM_MODE_1: 909 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_PWM1; 910 | break; 911 | case PWM_MODE_2: 912 | TIM_CCMR1(_timer) = oc2m_clear_mask | TIM_CCMR1_OC2M_PWM2; 913 | break; 914 | } 915 | 916 | return OK; 917 | } 918 | 919 | // 9,12 920 | auto Timer::set_capture_compare_3_mode(CcMode mode) -> Result 921 | { 922 | bool channel_on = TIM_CCER(_timer) & TIM_CCER_CC3E; 923 | 924 | if (channel_on) { 925 | return USAGE_ERROR; 926 | } 927 | 928 | const uint32_t oc3s_clear_mask = 929 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_CC3S_MASK); 930 | 931 | switch (mode) { 932 | case OUTPUT: 933 | TIM_CCMR2(_timer) = oc3s_clear_mask | TIM_CCMR2_CC3S_OUT; 934 | break; 935 | case INPUT_MAPPED_TI3: 936 | TIM_CCMR2(_timer) = oc3s_clear_mask | TIM_CCMR2_CC3S_IN_TI3; 937 | break; 938 | case INPUT_MAPPED_TI4: 939 | TIM_CCMR2(_timer) = oc3s_clear_mask | TIM_CCMR2_CC3S_IN_TI4; 940 | break; 941 | case INPUT_MAPPED_TRC: 942 | TIM_CCMR2(_timer) = oc3s_clear_mask | TIM_CCMR2_CC3S_IN_TRC; 943 | break; 944 | 945 | case INPUT_MAPPED_TI1: 946 | case INPUT_MAPPED_TI2: 947 | break; 948 | } 949 | 950 | return OK; 951 | } 952 | 953 | // 9,12 954 | auto Timer::set_capture_compare_4_mode(CcMode mode) -> Result 955 | { 956 | bool channel_on = TIM_CCER(_timer) & TIM_CCER_CC4E; 957 | 958 | if (channel_on) { 959 | return USAGE_ERROR; 960 | } 961 | 962 | const uint32_t oc4s_clear_mask = 963 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_CC4S_MASK); 964 | 965 | switch (mode) { 966 | case OUTPUT: 967 | TIM_CCMR2(_timer) = oc4s_clear_mask | TIM_CCMR2_CC4S_OUT; 968 | break; 969 | case INPUT_MAPPED_TI3: 970 | TIM_CCMR2(_timer) = oc4s_clear_mask | TIM_CCMR2_CC4S_IN_TI3; 971 | break; 972 | case INPUT_MAPPED_TI4: 973 | TIM_CCMR2(_timer) = oc4s_clear_mask | TIM_CCMR2_CC4S_IN_TI4; 974 | break; 975 | case INPUT_MAPPED_TRC: 976 | TIM_CCMR2(_timer) = oc4s_clear_mask | TIM_CCMR2_CC4S_IN_TRC; 977 | break; 978 | 979 | case INPUT_MAPPED_TI1: 980 | case INPUT_MAPPED_TI2: 981 | break; 982 | } 983 | 984 | return OK; 985 | } 986 | 987 | // 9,12 988 | auto Timer::set_input_capture_3_prescaler(Prescaler prescaler) -> Result 989 | { 990 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC3S_MASK; 991 | 992 | if (!channel_is_input) { 993 | return USAGE_ERROR; 994 | } 995 | 996 | const uint32_t ic3psc_clear_mask = 997 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_IC3PSC_MASK); 998 | 999 | switch (prescaler) { 1000 | case NO_PRESCALER: 1001 | TIM_CCMR2(_timer) = ic3psc_clear_mask | TIM_CCMR2_IC3PSC_OFF; 1002 | break; 1003 | case CAPTURE_EVERY_2_EVENTS: 1004 | TIM_CCMR2(_timer) = ic3psc_clear_mask | TIM_CCMR2_IC3PSC_2; 1005 | break; 1006 | case CAPTURE_EVERY_4_EVENTS: 1007 | TIM_CCMR2(_timer) = ic3psc_clear_mask | TIM_CCMR2_IC3PSC_4; 1008 | break; 1009 | case CAPTURE_EVERY_8_EVENTS: 1010 | TIM_CCMR2(_timer) = ic3psc_clear_mask | TIM_CCMR2_IC3PSC_8; 1011 | break; 1012 | } 1013 | 1014 | return OK; 1015 | } 1016 | 1017 | // 9,12 1018 | auto Timer::set_input_capture_4_prescaler(Prescaler prescaler) -> Result 1019 | { 1020 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC4S_MASK; 1021 | 1022 | if (!channel_is_input) { 1023 | return USAGE_ERROR; 1024 | } 1025 | 1026 | const uint32_t ic4psc_clear_mask = 1027 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_IC4PSC_MASK); 1028 | 1029 | switch (prescaler) { 1030 | case NO_PRESCALER: 1031 | TIM_CCMR2(_timer) = ic4psc_clear_mask | TIM_CCMR2_IC4PSC_OFF; 1032 | break; 1033 | case CAPTURE_EVERY_2_EVENTS: 1034 | TIM_CCMR2(_timer) = ic4psc_clear_mask | TIM_CCMR2_IC4PSC_2; 1035 | break; 1036 | case CAPTURE_EVERY_4_EVENTS: 1037 | TIM_CCMR2(_timer) = ic4psc_clear_mask | TIM_CCMR2_IC4PSC_4; 1038 | break; 1039 | case CAPTURE_EVERY_8_EVENTS: 1040 | TIM_CCMR2(_timer) = ic4psc_clear_mask | TIM_CCMR2_IC4PSC_8; 1041 | break; 1042 | } 1043 | 1044 | return OK; 1045 | } 1046 | 1047 | // 9,12 1048 | auto Timer::set_input_capture_3_filter(Filter filter) -> Result 1049 | { 1050 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC3S_MASK; 1051 | 1052 | if (!channel_is_input) { 1053 | return USAGE_ERROR; 1054 | } 1055 | 1056 | const uint32_t ic3f_clear_mask = 1057 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_IC3F_MASK); 1058 | 1059 | switch (filter) { 1060 | case NO_FILTER: 1061 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_OFF; 1062 | break; 1063 | case CK_INT_N_2: 1064 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_CK_INT_N_2; 1065 | break; 1066 | case CK_INT_N_4: 1067 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_CK_INT_N_4; 1068 | break; 1069 | case CK_INT_N_8: 1070 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_CK_INT_N_8; 1071 | break; 1072 | case DTF_DIV_2_N_6: 1073 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_2_N_6; 1074 | break; 1075 | case DTF_DIV_2_N_8: 1076 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_2_N_8; 1077 | break; 1078 | case TF_DIV_4_N_6: 1079 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_4_N_6; 1080 | break; 1081 | case DTF_DIV_4_N_8: 1082 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_4_N_8; 1083 | break; 1084 | case DTF_DIV_8_N_6: 1085 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_8_N_6; 1086 | break; 1087 | case DTF_DIV_8_N_8: 1088 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_8_N_8; 1089 | break; 1090 | case DTF_DIV_16_N_5: 1091 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_16_N_5; 1092 | break; 1093 | case DTF_DIV_16_N_6: 1094 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_16_N_6; 1095 | break; 1096 | case DTF_DIV_16_N_8: 1097 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_16_N_8; 1098 | break; 1099 | case DTF_DIV_32_N_5: 1100 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_32_N_5; 1101 | break; 1102 | case DTF_DIV_32_N_6: 1103 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_32_N_6; 1104 | break; 1105 | case DTF_DIV_32_N_8: 1106 | TIM_CCMR2(_timer) = ic3f_clear_mask | TIM_CCMR2_IC3F_DTF_DIV_32_N_8; 1107 | break; 1108 | } 1109 | 1110 | return OK; 1111 | } 1112 | 1113 | // 9,12 1114 | auto Timer::set_input_capture_4_filter(Filter filter) -> Result 1115 | { 1116 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC4S_MASK; 1117 | 1118 | if (!channel_is_input) { 1119 | return USAGE_ERROR; 1120 | } 1121 | 1122 | const uint32_t ic4f_clear_mask = 1123 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_IC4F_MASK); 1124 | 1125 | switch (filter) { 1126 | case NO_FILTER: 1127 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_OFF; 1128 | break; 1129 | case CK_INT_N_2: 1130 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_CK_INT_N_2; 1131 | break; 1132 | case CK_INT_N_4: 1133 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_CK_INT_N_4; 1134 | break; 1135 | case CK_INT_N_8: 1136 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_CK_INT_N_8; 1137 | break; 1138 | case DTF_DIV_2_N_6: 1139 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_2_N_6; 1140 | break; 1141 | case DTF_DIV_2_N_8: 1142 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_2_N_8; 1143 | break; 1144 | case TF_DIV_4_N_6: 1145 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_4_N_6; 1146 | break; 1147 | case DTF_DIV_4_N_8: 1148 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_4_N_8; 1149 | break; 1150 | case DTF_DIV_8_N_6: 1151 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_8_N_6; 1152 | break; 1153 | case DTF_DIV_8_N_8: 1154 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_8_N_8; 1155 | break; 1156 | case DTF_DIV_16_N_5: 1157 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_16_N_5; 1158 | break; 1159 | case DTF_DIV_16_N_6: 1160 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_16_N_6; 1161 | break; 1162 | case DTF_DIV_16_N_8: 1163 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_16_N_8; 1164 | break; 1165 | case DTF_DIV_32_N_5: 1166 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_32_N_5; 1167 | break; 1168 | case DTF_DIV_32_N_6: 1169 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_32_N_6; 1170 | break; 1171 | case DTF_DIV_32_N_8: 1172 | TIM_CCMR2(_timer) = ic4f_clear_mask | TIM_CCMR2_IC4F_DTF_DIV_32_N_8; 1173 | break; 1174 | } 1175 | 1176 | return OK; 1177 | } 1178 | 1179 | // 9,12 1180 | auto Timer::enable_fast_output_compare_3() -> Result 1181 | { 1182 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC3S_MASK; 1183 | 1184 | if (channel_is_input) { 1185 | return USAGE_ERROR; 1186 | } 1187 | 1188 | TIM_CCMR2(_timer) |= TIM_CCMR2_OC3FE; 1189 | return OK; 1190 | } 1191 | // 9,12 1192 | auto Timer::disable_fast_output_compare_3() -> Result 1193 | { 1194 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC3S_MASK; 1195 | 1196 | if (channel_is_input) { 1197 | return USAGE_ERROR; 1198 | } 1199 | 1200 | TIM_CCMR2(_timer) &= ~to_u32(TIM_CCMR2_OC3FE); 1201 | return OK; 1202 | } 1203 | 1204 | // 9,12 1205 | auto Timer::enable_fast_output_compare_4() -> Result 1206 | { 1207 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC4S_MASK; 1208 | 1209 | if (channel_is_input) { 1210 | return USAGE_ERROR; 1211 | } 1212 | 1213 | TIM_CCMR2(_timer) |= TIM_CCMR2_OC4FE; 1214 | return OK; 1215 | } 1216 | 1217 | // 9,12 1218 | auto Timer::disable_fast_output_compare_4() -> Result 1219 | { 1220 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC4S_MASK; 1221 | 1222 | if (channel_is_input) { 1223 | return USAGE_ERROR; 1224 | } 1225 | 1226 | TIM_CCMR2(_timer) &= ~to_u32(TIM_CCMR2_OC4FE); 1227 | return OK; 1228 | } 1229 | 1230 | // 9,12 1231 | auto Timer::enable_output_compare_3_preload() -> Result 1232 | { 1233 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC3S_MASK; 1234 | 1235 | if (channel_is_input) { 1236 | return USAGE_ERROR; 1237 | } 1238 | 1239 | TIM_CCMR2(_timer) |= TIM_CCMR2_OC3PE; 1240 | return OK; 1241 | } 1242 | 1243 | // 9,12 1244 | auto Timer::disable_output_compare_3_preload() -> Result 1245 | { 1246 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC3S_MASK; 1247 | 1248 | if (channel_is_input) { 1249 | return USAGE_ERROR; 1250 | } 1251 | 1252 | TIM_CCMR2(_timer) &= ~to_u32(TIM_CCMR2_OC3PE); 1253 | return OK; 1254 | } 1255 | 1256 | // 9,12 1257 | auto Timer::enable_output_compare_4_preload() -> Result 1258 | { 1259 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC4S_MASK; 1260 | 1261 | if (channel_is_input) { 1262 | return USAGE_ERROR; 1263 | } 1264 | 1265 | TIM_CCMR2(_timer) |= TIM_CCMR2_OC4PE; 1266 | return OK; 1267 | } 1268 | 1269 | // 9,12 1270 | auto Timer::disable_output_compare_4_preload() -> Result 1271 | { 1272 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC4S_MASK; 1273 | 1274 | if (channel_is_input) { 1275 | return USAGE_ERROR; 1276 | } 1277 | 1278 | TIM_CCMR2(_timer) &= ~to_u32(TIM_CCMR2_OC4PE); 1279 | return OK; 1280 | } 1281 | 1282 | // 9,12 1283 | auto Timer::set_output_compare_3_mode(OcMode mode) -> Result 1284 | { 1285 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC3S_MASK; 1286 | 1287 | if (channel_is_input) { 1288 | return USAGE_ERROR; 1289 | } 1290 | 1291 | const uint32_t oc3m_clear_mask = 1292 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_OC3M_FROZEN); 1293 | 1294 | switch (mode) { 1295 | case FROZEN: 1296 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_FROZEN; 1297 | break; 1298 | case ACTIVE_LEVEL_ON_MATCH: 1299 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_ACTIVE; 1300 | break; 1301 | case INACTIVE_LEVEL_ON_MATCH: 1302 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_INACTIVE; 1303 | break; 1304 | case TOGGLE: 1305 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_TOGGLE; 1306 | break; 1307 | case FORCE_INACTIVE_LEVEL: 1308 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_FORCE_LOW; 1309 | break; 1310 | case FORCE_ACTIVE_LEVEL: 1311 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_FORCE_HIGH; 1312 | break; 1313 | case PWM_MODE_1: 1314 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_PWM1; 1315 | break; 1316 | case PWM_MODE_2: 1317 | TIM_CCMR2(_timer) = oc3m_clear_mask | TIM_CCMR2_OC3M_PWM2; 1318 | break; 1319 | } 1320 | 1321 | return OK; 1322 | } 1323 | 1324 | // 9,12 1325 | auto Timer::set_output_compare_4_mode(OcMode mode) -> Result 1326 | { 1327 | bool channel_is_input = TIM_CCMR2(_timer) & TIM_CCMR2_CC4S_MASK; 1328 | 1329 | if (channel_is_input) { 1330 | return USAGE_ERROR; 1331 | } 1332 | 1333 | const uint32_t oc4m_clear_mask = 1334 | TIM_CCMR2(_timer) & ~to_u32(TIM_CCMR2_OC4M_MASK); 1335 | 1336 | switch (mode) { 1337 | case FROZEN: 1338 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_FROZEN; 1339 | break; 1340 | case ACTIVE_LEVEL_ON_MATCH: 1341 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_ACTIVE; 1342 | break; 1343 | case INACTIVE_LEVEL_ON_MATCH: 1344 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_INACTIVE; 1345 | break; 1346 | case TOGGLE: 1347 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_TOGGLE; 1348 | break; 1349 | case FORCE_INACTIVE_LEVEL: 1350 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_FORCE_LOW; 1351 | break; 1352 | case FORCE_ACTIVE_LEVEL: 1353 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_FORCE_HIGH; 1354 | break; 1355 | case PWM_MODE_1: 1356 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_PWM1; 1357 | break; 1358 | case PWM_MODE_2: 1359 | TIM_CCMR2(_timer) = oc4m_clear_mask | TIM_CCMR2_OC4M_PWM2; 1360 | break; 1361 | } 1362 | 1363 | return OK; 1364 | } 1365 | 1366 | // 9,12 1367 | auto Timer::enable_capture_compare_1() -> Result 1368 | { 1369 | TIM_CCER(_timer) |= TIM_CCER_CC1E; 1370 | return OK; 1371 | } 1372 | 1373 | // 9,12 1374 | auto Timer::disable_capture_compare_1() -> Result 1375 | { 1376 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC1E); 1377 | return OK; 1378 | } 1379 | 1380 | // 9,12 1381 | auto Timer::set_capture_compare_1_polarity(Polarity polarity) -> Result 1382 | { 1383 | switch (polarity) { 1384 | case LO_FALLING_EDGE: 1385 | TIM_CCER(_timer) |= TIM_CCER_CC1P; 1386 | break; 1387 | case HI_RISING_EDGE: 1388 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC1P); 1389 | break; 1390 | } 1391 | 1392 | return OK; 1393 | } 1394 | 1395 | auto Timer::set_capture_compare_1_com_polarity(Polarity polarity) -> Result 1396 | { 1397 | switch (polarity) { 1398 | case LO_FALLING_EDGE: 1399 | TIM_CCER(_timer) |= TIM_CCER_CC1NP; 1400 | break; 1401 | case HI_RISING_EDGE: 1402 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC1NP); 1403 | break; 1404 | } 1405 | 1406 | return OK; 1407 | } 1408 | 1409 | // 9,12 1410 | auto Timer::enable_capture_compare_2() -> Result 1411 | { 1412 | TIM_CCER(_timer) |= TIM_CCER_CC2E; 1413 | return OK; 1414 | } 1415 | 1416 | // 9,12 1417 | auto Timer::disable_capture_compare_2() -> Result 1418 | { 1419 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC2E); 1420 | return OK; 1421 | } 1422 | 1423 | // 9,12 1424 | auto Timer::set_capture_compare_2_polarity(Polarity polarity) -> Result 1425 | { 1426 | switch (polarity) { 1427 | case LO_FALLING_EDGE: 1428 | TIM_CCER(_timer) |= TIM_CCER_CC2P; 1429 | break; 1430 | case HI_RISING_EDGE: 1431 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC2P); 1432 | break; 1433 | } 1434 | 1435 | return OK; 1436 | } 1437 | 1438 | auto Timer::enable_capture_compare_3() -> Result 1439 | { 1440 | TIM_CCER(_timer) |= TIM_CCER_CC3E; 1441 | return OK; 1442 | } 1443 | 1444 | // 9,12 1445 | auto Timer::disable_capture_compare_3() -> Result 1446 | { 1447 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC3E); 1448 | return OK; 1449 | } 1450 | 1451 | // 9,12 1452 | auto Timer::set_capture_compare_3_polarity(Polarity polarity) -> Result 1453 | { 1454 | switch (polarity) { 1455 | case LO_FALLING_EDGE: 1456 | TIM_CCER(_timer) |= TIM_CCER_CC3P; 1457 | break; 1458 | case HI_RISING_EDGE: 1459 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC3P); 1460 | break; 1461 | } 1462 | 1463 | return OK; 1464 | } 1465 | 1466 | auto Timer::set_capture_compare_3_com_polarity(Polarity polarity) -> Result 1467 | { 1468 | switch (polarity) { 1469 | case LO_FALLING_EDGE: 1470 | TIM_CCER(_timer) |= TIM_CCER_CC3NP; 1471 | break; 1472 | case HI_RISING_EDGE: 1473 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC3NP); 1474 | break; 1475 | } 1476 | 1477 | return OK; 1478 | } 1479 | 1480 | // 9,12 1481 | auto Timer::enable_capture_compare_4() -> Result 1482 | { 1483 | TIM_CCER(_timer) |= TIM_CCER_CC4E; 1484 | return OK; 1485 | } 1486 | 1487 | // 9,12 1488 | auto Timer::disable_capture_compare_4() -> Result 1489 | { 1490 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC4E); 1491 | return OK; 1492 | } 1493 | 1494 | // 9,12 1495 | auto Timer::set_capture_compare_4_polarity(Polarity polarity) -> Result 1496 | { 1497 | switch (polarity) { 1498 | case LO_FALLING_EDGE: 1499 | TIM_CCER(_timer) |= TIM_CCER_CC4P; 1500 | break; 1501 | case HI_RISING_EDGE: 1502 | TIM_CCER(_timer) &= ~to_u32(TIM_CCER_CC4P); 1503 | break; 1504 | } 1505 | 1506 | return OK; 1507 | } 1508 | 1509 | auto Timer::set_capture_compare_4_com_polarity(Polarity polarity) -> Result 1510 | { 1511 | switch (polarity) { 1512 | case LO_FALLING_EDGE: 1513 | TIM_CCER(_timer) |= to_u32(1 << 15); 1514 | break; 1515 | case HI_RISING_EDGE: 1516 | TIM_CCER(_timer) &= ~to_u32(1 << 15); 1517 | break; 1518 | } 1519 | 1520 | return OK; 1521 | } 1522 | 1523 | // 9,12 1524 | uint16_t Timer::get_counter_value() const 1525 | { 1526 | return static_cast(TIM_CNT(_timer)); 1527 | } 1528 | 1529 | uint32_t Timer::get_counter_value32() const 1530 | { 1531 | return TIM_CNT(_timer); 1532 | } 1533 | 1534 | // 9,12 1535 | void Timer::set_counter_value(uint16_t value) 1536 | { 1537 | TIM_CNT(_timer) = value; 1538 | } 1539 | 1540 | // 9,12 1541 | uint16_t Timer::get_prescaler_value() const 1542 | { 1543 | return static_cast(TIM_PSC(_timer)); 1544 | } 1545 | 1546 | // 9,12 1547 | void Timer::set_prescaler_value(uint32_t value) 1548 | { 1549 | TIM_PSC(_timer) = value; 1550 | } 1551 | 1552 | // 9,12 1553 | uint16_t Timer::get_autoreload_value() const 1554 | { 1555 | return static_cast(TIM_ARR(_timer)); 1556 | } 1557 | 1558 | // 9,12 1559 | void Timer::set_autoreload_value(uint32_t value) 1560 | { 1561 | TIM_ARR(_timer) = value; 1562 | } 1563 | 1564 | // 9,12 1565 | uint16_t Timer::get_capture_compare_1_value() const 1566 | { 1567 | return static_cast(TIM_CCR1(_timer)); 1568 | } 1569 | 1570 | // 9,12 1571 | void Timer::set_capture_compare_1_value(uint32_t value) 1572 | { 1573 | TIM_CCR1(_timer) = value; 1574 | } 1575 | 1576 | // 9,12 1577 | uint16_t Timer::get_capture_compare_2_value() const 1578 | { 1579 | return static_cast(TIM_CCR2(_timer)); 1580 | } 1581 | 1582 | // 9,12 1583 | void Timer::set_capture_compare_2_value(uint32_t value) 1584 | { 1585 | TIM_CCR2(_timer) = value; 1586 | } 1587 | 1588 | uint16_t Timer::get_capture_compare_3_value() const 1589 | { 1590 | return static_cast(TIM_CCR3(_timer)); 1591 | } 1592 | 1593 | // 9,12 1594 | void Timer::set_capture_compare_3_value(uint32_t value) 1595 | { 1596 | TIM_CCR3(_timer) = value; 1597 | } 1598 | 1599 | // 9,12 1600 | uint16_t Timer::get_capture_compare_4_value() const 1601 | { 1602 | return static_cast(TIM_CCR4(_timer)); 1603 | } 1604 | 1605 | // 9,12 1606 | void Timer::set_capture_compare_4_value(uint32_t value) 1607 | { 1608 | TIM_CCR4(_timer) = value; 1609 | } 1610 | 1611 | void Timer::enable_etr_clock() 1612 | { 1613 | TIM_SMCR(_timer) |= TIM_SMCR_ECE; // set enable bit 1614 | } 1615 | 1616 | void Timer::disable_etr_clock() 1617 | { 1618 | TIM_SMCR(_timer) &= ~to_u32(TIM_SMCR_ECE); // reset enable bit 1619 | } 1620 | 1621 | void Timer::set_etr_filter(ExtTriggerFilter filter) 1622 | { 1623 | timer_slave_set_filter(_timer, filter); 1624 | } 1625 | 1626 | void Timer::set_etr_prescaler(ExtTriggerPrescaler prescaler) 1627 | { 1628 | timer_slave_set_prescaler(_timer, prescaler); 1629 | } 1630 | 1631 | void Timer::set_etr_polarity(ExtTriggerPolarity polarity) 1632 | { 1633 | timer_slave_set_polarity(_timer, polarity); 1634 | } 1635 | 1636 | } // namespace tim 1637 | 1638 | } // namespace cm3cpp 1639 | -------------------------------------------------------------------------------- /cm3cpp/timer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | TIM C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #ifndef CM3CPP_TIMER_H_ 27 | #define CM3CPP_TIMER_H_ 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | namespace cm3cpp { 35 | 36 | namespace tim { 37 | 38 | class Timer 39 | { 40 | public: 41 | enum Result 42 | { 43 | OK, 44 | USAGE_ERROR, 45 | NOT_SUPPORTED 46 | }; 47 | 48 | enum UevSource 49 | { 50 | COUNTER_OVERFLOW_AND_UG, 51 | COUNTER_OVERFLOW, 52 | }; 53 | 54 | enum CounterMode 55 | { 56 | ONE_SHOT, 57 | CONTINUOUS 58 | }; 59 | 60 | enum CounterDirection 61 | { 62 | UP, 63 | DOWN 64 | }; 65 | 66 | enum Alignment 67 | { 68 | EDGE, 69 | CENTER_DOWN, 70 | CENTER_UP, 71 | CENTER_UP_DOWN 72 | }; 73 | 74 | enum ClockDivision 75 | { 76 | TIMER_CLOCK_MUL_1, 77 | TIMER_CLOCK_MUL_2, 78 | TIMER_CLOCK_MUL_4 79 | }; 80 | 81 | enum MasterMode 82 | { 83 | MASTER_RESET, 84 | ENABLE, 85 | UPDATE, 86 | COMPARE_PULSE, 87 | COMPARE_OC1REF, 88 | COMPARE_OC2REF, 89 | COMPARE_OC3REF, 90 | COMPARE_OC4REF, 91 | }; 92 | 93 | enum SlaveMode 94 | { 95 | DISABLED, 96 | SLAVE_RESET, 97 | GATED, 98 | TRIGGER, 99 | EXTERNAL_CLOCK 100 | }; 101 | 102 | enum Trigger 103 | { 104 | INTERNAL_TRIGGER_0, 105 | INTERNAL_TRIGGER_1, 106 | INTERNAL_TRIGGER_2, 107 | INTERNAL_TRIGGER_3, 108 | EDGE_DETECTOR, 109 | FILTERED_TIMER_INPUT_1, 110 | FILTERED_TIMER_INPUT_2 111 | }; 112 | 113 | enum Flag 114 | { 115 | UPDATE_INTERRUPT, 116 | CAPTURE_COMPARE_1_INTERRUPT, 117 | CAPTURE_COMPARE_2_INTERRUPT, 118 | CAPTURE_COMPARE_3_INTERRUPT, 119 | CAPTURE_COMPARE_4_INTERRUPT, 120 | TRIGGER_INTERRUPT, 121 | CAPTURE_COMPARE_1_OVERCAPTURE, 122 | CAPTURE_COMPARE_2_OVERCAPTURE, 123 | CAPTURE_COMPARE_3_OVERCAPTURE, 124 | CAPTURE_COMPARE_4_OVERCAPTURE 125 | }; 126 | 127 | enum CcMode 128 | { 129 | OUTPUT, 130 | INPUT_MAPPED_TI1, 131 | INPUT_MAPPED_TI2, 132 | INPUT_MAPPED_TI3, 133 | INPUT_MAPPED_TI4, 134 | INPUT_MAPPED_TRC 135 | }; 136 | 137 | enum Prescaler 138 | { 139 | NO_PRESCALER, 140 | CAPTURE_EVERY_2_EVENTS, 141 | CAPTURE_EVERY_4_EVENTS, 142 | CAPTURE_EVERY_8_EVENTS 143 | }; 144 | 145 | enum Filter 146 | { 147 | NO_FILTER, 148 | CK_INT_N_2, 149 | CK_INT_N_4, 150 | CK_INT_N_8, 151 | DTF_DIV_2_N_6, 152 | DTF_DIV_2_N_8, 153 | TF_DIV_4_N_6, 154 | DTF_DIV_4_N_8, 155 | DTF_DIV_8_N_6, 156 | DTF_DIV_8_N_8, 157 | DTF_DIV_16_N_5, 158 | DTF_DIV_16_N_6, 159 | DTF_DIV_16_N_8, 160 | DTF_DIV_32_N_5, 161 | DTF_DIV_32_N_6, 162 | DTF_DIV_32_N_8, 163 | }; 164 | 165 | enum OcMode 166 | { 167 | FROZEN, 168 | ACTIVE_LEVEL_ON_MATCH, 169 | INACTIVE_LEVEL_ON_MATCH, 170 | TOGGLE, 171 | FORCE_INACTIVE_LEVEL, 172 | FORCE_ACTIVE_LEVEL, 173 | PWM_MODE_1, 174 | PWM_MODE_2 175 | }; 176 | 177 | enum Polarity 178 | { 179 | LO_FALLING_EDGE, 180 | HI_RISING_EDGE 181 | }; 182 | 183 | using ExtTriggerFilter = tim_ic_filter; 184 | using ExtTriggerPrescaler = tim_ic_psc; 185 | using ExtTriggerPolarity = tim_et_pol; 186 | 187 | using TimerNumber = uint8_t; 188 | enum TimerRegister 189 | { 190 | #if (TIM1 + 0) 191 | TIM_1 = TIM1 192 | #endif 193 | #if (TIM2 + 0) 194 | , 195 | TIM_2 = TIM2 196 | #endif 197 | #if (TIM3 + 0) 198 | , 199 | TIM_3 = TIM3 200 | #endif 201 | #if (TIM4 + 0) 202 | , 203 | TIM_4 = TIM4 204 | #endif 205 | #if (TIM5 + 0) 206 | , 207 | TIM_5 = TIM5 208 | #endif 209 | #if (TIM6 + 0) 210 | , 211 | TIM_6 = TIM6 212 | #endif 213 | #if (TIM7 + 0) 214 | , 215 | TIM_7 = TIM7 216 | #endif 217 | #if (TIM8 + 0) 218 | , 219 | TIM_8 = TIM8 220 | #endif 221 | #if (TIM9 + 0) 222 | , 223 | TIM_9 = TIM9 224 | #endif 225 | #if (TIM10 + 0) 226 | , 227 | TIM_10 = TIM10 228 | #endif 229 | #if (TIM11 + 0) 230 | , 231 | TIM_11 = TIM11 232 | #endif 233 | #if (TIM12 + 0) 234 | , 235 | TIM_12 = TIM12 236 | #endif 237 | #if (TIM13 + 0) 238 | , 239 | TIM_13 = TIM13 240 | #endif 241 | #if (TIM14 + 0) 242 | , 243 | TIM_14 = TIM14 244 | #endif 245 | #if (TIM15 + 0) 246 | , 247 | TIM_15 = TIM15 248 | #endif 249 | #if (TIM16 + 0) 250 | , 251 | TIM_16 = TIM16 252 | #endif 253 | #if (TIM17 + 0) 254 | , 255 | TIM_17 = TIM17 256 | #endif 257 | #if (TIM21 + 0) 258 | , 259 | TIM_21 = TIM21 260 | #endif 261 | #if (TIM22 + 0) 262 | , 263 | TIM_22 = TIM22 264 | #endif 265 | }; 266 | 267 | Timer(TimerNumber timer_num) 268 | { 269 | #if defined(STM32F2) || defined(STM32F4) 270 | switch (timer_num) { 271 | case 1: 272 | _timer = static_cast(TIM1); 273 | rcc_periph_reset_pulse(RST_TIM1); 274 | break; 275 | case 2: 276 | _timer = static_cast(TIM2); 277 | rcc_periph_reset_pulse(RST_TIM2); 278 | break; 279 | case 3: 280 | _timer = static_cast(TIM3); 281 | rcc_periph_reset_pulse(RST_TIM3); 282 | break; 283 | case 4: 284 | _timer = static_cast(TIM4); 285 | rcc_periph_reset_pulse(RST_TIM4); 286 | break; 287 | case 5: 288 | _timer = static_cast(TIM5); 289 | rcc_periph_reset_pulse(RST_TIM5); 290 | break; 291 | case 6: 292 | _timer = static_cast(TIM6); 293 | rcc_periph_reset_pulse(RST_TIM6); 294 | break; 295 | case 7: 296 | _timer = static_cast(TIM7); 297 | rcc_periph_reset_pulse(RST_TIM7); 298 | break; 299 | case 8: 300 | _timer = static_cast(TIM8); 301 | rcc_periph_reset_pulse(RST_TIM8); 302 | break; 303 | case 9: 304 | _timer = static_cast(TIM9); 305 | rcc_periph_reset_pulse(RST_TIM9); 306 | break; 307 | case 10: 308 | _timer = static_cast(TIM10); 309 | rcc_periph_reset_pulse(RST_TIM10); 310 | break; 311 | case 11: 312 | _timer = static_cast(TIM11); 313 | rcc_periph_reset_pulse(RST_TIM11); 314 | break; 315 | case 12: 316 | _timer = static_cast(TIM12); 317 | rcc_periph_reset_pulse(RST_TIM12); 318 | break; 319 | case 13: 320 | _timer = static_cast(TIM13); 321 | rcc_periph_reset_pulse(RST_TIM13); 322 | break; 323 | case 14: 324 | _timer = static_cast(TIM14); 325 | rcc_periph_reset_pulse(RST_TIM14); 326 | break; 327 | default: 328 | assert(false); 329 | } 330 | #endif 331 | } 332 | // CR1////////////////////////////////////////////////////// 333 | Result enable_counter(); 334 | Result disable_counter(); 335 | Result enable_update_event_generation(); 336 | Result disable_update_event_generation(); 337 | Result set_update_event_source(UevSource source); 338 | Result set_counter_mode(CounterMode mode); 339 | Result set_counter_direction(CounterDirection dir); 340 | Result set_alignment(Alignment alignment); 341 | Result enable_autoreload_preload(); 342 | Result disable_autoreload_preload(); 343 | Result set_clock_division(ClockDivision div); 344 | // CR2////////////////////////////////////////////////////// 345 | Result set_master_mode(MasterMode mode); 346 | // SMCR///////////////////////////////////////////////////// 347 | Result set_slave_mode(SlaveMode mode); 348 | Result set_trigger(Trigger trigger); 349 | Result enable_master_slave_mode(); 350 | Result disable_master_slave_mode(); 351 | 352 | // ETR config (external trigger), TIM 1-8 (F4, F2) 353 | void enable_etr_clock(); //!< Enable CNT after ETR clock enabling 354 | void disable_etr_clock(); 355 | void set_etr_filter(ExtTriggerFilter); 356 | void set_etr_prescaler(ExtTriggerPrescaler); 357 | void set_etr_polarity(ExtTriggerPolarity); 358 | 359 | // DIER///////////////////////////////////////////////////// 360 | Result enable_update_interrupt(); 361 | Result disable_update_interrupt(); 362 | Result enable_capture_compare_1_interrupt(); 363 | Result disable_capture_compare_1_interrupt(); 364 | Result enable_capture_compare_2_interrupt(); 365 | Result disable_capture_compare_2_interrupt(); 366 | Result enable_capture_compare_3_interrupt(); 367 | Result disable_capture_compare_3_interrupt(); 368 | Result enable_capture_compare_4_interrupt(); 369 | Result disable_capture_compare_4_interrupt(); 370 | Result enable_trigger_interrupt(); 371 | Result disable_trigger_interrupt(); 372 | // SR/////////////////////////////////////////////////////// 373 | bool get_flag_status(Flag flag) const; 374 | Result clear_flag_status(Flag flag); 375 | // EGR////////////////////////////////////////////////////// 376 | void update_generation(); 377 | // CCMR1//////////////////////////////////////////////////// 378 | Result set_capture_compare_1_mode(CcMode mode); 379 | Result set_capture_compare_2_mode(CcMode mode); 380 | Result set_input_capture_1_prescaler(Prescaler prescaler); 381 | Result set_input_capture_2_prescaler(Prescaler prescaler); 382 | Result set_input_capture_1_filter(Filter filter); 383 | Result set_input_capture_2_filter(Filter filter); 384 | Result enable_fast_output_compare_1(); 385 | Result disable_fast_output_compare_1(); 386 | Result enable_fast_output_compare_2(); 387 | Result disable_fast_output_compare_2(); 388 | Result enable_output_compare_1_preload(); 389 | Result disable_output_compare_1_preload(); 390 | Result enable_output_compare_2_preload(); 391 | Result disable_output_compare_2_preload(); 392 | Result set_output_compare_1_mode(OcMode mode); 393 | Result set_output_compare_2_mode(OcMode mode); 394 | // CCMR2//////////////////////////////////////////////////// 395 | Result set_capture_compare_3_mode(CcMode mode); 396 | Result set_capture_compare_4_mode(CcMode mode); 397 | Result set_input_capture_3_prescaler(Prescaler prescaler); 398 | Result set_input_capture_4_prescaler(Prescaler prescaler); 399 | Result set_input_capture_3_filter(Filter filter); 400 | Result set_input_capture_4_filter(Filter filter); 401 | Result enable_fast_output_compare_3(); 402 | Result disable_fast_output_compare_3(); 403 | Result enable_fast_output_compare_4(); 404 | Result disable_fast_output_compare_4(); 405 | Result enable_output_compare_3_preload(); 406 | Result disable_output_compare_3_preload(); 407 | Result enable_output_compare_4_preload(); 408 | Result disable_output_compare_4_preload(); 409 | Result set_output_compare_3_mode(OcMode mode); 410 | Result set_output_compare_4_mode(OcMode mode); 411 | // CCER///////////////////////////////////////////////////// 412 | Result enable_capture_compare_1(); 413 | Result disable_capture_compare_1(); 414 | Result set_capture_compare_1_polarity(Polarity polarity); 415 | Result set_capture_compare_1_com_polarity(Polarity polarity); 416 | Result enable_capture_compare_2(); 417 | Result disable_capture_compare_2(); 418 | Result set_capture_compare_2_polarity(Polarity polarity); 419 | Result enable_capture_compare_3(); 420 | Result disable_capture_compare_3(); 421 | Result set_capture_compare_3_polarity(Polarity polarity); 422 | Result set_capture_compare_3_com_polarity(Polarity polarity); 423 | Result enable_capture_compare_4(); 424 | Result disable_capture_compare_4(); 425 | Result set_capture_compare_4_polarity(Polarity polarity); 426 | Result set_capture_compare_4_com_polarity(Polarity polarity); 427 | // CNT////////////////////////////////////////////////////// 428 | uint16_t get_counter_value() const; 429 | uint32_t get_counter_value32() const; 430 | void set_counter_value(uint16_t value); 431 | // PSC////////////////////////////////////////////////////// 432 | uint16_t get_prescaler_value() const; 433 | void set_prescaler_value(uint32_t value); 434 | // ARR////////////////////////////////////////////////////// 435 | uint16_t get_autoreload_value() const; 436 | void set_autoreload_value(uint32_t value); 437 | // CCR1///////////////////////////////////////////////////// 438 | uint16_t get_capture_compare_1_value() const; 439 | void set_capture_compare_1_value(uint32_t value); 440 | // CCR2///////////////////////////////////////////////////// 441 | uint16_t get_capture_compare_2_value() const; 442 | void set_capture_compare_2_value(uint32_t value); 443 | // CCR3///////////////////////////////////////////////////// 444 | uint16_t get_capture_compare_3_value() const; 445 | void set_capture_compare_3_value(uint32_t value); 446 | // CCR4///////////////////////////////////////////////////// 447 | uint16_t get_capture_compare_4_value() const; 448 | void set_capture_compare_4_value(uint32_t value); 449 | 450 | uint32_t periph_address() const { return _timer; } 451 | 452 | private: 453 | TimerRegister _timer; 454 | }; 455 | 456 | } // namespace tim 457 | 458 | } // namespace cm3cpp 459 | 460 | #endif /* CM3CPP_TIMER_H_ */ 461 | -------------------------------------------------------------------------------- /cm3cpp/usart.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | USART C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #include "usart.hpp" 27 | 28 | namespace cm3cpp { 29 | 30 | namespace usart { 31 | 32 | Usart::Usart(LowLevelConfig config, Settings settings) 33 | { 34 | init(config, settings); 35 | } 36 | 37 | void Usart::init(LowLevelConfig config, Settings settings) 38 | { 39 | _mode = settings.mode; 40 | 41 | switch (config.usart_number) { 42 | case 1: 43 | _usart = USART1; 44 | _usart_nvic = NVIC_USART1_IRQ; 45 | break; 46 | case 2: 47 | _usart = USART2; 48 | _usart_nvic = NVIC_USART2_IRQ; 49 | break; 50 | case 3: 51 | _usart = USART3; 52 | _usart_nvic = NVIC_USART3_IRQ; 53 | break; 54 | case 4: 55 | _usart = UART4; 56 | _usart_nvic = NVIC_UART4_IRQ; 57 | break; 58 | case 5: 59 | _usart = UART5; 60 | _usart_nvic = NVIC_UART5_IRQ; 61 | break; 62 | case 6: 63 | _usart = USART6; 64 | _usart_nvic = NVIC_USART6_IRQ; 65 | break; 66 | } 67 | 68 | set_settings(settings); 69 | usart_enable(_usart); 70 | 71 | if (_mode == Mode::RX or _mode == Mode::RX_TX) { 72 | _rx.init(config.rx); 73 | 74 | if ((config.usart_number >= 1) && (config.usart_number <= 3)) 75 | _rx.set_af(Gpio::AltFuncNumber::AF7); 76 | else 77 | _rx.set_af(Gpio::AltFuncNumber::AF8); 78 | 79 | _rx.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 80 | _rx.set_output_options(Gpio::OutputType::PUSH_PULL, 81 | Gpio::Speed::MEDIUM_25MHz); 82 | } 83 | 84 | if (_mode == Mode::TX or _mode == Mode::RX_TX) { 85 | _tx.init(config.tx); 86 | 87 | if ((config.usart_number >= 1) && (config.usart_number <= 3)) 88 | _tx.set_af(Gpio::AltFuncNumber::AF7); 89 | else 90 | _tx.set_af(Gpio::AltFuncNumber::AF8); 91 | 92 | _tx.mode_setup(Gpio::Mode::ALTERNATE_FUNCTION, Gpio::PullMode::NO_PULL); 93 | _tx.set_output_options(Gpio::OutputType::PUSH_PULL, 94 | Gpio::Speed::MEDIUM_25MHz); 95 | } 96 | 97 | nvic_set_priority(_usart_nvic, config.nvic_priority); 98 | nvic_enable_irq(_usart_nvic); 99 | } 100 | 101 | void Usart::deinit() 102 | { 103 | usart_disable(_usart); 104 | nvic_disable_irq(_usart_nvic); 105 | 106 | if (_mode == Mode::RX or _mode == Mode::RX_TX) 107 | _rx.mode_setup(Gpio::Mode::INPUT, Gpio::PullMode::NO_PULL); 108 | 109 | if (_mode == Mode::TX or _mode == Mode::RX_TX) 110 | _tx.mode_setup(Gpio::Mode::INPUT, Gpio::PullMode::NO_PULL); 111 | } 112 | 113 | void Usart::set_settings(Settings settings) 114 | { 115 | _mode = settings.mode; 116 | usart_set_baudrate(_usart, settings.baud_rate); 117 | usart_set_databits(_usart, settings.word_length); 118 | usart_set_stopbits(_usart, settings.stop_bits); 119 | usart_set_mode(_usart, settings.mode); 120 | usart_set_parity(_usart, settings.parity); 121 | usart_set_flow_control(_usart, settings.flow_control); 122 | } 123 | 124 | } // namespace usart 125 | 126 | } // namespace cm3cpp 127 | -------------------------------------------------------------------------------- /cm3cpp/usart.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | USART C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #ifndef CM3CPP_USART_H_ 27 | #define CM3CPP_USART_H_ 28 | 29 | // GENERAL INCLUDES 30 | #include 31 | 32 | // LIBOPENCM3 INCLUDES 33 | #include 34 | #ifdef STM32F2 35 | #include 36 | #endif 37 | #ifdef STM32F4 38 | #include 39 | #endif 40 | 41 | // CM3CPP INCLUDES 42 | #include "gpio.hpp" 43 | #include "irq/irq.hpp" 44 | #include "private/assert.h" 45 | 46 | namespace cm3cpp { 47 | 48 | namespace usart { 49 | 50 | enum DataBits : uint8_t 51 | { 52 | _8 = 8, 53 | _9 = 9 54 | }; 55 | 56 | enum Mode : uint16_t 57 | { 58 | RX = USART_MODE_RX, 59 | TX = USART_MODE_TX, 60 | RX_TX = USART_MODE_TX_RX 61 | }; 62 | 63 | enum StopBits : uint16_t 64 | { 65 | _0_5 = USART_STOPBITS_0_5, 66 | _1 = USART_STOPBITS_1, 67 | _1_5 = USART_STOPBITS_1_5, 68 | _2 = USART_STOPBITS_2 69 | }; 70 | 71 | enum Parity : uint16_t 72 | { 73 | PAR_NONE = USART_PARITY_NONE, 74 | PAR_EVEN = USART_PARITY_EVEN, 75 | PAR_ODD = USART_PARITY_ODD 76 | }; 77 | 78 | enum FlowControl : uint16_t 79 | { 80 | NONE = USART_FLOWCONTROL_NONE, 81 | RTS = USART_FLOWCONTROL_RTS, 82 | CTS = USART_FLOWCONTROL_CTS, 83 | RTS_CTS = USART_FLOWCONTROL_RTS_CTS 84 | }; 85 | 86 | class Usart 87 | { 88 | public: 89 | using Gpio = gpio::Gpio; 90 | 91 | enum class Flag : uint16_t 92 | { 93 | TRANSMIT_COMPLETE = USART_SR_TC, 94 | TX_BUFFER_EMPTY = USART_SR_TXE, 95 | RX_NOT_EMPTY = USART_SR_RXNE, 96 | }; 97 | 98 | struct Settings 99 | { 100 | uint32_t baud_rate; 101 | DataBits word_length; 102 | StopBits stop_bits; 103 | Parity parity; 104 | Mode mode; 105 | FlowControl flow_control; 106 | }; 107 | 108 | struct LowLevelConfig 109 | { 110 | uint8_t usart_number; 111 | gpio::Gpio::Pinout tx; 112 | gpio::Gpio::Pinout rx; 113 | uint8_t nvic_priority; 114 | }; 115 | 116 | Usart() = default; 117 | 118 | Usart(LowLevelConfig config, Settings settings); 119 | 120 | void init(LowLevelConfig config, Settings settings); 121 | 122 | void deinit(); 123 | 124 | void set_settings(Settings settings); 125 | 126 | bool get_flag_status(Flag flag) 127 | { 128 | return usart_get_flag(_usart, (uint16_t)flag); 129 | } 130 | 131 | bool interrupt_source_rx() 132 | { 133 | return (((USART_CR1(_usart) & USART_CR1_RXNEIE) != 0) && 134 | usart_get_flag(_usart, USART_SR_RXNE)); 135 | } 136 | 137 | bool interrupt_source_tx() 138 | { 139 | return (((USART_CR1(_usart) & USART_CR1_TXEIE) != 0) && 140 | usart_get_flag(_usart, USART_SR_TXE)); 141 | } 142 | 143 | bool interrupt_source_TC() 144 | { 145 | return (((USART_CR1(_usart) & USART_CR1_TCIE) != 0) && 146 | usart_get_flag(_usart, USART_SR_TC)); 147 | } 148 | 149 | void clear_tc_flag() { 150 | USART_SR(_usart) = ~static_cast(USART_SR_TC); 151 | } 152 | 153 | void enable_irq() { nvic_enable_irq(_usart_nvic); } 154 | 155 | void disable_irq() { nvic_disable_irq(_usart_nvic); } 156 | 157 | void enable_rx_interrupt() { usart_enable_rx_interrupt(_usart); } 158 | 159 | void enable_tx_interrupt() { usart_enable_tx_interrupt(_usart); } 160 | 161 | void enable_tc_interrupt() { USART_CR1(_usart) |= USART_CR1_TCIE; } 162 | 163 | void disable_rx_interrupt() { usart_disable_rx_interrupt(_usart); } 164 | 165 | void disable_tx_interrupt() { usart_disable_tx_interrupt(_usart); } 166 | 167 | void disable_tc_interrupt() { 168 | USART_CR1(_usart) &= ~static_cast(USART_CR1_TCIE); 169 | } 170 | 171 | bool is_framing_error() { return (USART_SR(_usart) & USART_SR_FE) != 0; } 172 | 173 | bool is_overrun_error() { return (USART_SR(_usart) & USART_SR_IDLE) != 0; } 174 | 175 | bool is_any_error_occurred() 176 | { 177 | return (USART_SR(_usart) & 178 | (USART_SR_ORE | USART_SR_FE | USART_SR_PE | USART_SR_NE)) != 0; 179 | } 180 | 181 | uint32_t get_sr_reg() { return USART_SR(_usart); } 182 | 183 | bool is_data_received() { return (USART_SR(_usart) & USART_SR_RXNE) != 0; } 184 | 185 | bool is_data_sended() { return (USART_SR(_usart) & USART_SR_TXE) != 0; } 186 | 187 | void write_blocking(uint16_t data) { usart_send_blocking(_usart, data); } 188 | 189 | void write(uint16_t data) { usart_send(_usart, data); } 190 | 191 | uint16_t read() { return usart_recv(_usart); } 192 | 193 | uint16_t read_blocking() { return usart_recv_blocking(_usart); } 194 | 195 | auto get_irq() { return static_cast(_usart_nvic); } 196 | 197 | auto get_uart_periph() { return _usart; } 198 | 199 | protected: 200 | Gpio _rx; 201 | Gpio _tx; 202 | uint32_t _usart; 203 | uint8_t _usart_nvic; 204 | 205 | Mode _mode; 206 | }; 207 | 208 | } // namespace usart 209 | 210 | } // namespace cm3cpp 211 | 212 | #endif /* CM3CPP_USART_H_ */ 213 | -------------------------------------------------------------------------------- /cm3cpp/usart_rb.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | USART C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #include "usart_rb.hpp" 27 | 28 | namespace cm3cpp { 29 | 30 | namespace usart { 31 | 32 | UsartRb::UsartRb(LowLevelConfig config, 33 | Settings settings, 34 | uint32_t rb_in_size, 35 | uint32_t rb_out_size) : 36 | Usart(config, settings) 37 | { 38 | rb_in = new utils::RoundBuffer(rb_in_size); 39 | rb_out = new utils::RoundBuffer(rb_out_size); 40 | 41 | if (settings.mode & USART_MODE_RX) 42 | usart_enable_rx_interrupt(_usart); 43 | } 44 | 45 | } // namespace usart 46 | 47 | } // namespace cm3cpp 48 | -------------------------------------------------------------------------------- /cm3cpp/usart_rb.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Anastasiia Lazareva 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | /* 23 | USART C++ Wrapper of libopencm3 library for STM32F2, STM32F4 24 | */ 25 | 26 | #ifndef CM3CPP_USART_RB_H_ 27 | #define CM3CPP_USART_RB_H_ 28 | 29 | #include 30 | #include 31 | 32 | /************************************************************************************************** 33 | * CM3CPP INCLUDES 34 | *************************************************************************************************/ 35 | #include "usart.hpp" 36 | #include "utils/round_buffer.hpp" 37 | 38 | namespace cm3cpp { 39 | 40 | namespace usart { 41 | 42 | class UsartRb : public Usart 43 | { 44 | public: 45 | utils::RoundBuffer* rb_in; 46 | utils::RoundBuffer* rb_out; 47 | 48 | UsartRb(LowLevelConfig config, 49 | Settings settings, 50 | uint32_t rb_in_size, 51 | uint32_t rb_out_size); 52 | 53 | CM3CPP_EXPLISIT_DESTRUCTOR(UsartRb) 54 | 55 | void start_send() { usart_enable_tx_interrupt(_usart); } 56 | 57 | void receive_handler() 58 | { 59 | if (interrupt_source_rx()) { 60 | using byte_t = uint8_t; 61 | 62 | const uint16_t byte16 = read(); 63 | assert(byte16 < std::numeric_limits::max()); 64 | 65 | rb_in->push(static_cast(byte16)); 66 | } 67 | } 68 | 69 | void transmit_handler() 70 | { 71 | if (interrupt_source_tx()) { 72 | if (rb_out->get_count()) { 73 | write(rb_out->pop()); 74 | } 75 | else { 76 | usart_disable_tx_interrupt(_usart); 77 | } 78 | } 79 | } 80 | 81 | void inirq() 82 | { 83 | receive_handler(); 84 | transmit_handler(); 85 | } 86 | }; 87 | 88 | } // namespace usart 89 | 90 | } // namespace cm3cpp 91 | 92 | #endif /* CM3CPP_USART_RB_H_ */ 93 | -------------------------------------------------------------------------------- /cm3cpp/utils/round_buffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Pavel Larionov 7 | * Written by Anastasiia Lazareva 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | */ 22 | 23 | /* 24 | ROUND BUFFER implementation, public interface 25 | */ 26 | 27 | #include "round_buffer.hpp" 28 | 29 | namespace cm3cpp { 30 | 31 | namespace utils { 32 | 33 | RoundBuffer::RoundBuffer() 34 | { 35 | init(ROUND_BUFFER_DEFAULT_SIZE); 36 | } 37 | 38 | RoundBuffer::RoundBuffer(uint32_t size) 39 | { 40 | init(size); 41 | } 42 | 43 | uint32_t RoundBuffer::get(void* buffer, uint32_t index, uint32_t count) 44 | { 45 | uint32_t cnt = get_count(); 46 | uint32_t cnt_out = ((count + index) <= cnt) ? (count + index) : cnt; 47 | for (uint32_t i = index; i < cnt_out; i++) 48 | ((uint8_t*)buffer)[i - index] = (*this)[i]; 49 | return (cnt_out); 50 | } 51 | 52 | bool RoundBuffer::push(void* buffer, uint32_t count) 53 | { 54 | bool result = true; 55 | 56 | for (uint32_t i = 0; i < count; i++) 57 | result = push(((uint8_t*)buffer)[i]); 58 | return result; 59 | } 60 | 61 | bool RoundBuffer::push(RoundBuffer* buffer, uint32_t count, bool withPop) 62 | { 63 | bool result = true; 64 | uint32_t max_size = buffer->get_count(); 65 | 66 | max_size = ((max_size < count) ? max_size : count); 67 | 68 | if (max_size > 0) { 69 | if (withPop) { 70 | for (uint32_t i = 0; i < max_size; i++) 71 | result = push(buffer->pop()); 72 | } 73 | 74 | else { 75 | for (uint32_t i = 0; i < max_size; i++) 76 | result = push(buffer->operator[](i)); 77 | } 78 | } 79 | 80 | return result; 81 | } 82 | 83 | uint32_t RoundBuffer::pop(void* buffer, uint32_t count) 84 | { 85 | uint32_t cnt = get_count(); 86 | uint32_t cnt_out = (count <= cnt) ? count : cnt; 87 | 88 | for (uint32_t i = 0; i < cnt_out; i++) 89 | ((uint8_t*)buffer)[i] = pop(); 90 | 91 | return (cnt_out); 92 | } 93 | 94 | uint32_t RoundBuffer::pop(uint32_t count) 95 | { 96 | uint32_t cnt = get_count(); 97 | uint32_t cnt_out = (count <= cnt) ? count : cnt; 98 | 99 | for (uint32_t i = 0; i < cnt_out; i++) 100 | pop(); 101 | 102 | return (cnt_out); 103 | } 104 | 105 | int RoundBuffer::memcmp(void* buffer, uint32_t sizebuf) 106 | { 107 | uint8_t* buf = (uint8_t*)buffer; 108 | unsigned int cnt = get_count(); 109 | 110 | if (!cnt || !sizebuf || (sizebuf > cnt)) 111 | return (-1); 112 | 113 | uint32_t i = 0; 114 | while (i < sizebuf && buf[i] == (*this)[i]) 115 | i++; 116 | 117 | if (i == sizebuf) 118 | return (0); //??????? 119 | 120 | return (static_cast(i) + 1); 121 | } 122 | 123 | int RoundBuffer::mem_search(void* buffer, uint32_t sizebuf) 124 | { 125 | uint32_t cnt = get_count(); 126 | if (cnt < sizebuf) 127 | return (-1); 128 | uint8_t* pbuf = (uint8_t*)buffer; 129 | for (uint32_t i_begin = 0; i_begin <= (cnt - sizebuf); i_begin++) { 130 | uint32_t i_word; 131 | uint8_t byte; 132 | for (i_word = 0; i_word < sizebuf; i_word++) { 133 | byte = (*this)[i_begin + i_word]; 134 | if (byte != pbuf[i_word]) { 135 | if (i_word != 0) 136 | i_word = 0; 137 | break; 138 | } 139 | } 140 | 141 | if (i_word == sizebuf) 142 | return static_cast(i_begin); 143 | } 144 | 145 | return (-2); 146 | } 147 | 148 | } // namespace utils 149 | 150 | } // namespace cm3cpp 151 | -------------------------------------------------------------------------------- /cm3cpp/utils/round_buffer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3_cpp_extensions project. 3 | * hosted at http://github.com/thirdpin/libopencm3_cpp_extensions 4 | * 5 | * Copyright (C) 2016 Third Pin LLC 6 | * Written by Pavel Larionov 7 | * Written by Anastasiia Lazareva 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | */ 22 | 23 | /* 24 | ROUND BUFFER implementation, public interface 25 | */ 26 | 27 | #ifndef UTILS_ROUND_BUFFER_H_ 28 | #define UTILS_ROUND_BUFFER_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "../private/assert.h" 35 | 36 | namespace cm3cpp { 37 | 38 | namespace utils { 39 | 40 | constexpr uint32_t ROUND_BUFFER_DEFAULT_SIZE = 1000; 41 | 42 | /** 43 | * @brief Initializes a new instance of the TplRoundBuffer class 44 | * that is empty and has the specified initial size. 45 | * @param size The number of bytes that the new TplRoundBuffer can initially 46 | * store. 47 | */ 48 | inline void init(uint32_t size); 49 | 50 | /** 51 | * @brief Initializes a new instance of the TplRoundBuffer class 52 | * that internally points to external buffer and has the 53 | * specified initial size. 54 | * @param buffer External buffer the new TplRoundBuffer should points to. 55 | * @param size The number of bytes that the new TplRoundBuffer can initially 56 | * store. 57 | */ 58 | inline void init(void* buffer, uint32_t size); 59 | 60 | /** 61 | * @brief Removes all bytes from the TplRoundBuffer. 62 | */ 63 | inline void clear(void); 64 | 65 | /** 66 | * @brief Removes a range of bytes from the top of the TplRoundBuffer. 67 | * @param count The number of bytes to remove. 68 | * @return flase if empty after removing; otherwise, true. 69 | */ 70 | inline bool remove_range(uint32_t count); 71 | 72 | /** 73 | * @brief Gets the number of bytes actually contained in the TplRoundBuffer. 74 | * @return The number of bytes actually contained in the TplRoundBuffer. 75 | */ 76 | inline uint32_t get_count(void); 77 | 78 | /** 79 | * @brief Gets two bytes starting from the specified index. 80 | * @param index The zero-based index of the first byte to get. 81 | * @return Two bytes starting from the specified index. 82 | */ 83 | inline uint16_t get_word_unsafe(uint32_t index); 84 | 85 | /** 86 | * @brief Adds a byte to the end of the TplRoundBuffer. 87 | * @param byte The byte to add to the TplRoundBuffer. 88 | * @return false if overflow; otherwise, true. 89 | */ 90 | inline bool push(uint8_t byte); 91 | 92 | /** 93 | * @brief Removes and returns the byte at the beginning of the TplRoundBuffer. 94 | * @return The byte at the beginning of the TplRoundBuffer. 95 | */ 96 | inline uint8_t pop(void); 97 | 98 | /** 99 | * @brief Removes and returns the byte at the beginning of the TplRoundBuffer. 100 | * @return The byte at the beginning of the TplRoundBuffer. 101 | */ 102 | inline uint8_t pop_unsafe(void); 103 | 104 | class RoundBuffer 105 | { 106 | public: 107 | /** 108 | * @brief Initializes a new instance of the TplRoundBuffer class 109 | * that is empty and has no initial size. 110 | */ 111 | RoundBuffer(); 112 | 113 | /** 114 | * @brief Prevent memory leak. 115 | */ 116 | CM3CPP_EXPLISIT_DESTRUCTOR(RoundBuffer) // prevent memory leak 117 | 118 | /** 119 | * @brief Initializes a new instance of the TplRoundBuffer class 120 | * that is empty and has the specified initial size. 121 | * @param size The number of bytes that the new TplRoundBuffer can 122 | * initially store. 123 | */ 124 | RoundBuffer(uint32_t size); 125 | 126 | /** 127 | * @brief Gets the byte at the specified index. 128 | * @param index The zero-based index of the byte to get. 129 | * @return The byte at the specified index. 130 | */ 131 | uint8_t operator[](uint32_t index) 132 | { 133 | uint32_t pos = _head; 134 | 135 | assert(index <= std::size_t(std::numeric_limits::max())); 136 | 137 | mrb_plus(&pos, static_cast(index)); 138 | 139 | return (_buffer[pos]); 140 | } 141 | /** 142 | * @brief Copies a range of bytes from the TplRoundBuffer to the external 143 | * buffer. 144 | * @param resultBuffer The external buffer. 145 | * @param index The zero-based starting index of the range of bytes to copy. 146 | * @param count The number of bytes to copy. 147 | * @return The number of actually copied bytes. 148 | */ 149 | uint32_t get(void* resultBuffer, uint32_t index, uint32_t count); 150 | 151 | /** 152 | * @brief Adds a range of bytes from the top of the specified external 153 | * buffer to the end of the TplRoundBuffer. 154 | * @param buffer The external buffer. 155 | * @param count The number of bytes to add. 156 | * @return false if overflow; otherwise, true. 157 | */ 158 | bool push(void* buffer, uint32_t count); 159 | 160 | /** 161 | * @brief Adds a range of bytes from the top of the specified TplRoundBuffer 162 | * to the end of the current TplRoundBuffer. 163 | * @param tplRoundBuffer The external TplRoundBuffer. 164 | * @param count The number of bytes to add. 165 | * @return false if overflow; otherwise, true. 166 | */ 167 | bool push(RoundBuffer* buffer, uint32_t count, bool with_pop = true); 168 | 169 | /** 170 | * @brief Removes a range of bytes from the beginning of the TplRoundBuffer 171 | * and adds it to the specified external buffer. 172 | * @param resultBuffer The external buffer. 173 | * @param count The number of bytes to remove. 174 | * @return The number of actually removed bytes. 175 | */ 176 | uint32_t pop(void* buffer, uint32_t count); 177 | 178 | /** 179 | * @brief Removes a range of bytes from the beginning of the TplRoundBuffer. 180 | * @param count The number of bytes to remove. 181 | * @return The number of actually removed bytes. 182 | */ 183 | uint32_t pop(uint32_t count); 184 | 185 | /** 186 | * @brief 187 | * @param 188 | * @param 189 | * @return 0 if ok 190 | */ 191 | int memcmp(void* buffer, uint32_t sizebuf); 192 | 193 | /** 194 | * @brief 195 | * @param 196 | * @param 197 | * @return >=0 - the begin of mem; <0 - negative 198 | */ 199 | int mem_search(void* buffer, uint32_t sizebuf); 200 | 201 | void init(uint32_t size) 202 | { 203 | _buffer = new uint8_t[size]; 204 | _size = size; 205 | clear(); 206 | } 207 | 208 | void init(void* buffer, uint32_t size) 209 | { 210 | _buffer = (uint8_t*)buffer; 211 | _size = size; 212 | clear(); 213 | } 214 | 215 | void clear(void) 216 | { 217 | _tail = 0; 218 | _head = 0; 219 | } 220 | 221 | bool remove_range(uint32_t count) 222 | { 223 | if (count >= get_count()) { 224 | clear(); 225 | return (false); 226 | } 227 | 228 | assert(count <= std::size_t(std::numeric_limits::max())); 229 | mrb_plus(&_head, static_cast(count)); 230 | 231 | return (true); 232 | } 233 | 234 | uint32_t get_count(void) 235 | { 236 | if (_tail >= _head) 237 | return (_tail - _head); 238 | return (_size - _head + _tail); 239 | } 240 | 241 | uint16_t get_word_unsafe(uint32_t index) 242 | { 243 | if ((index + 1) >= get_count()) { 244 | return 0; 245 | } 246 | 247 | #pragma GCC diagnostic push 248 | #pragma GCC diagnostic ignored "-Wconversion" 249 | return (*this)[index] + ((*this)[index + 1] << 8); 250 | #pragma GCC diagnostic pop 251 | } 252 | 253 | bool push(uint8_t byte) 254 | { 255 | _buffer[_tail] = byte; 256 | mrb_plus(&_tail, 1); 257 | 258 | if (_tail == _head) { 259 | mrb_plus(&_head, 1); 260 | return (false); 261 | } 262 | 263 | return (true); 264 | } 265 | 266 | uint8_t pop(void) 267 | { 268 | if (!get_count()) 269 | return (0); 270 | uint8_t byte = _buffer[_head]; 271 | mrb_plus(&_head, 1); 272 | return (byte); 273 | } 274 | 275 | uint8_t pop_unsafe(void) 276 | { 277 | uint8_t byte = _buffer[_head]; 278 | mrb_plus(&_head, 1); 279 | return (byte); 280 | } 281 | 282 | private: 283 | uint32_t _tail; 284 | uint32_t _head; 285 | uint8_t* _buffer; 286 | uint32_t _size; 287 | 288 | void mrb_plus(uint32_t* par, int32_t plus) 289 | { 290 | if (plus < 0 && (*par < (uint32_t)-plus)) { 291 | *par += static_cast(static_cast(_size) + plus); 292 | return; 293 | } 294 | *par += static_cast(plus); 295 | if (*par >= _size) 296 | *par -= _size; 297 | } 298 | }; 299 | 300 | } // namespace utils 301 | 302 | } // namespace cm3cpp 303 | 304 | #endif /* UTILS_ROUND_BUFFER_H_ */ 305 | --------------------------------------------------------------------------------