|
|
View previous topic :: View next topic |
Author |
Message |
AlastairM
Joined: 28 Apr 2008 Posts: 28
|
QEI on dsPIC33 |
Posted: Wed Mar 27, 2013 8:38 am |
|
|
Hi,
I am using a dsPIC33EP64MC504
compiler 4.141
Window 7 64-bit
I'm sensing the position of a 10000 pulses/rev encoder
I intend to use a x4 setting to give 0 - 39999 positions / rev
Code: |
#pin_select QEA1=PIN_B2
#pin_select QEB1=PIN_B1
#pin_select INDX1=PIN_B0
setup_qei(QEI_MODE_X4 | QEI_RESET_WHEN_IDX | QEI_IDX_WHEN_A1_B1,
QEI_FILTER_ENABLED | QEI_FILTER_DIV_1,
0, 0, 0, 39999);
|
The positive direction works OK i.e. after 39999 the count resets to zero (due to the index pulse) but in a negative direction the counter rolls over to 2^16. I had intended for MAXCOUNT (39999) to be loaded automatically.
I have tried many, many combinations of settings and stared at the datasheet for ages! Any help would be appreciated.
the header file is:
Code: |
////////////////////////////////////////////////////////////////// QEI
// QEI Functions: setup_qei(), qei_set_count(), qei_get_count(),
// qei_status(), qei_set_index_count(), qei_get_index_count(),
// qei_get_velocity_count(), qei_get_interval_count(),
// qei_get_capture()
//
// Constants used in setup_qei() first param are:
#define QEI_DISABLED 0x10000
#define QEI_MODE_X4 0x20000
#define QEI_MODE_TIMER_EXTERNAL_UPDOWN_EXTERNAL 0x20001
#define QEI_MODE_TIMER_EXTERNAL 0x20002
#define QEI_MODE_TIMER_INTERNAL 0x20003
#define QEI_TIMER_GATED 0x20004
#define QEI_COUNT_NEGATIVE 0x20008
#define QEI_TIMER_DIV_1 0x20000
#define QEI_TIMER_DIV_2 0x20010
#define QEI_TIMER_DIV_4 0x20020
#define QEI_TIMER_DIV_8 0x20030
#define QEI_TIMER_DIV_16 0x20040
#define QEI_TIMER_DIV_32 0x20050
#define QEI_TIMER_DIV_64 0x20060
#define QEI_TIMER_DIV_256 0x20070
#define QEI_IDX_WHEN_A1_B0 0x20100 // for 4X mode
#define QEI_IDX_WHEN_A0_B1 0x20200 // for 4X mode
#define QEI_IDX_WHEN_A1_B1 0x20300 // for 4X mode
#define QEI_RESET_WHEN_IDX 0x20400
#define QEI_INITIALIZE_ON_NEXT_IDX 0x20800
#define QEI_INITIALIZE_ON_FIRST_IDX_AFTER_HOME 0x20C00
#define QEI_INITIALIZE_ON_SECOND_IDX_AFTER_HOME 0x21000
#define QEI_RESET_WHEN_EQUAL 0x21400
#define QEI_MODULO_COUNT_MODE 0x21800
#define QEI_STOP_WHEN_IDLE 0x22000
// Constants used in setup_qei() second param are:
#define QEI_QEA_INVERTED 0x0010
#define QEI_QEB_INVERTED 0x0020
#define QEI_IDX_INVERTED 0x0040
#define QEI_HOME_INVERTED 0x0080
#define QEI_SWAP_AB 0x0100
#define QEI_OUTPUT_DISABLED 0x0000
#define QEI_OUTPUT_HIGH_GE 0x0200 // when POSxCNT >= QEIxGEC
#define QEI_OUTPUT_HIGH_LE 0x0400 // when POSxCNT <= QEIxLEC
#define QEI_OUTPUT_HIGH_LE_GE 0x0600 // when QEIxLEC >= POSxCNT >= QEIxGEC
#define QEI_FILTER_DIV_1 0x0000
#define QEI_FILTER_DIV_2 0x0800
#define QEI_FILTER_DIV_4 0x1000
#define QEI_FILTER_DIV_8 0x1800
#define QEI_FILTER_DIV_16 0x2000
#define QEI_FILTER_DIV_32 0x2800
#define QEI_FILTER_DIV_64 0x3000
#define QEI_FILTER_DIV_256 0x3800
#define QEI_FILTER_ENABLED 0x4000
#define QEI_HOME_TRIGGERS_CAPTURE 0x8000
// Constants used in setup_qei() third param are: //Forth param is less then or equal compare value, Fifth param is greater then or equal compare value, Sixth param is initilization value
#define QEI_IDX_INT_ENABLED 0x0001
#define QEI_HOME_INT_ENABLED 0x0004
#define QEI_VELOCITY_INT_ENABLED 0x0010
#define QEI_POS_HOMING_INT_ENABLED 0x0040
#define QEI_POS_OVERFLOW_INT_ENABLED 0x0100
#define QEI_POS_LE_INT_ENABLED 0x0400
#define QEI_POS_GE_INT_ENABLED 0x1000
// Constants returned from qei_status() are:
#define QEI_IDX_INT 0x0002
#define QEI_HOME_INT 0x0008
#define QEI_VELOCITY_OVERFLOW_INT 0x0020
#define QEI_POS_REINITIALIZED_INT 0x0080
#define QEI_POS_OVERFLOW_INT 0x0200
#define QEI_POS_LE_INT 0x0800 // POSxCNT <= QEIxLEC
#define QEI_POS_GE_INT 0x2000 // POSxCNT >= QEIxGEC
#define QEI_QEA_HIGH 0x10000
#define QEI_QEB_HIGH 0x20000
#define QEI_INDEX_HIGH 0x40000
#define QEI_HOME_HIGH 0x80000
|
Last edited by AlastairM on Sun Mar 31, 2013 3:49 pm; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Mar 27, 2013 9:04 am |
|
|
Have a look at P1MOD in the data sheet. It sounds as if you are after option 010, rather than 001?.
If so that is QEI_INITIALIZE_ON_NEXT_IDX, rather than QEI_RESET_WHEN_IDX.
Probably wrong, but see what it does.
Best Wishes |
|
|
AlastairM
Joined: 28 Apr 2008 Posts: 28
|
|
Posted: Thu Mar 28, 2013 6:03 am |
|
|
Your suggestion of QEI_INITIALIZE_ON_NEXT_IDX stops my count resetting at the index.
at the moment I have
Code: | setup_qei( QEI_MODE_X4 | QEI_RESET_WHEN_IDX | QEI_IDX_WHEN_A1_B1,
QEI_OUTPUT_DISABLED,
0, 0, 0, 39999);
|
This counts up to 39999 and then resets correct to 0 but in a negative direction there is a roll over to 65535.
If I change QEI_IDX_WHEN_A1_B1 to the other options it stops resetting so might it be a too short index pulse?
The dsPIC family datasheet has different registers and descriptions to this device's datasheet! So I'm reduced to alot of assumptions.
My requirement is the normal configuration for an encoder so am I missing the obvious?
Code: | 207004 mov.w #0x700,w4
047A 880E04 mov.w w4,0x01c0
047C EF21C2 clr.w 0x01c2
047E EF21C4 clr.w 0x01c4
0480 EF21E0 clr.w 0x01e0
0482 EF21E2 clr.w 0x01e2
0484 EF21DC clr.w 0x01dc
0486 EF21DE clr.w 0x01de
0488 EF21CA clr.w 0x01ca
048A EF21C6 clr.w 0x01c6
048C EF21DA clr.w 0x01da
048E EF21D6 clr.w 0x01d6
0490 EF21CC clr.w 0x01cc
0492 A8E1C1 bset.b 0x01c1,#7 |
as an aside what is the register 0x01c1 (last line)? I couldn't ind it in the datasheet! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Thu Mar 28, 2013 8:09 am |
|
|
0x1C1, is not used. There are some bits of CCS code, where it is written for a family of chips with some lacking registers, that they write to ones that don't exist on some chips....
On the QEI_INITIALIZE_ON_NEXT_IDX, it should load the count with the contents of the QEI1IC register. Try loading this with 39999, and see what then happens.
I can't actually see a mode that will set it to 0 in the forward direction, and 39999 in the reverse. I'd suspect you'd have to switch modes in the direction change interrupt routine, to get the behaviour you want.
Best Wishes |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Thu Mar 28, 2013 9:08 am |
|
|
OK.
You are meant to either have the counter reset on the count (in which case it will wrap to 0 if travelling forwards, or MAXCNT if travelling backwards), or on the index which does the same. If it reaches MAXCNT+1, in the forward direction, or FFFF going backwards _without seeing an index_, it'll raise the error flag, and trigger a CNTERR interrupt. It sounds as if this may be happening to you. How long is the index pulse. Are you sure it covers your test state "QEI_IDX_WHEN_A1_B1" in both directions?. It'd behave like you are seeing if the pulse wasn't on in this state in the 'down' direction. You can try the other three trigger options and see if one works?.
Remember there are four trigger locations in the cycle. Leaving this spec out, gives the fourth option.
If you have a logic analyser, record the states of the A and B lines when the index triggers.
Best Wishes |
|
|
AlastairM
Joined: 28 Apr 2008 Posts: 28
|
|
Posted: Thu Mar 28, 2013 5:12 pm |
|
|
The encoder is a DFS60 giving the following waveforms:
they look correct to me.
I got this response from CCS tech help:
Quote: | There is no way to get the hardware to automatically have it rollover from 0 to 39999. The index pulse will reset the counter to zero when ever it see's it. The only way to get it to do what you want is to enable the QEI index interrupt and then detect the direction in the ISR and set the counter to 39999 if it is counting down. |
Am I missing something here? Isn't this the basic way that an encoder would be connected - why isn't this built into the hardware?
Anyway time to code the interrupt...
(Thanks for your help Ttelmah!) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Mar 29, 2013 3:28 am |
|
|
I agree with you (and the Microchip notes on the QEI also agrees).....
You have presumably got document 70208C from Microchip?.
Section 15.5.3 describes exactly what you are trying to do, and in particular the right hand side of figure 15-9.
As far as you are concerned, the critical bit is that your index pulse is a 'gated' index pulse, so only occurs for one state of the decoder. In your case, both QEA, and QEB high. So IMV, needs both these bits set 'high'. So bits 10-9 of DFLTxCON=11. Now looking at the CCS defines, this agrees with the state you are using - QEI_IDX_WHEN_A1_B1.
Aargh. I was hoping you had got this wrong (then an easy fix....).
I have used the QEI, on another chip, and here it worked OK.
However the thing that started 'worrying' me, is that in the Microchip application sheet, the state that would appear to be 'right' for QEIM, is 110. X4 mode with position counter reset on index. The state given by the CCS 'QEI_RESET_WHEN_IDX' setting, bears no resemblance to this.
However it then gets worse. You talk about having had 'fun' trying to identify the registers. The phrase 'gurgle gurgle', describes what happens to your mind when you do try this.
The QEIM bits are not listed anywhere in the data sheet.
The IMV bits which according to the application notes are in DFLT1CON, are listed in the data sheet in QEI1CON instead, where the QEIM bits should be.
It's as if the QEI on this chip is 'half missing', with several of the registers/configurations not being available.
Unless there is an undocumented feature from Microchip (ask them), it appears that CCS's reply to you may be right. The chip doesn't have the register settings to allow the QEI to correctly reset on index in the -ve direction....
There seems to be a great big chunk of the peripheral missing on the EP family chips (I've used FJ).
So the easiest way I can see to do what you want, would be to set the MAXCNT value slightly above the value between indexes. Enable an interrupt on index, and then check the count direction, and if it is 'up' set the count back to zero, while if it is down, set it to your 39999.
Whoever designed this part at Microchip, should be ceremonially flogged!...
A warning. On the DsPIC33EP, somebody has butchered the QEI peripheral, and left out several quite important parts. :(
Best Wishes |
|
|
AlastairM
Joined: 28 Apr 2008 Posts: 28
|
|
Posted: Sun Mar 31, 2013 3:39 pm |
|
|
with some help from CCS tech support I've got this working.
Code: | #INT_QEI
void qei_isr(void)
{
static signed int32 PrevIndex = 0, CurrIndex;
CurrIndex = qei_get_index_count();
if(CurrIndex < PrevIndex) qei_set_count(39999);
PrevIndex = CurrIndex;
} |
Code: | setup_qei(QEI_MODE_X4 | QEI_RESET_WHEN_IDX | QEI_IDX_WHEN_A1_B1,
QEI_OUTPUT_DISABLED ,
QEI_IDX_INT_ENABLED,
0,
0,
0);
enable_interrupts(INT_QEI);
enable_interrupts(INTR_GLOBAL); |
I don't think this basic functionality should be missing from this family and also where is all the documentation CCS? I shouldn't have to mine the datasheets and registers!
The help file is not relevant for this part and there is insufficient documentation against each define in the header file. And functions that aren't even mentioned!
PS be extra careful when looking for the family datasheets - I was using the dsPIC33F instead of the dsPIC33E for a while! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Apr 01, 2013 1:24 am |
|
|
Yes, and no.
If CCS were to try to make their documentation cover every little variation in the PIC's, it'd be about a million pages long. This is what data sheets are _for_. However the real pity is that MicroChip's data sheets have gone downhill so much. Their older sheets told you everything about a chip. Because the chips have got so complex, this has become impossible even for them, so they instead reference you to the generic documents for the peripheral (first thing is that this should really be an automatic link in the pdf sheets), but then these generic documents, are simply 'wrong' in many cases. As here where the generic document covers the 'full' QEI as fitted to the 'F' chips, yet the 'E' chips have got bits missing....
To program hardware, you should expect to have to study the data-sheets.
Best Wishes |
|
|
AlastairM
Joined: 28 Apr 2008 Posts: 28
|
|
Posted: Mon Apr 01, 2013 10:01 am |
|
|
Yes they are too complicated to expect to be spoonfed but it doesn't take much to have.
Code: | ////////Fuses:
////////peripheral pin select:
//////// NOIOL1WAY multiple reconfiguration
//////// IOL1WAY single reconfiguration
//////// oscillator pun OSC2:
//////// NOOSCIO OSC2 is general purpose IO
etc...
|
rather than a mass of undocumented header file
Code: | //////// Fuses: NOOSCIO,NOIOL1WAY,IOL1WAY,CKSFSM,CKSNOFSM,NOCKSNOFSM,FRC
//////// Fuses: FRC_PLL,PR,PR_PLL,LPRC,FRC_PS,NOPWMLOCK,PWMLOCK,NOIESO,IESO
//////// Fuses: WRT,NOWRT,PROTECT,NOPROTECT |
(I wouldn't allow this in any commercial code!)
The header file #defines for peripherals should have just a few words against each one even if it's just the correct relevant Microchip bit / register names so it's easier to search the datasheet.
It's no problem if you use the same devices every design but surely everyone when designing with a new chip have the same problems?
As for missing function documentation An easy way would be to provide a file with all the in-built function prototypes (is there one?)
if I had access to the prototypes such as for the undocumented qei_get_index_count() I would at least know what size variables it's expecting! rather then dredging the datasheet.
Regards
Al |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Apr 01, 2013 11:52 am |
|
|
Have you looked in the file fuses.txt that CCS supply?....
Don't blame them if you don't read the data they supply.
Best Wishes |
|
|
AlastairM
Joined: 28 Apr 2008 Posts: 28
|
|
Posted: Mon Apr 01, 2013 2:05 pm |
|
|
Quote: | Have you looked in the file fuses.txt that CCS supply?.... |
Anyone else spotted that file - I haven't after 6 years!
That format of description in each header file would be perfect.
It's also reasonable to expect a proper entry in the help file for each in-built function. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|