PDA

View Full Version : Strange Behavior in setting several pin outputs states.



kappuz
- 5th December 2011, 00:19
Hello,

I have used Pic Basic Pro a lot, but now I am having a strange behavior, I want to know what can be the problem:

Here is the thing:

For example, if I set:

PORTC.3 = 1

Then the Pin goes High with out problems.

But if I write the code:

PORTC.3 = 1
PORTC.2 = 1

Then pin RC3 goes Low and pin RC2 goes High!

It seems that one instruction clears the previous one.

I am using PIC16F873A, and Setting TRIS Registers as following:

OUTPUT PORTC.3
OUTPUT PORTC.2

I am not assigning TRISC directly because my program uses USART, but that is not the problem I think because the same behavior happens with PortB!

I am using 20Mhz oscillator and defining it in the beginning of the code.

Thank you.

Charles Linquis
- 5th December 2011, 01:46
This is probably a read/modify/write issue. Try the following:

ShadowC VAR byte

ShadowC = PORTC
ShadowC.3 = 1
ShadowC.2 = 1
PORTC = ShadowC

You can use manipulate the individual bits of the TRISC register directly if you wish. For example:

TRISC.3 = 0
TRISC.2 = 0

Will work just fine.

kappuz
- 5th December 2011, 01:56
Thanks for the answer Charles,

I tried your suggestions and it does not work. The tristate of the pins is setting ok, the problem is when I try to set output states in sequential lines, for example:

PORTC.0 = 1
PORTC.1 = 1
PORTC.2 = 1
PORTC.3 = 1

This sequence just highs the pin PORTC.3, the remaining three pins states Low.

kappuz
- 5th December 2011, 02:10
Hi,

I discovered that adding a "PAUSE 100" statement between each pin assignment makes the thing to work. Is that normal?

Greetings.

Charles Linquis
- 5th December 2011, 04:54
Does your device have some other function assigned to those pins that you aren't taking into account?

HenrikOlsson
- 5th December 2011, 06:19
Definitely sounds like a RMW issue...
What are you driving with the pins? LEDs without series resistor or something capacitive?
I'm surprised you say that Charles workaround with the Shadow variable doesn't work though. Which PIC are you using? If it has LATx registers try using those instead of PORTx when setting your outputs.

/Henrik.

PICforBrains
- 5th December 2011, 09:57
This is almost certainly a peripheral-related issue, especially if the 'pause 100' makes a difference. Something is writing to the port or turning outputs to inputs during the RMW operation.
As Henrik asked, which PIC?

kappuz
- 6th December 2011, 01:21
I am using a PIC16F873A, I am connecting the output pins directly to an ATMEL microcontroller, the ATMEL microcontroller have pullup resistors in the corresponding inputs, but the initial state of all my output pins is set to High in the begginning of the program for the ATMEL microcontroller be compatible with negative logic.

I am using the USART of the PIC using an Assembler routine for the interrupt handler. When I send certain message to the USART via itīs input, the program evaluates the message, then changes the pin outputs, now I am working with PAUSE 10 between each output statement.

I can not assign directly to PORT registers because of the USART connected to some pins of PORTC.

Thanks for all your answers!

Charles Linquis
- 6th December 2011, 01:49
So what you are saying is that you didn't try the method I mentioned about the shadow register. It should still work. On most PICs the USART takes over the function of the pins so writing to PORTC.6 and PORTC.7 is then impossible.

kappuz
- 6th December 2011, 03:01
Yes, I am using your shadow method, but it only works with adding pauses this way:

PORTC.0 = 1
PAUSE 10
PORTC.1 = 1
PAUSE 10
PORTC.2 = 1
PAUSE 10
PORTC.3 = 1

If I remove the pauses, then the thing does not work...

Thank you very much again.

rmteo
- 6th December 2011, 03:44
What if you did it like this?


ShadowC VAR byte
ShadowC = PORTC

ShadowC.0 = 1
PORTC = ShadowC

ShadowC.1 = 1
PORTC = ShadowC

ShadowC.2 = 1
PORTC = ShadowC

ShadowC.3 = 1
PORTC = ShadowC

kappuz
- 9th December 2011, 01:05
I want to thank you very much.

The problem is resolved, now I am setting the pin output states super fast!

The final working code was the one posted by rmteo, but thank you all really!


ShadowC VAR byte
ShadowC = PORTC

ShadowC.0 = 1
PORTC = ShadowC

ShadowC.1 = 1
PORTC = ShadowC

ShadowC.2 = 1
PORTC = ShadowC

ShadowC.3 = 1
PORTC = ShadowC

HenrikOlsson
- 9th December 2011, 06:42
You can do it even faster by doing it the way Charles originally showed you, (did you REALLY try that and it didn't work?) in other words:

ShadowC VAR BYTE
ShadowC = PortC

ShadowC.0=1
ShadowC.1=1
ShadowC.2=1
ShadowC.3=1

PortC = ShadowC

/Henrik.

rmteo
- 9th December 2011, 15:41
You can do it even faster by doing it the way Charles originally showed you, (did you REALLY try that and it didn't work?) in other words:

ShadowC VAR BYTE
ShadowC = PortC

ShadowC.0=1
ShadowC.1=1
ShadowC.2=1
ShadowC.3=1

PortC = ShadowC

/Henrik.
Even faster would be this way - but obviously the OP did not try it the way Charles described.


ShadowC VAR BYTE
ShadowC = PortC

ShadowC.0 = $F

PortC = ShadowC

rmteo
- 9th December 2011, 16:06
Sorry for the typo - and the inability to edit a post.



ShadowC VAR BYTE
ShadowC = PortC

ShadowC = $f

PortC = ShadowC

HenrikOlsson
- 9th December 2011, 17:05
Hi,

Even faster would be this way - but obviously the OP did not try it the way Charles described.
Not really because then the top four bits will be 0 which they might not have been when PortC was read. And IF the top four bits doesn't matter then I see no reason for not simply writing to PortC directly, ie PortC = $F which would make THIS particular example even faster....

However, I suspect that setting the low four bits to 1 are just an example. Using bitwise AND/OR could also work but I'm not sure it's faster than simply flipping the four bits in ShadowC and then writing it to the port.

/Henrik.

rmteo
- 9th December 2011, 17:12
All of this is basic stuff - using a bit mask and writing directly to PORTC is the fastest way. Bottom line is that the OP did not do it the way Charles described and that is why it did not work for him. I just re-wrote it in a way that I felt would make sense to the OP.

NickMu
- 5th August 2017, 14:01
One of the best threads dealing with RMW and solutions to solve the problem is here:

http://www.picbasic.co.uk/forum/showthread.php?t=15843

Charles also explains that using this method should not affect your USART pins if they are on that particular port.

Just out of curiosity, is this method affecting your PWM if it is active on the same port and how?
Are there any other special or ordinary functions that could be affected?
I’m especially interested to know about inputs on the port that might be used for interrupts and the external source changes while this action is in progress.

Regards,

Nick

mpgmike
- 5th August 2017, 15:37
This thread was about an antiquated 16F877. I try to use only later model processors (2009 at the oldest). If a PORT pin is declared as a PWM port, none of the following will have any affect on that pin:
HIGH PWMpin
LOW PWMpin
HIGH LAT[PWMpin]
LOW LAT[PWMpin]
PWMpin = 0
PWMpin = 1

In other words, if you wanted to turn the output off, HPWM 1, 0, Freq
To turn it fully on, HPWM 1, 255, Freq.

With that said, the above methods of altering pins on a port will not affect PWM output (at least on the processors I use).

NickMu
- 5th August 2017, 15:57
Sorry, my bad. I posted to the wrong thread which in fact is the target of my link.
I was trying to post to this new thread:

http://www.picbasic.co.uk/forum/showthread.php?t=22951

Just so we do not create too much confusion, can my reply be moved to the right thread?

Regards,

Nick