[comp.protocols.misc] Need help programming Zilog 85C30 SCC

gram@uctcs.uucp (Graham Wheeler) (04/06/91)

Hi netters

I am trying to write a simple dumb terminal program for the Emulex DCP286i
card. This card has a 286 processor, 128kb of memory, and two Zilog 85C30 SCC
chips. I have used the Intel Microcommunications Handbook (82530SCC application
note), DCP286i Programming and Technical Reference Manual, and a sample
(synchronous) program that came with the card as my resources. My application
should use 1200 baud async, and just pass keystrokes from the PC to the card
and out the port, and received characters to the PC.

I have struggled for a while with this, and have got a program which certainly
runs; I have a variable `ready' which I use as a combined semaphore/debugging
message flag for use by the PC part of the program. However, nothing is coming
out the port, and I continually get messages that characters are being
received (always the same character), even when I have not plugged the port
into a DCE.

The most likely source of the problem would be in the initialisation of the 
85C30. I use an array of register/value pairs for this, called `scc_async_cb'.

If anyone reading this has programmed an 85C30 or 82530, particularly if they
have programmed a Emulex DCP card, I would appreciate it if they could take
a look at the code below (my slave program) and see anything that could be
wrong, particularly, as I said, in `scc_async_cb'.

Please E-mail any responses. Thanks in advance.

Graham

====== Text of slave.c =====================================================

#pragma inline

unsigned char tx_byte, tx_flag, rx_byte, rx_flag,
		ready, Channel, status0, status1;

#define BASE_PORT_ADDR	0x3E0
#define CH_A_CMD	(BASE_PORT_ADDR+2)
#define CH_A_DATA	(BASE_PORT_ADDR+3)
#define CH_B_CMD	(BASE_PORT_ADDR+0)
#define CH_B_DATA	(BASE_PORT_ADDR+1)

typedef unsigned char ctrlblk[];

ctrlblk scc_async_cb = {
	9, 0xC0, 	/* ch A & B reset */
	4, 0x4C,	/* 2 stop bits, no parity, x16 clock mode */
	1, 0,		/* no interrupts enabled */
	3, 0xC0,	/* Rx 8 bits/char, no auto-enable */
	5, 0x60,	/* Tx 8 bits/char */
	6, 0,
	7, 0,
	9, 0,
	10, 0,
	11, 0x54,	/* rxc=txc=BRG  */
	12, 0xBE,	/* To generate 1200 baud, x16 @ 10Mhz */
	13, 0x00,
	14, 3,		/* BRG src = SYS CLK, enable BRG */
	15, 0,		/* All ext status interrupts off */
	3, 0xC1,	/* receive enable */
	5, 0xEA,	/* tx enable, dtr on, rts on */
B
};

#define ASYNC_CB_LEN	16

// Output to a port on the DCP card

void s_out(unsigned short port, unsigned char val)
{
	_DX = port;
	_AL = val;
	asm out dx, al
}

// Input from a port on the DCP card

unsigned char s_in(unsigned short port)
{
	_DX=port;
	asm in al, dx
	return _AL;
}

// Read the status values in read registers 0 & 1

void get_status(void) {
	unsigned short ch_addr = (Channel==1 ? CH_A_CMD : CH_B_CMD);
	s_out(ch_addr,0);
	status0 = s_in(ch_addr);
	s_out(ch_addr,1);
	status1 = s_in(ch_addr);
}

// Output the control block to the SCC

void output_cb(int channel, ctrlblk cb, int len) {
	int i=0;
	unsigned short ch_addr = (channel==1 ? CH_A_CMD : CH_B_CMD);
	while (len--) {
		(void) s_in(ch_addr); // ensure control register pointer update
		s_out(ch_addr,cb[i++]);
		s_out(ch_addr,cb[i++]);
	}
}

void setup_scc(int channel) {
	output_cb(channel,scc_async_cb,ASYNC_CB_LEN);
}

/* Non-blocking send, returns 0-fail, 1-success */

int send_byte(int channel, unsigned char b) {
	unsigned short ch_addr = (channel==1 ? CH_A_CMD : CH_B_CMD);
	(void)s_in(ch_addr); s_out(ch_addr,0);
   	if (s_in(ch_addr)&4==0) return 0; // busy - fail
	s_out(ch_addr+1,b);
	return 1; // success

}

/* Non-blocking receive */

int receive_byte(int channel,unsigned char *b) {
	unsigned short ch_addr = (channel==1 ? CH_A_CMD : CH_B_CMD);
	(void)s_in(ch_addr); s_out(ch_addr,0);
   	if (s_in(ch_addr)&1==0) return 0; // none available - fail
	*b = s_in(ch_addr+1);
	return 1; // success
}

/* Blocking send & receive */

void put_byte(int channel, unsigned char b) {
	while (send_byte(channel,b)==0);
}

void get_byte(int channel,unsigned char *b) {
	while (receive_byte(channel,b)==0);
}

/* The main slave program */

#ifdef DEBUG
#define WAIT(n)		ready=n; while (ready) // ready is used as semaphore
#else
#define WAIT(n)
#endif

void slaveprog() {
	int n;
	WAIT(1);
	setup_scc(Channel);
	ready = 3;
	// The logic is:
	//	If we have received something, and the receive flag
	//	is clear, get the byte, and set the receive flag.
	//	If the send flag is set, try to send the byte.
	//	If successful, clear the send flag

	for (;;) {
		if (rx_flag==0) {
			WAIT(4);
			rx_flag = receive_byte(Channel,&rx_byte);
			WAIT(rx_flag ? 5 : 10);
		} else {
			WAIT(8);
		}
	 
		if (tx_flag==1) {
			WAIT(6);
			tx_flag = !send_byte(Channel,tx_byte);
			WAIT(tx_flag ? 7 : 11);
		} else {
			WAIT(9);
		}
	get_status();		
	}
}

Graham Wheeler <gram@cs.uct.ac.za> | "That which is weak conquers the strong,
Data Network Architectures Lab     | that which is soft conquers the hard.
Dept. of Computer Science          | All men know this; none practise it"
University of Cape Town            |		Lao Tzu - Tao Te Ching Ch.78