I apologize for not having time to look at your code but attached is a
test program that works: it spits out a 14 char packet (115200 bps) at
60 Hz on the first serial port. give it a try ...
It requires that the rtl_sched.o module be loaded.
for those interested:
The code here is the beginning of a rewrite of the rt-com code, which I
intend to contribute in a few months. The original code is missing a lot
of RX/TX error detection, UART type autodection, API, etc. i'm going to
merge it with code from Chris Karcher's "RS232.C" freeware, which is
quite reliable (I have used it over the past few years).
--
Steve Rosenbluth
Jim Henson's Creature Shop
2821 Burton St, Burbank CA
(818) 953-3030
/* file: periodic_serial.c*/
/* sends serial packets out first serial port at 60 Hz using RTLinux */
/* steve Rosenbluth, JHCS 2-99 */
/* epson dot-matrix printer condense code */
/*original serial code by Jens Michaelsen HCC */
/* compile with: gcc -Wall -O2 -D__KERNEL__ -D__RT__ -DMODULE -c periodic_serial.c */
/*------------------------- start of file rt_com.h ---------------*/
/* status masks, several bits may be set simultaneously */
/* status information is returned by LineStatus and as */
/* the high byte of COMData */
#define DATA_READY 0x01 /* not an error */
#define OVERRUN 0x02 /* error detected by hardware */
#define PARITY 0x04 /* error detected by hardware */
#define FRAME 0x08 /* error detected by hardware */
#define BREAK 0x10 /* not an error */
#define BUFFER_FULL 0x80 /* error detected by software */
#define TXB_EMPTY 0x20 /* not an error */
#define HARD_ERROR (OVERRUN | PARITY | FRAME | BREAK)
#define RXB 0x00 /* port offsets */
#define TXB 0x00
#define IER 0x01
#define IIR 0x02
#define FCR 0x02
#define LCR 0x03
#define MCR 0x04
#define LSR 0x05
#define MSR 0x06
#define DLL 0x00
#define DLM 0x01
#define PARITY_EVEN 0 /* for port initialisation */
#define PARITY_ODD 1
#define PARITY_NONE 2
/* bit masks which may be written to the MCR using ModemControl */
#define DTR 0x01 /* data Terminal Ready */
#define RTS 0x02 /* Request To Send */
#define Out1 0x04
#define Out2 0x08
#define LoopBack 0x10
#define RT_SERIAL_BUFSIZE 256
#define TRIGGER_LEVEL 4
#define FIFO 4
#define STD_COM_FLAG 0
#define RT_COM_CNT 3
#define COM_0 0
#define COM_1 1
#define COM_2 2
#define COM_3 3
#define BPS_110 110 /* 110 baud */
#define BPS_300 300 /* . */
#define BPS_600 600 /* . */
#define BPS_1200 1200 /* . */
#define BPS_2400 2400 /* . */
#define BPS_4800 4800 /* . */
#define BPS_9600 9600 /* . */
#define BPS_19K 19200 /* . */
#define BPS_38K 38400 /* . */
#define BPS_57K 57600 /* . */
#define BPS_115K 115200 /* 115200 baud */
#ifndef NULL
#define NULL 0
#endif
#define RT_HIGHEST_PRIORITY 1 /* for
rt_task_init */
/************* typedefs ************/
typedef struct {
int head;
int tail;
char buf[ RT_SERIAL_BUFSIZE ];
} rt_buf_struct_t;
typedef struct {
int magic;
int baud_base;
int port;
int irq;
int flag;
void (*isr)(void); /* irq handler pointer */
int type;
int ier; /* copy of chip register */
rt_buf_struct_t ibuf;
rt_buf_struct_t obuf;
} rt_com_struct_t;
/************ prototypes *************/
int rt_com_read(rt_com_struct_t *com_p, char * ptr, int cnt );
void rt_com_write(rt_com_struct_t *com_p, char * ptr, int cnt );
void rt_com_setup( int, unsigned, unsigned, unsigned, unsigned );
void rt_com_init( void );
void rt_com0_isr(void);
void rt_com_exit( void );
#if 0
static void rt_com_isr( int com );
static void rt_com0_isr(void) { rt_com_isr( 0 ); }
static void rt_com1_isr(void) { rt_com_isr( 1 ); }
static void rt_com2_isr(void) { rt_com_isr( 2 ); }
//static void rt_com3_isr(void) { rt_com_isr( 3 ); }
#endif
/*------------------------ start of file rt_com.c ----------------*/
#include <linux/version.h> /* for modversions ? */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <asm/rt_irq.h>
#include <asm/system.h> /* for r_save_flags(), r_cli() */
#include <asm/io.h> /* for outb() */
#include </usr/src/rtl/include/rtl_sched.h> /* scheduling header*/
/*************** global vars *****************/
rt_buf_struct_t rt_buf_struct;
rt_com_struct_t rt_com_struct;
#if 0
struct rt_com_struct rt_com_table[RT_COM_CNT] = {
{0,115200_BPS,0x3F8,4,STD_COM_FLAG,rt_com0_isr},
{0,115200_BPS,0x2F8,3,STD_COM_FLAG,rt_com1_isr},
{0,115200_BPS,0x3E8,5,STD_COM_FLAG,rt_com2_isr},
// {0,115200_BPS,0x2E8,3,STD_COM_FLAG,rt_com4_isr},
};
#endif
RT_TASK thetask_struct; /* real
time task structure. must not become deallocated */
/*const int MSSGLEN = 5; */
const int task_stack_size = 4000; /* so
parent can specify stack for real time task */
rt_com_struct_t com0 = {0,(int)BPS_115K,0x3F8,4,STD_COM_FLAG,rt_com0_isr};
/*-----------------------------------------------------------------------*/
void rt_com_write(rt_com_struct_t *com_p, char * ptr, int cnt )
{
rt_buf_struct_t *b;
long flags;
b = &(com_p->obuf);
r_save_flags(flags);
r_cli();
while(--cnt>=0)
{
b->buf[b->head++] = *ptr++;
b->head &= (RT_SERIAL_BUFSIZE-1);
}
com_p->ier|=0x02;
outb( com_p->ier, com_p->port + IER);
r_restore_flags(flags);
}
/*-----------------------------------------------------------------------*/
int rt_com_read(rt_com_struct_t *com_p, char * ptr, int cnt )
{
rt_buf_struct_t *b;
long flags;
int done = 0;
b = &(com_p->ibuf);
r_save_flags(flags); r_cli();
while( ( b->head != b->tail ) && (--cnt >= 0 ) )
{
done++;
*ptr++ = b->buf[b->tail++];
b->tail &= (RT_SERIAL_BUFSIZE-1);
}
r_restore_flags(flags);
return( done );
}
/*-----------------------------------------------------------------------*/
int rt_com_irq_get(rt_com_struct_t *p, unsigned char *c )
{
rt_buf_struct_t *b = &( p->obuf );
if( b->head != b->tail )
{
*c = b->buf[b->tail++];
b->tail &= (RT_SERIAL_BUFSIZE-1);
return( 1 );
}
return( 0 );
}
/*-----------------------------------------------------------------------*/
void rt_com_irq_put(rt_com_struct_t *p, unsigned char ch )
{
rt_buf_struct_t *b = &( p->ibuf );
b->buf[b->head++] = ch;
b->head &= (RT_SERIAL_BUFSIZE-1);
}
/*-----------------------------------------------------------------------*/
/* the interrupt handler(s) */
void rt_com0_isr(void)
{
rt_com_struct_t *com_p;
unsigned char data;
unsigned char isr;
unsigned char stat;
char loop = 4;
com_p = &com0;
do
{
/* Receive */
stat = inb(com_p->port + LSR);
while( stat & DATA_READY )
{
data = inb(com_p->port + RXB);
rt_com_irq_put(com_p,data);
stat = inb(com_p->port + LSR);
};
/* now Transmit */
inb(com_p->port + MSR);
if( stat & 0x20 )
{
if( rt_com_irq_get(com_p,&data) )
{
do
{
outb( data, com_p->port + TXB );
stat = inb(com_p->port + LSR);
} while( --loop>0 && rt_com_irq_get(com_p,&data) );
}
else
{
com_p->ier &= ~0x02;
outb( com_p->ier, com_p->port + IER );
}
stat = inb(com_p->port + LSR);
};
isr = inb(com_p->port + IIR) & 0x0F;
} while( (isr) && --loop>0);
}
/*-----------------------------------------------------------------------*/
static void enable_fifo(int base, int trigger)
{
switch (trigger)
{
case 0: outb( 0x00, base + FCR ); break;
case 1: outb( 0x01, base + FCR ); break;
case 4: outb( 0x41, base + FCR ); break;
case 8: outb( 0x81, base + FCR ); break;
case 14: outb( 0xC1, base + FCR ); break;
default:
}
}
/*-----------------------------------------------------------------------*/
void rt_com_setup( int com, unsigned baud, unsigned parity,
unsigned stopbits, unsigned wordlength )
{
/*struct rt_com_struct * p = &(rt_com_table[com]);*/
rt_com_struct_t *com_p;
unsigned char temp;
unsigned char rs_dvsrl,rs_dvsrh;
com_p = &com0;
outb( 0x00, com_p->port + IER ); /* disable UART interrupts */
inb( com_p->port + IIR ); /* clear irq */
inb( com_p->port + LSR );
inb( com_p->port + RXB );
inb( com_p->port + MSR );
#if 0
if(!baud) return;
divider = (unsigned) ((com_p->baud_base + com_p->baud_base % baud) / baud);
outb( divider % 256, com_p->port + DLL );
outb( divider / 256, com_p->port + DLM );
#endif
/* get the baud rate divisor values */
rs_dvsrh = 0;
switch(baud){
case 110:
rs_dvsrh = 0x04;
rs_dvsrl = 0x17;
break;
case 300:
rs_dvsrh = 0x01;
rs_dvsrl = 0x80;
break;
case 600:
rs_dvsrl = 0xC0;
break;
case 1200:
rs_dvsrl = 0x60;
break;
case 2400:
rs_dvsrl = 0x30;
break;
case 4800:
rs_dvsrl = 0x18;
break;
case 9600:
rs_dvsrl = 0x0C;
break;
case 19200:
rs_dvsrl = 0x06;
break;
case 38400:
rs_dvsrl = 0x03;
break;
case 57600:
rs_dvsrl = 0x02;
break;
case 115200:
rs_dvsrl = 0x01;
break;
default:
/* FIXME: return error */
rs_dvsrl = 0x01;
}
outb( 0x80, com_p->port + LCR ); /* enable baud rate divisor registers */
outb(rs_dvsrl, com_p->port + DLL );
outb(rs_dvsrh, com_p->port + DLM );
switch (parity)
{
case PARITY_ODD: temp = 0x08; break;
case PARITY_EVEN: temp = 0x18; break;
default: temp = 0x00;
}
outb( (wordlength-5) + ((stopbits-1) << 2) + temp, com_p->port + LCR );
outb( DTR + RTS + Out1 + Out2, com_p->port + MCR );
com_p->ier = 0x01;
outb( com_p->ier, com_p->port + IER);
enable_fifo( com_p->port, TRIGGER_LEVEL );
}
/*-----------------------------------------------------------------------*/
void rt_com_init( void )
{
rt_com_struct_t *com_p;
com_p = &com0;
/* FIXME: handle the error !!*/
if (!check_region(com_p->port,8))
return;
request_region(com_p->port,8,"rt_com");
request_RTirq(com_p->irq, com_p->isr);
rt_com_setup(COM_0,BPS_115K,0,1,8);
}
/*-----------------------------------------------------------------------*/
void rt_com_exit( void )
{
rt_com_struct_t *com_p;
com_p = &com0;
rt_com_setup(COM_0,0,0,1,8);
release_region(com_p->port,8);
free_RTirq(com_p->irq);
}
/****************************//* the entry-point function of the rt task */
void Periodic_entry_point(int arg) /* initing parent
sends in unique fifo number */
{
#define MESSAGE_LEN 14
static char message[MESSAGE_LEN] = "Serial_Packet ";
/* int ret;*/
/*static int i=0;*/
while (1)
{
#if 0
ret = rtf_put(incoming_fifo_id, message, MSSG_LEN); /*
shove our message into the chat fifo */
if (ret == RT_ERROR)
; /*
FIXME: handle error */
#endif
rt_com_write(&com0, message, (int)MESSAGE_LEN );
/*printk("!");*/
rt_task_wait(); /* end
this task until next periodic call */
}
}
/****************************/
int init_module(void) /*
called by kernel ?!? */
{
RTIME now, period;
/* (64 bit) for storing current captured clock tick */
rt_com_init();
/*rtf_create(CTL_FIFO_ID, CTL_FIFO_LEN); */ /*
control channel for messages to rt process */
/*rtf_create(CHAT_FIFO_ID, CHAT_FIFO_LEN); */ /*
fifo from which rt task talks to us */
rt_task_init(&thetask_struct, Periodic_entry_point, NULL, task_stack_size,
RT_HIGHEST_PRIORITY);
now = rt_get_time(); /* capture
current time to start periodic func now */
period = (RTIME) ((long double)RT_TICKS_PER_SEC * (1.0 / 60.0)); /* calc #
ticks in one period of desired frequency */
/*printk("making periodic...\n");*/
rt_task_make_periodic(&thetask_struct, now, period); /* makes rt task
actually run */
/*rtf_create_handler(CTL_FIFO_ID, Ctl_fifo_handler); */ /*
register our handler: invoked when fifo is written */
return 0;
}
/****************************/
void cleanup_module(void)
{
#if 0
rtf_destroy(CTL_FIFO_ID); /* get
rid of the control fifo */
rtf_destroy(CHAT_FIFO_ID); /* get
rid of chat fifo */
#endif
rt_task_delete(&thetask_struct); /* take
our task out of the rt executive */
}