Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 1 | #include "cape/encoder.h" |
| 2 | |
| 3 | #include <STM32F2XX.h> |
| 4 | |
| 5 | #include "cape/util.h" |
| 6 | |
| 7 | // Here is where each encoder is hooked up: |
| 8 | // 0: PC6,PC7 TIM8 |
| 9 | // 1: PC0,PC1 EXTI0,EXTI1 |
| 10 | // 2: PA0,PA1 TIM5(32) |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 11 | // 3: PA2,PA3 TIM9.1,EXTI3 |
| 12 | // 4: PA8,PB0 TIM1.1,TIM3.3 |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 13 | // 5: PA5,PB3 TIM2(32) |
| 14 | // 6: PA6,PB5 TIM3 |
| 15 | // 7: PB6,PB7 TIM4 |
| 16 | |
| 17 | volatile int32_t encoder1_value = 0; |
| 18 | volatile int32_t encoder3_value = 0; |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 19 | volatile int32_t encoder4_value = 0; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 20 | |
| 21 | // 1.A |
| 22 | void EXTI0_IRQHandler(void) { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 23 | uint32_t inputs = GPIOC->IDR; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 24 | EXTI->PR = EXTI_PR_PR0; |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 25 | int32_t old_value = encoder1_value; |
| 26 | int32_t new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 27 | // This looks like a weird way to XOR the 2 inputs, but it compiles down to |
| 28 | // just 2 instructions, which is hard to beat. |
| 29 | if (((inputs >> 1) ^ inputs) & (1 << 0)) { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 30 | new_value = old_value + 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 31 | } else { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 32 | new_value = old_value - 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 33 | } |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 34 | encoder1_value = new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 35 | } |
| 36 | |
| 37 | // 1.B |
| 38 | void EXTI1_IRQHandler(void) { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 39 | uint32_t inputs = GPIOC->IDR; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 40 | EXTI->PR = EXTI_PR_PR1; |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 41 | int32_t old_value = encoder1_value; |
| 42 | int32_t new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 43 | if (((inputs >> 1) ^ inputs) & (1 << 0)) { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 44 | new_value = old_value - 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 45 | } else { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 46 | new_value = old_value + 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 47 | } |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 48 | encoder1_value = new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | // 3.A |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 52 | void TIM1_BRK_TIM9_IRQHandler(void) { |
| 53 | uint32_t inputs = GPIOA->IDR; |
Brian Silverman | 176c676 | 2013-12-19 16:28:09 -0800 | [diff] [blame] | 54 | TIM9->SR = ~TIM_SR_CC1IF; |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 55 | int32_t old_value = encoder3_value; |
| 56 | int32_t new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 57 | if (((inputs >> 1) ^ inputs) & (1 << 2)) { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 58 | new_value = old_value + 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 59 | } else { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 60 | new_value = old_value - 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 61 | } |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 62 | encoder3_value = new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | // 3.B |
| 66 | void EXTI3_IRQHandler(void) { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 67 | uint32_t inputs = GPIOA->IDR; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 68 | EXTI->PR = EXTI_PR_PR3; |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 69 | int32_t old_value = encoder3_value; |
| 70 | int32_t new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 71 | if (((inputs >> 1) ^ inputs) & (1 << 2)) { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 72 | new_value = old_value - 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 73 | } else { |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 74 | new_value = old_value + 1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 75 | } |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 76 | encoder3_value = new_value; |
| 77 | } |
| 78 | |
| 79 | // 4.A |
| 80 | void TIM1_CC_IRQHandler(void) { |
| 81 | uint32_t a_inputs = GPIOA->IDR, b_inputs = GPIOB->IDR; |
| 82 | TIM1->SR = ~TIM_SR_CC1IF; |
| 83 | int32_t old_value = encoder4_value; |
| 84 | int32_t new_value; |
| 85 | if (((a_inputs >> 8) ^ b_inputs) & (1 << 0)) { |
| 86 | new_value = old_value + 1; |
| 87 | } else { |
| 88 | new_value = old_value - 1; |
| 89 | } |
| 90 | encoder4_value = new_value; |
| 91 | } |
| 92 | |
| 93 | // 4.B |
| 94 | void TIM3_IRQHandler(void) { |
| 95 | uint32_t a_inputs = GPIOA->IDR, b_inputs = GPIOB->IDR; |
| 96 | TIM3->SR = ~TIM_SR_CC3IF; |
| 97 | int32_t old_value = encoder4_value; |
| 98 | int32_t new_value; |
| 99 | if (((a_inputs >> 8) ^ b_inputs) & (1 << 0)) { |
| 100 | new_value = old_value - 1; |
| 101 | } else { |
| 102 | new_value = old_value + 1; |
| 103 | } |
| 104 | encoder4_value = new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | static void encoder_setup(TIM_TypeDef *timer) { |
Brian Silverman | ffeef3f | 2013-12-22 14:06:23 -0800 | [diff] [blame] | 108 | timer->CR1 = |
| 109 | TIM_CR1_URS /* don't generate spurious update interrupts that |
| 110 | might be shared with other timers */; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 111 | timer->SMCR = 3; // 4x quadrature encoder mode |
| 112 | timer->CCMR1 = |
| 113 | TIM_CCMR1_CC2S_0 | /* input pin 2 -> timer input 2 */ |
Brian Silverman | 3e0a05b | 2013-12-22 11:33:42 -0800 | [diff] [blame] | 114 | TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */ |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 115 | timer->EGR = TIM_EGR_UG; |
| 116 | timer->CR1 |= TIM_CR1_CEN; |
| 117 | } |
| 118 | |
| 119 | void encoder_init(void) { |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 120 | // Set up the 3 simple software encoder inputs. |
| 121 | EXTI_set(0, 2); |
| 122 | EXTI_set(1, 2); |
| 123 | EXTI_set(3, 0); |
| 124 | EXTI->IMR |= EXTI_IMR_MR0 | EXTI_IMR_MR1 | EXTI_IMR_MR3; |
| 125 | EXTI->RTSR |= EXTI_RTSR_TR0 | EXTI_RTSR_TR1 | EXTI_RTSR_TR3; |
| 126 | EXTI->FTSR |= EXTI_FTSR_TR0 | EXTI_FTSR_TR1 | EXTI_FTSR_TR3; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 127 | NVIC_EnableIRQ(EXTI0_IRQn); |
| 128 | NVIC_EnableIRQ(EXTI1_IRQn); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 129 | NVIC_EnableIRQ(EXTI3_IRQn); |
| 130 | |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 131 | // Set up the A2 software encoder input through TIM9 input 1. |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 132 | gpio_setup_alt(GPIOA, 2, 3); |
| 133 | RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; |
Brian Silverman | ffeef3f | 2013-12-22 14:06:23 -0800 | [diff] [blame] | 134 | TIM9->CR1 = 0; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 135 | TIM9->DIER = TIM_DIER_CC1IE; |
| 136 | TIM9->CCMR1 = TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */ |
| 137 | TIM9->CCER = TIM_CCER_CC1NP | TIM_CCER_CC1P | TIM_CCER_CC1E; |
| 138 | TIM9->EGR = TIM_EGR_UG; |
| 139 | TIM9->CR1 |= TIM_CR1_CEN; |
| 140 | NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); |
| 141 | |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 142 | // Set up the A4 software encoder input through TIM1 input 1. |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 143 | gpio_setup_alt(GPIOA, 8, 1); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 144 | RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame^] | 145 | TIM1->CR1 = 0; |
| 146 | TIM1->DIER = TIM_DIER_CC1IE; |
| 147 | TIM1->CCMR1 = TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */ |
| 148 | TIM1->CCER = TIM_CCER_CC1NP | TIM_CCER_CC1P | TIM_CCER_CC1E; |
| 149 | TIM1->EGR = TIM_EGR_UG; |
| 150 | TIM1->CR1 |= TIM_CR1_CEN; |
| 151 | NVIC_EnableIRQ(TIM1_CC_IRQn); |
| 152 | |
| 153 | // Set up the B4 software encoder input through TIM3 input 3. |
| 154 | gpio_setup_alt(GPIOB, 0, 2); |
| 155 | RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; |
| 156 | TIM3->CR1 = 0; |
| 157 | TIM3->DIER = TIM_DIER_CC3IE; |
| 158 | TIM3->CCMR2 = TIM_CCMR2_CC3S_0; /* input pin 3 -> timer input 3 */ |
| 159 | TIM3->CCER = TIM_CCER_CC3NP | TIM_CCER_CC3P | TIM_CCER_CC3E; |
| 160 | TIM3->EGR = TIM_EGR_UG; |
| 161 | TIM3->CR1 |= TIM_CR1_CEN; |
| 162 | NVIC_EnableIRQ(TIM3_IRQn); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 163 | |
| 164 | gpio_setup_alt(GPIOA, 5, 1); |
| 165 | gpio_setup_alt(GPIOB, 3, 1); |
| 166 | RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; |
| 167 | encoder_setup(TIM2); |
| 168 | |
| 169 | gpio_setup_alt(GPIOA, 6, 2); |
| 170 | gpio_setup_alt(GPIOB, 5, 2); |
| 171 | RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; |
| 172 | encoder_setup(TIM3); |
| 173 | |
| 174 | gpio_setup_alt(GPIOB, 6, 2); |
| 175 | gpio_setup_alt(GPIOB, 7, 2); |
| 176 | RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; |
| 177 | encoder_setup(TIM4); |
| 178 | |
| 179 | gpio_setup_alt(GPIOA, 0, 2); |
| 180 | gpio_setup_alt(GPIOA, 1, 2); |
| 181 | RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; |
| 182 | encoder_setup(TIM5); |
| 183 | |
| 184 | gpio_setup_alt(GPIOC, 6, 3); |
| 185 | gpio_setup_alt(GPIOC, 7, 3); |
| 186 | RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; |
| 187 | encoder_setup(TIM8); |
| 188 | } |