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: |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 8 | // 0: PC6,PC7 TIM8(APB2) |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 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 | |
Brian Silverman | 1b7fe84 | 2014-04-01 14:25:18 -0700 | [diff] [blame^] | 79 | #if 0 |
| 80 | TODO(brians): Figure out a good way to let robot_comp override this. |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame] | 81 | // 4.A |
| 82 | void TIM1_CC_IRQHandler(void) { |
| 83 | uint32_t a_inputs = GPIOA->IDR, b_inputs = GPIOB->IDR; |
| 84 | TIM1->SR = ~TIM_SR_CC1IF; |
| 85 | int32_t old_value = encoder4_value; |
| 86 | int32_t new_value; |
| 87 | if (((a_inputs >> 8) ^ b_inputs) & (1 << 0)) { |
| 88 | new_value = old_value + 1; |
| 89 | } else { |
| 90 | new_value = old_value - 1; |
| 91 | } |
| 92 | encoder4_value = new_value; |
| 93 | } |
Brian Silverman | 1b7fe84 | 2014-04-01 14:25:18 -0700 | [diff] [blame^] | 94 | #endif |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame] | 95 | |
| 96 | // 4.B |
| 97 | void TIM3_IRQHandler(void) { |
| 98 | uint32_t a_inputs = GPIOA->IDR, b_inputs = GPIOB->IDR; |
| 99 | TIM3->SR = ~TIM_SR_CC3IF; |
| 100 | int32_t old_value = encoder4_value; |
| 101 | int32_t new_value; |
| 102 | if (((a_inputs >> 8) ^ b_inputs) & (1 << 0)) { |
| 103 | new_value = old_value - 1; |
| 104 | } else { |
| 105 | new_value = old_value + 1; |
| 106 | } |
| 107 | encoder4_value = new_value; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 108 | } |
| 109 | |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 110 | static void encoder_setup(TIM_TypeDef *timer, int fast) { |
Brian Silverman | ffeef3f | 2013-12-22 14:06:23 -0800 | [diff] [blame] | 111 | timer->CR1 = |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 112 | TIM_CR1_URS | /* don't generate spurious update interrupts that |
| 113 | might be shared with other timers */ |
| 114 | (fast ? (1 << 8) : 0) /* divide filter clock by 2 on fast encoders */; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 115 | timer->SMCR = 3; // 4x quadrature encoder mode |
Brian Silverman | 5f4bfe0 | 2014-02-18 00:57:53 -0800 | [diff] [blame] | 116 | timer->CCER = 0; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 117 | timer->CCMR1 = |
| 118 | TIM_CCMR1_CC2S_0 | /* input pin 2 -> timer input 2 */ |
Brian Silverman | 5f4bfe0 | 2014-02-18 00:57:53 -0800 | [diff] [blame] | 119 | TIM_CCMR1_CC1S_0 | /* input pin 1 -> timer input 1 */ |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 120 | (0xE << 4) | /* divide filter clock by 32, need 6 in a row to trigger */ |
| 121 | (0xE << 12) /* same for other input */; |
Brian Silverman | 5f4bfe0 | 2014-02-18 00:57:53 -0800 | [diff] [blame] | 122 | timer->PSC = 0; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 123 | timer->EGR = TIM_EGR_UG; |
| 124 | timer->CR1 |= TIM_CR1_CEN; |
| 125 | } |
| 126 | |
| 127 | void encoder_init(void) { |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 128 | // Set up the 3 simple software encoder inputs. |
| 129 | EXTI_set(0, 2); |
| 130 | EXTI_set(1, 2); |
| 131 | EXTI_set(3, 0); |
| 132 | EXTI->IMR |= EXTI_IMR_MR0 | EXTI_IMR_MR1 | EXTI_IMR_MR3; |
| 133 | EXTI->RTSR |= EXTI_RTSR_TR0 | EXTI_RTSR_TR1 | EXTI_RTSR_TR3; |
| 134 | EXTI->FTSR |= EXTI_FTSR_TR0 | EXTI_FTSR_TR1 | EXTI_FTSR_TR3; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 135 | NVIC_EnableIRQ(EXTI0_IRQn); |
| 136 | NVIC_EnableIRQ(EXTI1_IRQn); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 137 | NVIC_EnableIRQ(EXTI3_IRQn); |
| 138 | |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame] | 139 | // Set up the A2 software encoder input through TIM9 input 1. |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 140 | gpio_setup_alt(GPIOA, 2, 3); |
| 141 | RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; |
Brian Silverman | ffeef3f | 2013-12-22 14:06:23 -0800 | [diff] [blame] | 142 | TIM9->CR1 = 0; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 143 | TIM9->DIER = TIM_DIER_CC1IE; |
| 144 | TIM9->CCMR1 = TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */ |
| 145 | TIM9->CCER = TIM_CCER_CC1NP | TIM_CCER_CC1P | TIM_CCER_CC1E; |
| 146 | TIM9->EGR = TIM_EGR_UG; |
| 147 | TIM9->CR1 |= TIM_CR1_CEN; |
| 148 | NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); |
| 149 | |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame] | 150 | // Set up the A4 software encoder input through TIM1 input 1. |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 151 | gpio_setup_alt(GPIOA, 8, 1); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 152 | RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; |
Brian Silverman | d4a64d9 | 2013-12-25 15:52:59 -0800 | [diff] [blame] | 153 | TIM1->CR1 = 0; |
| 154 | TIM1->DIER = TIM_DIER_CC1IE; |
| 155 | TIM1->CCMR1 = TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */ |
| 156 | TIM1->CCER = TIM_CCER_CC1NP | TIM_CCER_CC1P | TIM_CCER_CC1E; |
| 157 | TIM1->EGR = TIM_EGR_UG; |
| 158 | TIM1->CR1 |= TIM_CR1_CEN; |
| 159 | NVIC_EnableIRQ(TIM1_CC_IRQn); |
| 160 | |
| 161 | // Set up the B4 software encoder input through TIM3 input 3. |
| 162 | gpio_setup_alt(GPIOB, 0, 2); |
| 163 | RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; |
| 164 | TIM3->CR1 = 0; |
| 165 | TIM3->DIER = TIM_DIER_CC3IE; |
| 166 | TIM3->CCMR2 = TIM_CCMR2_CC3S_0; /* input pin 3 -> timer input 3 */ |
| 167 | TIM3->CCER = TIM_CCER_CC3NP | TIM_CCER_CC3P | TIM_CCER_CC3E; |
| 168 | TIM3->EGR = TIM_EGR_UG; |
| 169 | TIM3->CR1 |= TIM_CR1_CEN; |
| 170 | NVIC_EnableIRQ(TIM3_IRQn); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 171 | |
| 172 | gpio_setup_alt(GPIOA, 5, 1); |
| 173 | gpio_setup_alt(GPIOB, 3, 1); |
| 174 | RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 175 | encoder_setup(TIM2, 0); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 176 | |
| 177 | gpio_setup_alt(GPIOA, 6, 2); |
| 178 | gpio_setup_alt(GPIOB, 5, 2); |
| 179 | RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 180 | encoder_setup(TIM3, 0); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 181 | |
| 182 | gpio_setup_alt(GPIOB, 6, 2); |
| 183 | gpio_setup_alt(GPIOB, 7, 2); |
| 184 | RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 185 | encoder_setup(TIM4, 0); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 186 | |
| 187 | gpio_setup_alt(GPIOA, 0, 2); |
| 188 | gpio_setup_alt(GPIOA, 1, 2); |
| 189 | RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 190 | encoder_setup(TIM5, 0); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 191 | |
| 192 | gpio_setup_alt(GPIOC, 6, 3); |
| 193 | gpio_setup_alt(GPIOC, 7, 3); |
| 194 | RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; |
Brian Silverman | e6e9df7 | 2014-02-18 15:14:27 -0800 | [diff] [blame] | 195 | encoder_setup(TIM8, 1); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 196 | } |