/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC (MPFS) microprocessor subsystem CAN bare metal software driver * implementation. */ /******************************************************************************* * Include files */ #include "mpfs_hal/mss_hal.h" #include "mss_can.h" #ifdef __cplusplus extern "C" { #endif /******************************************************************************* * Macros */ #define CAN_ID_SHIFT 18u #define CAN_ERROR_STATUS_SHIFT 16u #define CAN_ERROR_STATUS_MASK 0x03u #define CAN_RX_GTE96_SHIFT 19u #define CAN_FLAG_MASK 0x01u #define CAN_ERROR_COUNT_SHIFT 8u #define CAN_ERROR_COUNT_MASK 0xFFu #define CAN_TXGTE96_SHIFT 18u #define CAN_INT_MASK 0xFFFFFFFCu #define ENABLE 1u #define DISABLE 0u #define SYSREG_CAN_SOFTRESET_MASK (uint32_t)(3 << 14u) /******************************************************************************* * Instance definition */ mss_can_instance_t g_mss_can_0_lo; mss_can_instance_t g_mss_can_1_lo; mss_can_instance_t g_mss_can_0_hi; mss_can_instance_t g_mss_can_1_hi; static void global_init ( mss_can_instance_t* this_wd ); /***************************************************************************//** * MSS_CAN_init() * See "mss_can.h" for details of how to use this function. */ 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 ) { uint32_t temp; uint8_t mailbox_number; uint8_t ret_value; mss_can_rxmsgobject canrxobj; global_init(this_can); /* Initialize the device structure */ this_can->basic_can_rx_mb = basic_can_rx_mb; this_can->basic_can_tx_mb = basic_can_tx_mb; /* Initialize the rx mailbox */ canrxobj.ID = 0u; canrxobj.DATAHIGH = 0u; canrxobj.DATALOW = 0u; canrxobj.AMR.L = 0u; canrxobj.ACR.L = 0u; canrxobj.AMR_D = 0u; canrxobj.ACR_D = 0u; canrxobj.RXB.L = (0u | CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL); for (mailbox_number = 0u; mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { ret_value = MSS_CAN_config_buffer_n(this_can, mailbox_number, &canrxobj); } /* Configure CAN controller */ if (CAN_SPEED_MANUAL == bitrate) { /* * If user wants to specify registers directly Check if parameters * meet minimums. */ if (pcan_config->CFG_TSEG1 < 2u) { return (CAN_TSEG1_TOO_SMALL ); } if ((pcan_config->CFG_TSEG2 == 0u) || ((pcan_config->SAMPLING_MODE == 1u) && (pcan_config->CFG_TSEG2 == 1u))) { return (CAN_TSEG2_TOO_SMALL); } temp = pcan_config->CFG_SJW; if ((temp > pcan_config->CFG_TSEG1) || (temp > pcan_config->CFG_TSEG2)) { return (CAN_SJW_TOO_BIG); } this_can->hw_reg->Config.L = pcan_config->L; } else { /* User has chosen a default setting. */ this_can->hw_reg->Config.L = bitrate; } /* Disable Interrupts */ this_can->hw_reg->IntEbl.L = DISABLE; return (CAN_OK); } /***************************************************************************//** * MSS_CAN_set_config_reg() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_set_config_reg ( mss_can_instance_t* this_can, uint32_t cfg ) { /* Clear all pending interrupts */ this_can->hw_reg->IntStatus.L = DISABLE; /* Disable CAN Device */ this_can->hw_reg->Command.RUN_STOP = DISABLE; /* Disable receive interrupts. */ this_can->hw_reg->IntEbl.RX_MSG = DISABLE; /* Disable interrupts from CAN device. */ this_can->hw_reg->IntEbl.INT_EBL = DISABLE; /* Sets configuration bits */ this_can->hw_reg->Config.L = cfg; MSS_CAN_start(this_can); } /***************************************************************************//** * MSS_CAN_set_mode() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_set_mode ( mss_can_instance_t* this_can, mss_can_mode_t mode ) { this_can->hw_reg->Command.RUN_STOP = DISABLE; if (CANOP_SW_RESET == mode) { SYSREG->SOFT_RESET_CR |= SYSREG_CAN_SOFTRESET_MASK; SYSREG->SOFT_RESET_CR &= ~SYSREG_CAN_SOFTRESET_MASK; } else { this_can->hw_reg->Command.L = (uint32_t)mode; } } /***************************************************************************//** * MSS_CAN_start() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_start ( mss_can_instance_t* this_can ) { /* Clear all pending interrupts*/ this_can->hw_reg->IntStatus.L = DISABLE; /* Enable CAN Device*/ this_can->hw_reg->Command.RUN_STOP = ENABLE; /* Enable CAN Interrupt at NVIC level- if supported */ #ifdef MSS_CAN_ENABLE_INTERRUPTS if (if (&g_mss_can_0_lo == this_can) || (&g_mss_can_0_hi == this_can)) { PLIC_DisableIRQ(CAN0_PLIC); } else { PLIC_DisableIRQ(CAN1_PLIC); } #endif /* Enable receive interrupts. */ this_can->hw_reg->IntEbl.RX_MSG = ENABLE; /* Enable interrupts from CAN device.*/ this_can->hw_reg->IntEbl.INT_EBL = ENABLE; } /***************************************************************************//** * MSS_CAN_stop() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_stop ( mss_can_instance_t* this_can ) { this_can->hw_reg->Command.RUN_STOP = DISABLE; } /***************************************************************************//** * MSS_CAN_get_id() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_id ( pmss_can_msgobject pmsg ) { if (pmsg->IDE) { return (pmsg->ID); } else { return (pmsg->ID >> CAN_ID_SHIFT); } } /***************************************************************************//** * MSS_CAN_set_id() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_set_id ( pmss_can_msgobject pmsg ) { if (pmsg->IDE) { return (pmsg->ID); } else { return (pmsg->ID << CAN_ID_SHIFT); } } /***************************************************************************//** * MSS_CAN_get_msg_filter_mask() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_msg_filter_mask ( uint32_t id, uint8_t ide, uint8_t rtr ) { if (ide) { id <<= 3u; } else { id <<= 21; /* Set unused ID bits to 1! */ id |= (0x3FFFF << 3u); } id |= ((uint32_t)(ide << 2u) | (uint32_t)(rtr << 1u)); return (id); } /***************************************************************************//** * MSS_CAN_set_int_ebl() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_set_int_ebl ( mss_can_instance_t* this_can, uint32_t irq_flag ) { this_can->hw_reg->IntEbl.L |= irq_flag; } /***************************************************************************//** * MSS_CAN_clear_int_ebl() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_clear_int_ebl ( mss_can_instance_t* this_can, uint32_t irq_flag ) { this_can->hw_reg->IntEbl.L &= ~irq_flag; } /***************************************************************************//** * MSS_CAN_get_global_int_ebl() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_global_int_ebl ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->IntEbl.INT_EBL); } /***************************************************************************//** * MSS_CAN_get_int_ebl() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_int_ebl ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->IntEbl.L & CAN_INT_MASK); } /***************************************************************************//** * MSS_CAN_clear_int_status() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_clear_int_status ( mss_can_instance_t* this_can, uint32_t irq_flag ) { this_can->hw_reg->IntStatus.L = irq_flag; } /***************************************************************************//** * MSS_CAN_get_int_status() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_int_status ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->IntStatus.L); } /***************************************************************************//** * MSS_CAN_set_rtr_message_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_set_rtr_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { return (CAN_BASIC_CAN_MAILBOX); } /* Is buffer configured for RTR auto-replay? */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLY == 0u) { return (CAN_NO_RTR_MAILBOX); } else { /* Transfer the ID. */ this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; return (CAN_OK); } } /***************************************************************************//** * MSS_CAN_get_rtr_message_abort_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_rtr_message_abort_n ( mss_can_instance_t* this_can, uint8_t mailbox_number ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { /* Mailbox is configured for basic CAN */ return (CAN_BASIC_CAN_MAILBOX); } /* Set abort request */ this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRABORT = 1u; /* Check the abort is granted */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLYPEND == 0u) { /* If the RX buffer isn't busy. Abort was successful */ return (CAN_OK); } else { /* Message not aborted.*/ return (CAN_ERR); } } /***************************************************************************//** * MSS_CAN_config_buffer() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_config_buffer ( mss_can_instance_t* this_can, pmss_can_filterobject pfilter ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_rx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that has a message available */ for (mailbox_number = CAN_RX_MAILBOX - this_can->basic_can_rx_mb; \ mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { /* Set filters */ this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pfilter->ACR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pfilter->AMR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pfilter->AMCR_D.MASK; this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pfilter->AMCR_D.CODE; /* Configure mailbox */ if (mailbox_number < (CAN_RX_MAILBOX - 1)) { /* set link flag, if not last buffer */ this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \ CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL | \ CAN_RX_LINK_EBL); } else { this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \ CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL); } success = CAN_OK; } return (success); } /***************************************************************************//** * MSS_CAN_config_buffer_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_config_buffer_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_rxmsgobject pmsg ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { return (CAN_BASIC_CAN_MAILBOX); } /* Configure mailbox */ this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pmsg->ACR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pmsg->AMR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pmsg->AMR_D; this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pmsg->ACR_D; this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (pmsg->RXB.L | \ CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \ CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL); return (CAN_OK); } /***************************************************************************//** * MSS_CAN_get_message_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { return (CAN_BASIC_CAN_MAILBOX); } /* Check that a new message is available and get it */ if ((ENABLE == this_can->hw_reg->Command.RUN_STOP) && (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV)) { /* Copy ID */ pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID; /* Copy 4 of the data bytes */ pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW; /* Copy the other 4 data bytes. */ pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH; /* Get DLC, IDE and RTR and time stamp. */ pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L; /* Ack that it's been removed from the FIFO */ this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE; /* And let app know there is a message. */ return (CAN_VALID_MSG); } else { return (CAN_NO_MSG); } } /******************************************************************************* * MSS_CAN_get_message() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_message ( mss_can_instance_t* this_can, pmss_can_msgobject pmsg ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_rx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that has a message available */ for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb; \ mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { /* Check that if there is a valid message */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV) { /* Copy ID */ pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID; /* Copy 4 of the data bytes */ pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW; /* Copy the other 4 data bytes.*/ pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH; /* Get DLC, IDE and RTR and time stamp.*/ pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L; /* Ack that it's been removed from the FIFO */ this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE; success = CAN_VALID_MSG; break; } } return (success); } /***************************************************************************//** * MSS_CAN_get_message_av() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_message_av ( mss_can_instance_t* this_can ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_rx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that has a message available */ for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb; \ mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { /* Check that buffer is enabled and contains a message */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV) { success = CAN_VALID_MSG; break; } } return (success); } /***************************************************************************//** * MSS_CAN_send_message_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ) { /* Can't send if device is disabled */ if (DISABLE == this_can->hw_reg->Command.RUN_STOP) { /* Message not sent. */ return (CAN_NO_MSG); } /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb)) { /* mailbox is configured for basic CAN */ return (CAN_BASIC_CAN_MAILBOX); } if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u) { /* If the Tx buffer isn't busy.... */ this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \ CAN_TX_WPNH_EBL | \ CAN_TX_REQ); return (CAN_VALID_MSG); } else { /* Message not sent. */ return (CAN_NO_MSG); } } /***************************************************************************//** * MSS_CAN_send_message_abort_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message_abort_n ( mss_can_instance_t* this_can, uint8_t mailbox_number ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb)) { /* mailbox is configured for basic CAN */ return (CAN_BASIC_CAN_MAILBOX); } /* Set abort request */ this_can->hw_reg->TxMsg[mailbox_number].TXB.L = ((this_can->hw_reg->TxMsg[mailbox_number].TXB.L & ~CAN_TX_REQ) | \ CAN_TX_ABORT); /* Check the abort is granted */ if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXABORT == 0u) { /* If the Tx buffer isn't busy, Abort was successful */ return (CAN_OK); } else { /* Message not aborted. */ return (CAN_ERR); } } /***************************************************************************//** * MSS_CAN_send_message_ready() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message_ready ( mss_can_instance_t* this_can ) { uint8_t success = CAN_ERR; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_tx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that is available */ for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb; \ mailbox_number < CAN_TX_MAILBOX; mailbox_number++) { if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u) { /* Tx buffer isn't busy */ success = CAN_OK; break; } } return (success); } /***************************************************************************//** * MSS_CAN_send_message() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message ( mss_can_instance_t* this_can, pmss_can_msgobject pmsg ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_tx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that is available */ for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb; \ mailbox_number < CAN_TX_MAILBOX; mailbox_number++) { /* Check which transmit mailbox is not busy and use it. */ if ((MSS_CAN_get_tx_buffer_status(this_can) & (1u << mailbox_number)) == 0) { /* If the Tx buffer isn't busy.... */ this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \ CAN_TX_WPNH_EBL | \ CAN_TX_REQ); success = CAN_VALID_MSG; break; } } return (success); } /***************************************************************************//** * MSS_CAN_get_mask_n() * See "mss_can.h" for details of how to use this function. */ 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 ) { if (mailbox_number >= CAN_RX_MAILBOX) { return (CAN_BASIC_CAN_MAILBOX); } *pamr = this_can->hw_reg->RxMsg[mailbox_number].AMR.L; *pacr = this_can->hw_reg->RxMsg[mailbox_number].ACR.L; *pdta_acr = this_can->hw_reg->RxMsg[mailbox_number].ACR_D; *pdta_amr = this_can->hw_reg->RxMsg[mailbox_number].AMR_D; return (CAN_OK); } /***************************************************************************//** * MSS_CAN_set_mask_n() * See "mss_can.h" for details of how to use this function. */ 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 ) { if (mailbox_number >= CAN_RX_MAILBOX) { return (CAN_BASIC_CAN_MAILBOX); } this_can->hw_reg->RxMsg[mailbox_number].AMR.L = amr; this_can->hw_reg->RxMsg[mailbox_number].ACR.L = acr; this_can->hw_reg->RxMsg[mailbox_number].AMR_D = (uint32_t)dta_amr; this_can->hw_reg->RxMsg[mailbox_number].ACR_D = (uint32_t)dta_acr; return (CAN_OK); } /***************************************************************************//** * MSS_CAN_get_rx_buffer_status() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_rx_buffer_status ( mss_can_instance_t* this_can ) { #ifdef CANMOD3 return (this_can->hw_reg->BufferStatus.L & 0x0000FFFF); #else return (this_can->hw_reg->BufferStatus.RXMSGAV); #endif } /***************************************************************************//** * MSS_CAN_get_tx_buffer_status() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_tx_buffer_status ( mss_can_instance_t* this_can ) { #ifdef CANMOD3 return ((this_can->hw_reg->BufferStatus.L >> 16u) & 0x00FF); #else return (this_can->hw_reg->BufferStatus.TXREQ); #endif } /***************************************************************************//** * MSS_CAN_get_error_status() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_error_status ( mss_can_instance_t* this_can, uint32_t *status ) { /* Supply error register info if user wants. */ *status = this_can->hw_reg->ErrorStatus.L; /* 00 Error Active, 01 Error Passive, 1x Bus Off */ return ((uint8_t)(((*status) >> CAN_ERROR_STATUS_SHIFT) & CAN_ERROR_STATUS_MASK)); } /***************************************************************************//** * MSS_CAN_get_rx_error_count() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_rx_error_count ( mss_can_instance_t* this_can ) { return ((this_can->hw_reg->ErrorStatus.L >> CAN_ERROR_COUNT_SHIFT) & \ CAN_ERROR_COUNT_MASK); } /***************************************************************************//** * MSS_CAN_get_rx_gte96() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_rx_gte96 ( mss_can_instance_t* this_can ) { return ((this_can->hw_reg->ErrorStatus.L >> CAN_RX_GTE96_SHIFT) & \ CAN_FLAG_MASK); } /***************************************************************************//** * MSS_CAN_get_tx_error_count() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_tx_error_count ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->ErrorStatus.L & CAN_ERROR_COUNT_MASK); } /***************************************************************************//** * MSS_CAN_get_tx_gte96 () * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_tx_gte96 ( mss_can_instance_t* this_can ) { return ((this_can->hw_reg->ErrorStatus.L >> CAN_TXGTE96_SHIFT) & \ CAN_FLAG_MASK); } /******************************************************************************* * Global initialization for all modes */ static void global_init ( mss_can_instance_t* this_wd ) { if (&g_mss_can_0_lo == this_wd) { this_wd->hw_reg = MSS_CAN_0_LO_BASE; this_wd->irqn = CAN0_PLIC; this_wd->int_type = 0; } else if (&g_mss_can_1_lo == this_wd) { this_wd->hw_reg = MSS_CAN_1_LO_BASE; this_wd->irqn = CAN1_PLIC; this_wd->int_type = 0; } else if (&g_mss_can_0_hi == this_wd) { this_wd->hw_reg = MSS_CAN_0_HI_BASE; this_wd->irqn = CAN0_PLIC; this_wd->int_type = 0; } else if (&g_mss_can_1_hi == this_wd) { this_wd->hw_reg = MSS_CAN_1_HI_BASE; this_wd->irqn = CAN1_PLIC; this_wd->int_type = 0; } else { ;/* LDRA Warning */ } } #ifndef MSS_CAN_USER_ISR /***************************************************************************//** * CAN interrupt service routine. * CAN_IRQHandler is included within the RISC-V vector table as part of the * MPFS HAL. */ uint8_t External_can0_plic_IRQHandler(void) { #ifdef MSS_CAN_ENABLE_INTERRUPTS /* User provided code is required here to handle interrupts from the MSS CAN * peripheral. Remove the assert once this is in place.*/ ASSERT(!"An ISR is required here if interrupts are enabled"); #else ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \ disabled"); #endif return 0; } uint8_t can1_IRQHandler(void) { #ifdef MSS_CAN_ENABLE_INTERRUPTS /* User provided code is required here to handle interrupts from the MSS CAN * peripheral. Remove the assert once this is in place.*/ ASSERT(!"An ISR is required here if interrupts are enabled"); #else ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \ disabled"); #endif return 0; } #endif #ifdef __cplusplus } #endif