1 /*******************************************************************************
2 * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * PolarFire SoC (MPFS) microprocessor subsystem CAN bare metal software driver
7 * implementation.
8 */
9
10
11 /*******************************************************************************
12 * Include files
13 */
14 #include "mpfs_hal/mss_hal.h"
15 #include "mss_can.h"
16
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20
21 /*******************************************************************************
22 * Macros
23 */
24 #define CAN_ID_SHIFT 18u
25 #define CAN_ERROR_STATUS_SHIFT 16u
26 #define CAN_ERROR_STATUS_MASK 0x03u
27 #define CAN_RX_GTE96_SHIFT 19u
28 #define CAN_FLAG_MASK 0x01u
29 #define CAN_ERROR_COUNT_SHIFT 8u
30 #define CAN_ERROR_COUNT_MASK 0xFFu
31 #define CAN_TXGTE96_SHIFT 18u
32 #define CAN_INT_MASK 0xFFFFFFFCu
33 #define ENABLE 1u
34 #define DISABLE 0u
35 #define SYSREG_CAN_SOFTRESET_MASK (uint32_t)(3 << 14u)
36
37 /*******************************************************************************
38 * Instance definition
39 */
40 mss_can_instance_t g_mss_can_0_lo;
41 mss_can_instance_t g_mss_can_1_lo;
42 mss_can_instance_t g_mss_can_0_hi;
43 mss_can_instance_t g_mss_can_1_hi;
44
45 static void global_init
46 (
47 mss_can_instance_t* this_wd
48 );
49
50 /***************************************************************************//**
51 * MSS_CAN_init()
52 * See "mss_can.h" for details of how to use this function.
53 */
54 uint8_t
MSS_CAN_init(mss_can_instance_t * this_can,uint32_t bitrate,pmss_can_config_reg pcan_config,uint8_t basic_can_rx_mb,uint8_t basic_can_tx_mb)55 MSS_CAN_init
56 (
57 mss_can_instance_t* this_can,
58 uint32_t bitrate,
59 pmss_can_config_reg pcan_config,
60 uint8_t basic_can_rx_mb,
61 uint8_t basic_can_tx_mb
62 )
63 {
64 uint32_t temp;
65 uint8_t mailbox_number;
66 uint8_t ret_value;
67 mss_can_rxmsgobject canrxobj;
68
69 global_init(this_can);
70
71 /* Initialize the device structure */
72 this_can->basic_can_rx_mb = basic_can_rx_mb;
73 this_can->basic_can_tx_mb = basic_can_tx_mb;
74
75 /* Initialize the rx mailbox */
76 canrxobj.ID = 0u;
77 canrxobj.DATAHIGH = 0u;
78 canrxobj.DATALOW = 0u;
79 canrxobj.AMR.L = 0u;
80 canrxobj.ACR.L = 0u;
81 canrxobj.AMR_D = 0u;
82 canrxobj.ACR_D = 0u;
83 canrxobj.RXB.L = (0u | CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL);
84
85 for (mailbox_number = 0u; mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
86 {
87 ret_value = MSS_CAN_config_buffer_n(this_can, mailbox_number,
88 &canrxobj);
89 }
90
91 /* Configure CAN controller */
92 if (CAN_SPEED_MANUAL == bitrate)
93 {
94 /*
95 * If user wants to specify registers directly Check if parameters
96 * meet minimums.
97 */
98 if (pcan_config->CFG_TSEG1 < 2u)
99 {
100 return (CAN_TSEG1_TOO_SMALL );
101 }
102
103 if ((pcan_config->CFG_TSEG2 == 0u) ||
104 ((pcan_config->SAMPLING_MODE == 1u) && (pcan_config->CFG_TSEG2
105 == 1u)))
106 {
107 return (CAN_TSEG2_TOO_SMALL);
108 }
109 temp = pcan_config->CFG_SJW;
110 if ((temp > pcan_config->CFG_TSEG1) ||
111 (temp > pcan_config->CFG_TSEG2))
112 {
113 return (CAN_SJW_TOO_BIG);
114 }
115
116 this_can->hw_reg->Config.L = pcan_config->L;
117 }
118 else
119 {
120 /* User has chosen a default setting. */
121 this_can->hw_reg->Config.L = bitrate;
122 }
123
124 /* Disable Interrupts */
125 this_can->hw_reg->IntEbl.L = DISABLE;
126
127 return (CAN_OK);
128 }
129
130 /***************************************************************************//**
131 * MSS_CAN_set_config_reg()
132 * See "mss_can.h" for details of how to use this function.
133 */
134 void
MSS_CAN_set_config_reg(mss_can_instance_t * this_can,uint32_t cfg)135 MSS_CAN_set_config_reg
136 (
137 mss_can_instance_t* this_can,
138 uint32_t cfg
139 )
140 {
141 /* Clear all pending interrupts */
142 this_can->hw_reg->IntStatus.L = DISABLE;
143
144 /* Disable CAN Device */
145 this_can->hw_reg->Command.RUN_STOP = DISABLE;
146
147 /* Disable receive interrupts. */
148 this_can->hw_reg->IntEbl.RX_MSG = DISABLE;
149
150 /* Disable interrupts from CAN device. */
151 this_can->hw_reg->IntEbl.INT_EBL = DISABLE;
152
153 /* Sets configuration bits */
154 this_can->hw_reg->Config.L = cfg;
155 MSS_CAN_start(this_can);
156 }
157
158 /***************************************************************************//**
159 * MSS_CAN_set_mode()
160 * See "mss_can.h" for details of how to use this function.
161 */
162 void
MSS_CAN_set_mode(mss_can_instance_t * this_can,mss_can_mode_t mode)163 MSS_CAN_set_mode
164 (
165 mss_can_instance_t* this_can,
166 mss_can_mode_t mode
167 )
168 {
169 this_can->hw_reg->Command.RUN_STOP = DISABLE;
170 if (CANOP_SW_RESET == mode)
171 {
172 SYSREG->SOFT_RESET_CR |= SYSREG_CAN_SOFTRESET_MASK;
173 SYSREG->SOFT_RESET_CR &= ~SYSREG_CAN_SOFTRESET_MASK;
174 }
175 else
176 {
177 this_can->hw_reg->Command.L = (uint32_t)mode;
178 }
179 }
180
181 /***************************************************************************//**
182 * MSS_CAN_start()
183 * See "mss_can.h" for details of how to use this function.
184 */
185 void
MSS_CAN_start(mss_can_instance_t * this_can)186 MSS_CAN_start
187 (
188 mss_can_instance_t* this_can
189 )
190 {
191 /* Clear all pending interrupts*/
192 this_can->hw_reg->IntStatus.L = DISABLE;
193
194 /* Enable CAN Device*/
195 this_can->hw_reg->Command.RUN_STOP = ENABLE;
196
197 /* Enable CAN Interrupt at NVIC level- if supported */
198 #ifdef MSS_CAN_ENABLE_INTERRUPTS
199 if (if (&g_mss_can_0_lo == this_can) || (&g_mss_can_0_hi == this_can))
200 {
201 PLIC_DisableIRQ(CAN0_PLIC);
202 }
203 else
204 {
205 PLIC_DisableIRQ(CAN1_PLIC);
206 }
207 #endif
208
209 /* Enable receive interrupts. */
210 this_can->hw_reg->IntEbl.RX_MSG = ENABLE;
211
212 /* Enable interrupts from CAN device.*/
213 this_can->hw_reg->IntEbl.INT_EBL = ENABLE;
214
215 }
216
217 /***************************************************************************//**
218 * MSS_CAN_stop()
219 * See "mss_can.h" for details of how to use this function.
220 */
221 void
MSS_CAN_stop(mss_can_instance_t * this_can)222 MSS_CAN_stop
223 (
224 mss_can_instance_t* this_can
225 )
226 {
227 this_can->hw_reg->Command.RUN_STOP = DISABLE;
228 }
229
230 /***************************************************************************//**
231 * MSS_CAN_get_id()
232 * See "mss_can.h" for details of how to use this function.
233 */
234 uint32_t
MSS_CAN_get_id(pmss_can_msgobject pmsg)235 MSS_CAN_get_id
236 (
237 pmss_can_msgobject pmsg
238 )
239 {
240 if (pmsg->IDE)
241 {
242 return (pmsg->ID);
243 }
244 else
245 {
246 return (pmsg->ID >> CAN_ID_SHIFT);
247 }
248 }
249
250 /***************************************************************************//**
251 * MSS_CAN_set_id()
252 * See "mss_can.h" for details of how to use this function.
253 */
254 uint32_t
MSS_CAN_set_id(pmss_can_msgobject pmsg)255 MSS_CAN_set_id
256 (
257 pmss_can_msgobject pmsg
258 )
259 {
260 if (pmsg->IDE)
261 {
262 return (pmsg->ID);
263 }
264 else
265 {
266 return (pmsg->ID << CAN_ID_SHIFT);
267 }
268 }
269
270 /***************************************************************************//**
271 * MSS_CAN_get_msg_filter_mask()
272 * See "mss_can.h" for details of how to use this function.
273 */
274 uint32_t
MSS_CAN_get_msg_filter_mask(uint32_t id,uint8_t ide,uint8_t rtr)275 MSS_CAN_get_msg_filter_mask
276 (
277 uint32_t id,
278 uint8_t ide,
279 uint8_t rtr
280 )
281 {
282 if (ide)
283 {
284 id <<= 3u;
285 }
286 else
287 {
288 id <<= 21;
289
290 /* Set unused ID bits to 1! */
291 id |= (0x3FFFF << 3u);
292 }
293 id |= ((uint32_t)(ide << 2u) | (uint32_t)(rtr << 1u));
294
295 return (id);
296 }
297
298 /***************************************************************************//**
299 * MSS_CAN_set_int_ebl()
300 * See "mss_can.h" for details of how to use this function.
301 */
302 void
MSS_CAN_set_int_ebl(mss_can_instance_t * this_can,uint32_t irq_flag)303 MSS_CAN_set_int_ebl
304 (
305 mss_can_instance_t* this_can,
306 uint32_t irq_flag
307 )
308 {
309 this_can->hw_reg->IntEbl.L |= irq_flag;
310 }
311
312 /***************************************************************************//**
313 * MSS_CAN_clear_int_ebl()
314 * See "mss_can.h" for details of how to use this function.
315 */
316 void
MSS_CAN_clear_int_ebl(mss_can_instance_t * this_can,uint32_t irq_flag)317 MSS_CAN_clear_int_ebl
318 (
319 mss_can_instance_t* this_can,
320 uint32_t irq_flag
321 )
322 {
323 this_can->hw_reg->IntEbl.L &= ~irq_flag;
324 }
325
326 /***************************************************************************//**
327 * MSS_CAN_get_global_int_ebl()
328 * See "mss_can.h" for details of how to use this function.
329 */
330 uint32_t
MSS_CAN_get_global_int_ebl(mss_can_instance_t * this_can)331 MSS_CAN_get_global_int_ebl
332 (
333 mss_can_instance_t* this_can
334 )
335 {
336 return (this_can->hw_reg->IntEbl.INT_EBL);
337 }
338
339 /***************************************************************************//**
340 * MSS_CAN_get_int_ebl()
341 * See "mss_can.h" for details of how to use this function.
342 */
343 uint32_t
MSS_CAN_get_int_ebl(mss_can_instance_t * this_can)344 MSS_CAN_get_int_ebl
345 (
346 mss_can_instance_t* this_can
347 )
348 {
349 return (this_can->hw_reg->IntEbl.L & CAN_INT_MASK);
350 }
351
352 /***************************************************************************//**
353 * MSS_CAN_clear_int_status()
354 * See "mss_can.h" for details of how to use this function.
355 */
356 void
MSS_CAN_clear_int_status(mss_can_instance_t * this_can,uint32_t irq_flag)357 MSS_CAN_clear_int_status
358 (
359 mss_can_instance_t* this_can,
360 uint32_t irq_flag
361 )
362 {
363 this_can->hw_reg->IntStatus.L = irq_flag;
364 }
365
366 /***************************************************************************//**
367 * MSS_CAN_get_int_status()
368 * See "mss_can.h" for details of how to use this function.
369 */
370 uint32_t
MSS_CAN_get_int_status(mss_can_instance_t * this_can)371 MSS_CAN_get_int_status
372 (
373 mss_can_instance_t* this_can
374 )
375 {
376 return (this_can->hw_reg->IntStatus.L);
377 }
378
379 /***************************************************************************//**
380 * MSS_CAN_set_rtr_message_n()
381 * See "mss_can.h" for details of how to use this function.
382 */
383 uint8_t
MSS_CAN_set_rtr_message_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_msgobject pmsg)384 MSS_CAN_set_rtr_message_n
385 (
386 mss_can_instance_t* this_can,
387 uint8_t mailbox_number,
388 pmss_can_msgobject pmsg
389 )
390 {
391 /* Is buffer configured for Full CAN? */
392 if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
393 {
394 return (CAN_BASIC_CAN_MAILBOX);
395 }
396
397 /* Is buffer configured for RTR auto-replay? */
398 if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLY == 0u)
399 {
400 return (CAN_NO_RTR_MAILBOX);
401 }
402 else
403 {
404 /* Transfer the ID. */
405 this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID;
406 this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
407 this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
408 return (CAN_OK);
409 }
410 }
411
412 /***************************************************************************//**
413 * MSS_CAN_get_rtr_message_abort_n()
414 * See "mss_can.h" for details of how to use this function.
415 */
416 uint8_t
MSS_CAN_get_rtr_message_abort_n(mss_can_instance_t * this_can,uint8_t mailbox_number)417 MSS_CAN_get_rtr_message_abort_n
418 (
419 mss_can_instance_t* this_can,
420 uint8_t mailbox_number
421 )
422 {
423 /* Is buffer configured for Full CAN? */
424 if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
425 {
426 /* Mailbox is configured for basic CAN */
427 return (CAN_BASIC_CAN_MAILBOX);
428 }
429
430 /* Set abort request */
431 this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRABORT = 1u;
432
433 /* Check the abort is granted */
434 if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLYPEND == 0u)
435 {
436 /* If the RX buffer isn't busy. Abort was successful */
437 return (CAN_OK);
438 }
439 else
440 {
441 /* Message not aborted.*/
442 return (CAN_ERR);
443 }
444 }
445
446 /***************************************************************************//**
447 * MSS_CAN_config_buffer()
448 * See "mss_can.h" for details of how to use this function.
449 */
450 uint8_t
MSS_CAN_config_buffer(mss_can_instance_t * this_can,pmss_can_filterobject pfilter)451 MSS_CAN_config_buffer
452 (
453 mss_can_instance_t* this_can,
454 pmss_can_filterobject pfilter
455 )
456 {
457 uint8_t success = CAN_NO_MSG;
458 uint8_t mailbox_number;
459
460 /* Is a buffer configured for Basic CAN? */
461 if (this_can->basic_can_rx_mb == 0u)
462 {
463 return (CAN_INVALID_MAILBOX);
464 }
465
466 /* Find next BASIC CAN buffer that has a message available */
467 for (mailbox_number = CAN_RX_MAILBOX - this_can->basic_can_rx_mb; \
468 mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
469 {
470 /* Set filters */
471 this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pfilter->ACR.L;
472 this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pfilter->AMR.L;
473 this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pfilter->AMCR_D.MASK;
474 this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pfilter->AMCR_D.CODE;
475
476 /* Configure mailbox */
477 if (mailbox_number < (CAN_RX_MAILBOX - 1))
478 {
479 /* set link flag, if not last buffer */
480 this_can->hw_reg->RxMsg[mailbox_number].RXB.L =
481 (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \
482 CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL | \
483 CAN_RX_LINK_EBL);
484 }
485 else
486 {
487 this_can->hw_reg->RxMsg[mailbox_number].RXB.L =
488 (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \
489 CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL);
490 }
491 success = CAN_OK;
492 }
493 return (success);
494 }
495
496 /***************************************************************************//**
497 * MSS_CAN_config_buffer_n()
498 * See "mss_can.h" for details of how to use this function.
499 */
500 uint8_t
MSS_CAN_config_buffer_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_rxmsgobject pmsg)501 MSS_CAN_config_buffer_n
502 (
503 mss_can_instance_t* this_can,
504 uint8_t mailbox_number,
505 pmss_can_rxmsgobject pmsg
506 )
507 {
508 /* Is buffer configured for Full CAN? */
509 if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
510 {
511 return (CAN_BASIC_CAN_MAILBOX);
512 }
513
514 /* Configure mailbox */
515 this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID;
516 this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
517 this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
518 this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pmsg->ACR.L;
519 this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pmsg->AMR.L;
520 this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pmsg->AMR_D;
521 this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pmsg->ACR_D;
522 this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (pmsg->RXB.L | \
523 CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \
524 CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL);
525 return (CAN_OK);
526 }
527
528 /***************************************************************************//**
529 * MSS_CAN_get_message_n()
530 * See "mss_can.h" for details of how to use this function.
531 */
532 uint8_t
MSS_CAN_get_message_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_msgobject pmsg)533 MSS_CAN_get_message_n
534 (
535 mss_can_instance_t* this_can,
536 uint8_t mailbox_number,
537 pmss_can_msgobject pmsg
538 )
539 {
540 /* Is buffer configured for Full CAN? */
541 if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
542 {
543 return (CAN_BASIC_CAN_MAILBOX);
544 }
545
546 /* Check that a new message is available and get it */
547 if ((ENABLE == this_can->hw_reg->Command.RUN_STOP) &&
548 (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV))
549 {
550 /* Copy ID */
551 pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID;
552
553 /* Copy 4 of the data bytes */
554 pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW;
555
556 /* Copy the other 4 data bytes. */
557 pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH;
558
559 /* Get DLC, IDE and RTR and time stamp. */
560 pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L;
561
562 /* Ack that it's been removed from the FIFO */
563 this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE;
564
565 /* And let app know there is a message. */
566 return (CAN_VALID_MSG);
567 }
568 else
569 {
570 return (CAN_NO_MSG);
571 }
572 }
573
574 /*******************************************************************************
575 * MSS_CAN_get_message()
576 * See "mss_can.h" for details of how to use this function.
577 */
578 uint8_t
MSS_CAN_get_message(mss_can_instance_t * this_can,pmss_can_msgobject pmsg)579 MSS_CAN_get_message
580 (
581 mss_can_instance_t* this_can,
582 pmss_can_msgobject pmsg
583 )
584 {
585 uint8_t success = CAN_NO_MSG;
586 uint8_t mailbox_number;
587
588 /* Is a buffer configured for Basic CAN? */
589 if (this_can->basic_can_rx_mb == 0u)
590 {
591 return (CAN_INVALID_MAILBOX);
592 }
593
594 /* Find next BASIC CAN buffer that has a message available */
595 for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb; \
596 mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
597 {
598 /* Check that if there is a valid message */
599 if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV)
600 {
601 /* Copy ID */
602 pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID;
603
604 /* Copy 4 of the data bytes */
605 pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW;
606
607 /* Copy the other 4 data bytes.*/
608 pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH;
609
610 /* Get DLC, IDE and RTR and time stamp.*/
611 pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L;
612
613 /* Ack that it's been removed from the FIFO */
614 this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE;
615 success = CAN_VALID_MSG;
616 break;
617 }
618 }
619 return (success);
620 }
621
622 /***************************************************************************//**
623 * MSS_CAN_get_message_av()
624 * See "mss_can.h" for details of how to use this function.
625 */
626 uint8_t
MSS_CAN_get_message_av(mss_can_instance_t * this_can)627 MSS_CAN_get_message_av
628 (
629 mss_can_instance_t* this_can
630 )
631 {
632 uint8_t success = CAN_NO_MSG;
633 uint8_t mailbox_number;
634
635 /* Is a buffer configured for Basic CAN? */
636 if (this_can->basic_can_rx_mb == 0u)
637 {
638 return (CAN_INVALID_MAILBOX);
639 }
640
641 /* Find next BASIC CAN buffer that has a message available */
642 for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb; \
643 mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
644 {
645 /* Check that buffer is enabled and contains a message */
646 if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV)
647 {
648 success = CAN_VALID_MSG;
649 break;
650 }
651 }
652 return (success);
653 }
654
655 /***************************************************************************//**
656 * MSS_CAN_send_message_n()
657 * See "mss_can.h" for details of how to use this function.
658 */
659 uint8_t
MSS_CAN_send_message_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_msgobject pmsg)660 MSS_CAN_send_message_n
661 (
662 mss_can_instance_t* this_can,
663 uint8_t mailbox_number,
664 pmss_can_msgobject pmsg
665 )
666 {
667 /* Can't send if device is disabled */
668 if (DISABLE == this_can->hw_reg->Command.RUN_STOP)
669 {
670 /* Message not sent. */
671 return (CAN_NO_MSG);
672 }
673
674 /* Is buffer configured for Full CAN? */
675 if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb))
676 {
677 /* mailbox is configured for basic CAN */
678 return (CAN_BASIC_CAN_MAILBOX);
679 }
680
681 if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u)
682 {
683 /* If the Tx buffer isn't busy.... */
684 this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID;
685 this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
686 this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
687 this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \
688 CAN_TX_WPNH_EBL | \
689 CAN_TX_REQ);
690 return (CAN_VALID_MSG);
691 }
692 else
693 {
694 /* Message not sent. */
695 return (CAN_NO_MSG);
696 }
697 }
698
699 /***************************************************************************//**
700 * MSS_CAN_send_message_abort_n()
701 * See "mss_can.h" for details of how to use this function.
702 */
703 uint8_t
MSS_CAN_send_message_abort_n(mss_can_instance_t * this_can,uint8_t mailbox_number)704 MSS_CAN_send_message_abort_n
705 (
706 mss_can_instance_t* this_can,
707 uint8_t mailbox_number
708 )
709 {
710 /* Is buffer configured for Full CAN? */
711 if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb))
712 {
713 /* mailbox is configured for basic CAN */
714 return (CAN_BASIC_CAN_MAILBOX);
715 }
716
717 /* Set abort request */
718 this_can->hw_reg->TxMsg[mailbox_number].TXB.L =
719 ((this_can->hw_reg->TxMsg[mailbox_number].TXB.L & ~CAN_TX_REQ) | \
720 CAN_TX_ABORT);
721
722 /* Check the abort is granted */
723 if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXABORT == 0u)
724 {
725 /* If the Tx buffer isn't busy, Abort was successful */
726 return (CAN_OK);
727 }
728 else
729 {
730 /* Message not aborted. */
731 return (CAN_ERR);
732 }
733 }
734
735 /***************************************************************************//**
736 * MSS_CAN_send_message_ready()
737 * See "mss_can.h" for details of how to use this function.
738 */
739 uint8_t
MSS_CAN_send_message_ready(mss_can_instance_t * this_can)740 MSS_CAN_send_message_ready
741 (
742 mss_can_instance_t* this_can
743 )
744 {
745 uint8_t success = CAN_ERR;
746 uint8_t mailbox_number;
747
748 /* Is a buffer configured for Basic CAN? */
749 if (this_can->basic_can_tx_mb == 0u)
750 {
751 return (CAN_INVALID_MAILBOX);
752 }
753
754 /* Find next BASIC CAN buffer that is available */
755 for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb; \
756 mailbox_number < CAN_TX_MAILBOX; mailbox_number++)
757 {
758 if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u)
759 {
760 /* Tx buffer isn't busy */
761 success = CAN_OK;
762 break;
763 }
764 }
765
766 return (success);
767 }
768
769 /***************************************************************************//**
770 * MSS_CAN_send_message()
771 * See "mss_can.h" for details of how to use this function.
772 */
773 uint8_t
MSS_CAN_send_message(mss_can_instance_t * this_can,pmss_can_msgobject pmsg)774 MSS_CAN_send_message
775 (
776 mss_can_instance_t* this_can,
777 pmss_can_msgobject pmsg
778 )
779 {
780 uint8_t success = CAN_NO_MSG;
781 uint8_t mailbox_number;
782
783 /* Is a buffer configured for Basic CAN? */
784 if (this_can->basic_can_tx_mb == 0u)
785 {
786 return (CAN_INVALID_MAILBOX);
787 }
788
789 /* Find next BASIC CAN buffer that is available */
790 for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb; \
791 mailbox_number < CAN_TX_MAILBOX; mailbox_number++)
792 {
793 /* Check which transmit mailbox is not busy and use it. */
794 if ((MSS_CAN_get_tx_buffer_status(this_can) & (1u << mailbox_number))
795 == 0)
796 {
797 /* If the Tx buffer isn't busy.... */
798 this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID;
799 this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
800 this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
801 this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \
802 CAN_TX_WPNH_EBL | \
803 CAN_TX_REQ);
804 success = CAN_VALID_MSG;
805 break;
806 }
807 }
808
809 return (success);
810 }
811
812 /***************************************************************************//**
813 * MSS_CAN_get_mask_n()
814 * See "mss_can.h" for details of how to use this function.
815 */
816 uint8_t
MSS_CAN_get_mask_n(mss_can_instance_t * this_can,uint8_t mailbox_number,uint32_t * pamr,uint32_t * pacr,uint16_t * pdta_amr,uint16_t * pdta_acr)817 MSS_CAN_get_mask_n
818 (
819 mss_can_instance_t* this_can,
820 uint8_t mailbox_number,
821 uint32_t *pamr,
822 uint32_t *pacr,
823 uint16_t *pdta_amr,
824 uint16_t *pdta_acr
825 )
826 {
827 if (mailbox_number >= CAN_RX_MAILBOX)
828 {
829 return (CAN_BASIC_CAN_MAILBOX);
830 }
831
832 *pamr = this_can->hw_reg->RxMsg[mailbox_number].AMR.L;
833 *pacr = this_can->hw_reg->RxMsg[mailbox_number].ACR.L;
834 *pdta_acr = this_can->hw_reg->RxMsg[mailbox_number].ACR_D;
835 *pdta_amr = this_can->hw_reg->RxMsg[mailbox_number].AMR_D;
836
837 return (CAN_OK);
838 }
839
840 /***************************************************************************//**
841 * MSS_CAN_set_mask_n()
842 * See "mss_can.h" for details of how to use this function.
843 */
844 uint8_t
MSS_CAN_set_mask_n(mss_can_instance_t * this_can,uint8_t mailbox_number,uint32_t amr,uint32_t acr,uint16_t dta_amr,uint16_t dta_acr)845 MSS_CAN_set_mask_n
846 (
847 mss_can_instance_t* this_can,
848 uint8_t mailbox_number,
849 uint32_t amr,
850 uint32_t acr,
851 uint16_t dta_amr,
852 uint16_t dta_acr
853 )
854 {
855 if (mailbox_number >= CAN_RX_MAILBOX)
856 {
857 return (CAN_BASIC_CAN_MAILBOX);
858 }
859
860 this_can->hw_reg->RxMsg[mailbox_number].AMR.L = amr;
861 this_can->hw_reg->RxMsg[mailbox_number].ACR.L = acr;
862 this_can->hw_reg->RxMsg[mailbox_number].AMR_D = (uint32_t)dta_amr;
863 this_can->hw_reg->RxMsg[mailbox_number].ACR_D = (uint32_t)dta_acr;
864
865 return (CAN_OK);
866 }
867
868 /***************************************************************************//**
869 * MSS_CAN_get_rx_buffer_status()
870 * See "mss_can.h" for details of how to use this function.
871 */
872 uint32_t
MSS_CAN_get_rx_buffer_status(mss_can_instance_t * this_can)873 MSS_CAN_get_rx_buffer_status
874 (
875 mss_can_instance_t* this_can
876 )
877 {
878 #ifdef CANMOD3
879 return (this_can->hw_reg->BufferStatus.L & 0x0000FFFF);
880 #else
881 return (this_can->hw_reg->BufferStatus.RXMSGAV);
882 #endif
883 }
884
885 /***************************************************************************//**
886 * MSS_CAN_get_tx_buffer_status()
887 * See "mss_can.h" for details of how to use this function.
888 */
889 uint32_t
MSS_CAN_get_tx_buffer_status(mss_can_instance_t * this_can)890 MSS_CAN_get_tx_buffer_status
891 (
892 mss_can_instance_t* this_can
893 )
894 {
895 #ifdef CANMOD3
896 return ((this_can->hw_reg->BufferStatus.L >> 16u) & 0x00FF);
897 #else
898 return (this_can->hw_reg->BufferStatus.TXREQ);
899 #endif
900 }
901
902 /***************************************************************************//**
903 * MSS_CAN_get_error_status()
904 * See "mss_can.h" for details of how to use this function.
905 */
906 uint8_t
MSS_CAN_get_error_status(mss_can_instance_t * this_can,uint32_t * status)907 MSS_CAN_get_error_status
908 (
909 mss_can_instance_t* this_can,
910 uint32_t *status
911 )
912 {
913 /* Supply error register info if user wants. */
914 *status = this_can->hw_reg->ErrorStatus.L;
915
916 /* 00 Error Active, 01 Error Passive, 1x Bus Off */
917 return ((uint8_t)(((*status) >> CAN_ERROR_STATUS_SHIFT) &
918 CAN_ERROR_STATUS_MASK));
919 }
920
921 /***************************************************************************//**
922 * MSS_CAN_get_rx_error_count()
923 * See "mss_can.h" for details of how to use this function.
924 */
925 uint32_t
MSS_CAN_get_rx_error_count(mss_can_instance_t * this_can)926 MSS_CAN_get_rx_error_count
927 (
928 mss_can_instance_t* this_can
929 )
930 {
931 return ((this_can->hw_reg->ErrorStatus.L >> CAN_ERROR_COUNT_SHIFT) & \
932 CAN_ERROR_COUNT_MASK);
933 }
934
935 /***************************************************************************//**
936 * MSS_CAN_get_rx_gte96()
937 * See "mss_can.h" for details of how to use this function.
938 */
939 uint32_t
MSS_CAN_get_rx_gte96(mss_can_instance_t * this_can)940 MSS_CAN_get_rx_gte96
941 (
942 mss_can_instance_t* this_can
943 )
944 {
945 return ((this_can->hw_reg->ErrorStatus.L >> CAN_RX_GTE96_SHIFT) & \
946 CAN_FLAG_MASK);
947 }
948
949 /***************************************************************************//**
950 * MSS_CAN_get_tx_error_count()
951 * See "mss_can.h" for details of how to use this function.
952 */
953 uint32_t
MSS_CAN_get_tx_error_count(mss_can_instance_t * this_can)954 MSS_CAN_get_tx_error_count
955 (
956 mss_can_instance_t* this_can
957 )
958 {
959 return (this_can->hw_reg->ErrorStatus.L & CAN_ERROR_COUNT_MASK);
960 }
961
962 /***************************************************************************//**
963 * MSS_CAN_get_tx_gte96 ()
964 * See "mss_can.h" for details of how to use this function.
965 */
966 uint32_t
MSS_CAN_get_tx_gte96(mss_can_instance_t * this_can)967 MSS_CAN_get_tx_gte96
968 (
969 mss_can_instance_t* this_can
970 )
971 {
972 return ((this_can->hw_reg->ErrorStatus.L >> CAN_TXGTE96_SHIFT) & \
973 CAN_FLAG_MASK);
974 }
975
976 /*******************************************************************************
977 * Global initialization for all modes
978 */
global_init(mss_can_instance_t * this_wd)979 static void global_init
980 (
981 mss_can_instance_t* this_wd
982 )
983 {
984 if (&g_mss_can_0_lo == this_wd)
985 {
986 this_wd->hw_reg = MSS_CAN_0_LO_BASE;
987 this_wd->irqn = CAN0_PLIC;
988 this_wd->int_type = 0;
989 }
990 else if (&g_mss_can_1_lo == this_wd)
991 {
992 this_wd->hw_reg = MSS_CAN_1_LO_BASE;
993 this_wd->irqn = CAN1_PLIC;
994 this_wd->int_type = 0;
995 }
996 else if (&g_mss_can_0_hi == this_wd)
997 {
998 this_wd->hw_reg = MSS_CAN_0_HI_BASE;
999 this_wd->irqn = CAN0_PLIC;
1000 this_wd->int_type = 0;
1001 }
1002 else if (&g_mss_can_1_hi == this_wd)
1003 {
1004 this_wd->hw_reg = MSS_CAN_1_HI_BASE;
1005 this_wd->irqn = CAN1_PLIC;
1006 this_wd->int_type = 0;
1007 }
1008 else
1009 {
1010 ;/* LDRA Warning */
1011 }
1012 }
1013
1014 #ifndef MSS_CAN_USER_ISR
1015 /***************************************************************************//**
1016 * CAN interrupt service routine.
1017 * CAN_IRQHandler is included within the RISC-V vector table as part of the
1018 * MPFS HAL.
1019 */
External_can0_plic_IRQHandler(void)1020 uint8_t External_can0_plic_IRQHandler(void)
1021 {
1022 #ifdef MSS_CAN_ENABLE_INTERRUPTS
1023 /* User provided code is required here to handle interrupts from the MSS CAN
1024 * peripheral. Remove the assert once this is in place.*/
1025 ASSERT(!"An ISR is required here if interrupts are enabled");
1026 #else
1027 ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \
1028 disabled");
1029 #endif
1030 return 0;
1031 }
1032
can1_IRQHandler(void)1033 uint8_t can1_IRQHandler(void)
1034 {
1035 #ifdef MSS_CAN_ENABLE_INTERRUPTS
1036 /* User provided code is required here to handle interrupts from the MSS CAN
1037 * peripheral. Remove the assert once this is in place.*/
1038 ASSERT(!"An ISR is required here if interrupts are enabled");
1039 #else
1040 ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \
1041 disabled");
1042 #endif
1043 return 0;
1044 }
1045 #endif
1046
1047 #ifdef __cplusplus
1048 }
1049 #endif
1050