You are here

Reading current status of output values on a port on a CY8C9560A | Cypress Semiconductor

Reading current status of output values on a port on a CY8C9560A

Summary: 15 Replies, Latest post by Bob Marlowe on 31 May 2012 01:01 PM PDT
Verified Answers: 1
Last post
Log in to post new comments.
user_209030878's picture
User
11 posts

Suppose all the pins on port 7 are configured for output and some are high & some are low.  What are the correct commands to send to read the current state of the port?  Everything I've tried returns 0xFF.  Thanks.

user_1377889's picture
User
10803 posts

Datasheet says:

Input Port Registers (00h - 07h)

 

These registers represent actual logical levels on the pins and

are used for I/O port reading operations. They are read only.

So a read from register 0x07 will present you with the actual states of the pins, no need to use the Port-Select-Register first.   Bob

user_209030878's picture
User
11 posts

 Bob,  thanks.  That one was easy.  Now I'm having a stranger problem.  I can set the pin value and read it back and it comes back as I expect.  However, no current seems to be delivered to the pin (most of the time).  I have LEDs set on all the pins on port 7 to test this and on rare cases it works but most of the time the LEDs stay low although reading the pin values through the register says they are high.  Any ideas what's going on here?

My high-level test code is simply this...

 

const byte PORT = 7;

io60p16.SetPortMode(PORT, PORT_DRIVEMODE.RES_PULLDOWN);

io60p16.SetPortDirection(PORT, 0xff);

byte v = io60p16.GetPortOutput(PORT);

if (v == 0) v = 0xff;

else v = (byte)(v >> 1);              // cycle through the pins...

io60p16.SetPortOutput(PORT, 0x00);

io60p16.SetPortOutput(PORT, v);

Thread.Sleep(1000);

Debug.Print(io60p16.GetPortOutput(PORT).ToString());

Debug.Print(io60p16.GetPortInput(PORT).ToString());

 

user_1377889's picture
User
10803 posts

Ian, i cannot see that you really loop through the port-pins (no while(), no for())

There is a difference between the logic state of a pin and the value red back: independently of the logic state the output has, the value red is the actual voltage on the pin interpeted as a logic state.

Imagine your LED connected to light as active low (as in your example) when the output is driven low, due to the input resistance of the pin-circuit there will be a voltage (depending on LED-Type and resistor) that can be high enough to be interpreted as a logic "High" although the output is driven "Low". 

Give it a try with a DMM (NO SHORTS, PLEASE!).

An approach to come out of this io-trap is to use a "shadow-register" which buffers the wanted output-state and manipulations (bit-set and resets) and is written completely after alterations out to the port.

Give yourself a "Keyword Search" (upper right-hand corner of this window) for "read modify write".

Bob

user_39759791's picture
User
357 posts

also make sure you are not drawing more current than the combined 40mA  maximum on PORT7

user_209030878's picture
User
11 posts

Bob, I should have explained my setup better.  The code posted actually executes within a timer that get's fires every 2s.  I'm not concerned about previous values for this test.  I'm treating all pins on the port as output and the code should simply read the number of bits that are high then turn off the high bit so that the LEDs cycle from 8 pins high to 7, 6, 5...0, 8...  I'm familiar with the shadow register technique but I don't think that applies here.  Correct me if I'm wrong.

If I change the (C#) code slightly to this...

            var timer = new GT.Timer(2000);
            timer.Tick += timer1 =>
                              {
                                const byte PORT = 7;
                                io60p16.SetPortMode(PORT, PORT_DRIVEMODE.RES_PULLDOWN);

                                io60p16.SetPortDirection(PORT, 0xff);
                                byte v = io60p16.GetPortOutput(PORT);
                                if (v == 0) v = 0xff;
                                else v = (byte)(v >> 1);              // cycle through the pins...
                                io60p16.SetPortOutput(PORT, 0x00);
                                io60p16.SetPortOutput(PORT, v);
                                Thread.Sleep(500);
                                byte n = io60p16.GetPortOutput(PORT);
                                Debug.Print("Setting to: " + v + "\tReads as: " + n);
                              };
            timer.Start();    

Then I get this output...

Setting to: 255 Reads as: 255
Setting to: 127 Reads as: 127
Setting to: 127 Reads as: 127
Setting to: 63  Reads as: 63
Setting to: 31  Reads as: 31
Setting to: 15  Reads as: 15
Setting to: 127 Reads as: 255
Setting to: 63  Reads as: 63
Setting to: 31  Reads as: 31
Setting to: 15  Reads as: 15
Setting to: 7 Reads as: 7
Setting to: 3 Reads as: 3
Setting to: 1 Reads as: 1
Setting to: 0 Reads as: 0
Setting to: 255 Reads as: 255
Setting to: 127 Reads as: 127
Setting to: 63         Reads as: 255
Setting to: 127 Reads as: 127
Setting to: 63  Reads as: 63
Setting to: 31  Reads as: 31
Setting to: 15  Reads as: 255
Setting to: 7 Reads as: 7
Setting to: 3 Reads as: 3
Setting to: 1 Reads as: 1
Setting to: 0 Reads as: 255
Setting to: 255 Reads as: 255
Setting to: 127 Reads as: 127
Setting to: 63         Reads as: 63

You can see that in most cases the values being written are also be read back correctly.  However, none of my LEDs lighting.  I should also note that if I first enable all the pullup resistors for the port before doing the pulldown then they will all light up.  So, I know there's not a wiring problem.

Am I not fully understanding what you're telling me or is there really something weird going on here?

 

user_209030878's picture
User
11 posts

"also make sure you are not drawing more current than the combined 40mA  maximum on PORT7"

Now that is useful information!  I don't recall seeing that in the datasheet.  I was making an assumption that it was 40mA per pin and not per port.  Each LED is ~20mA and since I'm lighting them all I've probably messed it up :(  What happens in this case?  Is the chip smart enough to just do nothing I need to get a new chip :(

user_1377889's picture
User
10803 posts

The first thing I notice is that you set the pin's mode within the timer-interrupt routine which you should do outsides in a hardware-initialization because there is no need to set that over and over again.

The second you're referring to a variable v and reading the port. Here exactly happens what I tried to explain in my last post. Imagine, you short a pin to GND. Although you wrote a "1" to the pin, You'll read back a "0" because it's tied to GND!!!

To overcome that:

Declare v as static byte v = 0xff;

Do NOT read back v but shift and set it as before

Set your port with v as usual.

By the way: To save a byte and some code, make your const byte PORT = 7    - to

#define PORT 7

Bob

user_209030878's picture
User
11 posts

Bob, I appreciate the code criticism but this is by no means meant to be production code.  I am just trying to verify some very basic functionality of the chip which so far I'm unable to do.  You may recall helping me on another post a week or so back where I was able to blink and LED but was not able to read the value back.  Now, I can read the value back but the LED doesn't light.  So, let's simplify this a little so there's no distractions...  My circuit is nothing except an LED + 56 ohm resistor connected to Port #7 Pin #2.  There's no chance that anything is shorted anywhere and I don't care about the state of any other pins.  The following code should cause the LED to blink and me be able to read the port's current value after setting it.

const byte PORT = 7;
io60p16.SetPortMode(PORT, PORT_DRIVEMODE.RES_PULLDOWN);
io60p16.SetPortDirection(PORT, 0xff);

var timer = new GT.Timer(2000);
timer.Tick += timer1 =>
                    {
                    io60p16.SetPortOutput(PORT, 0x00);
                    Thread.Sleep(500);
                    io60p16.SetPortOutput(PORT, 0x04);
                    Thread.Sleep(500);
                    byte n = io60p16.GetPortOutput(PORT);
                    Debug.Print("Setting to: 0x04 \tReads as: " + n);
                    };
timer.Start();            

The first thing I notice is that you set the pin's mode within the timer-interrupt routine which you should do outsides in a hardware-initialization because there is no need to set that over and over again.

Agreed.  But for this simple test it shouldn't hurt anything.  I've moved it outside the thread for this new test.

 

By the way: To save a byte and some code, make your const byte PORT = 7    - to

#define PORT 7

 

 

This is C# code, not C.  "const" is the C# equivalent of "#define".

user_1377889's picture
User
10803 posts

OK, next step: any reason why you use resistive pull-down-mode? A pin usually can sink a lot more than it may source.

I'd choose open drain low and connect the LED and the limiting resistor (5V-1.7V)/20mA = 165Ohms to VCC.and driving low the pin to turn on the LED.

I do not want you to tinker with your project, but afaik this is the usual way to light an LED.

BTW: what is the reason you want to read-back the port-values? Experimental?? Or do you have something special in mind which you may talk about?.

Bob

user_209030878's picture
User
11 posts

 Bob, I'm building a high-level driver for this Gadgeteer platform module:

http://www.ghielectronics.com/catalog/product/363

There is no specific project at this time.  This is an open source task that I volunteered to do.  So, the idea is to build a driver model that abstracts out all of the I2C goodness into something friendlier to hobbyist that's more suitable of a C# Gadgeteer environment.  I agree that in a real project, I would definitely sink to the pin.  However, in this case I only want to see that the pin is actually going high.  So, it was easier to just plug in a LED as in the attached pic and use the pulldown.  All I'm trying to accomplish at this point is to create the basic I2C functions to read/write/SetPulse etc.  So far, this has proven to be much more difficult than I ever expected.  Much of the problem has been with the software based I2C that I'm having to use.  I don't think that's the case in this problem since I can read that the values are being set but there simply appears to be no current being delivered.  

Thanks for hangin' in there with me.

Log in to post new comments.