View previous topic :: View next topic |
Author |
Message |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
Looking for SW serial port example under interrupt control |
Posted: Thu Mar 18, 2004 4:51 pm |
|
|
I'm writing an application that has to read data from one serial RS-232 device, process the data and then pass it on to a second serial device. One of these devices can use the inbuilt USART of my PIC18F458, but the other device must be handled by a software driven serial port.
Because I have several other ports to manage as well and the data can arrive any moment in time, I'm looking for a bit banging example under interrupt control. I rather don't use an external UART if I can save the money doing it in software.
I found an example in the book Serial PIC'n by Roger Stevens but haven't managed yet to port the assembly code to my CCS-compiler. Also I'm not so sure this code can handle higher data rates.
What clock rates are you people running your PICs at? A nice round value like 20MHz or a multiple of 1024Hz, like 19,66MHz so you can easily use the Timer0 overflow?
What experiences do you people have using bit banging? Is it reliable?
Hints, tips or example code are appreciated. |
|
|
ritchie
Joined: 13 Sep 2003 Posts: 87
|
|
Posted: Thu Mar 18, 2004 5:18 pm |
|
|
Try this forum link http://www.ccsinfo.com/forum/viewtopic.php?t=17448&highlight=intext
Scroll to the bottom of the page... their u can see an example on how to implement software-based UART using external interrupt.
BTW, their is a limitation of software UART in terms of baud rate due to latency issue. I guess you have to check or conduct test on the speed you are going to use.
Hope this helps....
|
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Thu Mar 18, 2004 5:39 pm |
|
|
Or you can connect your RX line to a capture pin and configure it to interrupt on the falling edge. I've used it before and it works like a charm. |
|
|
Guest
|
|
Posted: Sun Mar 21, 2004 6:08 pm |
|
|
Haplo wrote: | Or you can connect your RX line to a capture pin and configure it to interrupt on the falling edge. I've used it before and it works like a charm. |
Do you have a sample snippet in using the capture pin and configured to interrupt?
This might be better than the external interrupt.
Thanx |
|
|
ritchie
Joined: 13 Sep 2003 Posts: 87
|
|
Posted: Sun Mar 21, 2004 6:27 pm |
|
|
Haplo wrote: | Or you can connect your RX line to a capture pin and configure it to interrupt on the falling edge. I've used it before and it works like a charm. |
This is great software UART using CCP interrupt!!! at what speed did you configure the UART? Is it capable of handling 115200bps?
Is it possible to share a snippet in utilizing this method? CCP configuration and #int_ccp configuration?
Thanx |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Sun Mar 21, 2004 10:07 pm |
|
|
Whether it is capable of 115200 or not depends on many factors such as your crystal speed and the other interrupts you are using. As for the code, there is not much to share. Initialise the capture module with
setup_ccp1(CCP_CAPTURE_FE);
enable_interrupts(INT_CCP1);
And then read a whole byte (and put it in your receive buffer) in the interrupt routine. Remember this method is only good enough if you can afford to wait for one whole byte in your interrupt routine. Otherwise you'll also need to use timer interrupts to be able to capture each bit one by one. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Mar 23, 2004 2:46 am |
|
|
I do like the idea of using the capture register for receiving data!
This way I get an accurate 16-bit timestamp and have the advantage of being able to wake up from sleep-mode without using one of the EXT-INT lines.
Disadvantage is that for full-duplex transmissions I still need one of the timers for generating bit-time interrupts. And because it all works under interrupt I have to be very carefull not to generate jitter on the transmitting.
Quote: | And then read a whole byte (and put it in your receive buffer) in the interrupt routine. Remember this method is only good enough if you can afford to wait for one whole byte in your interrupt routine. |
I don't like to block my interrupt routine for reading a whole byte! And I don't see the reason for blocking, why not implement it like this: In your interrupt routine you can save the timestamp and set the interrupt to trigger on the opposite edge. Then, next time the interrupt gets triggered you can read the time difference between the interrupts and from this derive the number of received bits with same level. Then set opposite edge again and repeat until the whole byte is received. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Mar 23, 2004 4:01 am |
|
|
I'm sure it is possible to create full duplex serial communications in software, but I'm afraid it will take a lot of time to make it stable for commercial use. Especially I'm concerned about bit-jitter in the transmitting.
Just for fun a timing calculation:
Running at 20Mhz and transmitting data at 19200 baud gives me about 260 instructions / bit time for the transmit. Assuming the receiver will sample the data somewhere between 1/3 and 2/3 of the bittime gives a maximum allowed latency of 86 instructions.
Checking the generated code for #int_global gives an overhead of 45 instructions, so my transmit and receive functions will have to do their job in 41 instructions.... Is feasable, but tight.
A future development will require my device to accept 56k baud... I think it's better to safe development time and spend the saved the money on an additional hardware UART like the MAX3100 or MAX3110. |
|
|
Haplo
Joined: 06 Sep 2003 Posts: 659 Location: Sydney, Australia
|
|
Posted: Tue Mar 23, 2004 6:54 am |
|
|
If you don't want to use CCS software interrupt and want to implement it yourself, you'd have to:
1.Get a capture interrupt to detect the start bit
2.Disable the capture interrupt
3.Load one of the timers so it would overflow in half-bit time
4.In the timer ISR read one bit and store it
5.Reload the timer, go to 3, continue until you receive the stop bit
6.Put all the bits together and create the data byte
7.Disable the timer interrupt, enable the capture interrupt and wait for the next byte to come.
This should be easy to do, none of the two ISRs will have more than a few instruction. |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Wed Mar 24, 2004 10:58 am |
|
|
I have done this for 19200 baud, but it isn't true full duplex. I wanted to use a single timer for incoming and outgoing data, and keep the same timer running to operate other processor functions (minor glitches are acceptable). So my design shifts the timer trip point as needed to process incoming data bytes, which means that if an outgoing byte is in progress when the incoming byte begins, it'll get distorted and most likely won't be properly received. There are checksums included, though, so the computer that's on the other end of the line can verify the incoming packets and ask for a re-transmission if necessary.
This would all be a lot easier if half-duplex operation were usable. I could imagine various ways to set this up, depending on which direction of data has priority. |
|
|
|