1 /*
2 * Copyright (c) 2022-2024 Vestas Wind Systems A/S
3 * Copyright (c) 2019 Alexander Wachter
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/drivers/can.h>
9 #include <zephyr/ztest.h>
10 #include <strings.h>
11
12 /**
13 * @addtogroup t_driver_can
14 * @{
15 * @defgroup t_can_timing test_can_timing
16 * @}
17 */
18
19 /**
20 * @brief Defines a set of CAN timing test values
21 */
22 struct can_timing_test {
23 /** Bitrate in bit/s */
24 uint32_t bitrate;
25 /** Desired sample point in permille */
26 uint16_t sp;
27 };
28
29 /**
30 * @brief List of CAN timing values to test.
31 */
32 static const struct can_timing_test can_timing_tests[] = {
33 /* CiA 301 recommended bitrates */
34 #ifdef CONFIG_TEST_ALL_BITRATES
35 { 10000, 875 },
36 #endif /* CONFIG_TEST_ALL_BITRATES */
37 { 20000, 875 },
38 { 50000, 875 },
39 { 125000, 875 },
40 { 250000, 875 },
41 { 500000, 875 },
42 { 800000, 800 },
43 { 1000000, 750 },
44 };
45
46 /**
47 * @brief List of CAN FD data phase timing values to test.
48 */
49 static const struct can_timing_test can_timing_data_tests[] = {
50 /* CiA 601-2 recommended data phase bitrates */
51 { 1000000, 750 },
52 #ifdef CONFIG_TEST_ALL_BITRATES
53 { 2000000, 750 },
54 { 4000000, 750 },
55 { 5000000, 750 },
56 { 8000000, 750 },
57 #endif /* CONFIG_TEST_ALL_BITRATES */
58 };
59
60 /**
61 * @brief Assert that a CAN timing struct matches the specified bitrate
62 *
63 * Assert that the values of a CAN timing struct matches the specified bitrate
64 * for a given CAN controller device instance.
65 *
66 * @param dev pointer to the device structure for the driver instance
67 * @param timing pointer to the CAN timing struct
68 * @param bitrate the CAN bitrate in bit/s
69 */
assert_bitrate_correct(const struct device * dev,struct can_timing * timing,uint32_t bitrate)70 static void assert_bitrate_correct(const struct device *dev, struct can_timing *timing,
71 uint32_t bitrate)
72 {
73 const uint32_t ts = 1 + timing->prop_seg + timing->phase_seg1 + timing->phase_seg2;
74 uint32_t core_clock;
75 uint32_t bitrate_calc;
76 int err;
77
78 zassert_not_equal(timing->prescaler, 0, "prescaler is zero");
79
80 err = can_get_core_clock(dev, &core_clock);
81 zassert_equal(err, 0, "failed to get core CAN clock");
82
83 bitrate_calc = core_clock / timing->prescaler / ts;
84 zassert_equal(bitrate, bitrate_calc, "bitrate mismatch");
85 }
86
87 /**
88 * @brief Assert that a CAN timing struct is within the bounds
89 *
90 * Assert that the values of a CAN timing struct are within the bounds for a
91 * given CAN controller device instance.
92 *
93 * @param dev pointer to the device structure for the driver instance
94 * @param timing pointer to the CAN timing struct
95 */
assert_timing_within_bounds(struct can_timing * timing,const struct can_timing * min,const struct can_timing * max)96 static void assert_timing_within_bounds(struct can_timing *timing,
97 const struct can_timing *min,
98 const struct can_timing *max)
99 {
100 zassert_true(timing->sjw <= max->sjw, "sjw exceeds max");
101 zassert_true(timing->prop_seg <= max->prop_seg, "prop_seg exceeds max");
102 zassert_true(timing->phase_seg1 <= max->phase_seg1, "phase_seg1 exceeds max");
103 zassert_true(timing->phase_seg2 <= max->phase_seg2, "phase_seg2 exceeds max");
104 zassert_true(timing->prescaler <= max->prescaler, "prescaler exceeds max");
105
106 zassert_true(timing->sjw >= min->sjw, "sjw lower than min");
107 zassert_true(timing->prop_seg >= min->prop_seg, "prop_seg lower than min");
108 zassert_true(timing->phase_seg1 >= min->phase_seg1, "phase_seg1 lower than min");
109 zassert_true(timing->phase_seg2 >= min->phase_seg2, "phase_seg2 lower than min");
110 zassert_true(timing->prescaler >= min->prescaler, "prescaler lower than min");
111 }
112
113 /**
114 * @brief Assert that a sample point is within a specified margin
115 *
116 * Assert that values of a CAN timing struct results in a specified sample point
117 * within a given margin.
118 *
119 * @param timing pointer to the CAN timing struct
120 * @param sp sample point in permille
121 * @param sp_margin sample point margin in permille
122 */
assert_sp_within_margin(struct can_timing * timing,uint16_t sp,uint16_t sp_margin)123 static void assert_sp_within_margin(struct can_timing *timing, uint16_t sp, uint16_t sp_margin)
124 {
125 const uint32_t ts = 1 + timing->prop_seg + timing->phase_seg1 + timing->phase_seg2;
126 const uint16_t sp_calc = ((1 + timing->prop_seg + timing->phase_seg1) * 1000) / ts;
127
128 zassert_within(sp, sp_calc, sp_margin,
129 "sample point %d not within calculated sample point %d +/- %d",
130 sp, sp_calc, sp_margin);
131 }
132
133 /**
134 * @brief Test a set of CAN timing values
135 *
136 * Test a set of CAN timing values on a specified CAN controller device
137 * instance.
138 *
139 * @param dev pointer to the device structure for the driver instance
140 * @param test pointer to the set of CAN timing values
141 * returns true if bitrate was supported, false otherwise
142 */
test_timing_values(const struct device * dev,const struct can_timing_test * test,bool data_phase)143 static bool test_timing_values(const struct device *dev, const struct can_timing_test *test,
144 bool data_phase)
145 {
146 const struct can_timing *max = NULL;
147 const struct can_timing *min = NULL;
148 struct can_timing timing = { 0 };
149 int sp_err = -EINVAL;
150 int err;
151
152 printk("testing bitrate %u, sample point %u.%u%%: ",
153 test->bitrate, test->sp / 10, test->sp % 10);
154
155 if (data_phase) {
156 if (IS_ENABLED(CONFIG_CAN_FD_MODE)) {
157 min = can_get_timing_data_min(dev);
158 max = can_get_timing_data_max(dev);
159 sp_err = can_calc_timing_data(dev, &timing, test->bitrate, test->sp);
160 } else {
161 zassert_unreachable("data phase timing test without CAN FD support");
162 }
163 } else {
164 min = can_get_timing_min(dev);
165 max = can_get_timing_max(dev);
166 sp_err = can_calc_timing(dev, &timing, test->bitrate, test->sp);
167 }
168
169 if (sp_err == -ENOTSUP) {
170 printk("bitrate not supported\n");
171 return false;
172 } else {
173 zassert_true(sp_err >= 0, "unknown error %d", sp_err);
174 zassert_true(sp_err <= CONFIG_CAN_SAMPLE_POINT_MARGIN,
175 "sample point error %d too large", sp_err);
176
177 printk("sjw = %u, prop_seg = %u, phase_seg1 = %u, phase_seg2 = %u, prescaler = %u ",
178 timing.sjw, timing.prop_seg, timing.phase_seg1, timing.phase_seg2,
179 timing.prescaler);
180
181 assert_bitrate_correct(dev, &timing, test->bitrate);
182 assert_timing_within_bounds(&timing, min, max);
183 assert_sp_within_margin(&timing, test->sp, CONFIG_CAN_SAMPLE_POINT_MARGIN);
184
185 if (IS_ENABLED(CONFIG_CAN_FD_MODE) && data_phase) {
186 err = can_set_timing_data(dev, &timing);
187 } else {
188 err = can_set_timing(dev, &timing);
189 }
190 zassert_equal(err, 0, "failed to set timing (err %d)", err);
191
192 printk("OK, sample point error %d.%d%%\n", sp_err / 10, sp_err % 10);
193 }
194
195 return true;
196 }
197
198 /**
199 * @brief Test all CAN timing values
200 */
ZTEST_USER(can_timing,test_timing)201 ZTEST_USER(can_timing, test_timing)
202 {
203 const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
204 int count = 0;
205 int i;
206
207 for (i = 0; i < ARRAY_SIZE(can_timing_tests); i++) {
208 if (test_timing_values(dev, &can_timing_tests[i], false)) {
209 count++;
210 }
211 }
212
213 zassert_true(count > 0, "no bitrates supported");
214 }
215
216 /**
217 * @brief Test all CAN timing values for the data phase.
218 */
ZTEST_USER(can_timing,test_timing_data)219 ZTEST_USER(can_timing, test_timing_data)
220 {
221 const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
222 can_mode_t cap;
223 int count = 0;
224 int err;
225 int i;
226
227 err = can_get_capabilities(dev, &cap);
228 zassert_equal(err, 0, "failed to get CAN controller capabilities (err %d)", err);
229
230 if ((cap & CAN_MODE_FD) == 0) {
231 ztest_test_skip();
232 }
233
234 for (i = 0; i < ARRAY_SIZE(can_timing_data_tests); i++) {
235 if (test_timing_values(dev, &can_timing_data_tests[i], true)) {
236 count++;
237 }
238 }
239
240 zassert_true(count > 0, "no data phase bitrates supported");
241 }
242
can_timing_setup(void)243 void *can_timing_setup(void)
244 {
245 const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
246 uint32_t core_clock;
247 int err;
248
249 zassert_true(device_is_ready(dev), "CAN device not ready");
250 k_object_access_grant(dev, k_current_get());
251
252 err = can_get_core_clock(dev, &core_clock);
253 zassert_equal(err, 0, "failed to get core CAN clock");
254
255 printk("testing on device %s @ %u Hz, sample point margin +/-%u permille\n", dev->name,
256 core_clock, CONFIG_CAN_SAMPLE_POINT_MARGIN);
257
258 if (IS_ENABLED(CONFIG_CAN_FD_MODE)) {
259 can_mode_t cap;
260
261 err = can_get_capabilities(dev, &cap);
262 zassert_equal(err, 0, "failed to get CAN controller capabilities (err %d)", err);
263
264 if ((cap & CAN_MODE_FD) != 0) {
265 switch (core_clock) {
266 case MHZ(20):
267 break;
268 case MHZ(40):
269 break;
270 case MHZ(80):
271 break;
272 default:
273 TC_PRINT("Warning: CiA 601-3 recommends a CAN FD core clock of "
274 "20, 40, or 80 MHz for good node interoperability\n");
275 break;
276 }
277 }
278 }
279
280 if (!IS_ENABLED(CONFIG_TEST_ALL_BITRATES)) {
281 TC_PRINT("Warning: Testing limited selection of bitrates "
282 "(CONFIG_TEST_ALL_BITRATES=n)\n");
283 }
284
285 return NULL;
286 }
287
288 ZTEST_SUITE(can_timing, NULL, can_timing_setup, NULL, NULL, NULL);
289