blob: 93868fb60b4d89d57cd45009a72e5ba2748c6154 [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)
Brian Silvermand4a64d92013-12-25 15:52:59 -080011// 3: PA2,PA3 TIM9.1,EXTI3
12// 4: PA8,PB0 TIM1.1,TIM3.3
Brian Silverman1b6fbd02013-12-12 18:08:47 -080013// 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;
Brian Silvermand4a64d92013-12-25 15:52:59 -080019volatile int32_t encoder4_value = 0;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080020
21// 1.A
22void EXTI0_IRQHandler(void) {
Brian Silvermand4a64d92013-12-25 15:52:59 -080023 uint32_t inputs = GPIOC->IDR;
Brian Silverman25a06d92013-12-15 16:28:52 -080024 EXTI->PR = EXTI_PR_PR0;
Brian Silvermand4a64d92013-12-25 15:52:59 -080025 int32_t old_value = encoder1_value;
26 int32_t new_value;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080027 // 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 Silvermand4a64d92013-12-25 15:52:59 -080030 new_value = old_value + 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080031 } else {
Brian Silvermand4a64d92013-12-25 15:52:59 -080032 new_value = old_value - 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080033 }
Brian Silvermand4a64d92013-12-25 15:52:59 -080034 encoder1_value = new_value;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080035}
36
37// 1.B
38void EXTI1_IRQHandler(void) {
Brian Silvermand4a64d92013-12-25 15:52:59 -080039 uint32_t inputs = GPIOC->IDR;
Brian Silverman25a06d92013-12-15 16:28:52 -080040 EXTI->PR = EXTI_PR_PR1;
Brian Silvermand4a64d92013-12-25 15:52:59 -080041 int32_t old_value = encoder1_value;
42 int32_t new_value;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080043 if (((inputs >> 1) ^ inputs) & (1 << 0)) {
Brian Silvermand4a64d92013-12-25 15:52:59 -080044 new_value = old_value - 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080045 } else {
Brian Silvermand4a64d92013-12-25 15:52:59 -080046 new_value = old_value + 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080047 }
Brian Silvermand4a64d92013-12-25 15:52:59 -080048 encoder1_value = new_value;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080049}
50
51// 3.A
Brian Silvermand4a64d92013-12-25 15:52:59 -080052void TIM1_BRK_TIM9_IRQHandler(void) {
53 uint32_t inputs = GPIOA->IDR;
Brian Silverman176c6762013-12-19 16:28:09 -080054 TIM9->SR = ~TIM_SR_CC1IF;
Brian Silvermand4a64d92013-12-25 15:52:59 -080055 int32_t old_value = encoder3_value;
56 int32_t new_value;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080057 if (((inputs >> 1) ^ inputs) & (1 << 2)) {
Brian Silvermand4a64d92013-12-25 15:52:59 -080058 new_value = old_value + 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080059 } else {
Brian Silvermand4a64d92013-12-25 15:52:59 -080060 new_value = old_value - 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080061 }
Brian Silvermand4a64d92013-12-25 15:52:59 -080062 encoder3_value = new_value;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080063}
64
65// 3.B
66void EXTI3_IRQHandler(void) {
Brian Silvermand4a64d92013-12-25 15:52:59 -080067 uint32_t inputs = GPIOA->IDR;
Brian Silverman25a06d92013-12-15 16:28:52 -080068 EXTI->PR = EXTI_PR_PR3;
Brian Silvermand4a64d92013-12-25 15:52:59 -080069 int32_t old_value = encoder3_value;
70 int32_t new_value;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080071 if (((inputs >> 1) ^ inputs) & (1 << 2)) {
Brian Silvermand4a64d92013-12-25 15:52:59 -080072 new_value = old_value - 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080073 } else {
Brian Silvermand4a64d92013-12-25 15:52:59 -080074 new_value = old_value + 1;
Brian Silverman1b6fbd02013-12-12 18:08:47 -080075 }
Brian Silvermand4a64d92013-12-25 15:52:59 -080076 encoder3_value = new_value;
77}
78
79// 4.A
80void 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
94void 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 Silverman1b6fbd02013-12-12 18:08:47 -0800105}
106
107static void encoder_setup(TIM_TypeDef *timer) {
Brian Silvermanffeef3f2013-12-22 14:06:23 -0800108 timer->CR1 =
109 TIM_CR1_URS /* don't generate spurious update interrupts that
110 might be shared with other timers */;
Brian Silverman1b6fbd02013-12-12 18:08:47 -0800111 timer->SMCR = 3; // 4x quadrature encoder mode
112 timer->CCMR1 =
113 TIM_CCMR1_CC2S_0 | /* input pin 2 -> timer input 2 */
Brian Silverman3e0a05b2013-12-22 11:33:42 -0800114 TIM_CCMR1_CC1S_0; /* input pin 1 -> timer input 1 */
Brian Silverman1b6fbd02013-12-12 18:08:47 -0800115 timer->EGR = TIM_EGR_UG;
116 timer->CR1 |= TIM_CR1_CEN;
117}
118
119void encoder_init(void) {
Brian Silverman25a06d92013-12-15 16:28:52 -0800120 // 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 Silverman1b6fbd02013-12-12 18:08:47 -0800127 NVIC_EnableIRQ(EXTI0_IRQn);
128 NVIC_EnableIRQ(EXTI1_IRQn);
Brian Silverman1b6fbd02013-12-12 18:08:47 -0800129 NVIC_EnableIRQ(EXTI3_IRQn);
130
Brian Silvermand4a64d92013-12-25 15:52:59 -0800131 // Set up the A2 software encoder input through TIM9 input 1.
Brian Silverman25a06d92013-12-15 16:28:52 -0800132 gpio_setup_alt(GPIOA, 2, 3);
133 RCC->APB2ENR |= RCC_APB2ENR_TIM9EN;
Brian Silvermanffeef3f2013-12-22 14:06:23 -0800134 TIM9->CR1 = 0;
Brian Silverman25a06d92013-12-15 16:28:52 -0800135 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 Silvermand4a64d92013-12-25 15:52:59 -0800142 // Set up the A4 software encoder input through TIM1 input 1.
Brian Silverman1b6fbd02013-12-12 18:08:47 -0800143 gpio_setup_alt(GPIOA, 8, 1);
Brian Silverman1b6fbd02013-12-12 18:08:47 -0800144 RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
Brian Silvermand4a64d92013-12-25 15:52:59 -0800145 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 Silverman1b6fbd02013-12-12 18:08:47 -0800163
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}