Teensy 3.1 and CAN Bus

Would be good if you find a way to make it configurable. Defining a fixed interrupt vector in the library may make it incompatible with other libraries.
pawelsky can you explain what the interrupt vector concern is in more detail? The IRQ driver would provide service routines for can0_ vectors. FLEXCAN_ register access will need to largely move into these routines to avoid critical section bugs. The assumption would be that other libraries would not touch the FLEXCAN_ registers or can0_ vectors.

The simpler possibility would be notification signaling but I don't know and need to research if Arduino/Teensy 3.1 has such a mechanism.
 
pawelsky can you explain what the interrupt vector concern is in more detail? The IRQ driver would provide service routines for can0_ vectors. FLEXCAN_ register access will need to largely move into these routines to avoid critical section bugs. The assumption would be that other libraries would not touch the FLEXCAN_ registers or can0_ vectors.

The simpler possibility would be notification signaling but I don't know and need to research if Arduino/Teensy 3.1 has such a mechanism.

In one of my libraries I had some optional functionality that used pin change interrupts. In order to use that I had to define an interrupt vector (basically a function that is called when an interrupt happens), which was ISR(PCINT0_vect) in my case. Unfortunately any other library that was using the same interrupt vector would complain that it is redefined, even when I wasn't using this functionality. I didn't find any user friendly way to make it user configurable. :(
 
In one of my libraries I had some optional functionality that used pin change interrupts. In order to use that I had to define an interrupt vector (basically a function that is called when an interrupt happens), which was ISR(PCINT0_vect) in my case. Unfortunately any other library that was using the same interrupt vector would complain that it is redefined, even when I wasn't using this functionality. I didn't find any user friendly way to make it user configurable. :(
Ok, thanks. I can imagine that happening with GPIO peripheral change interrupts being commonly used. The can0_ vectors should be safe, there is no use for them outside of a CAN driver.
 
Pretty much fixed my issue with missing messages when logging to SD card. Switching to SDfat from SD.h sorted it.
 
I just spent the past couple of days beating my head against this, and I haven't seen it mentioned anywhere else. The FlexCAN library doesn't work with the CPU Speed set to 72 MHz. Knocking it down to 48 MHz made it work just fine, and I haven't tried other speeds yet.

-Neil
 
I've run all my tests at 96MHz CPU speed (overclock) and never had any issue. I never even tried any slower speed. So the issue is not with the library but more likely with something in your setup.

Jean
 
It is not the setup problem. I guess the library assumes 48MHz bus clock so it will only work for CPU speeds that use this bus clock (so 48, 96 and 144).
 
pawelsky is right, it would appear to be something about the timing in the code.

Using a 500 kbps bitrate, running at 96 MHz (I had avoided it because in my mind, overclock == unstable) and 48 MHz both work just fine. Using teachop's original FlexCAN library and CANTest sketch, there is a frame every 98.67ms according to my bus analyzer.

Using any other CPU speed puts unreadable garbage onto the bus, and nothing comes out the other end. Not even periodic garbage, just a constant stream of highs and lows.
 
Looks like the library is setting the CLKSRC bit in CTRL1, which causes the CAN peripheral to clock from the bus clock.

https://github.com/teachop/FlexCAN_Library/blob/master/FlexCAN.cpp#L20

There's no #ifdef code for different prescaler and other timing changes with different bus clocks, so the code probably only works with the bus clock is 48 MHz, which happens when the CPU is 48 or 96 or 144 MHz.

When the CPU is 72 MHz, the bus clock becomes 36 MHz. When you specify 250 kbit/sec, it's probably generating 187.5 kbit/sec.

An ideal long-term solution is probably using CLKSRC=0, which lets the CAN peripheral run directly from the 16 MHz crystal for an extremely low jitter clock. But this would require changing those prescaler numbers and other timing settings. It's not perfectly clear to me how they all work.

In the short term, the library really ought to have something like this:

Code:
#if F_BUS != 48000000
#error "Only CPU speeds 48, 96 and 144 are supported"
#endif
 
I am fine with that, yes. The driver is stable based on no issue reports, so I don't have plans to make changes unless people request more. Anyone else please freely chime in too with opinions. If you need anything holler or post an issue on the repo. Thanks.
 
Are you thinking TX and RX structure software FIFOs handled in IRQ state, that handshake with the mainline API? This has benefits no doubt if the hardware peripheral buffering isn't working out for applications. Benefits being capacity and in-order issues. I guess now is the time to decide if we need that capability.
 
I am fine with that, yes. The driver is stable based on no issue reports, so I don't have plans to make changes unless people request more. Anyone else please freely chime in too with opinions. If you need anything holler or post an issue on the repo. Thanks.

I've been using the library for quite a while and had no problems. Once the fixed F_BUS clock issue is resolved I would love to see the library as a part of the TeensyDuino.
 
Are you thinking TX and RX structure software FIFOs handled in IRQ state, that handshake with the mainline API? This has benefits no doubt if the hardware peripheral buffering isn't working out for applications. Benefits being capacity and in-order issues. I guess now is the time to decide if we need that capability.
Actually, I was thinking of simply having a function that enables the CAN RX interrupt and assigns a user-defined function pointer to the interrupt vector. That could also be done for TX interrupts.
 
Thinking about it, the interrupt vector has to be an initialization assignment. So the function would only be for enabling/disabling RX/TX interrupts.
 
Ok. I had pondered callback from the IRQ state, piddled around a bit with the idea. The user would almost certainly have code in IRQ state and the mainline sharing data buffers, resulting in hard to understand bugs.

I think it could be rolling fifo buffers of the message structures for tx and rx (like uart service except with structures instead of bytes) with all register access in the IRQ after init. Decided not to go there since the driver is working for applications with the perepheral hardware buffers (ordering warts and all) as is.
 
An ideal long-term solution is probably using CLKSRC=0, which lets the CAN peripheral run directly from the 16 MHz crystal for an extremely low jitter clock.
Paul if you are still listening on this thread I need some teensy advice. I made this change and updated CAN phase timings to work directly from the XTAL. CAN works, yea. However, I needed to do this:
Code:
  OSC0_CR |= OSC_ERCLKEN;
Which I would have thought already done by core teensy code. Without this there is no CAN module input clock (unless CLKSRC is set of course). Does this seem expected, needing to enable OSCERCLK here?

(Regardless I have more research and testing to do with the peripheral running 2.5x slower, particularly at 1M bus rate to be sure there is adequate performance. Maybe I could just have detected the bus speed and redone the timings to match, might try that too.)
 
Back
Top