Serial data transfer on the Amiga

While implementing serial support for my tool APCComm I stumbled across some weird issues with the serial port at the Amiga and I could not find much information about those specific issues. Basically I was following the good documentation at https://wiki.amigaos.net/wiki/Serial_Device

However, some issues arose during implementation and testing:

  1. 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.
  2. 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:
      1. Use a larger buffer (io_RBufLen in SETPARAM) to get more time processing the data.
      2. Query data more often.
      However, I think with proper 7-wire communication, this error should not happen as the Amiga will indicate that the buffer is full stopping the other side from sending data.
    • 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:

      1. 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).
      2. Reduce serial speed. This is obvious, a slower speed means more time between bytes thus reducing the chance of a buffer overflow.
      3. 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.
  3. 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 of
    CreateMsgPort()
    and
    CreateExtIO
    instead of
    CreateIORequest

    For cleaning up, you do

    DeleteExtIO
    instead of
    DeleteIORequest
    and
    DeletePort
    instead of
    DeleteMsgPort

    The calls to OpenDevice and DoIO can remain the same.

Conclusion

While it is relatively easy to program the serial.device on the Amiga, having a reliable high speed connection seems to be hard to do with full multitasking enabled. Especially the hardware overrun error is hard to avoid since you can't control the priority of interrupts.
tags: amiga8
older (2021-08-15): Data corruption on Amiga 600/1200 IDE controller