I am trying to configure CAN interface of i.MX6 to work at the bitrate of 800Kb/s in Kernel 3.10.53. The default clock frequency of CAN driver is 30Mhz which causes bitrate error of 1.3%:
#canconfig can1 bitrate 800000
can1 bitrate: 789473, sample-point: 0.789
flexcan 2094000.flexcan can1: bitrate error 1.3%
More details on this issue and what I have tried comes in the following:
To solve this issue, I have to increase the clock frequency of CAN to be a multiple of 800Khz (I guess?). It seems the clock setup for i.MX6 is done in arch/arm/mach-imx/clk-imx6q.c. The lines related to CAN clock are:
clk[can_root] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
clk[can1_ipg] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
clk[can1_serial] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16);
clk[can2_ipg] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
clk[can2_serial] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20);
One solution I came up with was to change the settings for can_root clock from pll3_60m to pll3_120m. With this change, the canconfig will report the correct bitrate (800Kb instead of ~789Kb) and there is no warning about bitrate error. HOWEVER, the i.MX6 still cannot receive any can packets and goes to BUS-OFF mode.
This result is very similar to what I got in kernel 3.0.35 before, when I did the similar thing in arch/arm/clock.c file. I guess I am missing some architectural limitation in i.MX6 clocking that causes this solution to fail.
What we ended up in kernel 3.0.35 was to set the clock rate explicitly during initialization by:
clk_set_rate(&can_clk_root, 60000000);
This hack solved the issue and i.MX6 could send and receive CAN packets on 800Kb/s successfully.
I am looking for the right approach to increase CAN clock frequency to support 800Kb/s on Kernel 3.10, or a similar hack for this kernel.
Solved! Go to Solution.
Hi Alejandro,
Sorry for the delay. Yes, I solved the issue by setting the CAN_CLK_PODF bits in CSCMR2 to 000000 register:
unsigned long reg;
reg = readl(base + 0x20);
reg &= 0xFFFFFF03;
writel(reg, base + 0x20);
which means the value of divider of parent CAN clock will be 1, so parent clock of can will be 60Mhz. (More information: i.MX6 Reference Manual, 18.6.9 CCM Serial Clock Multiplexer Register 2 (CCM_CSCMR2))
Do you recommend this approach? BTW, what is difference between writel and writel_relaxed? Are there any other variations? Where is this all documented?
Hi,
i am already facing with the same problem in kernel 3.14.28.
i tried also to change the 'can_clk_podf'-Register in 'CCM_CSCMR2' to 0x0, as described here and in Technical ref. man. of imx6q, but
i am still getting the 1.6% bitrate erorr. Surprisingly can-clock seems to be still at 30MHz, even after setting 'can_clk_podf' to 0x00!!!
According to Kernel source linux-imx6/clk-imx6q.c at boundary-imx_3.14.28_1.0.0_ga · boundarydevices/linux-imx6 · GitHub:
clk[IMX6QDL_CLK_CAN_ROOT] | = imx_clk_divider("can_root", | "pll3_60m", | base + 0x20, 2, 6); |
with prev. settings i thought my CAN-Clock should be now at 60Mhz!!
BUT:
--------------------------------------------------------------------------------
#~ ip -d link show can0
2: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN mode DE2
link/can promiscuity 0
can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100
bitrate 789473 sample-point 0.789
tq 66 prop-seg 7 phase-seg1 7 phase-seg2 4 sjw 1
flexcan: tseg1 4..16 tseg2 2..8 sjw 1..4 brp 1..256 brp-inc 1
clock 30000000
--------------------------------------------------------------------------------
am i missing something??
Hi Arash,
We haven't switched to 3.14.28 for the production, but as far as I remember we used the same solution as kernel 3.10 to solve the CAN bitrate issue. We have tested this on Ka-Ro TX6U module (which is based on i.MX6DL). Which module are you using? Also, if you could boot kernel 3.10 on your module, it worth giving it a try to see how this solution works out.
The registry I have mentioned doesn't increase the base clock frequency of CAN. It just sets a clock divider to be 1 (instead of 2).
Here is my CAN1 configuration:
root@imx6qsabresd:~# canconfig can1
can1 bitrate: 800000, sample-point: 0.800
can1 bittiming:
tq: 83, prop-seq: 5 phase-seq1: 6 phase-seq2: 3 sjw: 1, brp: 5
can1 state: ERROR-ACTIVE
can1 restart-ms: 0
can1 ctrlmode: loopback[OFF], listen-only[OFF], tripple-sampling[OFF],one-shot[OFF], berr-reporting[OFF]
can1 clock freq: 60000000
can1 bittiming-constants: name flexcan,
tseg1-min: 4, tseg1-max: 16, tseg2-min: 2, tseg2-max: 8,
sjw-max 4, brp-min: 1, brp-max: 256, brp-inc: 1,
And here is the clock configuration related to CAN:
root@imx6qsabresd:~# cat /sys/kernel/debug/clk/clk_summary | grep can
can_root 1 1 60000000
can2_serial 1 1 60000000
can1_serial 0 0 60000000
can2_ipg 1 1 66000000
can1_ipg 0 0 66000000
Hope this helps,
Hi,
Were you able to solve the problem?
/Alejandro
Hi Alejandro,
Sorry for the delay. Yes, I solved the issue by setting the CAN_CLK_PODF bits in CSCMR2 to 000000 register:
unsigned long reg;
reg = readl(base + 0x20);
reg &= 0xFFFFFF03;
writel(reg, base + 0x20);
which means the value of divider of parent CAN clock will be 1, so parent clock of can will be 60Mhz. (More information: i.MX6 Reference Manual, 18.6.9 CCM Serial Clock Multiplexer Register 2 (CCM_CSCMR2))
Do you recommend this approach? BTW, what is difference between writel and writel_relaxed? Are there any other variations? Where is this all documented?
Hi,
That is great news!!
I found this in the kernel documentation:
readX_relaxed(), writeX_relaxed()
These are similar to readX() and writeX(), but provide weaker memory
ordering guarantees. Specifically, they do not guarantee ordering with
respect to normal memory accesses (e.g. DMA buffers) nor do they guarantee
ordering with respect to LOCK or UNLOCK operations. If the latter is
required, an mmiowb() barrier can be used. Note that relaxed accesses to
the same peripheral are guaranteed to be ordered with respect to each
other.
You can find more detials at:
https://www.kernel.org/doc/Documentation/memory-barriers.txt
/Alejandro
Hi,
Are you able to transmit data correctly? Have you checked that the bitrate is correctly with a scope?
Best Regards,
Alejandro