vector table modification......

24 Mar 2010

Hi,

 

I want to write an isr routine at the vector location 0x000BC (QEI interrupt).(LPC 1768)

Please let me know how do i put my isr in the above vector location so that when the hardware interrupt occurs i can perform my specified task.

 

Regards,

 

Dhaval

24 Mar 2010

There are two ways to have your own interrupt handler.

First, let the linker do it. Just declare your handler as following:

extern "C" void QEI_IRQHandler()
{
//handler code
}

Another way is to install the handler dynamically:

NVIC_SetVector(QEI_IRQn, (uint32_t)QEI_IRQHandler);

In both cases you might need to enable the interrupt in the NVIC, and optionally set priority.

NVIC_SetPriority(QEI_IRQn, 0);  /* highest priority */
/* Enable the Interrupt */
NVIC_EnableIRQ(QEI_IRQn);

 

See also a sample program from Simon Blandford (he used ADC interrupt): http://mbed.org/users/simonb/programs/ADC_test/5zlnn/

24 Mar 2010

Hi Igor,

this is the program i have written in which when position conter = position compare 0 my qei interrupt isr should run.

Please verify if poss. all macros are initialsed from my side properly.


#include "mbed.h"
#include "define.h"

Serial pc(USBTX,USBRX);
DigitalOut output(p5);
DigitalOut led(LED1);

#define enable_qei_interrupt {NVIC->ISER[0] &= 0x7FFFFFFF; NVIC->ISER[0] |= 0x80000000;}
#define qei_config_reg {LPC_QEI->QEICONF = 0x00000006;}
#define qei_enable_clear {LPC_QEI->QEIIEC = 0xFFFFFFFF;}
#define position_compare0_load {LPC_QEI->CMPOS0 = 0x00000004;}


void init_qei( ) {
power_qei_peripheral;
clk_sel_cclk;
pinsel_portpins;
configure_pullup;
position0_equal_currentposition_enable;
position_compare0_load;
qei_config_reg;
NVIC_SetPriority(QEI_IRQn, 0);  /* highest priority */
NVIC_EnableIRQ(QEI_IRQn);       /* Enable the Interrupt */
}


extern "C" void QEI_IRQHandler()

{
output.write(1);
wait_us(25);
output.write(0);
reset_position_counter;

}

int main() {

init_qei();
while (1);
}

24 Mar 2010

I am trying to execute this 1 but its nt working............please suggest me the changes.I think the interrupt initialization is a problem............

25 Mar 2010

he guys i am stuck with the above program please suggest me the solution for it.

25 Mar 2010

Sorry, I'm not familiar with QEI so can't say how to configure it.

25 Mar 2010

Hi Dhaval,

If you take a look at http://ics.nxp.com/support/documents/microcontrollers/all/?scope=LPC1768, there is a code example bundle:

That appears to have a QEI example in it which may be helpful to demonstrate how to use this device.

For people to be able to help you with your problem, it might be worth giving a bit more context, and discussing what you've tried, what is working, and where the problem seems to be. This driver example should probably highlight the problem however, so take a look at that.

Simon

28 Mar 2010

he thank you all guys.......i am done with encoder stuff and its working great.....if any 1 requires help regarding this i will be more than happy to help....

 

Dhaval

12 Oct 2010

Dhaval

Would it be possible to see your code for setting up the QEI and reading position?  I dont like the idea of being speed limited by using the simple QEI library rather than the native QEI hardware interface.  Any help would be greatly appreciated.

Matt

buckeyes1997@yahoo.com

13 Oct 2010

Dear Matt

The code is shown below

This function first initialises the qei with all the registers set to their default values and then modifies the registers for my application. Here i have configured the QEI interrupt for compare position 0. And the compare position 0 register is preloaded to 1. so i get an interrupt for every "absolute forward" motion tick. That might not be necessary for your application.

The register LPC_QEI->QEIPOS holds the current position value. It is a read only register. So an instruction like

variable = LPC_QEI->QEIPOS; would load the current value in the variable.

I have not tried this myself (not neede for my application) but am sure that it will work.

The default clock for all peripherals is CCLK/4. So though the core operates at 96MHz, the peripherals will operate at 24MHz. so an instruction is used to make the QEI peripheral clock equal to core clock.

The QEI is used in x4 mode so that i get a pulse (internal) for every rising as well as falling edges of both the phase a and b. So you have an encoder of say 2500 ppr,effectively you will get 10000 ppr in the QEI position register.

void init_qei(void) {
LPC_SC->PCONP &= 0xFFFBFFFF;
LPC_SC->PCONP |= 0x00040000;    // power up the QEI peripheral
/* reset alll the QEI registers to their default (reset) values */
LPC_QEI->QEICON = 0;
LPC_QEI->QEICONF = 0;
LPC_QEI->QEIMAXPOS = 0;
LPC_QEI->CMPOS0 = 0;
LPC_QEI->CMPOS1 = 0;
LPC_QEI->CMPOS2 = 0;
LPC_QEI->INXCMP = 0;
LPC_QEI->QEILOAD = 0;
LPC_QEI->VELCOMP = 0;
LPC_QEI->FILTER = 0;
LPC_QEI->QEICLR = 0xFFFFFFFF;
LPC_QEI->QEIIEC = 0xFFFFFFFF;
LPC_QEI->QEIIES = 0;
/* configure the qei for my application*/
LPC_SC->PCLKSEL1 &= 0xFFFFFFFE;
LPC_SC->PCLKSEL1 |= 1;      // QEI clock selection
// QEI clock = core clock = 96MHz
LPC_PINCON->PINSEL3 &= 0xFFFF3CFF;
LPC_PINCON->PINSEL3 |= 0x00004100;  // set pha and phb as inputs
LPC_PINCON->PINMODE3 &= 0xFFFF3CFF;
LPC_PINCON->PINMODE3 |= 0;          // set pha and phb to pull up mode
LPC_QEI->QEICONF &= 0xFFFFFFF9;
LPC_QEI->QEICONF |= 4;              // select sigmode and x4 mode
LPC_QEI->QEIMAXPOS = 0xFFFFFFFF;    // set the max encoder position
LPC_QEI->CMPOS0 = 1;                // set compare position 0 value
LPC_QEI->QEIIES = 0x00000040;       // enable position 0 compare interrupt
}

hope this helps

Rahul

08 Jan 2011

Hi Rahul,

What is the interrupt fuction heading, and how is this linked to the vector table?

John

10 Jan 2011

Hi John,

The QEI interrupt handler code was not listed in the previous post. It is the QEI initialization function only. The interrupt handler is shown below

void QEI_IRQHandler (void) {
unsigned int mask;
mask = LPC_QEI->QEIINTSTAT & 64;    // mask the QEI interrupt status register
// to extract the position compare 0 interrupt
switch (mask) {
case(64):
LPC_QEI->QEICLR = 0xFFFFFFFF;   // clear the position 0 and all the other interrupts
LPC_QEI->QEICON = 1;    // reset the counter position
output1 = !output1;     // toggle the outputs -- this is specific to my project
output2 = !output2; // this is specific to my project
led3 = !led3; // this is specific to my project
led4 = !led4; // this is specific to my project
led1 = !led1; // this is specific to my project
break;
default:
LPC_QEI->QEICLR = 0xFFFFFFFF;   // clear the position 0 and all the other interrupts
break;
}
}

In this code I am looking out for campare position 0 interrupt only and hasve to take some actions based on that.

Hope this clarifies the matter

Rahul

10 Jan 2011

Thanks Rahul,

I think I now have all the pieces. The project board is being assembled, this week, so next week will be the moment of truth.

A couple of things that might help you. I have been using motor mounted optical encoders for a number of years, and mostly using FPGA code to generate position error values for servo loop control. From this I've learned two things:

1. While the motor may only be set to rotate one way. Motor shafted vibration will result in some backward encoder counts mixed in with a lot of forward counts, so you have to detect both up and down positions changes with the interrupt or you will loose track.

2. Motors are great noise generators so it is good to to add a low pass filter on the A and B inputs. My encoders are rated for 100KHz, so a 1Mhz filter does a good job of limiting the noise. There is some mention of a built in filter as part of the QEI block. I am going to explore how that works, but I have also made provision for simple RC filters on the project board just to be sure

John

10 Jan 2011

Jophn -

You might also be interested in the driver for the qei hardware found on my notebook page. It supports use-added interrupts, hardware noise filters, etc.

See http://mbed.org/users/hexley/libraries/QEI_hw/lk55sm, with hardware notes at http://mbed.org/users/hexley/notebook/qei_hw-interface-implementation-notes/.

-hb

26 Mar 2012

When writing interrupt handlers in C, there's usually some way of telling the compiler that the code in question is an interrupt handler and that the compiler should generate additional instructions to save the current context, i.e. to push all of the registers onto the stack. I don't see anything like that going on here. How can I be sure my interrupt handler won't corrupt the registers?

26 Mar 2012

Hugh S wrote:

When writing interrupt handlers in C, there's usually some way of telling the compiler that the code in question is an interrupt handler and that the compiler should generate additional instructions to save the current context, i.e. to push all of the registers onto the stack. I don't see anything like that going on here. How can I be sure my interrupt handler won't corrupt the registers?

The Cortex-M3 NVIC takes care of it for you. It automatically pushes all volatile registers that may be be spoiled by compiled code (R0-R3, R12, PC, PSR and LR) and restores them on exit from the interrupt handler. This means the compiler does not have to do anything additional compared to standard housekeeping for normal functions.