|
|
View previous topic :: View next topic |
Author |
Message |
stephan
Joined: 31 Jan 2004 Posts: 3 Location: Germany
|
Software-RS232 produces wrong baudrate with TIMER0-IRQ |
Posted: Sat Jan 31, 2004 6:21 pm |
|
|
Hi!
I have a problem with (software) RS232 communication on a 16C621: When using Timer0 IRQ (at 1kHz), the RS232 baudrate slows down from 300 bauds to about 280 bauds.
I guess the cause is clearly because the software uart uses fixed delays without interrupts, as mentioned here: http://www.ccsinfo.com/forum/viewtopic.php?t=18195
The question is now, how to get around this problem. I could just increase the baudrate, but this would be dependent on a constant time being spent in the irq handler, wich doesn't occur in reality.
Is there any way to use the original software RS232 routines together with IRQs? Or do I have to create an uart using IRQ myself?
Thanks in advance!
Stephan |
|
|
Ttelmah Guest
|
Re: Software-RS232 produces wrong baudrate with TIMER0-IRQ |
Posted: Sun Feb 01, 2004 3:51 am |
|
|
stephan wrote: | Hi!
I have a problem with (software) RS232 communication on a 16C621: When using Timer0 IRQ (at 1kHz), the RS232 baudrate slows down from 300 bauds to about 280 bauds.
I guess the cause is clearly because the software uart uses fixed delays without interrupts, as mentioned here: http://www.ccsinfo.com/forum/viewtopic.php?t=18195
The question is now, how to get around this problem. I could just increase the baudrate, but this would be dependent on a constant time being spent in the irq handler, wich doesn't occur in reality.
Is there any way to use the original software RS232 routines together with IRQs? Or do I have to create an uart using IRQ myself?
Thanks in advance!
Stephan |
1) Keep the time spent in the interrupt handler really short. Your change, implies that either the timer is being called a lot, or a rather long time is being spent in the handler. Normally, using the 'soft' comms at high baud rates is impossible, but at 300bps, it dhould be achievable with an acceptable level of error, if the interrupt is kept very short.
2) Use an 'encapsulated' version of the putc function, with something like:
Code: |
void noint_putc(int8 val) {
disable_interrupts(global);
putc(val);
enable_interrupts(global);
}
//Then you can 'printf' with:
printf(noint_putc,"Demo string");
//Or putc with:
noint_putc('\n');
|
The interrupt will be disabled for each character in turn, but not for the whole string.
The fact you are using timer0, suggests you may be calling the interrupt rather a lot (if you are using the 1:1 prescaler, the interrupt will be occuring every 256 instructions), given the overhead of the global interrupt handler (typically about 30 instruction times), your sort of error would be seen. Using a less frequent interrupt, reduces the overall effect.
If this is your only interrupt handler, and only does a small amount of work (incrementing a counter for instance), you can reduce the overhead very significantly, by writing your own 'int_global' function, and only saving the W reg, status, & BSR, then doing your simple code, restoring the registers, and returning. It is possible to reduce the overhead to only about half that of the normal routine this way.
Serial timing errors, up to about 3%, are 'acceptable', in terms of still giving reliable comms.
It should be possible to make the timer interupt take an allmost constant time, by 'padding' the faster parts. Though this is slightly 'nasty', it might represent a way round your problem.
Best Wishes |
|
|
stephan
Joined: 31 Jan 2004 Posts: 3 Location: Germany
|
|
Posted: Sun Feb 01, 2004 6:58 am |
|
|
Hi Ttelmah!
Thanks a lot for the idea with the encapsulated putc()! I think this does the job for me.
Just for clarification of your assumptions:
- Timer0 was used because it's the only one in a 16C621
- A Timer0-IRQ was generated at 1kHz rate, that made 3 IRQs per char in average.
- The IRQ handler just incremented some counters, so I think the overhead contributed its part to the 240us delay per char / 80us per IRQ (@3,6864MHz clock speed).
I will have to reduce the timer IRQ frequency to avoid multiple IRQs during a single putc(), but then your solution should work perfectly!
Thanks again & best regards
Stephan |
|
|
Ttelmah Guest
|
|
Posted: Sun Feb 01, 2004 3:38 pm |
|
|
stephan wrote: | Hi Ttelmah!
Thanks a lot for the idea with the encapsulated putc()! I think this does the job for me.
Just for clarification of your assumptions:
- Timer0 was used because it's the only one in a 16C621
- A Timer0-IRQ was generated at 1kHz rate, that made 3 IRQs per char in average.
- The IRQ handler just incremented some counters, so I think the overhead contributed its part to the 240us delay per char / 80us per IRQ (@3,6864MHz clock speed).
I will have to reduce the timer IRQ frequency to avoid multiple IRQs during a single putc(), but then your solution should work perfectly!
Thanks again & best regards
Stephan |
I have to ask why you need to interrupt this often?. Unless you really 'must' have events happening at the 1mSec seperation level, why not just increase the prescaler on the timer interrupt. The big advantage, is that if you drop the timer interval below the time needed for one character, then you can stop the interrupts for each character using the system I posted, and though you will then get an interrupt very late, no time will be lost by the system.
This then gives nice timekeeping from the timer, and the ability to do the serial transmission, without problems. :-)
You can also potentially use the approach if you need a serial 'receive', or using the interrupt input pin for the chip as the receive line, generating an interrupt on the first 'edge' of the incoming character, and call the 'polling' code inside the interrupt routine. Then since you are now inside an interrupt handler, there will be no response to the other interrupt till the reception is finished. The only problems come if a character arrives while interrupts are disabled (in the transmit routine, or in the timer interrupt). Even the latter case should be OK, just resulting in the polling beginning perhaps 100uSec late.
Good luck anyway. :-)
Best Wishes |
|
|
stephan
Joined: 31 Jan 2004 Posts: 3 Location: Germany
|
|
Posted: Mon Feb 02, 2004 9:27 am |
|
|
Hi Ttelmah!
Quote: |
that if you drop the timer interval below the time needed for one character, then you can stop the interrupts for each character using the system I posted
|
Yes, that is exactly what I meant. I'm now using 1200 baud & 100 Hz interrupt rate, so that no two irq's can occur during a single char. This works well.
Having 1ms steps in timing definitions was just nice, 10ms is still okay. So you are right here and I changed that.
Chars arriving during transmission are not an issue in my case, because it's a half duplex RS485 bus with multiple nodes and arbitration is done before the transmission itself.
Thank you once more :-)
Stephan |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|