quad uart interrupt driven

General discussion on mikroPascal PRO for dsPIC30/33 and PIC24.
Post Reply
Author
Message
jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

quad uart interrupt driven

#1 Post by jpc » 08 Feb 2011 20:03

seems i never published this so on request hereby library for P24FJxxGB10x , PIC's offering 4 uarts

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.
Au royaume des aveugles, les borgnes sont rois.

Post Reply

Return to “mikroPascal PRO for dsPIC30/33 and PIC24 General”