It is currently 18 Oct 2018 23:10

All times are UTC + 1 hour




Post new topic Reply to topic  [ 22 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: PIC18F45K22 EUSART
PostPosted: 10 Aug 2017 07:00 
Offline

Joined: 04 May 2012 10:52
Posts: 34
Location: Canada
Hi guys,
I am trying to use interrupts on the EUSART module with PIC18F45K22. Does not work for some reason. Could you please take a look and point me what is wrong in my code.
Thanks in advance!

{*
 * Project name:
     UART (Simple usage of UART module library functions)
     Oscillator:      HS-PLL 32.0000 MHz, 8.0000 MHz Crystal
 *}

program UART;
var RecState  :byte;
     ArrRxData: array[0..12] of byte;
     RecCount : Integer;
  iRxStatus   : byte;
 bDataReceived: boolean;
  iRxData     : byte;    // private to interrupt !
              i: byte;

procedure Main_Init;
begin
 ANSELC     := 0;      // Configure PORTC pins as digital
 TRISB      := 0xFF;
 PORTB      := 0x00;  // clear portb
 TRISC      := %10000000;
//  CMCON := 7;            // disable comparators
  INTCON.GIE := 1;       // |- enable interrupt
  INTCON.PEIE := 1;      // |
  PIE1.RC1IE := 1;       // |
  T1CON.T1CKPS1 := 1;    // |
 // iRxByteCount := 0;
  TMR0IF_bit := 0;

  // init USART
  TXSTA1.BRGH := 0;    // low speed baud rate
  TXSTA1.SYNC := 0;    // asynchronous mode
  TXSTA1.BRG16 := 0;
  TXSTA1.TX9  := 0;     // 8-bits transmission
  TXSTA1.TXEN := 1;    // Tx enabled
  RCSTA1.CREN := 1;    // enable receiving / accept continuous mode
  RCSTA1.SPEN := 1;    // Rx enabled;
  RCSTA1.RX9 := 0;     // 8-bits transmission//Timer0
  UART1_Init(9600);    // Initialize UART module at 9600 bps
  Delay_ms(100);
 
end;
//Timer0
//Prescaler 1:64; TMR0 Preload = 31; Actual Interrupt Time : 1.8 ms

//Place/Copy this part in declaration section
procedure InitTimer0();
begin
  T0CON    := 0xC5;
  TMR0L    := 0x1F;
  GIE_bit    := 1;
  TMR0IE_bit    := 1;
end;

procedure Interrupt();
begin
  if (TMR0IF_bit) then
  begin
    TMR0IF_bit := 0;
    TMR0L    := 0x1F;
    //Enter your code here
    //Enter your code here
   if PIR1.RC1IF = 1 then
  begin
    iRxStatus := RCSTA1; // Error-handling
    //  always read RCREG, error detected or not
    iRxData := RCREG1;
    // no error detected in reception, handle last received byte
    if TestBit(RCSTA1, OERR) = 0 then
     begin
      if (UART1_Data_Ready() <> 0) then    RecState := 3;
          end
           else
            begin
             RecState := 0;
             RecCount := 0;
            end;
          end;
      // end;
    end
    else
    // error detected in reception, clear error flag
    begin
      Clearbit(RCSTA1, CREN);
      Setbit(RCSTA1, CREN);
    end;
end;
//end;

procedure Data_Reset;
begin
  for RecCount := 0 to 12 do
    ArrRxData[RecCount] := $00;
end;


procedure Data_Send;
begin

   UART1_Write_Text('Start');
   PORTB := 0xFF;
   
end;

//main program
begin
  Main_Init;
 // Data_Reset;

  while TRUE do
   begin


   if RecState = 3 then
     begin
        Data_Send;
        RecCount := 0;
  end;
 end;
end.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 10 Aug 2017 14:08 
Offline
User avatar

Joined: 21 Mar 2017 16:57
Posts: 527
Hello,

By looking at your code, I see that you want to trigger a timer interrupt, but you haven't used InitTimer0() procedure anywhere in your main program. You need to init the timer before interrupts start to happen...

Best regards


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 10 Aug 2017 18:53 
Offline

Joined: 22 Apr 2005 17:40
Posts: 1975
Location: France 87
is there any reason in your application to put the UART interrupt handler inside a timer interrupt?
I also would suggest to initialize all interrupts before you enable them by setting the GIE_bit, your code starts by setting this and possibly that is the very last thing your code does, it is also good practice to clear all interrupt flags of the interrupt sources you enable before enabling the interrupts

_________________
Au royaume des aveugles, les borgnes sont rois.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 11 Aug 2017 05:05 
Offline

Joined: 04 May 2012 10:52
Posts: 34
Location: Canada
But you haven't used InitTimer0() procedure anywhere in your main program - Oh! You are right!

is there any reason in your application to put the UART interrupt handler inside a timer interrupt? - Agree, it looks ugly. Replaced with:
 if TestBit(RCSTA1, OERR) = 0 then
     begin
      if bDataReceived = true then    RecState := 3;
          end


Darko, jpc Thank you, guys, for your suggestions!


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 11 Aug 2017 11:53 
Offline

Joined: 22 Apr 2005 17:40
Posts: 1975
Location: France 87
you better show the complete interrupt as you have it now, i did not understand calling UART1_Data_Ready after reading RCREG1, not sure what will be the returnvalue of this function will be.
As such there is no need for it as you already know there is a character received, after all this triggered the interrupt.

_________________
Au royaume des aveugles, les borgnes sont rois.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 11 Aug 2017 14:49 
Offline
User avatar

Joined: 21 Mar 2017 16:57
Posts: 527
Hi,

I didn't want to question the use of the timer interrupt, I have just reacted at the first obvious error I saw in the code. But Vladimir, if you have difficulties with your code, feel free to discuss it here...

Best regards


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 12 Aug 2017 01:28 
Offline

Joined: 04 May 2012 10:52
Posts: 34
Location: Canada
Darko, jpc

If you have difficulties with your code, feel free to discuss it here... - Yes, I will :D! It works now with no errors. The code simply returnes a byte which has been received, PORTB LEDs confirm the byte receiving.

You better show the complete interrupt as you have it now - Sure, please look at:

{*
 * Project name:
     UART (Simple usage of UART module library functions)
     Oscillator:      HS-PLL 32.0000 MHz, 8.0000 MHz Crystal
 *}

program UART;
var RecState  :byte;
     ArrRxData: array[0..12] of byte;
     RecCount : Integer;
  iRxStatus   : byte;
 bDataReceived: boolean;
  iRxData     : byte;    // private to interrupt !
              i: byte;

procedure Main_Init;
begin
 ANSELC     := 0;      // Configure PORTC pins as digital
 TRISB      := 0x00;
 PORTB      := 0x00;  // clear portb
 TRISC      := %10000000; //RC7 - Rx
//  CMCON := 7;            // disable comparators
  INTCON.GIE := 0;       // |- disable interrupt
  INTCON.PEIE := 0;      // |
  PIE1.RC1IE := 0;       // |
  T1CON.T1CKPS1 := 1;    // |
  PIR1.RC1IF := 0;
 // iRxByteCount := 0;
  TMR0IF_bit := 0;

  // init USART
  TXSTA1.BRGH := 0;    // low speed baud rate
  TXSTA1.SYNC := 0;    // asynchronous mode
 // TXSTA1.BRG16 := 0;
  TXSTA1.TX9  := 0;     // 8-bits transmission
  TXSTA1.TXEN := 1;    // Tx enabled
  RCSTA1.CREN := 1;    // enable receiving / accept continuous mode
  RCSTA1.SPEN := 1;    // Rx enabled;
  RCSTA1.RX9 := 0;     // 8-bits transmission//Timer0
  UART1_Init(9600);    // Initialize UART module at 9600 bps
  Delay_ms(100);
 
end;
//Timer0
//Prescaler 1:64; TMR0 Preload = 31; Actual Interrupt Time : 1.8 ms

//Place/Copy this part in declaration section
procedure InitTimer0();
begin
  T0CON         := 0xC5;
  TMR0L         := 0x1F;
  GIE_bit         := 1;       // Enable interrupts!
  TMR0IE_bit    := 1;
end;

procedure Interrupt();
begin
  if (TMR0IF_bit) then
  begin
    TMR0IF_bit := 0;
    TMR0L         := 0x1F;
    //Enter your code here
    //Enter your code here
   if PIR1.RC1IF = 1 then
  begin
    iRxStatus := RCSTA1; // Error-handling
    //  always read RCREG, error detected or not
    bDataReceived := true;
    iRxData := RCREG1;
    // no error detected in reception, handle last received byte
    if TestBit(RCSTA1, OERR) = 0 then
     begin
      if bDataReceived = true then    RecState := 3;
          end
           else
            begin
             RecState := 0;
             RecCount := 0;
            end;
          end;
      // end;
    end
    else
    // error detected in reception, clear error flag
    begin
      Clearbit(RCSTA1, CREN);
      Setbit(RCSTA1, CREN);
    end;
end;
//end;

procedure Data_Reset;
begin
  for RecCount := 0 to 12 do
    ArrRxData[RecCount] := $00;
end;


procedure Data_Send;
begin

  // UART1_Write_Text('Start');
  UART1_Write(iRxData);
   PORTB := 0xFF;
   Delay_ms (1000);
    PORTB := 0x00;
    bDataReceived := false;
         RecState := 0;
   
end;

//main program
begin
  Main_Init;
  InitTimer0();
 // Data_Reset;

  while TRUE do
   begin

   if RecState = 3 then
     begin
       Data_Send;
  end;
 end;
end.


I have a question regarding baudrate. I would like to use 115.2K baudrate for example. According to PIC18F45K22 datasheet I am able to use a 11.0592 MHz crystal which provides 0% error for 115.2K. Using Danny's oscillator config tool I get 44.24MHz MCU clock frequency. How to calculate a delay for the interrupt procedure with 44.24 MHz? The Timer_Calculator settings are 42 and 48 MHz.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 13 Aug 2017 08:52 
Offline

Joined: 22 Apr 2005 17:40
Posts: 1975
Location: France 87
why do you want the uart reception to be inside a timer-interrupt?
As far as i see you do not need the timer interrupt at all but you should enable the Uart interrupt after calling the Uartx_Init()

All the configuration you do in this section
Quote:
TXSTA1.BRGH := 0; // low speed baud rate
TXSTA1.SYNC := 0; // asynchronous mode
// TXSTA1.BRG16 := 0;
TXSTA1.TX9 := 0; // 8-bits transmission
TXSTA1.TXEN := 1; // Tx enabled
RCSTA1.CREN := 1; // enable receiving / accept continuous mode
RCSTA1.SPEN := 1; // Rx enabled;
RCSTA1.RX9 := 0; // 8-bits transmission//Timer0

is meaningless as you call
Quote:
UART1_Init(9600); // Initialize UART module at 9600 bps

which deals with all aspects of the Uart configuration.
Also this answers your question about higher baudrate, a simple UART1_Init(115200) will do, the compiler may report the baudrate-error but this error is most likely neglectible.

_________________
Au royaume des aveugles, les borgnes sont rois.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 14 Aug 2017 04:12 
Offline

Joined: 04 May 2012 10:52
Posts: 34
Location: Canada
Hi jpc,
- why do you want the uart reception to be inside a timer-interrupt? - Because the Timer calculator tool gives "//Enter your code here" which is inside of the timer-interrupt:
 
procedure Interrupt();
begin
  if (TMR0IF_bit) then
  begin
    TMR0IF_bit := 0;
    TMR0L    := 0x1F;
   [b] //Enter your code here[/b]
  end;
end;

If I put the UART reception to a main program it does not work.

- but you should enable the Uart interrupt after calling the Uartx_Init() - Compiler gives me a "Recursion or cross-calling of Interrupt" error. How to enable it properly? Could you please provide an example of working interrupt procedure.
- a simple UART1_Init(115200) will do, the compiler may report the baudrate-error but this error is most likely neglectible. - Yes, it works with 11.0592 MHz crystal (44.236 MHz MCU clock) with no compiler errors and the same timer settings as for 9600 baud rate. Some changes in the T0CON timer setting stops bytes receiving


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 14 Aug 2017 16:41 
Offline

Joined: 22 Apr 2005 17:40
Posts: 1975
Location: France 87
the uart can generate interrupts by itself, it does not need any timer for that.
Simply study the datasheet to see how you enable the Uart interrupt.
The recursion or cross-calling error only occurs when you call any function in both main and interrupt.

_________________
Au royaume des aveugles, les borgnes sont rois.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 14 Aug 2017 16:58 
Offline

Joined: 04 May 2012 10:52
Posts: 34
Location: Canada
I already use the UART RCxIF interrupt flag in my code:
 if PIR1.RC1IF = 1 then

it does not need any timer for that - Yes, It does! We have to use the timer for reliable byte reception. Timer settings depends on baud rate.

The PIC18F45K22 datasheet says:
16.1.2.4 Receive Interrupts
The RCxIF interrupt flag bit of the PIR1/PIR3 register is set whenever the EUSART receiver is enabled and there is an unread character in the receive FIFO. The
RCxIF interrupt flag bit is read-only, it cannot be set or cleared by software. RCxIF interrupts are enabled by setting the following bits:
• RCxIE interrupt enable bit of the PIE1/PIE3 register
• PEIE/GIEL peripheral interrupt enable bit of the INTCON register
• GIE/GIEH global interrupt enable bit of the INTCON register
The RCxIF interrupt flag bit will be set when there is an unread character in the FIFO, regardless of the state of interrupt enable bits.

It seems everything is Ok with USART interrupts in my code, isn't it?

But... The timer delay setting is set up for 8 MHz crystal (32 MHz MCU Clock) 9600 bit/sec and it works with 11.0592 MHz crystal (44.236 MHz MCU clock) for 115200 bit/sec as well which does not make any sense for me. Althrough it may work for 1 byte receiving and would not work for byte array, I could be wrong and need time for further testing.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 19 Aug 2017 01:05 
Offline
User avatar

Joined: 21 Mar 2017 16:57
Posts: 527
Hello

VladaG, sorry to say this, but I think that your code has many flaws, indeed. It seems that you still do not understand the meaning of a library concept inside the mikro compilers. Let me try to explain:

When you use libraries, you do not have to set things manually. If you do so, you can interfere with the library's way of dealing with the certain problem, so you should decide what you want to do. With a proper knowledge of what library does and how, you can complement it with your own code, though. Let's take a look at this part here:

// init USART
TXSTA1.BRGH : = 0; // low speed baud rate
TXSTA1.SYNC : = 0; // asynchronous mode
// TXSTA1.BRG16 := 0;
TXSTA1.TX9 : = 0;  // 8-bits transmission
TXSTA1.TXEN : = 1; // Tx enabled
RCSTA1.CREN : = 1; // enable receiving / accept continuous mode
RCSTA1.SPEN : = 1; // Rx enabled;
RCSTA1.RX9 : = 0;  // 8-bits transmission//Timer0
UART1_Init(9600);  // Initialize UART module at 9600 bps  < what is the point of this ???
Delay_ms(100);


...and so on, there are several examples of what you did here. You are using registers, then you fire up our library function with it's own register settings, and you expect it to work. Maybe it does, but it's simply... a bad habit, if nothing else. Also your program is called : UART (Simple usage of UART module library functions), so - let's use those library functions then:

Take a look at this beauty here. It uses just the regular 8MHz crystal... Only several lines of code. I've used libraries because I think that is what you wanted. Again - if you do want to actually learn about the EUSART modules and how they operate, then do not use libraries at all, try making your own code, from the ground up.

program UART;

procedure IRQ(); iv 0x0008; ics ICS_AUTO;
begin
  RC1IF_bit := 0;           //First thing when you enter the IRQ is to clear the flag
  LATB     := UART1_Read(); //Just for fun: display the received data on port B
end;

begin
  UART1_Init(9600);         //Init the UART with defaults: 8N1 9600bps
  ANSELB    := 0;           //Set B port as digital
  ANSELC    := 0;           //Set C port as digital
  TRISB     := 0x00;        //Set pin direction to OUT, Rx and Tx directions are taken care of by the lib
  LATB      := 0x00;        //Clear port B (do not use PORT when you write on PIC18F)
  GIE_bit   := 1;           //Set Global IRQ - define it this way and it will work on more MCUs...
  PEIE_bit  := 1;           //Peripheral IRQ set
  RC1IE_bit := 1;           //RX IRQ set

  while (1) do;             //Have fun in the main loop while receiving in your IRQ

end.

Also I could have skipped the interrupt entirely if I wanted to rely on libraries only, by using 'if (Uart1_Data_Ready())';
It was tested on the PIC18F45k22

Feel free to ask if you still have questions about this...
Regards


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 19 Aug 2017 16:10 
Offline

Joined: 18 Feb 2006 13:17
Posts: 4982
VladimirG wrote:
it does not need any timer for that - Yes, It does! We have to use the timer for reliable byte reception.
No, it does not :) . Processor has a complete hardware serial interface with bit-timing included. As for consecutive characters' arrival, this is an asynchronous communication which means that incoming character is recognized by the start bit, not by timing.

Naturally, one may add some protocol on top of the asynchronous communication that will, for example, define delays or allowed timeouts between consecutive sent or incoming characters. Even in such case, however, timer would be used to validate the observed delays, not to block or time reception.

_________________
Replacement libraries for mP PRO and PIC18 processors, mP PRO tips & trics


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 05 Sep 2017 04:53 
Offline

Joined: 04 May 2012 10:52
Posts: 34
Location: Canada
Hi guys,

Thanks all for the inputs. There is working EUSART based on Darko suggestion. It receives 4 bytes to an array and simply sends it back to the port:
{*
 * Project name:
     UART (Simple usage of UART module library functions)
     Oscillator:      HS-PLL 32.0000 MHz, 8.0000 MHz Crystal
 *}

program UART;
var RecState  :byte;
     ArrRxData: array[0..4] of byte;
     RecCount : Integer;
   iRxStatus   : byte;
 bDataReceived: boolean;
 
procedure IRQ(); iv 0x0008; ics ICS_AUTO;
begin
  RC1IF_bit := 0;           //First thing when you enter the IRQ is to clear the flag
  iRxData  := UART1_Read(); //Just for fun: display the received data on port B
  RecState := 3;
end;

procedure Main_Init;
begin
  UART1_Init(9600);         //Init the UART with defaults: 8N1 9600bps
  ANSELB    := 0;           //Set B port as digital
  ANSELC    := 0;           //Set C port as digital
  TRISB     := 0x00;        //Set pin direction to OUT, Rx and Tx directions are taken care of by the lib
  LATB      := 0x00;        //Clear port B (do not use PORT when you write on PIC18F)
  TRISD     := 0x00;        //Set pin direction to OUT, Rx and Tx directions are taken care of by the lib
  LATD      := 0x00;
  GIE_bit   := 1;           //Set Global IRQ - define it this way and it will work on more MCUs...
  PEIE_bit  := 1;           //Peripheral IRQ set
  RC1IE_bit := 1;           //RX IRQ set
   RecCount := 0;
end;


procedure Data_Reset;
begin
  for RecCount := 0 to 4 do
    ArrRxData[RecCount] := $00;
         RecState := 0;
         RecCount := 0;
       iRxData := 0x00;
end;

procedure Do_Nothing;
begin
  nop;
end;


procedure Data_Send;
begin
  for RecCount := 0 to 4 do
    UART1_Write(ArrRxData[RecCount]);
    Data_Reset;
end;


 begin
 Main_Init;
 
 
 while TRUE do
   begin
     if RecState = 3 then
             begin
     RecState := 0;
     inc(RecCount);
     ArrRxData[RecCount] := iRxData;
      end ;
 if RecCount < 4 then
      begin
          Do_nothing;
      end
       else if RecCount = 4 then
        begin       
         Data_Send;
   end;
   end;
 end.


Top
 Profile  
 
 Post subject: Re: PIC18F45K22 EUSART
PostPosted: 05 Sep 2017 21:23 
Offline
User avatar

Joined: 21 Mar 2017 16:57
Posts: 527
Hi,

I am really happy that you have made it work. I have suggested the library based approach because it is much easier to work with, but don't get me wrong - working with the registers is good too, as long as you know what is going on in the libraries. Think of them as of some functions, defined outside of your code - so as long as you know how to combine them with your own code, it's all good.

The similar method is used in some of our own examples - we use the interrupt for the RX, but instead of reading buffer registers and worrying about setting them all correctly, we simply read the UART and store the data in a variable - like your array. Once when you want to really dig into the registers and program some lower level code, you will want the full control, so leave the libraries behind in that case...

Good luck and best regards


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 22 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: