1 /*
2  * Copyright (c) 2021-2024 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_NOMINAL (2U)
20 #define TSEG1_MAX_FOR_CANFD_NOMINAL (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_NOMINAL (1U)
29 #define TSEG2_MAX_FOR_CANFD_NOMINAL (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_NOMINAL (1U)
38 #define TSJW_MAX_FOR_CANFD_NOMINAL (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_NOMINAL + TSEG2_MAX_FOR_CANFD_NOMINAL)
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 CAN_TIMEOUT_CNT (0xFFFFFFUL)
60 
61 #define CAN_SAMPLEPOINT_MIN (750U)
62 #define CAN_SAMPLEPOINT_MAX (875U)
63 
64 
65 #define CAN_DEFAULT_FILTER_SETTING {0, can_filter_id_mode_both_frames, true, 0, (1UL << 29) - 1U }
66 
67 /*
68  * @brief CAN bit-timing table
69  */
70 typedef struct {
71     uint8_t tq_min;
72     uint8_t tq_max;
73     uint8_t seg1_min;
74     uint8_t seg1_max;
75     uint8_t seg2_min;
76     uint8_t seg2_max;
77     uint8_t sjw_min;
78     uint8_t sjw_max;
79     uint8_t min_diff_seg1_minus_seg2;
80 } can_bit_timing_table_t;
81 
82 /**
83  * @brief CAN bit timing list for all supported bit timing modes
84  */
85 static const can_bit_timing_table_t s_can_bit_timing_tbl[3] = {
86         {
87                 .tq_min = NUM_TQ_MIN_FOR_CAN2_0,
88                 .tq_max = NUM_TQ_MAX_FOR_CAN2_0,
89                 .seg1_min = TSEG1_MIN_FOR_CAN2_0,
90                 .seg1_max = TSEG1_MAX_FOR_CAN2_0,
91                 .seg2_min = TSEG2_MIN_FOR_CAN2_0,
92                 .seg2_max = TSEG2_MAX_FOR_CAN2_0,
93                 .sjw_min = TSJW_MIN_FOR_CAN2_0,
94                 .sjw_max = TSJW_MAX_FOR_CAN2_0,
95                 .min_diff_seg1_minus_seg2 = 2,
96         },
97         {
98                 .tq_min = NUM_TQ_MIN_FOR_CANFD_NOMINAL,
99                 .tq_max = NUM_TQ_MAX_FOR_CANFD_NOMINAL,
100                 .seg1_min = TSEG1_MIN_FOR_CANFD_NOMINAL,
101                 .seg1_max = TSEG1_MAX_FOR_CANFD_NOMINAL,
102                 .seg2_min = TSEG2_MIN_FOR_CANFD_NOMINAL,
103                 .seg2_max = TSEG2_MAX_FOR_CANFD_NOMINAL,
104                 .sjw_min = TSJW_MIN_FOR_CANFD_NOMINAL,
105                 .sjw_max = TSJW_MAX_FOR_CANFD_NOMINAL,
106                 .min_diff_seg1_minus_seg2 = 2,
107         },
108         {
109                 .tq_min = NUM_TQ_MIN_FOR_CANFD_DATA,
110                 .tq_max = NUM_TQ_MAX_FOR_CANFD_DATA,
111                 .seg1_min = TSEG1_MIN_FOR_CANFD_DATA,
112                 .seg1_max = TSEG1_MAX_FOR_CANFD_DATA,
113                 .seg2_min = TSEG2_MIN_FOR_CANFD_DATA,
114                 .seg2_max = TSEG2_MAX_FOR_CANFD_DATA,
115                 .sjw_min = TSJW_MIN_FOR_CANFD_DATA,
116                 .sjw_max = TSJW_MAX_FOR_CANFD_DATA,
117                 .min_diff_seg1_minus_seg2 = 1,
118         }
119 };
120 
121 /***********************************************************************************************************************
122  *
123  *  Prototypes
124  */
125 static uint32_t find_optimal_prescaler(uint32_t num_tq_mul_prescaler, uint32_t start_prescaler,
126                                        uint32_t max_tq, uint32_t min_tq);
127 
128 static uint8_t can_get_data_words_from_dlc(uint32_t dlc);
129 
130 static void can_fill_tx_buffer(CAN_Type *base, const can_transmit_buf_t *message);
131 
132 static bool is_can_bit_timing_param_valid(can_bit_timing_option_t option, const can_bit_timing_param_t *param);
133 
134 
135 /***********************************************************************************************************************
136  *
137  *  Codes
138  */
find_optimal_prescaler(uint32_t num_tq_mul_prescaler,uint32_t start_prescaler,uint32_t max_tq,uint32_t min_tq)139 static uint32_t find_optimal_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_optimal_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 
is_can_bit_timing_param_valid(can_bit_timing_option_t option,const can_bit_timing_param_t * param)242 static bool is_can_bit_timing_param_valid(can_bit_timing_option_t option, const can_bit_timing_param_t *param)
243 {
244     bool result = false;
245     const can_bit_timing_table_t *tbl = &s_can_bit_timing_tbl[(uint8_t) option];
246     do {
247         if ((param->num_seg1 < tbl->seg1_min) || (param->num_seg1 > tbl->seg1_max)) {
248             break;
249         }
250         if ((param->num_seg2 < tbl->seg2_min) || (param->num_seg2 > tbl->seg2_max)) {
251             break;
252         }
253         if ((param->num_sjw < tbl->sjw_min) || (param->num_sjw > tbl->sjw_max)) {
254             break;
255         }
256         if (param->prescaler > NUM_PRESCALE_MAX) {
257             break;
258         }
259         result = true;
260     } while (false);
261 
262     return result;
263 }
264 
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)265 hpm_stat_t can_set_bit_timing(CAN_Type *base, can_bit_timing_option_t option,
266                               uint32_t src_clk_freq, uint32_t baudrate,
267                               uint16_t samplepoint_min, uint16_t samplepoint_max)
268 {
269     hpm_stat_t status = status_invalid_argument;
270 
271     do {
272         if (base == NULL) {
273             break;
274         }
275 
276         can_bit_timing_param_t timing_param;
277         status = can_calculate_bit_timing(src_clk_freq, option, baudrate, samplepoint_min, samplepoint_max, &timing_param);
278 
279         if (status == status_success) {
280             if (option < can_bit_timing_canfd_data) {
281                 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) |
282                                 CAN_S_PRESC_S_SEG_2_SET(timing_param.num_seg2 - 1U) | CAN_S_PRESC_S_SJW_SET(timing_param.num_sjw - 1U);
283             } else {
284                 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) |
285                                 CAN_F_PRESC_F_SEG_2_SET(timing_param.num_seg2 - 1U) | CAN_F_PRESC_F_SJW_SET(timing_param.num_sjw - 1U);
286 
287             }
288             status = status_success;
289         }
290 
291     } while (false);
292 
293     return status;
294 }
295 
can_set_filter(CAN_Type * base,const can_filter_config_t * config)296 hpm_stat_t can_set_filter(CAN_Type *base, const can_filter_config_t *config)
297 {
298     hpm_stat_t status = status_invalid_argument;
299 
300     do {
301         if ((base == NULL) || (config == NULL)) {
302             break;
303         }
304         if (config->index > CAN_FILTER_INDEX_MAX) {
305             status = status_can_filter_index_invalid;
306             break;
307         }
308 
309         /* Configure acceptance code */
310         base->ACFCTRL = CAN_ACFCTRL_ACFADR_SET(config->index);
311         base->ACF = CAN_ACF_CODE_MASK_SET(config->code);
312 
313         /* Configure acceptance mask */
314         uint32_t acf_value = CAN_ACF_CODE_MASK_SET(config->mask);
315         if (config->id_mode == can_filter_id_mode_standard_frames) {
316             acf_value |= CAN_ACF_AIDEE_MASK;
317         } else if (config->id_mode == can_filter_id_mode_extended_frames) {
318             acf_value |= CAN_ACF_AIDEE_MASK | CAN_ACF_AIDE_MASK;
319         } else {
320             /* Treat it as the default mode */
321             acf_value |= 0;
322         }
323 
324         base->ACFCTRL = CAN_ACFCTRL_SELMASK_MASK | CAN_ACFCTRL_ACFADR_SET(config->index);
325         base->ACF = acf_value;
326 
327         if (config->enable) {
328             base->ACF_EN |= (1U << config->index);
329         } else {
330             base->ACF_EN &= (uint16_t) ~(1U << config->index);
331         }
332         status = status_success;
333     } while (false);
334 
335     return status;
336 }
337 
can_get_data_words_from_dlc(uint32_t dlc)338 static uint8_t can_get_data_words_from_dlc(uint32_t dlc)
339 {
340     uint32_t copy_words = 0;
341 
342     dlc &= 0xFU;
343     if (dlc <= 8U) {
344         copy_words = (dlc + 3U) / sizeof(uint32_t);
345     } else {
346         switch (dlc) {
347         case can_payload_size_12:
348             copy_words = 3U;
349             break;
350         case can_payload_size_16:
351             copy_words = 4U;
352             break;
353         case can_payload_size_20:
354             copy_words = 5U;
355             break;
356         case can_payload_size_24:
357             copy_words = 6U;
358             break;
359         case can_payload_size_32:
360             copy_words = 8U;
361             break;
362         case can_payload_size_48:
363             copy_words = 12U;
364             break;
365         case can_payload_size_64:
366             copy_words = 16U;
367             break;
368         default:
369             /* Code should never touch here */
370             break;
371         }
372     }
373 
374     return copy_words;
375 }
376 
can_fill_tx_buffer(CAN_Type * base,const can_transmit_buf_t * message)377 static void can_fill_tx_buffer(CAN_Type *base, const can_transmit_buf_t *message)
378 {
379     base->TBUF[0] = message->buffer[0];
380     base->TBUF[1] = message->buffer[1];
381 
382     uint32_t copy_words = can_get_data_words_from_dlc(message->dlc);
383     for (uint32_t i = 0U; i < copy_words; i++) {
384         base->TBUF[2U + i] = message->buffer[2U + i];
385     }
386 }
387 
can_send_message_blocking(CAN_Type * base,const can_transmit_buf_t * message)388 hpm_stat_t can_send_message_blocking(CAN_Type *base, const can_transmit_buf_t *message)
389 {
390     hpm_stat_t status = status_invalid_argument;
391 
392     do {
393 
394         if ((base == NULL) || (message == NULL)) {
395             break;
396         }
397 
398         status = status_success;
399         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
400 
401         can_fill_tx_buffer(base, message);
402 
403         /* Wait until STB is not full */
404         int32_t timeout_cnt = CAN_TIMEOUT_CNT;
405         while (CAN_CMD_STA_CMD_CTRL_TSSTAT_GET(base->CMD_STA_CMD_CTRL) == CAN_STB_IS_FULL) {
406             timeout_cnt--;
407             if (timeout_cnt <= 0) {
408                 status = status_timeout;
409                 break;
410             }
411         }
412         if (status != status_success) {
413             break;
414         }
415 
416         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TSNEXT_MASK | CAN_CMD_STA_CMD_CTRL_TSONE_MASK;
417         timeout_cnt = CAN_TIMEOUT_CNT;
418         while (CAN_CMD_STA_CMD_CTRL_TSSTAT_GET(base->CMD_STA_CMD_CTRL) != CAN_STB_IS_EMPTY) {
419             timeout_cnt--;
420             if (timeout_cnt <= 0) {
421                 status = status_timeout;
422                 break;
423             }
424         }
425 
426     } while (false);
427 
428     return status;
429 }
430 
can_send_high_priority_message_blocking(CAN_Type * base,const can_transmit_buf_t * message)431 hpm_stat_t can_send_high_priority_message_blocking(CAN_Type *base, const can_transmit_buf_t *message)
432 {
433     hpm_stat_t status = status_invalid_argument;
434 
435     do {
436         HPM_BREAK_IF((base == NULL) || (message == NULL));
437         status = status_success;
438 
439         /* Select the high-priority buffer */
440         base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
441 
442         can_fill_tx_buffer(base, message);
443 
444         /* Send the data out */
445         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TPE_MASK;
446         /* Wait until the data is sent out */
447         int32_t timeout_cnt = CAN_TIMEOUT_CNT;
448         while (IS_HPM_BITMASK_SET(base->CMD_STA_CMD_CTRL, CAN_CMD_STA_CMD_CTRL_TPE_MASK)) {
449             timeout_cnt--;
450             if (timeout_cnt <= 0) {
451                 status = status_timeout;
452                 break;
453             }
454         }
455     } while (false);
456 
457     return status;
458 }
459 
can_send_message_nonblocking(CAN_Type * base,const can_transmit_buf_t * message)460 hpm_stat_t can_send_message_nonblocking(CAN_Type *base, const can_transmit_buf_t *message)
461 {
462     hpm_stat_t status = status_invalid_argument;
463 
464     do {
465 
466         if ((base == NULL) || (message == NULL)) {
467             break;
468         }
469 
470         if (CAN_CMD_STA_CMD_CTRL_TSSTAT_GET(base->CMD_STA_CMD_CTRL) == CAN_STB_IS_FULL) {
471             status = status_can_tx_fifo_full;
472             break;
473         }
474 
475         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
476         can_fill_tx_buffer(base, message);
477         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TSNEXT_MASK | CAN_CMD_STA_CMD_CTRL_TSONE_MASK;
478 
479         status = status_success;
480 
481     } while (false);
482 
483     return status;
484 }
485 
can_send_high_priority_message_nonblocking(CAN_Type * base,const can_transmit_buf_t * message)486 hpm_stat_t can_send_high_priority_message_nonblocking(CAN_Type *base, const can_transmit_buf_t *message)
487 {
488     hpm_stat_t status = status_invalid_argument;
489 
490     do {
491         HPM_BREAK_IF((base == NULL) || (message == NULL));
492         status = status_success;
493 
494         if (IS_HPM_BITMASK_SET(base->CMD_STA_CMD_CTRL, CAN_CMD_STA_CMD_CTRL_TPE_MASK)) {
495             status = status_can_tx_fifo_full;
496             break;
497         }
498         /* Select the high-priority buffer */
499         base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TBSEL_MASK;
500 
501         can_fill_tx_buffer(base, message);
502 
503         /* Send the data out */
504         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_TPE_MASK;
505     } while (false);
506 
507     return status;
508 }
509 
can_receive_message_blocking(CAN_Type * base,can_receive_buf_t * message)510 hpm_stat_t can_receive_message_blocking(CAN_Type *base, can_receive_buf_t *message)
511 {
512     hpm_stat_t status = status_invalid_argument;
513 
514     do {
515         HPM_BREAK_IF((base == NULL) || (message == NULL));
516 
517         while (CAN_CMD_STA_CMD_CTRL_RSTAT_GET(base->CMD_STA_CMD_CTRL) == CAN_RXBUF_IS_EMPTY) {
518 
519         }
520 
521         /* Get the first 2 words (including CAN ID, Data length and other control bits) */
522         message->buffer[0] = base->RBUF[0];
523         message->buffer[1] = base->RBUF[1];
524 
525         if (message->error_type != 0U) {
526             switch (message->error_type) {
527             case 1:
528                 status = status_can_bit_error;
529                 break;
530             case 2:
531                 status = status_can_form_error;
532                 break;
533             case 3:
534                 status = status_can_stuff_error;
535                 break;
536             case 4:
537                 status = status_can_ack_error;
538                 break;
539             case 5:
540                 status = status_can_crc_error;
541                 break;
542             default:
543                 status = status_can_other_error;
544                 break;
545             }
546             break;
547         }
548 
549         if (message->remote_frame == 0U) {
550             uint32_t copy_words = can_get_data_words_from_dlc(message->dlc);
551 
552             for (uint32_t i = 0; i < copy_words; i++) {
553                 message->buffer[2U + i] = base->RBUF[2U + i];
554             }
555         }
556         /* Release the current buffer */
557         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_RREL_MASK;
558 
559         status = status_success;
560 
561     } while (false);
562 
563     return status;
564 }
565 
can_read_received_message(CAN_Type * base,can_receive_buf_t * message)566 hpm_stat_t can_read_received_message(CAN_Type *base, can_receive_buf_t *message)
567 {
568     hpm_stat_t status;
569 
570     assert((base != NULL) && (message != NULL));
571 
572     do {
573         /* Get the first 2 words (including CAN ID, Data length and other control bits) */
574         message->buffer[0] = base->RBUF[0];
575         message->buffer[1] = base->RBUF[1];
576 
577         if (message->error_type != 0U) {
578             switch (message->error_type) {
579             case 1:
580                 status = status_can_bit_error;
581                 break;
582             case 2:
583                 status = status_can_form_error;
584                 break;
585             case 3:
586                 status = status_can_stuff_error;
587                 break;
588             case 4:
589                 status = status_can_ack_error;
590                 break;
591             case 5:
592                 status = status_can_crc_error;
593                 break;
594             default:
595                 status = status_can_other_error;
596                 break;
597             }
598             break;
599         }
600 
601         if (message->remote_frame == 0U) {
602             uint32_t copy_words = can_get_data_words_from_dlc(message->dlc);
603 
604             for (uint32_t i = 0; i < copy_words; i++) {
605                 message->buffer[2U + i] = base->RBUF[2U + i];
606             }
607         }
608         /* Release the current buffer */
609         base->CMD_STA_CMD_CTRL |= CAN_CMD_STA_CMD_CTRL_RREL_MASK;
610 
611         status = status_success;
612 
613     } while (false);
614 
615     return status;
616 }
617 
can_get_default_config(can_config_t * config)618 hpm_stat_t can_get_default_config(can_config_t *config)
619 {
620     hpm_stat_t status = status_invalid_argument;
621     if (config != NULL) {
622 
623         /* Default timing mode */
624         config->baudrate = 1000000UL; /* 1Mbit/s */
625         config->baudrate_fd = 0U;
626         config->use_lowlevel_timing_setting = false;
627         config->can20_samplepoint_min = CAN_SAMPLEPOINT_MIN;
628         config->can20_samplepoint_max = CAN_SAMPLEPOINT_MAX;
629         config->canfd_samplepoint_min = CAN_SAMPLEPOINT_MIN;
630         config->canfd_samplepoint_max = CAN_SAMPLEPOINT_MAX;
631         config->enable_canfd = false;
632         config->enable_can_fd_iso_mode = true;
633 
634         config->mode = can_mode_normal;
635         config->enable_self_ack = false;
636         config->disable_stb_retransmission = false;
637         config->disable_ptb_retransmission = false;
638         config->enable_tx_buffer_priority_mode = false;
639         config->enable_tdc = false;
640 
641         /* Default filter settings */
642         config->filter_list_num = 0;
643         config->filter_list = NULL;
644 
645         /* Default Interrupt enable settings */
646         config->irq_txrx_enable_mask = 0;
647         config->irq_error_enable_mask = 0;
648 
649         status = status_success;
650     }
651 
652     return status;
653 }
654 
can_init(CAN_Type * base,can_config_t * config,uint32_t src_clk_freq)655 hpm_stat_t can_init(CAN_Type *base, can_config_t *config, uint32_t src_clk_freq)
656 {
657     hpm_stat_t status = status_invalid_argument;
658 
659     do {
660 
661         HPM_BREAK_IF((base == NULL) || (config == NULL) || (src_clk_freq == 0U) || (config->filter_list_num > 16U));
662 
663         can_reset(base, true);
664 
665         base->TTCFG &= ~CAN_TTCFG_TTEN_MASK;
666         base->CMD_STA_CMD_CTRL &= ~CAN_CMD_STA_CMD_CTRL_TTTBM_MASK;
667 
668         if (!config->use_lowlevel_timing_setting) {
669             if (config->enable_canfd) {
670                 status = can_set_bit_timing(base,
671                                             can_bit_timing_canfd_nominal,
672                                             src_clk_freq,
673                                             config->baudrate,
674                                             config->can20_samplepoint_min,
675                                             config->can20_samplepoint_max);
676                 HPM_BREAK_IF(status != status_success);
677                 status = can_set_bit_timing(base,
678                                             can_bit_timing_canfd_data,
679                                             src_clk_freq,
680                                             config->baudrate_fd,
681                                             config->canfd_samplepoint_min,
682                                             config->canfd_samplepoint_max);
683             } else {
684                 status = can_set_bit_timing(base,
685                                             can_bit_timing_can2_0,
686                                             src_clk_freq,
687                                             config->baudrate,
688                                             config->can20_samplepoint_min,
689                                             config->can20_samplepoint_max);
690             }
691         } else {
692             if (config->enable_canfd) {
693                 bool param_valid = is_can_bit_timing_param_valid(can_bit_timing_canfd_nominal, &config->can_timing);
694                 if (!param_valid) {
695                     status = status_can_invalid_bit_timing;
696                     break;
697                 }
698                 param_valid = is_can_bit_timing_param_valid(can_bit_timing_canfd_data, &config->canfd_timing);
699                 if (!param_valid) {
700                     status = status_can_invalid_bit_timing;
701                     break;
702                 }
703                 can_set_slow_speed_timing(base, &config->can_timing);
704                 can_set_fast_speed_timing(base, &config->canfd_timing);
705             } else {
706                 bool param_valid = is_can_bit_timing_param_valid(can_bit_timing_can2_0, &config->can_timing);
707                 if (!param_valid) {
708                     status = status_can_invalid_bit_timing;
709                     break;
710                 }
711                 can_set_slow_speed_timing(base, &config->can_timing);
712             }
713             status = status_success;
714         }
715 
716         /* Enable Transmitter Delay Compensation as needed */
717         uint32_t ssp_offset = CAN_F_PRESC_F_SEG_1_GET(base->F_PRESC) + 2U;
718         can_set_transmitter_delay_compensation(base, ssp_offset, config->enable_tdc);
719 
720         HPM_BREAK_IF(status != status_success);
721 
722 
723         /* Configure the CAN filters */
724         if (config->filter_list_num > CAN_FILTER_NUM_MAX) {
725             status = status_can_filter_num_invalid;
726             break;
727         } else if (config->filter_list_num == 0) {
728             can_filter_config_t default_filter = CAN_DEFAULT_FILTER_SETTING;
729             for (uint32_t i = 0; i < CAN_FILTER_NUM_MAX; i++) {
730                 can_disable_filter(base, i);
731             }
732             (void) can_set_filter(base, &default_filter);
733         } else {
734             for (uint32_t i = 0; i < CAN_FILTER_NUM_MAX; i++) {
735                 can_disable_filter(base, i);
736             }
737             for (uint32_t i = 0; i < config->filter_list_num; i++) {
738                 status = can_set_filter(base, &config->filter_list[i]);
739                 if (status != status_success) {
740                     return status;
741                 }
742             }
743         }
744 
745         /* Set CAN FD standard */
746         can_enable_can_fd_iso_mode(base, config->enable_can_fd_iso_mode);
747 
748         can_reset(base, false);
749 
750         /* The following mode must be set when the CAN controller is not in reset mode */
751 
752         /* Disable re-transmission on PTB on demand */
753         can_disable_ptb_retransmission(base, config->disable_ptb_retransmission);
754         /* Disable re-transmission on STB on demand */
755         can_disable_stb_retransmission(base, config->disable_stb_retransmission);
756 
757         /* Set Self-ack mode*/
758         can_enable_self_ack(base, config->enable_self_ack);
759 
760         /* Set CAN work mode */
761         can_set_node_mode(base, config->mode);
762 
763         /* Configure TX Buffer priority mode */
764         can_select_tx_buffer_priority_mode(base, config->enable_tx_buffer_priority_mode);
765 
766         /* Configure interrupt */
767         can_disable_tx_rx_irq(base, 0xFFU);
768         can_disable_error_irq(base, 0xFFU);
769         can_enable_tx_rx_irq(base, config->irq_txrx_enable_mask);
770         can_enable_error_irq(base, config->irq_error_enable_mask);
771 
772         status = status_success;
773     } while (false);
774 
775     return status;
776 }
777 
can_deinit(CAN_Type * base)778 void can_deinit(CAN_Type *base)
779 {
780     do {
781         HPM_BREAK_IF(base == NULL);
782         can_force_bus_off(base);
783         can_reset(base, true);
784     } while (false);
785 }