2010-03-04 02:16 PM
32bit quadrature encoder
2011-05-17 04:42 AM
Goddam forum threw an exception (three times) and lost my reply. Fix this bloody thing guys! Enough of us have been complaining about it. It's a real disincentive to start all over again
This method will mean you don't need to sacrifice a timer. I'd make it a very high priority interrupt TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); void TIM2_IRQHandler(void) { uint16_t snap = TIM2->CNT; TIM_ClearITPendingBit(TIM2, TIM_IT_Update); if ( snap < 0x7FFF ) rotary_encoder_control.encoder_total_count_tracker += (sint32_t)0xFFFF; //Roll over in upwards direction (high, then reset to low) else rotary_encoder_control.encoder_total_count_tracker -= (sint32_t)0xFFFF; //Roll over in downwards direction (low, then reset to high) rotary_encoder_control.encoder_count_interrupt_catcher = false; } In the function that retrieves the encoder count do { //encoder_count_interrupt_catcher is set to false in the interrupt that modifies encoder_total_count_tracker // If this process is interrupted by that interrupt we should detect it with the while condition below and // take another snapshot of the values rotary_encoder_control.encoder_count_interrupt_catcher = true; snap_tracker = rotary_encoder_control.encoder_total_count_tracker; snap_counter = TIM2->CNT; } while ( rotary_encoder_control.encoder_count_interrupt_catcher == false ); result = snap_tracker + (sint32_t)snap_counter; Darcy2011-05-17 04:42 AM
I like how you have created a ''lock'' around the counter read and the upper word increment. I implemented the same functionality but I like your implementation better.
One question - shouldn't the 0xFFFF be ''0x10000'' since the overflow happens at 0x10000 (65536) pulses? Harjit2011-05-17 04:42 AM
Looking at that, yes, it probably should inc/dec by 0x10000 :)
2011-05-17 04:42 AM
I haven't tried this yet, but does the STM32 support the STREX instruction? If so you could replace the access to the wrapped count as
do { snap_tracker = __LDREX(&rotary_encoder_control.encoder_total_count_tracker); result = snap_tracker + (sint32_t)TIM2->CNT; } while (__STREX(snap_tracker, &rotary_encoder_control.encoder_total_count_tracker); If the tracker is touched in between the LDREX and STREX instructions by the ISR the operation will be retried.2011-05-17 04:42 AM
It does have LDREX/STREX.
Thanks for this clever idea :) Btw. it's not possible by HW, there is no direction link between timers, except (probably) paralelizing the timers and setting the second one a prescaler by 32768 - and getting 31 bits. Never tested, though.2012-07-28 08:25 AM
Edison wrote:
Btw. it's not possible by HW, there is no direction link between timers, except (probably) paralelizing the timers and setting the second one a prescaler by 32768 - and getting 31 bits. Never tested, though. Seems not working. I tried to use the prescaler as electronic gear to switch the rotary encoder between mm and cm. User must not use the prescaler in encoder mode. In case of changing the rotary direction, the counter cannot follow the wheel becouse the prescaler generates a ''dead zone''. Reversing the direction several times, moves the index reference more and more away.