• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_can_drv.h"
9 #include <assert.h>
10 
11 /***********************************************************************************************************************
12  *
13  *  Definitions
14  *
15  **********************************************************************************************************************/
16 #define TSEG1_MIN_FOR_CAN2_0 (2U)
17 #define TSEG1_MAX_FOR_CAN2_0 (65U)
18 
19 #define TSEG1_MIN_FOR_CANFD_NORMINAL (2U)
20 #define TSEG1_MAX_FOR_CANFD_NORMINAL (65U)
21 
22 #define TSEG1_MIN_FOR_CANFD_DATA (2U)
23 #define TSEG1_MAX_FOR_CANFD_DATA (17U)
24 
25 #define TSEG2_MIN_FOR_CAN2_0 (1U)
26 #define TSEG2_MAX_FOR_CAN2_0 (8U)
27 
28 #define TSEG2_MIN_FOR_CANFD_NORMINAL (1U)
29 #define TSEG2_MAX_FOR_CANFD_NORMINAL (32U)
30 
31 #define TSEG2_MIN_FOR_CANFD_DATA (1U)
32 #define TSEG2_MAX_FOR_CANFD_DATA (8U)
33 
34 #define TSJW_MIN_FOR_CAN2_0 (1U)
35 #define TSJW_MAX_FOR_CAN2_0 (16U)
36 
37 #define TSJW_MIN_FOR_CANFD_NORMINAL (1U)
38 #define TSJW_MAX_FOR_CANFD_NORMINAL (16U)
39 
40 #define TSJW_MIN_FOR_CANFD_DATA (1U)
41 #define TSJW_MAX_FOR_CANFD_DATA (8U)
42 
43 #define NUM_TQ_MIN_FOR_CAN2_0 (8U)
44 #define NUM_TQ_MAX_FOR_CAN2_0 (TSEG1_MAX_FOR_CAN2_0 + TSEG2_MAX_FOR_CAN2_0)
45 
46 #define NUM_TQ_MIN_FOR_CANFD_NOMINAL (8U)
47 #define NUM_TQ_MAX_FOR_CANFD_NOMINAL (TSEG1_MAX_FOR_CANFD_NORMINAL + TSEG2_MAX_FOR_CANFD_NORMINAL)
48 
49 #define NUM_TQ_MIN_FOR_CANFD_DATA (8U)
50 #define NUM_TQ_MAX_FOR_CANFD_DATA (TSEG1_MAX_FOR_CANFD_DATA + TSEG2_MAX_FOR_CANFD_DATA)
51 
52 #define MIN_TQ_MUL_PRESCALE (10U)
53 
54 #define NUM_PRESCALE_MAX (256U)
55 
56 #define CAN_FILTER_INDEX_MAX (15U)
57 #define CAN_FILTER_NUM_MAX (16U)
58 
59 #define PRESCALER_MAX (256U)
60 
61 #define CAN_TIMEOUT_CNT (0xFFFFFFUL)
62 
63 #define CAN_SAMPLEPOINT_MIN (750U)
64 #define CAN_SAMPLEPOINT_MAX (875U)
65 
66 
67 #define CAN_DEFAULT_FILTER_SETTING {0, can_filter_id_mode_both_frames, true, 0, (1UL << 29) - 1U }
68 
69 /*
70  * @brief CAN bit-timing table
71  */
72 typedef struct {
73     uint8_t tq_min;
74     uint8_t tq_max;
75     uint8_t seg1_min;
76     uint8_t seg1_max;
77     uint8_t seg2_min;
78     uint8_t seg2_max;
79     uint8_t sjw_min;
80     uint8_t sjw_max;
81     uint8_t min_diff_seg1_minus_seg2;
82 } can_bit_timing_table_t;
83 
84 /**
85  * @brief CAN bit timing list for all supported bit timing modes
86  */
87 static const can_bit_timing_table_t s_can_bit_timing_tbl[3] = {
88         {
89                 .tq_min = NUM_TQ_MIN_FOR_CAN2_0,
90                 .tq_max = NUM_TQ_MAX_FOR_CAN2_0,
91                 .seg1_min = TSEG1_MIN_FOR_CAN2_0,
92                 .seg1_max = TSEG1_MAX_FOR_CAN2_0,
93                 .seg2_min = TSEG2_MIN_FOR_CAN2_0,
94                 .seg2_max = TSEG2_MAX_FOR_CAN2_0,
95                 .sjw_min = TSJW_MIN_FOR_CAN2_0,
96                 .sjw_max = TSJW_MAX_FOR_CAN2_0,
97                 .min_diff_seg1_minus_seg2 = 2,
98         },
99         {
100                 .tq_min = NUM_TQ_MIN_FOR_CANFD_NOMINAL,
101                 .tq_max = NUM_TQ_MAX_FOR_CANFD_NOMINAL,
102                 .seg1_min = TSEG1_MIN_FOR_CANFD_NORMINAL,
103                 .seg1_max = TSEG1_MAX_FOR_CANFD_NORMINAL,
104                 .seg2_min = TSEG2_MIN_FOR_CANFD_NORMINAL,
105                 .seg2_max = TSEG2_MAX_FOR_CANFD_NORMINAL,
106                 .sjw_min = TSJW_MIN_FOR_CANFD_NORMINAL,
107                 .sjw_max = TSJW_MAX_FOR_CANFD_NORMINAL,
108                 .min_diff_seg1_minus_seg2 = 2,
109         },
110         {
111                 .tq_min = NUM_TQ_MIN_FOR_CANFD_DATA,
112                 .tq_max = NUM_TQ_MAX_FOR_CANFD_DATA,
113                 .seg1_min = TSEG1_MIN_FOR_CANFD_DATA,
114                 .seg1_max = TSEG1_MAX_FOR_CANFD_DATA,
115                 .seg2_min = TSEG2_MIN_FOR_CANFD_DATA,
116                 .seg2_max = TSEG2_MAX_FOR_CANFD_DATA,
117                 .sjw_min = TSJW_MIN_FOR_CANFD_DATA,
118                 .sjw_max = TSJW_MAX_FOR_CANFD_DATA,
119                 .min_diff_seg1_minus_seg2 = 1,
120         }
121 };
122 
123 /***********************************************************************************************************************
124  *
125  *  Prototypes
126  */
127 static uint32_t find_closest_prescaler(uint32_t num_tq_mul_prescaler, uint32_t start_prescaler,
128                                        uint32_t max_tq, uint32_t min_tq);
129 
130 static uint8_t can_get_data_words_from_dlc(uint32_t dlc);
131 
132 static void can_fill_tx_buffer(CAN_Type *base, const can_transmit_buf_t *message);
133 
134 
135 /***********************************************************************************************************************
136  *
137  *  Codes
138  */
find_closest_prescaler(uint32_t num_tq_mul_prescaler,uint32_t start_prescaler,uint32_t max_tq,uint32_t min_tq)139 static uint32_t find_closest_prescaler(uint32_t num_tq_mul_prescaler, uint32_t start_prescaler,
140                                        uint32_t max_tq, uint32_t min_tq)
141 {
142     bool has_found = false;
143 
144     uint32_t prescaler = start_prescaler;
145 
146     while (!has_found) {
147 
148         if ((num_tq_mul_prescaler / prescaler > max_tq) || (num_tq_mul_prescaler % prescaler != 0)) {
149             ++prescaler;
150             continue;
151         } else {
152             uint32_t tq = num_tq_mul_prescaler / prescaler;
153             if (tq * prescaler == num_tq_mul_prescaler) {
154                 has_found = true;
155                 break;
156             } else if (tq < min_tq) {
157                 has_found = false;
158                 break;
159             } else {
160                 ++prescaler;
161             }
162         }
163     }
164 
165     return has_found ? prescaler : 0U;
166 }
167 
168 
can_calculate_bit_timing(uint32_t src_clk_freq,can_bit_timing_option_t option,uint32_t baudrate,uint16_t samplepoint_min,uint16_t samplepoint_max,can_bit_timing_param_t * timing_param)169 hpm_stat_t can_calculate_bit_timing(uint32_t src_clk_freq, can_bit_timing_option_t option, uint32_t baudrate,
170                               uint16_t samplepoint_min, uint16_t samplepoint_max,
171                               can_bit_timing_param_t *timing_param)
172 {
173     hpm_stat_t status = status_invalid_argument;
174     do {
175         if ((option > can_bit_timing_canfd_data) || (baudrate == 0U) ||
176             (src_clk_freq / baudrate < MIN_TQ_MUL_PRESCALE) || (timing_param == NULL)) {
177             break;
178         }
179 
180         const can_bit_timing_table_t *tbl = &s_can_bit_timing_tbl[(uint8_t) option];
181 
182         /* According to the CAN specification 2.0,
183          * the Tq must be in range specified in the above CAN bit-timing table
184          */
185         if (src_clk_freq / baudrate < tbl->tq_min) {
186             break;
187         }
188 
189         uint32_t num_tq_mul_prescaler = src_clk_freq / baudrate;
190         uint32_t start_prescaler = 1U;
191         uint32_t num_seg1, num_seg2;
192         bool has_found = false;
193 
194         /* Find out the minimum prescaler */
195         uint32_t current_prescaler;
196         while (!has_found) {
197             current_prescaler = find_closest_prescaler(num_tq_mul_prescaler, start_prescaler,
198                                                        tbl->tq_max,
199                                                        tbl->tq_min);
200             if ((current_prescaler < start_prescaler) || (current_prescaler > NUM_PRESCALE_MAX)) {
201                 break;
202             }
203             uint32_t num_tq = num_tq_mul_prescaler / current_prescaler;
204 
205             num_seg2 = (num_tq - tbl->min_diff_seg1_minus_seg2) / 2U;
206             num_seg1 = num_tq - num_seg2;
207             while (num_seg2 > tbl->seg2_max) {
208                 num_seg2--;
209                 num_seg1++;
210             }
211 
212             /* Recommended sample point is 75% - 87.5% */
213             while ((num_seg1 * 1000U) / num_tq < samplepoint_min) {
214                 ++num_seg1;
215                 --num_seg2;
216             }
217 
218             if ((num_seg1 * 1000U) / num_tq > samplepoint_max) {
219                 break;
220             }
221 
222             if ((num_seg2 >= tbl->seg2_min) && (num_seg1 <= tbl->seg1_max)) {
223                 has_found = true;
224             } else {
225                 start_prescaler = current_prescaler + 1U;
226             }
227         }
228 
229         if (has_found) {
230             uint32_t num_sjw = MIN(tbl->sjw_max, num_seg2);
231             timing_param->num_seg1 = num_seg1;
232             timing_param->num_seg2 = num_seg2;
233             timing_param->num_sjw = num_sjw;
234             timing_param->prescaler = current_prescaler;
235             status = status_success;
236         }
237     } while (false);
238 
239     return status;
240 }
241 
242 
can_set_bit_timing(CAN_Type * base,can_bit_timing_option_t option,uint32_t src_clk_freq,uint32_t baudrate,uint16_t samplepoint_min,uint16_t samplepoint_max)243 hpm_stat_t can_set_bit_timing(CAN_Type *base, can_bit_timing_option_t option,
244                               uint32_t src_clk_freq, uint32_t baudrate,
245                               uint16_t samplepoint_min, uint16_t samplepoint_max)
246 {
247     hpm_stat_t status = status_invalid_argument;
248 
249     do {
250         if (base == NULL) {
251             break;
252         }
253 
254         can_bit_timing_param_t timing_param;
255         status = can_calculate_bit_timing(src_clk_freq, option, baudrate, samplepoint_min, samplepoint_max, &timing_param);
256 
257         if (status == status_success) {
258             if (option < can_bit_timing_canfd_data) {
259                 base->S_PRESC = CAN_S_PRESC_S_PRESC_SET(timing_param.prescaler - 1U) | CAN_S_PRESC_S_SEG_1_SET(timing_param.num_seg1 - 2U) |
260                                 CAN_S_PRESC_S_SEG_2_SET(timing_param.num_seg2 - 1U) | CAN_S_PRESC_S_SJW_SET(timing_param.num_sjw - 1U);
261             } else {
262                 base->F_PRESC = CAN_F_PRESC_F_PRESC_SET(timing_param.prescaler - 1U) | CAN_F_PRESC_F_SEG_1_SET(timing_param.num_seg1 - 2U) |
263                                 CAN_F_PRESC_F_SEG_2_SET(timing_param.num_seg2 - 1U) | CAN_F_PRESC_F_SJW_SET(timing_param.num_sjw - 1U);
264 
265             }
266             status = status_success;
267         }
268 
269     } while (false);
270 
271     return status;
272 }
273 
can_set_filter(CAN_Type * base,const can_filter_config_t * config)274 hpm_stat_t can_set_filter(CAN_Type *base, const can_filter_config_t *config)
275 {
276     hpm_stat_t status = status_invalid_argument;
277 
278     do {
279         if ((base == NULL) || (config == NULL)) {
280             break;
281         }
282         if (config->index > CAN_FILTER_INDEX_MAX) {
283             status = status_can_filter_index_invalid;
284             break;
285         }
286 
287         /* Configure acceptance code */
288         base->ACFCTRL = CAN_ACFCTRL_ACFADR_SET(config->index);
289         base->ACF = CAN_ACF_CODE_MASK_SET(config->code);
290 
291         /* Configure acceptance mask */
292         uint32_t acf_value = CAN_ACF_CODE_MASK_SET(config->mask);
293         if (config->id_mode == can_filter_id_mode_standard_frames) {
294             acf_value |= CAN_ACF_AIDEE_MASK;
295         } else if (config->id_mode == can_filter_id_mode_extended_frames) {
296             acf_value |= CAN_ACF_AIDEE_MASK | CAN_ACF_AIDE_MASK;
297         } else {
298             /* Treat it as the default mode */
299             acf_value |= 0;
300         }
301 
302         base->ACFCTRL = CAN_ACFCTRL_SELMASK_MASK | CAN_ACFCTRL_ACFADR_SET(config->index);
303         base->ACF = acf_value;
304 
305         if (config->enable) {
306             base->ACF_EN |= (1U << config->index);
307         } else {
308             base->ACF_EN &= (uint16_t) ~(1U << config->index);
309         }
310         status = status_success;
311     } while (false);
312 
313     return status;
314 }
315 
can_get_data_words_from_dlc(uint32_t dlc)316 static uint8_t can_get_data_words_from_dlc(uint32_t dlc)
317 {
318     uint32_t copy_words = 0;
319 
320     dlc &= 0xFU;
321     if (dlc <= 8U) {
322         copy_words = (dlc + 3U) / sizeof(uint32_t);
323     } else {
324         switch (dlc) {
325         case can_payload_size_12:
326             copy_words = 3U;
327             break;
328         case can_payload_size_16:
329             copy_words = 4U;
330             break;
331         case can_payload_size_20:
332             copy_words = 5U;
333             break;
334         case can_payload_size_24:
335             copy_words = 6U;
336             break;
337         case can_payload_size_32:
338             copy_words = 8U;
339             break;
340         case can_payload_size_48:
341             copy_words = 12U;
342             break;
343         case can_payload_size_64:
344             copy_words = 16U;
345             break;
346         default:
347             /* Code should never touch here */
348             break;
349         }
350     }
351 
352     return copy_words;
353 }
354 
can_fill_tx_buffer(CAN_Type * base,const can_transmit_buf_t * message)355 static void can_fill_tx_buffer(CAN_Type *base, const can_transmit_buf_t *message)
356 {
357     base->TBUF[0] = message->buffer[0];
358     base->TBUF[1] = message->buffer[1];
359 
360     uint32_t copy_words = can_get_data_words_from_dlc(message->dlc);
361     for (uint32_t i = 0U; i < copy_words; i++) {
362         base->TBUF[2U + i] = message->buffer[2U + i];
363     }
364 }
365 
can_send_message_blocking(CAN_Type * base,const can_transmit_buf_t * message)366 hpm_stat_t can_send_message_blocking(CAN_Type *base, const can_transmit_buf_t *message)
367 {
368     hpm_stat_t status = status_invalid_argument;
369 
370     do {
371 
372         if ((base == NULL) || (message == NULL)) {
373             break;
374         }
375 
376         status = status_success;
377         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
378 
379         can_fill_tx_buffer(base, message);
380 
381         /* Wait until STB is not full */
382         int32_t timeout_cnt = CAN_TIMEOUT_CNT;
383         while (CAN_CMD_STA_CMD_CTRL_TSSTAT_GET(base->CMD_STA_CMD_CTRL) == CAN_STB_IS_FULL) {
384             timeout_cnt--;
385             if (timeout_cnt <= 0) {
386                 status = status_timeout;
387                 break;
388             }
389         }
390         if (status != status_success) {
391             break;
392         }
393 
394         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TSNEXT_MASK | CAN_CMD_STA_CMD_CTRL_TSONE_MASK;
395         timeout_cnt = CAN_TIMEOUT_CNT;
396         while (CAN_CMD_STA_CMD_CTRL_TSSTAT_GET(base->CMD_STA_CMD_CTRL) != CAN_STB_IS_EMPTY) {
397             timeout_cnt--;
398             if (timeout_cnt <= 0) {
399                 status = status_timeout;
400                 break;
401             }
402         }
403 
404     } while (false);
405 
406     return status;
407 }
408 
can_send_high_priority_message_blocking(CAN_Type * base,const can_transmit_buf_t * message)409 hpm_stat_t can_send_high_priority_message_blocking(CAN_Type *base, const can_transmit_buf_t *message)
410 {
411     hpm_stat_t status = status_invalid_argument;
412 
413     do {
414         HPM_BREAK_IF((base == NULL) || (message == NULL));
415         status = status_success;
416 
417         /* Select the high-priority buffer */
418         base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
419 
420         can_fill_tx_buffer(base, message);
421 
422         /* Send the data out */
423         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TPE_MASK;
424         /* Wait until the data is sent out */
425         int32_t timeout_cnt = CAN_TIMEOUT_CNT;
426         while (IS_HPM_BITMASK_SET(base->CMD_STA_CMD_CTRL, CAN_CMD_STA_CMD_CTRL_TPE_MASK)) {
427             timeout_cnt--;
428             if (timeout_cnt <= 0) {
429                 status = status_timeout;
430                 break;
431             }
432         }
433     } while (false);
434 
435     return status;
436 }
437 
can_send_message_nonblocking(CAN_Type * base,const can_transmit_buf_t * message)438 hpm_stat_t can_send_message_nonblocking(CAN_Type *base, const can_transmit_buf_t *message)
439 {
440     hpm_stat_t status = status_invalid_argument;
441 
442     do {
443 
444         if ((base == NULL) || (message == NULL)) {
445             break;
446         }
447 
448         if (CAN_CMD_STA_CMD_CTRL_TSSTAT_GET(base->CMD_STA_CMD_CTRL) == CAN_STB_IS_FULL) {
449             status = status_can_tx_fifo_full;
450             break;
451         }
452 
453         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
454         can_fill_tx_buffer(base, message);
455         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TSNEXT_MASK | CAN_CMD_STA_CMD_CTRL_TSONE_MASK;
456 
457         status = status_success;
458 
459     } while (false);
460 
461     return status;
462 }
463 
can_send_high_priority_message_nonblocking(CAN_Type * base,const can_transmit_buf_t * message)464 hpm_stat_t can_send_high_priority_message_nonblocking(CAN_Type *base, const can_transmit_buf_t *message)
465 {
466     hpm_stat_t status = status_invalid_argument;
467 
468     do {
469         HPM_BREAK_IF((base == NULL) || (message == NULL));
470         status = status_success;
471 
472         if (IS_HPM_BITMASK_SET(base->CMD_STA_CMD_CTRL, CAN_CMD_STA_CMD_CTRL_TPE_MASK)) {
473             status = status_can_tx_fifo_full;
474             break;
475         }
476         /* Select the high-priority buffer */
477         base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
478 
479         can_fill_tx_buffer(base, message);
480 
481         /* Send the data out */
482         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TPE_MASK;
483     } while (false);
484 
485     return status;
486 }
487 
can_receive_message_blocking(CAN_Type * base,can_receive_buf_t * message)488 hpm_stat_t can_receive_message_blocking(CAN_Type *base, can_receive_buf_t *message)
489 {
490     hpm_stat_t status = status_invalid_argument;
491 
492     do {
493         HPM_BREAK_IF((base == NULL) || (message == NULL));
494 
495         while (CAN_CMD_STA_CMD_CTRL_RSTAT_GET(base->CMD_STA_CMD_CTRL) == CAN_RXBUF_IS_EMPTY) {
496 
497         }
498 
499         /* Get the first 2 words (including CAN ID, Data length and other control bits) */
500         message->buffer[0] = base->RBUF[0];
501         message->buffer[1] = base->RBUF[1];
502 
503         if (message->error_type != 0U) {
504             switch (message->error_type) {
505             case 1:
506                 status = status_can_bit_error;
507                 break;
508             case 2:
509                 status = status_can_form_error;
510                 break;
511             case 3:
512                 status = status_can_stuff_error;
513                 break;
514             case 4:
515                 status = status_can_ack_error;
516                 break;
517             case 5:
518                 status = status_can_crc_error;
519                 break;
520             default:
521                 status = status_can_other_error;
522                 break;
523             }
524             break;
525         }
526 
527         if (message->remote_frame == 0U) {
528             uint32_t copy_words = can_get_data_words_from_dlc(message->dlc);
529 
530             for (uint32_t i = 0; i < copy_words; i++) {
531                 message->buffer[2U + i] = base->RBUF[2U + i];
532             }
533         }
534         /* Release the current buffer */
535         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_RREL_MASK;
536 
537         status = status_success;
538 
539     } while (false);
540 
541     return status;
542 }
543 
can_read_received_message(CAN_Type * base,can_receive_buf_t * message)544 hpm_stat_t can_read_received_message(CAN_Type *base, can_receive_buf_t *message)
545 {
546     hpm_stat_t status;
547 
548     assert((base != NULL) && (message != NULL));
549 
550     do {
551         /* Get the first 2 words (including CAN ID, Data length and other control bits) */
552         message->buffer[0] = base->RBUF[0];
553         message->buffer[1] = base->RBUF[1];
554 
555         if (message->error_type != 0U) {
556             switch (message->error_type) {
557             case 1:
558                 status = status_can_bit_error;
559                 break;
560             case 2:
561                 status = status_can_form_error;
562                 break;
563             case 3:
564                 status = status_can_stuff_error;
565                 break;
566             case 4:
567                 status = status_can_ack_error;
568                 break;
569             case 5:
570                 status = status_can_crc_error;
571                 break;
572             default:
573                 status = status_can_other_error;
574                 break;
575             }
576             break;
577         }
578 
579         if (message->remote_frame == 0U) {
580             uint32_t copy_words = can_get_data_words_from_dlc(message->dlc);
581 
582             for (uint32_t i = 0; i < copy_words; i++) {
583                 message->buffer[2U + i] = base->RBUF[2U + i];
584             }
585         }
586         /* Release the current buffer */
587         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_RREL_MASK;
588 
589         status = status_success;
590 
591     } while (false);
592 
593     return status;
594 }
595 
can_get_default_config(can_config_t * config)596 hpm_stat_t can_get_default_config(can_config_t *config)
597 {
598     hpm_stat_t status = status_invalid_argument;
599     if (config != NULL) {
600 
601         /* Default timing mode */
602         config->baudrate = 1000000UL; /* 1Mbit/s */
603         config->baudrate_fd = 0U;
604         config->use_lowlevel_timing_setting = false;
605         config->can20_samplepoint_min = CAN_SAMPLEPOINT_MIN;
606         config->can20_samplepoint_max = CAN_SAMPLEPOINT_MAX;
607         config->canfd_samplepoint_min = CAN_SAMPLEPOINT_MIN;
608         config->canfd_samplepoint_max = CAN_SAMPLEPOINT_MAX;
609         config->enable_canfd = false;
610         config->enable_can_fd_iso_mode = true;
611 
612         config->mode = can_mode_normal;
613         config->enable_self_ack = false;
614         config->disable_re_transmission_for_stb = false;
615         config->disable_re_transmission_for_ptb = false;
616         config->enable_tx_buffer_priority_mode = false;
617         config->enable_tdc = false;
618 
619         /* Default filter settings */
620         config->filter_list_num = 0;
621         config->filter_list = NULL;
622 
623         /* Default Interrupt enable settings */
624         config->irq_txrx_enable_mask = 0;
625         config->irq_error_enable_mask = 0;
626 
627         status = status_success;
628     }
629 
630     return status;
631 }
632 
can_init(CAN_Type * base,can_config_t * config,uint32_t src_clk_freq)633 hpm_stat_t can_init(CAN_Type *base, can_config_t *config, uint32_t src_clk_freq)
634 {
635     hpm_stat_t status = status_invalid_argument;
636 
637     do {
638 
639         HPM_BREAK_IF((base == NULL) || (config == NULL) || (src_clk_freq == 0U) || (config->filter_list_num > 16U));
640 
641         can_reset(base, true);
642 
643         base->TTCFG &= ~CAN_TTCFG_TTEN_MASK;
644         base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TTTBM_MASK;
645 
646         if (!config->use_lowlevel_timing_setting) {
647             if (config->enable_canfd) {
648                 status = can_set_bit_timing(base, can_bit_timing_canfd_norminal,
649                                             src_clk_freq, config->baudrate,
650                                             config->can20_samplepoint_min, config->can20_samplepoint_max);
651                 HPM_BREAK_IF(status != status_success);
652                 status = can_set_bit_timing(base, can_bit_timing_canfd_data,
653                                             src_clk_freq, config->baudrate_fd,
654                                             config->canfd_samplepoint_min, config->canfd_samplepoint_max);
655             } else {
656                 status = can_set_bit_timing(base, can_bit_timing_can2_0,
657                                             src_clk_freq, config->baudrate,
658                                             config->can20_samplepoint_min, config->can20_samplepoint_max);
659             }
660         } else {
661             can_set_slow_speed_timing(base, &config->can_timing);
662             if (config->enable_canfd) {
663                 can_set_fast_speed_timing(base, &config->canfd_timing);
664             }
665             status = status_success;
666         }
667 
668         /* Enable Transmitter Delay Compensation as needed */
669         uint32_t ssp_offset = CAN_F_PRESC_F_SEG_1_GET(base->F_PRESC) + 2U;
670         can_set_transmitter_delay_compensation(base, ssp_offset, config->enable_tdc);
671 
672         HPM_BREAK_IF(status != status_success);
673 
674         if (config->disable_re_transmission_for_ptb) {
675             base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TPSS_MASK;
676         } else {
677             base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TPSS_MASK;
678         }
679 
680         if (config->disable_re_transmission_for_stb) {
681             base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TSSS_MASK;
682         } else {
683             base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TSSS_MASK;
684         }
685 
686         /* Configure CAN filters */
687         if (config->filter_list_num > CAN_FILTER_NUM_MAX) {
688             status = status_can_filter_num_invalid;
689             break;
690         } else if (config->filter_list_num == 0) {
691             can_filter_config_t default_filter = CAN_DEFAULT_FILTER_SETTING;
692             for (uint32_t i = 0; i < CAN_FILTER_NUM_MAX; i++) {
693                 can_disable_filter(base, i);
694             }
695             (void) can_set_filter(base, &default_filter);
696         } else {
697             for (uint32_t i = 0; i < CAN_FILTER_NUM_MAX; i++) {
698                 can_disable_filter(base, i);
699             }
700             for (uint32_t i = 0; i < config->filter_list_num; i++) {
701                 status = can_set_filter(base, &config->filter_list[i]);
702                 if (status != status_success) {
703                     return status;
704                 }
705             }
706         }
707 
708         /* Set CAN FD standard */
709         can_enable_can_fd_iso_mode(base, config->enable_can_fd_iso_mode);
710 
711         can_reset(base, false);
712 
713         /* Set Self-ack mode*/
714         can_enable_self_ack(base, config->enable_self_ack);
715 
716         /* Set CAN work mode */
717         can_set_node_mode(base, config->mode);
718 
719         /* Configure TX Buffer priority mode */
720         can_select_tx_buffer_priority_mode(base, config->enable_tx_buffer_priority_mode);
721 
722         /* Configure interrupt */
723         can_disable_tx_rx_irq(base, 0xFFU);
724         can_disable_error_irq(base, 0xFFU);
725         can_enable_tx_rx_irq(base, config->irq_txrx_enable_mask);
726         can_enable_error_irq(base, config->irq_error_enable_mask);
727 
728         status = status_success;
729     } while (false);
730 
731     return status;
732 }
733 
can_deinit(CAN_Type * base)734 void can_deinit(CAN_Type *base)
735 {
736     do {
737         HPM_BREAK_IF(base == NULL);
738         can_reset(base, true);
739     } while (false);
740 }