Z80 SIO Programming hints
Micro Projects Home Page


 Microprocessor Basics

Micro Basics

Site Projects

Site Projects

Construction Techniques


Programming concepts




8085 page

8085 page

Fault Finding

Fault Finding

Data Sheets

Data Sheets

EEprom Programmer


Video Information

VIDEO info

Peripheral Circuitry

Peripheral circuitry

Central Heating and Z280's

Z280 and  Central Heating  Controllers

Concluding Ideas

Concluding ideas




The programming complexities of large scale integration components are usually directly proportional to the facilities and versatility of the device.In the case of the Z80SIO, it will probably take some time even for even the more experienced programmer to work out how to make it perform even the most rudimentary tasks. To the beginner at microprocessor programming, it is possible that the bewildering array of registers will cause a total confusion unless a logical approach is taken from the start.

Let us look at what is on offer then.

The SIO contains 3x READ ONLY registers for the 'B' channel, 2x READ ONLY registers for the 'A' channel, 8x WRITE registers on the 'B' channel and 7x WRITE registers for the 'A'. Clearly for anyone attempting to make one of these things work correctly, a degree of understanding on which have to be programmed and which may be left alone, will make the job much easier.

First of all, break down the task into more manageable chunks. Hopefully those new to the device will initially be concerned with a single channel. i.e. Receive 'A' and Transmit 'A'. We can therefore ignore any of the dedicated channel 'B' registers. Hopefully (!) Most programmers will be using the device in ASYNC mode, which means that we can ignore any references to SYNC, SDLC and HDLC. That's a few more out the way! Lastly, although it is up to the individual as to whether they use the extensive interrupt facilities on offer, or whether to use the much simpler 'Polling' method of operation.

With INTERRUPTS, the CPU ignores the SIO until it's attention is grabbed by the SIO raising an INTERRUPT. In the case of the much simpler POLLING method, the CPU periodically shuffles over to the SIO to see if it has anything that needs dealing with. Both can be made to work equally well, but from the programmer's point of view, it is often far easier to resort to polling.

Let's take a typical WORKING example that may be applied to ANY circuit using the device. Obviously, it may be necessary to change some of the values if the particular application calls for it.

First and foremost, ensure that you have a proper LIST of the addresses that will be needed to access the SIO. The HARDWARE will need to be organised correctly in order to do this.

Connect up the SIO as an I/O device with it's two control lines taken to Address lines 0 and 1. This allows the CPU to access the two separate channels and the control / data registers therein. In the programming example that follows, we will choose an I/O address of 30h. If we now attach the two register select lines A/B and C/D to address lines 0 and 1, we can select the registers by using the following table:

 30   Selects the Data register on channel A

 31   Selects the Data register on channel B

 32   Selects the Control registers on channel A

 33   Selects the Control registers on channel B

Both the READ and WRITE control registers (excepting register 0), need TWO consecutive SIO transfers in order to gain access to them. The FIRST access is a 'pointer' byte in write register 0 of that channel, before the chosen register can be either programmed or read. Look at the WORKING RECEIVER example which follows:

410C  3E

410D  18     Load the accumulator with value 18h

410E  D3  

410F  32     Output the 18h to Write control register 0. RESET CHANNEL

4110  00     NOP

4111  3E   

4112  04     Load the accumulator with value 04h

4113  D3

4114  32     Output 04h to write ctl reg 0: Request transfer to register 4

4115  3E

4116  44     Load the accumulator with 44h

4117  D3

4118  32     Output the 44 to Register 4: x16 clock, 1 stop bit, no parity

4119  3E    

411A  03     Load the accumulator with 03h

411B  D3

411C  32     Output the 03h to write ctl reg 0:Request transfer to register 3

411D  3E    

411E  C0     Load the accumulator with C0h

411F  D3    

4120  32     Output the C0h to register 3: Set receive config to 8 bits

4121  3E    

4122  05     Load A with 05h

4123  D3

4124  32     Output 05h to write control reg 0: Request transfer to reg 5

4125  3E   

4126  60     Load A with 60h

4127  D3  

4128  32     Output to Reg 5: Transmitter configuration set to 8 bits

Channel A can now be considered set up for both receiving and transmitting. The above initializing routines only need setting up at the beginning of the program, unless some factors are to be altered once the program is running.

In order to use the device for RECEIVING, (and by using the same transfer methods we used above) we need to send a C1h to Write register '3' (remember,at I/O address 32h?) - which will enable the receiver. After doing this, all that is necessary, if the POLLING method of usage is being applied is to periodically send a ZERO to read register 0 (code in the above example would be D3 32) then READ in the status register by using the command DB 32. As the'Read character available' bit in this register is actually Bit 0, we can rotate the result, so putting Bit 0 into the 'Carry' flag position by using the command 'RRA'. (there are of course several other alternative ways of testing it.) After which the 'Jump if no carry' command can be used if it is empty; thus:

481A   3E

481B   03    Ld A,03

481C   D3  

481D   32    Output to 32

481E   3E

481F   C1    Ld A,C1

4820   D3

4821   32    Output to 32

4822   00

4823   00



4825   D3

4826   32    Output to 00

4827   DB

4828   32    Read in 32

4829   1F    RRA

482A   D2

482B   35

482C   48    Jump if no carry to 4835h (go to do other tasks elsewhere)

482D   DB

482E   30    Carry bit is set. Read in ASCII character from SIO to accumulator

A few last points to note.

The conditional jump at 482C is there to allow other processing tasks to be performed before the program returns to 4824 to 'poll' the register again. Obviously once the program has found a character and is running beyond 482E,it is up to the programmer to determine just what to do with it!

A simple TRANSMITTER routine to set up and output a character follows here:

47DC    3E

47DD    05    LDA,05

47DE    D3

47DF    32    Output 05 to request register 5

47E0    3E

47E1    68    LDA,68

47E2    D3

47E3    32    Enable transmitter at register 5

47E4    97    Zero A

47E5    D3

47E6    32    Access read register 0

47E7    DB

47E8    32    Read in register 0

47E9    CB

47EA    57    Test bit 2 of byte read in for transmitter already busy

47EB    CA

47EC    E4

47ED    47    Jump if zero (i.e. not empty and in use) to 47E4 to retest

47EE    7A    LDA,D    Load A with the byte to transmit 

               - in this program we've put it in the D register

47EF    D3

47F0    30    Write the SIO data register with the byte to be sent

If a return were to be added to the bottom of this routine (at 47F1h) then the whole block of code may be considered a SUBROUTINE in it's own right - to use it, one simply has to place the character to be transmitted in the 'D'register then use the GOSUB command with the start address:




Strictly speaking (as I'm in a picky mood this evening!) It is not necessary to enable the transmitter each and every time one sends a character, so one could theoretically jump into the subroutine at address 47E4h.

Happy programming!