is it possible to disable the Uart FIFO on p24 ?

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

is it possible to disable the Uart FIFO on p24 ?

#1 Post by jpc » 02 May 2009 16:15

after implementing my Uart ISR on p24fj64ga002 i have some problem with the 4 byte deep hardware fifo on this chip. the datasheet tell me :
21.6.3 Receive Interrupt
The UARTx Receive Interrupt Flag (UxRXIF) is located in the corresponding Interrupt Flag Status
(IFSx) register. The URXISEL<1:0> (UxSTA<7:6>) control bits determine when the UART
receiver generates an interrupt.
a) If URXISEL<1:0> = 00 or 01, an interrupt is generated each time a data word is transferred
from the Receive Shift Register (UxRSR) to the receive buffer. There may be one or more
characters in the receive buffer.
b) If URXISEL<1:0> = 10, an interrupt is generated when a word is transferred from the
Receive Shift Register (UxRSR) to the receive buffer, and as a result, the receive buffer
contains 3 or 4 characters.
c) If URXISEL<1:0> = 11, an interrupt is generated when a word is transferred from the
Receive Shift Register (UxRSR) to the receive buffer, and as a result, the receive buffer
contains 4 characters (i.e., becomes full).
As i intend to read all received characters i have choosen to use the first option , one interrupt for each received character. In order to read this character however i must read the whole fifo , 3 dummy reads before i can get to the char i received. Is there anyone who has a better solution , some way to disable the fifo perhaps ?
Au royaume des aveugles, les borgnes sont rois.

Skyline
Posts: 267
Joined: 10 Jan 2006 09:35

#2 Post by Skyline » 03 May 2009 14:34

Hi,

I also use URXISEL<1:0> = %00 for my uart receive interrupt because my receive data is in bursts, and I did not want to have data in the FIFO that is not processed.

The FIFO buffer does not require 3 dummy reads to get to the required data. If the receive interrupt can process fast enough, a single read is sufficient in the interrupt routine. If the receive interrupt cannot process the data fast enough before another character comes it, then the receive interrupt has to allow for multiple reads if necessary by checking the URXDA data available flag. Even then, the FIFO buffer is transparent and it is not necessary to decide how many dummy reads to do in different situations to get at the real data.

I use a straightforward read (I use mikroBasic for dsPIC):

Code: Select all

sub procedure U2RxInt org 0x50 
  u2rxif = 0
  u2rxtmp = u2rxreg
  if (u2rxtmp = 10) ...
In the main code, receive interrupt is turned on before enabling uart:

Code: Select all

 u2rxie = 1
uarten2 = 1
The other possibility is if the FIFO buffer overflows. The interrupt routine would need to check and clear OERR if necessary.

Interrupt processing is normally set up fast enough and no dummy reads, URXDA or OERR processing is necessary.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

#3 Post by jpc » 03 May 2009 16:49

thanks for your reply skyline ,
i wonder if this is some anomaly of the chip i use here , i discovered in between that the same ISR i use for few years on P30 never gave me this issue. When i test it however on this 24fj64GA002 with this simple program

Code: Select all

 while true do
    begin
      if keypressed1 = true then
      begin
        k :=(readkey1);
        uart1_write_char(k);

      end;
    end;
i have to type 4 characters before the first one is echoed back. I am absolutly sure each character generates an individual interrupt , no data gets lost but there are allways 3 hiding in the fifo as it seems. The only way i can make it work is by reading the UxRXREG until UxSTA.URXDA becomes 0 as is shown in this ISR.

Code: Select all

procedure uart1_rx_irq; org $2A;  // Uart1 receiver interrupt
var n : byte;
begin
  if IFS0.11 = 1 then
  begin
    if  U1STA and %000000001110 = 0 then    // no error , get character
    begin
      while U1STA.0 = 1 do ik1 := U1RXREG;  // fetch character
      mrxbuf1[rxhead1]:= ik1;               // store it in circular buffer
      rxb1_empty := false;
      inc(rxhead1);
      if rxhead1 = rxbuf1size then
      begin
        rxhead1 := 0;
      end;
      if rxhead1 = rxtail1 then
      begin
        rxb1_full :=  true;                // buffer full
      end;
    end else
    begin
      if U1STA.1 = 1 then  // overrun error
      begin
        ClearBit(U1STA,1);
      end;
      if U1STA.2 = 1 then  // framing error
      begin
        ClearBit(U1STA,2);
      end;
      if U1STA.3 = 1 then  // parity error
      begin
        ClearBit(U1STA,3);
      end;
    end;
  end;
  IFS0.11 := 0;          // clear interrupt-flag
end;
Au royaume des aveugles, les borgnes sont rois.

Skyline
Posts: 267
Joined: 10 Jan 2006 09:35

#4 Post by Skyline » 03 May 2009 18:42

Hi jpc,

Strange behaviour indeed, and a couple of hours by me staring at the codes and datasheets obviously couldn't throw any more light on the issue than the expertise that has already been brought to bear!

Need to mull over a couple of points and do a few tests.

anton
Posts: 807
Joined: 23 Sep 2004 09:16
Location: South-Africa
Contact:

#5 Post by anton » 04 May 2009 04:36

Hi jpc,

I'm using your IRQ Uart library on my PIC24Fs.

I've successfully used it on a

Code: Select all

PIC24FJ16GA002
PIC24FJ32GA002
PIC24FJ64GA002
PIC24FJ96GA010
Please find the code here

Code: Select all

unit irq_uart1;

var     Delimiter   : array[0..5] of byte;

implementation

const rxbufsize : word = 1023;
      baudrate  : longint = 19200;

var ik          : byte; // private to interrupt !

    RXBufHead,
    RXBufTail   : word;
    RxBuf       : array[0..rxbufsize] of byte;

    RXbufempty  : boolean

    MessageCounter  : byte;

    Read_index,
    Delim_index : word;

function IRQ_Uart1_DataReady : boolean; // returns true if receivebuffer contains message terminated by delimiter
begin
  if MessageCounter > 0 then result := TRUE else result := FALSE;
end;

function IRQ_Uart1_MessageCount : byte; // returns true if receivebuffer contains message terminated by delimiter
begin
  result := MessageCounter;
end;

Procedure IRQ_Uart1_ClearBuffer;
begin
  RXBufHead := 0;
  RXBufTail := 0;
  RXbufempty := true;
  Read_index := 0;
  MessageCounter := 0;
  Delim_index := 0;
end;

procedure IRQ_Uart1_SendByte(k : byte); // write a byte to the TX-FIFO
begin
//  Uart1_Write(k);
  Uart1_Write_Char(k);
end;

procedure IRQ_Uart1_Send(var s : string[100]);
var i : word;
begin
  i := 0;
  while s[i] <> 0 do
  begin
    Uart1_Write_Char(s[i]);
    //Uart1_Write(s[i]);
    inc(i);
  end;
end;

function IRQ_Uart1_ReadByte : byte; // Read A Byte From The Input-fifo
var Rk : Byte;
Begin
  Rk := 0;
  If Rxbufempty = False then
  Begin
    Rk := Rxbuf[RxBufHead];
    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 Delimiter[Read_index] = 0 then
    begin
      if MessageCounter > 0 then dec(MessageCounter);
      Read_index := 0;
    end;
    
    Rxbuf[RxBufHead] := 0;    // Destructive Read
    Inc(RxBufHead);
    If RxBufHead >  Rxbufsize Then RxBufHead := 0;
    If RxBufHead = RxBufTail Then Rxbufempty := True;
  End;
  Result := Rk;
End;

procedure IRQ_Uart1_Read(var data : String[100]);
var k : byte;
    local_index : word;
    data_index : word;
begin
  local_index := 0;
  data_index  := 0;
  
  while delimiter[local_index] <> 0 do
  begin
    k := IRQ_Uart1_ReadByte;
    if k = delimiter[local_index] then
    Begin
      inc(local_index);
    End
    else
    Begin
      local_index := 0;
      if k = Delimiter[local_index] then inc(local_index);
    End;
    data[data_index] := k;
    inc(data_index);
  end;
//  data[data_index-2] := 0;
//  data[data_index-1] := 0;
  data[data_index] := 0;
//  result := data_index; // - length(Delimiter);
end;

procedure IRQ_Uart1_Int; org $2A;
begin
  IFS0 := IFS0 AND $F7FF;  // Clear UART 1 Rx flag

  ik := Uart1_Read_Char;

  if (U1STA AND %0000000000000110) > 0 then
  begin
    U1STA := 0x0000;
    U1MODE := 0x8000;
    NOP;
    U1STA := 0x0400;
    NOP;
    NOP;
    NOP;
    NOP;
    exit;
  end;

  RxBuf[RxBufTail] := Ik;
  Rxbufempty := False;
  Inc(RxBufTail);

  If RxBufTail > Rxbufsize Then RxBufTail := 0;

  If Ik = Delimiter[Delim_index] Then
  Begin
    Inc(Delim_index);
  End
  else
  Begin
    Delim_index := 0;
    if ik = Delimiter[Delim_index] then inc(Delim_index);
  End;
  If Delimiter[Delim_index] = 0 Then
  Begin
    Inc(MessageCounter);
    Delim_index := 0;
  End;

  IFS0 := IFS0 AND $F7FF;  // Clear UART 1 Rx flag
end;


procedure IRQ_Uart1_Init; // initialises interrupt's and variable's
begin
  memset(@RXbuf, 0, rxbufsize);
  Uart1_Init(19200);

  RXBufHead := 0;
  RXBufTail := 0;
  RXbufempty := true;
  Read_index := 0;
  MessageCounter := 0;
  Delim_index := 0;
  Delimiter[0] := 0x0D;
  Delimiter[1] := 0x0A; //0x0A;
  Delimiter[2] := 0;
  
  // Enable the interrupt
  IFS0 := IFS0 AND 0xF7FF;  // Clear UART 1 Rx flag
  IEC0 := IEC0 OR 0x0800;  // Enable UART 1 Rx Int
//  IPC2 := IPC2 OR 0x7000;

  Delay_Ms(1500);
end;

end.
Anton
Another proud user of LV 24-33A Development System and mikroPascal PRO for dsPIC :)
PortA not working? Add CMCON := 7; PortD not working? Add ADCON1 := 6;
To paste code on the forum, please use the [b] Code [/b] button !! ;)

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

#6 Post by jpc » 04 May 2009 11:00

Thanks Anton ,

i do not understand what i did wrong , your version seems to work ok ! The only difference i see is that you use the Uart-libray functions .
There are a few issues i do not understand :

You are NOT configuring the URxISEL bits in U1STA or do you rely on them beeing zero after reset ?
Why do you clear the Uart RX flag twice in the ISR ?
Why do you NOT deal with error-flags ( besides clearing all)?
What is the motivation behind all these NOP's in case of an error ?

Regards jpc
Au royaume des aveugles, les borgnes sont rois.

anton
Posts: 807
Joined: 23 Sep 2004 09:16
Location: South-Africa
Contact:

#7 Post by anton » 04 May 2009 11:13

jpc wrote: You are NOT configuring the URxISEL bits in U1STA or do you rely on them beeing zero after reset ?
I make use of the build in UART library's Init_Uart1 procedure, otherwise you could do something like this to init the port

Code: Select all

  U1BRG := 0x0081;          // BAUD - 9600 with 10 MHz PPL Enabled

  U1MODE := 0x8000;
  U1STA := 0x0400;
Why do you clear the Uart RX flag twice in the ISR ?
No need for this, it was accidentally and I'll remove it from my code. Thank you
Why do you NOT deal with error-flags ( besides clearing all)?
What I'm doing is checking the error flags with the following line

Code: Select all

  if (U1STA AND %0000000000000110) > 0 then
If there was a error I disable the UART port and enable it again with this code.

Code: Select all

  begin
    U1STA := 0x0000;
    U1MODE := 0x0000;
    NOP;
    U1MODE := 0x8000;
    NOP;
    U1STA := 0x0400;
    NOP;
  end;
I remember that I had problems with the interrupt when I only cleared the error flag and didn't re-init the port. I will try to find that in the datasheet and paste it here. It toook me a while to figure this out.

Hope I answered your question here. :roll:
What is the motivation behind all these NOP's in case of an error ?
There is only one NOP required in between setting U1MODE and U1STA but I added them hoping that it will be more fail save. In my application I'm using the power save functions alot and it helps on the wake from sleep where the PIC isn't running full speed yet. All of them aren't necessary.

Anton
Another proud user of LV 24-33A Development System and mikroPascal PRO for dsPIC :)
PortA not working? Add CMCON := 7; PortD not working? Add ADCON1 := 6;
To paste code on the forum, please use the [b] Code [/b] button !! ;)

anton
Posts: 807
Joined: 23 Sep 2004 09:16
Location: South-Africa
Contact:

#8 Post by anton » 04 May 2009 11:28

Hi,

Back to your first question.
The UARTx Receive Interrupt Flag (UxRXIF) is located in the corresponding Interrupt Flag Status
(IFSx) register. The URXISEL<1:0> (UxSTA<7:6>) control bits determine when the UART
receiver generates an interrupt.
a) If URXISEL<1:0> = 00 or 01, an interrupt is generated each time a data word is transferred
from the Receive Shift Register (UxRSR) to the receive buffer. There may be one or more
characters in the receive buffer.
b) If URXISEL<1:0> = 10, an interrupt is generated when a word is transferred from the
Receive Shift Register (UxRSR) to the receive buffer, and as a result, the receive buffer
contains 3 or 4 characters.
c) If URXISEL<1:0> = 11, an interrupt is generated when a word is transferred from the
Receive Shift Register (UxRSR) to the receive buffer, and as a result, the receive buffer
contains 4 characters (i.e., becomes full).
Yes, I accept that the URXISEL will be 0x00 after a reset. (Case a)

I also clear them when I set the U1STA register.

Anton
Another proud user of LV 24-33A Development System and mikroPascal PRO for dsPIC :)
PortA not working? Add CMCON := 7; PortD not working? Add ADCON1 := 6;
To paste code on the forum, please use the [b] Code [/b] button !! ;)

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

#9 Post by jpc » 04 May 2009 11:32

Anton ,

Ok, i understand your solution , still have no idea why i get those empty fields from the FIFO. In order to use this FIFO i must know how to disstinguish between valid data 0 and empty buffer position 0 , i am still looking for that answer.
Au royaume des aveugles, les borgnes sont rois.

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

#10 Post by jpc » 04 May 2009 12:14

ok , some more info :
if i replace in my version ik1 := U1RXREG; by ik1 := Uart1_Read_Char; all is ok , still do not see why however. On P30 never had this issue with exactly the same code.
Au royaume des aveugles, les borgnes sont rois.

anton
Posts: 807
Joined: 23 Sep 2004 09:16
Location: South-Africa
Contact:

#11 Post by anton » 04 May 2009 12:47

jpc wrote:ok , some more info :
if i replace in my version ik1 := U1RXREG; by ik1 := Uart1_Read_Char; all is ok , still do not see why however. On P30 never had this issue with exactly the same code.
Yes, now I remember I had the same problem. That is why I used the Uart1_Read_Char. What we can do is compile it with Uart1_Read_Char and check the asm output.

Anton
Another proud user of LV 24-33A Development System and mikroPascal PRO for dsPIC :)
PortA not working? Add CMCON := 7; PortD not working? Add ADCON1 := 6;
To paste code on the forum, please use the [b] Code [/b] button !! ;)

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

#12 Post by jpc » 04 May 2009 12:52

Anton,

you can imagine i did that and this already.

Code: Select all

;irq_uart_p24.dpas,53 :: 		ik1 := Uart1_Read_Char;
$0274	$07FFC5			RCALL	_uart1_read_char
$0276	$88C020			MOV	W0, irq_uart_p24_ik1

$0200	$	_uart1_read_char:
$0200	$FA0002			LNK	#2
;__Lib_Uart1_p24_p33.dpas,185 :: 		
;__Lib_Uart1_p24_p33.dpas,186 :: 		
$0202	$801130			MOV	U1RXREG, W0
$0204	$780F00			MOV	W0, [W14]
$0206	$	__Lib_Uart1_p24_p33_L_65:
;__Lib_Uart1_p24_p33.dpas,187 :: 		
$0206	$78001E			MOV	[W14], W0
$0208	$	L_end__uart1_read_char:
$0208	$FA8000			ULNK
$020A	$060000			RETURN

and my source results in :

Code: Select all

;irq_uart_p24.dpas,51 :: 		ik1 := U1RXREG;  // fetch character
$0268	$801130			MOV	U1RXREG, W0
$026A	$88C020			MOV	W0, irq_uart_p24_ik1
which does not work ok.
Au royaume des aveugles, les borgnes sont rois.

anton
Posts: 807
Joined: 23 Sep 2004 09:16
Location: South-Africa
Contact:

#13 Post by anton » 04 May 2009 12:52

Hi, this is the asm output

Code: Select all

$13C4	$	_uart1_read_char:
$13C4	$FA0002			LNK	#2
;__Lib_Uart1_p24_p33.dpas,185 :: 		
;__Lib_Uart1_p24_p33.dpas,186 :: 		
$13C6	$801130			MOV	U1RXREG, W0
$13C8	$780F00			MOV	W0, [W14]
$13CA	$	__Lib_Uart1_p24_p33_L_65:
;__Lib_Uart1_p24_p33.dpas,187 :: 		
$13CA	$78001E			MOV	[W14], W0
$13CC	$	L_end__uart1_read_char:
$13CC	$FA8000			ULNK
$13CE	$060000			RETURN
I don't see why

Code: Select all

ik1 := U1RXREG;
shouldn't work but it doesn't.

Anton
Another proud user of LV 24-33A Development System and mikroPascal PRO for dsPIC :)
PortA not working? Add CMCON := 7; PortD not working? Add ADCON1 := 6;
To paste code on the forum, please use the [b] Code [/b] button !! ;)

jpc
Posts: 1986
Joined: 22 Apr 2005 17:40
Location: France 87

#14 Post by jpc » 04 May 2009 12:53

ok, we both see the same phantom at least !
Au royaume des aveugles, les borgnes sont rois.

User avatar
zristic
mikroElektronika team
Posts: 6608
Joined: 03 Aug 2004 12:59
Contact:

#15 Post by zristic » 04 May 2009 12:53

Nothing special there:

Code: Select all

function Uart1_Read_Char : word;
begin
   result := U1RXREG;
end;

Post Reply

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