blob: 09c4918409d93dc660e99abb47538be7cd8e8ce9 [file] [log] [blame]
Brian Silverman1b6fbd02013-12-12 18:08:47 -08001#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
17volatile int32_t encoder1_value = 0;
18volatile int32_t encoder3_value = 0;
19
20// 1.A
21void EXTI0_IRQHandler(void) {
Brian Silverman1b6fbd02013-12-12 18:08:47 -080022 uint32_t inputs = GPIOA->IDR;
Brian Silverman25a06d92013-12-15 16:28:52 -080023 EXTI->PR = EXTI_PR_PR0;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080024 // 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
34void EXTI1_IRQHandler(void) {
Brian Silverman1b6fbd02013-12-12 18:08:47 -080035 uint32_t inputs = GPIOA->IDR;
Brian Silverman25a06d92013-12-15 16:28:52 -080036 EXTI->PR = EXTI_PR_PR1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080037 if (((inputs >> 1) ^ inputs) & (1 << 0)) {
38 --encoder1_value;
39 } else {
40 ++encoder1_value;
41 }
42}
43
44// 3.A
Brian Silverman25a06d92013-12-15 16:28:52 -080045void TIM1_TRG_COM_TIM11_IRQHandler(void) {
Brian Silverman1b6fbd02013-12-12 18:08:47 -080046 uint32_t inputs = GPIOC->IDR;
Brian Silverman176c6762013-12-19 16:28:09 -080047 TIM9->SR = ~TIM_SR_CC1IF;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080048 if (((inputs >> 1) ^ inputs) & (1 << 2)) {
49 ++encoder3_value;
50 } else {
51 --encoder3_value;
52 }
53}
54
55// 3.B
56void EXTI3_IRQHandler(void) {
Brian Silverman1b6fbd02013-12-12 18:08:47 -080057 uint32_t inputs = GPIOC->IDR;
Brian Silverman25a06d92013-12-15 16:28:52 -080058 EXTI->PR = EXTI_PR_PR3;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080059 if (((inputs >> 1) ^ inputs) & (1 << 2)) {
60 --encoder3_value;
61 } else {
62 ++encoder3_value;
63 }
64}
65
66static void encoder_setup(TIM_TypeDef *timer) {
Brian Silvermanffeef3f2013-12-22 14:06:23 -080067 timer->CR1 =
68 TIM_CR1_URS /* don't generate spurious update interrupts that
69 might be shared with other timers */;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080070 timer->SMCR = 3; // 4x quadrature encoder mode
71 timer->CCMR1 =
72 TIM_CCMR1_CC2S_0 | /* input pin 2 -> timer input 2 */
Brian Silverman3e0a05b2013-12-22 11:33:42 -080073 TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */
Brian Silverman1b6fbd02013-12-12 18:08:47 -080074 timer->EGR = TIM_EGR_UG;
75 timer->CR1 |= TIM_CR1_CEN;
76}
77
78void encoder_init(void) {
Brian Silverman25a06d92013-12-15 16:28:52 -080079 // 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 Silverman1b6fbd02013-12-12 18:08:47 -080086 NVIC_EnableIRQ(EXTI0_IRQn);
87 NVIC_EnableIRQ(EXTI1_IRQn);
Brian Silverman1b6fbd02013-12-12 18:08:47 -080088 NVIC_EnableIRQ(EXTI3_IRQn);
89
Brian Silverman25a06d92013-12-15 16:28:52 -080090 // Set up the A2 software encoder input through TIM9.
91 gpio_setup_alt(GPIOA, 2, 3);
92 RCC->APB2ENR |= RCC_APB2ENR_TIM9EN;
Brian Silvermanffeef3f2013-12-22 14:06:23 -080093 TIM9->CR1 = 0;
Brian Silverman25a06d92013-12-15 16:28:52 -080094 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 Silverman1b6fbd02013-12-12 18:08:47 -0800101 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}