123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- /**************************************************************************//**
- *
- * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2020-6-22 ChingI First version
- * 2022-1-8 Wayne Fix IE issue
- *
- ******************************************************************************/
- #include <rtconfig.h>
- #if defined(BSP_USING_CAN)
- #include <rtdevice.h>
- #include <rthw.h>
- #include "NuMicro.h"
- /* Private Define ---------------------------------------------------------------*/
- #define RX_MSG_ID_INDEX 16
- #define IS_CAN_STDID(STDID) ((STDID) <= 0x7FFU)
- #define IS_CAN_EXTID(EXTID) ((EXTID) <= 0x1FFFFFFFU)
- #define IS_CAN_DLC(DLC) ((DLC) <= 8U)
- /* Default config for serial_configure structure */
- #define NU_CAN_CONFIG_DEFAULT \
- { \
- CAN1MBaud, /* 1M bits/s */ \
- RT_CANMSG_BOX_SZ, /* message box max size */ \
- RT_CANSND_BOX_NUM, /* message box number */ \
- RT_CAN_MODE_NORMAL, /* Normal mode */ \
- 0, /* privmode */ \
- 0, /* reserved */ \
- 100, /* Timeout Tick */ \
- }
- enum
- {
- CAN_START = -1,
- #if defined(BSP_USING_CAN0)
- CAN0_IDX,
- #endif
- #if defined(BSP_USING_CAN1)
- CAN1_IDX,
- #endif
- #if defined(BSP_USING_CAN2)
- CAN2_IDX,
- #endif
- CAN_CNT
- };
- /* Private Typedef --------------------------------------------------------------*/
- struct nu_can
- {
- struct rt_can_device dev;
- char *name;
- CAN_T *base;
- IRQn_Type irqn;
- uint32_t rstidx;
- uint32_t int_flag;
- };
- typedef struct nu_can *nu_can_t;
- /* Private functions ------------------------------------------------------------*/
- static rt_err_t nu_can_configure(struct rt_can_device *can, struct can_configure *cfg);
- static rt_err_t nu_can_control(struct rt_can_device *can, int cmd, void *arg);
- static int nu_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
- static int nu_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno);
- static void nu_can_isr(nu_can_t can);
- static struct nu_can nu_can_arr[] =
- {
- #if defined(BSP_USING_CAN0)
- {
- .name = "can0",
- .base = CAN0,
- .rstidx = CAN0_RST,
- .irqn = CAN0_IRQn,
- },
- #endif
- #if defined(BSP_USING_CAN1)
- {
- .name = "can1",
- .base = CAN1,
- .rstidx = CAN1_RST,
- .irqn = CAN1_IRQn,
- },
- #endif
- #if defined(BSP_USING_CAN2)
- {
- .name = "can2",
- .base = CAN2,
- .rstidx = CAN2_RST,
- .irqn = CAN2_IRQn,
- },
- #endif
- }; /* struct nu_can */
- /* Public functions ------------------------------------------------------------*/
- /* Private variables ------------------------------------------------------------*/
- static const struct rt_can_ops nu_can_ops =
- {
- .configure = nu_can_configure,
- .control = nu_can_control,
- .sendmsg = nu_can_sendmsg,
- .recvmsg = nu_can_recvmsg,
- };
- static const struct can_configure nu_can_default_config = NU_CAN_CONFIG_DEFAULT;
- /* Interrupt Handle Function ----------------------------------------------------*/
- #if defined(BSP_USING_CAN0)
- /* CAN0 interrupt entry */
- void CAN0_IRQHandler(void)
- {
- /* enter interrupt */
- rt_interrupt_enter();
- nu_can_isr(&nu_can_arr[CAN0_IDX]);
- /* leave interrupt */
- rt_interrupt_leave();
- }
- #endif
- #if defined(BSP_USING_CAN1)
- /* CAN1 interrupt entry */
- void CAN1_IRQHandler(void)
- {
- /* enter interrupt */
- rt_interrupt_enter();
- nu_can_isr(&nu_can_arr[CAN1_IDX]);
- /* leave interrupt */
- rt_interrupt_leave();
- }
- #endif
- #if defined(BSP_USING_CAN2)
- /* CAN2 interrupt entry */
- void CAN2_IRQHandler(void)
- {
- /* enter interrupt */
- rt_interrupt_enter();
- nu_can_isr(&nu_can_arr[CAN2_IDX]);
- /* leave interrupt */
- rt_interrupt_leave();
- }
- #endif
- /* Private Variables ------------------------------------------------------------*/
- static void nu_can_isr(nu_can_t psNuCAN)
- {
- /* Get base address of CAN register */
- CAN_T *base = psNuCAN->base;
- /* Get interrupt event */
- uint32_t u32IIDRstatus = CAN_GET_INT_PENDING_STATUS(base) & CAN_IIDR_INTID_Msk;
- /* Check Status Interrupt Flag (Error status Int and Status change Int) */
- if (u32IIDRstatus == 0x00008000)
- {
- /**************************/
- /* Status Change interrupt*/
- /**************************/
- if (base->STATUS & CAN_STATUS_TXOK_Msk)
- {
- base->STATUS &= ~CAN_STATUS_TXOK_Msk; /* Clear Tx Ok status*/
- #ifndef RT_CAN_USING_HDR
- if (psNuCAN->int_flag & RT_DEVICE_FLAG_INT_TX)
- {
- /*Using as Lisen,Loopback,Loopback+Lisen mode*/
- rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_TX_DONE);
- }
- #endif
- }
- if (base->STATUS & CAN_STATUS_RXOK_Msk)
- {
- base->STATUS &= ~CAN_STATUS_RXOK_Msk; /* Clear Rx Ok status*/
- #ifndef RT_CAN_USING_HDR
- if (psNuCAN->int_flag & RT_DEVICE_FLAG_INT_RX)
- {
- /*Using as Lisen,Loopback,Loopback+Lisen mode*/
- rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_RX_IND);
- }
- #endif
- }
- /**************************/
- /* Error Status interrupt */
- /**************************/
- if (base->STATUS & CAN_STATUS_EWARN_Msk)
- {
- rt_kprintf("[%s]EWARN INT\n", psNuCAN->name) ;
- }
- if (base->STATUS & CAN_STATUS_BOFF_Msk)
- {
- rt_kprintf("[%s]BUSOFF INT\n", psNuCAN->name) ;
- /* To release busoff pin */
- CAN_EnterInitMode(base, CAN_CON_INIT_Msk | CAN_CON_CCE_Msk);
- CAN_LeaveInitMode(base);
- }
- if (base->STATUS & CAN_STATUS_LEC_Msk)
- {
- rt_kprintf("[%s] Last Error Code %03x\n", psNuCAN->name, base->STATUS & CAN_STATUS_LEC_Msk) ;
- }
- }
- #ifdef RT_CAN_USING_HDR
- /*IntId: 0x0001-0x0020, Number of Message Object which caused the interrupt.*/
- else if (u32IIDRstatus > 0 && u32IIDRstatus <= 32)
- {
- if ((psNuCAN->int_flag & RT_DEVICE_FLAG_INT_TX) &&
- (u32IIDRstatus <= RX_MSG_ID_INDEX))
- {
- /*Message RAM 0~RX_MSG_ID_INDEX for CAN Tx using*/
- rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_TX_DONE);
- }
- else if (psNuCAN->int_flag & RT_DEVICE_FLAG_INT_RX)
- {
- /*Message RAM RX_MSG_ID_INDEX~31 for CAN Rx using*/
- rt_hw_can_isr(&psNuCAN->dev, (RT_CAN_EVENT_RX_IND | ((u32IIDRstatus - 1) << 8)));
- }
- CAN_CLR_INT_PENDING_BIT(base, (u32IIDRstatus - 1)); /* Clear Interrupt Pending */
- }
- #endif
- }
- static void nu_can_ie(nu_can_t psNuCAN)
- {
- uint32_t u32CanIE = CAN_CON_IE_Msk;
- if (psNuCAN->int_flag & (RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX))
- {
- u32CanIE |= CAN_CON_SIE_Msk;
- }
- else
- {
- u32CanIE &= ~CAN_CON_SIE_Msk;
- }
- if (psNuCAN->int_flag & RT_DEVICE_CAN_INT_ERR)
- {
- u32CanIE |= CAN_CON_EIE_Msk;
- }
- else
- {
- u32CanIE &= ~CAN_CON_EIE_Msk;
- }
- if (u32CanIE & (CAN_CON_SIE_Msk | CAN_CON_EIE_Msk))
- {
- CAN_EnableInt(psNuCAN->base, u32CanIE);
- /* Enable interrupt. */
- NVIC_EnableIRQ(psNuCAN->irqn);
- }
- else
- {
- u32CanIE |= (CAN_CON_IE_Msk | CAN_CON_SIE_Msk);
- CAN_DisableInt(psNuCAN->base, u32CanIE);
- /* Disable interrupt. */
- NVIC_DisableIRQ(psNuCAN->irqn);
- }
- }
- static rt_err_t nu_can_configure(struct rt_can_device *can, struct can_configure *cfg)
- {
- nu_can_t psNuCAN = (nu_can_t)can;
- uint32_t u32CANMode;
- RT_ASSERT(can);
- RT_ASSERT(cfg);
- /* Get base address of CAN register */
- CAN_T *base = psNuCAN->base;
- /* Reset this module */
- SYS_ResetModule(psNuCAN->rstidx);
- u32CANMode = (cfg->mode == RT_CAN_MODE_NORMAL) ? CAN_NORMAL_MODE : CAN_BASIC_MODE;
- /*Set the CAN Bit Rate and Operating mode*/
- if (CAN_Open(base, cfg->baud_rate, u32CANMode) != cfg->baud_rate)
- goto exit_nu_can_configure;
- switch (cfg->mode)
- {
- case RT_CAN_MODE_NORMAL:
- #ifdef RT_CAN_USING_HDR
- CAN_LeaveTestMode(base);
- #else
- CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk);
- #endif
- break;
- case RT_CAN_MODE_LISEN:
- CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_SILENT_Msk);
- break;
- case RT_CAN_MODE_LOOPBACK:
- CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_LBACK_Msk);
- break;
- case RT_CAN_MODE_LOOPBACKANLISEN:
- CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_SILENT_Msk | CAN_TEST_LBACK_Msk);
- break;
- default:
- rt_kprintf("Unsupported Operating mode");
- goto exit_nu_can_configure;
- }
- nu_can_ie(psNuCAN);
- return RT_EOK;
- exit_nu_can_configure:
- CAN_Close(base);
- return -(RT_ERROR);
- }
- static rt_err_t nu_can_control(struct rt_can_device *can, int cmd, void *arg)
- {
- rt_uint32_t argval = (rt_uint32_t)arg;
- nu_can_t psNuCAN = (nu_can_t)can;
- RT_ASSERT(can);
- switch (cmd)
- {
- case RT_DEVICE_CTRL_SET_INT:
- psNuCAN->int_flag |= argval;
- nu_can_ie(psNuCAN);
- break;
- case RT_DEVICE_CTRL_CLR_INT:
- psNuCAN->int_flag &= ~argval;
- nu_can_ie(psNuCAN);
- break;
- case RT_CAN_CMD_SET_FILTER:
- {
- struct rt_can_filter_config *filter_cfg = (struct rt_can_filter_config *)arg;
- for (int i = 0; i < filter_cfg->count; i++)
- {
- /*set the filter message object*/
- if (filter_cfg->items[i].mode == 1)
- {
- if (CAN_SetRxMsgObjAndMsk(psNuCAN->base, MSG(filter_cfg->items[i].hdr + RX_MSG_ID_INDEX), filter_cfg->items[i].ide, filter_cfg->items[i].id, filter_cfg->items[i].mask, FALSE) == FALSE)
- {
- return -(RT_ERROR);
- }
- }
- else
- {
- /*set the filter message object*/
- if (CAN_SetRxMsgAndMsk(psNuCAN->base, MSG(filter_cfg->items[i].hdr + RX_MSG_ID_INDEX), filter_cfg->items[i].ide, filter_cfg->items[i].id, filter_cfg->items[i].mask) == FALSE)
- {
- return -(RT_ERROR);
- }
- }
- }
- }
- break;
- case RT_CAN_CMD_SET_MODE:
- if ((argval == RT_CAN_MODE_NORMAL) ||
- (argval == RT_CAN_MODE_LISEN) ||
- (argval == RT_CAN_MODE_LOOPBACK) ||
- (argval == RT_CAN_MODE_LOOPBACKANLISEN))
- {
- if (argval != can->config.mode)
- {
- can->config.mode = argval;
- return nu_can_configure(can, &can->config);
- }
- }
- else
- {
- return -(RT_ERROR);
- }
- break;
- case RT_CAN_CMD_SET_BAUD:
- {
- if ((argval == CAN1MBaud) ||
- (argval == CAN800kBaud) ||
- (argval == CAN500kBaud) ||
- (argval == CAN250kBaud) ||
- (argval == CAN125kBaud) ||
- (argval == CAN100kBaud) ||
- (argval == CAN50kBaud) ||
- (argval == CAN20kBaud) ||
- (argval == CAN10kBaud))
- {
- if (argval != can->config.baud_rate)
- {
- can->config.baud_rate = argval;
- return nu_can_configure(can, &can->config);
- }
- }
- else
- {
- return -(RT_ERROR);
- }
- }
- break;
- case RT_CAN_CMD_SET_PRIV:
- if (argval != RT_CAN_MODE_PRIV &&
- argval != RT_CAN_MODE_NOPRIV)
- {
- return -(RT_ERROR);
- }
- if (argval != can->config.privmode)
- {
- can->config.privmode = argval;
- return nu_can_configure(can, &can->config);
- }
- break;
- case RT_CAN_CMD_GET_STATUS:
- {
- rt_uint32_t errtype = psNuCAN->base->ERR;
- RT_ASSERT(arg);
- /*Receive Error Counter, return value is with Receive Error Passive.*/
- can->status.rcverrcnt = (errtype >> 8);
- /*Transmit Error Counter*/
- can->status.snderrcnt = (errtype & 0xFF);
- /*Last Error Type*/
- can->status.lasterrtype = CAN_GET_INT_STATUS(psNuCAN->base) & 0x8000;
- /*Status error code*/
- can->status.errcode = CAN_GET_INT_STATUS(psNuCAN->base) & 0x07;
- rt_memcpy(arg, &can->status, sizeof(struct rt_can_status));
- }
- break;
- default:
- return -(RT_EINVAL);
- }
- return RT_EOK;
- }
- static int nu_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno)
- {
- STR_CANMSG_T tMsg;
- struct rt_can_msg *pmsg;
- nu_can_t psNuCAN = (nu_can_t)can;
- RT_ASSERT(can);
- RT_ASSERT(buf);
- pmsg = (struct rt_can_msg *) buf;
- if (pmsg->ide == RT_CAN_STDID && IS_CAN_STDID(pmsg->id))
- {
- /* Standard ID (11 bits)*/
- tMsg.IdType = CAN_STD_ID;
- tMsg.Id = pmsg->id ;
- }
- else if (pmsg->ide == RT_CAN_EXTID && IS_CAN_EXTID(pmsg->id))
- {
- /* Extended ID (29 bits)*/
- tMsg.IdType = CAN_EXT_ID;
- tMsg.Id = pmsg->id ;
- }
- else
- {
- goto exit_nu_can_sendmsg;
- }
- if (pmsg->rtr == RT_CAN_DTR)
- {
- /* Data frame */
- tMsg.FrameType = CAN_DATA_FRAME;
- }
- else if (pmsg->rtr == RT_CAN_RTR)
- {
- /* Remote frame */
- tMsg.FrameType = CAN_REMOTE_FRAME;
- }
- else
- {
- goto exit_nu_can_sendmsg;
- }
- /* Check the parameters */
- if (IS_CAN_DLC(pmsg->len))
- {
- tMsg.DLC = pmsg->len;
- }
- else
- {
- goto exit_nu_can_sendmsg;
- }
- if (pmsg->data && pmsg->len)
- {
- rt_memcpy(&tMsg.Data[0], pmsg->data, pmsg->len);
- }
- else
- {
- goto exit_nu_can_sendmsg;
- }
- /* Configure Msg RAM and send the Msg in the RAM. */
- if (CAN_Transmit(psNuCAN->base, MSG(boxno), &tMsg) == FALSE)
- {
- goto exit_nu_can_sendmsg;
- }
- return RT_EOK;
- exit_nu_can_sendmsg:
- return -(RT_ERROR);
- }
- static int nu_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno)
- {
- STR_CANMSG_T tMsg;
- struct rt_can_msg *pmsg;
- nu_can_t psNuCAN = (nu_can_t)can;
- RT_ASSERT(can);
- RT_ASSERT(buf);
- pmsg = (struct rt_can_msg *) buf;
- /* get data */
- if (CAN_Receive(psNuCAN->base, boxno, &tMsg) == FALSE)
- {
- rt_kprintf("No available RX Msg.\n");
- return -(RT_ERROR);
- }
- #ifdef RT_CAN_USING_HDR
- /* Hardware filter messages are valid */
- pmsg->hdr = boxno - RX_MSG_ID_INDEX;
- can->hdr[pmsg->hdr].connected = 1;
- #endif
- pmsg->ide = (tMsg.IdType == CAN_STD_ID) ? RT_CAN_STDID : RT_CAN_EXTID;
- pmsg->rtr = (tMsg.FrameType == CAN_DATA_FRAME) ? RT_CAN_DTR : RT_CAN_RTR;
- pmsg->id = tMsg.Id;
- pmsg->len = tMsg.DLC ;
- if (pmsg->data && pmsg->len)
- rt_memcpy(pmsg->data, &tMsg.Data[0], pmsg->len);
- return RT_EOK;
- }
- /**
- * Hardware CAN Initialization
- */
- static int rt_hw_can_init(void)
- {
- int i;
- rt_err_t ret = RT_EOK;
- for (i = (CAN_START + 1); i < CAN_CNT; i++)
- {
- nu_can_arr[i].dev.config = nu_can_default_config;
- #ifdef RT_CAN_USING_HDR
- nu_can_arr[i].dev.config.maxhdr = RT_CANMSG_BOX_SZ;
- #endif
- /* Register can device */
- ret = rt_hw_can_register(&nu_can_arr[i].dev, nu_can_arr[i].name, &nu_can_ops, NULL);
- RT_ASSERT(ret == RT_EOK);
- }
- return (int)ret;
- }
- INIT_DEVICE_EXPORT(rt_hw_can_init);
- #endif //#if defined(BSP_USING_CAN)
|