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