You are here

PSoC 1 GPIO Demystified - Part 2 | Cypress Semiconductor

PSoC 1 GPIO Demystified - Part 2

In Part-1 we looked at the features of the PSoC1 GPIO.  In this part, let us look at application scenarios.

WRITING TO A GPIO PIN

To control a GPIO using the CPU, first the GPIO pin should be set to StdCPU mode in the GPIO configuration window in device editor.  This will clear the corresponding bit in the PRTxGS register disconnecting the pin from the Global bus.  The drive mode should be set to any mode other than HighZ or HighZ Analog.  Now the pin may be controlled by writing to the PRTxDR register.  Following are some examples in assembly and C.

Assembly Examples:

or reg[PRT1DR], 0x02     ; Set P1[1]
and reg[PRT1DR], ~0x80   ; Clear P1[7]
xor reg[PRT0DR], 0x04    ; Toggle P0[2]

 

C Examples:

PRT1DR |= 0x02;     // Set P1[1]
PRT1DR &= ~0x80;    // Clear P1[7]
PRT0DR ^= 0x04;     // Toggle P0[2]

Notes:

  • M8C.inc file has the register definitions for assembly and m8c.h file has the register definitions for C.
  • While writing in assembly make sure that the Register bank is set to 0 before writing to the PRTxDR register.  Register bank may be set to 0 by using the M8C_SetBank0 macro
  • While using C, the compiler takes care of register bank switching.

However, this method has a disadvantage that it is not portable.  For example, let us say we have placed an LED on P0[5] and have used PRT0DR to control the LED.  Later in the design cycle of the project, the LED is to be moved to P1[2].  Now we will have to search all the locations in the project where PRT0DR is accessed and change this to PRT1DR.  Using Pin names will solve this problem.  Below is the procedure.

1.    Give a meaningful name to the pin to be controlled.  For example “LED”
2.    PSoC designer generates include files called psocgpioint.inc and psocgpioint.h, which has defines for the registers and masks for the pins.
3.    Include psocgpioint.inc or psocgpioint.h file in the C or assembly source file.  Now the pins can be controlled by using code like:

LED_Data_ADDR |= LED_MASK;  // C Code
or reg[LED_Data_ADDR], LED_MASK   ; Assembly code

Now, if the LED were to be moved to any other port, the register definition in the psocgpiont.inc and psocgpioint.h files will be automatically updated by the PSoC designer and there will be no need to change the application code.

READING A GPIO PIN

The state of a GPIO can be read by reading the PRTxDR register.  One important thing to bear in mind is that the PRTxDR register reflects the state of the GPIO pin, not the value that was written to the register.  For example, if you had written a 1 to a GPIO pin configured as a pull up and when reading the PRTxDR register, if the pin were shorted to GND externally, the value read from the PRTxDR will be 0, not 1.  This behavior gives rise to some interesting but unwanted situations which are explained in the next section on Read Modify Write operations.

Following are C and Assembly code examples to read from a GPIO pin.  Either the PRTxDR can be directly used or register and mask names from psocgpioint include files can be used.  In the below examples, an input pin named SWITCH is read.

Assembly Example:

mov A, reg[SWITCH_Data_ADDR]
and A, SWITCH_MASK
jnz PinHigh
; Pin state is Low
PinHigh:
   ; Pin state is high.

C Example:

if (SWITCH_Data_ADDR & SWITCH_MASK)
{
    // Pin is set.  Add code to process
}

Notes:

  • When a GPIO pin has to be configured as a digital input, set the drive mode to HighZ, not HighZ Analog.  As the Schmitt trigger section in the GPIO cell is disabled in the HighZ Analog mode, the state of the PRTxDR register bit corresponding to the pin will always be zero.
  • When a pin is configured for Pull Up mode, for example to read an external switch connected between the pin and GND, a 1 has to be written to the PRTxDR register bit to enable the pull up resistor.  Similarly, when a GPIO is configured in Pull Down mode, a 0 has to be written to the PRTxDR register bit.

READ MODIFY WRITE INSTRUCTIONS AND SHADOW REGISTERS

When you have input pins configured as Pull Up or Pull Down, and if there are other pins on the same port which are configured as output pins, an instruction that is used to update an output pin may accidentally set or clear the input pin thus latching the input.  For example let us consider the following scenario.

P1[0] - PullUP, Connected to a switch. 1 has been written to the bit in PRT1DR to enable the pullup
P1[1] - Strong, drives an LED.

Now, the following instruction is used to switch off the LED

and reg[PRT1DR],~0x02

The above instruction is a Read/Modify/Write instruction, ie, it first reads the pin states (not the value written to PRT1DR register before), does an “AND” operation with the mask and then writes back the result to PRT1DR register.  If the switch were pressed when this instruction is executed, the pin state of P1[0] would be 0, so the result of the operation would be

Pin State: x x x x x x x 0
AND operation: (x x x x x x x 0) & (11111101) = x x x x x x 0 0
Write back: x x x x x x 0 0

Bit-0 which drives the switch has been cleared in PRT1DR now and will never become high.  This will result in the input pin stuck to 0, irrespective of the state of the switch.

A workaround for this condition is using Port shadow registers. Declare a variable in RAM and initialize this variable in the beginning of code to the initial Port value. After this, do any Read/Modify/Write operation on this shadow register and then write the value of shadow register to the PRTxDR register.

// Declare a shadow register
BYTE Port1Shadow;
// Initialize in the beginning of code
// Bit0 is set to enable the Pullup for the key
Port1Shadow = 0x01;
PRT1DR = Port1Shadow;
// Now to clear the LED
Port1Shadow &= ~0x02;
PRT1DR = Port1Shadow;

WRITING A GPIO ISR

Now, let us configure a GPIO pin for interrupt and write an ISR that increments a variable “IntCount”.  In the Device Editor GPIO configuration, set the interrupt to the desired type.  The PSoC Designer will take care of the PRTxIE and PRTxICx registers in the boot.asm code

In main, enable the Global interrupt by using the M8C_EnableGInt macro

In main,enable the GPIO interrupt by using the below code.

M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);   // C code to enable GPIO interrupt
M8C_EnableIntMasm INT_MSK0, INT_MSK0_GPIO   ; Assembly code

Whenever a pin is enabled for interrupt in the PSoC Designer Device editor, the IDE generates a file called psocgpioint.asm.  This file has the place holder to write an ISR for the GPIO interrupt.  The following code should be added within the user code marker in the ISR function.

PSoC_GPIO_ISR:
    
   ;@PSoC_UserCode_BODY@ (Do not change this line.)
   ;---------------------------------------------------
   ; Insert your custom code below this banner
   ;---------------------------------------------------
   inc [IntCount]
   ;---------------------------------------------------
   ; Insert your custom code above this banner
   ;---------------------------------------------------
   ;@PSoC_UserCode_END@ (Do not change this line.)

   reti

If you would like to write the ISR in C, then do the following.

Declare the ISR function using #pragma interrupt_handler

#pragma interrupt_handler MyGpioISR

Write the interrupt handler function.

void MyGpioISR(void)
{
   IntCount++;
}

In the psocgpioint.asm file, place an ljmp instruction to branch to the C ISR

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

   reti

More about C ISRs can be found in this KB Article

Comments

abid's picture

Hi,

Great article. Thanks for putting this together.

I have a question about writing a GPIO ISR. What if I have two pins on the same port that I want to use to create two separate interrupts. For example
GPIO P0[0] : GPIO interrupt, Drive: Pull Up, Interrupt: EnableInt.
GPIO P0[1] : GPIO interrupt, Drive: Pull Up, Interrupt: EnableInt.

How would I write my interrupts. Would they be written as:
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO); // C code to enable GPIO interrupt

void MyGpio_0_ISR(void)
{
IntCount_0++;
}

void MyGpio_1_ISR(void)
{
IntCount_1++;
}

graa's picture

Hi abid, PSoC1 has only one interrupt vector for GPIO interrupts. All the GPIO pins share the same interrupt vector. So, you have to write a single ISR, analyze which pin generated the interrupt and then process accordingly. Check out my other blog article on handling multiple GPIO interrupts. http://www.cypress.com/?rID=93132&cache=0

ALL CONTENT AND MATERIALS ON THIS SITE ARE PROVIDED "AS IS". CYPRESS SEMICONDUCTOR AND ITS RESPECTIVE SUPPLIERS MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THESE MATERIALS FOR ANY PURPOSE AND DISCLAIM ALL WARRANTIES AND CONDITIONS WITH REGARD TO THESE MATERIALS, INCLUDING BUT NOT LIMITED TO, ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT OF ANY THIRD PARTY INTELLECTUAL PROPERTY RIGHT. NO LICENSE, EITHER EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, IS GRANTED BY CYPRESS SEMICONDUCTOR. USE OF THE INFORMATION ON THIS SITE MAY REQUIRE A LICENSE FROM A THIRD PARTY, OR A LICENSE FROM CYPRESS SEMICONDUCTOR.

Content on this site may contain or be subject to specific guidelines or limitations on use. All postings and use of the content on this site are subject to the Terms and Conditions of the site; third parties using this content agree to abide by any limitations or guidelines and to comply with the Terms and Conditions of this site. Cypress Semiconductor and its suppliers reserve the right to make corrections, deletions, modifications, enhancements, improvements and other changes to the content and materials, its products, programs and services at any time or to move or discontinue any content, products, programs, or services without notice.