LPC1114 and Rotary necoder

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC1114 and Rotary necoder

2,433 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Fri Jun 12 16:09:01 MST 2015
Hello all

I have a problem which is literally driving me crazy and I can't solve it.
I want to control a variable "number" with my rotary encoder

Here's the code for initialisation

void controlsinit()
{
//PIO2_5 <-- A
//PIO0_6 <-- B
LPC_GPIO2->DIR &= ~(1<<5);//PIO2_5 as input
LPC_GPIO0->DIR &= ~(1<<6);//PIO0_6 as input

LPC_GPIO2->IS &= ~(1<<5);//edge sensitive
LPC_GPIO2->IBE &= ~(1<<5);//no both edges
LPC_GPIO2->IEV &= ~(1<<5);//falling edge
LPC_GPIO2->IE |= (1<<5);//falling edge

NVIC_EnableIRQ(EINT2_IRQn);
}


And here's the interrupt code
void PIOINT2_IRQHandler(void)
{
if (LPC_GPIO0->DATA & (1<<6)) number--;
else number++;
LPC_GPIO2->IC = LPC_GPIO2->RIS;//clear edge interrupt
delayck(5);
}


So I basically want to increment/decrement the variable number by rotating the knob.
The result is very random. Sometimes it is incrementing/decrementing by one, sometimes by 2 or even 50... sometimes it doesn't change the variable at all. Completely random.

Is there anything wrong with my code?
Labels (1)
0 Kudos
23 Replies

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Sat Jun 20 23:15:09 MST 2015
Did you switch on the hysteresis? Hysteresis is your friend when there are slow edges. See section 7.3.3 and 7.4.1 in the manual.
It will stop the odd behaviour on slow edges.

You don't need a stronger pull-up, 50µA is plenty. if there is any contact bounce it will make the problem worse, and you will just need a bigger capacitor to stop it.
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sat Jun 20 02:22:49 MST 2015

Quote: vladimirro
Without the caps (and without strong pullups too) there's no "weird" behaviour of the interrupts anymore. However the bounces started to occur but that's ok. I'll take care of them in a software way.



I wouldn't recommend to remove them at all, just use smaller caps  :)
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Sat Jun 20 02:04:19 MST 2015

Quote: R2D2

:~  Isn't that today (my time zone: Europe)...



It was too late yesterday for me :>


Quote: vladimirro

The internal pull-up is no real pull-up  :O  It's a 50µA current source...

And that's not much (= weak pull-up). So you should use a strong pull-up (start with 10k) ...



Without the caps (and without strong pullups too) there's no "weird" behaviour of the interrupts anymore. However the bounces started to occur but that's ok. I'll take care of them in a software way.

Thanks for help.
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Fri Jun 19 15:26:09 MST 2015

Quote: vladimirro
Will do tomorrow (my time zone).



:~  Isn't that today (my time zone: Europe)...


Quote: vladimirro
BTW isn't internal pull-up enough?



The internal pull-up is no real pull-up  :O  It's a 50µA current source...

And that's not much (= weak pull-up). So you should use a strong pull-up (start with 10k) ...
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Fri Jun 19 14:52:07 MST 2015

Quote: R2D2

Your rising edge is too slow  :O  Remove all caps and add a pull-up...



Will do tomorrow (my time zone). BTW isn't internal pull-up enough?
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Fri Jun 19 14:14:59 MST 2015

Quote: vladimirro
It seems like it caches the rising edge all the time many times because the rising edge is very slow. But why?



Toggle the pin to see how often the interrupt is triggered  ;-)

Your rising edge is too slow  :O  Remove all caps and add a pull-up...
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Fri Jun 19 13:57:00 MST 2015

Quote: R2D2

Just switch a few pins and scope them  :)



Now we're getting something. Unfortunately I have only two channels on my scope  :((
I'm probing the LED_ON/LED_OFF signal and one of the rotary encoder switcheds. Yellow one is a LED_ON/OFF (inerrupt)

It seems like it caches the rising edge all the time many times because the rising edge is very slow. But why? It is set to capture the falling one.
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Fri Jun 19 13:20:40 MST 2015

Quote: vladimirro
As a newbie I have to ask this. How do you do that? How do you analyse the interrupt signal?



Just switch a few pins and scope them 

void PIOINT2_IRQHandler(void)
{
 LED_ON;
 LPC_GPIO2->IC = LPC_GPIO2->RIS;//clear edge interrupt
 __NOP();__NOP();
 if (LPC_GPIO0->DATA & (1<<3))
 {
  OUT1_ON;
  number++;
 }
 else
 {
  OUT2_ON;
  number--;
 }
 LED_OFF;
}

0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Fri Jun 19 13:10:59 MST 2015

Quote: R2D2

I would expect to see a picture with encoder, interrupt and counter up / down  :O

Something like that:



As a newbie I have to ask this. How do you do that? How do you analyse the interrupt signal?
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Fri Jun 19 12:36:37 MST 2015

Quote: vladimirro

Quote: R2D2

As already suggested it could be useful to test your code without other functions  ;-)

Just generate an input signal (Logic analyzer), switch an output and scope it.

That should help you to understand if the problem is your encoder or parts of your software (SPI)...



Thanks for all the suggestions but I did test it without any functions. It's always the same!



:quest:

So how do you check interrupt and counter?

I would expect to see a picture with encoder, interrupt and counter up / down  :O

Something like that:

[img=1280x269]http://www.lpcware.com/system/files/Encoder_0.JPG[/img]
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Fri Jun 19 12:25:23 MST 2015

Quote: IanB
Switch on the hysteresis on the inputs.

You can get bounce if the signals stay where they are (which they will do with a capacitor across them) and the power supply moves up and down (which it will do if it is from a switching regulator)



When I switched on the hysteresis it indeed increment/decrement the variable. However there was a problem that when I rotated the knob too fast (and I mean two 'ticks'  per second which isn't actually really fast) the variable instead of incrementing subtracted by a big value... and the other way around it was the same.


Quote: IanB

As already suggested it could be useful to test your code without other functions Wink

Just generate an input signal (Logic analyzer), switch an output and scope it.

That should help you to understand if the problem is your encoder or parts of your software (SPI)...



Thanks for all the suggestions but I did test it without any functions. It's always the same!

I'm attaching what I scoped today. I finally managed to download the graphs from the scope...
I did 4 tests. 1 "tick" rotate left 10ms/div, 1 "tick" rotate right 10ms/div, 1 tick rotate left 50us/div and 1 tick rotate left 100ns/div. All those tests caused the variable to add or subtract by a random number from 1 to 50... instead of incrementing decrementing it.
I don't see any bounces, either my scope is a piece of.. or the encoder is fine.

EDIT. the scope outputs are signals from rotary encoder switches.


0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Tue Jun 16 14:40:20 MST 2015
Your GPIO setup should clear the interrupt before enabling it...

 LPC_GPIO2->IE |= (1<<5);//falling edge
[color=#f00] LPC_GPIO2->IC |= (1<<5);//clear int [/color]
 NVIC_EnableIRQ(EINT2_IRQn);

As mentioned already, don't use delays in your ISR. If you want to add a nop, add a nop 

Add volatile 
asm [color=#f00]volatile [/color]("nop");

or just the macro:
 __NOP();

Otherwise nop is optimized out in -Og 

As already suggested it could be useful to test your code without other functions 

Just generate an input signal (Logic analyzer), switch an output and scope it.

That should help you to understand if the problem is your encoder or parts of your software (SPI)...

0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Tue Jun 16 10:57:47 MST 2015
Switch on the hysteresis on the inputs.

You can get bounce if the signals stay where they are (which they will do with a capacitor across them) and the power supply moves up and down (which it will do if it is from a switching regulator)
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Tue Jun 16 10:11:11 MST 2015

Quote: R2D2

I'm still seeing no downloadable code and no picture from your input signal here...



I am attaching the code.
I will attach the input signal as soon as possible...


Quote: starblue

You need to look at it on the millisecond scale, say 10ms per division on the scope.



Yes, the falling edge width was just an additional info.
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by starblue on Mon Jun 15 01:57:32 MST 2015

Quote: vladimirro


Quote: starblue

If your rotary encoder consists of mechanical switches then you need some debouncing.


I have small capacitors in across the switches. I also measured it on the scope and everything looks perfect, no debouncing at all. The falling edge is about 100ns wide.


You need to look at it on the millisecond scale, say 10ms per division on the scope.
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Jun 14 06:24:36 MST 2015

Quote: vladimirro

Quote: R2D2

And of course, test your code [color=#f00]without[/color] other peripherals / interrupts like SPI, SSP, ADC, UART, CAN, Timer, I2C, USB and ADM  :O


Ok, done, still the same results :<



I'm still seeing no downloadable code and no picture from your input signal here...
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Sun Jun 14 05:55:30 MST 2015

Quote: R2D2

And of course, test your code [color=#f00]without[/color] other peripherals / interrupts like SPI, SSP, ADC, UART, CAN, Timer, I2C, USB and ADM  :O


Ok, done, still the same results :<
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Jun 14 05:37:16 MST 2015

Quote: vladimirro
Is there anything wrong with my code?



And of course, test your code [color=#f00]without[/color] other peripherals / interrupts like SPI, SSP, ADC, UART, CAN, Timer, I2C, USB and ADM  :O
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by vladimirro on Sun Jun 14 05:08:25 MST 2015

Quote: R2D2

- Clear interrupts as soon as possible...



Ok.


Quote: R2D2

- Don't use delays in interrupts...



I just followed the UM

Quote:
Remark:
The synchronizer between the GPIO and the
NVIC blocks causes a delay of
2 clocks. It is recommended
to add two NOPs after the clear of the interrupt edge
detection logic before the exit
of the interrupt service
routine



Quote: R2D2

- Use optimization...


Tried all the optimization modes. Always the same result.



Quote: R2D2

Anyway, your code snippet isn't showing very much, so I don't know what you expect  :~



Ok, I removed all the irrelevant parts and here it is:
#ifdef __USE_CMSIS
#include "LPC11xx.h"
#include "pseudospi.h"
#include "controls.h"
#include "bfunc.h"
#endif

#include <cr_section_macros.h>
volatile unsigned int number =100;
const unsigned int numbers[]={0x00,0x00,0x20,0x40,0xfe,0x00,0x00,//1  0
0x00,0x46,0x8a,0x8a,0x92,0x92,0x62,//2  7
0x00,0x44,0x82,0x92,0x92,0x92,0x7c,//3  14
0x00,0x18,0x28,0x48,0x88,0x3e,0x00,//4  21
0x00,0xf4,0x92,0x92,0x92,0x92,0x8c,//5  28
0x00,0x7c,0x92,0x92,0x92,0x92,0x4c,//6  35
0x00,0x00,0x80,0x80,0x86,0x98,0xe0,//7  42
0x00,0x6c,0x92,0x92,0x92,0x92,0x6c,//8  49
0x00,0x64,0x92,0x92,0x92,0x92,0x7c,//9  56
0x00,0x7c,0x82,0x82,0x82,0x82,0x7c};//0 63
int main(void)
{
initpseudospi();
controlsinit();
    while(1)
    {
    clearscr();
    writenumber(7,20,number,&numbers);
    }
}
void PIOINT2_IRQHandler(void)
{
LPC_GPIO2->IC = LPC_GPIO2->RIS;//clear edge interrupt
delayck(2);
if (LPC_GPIO0->DATA & (1<<6)) number++;
else number--;
}


writenumber is a function which displays the number on the LCD
void writecipher(unsigned int page, unsigned int x, unsigned int number,unsigned int* arraynumbers)
{
send_com(0b10110000|page);
send_com(0b00010000|(0b1111&(x>>4)));
send_com(0b00000000|(0b1111&x));
unsigned int numberhelp=typenumber(number);
for (unsigned int i=0;i<7;i++)
{
send_data(arraynumbers[numberhelp+i]);
}
}

void writenumber(unsigned int page, unsigned int x, unsigned int number,unsigned int* arraynumbers)
{
if (number<10)
{
writecipher(page,x,number,arraynumbers);
}
else if (number<100)
{
writecipher(page,x,(number/10),arraynumbers);
writecipher(page,x+7,(number%10),arraynumbers);
}
else if (number<1000)
{
writecipher(page,x,(number/100),arraynumbers);
writecipher(page,x+7,((number/10)%10),arraynumbers);
writecipher(page,x+14,(number%10),arraynumbers);
}
}



Quote: starblue

If your rotary encoder consists of mechanical switches then you need some debouncing.


I have small capacitors in across the switches. I also measured it on the scope and everything looks perfect, no debouncing at all. The falling edge is about 100ns wide.
0 Kudos

2,253 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by starblue on Sun Jun 14 04:38:31 MST 2015
If your rotary encoder consists of mechanical switches then you need some debouncing.

Alternatively you could try triggering the interrupt on both edges and count in opposite directions, that way the bounces might cancel.
0 Kudos