View previous topic :: View next topic |
Author |
Message |
123bally
Joined: 20 Jan 2013 Posts: 21
|
QEI Velocity Mode - 18f4431 |
Posted: Sun Jan 20, 2013 4:16 pm |
|
|
Hi Really appreciate some help on this:
Trying to use QEI to capture position and speed on a 18f4431. The position presented no problem and works well. Velocity is causing a headache and as MPLAB cannot simulate QEI I feel somewhat in the dark!
My understanding is that if I use the function
count=qei_get_count(QEI_GET_VELOCITY_COUNT);
Then count will have the value of timer 5 loaded and timer 5 will be reset.
I modified my position code but I seem to get no response when I run the encoder.
My rough cut test code below:
Code: |
#include <18F4431.H>
#fuses hs, NOWDT, NOBROWNOUT, PUT, NOLVP,NOMCLR
#use delay(clock = 20000000)
#USE rs232(bAUD=9600,XMIT=PIN_C6, RCV=pin_c7, BITS=8,errors)
#include "flex_lcd.c"
//*********************DEFINITIONS**************
#define Tare PIN_b0
#define Print PIN_B1
#define Alive PIN_B7
// note do note use PINS D0-D3 and Pins B4-B6 as they are reserved for ETAngleMeter-LCD driver
//*********************Variables************************************
signed long count;
float angle;
INT DIRF,ext;
//==========================
void main()
{
set_tris_b(0x03); // B0 - B1 as inputs
set_tris_a(0x3C); // RA2,Ra3,RA4 as input
set_tris_d(0x00);
setup_QEI(QEI_MODE_X4_RESET_with_indx );
setup_QEI(QEI_VELOCITY_PULSE_DIV_1); //add velocity options to original code
setup_QEI(QEI_VELOCITY_MODE_ENABLED);
SETUP_TIMER_5(T5_INTERNAL);
SETUP_TIMER_5(T5_DIV_BY_1);
while(true)
{
//count=qei_get_count(QEI_GET_POSITION_COUNT); //comment out
count=qei_get_count(QEI_GET_VELOCITY_COUNT);//add velocity capture
Angle=count/(float)4;
printf(lcd_putc,"Angle: %5.2f",angle);
}//while loop
} // end main
|
Thanks in advance for all help...
Andy |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9170 Location: Greensville,Ontario
|
|
Posted: Sun Jan 20, 2013 5:13 pm |
|
|
Just a couple of quick comments. While I don't use that PIC, I have used external encoders.
1) Try displaying the raw 'count' onto the LCD or PC screen..
this will confirm/deny the encoder and QEI peripheral is working/coded right.
2) "Angle=count/(float)4;" might not be what you want. Try 'hardcoding' a few numbers in for 'count' and see what is displayed in the print function.
I'm thinking that "angle=float(count/4)" might be the proper casting?
I find it best to break down even 'simple' programs like this, 'hard code' expected test data and see the results. Often it'll show that a couple of braces here a wrong semicolon there cause unexpected results.
Also be sure to list your compiler version as there may be a bug in yours and later versions have been corrected.
hth
jay |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jan 20, 2013 8:01 pm |
|
|
Quote: |
setup_QEI(QEI_MODE_X4_RESET_with_indx );
setup_QEI(QEI_VELOCITY_PULSE_DIV_1); //add velocity options to original code
setup_QEI(QEI_VELOCITY_MODE_ENABLED);
|
CCS functions are not cumulative. You don't add features by calling
setup_qei() multiple times. It should all be done in one call.
Look in the setup_qei() section of the manual. It has a code example
on the next page in the manual, after the function explanation:
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf |
|
![](templates/subSilver/images/spacer.gif) |
123bally
Joined: 20 Jan 2013 Posts: 21
|
|
Posted: Mon Jan 21, 2013 4:41 am |
|
|
Thanks for all the replies:
Temtronic - Appreciate your comments - thanks.
PCM - Thanks for the tip on calling setup functions. Not sure how I have managed for so long without fully appreciating this fact!
I have rewritten the code and got further forward but still struggling with velocity values. Basically I get a value captured but it is very erractic. I am still assuming that:
Enabling velocity mode will capture the value of timer5 and reset the timer to 0 with every velocity trigger event.
Thus COUNT=qei_get_count(QEI_GET_VELOCITY_COUNT); will tell me the time period between events.
So when I run the encoder I am expecting a high value at low speed and a low value at high speed.
What I get is the value is instable, using the whole 16bit range - regardless of speed. (Unless the encoder is stationary then it simply shows a constant but "random" value)
Over a range of 100-1000 rpm on a 360ppr encoder I am expecting velocity values of 37500 - 3750
Note position works fine showing 360 deg with a reset on index
Heres the new code: (CCS PCH version 4.132)
Code: | #include <18F4431.H>
#fuses hs, NOWDT, NOBROWNOUT, PUT, NOLVP,NOMCLR
#use delay(clock = 4000000)
#USE rs232(bAUD=9600,XMIT=PIN_C6, RCV=pin_c7, BITS=8,errors)
#include "flex_lcd.c"
//*********************DEFINITIONS**************
#define Tare PIN_b0
#define Print PIN_B1
#define Alive PIN_B7
// note do note use PINS D0-D3 and Pins B4-B6 as they are reserved for ETAngleMeter-LCD driver
//*********************Variables************************************
unsigned long count,timer;
signed long position;
float angle;
INT DIRF,ext;
//=========================
void main()
{
set_tris_b(0x03); // B0 - B1 as inputs
set_tris_a(0x3C); // RA2,Ra3,RA4 as input
set_tris_d(0x00);
setup_timer_5(T5_INTERNAL|T5_DIV_BY_1); // so timer 5 should roll over every 0.07 sec based on (4MHZ / 4 x 8)
setup_QEI(QEI_MODE_X4_RESET_WITH_INDX|QEI_VELOCITY_MODE_ENABLED|QEI_VELOCITY_PULSE_DIV_64);
delay_ms(15);
count=150;
lcd_init(); // Always call this first.
lcd_putc("\fHello World\n"); //putc - puts a set of characters, in ascii format, to the lcd (\f clears the screen and starts from x0,y0)
printf(lcd_putc,"Count: %6ld",count);
output_high(Alive);
delay_ms(1000);
output_low(alive);
while(true)
{
Position=qei_get_count(QEI_GET_POSITION_COUNT); //get position
COUNT=qei_get_count(QEI_GET_VELOCITY_COUNT); //get time between velocity events
Angle=Position/(float)4; // convert x4 to degrees
printf(lcd_putc,"\f Angle: %5.2f\n",angle); // print angle position
printf(lcd_putc,"count: %lu",count); // print value from get_velocity_count
output_toggle(alive); //
delay_ms(100); //allow LCD some responce time
}//while loop
} // end main
|
Thanks for all your help....
Andy |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Mon Jan 21, 2013 6:02 am |
|
|
I think you will have to read qei_status, and work out which bit is the overflow bit. This will be set when the count goes over 65535, and when this is set you then know your velocity is below the limits of reading.
I'd don't think reset on index is compatible with velocity mode.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
123bally
Joined: 20 Jan 2013 Posts: 21
|
|
Posted: Mon Jan 21, 2013 6:18 am |
|
|
More progress on this....
I had suspected that timer5 was not being reset on a velocity trigger event. That would expalin the inconsistent values. (Please note I have checked bit 6 of cap1ren (1) and it shows that the timer is set to reset on event)
I then found that the IC1IF is triggered by a velocity register update, table 17-7 in data sheet, so I used that interrupt to set the timer to zero. By forcing the reset in this interrupt my code now works!
If anyone can explain why I needed to do this It would be greatly appreciated.
Andy |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Mon Jan 21, 2013 8:13 am |
|
|
It is perhaps informative to look at the MicroChip application notes. AN899 in particular to see how they do this. I'd possibly try directly reading the velocity registers. It sounds rather as if GET_VELOCITY_COUNT is actually returning the count registers, rather than the velocity registers.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
123bally
Joined: 20 Jan 2013 Posts: 21
|
|
Posted: Mon Jan 21, 2013 9:32 am |
|
|
HI Ttelmah
I will check that app note in more detail - Thanks
When you refer to the velocity registers I assume you are refering to CAP1BUF. I can confirm that these are being read ok (0xf68 0xf69) by GET_VELOCITY_COUNT. (checked and confirmed in disassembly listing)
I am just curious as to why timer5 value is not reset. It clearly states that it should be in the data sheet:
PG168 Fig 17-13
3: The TMR5 counter is reset on the next Q1 clock cycle following the “velcap” pulse.
I have implemeted some further refinement to deal with timer 5 rolling over at low speed. Reset on index is working fine with this configuration.
Thanks Andy |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Mon Jan 21, 2013 9:52 am |
|
|
I'm referring to the VELR register. This is what has to be read for velocity.
Look at figure 16-13, which shows the operation. However CAP1BUF, is VELR in this mode.
Important thing is that resetting the counter is optional. You can either have it reset, or leave it running. The latter is used when you want to give an absolute measure for 'position' as well. The former is used when you only want velocity. 16.2.6.3 in the data sheet. You say you have checked CAP1REN though, which would give this operation. Note that in the Microchip note, they don't set this bit, and instead subtract the last reading from the current one. I wonder if there is a fault in the hardware here. Other thing to check is the programming bits of the timer, since this only works if it is running synchronous to the internal clock. It certainly _should_ be, but is it.....
I'd double check the CAP1REN bit. This is the only thing that makes sense. Other thing is note3, on fig 16-13, which says that the postscaler needs to be reset after enabling VELM.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Mon Jan 21, 2013 11:44 am |
|
|
You are reading the value continuously. It is not the act of reading, that resets timer5. It is the capture event trigger. When the capture event fires, the contents of timer5 are saved, and it is then reset.
As far as I can see you have no capture event.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
123bally
Joined: 20 Jan 2013 Posts: 21
|
|
Posted: Mon Jan 21, 2013 12:07 pm |
|
|
Quote: | You are reading the value continuously | --Yes, well every 100ms
Quote: | It is not the act of reading, that resets timer5. It is the capture event trigger. When the capture event fires, the contents of timer5 are saved, and it is then reset. | --completely agree.
Quote: | As far as I can see you have no capture event. | -- The capture event occurs when I run the encoder for 64 ticks as defined by QEI_VELOCITY_PULSE_DIV_64
So if capture events cease (encoder stationary) then it just reports the last captured value - I would agree this needs refinement but serves to prove operation.
I think we are pretty much on the same page with this one, exactly why i need to force timer to zero is a mystery. I am beginning to suspect that the CAP1REN bit may get changed during execution but I double checked and it is configured correctly during initialization. As QEI is not supported by the sim I am probably unable to prove this suspicion.
Makes for an interesting day though!
Andy |
|
![](templates/subSilver/images/spacer.gif) |
|