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) |
| 11 | // 3: PA2,PA3 EXTI2,EXTI3 |
| 12 | // 4: PA8,PB0 TIM1 |
| 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; |
| 19 | |
| 20 | // 1.A |
| 21 | void EXTI0_IRQHandler(void) { |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 22 | uint32_t inputs = GPIOA->IDR; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 23 | EXTI->PR = EXTI_PR_PR0; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 24 | // This looks like a weird way to XOR the 2 inputs, but it compiles down to |
| 25 | // just 2 instructions, which is hard to beat. |
| 26 | if (((inputs >> 1) ^ inputs) & (1 << 0)) { |
| 27 | ++encoder1_value; |
| 28 | } else { |
| 29 | --encoder1_value; |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | // 1.B |
| 34 | void EXTI1_IRQHandler(void) { |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 35 | uint32_t inputs = GPIOA->IDR; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 36 | EXTI->PR = EXTI_PR_PR1; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 37 | if (((inputs >> 1) ^ inputs) & (1 << 0)) { |
| 38 | --encoder1_value; |
| 39 | } else { |
| 40 | ++encoder1_value; |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | // 3.A |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 45 | void TIM1_TRG_COM_TIM11_IRQHandler(void) { |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 46 | uint32_t inputs = GPIOC->IDR; |
Brian Silverman | 176c676 | 2013-12-19 16:28:09 -0800 | [diff] [blame^] | 47 | TIM9->SR = ~TIM_SR_CC1IF; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 48 | if (((inputs >> 1) ^ inputs) & (1 << 2)) { |
| 49 | ++encoder3_value; |
| 50 | } else { |
| 51 | --encoder3_value; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | // 3.B |
| 56 | void EXTI3_IRQHandler(void) { |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 57 | uint32_t inputs = GPIOC->IDR; |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 58 | EXTI->PR = EXTI_PR_PR3; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 59 | if (((inputs >> 1) ^ inputs) & (1 << 2)) { |
| 60 | --encoder3_value; |
| 61 | } else { |
| 62 | ++encoder3_value; |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | static void encoder_setup(TIM_TypeDef *timer) { |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 67 | timer->CR1 = TIM_CR1_UDIS /* wait until we tell it to do anything */ | |
| 68 | TIM_CR1_URS /* don't generate spurious update interrupts that |
| 69 | might be shared with other timers */; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 70 | timer->SMCR = 3; // 4x quadrature encoder mode |
| 71 | timer->CCMR1 = |
| 72 | TIM_CCMR1_CC2S_0 | /* input pin 2 -> timer input 2 */ |
| 73 | TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1*/ |
| 74 | timer->EGR = TIM_EGR_UG; |
| 75 | timer->CR1 |= TIM_CR1_CEN; |
| 76 | } |
| 77 | |
| 78 | void encoder_init(void) { |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 79 | // Set up the 3 simple software encoder inputs. |
| 80 | EXTI_set(0, 2); |
| 81 | EXTI_set(1, 2); |
| 82 | EXTI_set(3, 0); |
| 83 | EXTI->IMR |= EXTI_IMR_MR0 | EXTI_IMR_MR1 | EXTI_IMR_MR3; |
| 84 | EXTI->RTSR |= EXTI_RTSR_TR0 | EXTI_RTSR_TR1 | EXTI_RTSR_TR3; |
| 85 | EXTI->FTSR |= EXTI_FTSR_TR0 | EXTI_FTSR_TR1 | EXTI_FTSR_TR3; |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 86 | NVIC_EnableIRQ(EXTI0_IRQn); |
| 87 | NVIC_EnableIRQ(EXTI1_IRQn); |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 88 | NVIC_EnableIRQ(EXTI3_IRQn); |
| 89 | |
Brian Silverman | 25a06d9 | 2013-12-15 16:28:52 -0800 | [diff] [blame] | 90 | // Set up the A2 software encoder input through TIM9. |
| 91 | gpio_setup_alt(GPIOA, 2, 3); |
| 92 | RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; |
| 93 | TIM9->CR1 = TIM_CR1_UDIS; |
| 94 | TIM9->DIER = TIM_DIER_CC1IE; |
| 95 | TIM9->CCMR1 = TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */ |
| 96 | TIM9->CCER = TIM_CCER_CC1NP | TIM_CCER_CC1P | TIM_CCER_CC1E; |
| 97 | TIM9->EGR = TIM_EGR_UG; |
| 98 | TIM9->CR1 |= TIM_CR1_CEN; |
| 99 | NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); |
| 100 | |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 101 | gpio_setup_alt(GPIOA, 8, 1); |
| 102 | gpio_setup_alt(GPIOB, 0, 1); |
| 103 | RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; |
| 104 | encoder_setup(TIM1); |
| 105 | |
| 106 | gpio_setup_alt(GPIOA, 5, 1); |
| 107 | gpio_setup_alt(GPIOB, 3, 1); |
| 108 | RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; |
| 109 | encoder_setup(TIM2); |
| 110 | |
| 111 | gpio_setup_alt(GPIOA, 6, 2); |
| 112 | gpio_setup_alt(GPIOB, 5, 2); |
| 113 | RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; |
| 114 | encoder_setup(TIM3); |
| 115 | |
| 116 | gpio_setup_alt(GPIOB, 6, 2); |
| 117 | gpio_setup_alt(GPIOB, 7, 2); |
| 118 | RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; |
| 119 | encoder_setup(TIM4); |
| 120 | |
| 121 | gpio_setup_alt(GPIOA, 0, 2); |
| 122 | gpio_setup_alt(GPIOA, 1, 2); |
| 123 | RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; |
| 124 | encoder_setup(TIM5); |
| 125 | |
| 126 | gpio_setup_alt(GPIOC, 6, 3); |
| 127 | gpio_setup_alt(GPIOC, 7, 3); |
| 128 | RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; |
| 129 | encoder_setup(TIM8); |
| 130 | } |