A Quadrature Encoder Controller. More...
Go to the source code of this file.
Defines | |
#define | QEC_MAX_BUFFER_LENGTH (64) |
Functions | |
static void | qec_calc_velocity (volatile QEC_DATA *data, int ticks_elapsed) |
Updates the data needed to calculate velocity. | |
int | qec_get_abs_pos (QEC_ID id) |
Returns the absolute position of the given encoder. | |
float | qec_get_velocity (QEC_ID id) |
Returns the velocity, in counts/sec, of the given encoder. | |
void | qec_init (QEC_RESOLUTION enc_res_1, int enc1_avg_time, QEC_RESOLUTION enc_res_2, int enc2_avg_time, VOID_VOID_F function) |
Initializes the quadrature encoder module. | |
static void | qec_init_data (volatile QEC_DATA *data, QEC_RESOLUTION resolution, int *pos_buf, int *time_buf, int length) |
Initializes an encoder's data. | |
int | qec_is_stopped (QEC_ID id) |
Returns 1 if the motor has stopped (time since last pulse was 2 ms), 0 otherwise. | |
void | qec_isr (void) |
The interrupt service routine for the qec module used by Timer 0. | |
static void | qec_update (volatile QEC_DATA *data, int flag_chA, int flag_chB, int chA, int chB) |
Updates the given encoder with data from the timer. | |
void | qec_update_velocity (void) |
MUST call this every schedule tick. | |
Variables | |
static volatile QEC_DATA | qec_data1 |
The encoder data for the first encoder - J3. | |
static volatile QEC_DATA | qec_data2 |
The encoder data for the second encoder - J9. | |
static unsigned int | qec_match_ticks = 0 |
Number of times the overflow (match value) has been reached and the timer reset. | |
static VOID_VOID_F | qec_overflow_funct = voidvoid |
The function to call when a timer match and reset occurs. | |
static int | qec_pos_buf1 [QEC_MAX_BUFFER_LENGTH] |
static int | qec_pos_buf2 [QEC_MAX_BUFFER_LENGTH] |
static unsigned int | qec_prev_ticks = 0 |
Previous value of the counter. | |
static float | qec_ticks_per_sec = 60000000.0f |
static int | qec_time_buf1 [QEC_MAX_BUFFER_LENGTH] |
static int | qec_time_buf2 [QEC_MAX_BUFFER_LENGTH] |
A Quadrature Encoder Controller.
Each quadrature encoder on a motor is represented by a QEC_DATA struct. The positive direction is defined as counter-clockwise when looking at the motor from the front.
A value of QEC_NULL in initialization will ignore both channels A and B, but the interrupts will continue to occur unless they are disabled in Hardware Setup.
A value of QEC_2X will ignore channel B interrupts, but similarly, interrupts for that channel will need to be disabled in Hardware Setup for that channel to take full advantage of the time savings.
A value of QEC_4X will use values from both channels, and the interrupts will need to be setup correctly.
This module uses Timer 0, but can be setup to run the scheduler if asched_tick is passed to the overflow function.
Example Hardware and Register Setup of pins and timer 0:
// ******************************************************************************* // QEC Setup // ******************************************************************************* //Enable Capture Interrupt For Falling and Rising Edges: PINSEL1 &= ~(3<<12); PINSEL1 &= ~(3<<0); //Clear bits 1:0 (P0.16) PINSEL1 &= ~(3<<26); //Clear bits 27:26 (P0.29) PINSEL1 &= ~(3<<22); PINSEL1 |= (2<<12); // set pin 0.22 to capture 0.0 PINSEL1 |= (2<<22); // set pin 0.27 to capture 0.1 PINSEL1 |= (3<<0); //Set P0.16 to Timer0 Capture 0.2 PINSEL1 |= (2<<26); //Set P0.29 to Timer0 Capture 0.3 //Set up the Timer Counter 0 Interrupt //Used to recod length of time between encoder pulses. T0IR = 0xFF; //clear interrupts in Timer0 //Enable Capture registers //Encoder 1 - J3 (Can comment out as needed for desired resolution) T0CCR |= (1<<0)|(1<<1)|(1<<2); //Cap0.0 on rising and falling edges T0CCR |= (1<<3)|(1<<4)|(1<<5); //Cap0.1 on rising and falling edges //Encoder 2 - J9 (Can comment out as needed for desired resolution) T0CCR |= (1<<6)|(1<<7)|(1<<8);//|(1<<9)|(1<<10)|(1<<11); //Cap0.2 on rising and falling edges T0CCR |= (1<<9)|(1<<10)|(1<<11); //Cap0.3 on rising and falling edges
Example interrupt setup (currently using FIQ):
add_fiq(VIC_TIMER0, qec_isr);
Definition in file qec.c.
static void qec_calc_velocity | ( | volatile QEC_DATA * | data, | |
int | ticks_elapsed | |||
) | [static] |
Updates the data needed to calculate velocity.
data | The encoder to update the data of. | |
ticks_elapsed | The number of ticks since the last call to update_velocity. |
Definition at line 180 of file qec.c.
References QEC_DATA::current_pos, QEC_DATA::delta_pos, QEC_DATA::delta_time, QEC_DATA::index, QEC_DATA::length, QEC_DATA::pos_buf, QEC_DATA::prev_pos, and QEC_DATA::time_buf.
Referenced by qec_update_velocity().
00180 { 00181 int new_pos = data->current_pos - data->prev_pos; 00182 int old_pos = data->pos_buf[data->index]; 00183 int new_time = ticks_elapsed; 00184 int old_time = data->time_buf[data->index]; 00185 00186 data->pos_buf[data->index] = new_pos; 00187 data->time_buf[data->index] = new_time; 00188 data->index = (data->index + 1) % data->length; 00189 data->prev_pos = data->current_pos; 00190 data->delta_pos = data->delta_pos + new_pos - old_pos; 00191 data->delta_time = data->delta_time + new_time - old_time; 00192 }
int qec_get_abs_pos | ( | QEC_ID | id | ) |
Returns the absolute position of the given encoder.
id | The id of the encoder, either QEC_1 (J3) or QEC_2 (J9). |
Definition at line 150 of file qec.c.
References QEC_DATA::current_pos, and error_occurred().
00151 { 00152 switch (id) { 00153 case QEC_1: return qec_data1.current_pos; 00154 case QEC_2: return qec_data2.current_pos; 00155 default: error_occurred(ERROR_QEC_BAD_ID); return 0; 00156 } 00157 }
float qec_get_velocity | ( | QEC_ID | id | ) |
Returns the velocity, in counts/sec, of the given encoder.
id | The id of the encoder to read from, either QEC_1 (J3) or QEC_2 (J9). |
Definition at line 199 of file qec.c.
References QEC_DATA::delta_pos, QEC_DATA::delta_time, error_occurred(), and QEC_DATA::velocity.
Referenced by qec_is_stopped().
00200 { 00201 volatile QEC_DATA* data; 00202 switch (id) { 00203 case QEC_1: data = &qec_data1; break; 00204 case QEC_2: data = &qec_data2; break; 00205 default: error_occurred(ERROR_QEC_BAD_ID); return 0.0; 00206 } 00207 data->velocity = (float)((data->delta_pos * qec_ticks_per_sec) / (float)data->delta_time); 00208 return data->velocity; 00209 }
void qec_init | ( | QEC_RESOLUTION | enc_res_1, | |
int | enc1_avg_time, | |||
QEC_RESOLUTION | enc_res_2, | |||
int | enc2_avg_time, | |||
VOID_VOID_F | function | |||
) |
Initializes the quadrature encoder module.
Encoders are enabled with the given resolution, and the overflow function will be called whenever there is a match and reset on match 0 of the timer.
enc_res_1 | The desired resolution for encoder 1, either NULL, 2X, or 4X. | |
enc1_avg_time | The time in ms over which the velocity is averaged for encoder 1. | |
enc_res_2 | The desired resolution for encoder 2, either NULL, 2X, or 4X. | |
enc2_avg_time | The time in ms over which the velocity is averaged for encoder 2. | |
function | This function will be called when a timer reset occurs. |
Definition at line 80 of file qec.c.
References qec_init_data(), qec_match_ticks, and qec_overflow_funct.
00081 { 00082 if (enc1_avg_time * SCHED_SPEED < QEC_MAX_BUFFER_LENGTH){ 00083 qec_init_data(&qec_data1, enc_res_1, qec_pos_buf1, qec_time_buf1, enc1_avg_time* SCHED_SPEED); 00084 } 00085 if (enc2_avg_time * SCHED_SPEED < QEC_MAX_BUFFER_LENGTH){ 00086 qec_init_data(&qec_data2, enc_res_2, qec_pos_buf2, qec_time_buf2, enc2_avg_time* SCHED_SPEED); 00087 } 00088 qec_overflow_funct = function; 00089 qec_match_ticks = T0MR0; 00090 }
static void qec_init_data | ( | volatile QEC_DATA * | data, | |
QEC_RESOLUTION | resolution, | |||
int * | pos_buf, | |||
int * | time_buf, | |||
int | length | |||
) | [static] |
Initializes an encoder's data.
data | A pointer to the encoder data struct. | |
time_buf | The time buffer. | |
pos_buf | The position buffer. | |
length | The length of both buffers. | |
resolution | The resolution desired for the encoder. |
Definition at line 100 of file qec.c.
References QEC_DATA::current_pos, QEC_DATA::index, QEC_DATA::length, QEC_DATA::pos_buf, QEC_DATA::resolution, and QEC_DATA::time_buf.
Referenced by qec_init().
int qec_is_stopped | ( | QEC_ID | id | ) |
Returns 1 if the motor has stopped (time since last pulse was 2 ms), 0 otherwise.
id | The encoder to check. |
Definition at line 217 of file qec.c.
References qec_get_velocity().
00217 { 00218 return (qec_get_velocity(id) < 0.2); //0.38 from old version 00219 }
void qec_isr | ( | void | ) |
The interrupt service routine for the qec module used by Timer 0.
Called whenever there is an edge in channel A or B, or timer 0 matched and was reset.
Definition at line 115 of file qec.c.
References qec_overflow_funct, qec_update(), and QEC_DATA::resolution.
00116 { 00117 unsigned int count = T0TC; 00118 unsigned int flags = T0IR; //save the interrupt flags 00119 unsigned int pins = FIO0PIN; //save the pin state 00120 int flag_overflow = flags & (1<<0); 00121 int flag_cap0 = flags & (1<<4); 00122 int flag_cap1 = flags & (1<<5); 00123 int flag_cap2 = flags & (1<<6); 00124 int flag_cap3 = flags & (1<<7); 00125 int chA1 = pins & (1<<22); //encoder 1 00126 int chB1 = pins & (1<<27); //"" 00127 int chA2 = pins & (1<<16); //encoder 2 00128 int chB2 = pins & (1<<29); //"" 00129 00130 //Clear interrupt register flags 00131 T0IR = flag_overflow | flag_cap0 | flag_cap1 | flag_cap2 | flag_cap3; 00132 00133 //Only update information for an encoder struct that exists 00134 if (qec_data1.resolution != QEC_NULL){ 00135 qec_update(&qec_data1, flag_cap0, flag_cap1, chA1, chB1); 00136 } 00137 if (qec_data2.resolution != QEC_NULL){ 00138 qec_update(&qec_data2, flag_cap2, flag_cap3, chA2, chB2); 00139 } 00140 if (flag_overflow){ 00141 qec_overflow_funct(); 00142 } 00143 }
static void qec_update | ( | volatile QEC_DATA * | data, | |
int | flag_chA, | |||
int | flag_chB, | |||
int | chA, | |||
int | chB | |||
) | [static] |
Updates the given encoder with data from the timer.
Called from qec_isr for both encoders, if applicable.
data | A pointer to the encoder's data struct. | |
flag_chA | Whether a capture interrupt occurred on channel A. | |
flag_chB | Whether a capture interrupt occurred on channel B. | |
chA | The state (1 = hi, 0 = lo) of channel A. | |
chB | The state of channel B. |
Definition at line 229 of file qec.c.
References QEC_DATA::current_pos, error_occurred(), QEC_DATA::prev_chA, QEC_DATA::prev_chB, and QEC_DATA::resolution.
Referenced by qec_isr().
00230 { 00231 int delta_pos; 00232 00233 //if resolution only 2x, ignore channel B 00234 if (data->resolution == QEC_2X){ 00235 flag_chB = 0; 00236 } 00237 00238 //both channels can't interrupt this fast; that would suck 00239 if (flag_chA && flag_chB){ 00240 error_occurred(ERROR_QEC_BOTH_CHS); 00241 } 00242 00243 // If captures occurred 00244 if (flag_chA){ 00245 if (data->prev_chA == chA){ //we are back even though we had an interrupt, MISSED COUNT! 00246 error_occurred(ERROR_QEC_MISSED_A); //missed a count on channel A 00247 } else { 00248 if (chA){ //A high 00249 if (chB) { //B high (B & A & fA) 00250 delta_pos = -1; 00251 } else { //B low (!B & A & fA) 00252 delta_pos = 1; 00253 } 00254 } else { //A low 00255 if (chB) { //B high (B & !A & fA) 00256 delta_pos = 1; 00257 } else { //B low (!B & !A & fA) 00258 delta_pos = -1; 00259 } 00260 } 00261 data->current_pos += delta_pos; 00262 data->prev_chA = chA; 00263 } 00264 } else if (flag_chB){ 00265 if (data->prev_chB == chB){ //missed count 00266 error_occurred(ERROR_QEC_MISSED_B); 00267 } else { 00268 if (chA){ //A high 00269 if (chB) { //B high 00270 delta_pos = 1; 00271 }else { //B low 00272 delta_pos = -1; 00273 } 00274 } else { //A low 00275 if (chB) { //B high 00276 delta_pos = -1; 00277 } else { //B low 00278 delta_pos = 1; 00279 } 00280 } 00281 data->current_pos += delta_pos; 00282 data->prev_chB = chB; 00283 } 00284 } 00285 00286 }
unsigned int qec_match_ticks = 0 [static] |
Number of times the overflow (match value) has been reached and the timer reset.
Definition at line 67 of file qec.c.
Referenced by qec_init(), and qec_update_velocity().
VOID_VOID_F qec_overflow_funct = voidvoid [static] |
The function to call when a timer match and reset occurs.
Definition at line 66 of file qec.c.
Referenced by qec_init(), and qec_isr().
unsigned int qec_prev_ticks = 0 [static] |
Previous value of the counter.
Definition at line 68 of file qec.c.
Referenced by qec_update_velocity().