Teensy CAN Bus IRQ

Status
Not open for further replies.

jblaze

Well-known member
Hello folks,

i try to attach an interrupt to the can bus of a teensy 3.2

during setup:
Code:
interrupts();
NVIC_ENABLE_IRQ(IRQ_CAN_MESSAGE);
attachInterruptVector(IRQ_CAN_MESSAGE,tester);

interrupt routine:
Code:
void tester(){
  Serial.println("CAN");
  return;
}

But nothing happens. There is definitely CAN data coming in, because it works without the interrupt during a loop. Any hints?

Cheers
Hendrik
 
Well, your code snippets are missing certain CAN controller related configuration, which also includes interrupt masks and stuff like that. Also, your ISR (tester()) needs to acknowledge the interrupt source, i.e. has to write to the CANx_IFLAG1 register, otherwise the CAN controller will never raise another CAN message interrupt.
 
Well I just start in "setup()) with
Code:
CANbus.begin();
(without any masks).

Within the ISR I will later isert something like this:

Code:
if(killCAN==true){this->pause();}
if ( CANbus.available() ) { // check if data coming
     while ( CANbus.read(rxmsg) ) {
      // do stuff
     }
    }
return true;
 
So I suppose you are using that FlexCAN library referenced elsewhere in this forum?

There are a few things I noticed while looking through that code:
  • It sets the CAN controller to Rx FIFO mode. That is important for the interrupt mask and flag handling stuff.
  • The read() method seems to fiddle with the BUF5I flag ("Frames available in Rx FIFO"), means the first read will acknowledge the interrupt for the CAN controller. This means you don't have to do that manually. Also try to be fast with the ISR, i.e. shift more complex CAN frame handling out of it. Alternatively, give the ISR a low priority (i.e. high priority number), then other interrupt sources can preempt your CAN ISR.¹
  • The CAN library doesn't seem to touch anything regarding the interrupt mask. After a reset, the CAN controller has all interrupts masked out (see section 44.3.10 in the reference manual² of the K20 SoC / CANx_IMASK1 description; same layout as CANx_IFLAG1, which is described after that one). This means after the initial setup is done, you will need to enable the corresponding interrupts in the CAN controller (either do that in your code or add this to the library code).


¹ In the automotive world, CAN is actually one of the core components with a tight limit on the overall timing, i.e. some messages arrive every 10ms or even faster than that. This sounds like a long time frame, but is not, if you have to catch and process multiple such messages and write something on the bus as well. This in return means that you have to consider whether it is a good idea or not to lower the priority of the CAN IRQs, depending on what else you want to do and whether you have such tight limits on the overall timing. For just packet sniffing it is probably not that much of an issue.

² Check out the datasheet page for the Teensy boards, if you haven't downloaded the (reference) manual, yet.
 
Thanks for your detailed answer.

So for me it is now up to this point.
[*]The CAN library doesn't seem to touch anything regarding the interrupt mask. After a reset, the CAN controller has all interrupts masked out (see section 44.3.10 in the reference manual² of the K20 SoC / CANx_IMASK1 description; same layout as CANx_IFLAG1, which is described after that one). This means after the initial setup is done, you will need to enable the corresponding interrupts in the CAN controller (either do that in your code or add this to the library code).[/list]

I thought I do this already with this piece of code, don't I?

Code:
interrupts();
NVIC_ENABLE_IRQ(IRQ_CAN_MESSAGE);
attachInterruptVector(IRQ_CAN_MESSAGE,tester);
 
I thought I do this already with this piece of code, don't I?

Code:
interrupts();
NVIC_ENABLE_IRQ(IRQ_CAN_MESSAGE);
attachInterruptVector(IRQ_CAN_MESSAGE,tester);
Maybe let me outline this in a bit more detail.

The last line assigns a function to an interrupt/exception. At the lowest level there is an exception/interrupt vector table, which is managed by the library code you are using; in the end, if the CAN message IRQ gets triggered, your function will be called.

The second line enables the CAN message interrupt in the NVIC. This NVIC is there to handle all things exception/interrupt related, i.e. you can assign priorities, you can enable/disable specific exceptions/interrupts etc. The least you have to do is to enable an interrupt in the NVIC so it reaches the actual ARM core.

The first line is in the end nothing else than saying "enable all interrupts", i.e. there are ways to block/unblock close to all interrupts/exceptions for special needs. Except for the core exceptions, "all" means "all these enabled in the NVIC". The others will never make it through the NVIC in the first place.

So far, all that is important and you have it done properly. What is missing? The source of the interrupt! In your case, this is the FlexCAN controller, which has to trigger the interrupt. To do so, you have to the tell the CAN controller to (a) actually trigger interrupts and (b) on what conditions it should trigger an interrupt. This must be configured in the CAN controller itself. Grab the reference manual and check for the part I referenced in my earlier post, read up on the stuff and then configure the CAN controller to your needs. Once that is done, you should see the interrupt actually getting triggered and your tester() function called :)
 
Status
Not open for further replies.
Back
Top