However, some issues arose during implementation and testing:
- For high speed communication with no data loss you normally want to
use hardware flow control (CTS/RTS). In the serial.device at the
Amiga this is called 7-wire support.
To make this work correctly, you not only have to set the SERF_7WIRE in the IORequest->io_SerFlags field when opening devices (as described in the manual), but also when adjusting parameters afterwards with SDCMD_SETPARAM. If 7WIRE is not set in this call, it will fall back to 3-wire communication. At least this happens on my Amiga OS 2.05 system. - Sending data is pretty much error free, but receiving data comes with some
issues.
There are basically two error types (returned in io_Status of the IORequest) which can happen during regular transmission.- First there is the SerErr_BufOverflow, which basically says
that the internal device buffer for incoming data is full. There
are two ways to prevent this from happening:
- Use a larger buffer (io_RBufLen in SETPARAM) to get more time processing the data.
- Query data more often.
- The second error is more severe. It is SerErr_LineErr (Hardware
data overrun).
I did not find any detailed documentation about when this error happens so the following is my interpretation of what happens.The UART responsible for serial transfer has a single shift register and a single byte buffer. Whenever a full byte is received, it is transferred to the buffer and a flag indicates the availability. If another bytes is received without the previous byte being read, the bit 15 (OVRUN) of the register SERDATR ($018) is set indicating data loss.
I think when this bit is set, the error SerErr_LineErr is returned. I have seen this error happening sporadically when there is high CPU load or a lot of interrupts going on. My guess is that the interrupt for getting the serial byte is not executed fast enough when there are other interrupts routines running.
With multitasking enabled, there is not much to do about this error. Here are some possible workarounds:
- Use a specific communication protocol so that the other communication side is only sending data when you are actually within the receive loop of your code. You could send a single character to let the other side start sending data. Otherwise the other side might already send data while your code is doing something else which could trigger interrupts (like disk access or so).
- Reduce serial speed. This is obvious, a slower speed means more time between bytes thus reducing the chance of a buffer overflow.
- Disable multitasking/interrupts and poll hardware registers directly. Controlling the serial port is relatively straight forward and when you have full control over the hardware, you can actually make sure you have CPU cycles available for reading the byte buffer from the UART. Downside is of course, that the OS is basically disabled during that time with other consequences.
- First there is the SerErr_BufOverflow, which basically says
that the internal device buffer for incoming data is full. There
are two ways to prevent this from happening:
- Support for OS < 2.0
The current OS documentation usually covers the current library functions but access to the serial.device is possible with Kickstart 1.3 functions as well. But it is hard to find documentation about how to do stuff in older OS version.All you have to do is to use the function
CreatePort("somename",0)
instead ofCreateMsgPort()
andCreateExtIO
instead ofCreateIORequest
For cleaning up, you do
DeleteExtIO
instead ofDeleteIORequest
andDeletePort
instead ofDeleteMsgPort
The calls to OpenDevice and DoIO can remain the same.