View previous topic :: View next topic |
Author |
Message |
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
output_high() DOES NOT STAY HIGH |
Posted: Wed Aug 22, 2012 12:51 pm |
|
|
Hi All,
Hopefully a simple answer. If during pre-processor directives and main I had:
Code: | #define latch PIN_B7
void main ()
output_high(latch);
go and do program 1 ();
go and do program 2 ();
.....
go and do program x ();
|
When I enter different programs - pin_B7 does not stay high - it resets to low. I presume this in normal??
I thought that it would stay high unitil i pulled it low with:
but this is not happening.
Can anyone confirm that this is actually what is supposed to happen and more importantly a way around it - so that a pin stays high regardless, untill it is pulled low by a command.
Thanks
Carl |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Aug 22, 2012 1:04 pm |
|
|
You may well be suffering from the PIC RMW problem.
When another pin in the same port is written, the hardware performs the following operations:
1) read the levels on the other pins.
2) change the new pin, and write the levels back.
Problem comes if a pin is not actually going 'high'. If (for instance), a pin is connected to an LED without a current limiting resistor, though it goes 'up', it does not reach the voltage the port pin considers to be 'high', so when the 'read levels' operation is done, it is wrongly read as low.....
This is called the 'read modify write' problem. A search here will find a lot about it (and at Microchip).
There are a number of fixes, but the first one is to ensure the pin is not overloaded, since this will cause overheating, and possible damage to the chip....
Best Wishes |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Wed Aug 22, 2012 1:28 pm |
|
|
Thanks Ttelmah,
I think this is whats happening.
I have just read briefly now and it seems to indicate that if when another pin is changed on the same port as a pin that has been 'set' - if that 'set' pin is now under the switching thresholds for TTL (because of the load it is connected to) then it could possibly reset the pin.
I have a few pins that need to stay high for different functions - so it might happen to a few of them. The function that initially caused this question was for a relay - and when 'active' the voltage reads 3.6V.
So this has probably been read by the port and then reset it to 0V.
Not good. I will read further. One brief thing I read was that writing to the latch register instead of the port is a good plan.
Thanks
Carl |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Aug 22, 2012 1:34 pm |
|
|
Yes there are several possible fixes like writing to the latch register (if this is a PIC18 - on PIC16's you can't do this).
It also depends on the input threshold for the pin (TTL for many pins, but Schmitt levels for some). If it is happening at 3.6v, then this is probably the case for this pin (depends on the PIC). Reducing the drive though is the 'better' solution.
Best Wishes |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 24, 2012 7:54 am |
|
|
Hi Ttelmah,
I think I am going to have to go down the write and read to the latch registors. Could you advise if this is a good way to do do it: Code: | #byte PORTD_DIRECT = getenv("SFR:PORTD")
#bit portd0 = PORTD_DIRECT.0
#bit portd1 = PORTD_DIRECT.1
#bit portd2 = PORTD_DIRECT.2
#bit portd3 = PORTD_DIRECT.3
#bit portd4 = PORTD_DIRECT.4
#bit portd5 = PORTD_DIRECT.5
#bit portd6 = PORTD_DIRECT.6
#bit portd7 = PORTD_DIRECT.7 |
And then I can just write or read to the the individual latch bits like:
Code: |
void main()
{
int8 value;
value = portd5; // Read the latch register for Port D pin 5
portd6 = 1; // write '1' to the latch register for Port D pin 6
while(1);
}
|
Is this the best way of doing it? |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 24, 2012 9:44 am |
|
|
Tried this as well but no change:
Code: | #byte LATA_DIRECT = getenv("SFR:LATA")
#byte LATB_DIRECT = getenv("SFR:LATB")
#byte LATC_DIRECT = getenv("SFR:LATC")
#byte LATD_DIRECT = getenv("SFR:LATC")
#byte LATE_DIRECT = getenv("SFR:LATE")
#bit portd0 = LATD_DIRECT.0
#bit portd1 = LATD_DIRECT.1
#bit portd2 = LATD_DIRECT.2
#bit portd3 = LATD_DIRECT.3
#bit portd4 = LATD_DIRECT.4
#bit portd5 = LATD_DIRECT.5
#bit portd6 = LATD_DIRECT.6
#bit portd7 = LATD_DIRECT.7
#bit porta0 = LATA_DIRECT.0
#bit porta1 = LATA_DIRECT.1
#bit porta2 = LATA_DIRECT.2
#bit porta3 = LATA_DIRECT.3
#bit porta4 = LATA_DIRECT.4
#bit porta5 = LATA_DIRECT.5
#bit porta6 = LATA_DIRECT.6
#bit porta7 = LATA_DIRECT.7
#bit portb0 = LATB_DIRECT.0
#bit portb1 = LATB_DIRECT.1
#bit portb2 = LATB_DIRECT.2
#bit portb3 = LATB_DIRECT.3
#bit portb4 = LATB_DIRECT.4
#bit portb5 = LATB_DIRECT.5
#bit portb6 = LATB_DIRECT.6
#bit portb7 = LATB_DIRECT.7
#bit portc0 = LATC_DIRECT.0
#bit portc1 = LATC_DIRECT.1
#bit portc2 = LATC_DIRECT.2
#bit portc3 = LATC_DIRECT.3
#bit portc4 = LATC_DIRECT.4
#bit portc5 = LATC_DIRECT.5
#bit portc6 = LATC_DIRECT.6
#bit portc7 = LATC_DIRECT.7
#bit porte0 = LATE_DIRECT.0
#bit porte1 = LATE_DIRECT.1
#bit porte2 = LATE_DIRECT.2
#bit porte3 = LATE_DIRECT.3
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Aug 24, 2012 12:01 pm |
|
|
What's your PIC and your compiler version ? |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 24, 2012 1:20 pm |
|
|
HI PCM,
CCS Version: 4.038.
PIC is 4550.
I know that 4.038 is not good, and may be the cause for numerous errors, but I also dont know if I am carrying out the function correctly either. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Aug 24, 2012 1:26 pm |
|
|
Quote: | Tried this as well but no change:
#byte LATA_DIRECT = getenv("SFR:LATA")
#byte LATB_DIRECT = getenv("SFR:LATB")
#byte LATC_DIRECT = getenv("SFR:LATC")
#byte LATD_DIRECT = getenv("SFR:LATC")
#byte LATE_DIRECT = getenv("SFR:LATE")
|
See the typo shown in bold above.
Quote: | value = portd5; // Read the latch register for Port D pin 5
|
Not sure why you want to read the latch. It holds what you wrote to it. |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 24, 2012 1:37 pm |
|
|
Deary me
Been at it too long!!!
Thanks
I will give it a go tomorrow and see if it clears things up.
I am having problems with the rmw issue - and therefore need to ensure that I write to the Latch's - because writing to the ports with output_high() is not working - keeps resetting.
I understand what Ttelmah has said about reducing the power consumption of the load, but tried without success at the moment. It is not a capacitive issue either - Its voltage being dropped across a load (relay in this particular case). Other peripherals will also probably do the same thing (I try to protect as much as possible - resistors, drivers etc).
So I need a sure-fire way of writing and reading to the pins which won't reset due to the rmw issue. Is the way I suggest correct?? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Aug 24, 2012 2:02 pm |
|
|
Make a test program and compile it and look at the .LST file.
It did that with vs. 4.038 and I got this:
Code: |
.................... output_high(LATCH);
001C: BCF TRISD.6
001E: BSF LATD.LATD6
....................
.................... output_low(LATCH);
0020: BCF TRISD.6
0022: BCF LATD.LATD6
|
The compiler is writing to the latch register. So therefore, the problem
is not a RMW issue. It's likely related to your load. Don't drive high
current loads directly with a PIC pin. Use a relay driver chip, such as
ULN2003A. Or any relay driver.
Test program:
Code: |
#include <18F4550.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4M)
#define LATCH PIN_D6
//==========================
void main()
{
output_high(LATCH);
output_low(LATCH);
while(1);
} |
Thread on relay drivers:
http://www.ccsinfo.com/forum/viewtopic.php?t=34119
There could also be power supply track layout issues, or other issues:
http://www.ccsinfo.com/forum/viewtopic.php?t=34352 |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 24, 2012 2:15 pm |
|
|
for the same program you wrote I would get the same as you have shown - and the pin would go high and low.
It only occurs when other programs are accessed - which rmw to the port, and then the pin does not stay high.
It is such a good learning curve though - now I know that for many output pin fucntions (connected to different loads) - to absolutely ensure that they are protected (driver, resistor etc).
Thanks anyway
Carl |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Aug 25, 2012 5:16 am |
|
|
I'm getting confused now.
My understanding is what Ttelmah wrote here Quote: | You may well be suffering from the PIC RMW problem.
When another pin in the same port is written, the hardware performs the following operations:
1) read the levels on the other pins.
2) change the new pin, and write the levels back.
Problem comes if a pin is not actually going 'high'. If (for instance), a pin is connected to an LED without a current limiting resistor, though it goes 'up', it does not reach the voltage the port pin considers to be 'high', so when the 'read levels' operation is done, it is wrongly read as low.....
This is called the 'read modify write' problem. A search here will find a lot about it (and at Microchip).
There are a number of fixes, but the first one is to ensure the pin is not overloaded, since this will cause overheating, and possible damage to the chip....
|
The key point that I am trying to investigate is that is another pin is WRITTEN to on the same port - then the rwm problem exists. I am seeing this though when the port is READ not WRITTEN TO.
So does the same occur when the port ir read??
something like below: Code: |
void main (){
output_high (relay); // relay is pin d_4 and reads 3.6V when high.
}
while (true){
rval=input_d();
} |
when I read input_d, the latch goes low.
so does the rwm problem also exist when you READ to the port (or pin?) and not just WRITE to the port (or pin?).
Also looking at the rwm issue, everywhere states to WRITE to the LATx register and READ from the ports. OK I first tried to just write to the LAT registers and toggle a pin as below using portc - but it did nothing: Code: | #byte LATA_DIRECT = getenv("SFR:LATA")
#byte LATB_DIRECT = getenv("SFR:LATB")
#byte LATC_DIRECT = getenv("SFR:LATC")
#byte LATD_DIRECT = getenv("SFR:LATD")
#byte LATE_DIRECT = getenv("SFR:LATE")
#bit portd0 = LATD_DIRECT.0
#bit portd1 = LATD_DIRECT.1
#bit portd2 = LATD_DIRECT.2
#bit portd3 = LATD_DIRECT.3
#bit portd4 = LATD_DIRECT.4
#bit portd5 = LATD_DIRECT.5
#bit portd6 = LATD_DIRECT.6
#bit portd7 = LATD_DIRECT.7
#bit porta0 = LATA_DIRECT.0
#bit porta1 = LATA_DIRECT.1
#bit porta2 = LATA_DIRECT.2
#bit porta3 = LATA_DIRECT.3
#bit porta4 = LATA_DIRECT.4
#bit porta5 = LATA_DIRECT.5
#bit porta6 = LATA_DIRECT.6
#bit porta7 = LATA_DIRECT.7
#bit portb0 = LATB_DIRECT.0
#bit portb1 = LATB_DIRECT.1
#bit portb2 = LATB_DIRECT.2
#bit portb3 = LATB_DIRECT.3
#bit portb4 = LATB_DIRECT.4
#bit portb5 = LATB_DIRECT.5
#bit portb6 = LATB_DIRECT.6
#bit portb7 = LATB_DIRECT.7
#bit portc0 = LATC_DIRECT.0
#bit portc1 = LATC_DIRECT.1
#bit portc2 = LATC_DIRECT.2
#bit portc3 = LATC_DIRECT.3
#bit portc4 = LATC_DIRECT.4
#bit portc5 = LATC_DIRECT.5
#bit portc6 = LATC_DIRECT.6
#bit portc7 = LATC_DIRECT.7
#bit porte0 = LATE_DIRECT.0
#bit porte1 = LATE_DIRECT.1
#bit porte2 = LATE_DIRECT.2
#bit porte3 = LATE_DIRECT.3
void main()
{
while(true) {
portc0 = 1;
delay_ms(5000);
portc0 = 0;
delay_ms(5000);
}
} |
and then i wrote to the port first and then it worked Code: |
void main()
{
output_high(relay);
while(true) {
portc0 = 1;
delay_ms(5000);
portc0 = 0;
delay_ms(5000);
}
} |
I just dont understand how this is supposed to work[/code] |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Sat Aug 25, 2012 6:48 am |
|
|
When you write directly, you need to set the tris direction. When you use output_high() it does that for you (see the LST file listing posted earlier). Writing to the latch of a port set to read only does nothing. |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Aug 25, 2012 7:10 am |
|
|
Thanks Jeremiah,
So you cannot use standard_io if you want to write to the port directly?
As standard_io sets the tris automatically.
so every port would have to be set to fast_io (and then the tris can be set) if I intended to write to the latch directly? |
|
|
|