|
|
View previous topic :: View next topic |
Author |
Message |
shson
Joined: 12 Feb 2016 Posts: 11
|
Multiple interrupts on PIC18F, PIC hangs |
Posted: Wed Aug 24, 2016 6:49 pm |
|
|
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
|
|
Posted: Wed Aug 24, 2016 7:45 pm |
|
|
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: 19513
|
|
Posted: Thu Aug 25, 2016 12:34 am |
|
|
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
|
|
Posted: Thu Aug 25, 2016 2:59 am |
|
|
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
|
|
Posted: Thu Aug 25, 2016 3:28 am |
|
|
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
|
|
Posted: Thu Aug 25, 2016 12:01 pm |
|
|
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 !!
}
}
|
|
|
|
|
|
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
|