写了一个串口驱动,解决了问题半天赶工的,程序本身还很粗糙。但是能用(包括查询方式和中断方式)
#include <pkgconf/hal.h>
#include <pkgconf/infra.h>
#include <pkgconf/system.h>
#include <pkgconf/io_serial.h>
#include <pkgconf/io.h>
#include <pkgconf/kernel.h>
#include <cyg/io/io.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/io/devtab.h>
#include <cyg/io/serial.h>
#include <cyg/infra/diag.h>
#include <cyg/infra/cyg_type.h>
#ifdef CYGPKG_IO_SERIAL_ARM_LPC2XXX
const unsigned int select_baud[] = {
9999,
50,
75,
110,
134.5,
150,
200,
300,
600,
1200,
1800,
2400,
3600,
4800,
7200,
9600,
14400,
19200,
38400,
57600,
115200,
230400
};
typedef struct lpc2xxx_serial_info {
int int_num;
cyg_interrupt serial_interrupt;
cyg_handle_t serial_interrupt_handle;
} lpc2xxx_serial_info;
static bool lpc2xxx_serial_init(struct cyg_devtab_entry *tab);
static Cyg_ErrNo lpc2xxx_serial_lookup(struct cyg_devtab_entry **tab,
struct cyg_devtab_entry *sub_tab,
const char *name);
static Cyg_ErrNo lpc2xxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
const void *xbuf, cyg_uint32 *len);
static void lpc2xxx_serial_start_xmit(serial_channel *chan);
static void lpc2xxx_serial_stop_xmit(serial_channel *chan);
static cyg_uint32 lpc2xxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
static void lpc2xxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
static bool lpc2xxx_serial_putc_interrupt(serial_channel *chan, unsigned char c);
static unsigned char lpc2xxx_serial_getc_interrupt(serial_channel *chan);
static bool lpc2xxx_serial_putc_polled(serial_channel *chan, unsigned char c);
static unsigned char lpc2xxx_serial_getc_polled(serial_channel *chan);
#if (CYGNUM_IO_SERIAL_ARM_LPC2XXX_SERIAL0_BUFSIZE > 0)
static SERIAL_FUNS(lpc2xxx_serial_funs_interrupt,
lpc2xxx_serial_putc_interrupt,
lpc2xxx_serial_getc_interrupt,
lpc2xxx_serial_set_config,
lpc2xxx_serial_start_xmit,
lpc2xxx_serial_stop_xmit
);
#endif
#if (CYGNUM_IO_SERIAL_ARM_LPC2XXX_SERIAL0_BUFSIZE == 0)
static SERIAL_FUNS(lpc2xxx_serial_funs_polled,
lpc2xxx_serial_putc_polled,
lpc2xxx_serial_getc_polled,
lpc2xxx_serial_set_config,
lpc2xxx_serial_start_xmit,
lpc2xxx_serial_stop_xmit
);
#endif
static lpc2xxx_serial_info lpc2xxx_serial_info0 = {
int_num : CYGNUM_HAL_INTERRUPT_UART1
};
#if CYGNUM_IO_SERIAL_ARM_LPC2XXX_SERIAL0_BUFSIZE > 0
static unsigned char lpc2xxx_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_LPC2XXX_SERIAL0_BUFSIZE];
static unsigned char lpc2xxx_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_LPC2XXX_SERIAL0_BUFSIZE];
static SERIAL_CHANNEL_USING_INTERRUPTS(lpc2xxx_serial_channel0,
lpc2xxx_serial_funs_interrupt,
lpc2xxx_serial_info0,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_LPC2XXX_SERIAL0_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT,
&lpc2xxx_serial_out_buf0[0], sizeof(lpc2xxx_serial_out_buf0),
&lpc2xxx_serial_in_buf0[0], sizeof(lpc2xxx_serial_in_buf0)
);
#else
static SERIAL_CHANNEL(lpc2xxx_serial_channel0,
lpc2xxx_serial_funs_polled,
lpc2xxx_serial_info0,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_LPC2XXX_SERIAL0_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT
);
#endif
DEVTAB_ENTRY(lpc2xxx_serial_io0,
CYGDAT_IO_SERIAL_ARM_LPC2XXX_SERIAL0_NAME,
0,
&cyg_io_serial_devio,
lpc2xxx_serial_init,
lpc2xxx_serial_lookup,
&lpc2xxx_serial_channel0
);
static bool
lpc2xxx_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config)
{
unsigned int baud_rate = select_baud[new_config->baud];
unsigned short baud_divisor = CYG_HAL_ARM_LPC2XXX_BAUD_GENERATOR(baud_rate);
HAL_WRITE_UINT8(LPC2XXX_U1IER, 0x00);
HAL_WRITE_UINT8(LPC2XXX_U1LCR, 0x83);
HAL_WRITE_UINT8(LPC2XXX_U1DLM, baud_divisor >> 8);
HAL_WRITE_UINT8(LPC2XXX_U1DLL, baud_divisor & 0xFF);
HAL_WRITE_UINT8(LPC2XXX_U1LCR, 0x03);
HAL_WRITE_UINT8(LPC2XXX_U1FCR, 0x07);
HAL_WRITE_UINT8(LPC2XXX_U1IER, 0x01);
if (new_config != &chan->config) {
chan->config = *new_config;
}
return true;
}
static bool
lpc2xxx_serial_init(struct cyg_devtab_entry *tab)
{
serial_channel * const chan = (serial_channel *) tab->priv;
lpc2xxx_serial_info * const lpc2xxx_chan = (lpc2xxx_serial_info *) chan->dev_priv;
(chan->callbacks->serial_init)(chan);
if (chan->out_cbuf.len != 0) {
cyg_drv_interrupt_create(lpc2xxx_chan->int_num,
4,
(cyg_addrword_t)chan,
lpc2xxx_serial_ISR,
lpc2xxx_serial_DSR,
&lpc2xxx_chan->serial_interrupt_handle,
&lpc2xxx_chan->serial_interrupt);
cyg_drv_interrupt_attach(lpc2xxx_chan->serial_interrupt_handle);
cyg_drv_interrupt_unmask(lpc2xxx_chan->int_num);
}
lpc2xxx_serial_config_port(chan, &chan->config);
return true;
}
static Cyg_ErrNo
lpc2xxx_serial_lookup(struct cyg_devtab_entry **tab,
struct cyg_devtab_entry *sub_tab,
const char *name)
{
serial_channel * const chan = (serial_channel *) (*tab)->priv;
(chan->callbacks->serial_init)(chan);
return ENOERR;
}
static bool
lpc2xxx_serial_putc_interrupt(serial_channel *chan, unsigned char c)
{
cyg_uint8 uart_lsr;
HAL_READ_UINT8(LPC2XXX_U1LSR, uart_lsr);
if (uart_lsr & 0x20) {
HAL_WRITE_UINT8(LPC2XXX_U1THR, c);
return true;
}
return false;
}
static bool
lpc2xxx_serial_putc_polled(serial_channel *chan, unsigned char c)
{
cyg_uint8 uart_lsr;
HAL_WRITE_UINT8(LPC2XXX_U1THR, c);
while (1) {
HAL_READ_UINT8(LPC2XXX_U1LSR, uart_lsr);
if (uart_lsr & 0x40) break;
}
return true;
}
static unsigned char
lpc2xxx_serial_getc_interrupt(serial_channel *chan)
{
cyg_uint8 c;
HAL_READ_UINT8(LPC2XXX_U1RBR, c);
return (unsigned char) c;
}
static unsigned char
lpc2xxx_serial_getc_polled(serial_channel *chan)
{
cyg_uint8 c;
cyg_uint8 uart_lsr;
while (1) {
HAL_READ_UINT8(LPC2XXX_U1LSR, uart_lsr);
if (uart_lsr & 0x01) break;
}
HAL_READ_UINT8(LPC2XXX_U1RBR, c);
return (unsigned char) c;
}
static Cyg_ErrNo
lpc2xxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
const void *xbuf, cyg_uint32 *len)
{
switch (key) {
case CYG_IO_SET_CONFIG_SERIAL_INFO:
{
cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
if ( *len < sizeof(cyg_serial_info_t) ) {
return -EINVAL;
}
*len = sizeof(cyg_serial_info_t);
if ( true != lpc2xxx_serial_config_port(chan, config) )
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return ENOERR;
}
static void
lpc2xxx_serial_start_xmit(serial_channel *chan)
{
cbuf_t *cbuf = &chan->out_cbuf;
serial_funs *funs = chan->funs;
cyg_uint8 uart_lsr;
cyg_uint8 uart_ier;
cyg_uint8 c;
c = cbuf->data[cbuf->get];
HAL_WRITE_UINT8(LPC2XXX_U1THR, c);
while (1) {
HAL_READ_UINT8(LPC2XXX_U1LSR, uart_lsr);
if (uart_lsr & 0x20) break;
}
cbuf->get++;
if (cbuf->get == cbuf->len) cbuf->get = 0;
cbuf->nb--;
HAL_READ_UINT8(LPC2XXX_U1IER, uart_ier);
uart_ier |= 0x02;
HAL_WRITE_UINT8(LPC2XXX_U1IER, uart_ier);
}
static void
lpc2xxx_serial_stop_xmit(serial_channel *chan)
{
cyg_uint8 uart_ier;
HAL_READ_UINT8(LPC2XXX_U1IER, uart_ier);
uart_ier &= ~0x02;
HAL_WRITE_UINT8(LPC2XXX_U1IER, uart_ier);
}
static cyg_uint32
lpc2xxx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
lpc2xxx_serial_info *lpc2xxx_chan = (lpc2xxx_serial_info *)chan->dev_priv;
cyg_drv_interrupt_mask(lpc2xxx_chan->int_num);
cyg_drv_interrupt_acknowledge(lpc2xxx_chan->int_num);
return CYG_ISR_CALL_DSR;
}
static void
lpc2xxx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
lpc2xxx_serial_info *lpc2xxx_chan = (lpc2xxx_serial_info *)chan->dev_priv;
cyg_uint8 uart_iir;
HAL_READ_UINT8(LPC2XXX_U1IIR, uart_iir);
while ((uart_iir & 01) == 0) {
switch (uart_iir & 0x0E) {
case 0x04:
case 0x0C:
{
cyg_uint8 uart_lsr;
unsigned char c;
HAL_READ_UINT8(LPC2XXX_U1LSR, uart_lsr);
while(uart_lsr & 0x01) {
HAL_READ_UINT8(LPC2XXX_U1RBR, c);
(chan->callbacks->rcv_char)(chan, c);
HAL_READ_UINT8(LPC2XXX_U1LSR, uart_lsr);
}
break;
}
case 0x02:
(chan->callbacks->xmt_char)(chan);
break;
}
HAL_READ_UINT8(LPC2XXX_U1IIR, uart_iir);
}
cyg_drv_interrupt_unmask(lpc2xxx_chan->int_num);
}
#endif |