GPIO Interrupt

A catchall for PSoC Mixed-Signal Array (microcontroller) discussions not captured by the other forums.

Moderator: ericb

GPIO Interrupt

Postby bdring on Sun Jan 08, 2006 4:10 pm

I am trying to learn how to use GPIO interrupts. I have written a small program in C to toggle an LED on each button push. It works on the first button push, but not subsequent pushes. Do I need to clear the interrupt in my ISR? If so how? I tried various flavors of M8C_ClearIntFlag(INT_CLR0, INT_MSK0_GPIO);

I am using the PSocEval1 board. I have Port2_2 set to StdCPU, Pull Down, RisingEdge.



Code: Select all
#include <m8c.h>        // part specific constants and macros
#include "PSoCAPI.h"    // PSoC API definitions for all User Modules

#pragma interrupt_handler    PSoC_GPIO_ISR



void main()
{
   PRT2DR = 0;  //set all low for pull down
   
   PRT2DR |= 0x04;  //turn on LED on Port2_2
   
   M8C_EnableGInt;
   M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);


   
    while(1)
    {
   
    }
}

void PSoC_GPIO_ISR()
{   
   PRT2DR ^= 0x04; //flip bit 2   
}
bdring
Newbie
Newbie
 
Posts: 4
Joined: Sun Jan 08, 2006 3:58 pm

Postby mysorenarayan on Sun Jan 08, 2006 7:23 pm

Hi bdring,

There is a small bug in the naming of GPIO ISR assembly routine in psocgpioint.asm file. It is named as “PSoC_GPIO_ISR” instead of “_PSoC_GPIO_ISR”. That has created u the problem.

So in case of GPIO interrupt, do not use the “#pragma interrupt_handler” for your C routine. Just use a call/lcall statement in the psocgpioint.asm.

In main.c
Code: Select all
Void PSoC_GPIO_ISR_IN_C()
{
   PRT2DR ^= 0x04; //flip bit 2
}


in psocgpioint.asm
Code: Select all
PSoC_GPIO_ISR:
   ;@PSoC_UserCode_BODY@ (Do not change this line.)
   ;---------------------------------------------------
   ; Insert your custom code below this banner
   ;---------------------------------------------------
   call   _PSoC_GPIO_ISR_IN_C
   ;---------------------------------------------------
   ; Insert your custom code above this banner
   ;---------------------------------------------------
   ;@PSoC_UserCode_END@ (Do not change this line.)

   reti


Hope this helps
NS
User avatar
mysorenarayan
Cheese Wheel
Cheese Wheel
 
Posts: 71
Joined: Mon May 24, 2004 6:30 am
Location: Mysore, India

Postby bdring on Mon Jan 09, 2006 7:19 pm

Thanks for the reply.

I did notice that and manually renamed it to _PSoC_GPIO_ISR before compiling. The thing that was bugging me was that the ISR seemed to run once, but not again. I will try your suggestion when I get back to my bench.
bdring
Newbie
Newbie
 
Posts: 4
Joined: Sun Jan 08, 2006 3:58 pm

Postby alager on Wed Jan 11, 2006 8:21 am

Depending on the type of interrupt you've selected you may need to "read" the port that the button is on.
Eg. for interrupt on change:
foo=PRT1DR;

Also, I've found it helpfull that before exiting the GPIO ISR to clear pending GPIO interrupts. This will prevent double triggers from happening if you have a slow rise time signal.

Aaron
User avatar
alager
The Big Cheese
The Big Cheese
 
Posts: 506
Joined: Tue Mar 15, 2005 2:26 pm
Location: Peteluma, CA

can't added call for '_PSoC_GPIO_ISR_IN_C'

Postby Ryan on Thu Nov 09, 2006 11:38 am

I tried to do what this thread talks about and I get:
!ERROR psocgpioint.asm[line number unavailable] undefined symbol '_PSoC_GPIO_ISR_IN_C'

when I add
call _PSoC_GPIO_ISR_IN_C

to psocgpioint.asm

I downloaded an example from another thread that has this same line, and it compiles/builds fine.

What do I need to do? My project has only an LCD screen module. Other than modifying the pin to pull down and detect rising edge, I have done nothing.

My code is:
#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include <stdlib.h>
//#pragma interrupt_handler PSoC_GPIO_ISR

void main()
{
LCD_1_Start(); // Initialize LCD
LCD_1_Position(0,0); // Place LCD cursor at row 0, col 0.
LCD_1_PrCString("Edge Detect");
PRT0DR = 0; //set all low for pull down

PRT0DR |= 0x04; //turn on LED on Port0_2

M8C_EnableGInt;
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);

while(1);
}

void PSoC_GPIO_ISR()
{
PRT0DR ^= 0x04; //flip bit 2
LCD_1_Position(1,0); // Place LCD cursor at row 0, col 0.
LCD_1_PrCString("Trigger");
}

Thanks,

Ryan
Ryan
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 22
Joined: Sat Oct 28, 2006 11:46 am

Postby alager on Thu Nov 09, 2006 11:48 am

Uncomment your pragma statemen and add "_C" to the end:
Code: Select all
#pragma interrupt_handler PSoC_GPIO_ISR_C

and then in your boot.asm find the line that looks like:
Code: Select all
   org 38h                 ;GPIO Interrupt Vector
    ljmp   PSoC_GPIO_ISR
    reti

and change it to:
Code: Select all
   org 38h                 ;GPIO Interrupt Vector
    ljmp   PSoC_GPIO_ISR_C
    reti

Then change the name of your function to match:
Code: Select all
void PSoC_GPIO_ISR_C() {
User avatar
alager
The Big Cheese
The Big Cheese
 
Posts: 506
Joined: Tue Mar 15, 2005 2:26 pm
Location: Peteluma, CA

Postby Ryan on Thu Nov 09, 2006 12:10 pm

Now I get
!ERROR boot.asm[line number unavailable] undefined symbol 'PSoC_GPIO_ISR_C'
when I try to build.
Ryan
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 22
Joined: Sat Oct 28, 2006 11:46 am

Postby alager on Thu Nov 09, 2006 12:16 pm

Try adding a prototype to main.h for your ISR function.

Aaron
User avatar
alager
The Big Cheese
The Big Cheese
 
Posts: 506
Joined: Tue Mar 15, 2005 2:26 pm
Location: Peteluma, CA

Postby Ryan on Thu Nov 09, 2006 12:23 pm

No, that didn't work either. I had to create main.h and the dialog had a check box for add to current project. Do I need to do anything else?

I sort of have this working with
//#pragma interrupt_handler PSoC_GPIO_ISR_C
commented out and using the correct name in psocpionint.asm:
call _PSoC_GPIO_ISR_C

There are lots of GPIO interrupt threads out there and these seems to be some disagreement about whether or not to use
#pragma interrupt_handler PSoC_GPIO_ISR_C
and whether you should have to edit boot.asm or psocgpioint.asm. How do I know what is the right approach for my application?

Also, I now seem to be catching only the first rising edge. I think I read in other reads about reseting problems, but if someone knows off the top of their head how to do it, that would be great.

Thanks,

Ryan
Ryan
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 22
Joined: Sat Oct 28, 2006 11:46 am

Postby alager on Thu Nov 09, 2006 12:31 pm

When you say, "that didn't work either" what do you mean? Did it compile?
Is it a run time issue?

Are you debouncing your input in the ISR? If you have a slow rise time then you'll get multiple GPIO interrupts. Also if you have more than one GPIO interrupt set, then you need to figure out which pin caused the ISR to trigger.

Whether to modify the boot.asm or not is a discussion best left to the purists. It really boils down to a few bytes being thrown onto the stack or not.

Aaron
User avatar
alager
The Big Cheese
The Big Cheese
 
Posts: 506
Joined: Tue Mar 15, 2005 2:26 pm
Location: Peteluma, CA

Postby Ryan on Thu Nov 09, 2006 12:35 pm

Sorry, "it didn't work" means that the C code compiles, but I get an error message when I try to build to hex.

I have a button on the PSoCEval1 wired directly to the port. I am not debouncing it (how do I do that?). Here is my code that catches only the first event:

#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include <stdlib.h>
//#pragma interrupt_handler PSoC_GPIO_ISR

//#pragma interrupt_handler PSoC_GPIO_ISR_C
//void PSoC_GPIO_ISR_C(void);

int foo;

void main()
{
LCD_1_Start(); // Initialize LCD
LCD_1_Position(0,0); // Place LCD cursor at row 0, col 0.
LCD_1_PrCString("Edge Detect");
PRT0DR = 0; //set all low for pull down

PRT0DR |= 0x04; //turn on LED on Port0_2

M8C_EnableGInt;
M8C_EnableIntMask(INT_MSK0,INT_MSK0_GPIO); //activate GPIO ISR

while(1);
}

void PSoC_GPIO_ISR_C(void)
{
PRT0DR ^= 0x04; //flip bit 2
LCD_1_Position(1,0); // Place LCD cursor at row 0, col 0.
LCD_1_PrCString("Trigger");
foo=PRT0DR;
M8C_ClearIntFlag(INT_CLR0, INT_MSK0_GPIO);
}

My initial attempt at reading and clearing did not work.

Thanks,

Ryan
Ryan
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 22
Joined: Sat Oct 28, 2006 11:46 am

Postby gilmotta on Mon Jan 15, 2007 5:49 pm

Ryan wrote:Now I get
!ERROR boot.asm[line number unavailable] undefined symbol 'PSoC_GPIO_ISR_C'
when I try to build.


Standard to the PSoC Designer C Compiler and Assembler is an underscore which is implicitly added to C function and variable names. your call from Assembler should be
"_PSoC_GPIO_ISR_C"

Gil
gilmotta
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 10
Joined: Mon Jan 15, 2007 1:20 pm
Location: USA

Postby Peter on Tue Jan 16, 2007 5:07 am

hi!

i also experienced the same problem (led switched once, but then stayed the same).
i used the LED module for better overview, and finally it's working properly :)

my code in "main.c" is: (pushbutton at P1.4, led at P2.0)
Code: Select all
#include <m8c.h>        // part specific constants and macros
#include "PSoCAPI.h"    // PSoC API definitions for all User Modules

#pragma interrupt_handler _PSoC_GPIO_ISR_C

void main()
{

    LED_1_Start();
   M8C_EnableGInt;
   M8C_EnableIntMask(INT_MSK0,INT_MSK0_GPIO);
   
    while(1);
}

void PSoC_GPIO_ISR_C()
{
   LED_1_Invert();
}


in "boot.asm":
Code: Select all
    org   1Ch                      ;GPIO Interrupt Vector
    ljmp   PSoC_GPIO_ISR
    reti


and in "psocpioint.asm":
Code: Select all
PSoC_GPIO_ISR:


   ;@PSoC_UserCode_BODY@ (Do not change this line.)
   ;---------------------------------------------------
   ; Insert your custom code below this banner
   ;---------------------------------------------------
   call _PSoC_GPIO_ISR_C
   ;---------------------------------------------------
   ; Insert your custom code above this banner
   ;---------------------------------------------------
   ;@PSoC_UserCode_END@ (Do not change this line.)

   reti


hope i could help :)
regards peter
Peter
Newbie
Newbie
 
Posts: 2
Joined: Tue Dec 12, 2006 6:08 am
Location: Austria

PSoC GPIO interrupts in C (corrected)

Postby kyoung2112 on Fri May 09, 2008 8:06 am

Peter's code is close but not quite correct.

There are two things that need to be changed in his code:

  1. The #pragma interrupt_handler should reference the C function name without the leading underscore. Note that the underscore is only needed when assembly references C functions and variables. When C references functions and variables declared in C, no underscore is needed. Unfortunately there is no warning when the #pragma interrupt_handler argument is invalid, so putting an underscore here will prevent your ISR handler from getting the proper treatment by the compiler.
  2. The call from psocgpioint.asm needs to be a ljmp instead of a call. Don't worry about the fact that it is jumping and not returning. Your #pragma statement tells the compiler to end the function with reti.

I have modified Peter's code to the correct format here (and kept his comments):

my code in "main.c" is: (pushbutton at P1.4, led at P2.0)
Code: Select all
#include <m8c.h>        // part specific constants and macros
#include "PSoCAPI.h"    // PSoC API definitions for all User Modules

#pragma interrupt_handler PSoC_GPIO_ISR_C

void main()
{

    LED_1_Start();
   M8C_EnableGInt;
   M8C_EnableIntMask(INT_MSK0,INT_MSK0_GPIO);
   
    while(1);
}

void PSoC_GPIO_ISR_C()
{
   LED_1_Invert();
}


in "boot.asm":
Code: Select all
    org   1Ch                      ;GPIO Interrupt Vector
    ljmp   PSoC_GPIO_ISR
    reti


and in "psocpioint.asm":
Code: Select all
PSoC_GPIO_ISR:


   ;@PSoC_UserCode_BODY@ (Do not change this line.)
   ;---------------------------------------------------
   ; Insert your custom code below this banner
   ;---------------------------------------------------
   ljmp _PSoC_GPIO_ISR_C
   ;---------------------------------------------------
   ; Insert your custom code above this banner
   ;---------------------------------------------------
   ;@PSoC_UserCode_END@ (Do not change this line.)

   reti


Regards,
Kris
kyoung2112
Cheese Wheel
Cheese Wheel
 
Posts: 77
Joined: Wed Sep 01, 2004 8:35 am
Location: Atlanta, GA

Postby verticale on Wed May 14, 2008 1:59 am

alager wrote:Depending on the type of interrupt you've selected you may need to "read" the port that the button is on.
Eg. for interrupt on change:
foo=PRT1DR;

Anybody could explain me why in this last example from Peter and Kyoung2112 there is not port reading? (There is no trace in "void PSoC_GPIO_ISR_C()" of the pushbutton at P1.4).
Does it depend on the Interrupt Setting of P 1.4? (FallingEdge, RisingEdge, ChangeFromRead...which one to choose?).
verticale
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 19
Joined: Mon May 05, 2008 6:50 am
Location: Brescia, Italy

Postby kyoung2112 on Wed May 14, 2008 12:37 pm

If you are set to interrupt on change, you will need to read the port in the interrupt to "reset" it. If you are set to rising edge or falling edge, the interrupt will be "reset" when the signal transitions from the interrupt trigger level to the opposite sense and no port read is necessary.
kyoung2112
Cheese Wheel
Cheese Wheel
 
Posts: 77
Joined: Wed Sep 01, 2004 8:35 am
Location: Atlanta, GA

Postby verticale on Thu May 15, 2008 1:57 am

Thank you! Now it is clear to me.
Regards,
Stefano
verticale
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 19
Joined: Mon May 05, 2008 6:50 am
Location: Brescia, Italy

Postby ctorres on Tue May 20, 2008 7:56 am

I have implemented a 3 buttons menu what testing the buttons by polling. Now I want to change it for interrupts. I wrote a little program based in above code. The program has implemented a debounce system.

I am just started in GPIO and I would like to know your opinions and suggestions... you shouldn't be cruel with me please :oops: haha

Code: Select all
#include <m8c.h>        // part specific constants and macros
#include "PSoCAPI.h"    // PSoC API definitions for all User Modules

#pragma interrupt_handler PSoC_GPIO_ISR_C
char buttons[3]={'0','0','0'}; // [push2, push1, push0]

void main()
{

   LED_1_Start();
   M8C_EnableGInt;
   M8C_EnableIntMask(INT_MSK0,INT_MSK0_GPIO);
   
    while(1){
   
    if (buttons[2]=='1'){
          LED_1_Invert();
          buttons[2]='0';
    }
   
    if (buttons[1]=='1'){
          LED_1_Invert();
          buttons[1]='0';
    }
       
    if (buttons[0]=='1'){
          LED_1_Invert();
          buttons[0]='0';
    }   
   
    }
}

void PSoC_GPIO_ISR_C()
{
   
   if (PRT1DR & 0x80){
      LCD_Delay50uTimes(200);LCD_Delay50uTimes(200);      //20 ms delay
      if (PRT1DR & 0x80); buttons[2] = '1';             
   }
   
   if (PRT1DR & 0x40){
      LCD_Delay50uTimes(200);LCD_Delay50uTimes(200);      //20 ms delay
      if (PRT1DR & 0x40); buttons[1]='1';             
   }
   
   if (PRT1DR & 0x20){
      LCD_Delay50uTimes(200);LCD_Delay50uTimes(200);      //20 ms delay
      if (PRT1DR & 0x20); buttons[0]='1';   
   
   }


}
Carlos Torres Martinez
User avatar
ctorres
Cheese Cube
Cheese Cube
 
Posts: 58
Joined: Tue Aug 07, 2007 3:03 am
Location: Granada, Spain

Postby kyoung2112 on Tue May 20, 2008 10:59 am

Carlos,

I would avoid doing your delay within the GPIO ISR. While you are in the ISR, other interrupts can not be processed which could lead to problems with other aspects of your design. What you could do is set a flag in the ISR saying that a button is pressed, and then start a Counter8 module. Have another ISR for the Counter8 in which you check that button again, and if still pressed, declare the button pressed (set your button variable).

Does this make sense?

Regards,
Kris
kyoung2112
Cheese Wheel
Cheese Wheel
 
Posts: 77
Joined: Wed Sep 01, 2004 8:35 am
Location: Atlanta, GA

Postby ctorres on Tue May 20, 2008 11:46 pm

Thank you for your help Kris,

I did you say and I think now it's much better.

This is my new 3 buttons menu with debounce sample code:


Main:
Code: Select all
#include <m8c.h>        // part specific constants and macros
#include "PSoCAPI.h"    // PSoC API definitions for all User Modules

#pragma interrupt_handler PSoC_GPIO_ISR_C
#pragma interrupt_handler PSoC_Counter8_ISR_C

char buttons[3]={0, 0, 0};


void main()
{

   LED_1_Start();
   Counter8_EnableInt();
   M8C_EnableGInt;
   M8C_EnableIntMask(INT_MSK0,INT_MSK0_GPIO);
   
    while(1){
   
    if (buttons[2]==1){
          LED_1_Invert(); //Do something
          buttons[2]=0;
    }
   
    if (buttons[1]==1){
          LED_1_Invert(); //Do something
          buttons[1]=0;
    }
       
    if (buttons[0]==1){
          LED_1_Invert(); //Do something
          buttons[0]=0;
    }   
   
    }
}



PSoC_GPIO_ISR_C:
Code: Select all
void PSoC_GPIO_ISR_C()

     
   if (PRT1DR & 0x80){
      Counter8_Start();               
   }
   
   if (PRT1DR & 0x40){
      Counter8_Start();       
   }
   
   if (PRT1DR & 0x20){
      Counter8_Start();   
   }

}



PSoC_Counter8_ISR_C:
Code: Select all
void PSoC_Counter8_ISR_C()
{
   if (PRT1DR & 0x80){
      buttons[2]=1;
      Counter8_Stop();
   }

   if (PRT1DR & 0x40){
      buttons[1]=1;
      Counter8_Stop();
   }
   
   if (PRT1DR & 0x20){
      buttons[0]=1;
      Counter8_Stop();
   }
   
}


Best regards :wink:
Carlos Torres Martinez
User avatar
ctorres
Cheese Cube
Cheese Cube
 
Posts: 58
Joined: Tue Aug 07, 2007 3:03 am
Location: Granada, Spain

Next

Return to PSoC1 General

Who is online

Users browsing this forum: Bing [Bot] and 1 guest