📄 cycduart.c
字号:
//=============================================================================
//
// cycduart.c - Cyclone UART Diagnostics
//
//=============================================================================
//####COPYRIGHTBEGIN####
//
// -------------------------------------------
// The contents of this file are subject to the Red Hat eCos Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.redhat.com/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is eCos - Embedded Configurable Operating System,
// released September 30, 1998.
//
// The Initial Developer of the Original Code is Red Hat.
// Portions created by Red Hat are
// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
// All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): Scott Coulter, Jeff Frazier, Eric Breeden
// Contributors:
// Date: 2001-01-25
// Purpose:
// Description:
//
//####DESCRIPTIONEND####
//
//===========================================================================*/
#include "cycduart.h"
#include "iq80310.h"
#define DFLTLOOPERMS 500
extern int printf(char*,...);
extern long hexIn();
int break_flag = 0;
unsigned long baud_rate = 0;
static int duart_already_init = FALSE;
static unsigned int uart_unit = DFLTPORT;
static int looperms;
static int calc_looperms(void);
void serial_init(void);
int inreg(int);
void outreg(int, unsigned char);
void serial_set(unsigned long);
void serial_loopback(int);
int serial_getc();
void serial_putc(int);
int serial_write(int, const unsigned char *, int);
int serial_read(int, unsigned char *, int, int);
extern int enable_external_interrupt (int int_id);
extern int disable_external_interrupt (int int_id);
extern int isr_connect(int int_num, void (*handler)(int), int arg);
extern int isr_disconnect(int int_num);
void duart_initialize()
{
if (duart_already_init == FALSE)
{
/* Calculate the time constant for timeouts on serial_read. */
if ((looperms = calc_looperms()) <= 0)
looperms = DFLTLOOPERMS;
}
/* Initialize the serial port and set the baud rate.
* The baud rate is set here for sanity only; the autobaud
* mechanism will change it as required when the host connects.
*/
serial_init();
serial_set(baud_rate?baud_rate:9600L);
duart_already_init = TRUE;
}
/* Establish the loop/time constant to be used in the timing loop in
* serial_read. This is done by putting the UART into loopback mode.
* After transmitting a character at 300 baud, we wait for the character
* to be received. Then divide the number of loops waited by the number
* of milliseconds it takes to transmit 10 bits at 300 baud.
* If your transmitter doesn't have a loopback mode, this value can be
* calculated using a timer or some other facility, or an approximate
* constant can be used.
*/
#define TESTBAUD 300L
#define NBYTES 10
#define BITS_PER_BYTE 10 /* 1 start bit, 8 data bits, 1 stop bit */
#define TOTAL_MS (NBYTES*BITS_PER_BYTE*1000/TESTBAUD)
static int
calc_looperms(void)
{
int i, count, c;
int totalloops = 0;
serial_init();
serial_set(TESTBAUD); /* set 300 baud */
serial_loopback(1); /* enable loop back mode */
for (i=0; i < NBYTES; i++)
{
count = 1;
serial_putc(0xaa); /* xmit character */
/*
* The timing loop is the same as the loops in serial_read.
* Any changes to the loops in serial_read should be reflected
* here.
*/
do
{
c = serial_getc();
} while (c < 0 && count++ > 0);
totalloops += count;
}
serial_loopback(0);
return(totalloops/TOTAL_MS);
}
/*
* Initialize the device driver.
*/
void serial_init(void)
{
/* If the serial port has been init'd before, there may be data in it */
/* Wait for the transmit FIFO to empty out before resetting anything */
if (duart_already_init == TRUE)
{
while (!(inreg(LSR) & LSR_TSRE));
}
/*
* Configure active port, (uart_unit already set.)
*
* Set 8 bits, 1 stop bit, no parity.
*
* LCR<7> 0 divisor latch access bit
* LCR<6> 0 break control (1=send break)
* LCR<5> 0 stick parity (0=space, 1=mark)
* LCR<4> 0 parity even (0=odd, 1=even)
* LCR<3> 0 parity enable (1=enabled)
* LCR<2> 0 # stop bits (0=1, 1=1.5)
* LCR<1:0> 11 bits per character(00=5, 01=6, 10=7, 11=8)
*/
outreg(LCR, 0x3);
/* Assert DTR and RTS to prevent hardware handshake problems with
serial terminals, etc. which can be connected to the serial port */
outreg(MCR, MCR_DTR | MCR_RTS);
outreg(FCR, FIFO_ENABLE); /* Enable the FIFO */
outreg(IER, INT_ENABLE); /* Enable appropriate interrupts */
}
/* Read a received character if one is available. Return -1 otherwise. */
int serial_getc()
{
if (inreg(LSR) & LSR_DR)
{
return inreg(DataIn);
}
return -1;
}
/* Transmit a character. */
void serial_putc(int c)
{
while ((inreg(LSR) & LSR_THRE) == 0)
;
outreg(DataOut, c);
}
/*
* Set the baud rate.
*/
void serial_set(unsigned long baud)
{
unsigned char sav_lcr;
if(baud == 0)
baud = 9600L;
/*
* Enable access to the divisor latches by setting DLAB in LCR.
*
*/
sav_lcr = inreg(LCR);
outreg(LCR, LCR_DLAB | sav_lcr);
/*
* Set divisor latches.
*/
outreg(BaudLsb, XTAL/(16*baud));
outreg(BaudMsb, (XTAL/(16*baud)) >> 8);
/*
* Restore line control register
*/
outreg(LCR, sav_lcr);
}
/*
* This routine is used by calc_looperms to put the UART in loopback mode.
*/
void serial_loopback(int flag)
{
if (flag)
outreg(MCR, inreg(MCR) | MCR_LOOP); /* enable loop back mode */
else
outreg(MCR, inreg(MCR) & ~MCR_LOOP); /* disable loop back mode */
}
/*
* These routines are used to read and write to the registers of the
* 16552. The delay routine guarantees the required recovery time between
* cycles to the 16552.
* DUART is the base address of the 16552.
* DUART_DELTA gives the spacing between adjacent registers of the 16552.
* For example, if A0,A1,A2 of the 16552 are connected to A2,A3,A4 of
* the processor, DUART_DELTA must be 4.
*/
int inreg(int reg)
{
int val;
val = *((volatile unsigned char *)TERMINAL + (uart_unit * SCALE + reg));
return val;
}
void outreg(int reg, unsigned char val)
{
*((volatile unsigned char *)TERMINAL + (uart_unit * SCALE + reg)) = val;
}
/****************************************************************/
/* The following functions are all part of the Breeze UART test */
/****************************************************************/
static volatile int uart_int;
/************************************************/
/* BUS_TEST */
/* This routine performs a walking ones test */
/* on the given uart chip to test it's bus */
/* interface. It writes to the scratchpad reg. */
/* then reads it back. During */
/* this test all 8 data lines from the chip */
/* get written with both 1 and 0. */
/************************************************/
static int bus_test ()
{
unsigned char out, in;
int bitpos;
volatile int junk;
junk = (int) &junk; /* Don't let compiler optimize or "registerize" */
outreg(SCR,0); /* Clear scratchpad register */
for (bitpos = 0; bitpos < 8; bitpos++)
{
out = 1 << bitpos;
outreg(SCR,out); /* Write data to scratchpad reg. */
junk = ~0; /* Force data lines high */
in = inreg(SCR); /* Read data */
printf ("%02X ", in);
/* make sure it's what we wrote */
if (in != out)
return (0);
}
outreg(SCR,0); /* Clear scratchpad register */
printf ("\n");
return (1);
}
/************************************************/
/* DISABLE_UART_INTS */
/* This routine disables uart interrupts */
/************************************************/
static void disable_uart_ints ()
{
outreg(IER,0); /* Make the uart shut up */
}
/************************************************/
/* UART_ISR */
/* This routine responds to uart interrupts */
/* must return 1 to indicate that an interrupt */
/* was serviced. */
/************************************************/
static void uart_isr (int unused)
{
unsigned char iir;
disable_uart_ints ();
uart_int = 1;
/* read the IIR to clear the interrupt */
iir = inreg(IIR);
return ;
}
/************************************************/
/* INIT_UART */
/* This routine initializes the 16550 interrupt */
/* and uart registers and initializes the uart */
/* count. */
/************************************************/
static void init_uart ()
{
outreg(IER,0x02); /* Enable Tx Empty interrupt -
should generate an interrupt since Tx is
empty to begin with */
}
/****************************************/
/* UART DIAGNOSTIC TEST */
/****************************************/
void uart_test ()
{
volatile int loop;
int looplim;
int int_id;
unsigned long* reg_ptr;
int i, baud;
/*11/01/00 */
char info[] = {"Move Console Cable back to Connector J9 and hit <CR> to exit test"};
int index;
looplim = 400000;
/* perform tests on both UARTs */
for (uart_unit = 0; uart_unit < 2; uart_unit++)
{
if (uart_unit == 0)
int_id = UART1_INT_ID;
else
int_id = UART2_INT_ID;
if (!bus_test ())
printf ("\nERROR: bus_test for UART Unit %d failed\n", uart_unit);
else
{
printf ("\nbus_test for UART Unit %d passed\n", uart_unit);
uart_int = 0;
isr_connect (int_id, uart_isr, 0);
if (enable_external_interrupt(int_id) != OK)
printf("ERROR enabling UART UINT %d interrupt!\n", uart_unit);
init_uart ();
loop = 0;
while (!uart_int && (loop < looplim))
loop++;
if (!uart_int)
printf ("UART Unit %d INTERRUPT test failed %X\n", uart_unit, loop) ;
else
printf ("UART Unit %d INTERRUPT test passed\n", uart_unit);
serial_putc(' ');
}
/* disable UART interrupt */
if (disable_external_interrupt(int_id)!= OK)
printf("ERROR disabling UART UNIT %d interrupt!\n", uart_unit);
/* disconnect test handler */
isr_disconnect (int_id);
}
/* 11/01/00 */
/* #if 0 */ /* writing to port 2 doesnt work yet... */
#if 1 /* writing to port 2 doesnt work yet... */
/*
printf ("\nMove the Console Cable to the 2nd Serial Port,\n");
printf ("Connector J10,\n");
printf ("and Hit <CR> when the cable is connected.\n\n");
printf ("After alphabet prints, move Console Cable back to 1st Serial Port,\n");
printf ("Connector J9,\n");
printf ("and hit <CR> to exit test\n");
*/
/* 10/30/00 */
uart_unit = DFLTPORT; /* test J10, the PCI-700 GDB port */
printf ("\nMove the Console Cable to the 2nd Serial Port, Connector J10,\n");
printf ("and Hit <CR> when the cable is connected.\n");
printf ("The alphabet should print on the screen.\n\n");
/* 11/01/00 */
/*
printf ("After alphabet prints, move Console Cable back to 1st Serial Port,\n");
printf ("Connector J9,\n");
printf ("and hit <CR> to exit test\n");
*/
baud = 115200;
serial_init();
serial_set(baud?baud:115200L);
/* while (serial_getc() == -1); */
while (serial_getc() != 0x0d); /* wait for a carriage return character to start test */
/*
while (1)
{
for ( i = 65; i <= 90; i++ )
serial_putc(i);
}
*/
for ( i = 65; i <= 90; i++ ) /* transmit the alphabet */
serial_putc(i);
serial_putc(10); /* transmit a New Line */
serial_putc(13); /* transmit a Carriage Return */
serial_putc(10); /* transmit a New Line */
for (index=0; info[index] != '\0'; index++) /* transmit some instructions to the user */
{
serial_putc(info[index]);
}
/* point at default port before returning */
/* uart_unit = DFLTPORT; */
(void)hexIn();
#endif
printf ("\n\nUART tests done.\n");
printf ("Press return to continue.\n");
(void) hexIn();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -