CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Multiple interrupts on PIC18F, PIC hangs

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
shson



Joined: 12 Feb 2016
Posts: 11

View user's profile Send private message

Multiple interrupts on PIC18F, PIC hangs
PostPosted: Wed Aug 24, 2016 6:49 pm     Reply with quote

PIC18F44K22, v5.061

Hello

I'm having trouble using multiple interrupts on PIC18F44K22, namely RDA, RDA2 and CCP3. After searching the forum I realised that the order of in which I enable interrupt affects the behaviour, so I moved CCP3 interrupt enable to the top.

But whenever I uncomment the enable_interrupt for RDA and RDA2, CCP3 interrupt stops working, in fact, the whole PIC appears to stop responding and simply hangs (I'm assuming it's hang because it does not respond to if (!input(BOOTLOADER_START)) even though I pulled the input low.

Any ideas?

Thank you
Eric

Main header:

Code:
#include <18F44K22.h>
#device ADC=10

#FUSES HSH
#FUSES PRIMARY_ON               //Primary clock is always enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES BORV19                   //Brownout reset at 1.9V
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES CCP3B5                   //CCP3 input/output multiplexed with RB5
#FUSES HFOFST                   //High Frequency INTRC starts clocking CPU immediately
#FUSES TIMER3C0                 //Timer3 Clock In is on pin C0
#FUSES CCP2B3                   //CCP2 input/output multiplexed with B3
#FUSES MCLR                     //Master Clear pin enabled
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES LVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PROTECT                  //Code protected from reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTC                   //Configuration registers not write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES EBTR                     //Memory protected from table reads
#FUSES EBTRB                    //Boot block protected from table reads

#use delay(crystal=18432000)

#use FIXED_IO( A_outputs=PIN_A1,PIN_A3 )
#use FIXED_IO( C_outputs=PIN_C5 )
#use FIXED_IO( D_outputs=PIN_D3 )

#define STATUS                PIN_A3
#define OSC2                  PIN_A6
#define OSC1                  PIN_A7
#define COUNT_RESET_SIGNAL    PIN_B2
#define RATIOM_HALL_SIGNAL    PIN_B3
#define OPENC_HALL_SIGNAL     PIN_B5
#define ICSPCLK               PIN_B6
#define ICSPDAT               PIN_B7

#define UART1_TX              PIN_C6
#define UART1_RX              PIN_C7
#define UART2_TX              PIN_D6
#define UART2_RX              PIN_D7

#define BOOTLOADER_START      PIN_E2
#define MCLR                  PIN_E3
#define WIFLY1_RESET          PIN_C5
#define WIFLY2_RESET          PIN_D3
#define WIFLY3_RESET          PIN_A1

#define bTRUE     1
#define bFALSE    0
#define UINT8     unsigned int8
#define UINT16    unsigned int16
#define BOOL      short int1

//#use rs232(baud=9600,parity=N,xmit=UART2_TX,rcv=UART2_RX,bits=8,stream=WIFI_COMM,errors)
//#use rs232(baud=9600,parity=N,xmit=UART1_TX,rcv=UART1_RX,bits=8,stream=LOCAL_COMM,errors)

#use rs232(UART1,baud=9600,parity=N,bits=8,stream=LOCAL_COMM,errors)
#use rs232(UART2,baud=9600,parity=N,bits=8,stream=WIFI_COMM,errors)


Main.c:

Code:

#include <main.h>
//#include <bootloader.h>
#include "SCI.c"

UINT16 pulse_count;
BOOL f_moving;

#INT_RDA
void ISR_UART1_Local_Comm()
{
   output_toggle(STATUS);  // Toggle LED if UART1 RDA interrupt fires
}

#INT_RDA2
void ISR_UART2_WiFi_Comm()
{
   output_toggle(STATUS);  // Toggle LED if UART2 RDA2 interrupt fires
}

// ----------------------------------------
// ISR_CCP3_OPENCL_Hall_Detected
//
// Handles CCP3 rising/falling edge hall sensor signal
// Input:
//   none
// Output:
//   none
// Conditions:
//   none

#INT_CCP3
void ISR_CCP3_OPENCL_Signal_Detected()
{
   ++pulse_count;
   f_moving = bTRUE;
}

// ----------------------------------------
// main
//
// main program loop
// Input:
//   none
// Output:
//   none
// Conditions:
//   none

void main()
{   
   set_tris_a(0b00111100);
   setup_ccp3(CCP_CAPTURE_FE);

   setup_uart(9600, WIFI_COMM);
   setup_uart(9600, LOCAL_COMM);
   
   clear_interrupt(INT_CCP3);
   clear_interrupt(INT_RDA);
   clear_interrupt(INT_RDA2);

   enable_interrupts(INT_CCP3);
   // If I uncomment RDA2 and RDA interrupt enable, CCP stops working
   //enable_interrupts(INT_RDA2);
   //enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   pulse_count       = 0;           // initialise hall effect sensor pulse count
   f_moving          = bFALSE;      // flags to indicate whether new pulse is detected
   
   fprintf(LOCAL_COMM,"\r\nStarting main loop");
   
   while(TRUE)
   { 
      if (f_moving)
      {
         fprintf(LOCAL_COMM,"\r\n%05Lua", pulse_count);
         fprintf(WIFI_COMM,"\r\n%05Lua", pulse_count);
         f_moving = bFALSE;
      }
     
      if (!input(BOOTLOADER_START))
         reset_cpu();

   }

}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Aug 24, 2016 7:45 pm     Reply with quote

Many PIC interrupts require an action by you the programmer, to clear the
interrupt condition. In the case of #int_rda, you must call getc() or fgetc()
to get the character from the hardware fifo buffer. In your current code
you are not doing this, and that's the problem.
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Thu Aug 25, 2016 12:34 am     Reply with quote

Just to iterate and expand on what PCM_programmer has said.

INT_RDA, says 'there is a character waiting to be read'.

The compiler will clear the interrupt, but if there is still a character waiting to be read, it will set again immediately. Result the handler will be called and called, and called and called. Hang.

Interrupts that require handling are (may miss some)

INT_RB (and any of the other 'change' interrupts)
Requires the corresponding port to be read.
INT_RDAx
Requires you to read the character from the corresponding UART.
INT_TBEx
Requires a character to be written to the UART (or disable).
INT_SSP
Requires MSSP status updated (read or write).

There are other 'more exotic' ones when you get to things like CAN, but these are the standard ones.
shson



Joined: 12 Feb 2016
Posts: 11

View user's profile Send private message

PostPosted: Thu Aug 25, 2016 2:59 am     Reply with quote

Ttelmah wrote:

The compiler will clear the interrupt, but if there is still a character waiting to be read, it will set again immediately. Result the handler will be called and called, and called and called. Hang.


Ahh it's making sense now as to why it would hang. I expected that calling an interrupt handler routine cleared the interrupt, not actually in case for INT_RDA, call getc()/fgetc() to clear the interrupt.

As per PCM's suggestion, I've added relevant interrupt handlers for both RDA and RDA2 and everything is working as expected. It was a copy and paste of ex_sisr.c with different buffers for UART1 and UART2.

Added these in main.c,

Code:

#INT_RDA
void ISR_UART1_Local_Comm()
{
   int t;

   local_comm_buff[local_comm_next_in ] = fgetc(LOCAL_COMM);
   t = local_comm_next_in;
   local_comm_next_in = (local_comm_next_in + 1) % BUFFER_SIZE;
   if(local_comm_next_in == local_comm_next_out)
     local_comm_next_in = t;           // Buffer full !!
}

#INT_RDA2
void ISR_UART2_WiFi_Comm()
{
   int t;

   wifi_comm_buff[wifi_comm_next_in ] = fgetc(WIFI_COMM);
   t = wifi_comm_next_in;
   wifi_comm_next_in = (wifi_comm_next_in + 1) % BUFFER_SIZE;
   if(wifi_comm_next_in == wifi_comm_next_out)
     wifi_comm_next_in = t;           // Buffer full !!
}


And added buffer definitions and routines,

Code:

#define BUFFER_SIZE   32

/* Define UART2 (WiFi module) buffer */

BYTE wifi_comm_buff[BUFFER_SIZE];
BYTE wifi_comm_next_in = 0;
BYTE wifi_comm_next_out = 0;

#define wifi_comm_bkbhit (wifi_comm_next_in != wifi_comm_next_out)

BYTE GetChar_WIFI_COMM() {
   BYTE c;

   while(!wifi_comm_bkbhit) ;
   c = wifi_comm_buff[wifi_comm_next_out];
   wifi_comm_next_out = (wifi_comm_next_out + 1) % BUFFER_SIZE;
   return(c);
}

/* Define UART1 (local RS232) buffer */

BYTE local_comm_buff[BUFFER_SIZE];
BYTE local_comm_next_in = 0;
BYTE local_comm_next_out = 0;

#define local_comm_bkbhit (local_comm_next_in != local_comm_next_out)

BYTE GetChar_LOCAL_COMM() {
   BYTE c;

   while(!local_comm_bkbhit) ;
   c = local_comm_buff[local_comm_next_out];
   local_comm_next_out = (local_comm_next_out + 1) % BUFFER_SIZE;
   return(c);
}


Thank you!
Eric
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Thu Aug 25, 2016 3:28 am     Reply with quote

Quote:
I expected that calling an interrupt handler routine cleared the interrupt, not actually in case for INT_RDA, call getc()/fgetc() to clear the interrupt.


The interrupt is cleared by compiler supplied (and usually hidden) code. However, the cause of the interrupt must be dealt with by the user. In this case, the RDA interrupt flag is cleared, but the user must read the character from the port otherwise a new interrupt will be generated, i.e. the interrupt flag set again immediately when interrupts are re-enabled by the return from the ISR.

Interrupts are a mechanism where stuff that needs to be serviced can tell the code that something has happened and request action. The mechanics of the interrupt itself is dealt with automatically, but its down to the user to deal with the reason why the interrupt was raised in the first place. So, in serial receive character ready interrupts, RDAs, the user must read the character. In bit change interrupts, IOC, the user must reset the bit detector by reading it, and so on.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Thu Aug 25, 2016 12:01 pm     Reply with quote

here is a partial code snippet i've used at bauds of 115200 and greater with the 46k22

perhaps it will help you and aid your understanding of how
to handle your 2 port system - based on CCS examples but
more efficient with non-power-of two buffer sizes
next_in and out and buffer becomes buffer2[buffer_size] etc as well as next_IN[2] and so on for 2 channel
a

Code:

#int_rda          // in two chan systems  INT_RDA  INT_RDA2
   void serial_isr() {
   int t;
 while(kbhit()){  // in two chan systems (kbhit (0 or 1)
   t=next_in;
   buffer[next_in++]=getc();  // in two chan systems (kbhit (0 or 1)
   if (next_in==BUFFER_SIZE) next_in=0;;
   if(next_in==next_out)  next_in=t;           // Buffer full !!
 }
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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 vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group