CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

QEI on dsPIC33

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
AlastairM



Joined: 28 Apr 2008
Posts: 28

View user's profile Send private message

QEI on dsPIC33
PostPosted: Wed Mar 27, 2013 8:38 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 27, 2013 9:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 28, 2013 6:03 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 28, 2013 8:09 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 28, 2013 9:08 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 28, 2013 5:12 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Mar 29, 2013 3:28 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Mar 31, 2013 3:39 pm     Reply with quote

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! Evil or Very Mad
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

View user's profile Send private message

PostPosted: Mon Apr 01, 2013 1:24 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 01, 2013 10:01 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 01, 2013 11:52 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 01, 2013 2:05 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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