PCINT interrupt problem, not entirely sure what's wrong

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi - I'm trying to use PCINT1 on an ATMEGA168. I am using the most recent WinAVR. I've included my full code below, but the relevant parts are the initialization:

PCMSK0 = 1<<PCINT0;
PCICR = 1<<PCIE0;

and the interrupt handler:

ISR (PCINT1_vect)
{
SendString("pcint1 interrupt\r");
}

The symptoms are that it just seems to continuously reset. The interrupt handler never fires.

Anybody have any idea what I'm doing wrong? I have confirmed that the PCINT1 pin is changing when I expect it to.

/*
pin locations:
PB0 O CLKO
PB1 I MCP2515_INT'
PB2 O MCP2515 SS'
PB3 O MOSI
PB4 I MISO
PB5 O SCK

PC0 N/C
PC1 O LED
PC2 I SPWR1
PC3 I POT1
PC4 I SPWR0
PC5 I POT0

PD0 I RXD
PD1 O TXD
PD2 O PWM0
PD3 O PWM1
PD4 O PWM2
PD5 O MCP2515_TX0RTS'
PD6 O MCP2515_TX1RTS'
PD7 O MCP2515_TX2RTS'

ADC6 I POT2
ADC7 I SPWR2
*/

#define SPWR0 4
#define SPWR1 2
#define SPWR2 7
#define POT0 5
#define POT1 3
#define POT2 6

//MCP2515 modes
#define mcp_normal 0
#define mpc_sleep 1
#define mpc_loopback 2
#define mpc_listen 3
#define mpc_config 4

#include 
#include 
#include 
#include 
#include 

/* UART functions */
void SendString(char *StringToSend);
void WriteInt(int n);

unsigned char spitxrx(unsigned char sendme);
unsigned int readadc(char channel);
unsigned char readreg(char regaddress);
void writereg(char regaddress, char writeme);
void readcantx(unsigned char RXBnDLC);

ISR (PCINT1_vect)
{
	SendString("pcint1 interrupt!\r");
}

int main(void)
{
	/* initialize UART */
	UCSR0B=1<<RXEN0|1<<TXEN0; /* no rx interrupt (1<<RXCIE0), enable tx and rx, */
	UCSR0C=1<<UCSZ01|1<<UCSZ00; /* 8b character size, no parity, 1 stop bit */
	//UBRR = (Freq/(16*baudrate)) - 1
	//baudrate = freq/(16*(UBRR + 1))
	UBRR0=64; /* 9600 bps baudrate with 10mhz oscilator, .16% error */
	
	//enable ADC, ADC clock = system clock/128
	ADCSRA = (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);
	
	//set data directions, high = output
	DDRB = (1<<PB0)|(1<<PB2)|(1<<PB3)|(1<<PB5);
	DDRC = 1<<PC1;
	DDRD = (1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
	
	//turn off mcp2515 cs'
	PORTB = 1<<PB2;
	
	//turn on LED
	//PORTC = (1<<PC1);
	
	//set high all MCP2515 TXRTS pins
	PORTD = (1<<PD5)|(1<<PD6)|(1<<PD7);
	
	SPCR = (1<<SPE)|(1<<MSTR); //enable SPI, set as master
	SPSR = 1<<SPI2X; //5mhz SCK
	
	//enable MCP2515 interrupt
	PCMSK0 = 1<<PCINT0;
	PCICR = 1<<PCIE0;
	
	
	//reset mcp2515
	PORTB = 0;
	spitxrx(0xC0);
	PORTB = 1<<PB2;
	
	SendString("CANCTRL register: ");
	WriteInt((int)readreg(0x0F));
	
	
	/*>>>>>in config mode, config mcp2515<<<<*/
	
	//turn off clock output in CANCTRL
	writereg(0x0F, 0x80);

	//turn on TX[0-2]RTS' pins in TXRTSCTRL 
	writereg(0x0D, 0x07);
	
	//configure CNF1, SJW = 4, BRP = 0, CNF1 = 0b11000000
	writereg(0x2A, 0xC0);
	
	//configure CNF2 = 0b10010010, PS1 = 3TQ, propseg = 3TQ
	writereg(0x29, 0x92);
	
	//configure CNF3 = 0b00000010, PS2 = 3TQ
	writereg(0x28, 0x01);
	
	//configure masks and filters, configure as leg1, identifier = 1 (0b00000000001)
	//RXM0 = 0b11111111111
	writereg(0x20, 0xFF);
	writereg(0x21, 0xE0);
	
	//RXF0 == 0b00000000001
	writereg(0x00, 0x00);
	writereg(0x01, 0x20);
	
	//RXF1 == 0b00000000001
	writereg(0x04, 0x00);
	writereg(0x05, 0x20);
	
	/*>>>>Enter normal mode<<<<*/
	
	writereg(0x0F, 0x00);
	
	//enable rollover in RXB0CTRL
	writereg(0x60, 0x04);
	
	//enable rx interrupts in CANINTE
	writereg(0x2B, 0x03);
	
	//test out rx interrupt by setting interrupt
	sei();
	writereg(0x2C, 0x01);
	
	
	SendString("\rtesting out ADC: ");
	WriteInt(readadc(POT0));
	while (1) asm volatile ("nop"::);
}

void SendString(char *StringToSend)
{ /* Writes StringToSend to terminal */
	while (*StringToSend)
	{
		while (!(UCSR0A & (1<<UDRE0))) ;  /* wait till uart buffer is empty */
		UDR0 = *StringToSend;  /* write next byte to uart */
		StringToSend++;
	}
}

void WriteInt(int n)
{ /* function stolen from http://www.cs.uiowa.edu/~jones/bcd/decimal.html This function converts an integer to a string and has it sent through the UART*/
	char Output[6];
	for (Output[0] = '0' - 1; n >= 0; n -= 10000) ++Output[0];
	for (Output[1] = '9' + 1; n <  0; n += 1000) --Output[1];
	for (Output[2] = '0' - 1; n >= 0; n -= 100) ++Output[2];
	for (Output[3] = '9' + 1; n <  0; n += 10) --Output[3];
	Output[4] = n + '0';
	Output[5] = '\0';
	SendString(Output);
}

unsigned char spitxrx(unsigned char sendme)
{
	////wait for last SPI transfer to finish
	//while (!(SPSR & (1<<SPIF))) ;
	SPDR = sendme;
	//wait for current spi transfer to finish
	while (!(SPSR & (1<<SPIF))) ;
	return SPDR;
}

unsigned int readadc(char channel)
{
	ADMUX = channel|0x40;
	ADCSRA |= (1<<ADSC); //begin ADC
	while (!(ADCSRA & (1<<ADIF))) ; //wait till ADC finishes
	return (ADC);
}

unsigned char readreg(char regaddress)
{
	PORTB = 0;
	spitxrx(0x03); //read register
	spitxrx(regaddress); //give address
	unsigned char temp = spitxrx(0x00); //read in *regaddress
	PORTB = 1<<PB2;
	return temp;
}

void writereg(char regaddress, char writeme)
{
	PORTB = 0;
	spitxrx(0x02); //write register
	spitxrx(regaddress); //give address
	spitxrx(writeme); //write in data
	PORTB = 1<<PB2;
}

void readcantx(unsigned char RXBnDLC)
{
	unsigned char x;
	for (x = 0x0F | readreg(RXBnDLC); x != 0; x--)
	{
		RXBnDLC++;
		WriteInt((int)readreg(RXBnDLC));
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR (PCINT1_vect)

shouldn't this be

ISR (PCINT0_vect)

?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mckenney wrote:

ISR (PCINT1_vect)

shouldn't this be

ISR (PCINT0_vect)

?

Hi - you're right about the typo, though this is the line that was wrong:

PCMSK0 = 1<<PCINT0;

whereas it should have been:

PCMSK0 = 1<<PCINT1;

But actually before posting I had had it as hex values, and just changed it right before posting for clarity of code, and made the typo then. Just to be sure, I tried out the corrected code, and the same symptoms persist.

If it matters, using the code above (but with the line fixed), this is what I get in my terminal when interrupts are not enabled:

CANCTRL register: 00135
testing out ADC: 00492

And this is what I get when interrupts are enabled

CANCTRL register: 00135CANCTRL register: 001™M¨9
QI1register: 001M¨9
QI1register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 001M¨9
QI1register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9
QI1register: 00135CANCTRL register: 001™M¨9

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As another experiment, I tried adding a line of code right below the sei() like this:

sei();
SendString("past interrupt enabled\r");

And now the output on the terminal looks like this:

CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled
CANCTRL register: 00135CANCTRL register: 00135past interrupt enabled

So it seems to restart right after the interrupt is triggered. Like for some reason it is jumping to the reset interrupt handler instead of the PCINT1 interrupt handler

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually I was looking at

PCICR = 1<<PCIE0; 

which enables PCINT0_vect, not PCINT1_vect.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mckenney wrote:
Actually I was looking at

PCICR = 1<<PCIE0; 

which enables PCINT0_vect, not PCINT1_vect.


Oh wow... You're completely correct. I thought that to use the PCINT1 pin interrupt I'd use the PCINT1_vect interrupt. But I guess PCINT[0-7] all are handled by PCINT0_vect. I didn't read the datasheet carefully enough. I just changed the ISR (PCINT1_vect) to ISR (PCINT0_vect) and suddenly it works perfectly. This makes perfect sense as well, as that means it was jumping to the PCINT1 handler and then falling through till it hit my main().

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
then falling through till it hit my main().

Close, but not quite that random -- with avr-libc all un-caught interrupts
cause an explicit jump to location 0 (pseudo-reset).