GPIO shadow register, by example

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

Moderator: ericb

GPIO shadow register, by example

Postby LLamaBob on Wed Apr 26, 2006 7:32 pm

I've read the GPIO Help post, and everything else I could read on shadow registers, and I'm still a little confused. I'm using a real example, where I have a mixture of C and assembly, inputs with pull-ups, pull-downs, some routed to user modules, all on Port 2 of a CY8C29466-24PXI.

I have inputs on P2_0, P2_2, eventually routed to inputs on digital modules. I don't want these two inputs to float, and I understand I can't make them pull-down because they're going to global busses, so I've routed each of these pins on the PC board to two unused input pins... P2_0 to P2_6, and P2_2 to P2_4. In the device editor, I've made P2_4 and P2_6 Pull-Down.

I have another input pin that I've initialized as a pull-up, P2_7. It is not associated with a user module, and the select value is StdCPU.

I have 2 outputs on P2_1 and P2_3 that come from two PWM modules.

I also have an output pin P2_5 that is not associated with any user module, driving an LED and current-limiting resistor to Gnd.

In C, what I currently do now just before my main loop is

PRT2DR &=0xAF ;
PRT2DR |=0x80;

... which I understand may not a good technique, because of the read-modify-write potential of messing up my pull down / ups.

So.. I definied a shadow register in assembly:
_Port2Shadow:: BLK 1
and exported it, so that I can see the same variable in C, as
extern unsigned char Port2Shadow;

Now I can use it in C and my asy interrup routine, where I need to manipulate the port some.

So here's my questions:

1. How do I first initialize and use the shadow register in C, to replace this:

PRT2DR &=0xAF;
PRT2DR |=0x80;

I'm assuming:

Port2Shadow = 0x80;
PRT2DR = Port2Shadow;

This should make my pull-up input P2_7 high, and my two pull-down inputs P2_4 & P2_6 low, and turn off my LED.

2. How do I read my input P2_7 in C ? What about assembly?

Currently this is what I do:
if (PRT2DR & 0x80) {
etc...

3. How do I turn on and off my LED on port P2_5 in assembly? What about C?

Currently this is how I turn it on:
or reg[PRT2DR], 0x20; // rmw issue?

and off

and reg[PRT2DR], ~0x20;

Thanks,
Bob
User avatar
LLamaBob
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 20
Joined: Thu May 19, 2005 7:45 am

Postby wrightpc on Thu Apr 27, 2006 8:19 pm

Bob,

Reading the port directly is fine and will not change the data value. It is only a read-modify-write that can muck up the port.

My usual solution is to create assembly routines that I can call that do the job for me (:

prt2_load(value);
prt2_and(value);
prt2_or(value);

the assembly routine keeps the port up to date. In your startup you can call prt2_load with the default value which will update the port AND the virtual register.

Here is some non-LMM code:
Code: Select all
;*******|*******|***********************|***************************************
;  Variable Definitions for use in this file (RAM)
;*******|*******|***********************|***************************************
area InterruptRAM(RAM)

; Virtual Port Registers (_NOT_ GLOBAL!)
PRT4DR_virtual: blk 1
PRT6DR_virtual: blk 1

;*******|*******|***********************|***************************************
;  Source code area (ROM)
;*******|*******|***********************|***************************************
area text(ROM,REL)


;===============================================================================
; Virtual Port Write Functions
;===============================================================================

_load_prt4dr_virtual::
        mov     [PRT4DR_virtual], A
        mov     reg[PRT4DR], A           
        ret
_and_prt4dr::
        and     [PRT4DR_virtual], A
        mov     A, [PRT4DR_virtual]
        mov     reg[PRT4DR], A           
        ret
_or_prt4dr::
        or      [PRT4DR_virtual], A
        mov     A, [PRT4DR_virtual]
        mov     reg[PRT4DR], A           
        ret


In the header file you define the functions:
#pragma fastcall16 and_prt4dr
void and_prt4dr (uint8);

fastcall means parameter passed in A to assembly. To use these routine from assembly simply
mov A, value
lcall _and_prt4dr

Hope this helps.

Paul. :)
User avatar
wrightpc
The Big Cheese
The Big Cheese
 
Posts: 736
Joined: Thu Jul 28, 2005 7:56 pm
Location: Christchurch, New Zealand

Postby LLamaBob on Sat Apr 29, 2006 12:34 pm

Thank you for your detailed reply. Your method seems to be very robust for assembly. To round out my options for doing the same in C, do you think this would be okay for writing to a port:

// Initialize shadow register and physical register
// Input Port 2_7 input pull-up, all other port2 inputs pull-down
Port2Shadow = 0x80;
PRT2DR = Port2Shadow;

// Write to register, need to use shadow

// Turn on port 2_5
PRT2DR = (Port2Shadow |= 0x20);
// Turn off port 2_5
PRT2DR = (Port2Shadow &= ~0x20);

Thanks,
Bob
User avatar
LLamaBob
Bite-Size Cheese
Bite-Size Cheese
 
Posts: 20
Joined: Thu May 19, 2005 7:45 am

Postby graaja on Sun Apr 30, 2006 5:01 am

Bob,

Yes. Your code in C will work the same way as Paul's assembly code.
User avatar
graaja
PSoC Master
PSoC Master
 
Posts: 3084
Joined: Thu Dec 18, 2003 4:35 pm
Location: India

Postby wrightpc on Sun Apr 30, 2006 1:30 pm

Bob,

That's quite neat what you have done keeping it all on the same line. Excellent! :-)

Paul.
User avatar
wrightpc
The Big Cheese
The Big Cheese
 
Posts: 736
Joined: Thu Jul 28, 2005 7:56 pm
Location: Christchurch, New Zealand


Return to PSoC1 General

Who is online

Users browsing this forum: No registered users and 1 guest