Code: Select all
unit quad_irq_uart ;
// @jpc 2010
// MP PRO dsPIC quad uart ISR
procedure irq_usart1_init(baudrate : longint; priority : byte;); //
procedure irq_usart2_init(baudrate : longint; priority : byte;); //
procedure irq_usart3_init(baudrate : longint; priority : byte;); //
procedure irq_usart4_init(baudrate : longint; priority : byte;); //
procedure put(channel,value : byte); // write a single character
procedure write(channel : byte; var s : string[255]); // write a string
Procedure Writeln(channel : byte; Var S : String[255]); // write a string followed by crlf
function Readkey(channel : byte) :Byte; // read one character from fifo
function testkey(channel : byte) :Byte; // preread one character without removing from fifo
function keypressed(channel : byte) : boolean; // test if any character in the fifo
procedure set_delimiter(channel : byte; var pattern:string[6]); // configure message delimiter ( defaults to crlf
function messages_received(channel : byte) : byte; // returns the number of complete delimited packets in the fifo
function get_ms : dword; // get milliseconds timer
function get_sec : dword; // get seconds timer
procedure cleanup_buffer(channel : byte); // replace all comma separators in the fifo by spaces in preparation for parser
procedure reset_buffer(channel: byte); // flush fifo
implementation
const uart_bufsize = 500; // may be modified according to application needs
lf : byte = 10;
cr : byte = 13;
space : byte = 32;
crlf : string[3] = (13,10,0);
msecvalue : word = clock_khz div 4;
type uart_type = record
rxhead ,
rxtail : word; // if bufsize fit's in byte these can be redimensioned
rxbuf : array[uart_bufsize] of byte;
delimiter : string[3];
read_index,
delim_index,
termflag,
match : word;
full,
empty : boolean;
end;
type uart_ptr = ^uart_type;
var uart1,
uart2,
uart3,
uart4 : uart_type;
this_uart : uart_ptr;
msecs : dword; // public ms_tick
secs : dword; //
disturbed : boolean;// flag to allow reading timervalues without risk of interference
procedure ms_tick_clock; org IVT_ADDR_T3INTERRUPT;
begin
disturbed := true;
if inc(msecs) mod 1000 = 0 then inc(secs);
IFS0.7 := 0; // clear flag
end;
function get_ms : dword;
begin
disturbed := false;
get_ms := msecs;
if disturbed = true then get_ms := msecs; // if ever the read was interrupted read again
end;
function get_sec : dword;
begin
disturbed := false;
get_sec := secs;
if disturbed = true then get_sec := secs; // if ever the read was interrupted read again
end;
procedure put(channel,value : byte);
begin
case channel of
1 : uart1_write(value);
2 : uart2_write(value);
3 : uart3_write(value);
4 : uart4_write(value);
end; // case
end;
procedure write(channel : byte; var s : string[255]);
var i : byte;
begin
case channel of
1,
2,
3,
4 : begin
i := 0;
while s[i] <> 0 do
begin
put(channel,s[i]);
inc(i);
end;
end;
end; // case
end;
Procedure Writeln(channel : byte; Var S : String[255]);
var outstr : string[3];
Begin
case channel of
1 : begin
uart1_write_text(s);
uart1_write(13);
uart1_write(10);
end;
2 : begin
uart2_write_text(s);
uart2_write(13);
uart2_write(10);
end;
3 : begin
uart3_write_text(s);
uart3_write(13);
uart3_write(10);
end;
4 : begin
uart4_write_text(s);
uart4_write(13);
uart4_write(10);
end;
end; // case
End;
function Readkey(channel : byte) :Byte; // Read A Byte From The Uart Input-fifo
Var Rk : Byte;
Begin
case channel of
1 : this_uart := @uart1;
2 : this_uart := @uart2;
3 : this_uart := @uart3;
4 : this_uart := @uart4;
end;
with this_uart^ do
begin
Rk := 0;
If empty = false Then
Begin
Rk := Rxbuf[rxtail];
if rk = Delimiter[read_index] then
Begin
Inc(read_index);
End else
Begin
read_index := 0;
if rk = Delimiter[read_index] then Inc(read_index);
End;
If Read_index = Match Then
Begin
Dec(Termflag);
Read_index := 0;
End;
Rxbuf[rxtail] := 0; // Destructive Read
If inc(rxtail) = uart_bufsize Then rxtail := 0;
If rxtail = rxhead Then empty := true Else full := false;
End;
Result := Rk;
end;
End;
function testkey(channel : byte) :Byte;
begin
case channel of
1 : with uart1 do testkey := rxbuf[rxtail];
2 : with uart2 do testkey := rxbuf[rxtail];
3 : with uart3 do testkey := rxbuf[rxtail];
4 : with uart4 do testkey := rxbuf[rxtail];
end; // case
end;
procedure set_delimiter(channel : byte; var pattern:string[6]);
begin
case channel of
1 : this_uart := @uart1;
2 : this_uart := @uart2;
3 : this_uart := @uart3;
4 : this_uart := @uart4;
end;
with this_uart^ do
begin
match := 0;
while pattern[match] <> 0 do
begin
delimiter[match] := pattern[match];
inc(match);
end;
end;
end;
procedure irq_usart1_init(baudrate : longint;priority : byte;);
begin
// initialise TMR to provide ms and seconds
msecs := 0;
secs := 0;
PR3 :=msecvalue;
T3CON := %1000000000000000;
TMR3 := 3;
IFS0.7 := 0; // clear flag
IEC0.7 := 1; // enable timer3 interrupts
memset(@uart1,0,sizeof(uart1));
set_delimiter(1,crlf); // default delimiter crlf
uart1.empty := true;
uart1.full := false;
Uart1_Init(baudrate);
delay_ms(10);
While Uart1_data_Ready do Uart1_Read; // flush Uart Fifo
U1RXIP_0_bit := priority.0; // set interrupt priority level
U1RXIP_1_bit := priority.1;
U1RXIP_2_bit := priority.2;
U1RXIF_bit := 0; // clear flag
U1RXIE_bit := 1; // enable interrupt
end;
procedure irq_usart2_init(baudrate : longint;priority : byte;);
begin
memset(@uart2,0,sizeof(uart2));
set_delimiter(2,crlf);
Uart2_Init(baudrate);
delay_ms(10);
While Uart2_data_Ready do Uart2_Read;
U2RXIP_0_bit := priority.0;
U2RXIP_1_bit := priority.1;
U2RXIP_2_bit := priority.2;
U2RXIF_bit := 0;
U2RXIE_bit := 1;
end;
procedure irq_usart3_init(baudrate : longint;priority : byte;);
begin
memset(@uart3,0,sizeof(uart3));
set_delimiter(3,crlf);
Uart3_Init(baudrate);
delay_ms(10);
While Uart3_data_Ready do Uart3_Read;
U3RXIP_0_bit := priority.0;
U3RXIP_1_bit := priority.1;
U3RXIP_2_bit := priority.2;
U3RXIF_bit := 0;
U3RXIE_bit := 1;
end;
procedure irq_usart4_init(baudrate : longint;priority : byte;);
begin
memset(@uart4,0,sizeof(uart4));
set_delimiter(4,crlf);
Uart4_Init(baudrate);
delay_ms(10);
While Uart4_data_Ready do Uart4_Read;
U4RXIP_0_bit := priority.0;
U4RXIP_1_bit := priority.1;
U4RXIP_2_bit := priority.2;
U4RXIF_bit := 0;
U4RXIE_bit := 1;
end;
function keypressed(channel : byte) : boolean; // returns 0 if no byte available in RX-FIFO
begin
case channel of
1 : result := not uart1.empty;//if uart1.empty = 1 then result := 0 else result := 1;
2 : result := not uart2.empty;
3 : result := not uart3.empty;
4 : result := not uart4.empty;
end;
end;
function messages_received(channel : byte) : byte;
begin
case channel of
1 : result := uart1.termflag; //if uart1.empty = 1 then result := 0 else result := 1;
2 : result := uart2.termflag;
3 : result := uart3.termflag;
4 : result := uart4.termflag;
end;
end;
procedure uart1_isr; org IVT_ADDR_U1RXINTERRUPT;
var ik : byte;
begin
with uart1 do
begin
if U1STA and %1110 = 0 then // no error , get character
begin
ik := uart1_read;
if ik = delimiter[delim_index] then inc(delim_index) else
begin
if ik = delimiter[0] then delim_index := 1 else delim_index := 0;
end;
if delim_index = match then
begin
inc(termflag);
delim_index := 0;
end;
rxbuf[rxhead]:= ik; // store it in circular buffer
empty := false;
if inc(rxhead) = Uart_bufsize then
begin
rxhead := 0;
end;
if rxhead = rxtail then
begin
// buffer full
end;
end else
begin
ik := uart1_read;
if OERR_bit = 1 then // overrun error
begin
OERR_bit := 0;
end;
if FERR_bit = 1 then // framing error
begin
FERR_bit := 0;
end;
if PERR_bit = 1 then // parity error
PERR_bit := 0;
end;
end;
U1RXIF_bit := 0;
end;
procedure uart2_isr; org IVT_ADDR_U2RXINTERRUPT;
var ik : byte;
begin
with uart2 do
begin
if U2STA and %1110 = 0 then // no error , get character
begin
ik := uart2_read;
if ik = delimiter[delim_index] then inc(delim_index) else
begin
if ik = delimiter[0] then delim_index := 1 else delim_index := 0;
end;
if delim_index = match then
begin
inc(termflag);
delim_index := 0;
end;
rxbuf[rxhead]:= ik; // store it in circular buffer
empty := false;
if inc(rxhead) = Uart_bufsize then
begin
rxhead := 0;
end;
if rxhead = rxtail then
begin
// buffer full
// latd := 0;
end;
end else
begin
ik := uart2_read;
if OERR_U2STA_bit = 1 then // overrun error
begin
OERR_U2STA_bit := 0;
end;
if FERR_U2STA_bit = 1 then // framing error
begin
FERR_U2STA_bit := 0;
end;
if PERR_U2STA_bit = 1 then // parity error
begin
PERR_U2STA_bit := 0;
end;
end;
end;
U2RXIF_bit := 0;
end;
procedure uart3_isr; org IVT_ADDR_U3RXINTERRUPT;
var ik : byte;
begin
with uart3 do
begin
if U3STA and %1110 = 0 then // no error , get character
begin
ik := uart3_read;
if ik = delimiter[delim_index] then inc(delim_index) else
begin
if ik = delimiter[0] then delim_index := 1 else delim_index := 0;
end;
if delim_index = match then
begin
inc(termflag);
delim_index := 0;
end;
rxbuf[rxhead]:= ik; // store it in circular buffer
empty := false;
if inc(rxhead) = Uart_bufsize then
begin
rxhead := 0;
end;
if rxhead = rxtail then
begin
// buffer full
// latd := 0;
end;
end else
begin
ik := uart3_read;
if OERR_U3STA_bit = 1 then // overrun error
begin
OERR_U3STA_bit := 0;
end;
if FERR_U3STA_bit = 1 then // framing error
begin
FERR_U3STA_bit := 0;
end;
if PERR_U3STA_bit = 1 then // parity error
begin
PERR_U3STA_bit := 0;
end;
end;
end;
U3RXIF_bit := 0;
end;
procedure uart4_isr; org IVT_ADDR_U4RXINTERRUPT;
var ik : byte;
begin
with uart4 do
begin
if U4STA and %1110 = 0 then // no error , get character
begin
ik := uart4_read;
if ik = delimiter[delim_index] then inc(delim_index) else
begin
if ik = delimiter[0] then delim_index := 1 else delim_index := 0;
end;
if delim_index = match then
begin
inc(termflag);
delim_index := 0;
end;
rxbuf[rxhead]:= ik; // store it in circular buffer
empty := false;
if inc(rxhead) = Uart_bufsize then
begin
rxhead := 0;
end;
if rxhead = rxtail then
begin
// buffer full
// latd := 0;
end;
end else
begin
ik := uart4_read;
if OERR_U4STA_bit = 1 then // overrun error
begin
OERR_U4STA_bit := 0;
end;
if FERR_U4STA_bit = 1 then // framing error
begin
FERR_U4STA_bit := 0;
end;
if PERR_U4STA_bit = 1 then // parity error
begin
PERR_U4STA_bit := 0;
end;
end;
end;
U4RXIF_bit := 0;
end;
procedure cleanup_buffer(channel : byte);
{ specific to be used on comma separated, crlf terminated messages ( e.g. command interpreter )
this procedure parses the buffer until it encounters a cr , replaces all comma-separators by a space
in order to prepare it for the parser}
Var i : word;
begin
case channel of
1 : this_uart := @uart1;
2 : this_uart := @uart2;
3 : this_uart := @uart3;
4 : this_uart := @uart4;
end;
with this_uart^ do
begin
i := rxtail;
while rxbuf[i] <> cr do
begin
if rxbuf[i]=','then rxbuf[i]:=' ';
if (inc(i) = uart_bufsize) then i := 0;
end;
end;
end;
procedure reset_buffer(channel: byte);
begin
case channel of
1 : this_uart := @uart1;
2 : this_uart := @uart2;
3 : this_uart := @uart3;
4 : this_uart := @uart4;
end;
with this_uart^ do
begin
memset(@rxbuf,0,uart_bufsize);
rxtail := 0;
rxhead := 0;
empty := true;
full := false;
termflag := 0;
end;
end;
end.