How can I set the hardware CAN ID mask on MX53 under Linux?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How can I set the hardware CAN ID mask on MX53 under Linux?

Jump to solution
6,427 Views
jarodnan
Contributor I

I'm building a system that doing some DAQ work and a CAN masseges monitoring. I'm wanting to reduce the load of the CPU in order not to disturb the DAQ work too much. So I want to set the hardware CAN ID mask to reduce the interrupts.

I'm using the 2.6.35 Linux kernel, but I can't find anyway to set this up.

Labels (3)
0 Kudos
1 Solution
4,592 Views
TomE
Specialist II

Is that kernel version using SocketCAN?

http://en.wikipedia.org/wiki/Socketcan

If it is, you set the filters with something like:

struct can_filter rfilter[1];

rfilter[0].can_id   = stdid;

rfilter[0].can_mask = CAN_EFF_FLAG|CAN_SFF_MASK;

rc=setsockopt(skt, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

But, depending on the CAN driver, that may not translate into hardware filters.

You'll have to read the source of the CAN driver to see if it has any code to access any of the hardware filter registers.

If it doesn't, you may need to add some yourself.

The problem with these drivers is that they're buried under the "networking" system, and are VERY hard to send commands to directly as you're not opening the driver directly.

You may need to add code to get to them via /proc or /sys or some such.

Otherwise, you should add code (like I did) to start using the different interrupt priorities that are available in the hardware. I changed the levels in my kernel to give CAN priority over the FEC.

Tom

View solution in original post

0 Kudos
12 Replies
4,593 Views
TomE
Specialist II

Is that kernel version using SocketCAN?

http://en.wikipedia.org/wiki/Socketcan

If it is, you set the filters with something like:

struct can_filter rfilter[1];

rfilter[0].can_id   = stdid;

rfilter[0].can_mask = CAN_EFF_FLAG|CAN_SFF_MASK;

rc=setsockopt(skt, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

But, depending on the CAN driver, that may not translate into hardware filters.

You'll have to read the source of the CAN driver to see if it has any code to access any of the hardware filter registers.

If it doesn't, you may need to add some yourself.

The problem with these drivers is that they're buried under the "networking" system, and are VERY hard to send commands to directly as you're not opening the driver directly.

You may need to add code to get to them via /proc or /sys or some such.

Otherwise, you should add code (like I did) to start using the different interrupt priorities that are available in the hardware. I changed the levels in my kernel to give CAN priority over the FEC.

Tom

0 Kudos
4,592 Views
jarodnan
Contributor I

Thanks Tom.

I've look into the source code for some while and will try to do that.

0 Kudos
4,592 Views
TomE
Specialist II

What is the "DAQ Work" you're doing? Do you mean "Data Acquisition"? How time critical is it?

How fast is the CAN bus? Do you KNOW the interrupt load is a problem? It may not be worth worrying about.

For reference, with the MX53 FlexCAN drivers, the worst that can happen (apart from a really 100% full CAN bus which is unusual) is to have a DISCONNECTED CAN bus, and then have software try and send a message. The FlexCAN driver has all interrupts on, so it unnecessarily interrupts for every time it tries to resent the message, which is as fast as it can. That's about 30,900 interrupts/second on a 1MBit CAN bus.

That steals about 15% of our 800MHz i.MX53 CPU. Two buses doing the same thing take 33%.

If you never send a CAN message then this won't happen to you.


Automotive CAN buses are seldom 1MBit, and they're seldom full. They should run pretty conservatively. So the loading on your CPU may only be a few percent.

You shouldn't be pressing the CPU so hard that this matters, and the interrupts are all pretty short so it shouldn't delay you other code by much. Traffic on Ethernet is a far worse problem. These error interrupts do schedule NAPI processes though.

> I've look into the source code for some while

The chip is quite powerful and flexible, but none of this is made available by the driver. The only reference to the filter registers in our Linux 3.4 source is:

drivers/net/can/flexcan.c:

/* acceptance mask/acceptance code (accept everything) */

flexcan_write(0x0, &regs->rxgmask);

flexcan_write(0x0, &regs->rx14mask);

flexcan_write(0x0, &regs->rx15mask);

You would have a lot of trouble trying to make it any smarter, as I seem to remember that the "filter matching" is performed in a totally separate piece of code somewhere. The purpose of the "filters" is to control the distribution of the received CAN messages to the appropriate user socket. It is not there to filter at the hardware level.

Tom

4,592 Views
Firos
Contributor I

Hi

You may refer the attached patch to be able to use the advanced feature of Rx FIFO filtering provided by the FlexCAN controller. We have used just 10 filters but the method allows upto filtering 256 IDs.

Linux Kernel: 3.10.17, SoC: IMX6Q

-

Firos

0 Kudos
4,592 Views
moowonlee
Contributor II

I used patch you provided. but I received all can id from CAN generator. :smileyconfused:

My linux version is linux-3.10.53 and My SOC is i.mx6sx .

How do i use filtering ?

0 Kudos
4,592 Views
abhi_nc
Contributor I

Hey,

Did you find any solution for HW filters?

0 Kudos
4,592 Views
TomE
Specialist II

I see I've been here before, six years ago.

First, why do you need it? Can is "slow" compared to the speed of the CPU. I can't think of any reason why you might need filtering, unless you're trying to power the CPU right down and only have it wake up on specific CAN messages. In which case "power down and wake on specific message" is a different problem.

CAN Hardware Filters and Linux aren't a good fit. There's a large variation in different CAN hardware and what it can and can't do, and the "philosophy" of Linux is that your program shouldn't affect what any other program on the system is doing. And forcing hardware filters would certainly affect other programs.

The "best" way to use hardware filters would be to have the calls to register reception on specific CAN IDs passed all the way down to the driver so it can apply filters there. I don't think there's any pathway from the "standard CAN demultiplexing code" to the drivers, so this is a major architectural change that might need to be added to the whole system to support. Then the driver would have to make a "best effort" until it gets too many individual addresses for the hardware filters, then it could try to overlap/combine them until falling back to "transparent". Tricky and difficult and somewhat unpredictable. And with modern GHz CPUs, why bother?

The "usual hack" would be to add a new and custom IOCTL that user code can use to call down to the driver to force filtering.

The patch provided be Firos doesn't do either of these. It does this (together with code to load up the registers):

+/* populate here the CAN IDs that are only to be received */
+u32 can_ids_rx_filtering[] = {
+ 0x101,
+ 0x29a,
+ 0x102,
+ 0x5da,
+ 0x66a,
+ 0x212,
+ 0x186,
+ 0x623,
+ 0x7f0,
+ 0x445
+};

So you have to populate that array with the CAN IDs you want to receive and then compile a new driver, and potentially a new kernel and use that. Not flexible, but OK for a specific embedded device.

Tom

0 Kudos
4,592 Views
TomE
Specialist II

What version of Linux is that patch for?

I can tell by reading it that it isn't for 2.6.35, which is the version the OP was asking about.

The patch looks to be for a later version, introduced in 2.6.38 and continuing through through 3 and 4 releases. But none of them were ever supported by Freescale on the i.MX53.

Tom

0 Kudos
4,592 Views
jarodnan
Contributor I

Great thanks to your reply with details and explanations, Tom.

As you said, my concerns about the CAN interrupts are mostly unnecessary.

I've checked out again, the CAN baudrate is 250k, about 50 frames per second. I should not worry about the load.

My DAQ work does mean Data Acquisition. It's acquiring data from an FPGA via UART. It can be up to 80k bytes per second. So I tried to enbale DMA on the UART, but I've got some strange things. Can you give me any advice?

Strange problem while using UART with DMA

0 Kudos
4,592 Views
TomE
Specialist II

> It's acquiring data from an FPGA via UART. It can be up to 80k bytes per second.

That's not a "standard" baud rate then. Is that the average or maximum burst data rate? I'll assume burst, so 12.5us/byte. The UART FIFOs are 32 byte, so they'll overflow in 400us.

400us isn't very long. It is a hugely long time as it is 320,000 CPU instructions of time, but Linux can decide to do something else for that long.  If you're unlucky with the other drivers then Linux could delay servicing the UARTs for that long.

Check the UART drivers and see if they're reading in the interrupt routine or delaying reading to NAPI. I've been trying to find the relevant UART sources on free-electrons, but the linkage is so complicated I can't find the correct source file, or even the register definitions to track it down with. ... Finally found it by searching for "ONEMS":

http://lxr.free-electrons.com/source/drivers/serial/imx.c?v=2.6.28

Good. The receive interrupt empties the FIFO directly. That's good.

> Can you give me any advice?

Not really, I've never used DMA on these things.

You're listing in your other post that you're getting data, but now what the data IS. It would be easier to analyse if you sent a recognizable pattern of bytes like "1 2 3 4 5 6 ... 255" and then saw which bytes came out when at the other end.

DMA on serial ports is a pain. It only really works if you have a protocol where the other end sends a short packet saying "I want to send you 500 bytes" that you receive into the FIFO and then it waits for you to send a message back saying "I've set up a 500-byte DMA transfer, so go for it!". Then when the DMA transfer completes you know you have all the data. If you're getting "random data" or a continuous stream it is a lot harder. Best avoided (and use interrupts) if you can.

You're probably going to have interrupt overheads when the DMA buffer runs out unless you can chain them. So you'll have an interrupt latency happening then, and giving infrequent dropouts rather than frequent ones, making problems harder to diagnose without actually solving them. Then you never know when the data has stopped arriving to know where valid data is in the buffer. Then you've got the "dirty buffer" problem, requiring uncached memory or cache flushes (which may take 100us to complete on an MX53 due to the large L2 cache).

Tom

0 Kudos
4,592 Views
jarodnan
Contributor I

> That's not a "standard" baud rate then. Is that the average or maximum burst data rate? I'll assume burst, so 12.5us/byte. The UART FIFOs are 32 byte, so they'll overflow in 400us.

I meant the load of UART is up to 80K bytes per second transmission, not the baudrate. I can used the standard 1M bps baudrate.

> Then when the DMA transfer completes you know you have all the data. If you're getting "random data" or a continuous stream it is a lot harder. Best avoided (and use interrupts) if you can.

The FPGA is reading some AD and DI waveforms and transmit to the MX53. The waveform data can be up to 80K bytes per second. Because of the on chip resources, the waveform data is sent in packets. Packet count per second and size are determined. I think DMA is suitable for this.

> You're probably going to have interrupt overheads when the DMA buffer runs out unless you can chain them.

In a DMA interrupt, the data in the DMA buffer is carried to the tty buffer, so the DMA buffer is not likely to run out so often with enough tty buffer. The MX53 has an SDMA engine with a dedicated cpu to handle the peripheral interrupts. Only in the DMA interrupt, it's MX53's turn to handle the data. It looks like extending the UART's hardware buffer.

> Then you never know when the data has stopped arriving to know where valid data is in the buffer.

The MX53 has a DMA aging timer to solve the problem. The driver has already included.

Aging DMA Timer Enable. Enables/Disables the receive DMA request dma_req_rx for the aging timer interrupt (triggered with AGTIM flag in USR1[8]).

Ageing Timer Interrupt Flag. Indicates that data in the RxFIFO has been idle for a time of 8 character lengths (where a character length consists of 7 or 8 bits, depending on the setting of the WS bit in UCR2, with the bit time corresponding to the baud rate setting) and FIFO data level is less than RxFIFO threshold level (RXTL in the UFCR). Clear by writing a 1 to it.

After reading the replies of my other thread, I realize that I should get to understand exactly how to used the UART's CTS/RTS signal in DCE mode.

0 Kudos
4,592 Views
jamesbone
NXP TechSupport
NXP TechSupport

Great Jarod,

Let us know if you still have the issue.

0 Kudos