I'm trying for many days to make a Serial routine for a 16c84, it seems
to
work on MPLAB simulator, but in reality ... %-(
I must say that i'v a LCD(HD44780) in my application, so i can see
what i get ...
First, i'v tryed to connect with a serie resistor straight to Tx(tested:
82k,200k,382k) and a common Ground; noisy results.
Now, i'v wired it with a MAX232; noisy results too.
I wanna do this in ISR (interrupt), like that I'm free of this in MAIN
program.
I thought about few methods to do this :
- I could set TMR0 to 0xFF, triggered by RA4/T0CLK input to make
a T0IF(timer overflow), etc...
* Not good for my purpose, cause i need TMR0 for a base time.
- I could set interrupt on PORTB change.
* Not recommended.(I heared this, near here)
- I could sample the Rx pin.
* Good, but wasted time to sample each bit, as many it was
super-sampled.(3,4 times ?)
- And i could set RB0/INT for interrupt on transition, and calculate
time between each of them.
* This is my choice ...
I want to implement a classic 8,N,1 @ 1200
(1bit start, 8bit data lsb/msb, no parity, 1bit stop, at 1200 baud.)
(1) set first for falling edge interrupt(INTEDG=0)
(2) interrupt(INTF)
- next INTF on rising edge(INTEDG=1)
- at least(+/- 1.2% ?), 10*(1/1200)/second later must come a rising
edge.(STOP bit)
(3) interrupt(INTF)
- next INTF on falling edge(INTEDG=0)
- calculate time between (2) & (3), to count how many 1 bit
- n*bit=time/(1/1200s), including at least START bit.
- if n*bit=10, a byte received.(start+'11111111'+stop)
(4) interrupt(INTF)
- next INTF on rising edge(INTEDG=1)
- calculate time between (3) & (4), to count how many 0 bit
- n*bit=time/(1/1200s).
- if n*bit>=10, error, STOP bit must be on rising edge !
(etc) until 10 bits counted, do/calculate, INTF rising/falling time.
To calculate time(wrong ?):
My ISR routineÓ is shared with TMR0 overflow, so each time TMR0 roll
over,
it reloaded with a pre-calculated value: (CLK/4)/prescaler/(256-value)=
interrupt/s
The wanted result(?) is 4 times the baud rate, ~4800 Hz
4194304/4 /1 /218= 4809 int/s, then Reload value = (256-218) = 38
btfsc INTCON, INTF ; test if transition on RB0/INT
goto _RxINT ; an INTF occur, go to serial
; else it's a TMR0 overflow
bcf INTCON, T0IF ; clear TMR0 overflow bit
; some code here
movlw Reload ; The pre-calculated value = 38,
cf upper text
addwf TMR0, f ; to reload TMR0 + elapsed time
>from T0IF
incf RxTIMER ; this is for serial, +1 every
1/4800s
; cleared, on each transition in
_RxINT
; to be divided by 4, to count bit
@ 1200 bps
pop ; MACRO restore W & STATUS
retfie ; Exit ISR
_RxINT: bcf INTCON, INTF ; clear INTF transition bit
; some code here
pop ; MACRO restore W & STATUS
retfie ; Exit ISR
;***********************************************************************************
- Do you estimate this method accurate ?
- Is my vision of serial transmit good ?
- What about TMR0 reload and interrupt latency ?
- Do you think i could have noise from LCD, pin not tied(set to output),
or serial(PC) ?
- Or what ? (may be i'm a dude ?, hope not !)
Please, switch my light !
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
*Happy X_MAS lovely people !*
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
>First, i'v tryed to connect with a serie resistor straight to
>Tx(tested:
>82k,200k,382k) and a common Ground; noisy results.
The results should not be "noisy". A resistor of 220K to 1M is suitable.
The resistor should be connected near the PIC pin, without extra
circuitry loading down the node between the resistor and PIC. It could
be that the timing in your program is imprecise, this is causing errors
which you attribute to "noise".
>Now, i'v wired it with a MAX232; noisy results too.
>
>
>I wanna do this in ISR (interrupt), like that I'm free of this in MAIN
>program.
>
>I thought about few methods to do this :
>
>- I could set TMR0 to 0xFF, triggered by RA4/T0CLK input to make=20
> a T0IF(timer overflow), etc...
> * Not good for my purpose, cause i need TMR0 for a base time.
I think it would be possible to run the TIMR0 constantly at 1200 Hz, and
use a RB0 interrupt from the start bit to synchronize (restart it in
phase) with the start bit, so subsequent overflows are at the proper
times to sample the data bits. After the last bit, it would be restarted
again so that the next interrupt is in the proper phase to continue as it
was before the start bit. Thus the phase of the base time would vary
during reception, but the overall frequency would remain without error.
Depending on what else the base time is used for this may be acceptable.
>
>- I could set interrupt on PORTB change.
> * Not recommended.(I heared this, near here)
Don't do this. The RB on change interrupt is only suitable for
restarting the PIC from sleep. It should not be used while the PIC is
awake.
>
>- I could sample the Rx pin.
> * Good, but wasted time to sample each bit, as many it was
>super-sampled.(3,4 times ?)
It appears you want to set the timer for 4800 Hz anyway, thus it is
well-suited to this method.
>- And i could set RB0/INT for interrupt on transition, and calculate
> time between each of them.
> * This is my choice ...
>
>
>I want to implement a classic 8,N,1 @ 1200
>(1bit start, 8bit data lsb/msb, no parity, 1bit stop, at 1200 baud.)
>
>May be i'm in wrong, for this case it's,
>
> start stop (hope ASCII drawing good.)
>1______ _______________ _____
> |_|_|_|_|_|_|_|_|_|_|
>0 1 2 3 4 5 6 7 8
This is wrong. The stop bit is a logic 1.
The signal drawn above (except for the stop bit) is what would be
received after an inverting line receiver (MAX232, etc). If you connect
the RS-232 line directly (via resistor) to the PIC, then start bits are
high, zero data bits are high, and 1 data bits are low.
>(1) set first for falling edge interrupt(INTEDG=3D0)
>
>(2) interrupt(INTF)
> - next INTF on rising edge(INTEDG=3D1)
> - at least(+/- 1.2% ?), 10*(1/1200)/second later must come a
>rising
>edge.(STOP bit)
>
No, the routine must have a timeout. If, for example, the data sent is
0xFF, the start bit is the only pulse:
____ _______________
_
IIIIS01234567KIIIIII
I = line idle, S = Start bit, 0-7 = data bit, K = stop bit.
If it is some other pattern of the form 11111000, etc. the result is
similar, the start bit and the zero data bits form a longer single pulse.
Although the general principle described of interrupting on transistions
and computing the number and polarity of bits received based on the time
is sound, there needs to be a little time-based processing to decide when
the byte is complete if it doesn't have a final transition (MSB is 1).
Or if some error occurs. Note that triggering on transitions is rather
sensitive to noise. If the transitions don't occur cleanly and singly,
multiple interrupts could occur which could require a lot of processing.
At 1200 baud, it's usually not impractical to set the timer interrupt at
a multiple of the baud rate and use an oversampling type of receiver as
part of the timer ISR...
>The wanted result(?) is 4 times the baud rate, ~4800 Hz
>
>4194304/4 /1 /218=3D 4809 int/s, then Reload value =3D (256-218) =3D
>38=20
If possible, use a crystal that works out exactly, this prevents needing
to reload the timer at all. Not reloading saves processing time and the
possible (though predictable) error from the prescaler clearing and the
timer stopping briefly after each reload. For example, 4.9152 MHz and
prescale of 1 (no prescale) gives 4800 overflows per second.
What is the problem with RB change interrupts, other than the caution
mentioned in the data sheets regarding mixing of polling with interrupt
detection?
I've used it to detect edges in order to track a quadrature encoder and
it seems rock solid. The interrupt routine just reads and processes the
quad inputs as recently discussed, but this way the routine only has to
run when there has been a change, rather than having to poll at high
speed.
I would probably have to poll at 1 mSec intervals otherwise, to avoid
missed states.
>What is the problem with RB change interrupts, other than the caution
>mentioned in the data sheets regarding mixing of polling with
>interrupt
>detection?
Maybe this is a little harsh to say never to use it. Because of the way
it is implemented, there are circumstances that can cause a change to
occasionally be missed (no interrupt generated). In some applications,
occasional missed changes may be OK.
The change detector is implemented with a new register which holds the
*last value read* from PORTB. The current state of the pins is xor'd
with this register to detect a change. The register is not directly
accessable.
If the port is being read at the exact instant that an external change
occurs, the change detector won't trigger. This seems easy to work
around at first, but realize that the architecture of the PIC causes some
extra reads. For example, a movwf PORTB reads the port first, discards
the value, then writes the value from W. So attempting to use the other
4 bits of the port in any way could prevent changes from being detected.
In older silicon, a RETURN would also access PORTB (the opcode also
executed as MOVWF PORTB,w which would ordinarily do nothing). I think
that additional logic has been added to prevent this. The CLRW
'instruction' used to be encoded as CLRF INDF,w which would be trouble if
FSR pointed to PORTB. Newer assemblers encode it as CLRF 3,W. These 2
problems have been quietly dealt with by Microchip.
Keeping all this in mind, it is still possible to work around the
limitations of the change detector and use the RB change interrupt in a
program. The primary consideration would be not to read or write PORTB
except as a response to a detected change.
I should have mentioned I am using the 16C6x family and have just
realised the discussion may have been about 16C5x. Does this have any
bearing on things? My understanding from the 16C6x book is that the 'A'
versions of this family have no problem with reading the port causing
lost interrupts?
I use the other 6 bits of PORTB to drive LED's which are written
asyncronously to the interrupt servicing, so this would be a worry.
I was intrigued to learn a RETURN used to perform a hidden access to
PORTB, it confirms my view (as an ageing Intel hippy) that the PIC is a
pretty wierd machine.
I also didn't know (am I alone?) that clrw is really clrf n,w. I
thought it was a real instruction.
What a mine of information! (Is this really in the book somewhere?)
Regards to all,
--
Alan Hall, Ipswich, UK
(01473) 652301
> Keeping all this in mind, it is still possible to work around the
> limitations of the change detector and use the RB change interrupt in a
> program. The primary consideration would be not to read or write PORTB
> except as a response to a detected change.
Or, if you have some PORTA pins available, connect them in parallel with
the PORTB pins. After each PORTB access, read PORTA, compare. If the
read on PORTA says the pin changed, but the interrupt routine wasn't
called, call the interrupt routine directly. It's complex to get right,
but not impossible.
Note, you may want to put resistors in series with the PORTA pins. That
way if there is a bug and the pins become outputs, the PIC won't get
damaged if the PORTA pin fights the PORTB pin.
> <Interesting info on using RB change interrupts>
>
> I should have mentioned I am using the 16C6x family and have just
> realised the discussion may have been about 16C5x. Does this have any
> bearing on things? My understanding from the 16C6x book is that the 'A'
> versions of this family have no problem with reading the port causing
> lost interrupts?
>
> I use the other 6 bits of PORTB to drive LED's which are written
> asyncronously to the interrupt servicing, so this would be a worry.
Not sure about the A suffix but I expect the problem will NOT be
fixed.
To control LEDs you might want to set the output register to 0x00
for post B and then use the TRIS register to control the LEDs This
is known not to cause a significant problem with the interrupt
on change hardware. Obviously you would have to look very carefully
about what happens when you muck about with the 2 bits that are part
of the high nibble, the low 4 bits should work securely if you just
work the direction control and never change the output register (with
the associated read of the input register).
>Or, if you have some PORTA pins available, connect them in parallel
>with
>the PORTB pins.
I don't see any advantage to doing this. Software will always read the
PORTB pins correctly. Though this read could cause a change interrupt to
be missed, it would be at the exact moment that the software change
detector is looking for it. If there are extra PORTA pins, use them for
I/O so PORTB doesn't need to be accessed. Kalle's idea to control PORTB
outputs in simulated open-collector mode using the TRIS register is a
good one.
For combined hardware/software change detection, the ISR should read the
port (to reset the hardware change detector) and save the last accepted
value of the pins in RAM. The software change detector (invoked after
every access of the port for other reasons) would read PORTB and force
the interrupt directly if different from the accepted value in RAM. The
interrupt should be disabled during a software compare to prevent
multiple interrupts. It should be possible to force a change interrupt
by directly setting the flag bit.
Of course, the latency to detect a change becomes large and variable
using this workaround. It may help to organize things to only use the
hardware change detector during parts of the program that won't disrupt
it, and software detection at other times.
Thanks to all for recent contributions on the subject of RB change
interrupts, I thought I had bypassed that by using the spare pins as
outputs, little suspecting a simple write would be preceded by a read!
Kalle's suggestion of using TRIS is great.
However, not wishing to be awkward, but I am still uncertain as to
whether there is a problem here at all - I was told by UK Microchip
people this was "fixed" on all 'A' suffix parts in the 16C6x series, and
that the 16C63 never suffered at all.
If you look at the data book you will see 2 versions of the port B
circuitry, the original being an asynchronous design, where you can see
how the problem would arise, and the Mark II which uses 2 latches,
clocked on different internal states. It seems to me this avoids the
problem since these is now no vulnerable period where the port pin can
change without setting RBIF. Maybe I should set up a rig to settle this
once and for all?
Slightly related, various other "features" of the PIC have been
discussed here recently, which I had been told by Microchip UK techies
had been "fixed". I am now nervous about whether this is indeed true.
Could the gurus comment on the status of these PIC gems:
1) The need to disable interrupts during table reads.
AN556 suggests that if an interrupt occurs during a table read (using
addwf ... retlw) then the retlw after the one you wanted may be accessed
in error. I was told this is fixed, and no need to disable interrupts.
2) The need, when globally disabling interrupts, to check that they have
indeed been disabled.
AN576 (and the recent discussion) suggests this is necessary, again
Microchip have told me this does not apply to 'A' suffix parts in the
16C6x series, or to the 16C63. Only the 16C61 suffers, and will not go
to 'A' revision, use the 16C620/621 instead.
(1) and (2) together would be a real pain if you have a lot of lookups
(guess what I've got a lot of?).
> If you look at the data book you will see 2 versions of the port B
> circuitry, the original being an asynchronous design, where you can see
> how the problem would arise, and the Mark II which uses 2 latches,
> clocked on different internal states. It seems to me this avoids the
> problem since these is now no vulnerable period where the port pin can
> change without setting RBIF. Maybe I should set up a rig to settle this
> once and for all?
How does this relate to the portB interrupt-on-sleep function? When the
device is sleeping there aren't any clocks; is a seperate mechanism used
to handle that, or how does it work?
My preference (except that it wouldn't be compatible with existing parts)
would be to have the portB pins compared to the OUTPUT latches. This would
save circuitry and eliminate many of the problems related to PORTB interrupts.
Unfortunately, I don't know how to do that without breaking some existing
designs.
>My preference (except that it wouldn't be compatible with existing
>parts)
>would be to have the portB pins compared to the OUTPUT latches. This
>would
>save circuitry and eliminate many of the problems related to PORTB
>interrupts.
>Unfortunately, I don't know how to do that without breaking some
>existing
>designs.
This is definitely the way it should have been done in the first place.
What other use are the output latches when the pins are set for input?
Most existing software would not work though, since it just does a read
to reset the change detector before sleeping. If the existing
application uses the RB change detector in the recommended way only to
wakeup from SLEEP, the SLEEP instruction could be hooked to new logic
that resets the change detector. The SLEEP sequence would copy the pins
being compared to the output latch, and reset the RBIF bit. Most, though
certainly can't be sure if all, such applications would attempt to reset
the change detector immediately before sleeping.
On Tue, 30 Dec 1997 09:01:09 -0400 (EDTO) Paul Haas <RemoveMEpaulhTakeThisOuThamjudo.com>
writes:
>On Mon, 29 Dec 1997, Mike Keitz wrote:
>
>> Of course, the latency to detect a change becomes large and variable
>> using this workaround. It may help to organize things to only use
>the
>> hardware change detector during parts of the program that won't
>disrupt
>> it, and software detection at other times.
>
>If the PORTB pins can change independently, your scheme can still miss
>a
>change. Say B6 changes causing an interrupt. The interrupt routine
>must
>read PORTB to reset the comparison latch.
This could be handled by placing a software change detector in the ISR.
If the value read from PORTB the second time is not the same as the one
accepted the first time, the RBIF flag would be set again, or just not
cleared, causing another interrupt. Every time PORTB is read or written,
the inputs need to be compared to see if they changed (and may not have
been detected by hardware). In general the principle is to keep
interrupting until the value actually present on the PORTB pins is the
same as the one last accepted by the ISR, copied into RAM, and acted
upon.
If a pin changes, then changes back within the time that the change
detect ISR requires, it may not be processed properly. If multiple pins
change, there may not be time to process them all in the right order.
Very short pulses may fire the hardware or software change detectors, but
not remain long enough to be read and recognized by the ISR. These would
be problems even if the hardware change detector worked ideally. It only
detects changes, it doesn't queue and remember them.
In message <199712301922.NAA20751EraseME.....Mars.mcs.net>, John Payson
<EraseMEsupercatMCS.NET> writes
>
>How does this relate to the portB interrupt-on-sleep function? When the
>device is sleeping there aren't any clocks; is a seperate mechanism used
>to handle that, or how does it work?
A very good question, and one I hadn't considered. For the record, the
diagram I am looking at is labelled:
Fig 5.4: Block diagram of the RB7:RB4 pins for the PIC16C62A/63/64A/65A
The XOR gate which detects the pin change is driven from the outputs of
2 latches, driven from Q1 and Q3.
The latches appear to be transparent rather than edge clocked, so I can
only assume that the clock (Q1) to the latch which monitors the actual
port pin goes high during sleep. Then any pin change will pass through
the latch to the XOR, generating an interrupt?
It looks like Blighty is in for foul weather this weekend, so I'll try
to set up an empirical test of all this RB change stuff and report back.
Did anyone have a view on my other question, regarding the need to check
after disabling global interrupts?
>Did anyone have a view on my other question, regarding the need to
>check
>after disabling global interrupts?
This is necessary, because an interrupt could occur at the start of the
instruction that clears GIE (while GIE is still set). Since the
instruction has already started, the processor finishes it, clearing GIE.
Then the hardware clears GIE again and goes to the ISR. At the end of
the ISR, the RETFIE instruction sets GIE again. The program continues at
the instruction following the one that was supposed to clear GIE, but GIE
is still set. The official way is to check GIE and clear it again if it
ends up set. Blindly clearing GIE twice could work too, as long as "back
to back" interrupts can't occur.
Rather than clear GIE to disable interrutps, the individual interrupt
enable bit(s) could be cleared instead. Usually the ISR doesn't touch
them, so even if the clearing process were interrupted, they would stay
disabled afterward. The interrupt flag bits would remember any pending
interrupt.
> This is necessary, because an interrupt could occur at the start of the
> instruction that clears GIE (while GIE is still set). Since the
> instruction has already started, the processor finishes it, clearing GIE.
> Then the hardware clears GIE again and goes to the ISR. At the end of
> the ISR, the RETFIE instruction sets GIE again. The program continues at
> the instruction following the one that was supposed to clear GIE, but GIE
> is still set. The official way is to check GIE and clear it again if it
> ends up set. Blindly clearing GIE twice could work too, as long as "back
> to back" interrupts can't occur.
But what happened if the interrupt (frome another source, for example)
occur during ISR?
I think two instructions clearing GIE couldn't work in this case.
>But what happened if the interrupt (frome another source, for example)
>occur during ISR?
>I think two instructions clearing GIE couldn't work in this case.
Exactly. There are only a few cases where it will work. One case is if
the timer is the only source of interrupt. It is usually certain that
the timer will not run out again while its interrupt is being processed.
Anything that has more than one asynchronous source of interrupts would
need to use the check and loop method (or a lot of repeated clear GIEs).