Mega + MCP2515 : Interrupt Issues

Hi all,

I'm trying to interface with an MCP2515 CAN controller ( ) and use the interrupts generated on RX0BF and RX1BF to signal when data is ready to be read out of the buffers.

I've connected the two RXnBF pins to 18 and 19 on the mega, and used the following code during setup to attach to the interrupts:

  attachInterrupt(5,intReadRX0,FALLING); // Attach interrupt functions

When I monitor the voltage on the relevant pins with a scope/meter, it does drop when the buffer is full however the interrupt functions (intReadRX0 and intReadRX1) never seem to fire. If I attach pins 18 and 19 to another pin and generate an interrupt signal myself (digital write high > low > high) then it does get picked up and the function runs.

Am I missing something obvious? I've tried with and without a pull-up resistor (had a 33k to hand, so went with that), I've tried different interrupt pins on the mega and as I've said, I've tried monitoring the state of the line with extra equipment to make sure the voltage does drop when the buffer is full.

One of the things I'm doing within the interrupt is reading from the MCP2515 over SPI. Does anyone know if reading from SPI uses interrupts in any way? Since nothing else should be firing interrupts at the time (MCP2515 stops until the ISR finishes and clears the interrupt flag) it should be reasonably safe to enable them at the start of the ISR, but I won't get a chance to test it until tomorrow afternoon. Would be nice to know if anyone else has had similar experiences.

I’ve stripped the interrupt code down as far as I can and I’ve come up with:

    unsigned int retID;
    int i;
    unsigned short id_h,id_l,extid_8,extid_0;
    id_h = (unsigned short) SPI.transfer(0xFF); //id high
    id_l = (unsigned short) SPI.transfer(0xFF); //id low
    extid_8 = (unsigned short) SPI.transfer(0xFF); //extended id high
    extid_0 = (unsigned short) SPI.transfer(0xFF); //extended id low
    retID = ((((((((id_h << 3) + ((id_l & 0xE0) >> 5))<<2)+(id_l&0x03))<<8)+extid_8)<<8)+extid_0); //repack identifier
    ECU[i].length = (SPI.transfer(0xFF) & 0x0F);
    ECU[i].time = millis();
    ECU[i].address = retID;
    ECU[i].data1 = SPI.transfer(0xFF);
    ECU[i].data2 = SPI.transfer(0xFF);
    ECU[i].data3 = SPI.transfer(0xFF);
    ECU[i].data4 = SPI.transfer(0xFF);
    ECU[i].data5 = SPI.transfer(0xFF);
    ECU[i].data6 = SPI.transfer(0xFF);
    ECU[i].data7 = SPI.transfer(0xFF);
    ECU[i].data8 = SPI.transfer(0xFF);

    logLine("Received interrupt on RX0 address: 0x",0);
    CAN.regBitClr(CANINTF,0x01); // Clear interrupt flag in MCP2515

Still, there’s no time between interrupts to do any other processing. ‘logLine’ is just a function that sends the output to serial and an SD card. Is it something within my code that’s not running fast enough or is the SPI just too latent to use within an interrupt in this way? ATM I’ve got it down to just reading one data packet out of the CAN stream that’s sent at 10Hz, but even this isn’t leaving any time to process the data on the fly.

I’m currently toying with the idea of picking up a Due to test the code on and see if the faster clock speeds can handle it, but I don’t want to throw away money if there’s something wrong in the code itself.

You should never try to do serial IO inside an interrupt service routine. Get rid of those logLine calls, and instead set a flag that your main program can pick up and do whatever logging is necessary.

Also, re-enabling interrupts inside an ISR is generally a bad idea, because the ISR will be re-entered if you get another interrupt before you finished processing the last one.

Re-enabling the interrupts was a last ditch effort because I can be certain another interrupt won't come along (until the CAN.setRegister changes the flag in the MCP2515) and the SPI stuff didn't seem to happen without it. I'll drop the logging (since that part was more for debugging so I could see if the interrupt was firing) tomorrow and see if it's any more responsive, thanks.