I'm still having trouble with the interrupts in my project so I've taken the time to dig a little deeper into the datasheet. In the interrupt section there is the following. I need help understanding the part in bold.
"The Interrupt Control register (INTCON) records individual interrupt requests in flag bits. It also has individual and global interrupt enable bits. A Global Interrupt Enable bit, GIE (INTCON<7>) enables (if set) all un-masked interrupts or disables (if cleared) all interrupts. Individual interrupts can be disabled through their corresponding enable bits in INTCON register. GIE is cleared on Reset. The “return-from-interrupt” instruction, RETFIE, exits interrupt routine as well as sets the GIE bit, which reenables RB0/INT interrupts. The INT pin interrupt, the RB port change interrupt and the TMR0 overflow interrupt flags are contained in the INTCON register. The peripheral interrupt flag is contained in the special register PIR1. The corresponding interrupt enable bit is contained in special registers PIE1. When an interrupt is responded to, the GIE is cleared to disable any further interrupt, the return address is pushed into the stack and the PC is loaded with 0004h. Once in the interrupt service routine, the source(s) of the interrupt can be determined by polling the interrupt flag bits. The interrupt flag bit(s) must be cleared in software before re-enabling interrupts to avoid RB0/ INT recursive interrupts. For external interrupt events, such as the INT pin or PORTB change interrupt, the interrupt latency will be three or four instruction cycles. The exact latency depends when the interrupt event occurs (Figure 14-15). The latency is the same for one or two-cycle instructions. Once in the interrupt service routine, the source(s) of the interrupt can be determined by polling the interrupt flag bits. The interrupt flag bit(s) must be cleared in software before re-enabling interrupts to avoid multiple interrupt requests."
For some reason, my INT interrupt never fires...I'm wondering if my Rx interrupt is holding it up some how? Does this mean every time an interrupt fires I need to set GIE after I clear that specific interrupt flag? Thanks in advance for any help!.
Here is a dumb question, in my circuit VDD is 3.3V. Is RB0 still expecting 5V to register a high or is 3.3 ok?
Really pulling my hair out over this one...here is the code.
"The Interrupt Control register (INTCON) records individual interrupt requests in flag bits. It also has individual and global interrupt enable bits. A Global Interrupt Enable bit, GIE (INTCON<7>) enables (if set) all un-masked interrupts or disables (if cleared) all interrupts. Individual interrupts can be disabled through their corresponding enable bits in INTCON register. GIE is cleared on Reset. The “return-from-interrupt” instruction, RETFIE, exits interrupt routine as well as sets the GIE bit, which reenables RB0/INT interrupts. The INT pin interrupt, the RB port change interrupt and the TMR0 overflow interrupt flags are contained in the INTCON register. The peripheral interrupt flag is contained in the special register PIR1. The corresponding interrupt enable bit is contained in special registers PIE1. When an interrupt is responded to, the GIE is cleared to disable any further interrupt, the return address is pushed into the stack and the PC is loaded with 0004h. Once in the interrupt service routine, the source(s) of the interrupt can be determined by polling the interrupt flag bits. The interrupt flag bit(s) must be cleared in software before re-enabling interrupts to avoid RB0/ INT recursive interrupts. For external interrupt events, such as the INT pin or PORTB change interrupt, the interrupt latency will be three or four instruction cycles. The exact latency depends when the interrupt event occurs (Figure 14-15). The latency is the same for one or two-cycle instructions. Once in the interrupt service routine, the source(s) of the interrupt can be determined by polling the interrupt flag bits. The interrupt flag bit(s) must be cleared in software before re-enabling interrupts to avoid multiple interrupt requests."
For some reason, my INT interrupt never fires...I'm wondering if my Rx interrupt is holding it up some how? Does this mean every time an interrupt fires I need to set GIE after I clear that specific interrupt flag? Thanks in advance for any help!.
Here is a dumb question, in my circuit VDD is 3.3V. Is RB0 still expecting 5V to register a high or is 3.3 ok?
Really pulling my hair out over this one...here is the code.
C:
// Defines
#define _XTAL_FREQ 4000000 // running the chip at 4Mhz
#define ID_MAX 63 // highest ID number possible. 6 bits base^n
#define ID 1 // #DEFINE for hardcoded ID's. Safe route for presentation
#define BOOT_STALL 750 // Number of mS to delay upon receiving ACK from raspi
#define TMR_TWO_PERIOD 62500 // Remaing counts, 245 rolls roughly one second. 50% duty cycle
//#define TMR_TWO_HALF_PERIOD // see above...
#define DISTRESS 0x11 // distress state
#define ALERT 0x02 // alert state
#define BOOT_MASK 0x40 // boot packet mask
#define ALARM_MASK 0xC0 // alarm packet mask
volatile char rx_buffer; // dumping UART data in here for processing
int timer_1_overflow_count = 0; // Timer 1 overflow counter, keeps track of how often timer 1 overflows
int timer_2_overflow_count = 0; // Timer 2 overflow counter, keeps track of how often timer 2(16bit) overflows
int id_ok = 0; // Set high when id is echoed(accepted) back by raspi.
volatile int tmr1_rc = 0; // counts rolls of timer 1
volatile int tmr2_rc = 0; // counts rolls of timer 2
char strobe_ok = 0x0; // determines weather or not its ok for the strobe light to come on
char vibe_ok = 0x0; // determines weather or not its ok for the vibration to come on
char packet = 0x0; // transmission packet
volatile char state = 0x00; // 0x01 distress 0x02 alert
// ISRS
void interrupt ISR (void)
{
/* External RB0 rising edge interrupt */
if(INTF) // RBO/INT interrupt, must clear flag in software. Disable Rx interrupt.
{
state = DISTRESS;
INTF = 0;
}
if(RCIF && state != DISTRESS) // If i receive a message from the network
{
rx_buffer = RCREG;
CREN = 0; // handles possible OREN situation
CREN = 1;
if(state != DISTRESS)
state = ALERT;
}
// End Receiving ISR
// Timer 1(16 bit) ISR transmits distress signal
if(TMR1IF)
{
tmr1_rc++;
TMR1 = 0x7AE0; // dumping 31456 inside the register. Leaving roughly 1 second worth of counts remaining
TMR1IF = 0;
}
// end timer 1 ISR
// Timer 2 ISR drives piezo buzzer
if(TMR2IF) // timer 2 overflowed, used to control peizo
{
tmr2_rc++;
TMR2IF = 0; // reset flag
}
// End Timer 2 ISR
}
int id_start = 0; // starting point for ID's 0-63. 64 possible ID's. Only used for dynamic IDing system
void main()
{
// ENABLING INTERRUPTS
GIE = 1; // General interrupt enable
PEIE = 1; // peripheral interrupt enable
// IO SETUP
TRISA = 0xBD; // RA1 & RA6 outputs, rest inputs
TRISB = 0x2F; // RB4, RB6, RB7 outputs, rest inputs
CMCONbits.CM = 0b111; // turn off comparator
// Timer setup
/* TMR 0 Setup used to control strobe light */
// No Prescaler in timer mode...
OPTION_REGbits.T0CS = 0; // timer mode
/* TMR 1 Setup used to control Tx distress packet */
T1CONbits.T1CKPS = 0b11; // 1:8 prescaler 125000 counts = second. Roughly 2 rolls = one second. 16 bit timer
TMR1 = 0x7AE0; // dumping 31456 inside the register. Leaving roughly 1 second worth of counts remaining
/* TMR 2 Setup */
T2CONbits.T2CKPS = 0b10; // 1:16 prescaler 62500 counts = second. Roughly 245 rolls = one second.
/************************************************* Boot Sequence Starts Here ***********************************************************/
/* details coming soon */
// Check xbee health. Loops until xbee is powered on
while(!RB5) // if xbee isn't on(RB5 low)....(using a while as an if statement just incase xbee comes on after MCU)
{
RA1 = 0; // turn GIL off...
RA6 = 1; // turn RIL on...
__delay_ms(1000); // wait one second
RA6 = 0; // turn RIL off...
__delay_ms(1000); // wait one second
}
RA1 = 1; // Turn GIL on
// if we make it this far xbee is ok...time to init the UART
/************************ UART COMMS SETUP ********************************************/
BRGH = 1; // highspeed selected, designed 9600 actual 9615
SPBRG = 25; // baud rate = Fosc/16(SPBRG+1)
CSRC = 0; // Asynchronous mode, internal BRG
TXEN = 1; // Transmit enable
SYNC = 0; // Asynchronous mode
SPEN = 1; // Enable serial comm
CREN = 1; // Continuous receive
RCIE = 1; // RS232 receive interrupt enable
/************************ END UART COMMS SETUP ****************************************/
/* lets build our boot packet Dynamic IDs
packet = packet | 0x40; // or'ing the packet bitfield with 01000000 in order to turn on bit 6. Now its a boot packet
while(1) // manually breaking this loop once we get an accepted ID or max out
{
packet = packet | id_start; // copying any high bits from id_start into packet. So now we have a "boot packet" with an id stored in bits 0-5
TXREG = packet; // send it out to the network, only the raspi responds to boot packets
}*/
/* Lets build our boot packet Static IDs */
packet = packet | BOOT_MASK; // or'ing the packet bitfield with 01000000 in order to turn on bit 6. Now its a boot packet
packet = packet | ID; // copying any high bits from ID into packet. So now we have a "boot packet" with an id stored in bits 0-5
while(rx_buffer != packet) // keep broadcasting every 1.5 seconds until raspi echos it back. "Handshaking" in a very very simple/unreliable sense
{
TXREG = packet;
RA1 = 0; RA6 = 1; // toggling lights to signal handshaking....
__delay_ms(BOOT_STALL); // delay for x seconds, doesn't really need to be that long
RA1 = 1; RA6 = 0; // toggling lights to signal handshaking....
__delay_ms(BOOT_STALL); // delay for x seconds, doesn't really need to be that long*/
if(id_ok) // id is ok, no need to loop anymore
break;
}
/************************************************* Connected to Wireless e Data Network ***********************************************************/
/************************************************* Boot Sequence Ends Here ***********************************************************/
/************************************************* Device Active ***********************************************************/
//T0IE = 1; // timer 0 overflow interrupt enable
INTE = 1; // RBO/INT interrupt enable
INTEDG = 1; // RBO/INT RISING edge, for now
RA1 = 1; // turn on GIL
while(1) // Loop forever...state machine
{
// state machine
switch(state)
{
case DISTRESS :
RA1 = 0; // kill GIL
RA6 = 1;
INTE = 0; // disable INT interrupt
RCIE = 0; // RS232 receive interrupt disabled
CREN = 0;
vibe_ok = 0x00;
if(!TMR1ON)
{
T1CONbits.TMR1ON = 1; // turn timer1 on Tx clock
T2CONbits.TMR2ON = 1; // turn timer2 on Strobe clock
TMR1IE = 1; // timer 1 overflow interrupt enable
TMR2IE = 1; // timer 2 overflow interrupt enable
}
if(tmr1_rc >= 5) // 5 rolls..5 seconds.
{
packet = packet | ALARM_MASK;// turn it into a fall packet
packet = packet | ID; // attaching ID to last 6 bits
TXREG = packet; // transmit the distress signal
tmr1_rc = 0; // reset roll counter
}
if(tmr2_rc >= 122) // 122 rolls = half second
{
RB4 = !RB4; // drive/silence peizo
RB7 = !RB7; // drive/silence strobe
tmr2_rc = 0;
}
break;
case ALERT :
if((rx_buffer & ALARM_MASK) == ALARM_MASK) // someone transmitted, &'ing packet against fall mask 0xC0. Latching state, unlatched by INTF ISR
{
RCIE = 0; // disable Rx Interrupt, someone fell we're in alarm until the device is power cycled. Ignore all other incoming packets
CREN = 0;
vibe_ok = 1; // putting us in "help" or "alert" mode
while(RCREG)
if(!RCREG)
GIE = 1;
} else if ((rx_buffer & BOOT_MASK) == BOOT_MASK && !id_ok) { // we've received a boot packet
if(rx_buffer == packet) // boot packet matches what was sent out
{
id_ok = 1; // id accepted by network
while(RCREG) // clear the fifo buffer
if(!RCREG)
GIE = 1;
}
}
if(vibe_ok & tmr2_rc >= 122) // we're ok...but someone else fell wake up and help! Vibe on
{
RB6 = !RB6; // Vibe toggle
tmr2_rc = 0;
}
break;
default :
;
}
}
}
Last edited: